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)
pending
pending
pending
PR #5501 已合并 dev-v3;本文按合并代码静态核对 8 个 admin Controller 共 56 端点,尚未对本 PR 执行测试服网关 HTTP 验证。
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。
4. 完整接口清单( 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
微信支付商户号冲突
新增/编辑支付配置
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. 关联/联系人