# 合同管理完整对接方案 > 日期: 2026-03-19 | 服务: hl-contract-service --- ## 一、功能说明 订单确认后,定制师需要为订单签订旅游合同。支持两种模式: - **标准模式(STANDARD)**:电子签,平台自动发送签署短信给出行人,出行人在线签署 - **同步模式(SYNC)**:线下签,管理员上传已签署的PDF文件 ### 合同状态流转 ``` 标准模式(电子签): 创建 → GENERATED(已生成) → SIGNING(签署中) → SIGNED(已签署) ↓ VOIDED(已作废) ← VOIDING(作废中) 同步模式(线下签): 创建 → REPORTED(已上报) → UPLOADED(已上传PDF) ↓ VOIDED(已作废) ← VOIDING(作废中) ``` ### 关联字典 **`contract_status`(合同状态)**: | dict_value | dict_label | |-----------|-----------| | PENDING | 待生成 | | GENERATED | 已生成 | | SIGNING | 签署中 | | SIGNED | 已签署 | | REPORTED | 已上报 | | UPLOADED | 已上传 | | VOIDING | 作废中 | | VOIDED | 已作废 | **`contract_platform`(签约平台)**: | dict_value | dict_label | |-----------|-----------| | 12301 | 全国旅游监管平台 | | FADADA | 法大大 | **`contract_type`(合同类型)**: | dict_value | dict_label | |-----------|-----------| | TOUR | 旅游合同 | | INSURANCE | 保险单 | --- ## 二、接口清单 | # | 方法 | 路径 | 说明 | 使用场景 | |---|------|------|------|---------| | 1 | POST | `/admin/contract/create` | 创建电子签合同 | 订单详情 → 去签合同 | | 2 | POST | `/admin/contract/report` | 报备合同(线下签) | 订单详情 → 线下签合同 | | 3 | GET | `/admin/contract/list` | 合同列表(分页) | 合同管理页 | | 4 | GET | `/admin/contract/{id}` | 合同详情 | 合同详情页 | | 5 | GET | `/admin/contract/by-order/{orderId}` | 按订单查合同 | 订单详情 → 合同信息 | | 6 | GET | `/admin/contract/active-by-order/{orderId}` | 订单有效合同 | 订单详情 → 当前合同 | | 7 | GET | `/admin/contract/{id}/status` | 刷新合同状态 | 合同详情 → 刷新 | | 8 | POST | `/admin/contract/{id}/invalidate` | 作废合同 | 合同详情 → 作废 | | 9 | POST | `/admin/contract/{id}/resend-sms` | 重发签署短信 | 合同详情 → 重发 | | 10 | POST | `/admin/contract/{id}/upload-pdf` | 上传签署PDF | 同步模式 → 上传 | | 11 | GET | `/admin/contract/templates` | 合同模板列表 | 创建合同弹窗 → 模板选择 | | 12 | GET | `/admin/contract/platforms` | 可用平台列表 | 创建合同弹窗 → 平台选择 | | 13 | GET | `/admin/contract/agencies` | 旅行社列表 | 创建合同弹窗 → 旅行社选择 | | 14 | GET | `/admin/contract/clause-template/list` | 补充约定模板 | 创建合同弹窗 → 补充约定 | ### 补充约定模板管理 | # | 方法 | 路径 | 说明 | |---|------|------|------| | 15 | GET | `/admin/contract/clause-template/list-all` | 全部模板(含停用) | | 16 | POST | `/admin/contract/clause-template` | 创建模板 | | 17 | PUT | `/admin/contract/clause-template/{id}` | 更新模板 | | 18 | PUT | `/admin/contract/clause-template/{id}/toggle-status` | 启用/停用 | | 19 | DELETE | `/admin/contract/clause-template/{id}` | 删除模板 | --- ## 三、核心接口详细定义 ### 1. 创建电子签合同(标准模式) **接口**:`POST /admin/contract/create` **使用场景**:订单详情页点击「去签合同」,弹窗填写信息后提交 **请求体**: ```json { "orderId": "2031625428892893186", "contractType": "TOUR", "templateCode": "TOURAGE_STANDARD", "destination": "哈尔滨-亚布力-雪乡", "routeName": "嗨·冰雪3.0南线(6天5晚)", "departureDate": "2026-03-11", "returnDate": "2026-03-16", "days": 6, "nights": 5, "departureCity": "哈尔滨", "signatoryName": "张三", "signatoryPhone": "13800138000", "signatoryIdNumber": "110101199001011234", "signatoryMode": 1, "contactName": "OOPS", "contactPhone": "17600545225", "adultCost": 5700.00, "childCost": 0, "totalAmount": 5700.00, "paymentMethod": 3, "disputeResolution": 2, "supplementaryClause": "冬季出行补充约定...", "travelers": [ { "name": "张三", "idCardNo": "110101199001011234", "phone": "13800138000", "idCardType": 1, "isSigner": true, "isChild": false } ] } ``` **请求字段说明**: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | orderId | String | 是 | 订单ID | | contractType | String | 否 | 合同类型,默认 `TOUR`。可选:`TOUR`(旅游合同)/ `INSURANCE`(保险单) | | templateCode | String | 是 | 模板编码,从模板列表接口获取 | | platform | String | 否 | 平台,不传则由模板自动确定 | | agencyCode | String | 否 | 旅行社编号,不传用系统默认值 | | destination | String | 是 | 目的地 | | routeName | String | 是 | 线路名称(产品名称) | | departureDate | String | 是 | 出发日期,格式 `yyyy-MM-dd` | | returnDate | String | 是 | 返回日期,格式 `yyyy-MM-dd` | | days | Integer | 否 | 行程天数(不传自动计算) | | nights | Integer | 否 | 住宿晚数(不传自动计算) | | departureCity | String | 否 | 出发城市 | | signatoryName | String | 是 | **签署人姓名**(出行人中 isSigner=true 的那位) | | signatoryPhone | String | 是 | **签署人电话**(平台发短信用) | | signatoryIdNumber | String | 是 | **签署人证件号码** | | signatoryIdType | Integer | 否 | 签署人证件类型:1=身份证(默认)| | signatoryMode | Integer | 否 | 签署模式:1=短信签署(默认)2=现场 3=线下 | | contactName | String | 是 | 联系人姓名(可与签署人不同) | | contactPhone | String | 是 | 联系人电话 | | adultCost | Number | 是 | 成人费用(单价) | | childCost | Number | 否 | 儿童费用(单价) | | totalAmount | Number | 是 | 合同总金额 | | paymentMethod | Integer | 否 | 付款方式:1=现金 2=转账 3=在线支付(默认2) | | disputeResolution | Integer | 否 | 争议解决:1=仲裁 2=诉讼(默认2) | | leastCustomerNumber | Integer | 否 | 最低成团人数(默认1) | | supplementaryClause | String | 否 | 补充约定内容 | | travelers | Array | 是 | 出行人列表,至少1人 | **出行人(travelers)字段**: | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | name | String | 是 | 姓名 | | idCardNo | String | 是 | 证件号码 | | phone | String | 签署人必填 | 手机号(签署人需要接收短信) | | idCardType | Integer | 否 | 证件类型:1=身份证(默认)2=护照 | | isSigner | Boolean | 否 | 是否签署人(默认false),至少1人为true | | isChild | Boolean | 否 | 是否儿童(默认false) | | gender | String | 否 | 性别:male/female | | age | Integer | 否 | 年龄 | **响应示例**: ```json { "code": 200, "message": "成功", "data": { "contractId": "2035000000000000001", "orderId": "2031625428892893186", "templateCode": "TOURAGE_STANDARD", "templateName": "12301标准模板", "contractNumber": "CN20260319001", "platform": "12301", "contractType": "TOUR", "mode": "STANDARD", "status": "GENERATED", "statusLabel": "已生成", "signUrl": "https://dz.12301.cn/sign/xxxxx", "qrCodeUrl": "https://dz.12301.cn/qr/xxxxx", "fileUrl": null, "agencyCode": "L-FJ-100005", "travelAgencyName": "博华(厦门)国际旅行社有限公司", "destination": "哈尔滨-亚布力-雪乡", "departureDate": "2026-03-11", "returnDate": "2026-03-16", "totalAmount": 5700.00, "touristCount": 1, "contactName": "OOPS", "contactPhone": "17600545225", "createTime": "2026-03-19 17:30:00", "supplementaryClause": "冬季出行补充约定...", "travelers": [ { "travelerId": "2035100000000000001", "name": "张三", "idCardType": "ID_CARD", "idCardNo": "1101****1234", "phone": "138****8000", "isSigner": true } ], "statusLogs": [ { "logId": "2035200000000000001", "oldStatus": "PENDING", "newStatus": "GENERATED", "source": "MANUAL", "createTime": "2026-03-19 17:30:00" } ] } } ``` **业务规则**: - 同一订单同一类型(TOUR/INSURANCE)只能有一个有效合同,创建前会校验 - 如果订单已有有效的 TOUR 合同,需先作废再创建新的 - 创建成功后自动完成订单的 CONTRACT 待办 --- ### 2. 报备合同(同步模式 / 线下签) **接口**:`POST /admin/contract/report` **使用场景**:线下已签署纸质合同,需在系统中报备 **请求体**:与创建合同相同,区别: - `templateCode` 使用同步模式模板(如 `TOURAGE_SYNC`) - `signatoryMode` 默认为 2(现场) - 创建后状态直接为 `REPORTED`(已上报),无需等待签署 **后续步骤**:创建后需上传已签署的PDF → 调用上传接口 --- ### 3. 合同列表(分页) **接口**:`GET /admin/contract/list` **使用场景**:合同管理页面 **请求参数**(Query): | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | orderId | String | 否 | 按订单ID筛选 | | status | String | 否 | 按状态筛选(如 `SIGNED`) | | platform | String | 否 | 按平台筛选(如 `12301`) | | page | Integer | 否 | 页码(默认1) | | pageSize | Integer | 否 | 每页条数(默认20,最大100) | **响应示例**: ```json { "code": 200, "message": "成功", "data": { "list": [ { "contractId": "2035000000000000001", "orderId": "2031625428892893186", "contractNumber": "CN20260319001", "platform": "12301", "contractType": "TOUR", "mode": "STANDARD", "status": "SIGNED", "statusLabel": "已签署", "signUrl": "https://...", "fileUrl": "https://pdf.12301.cn/CN20260319001.pdf", "destination": "哈尔滨-亚布力-雪乡", "departureDate": "2026-03-11", "returnDate": "2026-03-16", "totalAmount": 5700.00, "touristCount": 1, "contactName": "OOPS", "contactPhone": "17600545225", "createTime": "2026-03-19 17:30:00" } ], "total": 1, "page": 1, "pageSize": 20 } } ``` --- ### 4. 合同详情 **接口**:`GET /admin/contract/{id}` **路径参数**:`id` = 合同ID **响应**:返回 `ContractDetailVO`(比列表多 `travelers`、`statusLogs`、`supplementaryClause`),结构同创建合同的响应。 --- ### 5. 按订单查合同 **接口**:`GET /admin/contract/by-order/{orderId}` **说明**:返回该订单所有合同(含已作废),按创建时间倒序 **响应**:`List` --- ### 6. 获取订单有效合同 **接口**:`GET /admin/contract/active-by-order/{orderId}` **说明**:返回最新的非作废合同,如果没有返回 null **响应**:`ContractVO` 或 `null` --- ### 7. 刷新合同状态 **接口**:`GET /admin/contract/{id}/status` **说明**:主动从签约平台同步最新状态(用于回调未及时到达的情况) **响应**:`ContractVO`(包含最新状态) --- ### 8. 作废合同 **接口**:`POST /admin/contract/{id}/invalidate` **请求体**:无 **响应**:`ContractVO`(状态变为 `VOIDING` 或 `VOIDED`) **注意**:作废不可恢复,需要新签则重新创建 --- ### 9. 重发签署短信 **接口**:`POST /admin/contract/{id}/resend-sms` **说明**:仅 `SIGNING` 状态可用,重新发送签署链接短信给签署人 **响应**:`Boolean`(true=发送成功) --- ### 10. 上传签署PDF **接口**:`POST /admin/contract/{id}/upload-pdf` **说明**:同步模式专用,上传线下签署的合同PDF **请求**:`multipart/form-data`,字段名 `file` **响应**:`ContractVO`(状态变为 `UPLOADED`) --- ### 11. 合同模板列表 **接口**:`GET /admin/contract/templates` **响应示例**: ```json { "code": 200, "message": "成功", "data": [ { "templateId": "1001", "templateCode": "TOURAGE_STANDARD", "templateName": "12301标准电子签模板", "platform": "12301", "mode": "STANDARD", "status": "ACTIVE", "description": "全国旅游监管平台标准电子签" }, { "templateId": "1002", "templateCode": "TOURAGE_SYNC", "templateName": "12301同步报备模板", "platform": "12301", "mode": "SYNC", "status": "ACTIVE", "description": "线下签署后同步报备到12301" } ] } ``` **模板字段说明**: | 字段 | 类型 | 说明 | |------|------|------| | templateId | String | 模板ID | | templateCode | String | **创建合同时传这个值** | | templateName | String | 模板名称(下拉框显示) | | platform | String | 所属平台 | | mode | String | `STANDARD`=电子签 / `SYNC`=线下签 | | status | String | `ACTIVE`=启用 / `INACTIVE`=停用 | --- ### 12. 补充约定模板列表 **接口**:`GET /admin/contract/clause-template/list` **说明**:获取启用的补充约定模板,用于创建合同时选择/预填 **响应示例**: ```json { "code": 200, "message": "成功", "data": [ { "templateId": "2001", "name": "冬季出行补充约定", "content": "1. 冬季道路可能存在积雪结冰,行程可能适当调整...\n2. ...", "sortOrder": 1, "status": "ACTIVE" }, { "templateId": "2002", "name": "高原出行补充约定", "content": "1. 高原地区海拔较高,请自备抗高反药物...", "sortOrder": 2, "status": "ACTIVE" } ] } ``` --- ## 四、前端页面布局 ### 1. 订单详情 → 签合同入口 在订单待办面板的 CONTRACT 待办项,按钮为「去签合同」: ``` ┌──────────────────────────────────────────────┐ │ 待办事项 │ │ │ │ ✅ 确认订单 已完成 │ │ ✅ 配置保险 已完成 │ │ ⏳ 签订合同 [ 去签合同 ] │ │ ... │ └──────────────────────────────────────────────┘ ``` 点击「去签合同」→ 打开创建合同弹窗/抽屉 ### 2. 创建合同弹窗 ``` ┌─────────────────────────────────────────────────────┐ │ 创建旅游合同 │ │ │ │ 签约模板 [▼ 12301标准电子签模板 ] │ │ 选项来源: GET /admin/contract/templates │ │ │ │ ─── 行程信息(从订单自动填充) ─── │ │ 目的地 [ 哈尔滨-亚布力-雪乡 ] │ │ 线路名称 [ 嗨·冰雪3.0南线(6天5晚) ] │ │ 出发日期 [ 2026-03-11 ] │ │ 返回日期 [ 2026-03-16 ] │ │ 出发城市 [ 哈尔滨 ] │ │ │ │ ─── 费用信息(从订单自动填充) ─── │ │ 成人费用 [ 5700.00 ] │ │ 儿童费用 [ 0 ] │ │ 总金额 [ 5700.00 ] │ │ 付款方式 [▼ 在线支付 ] │ │ │ │ ─── 签署人信息(从出行人选择) ─── │ │ 签署人 [▼ 张三 - 110101****1234 ] │ │ 选择后自动填充姓名/电话/证件号 │ │ │ │ ─── 联系人信息(从订单自动填充) ─── │ │ 联系人 [ OOPS ] │ │ 联系电话 [ 17600545225 ] │ │ │ │ ─── 补充约定(可选) ─── │ │ 快捷选择 [▼ 冬季出行补充约定 ] │ │ 选项来源: GET /clause-template/list │ │ 约定内容 [ 多行文本框,选模板后自动填充 ] │ │ │ │ ─── 出行人列表(从订单出行人自动加载) ─── │ │ ☑ 张三 身份证 110101****1234 13800138000 [签署人] │ │ │ │ [ 取消 ] [ 创建合同 ] │ └─────────────────────────────────────────────────────┘ ``` ### 3. 合同管理列表页 ``` ┌────────────────────────────────────────────────────────────┐ │ 合同管理 │ │ │ │ 状态 [▼ 全部] 平台 [▼ 全部] [ 搜索 ] [ 重置 ] │ │ │ │ 合同编号 订单号 产品 状态 操作 │ │ CN20260319001 HL2026031114... 冰雪南线 已签署 详情 │ │ CN20260318005 HL2026031800... 海岛亲子 签署中 详情 重发短信 │ │ CN20260317002 HL2026031700... 冰雪北线 已作废 详情 │ └────────────────────────────────────────────────────────────┘ ``` ### 4. 合同详情页 ``` ┌──────────────────────────────────────────────────────┐ │ 合同详情 │ │ │ │ 合同编号: CN20260319001 平台: 12301 │ │ 状态: 已签署 ✅ 模式: 电子签 │ │ 目的地: 哈尔滨-亚布力-雪乡 │ │ 出发: 2026-03-11 → 返回: 2026-03-16 │ │ 总金额: ¥5,700.00 出行人数: 1 │ │ │ │ ─── 出行人 ─── │ │ 张三 身份证 110101****1234 ⭐签署人 │ │ │ │ ─── 操作按钮(按状态显示) ─── │ │ [查看签署链接] [重发短信] [刷新状态] [查看PDF] [作废] │ │ │ │ ─── 状态日志 ─── │ │ 2026-03-19 17:30 PENDING → GENERATED (创建) │ │ 2026-03-19 17:35 GENERATED → SIGNING (回调) │ │ 2026-03-19 17:40 SIGNING → SIGNED (回调) │ └──────────────────────────────────────────────────────┘ ``` ### 5. 操作按钮显示规则 | 状态 | 可用操作 | |------|---------| | GENERATED | 查看签署链接、刷新状态、作废 | | SIGNING | 重发短信、刷新状态、作废 | | SIGNED | 查看PDF、作废 | | REPORTED | 上传PDF、作废 | | UPLOADED | 查看PDF、作废 | | VOIDING | 刷新状态 | | VOIDED | 无操作 | --- ## 五、数据预填逻辑 创建合同弹窗打开时,大部分字段可从订单详情自动填充: | 合同字段 | 来源 | 说明 | |---------|------|------| | orderId | 当前订单 | 自动 | | routeName | order.productName | 产品名称 | | destination | order.destination 或从行程中提取 | 可能需要手动填 | | departureDate | order.departureDate | 出发日期 | | returnDate | 计算:departureDate + tripDays - 1 | 自动计算 | | days | order.tripDays | 行程天数 | | nights | tripDays - 1 | 自动计算 | | contactName | order.contactName | 联系人 | | contactPhone | order.contactPhone | 联系电话 | | totalAmount | order.totalPrice | 订单总价 | | adultCost | order.totalPrice / adultCount | 参考值,可修改 | | travelers | 从 `GET /admin/order/{orderId}/travelers` 获取 | 自动加载 | | signatoryName/Phone/IdNumber | 从出行人中选择签署人 | 用户选择 | --- ## 六、完整调用示例 ```javascript import { http } from '@/utils/request' // 1. 获取模板列表(创建弹窗打开时) const templates = await http.get('/contract/templates') // templates = [{ templateCode: 'TOURAGE_STANDARD', templateName: '12301标准电子签模板', ... }] // 2. 获取补充约定模板(可选) const clauses = await http.get('/contract/clause-template/list') // clauses = [{ name: '冬季出行补充约定', content: '...', ... }] // 3. 创建电子签合同 const contract = await http.post('/contract/create', { orderId: currentOrder.orderId, templateCode: 'TOURAGE_STANDARD', destination: '哈尔滨-亚布力-雪乡', routeName: currentOrder.productName, departureDate: currentOrder.departureDate, returnDate: '2026-03-16', contactName: currentOrder.contactName, contactPhone: currentOrder.contactPhone, signatoryName: selectedTraveler.name, signatoryPhone: selectedTraveler.phone, signatoryIdNumber: selectedTraveler.idCardNo, adultCost: 5700.00, totalAmount: currentOrder.totalPrice, supplementaryClause: selectedClause?.content || null, travelers: orderTravelers.map(t => ({ name: t.name, idCardNo: t.idCardNo, phone: t.phone, idCardType: 1, isSigner: t.travelerId === selectedSignerId })) }) // contract.signUrl → 签署链接(可复制/展示二维码给出行人) // contract.status → 'GENERATED' // 4. 查看订单的有效合同 const activeContract = await http.get(`/contract/active-by-order/${orderId}`) // 5. 刷新合同状态(轮询或手动刷新) const updated = await http.get(`/contract/${contractId}/status`) // 6. 重发签署短信 await http.post(`/contract/${contractId}/resend-sms`) // 7. 作废合同 await http.post(`/contract/${contractId}/invalidate`) // 8. 上传PDF(同步模式) const formData = new FormData() formData.append('file', pdfFile) await http.post(`/contract/${contractId}/upload-pdf`, formData) // 9. 合同列表(合同管理页) const list = await http.get('/contract/list', { params: { page: 1, pageSize: 20, status: 'SIGNED' } }) ``` --- ## 七、与订单待办的关联 1. 合同创建成功后,系统**自动完成**订单的 `CONTRACT` 待办 2. 前端点击订单待办的「去签合同」按钮时: - 先检查 `GET /admin/contract/active-by-order/{orderId}` 是否已有合同 - 有 → 跳转合同详情 - 无 → 打开创建合同弹窗 3. 合同作废后,如果订单流程需要重签,会重新生成 `CONTRACT` 待办 --- ## 八、注意事项 - 同一订单的 TOUR 和 INSURANCE 合同互相独立,可各有一份有效合同 - 出行人变更(增删改)会自动级联作废已有 TOUR 合同 - 签署链接(`signUrl`)有有效期,过期需重发短信(`resend-sms`) - 合同PDF(`fileUrl`)签署完成后才有值 - 12301平台通过回调自动推送状态变更,前端也可手动刷新(`/{id}/status`)