更新第四种复杂的rooming list
This commit is contained in:
1 parent
e23131f4d0
commit
3bce336b6c
7 files changed
+315
-23
No files matched your search
@@ -96,7 +96,7 @@
|
||||
| `GET/POST/PUT /api/admin/menus...` | 系统管理菜单维护 | 需要 `SYSTEM_MENU_MANAGE`;允许保存未知路由,前端必须有未知路由兜底页;已提供完整菜单树查询和批量树排序保存。 |
|
||||
| `GET/POST/PUT /api/admin/hotels...` | 系统管理酒店维护 | 需要 `HOTEL_MANAGE`;新增酒店默认 `DISABLED`,单酒店阶段不能启用第二家 `ACTIVE`。 |
|
||||
| `GET /api/admin/audits` | 系统管理操作审计 | 需要 `SYSTEM_ADMIN_CONSOLE_ACCESS`;用于查看管理后台写操作审计,不包含密码、token、secret。 |
|
||||
| `POST /api/reservation/rooming-lists/generations` | 生成 Rooming List Excel | 必须带 Bearer token,需要 `RESERVATION_ROOMING_LIST_GENERATE`;请求为 multipart/form-data,成功后直接返回 `.xlsx` 文件流,前端按 Blob 下载处理。CP2 已实现:后端从来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 按分房结果计算,目标默认值区域只保留 Payment Type / Nationality。CP3 已实现:兼容 `英文姓` + `英文名` 第二种来源样式。CP4 已实现:兼容单列 `英文名` 第三种来源样式。无旅游日期来源样式使用前端提交的 `arrival` / `departure`。 |
|
||||
| `POST /api/reservation/rooming-lists/generations` | 生成 Rooming List Excel | 必须带 Bearer token,需要 `RESERVATION_ROOMING_LIST_GENERATE`;请求为 multipart/form-data,成功后直接返回 `.xlsx` 文件流,前端按 Blob 下载处理。CP2 已实现:后端从来源 Excel `旅游日期` 派生 Arrival / Departure,Adults 按分房结果计算,目标默认值区域只保留 Payment Type / Nationality。CP3 已实现:兼容 `英文姓` + `英文名` 第二种来源样式。CP4 已实现:兼容单列 `英文名` 第三种来源样式。CP5 已实现:兼容 `拼音` + `分房` 第四种来源样式并尊重原表分房,`儿童情况=不占床` 进入 Accompanying Guests 但不计入 Adults。无旅游日期来源样式使用前端提交的 `arrival` / `departure`。 |
|
||||
|
||||
### 5.1 本轮新增 / 修改接口说明
|
||||
|
||||
@@ -464,7 +464,7 @@ M009 后端 CP2 已实现:页面可不依赖订单或任务,用户手工填
|
||||
|
||||
### 5.12 Rooming List Excel 生成页面接入方向
|
||||
|
||||
M010 后端 CP1 已实现。第一版生成结果直接下载 `.xlsx`,不落库、不上传 OSS,不依赖订单或任务。CP2 已实现,前后端按本节新口径接入。CP3 已实现:兼容 `英文姓` + `英文名` 第二种来源名单样式。CP4 已实现:兼容单列 `英文名` 第三种来源名单样式。无旅游日期来源样式均由用户补充入住 / 离店日期。
|
||||
M010 后端 CP1 已实现。第一版生成结果直接下载 `.xlsx`,不落库、不上传 OSS,不依赖订单或任务。CP2 已实现,前后端按本节新口径接入。CP3 已实现:兼容 `英文姓` + `英文名` 第二种来源名单样式。CP4 已实现:兼容单列 `英文名` 第三种来源名单样式。CP5 已实现:兼容 `拼音` + `分房` 第四种来源名单样式并尊重原表分房。无旅游日期来源样式均由用户补充入住 / 离店日期。
|
||||
|
||||
接口:
|
||||
|
||||
@@ -484,12 +484,13 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
|
||||
- 前端 V1 已新增 `/reservation/rooming-lists/new` 页面,按 `RESERVATION_ROOMING_LIST_GENERATE` 路由权限保护,并使用登录态 Bearer token 调用正式业务接口。
|
||||
- 侧边栏入口不由前端硬编码公开,仍依赖后端登录态 `menus[]`。如需菜单中展示,建议菜单管理配置 `menu_code=RESERVATION_ROOMING_LIST`、`route_path=/reservation/rooming-lists/new`、`permission_code=RESERVATION_ROOMING_LIST_GENERATE`。
|
||||
- 该页面上传来源名单 Excel;第一种来源样式后端识别 `护照全名` 和 `旅游日期`,第二种来源样式后端识别 `英文姓` 和 `英文名`,第三种来源样式后端识别单列 `英文名`。
|
||||
- 第一种来源样式姓名支持 `LI/CHUNHONG` 和 `LI CHUNHONG` 两类格式;后端会把第一段写入目标 `Name`,剩余部分写入目标 `First Name`。第二种来源样式直接使用 `英文姓` 写入 `Name`,使用 `英文名` 写入 `First Name`。第三种来源样式复用第一种姓名拆分规则,支持 `CAI/HAIYUN` 或 `CAI HAIYUN`。
|
||||
- 前端必须让用户输入 `people_per_room` 和目标 `Room Type`,后端按名单顺序分组,并用 `ceil(total_people / people_per_room)` 生成房间行。
|
||||
- 该页面上传来源名单 Excel;第一种来源样式后端识别 `护照全名` 和 `旅游日期`,第二种来源样式后端识别 `英文姓` 和 `英文名`,第三种来源样式后端识别单列 `英文名`,第四种来源样式后端识别 `拼音` 和 `分房`。
|
||||
- 第一种来源样式姓名支持 `LI/CHUNHONG` 和 `LI CHUNHONG` 两类格式;后端会把第一段写入目标 `Name`,剩余部分写入目标 `First Name`。第二种来源样式直接使用 `英文姓` 写入 `Name`,使用 `英文名` 写入 `First Name`。第三种来源样式复用第一种姓名拆分规则,支持 `CAI/HAIYUN` 或 `CAI HAIYUN`。第四种来源样式使用 `拼音` 列,支持 `ZHANG JIANWEI` 这类空格拆分。
|
||||
- 前端必须让用户输入 `people_per_room` 和目标 `Room Type`。第一、二、三种来源样式后端按名单顺序分组,并用 `ceil(total_people / people_per_room)` 生成房间行;第四种 `拼音` + `分房` 来源样式中,`people_per_room` 仅为接口兼容必填,后端忽略其分组作用并完全尊重来源表原始分房。
|
||||
- 每组第一位旅客写入 `Name` / `First Name`,同组剩余旅客写入 `Accompanying Guests`,多人用英文逗号分隔。
|
||||
- CP3 起前端恢复 `Arrival` / `Departure` 日期输入:第一种来源样式可不填,后端优先从来源 Excel 的 `旅游日期` 派生;无旅游日期来源样式必须填写,后端使用用户提交日期写入目标 Excel。样例 `2026年5月9日-5月14日` 仍应生成 `Arrival=2026/05/09`、`Departure=2026/05/14`。
|
||||
- CP3 起前端恢复 `Arrival` / `Departure` 日期输入:第一种来源样式可不填,后端优先从来源 Excel 的 `旅游日期` 派生;无旅游日期来源样式必须填写,后端使用用户提交日期写入目标 Excel。样例 `2026年5月9日-5月14日` 仍应生成 `Arrival=09/05/2026`、`Departure=14/05/2026`。
|
||||
- 第二种和第三种来源样式中领队也进入房表;例如 `23+1` 或 `19+1` 表示客人 + 领队全部参与分房,实际人数以后端读取到的有效名单行数为准。
|
||||
- 第四种来源样式中 `分房=外住` 行不进入目标 Rooming List;`分房=用房1间` 开始一间新房,后续 `分房` 为空的名单行归入当前房间;`儿童情况=不占床` 的旅客仍显示在 `Accompanying Guests`,但不计入 `Adults`。
|
||||
- CP2 起前端不再展示或提交 `Adults`,后端按每个分房行的实际人数派生;尾房不足满房人数时按尾房实际人数写入。`Children` 第一版固定为 `0`。
|
||||
- CP2 起目标默认值区域只保留 `Payment Type` 和 `Nationality`:`Payment Type` 默认 `BTQR`,当前允许 `BTQR`、`CA`;`Nationality` 只允许 `KR`、`CN`、`TH`、`MM`、`RS`、`TW`。
|
||||
- CP2 页面不再展示或提交 `Title`、`Rate Code`、`VIP`、`Email`、`ID Type`、`ID Number`,这些目标列第一版固定为空。
|
||||
@@ -497,7 +498,7 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
- 失败时返回统一 JSON 错误,例如 `ROOMING_LIST_VALIDATION_FAILED`、`ROOMING_LIST_SOURCE_FILE_INVALID`、`HOTEL_ACCESS_DENIED` 或 `FRONTEND_PERMISSION_DENIED`。
|
||||
- 该上传接口会在 multipart 参数绑定前先校验 Bearer token 和 `RESERVATION_ROOMING_LIST_GENERATE` 权限;未登录时优先返回 401,不会因为缺少业务字段先返回 400。
|
||||
- `ROOMING_LIST_VALIDATION_FAILED` 应覆盖 multipart 必填字段缺失、`people_per_room` 数字格式错误、无旅游日期来源样式下缺少或错误的 `arrival` / `departure`、`payment_type` / `nationality` 枚举错误,`details[]` 返回字段级提示。
|
||||
- `ROOMING_LIST_SOURCE_FILE_INVALID` 应覆盖来源文件缺失、非 Excel、无法读取、既不能识别第一种 `护照全名` + `旅游日期`、也不能识别第二种 `英文姓` + `英文名` 或第三种单列 `英文名`、第一种来源样式旅游日期格式无法解析或同一文件出现多个不同旅游日期区间。
|
||||
- `ROOMING_LIST_SOURCE_FILE_INVALID` 应覆盖来源文件缺失、非 Excel、无法读取、既不能识别第一种 `护照全名` + `旅游日期`、也不能识别第二种 `英文姓` + `英文名`、第三种单列 `英文名` 或第四种 `拼音` + `分房`、第一种来源样式旅游日期格式无法解析或同一文件出现多个不同旅游日期区间。
|
||||
- 页面不要把上传文件内容、客人名单、生成文件内容写入浏览器日志、埋点、错误上报、URL 或 localStorage。
|
||||
- 第一版没有 preview 接口、生成记录接口、OSS URL、历史下载和订单 / 任务预填;前端不要在页面上承诺这些能力。
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
| 项目 | 内容 |
|
||||
| --- | --- |
|
||||
| 文档状态 | 后端 CP1 已实现;CP2 已实现旅游日期派生、Adults 系统计算和目标默认值字段收口;CP3 第二种来源名单样式已实现;CP4 第三种单列 `英文名` 来源名单样式已实现 |
|
||||
| 文档状态 | 后端 CP1 已实现;CP2 已实现旅游日期派生、Adults 系统计算和目标默认值字段收口;CP3 第二种来源名单样式已实现;CP4 第三种单列 `英文名` 来源名单样式已实现;CP5 第四种 `拼音` + `分房` 原表分房样式已实现 |
|
||||
| 适用范围 | 从旅行团名单 Excel 解析护照姓名,并生成酒店 / PMS 可导入的 Rooming List Excel |
|
||||
| 当前目标 | CP1 已支持前端上传来源 Excel、填写分房和目标列默认值,后端同步生成目标格式 `.xlsx`;CP2 收口为后端从来源 `旅游日期` 派生入住 / 离店日期,成人数由系统按分房结果计算,目标默认值区域只保留付款方式和国籍;CP3 兼容 `英文姓` + `英文名` 第二种名单样式;CP4 兼容单列 `英文名` 第三种名单样式;无旅游日期来源样式均由用户补充入住 / 离店日期 |
|
||||
| 当前目标 | CP1 已支持前端上传来源 Excel、填写分房和目标列默认值,后端同步生成目标格式 `.xlsx`;CP2 收口为后端从来源 `旅游日期` 派生入住 / 离店日期,成人数由系统按分房结果计算,目标默认值区域只保留付款方式和国籍;CP3 兼容 `英文姓` + `英文名` 第二种名单样式;CP4 兼容单列 `英文名` 第三种名单样式;CP5 兼容 `拼音` + `分房` 第四种名单样式并尊重原表分房;无旅游日期来源样式均由用户补充入住 / 离店日期 |
|
||||
| 依赖能力 | 登录权限、酒店上下文、Apache POI 或等价 Excel 读写能力 |
|
||||
|
||||
## 1. 背景
|
||||
@@ -53,6 +53,17 @@ CP4 目标调整:
|
||||
- 第三种样式中的 `领队` 行也进入房表。例如 `19+1` 应理解为 19 位客人 + 1 位领队,合计 20 位入住人全部参与分房。
|
||||
- 来源表中的中文名、性别、证件号、生日、出生地、签发地、联系方式、小费、住宿说明等字段第一版仍不写入目标 Excel,也不在错误响应或日志中回显。
|
||||
|
||||
CP5 目标调整:
|
||||
|
||||
- 兼容第四种来源名单样式:表头包含 `拼音`、`分房`,可选包含 `儿童情况`。
|
||||
- 第四种样式的 `拼音` 单元格值形如 `ZHANG JIANWEI`,后端复用空格拆分规则,第一段写入目标 `Name`,剩余部分写入目标 `First Name`。
|
||||
- 第四种样式必须尊重来源表已经标注的分房结果:`用房1间` 表示开始一间新房,后续 `分房` 为空的名单行归入当前房间,直到下一次 `用房1间` 或 `外住`。
|
||||
- `分房=外住` 的行不进入目标 Rooming List;如果当前房间已开始,遇到 `外住` 前会先结束当前房间。
|
||||
- `儿童情况=不占床` 的旅客仍进入当前房间的 `Accompanying Guests`,但不计入目标 `Adults`;`儿童情况=占床` 或空白按占床人员计入 `Adults`。
|
||||
- 第四种样式没有可靠入住 / 离店日期来源,后端不得从标题、团号或航班日期猜测酒店入住 / 离店日期;必须使用前端提交的 `arrival` / `departure`。
|
||||
- 第四种样式下 `people_per_room` 仍因当前接口兼容保持必填,但实际生成时忽略该字段,目标房间行完全以后端读取到的来源原表分房为准。
|
||||
- 来源表中的中文名、性别、出生日期、出生地、护照、签发地、签发日期、有效期、联系方式、备注等字段第一版仍不写入目标 Excel,也不在错误响应或日志中回显。
|
||||
|
||||
第一阶段不做:
|
||||
|
||||
- 不落业务订单。
|
||||
@@ -78,7 +89,7 @@ CP4 目标调整:
|
||||
|
||||
## 4. 来源 Excel 解析规则
|
||||
|
||||
基于当前样例来源文件,当前支持三类来源名单格式。后端应先在来源 Excel 中识别表头组合,再选择对应解析器。
|
||||
基于当前样例来源文件,当前支持四类来源名单格式。后端应先在来源 Excel 中识别表头组合,再选择对应解析器。
|
||||
|
||||
### 4.1 第一种来源样式:护照全名 + 旅游日期
|
||||
|
||||
@@ -199,6 +210,36 @@ Sheet1 第 4 行起:名单数据
|
||||
- 不读取也不返回中文名、性别、证件号、生日、出生地、签发地、联系方式、小费、住宿说明。
|
||||
- 第三种样式没有 `旅游日期`,后端不得从航班行猜测入住 / 离店日期;必须使用前端提交的 `arrival` / `departure`。
|
||||
|
||||
### 4.4 第四种来源样式:拼音 + 分房
|
||||
|
||||
第四种样式识别以下表头:
|
||||
|
||||
| 来源字段 | 中文说明 | 第一版用途 |
|
||||
| --- | --- | --- |
|
||||
| `拼音` | 护照英文姓名,通常为空格分隔 | 拆分后写入目标 Excel 的 `Name` 和 `First Name` |
|
||||
| `分房` | 来源表人工分房标记,例如 `用房1间`、`外住` | 用于生成目标 Excel 的房间行,不再按 `people_per_room` 自动切房 |
|
||||
| `儿童情况` | 儿童占床说明,例如 `不占床` | `不占床` 不计入 `Adults`,但仍进入 `Accompanying Guests` |
|
||||
|
||||
已确认样例:
|
||||
|
||||
```text
|
||||
Sheet1:团队名单表
|
||||
表头:序号 / 姓名 / 拼音 / 性别 / 出生日期 / 出生地 / 护照 / 签发地 / 签发日期 / 有效期 / 联系方式 / 儿童情况 / 分房 / 备注
|
||||
名单行:1L 领队可标记 `外住`;客人行通过 `用房1间` 和空白 `分房` 表示同房关系。
|
||||
```
|
||||
|
||||
解析规则:
|
||||
|
||||
- 在前若干行内查找同一行同时包含 `拼音` 和 `分房` 的表头;`儿童情况` 可选。
|
||||
- 从表头下一行开始读取名单行。
|
||||
- `拼音` 为空的行跳过。
|
||||
- `分房` 包含 `外住` 的行不进入目标 Rooming List。
|
||||
- `分房` 包含 `用房` 的行开始一间新房;后续 `分房` 为空的有效姓名行归入当前房间。
|
||||
- 如果在第一个 `用房` 标记前出现普通名单行,第一版跳过,避免把未分房人员误归入目标房间。
|
||||
- 每间房第一位旅客写入目标 `Name` / `First Name`;同房其他旅客写入 `Accompanying Guests`。
|
||||
- `儿童情况=不占床` 的旅客仍保留在 `Accompanying Guests`,但不计入 `Adults`;`Children` 第一版仍固定为 `0`。
|
||||
- 第四种样式没有 `旅游日期`,后端不得从标题、团号或航班行猜测入住 / 离店日期;必须使用前端提交的 `arrival` / `departure`。
|
||||
|
||||
## 5. 分房生成规则
|
||||
|
||||
前端需要传入 `people_per_room`,表示每间房人数。
|
||||
@@ -206,6 +247,7 @@ Sheet1 第 4 行起:名单数据
|
||||
规则:
|
||||
|
||||
- 按来源 Excel 中旅客出现顺序分组。
|
||||
- 第四种 `拼音` + `分房` 来源样式例外:后端尊重来源表原始分房,忽略 `people_per_room` 的分组作用。
|
||||
- `room_count = ceil(total_people / people_per_room)`。
|
||||
- 每组第一位旅客写入目标 Excel 的 `Name` 和 `First Name`。
|
||||
- 同组剩余旅客写入目标 Excel 的 `Accompanying Guests`。
|
||||
@@ -325,7 +367,7 @@ Content-Disposition: attachment; filename="rooming-list-<timestamp>.xlsx"
|
||||
- `payment_type` 非 `BTQR` / `CA`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- `nationality` 非 `KR` / `CN` / `TH` / `MM` / `RS` / `TW`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- 无旅游日期来源样式缺少 `arrival` / `departure`、日期格式错误或 `departure` 不晚于 `arrival`,返回 `ROOMING_LIST_VALIDATION_FAILED`。
|
||||
- 来源文件缺失、非 `.xls` / `.xlsx`、无法读取、既不能识别第一种 `护照全名` + `旅游日期`,也不能识别第二种 `英文姓` + `英文名` 或第三种单列 `英文名`,返回 `ROOMING_LIST_SOURCE_FILE_INVALID`。
|
||||
- 来源文件缺失、非 `.xls` / `.xlsx`、无法读取、既不能识别第一种 `护照全名` + `旅游日期`,也不能识别第二种 `英文姓` + `英文名`、第三种单列 `英文名` 或第四种 `拼音` + `分房`,返回 `ROOMING_LIST_SOURCE_FILE_INVALID`。
|
||||
- 第一种来源样式缺少 / 无法解析 `旅游日期` 表头,返回 `ROOMING_LIST_SOURCE_FILE_INVALID`。
|
||||
- 同一来源文件出现多个不同旅游日期区间,CP2 返回受控错误,不生成 Excel。
|
||||
- 错误详情只返回字段名或行号,不回显完整名单、证件号或源文件内容。
|
||||
@@ -359,7 +401,7 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
| `ReservationRoomingListGenerationController` | 接收前端上传请求,做登录、权限和酒店上下文校验 |
|
||||
| `ReservationRoomingListGenerationService` | 编排来源解析、分房、目标 Excel 渲染和文件响应 |
|
||||
| `ReservationRoomingListGenerationServiceImpl` | 具体业务实现 |
|
||||
| `RoomingListSourceExcelParser` | CP1 解析来源 Excel,提取护照姓名;CP2 已扩展为同时提取并校验统一旅游日期区间;CP3 已扩展第二种 `英文姓` + `英文名` 样式;CP4 已扩展第三种单列 `英文名` 样式;无旅游日期来源样式要求用户补日期 |
|
||||
| `RoomingListSourceExcelParser` | CP1 解析来源 Excel,提取护照姓名;CP2 已扩展为同时提取并校验统一旅游日期区间;CP3 已扩展第二种 `英文姓` + `英文名` 样式;CP4 已扩展第三种单列 `英文名` 样式;CP5 已扩展第四种 `拼音` + `分房` 原表分房样式;无旅游日期来源样式要求用户补日期 |
|
||||
| `RoomingListNameParser` | 拆分 `/` 或空格格式的护照姓名 |
|
||||
| `RoomingListGroupingService` | 按每房人数分组并生成目标行模型 |
|
||||
| `RoomingListExcelRenderer` | 生成目标格式 `.xlsx` |
|
||||
@@ -419,6 +461,11 @@ RESERVATION_ROOMING_LIST_GENERATE
|
||||
- 能识别第三种来源样式单列 `英文名` 表头。
|
||||
- 第三种来源样式下 `英文名=CAI/HAIYUN` 能生成 `Name=CAI`、`First Name=HAIYUN`。
|
||||
- 第三种来源样式下领队也进入房表,实际人数以后端读取到的有效名单行数为准。
|
||||
- 能识别第四种来源样式 `拼音` / `分房` 表头。
|
||||
- 第四种来源样式下 `拼音=ZHANG JIANWEI` 能生成 `Name=ZHANG`、`First Name=JIANWEI`。
|
||||
- 第四种来源样式尊重原表 `用房1间` 分房,不按 `people_per_room` 重新切房。
|
||||
- 第四种来源样式下 `分房=外住` 行不进入目标 Rooming List。
|
||||
- 第四种来源样式下 `儿童情况=不占床` 的旅客进入 `Accompanying Guests`,但不计入 `Adults`。
|
||||
- 无旅游日期来源样式使用前端提交的 `arrival` / `departure` 写入目标 Excel。
|
||||
- 无旅游日期来源样式缺少 `arrival` / `departure` 返回受控错误。
|
||||
- `LI/CHUNHONG` 能拆成 `Name=LI`、`First Name=CHUNHONG`。
|
||||
|
||||
Reference in new issue
Block a user