hl-api-changelog/changelogs/2026-03/2026-03-19_contract_signing.md
API Changelog Bot b8a7f4c16c feat: 合同管理完整对接方案
19个接口详细定义 + 创建合同请求字段 + 状态流转 + 页面布局 + 数据预填逻辑 + 调用示例

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:53:04 +08:00

24 KiB

合同管理完整对接方案

日期: 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

使用场景:订单详情页点击「去签合同」,弹窗填写信息后提交

请求体

{
  "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 年龄

响应示例

{
  "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

响应示例

{
  "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(比列表多 travelersstatusLogssupplementaryClause),结构同创建合同的响应。


5. 按订单查合同

接口GET /admin/contract/by-order/{orderId}

说明:返回该订单所有合同(含已作废),按创建时间倒序

响应List<ContractVO>


6. 获取订单有效合同

接口GET /admin/contract/active-by-order/{orderId}

说明:返回最新的非作废合同,如果没有返回 null

响应ContractVOnull


7. 刷新合同状态

接口GET /admin/contract/{id}/status

说明:主动从签约平台同步最新状态(用于回调未及时到达的情况)

响应ContractVO(包含最新状态)


8. 作废合同

接口POST /admin/contract/{id}/invalidate

请求体:无

响应ContractVO(状态变为 VOIDINGVOIDED

注意:作废不可恢复,需要新签则重新创建


9. 重发签署短信

接口POST /admin/contract/{id}/resend-sms

说明:仅 SIGNING 状态可用,重新发送签署链接短信给签署人

响应Booleantrue=发送成功)


10. 上传签署PDF

接口POST /admin/contract/{id}/upload-pdf

说明同步模式专用,上传线下签署的合同PDF

请求multipart/form-data,字段名 file

响应ContractVO(状态变为 UPLOADED


11. 合同模板列表

接口GET /admin/contract/templates

响应示例

{
  "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

说明:获取启用的补充约定模板,用于创建合同时选择/预填

响应示例

{
  "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 从出行人中选择签署人 用户选择

六、完整调用示例

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
  • 合同PDFfileUrl)签署完成后才有值
  • 12301平台通过回调自动推送状态变更,前端也可手动刷新/{id}/status