feat: 优化差旅报销预审流程与个人工作台 UI 体系
- 完善 user_agent_application 申请差旅报销预审槽位与消息组装 - 增强预算助理报告与风险建议卡片交互 - 重构登录页视觉样式与移动端响应式适配 - 优化个人工作台、文档中心、政策中心、员工管理等页面布局 - 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型 - 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
} from './travelReimbursementAttachmentModel.js'
|
||||
import { resolveAssistantScopeGuard } from '../../utils/assistantSessionScope.js'
|
||||
import {
|
||||
applyApplicationBusinessTimeContext,
|
||||
applyApplicationPolicyEstimateError,
|
||||
applyApplicationPolicyEstimateResult,
|
||||
buildApplicationPolicyEstimateRequest,
|
||||
@@ -58,6 +59,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
currentInsight,
|
||||
currentUser,
|
||||
draftClaimId,
|
||||
emitDraftSaved,
|
||||
emitOperationCompleted,
|
||||
emitRequestUpdated,
|
||||
extractReviewAttachmentNames,
|
||||
@@ -139,6 +141,20 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
return `attachment-association-${Date.now()}-${Math.random().toString(16).slice(2)}`
|
||||
}
|
||||
|
||||
function emitSavedDraftRefresh(draftPayload) {
|
||||
if (!emitDraftSaved || isKnowledgeSession.value || !draftPayload?.claim_no) {
|
||||
return
|
||||
}
|
||||
const draftType = String(draftPayload.draft_type || '').trim()
|
||||
emitDraftSaved({
|
||||
claimId: String(draftPayload.claim_id || draftPayload.claimId || '').trim(),
|
||||
claimNo: String(draftPayload.claim_no || draftPayload.claimNo || '').trim(),
|
||||
status: String(draftPayload.status || '').trim(),
|
||||
approvalStage: String(draftPayload.approval_stage || draftPayload.approvalStage || '').trim(),
|
||||
documentType: draftType === 'expense_application' ? 'application' : 'reimbursement'
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeRecognizedAttachmentData(data) {
|
||||
if (!data || typeof data !== 'object') {
|
||||
return null
|
||||
@@ -351,9 +367,12 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
return currentUser.value || user
|
||||
}
|
||||
|
||||
async function buildApplicationPreviewWithModelReview(rawText) {
|
||||
async function buildApplicationPreviewWithModelReview(rawText, businessTimeContext = null) {
|
||||
const user = await resolveApplicationPreviewUser()
|
||||
const localPreview = buildLocalApplicationPreview(rawText, user)
|
||||
const localPreview = applyApplicationBusinessTimeContext(
|
||||
buildLocalApplicationPreview(rawText, user),
|
||||
businessTimeContext
|
||||
)
|
||||
|
||||
const enrichWithPolicyEstimate = async (preview) => {
|
||||
const estimateRequest = buildApplicationPolicyEstimateRequest(preview, user)
|
||||
@@ -393,11 +412,14 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
}
|
||||
)
|
||||
|
||||
const refinedPreview = buildModelRefinedApplicationPreview(
|
||||
localPreview,
|
||||
ontology,
|
||||
rawText,
|
||||
user
|
||||
const refinedPreview = applyApplicationBusinessTimeContext(
|
||||
buildModelRefinedApplicationPreview(
|
||||
localPreview,
|
||||
ontology,
|
||||
rawText,
|
||||
user
|
||||
),
|
||||
businessTimeContext
|
||||
)
|
||||
return {
|
||||
applicationPreview: await enrichWithPolicyEstimate(refinedPreview),
|
||||
@@ -462,6 +484,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
: mergeBusinessTimeIntoExtraContext(initialExtraContext, selectedBusinessTimeContext)
|
||||
const reviewAction = String(extraContext.review_action || '').trim()
|
||||
const feedbackOperationType = String(options.feedbackOperationType || '').trim()
|
||||
const isApplicationSubmitOperation = feedbackOperationType === 'submit_application'
|
||||
const attachmentAssociationConfirmed = Boolean(
|
||||
options.associationConfirmed ||
|
||||
extraContext.attachment_association_confirmed ||
|
||||
@@ -499,7 +522,11 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
? `新上传 ${fileNames.length} 份票据,请单独建立报销单。`
|
||||
: `我上传了 ${fileNames.length} 份票据,请帮我识别并整理报销建议。`)
|
||||
|
||||
if (shouldUseBudgetCompileReport(rawText, { sessionType: activeSessionType.value }) && !reviewAction) {
|
||||
if (shouldUseBudgetCompileReport(rawText, {
|
||||
sessionType: activeSessionType.value,
|
||||
entrySource: props.entrySource,
|
||||
budgetContext: props.initialBudgetContext
|
||||
}) && !reviewAction) {
|
||||
return handleBudgetCompileReportSubmit({
|
||||
adjustComposerTextareaHeight,
|
||||
clearAttachedFiles,
|
||||
@@ -518,6 +545,8 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
rawText,
|
||||
replaceMessage,
|
||||
resetFlowRun,
|
||||
refreshCurrentUserFromBackend,
|
||||
budgetContext: props.initialBudgetContext,
|
||||
scrollToBottom,
|
||||
startFlowStep,
|
||||
submitting,
|
||||
@@ -595,7 +624,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
const { applicationPreview, meta } = await buildApplicationPreviewWithModelReview(rawText)
|
||||
const { applicationPreview, meta } = await buildApplicationPreviewWithModelReview(rawText, selectedBusinessTimeContext)
|
||||
const reviewStatus = String(meta?.[1] || '').trim()
|
||||
completeFlowStep('intent', '已识别为费用申请事项', Date.now() - intentStartedAt)
|
||||
completeFlowStep(
|
||||
@@ -725,7 +754,13 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
} else {
|
||||
clearFlowSimulationTimers()
|
||||
}
|
||||
if (rawText && !reviewAction) {
|
||||
if (isApplicationSubmitOperation) {
|
||||
startFlowStep('application-submit-success', {
|
||||
title: '申请单提交成功',
|
||||
tool: 'ApplicationSubmit',
|
||||
detail: '正在提交费用申请...'
|
||||
})
|
||||
} else if (rawText && !reviewAction) {
|
||||
startFlowStep('intent', '正在识别业务意图...')
|
||||
if (waitForExpenseIntentConfirmation) {
|
||||
startExpenseIntentConfirmationFlowPreview(rawText)
|
||||
@@ -947,10 +982,12 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
extraContext.review_action = 'create_new_claim_from_documents'
|
||||
}
|
||||
|
||||
startExpenseClaimDraftFlowStep(String(extraContext.review_action || '').trim(), {
|
||||
attachmentCount: effectiveFileNames.length,
|
||||
waitForSceneSelection: waitForExpenseSceneSelection
|
||||
})
|
||||
if (!isApplicationSubmitOperation) {
|
||||
startExpenseClaimDraftFlowStep(String(extraContext.review_action || '').trim(), {
|
||||
attachmentCount: effectiveFileNames.length,
|
||||
waitForSceneSelection: waitForExpenseSceneSelection
|
||||
})
|
||||
}
|
||||
|
||||
const backendMessage = buildBackendMessage(rawText, effectiveFileNames, effectiveOcrSummary)
|
||||
const orchestratorOptions = isKnowledgeSession.value
|
||||
@@ -977,9 +1014,17 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
department: user.department || user.departmentName || '',
|
||||
department_name: user.department || user.departmentName || '',
|
||||
position: user.position || '',
|
||||
grade: user.grade || '',
|
||||
employee_position: user.position || user.employeePosition || user.employee_position || '',
|
||||
employeePosition: user.position || user.employeePosition || user.employee_position || '',
|
||||
grade: user.grade || user.employeeGrade || user.employee_grade || '',
|
||||
employee_grade: user.grade || user.employeeGrade || user.employee_grade || '',
|
||||
employeeGrade: user.grade || user.employeeGrade || user.employee_grade || '',
|
||||
employee_no: user.employeeNo || user.employee_no || '',
|
||||
employeeNo: user.employeeNo || user.employee_no || '',
|
||||
manager_name: user.managerName || user.manager_name || '',
|
||||
managerName: user.managerName || user.manager_name || '',
|
||||
direct_manager_name: user.managerName || user.manager_name || user.directManagerName || user.direct_manager_name || '',
|
||||
directManagerName: user.managerName || user.manager_name || user.directManagerName || user.direct_manager_name || '',
|
||||
employee_location: user.location || '',
|
||||
cost_center: user.costCenter || user.cost_center || '',
|
||||
finance_owner_name: user.financeOwnerName || user.finance_owner_name || '',
|
||||
@@ -1051,6 +1096,9 @@ export function useTravelReimbursementSubmitComposer(ctx) {
|
||||
}
|
||||
currentInsight.value = nextInsight
|
||||
completeFlowResult(payload, flowRunDetail)
|
||||
if (['save_draft', 'link_to_existing_draft', 'create_new_claim_from_documents'].includes(reviewActionResult)) {
|
||||
emitSavedDraftRefresh(payload?.result?.draft_payload || null)
|
||||
}
|
||||
persistSessionState()
|
||||
nextTick(scrollToBottom)
|
||||
const resolvedDraftClaimId = String(payload?.result?.draft_payload?.claim_id || draftClaimId.value || '').trim()
|
||||
|
||||
Reference in New Issue
Block a user