feat(admin): 订单列表只展示平台判断 SKU
This commit is contained in:
@@ -49,6 +49,7 @@ test('mapAdminOrderListItem formats itemTitle, skuNick, and summary correctly fo
|
||||
|
||||
assert.equal(mapped.itemTitle, '和平精英地铁逃生装备满钻低价苏尔南怒嚎暗潮手枪璀璨无暇1到7钻')
|
||||
assert.equal(mapped.skuNick, '安卓血宴2钻')
|
||||
assert.equal(mapped.matchSku, '安卓血宴2钻')
|
||||
assert.equal(
|
||||
mapped.itemSummary,
|
||||
'和平精英地铁逃生装备满钻低价苏尔南怒嚎暗潮手枪璀璨无暇1到7钻 (安卓血宴2钻)',
|
||||
@@ -59,6 +60,7 @@ test('mapAdminOrderListItem formats itemTitle, skuNick, and summary correctly fo
|
||||
{
|
||||
itemTitle: '和平精英地铁逃生装备满钻低价苏尔南怒嚎暗潮手枪璀璨无暇1到7钻',
|
||||
skuNick: '安卓血宴2钻',
|
||||
matchSku: '安卓血宴2钻',
|
||||
quantity: 1,
|
||||
},
|
||||
])
|
||||
@@ -133,6 +135,7 @@ test('mapAdminOrderListItem falls back to PDD goods_name/out_sku_sn when orderIt
|
||||
|
||||
assert.equal(mapped.itemTitle, '和平精英地铁逃生苏尔南暗潮怒嚎血宴')
|
||||
assert.equal(mapped.skuNick, '安卓怒嚎3钻')
|
||||
assert.equal(mapped.matchSku, '安卓怒嚎3钻')
|
||||
assert.equal(mapped.itemCount, 1)
|
||||
assert.equal(mapped.totalQuantity, 1)
|
||||
})
|
||||
@@ -211,4 +214,48 @@ test('抖音码速达:商品列展示内部 SKU,引流标题降级为 skuNic
|
||||
assert.equal(mapped.skuNick, '【测试专用】和平精英皮肤小店入口出售返场吃鸡皮肤浪漫天命专用')
|
||||
// 列表摘要同样以内部 SKU 为主
|
||||
assert.match(summarizeOrderItems(orderItems, order), /^幸运币2个/)
|
||||
// 列表只展示判断用的内部 SKU,不能退回引流标题
|
||||
assert.equal(mapped.matchSku, '幸运币2个')
|
||||
assert.equal(mapped.items?.[0]?.matchSku, '幸运币2个')
|
||||
})
|
||||
|
||||
test('拼多多匹配 SKU 优先 sku_name,不用带地区的长 spec', () => {
|
||||
const order: OrderListRow = {
|
||||
id: 100,
|
||||
provider: 'pdd',
|
||||
platform: 'pdd',
|
||||
shop_id: 'pdd-shop',
|
||||
shop_name: '拼多多店铺',
|
||||
platform_order_id: '260915-72034516082531',
|
||||
order_status: 'paid',
|
||||
pay_status: 'paid',
|
||||
buyer_id: '',
|
||||
buyer_name: '',
|
||||
receiver_contact: '',
|
||||
total_amount: 100,
|
||||
currency: 'CNY',
|
||||
raw_payload_json: {},
|
||||
paid_at: '2026-10-09T04:55:05.000Z',
|
||||
created_at: '2026-10-09T04:55:05.000Z',
|
||||
updated_at: '2026-10-09T04:55:05.000Z',
|
||||
}
|
||||
|
||||
const orderItems: OrderItemRow[] = [
|
||||
{
|
||||
id: 1,
|
||||
order_id: 100,
|
||||
sku_code: '安卓怒嚎1钻',
|
||||
sku_name: '安卓怒嚎1钻',
|
||||
quantity: 1,
|
||||
spec_json: JSON.stringify({
|
||||
itemTitle: '和平精英地铁逃生苏尔南暗潮怒嚎血宴',
|
||||
skuNick: '安卓区(qv互通),苏尔南-怒嚎1钻',
|
||||
}),
|
||||
item_snapshot_json: JSON.stringify({}),
|
||||
},
|
||||
]
|
||||
|
||||
const mapped = mapAdminOrderListItem(order, { orderItems })
|
||||
assert.equal(mapped.matchSku, '安卓怒嚎1钻')
|
||||
assert.equal(mapped.items?.[0]?.matchSku, '安卓怒嚎1钻')
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||
import {
|
||||
resolveDisplayShopName,
|
||||
resolveOrderItemMatchSku,
|
||||
resolveOrderItemSkuNick,
|
||||
resolveOrderItemTitle,
|
||||
} from './admin-read-shared-helpers.js'
|
||||
@@ -34,28 +35,34 @@ export function mapAdminOrderListItem(
|
||||
|
||||
let resolvedItemTitle = ''
|
||||
let resolvedSkuNick = ''
|
||||
let resolvedMatchSku = ''
|
||||
let itemsList: AdminOrderItemSummary[] = []
|
||||
|
||||
if (normalizedItems.length > 0) {
|
||||
itemsList = normalizedItems.map((orderItem) => {
|
||||
const itTitle = resolveOrderItemTitle(orderItem, item, vouchers)
|
||||
const itSkuNick = resolveOrderItemSkuNick(orderItem, item, vouchers)
|
||||
const itMatchSku = resolveOrderItemMatchSku(orderItem, item, vouchers)
|
||||
return {
|
||||
itemTitle: itTitle,
|
||||
skuNick: itSkuNick,
|
||||
matchSku: itMatchSku,
|
||||
quantity: Math.max(1, Number(orderItem.quantity || 1)),
|
||||
}
|
||||
})
|
||||
resolvedItemTitle = itemsList[0]?.itemTitle || ''
|
||||
resolvedSkuNick = itemsList[0]?.skuNick || ''
|
||||
resolvedMatchSku = itemsList[0]?.matchSku || ''
|
||||
} else {
|
||||
resolvedItemTitle = resolveOrderItemTitle(null, item, vouchers)
|
||||
resolvedSkuNick = resolveOrderItemSkuNick(null, item, vouchers)
|
||||
if (resolvedItemTitle || resolvedSkuNick) {
|
||||
resolvedMatchSku = resolveOrderItemMatchSku(null, item, vouchers)
|
||||
if (resolvedItemTitle || resolvedSkuNick || resolvedMatchSku) {
|
||||
itemsList = [
|
||||
{
|
||||
itemTitle: resolvedItemTitle,
|
||||
skuNick: resolvedSkuNick,
|
||||
matchSku: resolvedMatchSku,
|
||||
quantity: 1,
|
||||
},
|
||||
]
|
||||
@@ -99,6 +106,7 @@ export function mapAdminOrderListItem(
|
||||
itemSummary,
|
||||
itemTitle: resolvedItemTitle,
|
||||
skuNick: resolvedSkuNick,
|
||||
matchSku: resolvedMatchSku,
|
||||
items: itemsList,
|
||||
taskCount: tasks.length,
|
||||
workOrderCount,
|
||||
|
||||
@@ -637,6 +637,41 @@ export function resolveOrderItemSkuNick(
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表展示用的「平台判断 SKU」:只保留能用于匹配的短 SKU,不展示引流长标题。
|
||||
* 抖音的内部 SKU 存在 itemTitle(resolveOrderItemTitle 已优先返回 code),
|
||||
* 拼多多用 sku_name/sku_code 更干净,91/快手优先用 skuNick。
|
||||
*/
|
||||
export function resolveOrderItemMatchSku(
|
||||
item: Partial<OrderItemRow> | null | undefined,
|
||||
fallbackOrder?: Partial<OrderRow> | null | undefined,
|
||||
vouchers?: KuaishouIndustryVoucherRow[] | null | undefined,
|
||||
): string {
|
||||
const provider = String(fallbackOrder?.provider || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
const spec = item ? safeParseJson(item.spec_json) : {}
|
||||
const snapshot = item ? safeParseJson(item.item_snapshot_json) : {}
|
||||
const source = pickFirstNonEmpty([spec.source, snapshot.source]).toLowerCase()
|
||||
const isDouyin = provider.includes('douyin') || source.includes('douyin')
|
||||
|
||||
const itemTitle = resolveOrderItemTitle(item, fallbackOrder, vouchers)
|
||||
const skuNick = resolveOrderItemSkuNick(item, fallbackOrder, vouchers)
|
||||
const skuName = String(item?.sku_name || '').trim()
|
||||
const skuCode = String(item?.sku_code || '').trim()
|
||||
|
||||
if (isDouyin) {
|
||||
// 抖音 skuNick 往往是引流标题,内部 SKU 才是判断依据。
|
||||
return itemTitle || skuName || skuCode
|
||||
}
|
||||
|
||||
if (provider === 'pdd') {
|
||||
return skuName || skuCode || skuNick || itemTitle
|
||||
}
|
||||
|
||||
return skuNick || skuName || skuCode || itemTitle
|
||||
}
|
||||
|
||||
export function resolveOrderItemDeliveryMode(
|
||||
tasks: TaskLike[] | null | undefined,
|
||||
orderItemId: number | string,
|
||||
|
||||
@@ -9,6 +9,7 @@ export type AdminOrderFulfillmentProgress = {
|
||||
export type AdminOrderItemSummary = {
|
||||
itemTitle: string
|
||||
skuNick: string
|
||||
matchSku: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ export type AdminOrderListItem = {
|
||||
itemSummary: string
|
||||
itemTitle?: string
|
||||
skuNick?: string
|
||||
matchSku?: string
|
||||
items?: AdminOrderItemSummary[]
|
||||
taskCount: number
|
||||
resourceStatus: string
|
||||
|
||||
Reference in New Issue
Block a user