120 lines
4.4 KiB
JavaScript
120 lines
4.4 KiB
JavaScript
|
|
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')
|
|||
|
|
}
|
|||
|
|
|