文件
hl-api-changelog/changelogs-v2/2026-09/11_7500_游玩项目按景区口径接入供应商关系-修改接口-管理后台.md
T
2026-09-11 14:46:14 +08:00

25 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 7500 游玩项目按景区口径接入供应商关系 admin lc(GIT) 修改接口 deployed verified verified mmg 7d7cf020 2026-09-11 后端已部署并经 Gateway 验证;待前端展示游玩项目列表供应商全称并接入游玩项目供应商关系操作。前端已交付(hl-admin 7d7cf020):ACTIVITY 加入供应商关系免变更原因集合(设置/改绑/解绑),395061 订单门禁走兜底 message 透后端原文。 2026-09-11 dev-v3

游玩项目管理:按景区口径接入供应商关系

服务: hl-resource-service(8082) PR: #7507 Issue: #7500 日期: 2026-09-11 影响范围: 管理端游玩项目列表、游玩项目供应商查询/设置/改绑/解绑,以及带游玩项目上下文的供应商候选列表

⚠️ 关键变化

  • 游玩项目列表每条记录固定返回 supplierFullName;无当前供应商时为 null。
  • 游玩项目使用通用资源供应商关系接口,路径参数固定传 resourceModule=ACTIVITY。
  • 游玩项目供应商类型固定为 ACTIVITY:设置、改绑可省略 requiredTypeCode;传入其他类型编码返回 400。此前该模块要求前端显式传类型。
  • 供应商候选列表携带 resourceModule=ACTIVITY 与 resourceId 时返回具备 ACTIVITY 类型的合作中供应商;此前该组合返回 400。
  • 游玩项目首次绑定、改绑和解绑都可以省略 changeReason;真正改绑或解绑前会检查 V2、V3 订单,存在未结束订单时返回 395061。

一、背景

游玩项目管理此前无法从列表直接取得当前供应商全称,候选供应商列表在游玩项目上下文下直接报错,关系操作还要求前端传类型和原因。本次按景区、餐厅现行口径冻结游玩项目所需的展示字段、调用参数、类型与原因规则以及订单状态边界。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 游玩项目列表 GET /admin/activity/items 响应字段新增 每条记录固定返回 supplierFullName
2 供应商候选列表 GET /admin/supplier/items/list 行为修改 resourceModule=ACTIVITY 时按 ACTIVITY 类型筛选合作中供应商
3 查询游玩项目当前供应商 GET /admin/supplier/resource-relations/{resourceModule}/{resourceId}/view 调用契约补充 游玩项目传 resourceModule=ACTIVITY
4 设置或改绑游玩项目供应商 PUT /admin/supplier/resource-relations/{resourceModule}/{resourceId}/update 请求与行为修改 可省略类型与原因;真正改绑增加未结束订单门禁
5 解绑游玩项目供应商 POST /admin/supplier/resource-relations/{resourceModule}/{resourceId}/unbind 行为修改 可省略原因;增加未结束订单门禁

三、接口详情

1. 游玩项目列表 GET /admin/activity/items

VO: ActivityQueryRequest / PageResult<ActivityAdminListVO>

使用场景

游玩项目管理列表初始化、翻页、筛选或刷新时调用;列表列直接读取 supplierFullName。

入参

字段 位置 类型 必填 约束 说明
keyword Query String 否 最长 100 字 名称/副标题模糊搜索
cityKeyword Query String 否 最长 100 字 城市名、省份、地址模糊搜索
categoryCode Query String 否 现有字典值 分类编码
billingType Query String 否 PER_PERSON / PER_GROUP / PER_TIME 计费类型
physicalLevel Query String 否 LOW / MEDIUM / HIGH 体力要求
environmentType Query String 否 INDOOR / OUTDOOR / BOTH 环境类型
weatherDependent Query Integer 否 0 否,1 是 是否受天气影响
status Query Integer 否 0 下架,1 上架 状态筛选
tagId / tagIds Query String 否 tagIds 用逗号分隔 标签筛选
city Query String 否 - 城市
seasons / productLineId Query Array / String 否 现有规则 季节过滤(不变)
sortBy Query String 否 最长 50 字 排序字段
sortDir Query String 否 asc 或 desc 排序方向
page Query Integer 否 最小 1,默认 1 页码
pageSize Query Integer 否 1~100,默认 20 每页条数

出参 Result<PageResult<ActivityAdminListVO>>

字段 类型 说明
code / message / success Integer / String / Boolean 业务结果
data.total / page / pageSize Long / Integer / Integer 分页信息
data.records[].activityId String 游玩项目 ID
data.records[].name String 游玩项目名称
data.records[].supplierFullName String 或 null 当前有效供应商的法定全称;未关联或供应商已删除时为 null,字段始终存在
data.records[] 其他字段 Object 原游玩项目列表字段保持不变

请求示例

GET /admin/activity/items?page=1&pageSize=20&sortDir=desc HTTP/1.1

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "total": 2,
    "page": 1,
    "pageSize": 20,
    "records": [
      {"activityId": "2029000000000000001", "name": "示例游玩项目 A", "status": 1, "supplierFullName": "示例游玩供应商有限公司"},
      {"activityId": "2029000000000000002", "name": "示例游玩项目 B", "status": 1, "supplierFullName": null}
    ]
  }
}

空数据 / 降级响应

{"code":200,"message":"成功","success":true,"data":{"total":0,"page":1,"pageSize":20,"records":[]}}

错误响应

{"code":401,"message":"缺少有效的 Authorization 头","success":false,"data":null}

业务边界

  • 本次不新增筛选、排序或分页规则;supplierFullName 只用于展示,不是供应商名称快照。
  • 无当前有效关系时必须按 null 处理,不要根据字段是否存在分支。小程序游玩项目列表不返回该字段。

2. 供应商候选列表 GET /admin/supplier/items/list

VO: SupplierListReqVO / List<SupplierListItemRespVO>

使用场景

游玩项目供应商弹窗中选择目标供应商时调用,携带当前游玩项目上下文,后端按 ACTIVITY 类型过滤。

入参

字段 位置 类型 必填 约束 说明
resourceModule Query String 游玩项目场景是 固定 ACTIVITY;与 resourceId 同时传或同时省略 资源模块
resourceId Query String 游玩项目场景是 正整数 游玩项目 ID
keyword Query String 否 最长 500 字 编码、全称、简称模糊匹配,税号等值匹配
limit Query Integer 否 1~200,默认 50 最大返回条数

携带资源上下文时,类型固定取 ACTIVITY、状态固定为合作中(ACTIVE),不需要也不应再传 typeCode / status。

出参 Result<List<SupplierListItemRespVO>>

字段 类型 说明
code / message / success Integer / String / Boolean 业务结果
data[].supplierId String 供应商 ID(选中后作为设置/改绑的 supplierId)
data[].supplierNo / fullName / shortName String 编码、法定全称、简称
data[].types[] Array typeCode 类型字典值、typeName 类型名称、isPrimary 是否主类型
data[].status / statusName String 生命周期状态(此场景均为 ACTIVE)与展示名
data[].creditLevel / totalScore String / Number 信用等级、综合评分
data[].activeAccountCount Integer 有效收款账户数
data[].contactPhone String 公司联系电话
data[].createTime / updateTime String yyyy-MM-dd HH:mm:ss

请求示例

GET /admin/supplier/items/list?resourceModule=ACTIVITY&resourceId=2029000000000000001&limit=50 HTTP/1.1

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": [
    {
      "supplierId": "2097899397319684099",
      "supplierNo": "SUP2097899397319684099",
      "fullName": "示例游玩供应商有限公司",
      "shortName": "示例游玩",
      "types": [{"typeCode": "ACTIVITY", "typeName": "游玩项目管理", "isPrimary": true}],
      "status": "ACTIVE",
      "statusName": "合作中",
      "creditLevel": "A",
      "totalScore": 90,
      "activeAccountCount": 1,
      "contactPhone": "0471-0000000",
      "createTime": "2026-09-01 10:00:00",
      "updateTime": "2026-09-01 10:00:00"
    }
  ]
}

空数据 / 降级响应

{"code":200,"message":"成功","success":true,"data":[]}

错误响应

{"code":400,"message":"resourceModule与resourceId必须同时提供或同时省略","success":false,"data":null}

业务边界

  • 仅 resourceModule=ACTIVITY 的行为变化:由 400 requiredTypeCode不能为空 改为按 ACTIVITY 类型返回合作中供应商;其他模块和不带上下文的通用列表不变。
  • 需要列表权限及资源查看权限、数据范围;游玩项目不存在时返回资源不存在错误。

3. 查询游玩项目当前供应商 GET /admin/supplier/resource-relations/{resourceModule}/{resourceId}/view

VO: SupplierResourceRelationRespVO

使用场景

打开游玩项目供应商弹窗或在写操作后刷新当前关系时调用。

入参

字段 位置 类型 必填 约束 说明
resourceModule Path String 是 游玩项目固定为 ACTIVITY 资源模块
resourceId Path String 是 正整数 游玩项目 ID

出参 Result<SupplierResourceRelationRespVO>

字段 类型 说明
code / message / success Integer / String / Boolean 业务结果
data.relationId String 当前关系 ID
data.supplierId / supplierNo / supplierName String 当前供应商 ID、编号和全称
data.resourceModule / moduleName String ACTIVITY / 游玩项目管理
data.resourceId / resourceName String 游玩项目 ID 和名称
data.requiredTypeCode / requiredTypeName String ACTIVITY / 游玩项目管理
data.remark String 或 null 关系备注
data.available / unavailableReasons Boolean / Array 当前关系是否仍可用及不可用原因
data.createTime / updateTime String yyyy-MM-dd HH:mm:ss;写操作使用最新 updateTime

请求示例

GET /admin/supplier/resource-relations/ACTIVITY/2029000000000000001/view HTTP/1.1

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "relationId": "2098200000000000001",
    "supplierId": "2097899397319684099",
    "supplierNo": "SUP2097899397319684099",
    "supplierName": "示例游玩供应商有限公司",
    "resourceModule": "ACTIVITY",
    "moduleName": "游玩项目管理",
    "resourceId": "2029000000000000001",
    "resourceName": "示例游玩项目 A",
    "requiredTypeCode": "ACTIVITY",
    "requiredTypeName": "游玩项目管理",
    "remark": null,
    "available": true,
    "unavailableReasons": [],
    "createTime": "2026-09-11 20:00:00",
    "updateTime": "2026-09-11 20:00:00"
  }
}

空数据 / 降级响应

当前没有有效关系时不是空成功,返回 395038。

错误响应

{"code":395038,"message":"供应商资源关联不存在","success":false,"data":null}

业务边界

  • 使用现有登录凭证及 supplier:resource:view 服务端权限;前端按钮可见性不能替代后端判权。
  • 未关联时按 395038 展示“未设置供应商”;不要把它当成系统异常。

4. 设置或改绑游玩项目供应商 PUT /admin/supplier/resource-relations/{resourceModule}/{resourceId}/update

VO: SupplierResourceReassignReqVO / SupplierResourceRelationRespVO

使用场景

游玩项目当前无关系时首次设置供应商,或选择另一供应商后改绑。

入参

字段 位置 类型 必填 约束 说明
resourceModule Path String 是 游玩项目固定为 ACTIVITY 资源模块
resourceId Path String 是 正整数 游玩项目 ID
supplierId Body String 是 正整数 目标供应商 ID
requiredTypeCode Body String 否 可省略;传值只能为 ACTIVITY 关系要求的供应商类型,由后端固定
remark Body String 否 最长 500 字 关系备注
expectedCurrentSupplierId Body String 改绑时是 与版本时间同时传或同时省略 当前关系的 supplierId
expectedRelationUpdateTime Body String 改绑时是 yyyy-MM-dd HH:mm:ss 当前关系的 updateTime
changeReason Body String 否 最长 500 字 首次设置和改绑均可省略;不要补默认原因

出参 Result<SupplierResourceRelationRespVO>

字段 类型 说明
code / message / success Integer / String / Boolean 业务结果
data.relationId / supplierId / supplierNo / supplierName String 生效关系及供应商信息
data.resourceModule / moduleName / resourceId / resourceName String 游玩项目模块和资源信息
data.requiredTypeCode / requiredTypeName String 固定 ACTIVITY / 游玩项目管理
data.remark String 或 null 关系备注
data.available / unavailableReasons Boolean / Array 当前可用性
data.createTime / updateTime String 当前关系时间与后续操作版本

请求示例

首次绑定时不要传两个 expected* 字段,也无需传 requiredTypeCode、changeReason:

{"supplierId":"2097899397319684099"}

改绑时两个版本字段必须来自最新关系回读:

{"supplierId":"2097849575707475970","expectedCurrentSupplierId":"2097899397319684099","expectedRelationUpdateTime":"2026-09-11 20:00:00"}

响应示例

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "relationId": "2098200000000000002",
    "supplierId": "2097849575707475970",
    "supplierNo": "SUP2097849575707475970",
    "supplierName": "示例新游玩供应商有限公司",
    "resourceModule": "ACTIVITY",
    "moduleName": "游玩项目管理",
    "resourceId": "2029000000000000001",
    "resourceName": "示例游玩项目 A",
    "requiredTypeCode": "ACTIVITY",
    "requiredTypeName": "游玩项目管理",
    "remark": null,
    "available": true,
    "unavailableReasons": [],
    "createTime": "2026-09-11 20:01:00",
    "updateTime": "2026-09-11 20:01:00"
  }
}

空数据 / 降级响应

无空成功结果;订单服务、权限或字典等必要依赖无法明确核验时返回失败且不改变关系。

错误响应

{"code":395061,"message":"游玩项目已关联订单,不能更换供应商","success":false,"data":null}
{"code":400,"message":"requiredTypeCode与资源模块不匹配","success":false,"data":null}

业务边界

  • 当前无关系时是首次绑定:不传版本对;即使游玩项目已有订单也允许绑定。
  • 当前有关系且目标供应商不同才是真正改绑:必须传完整、最新版本对;仅关联 COMPLETED、CANCELLED 订单(包括两者混合)时允许,存在其他状态时返回 395061,原关系不变。
  • requiredTypeCode 传 ACTIVITY 以外的值返回 400;目标供应商必须具备 ACTIVITY 类型并满足合作状态与资格要求。
  • 版本过期返回 395014;必要依赖无法明确判断返回 395039;失败不改变关系或审计。

5. 解绑游玩项目供应商 POST /admin/supplier/resource-relations/{resourceModule}/{resourceId}/unbind

VO: SupplierResourceUnbindReqVO / Result<Void>

使用场景

用户确认清除游玩项目当前供应商关系时调用。

入参

字段 位置 类型 必填 约束 说明
resourceModule Path String 是 游玩项目固定为 ACTIVITY 资源模块
resourceId Path String 是 正整数 游玩项目 ID
expectedCurrentSupplierId Body String 是 正整数 当前关系的 supplierId
expectedRelationUpdateTime Body String 是 yyyy-MM-dd HH:mm:ss 当前关系的 updateTime
changeReason Body String 否 最长 500 字 可省略、null、空串或空白;不要补默认原因

出参 Result<Void>

字段 类型 说明
code / message / success Integer / String / Boolean 业务结果
data null 成功时固定为 null

请求示例

{"expectedCurrentSupplierId":"2097849575707475970","expectedRelationUpdateTime":"2026-09-11 20:01:00"}

响应示例

{"code":200,"message":"成功","success":true,"data":null}

空数据 / 降级响应

当前无关系时返回 395038;必要依赖无法明确核验时返回 395039,均不执行解绑。

错误响应

{"code":395061,"message":"游玩项目已关联订单,不能更换供应商","success":false,"data":null}

业务边界

  • 解绑必须使用当前关系最新版本对;版本过期返回 395014,原关系不变。
  • 仅关联 COMPLETED、CANCELLED 订单(包括两者混合)时允许解绑;存在其他状态时返回 395061。
  • 登录、supplier:resource:manage 服务端权限、数据范围、幂等、锁和审计规则保持不变;失败零写入。

四、契约约束与正确调用方式

场景 正确 payload 调用结果
候选列表 ?resourceModule=ACTIVITY&resourceId=66 返回 ACTIVITY 类型合作中供应商
查询当前关系 无请求体,resourceModule=ACTIVITY 返回关系;无关系为 395038
首次绑定 {"supplierId":"22"} 不传版本对、类型和原因
改绑 {"supplierId":"33","expectedCurrentSupplierId":"22","expectedRelationUpdateTime":"2026-09-11 20:00:00"} 两个版本字段必须成对且取最新关系值
解绑 {"expectedCurrentSupplierId":"33","expectedRelationUpdateTime":"2026-09-11 20:01:00"} 可省略 changeReason
错误:传其他类型 {"supplierId":"33","requiredTypeCode":"SCENIC"} 返回 400,不写入
错误:版本字段只传一个 {"supplierId":"33","expectedCurrentSupplierId":"22"} 返回 400,不写入

每次改绑或解绑前先回读当前关系,成功后重新刷新关系和游玩项目列表。业务失败可能仍为 HTTP 200,必须同时判断响应体 code 与 success。

五、数据库行为

前端操作 外部可观察结果
首次绑定 生成一个当前有效关系,requiredTypeCode=ACTIVITY;未填原因时不虚构默认原因
改绑 旧关系转为历史,新供应商成为唯一当前关系,并保留正常变更审计
解绑 当前关系消失并保留正常解绑审计;游玩项目列表返回 supplierFullName: null
订单、版本、权限、类型或资格校验失败 当前关系和审计均不变化

本次不迁移或回填任何数据,不修改订单业务、订单数据或订单供应商快照。

六、边界行为

  • 未登录返回 401;关系查询要求查看权限,设置、改绑、解绑要求维护权限及对应数据范围。
  • 游玩项目未绑定供应商时,列表返回 supplierFullName: null,关系查询返回 395038。
  • changeReason 最长 500 字;省略、null、空串或纯空白均按未填写处理。
  • 未结束订单包含除 COMPLETED、CANCELLED 以外的状态以及未知状态;V2 或 V3 任一服务确认存在即返回 395061。
  • 无法从任一订单服务得到明确结果时返回 395039,不把依赖异常当成无订单。

六.5、枚举 / 数据字典

resourceModule / requiredTypeCode(游玩项目供应商关系)

所属字段: Path/Query resourceModule、Body/Response requiredTypeCode、types[].typeCode | 类型: String

值 中文 说明
ACTIVITY 游玩项目管理 游玩项目关系固定值;requiredTypeCode 可省略并由后端确定

业务错误码

值 中文 说明
395061 游玩项目已关联订单,不能更换供应商 本次新增;真正改绑或解绑时存在未结束订单

六.6、修改前后对比

字段级对比

字段 改前 改后
GET /admin/activity/items 的 records[].supplierFullName 不返回 每条固定返回 String 或 null
游玩项目设置/改绑的 requiredTypeCode 必填,任意类型 可省略,固定 ACTIVITY,传其他值 400
游玩项目设置/改绑的 changeReason 必填 可省略;原有非空值继续兼容
游玩项目解绑的 changeReason 已可省略 保持可省略

行为级对比

行为 改前 改后
游玩项目列表展示供应商 列表无名称字段 直接读取 supplierFullName
候选列表带 ACTIVITY 上下文 返回 400 requiredTypeCode不能为空 返回 ACTIVITY 类型合作中供应商
游玩项目真正改绑、解绑 不检查订单 仅完成/取消订单放行;其他状态返回 395061
尚未绑定供应商的游玩项目 可首次绑定 保持可首次绑定,即使已有订单

六.7、影响评估

  • 是否破坏向后兼容: 仅游玩项目收紧:requiredTypeCode 只接受 ACTIVITY(TEST 当前无游玩项目供应商关系存量);其余为新增可空字段、放宽可选入参与业务保护。
  • 前端是否必须同步上线: 是。
  • 前端 workaround 清理点: 游玩项目列表直接展示 supplierFullName;复用供应商关系弹窗并传 ACTIVITY;候选列表传 resourceModule=ACTIVITY&resourceId;删除游玩项目类型选择、设置/改绑/解绑原因弹框和必填校验;收到 395061 时提示原文并保持当前关系。

七、不影响范围

  • 仅影响: 管理端游玩项目列表、游玩项目供应商关系操作,以及带游玩项目上下文的候选列表。
  • 零影响: 订单创建、状态流转、结算、支付、退款、订单数据和订单供应商快照;小程序游玩项目列表。
  • 景区、餐厅及其他资源模块的字段、类型、原因规则和订单门禁保持原契约;数据库结构、配置、Redis、MQ 和 Gateway 路由无变化。

八、测试环境已验证

  • GET /admin/activity/items:HTTP 200、业务码 200;当前页每条记录均含 supplierFullName;目标游玩项目未关联时为 null,绑定后为供应商全称,解绑后恢复 null;匿名请求返回业务码 401。
  • GET /admin/supplier/items/list?resourceModule=ACTIVITY&resourceId={id}:业务码 200,返回的候选均具备 ACTIVITY 类型且状态为 ACTIVE。
  • GET /admin/supplier/resource-relations/ACTIVITY/{resourceId}/view:未绑定返回 395038,绑定后返回 requiredTypeCode=ACTIVITY;匿名请求返回业务码 401。
  • PUT .../update:传 requiredTypeCode=SCENIC 返回 400 requiredTypeCode与资源模块不匹配 且零写入;省略 changeReason 与 requiredTypeCode 的首次绑定、无未结束订单时的改绑均成功。
  • POST .../unbind:省略 changeReason 解绑成功;验收后目标游玩项目恢复为未绑定。
  • 订单侧只读:验收前后目标游玩项目的 V3 行程节点与未结束订单摘要哈希一致。存在未结束订单时返回 395061、已有订单仍可首次绑定由资源门禁测试及 V2/V3 隔离 MySQL 测试覆盖。

当前状态:后端已部署并验证;待前端处理。

九、相关历史 PR

PR Issue 说明 是否仍有效
#7358 #7357 景区改绑供应商免原因 是
#7401 #7400 全部资源供应商解绑免原因 是
#7493 #7387 餐厅列表、原因规则与订单门禁 是,游玩项目沿用相同口径
#7507 #7500 游玩项目列表、固定类型、候选列表、原因规则与订单门禁 是,游玩项目最新契约

十、相关文档

关联 / 联系人

链接

联系人

  • 后端负责人: @lc