180 lines
6.2 KiB
TypeScript
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,
|
|
})
|
|
})
|
|
})
|