文件
hl-api-changelog/changelogs-v2/2026-09/22_8150_团期staff保存scopeRoles元素级非空校验-修改接口-管理后台.md
T
2026-09-22 21:51:31 +08:00

26 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 8150 团期 staff 保存:scopeRoles 元素级非空校验,[null] 由静默 200 空操作改为 400 拒绝 admin wx(GIT) 修改接口 deployed not_required not_required backend_status=deployed:测试服 hl-order-service-v3 双实例(8086 / 8186)当前运行 sha=843de6401。本单修复提交 bfc10966e 不是该 sha 本身而是它的祖先,故用两条互相独立的判据:①git merge-base --is-ancestor bfc10966e 843de6401 → 退出码 0(是祖先),且 deploy-status.sh 登记 dev-v3 / 843de6401 / BEHIND=0/N;②jar mtime 2026-09-22 18:55:47,晚于 bfc10966e 的提交时刻 2026-09-22 15:24:50 +0800。两条之外还有第三条活体判据:本单契约在 18:5x 经网关实测四组请求取证(见第八节),其中三组的返回值在改动前不可能出现。gateway_status=not_required:本单零网关改动。PUT /v3/admin/group-batch/{productBatchId}/staff 是存量端点、路径未变,命中既有通配路由 Path=/v3/admin/**,未引入任何新路径段,也未改 hl-gateway 的路由或 Nacos 配置。frontend_status=not_required:本单收紧的是一个前端目前不会构造的取值。判据——对 mmg/hl-ui origin/v2.1 的调用方 grep,scopeRoles 一律由 roleMeta.memberRoles 这类字面量常量数组提供(GroupBatchStaffConfigModal.vue:153-154 写死 ['GUIDE','LEADER'] 与 ['PHOTOGRAPHER']),无任何一处会产出 null / 空串 / 纯空白元素;对 [""] 与 [" "] 本单只改 message 文案长度、不改 code。⚠️ 覆盖边界:这是「现有实现不会命中」,不是「将来也不会」——若前端改为由下拉或接口回填拼 scopeRoles,未选中的空值会直接命中本单的 400,请按第四节的契约处理。 | 2026-09-22 mmg 复核:grep 实证前端唯一构造点 ROLE_META.memberRoles 为字面量常量数组,零行为改动;orderV2GroupBatch.js JSDoc 补记新口径(拼接串禁全等、回填须 filter(Boolean)),见 hl-ui@6bf97829e 2026-09-22 dev-v3

order-v3: 团期 staff 保存,scopeRoles 元素级非空校验(#8150)

存放目录: changelogs-v2/2026-09/

服务: hl-order-service-v3 (端口 8086 / 8186) PR: #8177 Issue: #8150 日期: 2026-09-22 影响范围: 团期 staff 配置保存接口 PUT /v3/admin/group-batch/{productBatchId}/staff 的 scopeRoles 字段入参校验

📐 本份的覆盖边界:本份只覆盖 scopeRoles 字段的入参校验契约。同端点的其他契约(staffList 语义、582115 / 582116 的判定规则、扇出行为)本单一律未改,见第七节与第十节列出的既有交接件。


⚠️ 关键变化

变化 1:scopeRoles: [null] 从「HTTP 200 静默空操作」变成 code: 400

这是本单的主体。改动前,scopeRoles 里混进一个 null 元素,接口会返回一个和保存成功长得一模一样的 200,而库里一行都没动。

为什么旧行为是静默失败,四步连起来看:

  1. JSR-380 规定 @Pattern 对 null 恒为 true,所以 [null] 整条走完了参数校验,一个违约都不产生;
  2. 它非 null 非空(数组本身非空,@Size(min = 1) 也过),整位守卫(582116)的短路条件不成立,不抛;
  3. 但 null 这个元素一个配置位都 contains 不到 ⇒ 整位守卫内部的 touched 恒为 false,也不抛;
  4. scopeRoles 同时是删除窗口 —— 窗口 {null} 删不到任何行;插入集合同时为空 ⇒ 库里一行没动,接口返 200。

调用方拿到的不是错误,是一个空操作,没有任何错误码提示它写错了。这不是"写脏数据",是静默失败:前端以为保存成功、页面刷新后配置没变,而后端日志里也没有异常。

改动后返回:

{"code":400,"message":"scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

变化 2:scopeRoles: [""] / [" "] 的 message 从一条变成两条拼接

这两个取值改动前就已经是 400(@Pattern 是容器元素约束,空串与纯空白匹配不上取值域),本单没有改变它们的 code。变的是 message:

{"code":400,"message":"scopeRoles 取值不在员工角色取值域内; scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

🔴 两条约束是并列触发、不是后者替换前者:@NotBlank 与 @Pattern 对空串同时失败,GlobalExceptionHandler 把多条 Bean Validation 违约的 message 用 "; " 拼接成一条字符串返回。

🔴 拼接顺序不保证,前端不得按顺序解析、也不得按精确相等匹配 message。Bean Validation 规范不保证同一字段上多个约束的执行顺序,上面示例里 @Pattern 在前只是本轮实现的偶然结果,换一个 Hibernate Validator 版本就可能颠倒。需要判定失败原因时:

  • 判「是不是入参校验失败」→ 看 code == 400;
  • 判「是哪个字段」→ 用 message.contains("scopeRoles"),不要用 ==;
  • 展示给用户 → 整串原样展示即可,它本身是可读的中文。

一、背景

scopeRoles 是 #8006 引入的部分覆盖开关:不传 = 整期全量覆盖(历史行为),传了则只在这些角色内覆盖、范围外的既有行一行不动。它同时是删除窗口 —— 漏声明的同位行既不会被删也不会被重建。

正因为它兼任删除窗口,一个取不到任何配置位的 scopeRoles 会让整次保存退化成空操作。而字段原本只加了元素级 @Pattern,JSR-380 明文规定 @Pattern 对 null 恒为 true,于是 [null] 是唯一一个能穿过校验层、又在业务层什么都不做、还返 200 的取值。

本单补上元素级 @NotBlank,把这个洞封掉。选 @NotBlank 而不是 @NotNull 的理由在第六.6 节的对比表里 —— 不是为了可达性(@NotNull 同样能救回 [null]),是为了让空串与纯空白也拿到一条**点名"为空"**的文案,而不是只被告知"取值不在取值域内"。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 保存团期 staff 配置(含扇出) PUT /v3/admin/group-batch/{productBatchId}/staff 修改接口 scopeRoles 增加元素级 @NotBlank(入参校验收紧);code、响应结构、业务语义均未变

未新增、未删除、未改名任何端点。


三、接口详情

1. 保存团期 staff 配置(含扇出) PUT /v3/admin/group-batch/{productBatchId}/staff

VO: BatchStaffConfigReqVO → Result<BatchStaffConfigRespVO>

权限: GroupBatchPermissionGuard.PERMISSION_MANAGE(hl-gateway 侧命中既有通配路由 Path=/v3/admin/**)

使用场景

团期详情页「配导游 / 配摄影」弹窗保存。传入列表即为覆盖范围内的最终状态,保存成功后异步扇出到团内所有活跃订单的 order_staff_assignment(source=GROUP_BATCH)。

入参

字段 位置 类型 必填 约束 说明
productBatchId path Long 是 — 产品侧排期 ID(group_tour_batch.batch_id),不是运营团期主键 order_group_batch.group_batch_id。两者 1:1 但值不同,传错不会报错、只会走不到团期
scopeRoles body List<String> 否 数组 @Size(min = 1);🆕 元素 @NotBlank + 元素 @Pattern 本次保存覆盖的角色范围。不传 = 整期全量覆盖(历史行为);传了则只在这些角色内覆盖。取值域见第六.5 节。数组不能是空数组(清空语义只由 staffList 表达);🆕 元素不能是 null / 空串 / 纯空白——本单唯一的行为变化就在这里
staffList body List<Item> 是 @NotNull + @Valid 覆盖范围内的最终状态。显式传 [] 即清空该范围。缺字段或字段名拼错一律 400(审计 F-03,Refs #6950 / #7377)。本单未改动
staffList[].staffId body Long 是 @NotNull 用户域员工 ID。本单未改动
staffList[].staffRole body String 是 @NotBlank + @Pattern 员工角色,取值域见第六.5 节。本单未改动
staffList[].sortOrder body Integer 否 — 展示排序,默认 0。本单未改动
staffList[].remark body String 否 @Size(max = 500) 备注,≤500 字。本单未改动

出参(本单未改动,列出供对照)

字段 类型 说明
productBatchId String(Long 序列化为字符串) 回显路径参数,恒非 null
groupBatchId String(Long 序列化为字符串) 运营团期 ID,由 productBatchId 反查。本端点的 200 响应里恒非 null(入口第一道守卫就是成团校验)
staffList Array 保存后的团期 staff 配置快照
staffList[].id Long 记录 ID(batch_staff_id)
staffList[].staffId Long 用户域员工 ID
staffList[].staffRole String 员工角色 code
staffList[].staffRoleName String 角色中文名;staffRole 为 null 时为 null,取值不在枚举内时回落原 code
staffList[].staffName String 员工姓名(快照)
staffList[].staffPhone String 手机号,脱敏前 3 后 4
staffList[].avatarUrl String 头像 URL(快照)
staffList[].sortOrder Integer 展示排序
staffList[].remark String 备注
staffList[].reporterRank String 报账人等级 PRIMARY / SECONDARY / NONE,空值归一为 NONE,恒非 null
staffList[].reporterRankName String 报账人等级中文名,与 reporterRank 同生同灭
affectedOrderCount int 扇出影响的订单数(已触发异步写入的活跃订单数)

请求示例(正确用法,本单未改变它的行为)

PUT /v3/admin/group-batch/80001/staff

{
  "scopeRoles": ["GUIDE", "LEADER"],
  "staffList": [
    {"staffId": 40001, "staffRole": "LEADER", "sortOrder": 0, "remark": "首席领队"},
    {"staffId": 40002, "staffRole": "GUIDE",  "sortOrder": 1}
  ]
}

响应示例

保存成功(code 为 200,本单未改变响应结构):

{
  "code": 200,
  "message": "操作成功",
  "data": {
    "productBatchId": "80001",
    "groupBatchId": "90211",
    "staffList": [
      {
        "id": 770001,
        "staffId": 40001,
        "staffRole": "LEADER",
        "staffRoleName": "领队",
        "staffName": "刘领队",
        "staffPhone": "138****6677",
        "avatarUrl": null,
        "sortOrder": 0,
        "remark": "首席领队",
        "reporterRank": "NONE",
        "reporterRankName": "非报账人"
      }
    ],
    "affectedOrderCount": 3
  },
  "traceId": null,
  "success": true
}

🔎 本示例按 BatchStaffConfigRespVO 的字段逐个列出,用于说明结构;本单未改动响应结构中的任何一个字段。成功路径的活体读数不在本单的取证范围内(本单取证用的是不存在的团期,见第八节),需要成功响应的真实样本请见第十节 #8006 的交接件。

空数据 / 降级响应

本单不涉及。staffList: [] 的「清空该范围」语义未变,该情形下 data.staffList 返回空数组(不是 null),affectedOrderCount 照常返回扇出订单数。

错误响应

🆕 scopeRoles 元素为 null(本单新增的拒绝):

{"code":400,"message":"scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

scopeRoles 元素为空串 / 纯空白(改前已是 400,本单只让 message 多带一条):

{"code":400,"message":"scopeRoles 取值不在员工角色取值域内; scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

全部错误码:

code 触发条件 本单是否改动
400 scopeRoles 元素为 null 🆕 本单新增(改前是 200 静默空操作)
400 scopeRoles 元素为空串 / 纯空白 改前已是 400,本单只让 message 多带一条
400 scopeRoles 传了 [](空数组) 否(@Size(min = 1))
400 scopeRoles 元素不在取值域内 否
400 缺 staffList 字段 否
582115 staffList 里出现 scopeRoles 范围外的角色 否,且零写入
582116 scopeRoles 只声明了半个配置位(如只传 GUIDE 不传 LEADER) 否,且零写入
589552 / 589553 团期未建团 / 未成团或已流团 否

🔴 HTTP 状态行恒为 200,body.code 才是真相。本服务的业务失败与入参校验一律返 HTTP 200(GlobalExceptionHandler 带 @ResponseStatus(HttpStatus.OK)),成功码是 200 不是 0。判成败请读 body.code,不要读 HTTP 状态码。

业务边界

  • 本单唯一的行为变化在 scopeRoles 的元素上:[null] 由「HTTP 200 + 静默空操作」改为 code: 400。scopeRoles 不传、传合法值、以及 staffList 侧的一切语义都与改前逐字相同。
  • scopeRoles 不传 = 整期全量覆盖,传了 = 只在这些角色内覆盖;[] 一直被拒(@Size(min = 1)),清空语义只由 staffList: [] 表达。这三条改前改后一致。
  • [null] 改前不报错,但它做的事情是「什么都没做」:scopeRoles 含 null 时下游范围计算得到空范围,接口返 200、affectedOrderCount 为 0、库里零写入。调用方若据 200 判定「已保存」,实际保存从未发生 —— 这正是本单要关掉的静默失败。
  • [""] / [" "] 改前已是 400,本单只让 message 多带一条。不要对这两个值的 message 写全等比较:它是 @Pattern 与 @NotBlank 两条 violation 由 GlobalExceptionHandler 以 "; " 拼接而成,且 拼接顺序不属于契约(Bean Validation 不保证多个约束的执行顺序)。要判就判 code == 400,或判 message 包含你关心的那个子串。
  • 校验发生在 Spring @Valid 绑定层,在进 Service 之前:因此 productBatchId 是否真实存在不影响这三种 400 的出现。反过来,拿到 589552 / 589553 说明请求已经穿过绑定层、是团期状态问题,不是参数格式问题。
  • HTTP 状态行恒为 200,成功码是 200 不是 0,判成败一律读 body.code。

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

scopeRoles 取值对照表

payload 片段 结果 说明
字段整个不传 ✅ 整期全量覆盖 历史行为,未变
"scopeRoles": ["GUIDE","LEADER"] ✅ 只覆盖导游位 导游位并收这两个角色,必须同时传
"scopeRoles": ["PHOTOGRAPHER"] ✅ 只覆盖摄影位
"scopeRoles": ["GUIDE"] ❌ 582116 只声明半个配置位,零写入
"scopeRoles": [] ❌ 400 空数组被拒;清空语义只由 staffList: [] 表达
"scopeRoles": [null] ❌ 400 🆕 本单收紧。改前返 200 且库里一行没动
"scopeRoles": ["", "GUIDE"] ❌ 400 改前已是 400,本单只让 message 多一条
"scopeRoles": [" "] ❌ 400 同上
"scopeRoles": null(字段值为 null) ✅ 等同不传 整期全量覆盖

前端拼 scopeRoles 时的两条实践

  1. 过滤在前、校验在后:如果 scopeRoles 由下拉选中项或接口回填拼出,先 filter(Boolean) 掉未选中产生的空值再发;空数组要整个字段不传,而不是传 []。
  2. 不要按 message 精确相等判分支:多条约束并列失败时 message 是 "; " 拼接串且顺序不保证。要区分失败原因用 code,要展示就整串展示。

五、数据库行为

本单零数据库改动:不加表、不加列、不加索引、无 Flyway 脚本。

唯一与库相关的行为差异是「改前 [null] 那一次请求对库零写入且返 200,改后它根本进不到 Service」—— 两种情况下库里都是零写入,差别只在调用方能不能知道。


六、边界行为

场景 行为
scopeRoles 数组里混合合法值与空值(如 ["GUIDE", null]) 整条请求 400,零写入;Bean Validation 在进 Service 前就拦下,不存在"合法的那一半生效了"
同一次请求同时违反多条约束 message 为各条以 "; " 拼接,顺序不保证;code 恒为 400
staffList 里的 staffRole 为 null / 空串 由 Item.staffRole 自己的 @NotBlank + @Pattern 拦,本单未改
校验失败时的扇出 不发生。校验在 @Valid 绑定层,早于 Service,更早于异步扇出

六.5、枚举 / 数据字典

scopeRoles 元素 与 staffList[].staffRole 的取值域(两者同一套)

判定依据是 BatchStaffConfigReqVO.STAFF_ROLE_PATTERN 常量,共 8 个取值:

code 中文名
LEADER 领队
GUIDE 导游
DRIVER 司机
PHOTOGRAPHER 摄影
OTHER 其他
GUIDE_ASSISTANT 导游助理
STUDY_TEACHER 研学老师
LIFE_TEACHER 生活老师

后 3 个由 #7079(e61fc9ab6)引入,不是本单新加的,本单一个取值都没动。

⚠️ Swagger 上 staffList[].staffRole 的字段说明只列了前 5 个(LEADER=领队 / GUIDE=导游 / DRIVER=司机 / PHOTOGRAPHER=摄影 / OTHER=其他),与 @Pattern 实际放行的 8 个不一致。以本表为准 —— 本表取自 STAFF_ROLE_PATTERN 常量本身,那是校验实际执行的依据;另可交叉印证:响应侧 staffList[].staffRoleName 的字段说明已写全 8 个中文名("领队/司机/导游/摄影/其他/导游助理/研学老师/生活老师")。照请求侧 Swagger 文案写下拉会缺 3 项。

配置位与角色的对应

配置位 并收的角色 说明
导游位 GUIDE + LEADER 触及就必须两个都传,否则 582116
摄影位 PHOTOGRAPHER

配置位的成员读数据字典(#7079):字典加一个角色后,原本完整的范围当天就会变成不完整并被拒,错误码文案里的「还缺少 X」即为要补进 scopeRoles 的角色。


六.6、修改前后对比

字段级

字段 改前约束 改后约束
scopeRoles @Size(min = 1) + 元素级 @Pattern @Size(min = 1) + 元素级 @NotBlank + 元素级 @Pattern

其余字段一字未改。

行为级

请求 改前 改后(现网) 依据等级
"scopeRoles": [null] HTTP 200 / code: 200,库里零写入,无任何错误提示 code: 400,message = scopeRoles 的元素不能为空 改前:推导(见下);改后:网关活体实测
"scopeRoles": [""] code: 400,message 一条(scopeRoles 取值不在员工角色取值域内) code: 400,message 两条以 "; " 拼接 改前:单测层变异实测;改后:网关活体实测
"scopeRoles": [" "] 同上 同上(返回体与 [""] 逐字相同) 同上
"scopeRoles": ["GUIDE","LEADER"] 正常进 Service 不变 网关活体实测(作阴性对照)
"scopeRoles": [] code: 400 不变 源码(@Size(min = 1))
字段不传 整期全量覆盖 不变 源码

🔎 「改前」一列的依据分级,逐条说清楚(改前的 jar 已不在测试服上,无法回放):

  • [null] 改前返 200:两段拼起来的推导。①校验层:BatchStaffConfigReqVOValidationTest 的变异实测——移除元素级 @NotBlank 后,Validator#validate 对 [null] 返回 0 条违约(Expected size: 1 but was: 0),证明它确实能整条穿过校验层;②业务层:源码路径推导(整位守卫 touched 恒 false + 删除窗口 {null} 命中 0 行 + 插入集合为空),得出"零写入且返 200"。这一段是源码推导,没有改前的网关读数。
  • [""] / [" "] 改前是一条 message:单测层变异实测——同一轮变异里,[""] 返回 1 条违约、来自 @Pattern。这是 Validator 直调的读数,不是网关读数。

⚠️ 这里订正一条本仓代码注释里写错、并已同步订正的结论:早前的注释写「@NotBlank 对 "" / " " 带来的是错误文案从 X 变成 Y」,实测证明是两条并列、拼接,不是替换。注释与相关测试 javadoc 已一并订正。


六.7、影响评估

对 mmg/hl-ui origin/v2.1 的调用方核查结论:

  • scopeRoles 一律由字面量常量数组提供 —— GroupBatchStaffConfigModal.vue:153-154 写死 ['GUIDE','LEADER'](导游位)与 ['PHOTOGRAPHER'](摄影位),无任何一处会产出 null / 空串 / 纯空白元素;
  • 因此现有实现不会命中本单新增的 400,行为零改动,无需前端配合改造。

⚠️ 这个结论的有效期限于"现有实现"。若后续改为由下拉选中项、接口回填或用户输入拼 scopeRoles,未选中产生的空值会直接命中本单的 400 —— 按第四节的两条实践处理即可。


七、不影响范围

本单未改动以下任何一项,它们的契约保持原样:

  • staffList 的语义("覆盖范围内的最终状态"、显式传 [] 即清空该范围)
  • 582115(范围外角色,零写入)与 582116(半位声明,零写入)的判定规则与触发条件
  • 角色取值域本身(8 个取值一个没动)
  • 配置位的划分与成员(导游位 = GUIDE + LEADER,摄影位 = PHOTOGRAPHER)
  • 响应结构 BatchStaffConfigRespVO 的任何字段
  • 扇出行为(异步写 order_staff_assignment,source=GROUP_BATCH,ORDER 专属行不受影响)
  • 成团守卫(589552 / 589553)
  • 同端点以外的任何接口

八、测试环境已验证

部署状态(三条独立判据)

判据 读数
① 祖先关系 + 登记 git merge-base --is-ancestor bfc10966e 843de6401 → 退出码 0;deploy-status.sh 登记 hl-order-service-v3 / dev-v3 / 843de6401 / BEHIND=0(N) / ok
② jar 时间 jar mtime 2026-09-22 18:55:47,晚于 bfc10966e 的提交时刻 2026-09-22 15:24:50 +0800
③ 活体行为 下面四组请求中,①②③ 的返回值在改动前的代码上不可能出现

部署前后对照(deploy-status.sh):

前:hl-order-service-v3  dev-v3  776c0023d  BEHIND=10(Y)  2026-09-22 17:19:45  ok
后:hl-order-service-v3  dev-v3  843de6401  BEHIND=0(N)   2026-09-22 18:55:47  ok

网关实测四组(2026-09-22 18:5x,https://api.test.1814.love:9443)

端点一律 PUT /v3/admin/group-batch/999999999999999999/staff。

① scopeRoles: [null] —— 本单的主体

请求: {"scopeRoles":[null],"staffList":[]}
响应: {"code":400,"message":"scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

② scopeRoles: [""]

请求: {"scopeRoles":[""],"staffList":[]}
响应: {"code":400,"message":"scopeRoles 取值不在员工角色取值域内; scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

③ scopeRoles: [" "]

请求: {"scopeRoles":["  "],"staffList":[]}
响应: {"code":400,"message":"scopeRoles 取值不在员工角色取值域内; scopeRoles 的元素不能为空","data":null,"traceId":null,"success":false}

与 ② 的返回体逐字相同。

④ scopeRoles: ["GUIDE","LEADER"] —— 阴性对照

请求: {"scopeRoles":["GUIDE","LEADER"],"staffList":[]}
响应: {"code":589553,"message":"团期尚未创建(该班期还没有任何订单),请先建团并完成成团后再操作","data":null,"traceId":null,"success":false}

🔎 第 ④ 组不是凑数的:没有它,前三组的 400 也可能只是"这个端点对什么都返 400"。④ 用同一个不存在的 productBatchId、只换 scopeRoles 的取值,就穿过了绑定层抵达 Service 并拿到业务错误码 —— 证明前三组的 400 确实来自 scopeRoles 的元素级校验,而不是端点无差别拒绝。

🔎 取证为什么用不存在的团期:本单的校验发生在 Spring @Valid 绑定层、在进 Service 之前,所以 productBatchId 用一个不存在的值就够——前三组根本走不到 Service,不读不写任何真实团期数据。整轮实测零数据污染。

单测

BatchStaffConfigReqVOValidationTest(Validator 直调)与 GroupBatchStaffAdminControllerTest(@WebMvcTest)各有承载用例。后者除了断 $.code == 400 与 message 内容,还断了 verifyNoInteractions(groupBatchStaffConfigService),证明请求在进 Service 之前就被拦下 —— 没有这条断言,"@Valid 这道关生没生效"与"Service 内部某处恰好也返 400"在其余断言下完全同形。


九、已知缺口(不在本单范围)

  1. Swagger 请求侧 staffList[].staffRole 的取值域文案落后 3 个角色(只列前 5 个)。这是文案缺口不是实现缺口,校验按 8 个取值执行。以第六.5 节的表为准。

十、相关文档

文档 关系
21_8006_团期staff保存支持按角色范围覆盖-修改接口-管理后台.md / 22_8006_团期人员保存支持按角色范围覆盖-修改接口-管理后台.md scopeRoles 字段的完整契约出处(部分覆盖语义、删除窗口、582115)
22_8122_团期人员保存声明角色范围时必须整位覆盖-修改接口-管理后台.md 582116(半位声明拒绝)的契约出处
12_7530_团期staff去重与报账人扇出限定本团-修改接口-管理后台.md 扇出行为
12_7535_团期接口返回值整改非破坏批-修改接口-管理后台.md 响应字段(reporterRank 等)的出处

关联 / 联系人

  • Issue: #8150
  • PR: #8177(修复本体)、#8197(配套测试与注释订正)
  • 后端: wx
  • 前端: mmg(本单 frontend_status: not_required,判定依据见 frontmatter 的 status_note 与第六.7 节)