优化电子凭证操作与测试数据
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
buildOpen91QueryMock,
|
buildOpen91QueryMock,
|
||||||
createAffiliateDashMockClaim,
|
createAffiliateDashMockClaim,
|
||||||
createFeifeiMockClaim,
|
createFeifeiMockClaim,
|
||||||
|
createKuaishouIndustryVoucherMockData,
|
||||||
createLewanMockClaim,
|
createLewanMockClaim,
|
||||||
getDevMockStatus,
|
getDevMockStatus,
|
||||||
isDevMockEnabled,
|
isDevMockEnabled,
|
||||||
@@ -101,6 +102,23 @@ router.post(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/dev-mock/kuaishou-industry/vouchers',
|
||||||
|
createJsonHandler((req) => createKuaishouIndustryVoucherMockData(req.body || {}), {
|
||||||
|
successMessage: '快手电子凭证 Mock 已生成',
|
||||||
|
errorMessage: '生成快手电子凭证 Mock 失败',
|
||||||
|
scope: '[admin/dev-mock/kuaishou-industry/vouchers]',
|
||||||
|
audit: (_req, data) => ({
|
||||||
|
action: 'dev_mock_create_kuaishou_industry_vouchers',
|
||||||
|
targetType: 'dev_mock',
|
||||||
|
targetId: String((data as { sellerId?: string })?.sellerId || ''),
|
||||||
|
data: {
|
||||||
|
createdCount: (data as { createdCount?: number })?.createdCount || 0,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/dev-mock/open91/query',
|
'/dev-mock/open91/query',
|
||||||
createJsonHandler((req) => buildOpen91QueryMock(req.body || {}), {
|
createJsonHandler((req) => buildOpen91QueryMock(req.body || {}), {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import crypto from 'node:crypto'
|
|||||||
import { createOrder, findOrderByPlatformOrderId } from '../../repositories/order-repo.js'
|
import { createOrder, findOrderByPlatformOrderId } from '../../repositories/order-repo.js'
|
||||||
import { replaceOrderItems } from '../../repositories/order-item-repo.js'
|
import { replaceOrderItems } from '../../repositories/order-item-repo.js'
|
||||||
import { createTask, updateTask } from '../../repositories/task-repo.js'
|
import { createTask, updateTask } from '../../repositories/task-repo.js'
|
||||||
|
import { upsertKuaishouIndustryVoucher } from '../../repositories/kuaishou-industry-voucher-repo.js'
|
||||||
import {
|
import {
|
||||||
getFulfillmentProfileByKey,
|
getFulfillmentProfileByKey,
|
||||||
upsertFulfillmentProfile,
|
upsertFulfillmentProfile,
|
||||||
@@ -15,6 +16,10 @@ import { buildClaimUrl, createTaskClaimToken } from '../claim/claim-service.js'
|
|||||||
import { assertValidClaimUid, normalizeClaimUid } from '../claim/claim-identity.js'
|
import { assertValidClaimUid, normalizeClaimUid } from '../claim/claim-identity.js'
|
||||||
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER, assertOpen91Config } from '../open-91/config.js'
|
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER, assertOpen91Config } from '../open-91/config.js'
|
||||||
import { parseOpen91ProductNo } from '../platforms/ninetyone/order-service.js'
|
import { parseOpen91ProductNo } from '../platforms/ninetyone/order-service.js'
|
||||||
|
import {
|
||||||
|
getKuaishouIndustrySourceConfig,
|
||||||
|
listKuaishouIndustryShopConfigs,
|
||||||
|
} from '../platforms/kuaishou-industry/source-config-service.js'
|
||||||
import { isProductionLike } from '../../config/runtime-validation.js'
|
import { isProductionLike } from '../../config/runtime-validation.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { addHours, nowIso } from '../../utils/time.js'
|
import { addHours, nowIso } from '../../utils/time.js'
|
||||||
@@ -40,6 +45,16 @@ export type DevMockCreateResult = {
|
|||||||
open91QueryHint: string
|
open91QueryHint: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DevMockKuaishouIndustryVoucherResult = {
|
||||||
|
createdCount: number
|
||||||
|
sellerId: string
|
||||||
|
vouchers: Array<{
|
||||||
|
voucherCode: string
|
||||||
|
oid: string
|
||||||
|
status: string
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
type DeliveryItem = {
|
type DeliveryItem = {
|
||||||
cloudSkuId: number
|
cloudSkuId: number
|
||||||
cloudSkuName: string
|
cloudSkuName: string
|
||||||
@@ -554,6 +569,102 @@ export async function createAffiliateDashMockClaim(input: {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成电子凭证列表测试数据,不调用快手接口。
|
||||||
|
* 覆盖未使用、已核销、已销毁和发码失败等运营页面常见状态。
|
||||||
|
*/
|
||||||
|
export async function createKuaishouIndustryVoucherMockData(input: {
|
||||||
|
sellerId?: unknown
|
||||||
|
} = {}): Promise<DevMockKuaishouIndustryVoucherResult> {
|
||||||
|
assertDevMockEnabled()
|
||||||
|
|
||||||
|
const now = nowIso()
|
||||||
|
const timestamp = Date.now()
|
||||||
|
const sellerId = resolveMockIndustrySellerId(input.sellerId)
|
||||||
|
const specimens = [
|
||||||
|
{ status: 'UNUSED', callbackStatus: 'success', productName: '周卡 VIP 尊享礼包' },
|
||||||
|
{
|
||||||
|
status: 'UNUSED',
|
||||||
|
callbackStatus: 'failed',
|
||||||
|
callbackError: '开发 Mock 模拟发码回调失败',
|
||||||
|
productName: '幸运盲盒 限定款',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 'CONSUMED',
|
||||||
|
callbackStatus: 'success',
|
||||||
|
consumeSerialNum: `CONSUME-MOCK-${timestamp}-3`,
|
||||||
|
consumedAt: now,
|
||||||
|
productName: '星轨通行证月卡',
|
||||||
|
},
|
||||||
|
{ status: 'UNUSED', callbackStatus: 'success', productName: '精英荣耀专属礼盒' },
|
||||||
|
{
|
||||||
|
status: 'DESTROYED',
|
||||||
|
callbackStatus: 'success',
|
||||||
|
destroyedAt: now,
|
||||||
|
productName: '退款销毁测试券',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 'CONSUMED',
|
||||||
|
callbackStatus: 'success',
|
||||||
|
consumeSerialNum: `CONSUME-MOCK-${timestamp}-6`,
|
||||||
|
consumedAt: now,
|
||||||
|
productName: '浪漫天命皮肤礼包',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const vouchers: DevMockKuaishouIndustryVoucherResult['vouchers'] = []
|
||||||
|
for (const [index, specimen] of specimens.entries()) {
|
||||||
|
const oid = `MOCK-KS-${timestamp}-${index + 1}`
|
||||||
|
const voucher = await upsertKuaishouIndustryVoucher({
|
||||||
|
oid,
|
||||||
|
unitIndex: 1,
|
||||||
|
sellerId,
|
||||||
|
token: `mock-token-${timestamp}-${index + 1}`,
|
||||||
|
eticketType: 'GAME_OPEN_TICKET_CONSUME',
|
||||||
|
status: specimen.status,
|
||||||
|
validStartTime: timestamp - 60 * 60 * 1000,
|
||||||
|
validEndTime: timestamp + 7 * 24 * 60 * 60 * 1000,
|
||||||
|
consumeSerialNum: specimen.consumeSerialNum || '',
|
||||||
|
consumedAt: specimen.consumedAt || null,
|
||||||
|
destroyedAt: specimen.destroyedAt || null,
|
||||||
|
sendCallbackStatus: specimen.callbackStatus,
|
||||||
|
sendCallbackAttemptCount: specimen.callbackStatus === 'failed' ? 1 : 0,
|
||||||
|
sendCallbackLastError: specimen.callbackError || '',
|
||||||
|
sendCallbackResponseJson: {
|
||||||
|
mock: true,
|
||||||
|
success: specimen.callbackStatus === 'success',
|
||||||
|
},
|
||||||
|
sendCallbackSentAt: now,
|
||||||
|
rawPayloadJson: {
|
||||||
|
source: 'dev_mock',
|
||||||
|
mock: true,
|
||||||
|
productName: specimen.productName,
|
||||||
|
},
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!voucher) {
|
||||||
|
throw createHttpError('电子凭证 Mock 创建失败', {
|
||||||
|
statusCode: 500,
|
||||||
|
errorCode: 'dev_mock_kuaishou_industry_voucher_failed',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
vouchers.push({
|
||||||
|
voucherCode: voucher.voucher_code,
|
||||||
|
oid: voucher.oid,
|
||||||
|
status: voucher.status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
createdCount: vouchers.length,
|
||||||
|
sellerId,
|
||||||
|
vouchers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 91 查询请求体(带签名),可选对本机发起查询。
|
* 生成 91 查询请求体(带签名),可选对本机发起查询。
|
||||||
*/
|
*/
|
||||||
@@ -951,6 +1062,18 @@ function resolveMockUid(value: unknown, fallback: string) {
|
|||||||
return assertValidClaimUid(raw)
|
return assertValidClaimUid(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveMockIndustrySellerId(value: unknown): string {
|
||||||
|
const sellerId = String(value || '').trim()
|
||||||
|
if (sellerId) {
|
||||||
|
return sellerId
|
||||||
|
}
|
||||||
|
|
||||||
|
const shop = listKuaishouIndustryShopConfigs(getKuaishouIndustrySourceConfig()).find(
|
||||||
|
(item) => item.enabled !== false && (item.sellerId || item.shopId),
|
||||||
|
)
|
||||||
|
return String(shop?.sellerId || shop?.shopId || '141242642').trim()
|
||||||
|
}
|
||||||
|
|
||||||
function parseDeliveryItems(value: unknown): DeliveryItem[] {
|
function parseDeliveryItems(value: unknown): DeliveryItem[] {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -23,15 +23,19 @@ import {
|
|||||||
buildOpen91QueryDevMock,
|
buildOpen91QueryDevMock,
|
||||||
createAffiliateDashDevMock,
|
createAffiliateDashDevMock,
|
||||||
createFeifeiDevMock,
|
createFeifeiDevMock,
|
||||||
|
createKuaishouIndustryVoucherDevMock,
|
||||||
createLewanDevMock,
|
createLewanDevMock,
|
||||||
fetchDevMockStatus,
|
fetchDevMockStatus,
|
||||||
type DevMockCreateResult,
|
type DevMockCreateResult,
|
||||||
|
type DevMockKuaishouIndustryVoucherResult,
|
||||||
type DevMockOpen91QueryResult,
|
type DevMockOpen91QueryResult,
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
|
|
||||||
export default function AdminDevMockPage() {
|
export default function AdminDevMockPage() {
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
const [lastCreate, setLastCreate] = useState<DevMockCreateResult | null>(null)
|
const [lastCreate, setLastCreate] = useState<DevMockCreateResult | null>(null)
|
||||||
|
const [lastVoucherCreate, setLastVoucherCreate] =
|
||||||
|
useState<DevMockKuaishouIndustryVoucherResult | null>(null)
|
||||||
const [lastQuery, setLastQuery] = useState<DevMockOpen91QueryResult | null>(null)
|
const [lastQuery, setLastQuery] = useState<DevMockOpen91QueryResult | null>(null)
|
||||||
|
|
||||||
const statusQuery = useQuery({
|
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({
|
const open91Mutation = useMutation({
|
||||||
mutationFn: buildOpen91QueryDevMock,
|
mutationFn: buildOpen91QueryDevMock,
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
@@ -166,8 +181,17 @@ export default function AdminDevMockPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</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}>
|
<Col xs={24}>
|
||||||
<Card title="4. 模拟 91 查单(open-91/query)" bordered={false}>
|
<Card title="5. 模拟 91 查单(open-91/query)" bordered={false}>
|
||||||
<Form
|
<Form
|
||||||
layout="inline"
|
layout="inline"
|
||||||
initialValues={{ orderNo: defaultOrderNo, execute: '1' }}
|
initialValues={{ orderNo: defaultOrderNo, execute: '1' }}
|
||||||
@@ -284,6 +308,24 @@ export default function AdminDevMockPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
) : null}
|
) : 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 ? (
|
{lastQuery ? (
|
||||||
<Card title="91 查单结果">
|
<Card title="91 查单结果">
|
||||||
<Typography.Paragraph>
|
<Typography.Paragraph>
|
||||||
@@ -516,3 +558,26 @@ function AffiliateDashMockForm({
|
|||||||
</Form>
|
</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,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType, TabsProps } 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 { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
@@ -132,6 +132,8 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 50,
|
pageSize: 50,
|
||||||
})
|
})
|
||||||
|
// 异步接口返回后刷新列表时,仍使用用户最后一次输入的筛选条件。
|
||||||
|
const voucherFiltersRef = useRef(voucherFilters)
|
||||||
const [toolForm, setToolForm] = useState<AdminKuaishouIndustryVoucherToolPayload>({
|
const [toolForm, setToolForm] = useState<AdminKuaishouIndustryVoucherToolPayload>({
|
||||||
eticketType: '',
|
eticketType: '',
|
||||||
consumeType: 'consume',
|
consumeType: 'consume',
|
||||||
@@ -419,8 +421,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadVouchers(nextFilters: Partial<VoucherFilterState> = {}) {
|
async function loadVouchers(nextFilters: Partial<VoucherFilterState> = {}) {
|
||||||
const filters = { ...voucherFilters, ...nextFilters }
|
const filters = updateVoucherFilters(nextFilters)
|
||||||
setVoucherFilters(filters)
|
|
||||||
setVoucherLoading(true)
|
setVoucherLoading(true)
|
||||||
|
|
||||||
try {
|
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) {
|
function selectVoucher(row: AdminKuaishouIndustryVoucher) {
|
||||||
setSelectedVoucher(row)
|
setSelectedVoucher(row)
|
||||||
showSuccess(`已选择券码 ${row.voucherCode}`)
|
showSuccess(`已选择券码 ${row.voucherCode}`)
|
||||||
@@ -804,8 +823,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
placeholder="订单号 oid"
|
placeholder="订单号 oid"
|
||||||
value={voucherFilters.oid}
|
value={voucherFilters.oid}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setVoucherFilters({
|
updateVoucherFilters({
|
||||||
...voucherFilters,
|
|
||||||
oid: event.target.value,
|
oid: event.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -815,8 +833,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
placeholder="券码"
|
placeholder="券码"
|
||||||
value={voucherFilters.voucherCode}
|
value={voucherFilters.voucherCode}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setVoucherFilters({
|
updateVoucherFilters({
|
||||||
...voucherFilters,
|
|
||||||
voucherCode: event.target.value,
|
voucherCode: event.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -826,8 +843,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
placeholder="任务 ID"
|
placeholder="任务 ID"
|
||||||
value={voucherFilters.taskId}
|
value={voucherFilters.taskId}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setVoucherFilters({
|
updateVoucherFilters({
|
||||||
...voucherFilters,
|
|
||||||
taskId: event.target.value,
|
taskId: event.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -854,8 +870,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
placeholder="店铺 ID"
|
placeholder="店铺 ID"
|
||||||
value={voucherFilters.sellerId}
|
value={voucherFilters.sellerId}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setVoucherFilters({
|
updateVoucherFilters({
|
||||||
...voucherFilters,
|
|
||||||
sellerId: event.target.value,
|
sellerId: event.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -871,7 +886,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
{ label: '已核销', value: 'CONSUMED' },
|
{ label: '已核销', value: 'CONSUMED' },
|
||||||
{ label: '已销毁', value: 'DESTROYED' },
|
{ label: '已销毁', value: 'DESTROYED' },
|
||||||
]}
|
]}
|
||||||
onChange={(value) => setVoucherFilters({ ...voucherFilters, status: value || '' })}
|
onChange={(value) => updateVoucherFilters({ status: value || '' })}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -881,6 +896,7 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
>
|
>
|
||||||
查询
|
查询
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={clearVoucherFilters}>清空筛选</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,6 +35,16 @@ export type DevMockOpen91QueryResult = {
|
|||||||
response: unknown
|
response: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DevMockKuaishouIndustryVoucherResult = {
|
||||||
|
createdCount: number
|
||||||
|
sellerId: string
|
||||||
|
vouchers: Array<{
|
||||||
|
voucherCode: string
|
||||||
|
oid: string
|
||||||
|
status: string
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchDevMockStatus() {
|
export function fetchDevMockStatus() {
|
||||||
return apiGet<DevMockStatus>('/api/v1/admin/dev-mock/status')
|
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)
|
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: {
|
export function buildOpen91QueryDevMock(payload: {
|
||||||
orderNo: string
|
orderNo: string
|
||||||
execute?: boolean
|
execute?: boolean
|
||||||
|
|||||||
@@ -645,6 +645,13 @@ select {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kuaishou-industry-tool-card {
|
||||||
|
/* 右侧操作区跟随管理内容滚动容器,始终保持在可视区域内。 */
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
.kuaishou-industry-tool-section + .kuaishou-industry-tool-section {
|
.kuaishou-industry-tool-section + .kuaishou-industry-tool-section {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
@@ -1725,6 +1732,11 @@ select {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kuaishou-industry-tool-card {
|
||||||
|
/* 窄屏单列展示时不固定操作区,避免遮挡下方内容。 */
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
.manual-dispatch-grid,
|
.manual-dispatch-grid,
|
||||||
.fulfillment-overview-grid,
|
.fulfillment-overview-grid,
|
||||||
.task-flow-grid {
|
.task-flow-grid {
|
||||||
|
|||||||
Reference in New Issue
Block a user