From b7b04cf1ac9d3cc487af3007fb898efdba46daea Mon Sep 17 00:00:00 2001 From: andy Date: Mon, 20 Jul 2026 00:26:34 +0700 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=9B=AE=E5=BD=95=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=85=92=E5=BA=97=E7=AD=9B=E9=80=89=E4=B8=8E=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../systemReservationCatalogsView.spec.ts | 65 +++++++++++++++++++ .../system/SystemReservationCatalogsView.vue | 5 +- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/client/src/tests/systemReservationCatalogsView.spec.ts b/client/src/tests/systemReservationCatalogsView.spec.ts index 6028dfc..67e3be4 100644 --- a/client/src/tests/systemReservationCatalogsView.spec.ts +++ b/client/src/tests/systemReservationCatalogsView.spec.ts @@ -4,6 +4,7 @@ import { createI18n } from 'vue-i18n' import { beforeEach, describe, expect, it, vi } from 'vitest' import zhCN from '@/i18n/locales/zh-CN' +import { ApiError } from '@/services/httpClient' import { useAuthStore } from '@/stores/authStore' import SystemReservationCatalogsView from '@/views/system/SystemReservationCatalogsView.vue' @@ -145,6 +146,41 @@ describe('SystemReservationCatalogsView', () => { expect(wrapper.text()).toContain('新增后默认启用') }) + it('normalizes the blank hotel option to the selected hotel when querying lists', async () => { + const wrapper = mountCatalogView() + await flushPromises() + + await wrapper.find('select').setValue('') + await flushPromises() + + expect(systemAdminService.fetchAdminReservationCatalogAccounts).toHaveBeenLastCalledWith({ + hotel_id: 'HOTEL-TEST', + keyword: '', + status: '', + page_num: 1, + page_size: 20, + }) + }) + + it('shows backend duplicate-code conflict messages when catalog creation fails', async () => { + vi.mocked(systemAdminService.createAdminReservationCatalogAccount).mockRejectedValue( + new ApiError('Request failed with status 409', 409, { + error_code: 'RESERVATION_CATALOG_CODE_CONFLICT', + message: '目录代码已存在', + }), + ) + + const wrapper = mountCatalogView() + await flushPromises() + + await wrapper.find('[data-testid="catalog-account-code"]').setValue('QBD_TRAVEL') + await wrapper.find('[data-testid="catalog-account-name"]').setValue('Q.B.D. Travel') + await wrapper.find('[data-testid="catalog-create-form"]').trigger('submit') + await flushPromises() + + expect(wrapper.text()).toContain('目录代码已存在') + }) + it('switches to Room Type catalog and toggles status by catalog id', async () => { vi.mocked(systemAdminService.updateAdminReservationCatalogRoomTypeStatus).mockResolvedValue({ id: '20001', @@ -186,6 +222,35 @@ describe('SystemReservationCatalogsView', () => { }) }) + it('treats idempotent status responses as successful updates', async () => { + vi.mocked(systemAdminService.updateAdminReservationCatalogRoomTypeStatus).mockResolvedValue({ + id: '20001', + hotel_id: 'HOTEL-TEST', + catalog_type: 'ROOM_TYPE', + code: 'TWN', + display_name: 'Twin', + status: 'ACTIVE', + catalog_source: 'SYSTEM_MANAGED', + external_id: null, + sort_order: 100, + catalog_version: 'catalog-v1', + metadata_json: null, + version: 1, + created_at: '2026-07-19T02:00:00Z', + updated_at: '2026-07-19T02:00:00Z', + }) + + const wrapper = mountCatalogView() + await flushPromises() + + await wrapper.find('[data-testid="catalog-tab-room-types"]').trigger('click') + await flushPromises() + await wrapper.find('[data-testid="catalog-status-20001"]').trigger('click') + await flushPromises() + + expect(wrapper.text()).toContain('目录状态已更新') + }) + it('switches to Rate Code catalog and creates through the dedicated endpoint', async () => { vi.mocked(systemAdminService.createAdminReservationCatalogRateCode).mockResolvedValue({ id: '30001', diff --git a/client/src/views/system/SystemReservationCatalogsView.vue b/client/src/views/system/SystemReservationCatalogsView.vue index 5e86d95..513df60 100644 --- a/client/src/views/system/SystemReservationCatalogsView.vue +++ b/client/src/views/system/SystemReservationCatalogsView.vue @@ -559,7 +559,10 @@ async function loadCatalog(): Promise { loading.value = true errorMessage.value = '' try { - const query = { ...filters } + const query = { + ...filters, + hotel_id: activeHotelId(), + } const result = activeCatalog.value === 'accounts' ? await fetchAdminReservationCatalogAccounts(query) : activeCatalog.value === 'room-types'