---
schema: "hl-changelog/v2"
ticket: "5368"
title: "v3 合同管理完整接口与订单号搜索"
consumer: "admin"
change_type: "修改接口"
author: "yaosutu(GIT)"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "pi-main-session"
frontend_ref: "hl-admin@5925a3ff810b5ef0dbce027a0057e343a1910446"
target_release: ""
verified_at: "2026-08-04T22:35:00+08:00"
status_note: "PR #5501 已合并 dev-v3；deploy-panel 任务 0eae2ffb 成功，hl-order-service-v3 8086/8186 双实例 UP。已通过有效管理后台鉴权验证 Gateway 合同列表 12 个只读用例与目标合同详情；列表/详情 teamNo 一致。QA 报告因未保存含 PII 的详情截图仍为 PARTIAL，不影响已完成的运行时功能门禁。"
updated_at: "2026-08-04"
base: "dev-v3"
---

# 🔧【修改接口·管理后台】v3 合同管理完整接口与订单号搜索 (#5368)

> **PR**: [#5501](https://git.1814.love:8443/wx/HL/pulls/5501) | **服务**: `hl-order-service-v3` | **更新日期**: 2026-08-04
> **范围**: 仅 8 个 admin Controller 的 56 个 `/v3/admin/*` 端点；不含 internal、mp、callback、job。

## 1. 接口背景与历史文档关系

管理后台合同页需要统一使用 v3 读写链路，并在合同列表按订单号定位数据。本文同时给出该页面依赖的全部 admin 契约，便于前端一次性移除 v1/v3 混用。

与已发布的 `2026-07/31_5368_非订单页面统一补齐真实团号与团号搜索` 的关系：

- 2026-07 文档对应 PR #5386 / commit `c9d1b12618`，已约定 `teamNo: string|null`、列表 `teamNo` 搜索、详情返回 `teamNo` 和 v3 完整写侧。
- 本文对应 PR #5501；不重复声称上述能力是本次新增，而是补齐全量 admin 契约并说明本次仅有的两项可见变化。

## 2. 本次真实变更

| # | 接口 | 原来 | 现在 |
|---|---|---|---|
| 1 | `GET /v3/admin/contract/list` | 无独立 `orderNo` 查询参数 | 新增可选 `orderNo`，对人类可读订单号做包含匹配 |
| 2 | 同上 | `teamNo` / `contactName` 文本边界未完整固化 | `orderNo` / `teamNo` / `contactName` 统一 trim；全空白忽略；`%`、`_`、`\` 都按字面字符匹配；多条件按 AND 组合 |

N+1 消除是内部性能修复，不属于前端契约变更。

## 3. 通用协议

- 认证：所有端点都需要管理后台 JWT；旅行社敏感写操作按接口标注需 ADMIN 或 SUPER_ADMIN。
- 成功包装：`{
"code":200,"data":...,"message":"操作成功","success":true
}`，字段名是 `message`，不是 `msg`。
- 分页包装：`data.records` / `data.total` / `data.page` / `data.pageSize`。
- 失败包装：`{
"code":业务错误码,"data":null,"message":"可读提示","success":false
}`。
- 幂等：GET 幂等；PUT 为目标状态更新时可重试；POST 创建/上传不得盲目重试；DELETE 不保证重复调用仍成功。
- 金额按 JSON string 消费；雪花 ID 按 string 消费，不得转 JavaScript `Number`。

## 变更接口（完整接口清单，56）

| Controller | 数量 | 路径域 |
|---|---:|---|
| AdminContractController | 15 | `/v3/admin/contract` |
| AdminContractSchemeController | 7 | `/v3/admin/contract/scheme` |
| AdminContractSchemeAttachmentController | 4 | `/v3/admin/contract/scheme/<schemeId>/attachments` |
| AdminContractSchemeTourGuideController | 4 | `/v3/admin/contract/scheme/<schemeId>/tour-guides` |
| AdminClauseTemplateController | 6 | `/v3/admin/contract/clause-template` |
| AdminTravelAgencyController | 11 | `/v3/admin/travel-agency` |
| AdminTravelAgencyQualificationController | 4 | `/v3/admin/travel-agency/<agencyId>/qualification` |
| AdminTravelAgencyPaymentController | 5 | `/v3/admin/travel-agency/<agencyId>/payment` |

## 5. 接口详情

### 5.1 AdminContractController（15）

#### 5.1.1 创建合同（标准模式）

- **场景/协议**：手工填写全量签约数据；`POST /v3/admin/contract/create`；管理员 JWT；非幂等。
- **请求体（全部字段）**：`orderId:long?`、`contractType:string?(TOUR/INSURANCE)`、`platform:string?(12301/LOCAL/TENCENT_ESIGN)`、`vendorCode:string?`、`templateCode:string!`、`agencyCode:string?`、`mchId:string?`、`transactorName:string?`、`transactorPhone:string?`、`destination:string!`、`routeName:string!`、`days:int?`、`nights:int?`、`departureDate:date!`、`returnDate:date!`、`departureCity:string?`、`groupId:string?`、`signatoryMode:int?(1..3)`、`signatoryName:string!`、`signatoryPhone:string!`、`signatoryIdType:int?`、`signatoryIdNumber:string!`、`signingPlace:string?`、`adultCost:decimal!`、`childCost:decimal?`、`totalAmount:decimal!`、`paymentMethod:int?(1..3)`、`disputeResolution:int?(1..2)`、`tribunalName:string?`、`litigationCourt:string?`、`contactName:string!`、`contactPhone:string!`、`supplementaryClause:string?`、`travelers:array!`、`accordingContract:boolean?`、`accordingContractPhase:object?`、`contractNum:string?`、`holdNum:string?`、`paymentDescription:string?`、`paymentOther:string?`、`agreeToBuyInsurance:boolean?`、`insuranceCompany:string?`、`insuranceCoverage:string?`、`insurancePremium:string?`、`insuranceProductName:string?`、`insurancePurchaseMethod:int?(1..3)`、`guideServiceCost:decimal?`、`paymentTime:string?`、`startHour:int?(0..23)`、`endHour:int?(0..23)`、`touristCondition:string?`、`schemeId:string?`。`travelers[]`：`name:string!`、`gender:string?(0/1/2)`、`age:int?`、`idCardType:int?(1/2)`、`idCardNo:string!`、`phone:string?`、`isSigner:boolean?`、`isChild:boolean?`、`nationality:string?`、`race:string?`、`roomGroupNo:int?`。
- **响应（完整）**：`ContractDetailVO`：`contractId:string, orderId:string, schemeId:string|null, orderNo:string|null, teamNo:string|null, templateCode, templateName, contractNumber, platform, contractType, contractTypeLabel, mode, modeLabel, status, statusLabel, signUrl, qrCodeUrl, fileUrl, agencyCode, travelAgencyName, destination, departureDate, returnDate, totalAmount:string, touristCount:int, contactName, contactPhone, createTime, supplementaryClause, travelers[], statusLogs[]`；`travelers[]={
travelerId:string,name,idCardType,idCardTypeLabel,idCardNo,phone,isSigner
}`；`statusLogs[]={
logId:string,contractId:string,oldStatus,oldStatusLabel,newStatus,newStatusLabel,source,sourceLabel,rawPayload,createTime
}`。
- **边界/错误**：行程未确认 `510220`；已有有效合同 `510214`；模板不存在 `510215`；签署人手机缺失 `510213`；必填/长度/手机格式错误返回参数校验失败。
- **典型示例**：请求 `{
"orderId":"2079000000000000001","templateCode":"TOURAGE_STANDARD","destination":"呼伦贝尔","routeName":"草原5日","departureDate":"2026-08-10","returnDate":"2026-08-14","signatoryName":"张某","signatoryPhone":"138****8000","signatoryIdNumber":"110101********1234","adultCost":"3000.00","totalAmount":"6000.00","contactName":"张某","contactPhone":"138****8000","travelers":[{
"name":"张某","idCardNo":"110101********1234","isSigner":true
}]
}`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","orderId":"2079000000000000001","status":"GENERATED","totalAmount":"6000.00","travelers":[],"statusLogs":[]
},"message":"操作成功","success":true
}`。

#### 5.1.2 按方案创建合同

- **场景/协议**：后台从订单与方案自动组装合同；`POST /v3/admin/contract/create-by-scheme`； JWT；非幂等。
- **入参**：请求体 `orderId:string!`、`schemeId:string!`。
- **响应（完整）**：与 5.1.1 的 `ContractDetailVO` 字段完全一致：`contractId,orderId,schemeId,orderNo,teamNo,templateCode,templateName,contractNumber,platform,contractType,contractTypeLabel,mode,modeLabel,status,statusLabel,signUrl,qrCodeUrl,fileUrl,agencyCode,travelAgencyName,destination,departureDate,returnDate,totalAmount,touristCount,contactName,contactPhone,createTime,supplementaryClause,travelers[],statusLogs[]`。
- **边界/错误**：方案不存在/已停用 `510205`；方案未配模板 `510206`；订单信息失败 `510207`；行程未确认 `510220`；已有合同 `510214`。
- **示例**：请求 `{
"orderId":"2079000000000000001","schemeId":"2020001"
}`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","orderId":"2079000000000000001","schemeId":"2020001","status":"GENERATED","travelers":[],"statusLogs":[]
},"message":"操作成功","success":true
}`。

#### 5.1.3 作废合同

- **场景/协议**：不可恢复地作废有效合同；`POST /v3/admin/contract/<id>/invalidate`； JWT；重复调用不保证成功。
- **入参**：路径 `id:string!` 合同 ID；无请求体。
- **响应（完整）**：`ContractVO={
contractId,orderId,schemeId,orderNo,teamNo,templateCode,templateName,contractNumber,platform,contractType,contractTypeLabel,mode,modeLabel,status,statusLabel,signUrl,qrCodeUrl,fileUrl,agencyCode,travelAgencyName,destination,departureDate,returnDate,totalAmount:string,touristCount,contactName,contactPhone,createTime
}`。
- **边界/错误**：合同不存在 `510001`；缺合同编号 `510003`；上游作废失败 `510104`。
- **示例**：请求 `POST /v3/admin/contract/2080000000000000001/invalidate` 无 body；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","status":"VOIDED","statusLabel":"已作废"
},"message":"操作成功","success":true
}`。

#### 5.1.4 合同列表（本 PR 修改）

- **场景/协议**：合同管理分页列表；`GET /v3/admin/contract/list`； JWT；幂等。
- **Query（全部）**：`page:int?=1`、`pageSize:int?=10`、`orderId:string?`、`status:string?`、`platform:string?`、`orderNo:string?`、`teamNo:string?`、`contactName:string?`。三个文本条件都 trim；全空白忽略；`%` / `_` / `\` 字面匹配；条件间 AND。
- **响应（完整）**：`PageResult.records[]` 每项为 `ContractVO={
contractId,orderId,schemeId,orderNo,teamNo,templateCode,templateName,contractNumber,platform,contractType,contractTypeLabel,mode,modeLabel,status,statusLabel,signUrl,qrCodeUrl,fileUrl,agencyCode,travelAgencyName,destination,departureDate,returnDate,totalAmount:string,touristCount,contactName,contactPhone,createTime
}`；顶层 `total:long,page:int,pageSize:int`。
- **边界**：`orderNo=%` 只匹配订单号中真实的 `%`，不会全表命中；`orderNo=   ` 等价于未传；无结果返回空 `records`。
- **示例**：请求 `GET /v3/admin/contract/list?page=1&pageSize=10&orderNo=HL2026&teamNo=26-08`；响应 `{
"code":200,"data":{
"records":[{
"contractId":"2080000000000000001","orderId":"2079000000000000001","orderNo":"HL202608040001","teamNo":"26-0804","status":"SIGNED","totalAmount":"6000.00"
}],"total":1,"page":1,"pageSize":10
},"message":"操作成功","success":true
}`。

#### 5.1.5 合同详情

- **场景/协议**：查看合同、出行人和状态日志；`GET /v3/admin/contract/<id>`； JWT；幂等。
- **入参**：路径 `id:string!`。
- **响应（完整）**：`ContractDetailVO`全字段：`contractId,orderId,schemeId,orderNo,teamNo,templateCode,templateName,contractNumber,platform,contractType,contractTypeLabel,mode,modeLabel,status,statusLabel,signUrl,qrCodeUrl,fileUrl,agencyCode,travelAgencyName,destination,departureDate,returnDate,totalAmount,touristCount,contactName,contactPhone,createTime,supplementaryClause,travelers[{
travelerId,name,idCardType,idCardTypeLabel,idCardNo,phone,isSigner
}],statusLogs[{
logId,contractId,oldStatus,oldStatusLabel,newStatus,newStatusLabel,source,sourceLabel,rawPayload,createTime
}]`。
- **错误/示例**：不存在 `510001`。请求 `GET /v3/admin/contract/2080000000000000001`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","orderId":"2079000000000000001","teamNo":"26-0804","totalAmount":"6000.00","travelers":[{
"travelerId":"2081000000000000001","name":"张某"
}],"statusLogs":[]
},"message":"操作成功","success":true
}`。

#### 5.1.6 下载合同文件

- **场景/协议**：取得已签署/已上报合同下载 URL；`GET /v3/admin/contract/<id>/download`； JWT；幂等。
- **入参/响应**：路径 `id:string!`；`data:string` 为下载 URL，无其他 data 字段。
- **错误/边界**：`510001` 不存在；`510101` 未签署完成；`510102` 文件 URL 缺失。
- **示例**：请求 `GET /v3/admin/contract/2080000000000000001/download`；响应 `{
"code":200,"data":"https://example.invalid/signed/contract.pdf?token=masked","message":"操作成功","success":true
}`。

#### 5.1.7 重发签署短信

- **场景/协议**：为未完成签署的合同重发短信；`POST /v3/admin/contract/<id>/resend-sms`； JWT；有 1 分钟频控，不可并发重试。
- **入参/响应**：路径 `id:string!`；`data:boolean`。
- **错误/边界**：`510001`、`510005` 已签署、`510006` 过于频繁、`510007` 合同编号缺失、`510008` 联系人手机缺失。
- **示例**：请求 `POST /v3/admin/contract/2080000000000000001/resend-sms` 无 body；响应 `{
"code":200,"data":true,"message":"操作成功","success":true
}`。

#### 5.1.8 合同模板列表

- **场景/协议**：创建合同时选择平台模板；`GET /v3/admin/contract/templates`； JWT；幂等。
- **Query**：`platform:string?` (`12301` 等)。
- **响应（完整）**：`data[]` 每项 `templateId:string,templateCode:string,templateName:string,platform:string,mode:string,status:string,description:string|null,createTime:datetime`。
- **示例**：请求 `GET /v3/admin/contract/templates?platform=12301`；响应 `{
"code":200,"data":[{
"templateId":"101","templateCode":"TOURAGE_STANDARD","templateName":"标准旅游合同","platform":"12301","mode":"STANDARD","status":"ACTIVE","description":null,"createTime":"2026-08-01T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.1.9 刷新合同状态

- **场景/协议**：主动从合同平台同步最新状态；`GET /v3/admin/contract/<id>/status`； JWT；查询可重试，但可产生状态更新。
- **入参/响应**：路径 `id:string!`；`ContractVO`完整字段同 5.1.3。
- **错误/示例**：`510001`；`510103` 缺合同编号。请求 `GET /v3/admin/contract/2080000000000000001/status`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","status":"SIGNED","statusLabel":"已签署"
},"message":"操作成功","success":true
}`。

#### 5.1.10 按订单查询全部合同

- **场景/协议**：查询订单下包含已作废数据的全部合同；`GET /v3/admin/contract/by-order/<orderId>`； JWT；幂等。
- **入参/响应**：`orderId:string!`；`data[]` 每项为 5.1.3 的完整 `ContractVO`。无记录返回 `[]`。
- **示例**：请求 `GET /v3/admin/contract/by-order/2079000000000000001`；响应 `{
"code":200,"data":[{
"contractId":"2080000000000000001","orderId":"2079000000000000001","status":"SIGNED","totalAmount":"6000.00"
}],"message":"操作成功","success":true
}`。

#### 5.1.11 获取订单有效合同

- **场景/协议**：取指定订单最新非作废合同；`GET /v3/admin/contract/active-by-order/<orderId>`； JWT；幂等。
- **入参/响应**：`orderId:string!`；`data` 为 5.1.3 的完整 `ContractVO`，没有有效合同时可为 `null`。
- **示例**：请求 `GET /v3/admin/contract/active-by-order/2079000000000000001`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000001","status":"SIGNED","totalAmount":"6000.00"
},"message":"操作成功","success":true
}`。

#### 5.1.12 可用合同平台列表

- **场景/协议**：展示已注册平台及可用性；`GET /v3/admin/contract/platforms`； JWT；幂等；无入参。
- **响应（完整）**：`data[]` 每项 `platformName:string,displayName:string,available:boolean`。
- **示例**：请求 `GET /v3/admin/contract/platforms`；响应 `{
"code":200,"data":[{
"platformName":"12301","displayName":"12301团队报送","available":true
}],"message":"操作成功","success":true
}`。

#### 5.1.13 已配置旅行社列表

- **场景/协议**：按平台筛选可用旅行社；`GET /v3/admin/contract/agencies`； JWT；幂等。
- **Query**：`platform:string?`。
- **响应（完整）**：`data[]` 每项 `code,agencyName,licenseNumber,businessLicenseNumber,agencyAddress,agencyCountry,agencyState,agencyCity,agencyDistrict,transactorName,transactorPhone,regionId,businessScope,zjParentId,appId,signKey,teamReportAppId,teamReportSignKey,mchId,complaintPhone,email,supportedPlatforms[],bankCard,complaintProvince,complaintCity,complaintAreaCode,complaintAddress,tribunalName,litigationCourt`。注意其中存在高敏配置，仅在授权后台使用，不得写日志/埋点。
- **示例**：请求 `GET /v3/admin/contract/agencies?platform=12301`；响应 `{
"code":200,"data":[{
"code":"hulai","agencyName":"呼籁旅行社","licenseNumber":"L-XX-100001","supportedPlatforms":["12301"],"appId":"***","signKey":"***"
}],"message":"操作成功","success":true
}`。

#### 5.1.14 报备合同（线下签约）

- **场景/协议**：线下签完后上报监管平台；`POST /v3/admin/contract/report`； JWT；非幂等。
- **请求体**：字段、必填性与校验完全同 5.1.1 `CreateContractRequest`。
- **响应（完整）**：与 5.1.1 `ContractDetailVO` 完全一致。
- **错误/边界**：参数校验；未知旅行社 `510201`；上报失败 `510203`；腾讯电子签不支持 SYNC `510403`。
- **示例**：请求同 5.1.1，`platform=12301`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000002","mode":"SYNC","status":"REPORTED","travelers":[],"statusLogs":[]
},"message":"操作成功","success":true
}`。

#### 5.1.15 上传已签署合同 PDF

- **场景/协议**：仅 SYNC 合同上传签署后 PDF；`POST /v3/admin/contract/<id>/upload-pdf`； JWT；非幂等。
- **入参**：路径 `id:string!`；`multipart/form-data` 中 `file:file!`。
- **响应（完整）**：5.1.3 的完整 `ContractVO`。
- **错误/边界**：`510001`、`510105` 缺合同编号、`510106` 当前状态不允许、`510107` 上传失败；ONLINE/STANDARD 合同不适用。
- **示例**：请求 `POST /v3/admin/contract/2080000000000000002/upload-pdf` + `file=@signed-contract.pdf`；响应 `{
"code":200,"data":{
"contractId":"2080000000000000002","mode":"SYNC","status":"UPLOADED","fileUrl":"https://example.invalid/signed.pdf"
},"message":"操作成功","success":true
}`。

### 5.2 AdminContractSchemeController（7）

`ContractSchemeVO` 完整字段：`schemeId:string,name,description,contractPlatform,vendorCode,channel,contractTemplateCode,templateCode,contractTemplateName,contractMode,signatoryMode,agencyCode,agencyName,supplementaryClause,transactorName,transactorPhone,sortOrder,status,createTime`。`ContractSchemeRequest` 完整字段：`name:string!(max100),description:string?(max500),contractPlatform:string?(max50),vendorCode:string?(max32),channel:string?(max32),contractTemplateCode:string?(max50;兼容 templateCode/template_code),contractMode:string?(max50),signatoryMode:int?(1..3),agencyCode:string?(max50),supplementaryClause:string?(max2000),transactorName:string?(max50),transactorPhone:string?(11位手机),sortOrder:int?`。

#### 5.2.1 启用方案列表

- `GET /v3/admin/contract/scheme/list`；产品/合同方案下拉；JWT；幂等；无入参。
- **响应（完整）**：`data[]` 每项包含上述 `ContractSchemeVO` 全部 19 字段，仅返回 `status=ACTIVE`。
- **示例**：`GET .../list` → `{
"code":200,"data":[{
"schemeId":"2020001","name":"标准方案","contractPlatform":"12301","contractMode":"STANDARD","status":"ACTIVE"
}],"message":"操作成功","success":true
}`。

#### 5.2.2 全部方案列表

- `GET /v3/admin/contract/scheme/list-all`；方案管理页；JWT；幂等；无入参。
- **响应（完整）**：`data[]` 每项包含 `ContractSchemeVO` 全部 19 字段，包含 ACTIVE/INACTIVE。
- **示例**：`GET .../list-all` → `{
"code":200,"data":[{
"schemeId":"2020001","name":"标准方案","status":"ACTIVE"
},{
"schemeId":"2020002","name":"旧方案","status":"INACTIVE"
}],"message":"操作成功","success":true
}`。

#### 5.2.3 方案详情

- `GET /v3/admin/contract/scheme/<schemeId>`；编辑回显；JWT；幂等；路径 `schemeId:string!`。
- **响应（完整）**：`ContractSchemeVO` 全部 19 字段。不存在返回 `510209`。
- **示例**：`GET .../2020001` → `{
"code":200,"data":{
"schemeId":"2020001","name":"标准方案","contractPlatform":"12301","contractTemplateCode":"A00001","templateCode":"A00001","status":"ACTIVE"
},"message":"操作成功","success":true
}`。

#### 5.2.4 创建方案

- `POST /v3/admin/contract/scheme`；新增平台/模板/签约模式配置；JWT；非幂等。
- **请求体**：上述 `ContractSchemeRequest` 全部 13 字段。**响应**：上述 `ContractSchemeVO` 全部 19 字段。
- **边界/错误**：`name` 必填；手机/长度/签署模式校验；未知旅行社 `510201`。
- **示例**：请求 `{
"name":"标准方案","contractPlatform":"12301","contractTemplateCode":"A00001","contractMode":"STANDARD","signatoryMode":1,"agencyCode":"hulai","sortOrder":10
}`；响应 `{
"code":200,"data":{
"schemeId":"2020001","name":"标准方案","status":"ACTIVE"
},"message":"操作成功","success":true
}`。

#### 5.2.5 更新方案

- `PUT /v3/admin/contract/scheme/<schemeId>`；编辑方案；JWT；目标更新可重试。
- **入参**：路径 `schemeId:string!` + `ContractSchemeRequest` 全部字段。**响应**：`ContractSchemeVO` 全部字段。
- **边界/错误**：已用方案创建的合同不受后续修改影响；不存在 `510209`。
- **示例**：请求 `PUT .../2020001` + `{
"name":"标准方案V2","contractPlatform":"12301","contractMode":"STANDARD"
}`；响应 `{
"code":200,"data":{
"schemeId":"2020001","name":"标准方案V2","status":"ACTIVE"
},"message":"操作成功","success":true
}`。

#### 5.2.6 切换启停状态

- `PUT /v3/admin/contract/scheme/<schemeId>/toggle-status`；启用/停用方案；JWT；每次翻转，非幂等。
- **入参**：`schemeId:string!`；无 body。**响应**：`ContractSchemeVO` 全部字段。不存在 `510209`。
- **示例**：`PUT .../2020001/toggle-status` → `{
"code":200,"data":{
"schemeId":"2020001","status":"INACTIVE"
},"message":"操作成功","success":true
}`。

#### 5.2.7 删除方案

- `DELETE /v3/admin/contract/scheme/<schemeId>`；软删除；JWT；不保证重复调用成功。
- **入参/响应**：`schemeId:string!`；成功 `data:null`，无其他响应字段。
- **错误/边界**：不存在 `510209`；被产品引用 `510218`；引用校验不可用 `510219`。
- **示例**：`DELETE .../2020001` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.3 AdminContractSchemeAttachmentController（4）

`AttachmentResp` 完整字段：`attachmentId:string,schemeId:string,fileName:string,ossUrl:string,ossKey:string,fileSize:long,fileType:string,sortOrder:int,createTime:datetime`。

#### 5.3.1 附件列表

- `GET /v3/admin/contract/scheme/<schemeId>/attachments`；按 `sortOrder` 升序回显；JWT；幂等；`schemeId:string!`。
- **响应（完整）**：`data[]` 每项含 `AttachmentResp` 全部 9 字段；无配置返回 `[]`。
- **示例**：`GET .../2020001/attachments` → `{
"code":200,"data":[{
"attachmentId":"1010001","schemeId":"2020001","fileName":"service.pdf","ossUrl":"https://example.invalid/a.pdf","ossKey":"contract/a.pdf","fileSize":1024,"fileType":"PDF","sortOrder":10,"createTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.3.2 上传附件

- `POST /v3/admin/contract/scheme/<schemeId>/attachments`；上传合同方案附件；JWT；非幂等。
- **入参**：`schemeId:string!`；multipart `file:file!`、`fileType:string?(PDF/IMAGE/OTHER)`、`sortOrder:int?`。**响应**：`AttachmentResp` 全部 9 字段。
- **错误/边界**：空文件、超限、OSS 不可用或上传失败都返回 `510508`。
- **示例**：`POST .../2020001/attachments` + `file=@service.pdf&fileType=PDF&sortOrder=10` → `{
"code":200,"data":{
"attachmentId":"1010001","schemeId":"2020001","fileType":"PDF","sortOrder":10
},"message":"操作成功","success":true
}`。

#### 5.3.3 删除附件

- `DELETE /v3/admin/contract/scheme/<schemeId>/attachments/<attachmentId>`；软删；JWT；路径 `schemeId:string!`,`attachmentId:string!`；无 body。
- **响应/错误**：成功 `data:null`；附件不存在或不属于该方案 `510506`。已生成合同的旧 URL 不受影响。
- **示例**：`DELETE .../2020001/attachments/1010001` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.3.4 更新附件排序

- `PUT /v3/admin/contract/scheme/<schemeId>/attachments/<attachmentId>/sort`；JWT；目标更新可重试。
- **入参**：路径 `schemeId:string!`,`attachmentId:string!`；body `sortOrder:int!(>=0)`。**响应**：`data:null`。
- **错误/示例**：不存在 `510506`；负数为参数校验失败。请求 `{
"sortOrder":20
}` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.4 AdminContractSchemeTourGuideController（4）

`GuideResp={
guideId:string,schemeId:string,name:string,phone:string|null,licenseNumber:string|null,sortOrder:int,createTime:datetime
}`；`GuideSave={
name:string!(max50),phone:string?(11位手机,max20),licenseNumber:string?(max64),sortOrder:int?(>=0)
}`。

#### 5.4.1 导游列表

- `GET /v3/admin/contract/scheme/<schemeId>/tour-guides`；JWT；幂等；`schemeId:string!`；未配导游返回 `[]`，不兜底。
- **响应（完整）**：`data[]` 每项含 `GuideResp` 全部 7 字段。
- **示例**：`GET .../2020001/tour-guides` → `{
"code":200,"data":[{
"guideId":"3030001","schemeId":"2020001","name":"张某","phone":"138****8000","licenseNumber":"L-XX-100001","sortOrder":0,"createTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.4.2 新增导游

- `POST /v3/admin/contract/scheme/<schemeId>/tour-guides`；JWT；创建加锁，非幂等。
- **入参**：`schemeId:string!` + `GuideSave` 全部 4 字段。**响应**：`GuideResp` 全部 7 字段。
- **边界/示例**：姓名必填；手机格式错误拒绝。请求 `{
"name":"张某","phone":"13800138000","licenseNumber":"L-XX-100001","sortOrder":0
}` → `{
"code":200,"data":{
"guideId":"3030001","schemeId":"2020001","name":"张某","phone":"13800138000","licenseNumber":"L-XX-100001","sortOrder":0,"createTime":"2026-08-04T10:00:00"
},"message":"操作成功","success":true
}`。

#### 5.4.3 修改导游

- `PUT /v3/admin/contract/scheme/<schemeId>/tour-guides/<guideId>`；JWT；目标更新可重试。
- **入参**：`schemeId:string!`,`guideId:string!` + `GuideSave` 全部字段。**响应**：`GuideResp` 全部字段。
- **错误/示例**：不存在/归属不符 `510507`。请求 `{
"name":"李某","sortOrder":1
}` → `{
"code":200,"data":{
"guideId":"3030001","schemeId":"2020001","name":"李某","sortOrder":1
},"message":"操作成功","success":true
}`。

#### 5.4.4 删除导游

- `DELETE /v3/admin/contract/scheme/<schemeId>/tour-guides/<guideId>`；JWT；不保证重复调用成功。
- **入参/响应**：`schemeId:string!`,`guideId:string!`；成功 `data:null`。不存在/归属不符 `510507`。
- **示例**：`DELETE .../2020001/tour-guides/3030001` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.5 AdminClauseTemplateController（6）

`ClauseTemplateVO={
templateId:string,name:string,content:string,sortOrder:int,status:string,createTime:datetime
}`；`ClauseTemplateRequest={
name:string!,content:string!,sortOrder:int?
}`。

#### 5.5.1 启用模板列表

- `GET /v3/admin/contract/clause-template/list`；创建合同时选择；JWT；幂等；无入参。
- **响应（完整）**：`data[]` 每项含 `ClauseTemplateVO` 全部 6 字段，仅 ACTIVE。
- **示例**：`GET .../list` → `{
"code":200,"data":[{
"templateId":"401","name":"夏季小团","content":"脱敏示例条款","sortOrder":1,"status":"ACTIVE","createTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.5.2 全部模板列表

- `GET /v3/admin/contract/clause-template/list-all`；模板管理页；JWT；幂等；无入参。
- **响应（完整）**：`data[]` 每项含 `ClauseTemplateVO` 全部 6 字段，包含 ACTIVE/INACTIVE。
- **示例**：`GET .../list-all` → `{
"code":200,"data":[{
"templateId":"401","name":"夏季小团","content":"条款","sortOrder":1,"status":"INACTIVE","createTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.5.3 创建补充约定模板

- `POST /v3/admin/contract/clause-template`；JWT；非幂等。
- **请求/响应**：body `ClauseTemplateRequest` 全部 3 字段；返回 `ClauseTemplateVO` 全部 6 字段。名称和内容必填。
- **示例**：请求 `{
"name":"夏季小团","content":"脱敏示例条款","sortOrder":1
}` → `{
"code":200,"data":{
"templateId":"401","name":"夏季小团","content":"脱敏示例条款","sortOrder":1,"status":"ACTIVE","createTime":"2026-08-04T10:00:00"
},"message":"操作成功","success":true
}`。

#### 5.5.4 更新补充约定模板

- `PUT /v3/admin/contract/clause-template/<id>`；JWT；可重试。
- **入参/响应**：`id:string!` + `ClauseTemplateRequest` 全部字段；返回 `ClauseTemplateVO` 全部字段。旧合同快照不受影响。
- **错误/示例**：不存在 `510211`。请求 `{
"name":"夏季小团V2","content":"新条款","sortOrder":2
}` → `{
"code":200,"data":{
"templateId":"401","name":"夏季小团V2","content":"新条款","sortOrder":2,"status":"ACTIVE"
},"message":"操作成功","success":true
}`。

#### 5.5.5 切换模板启停

- `PUT /v3/admin/contract/clause-template/<id>/toggle-status`；JWT；每次翻转，非幂等。
- **入参/响应**：`id:string!`；无 body；返回 `ClauseTemplateVO` 全部 6 字段。不存在 `510211`。
- **示例**：`PUT .../401/toggle-status` → `{
"code":200,"data":{
"templateId":"401","name":"夏季小团","content":"条款","sortOrder":1,"status":"INACTIVE","createTime":"2026-08-04T10:00:00"
},"message":"操作成功","success":true
}`。

#### 5.5.6 删除补充约定模板

- `DELETE /v3/admin/contract/clause-template/<id>`；JWT；软删；重复调用不保证成功。
- **入参/响应**：`id:string!`；成功 `data:null`。已创建合同保留快照。不存在 `510211`。
- **示例**：`DELETE .../401` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.6 AdminTravelAgencyController（11）

`AgencySimpleResp={
agencyId:string,code,agencyName,isPrimary:int,sortOrder:int,createTime,updateTime
}`。

`AgencyResp` 完整字段：`agencyId:string,code,agencyName,licenseNumber,businessLicenseNumber,agencyCountry,agencyState,agencyCity,agencyDistrict,agencyAddress,transactorName,transactorPhone,email,bankCard,complaintPhone,complaintProvince,complaintCity,complaintAreaCode,complaintAddress,tribunalName,litigationCourt,regionId,businessScope,zjParentId,appId,signKey,teamReportAppId,teamReportSignKey,supportedPlatforms,supportedPlatformsList[],supportedPlatformsLabels[],isPrimary,status,statusLabel,sortOrder,visible,remark,qualifications[],payments[],createTime,updateTime`。
`AgencySave` 完整字段：`code:string!(2..32,小写字母/数字/-),agencyName:string!(max128),licenseNumber:string?(max64),businessLicenseNumber:string!,agencyCountry,agencyState,agencyCity,agencyDistrict,agencyAddress,transactorName,transactorPhone,email,bankCard,complaintPhone,complaintProvince,complaintCity,complaintAreaCode,complaintAddress,tribunalName,litigationCourt,regionId,businessScope,zjParentId:int?,appId,signKey,teamReportAppId,teamReportSignKey,supportedPlatforms:string(JSON array),isPrimary:int?(0/1),status:string?,sortOrder:int?,visible:int?(0/1),remark`。

#### 5.6.1 旅行社分页

- `GET /v3/admin/travel-agency/page`；管理列表；ADMIN+；幂等。
- **Query（全部）**：`page:int?`,`pageSize:int?`,`status:string?(ENABLED/DISABLED)`,`isPrimary:int?(0/1)`,`agencyName:string?`。
- **响应（完整）**：`records[]` 每项含上述 `AgencyResp` 全部字段；顶层 `total,page,pageSize`。
- **示例**：`GET .../page?page=1&pageSize=10&status=ENABLED` → `{
"code":200,"data":{
"records":[{
"agencyId":"7001","code":"hulai","agencyName":"呼籁旅行社","status":"ENABLED","statusLabel":"启用","qualifications":[],"payments":[]
}],"total":1,"page":1,"pageSize":10
},"message":"操作成功","success":true
}`。

#### 5.6.2 启用旅行社下拉

- `GET /v3/admin/travel-agency/enabled`；ADMIN+；幂等；无入参。
- **响应（完整）**：`data[]` 每项含 `AgencySimpleResp` 全部 7 字段。
- **示例**：`GET .../enabled` → `{
"code":200,"data":[{
"agencyId":"7001","code":"hulai","agencyName":"呼籁旅行社","isPrimary":1,"sortOrder":1,"createTime":"2026-08-01T10:00:00","updateTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.6.3 产品页可用旅行社

- `GET /v3/admin/travel-agency/enabled-for-product`；过滤经营许可证号为空的公司；ADMIN+；幂等；无入参。
- **响应（完整）**：`data[]` 每项含 `AgencySimpleResp` 全部 7 字段。
- **示例**：`GET .../enabled-for-product` → `{
"code":200,"data":[{
"agencyId":"7001","code":"hulai","agencyName":"呼籁旅行社","isPrimary":1,"sortOrder":1,"createTime":"2026-08-01T10:00:00","updateTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.6.4 按合同平台筛选旅行社

- `GET /v3/admin/travel-agency/enabled-by-platform`；合同方案下拉；ADMIN+；幂等。
- **Query**：`contractPlatform:string!` (`12301`/`TENCENT_ESIGN`)。**响应**：`AgencySimpleResp` 全部 7 字段；主体公司优先、ID 升序。
- **边界/示例**：空值返回“合同平台不能为空”。`GET .../enabled-by-platform?contractPlatform=12301` → `{
"code":200,"data":[{
"agencyId":"7001","code":"hulai","agencyName":"呼籁旅行社","isPrimary":1,"sortOrder":1,"createTime":"2026-08-01T10:00:00","updateTime":"2026-08-04T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.6.5 旅行社详情

- `GET /v3/admin/travel-agency/<id>`；含资质和支付子表；ADMIN+；幂等；`id:string!`。
- **响应（完整）**：上述 `AgencyResp` 全部字段；`qualifications[]` 字段见 5.7；`payments[]` 字段见 5.8。不存在 `594001`。
- **示例**：`GET .../7001` → `{
"code":200,"data":{
"agencyId":"7001","code":"hulai","agencyName":"呼籁旅行社","status":"ENABLED","qualifications":[],"payments":[]
},"message":"操作成功","success":true
}`。

#### 5.6.6 新建旅行社

- `POST /v3/admin/travel-agency`；SUPER_ADMIN；非幂等。
- **请求体**：上述 `AgencySave` 全部 33 字段。**响应**：`data:string` 新 agencyId，无其他 data 字段。
- **边界/错误**：编码重复 `594010`；非 SUPER_ADMIN `594009`；编码格式/必填/长度校验。高敏 key 不得打印。
- **示例**：请求 `{
"code":"demo-agency","agencyName":"示例旅行社","businessLicenseNumber":"9115********0001","supportedPlatforms":"[\"12301\"]","status":"ENABLED","isPrimary":0,"visible":1
}` → `{
"code":200,"data":"7002","message":"操作成功","success":true
}`。

#### 5.6.7 编辑旅行社

- `PUT /v3/admin/travel-agency/<id>`；ADMIN+；目标更新可重试。
- **入参/响应**：`id:string!` + `AgencySave` 全部字段；成功 `data:null`。`code` 编辑时不可改。
- **错误/示例**：不存在 `594001`。请求 `{
"code":"hulai","agencyName":"呼籁旅行社","businessLicenseNumber":"9115********0001","status":"ENABLED"
}` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.6.8 停用旅行社

- `PUT /v3/admin/travel-agency/<id>/disable`；ADMIN+；路径 `id:string!`；无 body；目标状态幂等。
- **响应/错误**：成功 `data:null`；不存在 `594001`；主体公司不可停用 `594005`。
- **示例**：`PUT .../7002/disable` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.6.9 启用旅行社

- `PUT /v3/admin/travel-agency/<id>/enable`；ADMIN+；路径 `id:string!`；无 body；目标状态幂等。
- **响应/错误**：成功 `data:null`；不存在 `594001`。
- **示例**：`PUT .../7002/enable` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.6.10 删除旅行社

- `DELETE /v3/admin/travel-agency/<id>`；ADMIN+；强保留语义（状态置 DISABLED）；不保证重复调用成功。
- **入参/响应**：`id:string!`；成功 `data:null`。
- **错误/边界**：`594001`；主体公司 `594005`；本接口不做物理删除。
- **示例**：`DELETE .../7002` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.6.11 设为主体公司

- `PUT /v3/admin/travel-agency/<id>/set-primary`；SUPER_ADMIN；路径 `id:string!`；无 body；目标状态幂等。
- **响应/错误**：成功 `data:null`；`594001`；目标停用或主体约束失败 `594005/594006`；非 SUPER_ADMIN `594009`。
- **示例**：`PUT .../7001/set-primary` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.7 AdminTravelAgencyQualificationController（4）

`QualificationResp={
qualificationId:string,agencyId:string,name,qualificationType,qualificationTypeLabel,fileUrl,fileType,fileTypeLabel,issueDate,expireDate,sortOrder,remark,createTime,updateTime
}`。
`QualificationSave={
name:string!(max64),qualificationType:string!(max32),fileUrl:string!,fileType:string?(PDF/IMAGE/OTHER),issueDate:date?,expireDate:date|null,sortOrder:int?,remark:string?
}`。

#### 5.7.1 资质列表

- `GET /v3/admin/travel-agency/<agencyId>/qualification`；ADMIN+；幂等；`agencyId:string!`。
- **响应（完整）**：`data[]` 每项含 `QualificationResp` 全部 14 字段；`fileUrl` 为有效期 30 分钟的临时 URL。
- **示例**：`GET .../7001/qualification` → `{
"code":200,"data":[{
"qualificationId":"8001","agencyId":"7001","name":"旅行社业务经营许可证","qualificationType":"TRAVEL_AGENCY_LICENSE","qualificationTypeLabel":"旅行社业务经营许可证","fileUrl":"https://example.invalid/temp?token=masked","fileType":"PDF","fileTypeLabel":"PDF","issueDate":"2024-01-01","expireDate":null,"sortOrder":1,"remark":null,"createTime":"2026-08-01T10:00:00","updateTime":"2026-08-01T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.7.2 新增资质

- `POST /v3/admin/travel-agency/<agencyId>/qualification`；ADMIN+；非幂等。
- **入参/响应**：`agencyId:string!` + `QualificationSave` 全部 8 字段；成功 `data:string` 新 qualificationId。
- **错误/边界**：文件无效（>10MB、非 PDF/JPG/PNG、上传失败）`594008`；长期有效传 `expireDate:null`。
- **示例**：请求 `{
"name":"旅行社业务经营许可证","qualificationType":"TRAVEL_AGENCY_LICENSE","fileUrl":"oss://private/masked.pdf","fileType":"PDF","issueDate":"2024-01-01","expireDate":null,"sortOrder":1
}` → `{
"code":200,"data":"8001","message":"操作成功","success":true
}`。

#### 5.7.3 编辑资质

- `PUT /v3/admin/travel-agency/<agencyId>/qualification/<qualificationId>`；ADMIN+；目标更新可重试。
- **入参/响应**：路径中 `agencyId` 用于 URL 归类，后端操作键为 `qualificationId:string!`；body `QualificationSave` 全部字段；成功 `data:null`。
- **错误/示例**：不存在 `594001`；文件无效 `594008`。请求 `{
"name":"经营许可证（新）","qualificationType":"TRAVEL_AGENCY_LICENSE","fileUrl":"oss://private/masked.pdf","fileType":"PDF"
}` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.7.4 删除资质

- `DELETE /v3/admin/travel-agency/<agencyId>/qualification/<qualificationId>`；ADMIN+；软删；不保证重复调用成功。
- **入参/响应**：`qualificationId:string!`；成功 `data:null`；不存在 `594001`。
- **示例**：`DELETE .../7001/qualification/8001` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

### 5.8 AdminTravelAgencyPaymentController（5）

`PaymentResp={
paymentId:string,agencyId:string,name,mchId,appId,apiV3Key,mchSerialNo,publicKeyId,privateKeyPath,publicKeyPath,isDefault:int,status,statusLabel,remark,createTime,updateTime
}`。
`PaymentSave={
name:string!(max64),mchId:string!(max32),appId:string!(max64),apiV3Key:string!,mchSerialNo:string?,publicKeyId:string?,isDefault:int?(0/1),status:string?(ENABLED/DISABLED),remark:string?
}`。这些接口包含高敏密钥/证书信息，仅 SUPER_ADMIN 使用，响应不得写入日志、埋点或客户端持久存储。

#### 5.8.1 支付配置列表

- `GET /v3/admin/travel-agency/<agencyId>/payment`；SUPER_ADMIN；幂等；`agencyId:string!`。
- **响应（完整）**：`data[]` 每项含 `PaymentResp` 全部 16 字段。
- **示例（脱敏）**：`GET .../7001/payment` → `{
"code":200,"data":[{
"paymentId":"9001","agencyId":"7001","name":"微信支付-主商户","mchId":"1106******39","appId":"wx************ff36","apiV3Key":"***","mchSerialNo":"***","publicKeyId":"PUB_***","privateKeyPath":"cert/***/apiclient_key.pem","publicKeyPath":"cert/***/public_key.pem","isDefault":1,"status":"ENABLED","statusLabel":"启用","remark":null,"createTime":"2026-08-01T10:00:00","updateTime":"2026-08-01T10:00:00"
}],"message":"操作成功","success":true
}`。

#### 5.8.2 新增支付配置

- `POST /v3/admin/travel-agency/<agencyId>/payment`；SUPER_ADMIN；非幂等。
- **入参/响应**：`agencyId:string!` + `PaymentSave` 全部 9 字段；成功 `data:string` 新 paymentId。`privateKeyPath/publicKeyPath` 不接受前端传入。
- **错误/边界**：商户号重复 `594011`；非 SUPER_ADMIN `594009`；必填/长度校验。
- **示例（虚构）**：请求 `{
"name":"微信支付-主商户","mchId":"1900000001","appId":"wxdemo000000000001","apiV3Key":"***REDACTED***","mchSerialNo":"***REDACTED***","publicKeyId":"PUB_DEMO","isDefault":1,"status":"ENABLED"
}` → `{
"code":200,"data":"9001","message":"操作成功","success":true
}`。

#### 5.8.3 编辑支付配置

- `PUT /v3/admin/travel-agency/<agencyId>/payment/<paymentId>`；SUPER_ADMIN；目标更新可重试。
- **入参/响应**：URL 含 `agencyId`，操作键为 `paymentId:string!`；body `PaymentSave` 全部字段；成功 `data:null`。
- **错误/示例**：不存在 `594001`；商户号冲突 `594011`。请求 `{
"name":"微信支付-主商户","mchId":"1900000001","appId":"wxdemo000000000001","apiV3Key":"***REDACTED***","status":"ENABLED"
}` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.8.4 删除支付配置

- `DELETE /v3/admin/travel-agency/<agencyId>/payment/<paymentId>`；SUPER_ADMIN；不保证重复调用成功。
- **入参/响应**：`paymentId:string!`；成功 `data:null`。
- **错误/边界**：不存在 `594001`；默认商户不可删 `594007`，须先将另一条设为默认。
- **示例**：`DELETE .../7001/payment/9002` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

#### 5.8.5 设为默认支付商户

- `PUT /v3/admin/travel-agency/<agencyId>/payment/<paymentId>/set-default`；SUPER_ADMIN；目标状态幂等。
- **入参/响应**：`agencyId:string!`,`paymentId:string!`；无 body；成功 `data:null`。
- **错误/边界**：支付配置不存在/归属不符 `594001`；同一公司最多一条 `isDefault=1`。
- **示例**：`PUT .../7001/payment/9001/set-default` → `{
"code":200,"data":null,"message":"操作成功","success":true
}`。

## 6. 枚举/数据字典（按类型分表）

### 6.1 `contract_status`

| 值 | 中文 | 说明 |
|---|---|---|
| `PENDING` | 待生成 | 初始等待 |
| `GENERATED` | 已生成 | 合同已生成，待签署 |
| `SIGNING` | 签署中 | 平台签署流程中 |
| `SIGNED` | 已签署 | 签署完成 |
| `REPORTED` | 已上报 | SYNC 报备完成 |
| `UPLOADED` | 已上传 | SYNC PDF 已上传 |
| `VOIDING` | 作废中 | 等待平台确认 |
| `VOIDED` | 已作废 | 终态 |

### 6.2 `contract_platform`

| 值 | 中文 | 说明 |
|---|---|---|
| `12301` | 12301 团队报送 | 监管平台 |
| `LOCAL` | 本地/线下 | 本地报备 |
| `TENCENT_ESIGN` | 腾讯电子签 | 电子签约 |

### 6.3 `contract_mode`

| 值 | 中文 | 说明 |
|---|---|---|
| `STANDARD` | 电子签约 | 平台生成并签署 |
| `SYNC` | 线下报备 | 线下签署后报备/上传 |

### 6.4 `common_status` / `contract_scheme_status` / `contract_template_status`

| 值 | 中文 | 说明 |
|---|---|---|
| `ACTIVE` | 启用 | 可供新业务选择 |
| `INACTIVE` | 停用 | 历史引用不受影响 |

### 6.5 `contract_attachment_type`

| 值 | 中文 | 说明 |
|---|---|---|
| `PDF` | PDF | PDF 附件 |
| `IMAGE` | 图片 | 图片附件 |
| `OTHER` | 其他 | 其他文件 |

### 6.6 `agency_status`

| 值 | 中文 | 说明 |
|---|---|---|
| `ENABLED` | 启用 | 可被产品/合同选择 |
| `DISABLED` | 停用 | 不可用于新业务 |

### 6.7 `agency_contract_platform`

| 值 | 中文 | 说明 |
|---|---|---|
| `12301` | 12301 团队报送 | 旅行社已开通 12301 |
| `TENCENT_ESIGN` | 腾讯电子签 | 旅行社已开通腾讯电子签 |

### 6.8 `agency_qualification_type`

| 值 | 中文 | 说明 |
|---|---|---|
| `BUSINESS_LICENSE` | 营业执照 | 公司营业执照 |
| `TRAVEL_AGENCY_LICENSE` | 旅行社业务经营许可证 | 旅行社经营资质 |
| `VALUE_ADDED_TELECOM_LICENSE` | 增值电信业务经营许可证 | 电信业务资质 |

### 6.9 `agency_qualification_file_type`

| 值 | 中文 | 说明 |
|---|---|---|
| `PDF` | PDF | PDF 文件 |
| `IMAGE` | 图片 | JPG/PNG 等 |
| `OTHER` | 其他 | 其他类型（服务端仍会做安全校验） |

### 6.10 其他取值

| 字段 | 值 | 说明 |
|---|---|---|
| `contractType` | `TOUR` / `INSURANCE` | 旅游合同 / 保险单 |
| `signatoryMode` | `1` / `2` / `3` | 短信 / 现场 / 线下 |
| `paymentMethod` | `1` / `2` / `3` | 现金 / 转账 / 在线 |
| `disputeResolution` | `1` / `2` | 诉讼 / 仲裁 |
| `insurancePurchaseMethod` | `1` / `2` / `3` | 委托旅行社 / 自行购买 / 放弃 |
| `gender` | `0` / `1` / `2` | 未知 / 男 / 女 |
| `idCardType` | `1` / `2` | 身份证 / 护照 |
| `channel` | `MP` / `ADMIN` / `CHANNEL` / `null` | 小程序 / 管理端 / 分销 / 兜底 |

## 7. 错误码摘要

| code | 含义 | 典型接口 |
|---:|---|---|
| 510001 | 合同不存在 | 详情/作废/下载/刷新/上传 |
| 510005-510008 | 短信重发状态、频控或必要数据缺失 | 重发短信 |
| 510101-510107 | 下载/刷新/作废/PDF 上传业务校验 | 合同写操作 |
| 510201-510220 | 旅行社、方案、模板、订单、签署人及重复合同校验 | 创建/方案管理 |
| 510403 | 腾讯电子签不支持 SYNC | 报备合同 |
| 510506-510508 | 附件/导游不存在或上传失败 | 方案附件/导游 |
| 594001 | 旅行社或其子资源不存在 | 旅行社/资质/支付 |
| 594005-594006 | 主体公司约束 | 停用/删除/设为主体 |
| 594007 | 默认支付商户不可删 | 删除支付配置 |
| 594008 | 资质文件无效 | 新增/编辑资质 |
| 594009 | 仅 SUPER_ADMIN 可执行 | 敏感管理操作 |
| 594010 | 旅行社编码重复 | 新建旅行社 |
| 594011 | 微信支付商户号冲突 | 新增/编辑支付配置 |

## 验证证据

- PR #5501 已合并：merge commit `45117d3d5896515909e303dcbfa9d3616f881803`，head `f66d236f2aea2d0a63db8cb58d59f2ae74e2b6fb`。
- 基于合并代码静态核对 8 个 admin Controller，端点计数 `15+7+4+4+6+11+4+5=56`。
- 文档本地自检：56 个接口小节、只有目标文件进入 commit、`git diff --check` 通过。
- deploy-panel 任务 `0eae2ffb` 执行成功；`hl-order-service-v3` 在 `dev-v3` 的 8086/8186 双实例均为 UP。
- 通过已登录管理后台的有效 Gateway 鉴权完成合同列表真实 HTTP 验证：`code=200`、`total=118`；共12个只读用例覆盖 `orderNo` 精确/模糊/trim、`teamNo`、`%`/`_` 字面匹配等边界。
- 真实非空样本为 `orderNo=HL20260803220907715`、`teamNo=26-2489`；随后在同一鉴权会话打开目标合同 `MOCK-2084280429048741890` 详情，详情显示 `teamNo=26-2489` 且含列表外字段，证明详情调用成功且列表/详情一致。
- QA 证据报告：`D:/work/project-doc/PRPs/reports/5368-contract-teamno-gateway-acceptance.md`，状态仍为 `PARTIAL`。原因是详情页含未脱敏联系电话/签署链接，为避免 PII 落盘未保存截图；运行时列表与详情功能门禁已验证。
- 本次未查询数据库实时行；上述结论来自部署状态与真实 Gateway HTTP/管理后台详情调用。

## 8. 业务边界与 v1/v3 数据隔离

- 根据 Issue #5368 在 2026-08-04 的决策，管理后台合同整页的列表、详情、创建、作废、刷新、下载、短信和上传统一调用 `/v3/admin/*`。
- v1 存量合同不迁移，自然消亡；新合同全部走 v3。
- v1 与 v3 合同数据不互通；不得把 v3 响应的 `contractId` 传给 v1 端点，也不得用 v3 详情读 v1 旧 ID。
- `teamNo` 未生成时为 `null`；不得用 `orderNo` 伪装团号。
- 列表多条件为 AND；文本筛选是数据库分页前的包含匹配，`total` 与翻页结果一致。

## 9. 修改前后对比

| 维度 | 修改前 | 修改后 |
|---|---|---|
| 订单号搜索 | 合同列表不能独立按 `orderNo` 查询 | 可传 `orderNo` 包含匹配 |
| 文本空白 | 语义未完整固化 | 三个文本条件 trim，全空白忽略 |
| LIKE 特殊字符 | 可能被当作通配符 | `%`、`_`、`\` 按字面字符 |
| 数据版本 | 前端可能仍混用 v1/v3 | 合同整页读写统一 v3，v1 存量不迁移 |

## 10. 影响评估/回滚

- **向后兼容**：是。`orderNo` 为新增可选 query；原有参数和响应字段不删除。
- **前端是否必须同步上线**：不必与后端强绑同时上线；但合同页应尽快切到本文的 v3 端点，否则无法正确消费 v3 数据。
- **回滚后前端行为**：停止传递 `orderNo`；保留原 `teamNo/contactName` 及其他查询。不得回滚为 v1/v3 混用。

## 11. 注意事项

- 前端可清理“拉全量合同后在浏览器按订单号过滤”的 workaround，直接传 `orderNo`。
- 请求参数中用户输入的 `%`、`_`、`\` 不需前端自行转义；正常 URL 编码即可。
- 支付配置、证书、身份证、手机号和签约密钥都不得写入前端日志/埋点；本文示例全部为虚构脱敏值。

## 12. 关联/联系人

- **Issue**: [#5368](https://git.1814.love:8443/wx/HL/issues/5368)
- **PR**: [#5501](https://git.1814.love:8443/wx/HL/pulls/5501)
- **Merge commit**: [45117d3d5896515909e303dcbfa9d3616f881803](https://git.1814.love:8443/wx/HL/commit/45117d3d5896515909e303dcbfa9d3616f881803)
- **Head commit**: [f66d236f2aea2d0a63db8cb58d59f2ae74e2b6fb](https://git.1814.love:8443/wx/HL/commit/f66d236f2aea2d0a63db8cb58d59f2ae74e2b6fb)
- **前置契约**: PR #5386 / commit `c9d1b12618` 的 `teamNo` 与 v3 写侧说明
- **后端负责人**: 腰苏图

## 关联/联系人

### 链接

- [后端工单 #5368](https://git.1814.love:8443/wx/HL/issues/5368)
- [后端 PR #5501](https://git.1814.love:8443/wx/HL/pulls/5501)
- Merge commit: `45117d3d58`

### 联系人

- **后端负责人**: @wx
