diff --git a/lib/__tests__/ding-workflow-sync.test.ts b/lib/__tests__/ding-workflow-sync.test.ts index 5e5620bd..962d6e22 100644 --- a/lib/__tests__/ding-workflow-sync.test.ts +++ b/lib/__tests__/ding-workflow-sync.test.ts @@ -4,6 +4,7 @@ import { isAllowedDingWorkflowProcessCode, isDingWorkflowOngoing, normalizeDingWorkflowBrand, + normalizeDingWorkflowDepartment, normalizeDingWorkflowProcessCode, sourceWorkflowTimestampToIso, } from '@/lib/ding-workflow-sync' @@ -64,4 +65,12 @@ describe('ding workflow snapshot sync semantics', () => { expect(normalizeDingWorkflowBrand('新品牌')).toBe('其他品牌') expect(normalizeDingWorkflowBrand(null)).toBe('其他品牌') }) + + it('normalizes DingTalk department fields before grouping requester dimensions', () => { + expect(normalizeDingWorkflowDepartment('["运营中心E"]')).toBe('运营中心E') + expect(normalizeDingWorkflowDepartment('[{"name":"品牌中心"}]')).toBe('品牌中心') + expect(normalizeDingWorkflowDepartment(['运营中心E', '运营中心E'])).toBe('运营中心E') + expect(normalizeDingWorkflowDepartment('综合支持部')).toBe('综合支持部') + expect(normalizeDingWorkflowDepartment(null)).toBeNull() + }) }) diff --git a/lib/ding-workflow-sync.ts b/lib/ding-workflow-sync.ts index 1e45012a..cfae4c3b 100644 --- a/lib/ding-workflow-sync.ts +++ b/lib/ding-workflow-sync.ts @@ -213,6 +213,34 @@ export function normalizeDingWorkflowBrand(value: unknown): string { return DING_WORKFLOW_BRANDS.find((brand) => normalized.includes(brand)) || '其他品牌' } +function collectDingWorkflowDepartmentNames(value: unknown): string[] { + if (value === null || value === undefined) return [] + if (Array.isArray(value)) { + return value.flatMap(collectDingWorkflowDepartmentNames) + } + if (typeof value === 'object') { + const record = value as Record + return ['name', 'label', 'value', 'text', 'title'] + .flatMap((key) => collectDingWorkflowDepartmentNames(record[key])) + } + + const normalized = clean(value) + if (!normalized) return [] + if (normalized.startsWith('[') || normalized.startsWith('{')) { + try { + return collectDingWorkflowDepartmentNames(JSON.parse(normalized)) + } catch { + // Keep non-JSON department names unchanged. + } + } + return [normalized] +} + +export function normalizeDingWorkflowDepartment(value: unknown): string | null { + const names = Array.from(new Set(collectDingWorkflowDepartmentNames(value))) + return names.length > 0 ? names.join(' / ') : null +} + function parseJson(value: unknown): unknown { const normalized = clean(value) if (!normalized) return null @@ -631,8 +659,8 @@ function buildSnapshotPayload( const schemeFields = schemeRowsByWorkflow.get(processInstanceId) || [] const assignments = extractContactAssignments(schemeFields) const brand = normalizeDingWorkflowBrand(firstSchemeValue(schemeFields, ['品牌'])) - const requesterDepartment = firstSchemeValue(schemeFields, ['需求部门']) - || clean(row.originatorDeptName) + const requesterDepartment = normalizeDingWorkflowDepartment(firstSchemeValue(schemeFields, ['需求部门'])) + || normalizeDingWorkflowDepartment(row.originatorDeptName) || '未记录部门' const originatorUserId = clean(row.originatorUserId) const requesterName = firstSchemeValue(schemeFields, ['需求人']) @@ -957,7 +985,9 @@ function mapSnapshotListItem(row: { projectType: row.projectType || getDingWorkflowProjectType(processCode), brand: row.brand || '其他品牌', requesterName: row.requesterName || '未记录', - requesterDepartment: row.requesterDepartment || row.originatorDeptName || '未记录部门', + requesterDepartment: normalizeDingWorkflowDepartment(row.requesterDepartment) + || normalizeDingWorkflowDepartment(row.originatorDeptName) + || '未记录部门', activeTasks: normalizeActiveTasks(row.activeTasks), originatorUserId: row.originatorUserId, originatorDeptName: row.originatorDeptName,