--- 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//attachments` | | AdminContractSchemeTourGuideController | 4 | `/v3/admin/contract/scheme//tour-guides` | | AdminClauseTemplateController | 6 | `/v3/admin/contract/clause-template` | | AdminTravelAgencyController | 11 | `/v3/admin/travel-agency` | | AdminTravelAgencyQualificationController | 4 | `/v3/admin/travel-agency//qualification` | | AdminTravelAgencyPaymentController | 5 | `/v3/admin/travel-agency//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//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/`; 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//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//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//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/`; 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/`; 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//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/`;编辑回显;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/`;编辑方案;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//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/`;软删除;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//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//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//attachments/`;软删;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//attachments//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//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//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//tour-guides/`;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//tour-guides/`;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/`;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//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/`;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/`;含资质和支付子表;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/`;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//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//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/`;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//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//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//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//qualification/`;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//qualification/`;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//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//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//payment/`;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//payment/`;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//payment//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 写侧说明 - **后端负责人**: 腰苏图