Merge OA latest child flow selection
This commit is contained in:
commit
dded0237d0
92
furniture-3d-system/src/lib/oa-board-flow-selection.test.ts
Normal file
92
furniture-3d-system/src/lib/oa-board-flow-selection.test.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { selectLatestRestartableChildFlows } from './oa-board-flow-selection'
|
||||
|
||||
type TestFlowRecord = {
|
||||
flowType: string
|
||||
processInstanceId: string
|
||||
createdAtSource: Date | null
|
||||
updatedAtSource: Date | null
|
||||
status: string
|
||||
}
|
||||
|
||||
function buildFlow(
|
||||
flowType: string,
|
||||
processInstanceId: string,
|
||||
createdAtSource: string | null,
|
||||
status: string,
|
||||
updatedAtSource = createdAtSource,
|
||||
): TestFlowRecord {
|
||||
return {
|
||||
flowType,
|
||||
processInstanceId,
|
||||
createdAtSource: createdAtSource ? new Date(createdAtSource) : null,
|
||||
updatedAtSource: updatedAtSource ? new Date(updatedAtSource) : null,
|
||||
status,
|
||||
}
|
||||
}
|
||||
|
||||
describe('OA 看板子流程版本选择', () => {
|
||||
it('首单、美术和限价流程各自只保留最晚发起的一条', () => {
|
||||
const records = [
|
||||
buildFlow('review', 'review-1', '2026-08-03T02:30:00Z', 'COMPLETED'),
|
||||
buildFlow('order', 'order-refused', '2026-08-03T08:00:00Z', 'REFUSED'),
|
||||
buildFlow('order', 'order-running', '2026-08-04T08:00:00Z', 'RUNNING'),
|
||||
buildFlow('art', 'art-refused', '2026-08-05T08:00:00Z', 'REFUSED'),
|
||||
buildFlow('art', 'art-completed', '2026-08-06T08:00:00Z', 'COMPLETED'),
|
||||
buildFlow('pricing', 'pricing-terminated', '2026-08-17T01:49:00Z', 'TERMINATED'),
|
||||
buildFlow('pricing', 'pricing-completed', '2026-08-17T01:51:00Z', 'COMPLETED'),
|
||||
buildFlow('main', 'main-1', '2026-08-17T02:00:00Z', 'RUNNING'),
|
||||
]
|
||||
|
||||
expect(
|
||||
selectLatestRestartableChildFlows(records).map((record) => record.processInstanceId),
|
||||
).toEqual([
|
||||
'review-1',
|
||||
'order-running',
|
||||
'art-completed',
|
||||
'pricing-completed',
|
||||
'main-1',
|
||||
])
|
||||
})
|
||||
|
||||
it('以发起时间为主,不让旧流程的较晚更新时间覆盖新流程', () => {
|
||||
const records = [
|
||||
buildFlow(
|
||||
'art',
|
||||
'old-art-updated-later',
|
||||
'2026-08-05T08:00:00Z',
|
||||
'REFUSED',
|
||||
'2026-08-08T08:00:00Z',
|
||||
),
|
||||
buildFlow(
|
||||
'art',
|
||||
'new-art',
|
||||
'2026-08-06T08:00:00Z',
|
||||
'RUNNING',
|
||||
'2026-08-06T09:00:00Z',
|
||||
),
|
||||
]
|
||||
|
||||
expect(selectLatestRestartableChildFlows(records)).toEqual([records[1]])
|
||||
})
|
||||
|
||||
it('发起时间相同时用更新时间稳定决定最新记录', () => {
|
||||
const records = [
|
||||
buildFlow(
|
||||
'pricing',
|
||||
'pricing-older-update',
|
||||
'2026-08-17T01:51:00Z',
|
||||
'TERMINATED',
|
||||
'2026-08-17T01:52:00Z',
|
||||
),
|
||||
buildFlow(
|
||||
'pricing',
|
||||
'pricing-newer-update',
|
||||
'2026-08-17T01:51:00Z',
|
||||
'COMPLETED',
|
||||
'2026-08-17T01:58:00Z',
|
||||
),
|
||||
]
|
||||
|
||||
expect(selectLatestRestartableChildFlows(records)).toEqual([records[1]])
|
||||
})
|
||||
})
|
||||
47
furniture-3d-system/src/lib/oa-board-flow-selection.ts
Normal file
47
furniture-3d-system/src/lib/oa-board-flow-selection.ts
Normal file
@ -0,0 +1,47 @@
|
||||
const RESTARTABLE_CHILD_FLOW_TYPES = new Set(['order', 'art', 'pricing'])
|
||||
|
||||
export type OaBoardFlowSelectionRecord = {
|
||||
flowType: string
|
||||
processInstanceId: string
|
||||
createdAtSource: Date | null
|
||||
updatedAtSource: Date | null
|
||||
}
|
||||
|
||||
function toTimestamp(value: Date | null) {
|
||||
const timestamp = value?.getTime() ?? 0
|
||||
return Number.isFinite(timestamp) ? timestamp : 0
|
||||
}
|
||||
|
||||
function compareFlowRecency(
|
||||
left: OaBoardFlowSelectionRecord,
|
||||
right: OaBoardFlowSelectionRecord,
|
||||
) {
|
||||
const createdAtDiff = toTimestamp(left.createdAtSource) - toTimestamp(right.createdAtSource)
|
||||
if (createdAtDiff !== 0) return createdAtDiff
|
||||
|
||||
const updatedAtDiff = toTimestamp(left.updatedAtSource) - toTimestamp(right.updatedAtSource)
|
||||
if (updatedAtDiff !== 0) return updatedAtDiff
|
||||
|
||||
return left.processInstanceId.localeCompare(right.processInstanceId)
|
||||
}
|
||||
|
||||
export function selectLatestRestartableChildFlows<T extends OaBoardFlowSelectionRecord>(
|
||||
records: T[],
|
||||
) {
|
||||
const latestByFlowType = new Map<string, T>()
|
||||
|
||||
records.forEach((record) => {
|
||||
if (!RESTARTABLE_CHILD_FLOW_TYPES.has(record.flowType)) return
|
||||
|
||||
const currentLatest = latestByFlowType.get(record.flowType)
|
||||
if (!currentLatest || compareFlowRecency(record, currentLatest) > 0) {
|
||||
latestByFlowType.set(record.flowType, record)
|
||||
}
|
||||
})
|
||||
|
||||
return records.filter(
|
||||
(record) =>
|
||||
!RESTARTABLE_CHILD_FLOW_TYPES.has(record.flowType) ||
|
||||
latestByFlowType.get(record.flowType) === record,
|
||||
)
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {
|
||||
import type sql from 'mssql'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { selectLatestRestartableChildFlows } from '@/lib/oa-board-flow-selection'
|
||||
import { externalEmployeeDirectoryService } from './external-employee-directory.service'
|
||||
import type { OaBoardProjectGraphInput } from './oa-board.service'
|
||||
import {
|
||||
@ -3106,7 +3107,10 @@ function buildProjectGroups(records: NormalizedFlowRecord[]): PreparedProjectGro
|
||||
})
|
||||
}
|
||||
|
||||
return Array.from(groups.values())
|
||||
return Array.from(groups.values()).map((group) => ({
|
||||
...group,
|
||||
flowRecords: selectLatestRestartableChildFlows(group.flowRecords),
|
||||
}))
|
||||
}
|
||||
|
||||
function countNestedRecords(projectGraphs: OaBoardProjectGraphInput[]) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user