best-unit 1.5.2 → 2.0.1

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.
@@ -0,0 +1,343 @@
1
+ import { Theme, type ThemeConfig } from "@/types";
2
+ import { getInitParams } from "@/utils/business";
3
+
4
+ function createDatePickerThemes() {
5
+ const theme = getInitParams<Theme>("theme");
6
+ const themeConfig = getInitParams<ThemeConfig>("themeConfig");
7
+
8
+ const base = {
9
+ container: {
10
+ position: "relative",
11
+ display: "inline-block",
12
+ },
13
+ input: {
14
+ display: "flex",
15
+ alignItems: "center",
16
+ justifyContent: "space-between",
17
+ padding: "8px 12px",
18
+ border: "1px solid #d9d9d9",
19
+ borderRadius: "6px",
20
+ backgroundColor: "#fff",
21
+ cursor: "pointer",
22
+ transition: "all 0.3s",
23
+ outline: "none",
24
+ fontSize: "14px",
25
+ lineHeight: "1.5715",
26
+ color: "rgba(0, 0, 0, 0.85)",
27
+ },
28
+ inputText: {
29
+ flex: 1,
30
+ textAlign: "left",
31
+ color: "rgba(0, 0, 0, 0.85)",
32
+ },
33
+ calendarIcon: {
34
+ fontSize: "16px",
35
+ color: "rgba(0, 0, 0, 0.45)",
36
+ marginLeft: "8px",
37
+ },
38
+ disabled: {
39
+ backgroundColor: "#f5f5f5",
40
+ color: "rgba(0, 0, 0, 0.25)",
41
+ cursor: "not-allowed",
42
+ },
43
+ panel: {
44
+ position: "absolute",
45
+ top: "100%",
46
+ left: 0,
47
+ zIndex: 1050,
48
+ backgroundColor: "#fff",
49
+ border: "1px solid #d9d9d9",
50
+ borderRadius: "6px",
51
+ boxShadow:
52
+ "0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05)",
53
+ padding: "8px",
54
+ minWidth: "280px",
55
+ marginTop: "4px",
56
+ },
57
+ header: {
58
+ display: "flex",
59
+ alignItems: "center",
60
+ justifyContent: "space-between",
61
+ padding: "8px 0",
62
+ marginBottom: "8px",
63
+ },
64
+ navButton: {
65
+ display: "flex",
66
+ alignItems: "center",
67
+ justifyContent: "center",
68
+ width: "24px",
69
+ height: "24px",
70
+ border: "none",
71
+ backgroundColor: "transparent",
72
+ cursor: "pointer",
73
+ borderRadius: "4px",
74
+ fontSize: "16px",
75
+ color: "rgba(0, 0, 0, 0.45)",
76
+ transition: "all 0.3s",
77
+ },
78
+ monthYear: {
79
+ fontSize: "16px",
80
+ fontWeight: 500,
81
+ color: "rgba(0, 0, 0, 0.85)",
82
+ },
83
+ weekHeader: {
84
+ display: "grid",
85
+ gridTemplateColumns: "repeat(7, 1fr)",
86
+ gap: "4px",
87
+ marginBottom: "8px",
88
+ },
89
+ weekDay: {
90
+ display: "flex",
91
+ alignItems: "center",
92
+ justifyContent: "center",
93
+ height: "32px",
94
+ fontSize: "14px",
95
+ fontWeight: 500,
96
+ color: "rgba(0, 0, 0, 0.85)",
97
+ },
98
+ calendarGrid: {
99
+ display: "grid",
100
+ gridTemplateColumns: "repeat(7, 1fr)",
101
+ gap: "4px",
102
+ },
103
+ dayButton: {
104
+ display: "flex",
105
+ alignItems: "center",
106
+ justifyContent: "center",
107
+ width: "32px",
108
+ height: "32px",
109
+ border: "none",
110
+ backgroundColor: "transparent",
111
+ cursor: "pointer",
112
+ borderRadius: "4px",
113
+ fontSize: "14px",
114
+ transition: "all 0.3s",
115
+ color: "rgba(0, 0, 0, 0.85)",
116
+ },
117
+ dayCurrentMonth: {
118
+ color: "rgba(0, 0, 0, 0.85)",
119
+ },
120
+ dayOtherMonth: {
121
+ color: "rgba(0, 0, 0, 0.25)",
122
+ },
123
+ dayToday: {
124
+ fontWeight: 600,
125
+ color: "#1890ff",
126
+ },
127
+ daySelected: {
128
+ backgroundColor: "#1890ff",
129
+ color: "#fff",
130
+ },
131
+ yearPicker: {
132
+ maxHeight: "200px",
133
+ overflowY: "auto",
134
+ marginBottom: "8px",
135
+ border: "1px solid #f0f0f0",
136
+ borderRadius: "4px",
137
+ padding: "8px",
138
+ },
139
+ yearGrid: {
140
+ display: "grid",
141
+ gridTemplateColumns: "repeat(4, 1fr)",
142
+ gap: "4px",
143
+ },
144
+ yearButton: {
145
+ display: "flex",
146
+ alignItems: "center",
147
+ justifyContent: "center",
148
+ padding: "6px 8px",
149
+ border: "none",
150
+ backgroundColor: "transparent",
151
+ cursor: "pointer",
152
+ borderRadius: "4px",
153
+ fontSize: "14px",
154
+ transition: "all 0.3s",
155
+ color: "rgba(0, 0, 0, 0.85)",
156
+ },
157
+ yearSelected: {
158
+ backgroundColor: "#1890ff",
159
+ color: "#fff",
160
+ },
161
+ small: {
162
+ padding: "4px 8px",
163
+ fontSize: "12px",
164
+ },
165
+ middle: {
166
+ padding: "8px 12px",
167
+ fontSize: "14px",
168
+ },
169
+ large: {
170
+ padding: "12px 16px",
171
+ fontSize: "16px",
172
+ },
173
+ };
174
+
175
+ const themes = {
176
+ white: {
177
+ ...base,
178
+ input: {
179
+ ...base.input,
180
+ border: "1px solid #d9d9d9",
181
+ backgroundColor: "#fff",
182
+ color: "rgba(0, 0, 0, 0.85)",
183
+ },
184
+ inputText: {
185
+ ...base.inputText,
186
+ color: "rgba(0, 0, 0, 0.85)",
187
+ },
188
+ calendarIcon: {
189
+ ...base.calendarIcon,
190
+ color: "rgba(0, 0, 0, 0.45)",
191
+ },
192
+ disabled: {
193
+ ...base.disabled,
194
+ backgroundColor: "#f5f5f5",
195
+ color: "rgba(0, 0, 0, 0.25)",
196
+ },
197
+ panel: {
198
+ ...base.panel,
199
+ backgroundColor: "#fff",
200
+ border: "1px solid #d9d9d9",
201
+ },
202
+ navButton: {
203
+ ...base.navButton,
204
+ color: "rgba(0, 0, 0, 0.45)",
205
+ },
206
+ monthYear: {
207
+ ...base.monthYear,
208
+ color: "rgba(0, 0, 0, 0.85)",
209
+ },
210
+ weekDay: {
211
+ ...base.weekDay,
212
+ color: "rgba(0, 0, 0, 0.85)",
213
+ },
214
+ dayButton: {
215
+ ...base.dayButton,
216
+ color: "rgba(0, 0, 0, 0.85)",
217
+ },
218
+ dayCurrentMonth: {
219
+ ...base.dayCurrentMonth,
220
+ color: "rgba(0, 0, 0, 0.85)",
221
+ },
222
+ dayOtherMonth: {
223
+ ...base.dayOtherMonth,
224
+ color: "rgba(0, 0, 0, 0.25)",
225
+ },
226
+ dayToday: {
227
+ ...base.dayToday,
228
+ color: "#1890ff",
229
+ },
230
+ daySelected: {
231
+ ...base.daySelected,
232
+ backgroundColor: "#1890ff",
233
+ color: "#fff",
234
+ },
235
+ yearPicker: {
236
+ ...base.yearPicker,
237
+ border: "1px solid #f0f0f0",
238
+ },
239
+ yearButton: {
240
+ ...base.yearButton,
241
+ color: "rgba(0, 0, 0, 0.85)",
242
+ },
243
+ yearSelected: {
244
+ ...base.yearSelected,
245
+ backgroundColor: "#1890ff",
246
+ color: "#fff",
247
+ },
248
+ },
249
+ dark: {
250
+ ...base,
251
+ input: {
252
+ ...base.input,
253
+ border: "1px solid #434343",
254
+ backgroundColor: "#141414",
255
+ color: "rgba(255, 255, 255, 0.85)",
256
+ },
257
+ inputText: {
258
+ ...base.inputText,
259
+ color: "rgba(255, 255, 255, 0.85)",
260
+ },
261
+ calendarIcon: {
262
+ ...base.calendarIcon,
263
+ color: "rgba(255, 255, 255, 0.45)",
264
+ },
265
+ disabled: {
266
+ ...base.disabled,
267
+ backgroundColor: "#262626",
268
+ color: "rgba(255, 255, 255, 0.25)",
269
+ },
270
+ panel: {
271
+ ...base.panel,
272
+ backgroundColor: "#141414",
273
+ border: "1px solid #434343",
274
+ },
275
+ navButton: {
276
+ ...base.navButton,
277
+ color: "rgba(255, 255, 255, 0.45)",
278
+ },
279
+ monthYear: {
280
+ ...base.monthYear,
281
+ color: "rgba(255, 255, 255, 0.85)",
282
+ },
283
+ weekDay: {
284
+ ...base.weekDay,
285
+ color: "rgba(255, 255, 255, 0.85)",
286
+ },
287
+ dayButton: {
288
+ ...base.dayButton,
289
+ color: "rgba(255, 255, 255, 0.85)",
290
+ },
291
+ dayCurrentMonth: {
292
+ ...base.dayCurrentMonth,
293
+ color: "rgba(255, 255, 255, 0.85)",
294
+ },
295
+ dayOtherMonth: {
296
+ ...base.dayOtherMonth,
297
+ color: "rgba(255, 255, 255, 0.25)",
298
+ },
299
+ dayToday: {
300
+ ...base.dayToday,
301
+ color: "#00E8C6",
302
+ },
303
+ daySelected: {
304
+ ...base.daySelected,
305
+ backgroundColor: "#00E8C6",
306
+ color: "#111",
307
+ },
308
+ yearPicker: {
309
+ ...base.yearPicker,
310
+ border: "1px solid #434343",
311
+ },
312
+ yearButton: {
313
+ ...base.yearButton,
314
+ color: "rgba(255, 255, 255, 0.85)",
315
+ },
316
+ yearSelected: {
317
+ ...base.yearSelected,
318
+ backgroundColor: "#00E8C6",
319
+ color: "#111",
320
+ },
321
+ },
322
+ };
323
+
324
+ const currentTheme = themes[theme] || themes.white;
325
+
326
+ // 应用自定义主题配置
327
+ const themeColor = themeConfig?.[theme]?.color;
328
+ if (themeColor) {
329
+ currentTheme.dayToday.color = themeColor;
330
+ currentTheme.daySelected.backgroundColor = themeColor;
331
+ currentTheme.yearSelected.backgroundColor = themeColor;
332
+ if (theme === "dark") {
333
+ currentTheme.daySelected.color = "#111";
334
+ currentTheme.yearSelected.color = "#111";
335
+ }
336
+ }
337
+
338
+ return currentTheme;
339
+ }
340
+
341
+ export function getDatePickerTheme() {
342
+ return createDatePickerThemes();
343
+ }
@@ -1,9 +1,45 @@
1
1
  import type { ComponentChildren } from "preact";
2
- import { useState } from "preact/hooks";
2
+ import { useState, useEffect } from "preact/hooks";
3
3
  import { getModalTheme } from "./theme";
4
4
  import { getInitParams } from "@/utils/business";
5
5
  import { Size } from "@/types";
6
+
6
7
  const size = getInitParams<Size>("size");
8
+
9
+ // 动态生成滚动条样式
10
+ function generateScrollbarStyles(theme: any) {
11
+ const styleId = `modal-scrollbar-${theme.scrollbarClass}`;
12
+
13
+ // 检查是否已经存在样式
14
+ if (document.getElementById(styleId)) {
15
+ return styleId;
16
+ }
17
+
18
+ const style = document.createElement("style");
19
+ style.id = styleId;
20
+ style.textContent = `
21
+ .${theme.scrollbarClass} {
22
+ scrollbar-width: thin;
23
+ scrollbar-color: ${theme.scrollbarThumbColor} transparent;
24
+ }
25
+ .${theme.scrollbarClass}::-webkit-scrollbar {
26
+ width: 6px;
27
+ }
28
+ .${theme.scrollbarClass}::-webkit-scrollbar-track {
29
+ background: transparent;
30
+ }
31
+ .${theme.scrollbarClass}::-webkit-scrollbar-thumb {
32
+ background: ${theme.scrollbarThumbColor};
33
+ border-radius: 3px;
34
+ }
35
+ .${theme.scrollbarClass}::-webkit-scrollbar-thumb:hover {
36
+ background: ${theme.scrollbarThumbHoverColor};
37
+ }
38
+ `;
39
+
40
+ document.head.appendChild(style);
41
+ return styleId;
42
+ }
7
43
  interface ModalProps {
8
44
  visible: boolean;
9
45
  onClose: () => void;
@@ -28,6 +64,11 @@ export function Modal({
28
64
  const [maskMouseDown, setMaskMouseDown] = useState(false);
29
65
  const theme = getModalTheme();
30
66
 
67
+ // 生成滚动条样式
68
+ useEffect(() => {
69
+ generateScrollbarStyles(theme);
70
+ }, [theme]);
71
+
31
72
  // 只有mousedown和mouseup都在mask上才关闭弹窗
32
73
  const handleMaskMouseDown = (e: any) => {
33
74
  if (e.target === e.currentTarget) {
@@ -66,33 +107,63 @@ export function Modal({
66
107
  <div
67
108
  style={{
68
109
  background: theme.modalBg,
69
- padding: size === Size.SMALL ? 24 : 32,
70
110
  borderRadius: size === Size.SMALL ? 8 : 12,
71
111
  minWidth: width,
72
112
  maxWidth: maxWidth,
73
113
  color: theme.modalColor,
74
114
  boxShadow: theme.modalBoxShadow,
75
115
  position: "relative",
116
+ // 响应式设计
117
+ width: typeof width === "string" ? width : `${width}px`,
118
+ maxHeight: "90vh",
119
+ display: "flex",
120
+ flexDirection: "column",
76
121
  }}
77
122
  onClick={(e) => e.stopPropagation()}
78
123
  >
79
- {/* 关闭按钮 */}
80
- {showClose && (
81
- <button
82
- type="button"
83
- onClick={onClose}
84
- style={theme.closeBtn}
85
- aria-label="关闭"
86
- >
87
- ×
88
- </button>
89
- )}
124
+ {/* 固定头部区域 */}
125
+ <div
126
+ style={{
127
+ position: "sticky",
128
+ top: 0,
129
+ background: theme.modalBg,
130
+ borderRadius: size === Size.SMALL ? "8px 8px 0 0" : "12px 12px 0 0",
131
+ padding:
132
+ size === Size.SMALL ? "24px 24px 0 24px" : "32px 32px 0 32px",
133
+ zIndex: 1,
134
+ borderBottom: `1px solid ${theme.headerBorder}`,
135
+ }}
136
+ >
137
+ {/* 关闭按钮 */}
138
+ {showClose && (
139
+ <button
140
+ type="button"
141
+ onClick={onClose}
142
+ style={theme.closeBtn}
143
+ aria-label="关闭"
144
+ >
145
+ ×
146
+ </button>
147
+ )}
90
148
 
91
- {/* 标题 */}
92
- {title && <div style={theme.title}>{title}</div>}
149
+ {/* 标题 */}
150
+ {title && <div style={theme.title}>{title}</div>}
151
+ </div>
93
152
 
94
- {/* 内容 */}
95
- {children}
153
+ {/* 可滚动内容区域 */}
154
+ <div
155
+ className={`modal-content ${theme.scrollbarClass}`}
156
+ style={{
157
+ flex: 1,
158
+ overflowY: "auto",
159
+ padding:
160
+ size === Size.SMALL
161
+ ? "16px 24px 24px 24px"
162
+ : "20px 32px 32px 32px",
163
+ }}
164
+ >
165
+ {children}
166
+ </div>
96
167
  </div>
97
168
  </div>
98
169
  );
@@ -33,6 +33,10 @@ function createModalThemes() {
33
33
  marginBottom: size === Size.SMALL ? 16 : 24,
34
34
  color: "#222",
35
35
  },
36
+ headerBorder: "#f0f0f0",
37
+ scrollbarClass: "light-scrollbar",
38
+ scrollbarThumbColor: "#d1d5db",
39
+ scrollbarThumbHoverColor: "#9ca3af",
36
40
  tabBtn: (active: boolean, isFirst: boolean) => ({
37
41
  flex: 1,
38
42
  padding: size === Size.SMALL ? "8px 10px" : "12px 16px",
@@ -73,6 +77,10 @@ function createModalThemes() {
73
77
  marginBottom: size === Size.SMALL ? 16 : 24,
74
78
  color: "#F5F6FA",
75
79
  },
80
+ headerBorder: "#374151",
81
+ scrollbarClass: "dark-scrollbar",
82
+ scrollbarThumbColor: "#4B5563",
83
+ scrollbarThumbHoverColor: "#6B7280",
76
84
  tabBtn: (active: boolean, isFirst: boolean) => ({
77
85
  flex: 1,
78
86
  padding: size === Size.SMALL ? "8px 10px" : "12px 16px",
package/src/demo/App.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import { useState } from "preact/hooks";
2
2
  import { npmTest, printCurrentTime } from "@/main";
3
3
  import { BestUnit } from "@/components/business/recharge-sdk";
4
+ import BestUnitPayment from "@/components/business/payment-sdk";
4
5
  import { initFundUnit, refreshBalance } from "@/main";
5
6
  import StatisticalBalance from "@/components/business/statistical-balance";
6
7
  import RefreshButton from "@/components/business/refresh-button";
@@ -44,6 +45,7 @@ export default function DemoApp() {
44
45
  theme: theme ?? Theme.WHITE,
45
46
  env: env ?? currentEnv,
46
47
  size: Size.SMALL,
48
+ biz_type: "fulfill",
47
49
  // themeConfig: {
48
50
  // white: {
49
51
  // color: "red",
@@ -323,6 +325,9 @@ export default function DemoApp() {
323
325
  BestUnit 组件演示:
324
326
  </h3>
325
327
  <BestUnit />
328
+ <div style={{ marginTop: 12 }}>
329
+ <BestUnitPayment />
330
+ </div>
326
331
  </div>
327
332
 
328
333
  <div>
package/src/local/en.ts CHANGED
@@ -32,6 +32,26 @@ export const en: Record<string, string> = {
32
32
  去支付: "Go to Pay",
33
33
  取消: "Cancel",
34
34
  关闭: "Close",
35
+ 在线支付: "Online Payment",
36
+ 选择支付方式: "Select Payment Method",
37
+ 支付方式: "Payment Method",
38
+ 付款人名称: "Payer Name",
39
+ 支付币种: "Payment Currency",
40
+ 支付金额: "Payment Amount",
41
+ 线上支付: "Online Payment",
42
+ 立即支付: "Pay Now",
43
+ "请在转账后提交银行回单,否则可能无法及时核验":
44
+ "Please submit the bank receipt after the transfer, otherwise verification may be delayed",
45
+ "支付金额须与申请金额一致,请勿多付、少付或分批提交。":
46
+ "The payment amount must match the requested amount exactly. Do not overpay, underpay, or split.",
47
+ "请妥善保存回单并提供准确的支付时间,否则可能无法核验。":
48
+ "Please keep the receipt and provide the exact payment time; otherwise, verification may fail.",
49
+ "工作时间提交4小时内审核,非工作时间将顺延至下一个工作日。":
50
+ "Submissions during business hours are reviewed within 4 hours; off-hours will be processed next business day.",
51
+ "如有问题,请联系平台客服。":
52
+ "If you have any questions, please contact customer service.",
53
+ "预付充值将收取平台服务费,具体以官方为准。":
54
+ "Prepaid top-ups are subject to a platform service fee; please refer to the official policy.",
35
55
 
36
56
  // 离线转账相关
37
57
  第三方支付平台: "Third-party Payment Platform",
@@ -59,6 +79,67 @@ export const en: Record<string, string> = {
59
79
  "正在上传...": "Uploading...",
60
80
  已上传: "Uploaded",
61
81
  移除: "Remove",
82
+
83
+ // Bank Transfer Related
84
+ 银行转账: "Transfer to Account",
85
+ 银行名称: "Bank Name",
86
+ 账户持有人: "Account Holder Name",
87
+ 账户号码: "Account Number",
88
+ "SWIFT/BIC代码": "SWIFT/BIC Code",
89
+ 银行代码: "Bank Code",
90
+ 银行地址: "Bank Address",
91
+ 复制: "Copy",
92
+ 复制成功: "Copied successfully",
93
+ 确认转账详情: "Confirm Transfer Details",
94
+ 转账后提交银行回单提示:
95
+ "Please make sure to submit the bank transaction slip after the transfer, otherwise the payment may not be verified in time",
96
+ 温馨提示: "Friendly Reminder",
97
+ 支付金额匹配提醒:
98
+ "The payment amount must match the transaction amount exactly. Overpayment, underpayment, or installment payments will not be approved. The actual amount shown on the bank receipt shall prevail. Do not submit duplicate applications for the same transfer.",
99
+ 保存交易回单提醒:
100
+ "Please print or take a photo of the transaction receipt and provide the exact payment time; otherwise, the transfer cannot be verified.",
101
+ 查看余额提醒:
102
+ "It is recommended to check your available balance 4 hours after successful submission. Transfers submitted during business hours will be processed the same day; those submitted outside business hours will be processed on the next working day.",
103
+ 联系客服提醒: "If you have any questions, please contact customer service.",
104
+ P卡转账延迟提醒:
105
+ "P-card transfers may experience a delay of up to 10 minutes. Please wait patiently.",
106
+ 平台服务费说明:
107
+ "Prepaid top-ups are subject to a 1% platform service fee. Please refer to the",
108
+ 费用政策: "Fee Policy",
109
+ 详情: "for details.",
110
+
111
+ // Bank Transfer Receipt Upload Related
112
+ 返回账户信息: "Return to Account Information",
113
+ 请上传银行转账回单: "Please upload the bank transfer receipt",
114
+ 点击或拖拽文件到此区域上传: "Click or drag file to this area to upload",
115
+ 转账时间: "Transfer Time",
116
+ 转账金额: "Transfer Amount",
117
+ 请输入实际转账金额: "Please enter the actual transfer amount",
118
+ 提交审核: "Submit for Review",
119
+ 请选择转账时间: "Please select transfer time",
120
+ 请输入转账金额: "Please enter transfer amount",
121
+
122
+ // Date picker related
123
+ 请选择日期: "Please select date",
124
+ 一月: "January",
125
+ 二月: "February",
126
+ 三月: "March",
127
+ 四月: "April",
128
+ 五月: "May",
129
+ 六月: "June",
130
+ 七月: "July",
131
+ 八月: "August",
132
+ 九月: "September",
133
+ 十月: "October",
134
+ 十一月: "November",
135
+ 十二月: "December",
136
+ 日: "Sun",
137
+ 一: "Mon",
138
+ 二: "Tue",
139
+ 三: "Wed",
140
+ 四: "Thu",
141
+ 五: "Fri",
142
+ 六: "Sat",
62
143
  };
63
144
 
64
145
  // 根据中文key获取英文文本的函数