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