feat(ai): unify verified expense application workflow
This commit is contained in:
@@ -305,148 +305,52 @@ test('workbench standalone draft action asks before creating a new reimbursement
|
||||
})
|
||||
})
|
||||
|
||||
test('workbench steward executable submit action runs precheck before submit and writes result message', async () => {
|
||||
const requests = []
|
||||
const originalFetch = globalThis.fetch
|
||||
globalThis.fetch = async (_url, options = {}) => {
|
||||
const body = JSON.parse(String(options.body || '{}'))
|
||||
requests.push(body)
|
||||
if (body.action_type === 'run_duplicate_precheck') {
|
||||
return {
|
||||
ok: true,
|
||||
async json() {
|
||||
return {
|
||||
action_type: 'run_duplicate_precheck',
|
||||
status: 'succeeded',
|
||||
message: '未发现重复或冲突申请,可以继续提交。',
|
||||
result_payload: {
|
||||
status: 'ok',
|
||||
blocking: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
async json() {
|
||||
return {
|
||||
action_type: 'submit_application',
|
||||
status: 'succeeded',
|
||||
message: '申请已提交审批。',
|
||||
result_payload: {
|
||||
draft_payload: {
|
||||
claim_id: 'claim-app-1',
|
||||
claim_no: 'A1BCDEF2'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
test('workbench steward application side effect opens signed preview before submit', () => {
|
||||
let previewPayload = null
|
||||
const router = useWorkbenchAiActionRouter({
|
||||
aiExpenseDraft: { value: null },
|
||||
applicationFlow: {
|
||||
isInlineSuggestedActionDisabled: () => false,
|
||||
executeInlineApplicationPreviewAction: () => {}
|
||||
},
|
||||
assistantDraft: { value: '' },
|
||||
attachmentFlow: { confirmAiAttachmentAssociation: () => {} },
|
||||
emit: () => {},
|
||||
expenseFlow: {
|
||||
linkAiExpenseApplication: () => {},
|
||||
pushInlineExpenseSceneSelectionPrompt: () => {},
|
||||
startAiApplicationPreviewFromAction: (payload) => {
|
||||
previewPayload = payload
|
||||
},
|
||||
startAiExpenseDraft: () => {}
|
||||
},
|
||||
focusAiModeInput: () => {},
|
||||
hasInlineAttachmentOcrDetails: () => false,
|
||||
resolveLatestInlineUserPrompt: () => '',
|
||||
selectedFiles: { value: [] },
|
||||
startInlineConversation: () => {},
|
||||
toast: () => {},
|
||||
toggleInlineAttachmentOcrDetails: () => {}
|
||||
})
|
||||
|
||||
try {
|
||||
const messages = []
|
||||
let messageSeq = 0
|
||||
const createInlineMessage = (role, content, options = {}) => ({
|
||||
id: options.id || `msg-${++messageSeq}`,
|
||||
role,
|
||||
content,
|
||||
pending: Boolean(options.pending),
|
||||
suggestedActions: Array.isArray(options.suggestedActions) ? options.suggestedActions : []
|
||||
})
|
||||
const replaceInlineMessage = (id, nextMessage) => {
|
||||
const index = messages.findIndex((item) => item.id === id)
|
||||
if (index >= 0) {
|
||||
messages.splice(index, 1, nextMessage)
|
||||
}
|
||||
}
|
||||
let persisted = false
|
||||
const router = useWorkbenchAiActionRouter({
|
||||
aiExpenseDraft: { value: null },
|
||||
applicationFlow: {
|
||||
isInlineSuggestedActionDisabled: () => false,
|
||||
executeInlineApplicationPreviewAction: () => {}
|
||||
},
|
||||
assistantDraft: { value: '' },
|
||||
attachmentFlow: {
|
||||
confirmAiAttachmentAssociation: () => {}
|
||||
},
|
||||
conversationMessages: { value: messages },
|
||||
createInlineMessage,
|
||||
emit: () => {},
|
||||
expenseFlow: {
|
||||
linkAiExpenseApplication: () => {},
|
||||
pushInlineExpenseSceneSelectionPrompt: () => {},
|
||||
startAiApplicationPreviewFromAction: () => {},
|
||||
startAiExpenseDraft: () => {}
|
||||
},
|
||||
focusAiModeInput: () => {},
|
||||
hasInlineAttachmentOcrDetails: () => false,
|
||||
persistCurrentConversation: () => {
|
||||
persisted = true
|
||||
},
|
||||
replaceInlineMessage,
|
||||
resolveLatestInlineUserPrompt: () => '2026-02-20 至 2026-02-23,去上海出差,交通火车,直接提交',
|
||||
scrollInlineConversationToBottom: () => {},
|
||||
selectedFiles: { value: [] },
|
||||
startInlineConversation: () => {},
|
||||
toast: () => {},
|
||||
toggleInlineAttachmentOcrDetails: () => {}
|
||||
})
|
||||
const sourceMessage = {
|
||||
suggestedActionsLocked: false
|
||||
router.handleInlineSuggestedAction({
|
||||
label: '确认提交申请',
|
||||
action_type: 'switch_session',
|
||||
payload: {
|
||||
steward_execute_action: true,
|
||||
steward_action_type: 'submit_application',
|
||||
steward_current_task: {
|
||||
task_id: 'task-app-1',
|
||||
task_type: 'expense_application',
|
||||
requested_action: 'submit'
|
||||
},
|
||||
carry_text: '2026-02-20 至 2026-02-23,去上海出差,交通火车,直接提交'
|
||||
}
|
||||
})
|
||||
|
||||
await router.handleInlineSuggestedAction({
|
||||
label: '确认提交申请',
|
||||
action_type: 'switch_session',
|
||||
payload: {
|
||||
steward_execute_action: true,
|
||||
steward_plan_id: 'plan-submit-1',
|
||||
steward_action_type: 'submit_application',
|
||||
steward_action_requires_confirmation: true,
|
||||
steward_action_step: {
|
||||
step_id: 'task-app-1:05',
|
||||
action_type: 'submit_application',
|
||||
requires_confirmation: true
|
||||
},
|
||||
steward_current_task: {
|
||||
task_id: 'task-app-1',
|
||||
task_type: 'expense_application',
|
||||
assigned_agent: 'application_assistant',
|
||||
title: '上海出差申请',
|
||||
summary: '2026-02-20 至 2026-02-23 去上海出差,交通火车。',
|
||||
requested_action: 'submit',
|
||||
ontology_fields: {
|
||||
expense_type: 'travel',
|
||||
time_range: '2026-02-20 至 2026-02-23',
|
||||
location: '上海',
|
||||
reason: '辅助国网仿生产服务器部署',
|
||||
transport_mode: 'train'
|
||||
},
|
||||
missing_fields: [],
|
||||
action_steps: [
|
||||
{ step_id: 'task-app-1:04', action_type: 'run_duplicate_precheck' },
|
||||
{ step_id: 'task-app-1:05', action_type: 'submit_application', requires_confirmation: true }
|
||||
]
|
||||
},
|
||||
carry_text: '2026-02-20 至 2026-02-23,去上海出差,交通火车,直接提交'
|
||||
}
|
||||
}, sourceMessage)
|
||||
|
||||
assert.equal(requests.length, 2)
|
||||
assert.equal(requests[0].action_type, 'run_duplicate_precheck')
|
||||
assert.equal(requests[1].action_type, 'submit_application')
|
||||
assert.equal(requests[1].confirmed, true)
|
||||
assert.equal(requests[1].context_json.precheck_result.status, 'ok')
|
||||
assert.equal(sourceMessage.suggestedActionsLocked, true)
|
||||
assert.equal(persisted, true)
|
||||
assert.match(messages.at(-1).content, /申请已提交审批/)
|
||||
assert.equal(messages.at(-1).suggestedActions[0].action_type, 'open_application_detail')
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch
|
||||
}
|
||||
assert.equal(previewPayload?.steward_action_type, 'submit_application')
|
||||
assert.equal(previewPayload?.steward_current_task?.task_type, 'expense_application')
|
||||
assert.match(previewPayload?.carry_text || '', /直接提交/)
|
||||
})
|
||||
|
||||
test('workbench steward continue-next-task reimbursement prefills ontology and forwards remaining tasks', () => {
|
||||
|
||||
Reference in New Issue
Block a user