payment-kit 1.20.7 → 1.20.9
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/api/src/crons/index.ts +1 -1
- package/api/src/index.ts +2 -2
- package/api/src/libs/{vendor → vendor-util}/adapters/factory.ts +9 -5
- package/api/src/libs/{vendor → vendor-util}/adapters/launcher-adapter.ts +3 -8
- package/api/src/libs/{vendor → vendor-util}/adapters/types.ts +1 -4
- package/api/src/libs/{vendor → vendor-util}/fulfillment.ts +11 -8
- package/api/src/queues/{vendor → vendors}/commission.ts +4 -5
- package/api/src/queues/{vendor → vendors}/fulfillment-coordinator.ts +33 -4
- package/api/src/queues/{vendor → vendors}/fulfillment.ts +2 -2
- package/api/src/queues/{vendor → vendors}/status-check.ts +2 -2
- package/api/src/routes/payment-links.ts +2 -1
- package/api/src/routes/products.ts +1 -0
- package/api/src/routes/vendor.ts +135 -213
- package/api/src/store/migrations/20250911-add-vendor-type.ts +26 -0
- package/api/src/store/models/product-vendor.ts +6 -24
- package/api/src/store/models/product.ts +1 -0
- package/blocklet.yml +1 -1
- package/doc/vendor_fulfillment_system.md +1 -1
- package/package.json +23 -22
- package/src/components/metadata/form.tsx +12 -19
- package/src/components/payment-link/before-pay.tsx +40 -0
- package/src/components/product/vendor-config.tsx +4 -11
- package/src/components/subscription/description.tsx +1 -6
- package/src/components/subscription/portal/list.tsx +82 -6
- package/src/components/subscription/vendor-service-list.tsx +128 -0
- package/src/components/vendor/actions.tsx +1 -33
- package/src/locales/en.tsx +13 -3
- package/src/locales/zh.tsx +13 -3
- package/src/pages/admin/products/links/create.tsx +2 -0
- package/src/pages/admin/products/vendors/create.tsx +108 -194
- package/src/pages/admin/products/vendors/index.tsx +14 -22
- package/src/pages/customer/subscription/detail.tsx +26 -11
|
@@ -66,6 +66,7 @@ export default function CreatePaymentLink() {
|
|
|
66
66
|
subscription_data: {
|
|
67
67
|
description: '',
|
|
68
68
|
trial_period_days: 0,
|
|
69
|
+
no_stake: false,
|
|
69
70
|
},
|
|
70
71
|
nft_mint_settings: {
|
|
71
72
|
enabled: false,
|
|
@@ -86,6 +87,7 @@ export default function CreatePaymentLink() {
|
|
|
86
87
|
'billing_address_collection',
|
|
87
88
|
'phone_number_collection',
|
|
88
89
|
'currency_id',
|
|
90
|
+
'metadata',
|
|
89
91
|
]);
|
|
90
92
|
|
|
91
93
|
useEffect(() => {
|
|
@@ -15,24 +15,22 @@ import {
|
|
|
15
15
|
MenuItem,
|
|
16
16
|
} from '@mui/material';
|
|
17
17
|
import { useState } from 'react';
|
|
18
|
-
import { useForm, Controller } from 'react-hook-form';
|
|
18
|
+
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
|
19
19
|
import { dispatch } from 'use-bus';
|
|
20
20
|
|
|
21
21
|
import { joinURL, withQuery } from 'ufo';
|
|
22
22
|
import DrawerForm from '../../../../components/drawer-form';
|
|
23
|
+
import MetadataForm from '../../../../components/metadata/form';
|
|
23
24
|
import { formatProxyUrl } from '../../../../libs/util';
|
|
24
25
|
|
|
25
26
|
interface Vendor {
|
|
26
27
|
id: string;
|
|
27
28
|
vendor_key: string;
|
|
29
|
+
vendor_type: string;
|
|
28
30
|
name: string;
|
|
29
31
|
description: string;
|
|
30
32
|
app_url: string;
|
|
31
|
-
webhook_path: string;
|
|
32
|
-
default_commission_rate: number;
|
|
33
|
-
default_commission_type: 'percentage' | 'fixed_amount';
|
|
34
33
|
status: 'active' | 'inactive';
|
|
35
|
-
order_create_params: Record<string, any>;
|
|
36
34
|
metadata: Record<string, any>;
|
|
37
35
|
created_at: string;
|
|
38
36
|
updated_at: string;
|
|
@@ -47,16 +45,12 @@ interface VendorCreateProps {
|
|
|
47
45
|
|
|
48
46
|
interface VendorFormData {
|
|
49
47
|
vendor_key: string;
|
|
48
|
+
vendor_type: string;
|
|
50
49
|
name: string;
|
|
51
50
|
description: string;
|
|
52
51
|
app_url: string;
|
|
53
|
-
webhook_path: string;
|
|
54
|
-
blocklet_meta_url: string;
|
|
55
|
-
default_commission_rate: number;
|
|
56
|
-
default_commission_type: 'percentage' | 'fixed_amount';
|
|
57
52
|
status: 'active' | 'inactive';
|
|
58
|
-
|
|
59
|
-
metadata: Record<string, any>;
|
|
53
|
+
metadata: Array<{ key: string; value: string }>;
|
|
60
54
|
app_pid?: string;
|
|
61
55
|
app_logo?: string;
|
|
62
56
|
}
|
|
@@ -72,41 +66,43 @@ export default function VendorCreate({
|
|
|
72
66
|
|
|
73
67
|
const isEditMode = !!vendorData;
|
|
74
68
|
|
|
69
|
+
const defaultValues = vendorData
|
|
70
|
+
? {
|
|
71
|
+
...vendorData,
|
|
72
|
+
metadata: vendorData.metadata
|
|
73
|
+
? Object.entries(vendorData.metadata).map(([key, value]) => ({
|
|
74
|
+
key,
|
|
75
|
+
value: typeof value === 'object' ? JSON.stringify(value) : String(value),
|
|
76
|
+
}))
|
|
77
|
+
: [],
|
|
78
|
+
}
|
|
79
|
+
: {
|
|
80
|
+
vendor_key: '',
|
|
81
|
+
vendor_type: 'launcher',
|
|
82
|
+
name: '',
|
|
83
|
+
description: '',
|
|
84
|
+
app_url: '',
|
|
85
|
+
status: 'inactive' as const,
|
|
86
|
+
metadata: [{ key: 'blockletMetaUrl', value: '' }],
|
|
87
|
+
app_pid: '',
|
|
88
|
+
app_logo: '',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const methods = useForm<VendorFormData>({
|
|
92
|
+
mode: 'onChange',
|
|
93
|
+
defaultValues,
|
|
94
|
+
});
|
|
95
|
+
|
|
75
96
|
const {
|
|
76
97
|
control,
|
|
77
98
|
handleSubmit,
|
|
78
99
|
reset,
|
|
79
100
|
formState: { errors, isValid },
|
|
80
101
|
watch,
|
|
81
|
-
} =
|
|
82
|
-
mode: 'onChange',
|
|
83
|
-
defaultValues: vendorData
|
|
84
|
-
? {
|
|
85
|
-
...vendorData,
|
|
86
|
-
default_commission_rate: vendorData.default_commission_rate,
|
|
87
|
-
blocklet_meta_url: vendorData.metadata?.blockletMetaUrl || '',
|
|
88
|
-
}
|
|
89
|
-
: {
|
|
90
|
-
vendor_key: '',
|
|
91
|
-
name: '',
|
|
92
|
-
description: '',
|
|
93
|
-
app_url: '',
|
|
94
|
-
webhook_path: '',
|
|
95
|
-
blocklet_meta_url: '',
|
|
96
|
-
default_commission_rate: 80,
|
|
97
|
-
default_commission_type: 'percentage',
|
|
98
|
-
status: 'inactive',
|
|
99
|
-
order_create_params: {},
|
|
100
|
-
metadata: {},
|
|
101
|
-
app_pid: '',
|
|
102
|
-
app_logo: '',
|
|
103
|
-
},
|
|
104
|
-
});
|
|
102
|
+
} = methods;
|
|
105
103
|
|
|
106
104
|
const watchedValues = watch();
|
|
107
105
|
|
|
108
|
-
const isPercentage = watchedValues.default_commission_type === 'percentage';
|
|
109
|
-
|
|
110
106
|
const validateUrl = (url: string) => {
|
|
111
107
|
if (!url) return t('admin.vendor.appUrlRequired');
|
|
112
108
|
try {
|
|
@@ -118,25 +114,6 @@ export default function VendorCreate({
|
|
|
118
114
|
}
|
|
119
115
|
};
|
|
120
116
|
|
|
121
|
-
const validateWebhookPath = (path: string) => {
|
|
122
|
-
if (!path) return true;
|
|
123
|
-
if (!path.startsWith('/')) {
|
|
124
|
-
return t('admin.vendor.webhookPathInvalid');
|
|
125
|
-
}
|
|
126
|
-
return true;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const validateBlockletMetaUrl = (url: string) => {
|
|
130
|
-
if (!url) return t('admin.vendor.blockletMetaUrlRequired'); // 必填字段
|
|
131
|
-
try {
|
|
132
|
-
// eslint-disable-next-line no-new
|
|
133
|
-
new URL(url);
|
|
134
|
-
return true;
|
|
135
|
-
} catch {
|
|
136
|
-
return t('admin.vendor.blockletMetaUrlInvalid');
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
117
|
const onSubmit = async (data: VendorFormData) => {
|
|
141
118
|
try {
|
|
142
119
|
setLoading(true);
|
|
@@ -151,14 +128,23 @@ export default function VendorCreate({
|
|
|
151
128
|
return;
|
|
152
129
|
}
|
|
153
130
|
|
|
154
|
-
// 准备提交数据,将
|
|
155
|
-
const {
|
|
131
|
+
// 准备提交数据,将 metadata 数组转换为对象
|
|
132
|
+
const { metadata: metadataArray, ...restData } = data;
|
|
133
|
+
const metadataObj = metadataArray.reduce((acc: Record<string, any>, item) => {
|
|
134
|
+
if (item.key && item.value) {
|
|
135
|
+
try {
|
|
136
|
+
// 尝试解析 JSON,如果失败则作为字符串处理
|
|
137
|
+
acc[item.key] = JSON.parse(item.value);
|
|
138
|
+
} catch {
|
|
139
|
+
acc[item.key] = item.value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return acc;
|
|
143
|
+
}, {});
|
|
144
|
+
|
|
156
145
|
const submitData = {
|
|
157
146
|
...restData,
|
|
158
|
-
metadata:
|
|
159
|
-
...data.metadata,
|
|
160
|
-
...(blockletMetaUrl && { blockletMetaUrl }),
|
|
161
|
-
},
|
|
147
|
+
metadata: metadataObj,
|
|
162
148
|
};
|
|
163
149
|
|
|
164
150
|
// 如果状态为启用,则检测应用地址可用性
|
|
@@ -227,20 +213,35 @@ export default function VendorCreate({
|
|
|
227
213
|
};
|
|
228
214
|
|
|
229
215
|
return (
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<Stack
|
|
216
|
+
<FormProvider {...methods}>
|
|
217
|
+
<DrawerForm
|
|
218
|
+
icon={isEditMode ? null : <AddOutlined />}
|
|
219
|
+
text={isEditMode ? t('admin.vendor.edit') : t('admin.vendor.create')}
|
|
220
|
+
open={open}
|
|
221
|
+
onClose={handleClose}
|
|
222
|
+
width={800}
|
|
223
|
+
addons={
|
|
224
|
+
<Button variant="contained" size="small" onClick={handleSubmit(onSubmit)} disabled={loading || !isValid}>
|
|
225
|
+
{loading && <CircularProgress size="small" sx={{ mr: 1 }} />}
|
|
226
|
+
{isEditMode ? t('admin.save') : t('admin.vendor.save')}
|
|
227
|
+
</Button>
|
|
228
|
+
}>
|
|
229
|
+
<Stack spacing={3}>
|
|
230
|
+
<Controller
|
|
231
|
+
name="vendor_type"
|
|
232
|
+
control={control}
|
|
233
|
+
rules={{
|
|
234
|
+
required: t('admin.vendor.vendorTypeRequired'),
|
|
235
|
+
}}
|
|
236
|
+
render={({ field }) => (
|
|
237
|
+
<FormControl fullWidth required error={!!errors.vendor_type}>
|
|
238
|
+
<InputLabel>{t('admin.vendor.vendorType')}</InputLabel>
|
|
239
|
+
<Select {...field} label={t('admin.vendor.vendorType')}>
|
|
240
|
+
<MenuItem value="launcher">{t('admin.vendor.launcher')}</MenuItem>
|
|
241
|
+
</Select>
|
|
242
|
+
</FormControl>
|
|
243
|
+
)}
|
|
244
|
+
/>
|
|
244
245
|
<Controller
|
|
245
246
|
name="vendor_key"
|
|
246
247
|
control={control}
|
|
@@ -266,9 +267,7 @@ export default function VendorCreate({
|
|
|
266
267
|
<Controller
|
|
267
268
|
name="name"
|
|
268
269
|
control={control}
|
|
269
|
-
rules={{
|
|
270
|
-
required: t('admin.vendor.nameRequired'),
|
|
271
|
-
}}
|
|
270
|
+
rules={{ required: t('admin.vendor.nameRequired') }}
|
|
272
271
|
render={({ field }) => (
|
|
273
272
|
<TextField
|
|
274
273
|
{...field}
|
|
@@ -276,143 +275,58 @@ export default function VendorCreate({
|
|
|
276
275
|
required
|
|
277
276
|
fullWidth
|
|
278
277
|
error={!!errors.name}
|
|
279
|
-
helperText={errors.name?.message}
|
|
278
|
+
helperText={errors.name?.message || t('admin.vendor.displayNameHelp')}
|
|
280
279
|
/>
|
|
281
280
|
)}
|
|
282
281
|
/>
|
|
283
|
-
</Stack>
|
|
284
|
-
|
|
285
|
-
<Controller
|
|
286
|
-
name="description"
|
|
287
|
-
control={control}
|
|
288
|
-
render={({ field }) => (
|
|
289
|
-
<TextField {...field} label={t('admin.vendor.description')} multiline rows={3} fullWidth />
|
|
290
|
-
)}
|
|
291
|
-
/>
|
|
292
|
-
|
|
293
|
-
<Controller
|
|
294
|
-
name="app_url"
|
|
295
|
-
control={control}
|
|
296
|
-
rules={{
|
|
297
|
-
required: t('admin.vendor.appUrlRequired'),
|
|
298
|
-
validate: validateUrl,
|
|
299
|
-
}}
|
|
300
|
-
render={({ field }) => (
|
|
301
|
-
<TextField
|
|
302
|
-
{...field}
|
|
303
|
-
label={t('admin.vendor.appUrl')}
|
|
304
|
-
required
|
|
305
|
-
fullWidth
|
|
306
|
-
error={!!errors.app_url}
|
|
307
|
-
helperText={errors.app_url?.message || t('admin.vendor.appUrlHelp')}
|
|
308
|
-
/>
|
|
309
|
-
)}
|
|
310
|
-
/>
|
|
311
282
|
|
|
312
|
-
<Controller
|
|
313
|
-
name="webhook_path"
|
|
314
|
-
control={control}
|
|
315
|
-
rules={{
|
|
316
|
-
validate: validateWebhookPath,
|
|
317
|
-
}}
|
|
318
|
-
render={({ field }) => (
|
|
319
|
-
<TextField
|
|
320
|
-
{...field}
|
|
321
|
-
label={t('admin.vendor.webhookPath')}
|
|
322
|
-
fullWidth
|
|
323
|
-
error={!!errors.webhook_path}
|
|
324
|
-
helperText={errors.webhook_path?.message || t('admin.vendor.webhookPathHelp')}
|
|
325
|
-
/>
|
|
326
|
-
)}
|
|
327
|
-
/>
|
|
328
|
-
|
|
329
|
-
<Controller
|
|
330
|
-
name="blocklet_meta_url"
|
|
331
|
-
control={control}
|
|
332
|
-
rules={{
|
|
333
|
-
required: t('admin.vendor.blockletMetaUrlRequired'),
|
|
334
|
-
validate: validateBlockletMetaUrl,
|
|
335
|
-
}}
|
|
336
|
-
render={({ field }) => (
|
|
337
|
-
<TextField
|
|
338
|
-
{...field}
|
|
339
|
-
label={t('admin.vendor.blockletMetaUrl')}
|
|
340
|
-
required
|
|
341
|
-
fullWidth
|
|
342
|
-
error={!!errors.blocklet_meta_url}
|
|
343
|
-
helperText={errors.blocklet_meta_url?.message || t('admin.vendor.blockletMetaUrlHelp')}
|
|
344
|
-
/>
|
|
345
|
-
)}
|
|
346
|
-
/>
|
|
347
|
-
|
|
348
|
-
<Stack direction="row" spacing={0} sx={{ width: '30%' }}>
|
|
349
|
-
{/* 分成类型 - 隐藏,固定为比例分成 */}
|
|
350
283
|
<Controller
|
|
351
|
-
name="
|
|
284
|
+
name="description"
|
|
352
285
|
control={control}
|
|
353
286
|
render={({ field }) => (
|
|
354
|
-
<
|
|
355
|
-
<InputLabel>{t('admin.vendor.commissionType')}</InputLabel>
|
|
356
|
-
<Select {...field} label={t('admin.vendor.commissionType')}>
|
|
357
|
-
<MenuItem value="percentage">{t('admin.vendor.percentage')}</MenuItem>
|
|
358
|
-
<MenuItem value="fixed_amount">{t('admin.vendor.fixedAmount')}</MenuItem>
|
|
359
|
-
</Select>
|
|
360
|
-
</FormControl>
|
|
287
|
+
<TextField {...field} label={t('admin.vendor.description')} multiline rows={3} fullWidth />
|
|
361
288
|
)}
|
|
362
289
|
/>
|
|
290
|
+
|
|
363
291
|
<Controller
|
|
364
|
-
name="
|
|
292
|
+
name="app_url"
|
|
365
293
|
control={control}
|
|
366
294
|
rules={{
|
|
367
|
-
required: t('admin.vendor.
|
|
368
|
-
|
|
369
|
-
value: 0,
|
|
370
|
-
message: t('admin.vendor.commissionRateMin'),
|
|
371
|
-
},
|
|
372
|
-
max: {
|
|
373
|
-
value: isPercentage ? 100 : 999999,
|
|
374
|
-
message: t('admin.vendor.commissionRateMax'),
|
|
375
|
-
},
|
|
295
|
+
required: t('admin.vendor.appUrlRequired'),
|
|
296
|
+
validate: validateUrl,
|
|
376
297
|
}}
|
|
377
298
|
render={({ field }) => (
|
|
378
299
|
<TextField
|
|
379
300
|
{...field}
|
|
380
|
-
label={
|
|
381
|
-
type="number"
|
|
301
|
+
label={t('admin.vendor.appUrl')}
|
|
382
302
|
required
|
|
383
303
|
fullWidth
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
304
|
+
error={!!errors.app_url}
|
|
305
|
+
helperText={errors.app_url?.message || t('admin.vendor.appUrlHelp')}
|
|
306
|
+
/>
|
|
307
|
+
)}
|
|
308
|
+
/>
|
|
309
|
+
|
|
310
|
+
<MetadataForm title={t('common.metadata.label')} />
|
|
311
|
+
|
|
312
|
+
<Controller
|
|
313
|
+
name="status"
|
|
314
|
+
control={control}
|
|
315
|
+
render={({ field }) => (
|
|
316
|
+
<FormControlLabel
|
|
317
|
+
sx={{ maxWidth: 'max-content' }}
|
|
318
|
+
control={
|
|
319
|
+
<Switch
|
|
320
|
+
checked={field.value === 'active'}
|
|
321
|
+
onChange={(e) => field.onChange(e.target.checked ? 'active' : 'inactive')}
|
|
322
|
+
/>
|
|
389
323
|
}
|
|
390
|
-
|
|
391
|
-
min: 0,
|
|
392
|
-
max: isPercentage ? 100 : 999999,
|
|
393
|
-
step: isPercentage ? 10 : 1,
|
|
394
|
-
}}
|
|
324
|
+
label={watchedValues.status === 'active' ? t('admin.vendor.enabled') : t('admin.vendor.disabled')}
|
|
395
325
|
/>
|
|
396
326
|
)}
|
|
397
327
|
/>
|
|
398
328
|
</Stack>
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
name="status"
|
|
402
|
-
control={control}
|
|
403
|
-
render={({ field }) => (
|
|
404
|
-
<FormControlLabel
|
|
405
|
-
control={
|
|
406
|
-
<Switch
|
|
407
|
-
checked={field.value === 'active'}
|
|
408
|
-
onChange={(e) => field.onChange(e.target.checked ? 'active' : 'inactive')}
|
|
409
|
-
/>
|
|
410
|
-
}
|
|
411
|
-
label={watchedValues.status === 'active' ? t('admin.vendor.enabled') : t('admin.vendor.disabled')}
|
|
412
|
-
/>
|
|
413
|
-
)}
|
|
414
|
-
/>
|
|
415
|
-
</Stack>
|
|
416
|
-
</DrawerForm>
|
|
329
|
+
</DrawerForm>
|
|
330
|
+
</FormProvider>
|
|
417
331
|
);
|
|
418
332
|
}
|
|
@@ -16,14 +16,11 @@ import VendorCreate from './create';
|
|
|
16
16
|
interface Vendor {
|
|
17
17
|
id: string;
|
|
18
18
|
vendor_key: string;
|
|
19
|
+
vendor_type: string;
|
|
19
20
|
name: string;
|
|
20
21
|
description: string;
|
|
21
22
|
app_url: string;
|
|
22
|
-
webhook_path: string;
|
|
23
|
-
default_commission_rate: number;
|
|
24
|
-
default_commission_type: 'percentage' | 'fixed_amount';
|
|
25
23
|
status: 'active' | 'inactive';
|
|
26
|
-
order_create_params: Record<string, any>;
|
|
27
24
|
metadata: Record<string, any>;
|
|
28
25
|
created_at: string;
|
|
29
26
|
updated_at: string;
|
|
@@ -95,7 +92,17 @@ export default function VendorsList() {
|
|
|
95
92
|
filter: true,
|
|
96
93
|
customBodyRenderLite: (_: string, index: number) => {
|
|
97
94
|
const item = data.list[index] as Vendor;
|
|
98
|
-
return
|
|
95
|
+
return (
|
|
96
|
+
<InfoCard
|
|
97
|
+
name={item.name}
|
|
98
|
+
description={
|
|
99
|
+
<Typography variant="body2" color="text.secondary" sx={{ textTransform: 'capitalize' }}>
|
|
100
|
+
{item.vendor_type}
|
|
101
|
+
</Typography>
|
|
102
|
+
}
|
|
103
|
+
logo={undefined}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
99
106
|
},
|
|
100
107
|
},
|
|
101
108
|
},
|
|
@@ -114,21 +121,6 @@ export default function VendorsList() {
|
|
|
114
121
|
},
|
|
115
122
|
},
|
|
116
123
|
},
|
|
117
|
-
{
|
|
118
|
-
label: t('admin.vendor.commission'),
|
|
119
|
-
name: 'commission',
|
|
120
|
-
options: {
|
|
121
|
-
filter: true,
|
|
122
|
-
customBodyRenderLite: (_: string, index: number) => {
|
|
123
|
-
const item = data.list[index] as Vendor;
|
|
124
|
-
const commissionText =
|
|
125
|
-
item.default_commission_type === 'percentage'
|
|
126
|
-
? `${item.default_commission_rate}%`
|
|
127
|
-
: `${item.default_commission_rate}`;
|
|
128
|
-
return <Typography variant="body2">{commissionText}</Typography>;
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
124
|
{
|
|
133
125
|
label: t('common.status'),
|
|
134
126
|
name: 'status',
|
|
@@ -197,7 +189,7 @@ export default function VendorsList() {
|
|
|
197
189
|
return (
|
|
198
190
|
<>
|
|
199
191
|
{/* 供应商服务公钥展示 */}
|
|
200
|
-
{
|
|
192
|
+
{window.blocklet.appPk && (
|
|
201
193
|
<Box
|
|
202
194
|
sx={{
|
|
203
195
|
display: 'flex',
|
|
@@ -237,7 +229,7 @@ export default function VendorsList() {
|
|
|
237
229
|
}}>
|
|
238
230
|
<Chip
|
|
239
231
|
sx={{ backgroundColor: 'grey.200', color: 'text.secondary' }}
|
|
240
|
-
label={
|
|
232
|
+
label={window.blocklet.appPk}
|
|
241
233
|
variant="outlined"
|
|
242
234
|
size="small"
|
|
243
235
|
/>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* eslint-disable react/no-unstable-nested-components */
|
|
2
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
3
3
|
import {
|
|
4
|
+
api,
|
|
4
5
|
CreditTransactionsList,
|
|
5
6
|
CustomerInvoiceList,
|
|
6
|
-
TxLink,
|
|
7
|
-
api,
|
|
8
7
|
formatBNStr,
|
|
9
8
|
formatTime,
|
|
10
9
|
hasDelegateTxHash,
|
|
10
|
+
TxLink,
|
|
11
11
|
useMobile,
|
|
12
12
|
} from '@blocklet/payment-react';
|
|
13
13
|
import type { TPaymentCurrency, TSubscriptionExpanded } from '@blocklet/payment-types';
|
|
@@ -25,31 +25,32 @@ import {
|
|
|
25
25
|
Button,
|
|
26
26
|
CircularProgress,
|
|
27
27
|
Divider,
|
|
28
|
-
Stack,
|
|
29
|
-
Typography,
|
|
30
|
-
Link as MuiLink,
|
|
31
28
|
IconButton,
|
|
29
|
+
Link as MuiLink,
|
|
30
|
+
Stack,
|
|
32
31
|
Tooltip,
|
|
32
|
+
Typography,
|
|
33
33
|
useTheme,
|
|
34
34
|
} from '@mui/material';
|
|
35
|
-
import { useRequest } from 'ahooks';
|
|
36
|
-
import { Link, useNavigate, useParams } from 'react-router-dom';
|
|
37
35
|
import { styled } from '@mui/system';
|
|
38
36
|
import { BN, fromUnitToToken } from '@ocap/util';
|
|
37
|
+
import { useRequest } from 'ahooks';
|
|
39
38
|
import { useCallback, useRef } from 'react';
|
|
39
|
+
import { Link, useNavigate, useParams } from 'react-router-dom';
|
|
40
40
|
import Currency from '../../../components/currency';
|
|
41
41
|
import CustomerLink from '../../../components/customer/link';
|
|
42
|
+
import InfoMetric from '../../../components/info-metric';
|
|
42
43
|
import InfoRow from '../../../components/info-row';
|
|
44
|
+
import InfoRowGroup from '../../../components/info-row-group';
|
|
43
45
|
import SubscriptionDescription from '../../../components/subscription/description';
|
|
44
46
|
import SubscriptionItemList from '../../../components/subscription/items';
|
|
45
47
|
import SubscriptionMetrics from '../../../components/subscription/metrics';
|
|
46
48
|
import SubscriptionActions, { ActionMethods } from '../../../components/subscription/portal/actions';
|
|
47
|
-
import
|
|
49
|
+
import VendorServiceList from '../../../components/subscription/vendor-service-list';
|
|
48
50
|
import { useSessionContext } from '../../../contexts/session';
|
|
49
|
-
import
|
|
50
|
-
import { useUnpaidInvoicesCheckForSubscription, usePendingAmountForSubscription } from '../../../hooks/subscription';
|
|
51
|
+
import { usePendingAmountForSubscription, useUnpaidInvoicesCheckForSubscription } from '../../../hooks/subscription';
|
|
51
52
|
import { formatSmartDuration, TimeUnit } from '../../../libs/dayjs';
|
|
52
|
-
import
|
|
53
|
+
import { canChangePaymentMethod } from '../../../libs/util';
|
|
53
54
|
|
|
54
55
|
const fetchData = (id: string | undefined): Promise<TSubscriptionExpanded> => {
|
|
55
56
|
return api.get(`/api/subscriptions/${id}`).then((res) => res.data);
|
|
@@ -691,6 +692,20 @@ export default function CustomerSubscriptionDetail() {
|
|
|
691
692
|
<SubscriptionItemList data={data.items} currency={data.paymentCurrency} mode="customer" />
|
|
692
693
|
</Box>
|
|
693
694
|
</Box>
|
|
695
|
+
{(() => {
|
|
696
|
+
const vendorServices = data.items?.map((item) => item.price?.product?.vendor_config || []).flat();
|
|
697
|
+
|
|
698
|
+
if (!vendorServices || vendorServices.length === 0) return null;
|
|
699
|
+
|
|
700
|
+
return (
|
|
701
|
+
<>
|
|
702
|
+
<Divider />
|
|
703
|
+
<Box className="section">
|
|
704
|
+
<VendorServiceList vendorServices={vendorServices} subscriptionId={id} />
|
|
705
|
+
</Box>
|
|
706
|
+
</>
|
|
707
|
+
);
|
|
708
|
+
})()}
|
|
694
709
|
<Divider />
|
|
695
710
|
{isCredit ? (
|
|
696
711
|
<Box className="section">
|