实现V4目录管理后台前端

This commit is contained in:
andy
2026-07-20 00:09:58 +07:00
parent 739fccd955
commit f40f90553f
19 changed files with 1654 additions and 11 deletions

View File

@@ -45,7 +45,7 @@
| SuperAgent 查询上下文接口 1、2 | `docs/project/requirements/M002-ai-query-minimal-fields.md` | 阶段记录,用于理解接口 1、2 的最小字段实现;如与总契约冲突,以总契约为准。 |
| 订单任务主流程 V3 | `docs/project/requirements/M002-order-task-workflow-v3.md` | 当前开发基线,基于 0711 P0 冻结基线和 0712 P0.1 Parent Group 修订,覆盖 S10/S99、40 路由、方案 C、type-known manual review 同卡解阻和 fail-closed。 |
| 任务卡字段控件契约 V1 | `docs/project/requirements/M002-task-field-control-contract-v1.md` | 后端已返回 `fields[]` 控件元数据,规定人工复核控件复用和前后端边界;前端待接入。 |
| 订单任务多卡模型 V4 | `docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md` | 当前 V4 后端主入口后端已开放工作台统一列表、V4 订单任务列表 / 详情、卡片确认、复核解阻、S10/S99 来源通知详情和 ack前端页面接入仍按后续 checkpoint 跟进。 |
| 订单任务多卡模型 V4 | `docs/project/requirements/M002-v4-order-task-card-domain-model-cp2.md` | 当前 V4 主入口后端已开放工作台统一列表、V4 订单任务列表 / 详情、卡片确认、复核解阻、S10/S99 来源通知详情和 ack前端已完成 V4 页面第一版、目录 lookup 接入、订单详情 V4 时间线消费和系统设置目录管理 CP1。 |
| Manual Invoice 手工开票生成 | `docs/project/requirements/M009-manual-invoice-generation-v1.md` | 当前有效;后端 CP2 已支持无订单 / 无任务手工填写字段、填 Excel 模板、转 PDF、OSS 输出和生成记录。 |
| Rooming List Excel 生成 | `docs/project/requirements/M010-rooming-list-excel-generation-v1.md` | 当前有效;后端 CP1 已支持前端上传来源名单并填写目标字段,同步生成 `.xlsx` 直接下载;前端 V1 已新增 `/reservation/rooming-lists/new`,按 Blob 下载处理,不落库、不上传 OSS。 |
| 订单任务主流程 V2 | `docs/project/requirements/M002-order-task-workflow-v2.md` | 已实现阶段记录,保留用于理解当前代码中的 S000/S999、订单任务流转和 OPERA 模拟骨架。 |

View File

@@ -67,6 +67,9 @@
| `GET /api/admin/reservation/catalogs/room-types` / `GET /api/admin/reservation/catalogs/rate-codes` | 管理后台 Room Type / Rate Code 目录列表 | 必须带 `RESERVATION_CATALOG_MANAGE`;支持 `hotel_id``keyword``status``page_num``page_size``keyword` 搜索 code 时大小写不敏感,显示名仍按数据库比较规则;返回 `items[] + page`,包含 `id``catalog_type``code``display_name``status``catalog_source``external_id``sort_order``catalog_version``metadata_json``version``created_at``updated_at`。 |
| `POST /api/admin/reservation/catalogs/room-types` / `POST /api/admin/reservation/catalogs/rate-codes` | 管理后台新增 Room Type / Rate Code | 必须带 `RESERVATION_CATALOG_MANAGE`;请求 `hotel_id``code``display_name`,可选 `external_id``sort_order``catalog_version``metadata_json`;新增后默认 `ACTIVE``catalog_source=SYSTEM_MANAGED`,写管理审计。 |
| `PUT /api/admin/reservation/catalogs/room-types/{catalogId}/status` / `PUT /api/admin/reservation/catalogs/rate-codes/{catalogId}/status` | 管理后台启用 / 停用 Room Type / Rate Code | 必须带 `RESERVATION_CATALOG_MANAGE`;请求 `{"status":"ACTIVE"}``{"status":"DISABLED"}`;按记录所属酒店校验;停用后对应普通 lookup 不再返回;如果提交的状态和当前状态一致,后端幂等返回当前记录,不新增管理审计。 |
前端已在系统设置下新增 `/system/reservation-catalogs` 消费上述目录管理接口。页面入口要求 `RESERVATION_CATALOG_MANAGE`,列表过滤直接传 `hotel_id``keyword``status``page_num``page_size`Account 新增第一版固定提交 `market_code=LEISURE``source_code=TRAVEL_AGENT`;状态重复提交按成功提示处理,不额外弹失败。
| `POST /api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/confirm` | 确认 V4 订单任务卡 | 必须带 Bearer token需要 `RESERVATION_TASK_CONFIRM`,请求 JSON 带 `version`,可选 `confirmed_payload`Basic Information 必须先确认,业务卡第一版不强制逐张顺序确认;前端只提交当前卡 `fields[]` 中可编辑字段,后端以展示快照为基准合并,未开放字段会被忽略;确认前会按当前酒店数据库目录校验 Account / Room Type / Rate Code嵌套字段错误会返回如 `business_fields.after.room_items.0.room_type_code` 的路径,失败返回 `V4_FIELD_VALIDATION_FAILED`;确认后卡片 `CONFIRMED`、写 `confirmed_payload_json/confirmed_at/confirmed_by` 并锁定,重复确认返回错误;成功返回刷新后的订单任务详情。 |
| `POST /api/reservation/order-tasks/{orderTaskId}/cards/{cardId}/review-resolution` | V4 复核解阻并确认卡片 | 必须带 Bearer token需要 `RESERVATION_MANUAL_REVIEW_RESOLVE`,仅用于 `card_status=REVIEW_REQUIRED`;请求 JSON 带 `version`,可选 `field_overrides[]``reason`;订单任务归属未解决时 `confirmed_order_id` 必填,且必须是当前酒店下真实可见订单;目录错误字段可按 `validation_errors_json` / `fields[].validation_errors` 指向的 pointer 修正;成功后卡片 `CONFIRMED``review_status=RESOLVED`,写 `review_resolution_json/confirmed_payload_json/confirmed_at/confirmed_by` 并返回刷新后的订单任务详情。 |
| `POST /api/reservation/source-notifications/{notificationId}/ack` | 确认 V4 S10/S99 来源通知已读 / 已处理 | 必须带 Bearer token需要 `RESERVATION_TASK_CONFIRM`,请求 JSON 带 `version`;仅允许 `route_code=S10/S99`;确认后 `notification_status=ACKED`,写 `ack_by/ack_at`,成功返回刷新后的来源通知详情;重复 ack 返回当前已确认状态且不新增审计;该动作不创建订单、不参与订单阻塞。 |

View File

@@ -499,7 +499,7 @@ SuperAgent 当前不调用本 lookup API。SuperAgent 目录供给后续有两
| --- | --- | --- |
| M002-V4-CP11 | DB 管理目录与 Lookup API V1 | 新增 Account / Code 目录表、Repository、DirectoryService DB 实现、Account / Room Type / Rate Code lookup 查询接口、权限和测试 |
| M002-V4-CP12 | 前端 Lookup 接入 | V4 卡片字段渲染按 `options_source` 调用 lookup替换固定种子硬编码选项处理 stale / warning / 空目录 |
| M002-V4-CP13 | 目录管理后台 V1 | CP1 已完成 Account / Room Type / Rate Code 后端列表、新增、启用 / 停用接口`RESERVATION_CATALOG_MANAGE` 权限和管理审计;前端页面、Market / Source 独立管理后置 |
| M002-V4-CP13 | 目录管理后台 V1 | CP1 已完成 Account / Room Type / Rate Code 后端列表、新增、启用 / 停用闭环`RESERVATION_CATALOG_MANAGE` 权限和管理审计Market / Source 独立管理后置 |
| M002-V4-CP14 | PMS / OPERA / OHIP 目录同步 | 同步 Adapter、同步 run 表、失败重试、最后成功快照、同步状态管理入口 |
| M002-V4-CP15 | SuperAgent 目录供给 | 明确目录版本如何给 SuperAgent必要时新增机器目录接口或导出包 |
@@ -507,7 +507,7 @@ CP11 已作为后端第一步落地,因为它不依赖真实 PMS也能让
## 15. 仍需确认的问题
1. Account 的第一版真实维护入口后端已放在系统管理后台接口;前端菜单和页面布局仍需后续确认。
1. Account 的第一版真实维护入口已放在系统设置 `/system/reservation-catalogs`;前端第一版固定使用 `market_code=LEISURE``source_code=TRAVEL_AGENT`Market / Source 独立管理仍需后续确认。
2. Account code 是否继续使用本系统定义的稳定 code例如 `QBD_TRAVEL`,还是必须对齐 PMS profile code。
3. Market / Source 是否只允许随 Account 派生,还是未来允许用户在 Basic Information 中单独改选。
4. Room Type 第一版后端已支持系统管理维护;后续是否仍要接 PMS / OHIP 同步替换为主来源待确认。

View File

@@ -85,7 +85,7 @@
| `/api/admin/permissions` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_ROLE_MANAGE` | 保持只读;前端不能自造权限码 | 不需要写审计 |
| `/api/admin/menus/**` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_MENU_MANAGE``GET /tree``PUT /tree-order` 已沿用该权限 | 保持;菜单可见性不替代后端权限;批量树排序只允许修改 `parent_id``sort_order``sort_order` 为空时按请求顺序生成稳定排序 | 写操作必须记录管理审计,树排序审计记录调整前后的父级和排序;树查询不写审计 |
| `/api/admin/hotels/**` | `FRONTEND_ADMIN` | 已强制登录和 `HOTEL_MANAGE` | 保持;单酒店阶段只能一家 `ACTIVE` | 写操作必须记录管理审计 |
| `/api/admin/reservation/catalogs/**` | `FRONTEND_ADMIN` | 已实现目录管理后台 CP1强制登录、`RESERVATION_CATALOG_MANAGE` 和目标酒店访问权 | 保持;第一版只开放 Account、Room Type、Rate Code 列表、新增、启用 / 停用Market / Source 独立管理和真实 PMS 同步后置;停用目录不再进入普通 lookup | 新增和状态实际变化必须记录管理审计;重复提交相同状态按幂等返回,不新增审计;列表查询不写审计;不得返回 PMS 原始响应、Secret 或外部同步错误详情 |
| `/api/admin/reservation/catalogs/**` | `FRONTEND_ADMIN` | 已实现目录管理后台 CP1前端入口为 `/system/reservation-catalogs`强制登录、`RESERVATION_CATALOG_MANAGE` 和目标酒店访问权 | 保持;第一版只开放 Account、Room Type、Rate Code 列表、新增、启用 / 停用Market / Source 独立管理和真实 PMS 同步后置;停用目录不再进入普通 lookup | 新增和状态实际变化必须记录管理审计;重复提交相同状态按幂等返回,不新增审计;列表查询不写审计;不得返回 PMS 原始响应、Secret 或外部同步错误详情 |
| `GET /api/admin/audits` | `FRONTEND_ADMIN` | 已强制登录和 `SYSTEM_ADMIN_CONSOLE_ACCESS` | 保持;不返回 Secret、密码或 token | 查询审计不再写审计 |
### 3.5 调试和系统接口

View File

@@ -0,0 +1,126 @@
# M002 V4 Catalog Admin Frontend CP1 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Implement the Reservation V4 catalog management frontend page under System Settings for Account, Room Type, and Rate Code catalogs.
**Architecture:** Extend the existing system admin module with typed admin catalog service functions, a guarded `/system/reservation-catalogs` route, and a single focused Vue page that switches between the three catalog types. The page follows existing system admin list/form/pagination patterns and never bypasses backend permission, hotel, or catalog validation.
**Tech Stack:** Vue 3.5, TypeScript, Vue Router, Pinia auth store, Vue I18n, Vitest, existing `httpClient` and system admin CSS.
## Global Constraints
- API calls must stay in `client/src/services/systemAdminService.ts`.
- Types must stay in `client/src/types/systemAdmin.ts`.
- Route and tab entry require `RESERVATION_CATALOG_MANAGE`.
- Account create uses default `market_code=LEISURE` and `source_code=TRAVEL_AGENT`.
- List filters are `hotel_id`, `keyword`, `status`, `page_num`, `page_size`.
- No backend changes, no PMS / OPERA / OHIP integration, no V4 task card behavior changes.
- Do not submit secrets, demo keys, build artifacts, IDE files, or unrelated working tree changes.
---
### Task 1: Service And Route Contract
**Files:**
- Modify: `client/src/types/auth.ts`
- Modify: `client/src/types/systemAdmin.ts`
- Modify: `client/src/services/systemAdminService.ts`
- Modify: `client/src/router/index.ts`
- Test: `client/src/tests/systemAdminService.spec.ts`
- Test: `client/src/tests/reservationRouter.spec.ts`
**Interfaces:**
- Produces: `fetchAdminReservationCatalogAccounts`, `createAdminReservationCatalogAccount`, `updateAdminReservationCatalogAccountStatus`.
- Produces: `fetchAdminReservationCatalogRoomTypes`, `createAdminReservationCatalogRoomType`, `updateAdminReservationCatalogRoomTypeStatus`.
- Produces: `fetchAdminReservationCatalogRateCodes`, `createAdminReservationCatalogRateCode`, `updateAdminReservationCatalogRateCodeStatus`.
- [x] **Step 1: Write failing service tests**
```ts
await fetchAdminReservationCatalogAccounts({ hotel_id: 'HOTEL-TEST', keyword: 'qbd', status: 'ACTIVE', page_num: 2, page_size: 10 })
await createAdminReservationCatalogAccount({ hotel_id: 'HOTEL-TEST', account_code: 'ACME', account_name: 'Acme', market_code: 'LEISURE', source_code: 'TRAVEL_AGENT' })
await updateAdminReservationCatalogAccountStatus('10001', { status: 'DISABLED' })
```
- [x] **Step 2: Write failing router tests**
```ts
expect(router.resolve('/system/reservation-catalogs').name).toBe('system-reservation-catalogs')
expect(router.resolve('/system/reservation-catalogs').meta.permission).toBe('RESERVATION_CATALOG_MANAGE')
```
- [x] **Step 3: Implement types, services, and route**
Add the catalog request/response interfaces and route metadata, using only backend paths documented in `M002-v4-real-catalog-lookup-api-design.md`.
- [x] **Step 4: Verify task tests**
Run: `CI=true pnpm --dir client test -- systemAdminService.spec.ts reservationRouter.spec.ts`
---
### Task 2: Catalog Management Page
**Files:**
- Create: `client/src/views/system/SystemReservationCatalogsView.vue`
- Modify: `client/src/views/system/SystemAdminLayoutView.vue`
- Modify: `client/src/i18n/locales/zh-CN.ts`
- Modify: `client/src/i18n/locales/en-US.ts`
- Modify: `client/src/i18n/locales/th-TH.ts`
- Test: `client/src/tests/systemReservationCatalogsView.spec.ts`
**Interfaces:**
- Consumes service functions from Task 1.
- Produces a page that lists, creates, enables, and disables Account, Room Type, and Rate Code records.
- [x] **Step 1: Write failing page tests**
```ts
expect(wrapper.text()).toContain('Reservation V4 目录管理')
expect(fetchAdminReservationCatalogAccounts).toHaveBeenCalledWith(expect.objectContaining({ hotel_id: 'HOTEL-TEST' }))
await wrapper.find('form').trigger('submit.prevent')
expect(createAdminReservationCatalogAccount).toHaveBeenCalledWith(expect.objectContaining({ market_code: 'LEISURE', source_code: 'TRAVEL_AGENT' }))
```
- [x] **Step 2: Implement page UI**
Use existing system admin sections: filters, create form, catalog table, pagination, and row status action buttons.
- [x] **Step 3: Add i18n keys**
Add `nav.systemReservationCatalogs` and `systemAdmin.catalogs.*` to zh-CN, en-US, and th-TH.
- [x] **Step 4: Verify page tests**
Run: `CI=true pnpm --dir client test -- systemReservationCatalogsView.spec.ts`
---
### Task 3: Verification, Review, And Commit
**Files:**
- Review all changed frontend files.
- Commit only files related to this frontend CP1.
- [ ] **Step 1: Run checks**
Run:
```bash
CI=true pnpm --dir client lint
CI=true pnpm --dir client typecheck
CI=true pnpm --dir client test
CI=true pnpm --dir client build
```
- [ ] **Step 2: Code review**
Review for endpoint paths, permission gates, hotel filter behavior, idempotent status actions, stale/disabled catalog explanation, and accidental staging of unrelated files.
- [ ] **Step 3: Commit**
```bash
git add <only M002 V4 catalog admin frontend files>
git commit -m "实现V4目录管理后台前端"
```