my-uniapp-tools 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/payment-example.js +179 -0
- package/package.json +1 -1
- package/src/index.js +6 -0
- package/src/system/index.ts +41 -10
- package/src/utils/index.ts +1 -0
- package/src/utils/payment/index.ts +153 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 支付功能使用示例
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { usePayment } from '../src/utils/index.ts';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 微信支付示例 (App端)
|
|
9
|
+
*/
|
|
10
|
+
export const wechatPayExample = async () => {
|
|
11
|
+
try {
|
|
12
|
+
const result = await usePayment('wxpay', {
|
|
13
|
+
// App端微信支付必需参数
|
|
14
|
+
appid: 'your_app_id',
|
|
15
|
+
partnerid: 'your_partner_id',
|
|
16
|
+
prepayid: 'your_prepay_id',
|
|
17
|
+
package: 'Sign=WXPay',
|
|
18
|
+
noncestr: 'random_string_' + Date.now(),
|
|
19
|
+
timestamp: Math.floor(Date.now() / 1000).toString(),
|
|
20
|
+
sign: 'your_calculated_sign'
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (result.success) {
|
|
24
|
+
console.log('微信支付成功!');
|
|
25
|
+
console.log('订单号:', result.orderInfo.orderId);
|
|
26
|
+
console.log('支付时间:', new Date(result.timestamp));
|
|
27
|
+
|
|
28
|
+
// 支付成功后的业务逻辑
|
|
29
|
+
handlePaymentSuccess(result);
|
|
30
|
+
} else {
|
|
31
|
+
console.error('微信支付失败:', result.error);
|
|
32
|
+
|
|
33
|
+
// 支付失败后的业务逻辑
|
|
34
|
+
handlePaymentFail(result);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('支付过程中发生错误:', error);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 支付宝支付示例 (小程序 - String类型)
|
|
43
|
+
*/
|
|
44
|
+
export const alipayMiniProgramExample = async () => {
|
|
45
|
+
try {
|
|
46
|
+
// 支付宝小程序支付,orderInfo 为 String 类型的交易号
|
|
47
|
+
const result = await usePayment('alipay', 'your_trade_no_from_server');
|
|
48
|
+
|
|
49
|
+
if (result.success) {
|
|
50
|
+
console.log('支付宝小程序支付成功!');
|
|
51
|
+
handlePaymentSuccess(result);
|
|
52
|
+
} else {
|
|
53
|
+
console.error('支付宝小程序支付失败:', result.error);
|
|
54
|
+
handlePaymentFail(result);
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('支付过程中发生错误:', error);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 支付宝支付示例 (App端 - String类型)
|
|
63
|
+
*/
|
|
64
|
+
export const alipayAppExample = async () => {
|
|
65
|
+
try {
|
|
66
|
+
// App端支付宝支付,orderInfo 为 String 类型的订单字符串
|
|
67
|
+
const result = await usePayment('alipay', 'your_complete_order_string_from_server');
|
|
68
|
+
|
|
69
|
+
if (result.success) {
|
|
70
|
+
console.log('支付宝App支付成功!');
|
|
71
|
+
handlePaymentSuccess(result);
|
|
72
|
+
} else {
|
|
73
|
+
console.error('支付宝App支付失败:', result.error);
|
|
74
|
+
handlePaymentFail(result);
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('支付过程中发生错误:', error);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 支付成功处理函数
|
|
85
|
+
*/
|
|
86
|
+
const handlePaymentSuccess = (result) => {
|
|
87
|
+
console.log('处理支付成功逻辑...');
|
|
88
|
+
|
|
89
|
+
// 1. 更新本地状态
|
|
90
|
+
// 2. 发送支付成功通知到服务器
|
|
91
|
+
// 3. 更新用户界面
|
|
92
|
+
// 4. 跳转到成功页面
|
|
93
|
+
|
|
94
|
+
// 示例:显示成功提示
|
|
95
|
+
uni.showToast({
|
|
96
|
+
title: '支付成功',
|
|
97
|
+
icon: 'success',
|
|
98
|
+
duration: 2000
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// 示例:跳转到成功页面
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
uni.navigateTo({
|
|
104
|
+
url: '/pages/payment/success?orderId=' + result.orderInfo.orderId
|
|
105
|
+
});
|
|
106
|
+
}, 2000);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 支付失败处理函数
|
|
111
|
+
*/
|
|
112
|
+
const handlePaymentFail = (result) => {
|
|
113
|
+
console.log('处理支付失败逻辑...');
|
|
114
|
+
|
|
115
|
+
// 1. 记录失败日志
|
|
116
|
+
// 2. 显示错误提示
|
|
117
|
+
// 3. 提供重试选项
|
|
118
|
+
|
|
119
|
+
let errorMessage = '支付失败,请重试';
|
|
120
|
+
|
|
121
|
+
// 根据错误类型显示不同提示
|
|
122
|
+
if (result.error && result.error.errMsg) {
|
|
123
|
+
if (result.error.errMsg.includes('cancel')) {
|
|
124
|
+
errorMessage = '支付已取消';
|
|
125
|
+
} else if (result.error.errMsg.includes('fail')) {
|
|
126
|
+
errorMessage = '支付失败,请检查网络或稍后重试';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
uni.showModal({
|
|
131
|
+
title: '支付提示',
|
|
132
|
+
content: errorMessage,
|
|
133
|
+
showCancel: true,
|
|
134
|
+
cancelText: '取消',
|
|
135
|
+
confirmText: '重试',
|
|
136
|
+
success: (res) => {
|
|
137
|
+
if (res.confirm) {
|
|
138
|
+
// 用户选择重试,重新发起支付
|
|
139
|
+
console.log('用户选择重试支付');
|
|
140
|
+
// 这里可以重新调用对应的支付函数
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 批量支付示例(多个商品)
|
|
148
|
+
*/
|
|
149
|
+
export const batchPaymentExample = async () => {
|
|
150
|
+
const orders = [
|
|
151
|
+
{ orderId: 'order_001', amount: 1000, description: '商品1' },
|
|
152
|
+
{ orderId: 'order_002', amount: 2000, description: '商品2' },
|
|
153
|
+
{ orderId: 'order_003', amount: 3000, description: '商品3' }
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// 计算总金额
|
|
157
|
+
const totalAmount = orders.reduce((sum, order) => sum + order.amount, 0);
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const result = await usePayment('wxpay', {
|
|
161
|
+
orderId: 'batch_order_' + Date.now(),
|
|
162
|
+
amount: totalAmount,
|
|
163
|
+
description: `批量购买${orders.length}个商品`,
|
|
164
|
+
orderList: orders // 附加订单列表信息
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (result.success) {
|
|
168
|
+
console.log('批量支付成功!');
|
|
169
|
+
console.log('总金额:', totalAmount / 100, '元');
|
|
170
|
+
console.log('商品数量:', orders.length);
|
|
171
|
+
handlePaymentSuccess(result);
|
|
172
|
+
} else {
|
|
173
|
+
console.error('批量支付失败:', result.error);
|
|
174
|
+
handlePaymentFail(result);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('批量支付过程中发生错误:', error);
|
|
178
|
+
}
|
|
179
|
+
};
|
package/package.json
CHANGED
package/src/index.js
CHANGED
package/src/system/index.ts
CHANGED
|
@@ -141,24 +141,55 @@ export const getStatusBarHeight = () => {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* 获取菜单按钮边界信息
|
|
146
|
+
* @returns 菜单按钮边界信息对象或null
|
|
147
|
+
* @description 获取小程序右上角菜单按钮的边界信息,仅在小程序平台有效
|
|
148
|
+
*/
|
|
149
|
+
export const getMenuButtonBoundingClientRect = () => {
|
|
150
|
+
try {
|
|
151
|
+
const platform = getPlatform();
|
|
152
|
+
|
|
153
|
+
// 只有在小程序平台才执行getMenuButtonBoundingClientRect
|
|
154
|
+
if (platform === 'weixin' || platform === 'alipay') {
|
|
155
|
+
return uni.getMenuButtonBoundingClientRect();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 非小程序平台返回null
|
|
159
|
+
return null;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error('获取菜单按钮边界信息失败:', error);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
144
166
|
/**
|
|
145
167
|
* 获取导航栏高度
|
|
146
168
|
* @returns 导航栏高度(单位:px)
|
|
147
|
-
* @description
|
|
169
|
+
* @description 获取导航栏的总高度,根据不同平台采用不同的计算方式
|
|
148
170
|
*/
|
|
149
171
|
export const getNavHeight = () => {
|
|
150
172
|
try {
|
|
151
173
|
// 获取状态栏高度
|
|
152
174
|
const statusBarHeight = getStatusBarHeight();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
const platform = getPlatform();
|
|
176
|
+
|
|
177
|
+
// 小程序平台:状态栏高度 + 菜单按钮高度
|
|
178
|
+
if (platform === 'weixin' || platform === 'alipay') {
|
|
179
|
+
const menuButtonInfo = getMenuButtonBoundingClientRect();
|
|
180
|
+
if (menuButtonInfo) {
|
|
181
|
+
const navHeight = menuButtonInfo.height + statusBarHeight;
|
|
182
|
+
console.log("🚀 ~ 小程序导航栏高度:", navHeight);
|
|
183
|
+
return navHeight;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// App和H5平台:使用默认导航栏高度
|
|
188
|
+
const defaultNavHeight = 44; // 默认导航栏高度
|
|
189
|
+
const totalHeight = statusBarHeight + defaultNavHeight;
|
|
190
|
+
console.log(`🚀 ~ ${platform}平台导航栏高度:`, totalHeight);
|
|
191
|
+
|
|
192
|
+
return totalHeight;
|
|
162
193
|
} catch (error) {
|
|
163
194
|
console.error('获取导航栏高度失败:', error);
|
|
164
195
|
// 返回默认高度(状态栏高度 + 44px 默认导航栏高度)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './payment/index'
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 支付相关工具函数
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 支付提供商类型
|
|
7
|
+
*/
|
|
8
|
+
export type PaymentProvider = 'wxpay' | 'alipay';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 支付订单信息类型
|
|
12
|
+
* @description 根据不同支付方式,orderInfo 的类型和结构会有所不同:
|
|
13
|
+
* - 支付宝小程序:String 类型,表示支付宝交易号(tradeNO)
|
|
14
|
+
* - App端支付宝:String 类型,完整的订单字符串
|
|
15
|
+
* - App端微信:Object 类型,包含微信支付必需参数
|
|
16
|
+
*/
|
|
17
|
+
export type PaymentOrderInfo = string | {
|
|
18
|
+
/** 微信支付参数 (App端) */
|
|
19
|
+
appid?: string;
|
|
20
|
+
partnerid?: string;
|
|
21
|
+
prepayid?: string;
|
|
22
|
+
package?: string;
|
|
23
|
+
noncestr?: string;
|
|
24
|
+
timestamp?: string;
|
|
25
|
+
sign?: string;
|
|
26
|
+
|
|
27
|
+
/** 其他通用参数 */
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 支付结果接口
|
|
33
|
+
*/
|
|
34
|
+
export interface PaymentResult {
|
|
35
|
+
/** 支付是否成功 */
|
|
36
|
+
success: boolean;
|
|
37
|
+
/** 支付提供商 */
|
|
38
|
+
provider: PaymentProvider;
|
|
39
|
+
/** 订单信息 */
|
|
40
|
+
orderInfo: PaymentOrderInfo;
|
|
41
|
+
/** 支付时间戳 */
|
|
42
|
+
timestamp: number;
|
|
43
|
+
/** 错误信息(支付失败时) */
|
|
44
|
+
error?: any;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 统一支付接口
|
|
49
|
+
* @param provider 支付提供商,默认为 'wxpay'
|
|
50
|
+
* @param orderInfo 订单信息对象
|
|
51
|
+
* @returns Promise<PaymentResult> 支付结果
|
|
52
|
+
* @description 封装 uni.requestPayment,提供统一的支付接口,支持多种支付方式
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // 微信支付 (App端)
|
|
56
|
+
* const wxResult = await usePayment('wxpay', {
|
|
57
|
+
* appid: 'your_app_id',
|
|
58
|
+
* partnerid: 'your_partner_id',
|
|
59
|
+
* prepayid: 'your_prepay_id',
|
|
60
|
+
* package: 'Sign=WXPay',
|
|
61
|
+
* noncestr: 'random_string',
|
|
62
|
+
* timestamp: '1234567890',
|
|
63
|
+
* sign: 'your_sign'
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // 支付宝支付 (小程序 - String类型)
|
|
67
|
+
* const alipayResult = await usePayment('alipay', 'your_trade_no_string');
|
|
68
|
+
*
|
|
69
|
+
* // 支付宝支付 (App端 - String类型)
|
|
70
|
+
* const alipayAppResult = await usePayment('alipay', 'your_order_string');
|
|
71
|
+
*
|
|
72
|
+
* // 检查支付结果
|
|
73
|
+
* if (wxResult.success) {
|
|
74
|
+
* console.log('支付成功');
|
|
75
|
+
* } else {
|
|
76
|
+
* console.error('支付失败:', wxResult.error);
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export const usePayment = (
|
|
81
|
+
provider: PaymentProvider = 'wxpay',
|
|
82
|
+
orderInfo: PaymentOrderInfo = {}
|
|
83
|
+
): Promise<PaymentResult> => {
|
|
84
|
+
return new Promise<PaymentResult>((resolve, reject) => {
|
|
85
|
+
// 参数验证
|
|
86
|
+
if (!provider) {
|
|
87
|
+
const error = new Error('支付提供商不能为空');
|
|
88
|
+
reject(error);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 根据不同平台验证 orderInfo 类型
|
|
93
|
+
if (orderInfo === null || orderInfo === undefined) {
|
|
94
|
+
const error = new Error('订单信息不能为空');
|
|
95
|
+
reject(error);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 支付宝小程序和App端支付宝需要 String 类型
|
|
100
|
+
if ((provider === 'alipay') && typeof orderInfo !== 'string' && typeof orderInfo !== 'object') {
|
|
101
|
+
const error = new Error('支付宝支付的订单信息格式不正确');
|
|
102
|
+
reject(error);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 其他平台需要 Object 类型
|
|
107
|
+
if (provider !== 'alipay' && typeof orderInfo !== 'object') {
|
|
108
|
+
const error = new Error('订单信息必须是一个对象');
|
|
109
|
+
reject(error);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 记录支付开始时间
|
|
114
|
+
const timestamp = Date.now();
|
|
115
|
+
|
|
116
|
+
// 调用 uni.requestPayment 进行支付
|
|
117
|
+
uni.requestPayment({
|
|
118
|
+
provider,
|
|
119
|
+
orderInfo,
|
|
120
|
+
success: () => {
|
|
121
|
+
// 支付成功,返回成功结果
|
|
122
|
+
const result: PaymentResult = {
|
|
123
|
+
success: true,
|
|
124
|
+
provider,
|
|
125
|
+
orderInfo,
|
|
126
|
+
timestamp,
|
|
127
|
+
};
|
|
128
|
+
resolve(result);
|
|
129
|
+
},
|
|
130
|
+
fail: (err) => {
|
|
131
|
+
// 支付失败,返回失败结果
|
|
132
|
+
const result: PaymentResult = {
|
|
133
|
+
success: false,
|
|
134
|
+
provider,
|
|
135
|
+
orderInfo,
|
|
136
|
+
timestamp,
|
|
137
|
+
error: err,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// 根据错误类型进行不同处理
|
|
141
|
+
if (err.errMsg && err.errMsg.includes('cancel')) {
|
|
142
|
+
console.log('用户取消支付');
|
|
143
|
+
} else {
|
|
144
|
+
console.error('支付失败:', err);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 这里选择 resolve 而不是 reject,让调用者通过 result.success 判断支付结果
|
|
148
|
+
// 这样可以避免未捕获的 Promise 异常
|
|
149
|
+
resolve(result);
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
};
|