优化V4预订事项用户化展示
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -8,8 +8,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="room-information__chips">
|
<div class="room-information__chips">
|
||||||
<span>{{ eventType || '-' }}</span>
|
<span>{{ eventTypeLabel }}</span>
|
||||||
<span>{{ bookingType || '-' }}</span>
|
<span>{{ bookingTypeLabel }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
@@ -257,6 +257,29 @@ const roomInformation = computed<ReservationV4RoomInformationDisplayModel | null
|
|||||||
})
|
})
|
||||||
const eventType = computed(() => roomInformation.value?.event_type ?? props.card.event_type ?? '')
|
const eventType = computed(() => roomInformation.value?.event_type ?? props.card.event_type ?? '')
|
||||||
const bookingType = computed(() => roomInformation.value?.booking_type ?? '')
|
const bookingType = computed(() => roomInformation.value?.booking_type ?? '')
|
||||||
|
const eventTypeLabel = computed(() => {
|
||||||
|
const normalizedEventType = eventType.value.trim().toUpperCase()
|
||||||
|
if (normalizedEventType === 'NEW_BOOKING') {
|
||||||
|
return t('taskV4.roomInformation.eventType.NEW_BOOKING')
|
||||||
|
}
|
||||||
|
if (normalizedEventType === 'UPDATE_BOOKING') {
|
||||||
|
return t('taskV4.roomInformation.eventType.UPDATE_BOOKING')
|
||||||
|
}
|
||||||
|
if (normalizedEventType === 'CANCEL_BOOKING') {
|
||||||
|
return t('taskV4.roomInformation.eventType.CANCEL_BOOKING')
|
||||||
|
}
|
||||||
|
return t('taskV4.roomInformation.eventType.unknown')
|
||||||
|
})
|
||||||
|
const bookingTypeLabel = computed(() => {
|
||||||
|
const normalizedBookingType = bookingType.value.trim().toUpperCase()
|
||||||
|
if (normalizedBookingType === 'GROUP') {
|
||||||
|
return t('taskV4.bookingTypeGroup')
|
||||||
|
}
|
||||||
|
if (normalizedBookingType === 'FIT') {
|
||||||
|
return t('taskV4.bookingTypeFit')
|
||||||
|
}
|
||||||
|
return t('taskV4.bookingTypeUnknown')
|
||||||
|
})
|
||||||
const currentValues = computed(() => normalizeValues(roomInformation.value?.current_values))
|
const currentValues = computed(() => normalizeValues(roomInformation.value?.current_values))
|
||||||
const proposedValues = computed(() => normalizeValues(roomInformation.value?.proposed_values))
|
const proposedValues = computed(() => normalizeValues(roomInformation.value?.proposed_values))
|
||||||
const finalValues = computed(() => normalizeValues(roomInformation.value?.final_values))
|
const finalValues = computed(() => normalizeValues(roomInformation.value?.final_values))
|
||||||
|
|||||||
@@ -369,20 +369,6 @@ function lookupHints(field: ReservationV4TaskCardFieldResult): LookupHint[] {
|
|||||||
tone: 'normal',
|
tone: 'normal',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (result.stale) {
|
|
||||||
hints.push({
|
|
||||||
key: `${kind}-stale`,
|
|
||||||
message: t('taskV4.lookup.stale'),
|
|
||||||
tone: 'warning',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
result.warnings.forEach((warning, index) => {
|
|
||||||
hints.push({
|
|
||||||
key: `${kind}-warning-${index}`,
|
|
||||||
message: t('taskV4.lookup.warning', { warning }),
|
|
||||||
tone: 'warning',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (!result.items.length) {
|
if (!result.items.length) {
|
||||||
hints.push({
|
hints.push({
|
||||||
key: `${kind}-empty`,
|
key: `${kind}-empty`,
|
||||||
|
|||||||
@@ -425,7 +425,8 @@ function handlePrimaryAction(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-card-section__status-actions {
|
.task-card-section__status-actions {
|
||||||
justify-content: flex-start;
|
align-self: stretch;
|
||||||
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ export default {
|
|||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
orders: 'Order list',
|
orders: 'Order list',
|
||||||
taskQueue: 'Task queue',
|
taskQueue: 'Reservation items',
|
||||||
manualInvoice: 'Manual invoice',
|
manualInvoice: 'Manual invoice',
|
||||||
roomingList: 'Rooming list',
|
roomingList: 'Rooming list',
|
||||||
sourceMessages: 'Source messages',
|
sourceMessages: 'Source messages',
|
||||||
systemStatus: 'System status',
|
systemStatus: 'System status',
|
||||||
orderDetail: 'Order detail',
|
orderDetail: 'Order overview',
|
||||||
taskDetail: 'Task detail',
|
taskDetail: 'Reservation item handling',
|
||||||
sourceMessageConversation: 'Email conversation',
|
sourceMessageConversation: 'Email conversation',
|
||||||
sourceNotificationDetail: 'Source notification detail',
|
sourceNotificationDetail: 'Source notification detail',
|
||||||
debugEml: 'Debug EML',
|
debugEml: 'Debug EML',
|
||||||
@@ -451,7 +451,7 @@ export default {
|
|||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
summary: 'Order summary',
|
summary: 'Order summary',
|
||||||
taskQueue: 'Order task queue',
|
taskQueue: 'Reservation items for this order',
|
||||||
v4TaskTimeline: 'Processing records',
|
v4TaskTimeline: 'Processing records',
|
||||||
v4TaskTimelineEmpty: 'No processing records.',
|
v4TaskTimelineEmpty: 'No processing records.',
|
||||||
v4TaskTimelineHint: 'Shows source-email processing records and item status summaries only. Complete actions in the reservation item page.',
|
v4TaskTimelineHint: 'Shows source-email processing records and item status summaries only. Complete actions in the reservation item page.',
|
||||||
@@ -609,7 +609,13 @@ export default {
|
|||||||
reviewResolved: 'Review submitted and detail refreshed.',
|
reviewResolved: 'Review submitted and detail refreshed.',
|
||||||
validationFailed: 'Fix current-card field errors first.',
|
validationFailed: 'Fix current-card field errors first.',
|
||||||
roomInformation: {
|
roomInformation: {
|
||||||
noDisplayModel: 'Room Information display model is not returned yet.',
|
noDisplayModel: 'Room and date information is temporarily unavailable. Refresh later or contact an administrator.',
|
||||||
|
eventType: {
|
||||||
|
NEW_BOOKING: 'New booking',
|
||||||
|
UPDATE_BOOKING: 'Booking update',
|
||||||
|
CANCEL_BOOKING: 'Booking cancellation',
|
||||||
|
unknown: 'Reservation item',
|
||||||
|
},
|
||||||
emptyValues: 'No fields to display.',
|
emptyValues: 'No fields to display.',
|
||||||
changeSummary: 'Change summary',
|
changeSummary: 'Change summary',
|
||||||
currentValues: 'Current values',
|
currentValues: 'Current values',
|
||||||
@@ -661,13 +667,13 @@ export default {
|
|||||||
action: 'Fixed action',
|
action: 'Fixed action',
|
||||||
},
|
},
|
||||||
lookup: {
|
lookup: {
|
||||||
loading: 'Loading catalog',
|
loading: 'Loading options',
|
||||||
empty: 'No options in the current catalog. A no-match search does not mean the catalog is uninitialized.',
|
empty: 'No options are available. Contact an administrator to maintain the choices.',
|
||||||
stale: 'This catalog is a stale snapshot. You can still select from it; backend validation remains final.',
|
stale: 'This catalog is a stale snapshot. You can still select from it; backend validation remains final.',
|
||||||
warning: 'Catalog note: {warning}',
|
warning: 'Catalog note: {warning}',
|
||||||
error: 'Catalog is temporarily unavailable. Refresh and retry.',
|
error: 'Options are temporarily unavailable. Refresh and retry.',
|
||||||
accountDerived: 'Market: {market} / Source: {source} will be shown from the catalog; backend confirmation remains final.',
|
accountDerived: 'Selecting this account fills Market: {market} / Source: {source}.',
|
||||||
currentNotInCatalog: 'Original value "{value}" is not in the current catalog. Select again.',
|
currentNotInCatalog: 'Original value "{value}" is not in the current options. Select again.',
|
||||||
},
|
},
|
||||||
sourceMessage: {
|
sourceMessage: {
|
||||||
subject: 'Subject',
|
subject: 'Subject',
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ export default {
|
|||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
orders: 'รายการออเดอร์',
|
orders: 'รายการออเดอร์',
|
||||||
taskQueue: 'คิวงาน',
|
taskQueue: 'รายการจองที่ต้องจัดการ',
|
||||||
manualInvoice: 'ออกใบแจ้งหนี้เอง',
|
manualInvoice: 'ออกใบแจ้งหนี้เอง',
|
||||||
roomingList: 'สร้าง Rooming List',
|
roomingList: 'สร้าง Rooming List',
|
||||||
sourceMessages: 'แหล่งที่มาข้อความ',
|
sourceMessages: 'แหล่งที่มาข้อความ',
|
||||||
systemStatus: 'สถานะระบบ',
|
systemStatus: 'สถานะระบบ',
|
||||||
orderDetail: 'รายละเอียดออเดอร์',
|
orderDetail: 'ภาพรวมออเดอร์',
|
||||||
taskDetail: 'รายละเอียดงาน',
|
taskDetail: 'จัดการรายการจอง',
|
||||||
sourceMessageConversation: 'เธรดอีเมล',
|
sourceMessageConversation: 'เธรดอีเมล',
|
||||||
sourceNotificationDetail: 'รายละเอียดแจ้งเตือนต้นทาง',
|
sourceNotificationDetail: 'รายละเอียดแจ้งเตือนต้นทาง',
|
||||||
debugEml: 'Debug EML',
|
debugEml: 'Debug EML',
|
||||||
@@ -451,7 +451,7 @@ export default {
|
|||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
summary: 'สรุปออเดอร์',
|
summary: 'สรุปออเดอร์',
|
||||||
taskQueue: 'คิวงานของออเดอร์นี้',
|
taskQueue: 'รายการจองของออเดอร์นี้',
|
||||||
v4TaskTimeline: 'ประวัติการดำเนินการ',
|
v4TaskTimeline: 'ประวัติการดำเนินการ',
|
||||||
v4TaskTimelineEmpty: 'ยังไม่มีประวัติการดำเนินการ',
|
v4TaskTimelineEmpty: 'ยังไม่มีประวัติการดำเนินการ',
|
||||||
v4TaskTimelineHint: 'แสดงเฉพาะประวัติการประมวลผลอีเมลต้นทางและสรุปสถานะรายการ หากต้องดำเนินการให้เข้าไปที่หน้าจัดการรายการจอง',
|
v4TaskTimelineHint: 'แสดงเฉพาะประวัติการประมวลผลอีเมลต้นทางและสรุปสถานะรายการ หากต้องดำเนินการให้เข้าไปที่หน้าจัดการรายการจอง',
|
||||||
@@ -609,7 +609,13 @@ export default {
|
|||||||
reviewResolved: 'ส่งผลตรวจสอบแล้วและรีเฟรชรายละเอียดแล้ว',
|
reviewResolved: 'ส่งผลตรวจสอบแล้วและรีเฟรชรายละเอียดแล้ว',
|
||||||
validationFailed: 'โปรดแก้ไขข้อมูลในการ์ดปัจจุบันก่อน',
|
validationFailed: 'โปรดแก้ไขข้อมูลในการ์ดปัจจุบันก่อน',
|
||||||
roomInformation: {
|
roomInformation: {
|
||||||
noDisplayModel: 'ยังไม่ได้รับโมเดลแสดงผล Room Information',
|
noDisplayModel: 'ข้อมูลห้องและวันที่ยังไม่พร้อมใช้งาน โปรดลองรีเฟรชภายหลังหรือติดต่อผู้ดูแลระบบ',
|
||||||
|
eventType: {
|
||||||
|
NEW_BOOKING: 'จองใหม่',
|
||||||
|
UPDATE_BOOKING: 'แก้ไขการจอง',
|
||||||
|
CANCEL_BOOKING: 'ยกเลิกการจอง',
|
||||||
|
unknown: 'รายการจอง',
|
||||||
|
},
|
||||||
emptyValues: 'ไม่มีฟิลด์ให้แสดง',
|
emptyValues: 'ไม่มีฟิลด์ให้แสดง',
|
||||||
changeSummary: 'สรุปการเปลี่ยนแปลง',
|
changeSummary: 'สรุปการเปลี่ยนแปลง',
|
||||||
currentValues: 'ค่าปัจจุบัน',
|
currentValues: 'ค่าปัจจุบัน',
|
||||||
@@ -661,13 +667,13 @@ export default {
|
|||||||
action: 'การดำเนินการคงที่',
|
action: 'การดำเนินการคงที่',
|
||||||
},
|
},
|
||||||
lookup: {
|
lookup: {
|
||||||
loading: 'กำลังโหลดแค็ตตาล็อก',
|
loading: 'กำลังโหลดตัวเลือก',
|
||||||
empty: 'ไม่มีตัวเลือกในแค็ตตาล็อกปัจจุบัน หากค้นหาไม่พบไม่ได้หมายความว่าแค็ตตาล็อกยังไม่เริ่มต้น',
|
empty: 'ยังไม่มีตัวเลือก หากต้องเพิ่มโปรดติดต่อผู้ดูแล',
|
||||||
stale: 'แค็ตตาล็อกนี้เป็น snapshot เก่า ยังเลือกได้ แต่การตรวจสอบฝั่งหลังบ้านเป็นผลสุดท้าย',
|
stale: 'แค็ตตาล็อกนี้เป็น snapshot เก่า ยังเลือกได้ แต่การตรวจสอบฝั่งหลังบ้านเป็นผลสุดท้าย',
|
||||||
warning: 'หมายเหตุแค็ตตาล็อก: {warning}',
|
warning: 'หมายเหตุแค็ตตาล็อก: {warning}',
|
||||||
error: 'แค็ตตาล็อกไม่พร้อมใช้งานชั่วคราว โปรดรีเฟรชแล้วลองใหม่',
|
error: 'ตัวเลือกไม่พร้อมใช้งานชั่วคราว โปรดรีเฟรชแล้วลองใหม่',
|
||||||
accountDerived: 'จะแสดง Market: {market} / Source: {source} จากแค็ตตาล็อก โดยผลยืนยันจากหลังบ้านเป็นผลสุดท้าย',
|
accountDerived: 'เมื่อเลือกแล้วจะแสดง Market: {market} / Source: {source}',
|
||||||
currentNotInCatalog: 'ค่าเดิม "{value}" ไม่อยู่ในแค็ตตาล็อกปัจจุบัน โปรดเลือกใหม่',
|
currentNotInCatalog: 'ค่าเดิม "{value}" ไม่อยู่ในตัวเลือกปัจจุบัน โปรดเลือกใหม่',
|
||||||
},
|
},
|
||||||
sourceMessage: {
|
sourceMessage: {
|
||||||
subject: 'หัวข้อ',
|
subject: 'หัวข้อ',
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ export default {
|
|||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
orders: '订单列表',
|
orders: '订单列表',
|
||||||
taskQueue: '任务队列',
|
taskQueue: '预订事项',
|
||||||
manualInvoice: '手工开票',
|
manualInvoice: '手工开票',
|
||||||
roomingList: '房表生成',
|
roomingList: '房表生成',
|
||||||
sourceMessages: '消息来源',
|
sourceMessages: '消息来源',
|
||||||
systemStatus: '系统状态',
|
systemStatus: '系统状态',
|
||||||
orderDetail: '订单详情',
|
orderDetail: '订单总览',
|
||||||
taskDetail: '任务详情',
|
taskDetail: '订单事项办理',
|
||||||
sourceMessageConversation: '邮件会话',
|
sourceMessageConversation: '邮件会话',
|
||||||
sourceNotificationDetail: '来源通知详情',
|
sourceNotificationDetail: '来源通知详情',
|
||||||
debugEml: 'Debug EML',
|
debugEml: 'Debug EML',
|
||||||
@@ -451,7 +451,7 @@ export default {
|
|||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
summary: '订单摘要',
|
summary: '订单摘要',
|
||||||
taskQueue: '同订单任务队列',
|
taskQueue: '同订单预订事项',
|
||||||
v4TaskTimeline: '处理记录',
|
v4TaskTimeline: '处理记录',
|
||||||
v4TaskTimelineEmpty: '暂无处理记录。',
|
v4TaskTimelineEmpty: '暂无处理记录。',
|
||||||
v4TaskTimelineHint: '只展示来源邮件处理记录和事项状态摘要;办理动作请进入订单事项办理页完成。',
|
v4TaskTimelineHint: '只展示来源邮件处理记录和事项状态摘要;办理动作请进入订单事项办理页完成。',
|
||||||
@@ -609,7 +609,13 @@ export default {
|
|||||||
reviewResolved: '复核已提交,详情已刷新。',
|
reviewResolved: '复核已提交,详情已刷新。',
|
||||||
validationFailed: '请先修正当前卡片字段。',
|
validationFailed: '请先修正当前卡片字段。',
|
||||||
roomInformation: {
|
roomInformation: {
|
||||||
noDisplayModel: 'Room Information 展示模型暂未返回。',
|
noDisplayModel: '房型与日期信息暂不可用,请稍后刷新或联系管理员。',
|
||||||
|
eventType: {
|
||||||
|
NEW_BOOKING: '新预订',
|
||||||
|
UPDATE_BOOKING: '修改预订',
|
||||||
|
CANCEL_BOOKING: '取消预订',
|
||||||
|
unknown: '预订事项',
|
||||||
|
},
|
||||||
emptyValues: '暂无可展示字段。',
|
emptyValues: '暂无可展示字段。',
|
||||||
changeSummary: '本次变更摘要',
|
changeSummary: '本次变更摘要',
|
||||||
currentValues: '当前值',
|
currentValues: '当前值',
|
||||||
@@ -661,13 +667,13 @@ export default {
|
|||||||
action: '固定动作',
|
action: '固定动作',
|
||||||
},
|
},
|
||||||
lookup: {
|
lookup: {
|
||||||
loading: '目录加载中',
|
loading: '选项加载中',
|
||||||
empty: '当前目录没有可选项;如果是搜索无结果,不代表目录未初始化。',
|
empty: '暂无可选项,如需新增请联系管理员维护资料。',
|
||||||
stale: '当前目录为过期快照,仍可选择,最终以后端校验为准。',
|
stale: '当前目录为过期快照,仍可选择,最终以后端校验为准。',
|
||||||
warning: '目录提示:{warning}',
|
warning: '目录提示:{warning}',
|
||||||
error: '目录暂不可用,请刷新后重试。',
|
error: '选项暂不可用,请刷新后重试。',
|
||||||
accountDerived: '选择后将参考目录展示 Market:{market} / Source:{source},最终以后端确认结果为准。',
|
accountDerived: '选择后会带出市场:{market} / 来源:{source}。',
|
||||||
currentNotInCatalog: '原值“{value}”不在当前目录中,请重新选择。',
|
currentNotInCatalog: '原值“{value}”不在当前可选项中,请重新选择。',
|
||||||
},
|
},
|
||||||
sourceMessage: {
|
sourceMessage: {
|
||||||
subject: '主题',
|
subject: '主题',
|
||||||
|
|||||||
@@ -14,11 +14,24 @@ describe('reservation i18n locales', () => {
|
|||||||
|
|
||||||
it('includes Thai labels for the P0 reservation navigation', () => {
|
it('includes Thai labels for the P0 reservation navigation', () => {
|
||||||
expect(thTH.nav.orders).toBe('รายการออเดอร์')
|
expect(thTH.nav.orders).toBe('รายการออเดอร์')
|
||||||
expect(thTH.nav.taskQueue).toBe('คิวงาน')
|
expect(thTH.nav.taskQueue).toBe('รายการจองที่ต้องจัดการ')
|
||||||
expect(thTH.nav.debugEml).toBe('Debug EML')
|
expect(thTH.nav.debugEml).toBe('Debug EML')
|
||||||
expect(thTH.taskList.viewConversation).toBe('ดูเธรดอีเมล')
|
expect(thTH.taskList.viewConversation).toBe('ดูเธรดอีเมล')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('uses user-facing reservation navigation labels instead of legacy task wording', () => {
|
||||||
|
expect(zhCN.nav.taskQueue).toBe('预订事项')
|
||||||
|
expect(zhCN.nav.taskDetail).toBe('订单事项办理')
|
||||||
|
expect(zhCN.nav.orderDetail).toBe('订单总览')
|
||||||
|
expect(enUS.nav.taskQueue).toBe('Reservation items')
|
||||||
|
expect(enUS.nav.taskDetail).toBe('Reservation item handling')
|
||||||
|
expect(enUS.nav.orderDetail).toBe('Order overview')
|
||||||
|
expect(thTH.nav.taskDetail).toBe('จัดการรายการจอง')
|
||||||
|
|
||||||
|
expect(zhCN.nav.taskQueue).not.toBe('任务队列')
|
||||||
|
expect(zhCN.nav.taskDetail).not.toBe('任务详情')
|
||||||
|
})
|
||||||
|
|
||||||
it('covers Debug EML backend error codes in all locales', () => {
|
it('covers Debug EML backend error codes in all locales', () => {
|
||||||
const expectedErrorCodes = [
|
const expectedErrorCodes = [
|
||||||
'REQUEST_FIELD_REQUIRED',
|
'REQUEST_FIELD_REQUIRED',
|
||||||
|
|||||||
@@ -199,6 +199,8 @@ describe('ReservationAppShell', () => {
|
|||||||
|
|
||||||
expect(wrapper.find('a[href="/reservation/orders"]').exists()).toBe(true)
|
expect(wrapper.find('a[href="/reservation/orders"]').exists()).toBe(true)
|
||||||
expect(wrapper.find('a[href="/reservation/tasks"]').exists()).toBe(true)
|
expect(wrapper.find('a[href="/reservation/tasks"]').exists()).toBe(true)
|
||||||
|
expect(wrapper.text()).toContain('预订事项')
|
||||||
|
expect(wrapper.text()).not.toContain('任务队列')
|
||||||
expect(wrapper.find('a[href="/debug/eml-superagent"]').exists()).toBe(false)
|
expect(wrapper.find('a[href="/debug/eml-superagent"]').exists()).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
import { createMemoryHistory, createRouter } from 'vue-router'
|
import { createMemoryHistory, createRouter } from 'vue-router'
|
||||||
|
|
||||||
|
import taskCardSectionSource from '@/components/reservation/ReservationV4TaskCardSection.vue?raw'
|
||||||
import zhCN from '@/i18n/locales/zh-CN'
|
import zhCN from '@/i18n/locales/zh-CN'
|
||||||
import { useAuthStore } from '@/stores/authStore'
|
import { useAuthStore } from '@/stores/authStore'
|
||||||
import type {
|
import type {
|
||||||
@@ -811,6 +812,25 @@ describe('reservation V4 pages', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows a user-facing empty state when Room Information display data is unavailable', async () => {
|
||||||
|
const detail = createOrderTaskDetail({
|
||||||
|
businessDisplayPayload: {},
|
||||||
|
})
|
||||||
|
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||||
|
|
||||||
|
const wrapper = await mountWithPlugins(
|
||||||
|
ReservationV4OrderTaskDetailView,
|
||||||
|
'/reservation/order-tasks/9001',
|
||||||
|
)
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
||||||
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.noDisplayModel)
|
||||||
|
expect(roomCard.text()).not.toContain('Room Information')
|
||||||
|
expect(roomCard.text()).not.toContain('display model')
|
||||||
|
expect(roomCard.text()).not.toContain('展示模型')
|
||||||
|
})
|
||||||
|
|
||||||
it('keeps backend errors for hidden Room Information fields visible as action messages', async () => {
|
it('keeps backend errors for hidden Room Information fields visible as action messages', async () => {
|
||||||
const detail = createOrderTaskDetail({
|
const detail = createOrderTaskDetail({
|
||||||
businessEventType: 'NEW_BOOKING',
|
businessEventType: 'NEW_BOOKING',
|
||||||
@@ -870,6 +890,8 @@ describe('reservation V4 pages', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
||||||
|
expect(roomCard.text()).toContain('新预订')
|
||||||
|
expect(roomCard.text()).not.toContain('NEW_BOOKING')
|
||||||
expect(roomCard.find('select[name="/room_information/final_values/group_booking_status"]').exists()).toBe(false)
|
expect(roomCard.find('select[name="/room_information/final_values/group_booking_status"]').exists()).toBe(false)
|
||||||
expect(roomCard.text()).toContain('TEN-Tentative')
|
expect(roomCard.text()).toContain('TEN-Tentative')
|
||||||
})
|
})
|
||||||
@@ -955,6 +977,8 @@ describe('reservation V4 pages', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
||||||
|
expect(roomCard.text()).toContain('修改预订')
|
||||||
|
expect(roomCard.text()).not.toContain('UPDATE_BOOKING')
|
||||||
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.changeSummary)
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.changeSummary)
|
||||||
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.currentValues)
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.currentValues)
|
||||||
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.proposedValues)
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.proposedValues)
|
||||||
@@ -1018,6 +1042,8 @@ describe('reservation V4 pages', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
const roomCard = wrapper.find('[data-testid="room-information-card"]')
|
||||||
|
expect(roomCard.text()).toContain('取消预订')
|
||||||
|
expect(roomCard.text()).not.toContain('CANCEL_BOOKING')
|
||||||
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.currentValues)
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.currentValues)
|
||||||
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.finalValues)
|
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.finalValues)
|
||||||
expect(roomCard.text()).toContain('GRP-V4-RI-CANCEL-001')
|
expect(roomCard.text()).toContain('GRP-V4-RI-CANCEL-001')
|
||||||
@@ -1073,7 +1099,7 @@ describe('reservation V4 pages', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows non-blocking lookup empty, stale and warning states', async () => {
|
it('shows lookup empty state without catalog technical warnings', async () => {
|
||||||
const detail = createOrderTaskDetail()
|
const detail = createOrderTaskDetail()
|
||||||
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
|
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
|
||||||
hotel_id: 'HOTEL-TEST',
|
hotel_id: 'HOTEL-TEST',
|
||||||
@@ -1098,8 +1124,8 @@ describe('reservation V4 pages', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.empty)
|
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.empty)
|
||||||
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.stale)
|
expect(wrapper.text()).not.toContain(zhCN.taskV4.lookup.stale)
|
||||||
expect(wrapper.text()).toContain('PMS sync is stale')
|
expect(wrapper.text()).not.toContain('PMS sync is stale')
|
||||||
expect(wrapper.text()).not.toContain('PMS_SYNC')
|
expect(wrapper.text()).not.toContain('PMS_SYNC')
|
||||||
expect(wrapper.text()).not.toContain('stale-v1')
|
expect(wrapper.text()).not.toContain('stale-v1')
|
||||||
})
|
})
|
||||||
@@ -1226,6 +1252,45 @@ describe('reservation V4 pages', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('hides catalog technical warnings from ordinary V4 business cards', async () => {
|
||||||
|
const detail = createOrderTaskDetail()
|
||||||
|
vi.mocked(service.fetchReservationV4AccountLookups).mockResolvedValue({
|
||||||
|
hotel_id: 'HOTEL-TEST',
|
||||||
|
catalog_type: 'ACCOUNT',
|
||||||
|
catalog_source: 'PMS_SYNC',
|
||||||
|
catalog_version: 'seed-v1',
|
||||||
|
stale: true,
|
||||||
|
items: [],
|
||||||
|
page: {
|
||||||
|
page_num: 1,
|
||||||
|
page_size: 100,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
warnings: ['固定种子初始化,后续接入真实 PMS。'],
|
||||||
|
})
|
||||||
|
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
|
||||||
|
|
||||||
|
const wrapper = await mountWithPlugins(
|
||||||
|
ReservationV4OrderTaskDetailView,
|
||||||
|
'/reservation/order-tasks/9001',
|
||||||
|
)
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.empty)
|
||||||
|
expect(wrapper.text()).not.toContain('固定种子初始化')
|
||||||
|
expect(wrapper.text()).not.toContain('真实 PMS')
|
||||||
|
expect(wrapper.text()).not.toContain('PMS_SYNC')
|
||||||
|
expect(wrapper.text()).not.toContain('seed-v1')
|
||||||
|
expect(wrapper.text()).not.toContain(zhCN.taskV4.lookup.stale)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps the per-card primary action right aligned on narrow screens', () => {
|
||||||
|
expect(taskCardSectionSource).toContain('@media (max-width: 980px)')
|
||||||
|
expect(taskCardSectionSource).toContain('.task-card-section__status-actions')
|
||||||
|
expect(taskCardSectionSource).toContain('align-self: stretch')
|
||||||
|
expect(taskCardSectionSource).toContain('justify-content: flex-end')
|
||||||
|
})
|
||||||
|
|
||||||
it('requires confirmed order id before resolving an unresolved V4 review card', async () => {
|
it('requires confirmed order id before resolving an unresolved V4 review card', async () => {
|
||||||
const detail = createOrderTaskDetail({
|
const detail = createOrderTaskDetail({
|
||||||
businessCardStatus: 'REVIEW_REQUIRED',
|
businessCardStatus: 'REVIEW_REQUIRED',
|
||||||
|
|||||||
Reference in New Issue
Block a user