优化本地Mock接单
This commit is contained in:
@@ -165,6 +165,11 @@ import {
|
|||||||
normalizeWorkOrderTimeoutPolicy,
|
normalizeWorkOrderTimeoutPolicy,
|
||||||
} from './worker-service.js'
|
} from './worker-service.js'
|
||||||
import { reprocessKuaishouSendCodeWorkOrders } from './sync-work-orders-from-send-code.js'
|
import { reprocessKuaishouSendCodeWorkOrders } from './sync-work-orders-from-send-code.js'
|
||||||
|
import {
|
||||||
|
getKuaishouIndustrySourceConfig,
|
||||||
|
listKuaishouIndustryShopConfigs,
|
||||||
|
type KuaishouIndustryShopConfig,
|
||||||
|
} from '../platforms/kuaishou-industry/source-config-service.js'
|
||||||
|
|
||||||
export async function listAdminWorkerLevels() {
|
export async function listAdminWorkerLevels() {
|
||||||
await ensureWorkerPlatformDefaults()
|
await ensureWorkerPlatformDefaults()
|
||||||
@@ -1881,7 +1886,11 @@ export function resolveAdminMaterialRewardAmount(input: {
|
|||||||
export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
||||||
const defaults = await ensureWorkerPlatformDefaults()
|
const defaults = await ensureWorkerPlatformDefaults()
|
||||||
const now = nowIso()
|
const now = nowIso()
|
||||||
const rewardAmount = normalizeAmountFen(payload.rewardAmount ?? payload.rewardAmountYuan, 2500)
|
const input = resolveAdminMockWorkOrderInput(
|
||||||
|
payload,
|
||||||
|
listKuaishouIndustryShopConfigs(getKuaishouIndustrySourceConfig()),
|
||||||
|
)
|
||||||
|
const rewardAmount = input.rewardAmount
|
||||||
const depositThresholdAmount = normalizeAmountFen(
|
const depositThresholdAmount = normalizeAmountFen(
|
||||||
payload.depositThresholdAmount ?? payload.depositThresholdAmountYuan,
|
payload.depositThresholdAmount ?? payload.depositThresholdAmountYuan,
|
||||||
DEFAULT_DEPOSIT_THRESHOLD_AMOUNT,
|
DEFAULT_DEPOSIT_THRESHOLD_AMOUNT,
|
||||||
@@ -1892,21 +1901,10 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
|||||||
? rewardAmount
|
? rewardAmount
|
||||||
: 0
|
: 0
|
||||||
: normalizeAmountFen(payload.requiredDepositAmount, 0)
|
: normalizeAmountFen(payload.requiredDepositAmount, 0)
|
||||||
const paymentFen =
|
const paymentFen = input.paymentAmount
|
||||||
payload.paymentAmount === undefined &&
|
|
||||||
payload.paymentAmountYuan === undefined &&
|
|
||||||
payload.userPaymentAmount === undefined
|
|
||||||
? rewardAmount
|
|
||||||
: normalizeAmountFen(
|
|
||||||
payload.paymentAmount ?? payload.paymentAmountYuan ?? payload.userPaymentAmount,
|
|
||||||
rewardAmount,
|
|
||||||
)
|
|
||||||
const materialComplete = payload.materialComplete === true || payload.materialComplete === 'true'
|
const materialComplete = payload.materialComplete === true || payload.materialComplete === 'true'
|
||||||
const fields = normalizeRequirementFields(payload.fields)
|
const fields = normalizeRequirementFields(payload.fields)
|
||||||
const platformOrderId = String(
|
const { platformOrderId, productName, shop } = input
|
||||||
payload.platformOrderId || payload.orderNo || `MOCKWORK${Date.now()}`,
|
|
||||||
).trim()
|
|
||||||
const productName = String(payload.productName || '指挥官秘钥1个').trim()
|
|
||||||
const material = {
|
const material = {
|
||||||
...(materialComplete
|
...(materialComplete
|
||||||
? {
|
? {
|
||||||
@@ -1926,7 +1924,11 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
|||||||
mock: true,
|
mock: true,
|
||||||
provider: 'mock',
|
provider: 'mock',
|
||||||
platform: 'mock',
|
platform: 'mock',
|
||||||
shopName: '模拟店铺',
|
sellerId: String(shop.sellerId || shop.shopId || '').trim(),
|
||||||
|
shopId: String(shop.shopId || shop.sellerId || '').trim(),
|
||||||
|
shopName: String(
|
||||||
|
shop.customShopName || shop.shopName || shop.shopId || shop.sellerId || '',
|
||||||
|
).trim(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const workOrder = await createWorkOrder({
|
const workOrder = await createWorkOrder({
|
||||||
@@ -1957,12 +1959,94 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
|||||||
eventType: 'mock_created',
|
eventType: 'mock_created',
|
||||||
fromStatus: '',
|
fromStatus: '',
|
||||||
toStatus: workOrder.status,
|
toStatus: workOrder.status,
|
||||||
payloadJson: JSON.stringify({ platformOrderId, productName, rewardAmount }),
|
payloadJson: JSON.stringify({
|
||||||
|
platformOrderId,
|
||||||
|
productName,
|
||||||
|
rewardAmount,
|
||||||
|
sellerId: String(shop.sellerId || shop.shopId || '').trim(),
|
||||||
|
}),
|
||||||
now,
|
now,
|
||||||
})
|
})
|
||||||
return { order: mapWorkOrderAdmin(workOrder) }
|
return { order: mapWorkOrderAdmin(workOrder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 本地 Mock 与真实订单保持相同的关键字段约束,避免生成无法追溯的测试工单。 */
|
||||||
|
export function resolveAdminMockWorkOrderInput(
|
||||||
|
payload: JsonObject,
|
||||||
|
shops: KuaishouIndustryShopConfig[],
|
||||||
|
) {
|
||||||
|
const platformOrderId = String(payload.platformOrderId || '').trim()
|
||||||
|
if (!platformOrderId) {
|
||||||
|
throw createHttpError('请填写订单号', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'mock_work_order_no_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const productName = String(payload.productName || '').trim()
|
||||||
|
if (!productName) {
|
||||||
|
throw createHttpError('请填写商品名称', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'mock_work_order_product_name_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const shopId = String(payload.sellerId || payload.shopId || '').trim()
|
||||||
|
if (!shopId) {
|
||||||
|
throw createHttpError('请选择店铺', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'mock_work_order_shop_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const shop =
|
||||||
|
shops.find(
|
||||||
|
(item) =>
|
||||||
|
String(item.sellerId || item.shopId || '').trim() === shopId ||
|
||||||
|
String(item.shopId || '').trim() === shopId,
|
||||||
|
) || null
|
||||||
|
if (!shop) {
|
||||||
|
throw createHttpError('所选店铺不存在', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'mock_work_order_shop_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (shop.enabled === false) {
|
||||||
|
throw createHttpError('所选店铺已停用', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'mock_work_order_shop_disabled',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
platformOrderId,
|
||||||
|
productName,
|
||||||
|
shop,
|
||||||
|
rewardAmount: requireMockWorkOrderAmount(payload.rewardAmount, '接单金额', 'reward_amount'),
|
||||||
|
paymentAmount: requireMockWorkOrderAmount(
|
||||||
|
payload.paymentAmount,
|
||||||
|
'用户付款金额',
|
||||||
|
'payment_amount',
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireMockWorkOrderAmount(value: unknown, label: string, field: string): number {
|
||||||
|
if (value === undefined || value === null || String(value).trim() === '') {
|
||||||
|
throw createHttpError(`请填写${label}`, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: `mock_work_order_${field}_required`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const amount = normalizeAmountFen(value, 0)
|
||||||
|
if (amount <= 0) {
|
||||||
|
throw createHttpError(`${label}必须大于 0`, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: `mock_work_order_${field}_invalid`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return amount
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateAdminWorkOrder(
|
export async function updateAdminWorkOrder(
|
||||||
workOrderId: number | string,
|
workOrderId: number | string,
|
||||||
payload: JsonObject = {},
|
payload: JsonObject = {},
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
maskWorkerLeaderboardDisplayName,
|
maskWorkerLeaderboardDisplayName,
|
||||||
resolveCollectSubmitTargetWorkOrder,
|
resolveCollectSubmitTargetWorkOrder,
|
||||||
resolveAdminMaterialRewardAmount,
|
resolveAdminMaterialRewardAmount,
|
||||||
|
resolveAdminMockWorkOrderInput,
|
||||||
resolveMatchingProductRuleDecision,
|
resolveMatchingProductRuleDecision,
|
||||||
resolveWorkerPermissions,
|
resolveWorkerPermissions,
|
||||||
resolveSkuNameQuantity,
|
resolveSkuNameQuantity,
|
||||||
@@ -172,6 +173,78 @@ test('接单密码至少八位且必须包含英文字母和数字', () => {
|
|||||||
assert.throws(() => validateWorkerPassword('12345678'), { errorCode: 'worker_password_invalid' })
|
assert.throws(() => validateWorkerPassword('12345678'), { errorCode: 'worker_password_invalid' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('本地 Mock 工单要求订单、店铺、商品与两个金额完整有效', () => {
|
||||||
|
const shops = [
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
sellerId: 'seller-1',
|
||||||
|
shopId: 'shop-1',
|
||||||
|
shopName: '测试店铺',
|
||||||
|
customShopName: '',
|
||||||
|
authState: '',
|
||||||
|
accessToken: '',
|
||||||
|
refreshToken: '',
|
||||||
|
accessTokenExpiresAt: '',
|
||||||
|
refreshTokenExpiresAt: '',
|
||||||
|
openId: '',
|
||||||
|
grantedScopes: '',
|
||||||
|
lastRefreshedAt: '',
|
||||||
|
lastRefreshError: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: false,
|
||||||
|
sellerId: 'seller-disabled',
|
||||||
|
shopId: 'shop-disabled',
|
||||||
|
shopName: '已停用店铺',
|
||||||
|
customShopName: '',
|
||||||
|
authState: '',
|
||||||
|
accessToken: '',
|
||||||
|
refreshToken: '',
|
||||||
|
accessTokenExpiresAt: '',
|
||||||
|
refreshTokenExpiresAt: '',
|
||||||
|
openId: '',
|
||||||
|
grantedScopes: '',
|
||||||
|
lastRefreshedAt: '',
|
||||||
|
lastRefreshError: '',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const baseInput = {
|
||||||
|
platformOrderId: 'MOCK-1',
|
||||||
|
productName: '测试商品',
|
||||||
|
sellerId: 'seller-1',
|
||||||
|
rewardAmount: 25,
|
||||||
|
paymentAmount: 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.throws(() => resolveAdminMockWorkOrderInput({}, shops), {
|
||||||
|
errorCode: 'mock_work_order_no_required',
|
||||||
|
})
|
||||||
|
assert.throws(() => resolveAdminMockWorkOrderInput({ platformOrderId: 'MOCK-1' }, shops), {
|
||||||
|
errorCode: 'mock_work_order_product_name_required',
|
||||||
|
})
|
||||||
|
assert.throws(
|
||||||
|
() =>
|
||||||
|
resolveAdminMockWorkOrderInput({ platformOrderId: 'MOCK-1', productName: '测试商品' }, shops),
|
||||||
|
{ errorCode: 'mock_work_order_shop_required' },
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => resolveAdminMockWorkOrderInput({ ...baseInput, sellerId: 'unknown' }, shops),
|
||||||
|
{ errorCode: 'mock_work_order_shop_invalid' },
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => resolveAdminMockWorkOrderInput({ ...baseInput, sellerId: 'seller-disabled' }, shops),
|
||||||
|
{ errorCode: 'mock_work_order_shop_disabled' },
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => resolveAdminMockWorkOrderInput({ ...baseInput, rewardAmount: undefined }, shops),
|
||||||
|
{ errorCode: 'mock_work_order_reward_amount_required' },
|
||||||
|
)
|
||||||
|
assert.throws(() => resolveAdminMockWorkOrderInput({ ...baseInput, paymentAmount: 0 }, shops), {
|
||||||
|
errorCode: 'mock_work_order_payment_amount_invalid',
|
||||||
|
})
|
||||||
|
assert.deepEqual(resolveAdminMockWorkOrderInput(baseInput, shops).rewardAmount, 2500)
|
||||||
|
})
|
||||||
|
|
||||||
test('排行榜打手名称仅展示首字符', () => {
|
test('排行榜打手名称仅展示首字符', () => {
|
||||||
assert.equal(maskWorkerLeaderboardDisplayName('张三'), '张****')
|
assert.equal(maskWorkerLeaderboardDisplayName('张三'), '张****')
|
||||||
assert.equal(maskWorkerLeaderboardDisplayName('Alice'), 'A****')
|
assert.equal(maskWorkerLeaderboardDisplayName('Alice'), 'A****')
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import {
|
|||||||
updateAdminWorkOrder,
|
updateAdminWorkOrder,
|
||||||
updateAdminWorkOrderSharing,
|
updateAdminWorkOrderSharing,
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
|
import { fetchAdminKuaishouIndustryShops } from '@/services/admin/kuaishou-industry'
|
||||||
import type {
|
import type {
|
||||||
CollectField,
|
CollectField,
|
||||||
UploadedFile,
|
UploadedFile,
|
||||||
@@ -78,6 +79,7 @@ import type {
|
|||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import { hasAdminRole } from '@/utils/admin-auth'
|
import { hasAdminRole } from '@/utils/admin-auth'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||||
|
import { buildMockWorkOrderShopOptions } from '@/utils/mock-work-order'
|
||||||
import {
|
import {
|
||||||
DeadlineCountdown,
|
DeadlineCountdown,
|
||||||
formatTimeoutPolicyLabel,
|
formatTimeoutPolicyLabel,
|
||||||
@@ -2293,12 +2295,18 @@ function formatRequirementFieldsText(fields: CollectField[]): string {
|
|||||||
function MockWorkOrderForm({ onCreated }: { onCreated: () => Promise<void> }) {
|
function MockWorkOrderForm({ onCreated }: { onCreated: () => Promise<void> }) {
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const shopsQuery = useQuery({
|
||||||
|
queryKey: ['admin-kuaishou-industry-shops', 'mock-work-order'],
|
||||||
|
queryFn: fetchAdminKuaishouIndustryShops,
|
||||||
|
})
|
||||||
|
const shopOptions = buildMockWorkOrderShopOptions(shopsQuery.data?.data.shops || [])
|
||||||
|
|
||||||
async function submit(values: {
|
async function submit(values: {
|
||||||
platformOrderId?: string
|
platformOrderId: string
|
||||||
productName?: string
|
sellerId: string
|
||||||
rewardAmount?: number
|
productName: string
|
||||||
paymentAmount?: number
|
rewardAmount: number
|
||||||
|
paymentAmount: number
|
||||||
materialComplete?: boolean
|
materialComplete?: boolean
|
||||||
}) {
|
}) {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
@@ -2314,32 +2322,58 @@ function MockWorkOrderForm({ onCreated }: { onCreated: () => Promise<void> }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form className="worker-order-mock-form" layout="inline" onFinish={submit}>
|
||||||
className="worker-order-mock-form"
|
<Form.Item
|
||||||
layout="inline"
|
className="worker-order-mock-field-order"
|
||||||
initialValues={{
|
label="订单号"
|
||||||
productName: '指挥官秘钥1个',
|
name="platformOrderId"
|
||||||
rewardAmount: 25,
|
rules={[{ required: true, whitespace: true, message: '请填写订单号' }]}
|
||||||
materialComplete: false,
|
>
|
||||||
}}
|
<Input placeholder="请输入订单号" />
|
||||||
onFinish={submit}
|
|
||||||
>
|
|
||||||
<Form.Item className="worker-order-mock-field-order" label="订单号" name="platformOrderId">
|
|
||||||
<Input placeholder="留空自动生成" />
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item className="worker-order-mock-field-product" label="商品" name="productName">
|
<Form.Item
|
||||||
<Input />
|
className="worker-order-mock-field-shop"
|
||||||
|
label="店铺"
|
||||||
|
name="sellerId"
|
||||||
|
rules={[{ required: true, message: '请选择店铺' }]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
loading={shopsQuery.isLoading}
|
||||||
|
options={shopOptions}
|
||||||
|
placeholder={shopOptions.length > 0 ? '请选择店铺' : '暂无可用店铺'}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item className="worker-order-mock-field-amount" label="接单金额" name="rewardAmount">
|
<Form.Item
|
||||||
|
className="worker-order-mock-field-product"
|
||||||
|
label="商品"
|
||||||
|
name="productName"
|
||||||
|
rules={[{ required: true, whitespace: true, message: '请填写商品名称' }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入商品名称" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
className="worker-order-mock-field-amount"
|
||||||
|
label="接单金额"
|
||||||
|
name="rewardAmount"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: '请填写接单金额' },
|
||||||
|
{ type: 'number', min: 0.01, message: '接单金额必须大于 0' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
<InputNumber min={0.01} step={1} addonAfter="元" />
|
<InputNumber min={0.01} step={1} addonAfter="元" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
className="worker-order-mock-field-amount"
|
className="worker-order-mock-field-amount"
|
||||||
label="用户付款金额"
|
label="用户付款金额"
|
||||||
name="paymentAmount"
|
name="paymentAmount"
|
||||||
tooltip="留空默认等于接单金额;填得比接单金额低,可测试超价提示"
|
rules={[
|
||||||
|
{ required: true, message: '请填写用户付款金额' },
|
||||||
|
{ type: 'number', min: 0.01, message: '用户付款金额必须大于 0' },
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber min={0} step={1} addonAfter="元" placeholder="默认同接单金额" />
|
<InputNumber min={0.01} step={1} addonAfter="元" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
className="worker-order-mock-field-complete"
|
className="worker-order-mock-field-complete"
|
||||||
|
|||||||
@@ -428,10 +428,11 @@ export function fetchAdminWorkOrderEvents(workOrderId: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createAdminMockWorkOrder(payload: {
|
export function createAdminMockWorkOrder(payload: {
|
||||||
platformOrderId?: string
|
platformOrderId: string
|
||||||
productName?: string
|
sellerId: string
|
||||||
rewardAmount?: number
|
productName: string
|
||||||
paymentAmount?: number
|
rewardAmount: number
|
||||||
|
paymentAmount: number
|
||||||
materialComplete?: boolean
|
materialComplete?: boolean
|
||||||
}) {
|
}) {
|
||||||
return apiPost<{ order: WorkOrder }>('/api/v1/admin/worker-platform/orders/mock', payload)
|
return apiPost<{ order: WorkOrder }>('/api/v1/admin/worker-platform/orders/mock', payload)
|
||||||
|
|||||||
@@ -115,23 +115,24 @@
|
|||||||
|
|
||||||
.worker-orders-toolbar {
|
.worker-orders-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
gap: 24px;
|
align-items: stretch;
|
||||||
|
gap: 16px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.worker-orders-search-controls {
|
.worker-orders-search-controls {
|
||||||
flex: 0 0 auto;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.worker-orders-mock {
|
.worker-orders-mock {
|
||||||
flex: 1;
|
width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
padding-left: 24px;
|
padding-top: 16px;
|
||||||
border-left: 1px solid #edf0f5;
|
border-top: 1px solid #edf0f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.worker-orders-mock > .ant-typography {
|
.worker-orders-mock > .ant-typography {
|
||||||
@@ -157,6 +158,10 @@
|
|||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.worker-order-mock-field-shop .ant-select {
|
||||||
|
width: 190px;
|
||||||
|
}
|
||||||
|
|
||||||
.worker-order-mock-field-product .ant-input {
|
.worker-order-mock-field-product .ant-input {
|
||||||
width: 190px;
|
width: 190px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export type MockWorkOrderShop = {
|
||||||
|
sellerId: string
|
||||||
|
shopId: string
|
||||||
|
shopName: string
|
||||||
|
enabled: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMockWorkOrderShopOptions(shops: MockWorkOrderShop[]) {
|
||||||
|
return shops
|
||||||
|
.filter((shop) => shop.enabled)
|
||||||
|
.map((shop) => {
|
||||||
|
const value = String(shop.sellerId || shop.shopId || '').trim()
|
||||||
|
const name = String(shop.shopName || shop.shopId || value).trim()
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
label: `${name}(${value})`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((shop) => Boolean(shop.value))
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import test from 'node:test'
|
||||||
|
|
||||||
|
import { buildMockWorkOrderShopOptions } from '../src/utils/mock-work-order.ts'
|
||||||
|
|
||||||
|
test('本地 Mock 店铺选择仅展示启用店铺', () => {
|
||||||
|
assert.deepEqual(
|
||||||
|
buildMockWorkOrderShopOptions([
|
||||||
|
{ sellerId: 'seller-1', shopId: 'shop-1', shopName: '测试店铺', enabled: true },
|
||||||
|
{ sellerId: 'seller-2', shopId: 'shop-2', shopName: '已停用店铺', enabled: false },
|
||||||
|
]),
|
||||||
|
[{ value: 'seller-1', label: '测试店铺(seller-1)' }],
|
||||||
|
)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user