e93e4b8f84
Co-authored-by: Cursor <cursoragent@cursor.com>
388 lines
13 KiB
TypeScript
388 lines
13 KiB
TypeScript
import { useState } from 'react';
|
|
import {
|
|
Button, Card, Col, Form, Input, InputNumber, Row, Space, Tabs, Typography, message,
|
|
} from 'antd';
|
|
import { MOCK_SMS_FIXED_CODE } from '@dukang/shared-types';
|
|
import { request } from '../lib/api';
|
|
|
|
type ApiResult = Record<string, unknown>;
|
|
|
|
function ResultBox({ data }: { data: ApiResult | null }) {
|
|
if (!data) return <Typography.Text type="secondary">调用后在此显示结果</Typography.Text>;
|
|
return (
|
|
<pre style={{
|
|
margin: 0, padding: 12, background: '#f5f5f5', borderRadius: 4,
|
|
maxHeight: 320, overflow: 'auto', fontSize: 12,
|
|
}}>
|
|
{JSON.stringify(data, null, 2)}
|
|
</pre>
|
|
);
|
|
}
|
|
|
|
export default function RedeemDebugPage() {
|
|
const [createForm] = Form.useForm();
|
|
const [previewForm] = Form.useForm();
|
|
const [confirmForm] = Form.useForm();
|
|
const [phoneLookupForm] = Form.useForm();
|
|
const [phoneBalanceForm] = Form.useForm();
|
|
const [phonePrepareForm] = Form.useForm();
|
|
const [phoneConfirmForm] = Form.useForm();
|
|
const [loading, setLoading] = useState(false);
|
|
const [createResult, setCreateResult] = useState<ApiResult | null>(null);
|
|
const [previewResult, setPreviewResult] = useState<ApiResult | null>(null);
|
|
const [confirmResult, setConfirmResult] = useState<ApiResult | null>(null);
|
|
const [phoneLookupResult, setPhoneLookupResult] = useState<ApiResult | null>(null);
|
|
const [phoneBalanceResult, setPhoneBalanceResult] = useState<ApiResult | null>(null);
|
|
const [phonePrepareResult, setPhonePrepareResult] = useState<ApiResult | null>(null);
|
|
const [phoneConfirmResult, setPhoneConfirmResult] = useState<ApiResult | null>(null);
|
|
|
|
async function invoke(
|
|
path: string,
|
|
body: unknown,
|
|
setResult: (v: ApiResult | null) => void,
|
|
successMsg: string,
|
|
onSuccess?: (res: ApiResult) => void,
|
|
) {
|
|
setLoading(true);
|
|
setResult(null);
|
|
try {
|
|
const res = await request<ApiResult>(path, {
|
|
method: 'POST',
|
|
body: JSON.stringify(body),
|
|
});
|
|
setResult(res);
|
|
message.success(successMsg);
|
|
onSuccess?.(res);
|
|
if (path.includes('create-token') && res.token) {
|
|
previewForm.setFieldsValue({ token: res.token });
|
|
confirmForm.setFieldsValue({ token: res.token });
|
|
}
|
|
if (path.includes('phone/balance') && res.sessionId) {
|
|
phonePrepareForm.setFieldsValue({
|
|
storeId: phoneBalanceForm.getFieldValue('storeId'),
|
|
sessionId: res.sessionId,
|
|
});
|
|
phoneConfirmForm.setFieldsValue({
|
|
storeId: phoneBalanceForm.getFieldValue('storeId'),
|
|
sessionId: res.sessionId,
|
|
});
|
|
}
|
|
} catch (e) {
|
|
message.error(e instanceof Error ? e.message : '调用失败');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
const tokenTabItems = [
|
|
{
|
|
key: 'create',
|
|
label: '1. 生成核销码',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={createForm} layout="vertical">
|
|
<Form.Item
|
|
name="userId"
|
|
label="用户"
|
|
rules={[{ required: true, message: '请填写用户 ID、编号或手机号' }]}
|
|
>
|
|
<Input placeholder="数据库 ID / 用户编号 / 手机号" />
|
|
</Form.Item>
|
|
<Form.Item name="amount" label="核销金额" rules={[{ required: true }]}>
|
|
<InputNumber min={0.01} max={500} step={1} style={{ width: '100%' }} />
|
|
</Form.Item>
|
|
<Form.Item name="couponId" label="指定券 ID(可选)">
|
|
<Input placeholder="不填则自动分摊" />
|
|
</Form.Item>
|
|
<Form.Item name="storeId" label="绑定门店 ID(可选)">
|
|
<Input placeholder="绑定后仅该门店可核销" />
|
|
</Form.Item>
|
|
<Button
|
|
type="primary"
|
|
loading={loading}
|
|
onClick={() => {
|
|
void createForm.validateFields().then((values) => {
|
|
void invoke('/admin/redeem/debug/create-token', values, setCreateResult, '核销码已生成');
|
|
});
|
|
}}
|
|
>
|
|
生成核销码
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={createResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'preview',
|
|
label: '2. 预览核销',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={previewForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="token" label="核销码" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Button
|
|
loading={loading}
|
|
onClick={() => {
|
|
const values = previewForm.getFieldsValue();
|
|
void invoke('/admin/redeem/debug/preview', values, setPreviewResult, '预览成功');
|
|
}}
|
|
>
|
|
预览
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={previewResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'confirm',
|
|
label: '3. 确认核销',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={confirmForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="token" label="核销码" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Space>
|
|
<Button
|
|
type="primary"
|
|
danger
|
|
loading={loading}
|
|
onClick={() => {
|
|
const values = confirmForm.getFieldsValue();
|
|
void invoke('/admin/redeem/debug/confirm', values, setConfirmResult, '核销成功');
|
|
}}
|
|
>
|
|
确认核销
|
|
</Button>
|
|
</Space>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={confirmResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
];
|
|
|
|
const phoneTabItems = [
|
|
{
|
|
key: 'phone-lookup',
|
|
label: '1. 发送查权益验证码',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={phoneLookupForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="phone" label="用户手机号" rules={[{ required: true }]}>
|
|
<Input placeholder="11 位手机号" />
|
|
</Form.Item>
|
|
<Button
|
|
type="primary"
|
|
loading={loading}
|
|
onClick={() => {
|
|
void phoneLookupForm.validateFields().then((values) => {
|
|
phoneBalanceForm.setFieldsValue({
|
|
storeId: values.storeId,
|
|
phone: values.phone,
|
|
});
|
|
void invoke(
|
|
'/admin/redeem/debug/phone/send-lookup-sms',
|
|
values,
|
|
setPhoneLookupResult,
|
|
'查权益验证码已发送',
|
|
);
|
|
});
|
|
}}
|
|
>
|
|
发送验证码
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={phoneLookupResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'phone-balance',
|
|
label: '2. 验证并查权益',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={phoneBalanceForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="phone" label="用户手机号" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="code" label="验证码" rules={[{ required: true }]}>
|
|
<Input placeholder={`Mock 默认 ${MOCK_SMS_FIXED_CODE}`} />
|
|
</Form.Item>
|
|
<Button
|
|
loading={loading}
|
|
onClick={() => {
|
|
void phoneBalanceForm.validateFields().then((values) => {
|
|
void invoke('/admin/redeem/debug/phone/balance', values, setPhoneBalanceResult, '权益查询成功');
|
|
});
|
|
}}
|
|
>
|
|
查询权益
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={phoneBalanceResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'phone-prepare',
|
|
label: '3. 发送核销确认码',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={phonePrepareForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="sessionId" label="会话 ID" rules={[{ required: true }]}>
|
|
<Input placeholder="上一步返回的 sessionId" />
|
|
</Form.Item>
|
|
<Form.Item name="amount" label="核销金额" rules={[{ required: true }]}>
|
|
<InputNumber min={0.01} max={500} step={1} style={{ width: '100%' }} />
|
|
</Form.Item>
|
|
<Button
|
|
loading={loading}
|
|
onClick={() => {
|
|
void phonePrepareForm.validateFields().then((values) => {
|
|
phoneConfirmForm.setFieldsValue({
|
|
storeId: values.storeId,
|
|
sessionId: values.sessionId,
|
|
});
|
|
void invoke('/admin/redeem/debug/phone/prepare', values, setPhonePrepareResult, '核销确认码已发送');
|
|
});
|
|
}}
|
|
>
|
|
发送确认码
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={phonePrepareResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'phone-confirm',
|
|
label: '4. 确认核销',
|
|
children: (
|
|
<Row gutter={16}>
|
|
<Col xs={24} lg={10}>
|
|
<Card size="small" title="参数">
|
|
<Form form={phoneConfirmForm} layout="vertical">
|
|
<Form.Item name="storeId" label="门店 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="sessionId" label="会话 ID" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item name="code" label="核销确认验证码" rules={[{ required: true }]}>
|
|
<Input placeholder={`Mock 默认 ${MOCK_SMS_FIXED_CODE}`} />
|
|
</Form.Item>
|
|
<Button
|
|
type="primary"
|
|
danger
|
|
loading={loading}
|
|
onClick={() => {
|
|
void phoneConfirmForm.validateFields().then((values) => {
|
|
void invoke('/admin/redeem/debug/phone/confirm', values, setPhoneConfirmResult, '手机号核销成功');
|
|
});
|
|
}}
|
|
>
|
|
确认核销
|
|
</Button>
|
|
</Form>
|
|
</Card>
|
|
</Col>
|
|
<Col xs={24} lg={14}>
|
|
<Card size="small" title="响应">
|
|
<ResultBox data={phoneConfirmResult} />
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<Typography.Title level={4}>核销调试</Typography.Title>
|
|
|
|
<Tabs
|
|
defaultActiveKey="token"
|
|
items={[
|
|
{
|
|
key: 'token',
|
|
label: '扫码核销',
|
|
children: <Tabs items={tokenTabItems} />,
|
|
},
|
|
{
|
|
key: 'phone',
|
|
label: '手机号核销',
|
|
children: <Tabs items={phoneTabItems} />,
|
|
},
|
|
]}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|