gongxiangp2/lib/__tests__/ding-workflow-delivery.test.ts
2026-08-28 10:52:44 +08:00

180 lines
6.2 KiB
TypeScript

import { assessDingWorkflowDelivery } from '@/lib/ding-workflow-delivery'
import type { DingWorkflowDetailFormFields, OngoingDingWorkflowActiveTask } from '@/lib/ding-workflow-sync'
const ART_PROCESS_CODE = 'PROC-3571C915-0506-4490-A91A-8AA7EA33F838'
const CONTENT_PROCESS_CODE = 'PROC-AE9FF3E1-A442-4E6A-85CF-0F2B86409673'
function formFields(overrides: Partial<DingWorkflowDetailFormFields> = {}): DingWorkflowDetailFormFields {
return {
platform: null,
brand: null,
category: null,
spu: null,
demandType: null,
standardOutputDeadline: null,
sourceType: null,
taskType: null,
installVideo: null,
quantity: null,
cameraQuantity: null,
planningTaskStats: null,
graphicTaskStats: null,
imageTaskStats: null,
...overrides,
}
}
function task(
nodeName: string,
createdAt: string,
finishedAt: string | null,
taskId = nodeName,
): OngoingDingWorkflowActiveTask {
return {
taskId,
activityId: null,
nodeName,
assigneeUserId: null,
assigneeName: '测试人员',
assigneeDepartment: '品牌中心',
isBrandCenter: true,
isLeadership: false,
isActive: finishedAt === null,
reviewPassed: finishedAt !== null,
result: finishedAt === null ? null : 'AGREE',
createdAt,
finishedAt,
}
}
describe('Ding workflow delivery SLA', () => {
it('uses post-July art task statistics and wall-clock days', () => {
const assessment = assessDingWorkflowDelivery({
processCode: ART_PROCESS_CODE,
sourceCreatedAt: '2026-07-10T00:00:00.000Z',
sourceFinishedAt: '2026-07-11T00:00:00.000Z',
formFields: formFields({
planningTaskStats: JSON.stringify([{
rowValue: [
{ label: '策划类型', value: '新品策划全案/新品全套图文' },
{ label: '策划细分', value: '全套新品的策划方案(主图视频脚本/策划方案/买家秀文案)' },
{ label: '策划数量', value: '1' },
],
}]),
}),
tasks: [
task('品牌策划主管分配任务', '2026-07-10T00:00:00.000Z', '2026-07-10T00:05:00.000Z'),
task('品牌策划主管审核', '2026-07-11T12:00:00.000Z', '2026-07-11T12:00:00.000Z'),
],
})
expect(assessment).toMatchObject({
status: 'on_time',
standardDuration: 2,
durationUnit: 'day',
actualDuration: 1.5,
startNodeLabel: '品牌策划主管分配任务',
endNodeLabel: '品牌策划主管审核',
})
})
it('uses the legacy art demand/source matrix before July', () => {
const assessment = assessDingWorkflowDelivery({
processCode: ART_PROCESS_CODE,
sourceCreatedAt: '2026-04-20T00:00:00.000Z',
sourceFinishedAt: '2026-04-24T00:00:00.000Z',
formFields: formFields({ demandType: '新品', sourceType: '仅出图' }),
tasks: [
task('品牌策划主管分配任务', '2026-04-20T00:00:00.000Z', '2026-04-20T00:05:00.000Z'),
task('品牌策划主管审核', '2026-04-24T00:00:00.000Z', '2026-04-24T00:00:00.000Z'),
],
})
expect(assessment).toMatchObject({ status: 'overtime', standardDuration: 3, actualDuration: 4 })
})
it('ends director-review content rules at 编导审核', () => {
const assessment = assessDingWorkflowDelivery({
processCode: CONTENT_PROCESS_CODE,
sourceCreatedAt: '2026-08-01T00:00:00.000Z',
sourceFinishedAt: '2026-08-03T00:00:00.000Z',
formFields: formFields({ demandType: '抖音-千川素材', taskType: '布景拍摄' }),
tasks: [
task('内容主管分配任务', '2026-08-01T00:00:00.000Z', '2026-08-01T00:05:00.000Z'),
task('编导审核', '2026-08-03T00:00:00.000Z', '2026-08-03T00:00:00.000Z'),
],
})
expect(assessment).toMatchObject({
status: 'on_time',
standardDuration: 72,
durationUnit: 'hour',
actualDuration: 48,
endNodeLabel: '编导审核',
})
})
it('uses the confirmed content assignment and review timestamps after report-clock normalization', () => {
const assessment = assessDingWorkflowDelivery({
processCode: CONTENT_PROCESS_CODE,
sourceCreatedAt: '2026-08-14T06:52:00.000Z',
sourceFinishedAt: '2026-08-17T01:10:00.000Z',
formFields: formFields({ demandType: '抖音-千川素材', taskType: '二次剪辑' }),
tasks: [
task('内容主管分配任务', '2026-08-14T06:59:00.000Z', '2026-08-14T08:04:00.000Z'),
task('编导', '2026-08-15T07:25:00.000Z', '2026-08-15T07:25:00.000Z'),
task('编导审核', '2026-08-15T07:35:00.000Z', '2026-08-15T09:11:00.000Z'),
],
})
expect(assessment).toMatchObject({
status: 'on_time',
standardDuration: 48,
durationUnit: 'hour',
actualDuration: 26.2,
startedAt: '2026-08-14T06:59:00.000Z',
finishedAt: '2026-08-15T09:11:00.000Z',
startNodeLabel: '内容主管分配任务',
endNodeLabel: '编导审核',
})
})
it('ends content-supervisor rules at 内容主管审核', () => {
const assessment = assessDingWorkflowDelivery({
processCode: CONTENT_PROCESS_CODE,
sourceCreatedAt: '2026-08-01T00:00:00.000Z',
sourceFinishedAt: '2026-08-02T06:00:00.000Z',
formFields: formFields({ demandType: '白底图-策划专用', taskType: '布局拍摄' }),
tasks: [
task('内容负责人分配任务', '2026-08-01T00:00:00.000Z', '2026-08-01T00:05:00.000Z'),
task('内容主管审核', '2026-08-02T06:00:00.000Z', '2026-08-02T06:00:00.000Z'),
],
})
expect(assessment).toMatchObject({
status: 'overtime',
standardDuration: 24,
durationUnit: 'hour',
actualDuration: 30,
startNodeLabel: '内容主管分配任务',
endNodeLabel: '内容主管审核',
})
})
it('keeps missing configuration or milestone data pending', () => {
const assessment = assessDingWorkflowDelivery({
processCode: CONTENT_PROCESS_CODE,
sourceCreatedAt: '2026-08-01T00:00:00.000Z',
sourceFinishedAt: null,
formFields: formFields({ demandType: '未知类型', taskType: '布局拍摄' }),
tasks: [],
})
expect(assessment).toMatchObject({
status: 'pending',
standardDuration: null,
actualDuration: null,
})
})
})