优化电子凭证操作与测试数据
This commit is contained in:
@@ -23,15 +23,19 @@ import {
|
||||
buildOpen91QueryDevMock,
|
||||
createAffiliateDashDevMock,
|
||||
createFeifeiDevMock,
|
||||
createKuaishouIndustryVoucherDevMock,
|
||||
createLewanDevMock,
|
||||
fetchDevMockStatus,
|
||||
type DevMockCreateResult,
|
||||
type DevMockKuaishouIndustryVoucherResult,
|
||||
type DevMockOpen91QueryResult,
|
||||
} from '@/services/admin'
|
||||
|
||||
export default function AdminDevMockPage() {
|
||||
const { message } = App.useApp()
|
||||
const [lastCreate, setLastCreate] = useState<DevMockCreateResult | null>(null)
|
||||
const [lastVoucherCreate, setLastVoucherCreate] =
|
||||
useState<DevMockKuaishouIndustryVoucherResult | null>(null)
|
||||
const [lastQuery, setLastQuery] = useState<DevMockOpen91QueryResult | null>(null)
|
||||
|
||||
const statusQuery = useQuery({
|
||||
@@ -76,6 +80,17 @@ export default function AdminDevMockPage() {
|
||||
},
|
||||
})
|
||||
|
||||
const voucherMutation = useMutation({
|
||||
mutationFn: createKuaishouIndustryVoucherDevMock,
|
||||
onSuccess: (response) => {
|
||||
setLastVoucherCreate(response.data)
|
||||
message.success(`已生成 ${response.data.createdCount} 条电子凭证 Mock`)
|
||||
},
|
||||
onError: (error) => {
|
||||
message.error(error instanceof Error ? error.message : '生成失败')
|
||||
},
|
||||
})
|
||||
|
||||
const open91Mutation = useMutation({
|
||||
mutationFn: buildOpen91QueryDevMock,
|
||||
onSuccess: (response) => {
|
||||
@@ -166,8 +181,17 @@ export default function AdminDevMockPage() {
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} xl={12}>
|
||||
<Card title="4. 快手电子凭证测试数据" bordered={false}>
|
||||
<KuaishouIndustryVoucherMockForm
|
||||
loading={voucherMutation.isPending}
|
||||
onSubmit={(values) => voucherMutation.mutate(values)}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24}>
|
||||
<Card title="4. 模拟 91 查单(open-91/query)" bordered={false}>
|
||||
<Card title="5. 模拟 91 查单(open-91/query)" bordered={false}>
|
||||
<Form
|
||||
layout="inline"
|
||||
initialValues={{ orderNo: defaultOrderNo, execute: '1' }}
|
||||
@@ -284,6 +308,24 @@ export default function AdminDevMockPage() {
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
{lastVoucherCreate ? (
|
||||
<Card
|
||||
title="最近生成的电子凭证 Mock"
|
||||
extra={<Link to="/admin/kuaishou-industry">查看电子凭证</Link>}
|
||||
>
|
||||
<Typography.Paragraph type="secondary">
|
||||
已为店铺 {lastVoucherCreate.sellerId} 写入 {lastVoucherCreate.createdCount} 条测试券码。
|
||||
</Typography.Paragraph>
|
||||
<Space direction="vertical" size={4}>
|
||||
{lastVoucherCreate.vouchers.map((voucher) => (
|
||||
<Typography.Text key={voucher.voucherCode} copyable>
|
||||
{voucher.status} · {voucher.voucherCode} · {voucher.oid}
|
||||
</Typography.Text>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
{lastQuery ? (
|
||||
<Card title="91 查单结果">
|
||||
<Typography.Paragraph>
|
||||
@@ -516,3 +558,26 @@ function AffiliateDashMockForm({
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
function KuaishouIndustryVoucherMockForm({
|
||||
loading,
|
||||
onSubmit,
|
||||
}: {
|
||||
loading: boolean
|
||||
onSubmit: (values: { sellerId?: string }) => void
|
||||
}) {
|
||||
return (
|
||||
<Form layout="vertical" onFinish={onSubmit}>
|
||||
<Form.Item
|
||||
label="店铺 ID(可空)"
|
||||
name="sellerId"
|
||||
extra="留空时使用快手行业配置中的首个启用店铺;会生成 6 条不同状态的券码。"
|
||||
>
|
||||
<Input allowClear placeholder="留空自动选择测试店铺" />
|
||||
</Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={loading} block>
|
||||
生成电子凭证 Mock
|
||||
</Button>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd'
|
||||
import type { TableColumnsType, TabsProps } from 'antd'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||
import PageHeader from '@/components/admin/PageHeader'
|
||||
@@ -132,6 +132,8 @@ export default function AdminKuaishouIndustryPage() {
|
||||
page: 1,
|
||||
pageSize: 50,
|
||||
})
|
||||
// 异步接口返回后刷新列表时,仍使用用户最后一次输入的筛选条件。
|
||||
const voucherFiltersRef = useRef(voucherFilters)
|
||||
const [toolForm, setToolForm] = useState<AdminKuaishouIndustryVoucherToolPayload>({
|
||||
eticketType: '',
|
||||
consumeType: 'consume',
|
||||
@@ -419,8 +421,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
}
|
||||
|
||||
async function loadVouchers(nextFilters: Partial<VoucherFilterState> = {}) {
|
||||
const filters = { ...voucherFilters, ...nextFilters }
|
||||
setVoucherFilters(filters)
|
||||
const filters = updateVoucherFilters(nextFilters)
|
||||
setVoucherLoading(true)
|
||||
|
||||
try {
|
||||
@@ -449,6 +450,24 @@ export default function AdminKuaishouIndustryPage() {
|
||||
}
|
||||
}
|
||||
|
||||
function updateVoucherFilters(patch: Partial<VoucherFilterState>): VoucherFilterState {
|
||||
const nextFilters = { ...voucherFiltersRef.current, ...patch }
|
||||
voucherFiltersRef.current = nextFilters
|
||||
setVoucherFilters(nextFilters)
|
||||
return nextFilters
|
||||
}
|
||||
|
||||
function clearVoucherFilters() {
|
||||
void loadVouchers({
|
||||
oid: '',
|
||||
voucherCode: '',
|
||||
taskId: '',
|
||||
sellerId: '',
|
||||
status: '',
|
||||
page: 1,
|
||||
})
|
||||
}
|
||||
|
||||
function selectVoucher(row: AdminKuaishouIndustryVoucher) {
|
||||
setSelectedVoucher(row)
|
||||
showSuccess(`已选择券码 ${row.voucherCode}`)
|
||||
@@ -804,8 +823,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
placeholder="订单号 oid"
|
||||
value={voucherFilters.oid}
|
||||
onChange={(event) =>
|
||||
setVoucherFilters({
|
||||
...voucherFilters,
|
||||
updateVoucherFilters({
|
||||
oid: event.target.value,
|
||||
})
|
||||
}
|
||||
@@ -815,8 +833,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
placeholder="券码"
|
||||
value={voucherFilters.voucherCode}
|
||||
onChange={(event) =>
|
||||
setVoucherFilters({
|
||||
...voucherFilters,
|
||||
updateVoucherFilters({
|
||||
voucherCode: event.target.value,
|
||||
})
|
||||
}
|
||||
@@ -826,8 +843,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
placeholder="任务 ID"
|
||||
value={voucherFilters.taskId}
|
||||
onChange={(event) =>
|
||||
setVoucherFilters({
|
||||
...voucherFilters,
|
||||
updateVoucherFilters({
|
||||
taskId: event.target.value,
|
||||
})
|
||||
}
|
||||
@@ -854,8 +870,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
placeholder="店铺 ID"
|
||||
value={voucherFilters.sellerId}
|
||||
onChange={(event) =>
|
||||
setVoucherFilters({
|
||||
...voucherFilters,
|
||||
updateVoucherFilters({
|
||||
sellerId: event.target.value,
|
||||
})
|
||||
}
|
||||
@@ -871,7 +886,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
{ label: '已核销', value: 'CONSUMED' },
|
||||
{ label: '已销毁', value: 'DESTROYED' },
|
||||
]}
|
||||
onChange={(value) => setVoucherFilters({ ...voucherFilters, status: value || '' })}
|
||||
onChange={(value) => updateVoucherFilters({ status: value || '' })}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -881,6 +896,7 @@ export default function AdminKuaishouIndustryPage() {
|
||||
>
|
||||
查询
|
||||
</Button>
|
||||
<Button onClick={clearVoucherFilters}>清空筛选</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -35,6 +35,16 @@ export type DevMockOpen91QueryResult = {
|
||||
response: unknown
|
||||
}
|
||||
|
||||
export type DevMockKuaishouIndustryVoucherResult = {
|
||||
createdCount: number
|
||||
sellerId: string
|
||||
vouchers: Array<{
|
||||
voucherCode: string
|
||||
oid: string
|
||||
status: string
|
||||
}>
|
||||
}
|
||||
|
||||
export function fetchDevMockStatus() {
|
||||
return apiGet<DevMockStatus>('/api/v1/admin/dev-mock/status')
|
||||
}
|
||||
@@ -69,6 +79,13 @@ export function createAffiliateDashDevMock(payload: {
|
||||
return apiPost<DevMockCreateResult>('/api/v1/admin/dev-mock/affiliate-dash', payload)
|
||||
}
|
||||
|
||||
export function createKuaishouIndustryVoucherDevMock(payload: { sellerId?: string } = {}) {
|
||||
return apiPost<DevMockKuaishouIndustryVoucherResult>(
|
||||
'/api/v1/admin/dev-mock/kuaishou-industry/vouchers',
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
export function buildOpen91QueryDevMock(payload: {
|
||||
orderNo: string
|
||||
execute?: boolean
|
||||
|
||||
@@ -645,6 +645,13 @@ select {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.kuaishou-industry-tool-card {
|
||||
/* 右侧操作区跟随管理内容滚动容器,始终保持在可视区域内。 */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.kuaishou-industry-tool-section + .kuaishou-industry-tool-section {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
@@ -1725,6 +1732,11 @@ select {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.kuaishou-industry-tool-card {
|
||||
/* 窄屏单列展示时不固定操作区,避免遮挡下方内容。 */
|
||||
position: static;
|
||||
}
|
||||
|
||||
.manual-dispatch-grid,
|
||||
.fulfillment-overview-grid,
|
||||
.task-flow-grid {
|
||||
|
||||
Reference in New Issue
Block a user