diff --git a/changelogs/2026-05/01_feat_contract_12301-spec-alignment-attachments-tour-guides-traveler-fields.md b/changelogs/2026-05/01_feat_contract_12301-spec-alignment-attachments-tour-guides-traveler-fields.md new file mode 100644 index 0000000..57fd9b1 --- /dev/null +++ b/changelogs/2026-05/01_feat_contract_12301-spec-alignment-attachments-tour-guides-traveler-fields.md @@ -0,0 +1,233 @@ +# 12301 合同 2026 spec 完整对齐: 新增附件管理 + 导游名单 + 出行人民族/同住分组录入 + +**类型**: 后端新接口 + 字段扩展 +**关联**: 工单 #1590 / PR #1592 +**日期**: 2026-05-01 +**前端处理者**: mmg +**影响范围**: 管理后台「合同方案管理」+「订单出行人录入」+「合同生成」三块联动改造 + +--- + +## 背景 + +用户反馈 12301 国家旅游服务监管平台合同上报字段大量空白,本 PR 完整对齐 2026 spec: + +- 12301 上报 21 个原本声明但未接通的 setter 全接通(投诉详细地址 / 合同份数 / 营业网点 / 付款明细 / 同住名单 / 导游列表 / race / nationality / 行程附件 / 自费购物 / 紧急联系人等) +- 新增 2 张子表 `contract_scheme_attachment` + `contract_tour_guide`(管理后台需要 UI 对应) +- `order_traveler` 加 `race`(民族) + `room_group_no`(同住分组号) +- 行程 PDF 自动生成上传 OSS 嵌入 12301 attachments[] 节点 + +业务规则锁定(用户明确): +- 所有产品**无购物**: shoppingArrangement = [] 永远 +- 所有产品**无额外收费**: selfExpenseItems = [] 永远 +- 付款方式**固定对公转账**: paymentMethod=2, payBankCard=15050161665209911111(从 nacos AgencyInfo.bankCard 注入) +- **导游有的产品没有**: tourGuides[] 允许空数组(无导游产品不强制录入) + +--- + +## 新增接口 1: 合同方案附件管理 + +### `GET /admin/contract/scheme/{schemeId}/attachments` + +查询合同方案附件列表。 + +**Path 参数**: +- `schemeId` (Long, 必填) — 合同方案 ID + +**返回示例**: +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "attachmentId": "2049914870366703618", + "schemeId": 3, + "fileName": "服务标准.pdf", + "ossUrl": "https://hlgl-test.oss-cn-beijing.aliyuncs.com/contract/scheme-attachment/2026-05/3_xxxxx.pdf", + "ossKey": "contract/scheme-attachment/2026-05/3_xxxxx.pdf", + "fileSize": 102400, + "fileType": "PDF", + "sortOrder": 10, + "createTime": "2026-05-01 02:12:45" + } + ] +} +``` + +### `POST /admin/contract/scheme/{schemeId}/attachments` + +上传新附件(multipart/form-data)。 + +**Path 参数**: +- `schemeId` (Long) + +**form-data**: +- `file` (MultipartFile, 必填) — 附件文件,支持 PDF/JPG/PNG 等 +- `fileType` (String, 必填) — 字典 `contract_attachment_type`: `PDF` / `IMAGE` / `OTHER` +- `sortOrder` (Integer, 选填,默认 0) — 排序号,越小越前 + +**返回**: 与 GET 列表的单项结构相同,含 `attachmentId` / `ossUrl` + +### `PUT /admin/contract/scheme/{schemeId}/attachments/{attachmentId}/sort` + +调整附件排序。 + +**Body**: +```json +{ "sortOrder": 20 } +``` + +### `DELETE /admin/contract/scheme/{schemeId}/attachments/{attachmentId}` + +删除附件(软删除)。 + +--- + +## 新增接口 2: 合同方案导游管理 + +### `GET /admin/contract/scheme/{schemeId}/tour-guides` + +查询合同方案导游列表。 + +**返回示例**: +```json +{ + "code": 200, + "message": "成功", + "data": [ + { + "guideId": "2049915142757388290", + "schemeId": 3, + "name": "李导", + "phone": "13800138000", + "licenseNumber": "L-NMG-100953", + "sortOrder": 1, + "createTime": "2026-05-01 02:13:50" + } + ] +} +``` + +### `POST /admin/contract/scheme/{schemeId}/tour-guides` + +新增导游(application/json)。 + +**Body**: +```json +{ + "name": "李导", + "phone": "13800138000", + "licenseNumber": "L-NMG-100953", + "sortOrder": 1 +} +``` + +**字段说明**: +- `name` (String, 必填,≤50 字) +- `phone` (String, 选填,11 位手机号) +- `licenseNumber` (String, 选填,≤64 字,导游证号) +- `sortOrder` (Integer, 选填,默认 0) + +### `PUT /admin/contract/scheme/{schemeId}/tour-guides/{guideId}` + +修改导游(同 POST body)。 + +### `DELETE /admin/contract/scheme/{schemeId}/tour-guides/{guideId}` + +删除导游(软删除)。 + +--- + +## 出行人字段扩展 + +### 新增字段 (3 个 SaveReqVO + TravelerVO 都要加) + +| 字段 | 类型 | 是否必填 | 说明 | +|------|------|---------|------| +| `race` | String | 选填 | 民族(默认\"汉族\"; 12301 race) | +| `nationality` | String | 选填 | 国籍(默认\"中国\"; 港澳台/外籍必填) | +| `roomGroupNo` | Integer | 选填 | 同住分组号(同号=同房; NULL 系统自动两两配对) | + +### 影响接口 + +| 接口 | 变更 | +|------|------| +| `POST /admin/order/traveler` 创建出行人 | Body 新增 race/nationality/roomGroupNo | +| `PUT /admin/order/traveler/{id}` 修改出行人 | Body 新增 race/nationality/roomGroupNo | +| `POST /mp/order/traveler` 小程序新增出行人 | Body 新增 race/nationality/roomGroupNo | +| `GET /admin/order/traveler/{id}` 查出行人详情 | Resp 新增 race/nationality/roomGroupNo 三个字段 | +| `GET /admin/order/traveler/list` 列表 | 同上 | + +### 兜底规则 + +- 后端:`race` null → 上报 12301 用 \"汉族\";`nationality` null → \"中国\"。前端可不强制要求,默认值由后端兜底 +- `roomGroupNo` 为空时,后端按 traveler 列表顺序两两配对(0+1, 2+3, ...);奇数尾巴单人成对(自配自避免空) +- 港澳台/护照证件出行人**建议前端引导填写**(身份证可反推国籍/民族,护照不可) + +--- + +## 前端管理后台需要新增的 UI + +### 1. 合同方案管理页 — 附件 Tab + +在合同方案编辑页(`/admin/contract/scheme/edit/{id}`)加一个「附件管理」分块: +- 附件列表表格(file_name / file_type / file_size / sort_order / 操作) +- 上传按钮(MultipartFile,限 PDF/JPG/PNG,大小 ≤ 10MB) +- 排序拖动 / 删除按钮 + +附件用途:**长期复用模板**,如旅行社服务标准 PDF / 公司资质照片等。生成合同时自动嵌入 12301 attachments[] 节点。 + +### 2. 合同方案管理页 — 导游 Tab + +同方案编辑页加「导游管理」分块: +- 导游列表表格(name / phone / license_number / sort_order / 操作) +- 新增按钮 → 弹窗表单(姓名 / 手机号 / 导游证号 / 排序) +- 修改 / 删除 + +业务规则: **没配导游就空,不强制录入**。有导游产品才需要在方案里配。 + +### 3. 订单出行人录入页 + +`/admin/order/{orderId}/traveler/edit` 表单加 3 个字段: +- 民族(下拉,使用字典 `nation` 或文本输入,默认\"汉族\") +- 国籍(下拉,默认\"中国\";使用字典 `nationality` 如有) +- 同住分组号(数字输入,提示\"同号=同房,空=系统自动两两配对\") + +小程序录入页 `/mp/order/traveler/edit` 同步加。 + +--- + +## 自动行程附件(无前端配合) + +**后端自动生成**: 创建合同时,后端自动从订单产品快照渲染一份「行程单.pdf」(用 PDFBox 渲染,中文用 arphic uming TTC),上传 OSS,嵌入 12301 attachments[] 节点的第一项。前端**不需要做任何事**,这块用户看到的是 12301 平台合同 PDF 内已有完整的每日行程内容。 + +样本: 测试服 round-trip 生成的 12301 合同 ECDJ260501IYZJR9, 25 页 PDF(含行程单作为附件 1)。 + +--- + +## 测试服验证 + +| 步骤 | 命令 | 结果 | +|------|------|------| +| 上传附件 | `POST /admin/contract/scheme/3/attachments` | 200 | +| 查附件 | `GET /admin/contract/scheme/3/attachments` | 返回 1 条 | +| 加导游 | `POST /admin/contract/scheme/3/tour-guides` | 200 | +| 查导游 | `GET /admin/contract/scheme/3/tour-guides` | 返回 1 条 | +| 创建合同 | `POST /admin/contract/create-by-scheme` body `{orderId,schemeId}` | 200, 合同号 ECDJ260501IYZJR9 | +| 12301 PDF | 25 页, 467 KB | 银行卡/投诉区号/附件1/海拉尔区营业部/汉族 全部呈现 | + +--- + +## 部署状态 + +- 测试服 SQL 已应用(2 张新表 + order_traveler 加 race/room_group_no) +- 测试服 nacos `hl-order-service-v2-test.yml` (namespace=test) 已推送 6 字段(3 agency × 6) +- 测试服 hl-order-service-v2 双实例已重启 +- 正式环境 nacos 配置补字段 + 部署待运维管理员处理 + +--- + +## 服务重启提示 + +合并后只需重启 `hl-order-service-v2`(单服务)。其他服务无影响。