节点确认流程组、稿件流转、修改意见与自动确认模式 (2026-09-22)

需求背景

  • 来源:Milestone Confirmation Flow 需求(老板 demo 的完整流转:节点确认时限 / 自动确认 + 稿件流转 / 修改意见);节点确认部分 PRD 见 docs/pipipen/prd/2026-09-18_worktask_stage_confirmation.md。发布接口显式 stage_confirm_mode 需求(任务 09-29-stage-confirm-mode-explicit)按同域在途迭代并入本文,原独立文档 2026-09-29_stage_confirm_mode.md 已合并删除。
  • 动机:
    1. 节点确认缺少「画师提交后谁来确认、多久自动确认」的闭环,客户容易漏确认卡住流转;
    2. 旧批次读模型(upload_batches)在部分重传、多轮修改时因索引找错与语义悬空,无法准确表达当前交付物;
    3. 修改意见与流程状态机耦合过深导致单文件讨论被误当成流程驳回;
    4. 2026-09-28 会议拍板:废除批次读模型,重构为单文件视角。将节点流转动作收拢为 stage_confirmation 专属接口组;节点表直接记录当前待确认文件集合(current_request_file_ids);单文件意见恢复独立留言,仅批量驳回入口触发退回修改;
    5. 发布 Open Call / service 时,自动确认时限原来只用一个 stage_confirm_hours 表达(null = 用平台默认、0 = 关闭自动确认、正数 = 自定义),调用方容易把 null 与 0 混淆,编辑回填也会丢语义;本次让发布方显式选择「平台默认 / 自定义时限 / 关闭自动确认」。
  • 范围:
    1. 节点确认流程组(stage_confirmation):画师发起确认(request)、客户确认完成(confirm,原 confrim_stage_work_status 路径保留为兼容别名,两者指向同一实现)、客户批量驳回(revision_request);
    2. 稿件上传与单文件意见:artist_center/work_task_files/create 回归纯上传(显式禁止 request_confirmation,传入报 422 prohibited);work_task_file_change_requests/create 恢复单文件顶层参数契约(与流转解耦,任何状态不改节点状态);
    3. 读模型重构:移除两侧 work_tasks/info 的 upload_batches 读模型,work_task_stages 新增 current_request_file_ids;不做后端意见聚合读接口,弹窗由前端组合渲染;
    4. 自动确认与时限配置:stage_confirm_hours 时限配置、awaiting_confirmation / revision 状态机、倒计时与自动确认直通逻辑保持;
    5. 发布模式:四个发布接口(POST /api/projects/create、POST /api/projects/update、POST /api/artist_center/services/create、POST /api/artist_center/services/update)改为 stage_confirm_mode + stage_confirm_hours 组合;Project / Service 的读取响应新增 stage_confirm_mode。本次不改落库编码与 stage_confirm_hours 字段、不改 commission 快照与节点倒计时 / 自动确认 / 提醒逻辑、不改全局默认时限设置、不改后台页面;pipipen-front 由前端负责人配套改造(见第 4.6 节)。
  • 面向读者:前端(用户端 + 画师端)、联调、测试。
  • 术语对照:commission = WorkTask(委托,对外展示名 commissions);Open Call = Project;service = Service;节点 = WorkTaskStage;当前请求确认的文件集合 = current_request_file_ids;stage_confirm_hours 仍是落库字段(小时数),stage_confirm_mode 是发布选择语义,不落库,由 stage_confirm_hours 推导。

更新记录

  • 2026-09-22 首次发布(开发阶段契约,前后端需同分支发布):
    • 批量修改意见 items 契约;
    • upload_batches 批次读模型;
    • set_auto_confirm_stages 开关与自动确认语义边界(含 429 锁竞争口径)。
  • 2026-09-22 合并节点确认契约(原 2026-09-18_worktask_stage_confirmation 移除):
    • 并入节点确认状态机、stage_confirm_hours 时限与倒计时;
    • 到期提醒与超时自动确认;
    • confrim_stage_work_status 与两侧详情 work_task_stages 新字段;
    • services / projects / 后台全局设置接口;
    • 页面事件与通知场景,以及通知模板 seeder 上线步骤。
  • 2026-09-23 修订:
    • 字段表去除 emoji 前缀;
    • echo / event 详情改为表格(按在途同域迭代规则,展示形式调整,契约无变化)。
  • 2026-09-28 补齐驳回反馈读取契约:
    • 新增两侧 work_task_file_change_requests/list 读取契约说明(读取即已读,revision 时历史反馈照常可读);
    • 修正 size 上限校验缺陷(min:1|max:50);
    • 读取列表补 orderBy('id') 稳定排序。
  • 2026-09-28 节点确认流程专属接口组与单文件意见模型重构(在途合并):
    • 废除 upload_batches 读模型,改由 work_task_stages[].current_request_file_ids 直挂当前待确认文件集合;
    • 新增 stage_confirmation 流程专属接口组(POST /api/artist_center/stage_confirmation/request 发起确认、POST /api/stage_confirmation/confirm 确认节点、POST /api/stage_confirmation/revision_request 批量驳回);
    • 原 POST /api/work_tasks/confrim_stage_work_status 迁移至 stage_confirmation/confirm;
    • POST /api/artist_center/work_task_files/create 剥离确认行为并显式禁止 request_confirmation(422 prohibited 拒绝);
    • POST /api/work_task_file_change_requests/create 恢复单文件契约(未发版 items-only 改造作废,现存前端单文件调用零改动保持兼容),且任何状态下单文件意见均与节点流转解耦;
    • 取消后端聚合读接口,画师「Revision Requested」弹窗由前端组合文件列表与文件级 list 并行渲染。
  • 2026-09-29 画师侧意见列表支持批量取数:
    • POST /api/artist_center/work_task_file_change_requests/list 新增 work_task_file_ids 数组参数(与 work_task_file_id 二选一);
    • 批量模式合并多个本人文件下的意见后统一按 id 升序分页,越权 / 不存在的 id 静默忽略,上限 50 个且自动去重;
    • 单文件模式行为完全不变,返回结构 {data, total} 不变。
  • 2026-09-29 勘误(表述与契约对齐,后端未发版就地迭代):
    • 确认接口不再表述为「改名迁移」:旧路径 POST /api/work_tasks/confrim_stage_work_status 仍注册为兼容别名,破坏性变更清单由 3 项修正为 2 项;
    • 补齐 confirm / revision_request / stage_confirmation/request / 单文件 create / work_task_files/create / set_auto_confirm_stages 的错误分支与参数说明;
    • 修正批量驳回通知 meta 字段为 work_task_id / work_task_stage_id / work_task_file_id(首个文件)/ count;
    • 补 unread_change_requests_count 计数口径。
  • 2026-09-29 勘误(§2 锚点修复与 §3 用户侧 list 小节补齐):
    • 修复 §2 七个坏锚点:两侧 work_tasks/info 与 projects / services 变更行的组合标题短锚改为指向实际组合 id;
    • 补 §3 用户侧 POST /api/work_task_file_change_requests/list 小节(参数、id 升序稳定分页、越权 404 与用户侧读取不改 artist_is_read 语义)。
  • 2026-09-29 画师按文件分组取数接口与旧批量入参回退(破坏性变更,在途合并):
    • 新增 POST /api/artist_center/work_task_files/list:只接受 work_task_file_ids 数组,按文件分页并内嵌该文件全部意见(id 升序、含参考图),可选 has_change_requests_only 只返回有意见的文件;读取即已读作用于当前页文件内嵌的意见;
    • POST /api/artist_center/work_task_file_change_requests/list 移除 work_task_file_ids 批量入参,恢复单文件 work_task_file_id 平铺分页;只要传入批量键(含 null / 空数组 / 与单文件同时传)一律 422;
    • 画师弹窗取数迁移到新接口:响应层级由「合并平铺」变为「文件分组嵌套」,分页对象由意见变为文件,已读范围由「合并后当前页意见」变为「当前页文件内的全部意见」,不能视为原批量入参的等价替换。
  • 2026-09-29 节点自动确认模式发布契约合并(同域在途迭代,破坏性变更;原 2026-09-29_stage_confirm_mode.md 并入本文):
    • 四个发布接口新增 stage_confirm_mode(create 必填、update 可选),stage_confirm_hours 改为仅 enable 下允许且必填;
    • default / disable 下出现 stage_confirm_hours 键(含 null、0、空数组、空串)一律 422;update 只传 stage_confirm_hours 也 422;stage_confirm_mode: null 非法;
    • Project / Service 读取响应新增只读字段 stage_confirm_mode(null → default、0 → disable、正数 → enable),保留 stage_confirm_hours;
    • 新增第 1.8–1.12 节(模式流转 / 映射 / 快照 / 时序 / 对接要点)、第 4.4–4.6 节(字段关系 / 快照语义 / C 端交接清单),第 5 章破坏性变更与发布协同同步扩充。

建议阅读顺序:第 1 章(一分钟上手)→ 第 2 章(接口变更总览)→ 第 3 章(接口示例)→ 第 4 章(字段补充说明)→ 第 5 章(兼容性)。

目录

章内容什么时候看
1. 一分钟上手状态机 + 自动确认判定 + 确认与弹窗时序 + 倒计时来源 + 自动确认模式映射 + 对接要点刚拿到文档
2. 接口变更全部端点与变更摘要找接口
3. 接口示例每个端点的参数、示例与错误对接具体接口
4. 字段补充说明current_request_file_ids、弹窗组合渲染、work_task_stages 新字段、自动确认边界、时限与模式字段、commission 快照、C 端交接查具体取值与展示
5. 兼容性说明破坏性变更、发布协同与上线部署步骤发布前确认

1. 一分钟上手

本文所有接口都是 POST + JSON body。核心流转聚焦在 stage_confirmation 专属接口组(发起确认 / 确认完成 / 批量驳回);文件上传与常规单文件讨论留言完全从流程状态机中解耦。

1.1 节点确认状态机

revision 状态表示客户在确认弹窗中正式驳回了该节点,倒计时暂停;画师修改完成后只需重传变动的文件,并调用 stage_confirmation/request 重新圈定待确认文件集合,倒计时按完整时限重置。终审节点豁免自动确认,必须客户手动确认。

1.2 确认流转完整生命周期

1.3 自动确认判定(客户开关开启时)

1.4 确认流程批量驳回时序(Request Revision)

1.5 倒计时、到期提醒与两步确认调用时序

1.6 画师侧「查看修改意见(Revision Requested)」弹窗组合渲染时序

1.7stage_confirm_hours 如何决定倒计时

1.8 三态模式与发布 / 编辑流转

update 时不传 stage_confirm_mode 表示「不修改当前模式」;显式传 null 会被 422 拒绝。default 与 disable 的落库值不同(null / 0),但两者响应里的 stage_confirm_mode 分别回 default / disable,前端据此回填即可区分。

1.9 请求 mode → 落库 hours → 响应 mode 的映射

1.10 commission 快照的取值来源

1.11 发布、编辑与 commission 创建时序

1.12 对接要点:自动确认模式发布与读取

  1. create 必须传 mode:stage_confirm_mode 取 default / enable / disable 之一,缺失、显式 null、空数组、非法字符串、数字、布尔都会 422。
  2. hours 只在 enable 出现:enable 时 stage_confirm_hours 必填且为 1~720 的整数("120" 这类整数字符串按既有 Laravel integer 规则接受);default / disable 时不得传递该字段,连 null / 0 / [] / "" 都会被 422 拒绝。
  3. update 的 mode 是「可选改动位」:不传该字段表示保留原值(包括原值为 null / 0 / 正数);显式 stage_confirm_mode: null 非法。只传 stage_confirm_hours 而不传 mode 也会 422。
  4. 编辑回填读 mode,不要读 hours:stage_confirm_hours 为 null(default)和 0(disable)在 data.stage_confirm_hours || 0 下都会变成 0;回填必须直接使用响应里的 data.stage_confirm_mode。
  5. 请求与响应形状不对称:响应同时含 stage_confirm_mode 与 stage_confirm_hours(disable 时 hours 仍为 0),但提交 default / disable 时不得携带 stage_confirm_hours;不要把响应对象整体回传当作请求体。
  6. 422 全部是字段校验错误:本次不新增业务错误码,stage_confirm_mode / stage_confirm_hours 的失败都走 Laravel validate() 的 422,前端按 errors 的字段名定位。
  7. 发布协同:这是破坏性变更,API 与 C 端须配套切换;旧前端请求新 API 会 422,新前端请求旧 API 会把 disable 静默当成 default(详见第 5 章)。

1.13 对接要点:节点确认与倒计时

  1. 上传与请求确认拆为两步:work_task_files/create 仅负责把文件传上去(禁止传 request_confirmation,传入报 422 prohibited);上传后画师勾选「请求用户确认」时,调用 POST /api/artist_center/stage_confirmation/request 并传入本次请求确认的文件 id 列表。
  2. 确认节点接口路径迁移:规范路径为 POST /api/stage_confirmation/confirm;原 POST /api/work_tasks/confrim_stage_work_status 仍注册为兼容别名,指向同一控制器与同一套参数、逻辑,现网前端可渐进迁移。
  3. 倒计时只读节点字段:confirm_deadline_at / remaining_seconds。work_status = awaiting_confirmation 且 remaining_seconds = null 表示「只接受手动确认」(时限为 0 或是最终节点),此时不要展示倒计时。
  4. remaining_seconds 语义:过期返回 0,未过期返回剩余秒数,非待确认态返回 null;不要按 confirm_deadline_at 自行判断「0 = 未开始」。
  5. 确认来源只读:confirm_source = manual 来自客户确认接口,auto 来自后端定时任务或开启开关后的自动完成;前端不能传 confirm_source。
  6. 退回修改会暂停倒计时:确认弹窗驳回后节点变 revision 并清空 confirm_deadline_at;画师重新提交并请求确认后,按完整时限重置。

1.14 对接要点:稿件修改意见与弹窗组合渲染

  1. 单文件意见与流程完全解耦:POST /api/work_task_file_change_requests/create 恢复单文件顶层参数契约(work_task_file_id + content + upload_images),现存前端 3 处调用零改动保持兼容。无论节点处于任何状态,发表单文件意见均不会改变节点状态机(不触发 revision,倒计时不暂停)。
  2. 批量驳回唯一触发流转:确认弹窗中的「Request Revision」调用 POST /api/stage_confirmation/revision_request(items 数组);校验所有文件必须属于该节点的 current_request_file_ids;提交后节点正式转入 revision。
  3. upload_batches 读模型彻底移除:两侧 info 接口不再返回 upload_batches 字段;前端详情页若需展示待确认范围,直接读取 work_task_stages[].current_request_file_ids。
  4. 画师侧弹窗按文件分组取数:画师打开「Revision Requested」弹窗时,调用 POST /api/artist_center/work_task_files/list,把该节点的 current_request_file_ids 作为 work_task_file_ids 一次传入(上限 50 个,自动去重,只接受数组)。响应以文件为单位分页,每个文件内嵌其全部意见(id 升序、含参考图);不属于本人 / 不存在的文件被静默忽略,全部无效时返回空列表。传 has_change_requests_only: true 可只返回有意见的文件;旧接口 POST /api/artist_center/work_task_file_change_requests/list 已移除批量入参,仅保留单文件平铺。
  5. 意见展示与文件详情同口径:弹窗内展示的意见就是文件详情里的意见,不存在两套数据;意见只分已读/未读(读取即已读),红点提醒统一以 unread_change_requests_count 为准。

2. 接口变更

stage_confirmation(流程专属组,两侧同名)

  • POST /api/artist_center/stage_confirmation/request
    • 功能:画师请求客户确认节点
    • 变更:✨ 新增接口,将文件 id 列表写入 current_request_file_ids,并推动节点进入 awaiting_confirmation(或触发自动确认完成)
  • POST /api/stage_confirmation/confirm
    • 功能:客户确认当前节点完成
    • 变更:⚠️ 规范路径调整(原 POST /api/work_tasks/confrim_stage_work_status 保留为兼容别名,与新路径指向同一实现,原有参数与逻辑完全保持不变;现网前端可渐进迁移)
  • POST /api/stage_confirmation/revision_request
    • 功能:客户确认弹窗批量驳回节点并提交修改意见
    • 变更:✨ 新增接口,items 批量契约,唯一触发节点进入 revision 的意见入口

user

artist_center


3. 接口示例

POST /api/artist_center/stage_confirmation/request

  • 功能说明:画师上传稿件完成后,主动发起请求客户确认节点。
  • 业务行为:将传入的文件列表写入该节点的 current_request_file_ids;若客户开启了自动确认且节点非最终已付款,则直接完成节点;否则进入 awaiting_confirmation 并启动倒计时。

请求参数

字段类型必填说明
work_task_stage_idinteger是节点 id,必须真实存在且属于当前画师
work_task_file_idsinteger[]是本次请求确认的文件 id 列表,至少 1 个,且必须全部属于该节点;服务端自动去重(unique())

请求示例

{
  "work_task_stage_id": 2001,
  "work_task_file_ids": [501, 502]
}

响应示例

进入 awaiting_confirmation(默认路径):

{
  "ok": true,
  "data": {
    "id": 2001,
    "work_status": "awaiting_confirmation",
    "current_request_file_ids": [501, 502],
    "confirm_deadline_at": "2026-09-30T12:00:00.000000Z",
    "remaining_seconds": 172800
  }
}

客户开启自动确认且节点非最终已付款时直接完成节点(跳过 awaiting_confirmation,自动直通):

{
  "ok": true,
  "data": {
    "id": 2001,
    "work_status": "finished",
    "current_request_file_ids": [501, 502],
    "confirmed_at": "2026-09-29T10:00:00.000000Z",
    "confirm_source": "auto"
  }
}

错误响应

404:节点不属于当前画师

{
  "message": "Work task stage not found"
}

400:节点状态不允许请求确认(非 working / revision)

{
  "code": 20007,
  "message": "Work task stage cannot request confirmation in the current status"
}

422:work_task_file_ids 中有 id 不存在(先命中 exists:work_task_files,id,errors key 为 work_task_file_ids.<下标>,到不了「不属于该节点」分支)

{
  "message": "The selected work_task_file_ids.0 is invalid.",
  "errors": {
    "work_task_file_ids.0": ["The selected work_task_file_ids.0 is invalid."]
  }
}

422:传入的文件均存在但不全属于该节点

{
  "message": "Some work task files do not belong to this stage.",
  "errors": {
    "work_task_file_ids": ["Some work task files do not belong to this stage."]
  }
}

429:自动确认直通路径并发锁竞争(内部走 confirmWithLock 的 lock:confirmStageWorkStatus:{work_task_id})

{
  "message": "系统繁忙,请稍后重试"
}

POST /api/stage_confirmation/confirm

  • 功能说明:客户确认当前节点完成。规范路径为 POST /api/stage_confirmation/confirm;原 POST /api/work_tasks/confrim_stage_work_status 保留为兼容别名,指向同一控制器,参数与业务逻辑完全一致。
  • 业务行为:节点标记为 finished,记录 confirm_source = manual;若下一节点已付款则自动激活为 working;若全单已完成且付清触发结算。

请求参数

字段类型必填说明
id / work_task_idinteger是commission id(work_tasks.id,两者传其一即可;同时传时 work_task_id 优先)

请求示例

{
  "id": 1001
}

响应示例

{
  "ok": true
}

错误响应

404:commission 存在但不属于当前客户

{
  "message": "Not found"
}

429:并发确认锁竞争(lock:confirmStageWorkStatus:{work_task_id} 未获取到)

{
  "message": "系统繁忙,请稍后重试"
}

400:存在未完成的 commission cancellation,确认被拒

{
  "code": 21012,
  "message": "Commission cancellation must finish before completion"
}

400:无可确认节点或状态不允许(20004 实际有两种 message,前端按 code 分支即可)

{
  "code": 20004,
  "message": "Work task stage cannot be confirmed in the current status"
}
{
  "code": 20004,
  "message": "No confirmable work task stage found"
}

POST /api/stage_confirmation/revision_request

  • 功能说明:客户在确认弹窗中点击「Request Revision」正式驳回节点并批量提交修改意见。唯一触发节点进入 revision 的意见入口。
  • 业务行为:校验节点处于 awaiting_confirmation 且所选文件全部位于该节点的 current_request_file_ids 内;事务内原子创建意见并推动节点进入 revision(倒计时清空);向画师发送一次合并通知与页面事件。

请求参数

字段类型必填说明
itemsobject[]是修改意见列表,至少 1 条
items[].work_task_file_idinteger是稿件文件 id,带 distinct(同文件重复报 422),且必须属于当前节点的 current_request_file_ids
items[].contentstring | object否意见文字内容(整批至少一条非空)
items[].content_langstring否语言代码,默认当前语言
items[].upload_imagesinteger[]否参考图 id 列表(upload_images.id),必须属于当前客户

其他校验规则

  • items[].work_task_file_id 带 distinct:同一文件在 items 中重复出现报 422。
  • 所有文件必须属于同一 commission 且同一节点:跨 commission 报 items.N: work task file belongs to another work task,跨节点报 items.N: work task file belongs to another stage(均落在 errors key items.N.work_task_file_id)。
  • 文件必须属于当前客户(user->workTaskFiles()):非本人文件报 items.N: work task file not found for current user。
  • items[].upload_images 中每个 id 必须属于当前客户,否则报 items.N: upload image not found for current user(errors key 为 items.N.upload_images)。
  • 整批至少一条 content 非空,否则报 At least one non-empty content is required.(errors key 为 items)。

请求示例

{
  "items": [
    {
      "work_task_file_id": 501,
      "content": { "en": "Please adjust the sketch proportion" },
      "upload_images": [9001]
    },
    {
      "work_task_file_id": 502,
      "content": { "en": "The colors look good, keep them" }
    }
  ]
}

响应示例

{
  "data": [
    {
      "id": 7001,
      "work_task_id": 1001,
      "work_task_file_id": 501,
      "content": { "en": "Please adjust the sketch proportion", "_lang": "en" },
      "artist_is_read": 0
    },
    {
      "id": 7002,
      "work_task_id": 1001,
      "work_task_file_id": 502,
      "content": { "en": "The colors look good, keep them", "_lang": "en" },
      "artist_is_read": 0
    }
  ]
}

错误响应

422:节点不处于 awaiting_confirmation 状态

{
  "message": "The stage of the referenced files is not awaiting confirmation.",
  "errors": {
    "items": ["The stage of the referenced files is not awaiting confirmation."]
  }
}

422:尝试对不在本次请求确认范围内的文件提驳回意见

{
  "message": "items.0: work task file is not in current requested files",
  "errors": {
    "items.0.work_task_file_id": ["items.0: work task file is not in current requested files"]
  }
}

422:同一文件在 items 中重复(distinct)

{
  "message": "The items.1.work_task_file_id field has a duplicate value.",
  "errors": {
    "items.1.work_task_file_id": ["The items.1.work_task_file_id field has a duplicate value."]
  }
}

422:文件不属于当前客户

{
  "message": "items.0: work task file not found for current user",
  "errors": {
    "items.0.work_task_file_id": ["items.0: work task file not found for current user"]
  }
}

422:文件跨 commission

{
  "message": "items.1: work task file belongs to another work task",
  "errors": {
    "items.1.work_task_file_id": ["items.1: work task file belongs to another work task"]
  }
}

422:文件跨节点

{
  "message": "items.1: work task file belongs to another stage",
  "errors": {
    "items.1.work_task_file_id": ["items.1: work task file belongs to another stage"]
  }
}

422:整批 content 全空

{
  "message": "At least one non-empty content is required.",
  "errors": {
    "items": ["At least one non-empty content is required."]
  }
}

422:参考图不属于当前客户

{
  "message": "items.0: upload image not found for current user",
  "errors": {
    "items.0.upload_images": ["items.0: upload image not found for current user"]
  }
}

422:commission 或节点不存在(文件校验通过但对应记录缺失)

{
  "message": "Work task or stage not found.",
  "errors": {
    "items": ["Work task or stage not found."]
  }
}

422:items[].work_task_file_id 不存在(exists:work_task_files,id 校验,先于归属判断)

{
  "message": "The selected items.0.work_task_file_id is invalid.",
  "errors": {
    "items.0.work_task_file_id": ["The selected items.0.work_task_file_id is invalid."]
  }
}

POST /api/work_task_file_change_requests/create

  • 功能说明:客户对单个稿件文件发表修改意见(讨论留言)。
  • 变更说明:🔧 契约恢复,恢复顶层参数。与节点确认流程完全解耦,发表意见不改变节点状态机,倒计时不暂停。在节点处于 working、awaiting_confirmation、revision 时均可调用;pending 或 finished 状态下拒绝。

请求参数

字段类型必填说明
work_task_file_idinteger是稿件文件 id,必须属于当前客户
contentstring | object是意见内容(字符串或多语言对象),不能为空(空多语言对象 / 各语言值均为空报 422)
content_langstring否语言代码
upload_imagesinteger[]否参考图 id 列表,必须属于当前客户

请求示例

{
  "work_task_file_id": 501,
  "content": "单文件卡片留言讨论",
  "upload_images": []
}

响应示例

{
  "data": {
    "id": 7003,
    "work_task_id": 1001,
    "work_task_file_id": 501,
    "content": { "zh": "单文件卡片留言讨论", "_lang": "zh" },
    "artist_is_read": 0,
    "upload_images": []
  }
}

错误响应

404:文件存在但不属于当前客户

{
  "message": "Work task file not found"
}

422:content 为空(空多语言对象,或对象内各语言值均为空)

{
  "message": "The content field cannot be empty.",
  "errors": {
    "content": ["The content field cannot be empty."]
  }
}

422:文件所在节点处于 pending / finished 状态

{
  "message": "Cannot add change request to a pending or finished stage.",
  "errors": {
    "work_task_file_id": ["Cannot add change request to a pending or finished stage."]
  }
}

422:参考图不属于当前客户

{
  "message": "Upload image not found for current user.",
  "errors": {
    "upload_images": ["Upload image not found for current user."]
  }
}

POST /api/work_task_file_change_requests/list

  • 功能说明:客户读取某稿件文件下的修改意见(含反馈图片),用于文件卡片详情展示。
  • 变更说明:修复 size 校验(min:1|max:50)与 id 升序稳定排序。
  • 读取语义:用户侧读取不会改变 artist_is_read。已读标记只在画师侧读取(POST /api/artist_center/work_task_file_change_requests/list)时置真,客户在本接口查询意见不影响画师的未读计数。

请求参数

字段类型必填说明
work_task_file_idinteger是稿件文件 id,必须属于当前客户;需存在于 work_task_files
pageinteger否页码,默认 1,最小 1
sizeinteger否每页条数,默认 15,范围 `min:1

其他校验规则

  • work_task_file_id:必填、正整数,且必须存在于 work_task_files;缺失报 422 required,不存在报 422 exists。
  • page / size:整数;size 超出 1~50 报 422。
  • 查询按意见 id 升序稳定排序后分页,upload_images 随记录一并预载返回。

请求示例

{
  "work_task_file_id": 501,
  "page": 1,
  "size": 15
}

响应示例

{
  "data": [
    {
      "id": 7003,
      "work_task_file_id": 501,
      "content": { "zh": "单文件卡片留言讨论", "_lang": "zh" },
      "artist_is_read": 0,
      "upload_images": []
    }
  ],
  "total": 1
}

错误响应

404:文件存在但不属于当前客户(该分支为控制器内手写 response()->json(['message' => 'Work task file not found'], 404),与同文件 create 的 abort(404, ...) 并存)

{
  "message": "Work task file not found"
}

422:work_task_file_id 缺失

{
  "message": "The work task file id field is required.",
  "errors": {
    "work_task_file_id": ["The work task file id field is required."]
  }
}

422:size 超出 1~50

{
  "message": "The size field must not be greater than 50.",
  "errors": {
    "size": ["The size field must not be greater than 50."]
  }
}

POST /api/artist_center/work_task_files/create

  • 功能说明:画师上传稿件文件(纯上传接口)。
  • 变更说明:⚠️ 彻底剥离确认分支。禁止传递 request_confirmation 参数;若传入该参数直接返回 422 prohibited 拒绝,防止旧前端未改造时静默丢失确认行为。

请求参数

字段类型必填说明
work_task_idinteger是commission id
work_task_stage_idinteger是节点 id,必须属于该 commission
upload_file_idsinteger[]否(与 upload_file_id 至少传一个)已上传文件 id 列表
upload_file_idinteger否(与 upload_file_ids 至少传一个)单值兼容(旧)
request_confirmationprohibited否显式禁止,传入报 422

upload_file_ids 与 upload_file_id 可以同时传,服务端合并后去重(merge(...)->filter()->unique());最终创建的稿件文件数等于去重后的 id 个数。

请求示例

{
  "work_task_id": 1001,
  "work_task_stage_id": 2001,
  "upload_file_ids": [501, 502]
}

响应示例

{
  "ok": true,
  "data": [
    {
      "id": 601,
      "work_task_id": 1001,
      "work_task_stage_id": 2001,
      "user_id": 11,
      "upload_batch_id": "0f2b6c1e-9a7d-4c3b-9f6e-1d2a3b4c5d6e"
    },
    {
      "id": 602,
      "work_task_id": 1001,
      "work_task_stage_id": 2001,
      "user_id": 11,
      "upload_batch_id": "0f2b6c1e-9a7d-4c3b-9f6e-1d2a3b4c5d6e"
    }
  ]
}

upload_batch_id 是本次创建生成的 UUID 分组列,同一批文件行共享同一值;批次读模型(upload_batches)已废弃,该列仅为历史兼容保留,前端不得再依赖它做分组展示。

错误响应

422:误传 request_confirmation

{
  "message": "The request confirmation field is prohibited.",
  "errors": {
    "request_confirmation": ["The request confirmation field is prohibited."]
  }
}

422:upload_file_ids 与 upload_file_id 都未传

{
  "message": "The work task file ids field is required when upload file id is not present.",
  "errors": {
    "upload_file_ids": ["The work task file ids field is required when upload file id is not present."]
  }
}

404:上传文件存在但不属于当前画师

{
  "message": "Upload file not found"
}

404:commission 存在但不属于当前画师

{
  "message": "Work task not found"
}

400:节点不属于该 commission

{
  "code": 20006,
  "message": "Work task stage does not belong to this work task"
}

POST /api/work_tasks/info 与POST /api/artist_center/work_tasks/info

  • 功能说明:查询约稿详情(两侧契约一致)。
  • 变更说明:⚠️ 破坏性变更,彻底移除 data.upload_batches;在 data.work_task_stages 数组元素中新增 current_request_file_ids(若从未请求确认则为 null)。

响应示例(节选)

{
  "data": {
    "id": 1001,
    "client_auto_confirm_stages": false,
    "work_task_stages": [
      {
        "id": 2001,
        "percent": 30,
        "amount": 300,
        "is_paid": 1,
        "work_status": "awaiting_confirmation",
        "current_request_file_ids": [501, 502],
        "confirm_deadline_at": "2026-09-30T12:00:00.000000Z",
        "remaining_seconds": 172800
      }
    ],
    "work_task_files": [
      { "id": 501, "work_task_stage_id": 2001 },
      { "id": 502, "work_task_stage_id": 2001 }
    ]
    // 注意:data.upload_batches 已不再返回!
  }
}

POST /api/artist_center/work_task_files/list

  • 功能说明:画师一次性读取多个稿件文件的修改意见,按文件分组返回(文件分页 + 每个文件内嵌全部意见 + 参考图)。画师「Revision Requested」弹窗取数使用本接口。
  • 变更说明:✨ 新增接口,替代原 POST /api/artist_center/work_task_file_change_requests/list 的批量取数能力;只接受 work_task_file_ids 数组,不提供单文件别名。

请求参数

字段类型必填说明
work_task_file_idsnumber[]是稿件文件 id 列表,至少 1 个、最多 50 个,重复 id 自动去重
has_change_requests_onlyboolean否默认 false;为 true 时只返回至少有一条意见的文件,为 false 时返回全部命中文件(含意见为空的文件)
pagenumber否文件页码,默认 1
sizenumber否每页文件数,默认 15,上限 50

其他校验规则

  • work_task_file_ids:必填非空整数数组,元素为正整数,最多 50 个;缺参、空数组、非数组、非法元素、超过 50 个均报 422。
  • 越权 / 不存在的 id 静默忽略(不加 exists 校验,经当前画师关系过滤);全部无效时返回 { "data": [], "total": 0 }(200)。
  • has_change_requests_only 为 sometimes|boolean,非布尔值报 422;筛选先于文件分页与 total 统计。
  • 文件按 id 升序稳定分页,total 为筛选后命中的文件数;静态数据集下跨页不重复不遗漏。
  • 读取即已读:仅当前页返回文件内嵌的意见会置 artist_is_read = true(响应也返回 true);未返回页、越权文件的意见保持原值;空意见文件不产生写入;重复读取不重复写库。

请求示例

{
  "work_task_file_ids": [501, 502, 503],
  "has_change_requests_only": true,
  "page": 1,
  "size": 15
}

响应示例

{
  "data": [
    {
      "id": 501,
      "work_task_id": 1001,
      "work_task_stage_id": 2001,
      "work_task_file_change_requests": [
        {
          "id": 221,
          "work_task_file_id": 501,
          "content": { "en": "Please adjust the sketch", "_lang": "en" },
          "artist_is_read": true,
          "upload_images": [
            { "id": 1, "url_og": "https://example.pipipen.com/ref.png" }
          ]
        }
      ]
    }
  ],
  "total": 1
}

错误响应

422:work_task_file_ids 缺失 / 空数组 / 超过 50 个 / 元素非法

{
  "message": "The work_task_file_ids field is required.",
  "errors": {
    "work_task_file_ids": ["The work_task_file_ids field is required."]
  }
}

422:has_change_requests_only 非布尔值

{
  "message": "The has_change_requests_only field must be true or false.",
  "errors": {
    "has_change_requests_only": ["The has_change_requests_only field must be true or false."]
  }
}

422:size 超过 50 或 page 小于 1

{
  "message": "The size field must not be greater than 50.",
  "errors": {
    "size": ["The size field must not be greater than 50."]
  }
}

POST /api/artist_center/work_task_file_change_requests/list

  • 功能说明:画师读取单个稿件文件的修改意见(读取即已读),意见平铺、按 id 升序分页。
  • 变更说明:⚠️ 破坏性变更,移除 work_task_file_ids 批量入参,恢复单文件 work_task_file_id 契约;需要跨文件按文件分组取数请改用 POST /api/artist_center/work_task_files/list。

请求参数

字段类型必填说明
work_task_file_idnumber是单个稿件文件 id
pagenumber否页码,默认 1
sizenumber否每页条数,默认 15,上限 50

其他校验规则

  • work_task_file_id:必填正整数,且必须存在于 work_task_files(不存在报 422);非当前画师文件返回 404。
  • 移除的 work_task_file_ids 只要作为键出现即报 422,包括 null、空数组 [],以及同时传入 work_task_file_id 时——不做静默忽略。
  • 读取即已读:仅当前页返回的意见置 artist_is_read = true。

请求示例

{
  "work_task_file_id": 501,
  "page": 1,
  "size": 15
}

响应示例

{
  "data": [
    {
      "id": 221,
      "work_task_file_id": 501,
      "content": { "en": "Please adjust the sketch", "_lang": "en" },
      "artist_is_read": true,
      "upload_images": [
        { "id": 1, "url_og": "https://example.pipipen.com/ref.png" }
      ]
    }
  ],
  "total": 1
}

错误响应

422:传入已移除的批量入参 work_task_file_ids(missing 规则的标准 message)

{
  "message": "The work_task_file_ids field must be missing.",
  "errors": {
    "work_task_file_ids": ["The work_task_file_ids field must be missing."]
  }
}

404:文件存在但不属于当前画师

{
  "message": "Work task file not found"
}

POST /api/work_tasks/set_auto_confirm_stages

  • 功能说明:客户开启 / 关闭「自动确认后续节点」。
  • 参数:work_task_id(integer,必填)、auto_confirm(boolean,必填)。
  • 仅当 work_tasks.status = working 时允许修改。

错误响应

404:commission 存在但不属于当前客户

{
  "message": "Work task not found"
}

400:commission 不在 working 状态(20008)

{
  "code": 20008,
  "message": "Auto confirm stages can only be changed while the work task is working"
}

POST /api/projects/create /POST /api/artist_center/services/create

  • 功能说明:发布 Open Call / service,同时确定节点自动确认模式。
  • 变更说明:⚠️ 破坏性变更,新增必填 stage_confirm_mode;stage_confirm_hours 仅在 stage_confirm_mode = enable 时允许且必填。

请求参数

字段类型必填说明
stage_confirm_modestring是自动确认模式:default(采用平台默认时限)、enable(自定义时限)、disable(关闭自动确认)
stage_confirm_hoursinteger仅 enable自定义自动确认时限(小时),1~720;其他模式不得传递该字段

请求参数矩阵

stage_confirm_modestage_confirm_hours结果
default不传200,落库 null
enable整数 1~720(含 "120" 这类整数字符串)200,落库该整数
enable缺失 / null / 0 / 721 / [] / ""422
disable不传200,落库 0
default / disable传了该字段(null、0、1、720、721、[]、""、"120" 等任意值)422
缺失 / null / [] / 非法字符串 / 数字 / 布尔任意422

其他校验规则

  • stage_confirm_mode 只接受 default / enable / disable 三个字符串值;其他类型(数字、布尔、数组)与非法字符串均报 422。
  • stage_confirm_hours 在 enable 下按 required|integer|min:1|max:720 校验;在 default / disable 下按 missing 校验,即按键存在性拒绝,不做值比较。
  • 校验在持久化与其他业务副作用之前完成,非法请求不产生 project / service 记录。
  • 两个接口的其余发布字段校验与本次改动无关,保持原有约定。

请求示例

{
  "stage_confirm_mode": "enable",
  "stage_confirm_hours": 120
}

上面的 JSON 只展示本次变更字段;实际请求还需带上各接口原有的必填字段(name / content / currency_id 等)。

响应示例

{
  "data": {
    "id": 3001,
    "stage_confirm_mode": "enable",
    "stage_confirm_hours": 120
    // ...其余字段省略
  }
}

default 与 disable 的响应差异:

{
  "data": {
    "id": 3002,
    "stage_confirm_mode": "default",
    "stage_confirm_hours": null
    // ...其余字段省略
  }
}
{
  "data": {
    "id": 3003,
    "stage_confirm_mode": "disable",
    "stage_confirm_hours": 0
    // ...其余字段省略
  }
}

错误响应

422:create 缺失 stage_confirm_mode、显式 null 或空数组

{
  "message": "The stage confirm mode field is required.",
  "errors": {
    "stage_confirm_mode": ["The stage confirm mode field is required."]
  }
}

422:stage_confirm_mode 非法字符串 / 数字 / 布尔

{
  "message": "The selected stage confirm mode is invalid.",
  "errors": {
    "stage_confirm_mode": ["The selected stage confirm mode is invalid."]
  }
}

422:enable 缺失 stage_confirm_hours(null、[]、"" 同此分支)

{
  "message": "The stage confirm hours field is required.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field is required."]
  }
}

422:enable 的 stage_confirm_hours 为 0

{
  "message": "The stage confirm hours field must be at least 1.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must be at least 1."]
  }
}

422:enable 的 stage_confirm_hours 为 721

{
  "message": "The stage confirm hours field must not be greater than 720.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must not be greater than 720."]
  }
}

422:default / disable 下出现 stage_confirm_hours 键

{
  "message": "The stage confirm hours field must be missing.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must be missing."]
  }
}

POST /api/projects/update /POST /api/artist_center/services/update

  • 功能说明:更新 Open Call / service,可选地切换节点自动确认模式。
  • 变更说明:⚠️ 破坏性变更,新增可选 stage_confirm_mode(不传 = 不修改);stage_confirm_hours 仅在 stage_confirm_mode = enable 时允许且必填。

请求参数

字段类型必填说明
idinteger是project / service id(原有字段)
stage_confirm_modestring否default / enable / disable;不传表示不修改,显式 null 报 422
stage_confirm_hoursinteger仅 enable同 create,1~720

请求参数矩阵

stage_confirm_modestage_confirm_hours结果
不传不传200,保留原 stage_confirm_hours(null / 0 / 正数均原样保留)
不传传了该字段422
default不传200,落库 null
enable整数 1~720200,落库该整数
disable不传200,落库 0
default / disable传了该字段(任意值)422
null / 非法字符串 / 数字 / 布尔 / 数组任意422
enable缺失 / null / 0 / 721 / [] / ""422

其他校验规则

  • stage_confirm_mode 按 sometimes|in:default,enable,disable 校验:未传时不参与校验,传了则必须是三值之一。
  • stage_confirm_hours 的校验规则与 create 一致;未传 mode 时也按 missing 处理,因此「未传 mode 却传 hours」会 422。
  • 非法请求不产生任何写入副作用(原 stage_confirm_hours 保持不变)。

请求示例

切换为自定义时限:

{
  "id": 3001,
  "stage_confirm_mode": "enable",
  "stage_confirm_hours": 200
}

切换为关闭自动确认(不携带 stage_confirm_hours):

{
  "id": 3001,
  "stage_confirm_mode": "disable"
}

不修改模式(两个键都不传):

{
  "id": 3001
}

响应示例

update 沿用既有约定,只返回 ok,不回传实体:

{
  "ok": true
}

更新后的 stage_confirm_mode / stage_confirm_hours 需从 POST /api/projects/list、GET /api/projects/info(service 为 GET /api/artist_center/services/list、/info)读取,不要尝试从 update 响应解构 data。

错误响应

422:显式 stage_confirm_mode: null、非法字符串 / 数字 / 布尔 / 数组

{
  "message": "The selected stage confirm mode is invalid.",
  "errors": {
    "stage_confirm_mode": ["The selected stage confirm mode is invalid."]
  }
}

422:未传 stage_confirm_mode 却传了 stage_confirm_hours

{
  "message": "The stage confirm hours field must be missing.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must be missing."]
  }
}

422:enable 缺失 / 越界 / 类型非法的 stage_confirm_hours

{
  "message": "The stage confirm hours field is required.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field is required."]
  }
}
{
  "message": "The stage confirm hours field must be at least 1.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must be at least 1."]
  }
}
{
  "message": "The stage confirm hours field must not be greater than 720.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must not be greater than 720."]
  }
}

422:default / disable 下出现 stage_confirm_hours 键

{
  "message": "The stage confirm hours field must be missing.",
  "errors": {
    "stage_confirm_hours": ["The stage confirm hours field must be missing."]
  }
}

POST /api/projects/list /GET /api/projects/info /GET /api/artist_center/services/list /GET /api/artist_center/services/info

  • 功能说明:读取 Open Call / service 的列表与详情。
  • 变更说明:✨ 响应新增只读字段 stage_confirm_mode;原 stage_confirm_hours 字段保留,存储与输出含义不变。

响应示例(节选)

{
  "data": {
    "id": 3003,
    "stage_confirm_mode": "disable",
    "stage_confirm_hours": 0
    // ...其余字段省略
  }
}

字段取值

stage_confirm_hours响应 stage_confirm_mode含义
nulldefault采用平台默认时限
0disable关闭自动确认
正数enable自定义时限

stage_confirm_mode 是 Project / Service 模型的 append 字段,所有序列化这两个模型的接口响应都会带上它(含公开内容侧的企划 / service 详情);本次回归覆盖的读取端点为上列四个。


4. 字段补充说明

4.1 ✨ 待确认文件集与画师弹窗组合渲染

本次模型重构后,彻底废弃了服务端批次读模型(upload_batches)。各端交互约定如下:

  1. 当前待确认范围:由 work_task_stages[].current_request_file_ids 数组明确定义。
  2. 画师侧弹窗组合渲染:
    • 画师点击「Revision Requested」弹窗时,前端获取该节点的 current_request_file_ids(例如 [501, 502]);
    • 前端调用 POST /api/artist_center/work_task_files/list,传 work_task_file_ids: [501, 502](可按需传 has_change_requests_only: true),响应以文件为单位分页、每个文件内嵌其全部意见;
    • 按文件卡片分组展示意见与参考图;若某文件在本次确认流程中未被提意见,默认不展示(has_change_requests_only: true 时服务端已过滤);
    • 弹窗中提供画师针对被驳回文件的重新上传入口。
  3. 旧文件全量平铺保留:历史文件永不删除、永不隐藏;历史意见直接在文件卡片详情中查看。
  4. 未读意见数口径:unread_change_requests_count 按 artist_is_read = false 计数(画师侧详情返回的未读意见总数),读取即为已读后归零。

4.2 节点返回字段变更(work_task_stages)

字段类型说明
work_statusstring取值:pending、working、awaiting_confirmation、revision、finished
current_request_file_idsinteger[] | null当前请求确认的文件 id 列表;未发起确认时为 null
confirm_deadline_atstring | null自动确认截止时间(待确认且非终审时有效)
confirmed_atstring | null节点确认时间
confirm_sourcestring | null确认来源:manual / auto
remaining_secondsinteger | null剩余秒数(过期返回 0,非待确认返回 null)

4.3 ⚠️ 自动确认语义边界

场景行为
开关开启 + 非最终 + 已付款节点 + 调用 stage_confirmation/request跳过 awaiting_confirmation,直接完成,confirm_source = auto
开关开启 + 最终节点不自动完成,进入 awaiting_confirmation(终审节点豁免自动确认)
开关开启 + 未付款节点不自动完成,进入 awaiting_confirmation
开关关闭全部进入 awaiting_confirmation(正常倒计时流程)
开关开启但仅上传未调 request仅创建文件,不改变节点状态

4.4 ⚠️stage_confirm_mode 与stage_confirm_hours 的关系

  • stage_confirm_mode 只存在于请求与响应,不落库、不新增数据库列或迁移;落库字段仍是 projects.stage_confirm_hours / services.stage_confirm_hours(integer null)。
  • 请求侧:mode 决定写入值(default → null、enable → 自定义值、disable → 0);hours 只作为 enable 的输入。
  • 响应侧:stage_confirm_hours 经 integer cast 后推导 stage_confirm_mode(null → default、0 → disable、正数 → enable)。字符串 "0" 的模型属性经 cast 后为整数 0,同样推导为 disable。
  • disable 的响应仍返回 stage_confirm_hours = 0,与 default 的 null 在响应里可区分;但请求侧不能把响应整体回传,提交 default / disable 时必须删除 stage_confirm_hours 键。

4.5 commission 快照语义

  • commission 创建时(Api/User/ProjectRequestController 与 Api/Artist/ServiceRequestController)从来源读取 stage_confirm_hours 写入 work_tasks.stage_confirm_hours 快照:
    • default(来源 null)→ 物化为创建当时的平台全局默认时限(该默认值本身可以为 0);
    • enable → 物化为自定义值;
    • disable(来源 0)→ 物化为 0。
  • 快照一旦写入即冻结:之后修改来源 project / service,或修改后台全局默认时限,都不回填已创建的 commission。
  • 既有非 null 快照行为不变;旧数据中 work_tasks.stage_confirm_hours 为 null 的 commission 仍按运行时回退到全局默认,本次不改其处理。
  • work_tasks 不新增 stage_confirm_mode;节点倒计时仍以 work_status = awaiting_confirmation 且存在 confirm_deadline_at 为依据。本次不改 deadline 生成、终审豁免、提醒查询与调度顺序。

4.6 C 端交接清单(pipipen-front,由前端负责人实施)

pipipen-front 本任务只读,需按下列要点完成两个发布 / 编辑页的改造,并与 API 配套发布:

  1. 模式选择控件:发布 / 编辑页提供三态选择 —
    • default:采用平台默认时限(不展示小时输入);
    • enable:自定义时限(展示 1~720 的小时输入,必填且为整数);
    • disable:关闭自动确认(不展示小时输入)。
  2. 编辑回填:使用响应里的 data.stage_confirm_mode 决定选中项;移除 data.stage_confirm_hours || 0 这类推断,它会把 default(null)与 disable(0)都读成 0。小时输入框的值取 data.stage_confirm_hours(仅 enable 时有意义)。
  3. payload 构造:
    • default → 只传 stage_confirm_mode: "default",不传 stage_confirm_hours;
    • enable → 同时传 stage_confirm_mode: "enable" 与 stage_confirm_hours: <整数>;
    • disable → 只传 stage_confirm_mode: "disable",不传 stage_confirm_hours;
    • 编辑且不修改模式 → 两个键都不要出现在 payload 里(不要传 null)。
    • 不要把读取到的响应对象整体作为请求体提交。
  4. 四端点联调:POST /api/projects/create、POST /api/projects/update、POST /api/artist_center/services/create、POST /api/artist_center/services/update 使用同一套 mode / hours 规则,四个端点都要按第 3 章的请求参数矩阵覆盖 default / enable / disable 三种提交与边界值(1、720)。
  5. 错误处理:422 时按 errors.stage_confirm_mode / errors.stage_confirm_hours 定位字段并提示;本次不引入新业务错误码。

5. 兼容性说明

  • 破坏性变更(6 项):
    1. 移除 upload_batches:两侧 work_tasks/info 不再返回 data.upload_batches;前端须改用 work_task_stages[].current_request_file_ids。
    2. 上传接口禁止 request_confirmation:work_task_files/create 传该参数直接返回 422;必须拆为先传文件、再调 stage_confirmation/request。
    3. 移除意见列表批量入参:POST /api/artist_center/work_task_file_change_requests/list 不再接受 work_task_file_ids(含 null / 空数组 / 与单文件同时传均 422);跨文件取数改用新接口 POST /api/artist_center/work_task_files/list。注意新接口响应为文件分页 + 按文件分组的嵌套意见,读取即已读范围为当前页文件内的意见,不是原批量平铺入参的等价替换。
    4. create 必填 stage_confirm_mode:POST /api/projects/create / POST /api/artist_center/services/create 旧调用只传 stage_confirm_hours 或不传,都会因缺少 stage_confirm_mode 收到 422。
    5. stage_confirm_hours 不再单独可用:default / disable 下出现该键(含 null)报 422;update 只传 stage_confirm_hours 也报 422。
    6. stage_confirm_mode: null 非法:update 想「不修改」必须不传该字段。
  • 迁移与发布顺序:
    • work_task_file_ids 批量入参(提交 96132c0f 不在 main)仅存在于在途契约与本文档。若已有调用方按本文档实现了批量调用,须先迁移到 POST /api/artist_center/work_task_files/list(改用文件分页、按文件分组消费嵌套意见),再随本版本发布;不要仅凭本地前端未调用就断定线上无批量消费者。
    • stage_confirm_mode 同样是未发版的破坏性变更,API 与 C 端必须配套切换(见下方「发布协同」)。
  • 发布协同(人工执行):API 与 C 端必须配套切换。
    • 旧前端 + 新 API:create 因缺少 stage_confirm_mode 一律收到 422;update 只在携带 stage_confirm_hours 时收到 422,两个键都不传时保持旧的「不改动时限」行为。
    • 新前端 + 旧 API:stage_confirm_mode 被旧 API 忽略。create 时 disable 因不携带 hours 会落库 null(即 disable 被静默当成 default,属于不可接受的静默错误),default 落库 null 恰好符合预期,enable 因携带 hours 仍可正常工作;update 时 disable / default 会变成静默不修改。
    • 建议流程:暂停相关发布写入并等待在途请求结束后,配套切换 API 与 C 端,验证四个端点的三种模式,再恢复流量;已打开的旧页面须刷新到配套版本后才可继续提交。
    • 回滚时同样配套切回;已创建 commission 的快照保留,无需回填。
  • 读取侧与无迁移:
    • 读取侧:新增 stage_confirm_mode 是增量字段,旧读取方忽略即可;stage_confirm_hours 的含义与输出(含 disable 的 0)不变。
    • 无 schema / 配置迁移:不新增数据库列、不改既有 stage_confirm_hours 编码、不回填历史数据;回滚无需改全局设置或回填 hours,已创建 commission 的快照保留。
  • 平滑兼容项(非破坏性):
    1. 确认接口路径兼容别名:新路径为 POST /api/stage_confirmation/confirm,原 POST /api/work_tasks/confrim_stage_work_status 仍注册并指向同一控制器,参数与逻辑完全一致;现网前端可继续调用旧路径并渐进迁移(不计入破坏性变更)。
    2. work_task_file_change_requests/create 恢复单文件契约,现存前端 3 处调用零改动兼容,且不破坏节点流转。
    3. work_task_files 平铺列表结构保持不变。
    4. unread_change_requests_count 口径保持不变(按 artist_is_read = false 计数)。
  • 前端负责人交接要点:
    • 画师上传组件拆为两步调用:上传文件 $\rightarrow$ 请求确认;
    • 确认节点接口推荐路径更新为 /api/stage_confirmation/confirm(旧路径仍兼容,可渐进迁移);
    • 确认弹窗驳回按钮调用 /api/stage_confirmation/revision_request;
    • 画师弹窗取数迁到 /api/artist_center/work_task_files/list(文件分页 + 内嵌意见,注意响应层级与已读范围变化);
    • 详情页移除对 upload_batches 的依赖;
    • 发布 / 编辑页按第 4.6 节改造:三态 stage_confirm_mode 控件、回填读 stage_confirm_mode、payload 只在 enable 携带 stage_confirm_hours。
  • 本次不做:不引入全局 enabled 开关,不调整全局默认时限设置结构与时限范围,不改提醒规则、终审规则、通知内容与调度顺序;管理后台(pipipen-admin-new)无配套改动。
ON THIS PAGE