feat(reservation): solidify booking email v0.1 intake
This commit is contained in:
1 parent
9f29b59c26
commit
d91cd717df
61 files changed
+13961
-377
No files matched your search
@@ -0,0 +1,951 @@
|
||||
export type PrototypeTaskKind =
|
||||
| 'new'
|
||||
| 'update'
|
||||
| 'cancel'
|
||||
| 'trace'
|
||||
| 'rooming-list'
|
||||
| 'payment'
|
||||
| 'risk'
|
||||
| 'general'
|
||||
|
||||
export type PrototypeTaskCategory = 'booking' | 'service' | 'notification'
|
||||
|
||||
export type PrototypeFieldControl =
|
||||
| 'text'
|
||||
| 'textarea'
|
||||
| 'select'
|
||||
| 'combobox'
|
||||
| 'date'
|
||||
| 'number'
|
||||
| 'derived'
|
||||
|
||||
export type PrototypeFieldOption =
|
||||
| string
|
||||
| {
|
||||
value: string
|
||||
label?: string
|
||||
group?: string
|
||||
}
|
||||
|
||||
export interface PrototypeField {
|
||||
key?: string
|
||||
label: string
|
||||
value: string
|
||||
note?: string
|
||||
editable?: boolean
|
||||
required?: boolean
|
||||
control?: PrototypeFieldControl
|
||||
options?: PrototypeFieldOption[]
|
||||
placeholder?: string
|
||||
min?: number
|
||||
}
|
||||
|
||||
export interface PrototypeChange {
|
||||
label: string
|
||||
before: string
|
||||
after: string
|
||||
note?: string
|
||||
}
|
||||
|
||||
export interface PrototypeRoomLine {
|
||||
key?: string
|
||||
roomType: string
|
||||
quantity: number
|
||||
occupancy: string
|
||||
meal?: string
|
||||
}
|
||||
|
||||
export interface PrototypeRequirement {
|
||||
key?: string
|
||||
title: string
|
||||
detail: string
|
||||
editable?: boolean
|
||||
}
|
||||
|
||||
export interface PrototypeAttachment {
|
||||
name: string
|
||||
mediaType: string
|
||||
size: string
|
||||
purpose: string
|
||||
}
|
||||
|
||||
export interface PrototypeBusinessCard {
|
||||
eyebrow: string
|
||||
title: string
|
||||
description: string
|
||||
fields?: PrototypeField[]
|
||||
changes?: PrototypeChange[]
|
||||
requirements?: PrototypeRequirement[]
|
||||
department?: 'FO' | 'HSK' | 'FO+HSK'
|
||||
departmentOptions?: Array<'FO' | 'HSK' | 'FO+HSK'>
|
||||
attachment?: PrototypeAttachment
|
||||
boundary?: string
|
||||
noticeReason?: string
|
||||
suggestedAction?: string
|
||||
}
|
||||
|
||||
export interface PrototypeRoomInformation {
|
||||
modeLabel: string
|
||||
summary: string
|
||||
currentTitle?: string
|
||||
current?: PrototypeField[]
|
||||
currentRooms?: PrototypeRoomLine[]
|
||||
targetTitle: string
|
||||
target: PrototypeField[]
|
||||
targetRooms: PrototypeRoomLine[]
|
||||
targetRoomsEditable?: boolean
|
||||
changes?: PrototypeChange[]
|
||||
}
|
||||
|
||||
export interface PrototypeSourceMessage {
|
||||
channel: string
|
||||
senderName: string
|
||||
senderEmail: string
|
||||
recipients: string
|
||||
receivedAt: string
|
||||
subject: string
|
||||
body: string[]
|
||||
attachments: PrototypeAttachment[]
|
||||
quotedHistory?: string[]
|
||||
}
|
||||
|
||||
export interface PrototypeTask {
|
||||
key: string
|
||||
code: string
|
||||
kind: PrototypeTaskKind
|
||||
category: PrototypeTaskCategory
|
||||
icon: string
|
||||
typeLabel: string
|
||||
title: string
|
||||
summary: string
|
||||
status: string
|
||||
priority: string
|
||||
receivedAt: string
|
||||
sectionLabels: string[]
|
||||
basicInformation?: PrototypeField[]
|
||||
businessCard: PrototypeBusinessCard
|
||||
roomInformation?: PrototypeRoomInformation
|
||||
sourceMessage: PrototypeSourceMessage
|
||||
evidence: PrototypeField[]
|
||||
}
|
||||
|
||||
const safeSender = 'reservations@agency-example.test'
|
||||
const safeRecipient = 'hotel-ops@example.test'
|
||||
|
||||
const accountOptions = [
|
||||
'Siam Atlas Travel',
|
||||
'Orchid Routes Co.',
|
||||
'Lotus MICE Partners',
|
||||
'Direct Guest',
|
||||
]
|
||||
const marketOptions = ['Leisure Group', 'FIT Wholesale', 'MICE Group', 'Corporate FIT']
|
||||
const sourceOptions = ['Email', 'Direct', 'GDS']
|
||||
|
||||
export interface PrototypeRateCodeGroup {
|
||||
label: string
|
||||
codes: string[]
|
||||
}
|
||||
|
||||
export const prototypeRateCodeGroups: PrototypeRateCodeGroup[] = [
|
||||
{ label: 'Q.B.D', codes: ['GRPA1', 'GRPA2', 'GRPA3', 'GRPA4'] },
|
||||
{ label: 'LIAN TAI', codes: ['WHO1', 'GRP1', 'WHO2', 'WHO3'] },
|
||||
{ label: 'LIANTAI ONLINE/DY', codes: ['LTLT', 'LBLT'] },
|
||||
{ label: 'RAINBOW/AI', codes: ['LBMS', 'LBSM'] },
|
||||
{ label: 'FENGRUN', codes: ['GLSPCB', 'LBW1'] },
|
||||
{ label: 'HONGTAI', codes: ['GL2000LT', 'LBKB'] },
|
||||
{ label: 'HONGYUN', codes: ['GL2100CN', 'LBLS'] },
|
||||
{ label: 'HANA TOUR', codes: ['WHKR2100B', 'GL2100B', 'GL2200KR'] },
|
||||
]
|
||||
|
||||
export const prototypeRateCodeOptions: PrototypeFieldOption[] = prototypeRateCodeGroups.flatMap(
|
||||
({ label, codes }) => codes.map((value) => ({ value, label: `${label} · ${value}`, group: label })),
|
||||
)
|
||||
export const prototypeRoomTypeOptions = [
|
||||
'RM2',
|
||||
'RM3',
|
||||
'RM4',
|
||||
'UG1',
|
||||
'UG2',
|
||||
'UG3',
|
||||
'SU1',
|
||||
'SU2',
|
||||
'SU3',
|
||||
'SU6',
|
||||
]
|
||||
export const prototypeOccupancyOptions = ['1 人', '2 人', '3 人']
|
||||
export const prototypeMealOptions = ['未提供', '含早餐', '不含早餐']
|
||||
|
||||
function createBasicInformation(
|
||||
account: string,
|
||||
market: string,
|
||||
source: string,
|
||||
accountNote: string,
|
||||
): PrototypeField[] {
|
||||
return [
|
||||
{
|
||||
key: 'account',
|
||||
label: 'Account',
|
||||
value: account,
|
||||
note: accountNote,
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'select',
|
||||
options: accountOptions,
|
||||
},
|
||||
{
|
||||
key: 'market',
|
||||
label: 'Market',
|
||||
value: market,
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'select',
|
||||
options: marketOptions,
|
||||
},
|
||||
{
|
||||
key: 'source',
|
||||
label: 'Source',
|
||||
value: source,
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'select',
|
||||
options: sourceOptions,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export const prototypeTasks: PrototypeTask[] = [
|
||||
{
|
||||
key: 'new-booking',
|
||||
code: 'LOCAL-NEW-001',
|
||||
kind: 'new',
|
||||
category: 'booking',
|
||||
icon: 'pi pi-plus-circle',
|
||||
typeLabel: 'New Booking',
|
||||
title: 'Bangkok Study Tour 新预订',
|
||||
summary: '18 间房,连续 3 晚,Rate Code 待人工确认',
|
||||
status: '待人工确认',
|
||||
priority: '今天处理',
|
||||
receivedAt: '09:24',
|
||||
sectionLabels: ['Basic', 'New Booking', 'Room', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Siam Atlas Travel',
|
||||
'Leisure Group',
|
||||
'Email',
|
||||
'由当前发件人映射,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'New Booking',
|
||||
title: '创建一笔团队订单',
|
||||
description: '本卡只表达邮件要求创建的订单,不混入付款、Trace 或房表动作。',
|
||||
boundary: 'Rate Code 是订单级字段。当前映射不唯一,需要在 Room Information 中人工选择。',
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '创建目标',
|
||||
summary: '邮件中的房型、日期和数量被整理为一笔待创建订单。',
|
||||
targetTitle: '要创建的订单',
|
||||
target: [
|
||||
{
|
||||
key: 'bookingType',
|
||||
label: 'Group / FIT',
|
||||
value: 'Group',
|
||||
control: 'derived',
|
||||
note: '由总房量自动判定:少于 5 间为 FIT,5 间及以上为 Group',
|
||||
},
|
||||
{
|
||||
key: 'groupCode',
|
||||
label: 'Group Code',
|
||||
value: 'BST-0821',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'text',
|
||||
},
|
||||
{
|
||||
key: 'groupName',
|
||||
label: 'Group Name / Block Name',
|
||||
value: 'Bangkok Study Tour',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'text',
|
||||
},
|
||||
{
|
||||
key: 'names',
|
||||
label: 'Name(s)',
|
||||
value: 'BKK-STUDY-21A',
|
||||
note: 'current 邮件以 Tour Code 作为可确认 Name 值;多个 Name 可换行填写',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'textarea',
|
||||
},
|
||||
{
|
||||
key: 'arrival',
|
||||
label: 'Arrival',
|
||||
value: '2026-08-21',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'date',
|
||||
},
|
||||
{
|
||||
key: 'departure',
|
||||
label: 'Departure',
|
||||
value: '2026-08-24',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'date',
|
||||
},
|
||||
{
|
||||
key: 'nights',
|
||||
label: 'Nights',
|
||||
value: '3',
|
||||
control: 'derived',
|
||||
note: '由入住和离店日期计算,不直接录入',
|
||||
},
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: '',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
placeholder: '选择候选或手动输入',
|
||||
note: '订单级字段;映射不唯一时由人工补齐',
|
||||
},
|
||||
],
|
||||
targetRooms: [
|
||||
{ key: 'room-1', roomType: 'RM2', quantity: 14, occupancy: '2 人', meal: '含早餐' },
|
||||
{ key: 'room-2', roomType: 'RM3', quantity: 4, occupancy: '2 人', meal: '含早餐' },
|
||||
],
|
||||
targetRoomsEditable: true,
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Siam Atlas Travel',
|
||||
senderEmail: safeSender,
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 09:24',
|
||||
subject: 'New booking request: Bangkok Study Tour, 21 Aug',
|
||||
body: [
|
||||
'Dear Reservations,',
|
||||
'Please create a new group booking for Bangkok Study Tour from 21 August to 24 August 2026.',
|
||||
'We need 14 Deluxe Twin rooms and 4 Deluxe King rooms, including breakfast. Group code is BST-0821.',
|
||||
'Please use Tour Code BKK-STUDY-21A as the booking Name. The final guest list will follow separately.',
|
||||
'Please advise the available rate code for our account.',
|
||||
'Best regards, Siam Atlas Travel',
|
||||
],
|
||||
attachments: [],
|
||||
quotedHistory: ['Previous discussion only confirmed the tentative travel window. It is not a current booking instruction.'],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'New Booking' },
|
||||
{ label: '定位依据', value: '正文包含明确 create new group booking 指令' },
|
||||
{ label: '分组依据', value: '同一 Group Code BST-0821' },
|
||||
{ label: '待核对', value: 'Rate Code 映射不唯一' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'update-booking',
|
||||
code: 'LOCAL-UPD-002',
|
||||
kind: 'update',
|
||||
category: 'booking',
|
||||
icon: 'pi pi-pencil',
|
||||
typeLabel: 'Update Booking',
|
||||
title: 'River Market FIT 修改离店日期',
|
||||
summary: '离店延后 1 晚,房型与间数保持不变',
|
||||
status: '待核对变更',
|
||||
priority: '今天处理',
|
||||
receivedAt: '09:10',
|
||||
sectionLabels: ['Basic', 'Update', 'Room 对比', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Siam Atlas Travel',
|
||||
'FIT Wholesale',
|
||||
'Email',
|
||||
'继承自已定位订单,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'Update Booking',
|
||||
title: '更新已存在的订单',
|
||||
description: '页面同时保留当前订单与邮件目标,人工确认后才形成最终值。',
|
||||
changes: [
|
||||
{ label: 'Departure', before: '2026-08-12', after: '2026-08-13' },
|
||||
{ label: 'Nights', before: '2', after: '3', note: '随离店日期重新计算' },
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
key: 'orderReference',
|
||||
label: 'Order Reference',
|
||||
value: 'FIT-240817',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'text',
|
||||
note: '如识别错订单,可在确认前人工修正定位值',
|
||||
},
|
||||
{ label: 'Unchanged', value: 'UG1,1 间,2 人' },
|
||||
],
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '变更对比',
|
||||
summary: '仅日期变化。房型、数量和 Rate Code 均保持当前订单值。',
|
||||
currentTitle: '当前订单',
|
||||
current: [
|
||||
{ key: 'bookingType', label: 'Group / FIT', value: 'FIT' },
|
||||
{ key: 'names', label: 'Name(s)', value: 'RIVER-MKT-240817' },
|
||||
{ label: 'Arrival', value: '2026-08-10' },
|
||||
{ label: 'Departure', value: '2026-08-12' },
|
||||
{ label: 'Nights', value: '2' },
|
||||
{ label: 'Rate Code', value: 'WHO1' },
|
||||
],
|
||||
currentRooms: [{ roomType: 'UG1', quantity: 1, occupancy: '2 人', meal: '含早餐' }],
|
||||
targetTitle: '邮件目标',
|
||||
target: [
|
||||
{
|
||||
key: 'bookingType',
|
||||
label: 'Group / FIT',
|
||||
value: 'FIT',
|
||||
control: 'derived',
|
||||
note: '由目标总房量计算',
|
||||
},
|
||||
{
|
||||
key: 'names',
|
||||
label: 'Name(s)',
|
||||
value: 'RIVER-MKT-240817',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'textarea',
|
||||
},
|
||||
{
|
||||
key: 'arrival',
|
||||
label: 'Arrival',
|
||||
value: '2026-08-10',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'date',
|
||||
},
|
||||
{
|
||||
key: 'departure',
|
||||
label: 'Departure',
|
||||
value: '2026-08-13',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'date',
|
||||
},
|
||||
{
|
||||
key: 'nights',
|
||||
label: 'Nights',
|
||||
value: '3',
|
||||
control: 'derived',
|
||||
note: '随目标日期自动计算',
|
||||
},
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: 'WHO1',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
note: '沿用现有订单;需要变更时由人工修改,不自动重算',
|
||||
},
|
||||
],
|
||||
targetRooms: [{ key: 'room-1', roomType: 'UG1', quantity: 1, occupancy: '2 人', meal: '含早餐' }],
|
||||
targetRoomsEditable: true,
|
||||
changes: [
|
||||
{ label: 'Departure', before: '2026-08-12', after: '2026-08-13' },
|
||||
{ label: 'Nights', before: '2', after: '3' },
|
||||
],
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Siam Atlas Travel',
|
||||
senderEmail: safeSender,
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 09:10',
|
||||
subject: 'Extension request for FIT-240817',
|
||||
body: [
|
||||
'Dear Team,',
|
||||
'Please extend booking FIT-240817 by one night. The new departure date should be 13 August 2026.',
|
||||
'Room type, guest count and meal plan remain unchanged.',
|
||||
'Thank you.',
|
||||
],
|
||||
attachments: [],
|
||||
quotedHistory: ['Original confirmation: arrival 10 August, departure 12 August, one Deluxe King room.'],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Update Booking' },
|
||||
{ label: '订单定位', value: 'Order Reference FIT-240817' },
|
||||
{ label: '变更字段', value: 'Departure,Nights' },
|
||||
{ label: '保持字段', value: 'Room Type,Quantity,Rate Code' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'cancel-booking',
|
||||
code: 'LOCAL-CAN-003',
|
||||
kind: 'cancel',
|
||||
category: 'booking',
|
||||
icon: 'pi pi-times-circle',
|
||||
typeLabel: 'Cancel Booking',
|
||||
title: 'Orchid Team 取消整笔订单',
|
||||
summary: '明确取消 Group Code ORC-0902 对应的完整订单',
|
||||
status: '待确认取消',
|
||||
priority: '高影响',
|
||||
receivedAt: '08:58',
|
||||
sectionLabels: ['Basic', 'Cancel', 'Room 快照', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Orchid Routes Co.',
|
||||
'Leisure Group',
|
||||
'Email',
|
||||
'继承自已定位订单,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'Cancel Booking',
|
||||
title: '取消一整笔订单',
|
||||
description: 'Cancel 只表达取消目标,不把减少房量误判为整单取消。',
|
||||
fields: [
|
||||
{
|
||||
key: 'orderReference',
|
||||
label: 'Order Reference',
|
||||
value: 'GRP-91308',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'text',
|
||||
},
|
||||
{
|
||||
key: 'cancellationScope',
|
||||
label: 'Cancellation Scope',
|
||||
value: 'Whole order',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'select',
|
||||
options: ['Whole order'],
|
||||
},
|
||||
{ label: 'Requested By', value: '当前邮件发件人' },
|
||||
],
|
||||
boundary: '这是高影响操作。原型仅展示待确认任务,不会执行 PMS 取消。',
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '取消目标快照',
|
||||
summary: '确认前展示将被取消的完整订单,避免只凭主题执行。',
|
||||
targetTitle: '将被取消的订单',
|
||||
target: [
|
||||
{ key: 'bookingType', label: 'Group / FIT', value: 'Group', control: 'derived' },
|
||||
{ key: 'groupCode', label: 'Group Code', value: 'ORC-0902' },
|
||||
{ key: 'groupName', label: 'Group Name / Block Name', value: 'Orchid Team' },
|
||||
{ key: 'names', label: 'Name(s)', value: 'ORC-0902-TOUR' },
|
||||
{ key: 'arrival', label: 'Arrival', value: '2026-09-02' },
|
||||
{ key: 'departure', label: 'Departure', value: '2026-09-05' },
|
||||
{ key: 'nights', label: 'Nights', value: '3', control: 'derived' },
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: 'GLSPCB',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
note: '继承值允许人工修正,但不会自动重算',
|
||||
},
|
||||
],
|
||||
targetRooms: [
|
||||
{ key: 'room-1', roomType: 'RM2', quantity: 10, occupancy: '2 人', meal: '含早餐' },
|
||||
{ key: 'room-2', roomType: 'SU1', quantity: 2, occupancy: '2 人', meal: '含早餐' },
|
||||
],
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Orchid Routes Co.',
|
||||
senderEmail: 'groups@orchid-example.test',
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 08:58',
|
||||
subject: 'Cancel complete booking ORC-0902',
|
||||
body: [
|
||||
'Dear Reservations,',
|
||||
'Please cancel the complete group booking under group code ORC-0902 and order reference GRP-91308.',
|
||||
'This request applies to all rooms and all dates in the booking.',
|
||||
'Please send cancellation confirmation after manual processing.',
|
||||
],
|
||||
attachments: [],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Cancel Booking' },
|
||||
{ label: '明确措辞', value: 'cancel the complete group booking' },
|
||||
{ label: '订单定位', value: 'Group Code 与 Order Reference 双重命中' },
|
||||
{ label: '执行边界', value: '只建卡,不自动取消 PMS 订单' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'trace-request',
|
||||
code: 'LOCAL-TRC-004',
|
||||
kind: 'trace',
|
||||
category: 'service',
|
||||
icon: 'pi pi-flag',
|
||||
typeLabel: 'Trace',
|
||||
title: 'Lotus Forum 到店服务要求',
|
||||
summary: '同一团队的两项服务要求,需要前台与客房部落实',
|
||||
status: '待分派',
|
||||
priority: '入住前完成',
|
||||
receivedAt: '08:46',
|
||||
sectionLabels: ['Basic', 'Trace', 'Room 快照', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Lotus MICE Partners',
|
||||
'MICE Group',
|
||||
'Email',
|
||||
'继承自已定位订单,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'Trace',
|
||||
title: '需要落实的服务要求',
|
||||
description: '同一 Group Code 的多项要求保留在一张 Trace 中,责任部门以单一选择值表达。',
|
||||
requirements: [
|
||||
{
|
||||
key: 'key-packets',
|
||||
title: '提前准备钥匙包',
|
||||
detail: '团队 13:30 到店,希望提前按房表准备钥匙包。',
|
||||
editable: true,
|
||||
},
|
||||
{
|
||||
key: 'feather-free',
|
||||
title: '无羽绒寝具',
|
||||
detail: '两间 SU2 需要使用无羽绒枕和被芯。',
|
||||
editable: true,
|
||||
},
|
||||
],
|
||||
department: 'FO+HSK',
|
||||
departmentOptions: ['FO', 'HSK', 'FO+HSK'],
|
||||
boundary: '邮件中的付款承担说明不进入 Trace,本卡只保留可执行服务要求。',
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '关联订单快照',
|
||||
summary: 'Room Information 用于说明服务要求影响哪一笔订单和哪些房间。',
|
||||
targetTitle: '当前订单',
|
||||
target: [
|
||||
{ key: 'bookingType', label: 'Group / FIT', value: 'Group', control: 'derived' },
|
||||
{ key: 'groupCode', label: 'Group Code', value: 'LTF-0828' },
|
||||
{ key: 'groupName', label: 'Group Name / Block Name', value: 'Lotus Forum' },
|
||||
{ key: 'names', label: 'Name(s)', value: 'LOTUS-FORUM-28' },
|
||||
{ key: 'arrival', label: 'Arrival', value: '2026-08-28' },
|
||||
{ key: 'departure', label: 'Departure', value: '2026-08-30' },
|
||||
{ key: 'nights', label: 'Nights', value: '2', control: 'derived' },
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: 'GL2000LT',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
note: '从关联订单继承,可人工修正但不自动重算',
|
||||
},
|
||||
],
|
||||
targetRooms: [
|
||||
{ key: 'room-1', roomType: 'RM4', quantity: 16, occupancy: '2 人', meal: '含早餐' },
|
||||
{ key: 'room-2', roomType: 'SU2', quantity: 2, occupancy: '2 人', meal: '含早餐' },
|
||||
],
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '会务公司邮件',
|
||||
senderName: 'Lotus MICE Partners',
|
||||
senderEmail: 'events@lotus-example.test',
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 08:46',
|
||||
subject: 'Arrival arrangements for LTF-0828',
|
||||
body: [
|
||||
'Dear Hotel Team,',
|
||||
'Our group LTF-0828 will arrive around 13:30. Please prepare the key packets according to the rooming list before arrival.',
|
||||
'Two Deluxe King rooms also require feather-free pillows and duvets.',
|
||||
'Please coordinate this with Front Office and Housekeeping.',
|
||||
],
|
||||
attachments: [],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Trace' },
|
||||
{ label: '分组依据', value: 'Group Code LTF-0828' },
|
||||
{ label: '要求数量', value: '2 项,原样保留' },
|
||||
{ label: '部门选择', value: 'FO+HSK' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'rooming-list',
|
||||
code: 'LOCAL-RML-005',
|
||||
kind: 'rooming-list',
|
||||
category: 'service',
|
||||
icon: 'pi pi-file-excel',
|
||||
typeLabel: 'Rooming List',
|
||||
title: 'Bangkok Study Tour 房表更新',
|
||||
summary: '当前邮件附带一份可下载的 Excel 名单',
|
||||
status: '待下载处理',
|
||||
priority: '普通',
|
||||
receivedAt: '08:32',
|
||||
sectionLabels: ['Basic', 'Rooming List', 'Room 快照', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Siam Atlas Travel',
|
||||
'Leisure Group',
|
||||
'Email',
|
||||
'继承自 New Booking,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'Rooming List',
|
||||
title: '当前邮件中的房表文件',
|
||||
description: '业务人员下载后自行处理。原型不解析名单,也不生成新的 Excel。',
|
||||
attachment: {
|
||||
name: 'BST-0821_rooming-list_v2.xlsx',
|
||||
mediaType: 'Excel workbook',
|
||||
size: '84 KB',
|
||||
purpose: '当前邮件房表附件',
|
||||
},
|
||||
boundary: '仅展示并下载当前邮件附件,不解析、不导入 PMS、不展示名单中的个人信息。',
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '关联订单快照',
|
||||
summary: '房表任务仍需展示其关联订单,帮助人工确认附件对应目标。',
|
||||
targetTitle: '关联订单',
|
||||
target: [
|
||||
{ key: 'bookingType', label: 'Group / FIT', value: 'Group', control: 'derived' },
|
||||
{ key: 'groupCode', label: 'Group Code', value: 'BST-0821' },
|
||||
{ key: 'groupName', label: 'Group Name / Block Name', value: 'Bangkok Study Tour' },
|
||||
{ key: 'names', label: 'Name(s)', value: 'BKK-STUDY-21A' },
|
||||
{ key: 'arrival', label: 'Arrival', value: '2026-08-21' },
|
||||
{ key: 'departure', label: 'Departure', value: '2026-08-24' },
|
||||
{ key: 'nights', label: 'Nights', value: '3', control: 'derived' },
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: 'GRPA1',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
note: '关联订单继承值,可人工修正;本邮件不触发重算',
|
||||
},
|
||||
],
|
||||
targetRooms: [
|
||||
{ key: 'room-1', roomType: 'RM2', quantity: 14, occupancy: '2 人', meal: '含早餐' },
|
||||
{ key: 'room-2', roomType: 'RM3', quantity: 4, occupancy: '2 人', meal: '含早餐' },
|
||||
],
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Siam Atlas Travel',
|
||||
senderEmail: safeSender,
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 08:32',
|
||||
subject: 'Updated rooming list for BST-0821',
|
||||
body: [
|
||||
'Dear Reservations,',
|
||||
'Please find the updated rooming list for BST-0821 attached.',
|
||||
'This version replaces the file sent yesterday. Please use the current attachment for manual processing.',
|
||||
'No room quantity or stay date changes are requested in this email.',
|
||||
],
|
||||
attachments: [
|
||||
{
|
||||
name: 'BST-0821_rooming-list_v2.xlsx',
|
||||
mediaType: 'Excel workbook',
|
||||
size: '84 KB',
|
||||
purpose: '当前邮件房表附件',
|
||||
},
|
||||
],
|
||||
quotedHistory: ['Yesterday: an earlier rooming-list version was attached. The current email explicitly replaces it.'],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Rooming List' },
|
||||
{ label: '附件范围', value: '仅当前邮件中的 xlsx' },
|
||||
{ label: '订单定位', value: 'Group Code BST-0821' },
|
||||
{ label: '处理边界', value: '下载给人工,不解析名单' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'payment-reference',
|
||||
code: 'LOCAL-PAY-006',
|
||||
kind: 'payment',
|
||||
category: 'service',
|
||||
icon: 'pi pi-image',
|
||||
typeLabel: 'Payment',
|
||||
title: 'Orchid Team 付款图片通知',
|
||||
summary: '当前邮件含一张付款参考图片,仅供人工核对',
|
||||
status: '待查看附件',
|
||||
priority: '普通',
|
||||
receivedAt: '08:18',
|
||||
sectionLabels: ['Basic', 'Payment', 'Room 快照', '邮件原文'],
|
||||
basicInformation: createBasicInformation(
|
||||
'Orchid Routes Co.',
|
||||
'Leisure Group',
|
||||
'Email',
|
||||
'继承自已定位订单,可从目录中人工修正',
|
||||
),
|
||||
businessCard: {
|
||||
eyebrow: 'Payment',
|
||||
title: '当前邮件中的付款参考图片',
|
||||
description: '本卡只确认收到了图片,不判断到账、不验证凭证、不改变订单状态。',
|
||||
attachment: {
|
||||
name: 'payment-reference_ORC-0902.jpg',
|
||||
mediaType: 'JPEG image',
|
||||
size: '412 KB',
|
||||
purpose: '付款参考图片',
|
||||
},
|
||||
boundary: '附件预览已做安全示意。正式系统应通过受控下载链读取原文件。',
|
||||
},
|
||||
roomInformation: {
|
||||
modeLabel: '关联订单快照',
|
||||
summary: '付款图片只关联订单,不改变当前房量、日期或价格状态。',
|
||||
targetTitle: '关联订单',
|
||||
target: [
|
||||
{ key: 'bookingType', label: 'Group / FIT', value: 'Group', control: 'derived' },
|
||||
{ key: 'groupCode', label: 'Group Code', value: 'ORC-0902' },
|
||||
{ key: 'groupName', label: 'Group Name / Block Name', value: 'Orchid Team' },
|
||||
{ key: 'names', label: 'Name(s)', value: 'ORC-0902-TOUR' },
|
||||
{ key: 'arrival', label: 'Arrival', value: '2026-09-02' },
|
||||
{ key: 'departure', label: 'Departure', value: '2026-09-05' },
|
||||
{ key: 'nights', label: 'Nights', value: '3', control: 'derived' },
|
||||
{
|
||||
key: 'rateCode',
|
||||
label: 'Rate Code',
|
||||
value: 'GLSPCB',
|
||||
editable: true,
|
||||
required: true,
|
||||
control: 'combobox',
|
||||
options: prototypeRateCodeOptions,
|
||||
note: '关联订单继承值,可人工修正;本邮件不触发重算',
|
||||
},
|
||||
],
|
||||
targetRooms: [
|
||||
{ key: 'room-1', roomType: 'RM2', quantity: 10, occupancy: '2 人', meal: '含早餐' },
|
||||
{ key: 'room-2', roomType: 'SU1', quantity: 2, occupancy: '2 人', meal: '含早餐' },
|
||||
],
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Orchid Routes Co.',
|
||||
senderEmail: 'groups@orchid-example.test',
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 08:18',
|
||||
subject: 'Payment reference image for ORC-0902',
|
||||
body: [
|
||||
'Dear Team,',
|
||||
'Attached is the payment reference image for group ORC-0902.',
|
||||
'Please pass it to the colleague responsible for manual checking.',
|
||||
'No booking changes are requested in this email.',
|
||||
],
|
||||
attachments: [
|
||||
{
|
||||
name: 'payment-reference_ORC-0902.jpg',
|
||||
mediaType: 'JPEG image',
|
||||
size: '412 KB',
|
||||
purpose: '付款参考图片',
|
||||
},
|
||||
],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Payment' },
|
||||
{ label: '附件范围', value: '当前邮件中的 1 张图片' },
|
||||
{ label: '订单定位', value: 'Group Code ORC-0902' },
|
||||
{ label: '处理边界', value: '不判断到账,不更新订单状态' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'risk-notification',
|
||||
code: 'LOCAL-RSK-007',
|
||||
kind: 'risk',
|
||||
category: 'notification',
|
||||
icon: 'pi pi-shield',
|
||||
typeLabel: 'Risk',
|
||||
title: '无法判断业务类型的邮件',
|
||||
summary: '正文只说“按上次方式处理”,缺少可定位的订单与动作',
|
||||
status: '待人工判断',
|
||||
priority: '需要关注',
|
||||
receivedAt: '08:04',
|
||||
sectionLabels: ['Risk', '邮件原文', '识别依据'],
|
||||
businessCard: {
|
||||
eyebrow: 'Risk',
|
||||
title: '业务意图无法安全分类',
|
||||
description: '整封 current 邮件存在业务信号,但不足以判断 New、Update、Cancel、Trace、Rooming List 或 Payment。',
|
||||
noticeReason: '缺少订单号、Group Code、日期和明确动作,附件名称也无法证明业务类型。',
|
||||
suggestedAction: '阅读邮件原文并联系发件人确认。一个邮件最多保留一张 Risk。',
|
||||
boundary: '邮件级通知不绑定订单,因此 Basic Information 与 Room Information 不适用。',
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '未识别渠道邮件',
|
||||
senderName: 'External Sender',
|
||||
senderEmail: 'contact@unknown-example.test',
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 08:04',
|
||||
subject: 'Please handle as before',
|
||||
body: [
|
||||
'Hi,',
|
||||
'Please handle the attached item in the same way as last time.',
|
||||
'Let me know when it is done.',
|
||||
],
|
||||
attachments: [
|
||||
{
|
||||
name: 'scan_0808.jpg',
|
||||
mediaType: 'JPEG image',
|
||||
size: '238 KB',
|
||||
purpose: '未能判断用途的附件',
|
||||
},
|
||||
],
|
||||
quotedHistory: ['No quoted message was available to explain what “last time” referred to.'],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'Risk' },
|
||||
{ label: '缺失信息', value: '订单定位、业务动作、日期' },
|
||||
{ label: '不可推断', value: '附件用途与 last time 指代' },
|
||||
{ label: '通知数量', value: '本邮件仅 1 张 Risk' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'general-notification',
|
||||
code: 'LOCAL-GEN-008',
|
||||
kind: 'general',
|
||||
category: 'notification',
|
||||
icon: 'pi pi-inbox',
|
||||
typeLabel: 'General',
|
||||
title: '旅行社营业时间通知',
|
||||
summary: '整封邮件没有需要酒店执行的订单或服务动作',
|
||||
status: '待查看',
|
||||
priority: '低',
|
||||
receivedAt: '07:42',
|
||||
sectionLabels: ['General', '邮件原文', '识别依据'],
|
||||
businessCard: {
|
||||
eyebrow: 'General',
|
||||
title: '仅需知悉的邮件',
|
||||
description: '只有当整封 current 邮件没有可处理任务时,才生成 General。',
|
||||
noticeReason: '内容只是通知对方假期营业时间,没有新建、修改、取消订单或服务要求。',
|
||||
suggestedAction: '阅读后标记已知悉。无需创建订单或关联既有订单。',
|
||||
boundary: '邮件级通知不绑定订单,因此 Basic Information 与 Room Information 不适用。',
|
||||
},
|
||||
sourceMessage: {
|
||||
channel: '旅行社邮件',
|
||||
senderName: 'Siam Atlas Travel',
|
||||
senderEmail: safeSender,
|
||||
recipients: safeRecipient,
|
||||
receivedAt: '2026-08-08 07:42',
|
||||
subject: 'Agency office hours for public holiday',
|
||||
body: [
|
||||
'Dear Partners,',
|
||||
'Our office will close at 16:00 on 12 August for the public holiday.',
|
||||
'Emergency contacts remain available through the usual channel.',
|
||||
'This is an information notice only. No action is required for existing bookings.',
|
||||
],
|
||||
attachments: [],
|
||||
},
|
||||
evidence: [
|
||||
{ label: '识别结论', value: 'General' },
|
||||
{ label: '任务扫描', value: '无 New、Update、Cancel 或服务动作' },
|
||||
{ label: '正文边界', value: '明确写明 no action is required' },
|
||||
{ label: '订单绑定', value: '不适用' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export function getPrototypeTask(taskKey: string | string[] | undefined): PrototypeTask | undefined {
|
||||
const normalizedKey = Array.isArray(taskKey) ? taskKey[0] : taskKey
|
||||
return prototypeTasks.find((task) => task.key === normalizedKey)
|
||||
}
|
||||
|
||||
export function getAdjacentPrototypeTasks(task: PrototypeTask): {
|
||||
previous?: PrototypeTask
|
||||
next?: PrototypeTask
|
||||
} {
|
||||
const index = prototypeTasks.findIndex((candidate) => candidate.key === task.key)
|
||||
return {
|
||||
previous: index > 0 ? prototypeTasks[index - 1] : undefined,
|
||||
next: index >= 0 ? prototypeTasks[index + 1] : undefined,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user