修复人工复核必填字段提交
This commit is contained in:
@@ -141,6 +141,7 @@ import type {
|
|||||||
} from '@/types/reservation'
|
} from '@/types/reservation'
|
||||||
import { normalizeStableCode } from '@/utils/reservationDisplay'
|
import { normalizeStableCode } from '@/utils/reservationDisplay'
|
||||||
import {
|
import {
|
||||||
|
isReservationFieldRequired,
|
||||||
isReservationManualReviewFieldWritable,
|
isReservationManualReviewFieldWritable,
|
||||||
readReservationFieldValue,
|
readReservationFieldValue,
|
||||||
} from '@/utils/reservationFieldRules'
|
} from '@/utils/reservationFieldRules'
|
||||||
@@ -184,11 +185,7 @@ const formErrorMessage = ref('')
|
|||||||
const fieldOverrideInputs = ref<Record<string, string>>({})
|
const fieldOverrideInputs = ref<Record<string, string>>({})
|
||||||
const isResolved = computed(() => normalizeStableCode(props.reviewStatus) === 'RESOLVED')
|
const isResolved = computed(() => normalizeStableCode(props.reviewStatus) === 'RESOLVED')
|
||||||
const reviewStatusLabel = computed(() => props.reviewStatus || t('task.manualResolution.pendingStatus'))
|
const reviewStatusLabel = computed(() => props.reviewStatus || t('task.manualResolution.pendingStatus'))
|
||||||
const supportedMissingFields = computed(() =>
|
const supportedMissingFields = computed(() => buildReviewFieldItems())
|
||||||
extractMissingFields(props.manualReview)
|
|
||||||
.map((reference) => resolveMissingField(reference))
|
|
||||||
.filter((item): item is ManualResolutionFieldItem => item !== null),
|
|
||||||
)
|
|
||||||
const unsupportedMissingFields = computed(() =>
|
const unsupportedMissingFields = computed(() =>
|
||||||
extractMissingFields(props.manualReview).filter((reference) => resolveMissingField(reference) === null),
|
extractMissingFields(props.manualReview).filter((reference) => resolveMissingField(reference) === null),
|
||||||
)
|
)
|
||||||
@@ -253,17 +250,58 @@ function resolveMissingField(reference: string): ManualResolutionFieldItem | nul
|
|||||||
item.legacy_field_path === referenceFieldPath,
|
item.legacy_field_path === referenceFieldPath,
|
||||||
)
|
)
|
||||||
if (field && isReservationManualReviewFieldWritable(field)) {
|
if (field && isReservationManualReviewFieldWritable(field)) {
|
||||||
return {
|
return reviewFieldItemFromField(field, pointer)
|
||||||
key: field.field_pointer ?? field.field_path,
|
|
||||||
pointer: field.field_pointer ?? pointer,
|
|
||||||
fieldPath: field.field_path,
|
|
||||||
label: field.display_name,
|
|
||||||
field,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildReviewFieldItems(): ManualResolutionFieldItem[] {
|
||||||
|
const items: ManualResolutionFieldItem[] = []
|
||||||
|
const seenKeys = new Set<string>()
|
||||||
|
extractMissingFields(props.manualReview).forEach((reference) => {
|
||||||
|
const item = resolveMissingField(reference)
|
||||||
|
if (item) {
|
||||||
|
appendReviewFieldItem(items, seenKeys, item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
props.fields
|
||||||
|
.filter((field) => isReservationManualReviewFieldWritable(field))
|
||||||
|
.filter((field) => isReservationFieldRequired(field))
|
||||||
|
.filter((field) => isEmptyReviewFieldValue(readReservationFieldValue(field, props.fieldValues)))
|
||||||
|
.forEach((field) => appendReviewFieldItem(items, seenKeys, reviewFieldItemFromField(field)))
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
function reviewFieldItemFromField(
|
||||||
|
field: ReservationTaskFieldResult,
|
||||||
|
fallbackPointer?: string,
|
||||||
|
): ManualResolutionFieldItem {
|
||||||
|
return {
|
||||||
|
key: field.field_pointer ?? field.field_path,
|
||||||
|
pointer: field.field_pointer ?? fallbackPointer,
|
||||||
|
fieldPath: field.field_path,
|
||||||
|
label: field.display_name,
|
||||||
|
field,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendReviewFieldItem(
|
||||||
|
items: ManualResolutionFieldItem[],
|
||||||
|
seenKeys: Set<string>,
|
||||||
|
item: ManualResolutionFieldItem,
|
||||||
|
): void {
|
||||||
|
const dedupeKeys = [
|
||||||
|
item.pointer,
|
||||||
|
item.fieldPath,
|
||||||
|
item.field?.legacy_field_path,
|
||||||
|
].filter((key): key is string => Boolean(key))
|
||||||
|
if (dedupeKeys.some((key) => seenKeys.has(key))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dedupeKeys.forEach((key) => seenKeys.add(key))
|
||||||
|
items.push(item)
|
||||||
|
}
|
||||||
|
|
||||||
function readCurrentFieldValue(item: ManualResolutionFieldItem): string {
|
function readCurrentFieldValue(item: ManualResolutionFieldItem): string {
|
||||||
const value = item.field
|
const value = item.field
|
||||||
? readReservationFieldValue(item.field, props.fieldValues)
|
? readReservationFieldValue(item.field, props.fieldValues)
|
||||||
@@ -275,6 +313,19 @@ function fieldPointerToFieldPath(pointer: string): string {
|
|||||||
return pointer.replace(/^\//, '').replace(/\//g, '.')
|
return pointer.replace(/^\//, '').replace(/\//g, '.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isEmptyReviewFieldValue(value: unknown): boolean {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value.trim() === ''
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.length === 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
function formatJson(value: unknown): string {
|
function formatJson(value: unknown): string {
|
||||||
return JSON.stringify(value ?? {}, null, 2)
|
return JSON.stringify(value ?? {}, null, 2)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -920,6 +920,17 @@ describe('ReservationTaskDetailPanel', () => {
|
|||||||
input_editable: 'N',
|
input_editable: 'N',
|
||||||
value: null,
|
value: null,
|
||||||
}),
|
}),
|
||||||
|
createRequiredField({
|
||||||
|
field_path: 'extracted_fields.room_items.0.room_quantity',
|
||||||
|
field_pointer: '/extracted_fields/room_items/0/room_quantity',
|
||||||
|
legacy_field_path: 'extracted_fields.room_quantity',
|
||||||
|
display_name: '房量',
|
||||||
|
control_type: 'number',
|
||||||
|
edit_scope: 'normal_and_manual_review',
|
||||||
|
write_target: 'draft_payload_and_review_resolution',
|
||||||
|
raw_readonly: false,
|
||||||
|
value: null,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -974,12 +985,15 @@ describe('ReservationTaskDetailPanel', () => {
|
|||||||
expect(wrapper.text()).toContain('人工复核解阻')
|
expect(wrapper.text()).toContain('人工复核解阻')
|
||||||
expect(wrapper.text()).toContain('/extracted_fields/room_items/0/pms_room_type_code')
|
expect(wrapper.text()).toContain('/extracted_fields/room_items/0/pms_room_type_code')
|
||||||
expect(wrapper.text()).toContain('PMS 房型代码')
|
expect(wrapper.text()).toContain('PMS 房型代码')
|
||||||
|
expect(wrapper.text()).toContain('/extracted_fields/room_items/0/room_quantity')
|
||||||
|
expect(wrapper.text()).toContain('房量')
|
||||||
expect(wrapper.text()).not.toContain('人工转换')
|
expect(wrapper.text()).not.toContain('人工转换')
|
||||||
expect(wrapper.text()).not.toContain('保存草稿')
|
expect(wrapper.text()).not.toContain('保存草稿')
|
||||||
expect(wrapper.text()).not.toContain('确认任务')
|
expect(wrapper.text()).not.toContain('确认任务')
|
||||||
expect(wrapper.text()).not.toContain('OPERA 模拟操作')
|
expect(wrapper.text()).not.toContain('OPERA 模拟操作')
|
||||||
|
|
||||||
await wrapper.find('input[name="manual_resolution_field_override_0"]').setValue('RM3')
|
await wrapper.find('input[name="manual_resolution_field_override_0"]').setValue('RM3')
|
||||||
|
await wrapper.find('input[name="manual_resolution_field_override_1"]').setValue('2')
|
||||||
await wrapper.find('textarea[name="manual_resolution_reason"]').setValue('确认 PMS 房型代码')
|
await wrapper.find('textarea[name="manual_resolution_reason"]').setValue('确认 PMS 房型代码')
|
||||||
await findButton(wrapper, '提交复核结果').trigger('click')
|
await findButton(wrapper, '提交复核结果').trigger('click')
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
@@ -993,6 +1007,11 @@ describe('ReservationTaskDetailPanel', () => {
|
|||||||
field_path: 'extracted_fields.room_items.0.pms_room_type_code',
|
field_path: 'extracted_fields.room_items.0.pms_room_type_code',
|
||||||
value: 'RM3',
|
value: 'RM3',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field_pointer: '/extracted_fields/room_items/0/room_quantity',
|
||||||
|
field_path: 'extracted_fields.room_items.0.room_quantity',
|
||||||
|
value: '2',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
expect(service.fetchReservationTaskDetail).toHaveBeenCalledTimes(2)
|
expect(service.fetchReservationTaskDetail).toHaveBeenCalledTimes(2)
|
||||||
|
|||||||
Reference in New Issue
Block a user