499 lines
21 KiB
JavaScript
499 lines
21 KiB
JavaScript
import { buildApplicationFieldsFromOntology } from './expenseApplicationOntology.js'
|
||
import { evaluateLocalApplicationIntentGate } from './expenseApplicationIntentGate.js'
|
||
import {
|
||
formatApplicationEstimateMoney,
|
||
parseApplicationEstimateMoney,
|
||
buildSystemApplicationEstimate
|
||
} from './expenseApplicationEstimate.js'
|
||
import {
|
||
APPLICATION_POLICY_PENDING_TEXT,
|
||
APPLICATION_PREVIEW_FIELD_DEFINITIONS,
|
||
APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT,
|
||
buildMissingFields,
|
||
buildTransportEstimateFromPolicyResult,
|
||
buildTransportPolicyText,
|
||
ensureApplicationPolicyFields,
|
||
formatDailyPolicyMoney,
|
||
formatPolicyMoney,
|
||
isApplicationPreviewValueProvided,
|
||
isTravelApplicationType,
|
||
normalizeAmountFromOntology,
|
||
normalizeApplicationTypeLabel,
|
||
normalizeTypedOntologyAmount,
|
||
parseApplicationDaysValue,
|
||
parseMoneyNumber,
|
||
resolveApplicationAmount,
|
||
resolveApplicationDays,
|
||
resolveApplicationFieldLabel,
|
||
resolveApplicationLocation,
|
||
resolveApplicationReason,
|
||
resolveApplicationSourceValidationIssues,
|
||
resolveApplicationTimeWithDefault,
|
||
resolveApplicationTransportMode,
|
||
resolveApplicationTripDateParts,
|
||
resolveApplicationType,
|
||
resolveApplicationValidationIssues,
|
||
resolveCurrentUserDepartment,
|
||
resolveCurrentUserGrade,
|
||
resolveCurrentUserManagerName,
|
||
resolveCurrentUserPosition,
|
||
resolveDaysFromDateRange,
|
||
resolveModelRefinedTransportMode,
|
||
resolveProvidedValue
|
||
} from './expenseApplicationPreviewParsing.js'
|
||
export {
|
||
APPLICATION_PREVIEW_FIELD_DEFINITIONS,
|
||
APPLICATION_TRANSPORT_MODE_OPTIONS,
|
||
applicationDateRangesOverlap,
|
||
normalizeTransportModeOption,
|
||
resolveApplicationDateRange,
|
||
resolveApplicationDaysFromDateRange,
|
||
resolveApplicationTimeLabel,
|
||
shouldRequireApplicationModelReview
|
||
} from './expenseApplicationPreviewParsing.js'
|
||
|
||
export function buildApplicationPolicyEstimateRequest(preview = {}, currentUser = {}) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const fields = normalized.fields || {}
|
||
const days = parseApplicationDaysValue(fields.days)
|
||
const location = String(fields.location || '').trim()
|
||
const grade = String(fields.grade || resolveCurrentUserGrade(currentUser)).trim()
|
||
const applicationType = String(fields.applicationType || '').trim()
|
||
const transportMode = String(fields.transportMode || '').trim()
|
||
const shouldEstimate = /差旅|住宿|交通/.test(applicationType) || Boolean(transportMode)
|
||
|
||
if (!shouldEstimate || !days || !location) {
|
||
return {
|
||
canCalculate: false,
|
||
reason: '缺少地点或天数',
|
||
payload: null
|
||
}
|
||
}
|
||
|
||
return {
|
||
canCalculate: true,
|
||
reason: '',
|
||
payload: {
|
||
days,
|
||
location,
|
||
grade,
|
||
transport_mode: transportMode || null,
|
||
origin_location: String(
|
||
currentUser.location
|
||
|| currentUser.officeLocation
|
||
|| currentUser.office_location
|
||
|| currentUser.baseCity
|
||
|| currentUser.base_city
|
||
|| ''
|
||
).trim() || null,
|
||
travel_date: resolveApplicationTripDateParts(fields).startDate || null
|
||
}
|
||
}
|
||
}
|
||
|
||
export function applyApplicationPolicyEstimateResult(preview = {}, result = {}, currentUser = {}) {
|
||
const fields = {
|
||
...(preview?.fields || {})
|
||
}
|
||
const hotelRate = formatPolicyMoney(result?.hotel_rate)
|
||
const hotelAmount = formatPolicyMoney(result?.hotel_amount)
|
||
const allowanceRate = formatPolicyMoney(result?.total_allowance_rate)
|
||
const allowanceAmount = formatPolicyMoney(result?.allowance_amount)
|
||
const matchedCity = String(result?.matched_city || fields.location || '').trim()
|
||
const grade = String(result?.grade || fields.grade || resolveCurrentUserGrade(currentUser)).trim()
|
||
if (isTravelApplicationType(fields.applicationType) && !String(fields.transportMode || '').trim()) {
|
||
const days = Number(result?.days) || parseApplicationDaysValue(fields.days) || 1
|
||
const baseTotalAmount = parseMoneyNumber(result?.hotel_amount) + parseMoneyNumber(result?.allowance_amount)
|
||
const baseTotalDisplay = Number.isFinite(baseTotalAmount) && baseTotalAmount > 0
|
||
? formatPolicyMoney(baseTotalAmount)
|
||
: ''
|
||
return normalizeApplicationPreview({
|
||
...preview,
|
||
fields: {
|
||
...fields,
|
||
grade,
|
||
lodgingDailyCap: formatDailyPolicyMoney(result?.hotel_rate),
|
||
subsidyDailyCap: formatDailyPolicyMoney(result?.total_allowance_rate),
|
||
transportPolicy: APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT,
|
||
policyEstimate: baseTotalDisplay
|
||
? `交通待补充 + 住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${baseTotalDisplay}元(${days}天,不含交通)`
|
||
: APPLICATION_POLICY_PENDING_TEXT,
|
||
amount: baseTotalDisplay ? `${baseTotalDisplay}元(不含交通)` : fields.amount,
|
||
matchedCity,
|
||
ruleName: String(result?.rule_name || '').trim(),
|
||
ruleVersion: String(result?.rule_version || '').trim(),
|
||
hotelAmount: hotelAmount ? `${hotelAmount}元` : '',
|
||
allowanceAmount: allowanceAmount ? `${allowanceAmount}元` : '',
|
||
transportEstimatedAmount: '',
|
||
transportEstimateDate: '',
|
||
transportQueryLatencyMs: '',
|
||
transportEstimateSource: '',
|
||
transportEstimateConfidence: '',
|
||
policyTotalAmount: baseTotalDisplay ? `${baseTotalDisplay}元(不含交通)` : ''
|
||
},
|
||
policyEstimateStatus: 'pending'
|
||
})
|
||
}
|
||
const days = Number(result?.days) || parseApplicationDaysValue(fields.days) || 1
|
||
let systemEstimate = buildSystemApplicationEstimate({
|
||
transportMode: fields.transportMode,
|
||
location: matchedCity || fields.location,
|
||
time: fields.time,
|
||
lodgingAmount: result?.hotel_amount,
|
||
allowanceAmount: result?.allowance_amount
|
||
})
|
||
const policyTransportEstimate = buildTransportEstimateFromPolicyResult(result, fields)
|
||
if (policyTransportEstimate) {
|
||
const lodging = parseApplicationEstimateMoney(result?.hotel_amount)
|
||
const allowance = parseApplicationEstimateMoney(result?.allowance_amount)
|
||
const backendTotal = parseApplicationEstimateMoney(result?.total_amount)
|
||
const totalAmount = backendTotal > 0
|
||
? backendTotal
|
||
: policyTransportEstimate.amount + lodging + allowance
|
||
systemEstimate = {
|
||
transportEstimate: policyTransportEstimate,
|
||
transportAmount: policyTransportEstimate.amount,
|
||
lodgingAmount: lodging,
|
||
allowanceAmount: allowance,
|
||
totalAmount,
|
||
transportAmountDisplay: policyTransportEstimate.amountDisplay,
|
||
lodgingAmountDisplay: formatApplicationEstimateMoney(lodging),
|
||
allowanceAmountDisplay: formatApplicationEstimateMoney(allowance),
|
||
totalAmountDisplay: formatApplicationEstimateMoney(totalAmount)
|
||
}
|
||
}
|
||
const transportEstimate = systemEstimate.transportEstimate
|
||
const transportText = transportEstimate
|
||
? `交通 ${systemEstimate.transportAmountDisplay}元 + `
|
||
: ''
|
||
const totalAmount = systemEstimate.totalAmountDisplay
|
||
const amount = totalAmount ? `${totalAmount}元` : fields.amount
|
||
|
||
return normalizeApplicationPreview({
|
||
...preview,
|
||
fields: {
|
||
...fields,
|
||
grade,
|
||
lodgingDailyCap: formatDailyPolicyMoney(result?.hotel_rate),
|
||
subsidyDailyCap: formatDailyPolicyMoney(result?.total_allowance_rate),
|
||
transportPolicy: buildTransportPolicyText(fields.transportMode, matchedCity || fields.location, transportEstimate, fields.time),
|
||
policyEstimate: `${transportText}住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${totalAmount}元(${days}天)`,
|
||
amount,
|
||
matchedCity,
|
||
ruleName: String(result?.rule_name || '').trim(),
|
||
ruleVersion: String(result?.rule_version || '').trim(),
|
||
hotelAmount: hotelAmount ? `${hotelAmount}元` : '',
|
||
allowanceAmount: allowanceAmount ? `${allowanceAmount}元` : '',
|
||
transportEstimatedAmount: systemEstimate.transportAmountDisplay ? `${systemEstimate.transportAmountDisplay}元` : '',
|
||
transportEstimateDate: transportEstimate?.queryDate || '',
|
||
transportQueryLatencyMs: transportEstimate?.simulatedLatencyMs ? `${transportEstimate.simulatedLatencyMs}ms` : '',
|
||
transportEstimateSource: transportEstimate?.source || '',
|
||
transportEstimateConfidence: transportEstimate?.confidence || '',
|
||
policyTotalAmount: totalAmount ? `${totalAmount}元` : ''
|
||
},
|
||
policyEstimate: {
|
||
...result,
|
||
grade,
|
||
matchedCity,
|
||
transport_estimate: transportEstimate,
|
||
system_total_amount: systemEstimate.totalAmount
|
||
},
|
||
policyEstimateStatus: 'completed'
|
||
})
|
||
}
|
||
|
||
export function refreshApplicationPreviewTransportEstimate(preview = {}) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const fields = { ...(normalized.fields || {}) }
|
||
const policyResult = normalized.policyEstimate && typeof normalized.policyEstimate === 'object'
|
||
? normalized.policyEstimate
|
||
: {}
|
||
const location = String(fields.matchedCity || policyResult.matched_city || fields.location || '').trim()
|
||
const hotelAmountSource = fields.hotelAmount || policyResult.hotel_amount || 0
|
||
const allowanceAmountSource = fields.allowanceAmount || policyResult.allowance_amount || 0
|
||
const systemEstimate = buildSystemApplicationEstimate({
|
||
transportMode: fields.transportMode,
|
||
location,
|
||
time: fields.time,
|
||
lodgingAmount: hotelAmountSource,
|
||
allowanceAmount: allowanceAmountSource
|
||
})
|
||
const transportEstimate = systemEstimate.transportEstimate
|
||
if (!transportEstimate) return normalized
|
||
|
||
const hotelAmount = formatPolicyMoney(hotelAmountSource)
|
||
const allowanceAmount = formatPolicyMoney(allowanceAmountSource)
|
||
const hasPolicyAmounts = parseMoneyNumber(hotelAmountSource) > 0 || parseMoneyNumber(allowanceAmountSource) > 0
|
||
const nextFields = {
|
||
...fields,
|
||
transportPolicy: buildTransportPolicyText(fields.transportMode, location, transportEstimate, fields.time),
|
||
transportEstimatedAmount: systemEstimate.transportAmountDisplay ? `${systemEstimate.transportAmountDisplay}元` : '',
|
||
transportEstimateDate: transportEstimate.queryDate || '',
|
||
transportQueryLatencyMs: transportEstimate.simulatedLatencyMs ? `${transportEstimate.simulatedLatencyMs}ms` : '',
|
||
transportEstimateSource: transportEstimate.source || '',
|
||
transportEstimateConfidence: transportEstimate.confidence || ''
|
||
}
|
||
|
||
if (hasPolicyAmounts) {
|
||
const days = Number(policyResult.days) || parseApplicationDaysValue(fields.days) || 1
|
||
const totalAmount = systemEstimate.totalAmountDisplay
|
||
nextFields.policyEstimate = `交通 ${systemEstimate.transportAmountDisplay}元 + 住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${totalAmount}元(${days}天)`
|
||
nextFields.amount = totalAmount ? `${totalAmount}元` : nextFields.amount
|
||
nextFields.policyTotalAmount = totalAmount ? `${totalAmount}元` : ''
|
||
}
|
||
|
||
return normalizeApplicationPreview({
|
||
...normalized,
|
||
fields: nextFields,
|
||
policyEstimate: {
|
||
...policyResult,
|
||
matchedCity: location,
|
||
transport_estimate: transportEstimate,
|
||
system_total_amount: systemEstimate.totalAmount
|
||
}
|
||
})
|
||
}
|
||
|
||
export function applyApplicationPolicyEstimateError(preview = {}, error = null, currentUser = {}) {
|
||
const fields = { ...(preview?.fields || {}) }
|
||
const message = String(error?.message || error || '').trim()
|
||
return normalizeApplicationPreview({
|
||
...preview,
|
||
fields: {
|
||
...fields,
|
||
grade: fields.grade || resolveCurrentUserGrade(currentUser),
|
||
transportPolicy: buildTransportPolicyText(fields.transportMode, fields.location, null, fields.time),
|
||
policyEstimate: message ? `规则中心暂未完成测算:${message}` : APPLICATION_POLICY_PENDING_TEXT
|
||
},
|
||
policyEstimateStatus: message ? 'failed' : 'pending'
|
||
})
|
||
}
|
||
|
||
export function shouldUseLocalApplicationPreview(rawText, options = {}) {
|
||
return evaluateLocalApplicationIntentGate(rawText, options).allowed
|
||
}
|
||
|
||
export function normalizeApplicationPreview(preview = {}) {
|
||
const fields = ensureApplicationPolicyFields(preview?.fields || {})
|
||
const missingFields = buildMissingFields(fields)
|
||
const validationIssues = [
|
||
...resolveApplicationValidationIssues(fields),
|
||
...resolveApplicationSourceValidationIssues(preview?.sourceText, fields, preview)
|
||
]
|
||
return {
|
||
...preview,
|
||
fields,
|
||
missingFields,
|
||
validationIssues,
|
||
readyToSubmit: missingFields.length === 0 && validationIssues.length === 0
|
||
}
|
||
}
|
||
|
||
export function applyApplicationBusinessTimeContext(preview = {}, businessTimeContext = null) {
|
||
if (!businessTimeContext || typeof businessTimeContext !== 'object') {
|
||
return normalizeApplicationPreview(preview)
|
||
}
|
||
|
||
const startDate = String(businessTimeContext.start_date || '').trim()
|
||
const endDate = String(businessTimeContext.end_date || startDate).trim()
|
||
const displayValue = String(
|
||
businessTimeContext.business_time ||
|
||
businessTimeContext.time_range ||
|
||
businessTimeContext.display_value ||
|
||
''
|
||
).trim()
|
||
const time = startDate && endDate
|
||
? (startDate === endDate ? startDate : `${startDate} 至 ${endDate}`)
|
||
: displayValue
|
||
if (!time) {
|
||
return normalizeApplicationPreview(preview)
|
||
}
|
||
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const fields = normalized.fields || {}
|
||
return normalizeApplicationPreview({
|
||
...normalized,
|
||
fields: {
|
||
...fields,
|
||
time,
|
||
days: resolveDaysFromDateRange(time) || fields.days
|
||
}
|
||
})
|
||
}
|
||
|
||
export function buildModelRefinedApplicationPreview(localPreview = {}, ontology = {}, rawText = '', currentUser = {}) {
|
||
const currentFields = localPreview?.fields || {}
|
||
const ontologyFields = buildApplicationFieldsFromOntology(ontology || {}, rawText, currentUser)
|
||
const parseStrategy = String(ontology?.parse_strategy || '').trim()
|
||
const refinedFields = {
|
||
...currentFields,
|
||
applicationType: normalizeApplicationTypeLabel(
|
||
ontologyFields.expenseTypeLabel,
|
||
currentFields.applicationType
|
||
),
|
||
time: resolveProvidedValue(ontologyFields.timeRange, currentFields.time),
|
||
location: resolveProvidedValue(ontologyFields.location, currentFields.location),
|
||
reason: resolveProvidedValue(ontologyFields.reason, currentFields.reason),
|
||
days: resolveProvidedValue(ontologyFields.days, currentFields.days),
|
||
transportMode: resolveModelRefinedTransportMode(ontologyFields, rawText, currentFields),
|
||
amount: normalizeAmountFromOntology(ontologyFields, currentFields.amount),
|
||
transportEstimatedAmount: normalizeTypedOntologyAmount(
|
||
ontologyFields.transportEstimatedAmount || ontologyFields.trainEstimatedAmount || ontologyFields.flightEstimatedAmount,
|
||
currentFields.transportEstimatedAmount
|
||
),
|
||
trainEstimatedAmount: normalizeTypedOntologyAmount(ontologyFields.trainEstimatedAmount, currentFields.trainEstimatedAmount),
|
||
flightEstimatedAmount: normalizeTypedOntologyAmount(ontologyFields.flightEstimatedAmount, currentFields.flightEstimatedAmount),
|
||
hotelAmount: normalizeTypedOntologyAmount(ontologyFields.hotelAmount, currentFields.hotelAmount),
|
||
allowanceAmount: normalizeTypedOntologyAmount(ontologyFields.allowanceAmount, currentFields.allowanceAmount),
|
||
policyTotalAmount: normalizeTypedOntologyAmount(ontologyFields.policyTotalAmount, currentFields.policyTotalAmount),
|
||
reimbursementAmount: normalizeTypedOntologyAmount(ontologyFields.reimbursementAmount, currentFields.reimbursementAmount),
|
||
grade: resolveProvidedValue(currentFields.grade, resolveCurrentUserGrade(currentUser)),
|
||
applicant: resolveProvidedValue(ontologyFields.applicant, currentFields.applicant),
|
||
department: resolveProvidedValue(ontologyFields.department, currentFields.department || resolveCurrentUserDepartment(currentUser)),
|
||
position: resolveProvidedValue(currentFields.position, resolveCurrentUserPosition(currentUser)),
|
||
managerName: resolveProvidedValue(
|
||
ontologyFields.managerName,
|
||
currentFields.managerName || resolveCurrentUserManagerName(currentUser)
|
||
)
|
||
}
|
||
|
||
return normalizeApplicationPreview({
|
||
...localPreview,
|
||
sourceText: String(rawText || localPreview.sourceText || '').trim(),
|
||
fields: refinedFields,
|
||
modelRefined: true,
|
||
parseStrategy,
|
||
modelReviewStatus: parseStrategy === 'llm_primary' ? 'completed' : 'fallback'
|
||
})
|
||
}
|
||
|
||
export function buildApplicationPreviewRows(preview = {}) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const fields = normalized.fields || {}
|
||
return APPLICATION_PREVIEW_FIELD_DEFINITIONS.flatMap((item) => {
|
||
if (item.key === 'time' && isTravelApplicationType(fields.applicationType)) {
|
||
const tripDates = resolveApplicationTripDateParts(fields)
|
||
const rawValue = fields[item.key]
|
||
const missing = item.required !== false && !isApplicationPreviewValueProvided(rawValue)
|
||
return [
|
||
{
|
||
...item,
|
||
label: '出发时间',
|
||
value: tripDates.startDate || '待补充',
|
||
editable: item.editable !== false,
|
||
highlight: Boolean(item.highlight),
|
||
missing
|
||
},
|
||
{
|
||
key: 'time_return',
|
||
label: '返回时间',
|
||
value: tripDates.endDate || '待补充',
|
||
editable: false,
|
||
highlight: Boolean(item.highlight),
|
||
missing
|
||
}
|
||
]
|
||
}
|
||
|
||
const rawValue = fields[item.key]
|
||
const value = String(rawValue || '').trim() || '待补充'
|
||
return [{
|
||
...item,
|
||
label: resolveApplicationFieldLabel(item, fields),
|
||
value,
|
||
editable: item.editable !== false,
|
||
highlight: Boolean(item.highlight),
|
||
missing: item.required !== false && !isApplicationPreviewValueProvided(rawValue)
|
||
}]
|
||
})
|
||
}
|
||
|
||
export function buildApplicationPreviewSubmitText(preview = {}) {
|
||
const rows = buildApplicationPreviewRows(preview)
|
||
return [
|
||
'费用申请确认提交',
|
||
...rows.map((row) => `${row.label}:${row.value}`),
|
||
'',
|
||
'确认提交'
|
||
].join('\n')
|
||
}
|
||
|
||
export function buildLocalApplicationPreview(rawText, currentUser = {}, options = {}) {
|
||
const sourceText = String(rawText || '').trim()
|
||
const explicitDays = resolveApplicationDays(sourceText)
|
||
const time = resolveApplicationTimeWithDefault(sourceText, explicitDays, options)
|
||
const days = explicitDays || resolveDaysFromDateRange(time)
|
||
const location = resolveApplicationLocation(sourceText)
|
||
const fields = {
|
||
applicationType: resolveApplicationType(sourceText),
|
||
time,
|
||
location,
|
||
reason: resolveApplicationReason(sourceText, { location }),
|
||
days,
|
||
transportMode: resolveApplicationTransportMode(sourceText),
|
||
amount: resolveApplicationAmount(sourceText),
|
||
grade: resolveCurrentUserGrade(currentUser),
|
||
applicant: currentUser.name || currentUser.username || '当前用户',
|
||
department: resolveCurrentUserDepartment(currentUser) || '待补充',
|
||
position: resolveCurrentUserPosition(currentUser) || '待补充',
|
||
managerName: resolveCurrentUserManagerName(currentUser) || '待补充'
|
||
}
|
||
|
||
return normalizeApplicationPreview({
|
||
sourceText,
|
||
fields,
|
||
modelReviewStatus: 'local'
|
||
})
|
||
}
|
||
|
||
export function buildApplicationTemplatePreview(currentUser = {}) {
|
||
return normalizeApplicationPreview({
|
||
sourceText: '快速发起申请',
|
||
fields: {
|
||
applicationType: '费用申请',
|
||
time: '',
|
||
location: '',
|
||
reason: '',
|
||
days: '',
|
||
transportMode: '',
|
||
amount: '',
|
||
grade: resolveCurrentUserGrade(currentUser),
|
||
applicant: currentUser.name || currentUser.username || '当前用户',
|
||
department: resolveCurrentUserDepartment(currentUser) || '待补充',
|
||
position: resolveCurrentUserPosition(currentUser) || '待补充',
|
||
managerName: resolveCurrentUserManagerName(currentUser) || '待补充'
|
||
},
|
||
modelReviewStatus: 'template'
|
||
})
|
||
}
|
||
|
||
export function buildLocalApplicationPreviewMessage(preview) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const modelReviewStatus = String(normalized.modelReviewStatus || '').trim()
|
||
return [
|
||
modelReviewStatus === 'completed'
|
||
? '我已完成模型复核,并整理成下方表格。请核查识别结果;点击对应行即可直接编辑。'
|
||
: modelReviewStatus === 'fallback'
|
||
? '模型复核没有返回稳定结果,我已先按规则兜底整理成下方表格。请重点核查识别结果;点击对应行即可直接编辑。'
|
||
: modelReviewStatus === 'failed'
|
||
? '模型复核暂时失败,我先保留一份临时核对表,方便您核查和补充信息。点击对应行即可直接编辑。'
|
||
: modelReviewStatus === 'template'
|
||
? '我已为你准备好费用申请模板。本步骤不调用大模型,也不会保存草稿;请点击对应行直接填写。'
|
||
: '我先整理出下方表格,请核查识别结果。点击对应行即可直接编辑。'
|
||
].join('\n')
|
||
}
|
||
|
||
export function buildApplicationPreviewFooterMessage(preview) {
|
||
const normalized = normalizeApplicationPreview(preview)
|
||
const missingFields = Array.isArray(normalized.missingFields) ? normalized.missingFields : []
|
||
const validationIssues = Array.isArray(normalized.validationIssues) ? normalized.validationIssues : []
|
||
if (validationIssues.length) {
|
||
return `${validationIssues[0].message} 请先修正后再提交申请。`
|
||
}
|
||
if (missingFields.length) {
|
||
return `当前还需要补充:${missingFields.join('、')}。补齐后我再帮您提交申请。`
|
||
}
|
||
|
||
return '请确认上述的信息是否填写正确?如果准确无误,点击 [确认](#application-submit) 进入审批环节。'
|
||
}
|