前端调整V4预订事项用户化展示

This commit is contained in:
andy
2026-07-21 20:54:24 +07:00
parent 350bb3310b
commit c521eb6dc0
20 changed files with 703 additions and 657 deletions

View File

@@ -52,7 +52,7 @@ describe('reservation V4 pages', () => {
mockCatalogLookups()
})
it('renders V4 order task cards, loads lookup options and confirms only selected codes', async () => {
it('renders reservation handling cards, hides default diagnostics and confirms only selected codes', async () => {
const detail = createOrderTaskDetail()
vi.mocked(service.fetchReservationV4OrderTaskDetail).mockResolvedValue(detail)
vi.mocked(service.confirmReservationV4OrderTaskCard).mockResolvedValue({
@@ -69,11 +69,18 @@ describe('reservation V4 pages', () => {
)
await flushPromises()
expect(wrapper.text()).toContain('V4 订单任务详情')
expect(wrapper.text()).toContain('订单事项办理')
expect(wrapper.text()).toContain('Booking Request')
expect(wrapper.text()).toContain('基础信息')
expect(wrapper.text()).toContain('业务任务卡')
expect(wrapper.text()).toContain('Backend contract issue')
expect(wrapper.text()).toContain('预订基础信息')
expect(wrapper.text()).toContain('预订事项')
expect(wrapper.text()).toContain('房型与日期')
expect(wrapper.text()).not.toContain('V4 订单任务详情')
expect(wrapper.text()).not.toContain('Backend contract issue')
expect(wrapper.text()).not.toContain('card-basic')
expect(wrapper.text()).not.toContain('card-room')
expect(wrapper.text()).not.toContain('#9001')
expect(wrapper.text()).not.toContain(zhCN.taskV4.orderTaskId)
expect(wrapper.text()).not.toContain(zhCN.taskV4.displayPayload)
expect(service.fetchReservationV4AccountLookups).toHaveBeenCalledWith({
hotel_id: 'HOTEL-TEST',
page_num: 1,
@@ -102,7 +109,7 @@ describe('reservation V4 pages', () => {
})
})
it('keeps V4 task card layout classes for styled card metadata and payload summary', async () => {
it('keeps task card layout classes and places the primary card action in the card header', async () => {
const detail = createOrderTaskDetail()
detail.business_cards[0]!.card_type = 'VOUCHER'
detail.business_cards[0]!.display_payload = {
@@ -119,10 +126,10 @@ describe('reservation V4 pages', () => {
expect(wrapper.findAll('.task-card-section')).toHaveLength(2)
expect(wrapper.find('.task-card-section__header').exists()).toBe(true)
expect(wrapper.find('.card-meta-grid').exists()).toBe(true)
expect(wrapper.find('.card-meta-item').text()).toContain(zhCN.task.reviewStatus)
expect(wrapper.find('details.safe-payload > summary').text()).toContain(zhCN.taskV4.displayPayload)
expect(wrapper.find('.card-actions .primary-button').text()).toContain(zhCN.taskV4.confirmCard)
expect(wrapper.find('.card-meta-grid').exists()).toBe(false)
expect(wrapper.find('details.safe-payload').exists()).toBe(false)
expect(wrapper.find('.task-card-section__header .primary-button').text()).toContain(zhCN.taskV4.confirmCard)
expect(wrapper.find('.card-actions .primary-button').exists()).toBe(false)
})
it('does not render direct attachment URLs from V4 source message payload', async () => {
@@ -184,17 +191,16 @@ describe('reservation V4 pages', () => {
)
await flushPromises()
expect(service.fetchSourceMessageConversation).toHaveBeenCalledWith('30001')
const pageText = wrapper.text()
const basicIndex = pageText.indexOf(zhCN.taskV4.basicInformationCard)
const businessIndex = pageText.indexOf(zhCN.taskV4.businessCards)
const sourceIndex = pageText.indexOf(zhCN.taskV4.sourceMessageCard)
expect(basicIndex).toBeGreaterThanOrEqual(0)
expect(businessIndex).toBeGreaterThan(basicIndex)
expect(sourceIndex).toBeGreaterThan(businessIndex)
const sections = wrapper.findAll('.th-section')
expect(sections[sections.length - 1]?.text()).toContain(zhCN.taskV4.sourceMessageCard)
expect(pageText).toContain('Current trigger email body opening.')
expect(sections[sections.length - 1]?.text()).toContain(zhCN.taskV4.sourceMessage.bodyCollapsed)
expect(service.fetchSourceMessageConversation).not.toHaveBeenCalled()
expect(pageText).not.toContain('Current trigger email body opening.')
expect(pageText).not.toContain('OLDER_MESSAGE_BODY')
expect(pageText).not.toContain('REPLY_MESSAGE_BODY')
expect(pageText).not.toContain('CURRENT_BODY_TAIL')
@@ -209,6 +215,8 @@ describe('reservation V4 pages', () => {
await expandButton!.trigger('click')
await flushPromises()
expect(service.fetchSourceMessageConversation).toHaveBeenCalledWith('30001')
expect(wrapper.text()).toContain('Current trigger email body opening.')
expect(wrapper.text()).toContain('CURRENT_BODY_TAIL')
expect(wrapper.text()).toContain(zhCN.taskV4.sourceMessage.collapseBody)
})
@@ -228,6 +236,17 @@ describe('reservation V4 pages', () => {
await flushPromises()
expect(wrapper.text()).toContain('Please book one twin room.')
expect(wrapper.text()).not.toContain(zhCN.taskV4.sourceMessage.bodyLoadFailed)
expect(service.fetchSourceMessageConversation).not.toHaveBeenCalled()
const expandButton = wrapper
.findAll('button')
.find((button) => button.text().includes(zhCN.taskV4.sourceMessage.showFullBody))
expect(expandButton).toBeTruthy()
await expandButton!.trigger('click')
await flushPromises()
expect(service.fetchSourceMessageConversation).toHaveBeenCalledWith('30001')
expect(wrapper.text()).toContain(zhCN.taskV4.sourceMessage.bodyLoadFailed)
expect(wrapper.text()).toContain(zhCN.task.viewConversation)
})
@@ -250,7 +269,7 @@ describe('reservation V4 pages', () => {
)
await flushPromises()
expect(wrapper.text()).toContain('Sanitized current email opening.')
expect(wrapper.text()).not.toContain('Sanitized current email opening.')
expect(wrapper.text()).not.toContain('SANITIZED_HTML_TAIL')
expect(wrapper.text()).not.toContain('RAW_HTML_SHOULD_NOT_RENDER')
@@ -261,6 +280,7 @@ describe('reservation V4 pages', () => {
await expandButton!.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('Sanitized current email opening.')
expect(wrapper.text()).toContain('SANITIZED_HTML_TAIL')
expect(wrapper.html()).toContain('<p>Sanitized current email opening.')
expect(wrapper.html()).not.toContain('RAW_HTML_SHOULD_NOT_RENDER')
@@ -283,6 +303,14 @@ describe('reservation V4 pages', () => {
)
await flushPromises()
expect(wrapper.text()).not.toContain('Plain text fallback body.')
const expandButton = wrapper
.findAll('button')
.find((button) => button.text().includes(zhCN.taskV4.sourceMessage.showFullBody))
expect(expandButton).toBeTruthy()
await expandButton!.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('Plain text fallback body.')
expect(wrapper.text()).not.toContain('SANITIZED_HTML_SHOULD_NOT_RENDER')
expect(wrapper.text()).not.toContain('RAW_HTML_SHOULD_NOT_RENDER')
@@ -373,7 +401,7 @@ describe('reservation V4 pages', () => {
const paymentCard = wrapper
.findAll('.task-card-section')
.find((section) => section.text().includes(zhCN.cardType.PAYMENT))
.find((section) => section.text().includes(zhCN.taskV4.paymentCard))
expect(paymentCard).toBeTruthy()
await paymentCard!.find('button.primary-button').trigger('click')
await flushPromises()
@@ -409,9 +437,8 @@ describe('reservation V4 pages', () => {
expect(roomingListCard.text()).toContain('GRP-001')
expect(roomingListSection!.findAll('a').filter((link) => link.text() === zhCN.task.viewOrder)).toHaveLength(1)
expect(wrapper.text()).toContain(zhCN.taskV4.sourceMessageCard)
expect(wrapper.text().indexOf(zhCN.taskV4.sourceMessageCard)).toBeGreaterThan(
wrapper.text().indexOf(zhCN.taskV4.roomingList.title),
)
const sections = wrapper.findAll('.th-section')
expect(sections[sections.length - 1]?.text()).toContain(zhCN.taskV4.sourceMessageCard)
expect(roomingListSection!.find('details.safe-payload').exists()).toBe(false)
expect(roomingListSection!.text()).not.toContain('ROW_SHOULD_NOT_RENDER')
@@ -592,13 +619,13 @@ describe('reservation V4 pages', () => {
.find((section) => section.find('[data-testid="trace-card"]').exists())
expect(traceSection).toBeTruthy()
expect(traceSection!.text()).toContain('SET EXTRA BED')
expect(traceSection!.find('select[name="/trace_items/0/target_room_type_code"]').text()).toContain('TWN - Twin')
expect(traceSection!.find('select[name="/trace_items/0/target_room_type_code"]').text()).toContain('RM2')
const roomCountInput = traceSection!.find('input[name="/trace_items/0/extra_bed_room_count"]')
expect(roomCountInput.attributes('type')).toBe('number')
expect(roomCountInput.attributes('min')).toBe('1')
expect(roomCountInput.attributes('step')).toBe('1')
await traceSection!.find('select[name="/trace_items/0/target_room_type_code"]').setValue('TWN')
await traceSection!.find('select[name="/trace_items/0/target_room_type_code"]').setValue('RM2')
await roomCountInput.setValue('0')
await traceSection!.find('select[name="/trace_items/0/department_code"]').setValue('FO+HSK')
await traceSection!.find('button.primary-button').trigger('click')
@@ -616,7 +643,7 @@ describe('reservation V4 pages', () => {
confirmed_payload: {
trace_items: [
{
target_room_type_code: 'TWN',
target_room_type_code: 'RM2',
extra_bed_room_count: 2,
department_code: 'FO+HSK',
},
@@ -770,11 +797,11 @@ describe('reservation V4 pages', () => {
group_block_name: '前端修正团队名',
arrival_date: '2026-07-26',
departure_date: '2026-07-29',
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
group_booking_status: 'DEF',
room_items: [
{
room_type_code: 'TWN',
room_type_code: 'RM2',
room_count: 2,
},
],
@@ -858,13 +885,13 @@ describe('reservation V4 pages', () => {
arrival_date: '2026-07-26',
departure_date: '2026-07-29',
nights: 3,
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
breakfast_included: true,
group_booking_status: 'TEN',
group_booking_status_label: 'TEN-Tentative',
room_items: [
{
room_type_code: 'TWN',
room_type_code: 'RM2',
room_count: 2,
},
],
@@ -874,7 +901,7 @@ describe('reservation V4 pages', () => {
departure_date: '2026-07-31',
room_items: [
{
room_type_code: 'DBL',
room_type_code: 'RM3',
room_count: 3,
},
],
@@ -884,13 +911,13 @@ describe('reservation V4 pages', () => {
arrival_date: '2026-07-27',
departure_date: '2026-07-31',
nights: 4,
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
breakfast_included: true,
group_booking_status: 'TEN',
group_booking_status_label: 'TEN-Tentative',
room_items: [
{
room_type_code: 'DBL',
room_type_code: 'RM3',
room_count: 3,
},
],
@@ -953,13 +980,13 @@ describe('reservation V4 pages', () => {
arrival_date: '2026-08-01',
departure_date: '2026-08-05',
nights: 4,
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
breakfast_included: true,
group_booking_status: 'DEF',
group_booking_status_label: 'DEF-Definite',
room_items: [
{
room_type_code: 'KING',
room_type_code: 'SU1',
room_count: 1,
},
],
@@ -969,13 +996,13 @@ describe('reservation V4 pages', () => {
arrival_date: '2026-08-01',
departure_date: '2026-08-05',
nights: 4,
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
breakfast_included: true,
group_booking_status: 'DEF',
group_booking_status_label: 'DEF-Definite',
room_items: [
{
room_type_code: 'KING',
room_type_code: 'SU1',
room_count: 1,
},
],
@@ -994,7 +1021,7 @@ describe('reservation V4 pages', () => {
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.currentValues)
expect(roomCard.text()).toContain(zhCN.taskV4.roomInformation.finalValues)
expect(roomCard.text()).toContain('GRP-V4-RI-CANCEL-001')
expect(roomCard.text()).toContain('KING')
expect(roomCard.text()).toContain('SU1')
expect(roomCard.find('input[name="/room_information/final_values/arrival_date"]').exists()).toBe(false)
expect(roomCard.find('select[name="/room_information/final_values/group_booking_status"]').exists()).toBe(false)
})
@@ -1027,7 +1054,7 @@ describe('reservation V4 pages', () => {
await flushPromises()
const roomCard = wrapper.find('[data-testid="room-information-card"]')
await roomCard.find('select[name="/room_information/final_values/room_items/0/room_type_code"]').setValue('TWN')
await roomCard.find('select[name="/room_information/final_values/room_items/0/room_type_code"]').setValue('RM2')
await wrapper.find('input[name="v4_confirmed_order_id"]').setValue('order-2001')
await wrapper.find('textarea').setValue('confirmed by email evidence')
await roomCard.find('button').trigger('click')
@@ -1040,7 +1067,7 @@ describe('reservation V4 pages', () => {
field_overrides: [
{
field_pointer: '/room_information/final_values/room_items/0/room_type_code',
value: 'TWN',
value: 'RM2',
},
],
})
@@ -1073,8 +1100,8 @@ describe('reservation V4 pages', () => {
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.empty)
expect(wrapper.text()).toContain(zhCN.taskV4.lookup.stale)
expect(wrapper.text()).toContain('PMS sync is stale')
expect(wrapper.text()).toContain('PMS_SYNC')
expect(wrapper.text()).toContain('stale-v1')
expect(wrapper.text()).not.toContain('PMS_SYNC')
expect(wrapper.text()).not.toContain('stale-v1')
})
it('does not submit a catalog field value that is missing from the loaded lookup result', async () => {
@@ -1359,8 +1386,8 @@ function mockCatalogLookups() {
stale: false,
items: [
{
code: 'TWN',
display_name: 'Twin',
code: 'RM2',
display_name: 'RM2',
status: 'ACTIVE',
catalog_source: 'SYSTEM_MANAGED',
market_code: null,
@@ -1386,8 +1413,8 @@ function mockCatalogLookups() {
stale: false,
items: [
{
code: 'GROUP',
display_name: 'Group Rate',
code: 'GRPA2-850UP',
display_name: 'GRPA2-850UP',
status: 'ACTIVE',
catalog_source: 'SYSTEM_MANAGED',
market_code: null,
@@ -1750,7 +1777,7 @@ function useTraceBusinessCard(
itemType === 'EXTRA_BED'
? {
item_type: 'EXTRA_BED',
target_room_type_code: 'TWN',
target_room_type_code: 'RM2',
extra_bed_room_count: 1,
department_code: 'FO',
content: 'CONTENT_SHOULD_NOT_RENDER',
@@ -1770,7 +1797,7 @@ function useTraceBusinessCard(
? [
createField('/trace_items/0/target_room_type_code', {
display_name: 'Target Room Type',
value: 'TWN',
value: 'RM2',
options_source: 'RESERVATION_V4_ROOM_TYPE_CATALOG',
control_type: 'SELECT',
edit_scope: isReviewRequired ? 'REVIEW' : 'CONFIRM',
@@ -1891,13 +1918,13 @@ function createRoomInformationDisplayPayload(overrides: {
arrival_date: '2026-07-26',
departure_date: '2026-07-29',
nights: 3,
rate_code: 'GROUP',
rate_code: 'GRPA2-850UP',
breakfast_included: true,
group_booking_status: 'TEN',
group_booking_status_label: 'TEN-Tentative',
room_items: [
{
room_type_code: 'TWN',
room_type_code: 'RM2',
room_count: 2,
},
],
@@ -1962,7 +1989,7 @@ function createRoomInformationFields(reviewMode = false): ReservationV4TaskCardR
}),
createField('/room_information/final_values/rate_code', {
display_name: 'Rate Code',
value: 'GROUP',
value: 'GRPA2-850UP',
required: true,
control_type: 'SELECT',
options_source: 'RESERVATION_V4_RATE_CODE_CATALOG',
@@ -1972,7 +1999,7 @@ function createRoomInformationFields(reviewMode = false): ReservationV4TaskCardR
}),
createField('/room_information/final_values/room_items/0/room_type_code', {
display_name: '房型代码',
value: reviewMode ? '' : 'TWN',
value: reviewMode ? '' : 'RM2',
required: true,
control_type: 'SELECT',
options_source: 'RESERVATION_V4_ROOM_TYPE_CATALOG',