接入V4房型信息展示模型

This commit is contained in:
andy
2026-07-21 09:04:13 +07:00
parent 1d593f05fd
commit 8d181ee8ad
21 changed files with 1390 additions and 77 deletions

View File

@@ -213,6 +213,7 @@ import {
buildReservationV4InitialFieldValues,
buildReservationV4ReviewOverrides,
isReservationV4ConfirmWritableField,
isReservationV4RoomInformationSafeField,
isReservationV4ReviewWritableField,
mapReservationV4BackendDetailsToFields,
reservationV4FieldKey,
@@ -341,7 +342,8 @@ function canReviewCard(card: ReservationV4TaskCardResult): boolean {
}
async function submitConfirm(card: ReservationV4TaskCardResult): Promise<void> {
const writableFields = card.fields.filter(isReservationV4ConfirmWritableField)
const submissionFields = submissionFieldsForCard(card)
const writableFields = submissionFields.filter(isReservationV4ConfirmWritableField)
const localErrors = validateReservationV4Fields(writableFields, cardValues.value[card.card_id] ?? {})
cardFieldErrors.value = {
...cardFieldErrors.value,
@@ -367,7 +369,7 @@ async function submitConfirm(card: ReservationV4TaskCardResult): Promise<void> {
try {
const result = await confirmReservationV4OrderTaskCard(orderTaskId.value, card.card_id, {
version: card.version,
confirmed_payload: buildReservationV4ConfirmedPayload(card.fields, cardValues.value[card.card_id] ?? {}),
confirmed_payload: buildReservationV4ConfirmedPayload(submissionFields, cardValues.value[card.card_id] ?? {}),
})
applyDetail(result)
cardSuccessMessages.value = {
@@ -383,7 +385,17 @@ async function submitConfirm(card: ReservationV4TaskCardResult): Promise<void> {
}
async function submitReview(card: ReservationV4TaskCardResult): Promise<void> {
const writableFields = card.fields.filter(isReservationV4ReviewWritableField)
const form = reviewForms.value[card.card_id] ?? { confirmed_order_id: '', reason: '' }
if (requiresConfirmedOrderId() && !form.confirmed_order_id.trim()) {
cardActionErrors.value = {
...cardActionErrors.value,
[card.card_id]: [t('taskV4.confirmedOrderRequired')],
}
return
}
const submissionFields = submissionFieldsForCard(card)
const writableFields = submissionFields.filter(isReservationV4ReviewWritableField)
const localErrors = validateReservationV4Fields(writableFields, cardValues.value[card.card_id] ?? {})
cardFieldErrors.value = {
...cardFieldErrors.value,
@@ -397,15 +409,6 @@ async function submitReview(card: ReservationV4TaskCardResult): Promise<void> {
return
}
const form = reviewForms.value[card.card_id] ?? { confirmed_order_id: '', reason: '' }
if (requiresConfirmedOrderId() && !form.confirmed_order_id.trim()) {
cardActionErrors.value = {
...cardActionErrors.value,
[card.card_id]: [t('taskV4.confirmedOrderRequired')],
}
return
}
submittingCardId.value = card.card_id
cardActionErrors.value = {
...cardActionErrors.value,
@@ -420,7 +423,7 @@ async function submitReview(card: ReservationV4TaskCardResult): Promise<void> {
version: card.version,
confirmed_order_id: form.confirmed_order_id.trim() || undefined,
reason: form.reason.trim() || undefined,
field_overrides: buildReservationV4ReviewOverrides(card.fields, cardValues.value[card.card_id] ?? {}),
field_overrides: buildReservationV4ReviewOverrides(submissionFields, cardValues.value[card.card_id] ?? {}),
})
applyDetail(result)
cardSuccessMessages.value = {
@@ -444,15 +447,43 @@ function requiresConfirmedOrderId(): boolean {
}
function editableFieldKeys(card: ReservationV4TaskCardResult): string[] {
const fields = submissionFieldsForCard(card)
const writableFields = card.card_status === 'REVIEW_REQUIRED'
? card.fields.filter(isReservationV4ReviewWritableField)
: card.fields.filter(isReservationV4ConfirmWritableField)
? fields.filter(isReservationV4ReviewWritableField)
: fields.filter(isReservationV4ConfirmWritableField)
return writableFields.map(reservationV4FieldKey)
}
function submissionFieldsForCard(card: ReservationV4TaskCardResult): ReservationV4TaskCardResult['fields'] {
return card.card_type === 'ROOM_INFORMATION'
? card.fields.filter((field) =>
isReservationV4RoomInformationSafeField(field) && !isGroupRoomInformationBreakfastField(card, field),
)
: card.fields
}
function isGroupRoomInformationBreakfastField(
card: ReservationV4TaskCardResult,
field: ReservationV4TaskCardResult['fields'][number],
): boolean {
return roomInformationBookingType(card) === 'GROUP' &&
reservationV4FieldKey(field) === '/room_information/final_values/breakfast_included'
}
function roomInformationBookingType(card: ReservationV4TaskCardResult): string {
const payload = card.display_payload
const roomInformation = isRecord(payload?.room_information) ? payload.room_information : null
const bookingType = roomInformation?.booking_type
return typeof bookingType === 'string' ? bookingType.toUpperCase() : ''
}
function isRecord(value: unknown): value is ReservationRecord {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
}
function applyCardActionError(card: ReservationV4TaskCardResult, error: unknown, fallback: string): void {
const formatted = formatApiError(error, fallback)
const mappedErrors = mapReservationV4BackendDetailsToFields(formatted.details, card.fields)
const mappedErrors = mapReservationV4BackendDetailsToFields(formatted.details, submissionFieldsForCard(card))
cardFieldErrors.value = {
...cardFieldErrors.value,
[card.card_id]: mappedErrors.fieldErrors,