feat: 优化差旅报销预审流程与个人工作台 UI 体系
- 完善 user_agent_application 申请差旅报销预审槽位与消息组装 - 增强预算助理报告与风险建议卡片交互 - 重构登录页视觉样式与移动端响应式适配 - 优化个人工作台、文档中心、政策中心、员工管理等页面布局 - 拆分 travelRequestDetailPreReviewModel 为 advice/submit 模型 - 补充报销草稿、风险复核、Item Sync 与模板执行器测试覆盖
This commit is contained in:
@@ -110,6 +110,20 @@ function normalizeValues(values) {
|
||||
}, {})
|
||||
}
|
||||
|
||||
function hasLinkedApplication(values) {
|
||||
return Boolean(normalizeText(values?.application_claim_id) || normalizeText(values?.application_claim_no))
|
||||
}
|
||||
|
||||
function buildApplicationSummaryParts(values) {
|
||||
return [
|
||||
normalizeText(values?.application_claim_no),
|
||||
normalizeText(values?.application_reason),
|
||||
normalizeText(values?.application_business_time),
|
||||
normalizeText(values?.application_location),
|
||||
normalizeText(values?.application_amount_label || values?.application_amount)
|
||||
].filter(Boolean)
|
||||
}
|
||||
|
||||
function normalizeApplicationCandidates(applications) {
|
||||
if (!Array.isArray(applications)) {
|
||||
return []
|
||||
@@ -125,6 +139,7 @@ function normalizeApplicationCandidates(applications) {
|
||||
location: normalizeText(item.location || item.application_location),
|
||||
amount: normalizeText(item.amount || item.application_amount),
|
||||
amount_label: normalizeText(item.amount_label || item.application_amount_label),
|
||||
business_time: normalizeText(item.business_time || item.application_business_time),
|
||||
status: normalizeText(item.status || item.application_status),
|
||||
status_label: normalizeText(item.status_label || item.application_status_label),
|
||||
application_date: normalizeText(item.application_date)
|
||||
@@ -238,7 +253,6 @@ export function waitForGuidedApplicationSelection(state, expenseType, applicatio
|
||||
|
||||
export function selectGuidedRequiredApplication(state, application = {}) {
|
||||
const current = normalizeGuidedFlowState(state)
|
||||
const steps = getGuidedReimbursementSteps(current.expenseType)
|
||||
return {
|
||||
...current,
|
||||
values: normalizeValues({
|
||||
@@ -249,9 +263,11 @@ export function selectGuidedRequiredApplication(state, application = {}) {
|
||||
application_location: application.application_location || application.location || '',
|
||||
application_amount: application.application_amount || application.amount || '',
|
||||
application_amount_label: application.application_amount_label || application.amount_label || '',
|
||||
application_status_label: application.application_status_label || application.status_label || ''
|
||||
application_business_time: application.application_business_time || application.business_time || '',
|
||||
application_status_label: application.application_status_label || application.status_label || '',
|
||||
application_date: application.application_date || ''
|
||||
}),
|
||||
stepKey: steps[0]?.key || 'summary',
|
||||
stepKey: 'summary',
|
||||
pendingInterruptionText: '',
|
||||
applicationCandidates: []
|
||||
}
|
||||
@@ -346,40 +362,41 @@ export function buildGuidedReimbursementSummaryText(state) {
|
||||
const current = normalizeGuidedFlowState(state)
|
||||
const typeLabel = getGuidedExpenseTypeLabel(current.expenseType) || '报销'
|
||||
const steps = getGuidedReimbursementSteps(current.expenseType)
|
||||
const linkedApplication = hasLinkedApplication(current.values)
|
||||
const lines = [
|
||||
`已完成“${typeLabel}”的引导填写。`,
|
||||
'',
|
||||
'请核查下面的关键信息:'
|
||||
]
|
||||
|
||||
if (current.values.application_claim_no) {
|
||||
const applicationParts = [
|
||||
current.values.application_claim_no,
|
||||
current.values.application_reason,
|
||||
current.values.application_location,
|
||||
current.values.application_amount_label
|
||||
].filter(Boolean)
|
||||
if (linkedApplication) {
|
||||
const applicationParts = buildApplicationSummaryParts(current.values)
|
||||
lines.push(`- 关联申请单:${applicationParts.join(' / ')}`)
|
||||
lines.push('- 报销票据:可先生成草稿,随后在草稿详情中上传对应票据。')
|
||||
} else {
|
||||
steps.forEach((step) => {
|
||||
const value = step.key === 'attachments'
|
||||
? (current.values.attachment_names?.length
|
||||
? current.values.attachment_names.join('、')
|
||||
: current.values.attachments || '稍后上传')
|
||||
: current.values[step.key]
|
||||
lines.push(`- ${step.summaryLabel}:${value || '待补充'}`)
|
||||
})
|
||||
}
|
||||
|
||||
steps.forEach((step) => {
|
||||
const value = step.key === 'attachments'
|
||||
? (current.values.attachment_names?.length
|
||||
? current.values.attachment_names.join('、')
|
||||
: current.values.attachments || '稍后上传')
|
||||
: current.values[step.key]
|
||||
lines.push(`- ${step.summaryLabel}:${value || '待补充'}`)
|
||||
})
|
||||
|
||||
lines.push('')
|
||||
lines.push('如果这些信息无误,我可以继续生成右侧报销核对信息;生成核对信息后,再由你决定保存草稿或继续下一步。')
|
||||
lines.push(
|
||||
linkedApplication
|
||||
? '如果关联信息无误,我可以直接生成报销草稿;后续由你在草稿详情中上传和归集票据。'
|
||||
: '如果这些信息无误,我可以继续生成报销草稿;草稿生成后可继续上传票据或补充信息。'
|
||||
)
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
export function buildGuidedReviewConfirmationActions() {
|
||||
return [{
|
||||
label: '生成报销核对信息',
|
||||
description: '进入现有报销核对流程,不会直接保存草稿',
|
||||
label: '生成报销草稿',
|
||||
description: '使用当前信息生成草稿,票据可在草稿详情继续上传',
|
||||
icon: 'mdi mdi-clipboard-check-outline',
|
||||
action_type: GUIDED_ACTION_CONFIRM_REIMBURSEMENT_REVIEW
|
||||
}]
|
||||
@@ -390,14 +407,23 @@ export function buildGuidedReviewSubmitOptions(state, files = []) {
|
||||
const type = getGuidedExpenseType(current.expenseType)
|
||||
const values = current.values || {}
|
||||
const typeLabel = type?.label || '其他费用'
|
||||
const fieldLines = getGuidedReimbursementSteps(current.expenseType).map((step) => {
|
||||
const value = step.key === 'attachments'
|
||||
? (values.attachment_names?.length ? values.attachment_names.join('、') : values.attachments || '稍后上传')
|
||||
: values[step.key]
|
||||
return `${step.summaryLabel}:${value || '待补充'}`
|
||||
})
|
||||
if (values.application_claim_no) {
|
||||
fieldLines.unshift(`关联申请单:${values.application_claim_no}`)
|
||||
const linkedApplication = hasLinkedApplication(values)
|
||||
const applicationReason = values.application_reason || ''
|
||||
const applicationLocation = values.application_location || ''
|
||||
const applicationAmount = values.application_amount || values.application_amount_label || ''
|
||||
const applicationBusinessTime = values.application_business_time || ''
|
||||
const fieldLines = []
|
||||
if (linkedApplication) {
|
||||
const applicationParts = buildApplicationSummaryParts(values)
|
||||
fieldLines.push(`关联申请单:${applicationParts.join(' / ')}`)
|
||||
fieldLines.push('报销票据:草稿生成后在详情中上传')
|
||||
} else {
|
||||
getGuidedReimbursementSteps(current.expenseType).forEach((step) => {
|
||||
const value = step.key === 'attachments'
|
||||
? (values.attachment_names?.length ? values.attachment_names.join('、') : values.attachments || '稍后上传')
|
||||
: values[step.key]
|
||||
fieldLines.push(`${step.summaryLabel}:${value || '待补充'}`)
|
||||
})
|
||||
}
|
||||
const rawText = [
|
||||
`报销类型:${typeLabel}`,
|
||||
@@ -406,31 +432,35 @@ export function buildGuidedReviewSubmitOptions(state, files = []) {
|
||||
const reviewFormValues = {
|
||||
expense_type: typeLabel,
|
||||
reimbursement_type: typeLabel,
|
||||
reason: values.reason || values.customer_name || '',
|
||||
reason_value: values.reason || '',
|
||||
reason: values.reason || applicationReason || values.customer_name || '',
|
||||
reason_value: values.reason || applicationReason || '',
|
||||
customer_name: values.customer_name || '',
|
||||
participants: values.participants || '',
|
||||
location: values.location || '',
|
||||
business_location: values.location || '',
|
||||
time_range: values.time_range || '',
|
||||
business_time: values.time_range || '',
|
||||
amount: values.amount || '',
|
||||
location: values.location || applicationLocation || '',
|
||||
business_location: values.location || applicationLocation || '',
|
||||
time_range: values.time_range || applicationBusinessTime || '',
|
||||
business_time: values.time_range || applicationBusinessTime || '',
|
||||
amount: linkedApplication ? (values.amount || '') : (values.amount || applicationAmount || ''),
|
||||
attachment_names: Array.isArray(values.attachment_names) ? values.attachment_names : [],
|
||||
application_claim_id: values.application_claim_id || '',
|
||||
application_claim_no: values.application_claim_no || '',
|
||||
application_reason: values.application_reason || '',
|
||||
application_location: values.application_location || '',
|
||||
application_amount: values.application_amount || ''
|
||||
application_amount: values.application_amount || '',
|
||||
application_amount_label: values.application_amount_label || '',
|
||||
application_business_time: values.application_business_time || '',
|
||||
application_date: values.application_date || ''
|
||||
}
|
||||
|
||||
return {
|
||||
rawText,
|
||||
userText: '生成报销核对信息',
|
||||
pendingText: '正在生成右侧报销核对信息...',
|
||||
userText: '生成报销草稿',
|
||||
pendingText: '正在生成报销草稿...',
|
||||
systemGenerated: true,
|
||||
files,
|
||||
extraContext: {
|
||||
draft_claim_id: '',
|
||||
review_action: 'save_draft',
|
||||
user_input_text: rawText,
|
||||
expense_scene_selection: {
|
||||
expense_type: type?.key || current.expenseType || 'other',
|
||||
|
||||
Reference in New Issue
Block a user