import assert from 'node:assert/strict' import test from 'node:test' import { createApprovalTaskSelectionState, reconcileApprovalTaskSelectionAfterBatch, reconcileApprovalTaskSelectionWithPage, resolveApprovalTaskSelectionMeta, resolveCurrentPageApprovalSelection, syncApprovalTaskSelectionFilters, toggleApprovalTaskSelection, toggleCurrentPageApprovalSelection } from '../src/views/scripts/approvalTaskQueueState.js' function task(id, overrides = {}) { return { id, status: 'pending', version: 1, canAct: true, availableActions: ['approve'], batchEligible: true, ...overrides } } test('任务可选性优先使用服务端权限和批量阻断原因', () => { assert.deepEqual(resolveApprovalTaskSelectionMeta(task('task-001')), { taskId: 'task-001', selectable: true, reason: '' }) assert.equal( resolveApprovalTaskSelectionMeta(task('task-002', { canAct: false, readOnlyReason: '该任务已委托给李审批' })).reason, '该任务已委托给李审批' ) assert.equal( resolveApprovalTaskSelectionMeta(task('task-003', { batchEligible: false, batchBlockReasons: ['存在开放高风险', '审批意见必须单独填写'] })).reason, '存在开放高风险;审批意见必须单独填写' ) assert.equal( resolveApprovalTaskSelectionMeta(task('task-004', { availableActions: ['delegate'] })).selectable, false ) }) test('当前页全选和半选只处理服务端允许批量审批的任务', () => { const rows = [ task('task-001'), task('task-002'), task('task-003', { batchEligible: false, batchBlockReasons: ['需单独核对'] }) ] let selected = toggleApprovalTaskSelection([], rows[0], true) let pageState = resolveCurrentPageApprovalSelection(rows, selected) assert.deepEqual(selected, ['task-001']) assert.equal(pageState.indeterminate, true) assert.equal(pageState.allSelected, false) selected = toggleCurrentPageApprovalSelection(selected, rows, true) pageState = resolveCurrentPageApprovalSelection(rows, selected) assert.deepEqual(selected, ['task-001', 'task-002']) assert.equal(pageState.allSelected, true) assert.equal(pageState.eligibleCount, 2) selected = toggleCurrentPageApprovalSelection(selected, rows, false) assert.deepEqual(selected, []) }) test('刷新后任务失去权限时从当前页选择中移除', () => { const selected = ['off-page-task', 'task-001', 'task-002'] const rows = [ task('task-001'), task('task-002', { canAct: false, readOnlyReason: '任务已转交' }) ] assert.deepEqual( reconcileApprovalTaskSelectionWithPage(selected, rows), ['off-page-task', 'task-001'] ) }) test('筛选变化清空选择但翻页和每页条数变化不清空', () => { let state = createApprovalTaskSelectionState({ selectedTaskIds: ['task-001', 'task-002'], filters: { status: 'pending', riskLevel: 'high', page: 1, pageSize: 20 } }) state = syncApprovalTaskSelectionFilters(state, { status: 'pending', riskLevel: 'high', page: 2, pageSize: 50 }) assert.deepEqual(state.selectedTaskIds, ['task-001', 'task-002']) state = syncApprovalTaskSelectionFilters(state, { status: 'pending', riskLevel: 'medium', page: 1, pageSize: 20 }) assert.deepEqual(state.selectedTaskIds, []) }) test('批量部分成功只移除成功和幂等重放项,失败项继续保留', () => { const selected = ['task-001', 'task-002', 'task-003', 'task-004', 'task-005', 'task-unreported'] const result = { status: 'partial', items: [ { taskId: 'task-001', status: 'succeeded' }, { taskId: 'task-002', status: 'replayed' }, { taskId: 'task-003', status: 'blocked' }, { taskId: 'task-004', status: 'conflict' }, { taskId: 'task-005', status: 'forbidden' } ] } assert.deepEqual( reconcileApprovalTaskSelectionAfterBatch(selected, result), ['task-003', 'task-004', 'task-005', 'task-unreported'] ) })