export const TRAVEL_PLANNING_ACTION_GENERATE = 'generate_travel_application_plan' export const TRAVEL_PLANNING_ACTION_SKIP = 'skip_travel_application_plan' function normalizeText(value) { return String(value || '').trim() } function isTravelApplication(applicationType = '') { return /差旅|出差/.test(normalizeText(applicationType)) } function extractDateParts(timeText = '') { const dates = normalizeText(timeText).match(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/g) || [] return { startDate: dates[0] || '', endDate: dates[dates.length - 1] || dates[0] || '' } } function resolveTravelPlanningContext(preview = {}, draftPayload = {}) { const fields = preview?.fields && typeof preview.fields === 'object' ? preview.fields : {} const applicationType = normalizeText(fields.applicationType) if (!isTravelApplication(applicationType)) { return null } const location = normalizeText(fields.location) const time = normalizeText(fields.time) if (!location || !time) { return null } const dates = extractDateParts(time) return { applicationType, location, time, startDate: dates.startDate, endDate: dates.endDate, days: normalizeText(fields.days), transportMode: normalizeText(fields.transportMode), reason: normalizeText(fields.reason), claimNo: normalizeText(draftPayload?.claim_no || draftPayload?.claimNo) } } export function buildTravelPlanningNudgeMessage(preview = {}, draftPayload = {}) { const context = resolveTravelPlanningContext(preview, draftPayload) if (!context) { return '' } const timeCopy = context.startDate && context.endDate && context.startDate !== context.endDate ? `${context.startDate} 至 ${context.endDate}` : context.time const transportCopy = context.transportMode ? `、${context.transportMode}时间窗口` : '、交通方式比选' return [ `本次${context.location}差旅申请已经提交。`, `如果您愿意,我可以继续按 ${timeCopy} 帮您整理一版行程规划,包括出发/返程${transportCopy}、酒店区域建议,以及还需要确认的事项。` ].join('\n') } export function buildTravelPlanningSuggestedActions(preview = {}, draftPayload = {}) { const context = resolveTravelPlanningContext(preview, draftPayload) if (!context) { return [] } return [ { label: '生成行程规划', action_type: TRAVEL_PLANNING_ACTION_GENERATE, description: '按本次申请的地点和时间给出交通、酒店和待确认事项。', icon: 'mdi mdi-map-clock-outline', emphasis: 'primary', payload: { context } }, { label: '暂不需要', action_type: TRAVEL_PLANNING_ACTION_SKIP, description: '保留申请结果,不继续生成规划。', icon: 'mdi mdi-check-outline', payload: { context } } ] } export function buildTravelPlanningRecommendation(preview = {}, draftPayload = {}) { const context = resolveTravelPlanningContext(preview, draftPayload) if (!context) { return '' } const outboundDate = context.startDate || '出发当天' const returnDate = context.endDate || '返回当天' const transport = context.transportMode || '火车/飞机' const reasonLine = context.reason ? `业务安排:${context.reason}` : '业务安排:以申请事由为准,出发前再确认具体到场时间。' const hotelArea = `${context.location}核心办公区、客户现场周边或交通枢纽 30 分钟通勤范围内` const claimLine = context.claimNo ? `关联申请单:${context.claimNo}` : '' return [ '可以,先给您一版轻量行程规划,后续您可以继续补充偏好。', '', claimLine, `行程时间:${context.time}${context.days ? `(${context.days})` : ''}`, reasonLine, '', `交通建议:${outboundDate} 优先看上午到中午抵达 ${context.location} 的${transport}班次,预留到达后 1.5 小时交通和现场准备时间;${returnDate} 优先看下午或晚间返程,避免压缩最后一天工作安排。`, `酒店建议:优先选择${hotelArea},同时关注可开发票、可取消、早餐和离现场距离。`, '需要确认:出发城市、客户现场地址、是否需要同行人、是否有指定住宿协议酒店、是否需要提前准备会议室或网络环境。', '', '您也可以继续告诉我出发城市、偏好的交通方式或预算,我再把规划细化成更具体的时间段。' ].filter(Boolean).join('\n') }