feat: 小程序跳转H5+支付

This commit is contained in:
zc 2025-11-08 20:34:15 +08:00
parent d4fecd7e9b
commit 581c7d8532
13 changed files with 216 additions and 156 deletions

View File

@ -7,7 +7,10 @@ const envVersion = accountInfo.miniProgram.envVersion || "trial";
const GDEnvs = { const GDEnvs = {
develop: { develop: {
web: "https://h5.goudezhao.com", // web: "http://192.168.1.105:3000",
web: "http://localhost:3000",
// web: "http://10.10.0.27:3000",
// web: "https://h5.goudezhao.com",
host: "https://api.1024api.com", host: "https://api.1024api.com",
mdHost: "https://tcomlog.yijiesudai.com", mdHost: "https://tcomlog.yijiesudai.com",
}, },

View File

@ -15,6 +15,7 @@
"pages": [ "pages": [
"pages/home/index", "pages/home/index",
"pages/login/index", "pages/login/index",
"pages/pay/index",
"pages/category/index", "pages/category/index",
"pages/shopping-cart/index", "pages/shopping-cart/index",
"pages/mine/index", "pages/mine/index",

View File

@ -195,7 +195,7 @@ Page({
categories: res.data.map((item: any) => ({ categories: res.data.map((item: any) => ({
id: item.id, id: item.id,
name: item.name, name: item.name,
icon: item.categoryImageUrl, icon: item.imageUrl,
categoryId: "", categoryId: "",
children: item.childrens.map((child: any) => ({ children: item.childrens.map((child: any) => ({
id: child.id, id: child.id,

View File

@ -82,8 +82,8 @@ $theme-color: #06CD31;
align-items: center; align-items: center;
margin-bottom: 20rpx; margin-bottom: 20rpx;
.category-icon { .category-icon {
width: 100rpx; width: 120rpx;
height: 100rpx; height: 120rpx;
background-color: #bbb; background-color: #bbb;
border-radius: 40rpx; border-radius: 40rpx;
margin-bottom: 8rpx; margin-bottom: 8rpx;

View File

@ -122,12 +122,13 @@ Page({
}, },
}); });
}, },
// testzc 去商品详情 // 去商品详情
onGoCommodity(e: any) { onGoCommodity(e: any) {
wx.navigateTo({ onGoH5Page({
url: `/pages/H5/index?url=${encodeURIComponent( is_need_login: false,
`https://h5.goudezhao.com/commodity-detail?id=${e.currentTarget.dataset.id}` type: "",
)}`, url: `/commodity-detail?id=${e.currentTarget.dataset.id}`,
// url: `/commodity-detail?id=56`,
}); });
}, },
// 添加到购物车 // 添加到购物车
@ -162,7 +163,7 @@ Page({
categories: res.data.map((item: any) => ({ categories: res.data.map((item: any) => ({
id: item.id, id: item.id,
name: item.name, name: item.name,
icon: item.categoryImageUrl, icon: item.imageUrl,
categoryId: "", categoryId: "",
})), })),
}); });

View File

@ -35,7 +35,7 @@
<text class="view-more">更多</text> <text class="view-more">更多</text>
</view> </view>
<scroll-view class="sale-products" scroll-x> <scroll-view class="sale-products" scroll-x>
<view class="sale-item" wx:for="{{flashSaleProducts}}" wx:key="id"> <view class="sale-item" wx:for="{{flashSaleProducts}}" wx:key="id" bindtap="onGoCommodity" data-id="{{item.id}}">
<image class="sale-image" src="{{item.image}}" /> <image class="sale-image" src="{{item.image}}" />
<view class="sale-price-wrap"> <view class="sale-price-wrap">
<text class="sale-price">¥{{item.price}}</text> <text class="sale-price">¥{{item.price}}</text>

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -0,0 +1 @@
/* pages/protocol/index.wxss */

View File

@ -0,0 +1,26 @@
// pages/protocol/index.ts
import { requestPayment } from "../../utils/common";
Page({
/**
*
*/
data: {
url: "",
},
/**
* --
*/
onLoad(options) {
var payParams = JSON.parse(decodeURIComponent(options.payParams as string));
requestPayment(payParams)
.then((res: any) => {
console.warn("----- my data is 2222: ", 2222, res);
})
.catch((err: any) => {
console.warn("----- my data is 3333: ", 3333, err);
});
console.warn("----- my data is 1111: ", 1111, payParams);
},
});

View File

@ -0,0 +1 @@
<web-view id="webview" src="{{url}}" />

View File

@ -16,3 +16,29 @@ export const getGlobalData = (key: string) => {
} }
return null; return null;
}; };
/**
*
* @param paymentParams
* @returns Promise
*/
export const requestPayment = (paymentParams: {
timeStamp: string;
nonceStr: string;
package: string;
signType?: "MD5" | "HMAC-SHA256";
paySign: string;
}): Promise<WechatMiniprogram.GeneralCallbackResult> => {
return new Promise((resolve, reject) => {
wx.requestPayment({
...paymentParams,
signType: paymentParams.signType || "MD5",
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err);
},
});
});
};

View File

@ -4,7 +4,6 @@ export const wxInfo = wx.getSystemInfoSync();
export const mpInfo = wx.getAccountInfoSync(); export const mpInfo = wx.getAccountInfoSync();
export const miniProgramVersion = mpInfo.miniProgram.version || "1.0.0"; export const miniProgramVersion = mpInfo.miniProgram.version || "1.0.0";
const webUrl = require("../api/base").allBaseUrl.GDEnvs.web; const webUrl = require("../api/base").allBaseUrl.GDEnvs.web;
// 获取微信小程序token // 获取微信小程序token
export const getWxToken = async () => { export const getWxToken = async () => {
return new Promise((resolve) => { return new Promise((resolve) => {
@ -12,48 +11,10 @@ export const getWxToken = async () => {
wx.getStorage({ wx.getStorage({
key: "user_info", key: "user_info",
async success(res) { async success(res) {
console.warn("----- my data is res1111: ", res);
if (res.data.token) { if (res.data.token) {
wx.hideLoading(); wx.hideLoading();
const envParams = { linktoken: "miniProgram" }; resolve(handleGetReturnData(res.data));
// 获取经纬度
const locationDataObj = wx.getStorageSync("locationData");
if (locationDataObj) Object.assign(envParams, { ...locationDataObj });
// 获取小程序启动时的参数
const launchOptions = wx.getStorageSync("launch_options");
if (launchOptions)
Object.assign(envParams, { wxXcxLaunchOptions: launchOptions });
// 获取系统信息
Object.assign(envParams, {
phoneType: wxInfo.model,
devType: wxInfo.platform === "ios" ? 0 : 1,
devOS: wxInfo.platform,
devOSVersion: wxInfo.system,
devVersion: wxInfo.version,
appVersion: miniProgramVersion.replace(/\./g, ""),
});
const extendParams = {
lzCode: "CJTG_XCX_LZ",
uniqueCode: res.data.uniqueCode,
userName: res.data.userName,
userId: res.data.userId,
token: res.data.token,
};
wx.getStorage({
key: "unique_code",
success(res) {
if (res) {
Object.assign(extendParams, { uniqueCode: res });
}
},
});
const obj = { envParams, extendParams };
const returnDataValue = encodeURIComponent(
Base64.encode(JSON.stringify(obj))
);
resolve(returnDataValue);
} }
}, },
fail() { fail() {
@ -83,14 +44,36 @@ export const onGoH5Page = (params: any) => {
if (type === "third") { if (type === "third") {
wx.navigateTo({ url: `/pages/H5/index?url=${encodeURIComponent(url)}` }); wx.navigateTo({ url: `/pages/H5/index?url=${encodeURIComponent(url)}` });
} else { } else {
const targetUrl = `${url}${ const userInfo = wx.getStorageSync("user_info") || {};
const returnData = handleGetReturnData(userInfo);
const targetUrl = `${webUrl}${url}${
/\?/.test(url) ? "&" : "?" /\?/.test(url) ? "&" : "?"
}jumpData=${encodeURIComponent( }returnData=${returnData}`;
Base64.encode(JSON.stringify({ is_need_login: false }))
)}`;
wx.navigateTo({ wx.navigateTo({
url: `/pages/H5/index?url=${encodeURIComponent(targetUrl)}`, url: `/pages/H5/index?url=${encodeURIComponent(targetUrl)}`,
}); });
} }
} }
}; };
const handleGetReturnData = (userInfo: any) => {
const envParams = {};
const locationDataObj = wx.getStorageSync("locationData") || {}; // 获取经纬度
const launchOptions = wx.getStorageSync("launch_options") || {}; // 获取小程序启动时的参数
Object.assign(
envParams,
{
wxXcxLaunchOptions: launchOptions,
phoneType: wxInfo.model,
devType: wxInfo.platform === "ios" ? 0 : 1,
devOS: wxInfo.platform,
devOSVersion: wxInfo.system,
devVersion: wxInfo.version,
appVersion: miniProgramVersion.replace(/\./g, ""),
},
locationDataObj
);
const obj = { envParams, extendParams: userInfo };
console.warn("----- my data is obj111: ", obj);
return encodeURIComponent(Base64.encode(JSON.stringify(obj)));
};

View File

@ -2,153 +2,149 @@
* @description: HTTP请求方法枚举 * @description: HTTP请求方法枚举
*/ */
export enum HttpMethod { export enum HttpMethod {
GET = 'GET', GET = "GET",
POST = 'POST', POST = "POST",
OPTIONS = 'OPTIONS', OPTIONS = "OPTIONS",
PUT = 'PUT', PUT = "PUT",
DELETE = 'DELETE' DELETE = "DELETE",
} }
/** /**
* @description: HTTP请求配置 * @description: HTTP请求配置
*/ */
interface RequestConfig { interface RequestConfig {
/** API路径 */ /** API路径 */
url?: string url?: string;
/** Method类型 */ /** Method类型 */
method?: HttpMethod method?: HttpMethod;
/** 接口返回数据 */ /** 接口返回数据 */
data?: any data?: any;
/** 无TOKEN触发异常捕获时是否执行异常逻辑 */ /** 无TOKEN触发异常捕获时是否执行异常逻辑 */
needToken?: boolean needToken?: boolean;
/** Header头部 */ /** Header头部 */
header?: object header?: object;
/** 返回的数据格式 */ /** 返回的数据格式 */
dataType?: string dataType?: string;
/** 请求报错时是否弹出message提示默认弹出*/ /** 请求报错时是否弹出message提示默认弹出*/
noShowMsg?: boolean noShowMsg?: boolean;
} }
class HttpRequest { class HttpRequest {
private static instance: HttpRequest private static instance: HttpRequest;
private constructor() { } private constructor() {}
public static getInstance(): HttpRequest { public static getInstance(): HttpRequest {
if (!this.instance) { if (!this.instance) {
this.instance = new HttpRequest() this.instance = new HttpRequest();
} }
return this.instance return this.instance;
} }
// 处理请求异常状态码 // 处理请求异常状态码
private handerErrorStatus(statusCode: number, requestConfig: RequestConfig) { private handerErrorStatus(statusCode: number, requestConfig: RequestConfig) {
let msg = '服务找不到' let msg = "服务找不到";
if (statusCode === 502 || statusCode === 503) { if (statusCode === 502 || statusCode === 503) {
msg = '服务器开小差了~' msg = "服务器开小差了~";
} }
!requestConfig.noShowMsg && wx.showToast({ !requestConfig.noShowMsg &&
title: `${msg},错误码:${statusCode}`, wx.showToast({
icon: 'none' title: `${msg},错误码:${statusCode}`,
}) icon: "none",
return msg });
return msg;
} }
// 处理请求异常 // 处理请求异常
private handerError(err: { errMsg: string }, requestConfig: RequestConfig) { private handerError(err: { errMsg: string }, requestConfig: RequestConfig) {
let msg = `请求异常` let msg = `请求异常`;
if (/timeout/.test(err.errMsg)) { if (/timeout/.test(err.errMsg)) {
msg = '请求超时' msg = "请求超时";
} }
!requestConfig.noShowMsg && wx.showToast({ !requestConfig.noShowMsg &&
title: msg, wx.showToast({
icon: 'none' title: msg,
}); icon: "none",
return msg });
return msg;
} }
// 服务器接口请求 // 服务器接口请求
public request<T>(requestConfig: RequestConfig): Promise<T> { public request<T>(requestConfig: RequestConfig): Promise<T> {
const _this = this const _this = this;
const wxSystemInfo = wx.getSystemInfoSync() const wxSystemInfo = wx.getSystemInfoSync();
const user_info = wx.getStorageSync("user_info") || {};
const reqData = Object.assign(requestConfig.data, { const reqData = Object.assign(requestConfig.data, {
channelCode: 'CJTG_XCX_LZ', buyerId: user_info.buyerId,
devType: wxSystemInfo.platform === 'ios' ? 0 : 1 flag: user_info.flag,
}) });
const user_info = wx.getStorageSync('user_info')
if (user_info) {
Object.assign(reqData, { token: user_info.token, userName: user_info.userName })
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
wx.request({ wx.request({
method: requestConfig.method, method: requestConfig.method,
url: `${requestConfig.url}`, url: `${requestConfig.url}`,
data: reqData, data: reqData,
header: requestConfig?.header, header: { ...(requestConfig?.header || {}), token: user_info.token },
dataType: 'json', dataType: "json",
success (res) { success(res) {
const code = res.statusCode || -404 const code = res.statusCode || -404;
const data = res.data const data = res.data;
const isWhiteApi = requestConfig.url?.indexOf('/front/problem')
/** 接口请求成功*/ /** 接口请求成功*/
if (code == 200) { if (code == 200) {
if (isWhiteApi === -1) { if (["1003", "1004", "1005", "1006"].includes((data as any).code)) {
if ([1003, 1004, 1005, 1006].includes((data as any).code)) { wx.showModal({
wx.showModal({ content: (data as any).msg,
content: (data as any).msg, success(res) {
success (res) { if (res.confirm) {
if (res.confirm) { wx.removeStorageSync("user_info");
wx.removeStorageSync('user_info') wx.navigateTo({ url: "/pages/login/index" });
wx.navigateTo({ url: '/pages/login/index' }) } else if (res.cancel) {
} else if (res.cancel) { try {
try { wx.removeStorageSync("user_info");
wx.removeStorageSync('user_info') } catch (e) {
} catch (e) { console.log("登录失效catch", e);
console.log('登录失效catch', e)
}
wx.reLaunch({ url: '/pages/index/index' })
wx.hideLoading()
} }
wx.reLaunch({ url: "/pages/index/index" });
wx.hideLoading();
} }
}) },
} else { });
resolve(data as any)
}
} else { } else {
resolve(data as any) resolve(data as any);
} }
} else if (code === 401) { } else if (code === 401) {
// 未授权 // 未授权
!requestConfig.noShowMsg && wx.showModal({ !requestConfig.noShowMsg &&
title: '登录失效', wx
content: '登录失效,请重新登录', .showModal({
}).then(resModa => { title: "登录失效",
if (resModa.confirm) { content: "登录失效,请重新登录",
wx.removeStorageSync('user_info') })
wx.navigateTo({ url: '/pages/login/index' }) .then((resModa) => {
} else if (resModa.cancel) { if (resModa.confirm) {
try { wx.removeStorageSync("user_info");
wx.removeStorageSync('user_info') wx.navigateTo({ url: "/pages/login/index" });
wx.reLaunch({ url: '/pages/index/index' }) } else if (resModa.cancel) {
} catch (e) { try {
console.log('登录失效catch', e) wx.removeStorageSync("user_info");
} wx.reLaunch({ url: "/pages/index/index" });
} } catch (e) {
}) console.log("登录失效catch", e);
reject({ code, msg: '未登录', data: data }) }
}
});
reject({ code, msg: "未登录", data: data });
} else { } else {
//非200及401状态码-数据处理 //非200及401状态码-数据处理
const errMsg = _this.handerErrorStatus(code, requestConfig) const errMsg = _this.handerErrorStatus(code, requestConfig);
reject({ code, msg: errMsg, data }) reject({ code, msg: errMsg, data });
} }
}, },
fail: err => { fail: (err) => {
console.log('失败了', err); console.log("失败了", err);
let msg = _this.handerError(err, requestConfig) let msg = _this.handerError(err, requestConfig);
reject({ msg }) reject({ msg });
} },
}) });
}) });
} }
/** /**
@ -159,7 +155,12 @@ class HttpRequest {
* @return {*} * @return {*}
*/ */
public get<T>(url: string, data?: Object, OtherConfig?: RequestConfig) { public get<T>(url: string, data?: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.GET, url, data, ...OtherConfig }) return this.request<T>({
method: HttpMethod.GET,
url,
data,
...OtherConfig,
});
} }
/** /**
@ -171,7 +172,12 @@ class HttpRequest {
* @return {*} * @return {*}
*/ */
public post<T>(url: string, data: Object, OtherConfig?: RequestConfig) { public post<T>(url: string, data: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.POST, url, data, ...OtherConfig }) return this.request<T>({
method: HttpMethod.POST,
url,
data,
...OtherConfig,
});
} }
/** /**
@ -182,7 +188,12 @@ class HttpRequest {
* @return {*} * @return {*}
*/ */
public delete<T>(url: string, data: Object, OtherConfig?: RequestConfig) { public delete<T>(url: string, data: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.DELETE, url, data, ...OtherConfig }) return this.request<T>({
method: HttpMethod.DELETE,
url,
data,
...OtherConfig,
});
} }
/** /**
@ -193,9 +204,13 @@ class HttpRequest {
* @return {*} * @return {*}
*/ */
public put<T>(url: string, data?: Object, OtherConfig?: RequestConfig) { public put<T>(url: string, data?: Object, OtherConfig?: RequestConfig) {
return this.request<T>({ method: HttpMethod.PUT, url, data, ...OtherConfig }) return this.request<T>({
method: HttpMethod.PUT,
url,
data,
...OtherConfig,
});
} }
} }
export const httpRequest = HttpRequest.getInstance() export const httpRequest = HttpRequest.getInstance();