feat: 财务看板口径重构与半年模拟数据及报销状态注册表

- 重构 finance_dashboard 口径计算,新增模拟公司画像数据生成与筛选
- 引入 expense_claim_status_registry 统一报销状态流转
- 完善报销草稿流程、Item Sync 与本体解析器
- 优化总览页趋势图、分页组件与请求进度步骤
- 增强报销申请快速预览、本体工具与详情展示
- 新增半年报销模拟数据种子脚本与状态审计工具
- 补充财务看板、报销状态注册与模拟数据测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-02 16:22:59 +08:00
parent ca691f3ee0
commit 0c74b4ab4a
54 changed files with 6810 additions and 1238 deletions

View File

@@ -90,7 +90,7 @@ export default {
const rows = demoDepartments
const max = Math.max(...rows.map((item) => item.amount), 1)
return rows.slice(0, 5).map((item, index) => ({
return rows.slice(0, 6).map((item, index) => ({
...item,
rank: index + 1,
shortName: item.name,

View File

@@ -83,13 +83,38 @@ function normalizeApplicationDateText(value) {
}
function normalizeApplicationBusinessTime(claim) {
const start = normalizeApplicationDateText(claim?.start_date || claim?.startDate || claim?.begin_date || claim?.beginDate)
const end = normalizeApplicationDateText(claim?.end_date || claim?.endDate || claim?.finish_date || claim?.finishDate)
const detail = resolveApplicationDetailPayload(claim)
const start = normalizeApplicationDateText(
detail.start_date
|| detail.startDate
|| detail.departure_date
|| detail.departureDate
|| claim?.start_date
|| claim?.startDate
|| claim?.begin_date
|| claim?.beginDate
)
const end = normalizeApplicationDateText(
detail.end_date
|| detail.endDate
|| detail.return_date
|| detail.returnDate
|| claim?.end_date
|| claim?.endDate
|| claim?.finish_date
|| claim?.finishDate
)
if (start && end && start !== end) {
return `${start}${end}`
}
return normalizeApplicationDateText(
start
|| detail.application_business_time
|| detail.applicationBusinessTime
|| detail.business_time
|| detail.businessTime
|| detail.time_range
|| detail.timeRange
|| claim?.business_time
|| claim?.businessTime
|| claim?.time_range
@@ -101,6 +126,21 @@ function normalizeApplicationBusinessTime(claim) {
)
}
function resolveApplicationDetailPayload(claim) {
const flags = Array.isArray(claim?.risk_flags_json)
? claim.risk_flags_json
: Array.isArray(claim?.riskFlags)
? claim.riskFlags
: []
const detailFlag = flags.find((flag) => (
flag &&
typeof flag === 'object' &&
normalizeLower(flag.source) === 'application_detail'
))
const detail = detailFlag?.application_detail || detailFlag?.applicationDetail || {}
return detail && typeof detail === 'object' ? detail : {}
}
function toTimestamp(value) {
const date = new Date(value)
return Number.isNaN(date.getTime()) ? 0 : date.getTime()
@@ -231,20 +271,51 @@ export function isUsableRequiredApplicationClaim(claim) {
}
export function normalizeRequiredApplicationCandidate(claim) {
const detail = resolveApplicationDetailPayload(claim)
const claimNo = normalizeText(claim?.claim_no || claim?.claimNo)
const location = normalizeText(claim?.location || claim?.business_location || claim?.businessLocation)
const amountText = formatAmount(claim?.amount || claim?.budget_amount || claim?.budgetAmount)
const location = normalizeText(
detail.location
|| detail.application_location
|| claim?.location
|| claim?.business_location
|| claim?.businessLocation
)
const amount = normalizeText(
detail.amount
|| detail.application_amount
|| claim?.amount
|| claim?.budget_amount
|| claim?.budgetAmount
)
const amountText = formatAmount(amount)
const status = normalizeApplicationStatus(claim)
return {
id: normalizeText(claim?.id || claim?.claim_id || claim?.claimId),
claim_no: claimNo,
expense_type: normalizeExpenseType(claim),
reason: normalizeText(claim?.reason || claim?.business_reason || claim?.description || claim?.title),
reason: normalizeText(detail.reason || detail.application_reason || claim?.reason || claim?.business_reason || claim?.description || claim?.title),
location,
amount: normalizeText(claim?.amount || claim?.budget_amount || claim?.budgetAmount),
amount,
amount_label: amountText,
business_time: normalizeApplicationBusinessTime(claim),
business_time: normalizeText(
detail.application_business_time
|| detail.applicationBusinessTime
|| detail.business_time
|| detail.businessTime
|| detail.time_range
|| detail.timeRange
|| detail.time
|| detail.application_time
) || normalizeApplicationBusinessTime(claim),
days: normalizeText(detail.days || detail.application_days),
transport_mode: normalizeText(detail.transport_mode || detail.application_transport_mode),
lodging_daily_cap: normalizeText(detail.lodging_daily_cap || detail.application_lodging_daily_cap),
subsidy_daily_cap: normalizeText(detail.subsidy_daily_cap || detail.application_subsidy_daily_cap),
transport_policy: normalizeText(detail.transport_policy || detail.application_transport_policy),
policy_estimate: normalizeText(detail.policy_estimate || detail.application_policy_estimate),
rule_name: normalizeText(detail.rule_name || detail.application_rule_name),
rule_version: normalizeText(detail.rule_version || detail.application_rule_version),
status,
status_label: STATUS_LABELS[status] || normalizeText(claim?.approval_stage || claim?.approvalStage || status),
application_date: normalizeApplicationDate(claim)
@@ -296,6 +367,14 @@ export function buildRequiredApplicationActions(applications, actionType) {
application_amount: application.amount,
application_amount_label: application.amount_label,
application_business_time: application.business_time,
application_days: application.days,
application_transport_mode: application.transport_mode,
application_lodging_daily_cap: application.lodging_daily_cap,
application_subsidy_daily_cap: application.subsidy_daily_cap,
application_transport_policy: application.transport_policy,
application_policy_estimate: application.policy_estimate,
application_rule_name: application.rule_name,
application_rule_version: application.rule_version,
application_status: application.status,
application_status_label: application.status_label,
application_date: application.application_date

View File

@@ -140,6 +140,14 @@ function normalizeApplicationCandidates(applications) {
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),
days: normalizeText(item.days || item.application_days),
transport_mode: normalizeText(item.transport_mode || item.application_transport_mode),
lodging_daily_cap: normalizeText(item.lodging_daily_cap || item.application_lodging_daily_cap),
subsidy_daily_cap: normalizeText(item.subsidy_daily_cap || item.application_subsidy_daily_cap),
transport_policy: normalizeText(item.transport_policy || item.application_transport_policy),
policy_estimate: normalizeText(item.policy_estimate || item.application_policy_estimate),
rule_name: normalizeText(item.rule_name || item.application_rule_name),
rule_version: normalizeText(item.rule_version || item.application_rule_version),
status: normalizeText(item.status || item.application_status),
status_label: normalizeText(item.status_label || item.application_status_label),
application_date: normalizeText(item.application_date)
@@ -264,6 +272,14 @@ export function selectGuidedRequiredApplication(state, application = {}) {
application_amount: application.application_amount || application.amount || '',
application_amount_label: application.application_amount_label || application.amount_label || '',
application_business_time: application.application_business_time || application.business_time || '',
application_days: application.application_days || application.days || '',
application_transport_mode: application.application_transport_mode || application.transport_mode || '',
application_lodging_daily_cap: application.application_lodging_daily_cap || application.lodging_daily_cap || '',
application_subsidy_daily_cap: application.application_subsidy_daily_cap || application.subsidy_daily_cap || '',
application_transport_policy: application.application_transport_policy || application.transport_policy || '',
application_policy_estimate: application.application_policy_estimate || application.policy_estimate || '',
application_rule_name: application.application_rule_name || application.rule_name || '',
application_rule_version: application.application_rule_version || application.rule_version || '',
application_status_label: application.application_status_label || application.status_label || '',
application_date: application.application_date || ''
}),
@@ -412,6 +428,7 @@ export function buildGuidedReviewSubmitOptions(state, files = []) {
const applicationLocation = values.application_location || ''
const applicationAmount = values.application_amount || values.application_amount_label || ''
const applicationBusinessTime = values.application_business_time || ''
const applicationTransportMode = values.application_transport_mode || ''
const fieldLines = []
if (linkedApplication) {
const applicationParts = buildApplicationSummaryParts(values)
@@ -440,6 +457,7 @@ export function buildGuidedReviewSubmitOptions(state, files = []) {
business_location: values.location || applicationLocation || '',
time_range: values.time_range || applicationBusinessTime || '',
business_time: values.time_range || applicationBusinessTime || '',
transport_mode: values.transport_mode || applicationTransportMode || '',
amount: linkedApplication ? (values.amount || '') : (values.amount || applicationAmount || ''),
attachment_names: Array.isArray(values.attachment_names) ? values.attachment_names : [],
application_claim_id: values.application_claim_id || '',
@@ -449,6 +467,14 @@ export function buildGuidedReviewSubmitOptions(state, files = []) {
application_amount: values.application_amount || '',
application_amount_label: values.application_amount_label || '',
application_business_time: values.application_business_time || '',
application_days: values.application_days || '',
application_transport_mode: values.application_transport_mode || '',
application_lodging_daily_cap: values.application_lodging_daily_cap || '',
application_subsidy_daily_cap: values.application_subsidy_daily_cap || '',
application_transport_policy: values.application_transport_policy || '',
application_policy_estimate: values.application_policy_estimate || '',
application_rule_name: values.application_rule_name || '',
application_rule_version: values.application_rule_version || '',
application_date: values.application_date || ''
}

View File

@@ -50,7 +50,7 @@ function buildTransportEstimatePendingPreview(preview = {}) {
...preview,
fields: {
...fields,
transportPolicy: '正在查询交通参考票价...',
transportPolicy: '正在预估交通费用...',
policyEstimate: '正在同步费用测算...',
transportEstimatedAmount: '查询中'
}

View File

@@ -288,8 +288,8 @@ export function useTravelReimbursementGuidedFlow({
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)
const applicationTransportMode = normalizeText(current.values.application_transport_mode)
if (!originalMessage || !expenseTypeLabel || !applicationNo) {
return null
}
@@ -326,14 +326,23 @@ export function useTravelReimbursementGuidedFlow({
business_location: applicationLocation,
time_range: applicationBusinessTime,
business_time: applicationBusinessTime,
amount: applicationAmount,
transport_mode: applicationTransportMode,
amount: '',
application_claim_id: applicationId,
application_claim_no: applicationNo,
application_reason: applicationReason,
application_location: applicationLocation,
application_amount: current.values.application_amount || '',
application_amount_label: current.values.application_amount_label || '',
application_business_time: applicationBusinessTime
application_business_time: applicationBusinessTime,
application_days: current.values.application_days || '',
application_transport_mode: current.values.application_transport_mode || '',
application_lodging_daily_cap: current.values.application_lodging_daily_cap || '',
application_subsidy_daily_cap: current.values.application_subsidy_daily_cap || '',
application_transport_policy: current.values.application_transport_policy || '',
application_policy_estimate: current.values.application_policy_estimate || '',
application_rule_name: current.values.application_rule_name || '',
application_rule_version: current.values.application_rule_version || ''
}
}
}