feat: show platform for conversion product ids
This commit is contained in:
parent
d0cd7ab979
commit
88f6c10799
@ -32,6 +32,7 @@ const workflowItem = {
|
||||
brand: '亿家达' as const,
|
||||
productId: '1041432226288',
|
||||
spu: 'SPU-001',
|
||||
platform: '天猫',
|
||||
completedAt: '2026-07-12T08:00:00.000Z',
|
||||
monitorStartDate: '2026-07-12',
|
||||
monitorEndDate: '2027-01-12',
|
||||
@ -134,6 +135,22 @@ describe('PerformanceConversionDashboard filters', () => {
|
||||
expect(detailUrl.searchParams.get('completedFrom')).toBe('2026-07-01')
|
||||
expect(detailUrl.searchParams.get('completedTo')).toBe('2026-07-31')
|
||||
expect(detailUrl.searchParams.get('page')).toBe('3')
|
||||
expect(screen.getAllByText('平台 天猫')).toHaveLength(2)
|
||||
expect(screen.queryByText(`实例 ${workflowItem.workflowId}`)).not.toBeInTheDocument()
|
||||
expect(fetchMock).not.toHaveBeenCalledWith(expect.stringContaining('/timeseries'), expect.anything())
|
||||
})
|
||||
|
||||
it('shows an explicit placeholder when the workflow platform is missing', async () => {
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
success: true,
|
||||
data: { ...emptyList, items: [{ ...workflowItem, platform: null }], total: 1 },
|
||||
}),
|
||||
} as Response)
|
||||
|
||||
render(<PerformanceConversionDashboard />)
|
||||
|
||||
expect(await screen.findAllByText('平台 —')).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
@ -93,12 +93,12 @@ function WorkflowTable({ items, detailHref }: {
|
||||
<caption className="sr-only">2026 年 4 月 1 日以后已完结美术流程关联的商品 ID</caption>
|
||||
<thead className="bg-slate-50 text-xs font-bold text-slate-500"><tr><th className="w-[18%] px-5 py-3">商品 ID</th><th className="w-[24%] px-4 py-3">审批编号</th><th className="w-[18%] px-4 py-3">完结时间</th><th className="w-[25%] px-4 py-3">监控区间</th><th className="w-[15%] px-4 py-3">状态</th></tr></thead>
|
||||
<tbody className="divide-y divide-slate-200">
|
||||
{items.map((item) => <tr key={item.key} className="bg-white hover:bg-slate-50"><td className="px-5 py-3"><Link href={detailHref(item)} className="break-all font-mono text-sm font-bold text-[#0050cb] underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]">{item.productId}</Link>{item.spu && <p className="mt-1 truncate text-xs text-slate-500">SPU {item.spu}</p>}</td><td className="px-4 py-3"><p className="break-all font-mono text-xs text-slate-700">{item.approvalNumber || '—'}</p><p className="mt-1 truncate text-xs text-slate-500" title={item.workflowId}>实例 {item.workflowId}</p></td><td className="px-4 py-3 tabular-nums text-slate-700">{formatDate(item.completedAt, true)}</td><td className="px-4 py-3 tabular-nums text-slate-700">{item.monitorStartDate} 至 {item.monitorEndDate}</td><td className="px-4 py-3"><span className={`inline-flex min-h-7 items-center rounded-md px-2 text-xs font-bold ${item.monitoringStatus === 'monitoring' ? 'bg-amber-50 text-amber-800 ring-1 ring-inset ring-amber-200' : 'bg-emerald-50 text-emerald-800 ring-1 ring-inset ring-emerald-200'}`}>{item.monitoringStatus === 'monitoring' ? '监控中' : '已满 6 个月'}</span></td></tr>)}
|
||||
{items.map((item) => <tr key={item.key} className="bg-white hover:bg-slate-50"><td className="px-5 py-3"><Link href={detailHref(item)} className="break-all font-mono text-sm font-bold text-[#0050cb] underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]">{item.productId}</Link><p className="mt-1 flex flex-wrap gap-x-2 text-xs text-slate-500">{item.spu && <span className="min-w-0 max-w-full break-all">SPU {item.spu}</span>}<span className="min-w-0 max-w-full break-all">平台 {item.platform || '—'}</span></p></td><td className="px-4 py-3"><p className="break-all font-mono text-xs text-slate-700">{item.approvalNumber || '—'}</p></td><td className="px-4 py-3 tabular-nums text-slate-700">{formatDate(item.completedAt, true)}</td><td className="px-4 py-3 tabular-nums text-slate-700">{item.monitorStartDate} 至 {item.monitorEndDate}</td><td className="px-4 py-3"><span className={`inline-flex min-h-7 items-center rounded-md px-2 text-xs font-bold ${item.monitoringStatus === 'monitoring' ? 'bg-amber-50 text-amber-800 ring-1 ring-inset ring-amber-200' : 'bg-emerald-50 text-emerald-800 ring-1 ring-inset ring-emerald-200'}`}>{item.monitoringStatus === 'monitoring' ? '监控中' : '已满 6 个月'}</span></td></tr>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<ul className="divide-y divide-slate-200 md:hidden" aria-label="美术流程商品 ID 列表">
|
||||
{items.map((item) => <li key={item.key} className="bg-white p-4"><Link href={detailHref(item)} className="block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]"><span className="font-mono text-sm font-bold text-[#0050cb]">{item.productId}</span><span className="mt-1 block text-xs text-slate-500">审批编号 {item.approvalNumber || '—'}</span><dl className="mt-3 grid grid-cols-2 gap-3 text-xs"><div><dt className="text-slate-500">完结时间</dt><dd className="mt-1 font-semibold text-slate-800">{formatDate(item.completedAt)}</dd></div><div><dt className="text-slate-500">状态</dt><dd className="mt-1 font-semibold text-slate-800">{item.monitoringStatus === 'monitoring' ? '监控中' : '已满 6 个月'}</dd></div><div className="col-span-2"><dt className="text-slate-500">监控区间</dt><dd className="mt-1 font-semibold text-slate-800">{item.monitorStartDate} 至 {item.monitorEndDate}</dd></div></dl></Link></li>)}
|
||||
{items.map((item) => <li key={item.key} className="bg-white p-4"><Link href={detailHref(item)} className="block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]"><span className="font-mono text-sm font-bold text-[#0050cb]">{item.productId}</span><span className="mt-1 flex flex-wrap gap-x-2 text-xs text-slate-500">{item.spu && <span className="min-w-0 max-w-full break-all">SPU {item.spu}</span>}<span className="min-w-0 max-w-full break-all">平台 {item.platform || '—'}</span></span><span className="mt-1 block break-all text-xs text-slate-500">审批编号 {item.approvalNumber || '—'}</span><dl className="mt-3 grid grid-cols-2 gap-3 text-xs"><div><dt className="text-slate-500">完结时间</dt><dd className="mt-1 font-semibold text-slate-800">{formatDate(item.completedAt)}</dd></div><div><dt className="text-slate-500">状态</dt><dd className="mt-1 font-semibold text-slate-800">{item.monitoringStatus === 'monitoring' ? '监控中' : '已满 6 个月'}</dd></div><div className="col-span-2"><dt className="text-slate-500">监控区间</dt><dd className="mt-1 font-semibold text-slate-800">{item.monitorStartDate} 至 {item.monitorEndDate}</dd></div></dl></Link></li>)}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
|
||||
@ -17,6 +17,7 @@ const detailData = {
|
||||
brand: '亿家达' as const,
|
||||
productId: '1041432226288',
|
||||
spu: 'SPU-001',
|
||||
platform: '天猫',
|
||||
completedAt: '2026-07-12T08:00:00.000Z',
|
||||
monitorStartDate: '2026-07-12',
|
||||
monitorEndDate: '2027-01-12',
|
||||
|
||||
@ -30,6 +30,7 @@ export type PerformanceConversionWorkflowItem = {
|
||||
brand: PerformanceConversionBrand
|
||||
productId: string
|
||||
spu: string | null
|
||||
platform: string | null
|
||||
completedAt: string
|
||||
monitorStartDate: string
|
||||
monitorEndDate: string
|
||||
|
||||
@ -34,6 +34,7 @@ function snapshot(
|
||||
brand: string,
|
||||
sourceFinishedAtRaw: string,
|
||||
productId: string | null,
|
||||
platform: string | null = '天猫',
|
||||
) {
|
||||
return {
|
||||
processInstanceId,
|
||||
@ -45,7 +46,7 @@ function snapshot(
|
||||
processCode: 'art-process',
|
||||
brand,
|
||||
sourceFinishedAtRaw,
|
||||
formFields: productId ? { productId } : {},
|
||||
formFields: productId ? { productId, platform } : {},
|
||||
syncedAt: new Date('2026-09-17T00:00:00.000Z'),
|
||||
}
|
||||
}
|
||||
@ -71,6 +72,7 @@ describe('performance conversion completion date filters', () => {
|
||||
})
|
||||
|
||||
expect(result.items.map((item) => item.productId)).toEqual(['222222', '333333'])
|
||||
expect(result.items.map((item) => item.platform)).toEqual(['天猫', '天猫'])
|
||||
expect(result.total).toBe(2)
|
||||
expect(result.invalidProductIdCount).toBe(1)
|
||||
expect(result.brands.find((item) => item.brand === '亿家达')?.count).toBe(2)
|
||||
@ -82,6 +84,21 @@ describe('performance conversion completion date filters', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('returns the workflow platform for every product id and keeps missing values explicit', async () => {
|
||||
findMany.mockResolvedValue([
|
||||
snapshot('multiple-ids', '亿家达', '2026-07-12T08:00:00.000Z', '111111, 222222', '京东'),
|
||||
snapshot('missing-platform', '亿家达', '2026-07-11T08:00:00.000Z', '333333', null),
|
||||
])
|
||||
|
||||
const result = await getPerformanceConversionWorkflows(null, { brand: '亿家达' })
|
||||
|
||||
expect(result.items.map(({ productId, platform }) => ({ productId, platform }))).toEqual([
|
||||
{ productId: '111111', platform: '京东' },
|
||||
{ productId: '222222', platform: '京东' },
|
||||
{ productId: '333333', platform: null },
|
||||
])
|
||||
})
|
||||
|
||||
it('rejects invalid or reversed date ranges before reading snapshots', async () => {
|
||||
await expect(getPerformanceConversionWorkflows(null, {
|
||||
completedFrom: '2026-02-29',
|
||||
|
||||
@ -107,6 +107,7 @@ function workflowItems(row: SnapshotRow): PerformanceConversionWorkflowItem[] {
|
||||
brand: brand as PerformanceConversionBrand,
|
||||
productId,
|
||||
spu: clean(fields.spu),
|
||||
platform: clean(fields.platform),
|
||||
completedAt,
|
||||
monitorStartDate,
|
||||
monitorEndDate,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user