实现V4订单详情总览页
This commit is contained in:
1 parent
e5218e10eb
commit
d45ff5b4ed
10 files changed
+889
-240
No files matched your search
@@ -11,6 +11,7 @@ import ReservationSourceMessageConversationView from '@/views/reservation/Reserv
|
||||
import ReservationTaskListView from '@/views/reservation/ReservationTaskListView.vue'
|
||||
import { useAuthStore } from '@/stores/authStore'
|
||||
import type {
|
||||
ReservationOrderDetailResult,
|
||||
ReservationOrderListResult,
|
||||
ReservationV4OrderTaskListResult,
|
||||
ReservationV4WorkbenchListResult,
|
||||
@@ -221,7 +222,7 @@ function createV4OrderTaskListResult(
|
||||
}
|
||||
}
|
||||
|
||||
function createOrderDetailResult(displayName = 'GRP-001') {
|
||||
function createOrderDetailResult(displayName = 'GRP-001'): ReservationOrderDetailResult {
|
||||
return {
|
||||
order: {
|
||||
order_id: displayName === 'GRP-002' ? '20002' : '20001',
|
||||
@@ -286,6 +287,49 @@ function createOrderDetailResult(displayName = 'GRP-001') {
|
||||
review_required_count: 1,
|
||||
confirmed_count: 0,
|
||||
},
|
||||
cards: [
|
||||
{
|
||||
card_id: '9100',
|
||||
card_type: 'SOURCE_MESSAGE_DISPLAY',
|
||||
event_type: null,
|
||||
source_event_index: 0,
|
||||
card_sort_order: 0,
|
||||
card_status: 'READONLY',
|
||||
review_status: null,
|
||||
confirmed_by: null,
|
||||
confirmed_at: null,
|
||||
latest_activity_at: '2026-07-08T05:05:00Z',
|
||||
ai_payload_json: 'unsafe ai payload must stay hidden',
|
||||
display_payload_json: 'unsafe display payload must stay hidden',
|
||||
confirmed_payload_json: 'unsafe confirmed payload must stay hidden',
|
||||
text_body: 'unsafe mail body must stay hidden',
|
||||
attachment_url: 'https://oss.example.test/private.xlsx',
|
||||
},
|
||||
{
|
||||
card_id: '9101',
|
||||
card_type: 'BASIC_INFORMATION',
|
||||
event_type: 'NEW_BOOKING',
|
||||
source_event_index: 1,
|
||||
card_sort_order: 10,
|
||||
card_status: 'CONFIRMED',
|
||||
review_status: null,
|
||||
confirmed_by: 'frontend-query-admin',
|
||||
confirmed_at: '2026-07-08T11:10:00Z',
|
||||
latest_activity_at: '2026-07-08T11:10:00Z',
|
||||
},
|
||||
{
|
||||
card_id: '9104',
|
||||
card_type: 'PAYMENT',
|
||||
event_type: 'PAYMENT',
|
||||
source_event_index: 3,
|
||||
card_sort_order: 60,
|
||||
card_status: 'REVIEW_REQUIRED',
|
||||
review_status: 'PENDING',
|
||||
confirmed_by: null,
|
||||
confirmed_at: null,
|
||||
latest_activity_at: '2026-07-08T11:20:00Z',
|
||||
},
|
||||
],
|
||||
source_message_summary: {
|
||||
source_message_id: '30003',
|
||||
hotel_id: 'HOTEL-TEST',
|
||||
@@ -303,8 +347,54 @@ function createOrderDetailResult(displayName = 'GRP-001') {
|
||||
latest_activity_at: '2026-07-08T05:10:00Z',
|
||||
},
|
||||
],
|
||||
order_overview: {
|
||||
account_code: 'QBD_TRAVEL',
|
||||
account_name: 'Q.B.D. TRAVEL GROUP CO., LTD',
|
||||
market_code: 'LEISURE',
|
||||
source_code: 'TRAVEL_AGENT',
|
||||
arrival_date: '2026-07-26',
|
||||
departure_date: '2026-07-29',
|
||||
rate_code: 'BAR',
|
||||
room_items: [
|
||||
{
|
||||
room_type_code: 'RM1',
|
||||
room_count: 2,
|
||||
},
|
||||
{
|
||||
room_type_code: 'RM2',
|
||||
room_count: 1,
|
||||
},
|
||||
],
|
||||
trace_card_status: 'CONFIRMED',
|
||||
rooming_list_card_status: 'PENDING_CONFIRM',
|
||||
payment_card_status: 'REVIEW_REQUIRED',
|
||||
latest_confirmed_at: '2026-07-08T11:20:00Z',
|
||||
ai_payload_json: 'unsafe overview payload must stay hidden',
|
||||
},
|
||||
next_v4_action: {
|
||||
order_task_id: '9001',
|
||||
card_id: '9104',
|
||||
action_type: 'REVIEW',
|
||||
action_status: 'REVIEW_REQUIRED',
|
||||
open_order_task_count: 1,
|
||||
},
|
||||
related_source_messages: [
|
||||
{
|
||||
source_message_id: '30003',
|
||||
hotel_id: 'HOTEL-TEST',
|
||||
external_message_id: 'm-v4-1',
|
||||
external_conversation_id: 'thread-v4-1',
|
||||
subject: 'V4 Booking Package',
|
||||
sender_summary: 'v4@example.test',
|
||||
received_at: '2026-07-08T05:00:00Z',
|
||||
source_sent_at: null,
|
||||
conversation_message_count: 1,
|
||||
html_body: '<strong>unsafe related mail body</strong>',
|
||||
attachment_url: 'https://oss.example.test/related.xlsx',
|
||||
},
|
||||
],
|
||||
warnings: [],
|
||||
}
|
||||
} as unknown as ReservationOrderDetailResult
|
||||
}
|
||||
|
||||
function createSourceMessageConversationResult(
|
||||
@@ -480,28 +570,65 @@ describe('reservation P0 views', () => {
|
||||
vi.mocked(service.fetchSourceMessageConversation).mockReset()
|
||||
})
|
||||
|
||||
it('renders active order task source evidence without the stale pending copy', async () => {
|
||||
it('renders the V4 order overview, next action, related source messages and safe card timeline', async () => {
|
||||
vi.mocked(service.fetchReservationOrderDetail).mockResolvedValue(createOrderDetailResult())
|
||||
|
||||
const wrapper = await mountWithPlugins(ReservationOrderDetailView, '/reservation/orders/20001', {
|
||||
ReservationTaskDetailPanel: {
|
||||
template: '<section />',
|
||||
},
|
||||
})
|
||||
const wrapper = await mountWithPlugins(ReservationOrderDetailView, '/reservation/orders/20001')
|
||||
await vi.dynamicImportSettled()
|
||||
|
||||
expect(wrapper.text()).toContain('Booking Request')
|
||||
expect(wrapper.text()).toContain('guest@example.test')
|
||||
expect(wrapper.text()).toContain('2')
|
||||
expect(wrapper.text()).toContain('前序任务未完成')
|
||||
expect(wrapper.text()).toContain('V4 当前确认快照')
|
||||
expect(wrapper.text()).toContain('QBD_TRAVEL')
|
||||
expect(wrapper.text()).toContain('Q.B.D. TRAVEL GROUP CO., LTD')
|
||||
expect(wrapper.text()).toContain('2026-07-26')
|
||||
expect(wrapper.text()).toContain('2026-07-29')
|
||||
expect(wrapper.text()).toContain('RM1 × 2')
|
||||
expect(wrapper.text()).toContain('下一步处理')
|
||||
expect(wrapper.find('a[href="/reservation/order-tasks/9001"]').text()).toContain('进入处理页')
|
||||
expect(wrapper.find('.primary-link[href="/reservation/order-tasks/9001"]').exists()).toBe(true)
|
||||
expect(wrapper.text()).toContain('关联来源消息')
|
||||
expect(wrapper.text()).toContain('v4@example.test')
|
||||
expect(wrapper.text()).toContain('查看邮件会话')
|
||||
expect(wrapper.find('a[href="/reservation/source-messages/30003/conversation"]').exists()).toBe(true)
|
||||
expect(wrapper.text()).toContain(zhCN.order.v4TaskTimeline)
|
||||
expect(wrapper.text()).toContain('order-ref-1')
|
||||
expect(wrapper.text()).toContain('V4 Booking Package')
|
||||
expect(wrapper.text()).not.toContain('PREVIOUS_TASK_NOT_FINISHED')
|
||||
expect(wrapper.find('.v4-timeline-item__main[href="/reservation/order-tasks/9001"]').exists()).toBe(true)
|
||||
expect(wrapper.text()).toContain('基础信息卡')
|
||||
expect(wrapper.text()).toContain('frontend-query-admin')
|
||||
expect(wrapper.text()).toContain('待复核')
|
||||
expect(wrapper.text()).not.toContain('unsafe ai payload must stay hidden')
|
||||
expect(wrapper.text()).not.toContain('unsafe display payload must stay hidden')
|
||||
expect(wrapper.text()).not.toContain('unsafe confirmed payload must stay hidden')
|
||||
expect(wrapper.text()).not.toContain('unsafe mail body must stay hidden')
|
||||
expect(wrapper.text()).not.toContain('https://oss.example.test')
|
||||
expect(wrapper.findComponent({ name: 'ReservationTaskDetailPanel' }).exists()).toBe(false)
|
||||
expect(wrapper.text()).not.toContain('来源邮件摘要字段待后端补充')
|
||||
})
|
||||
|
||||
it('shows empty states when an order has no V4 overview, next action, source messages or task timeline', async () => {
|
||||
const result = createOrderDetailResult()
|
||||
result.order_overview = null
|
||||
result.next_v4_action = {
|
||||
order_task_id: null,
|
||||
card_id: null,
|
||||
action_type: 'NONE',
|
||||
action_status: null,
|
||||
open_order_task_count: 0,
|
||||
}
|
||||
result.related_source_messages = []
|
||||
result.v4_order_tasks = []
|
||||
vi.mocked(service.fetchReservationOrderDetail).mockResolvedValue(result)
|
||||
|
||||
const wrapper = await mountWithPlugins(ReservationOrderDetailView, '/reservation/orders/20001')
|
||||
await vi.dynamicImportSettled()
|
||||
|
||||
expect(wrapper.text()).toContain('暂无已确认的 V4 订单快照')
|
||||
expect(wrapper.text()).toContain('暂无下一步 V4 处理动作')
|
||||
expect(wrapper.text()).toContain('暂无关联来源消息')
|
||||
expect(wrapper.text()).toContain(zhCN.order.v4TaskTimelineEmpty)
|
||||
expect(wrapper.find('a[href^="/reservation/order-tasks/"]').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('renders order list items returned by the backend', async () => {
|
||||
vi.mocked(service.fetchReservationOrders).mockResolvedValue(createOrderListResult())
|
||||
|
||||
|
||||
Reference in new issue
Block a user