需求背景
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 已合并删除。upload_batches)在部分重传、多轮修改时因索引找错与语义悬空,无法准确表达当前交付物;stage_confirmation 专属接口组;节点表直接记录当前待确认文件集合(current_request_file_ids);单文件意见恢复独立留言,仅批量驳回入口触发退回修改;stage_confirm_hours 表达(null = 用平台默认、0 = 关闭自动确认、正数 = 自定义),调用方容易把 null 与 0 混淆,编辑回填也会丢语义;本次让发布方显式选择「平台默认 / 自定义时限 / 关闭自动确认」。stage_confirmation):画师发起确认(request)、客户确认完成(confirm,原 confrim_stage_work_status 路径保留为兼容别名,两者指向同一实现)、客户批量驳回(revision_request);artist_center/work_task_files/create 回归纯上传(显式禁止 request_confirmation,传入报 422 prohibited);work_task_file_change_requests/create 恢复单文件顶层参数契约(与流转解耦,任何状态不改节点状态);work_tasks/info 的 upload_batches 读模型,work_task_stages 新增 current_request_file_ids;不做后端意见聚合读接口,弹窗由前端组合渲染;stage_confirm_hours 时限配置、awaiting_confirmation / revision 状态机、倒计时与自动确认直通逻辑保持;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 节)。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 / 后台全局设置接口;2026-09-23 修订:
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 改造作废,现存前端单文件调用零改动保持兼容),且任何状态下单文件意见均与节点流转解耦;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 小节补齐):
work_tasks/info 与 projects / services 变更行的组合标题短锚改为指向实际组合 id;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 非法;stage_confirm_mode(null → default、0 → disable、正数 → enable),保留 stage_confirm_hours;建议阅读顺序:第 1 章(一分钟上手)→ 第 2 章(接口变更总览)→ 第 3 章(接口示例)→ 第 4 章(字段补充说明)→ 第 5 章(兼容性)。
| 章 | 内容 | 什么时候看 |
|---|---|---|
| 1. 一分钟上手 | 状态机 + 自动确认判定 + 确认与弹窗时序 + 倒计时来源 + 自动确认模式映射 + 对接要点 | 刚拿到文档 |
| 2. 接口变更 | 全部端点与变更摘要 | 找接口 |
| 3. 接口示例 | 每个端点的参数、示例与错误 | 对接具体接口 |
| 4. 字段补充说明 | current_request_file_ids、弹窗组合渲染、work_task_stages 新字段、自动确认边界、时限与模式字段、commission 快照、C 端交接 | 查具体取值与展示 |
| 5. 兼容性说明 | 破坏性变更、发布协同与上线部署步骤 | 发布前确认 |
本文所有接口都是
POST+ JSON body。核心流转聚焦在stage_confirmation专属接口组(发起确认 / 确认完成 / 批量驳回);文件上传与常规单文件讨论留言完全从流程状态机中解耦。
revision状态表示客户在确认弹窗中正式驳回了该节点,倒计时暂停;画师修改完成后只需重传变动的文件,并调用stage_confirmation/request重新圈定待确认文件集合,倒计时按完整时限重置。终审节点豁免自动确认,必须客户手动确认。
stage_confirm_hours 如何决定倒计时update 时不传
stage_confirm_mode表示「不修改当前模式」;显式传null会被 422 拒绝。default与disable的落库值不同(null/0),但两者响应里的stage_confirm_mode分别回default/disable,前端据此回填即可区分。
stage_confirm_mode 取 default / enable / disable 之一,缺失、显式 null、空数组、非法字符串、数字、布尔都会 422。enable 时 stage_confirm_hours 必填且为 1~720 的整数("120" 这类整数字符串按既有 Laravel integer 规则接受);default / disable 时不得传递该字段,连 null / 0 / [] / "" 都会被 422 拒绝。null / 0 / 正数);显式 stage_confirm_mode: null 非法。只传 stage_confirm_hours 而不传 mode 也会 422。stage_confirm_hours 为 null(default)和 0(disable)在 data.stage_confirm_hours || 0 下都会变成 0;回填必须直接使用响应里的 data.stage_confirm_mode。stage_confirm_mode 与 stage_confirm_hours(disable 时 hours 仍为 0),但提交 default / disable 时不得携带 stage_confirm_hours;不要把响应对象整体回传当作请求体。stage_confirm_mode / stage_confirm_hours 的失败都走 Laravel validate() 的 422,前端按 errors 的字段名定位。disable 静默当成 default(详见第 5 章)。work_task_files/create 仅负责把文件传上去(禁止传 request_confirmation,传入报 422 prohibited);上传后画师勾选「请求用户确认」时,调用 POST /api/artist_center/stage_confirmation/request 并传入本次请求确认的文件 id 列表。POST /api/stage_confirmation/confirm;原 POST /api/work_tasks/confrim_stage_work_status 仍注册为兼容别名,指向同一控制器与同一套参数、逻辑,现网前端可渐进迁移。confirm_deadline_at / remaining_seconds。work_status = awaiting_confirmation 且 remaining_seconds = null 表示「只接受手动确认」(时限为 0 或是最终节点),此时不要展示倒计时。remaining_seconds 语义:过期返回 0,未过期返回剩余秒数,非待确认态返回 null;不要按 confirm_deadline_at 自行判断「0 = 未开始」。confirm_source = manual 来自客户确认接口,auto 来自后端定时任务或开启开关后的自动完成;前端不能传 confirm_source。revision 并清空 confirm_deadline_at;画师重新提交并请求确认后,按完整时限重置。POST /api/work_task_file_change_requests/create 恢复单文件顶层参数契约(work_task_file_id + content + upload_images),现存前端 3 处调用零改动保持兼容。无论节点处于任何状态,发表单文件意见均不会改变节点状态机(不触发 revision,倒计时不暂停)。POST /api/stage_confirmation/revision_request(items 数组);校验所有文件必须属于该节点的 current_request_file_ids;提交后节点正式转入 revision。upload_batches 读模型彻底移除:两侧 info 接口不再返回 upload_batches 字段;前端详情页若需展示待确认范围,直接读取 work_task_stages[].current_request_file_ids。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 已移除批量入参,仅保留单文件平铺。unread_change_requests_count 为准。POST /api/artist_center/stage_confirmation/request
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 的意见入口POST /api/work_task_file_change_requests/create
work_task_file_id + content + upload_images 参数,与节点流转解耦,不改变节点状态POST /api/work_task_file_change_requests/list
size 校验(min:1|max:50)与 id 升序稳定排序POST /api/work_tasks/set_auto_confirm_stages
working 时可配置POST /api/work_tasks/info
data.upload_batches;data.work_task_stages 新增 current_request_file_ids 字段POST /api/projects/create / POST /api/projects/update
stage_confirm_mode(create 必填、update 可选);stage_confirm_hours 改为仅 enable 下允许且必填POST /api/projects/list / GET /api/projects/info
stage_confirm_mode(保留 stage_confirm_hours)POST /api/artist_center/work_task_files/create
request_confirmation 参数(传入报 422 prohibited 拒绝)POST /api/artist_center/work_tasks/info
data.upload_batches;data.work_task_stages 新增 current_request_file_ids 字段POST /api/artist_center/work_task_files/list
work_task_file_ids 数组,可选 has_change_requests_only 只返回有意见的文件;读取即已读作用于当前页文件内嵌的意见POST /api/artist_center/work_task_file_change_requests/list
work_task_file_ids 批量入参,恢复单文件 work_task_file_id 平铺分页;传入批量键(含 null / 空数组 / 与单文件同时传)一律 422POST /api/artist_center/services/create / POST /api/artist_center/services/update
stage_confirm_mode(create 必填、update 可选);stage_confirm_hours 改为仅 enable 下允许且必填GET /api/artist_center/services/list / GET /api/artist_center/services/info
stage_confirm_mode(保留 stage_confirm_hours)POST /api/artist_center/stage_confirmation/requestcurrent_request_file_ids;若客户开启了自动确认且节点非最终已付款,则直接完成节点;否则进入 awaiting_confirmation 并启动倒计时。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_stage_id | integer | 是 | 节点 id,必须真实存在且属于当前画师 |
work_task_file_ids | integer[] | 是 | 本次请求确认的文件 id 列表,至少 1 个,且必须全部属于该节点;服务端自动去重(unique()) |
进入 awaiting_confirmation(默认路径):
客户开启自动确认且节点非最终已付款时直接完成节点(跳过 awaiting_confirmation,自动直通):
404:节点不属于当前画师
400:节点状态不允许请求确认(非 working / revision)
422:work_task_file_ids 中有 id 不存在(先命中 exists:work_task_files,id,errors key 为 work_task_file_ids.<下标>,到不了「不属于该节点」分支)
422:传入的文件均存在但不全属于该节点
429:自动确认直通路径并发锁竞争(内部走 confirmWithLock 的 lock:confirmStageWorkStatus:{work_task_id})
POST /api/stage_confirmation/confirmPOST /api/stage_confirmation/confirm;原 POST /api/work_tasks/confrim_stage_work_status 保留为兼容别名,指向同一控制器,参数与业务逻辑完全一致。finished,记录 confirm_source = manual;若下一节点已付款则自动激活为 working;若全单已完成且付清触发结算。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id / work_task_id | integer | 是 | commission id(work_tasks.id,两者传其一即可;同时传时 work_task_id 优先) |
404:commission 存在但不属于当前客户
429:并发确认锁竞争(lock:confirmStageWorkStatus:{work_task_id} 未获取到)
400:存在未完成的 commission cancellation,确认被拒
400:无可确认节点或状态不允许(20004 实际有两种 message,前端按 code 分支即可)
POST /api/stage_confirmation/revision_requestrevision 的意见入口。awaiting_confirmation 且所选文件全部位于该节点的 current_request_file_ids 内;事务内原子创建意见并推动节点进入 revision(倒计时清空);向画师发送一次合并通知与页面事件。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
items | object[] | 是 | 修改意见列表,至少 1 条 |
items[].work_task_file_id | integer | 是 | 稿件文件 id,带 distinct(同文件重复报 422),且必须属于当前节点的 current_request_file_ids |
items[].content | string | object | 否 | 意见文字内容(整批至少一条非空) |
items[].content_lang | string | 否 | 语言代码,默认当前语言 |
items[].upload_images | integer[] | 否 | 参考图 id 列表(upload_images.id),必须属于当前客户 |
items[].work_task_file_id 带 distinct:同一文件在 items 中重复出现报 422。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)。422:节点不处于 awaiting_confirmation 状态
422:尝试对不在本次请求确认范围内的文件提驳回意见
422:同一文件在 items 中重复(distinct)
422:文件不属于当前客户
422:文件跨 commission
422:文件跨节点
422:整批 content 全空
422:参考图不属于当前客户
422:commission 或节点不存在(文件校验通过但对应记录缺失)
422:items[].work_task_file_id 不存在(exists:work_task_files,id 校验,先于归属判断)
POST /api/work_task_file_change_requests/createworking、awaiting_confirmation、revision 时均可调用;pending 或 finished 状态下拒绝。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_file_id | integer | 是 | 稿件文件 id,必须属于当前客户 |
content | string | object | 是 | 意见内容(字符串或多语言对象),不能为空(空多语言对象 / 各语言值均为空报 422) |
content_lang | string | 否 | 语言代码 |
upload_images | integer[] | 否 | 参考图 id 列表,必须属于当前客户 |
404:文件存在但不属于当前客户
422:content 为空(空多语言对象,或对象内各语言值均为空)
422:文件所在节点处于 pending / finished 状态
422:参考图不属于当前客户
POST /api/work_task_file_change_requests/listsize 校验(min:1|max:50)与 id 升序稳定排序。artist_is_read。已读标记只在画师侧读取(POST /api/artist_center/work_task_file_change_requests/list)时置真,客户在本接口查询意见不影响画师的未读计数。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_file_id | integer | 是 | 稿件文件 id,必须属于当前客户;需存在于 work_task_files |
page | integer | 否 | 页码,默认 1,最小 1 |
size | integer | 否 | 每页条数,默认 15,范围 `min:1 |
work_task_file_id:必填、正整数,且必须存在于 work_task_files;缺失报 422 required,不存在报 422 exists。page / size:整数;size 超出 1~50 报 422。id 升序稳定排序后分页,upload_images 随记录一并预载返回。404:文件存在但不属于当前客户(该分支为控制器内手写 response()->json(['message' => 'Work task file not found'], 404),与同文件 create 的 abort(404, ...) 并存)
422:work_task_file_id 缺失
422:size 超出 1~50
POST /api/artist_center/work_task_files/createrequest_confirmation 参数;若传入该参数直接返回 422 prohibited 拒绝,防止旧前端未改造时静默丢失确认行为。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_id | integer | 是 | commission id |
work_task_stage_id | integer | 是 | 节点 id,必须属于该 commission |
upload_file_ids | integer[] | 否(与 upload_file_id 至少传一个) | 已上传文件 id 列表 |
upload_file_id | integer | 否(与 upload_file_ids 至少传一个) | 单值兼容(旧) |
request_confirmation | prohibited | 否 | 显式禁止,传入报 422 |
upload_file_ids 与 upload_file_id 可以同时传,服务端合并后去重(merge(...)->filter()->unique());最终创建的稿件文件数等于去重后的 id 个数。
upload_batch_id是本次创建生成的 UUID 分组列,同一批文件行共享同一值;批次读模型(upload_batches)已废弃,该列仅为历史兼容保留,前端不得再依赖它做分组展示。
422:误传 request_confirmation
422:upload_file_ids 与 upload_file_id 都未传
404:上传文件存在但不属于当前画师
404:commission 存在但不属于当前画师
400:节点不属于该 commission
POST /api/work_tasks/info 与POST /api/artist_center/work_tasks/infodata.upload_batches;在 data.work_task_stages 数组元素中新增 current_request_file_ids(若从未请求确认则为 null)。POST /api/artist_center/work_task_files/listPOST /api/artist_center/work_task_file_change_requests/list 的批量取数能力;只接受 work_task_file_ids 数组,不提供单文件别名。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_file_ids | number[] | 是 | 稿件文件 id 列表,至少 1 个、最多 50 个,重复 id 自动去重 |
has_change_requests_only | boolean | 否 | 默认 false;为 true 时只返回至少有一条意见的文件,为 false 时返回全部命中文件(含意见为空的文件) |
page | number | 否 | 文件页码,默认 1 |
size | number | 否 | 每页文件数,默认 15,上限 50 |
work_task_file_ids:必填非空整数数组,元素为正整数,最多 50 个;缺参、空数组、非数组、非法元素、超过 50 个均报 422。exists 校验,经当前画师关系过滤);全部无效时返回 { "data": [], "total": 0 }(200)。has_change_requests_only 为 sometimes|boolean,非布尔值报 422;筛选先于文件分页与 total 统计。id 升序稳定分页,total 为筛选后命中的文件数;静态数据集下跨页不重复不遗漏。artist_is_read = true(响应也返回 true);未返回页、越权文件的意见保持原值;空意见文件不产生写入;重复读取不重复写库。422:work_task_file_ids 缺失 / 空数组 / 超过 50 个 / 元素非法
422:has_change_requests_only 非布尔值
422:size 超过 50 或 page 小于 1
POST /api/artist_center/work_task_file_change_requests/listid 升序分页。work_task_file_ids 批量入参,恢复单文件 work_task_file_id 契约;需要跨文件按文件分组取数请改用 POST /api/artist_center/work_task_files/list。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
work_task_file_id | number | 是 | 单个稿件文件 id |
page | number | 否 | 页码,默认 1 |
size | number | 否 | 每页条数,默认 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。422:传入已移除的批量入参 work_task_file_ids(missing 规则的标准 message)
404:文件存在但不属于当前画师
POST /api/work_tasks/set_auto_confirm_stageswork_task_id(integer,必填)、auto_confirm(boolean,必填)。work_tasks.status = working 时允许修改。404:commission 存在但不属于当前客户
400:commission 不在 working 状态(20008)
POST /api/projects/create /POST /api/artist_center/services/createstage_confirm_mode;stage_confirm_hours 仅在 stage_confirm_mode = enable 时允许且必填。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
stage_confirm_mode | string | 是 | 自动确认模式:default(采用平台默认时限)、enable(自定义时限)、disable(关闭自动确认) |
stage_confirm_hours | integer | 仅 enable | 自定义自动确认时限(小时),1~720;其他模式不得传递该字段 |
stage_confirm_mode | stage_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 校验,即按键存在性拒绝,不做值比较。上面的 JSON 只展示本次变更字段;实际请求还需带上各接口原有的必填字段(
name/content/currency_id等)。
default 与 disable 的响应差异:
422:create 缺失 stage_confirm_mode、显式 null 或空数组
422:stage_confirm_mode 非法字符串 / 数字 / 布尔
422:enable 缺失 stage_confirm_hours(null、[]、"" 同此分支)
422:enable 的 stage_confirm_hours 为 0
422:enable 的 stage_confirm_hours 为 721
422:default / disable 下出现 stage_confirm_hours 键
POST /api/projects/update /POST /api/artist_center/services/updatestage_confirm_mode(不传 = 不修改);stage_confirm_hours 仅在 stage_confirm_mode = enable 时允许且必填。| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | integer | 是 | project / service id(原有字段) |
stage_confirm_mode | string | 否 | default / enable / disable;不传表示不修改,显式 null 报 422 |
stage_confirm_hours | integer | 仅 enable | 同 create,1~720 |
stage_confirm_mode | stage_confirm_hours | 结果 |
|---|---|---|
| 不传 | 不传 | 200,保留原 stage_confirm_hours(null / 0 / 正数均原样保留) |
| 不传 | 传了该字段 | 422 |
default | 不传 | 200,落库 null |
enable | 整数 1~720 | 200,落库该整数 |
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 保持不变)。切换为自定义时限:
切换为关闭自动确认(不携带 stage_confirm_hours):
不修改模式(两个键都不传):
update 沿用既有约定,只返回 ok,不回传实体:
更新后的
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、非法字符串 / 数字 / 布尔 / 数组
422:未传 stage_confirm_mode 却传了 stage_confirm_hours
422:enable 缺失 / 越界 / 类型非法的 stage_confirm_hours
422:default / disable 下出现 stage_confirm_hours 键
POST /api/projects/list /GET /api/projects/info /GET /api/artist_center/services/list /GET /api/artist_center/services/infostage_confirm_mode;原 stage_confirm_hours 字段保留,存储与输出含义不变。stage_confirm_hours | 响应 stage_confirm_mode | 含义 |
|---|---|---|
null | default | 采用平台默认时限 |
0 | disable | 关闭自动确认 |
| 正数 | enable | 自定义时限 |
stage_confirm_mode是 Project / Service 模型的 append 字段,所有序列化这两个模型的接口响应都会带上它(含公开内容侧的企划 / service 详情);本次回归覆盖的读取端点为上列四个。
本次模型重构后,彻底废弃了服务端批次读模型(upload_batches)。各端交互约定如下:
work_task_stages[].current_request_file_ids 数组明确定义。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 时服务端已过滤);unread_change_requests_count 按 artist_is_read = false 计数(画师侧详情返回的未读意见总数),读取即为已读后归零。work_task_stages)| 字段 | 类型 | 说明 |
|---|---|---|
work_status | string | 取值:pending、working、awaiting_confirmation、revision、finished |
current_request_file_ids | integer[] | null | 当前请求确认的文件 id 列表;未发起确认时为 null |
confirm_deadline_at | string | null | 自动确认截止时间(待确认且非终审时有效) |
confirmed_at | string | null | 节点确认时间 |
confirm_source | string | null | 确认来源:manual / auto |
remaining_seconds | integer | null | 剩余秒数(过期返回 0,非待确认返回 null) |
| 场景 | 行为 |
|---|---|
开关开启 + 非最终 + 已付款节点 + 调用 stage_confirmation/request | 跳过 awaiting_confirmation,直接完成,confirm_source = auto |
| 开关开启 + 最终节点 | 不自动完成,进入 awaiting_confirmation(终审节点豁免自动确认) |
| 开关开启 + 未付款节点 | 不自动完成,进入 awaiting_confirmation |
| 开关关闭 | 全部进入 awaiting_confirmation(正常倒计时流程) |
| 开关开启但仅上传未调 request | 仅创建文件,不改变节点状态 |
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 键。Api/User/ProjectRequestController 与 Api/Artist/ServiceRequestController)从来源读取 stage_confirm_hours 写入 work_tasks.stage_confirm_hours 快照:
default(来源 null)→ 物化为创建当时的平台全局默认时限(该默认值本身可以为 0);enable → 物化为自定义值;disable(来源 0)→ 物化为 0。work_tasks.stage_confirm_hours 为 null 的 commission 仍按运行时回退到全局默认,本次不改其处理。work_tasks 不新增 stage_confirm_mode;节点倒计时仍以 work_status = awaiting_confirmation 且存在 confirm_deadline_at 为依据。本次不改 deadline 生成、终审豁免、提醒查询与调度顺序。pipipen-front,由前端负责人实施)pipipen-front 本任务只读,需按下列要点完成两个发布 / 编辑页的改造,并与 API 配套发布:
default:采用平台默认时限(不展示小时输入);enable:自定义时限(展示 1~720 的小时输入,必填且为整数);disable:关闭自动确认(不展示小时输入)。data.stage_confirm_mode 决定选中项;移除 data.stage_confirm_hours || 0 这类推断,它会把 default(null)与 disable(0)都读成 0。小时输入框的值取 data.stage_confirm_hours(仅 enable 时有意义)。default → 只传 stage_confirm_mode: "default",不传 stage_confirm_hours;enable → 同时传 stage_confirm_mode: "enable" 与 stage_confirm_hours: <整数>;disable → 只传 stage_confirm_mode: "disable",不传 stage_confirm_hours;null)。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)。422 时按 errors.stage_confirm_mode / errors.stage_confirm_hours 定位字段并提示;本次不引入新业务错误码。upload_batches:两侧 work_tasks/info 不再返回 data.upload_batches;前端须改用 work_task_stages[].current_request_file_ids。request_confirmation:work_task_files/create 传该参数直接返回 422;必须拆为先传文件、再调 stage_confirmation/request。POST /api/artist_center/work_task_file_change_requests/list 不再接受 work_task_file_ids(含 null / 空数组 / 与单文件同时传均 422);跨文件取数改用新接口 POST /api/artist_center/work_task_files/list。注意新接口响应为文件分页 + 按文件分组的嵌套意见,读取即已读范围为当前页文件内的意见,不是原批量平铺入参的等价替换。stage_confirm_mode:POST /api/projects/create / POST /api/artist_center/services/create 旧调用只传 stage_confirm_hours 或不传,都会因缺少 stage_confirm_mode 收到 422。stage_confirm_hours 不再单独可用:default / disable 下出现该键(含 null)报 422;update 只传 stage_confirm_hours 也报 422。stage_confirm_mode: null 非法:update 想「不修改」必须不传该字段。work_task_file_ids 批量入参(提交 96132c0f 不在 main)仅存在于在途契约与本文档。若已有调用方按本文档实现了批量调用,须先迁移到 POST /api/artist_center/work_task_files/list(改用文件分页、按文件分组消费嵌套意见),再随本版本发布;不要仅凭本地前端未调用就断定线上无批量消费者。stage_confirm_mode 同样是未发版的破坏性变更,API 与 C 端必须配套切换(见下方「发布协同」)。create 因缺少 stage_confirm_mode 一律收到 422;update 只在携带 stage_confirm_hours 时收到 422,两个键都不传时保持旧的「不改动时限」行为。stage_confirm_mode 被旧 API 忽略。create 时 disable 因不携带 hours 会落库 null(即 disable 被静默当成 default,属于不可接受的静默错误),default 落库 null 恰好符合预期,enable 因携带 hours 仍可正常工作;update 时 disable / default 会变成静默不修改。stage_confirm_mode 是增量字段,旧读取方忽略即可;stage_confirm_hours 的含义与输出(含 disable 的 0)不变。stage_confirm_hours 编码、不回填历史数据;回滚无需改全局设置或回填 hours,已创建 commission 的快照保留。POST /api/stage_confirmation/confirm,原 POST /api/work_tasks/confrim_stage_work_status 仍注册并指向同一控制器,参数与逻辑完全一致;现网前端可继续调用旧路径并渐进迁移(不计入破坏性变更)。work_task_file_change_requests/create 恢复单文件契约,现存前端 3 处调用零改动兼容,且不破坏节点流转。work_task_files 平铺列表结构保持不变。unread_change_requests_count 口径保持不变(按 artist_is_read = false 计数)。/api/stage_confirmation/confirm(旧路径仍兼容,可渐进迁移);/api/stage_confirmation/revision_request;/api/artist_center/work_task_files/list(文件分页 + 内嵌意见,注意响应层级与已读范围变化);upload_batches 的依赖;stage_confirm_mode 控件、回填读 stage_confirm_mode、payload 只在 enable 携带 stage_confirm_hours。pipipen-admin-new)无配套改动。