feat: 优化差旅报销预审流程与个人工作台 UI 体系

- 完善 user_agent_application 申请差旅报销预审槽位与消息组装
- 增强预算助理报告与风险建议卡片交互
- 重构登录页视觉样式与移动端响应式适配
- 优化个人工作台、文档中心、政策中心、员工管理等页面布局
- 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型
- 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-02 14:01:51 +08:00
parent 92444e7eae
commit ca691f3ee0
107 changed files with 5663 additions and 1542 deletions

View File

@@ -228,7 +228,7 @@ export function useTravelReimbursementGuidedFlow({
function pushReimbursementSummary() {
pushAssistant(buildGuidedReimbursementSummaryText(guidedFlowState.value), {
meta: ['待生成核对信息'],
meta: ['待生成报销草稿'],
suggestedActions: buildGuidedReviewConfirmationActions()
})
}
@@ -286,6 +286,10 @@ export function useTravelReimbursementGuidedFlow({
const expenseTypeLabel = normalizeText(current.values.pending_scene_expense_type_label)
const applicationNo = normalizeText(current.values.application_claim_no)
const applicationId = normalizeText(current.values.application_claim_id)
const applicationReason = normalizeText(current.values.application_reason)
const applicationLocation = normalizeText(current.values.application_location)
const applicationAmount = normalizeText(current.values.application_amount || current.values.application_amount_label)
const applicationBusinessTime = normalizeText(current.values.application_business_time)
if (!originalMessage || !expenseTypeLabel || !applicationNo) {
return null
}
@@ -299,11 +303,12 @@ export function useTravelReimbursementGuidedFlow({
return {
rawText,
userText: `关联申请单 ${applicationNo}`,
pendingText: `已关联申请单,正在${expenseTypeLabel}识别...`,
pendingText: `已关联申请单,正在生成${expenseTypeLabel}草稿...`,
systemGenerated: true,
skipUserMessage: true,
extraContext: {
draft_claim_id: '',
review_action: 'save_draft',
user_input_text: originalMessage,
expense_scene_selection: {
expense_type: current.expenseType || 'other',
@@ -314,11 +319,21 @@ export function useTravelReimbursementGuidedFlow({
},
review_form_values: {
expense_type: expenseTypeLabel,
reimbursement_type: expenseTypeLabel,
reason: applicationReason,
reason_value: applicationReason,
location: applicationLocation,
business_location: applicationLocation,
time_range: applicationBusinessTime,
business_time: applicationBusinessTime,
amount: applicationAmount,
application_claim_id: applicationId,
application_claim_no: applicationNo,
application_reason: current.values.application_reason || '',
application_location: current.values.application_location || '',
application_amount: current.values.application_amount || ''
application_reason: applicationReason,
application_location: applicationLocation,
application_amount: current.values.application_amount || '',
application_amount_label: current.values.application_amount_label || '',
application_business_time: applicationBusinessTime
}
}
}
@@ -329,6 +344,21 @@ export function useTravelReimbursementGuidedFlow({
const currentStep = getCurrentGuidedStep(currentState)
const fileNames = buildFileNames(files)
if (isGuidedReimbursementReadyForReview(currentState) && fileNames.length) {
const mergedFiles = mergePendingFiles(guidedPendingFiles.value, files)
guidedPendingFiles.value = mergedFiles
const submitOptions = {
...buildGuidedReviewSubmitOptions(currentState, mergedFiles),
skipDraftAssociationPrompt: true,
skipUserMessage: true,
pendingText: '已关联申请单,正在识别票据并生成报销草稿...'
}
resetGuidedFlowState()
persistAndScroll()
await submitExistingComposer(submitOptions)
return
}
if (currentState.stepKey === 'expense_type') {
const expenseType = resolveGuidedExpenseTypeFromText(answerText)
if (!expenseType) {
@@ -343,7 +373,7 @@ export function useTravelReimbursementGuidedFlow({
}
if (currentState.stepKey === 'application_selection') {
pushAssistant('请先点击上方列出的申请单完成关联。关联后,我再继续询问报销依据。', {
pushAssistant('请先点击上方列出的申请单完成关联。关联后,我会直接进入生成报销草稿。', {
meta: ['等待关联申请单'],
suggestedActions: buildRequiredApplicationActions(
currentState.applicationCandidates,
@@ -521,6 +551,11 @@ export function useTravelReimbursementGuidedFlow({
await submitExistingComposer(pendingSceneSubmitOptions)
return true
}
if (isGuidedReimbursementReadyForReview(guidedFlowState.value)) {
pushReimbursementSummary()
persistAndScroll()
return true
}
pushNextReimbursementPrompt()
persistAndScroll()
return true