From 92198549f6738f86f6060070f47b33e9be62f7d4 Mon Sep 17 00:00:00 2001 From: caoxiaozhu Date: Wed, 3 Jun 2026 16:36:02 +0800 Subject: [PATCH] fix: require explicit transport mode for applications --- web/src/utils/expenseApplicationPreview.js | 21 +++++++++--- .../expense-application-fast-preview.test.mjs | 33 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/web/src/utils/expenseApplicationPreview.js b/web/src/utils/expenseApplicationPreview.js index abd5e1b..ef24c27 100644 --- a/web/src/utils/expenseApplicationPreview.js +++ b/web/src/utils/expenseApplicationPreview.js @@ -400,6 +400,22 @@ function normalizeTransportModeOption(value, fallback = '') { return APPLICATION_TRANSPORT_MODE_OPTIONS.includes(text) ? text : fallback } +function resolveModelRefinedTransportMode(ontologyFields = {}, rawText = '', currentFields = {}) { + const currentTransportMode = isApplicationPreviewValueProvided(currentFields.transportMode) + ? String(currentFields.transportMode).trim() + : '' + const explicitTransportMode = resolveApplicationTransportMode(rawText) + if (!explicitTransportMode) { + return currentTransportMode + } + + const ontologyTransportMode = normalizeTransportModeOption(ontologyFields.transportMode, '') + if (ontologyTransportMode && ontologyTransportMode === explicitTransportMode) { + return ontologyTransportMode + } + return currentTransportMode || explicitTransportMode +} + function normalizeAmountFromOntology(fields = {}, fallback = '') { const numericAmount = Number(fields.amount || 0) if (Number.isFinite(numericAmount) && numericAmount > 0) { @@ -640,10 +656,7 @@ export function buildModelRefinedApplicationPreview(localPreview = {}, ontology location: resolveProvidedValue(ontologyFields.location, currentFields.location), reason: resolveProvidedValue(ontologyFields.reason, currentFields.reason), days: resolveProvidedValue(ontologyFields.days, currentFields.days), - transportMode: normalizeTransportModeOption( - ontologyFields.transportMode, - currentFields.transportMode - ), + transportMode: resolveModelRefinedTransportMode(ontologyFields, rawText, currentFields), amount: normalizeAmountFromOntology(ontologyFields, currentFields.amount), grade: resolveProvidedValue(currentFields.grade, resolveCurrentUserGrade(currentUser)), applicant: resolveProvidedValue(ontologyFields.applicant, currentFields.applicant), diff --git a/web/tests/expense-application-fast-preview.test.mjs b/web/tests/expense-application-fast-preview.test.mjs index 40f4553..1212106 100644 --- a/web/tests/expense-application-fast-preview.test.mjs +++ b/web/tests/expense-application-fast-preview.test.mjs @@ -366,6 +366,39 @@ test('application preview can be refined by ontology model extraction', () => { assert.equal(refinedPreview.fields.transportMode, '火车') }) +test('application preview ignores model-only transport mode guesses', () => { + const rawText = '\u7533\u8bf7 2026-05-25 \u81f3 2026-05-27 \u53bb\u4e0a\u6d77\u51fa\u5dee3\u5929\uff0c\u670d\u52a1\u9879\u76ee\u90e8\u7f72\uff0c\u9884\u8ba1\u8d39\u75281800\u5143' + const localPreview = buildLocalApplicationPreview(rawText, { + name: '\u674e\u6587\u9759', + grade: 'P5' + }) + const refinedPreview = buildModelRefinedApplicationPreview( + localPreview, + { + parse_strategy: 'llm_primary', + entities: [ + { type: 'expense_type', value: '\u5dee\u65c5\u8d39', normalized_value: 'travel' }, + { type: 'location', value: '\u4e0a\u6d77', normalized_value: '\u4e0a\u6d77' }, + { type: 'reason', value: '\u670d\u52a1\u9879\u76ee\u90e8\u7f72', normalized_value: '\u670d\u52a1\u9879\u76ee\u90e8\u7f72' }, + { type: 'transport_mode', value: '\u706b\u8f66', normalized_value: '\u706b\u8f66' }, + { type: 'amount', value: '1800\u5143', normalized_value: '1800' } + ], + time_range: { + start: '2026-05-25', + end: '2026-05-27' + }, + missing_slots: [] + }, + rawText, + { name: '\u674e\u6587\u9759', grade: 'P5' } + ) + + assert.equal(localPreview.fields.transportMode, '') + assert.equal(refinedPreview.fields.transportMode, '') + assert.ok(refinedPreview.missingFields.includes('\u51fa\u884c\u65b9\u5f0f')) + assert.equal(refinedPreview.readyToSubmit, false) +}) + test('application preview precomputes a date range from today when only days are provided', () => { const preview = buildLocalApplicationPreview( '去北京出差3天,支撑国网仿生产环境部署,飞机,预计费用12000元',