Files
X-Financial/web/src/views/scripts/travelReimbursementGuidedFlowModel.js

622 lines
26 KiB
JavaScript
Raw Normal View History

export const GUIDED_FLOW_MODE_NONE = ''
export const GUIDED_FLOW_MODE_REIMBURSEMENT = 'reimbursement_guide'
export const GUIDED_FLOW_MODE_STATUS_QUERY = 'status_query_guide'
export const GUIDED_ACTION_START_REIMBURSEMENT = 'start_guided_reimbursement'
export const GUIDED_ACTION_START_APPLICATION = 'start_guided_application'
export const GUIDED_ACTION_START_STATUS_QUERY = 'start_guided_status_query'
export const GUIDED_ACTION_OPEN_TRAVEL_CALCULATOR = 'open_travel_calculator'
export const GUIDED_ACTION_SELECT_EXPENSE_TYPE = 'guided_select_expense_type'
export const GUIDED_ACTION_SELECT_REQUIRED_APPLICATION = 'guided_select_required_application'
export const GUIDED_ACTION_CONFIRM_REIMBURSEMENT_REVIEW = 'guided_confirm_reimbursement_review'
export const GUIDED_ACTION_CONTINUE_FILLING = 'guided_continue_filling'
export const GUIDED_ACTION_PROCESS_INTERRUPTION = 'guided_process_interruption'
export const GUIDED_ACTION_SELECT_QUERY_MODE = 'guided_select_query_mode'
export const GUIDED_ACTION_SELECT_QUERY_STATUS = 'guided_select_query_status'
export const GUIDED_EXPENSE_TYPES = [
{ key: 'travel', label: '差旅费', description: '出差、跨城交通、住宿和补贴', icon: 'mdi mdi-bag-suitcase-outline' },
{ key: 'transport', label: '交通费', description: '市内交通、打车、停车和通行费', icon: 'mdi mdi-car-outline' },
{ key: 'hotel', label: '住宿费', description: '单独住宿或酒店票据', icon: 'mdi mdi-bed-outline' },
{ key: 'meal', label: '业务招待费', description: '客户接待、餐饮和工作招待', icon: 'mdi mdi-food-fork-drink' },
{ key: 'office', label: '办公用品费', description: '办公用品、文具和低值易耗品', icon: 'mdi mdi-briefcase-outline' },
{ key: 'other', label: '其他费用', description: '暂不属于以上类型的费用', icon: 'mdi mdi-dots-horizontal-circle-outline' }
]
const GUIDED_REIMBURSEMENT_STEPS = {
travel: [
{ key: 'reason', summaryLabel: '事由', prompt: '请先告诉我本次出差事由,例如:去上海支持项目部署。' },
{ key: 'location', summaryLabel: '出差地点', prompt: '本次出差地点是哪里?可以回复城市或具体客户地点。' },
{ key: 'time_range', summaryLabel: '出差时间/天数', prompt: '请补充出差时间或天数例如2026-05-20 至 2026-05-23出差 3 天。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充本次预计或实际报销金额。如果还没有汇总,可以回复“待核算”。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '票据可以现在上传,也可以回复“稍后上传”。上传后我会在生成核对信息时一起处理。' }
],
transport: [
{ key: 'reason', summaryLabel: '出行事由', prompt: '请说明本次交通费事由,例如:送客户去机场。' },
{ key: 'time_range', summaryLabel: '出行时间', prompt: '请补充出行时间例如2026-05-20 下午。' },
{ key: 'location', summaryLabel: '路线/地点', prompt: '请补充出行路线或地点,例如:公司至机场。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充交通费金额。如果票据里再识别金额,可以回复“以票据为准”。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '请上传出租车、网约车、停车或通行费等票据;也可以回复“稍后上传”。' }
],
hotel: [
{ key: 'reason', summaryLabel: '住宿事由', prompt: '请说明住宿事由,例如:项目现场支持期间住宿。' },
{ key: 'location', summaryLabel: '城市/酒店地点', prompt: '住宿城市或酒店地点是哪里?' },
{ key: 'time_range', summaryLabel: '入住离店时间', prompt: '请补充入住和离店时间例如2026-05-20 至 2026-05-23。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充住宿金额。如果还没有汇总,可以回复“待核算”。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '请上传酒店发票或住宿水单;也可以回复“稍后上传”。' }
],
meal: [
{ key: 'customer_name', summaryLabel: '客户单位', prompt: '请补充客户单位或接待对象。' },
{ key: 'participants', summaryLabel: '参与人员', prompt: '请补充参与人员,例如:客户 2 人,我方 1 人。' },
{ key: 'time_range', summaryLabel: '招待时间', prompt: '请补充招待时间例如2026-05-20 晚。' },
{ key: 'location', summaryLabel: '招待地点', prompt: '请补充招待地点或商户名称。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充招待金额。' },
{ key: 'reason', summaryLabel: '事由', prompt: '请补充招待事由,例如:项目沟通或客户接待。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '请上传餐饮发票或相关凭证;也可以回复“稍后上传”。' }
],
office: [
{ key: 'reason', summaryLabel: '采购用途', prompt: '请说明采购用途,例如:项目现场临时采购办公用品。' },
{ key: 'location', summaryLabel: '商户/采购地点', prompt: '请补充商户或采购地点。' },
{ key: 'time_range', summaryLabel: '发生时间', prompt: '请补充费用发生时间。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充办公用品金额。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '请上传办公用品发票或购物凭证;也可以回复“稍后上传”。' }
],
other: [
{ key: 'reason', summaryLabel: '费用说明', prompt: '请说明这笔费用的具体内容和用途。' },
{ key: 'time_range', summaryLabel: '发生时间', prompt: '请补充费用发生时间。' },
{ key: 'location', summaryLabel: '地点/对象', prompt: '请补充费用发生地点或关联对象。' },
{ key: 'amount', summaryLabel: '金额', prompt: '请补充费用金额。' },
{ key: 'attachments', summaryLabel: '票据', prompt: '请上传相关票据;也可以回复“稍后上传”。' }
]
}
export const GUIDED_QUERY_MODES = [
{ key: 'claim_no', label: '按单号', description: '输入报销单号精准查询', icon: 'mdi mdi-pound' },
{ key: 'status', label: '按状态', description: '查询草稿、审批中或已归档单据', icon: 'mdi mdi-list-status' },
{ key: 'time_range', label: '按时间范围', description: '例如上周、去年、2026-05', icon: 'mdi mdi-calendar-search-outline' },
{ key: 'keyword', label: '按地点/事由', description: '例如北京、上海电力、服务器部署', icon: 'mdi mdi-map-search-outline' }
]
export const GUIDED_QUERY_STATUS_OPTIONS = [
{ key: 'draft', label: '草稿', description: '还没有正式提交的单据' },
{ key: 'pending', label: '审批中', description: '正在流转审批的单据' },
{ key: 'returned', label: '已退回', description: '需要补充或修改的单据' },
{ key: 'archived', label: '已归档', description: '已完成归档的单据' },
{ key: 'completed', label: '已完成', description: '已审核完成或已付款的单据' }
]
const NO_ATTACHMENT_TEXT_PATTERN = /^(稍后|暂不|不用|没有|待上传|后面|后续|先不|以票据为准)/u
const INTERRUPTION_PATTERN = /(查一下|查询|状态|报销了吗|报销了么|多少|总额|标准|制度|规则|为什么|怎么|可以吗|能不能|差旅计算器|计算一下|解释|风险|打开|跳转|查看|审批|归档|入账|[?])/u
function uniqueValues(values) {
return Array.from(new Set((Array.isArray(values) ? values : []).map((item) => String(item || '').trim()).filter(Boolean)))
}
function normalizeText(value) {
return String(value || '').trim()
}
function normalizeValues(values) {
if (!values || typeof values !== 'object') {
return {}
}
return Object.entries(values).reduce((result, [key, value]) => {
if (key === 'attachment_names') {
result[key] = uniqueValues(value)
return result
}
result[key] = normalizeText(value)
return result
}, {})
}
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 []
}
return applications
.map((item) => (item && typeof item === 'object' ? item : null))
.filter(Boolean)
.map((item) => ({
id: normalizeText(item.id || item.application_claim_id),
claim_no: normalizeText(item.claim_no || item.application_claim_no),
expense_type: normalizeText(item.expense_type || item.application_expense_type),
reason: normalizeText(item.reason || item.application_reason),
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)
}))
.filter((item) => item.id || item.claim_no)
}
export function createEmptyGuidedFlowState() {
return {
mode: GUIDED_FLOW_MODE_NONE,
stepKey: '',
expenseType: '',
values: {},
pendingInterruptionText: '',
applicationCandidates: []
}
}
export function normalizeGuidedFlowState(state) {
const source = state && typeof state === 'object' ? state : {}
const mode = normalizeText(source.mode)
const supportedMode = [GUIDED_FLOW_MODE_REIMBURSEMENT, GUIDED_FLOW_MODE_STATUS_QUERY].includes(mode)
? mode
: GUIDED_FLOW_MODE_NONE
if (!supportedMode) {
return createEmptyGuidedFlowState()
}
return {
mode: supportedMode,
stepKey: normalizeText(source.stepKey),
expenseType: normalizeText(source.expenseType),
values: normalizeValues(source.values),
pendingInterruptionText: normalizeText(source.pendingInterruptionText),
applicationCandidates: normalizeApplicationCandidates(source.applicationCandidates)
}
}
export function isGuidedFlowActive(state) {
return Boolean(normalizeGuidedFlowState(state).mode)
}
export function getGuidedExpenseType(expenseType) {
const key = normalizeText(expenseType)
return GUIDED_EXPENSE_TYPES.find((item) => item.key === key) || null
}
export function getGuidedExpenseTypeLabel(expenseType) {
return getGuidedExpenseType(expenseType)?.label || ''
}
export function buildGuidedExpenseTypeActions() {
return GUIDED_EXPENSE_TYPES.map((option) => ({
label: option.label,
description: option.description,
icon: option.icon,
action_type: GUIDED_ACTION_SELECT_EXPENSE_TYPE,
payload: {
expense_type: option.key,
expense_type_label: option.label
}
}))
}
export function buildGuidedReimbursementStartText() {
return [
'请问你要报销的类型?',
'',
'先选一个最贴近的费用场景,我会按对应流程逐项询问。这个过程只做本地引导,不会自动创建草稿。'
].join('\n')
}
export function createGuidedReimbursementState() {
return {
...createEmptyGuidedFlowState(),
mode: GUIDED_FLOW_MODE_REIMBURSEMENT,
stepKey: 'expense_type'
}
}
export function selectGuidedExpenseType(state, expenseType) {
const type = getGuidedExpenseType(expenseType)
if (!type) {
return normalizeGuidedFlowState(state)
}
const steps = GUIDED_REIMBURSEMENT_STEPS[type.key] || []
return {
...normalizeGuidedFlowState(state),
mode: GUIDED_FLOW_MODE_REIMBURSEMENT,
expenseType: type.key,
stepKey: steps[0]?.key || 'summary',
pendingInterruptionText: '',
applicationCandidates: []
}
}
export function waitForGuidedApplicationSelection(state, expenseType, applications = []) {
const type = getGuidedExpenseType(expenseType)
if (!type) {
return normalizeGuidedFlowState(state)
}
return {
...normalizeGuidedFlowState(state),
mode: GUIDED_FLOW_MODE_REIMBURSEMENT,
expenseType: type.key,
stepKey: 'application_selection',
pendingInterruptionText: '',
applicationCandidates: normalizeApplicationCandidates(applications)
}
}
export function selectGuidedRequiredApplication(state, application = {}) {
const current = normalizeGuidedFlowState(state)
return {
...current,
values: normalizeValues({
...current.values,
application_claim_id: application.application_claim_id || application.id || '',
application_claim_no: application.application_claim_no || application.claim_no || '',
application_reason: application.application_reason || application.reason || '',
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_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: 'summary',
pendingInterruptionText: '',
applicationCandidates: []
}
}
export function getGuidedReimbursementSteps(expenseType) {
const key = normalizeText(expenseType)
return GUIDED_REIMBURSEMENT_STEPS[key] || []
}
export function getCurrentGuidedStep(state) {
const current = normalizeGuidedFlowState(state)
if (current.mode !== GUIDED_FLOW_MODE_REIMBURSEMENT || !current.expenseType) {
return null
}
return getGuidedReimbursementSteps(current.expenseType).find((step) => step.key === current.stepKey) || null
}
export function buildGuidedStepPromptText(state) {
const current = normalizeGuidedFlowState(state)
const step = getCurrentGuidedStep(current)
const typeLabel = getGuidedExpenseTypeLabel(current.expenseType)
if (!step || !typeLabel) {
return buildGuidedReimbursementStartText()
}
const steps = getGuidedReimbursementSteps(current.expenseType)
const stepIndex = Math.max(0, steps.findIndex((item) => item.key === step.key))
return [
`已选择“${typeLabel}”。`,
'',
`${stepIndex + 1} 步:${step.summaryLabel}`,
step.prompt,
'',
'直接回复这一项即可。'
].join('\n')
}
export function resolveGuidedExpenseTypeFromText(text) {
const normalized = normalizeText(text)
if (!normalized) {
return ''
}
const exact = GUIDED_EXPENSE_TYPES.find((item) => normalized === item.label || normalized === item.key)
if (exact) {
return exact.key
}
const matched = GUIDED_EXPENSE_TYPES.find((item) => normalized.includes(item.label))
return matched?.key || ''
}
export function applyGuidedReimbursementAnswer(state, answerText, attachmentNames = []) {
const current = normalizeGuidedFlowState(state)
const step = getCurrentGuidedStep(current)
if (!step) {
return current
}
const answer = normalizeText(answerText)
const nextValues = { ...current.values }
if (step.key === 'attachments') {
const nextAttachmentNames = uniqueValues([
...(Array.isArray(nextValues.attachment_names) ? nextValues.attachment_names : []),
...attachmentNames
])
if (nextAttachmentNames.length) {
nextValues.attachment_names = nextAttachmentNames
}
nextValues.attachments = answer || (nextAttachmentNames.length ? `已选择 ${nextAttachmentNames.length} 份附件` : '稍后上传')
} else {
nextValues[step.key] = answer
}
const steps = getGuidedReimbursementSteps(current.expenseType)
const currentIndex = steps.findIndex((item) => item.key === step.key)
const nextStep = steps[currentIndex + 1]
return {
...current,
values: normalizeValues(nextValues),
stepKey: nextStep?.key || 'summary',
pendingInterruptionText: ''
}
}
export function isGuidedReimbursementReadyForReview(state) {
const current = normalizeGuidedFlowState(state)
return current.mode === GUIDED_FLOW_MODE_REIMBURSEMENT
&& Boolean(current.expenseType)
&& current.stepKey === 'summary'
}
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 (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 || '待补充'}`)
})
}
lines.push('')
lines.push(
linkedApplication
? '如果关联信息无误,我可以直接生成报销草稿;后续由你在草稿详情中上传和归集票据。'
: '如果这些信息无误,我可以继续生成报销草稿;草稿生成后可继续上传票据或补充信息。'
)
return lines.join('\n')
}
export function buildGuidedReviewConfirmationActions() {
return [{
label: '生成报销草稿',
description: '使用当前信息生成草稿,票据可在草稿详情继续上传',
icon: 'mdi mdi-clipboard-check-outline',
action_type: GUIDED_ACTION_CONFIRM_REIMBURSEMENT_REVIEW
}]
}
export function buildGuidedReviewSubmitOptions(state, files = []) {
const current = normalizeGuidedFlowState(state)
const type = getGuidedExpenseType(current.expenseType)
const values = current.values || {}
const typeLabel = type?.label || '其他费用'
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}`,
...fieldLines
].join('\n')
const reviewFormValues = {
expense_type: typeLabel,
reimbursement_type: typeLabel,
reason: values.reason || applicationReason || values.customer_name || '',
reason_value: values.reason || applicationReason || '',
customer_name: values.customer_name || '',
participants: values.participants || '',
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_label: values.application_amount_label || '',
application_business_time: values.application_business_time || '',
application_date: values.application_date || ''
}
return {
rawText,
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',
expense_type_label: typeLabel,
original_message: rawText,
application_claim_id: values.application_claim_id || '',
application_claim_no: values.application_claim_no || ''
},
review_form_values: reviewFormValues
}
}
}
export function shouldConfirmGuidedInterruption(text, state) {
const current = normalizeGuidedFlowState(state)
if (!current.mode || current.pendingInterruptionText) {
return false
}
const normalized = normalizeText(text)
if (!normalized || NO_ATTACHMENT_TEXT_PATTERN.test(normalized)) {
return false
}
return INTERRUPTION_PATTERN.test(normalized)
}
export function buildGuidedInterruptionText(text) {
return [
`我看到你刚才输入的是:“${normalizeText(text)}”。`,
'',
'这看起来像一个新的问题。你想继续填写当前引导,还是先暂停当前引导并处理这个问题?'
].join('\n')
}
export function buildGuidedInterruptionActions() {
return [
{
label: '继续填写',
description: '保留当前引导,继续回答这一项',
icon: 'mdi mdi-pencil-outline',
action_type: GUIDED_ACTION_CONTINUE_FILLING
},
{
label: '暂停当前引导并处理这个问题',
description: '暂停引导,把刚才输入交给财务助手处理',
icon: 'mdi mdi-chat-processing-outline',
action_type: GUIDED_ACTION_PROCESS_INTERRUPTION
}
]
}
export function createGuidedStatusQueryState() {
return {
...createEmptyGuidedFlowState(),
mode: GUIDED_FLOW_MODE_STATUS_QUERY,
stepKey: 'query_mode'
}
}
export function buildGuidedStatusQueryStartText() {
return [
'你想按什么条件查询单据状态?',
'',
'先选查询方式,我再向你收集对应条件。'
].join('\n')
}
export function buildGuidedQueryModeActions() {
return GUIDED_QUERY_MODES.map((option) => ({
label: option.label,
description: option.description,
icon: option.icon,
action_type: GUIDED_ACTION_SELECT_QUERY_MODE,
payload: {
query_mode: option.key,
query_mode_label: option.label
}
}))
}
export function buildGuidedQueryStatusActions() {
return GUIDED_QUERY_STATUS_OPTIONS.map((option) => ({
label: option.label,
description: option.description,
icon: 'mdi mdi-checkbox-marked-circle-outline',
action_type: GUIDED_ACTION_SELECT_QUERY_STATUS,
payload: {
query_status: option.key,
query_status_label: option.label
}
}))
}
export function resolveGuidedQueryModeFromText(text) {
const normalized = normalizeText(text)
if (!normalized) return ''
const exact = GUIDED_QUERY_MODES.find((item) => normalized === item.label || normalized === item.key)
if (exact) return exact.key
if (/单号|编号|EXP-|APP-|AP-|RE-|AD-/i.test(normalized)) return 'claim_no'
if (/状态|草稿|审批|退回|归档|完成/.test(normalized)) return 'status'
if (/上周|本周|去年|今年|月份|时间|日期|[0-9]{4}-[0-9]{2}/.test(normalized)) return 'time_range'
return 'keyword'
}
export function selectGuidedQueryMode(state, queryMode) {
const current = normalizeGuidedFlowState(state)
const mode = GUIDED_QUERY_MODES.find((item) => item.key === normalizeText(queryMode))
if (!mode) {
return current
}
return {
...current,
mode: GUIDED_FLOW_MODE_STATUS_QUERY,
stepKey: mode.key === 'status' ? 'status_value' : 'query_value',
values: {
...current.values,
query_mode: mode.key,
query_mode_label: mode.label
},
pendingInterruptionText: ''
}
}
export function buildGuidedQueryPromptText(state) {
const current = normalizeGuidedFlowState(state)
const mode = normalizeText(current.values.query_mode)
if (!mode) {
return buildGuidedStatusQueryStartText()
}
if (mode === 'status') {
return [
'请选择要查询的单据状态。',
'',
'我会按所选状态筛选最近的报销单据。'
].join('\n')
}
const prompts = {
claim_no: '请输入单据编号,例如 RE-20260525103045-ABCDEFGH。',
time_range: '请输入查询时间范围,例如:上周、今年 5 月、2025 年全年。',
keyword: '请输入地点、客户或事由关键词,例如:上海电力、北京、服务器部署。'
}
return prompts[mode] || '请补充查询条件。'
}
export function buildGuidedStatusQueryText(state, valueText) {
const current = normalizeGuidedFlowState(state)
const mode = normalizeText(current.values.query_mode)
const value = normalizeText(valueText)
if (mode === 'claim_no') {
return `帮我查询单号 ${value} 的报销单状态`
}
if (mode === 'status') {
return `帮我查询${value}的报销单据,筛选最近的 5 条记录`
}
if (mode === 'time_range') {
return `帮我查询${value}提交或发生的报销单据状态,筛选最近的 5 条记录`
}
return `帮我查询地点或事由包含“${value}”的报销单据状态,筛选最近的 5 条记录`
}