2026-06-03 09:25:23 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import test from 'node:test'
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
buildAdjacentProgressSteps,
|
|
|
|
|
buildWorkbenchSummary
|
|
|
|
|
} from '../src/utils/workbenchSummary.js'
|
|
|
|
|
|
|
|
|
|
const currentUser = { name: '张三', username: 'zhangsan' }
|
|
|
|
|
|
|
|
|
|
function buildStep(label, index, currentIndex) {
|
|
|
|
|
return {
|
|
|
|
|
label,
|
|
|
|
|
done: index < currentIndex,
|
|
|
|
|
active: index <= currentIndex,
|
|
|
|
|
current: index === currentIndex,
|
|
|
|
|
time: index === currentIndex ? '进行中' : '待处理'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test('workbench expense progress keeps only nearby four expense steps', () => {
|
|
|
|
|
const steps = ['创建单据', '待提交', '直属领导审批', '财务审批', '待付款', '归档入账']
|
|
|
|
|
.map((label, index) => buildStep(label, index, 3))
|
|
|
|
|
|
|
|
|
|
const visibleSteps = buildAdjacentProgressSteps(steps, 4)
|
|
|
|
|
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
visibleSteps.map((step) => step.label),
|
|
|
|
|
['直属领导审批', '财务审批', '待付款', '归档入账']
|
|
|
|
|
)
|
|
|
|
|
assert.equal(visibleSteps[1].current, true)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('workbench summary builds real user notifications and progress from requests', () => {
|
|
|
|
|
const summary = buildWorkbenchSummary(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'BX-001',
|
|
|
|
|
claimId: 'claim-1',
|
|
|
|
|
claimNo: 'BX-001',
|
|
|
|
|
person: '张三',
|
|
|
|
|
title: '差旅报销',
|
|
|
|
|
approvalKey: 'draft',
|
|
|
|
|
approvalStatus: '草稿',
|
|
|
|
|
status: 'draft',
|
|
|
|
|
amount: 1280,
|
|
|
|
|
createdAt: '2026-06-01T10:00:00+08:00',
|
|
|
|
|
updatedAt: '2026-06-01T10:10:00+08:00',
|
|
|
|
|
progressSteps: [
|
|
|
|
|
buildStep('创建单据', 0, 1),
|
|
|
|
|
buildStep('待提交', 1, 1),
|
|
|
|
|
buildStep('直属领导审批', 2, 1),
|
|
|
|
|
buildStep('财务审批', 3, 1),
|
|
|
|
|
buildStep('待付款', 4, 1)
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'BX-002',
|
|
|
|
|
claimId: 'claim-2',
|
|
|
|
|
claimNo: 'BX-002',
|
|
|
|
|
person: '李四',
|
|
|
|
|
title: '他人单据',
|
|
|
|
|
approvalKey: 'draft',
|
|
|
|
|
amount: 800,
|
|
|
|
|
progressSteps: []
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
currentUser
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert.equal(summary.todoItems.length, 1)
|
|
|
|
|
assert.equal(summary.todoItems[0].target.id, 'claim-1')
|
|
|
|
|
assert.equal(summary.progressItems.length, 1)
|
2026-06-09 08:32:00 +00:00
|
|
|
assert.match(summary.progressItems[0].prompt, /单据进度/)
|
|
|
|
|
assert.doesNotMatch(summary.progressItems[0].prompt, /费用进度/)
|
|
|
|
|
assert.equal(summary.progressItems[0].applicantLabel, '张三')
|
2026-06-03 09:25:23 +08:00
|
|
|
assert.deepEqual(
|
|
|
|
|
summary.progressItems[0].steps.map((step) => step.label),
|
|
|
|
|
['创建单据', '待提交', '直属领导审批', '财务审批']
|
|
|
|
|
)
|
2026-06-03 15:14:44 +08:00
|
|
|
assert.equal(summary.progressItems[0].expenseTypeLabel, '差旅交通')
|
2026-06-03 09:25:23 +08:00
|
|
|
assert.equal(summary.notifications.length, 1)
|
|
|
|
|
assert.equal(summary.unreadNotificationCount, 1)
|
2026-06-03 14:59:55 +08:00
|
|
|
assert.equal(summary.expenseStatsDetail.distributionRows[0].label, '差旅交通')
|
|
|
|
|
assert.equal(summary.expenseStatsDetail.distributionRows[0].count, 1)
|
|
|
|
|
assert.equal(summary.expenseStatsDetail.distributionRows[0].percentLabel, '100%')
|
|
|
|
|
assert.equal(summary.expenseStatsDetail.processingRows[0].requestId, 'BX-001')
|
|
|
|
|
assert.equal(summary.expenseStatsDetail.processingRows[0].durationLabel, '10分钟')
|
|
|
|
|
assert.equal(summary.expenseStatsDetail.processingRows[0].stepCount, 5)
|
|
|
|
|
assert.ok(summary.expenseStatsDetail.operationRows.some((item) => item.source === '待办'))
|
|
|
|
|
assert.ok(summary.expenseStatsDetail.operationRows.some((item) => item.source === '进度'))
|
2026-06-18 22:12:24 +08:00
|
|
|
assert.ok(Array.isArray(summary.reimbursementTrendRows))
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.length, 6)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-1).key, '2026-06')
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-1).amount, 1280)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-1).previousKey, '2025-06')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('workbench reimbursement trend compares monthly totals with last year same period', () => {
|
|
|
|
|
const summary = buildWorkbenchSummary(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'BX-202606',
|
|
|
|
|
claimNo: 'BX-202606',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '六月报销',
|
|
|
|
|
amount: 1280,
|
|
|
|
|
createdAt: '2026-06-15T10:00:00+08:00'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'BX-202605',
|
|
|
|
|
claimNo: 'BX-202605',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '五月报销',
|
|
|
|
|
amount: 860,
|
|
|
|
|
createdAt: '2026-05-10T10:00:00+08:00'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'BX-202506',
|
|
|
|
|
claimNo: 'BX-202506',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '去年六月报销',
|
|
|
|
|
amount: 920,
|
|
|
|
|
createdAt: '2025-06-12T10:00:00+08:00'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
currentUser
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
summary.reimbursementTrendRows.slice(-2).map((item) => item.label),
|
|
|
|
|
['5月', '6月']
|
|
|
|
|
)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-2).amount, 860)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-2).previousAmount, 0)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-1).amount, 1280)
|
|
|
|
|
assert.equal(summary.reimbursementTrendRows.at(-1).previousAmount, 920)
|
2026-06-03 09:25:23 +08:00
|
|
|
})
|
2026-06-06 17:19:07 +08:00
|
|
|
|
|
|
|
|
test('workbench progress keeps application document type for AP claims', () => {
|
|
|
|
|
const summary = buildWorkbenchSummary(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'AP-202606050001-ABCDEFGH',
|
|
|
|
|
claimId: 'application-1',
|
|
|
|
|
claimNo: 'AP-202606050001-ABCDEFGH',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '差旅费用',
|
|
|
|
|
approvalKey: 'in_progress',
|
|
|
|
|
approvalStatus: '直属领导审批',
|
|
|
|
|
amount: 1880,
|
|
|
|
|
createdAt: '2026-06-05T09:00:00+08:00',
|
|
|
|
|
updatedAt: '2026-06-05T09:10:00+08:00',
|
|
|
|
|
progressSteps: [
|
|
|
|
|
buildStep('创建申请', 0, 1),
|
|
|
|
|
buildStep('直属领导审批', 1, 1),
|
|
|
|
|
buildStep('归档', 2, 1)
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'REQ-APPLICATION-001',
|
|
|
|
|
claimId: 'application-2',
|
|
|
|
|
claimNo: 'REQ-APPLICATION-001',
|
|
|
|
|
documentTypeCode: 'application',
|
|
|
|
|
documentTypeLabel: '报销单',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '办公用品采购',
|
|
|
|
|
approvalKey: 'in_progress',
|
|
|
|
|
approvalStatus: '直属领导审批',
|
|
|
|
|
amount: 2600,
|
|
|
|
|
createdAt: '2026-06-05T09:05:00+08:00',
|
|
|
|
|
updatedAt: '2026-06-05T09:15:00+08:00',
|
|
|
|
|
progressSteps: [
|
|
|
|
|
buildStep('创建申请', 0, 1),
|
|
|
|
|
buildStep('直属领导审批', 1, 1),
|
|
|
|
|
buildStep('归档', 2, 1)
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
currentUser
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
summary.progressItems.map((item) => item.documentTypeLabel),
|
|
|
|
|
['申请单', '申请单']
|
|
|
|
|
)
|
|
|
|
|
})
|
2026-06-09 08:32:00 +00:00
|
|
|
|
|
|
|
|
test('workbench progress includes application rows without backend progress steps', () => {
|
|
|
|
|
const summary = buildWorkbenchSummary(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'AP-202606060001-NOSTEPS',
|
|
|
|
|
claimId: 'application-without-steps',
|
|
|
|
|
claimNo: 'AP-202606060001-NOSTEPS',
|
|
|
|
|
documentTypeCode: 'application',
|
|
|
|
|
person: currentUser.name,
|
|
|
|
|
title: '上海出差申请',
|
|
|
|
|
approvalKey: 'in_progress',
|
|
|
|
|
approvalStatus: '直属领导审批',
|
|
|
|
|
amount: 1880,
|
|
|
|
|
updatedAt: '2026-06-06T09:00:00+08:00'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
currentUser
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert.equal(summary.progressItems.length, 1)
|
|
|
|
|
assert.equal(summary.progressItems[0].documentTypeLabel, '申请单')
|
|
|
|
|
assert.equal(summary.progressItems[0].applicantLabel, currentUser.name)
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
summary.progressItems[0].steps.map((step) => step.label),
|
|
|
|
|
['创建申请', '直属领导审批', '关联单据状态', '已归档']
|
|
|
|
|
)
|
|
|
|
|
assert.equal(summary.progressItems[0].steps[1].current, true)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('workbench progress includes application documents assigned to current approver', () => {
|
|
|
|
|
const approverUser = {
|
|
|
|
|
name: '李经理',
|
|
|
|
|
username: 'manager@example.com',
|
|
|
|
|
roleCodes: ['approver']
|
|
|
|
|
}
|
|
|
|
|
const summary = buildWorkbenchSummary(
|
|
|
|
|
[
|
|
|
|
|
{
|
|
|
|
|
id: 'AP-202606060002-APPROVAL',
|
|
|
|
|
claimId: 'application-for-approver',
|
|
|
|
|
claimNo: 'AP-202606060002-APPROVAL',
|
|
|
|
|
documentTypeCode: 'application',
|
|
|
|
|
person: '张三',
|
|
|
|
|
managerName: '李经理',
|
|
|
|
|
title: '北京出差申请',
|
|
|
|
|
approvalKey: 'in_progress',
|
|
|
|
|
approvalStatus: '直属领导审批',
|
|
|
|
|
workflowNode: '直属领导审批',
|
|
|
|
|
amount: 2600,
|
|
|
|
|
updatedAt: '2026-06-06T11:00:00+08:00'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
approverUser
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert.equal(summary.totalCount, 0)
|
|
|
|
|
assert.equal(summary.progressItems.length, 1)
|
|
|
|
|
assert.equal(summary.progressItems[0].documentTypeLabel, '申请单')
|
|
|
|
|
assert.equal(summary.progressItems[0].applicantLabel, '张三')
|
|
|
|
|
assert.equal(summary.progressItems[0].requestId, 'AP-202606060002-APPROVAL')
|
|
|
|
|
})
|