状态:PRD(产品决策已确认,见 §17);后端已于 2026-09-18 实现,见 §19 实现记录 范围:
pipipen-api(后端);同步影响pipipen-front(只读,仅出接口约定) 关联接口变更记录:docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md发布配置契约变更(2026-09-29):发布接口改用显式stage_confirm_mode,见 §9.2;接口变更记录已并入docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md原型依据:Milestone Confirmation Flow 交互原型(画师上传 → 关联节点 → 请求确认 → 确认/退回修改 → 超时自动确认)
业务希望把「commission(worktask)的节点推进」从当前「客户端手动点确认」的单一动作, 升级为一套更完整、可自动化的确认流程:
原型 index-jsfiddle-w6Lbrzjx-2.html 完整描述了这套交互(上传→关联节点→请求确认→确认/退回修改→倒计时自动确认),本 PRD 将其落成后端需求。
本节的代码证据描述的是改造前的现状,保持历史原样,不回改。
| 概念 | 模型 / 表 | 关键字段 | 说明 |
|---|---|---|---|
| commission | WorkTask / work_tasks | status(pending/working/finished…)、busable_type(service|project)、reqable_type(service_request|project_request)、paid_amount、price | Open Call 与 service 的订单都落成 worktask |
| 节点 | WorkTaskStage / work_task_stages | work_status(pending/working/finished)、is_paid、percent、amount、name | 节点 = 分期里程碑 |
| 稿件 | WorkTaskFile / work_task_files | work_task_id、work_task_stage_id、artist_id、user_id、user_is_read | 已有关联节点字段 |
| 稿件附件 | UploadFile(morph uploadFiles) | url_og、state、mime、size | 一个稿件可挂多个文件 |
| 修改意见 | WorkTaskFileChangeRequest / work_task_file_change_requests | work_task_file_id、content(translatable)、morph uploadImages | 按「单个稿件」给修改意见 |
证据文件:
app/Models/WorkTask.php、app/Models/WorkTaskStage.phpapp/Models/WorkTaskFile.php、app/Models/WorkTaskFileChangeRequest.phpdatabase/migrations/2025_06_24_080719_create_work_tasks_table.php 等app/Enums/WorkTaskStageWorkStatus.php 只有三态:
work_task_stages.work_status 数据库列也是 enum('pending','working','finished')。
WorkTaskStage 仅提供 markAsFinished() / markAsWorking() 两个状态迁移方法。
画师上传稿件是两步:
POST /api/user/upload_file(Api\User\UserController@uploadFile)——上传原始文件,得到 upload_files.id。POST /api/artist_center/work_task_files/create(Api\Artist\WorkTaskFileController@create)——
传 upload_file_id + work_task_id + work_task_stage_id,创建 work_task_files 记录并 morph 挂上 UploadFile。现状问题(与需求相关):
create 没有校验 work_task_stage_id 是否属于 work_task_id(可直接传入其它 commission 的节点)。upload_file_id,多文件需前端循环调用。POST /api/work_tasks/confrim_stage_work_status
(Api\User\WorkTaskController@confirmStageWorkStatus,路由见 routes/api/userApi.php):
Cache::lock)+ 事务 + lockForUpdate。is_paid=1 && work_status=working 的当前节点 → markAsFinished()。is_paid=1 && work_status=pending 节点 → markAsWorking()。finished,触发 WorkTaskCompletionService 结算打款给画师。WorktaskPageEventService::eventConfirmStage / eventFinish,发通知。关键:确认入口只认 working 节点,没有「待确认」概念;无任何定时自动确认。
POST /api/work_task_file_change_requests/create
(Api\User\WorkTaskFileChangeRequestController@create):
按「单个稿件」创建修改意见(content + uploadImages),通知画师,不改变节点状态、没有倒计时语义。
| 需求点 | 现状 | 差距 |
|---|---|---|
| 节点增加「待确认」状态 | 只有 pending/working/finished | 需扩展枚举 + 迁移 |
| 上传稿件关联节点 | work_task_stage_id 字段已存在 | 缺校验、缺「请求确认」、缺一次多文件 |
| 长时间未确认自动确认 | 无 | 需新增 deadline + 定时任务 |
| 确认时间在发布时设置 | 无 | 需在 service/project 增加配置字段并快照 |
| 修改退回后暂停确认倒计时 | 无 | 需在节点状态机中体现 |
pending → working → finished 基础上插入 awaiting_confirmation(待确认)与 revision(需修改)。is_paid 的推进保持不变)。awaiting_confirmation 后不能退回 working(见 §17 决策 5)。pipipen-front 只读),只约定后端接口与数据。WorkTaskStageWorkStatus命名沿用现有
pending/working/finished小写下划线风格;对外展示文案「待确认 / 需修改」。
work_task_stages 新增列:
| 列 | 类型 | 说明 |
|---|---|---|
confirm_deadline_at | timestamp null | 进入待确认时的自动确认截止时间;revision/finished/working 下为 null;0/最终节点也为 null |
confirmed_at | timestamp null | 节点被确认(手动/自动)的时间 |
confirm_source | enum('manual','auto') null | 确认来源,用于审计与展示 |
confirm_reminder_sent_at | timestamp null | 到期前提醒已发送时间;幂等,避免重复提醒 |
同时把 work_status 枚举扩展为 ['pending','working','awaiting_confirmation','revision','finished']。
全局默认时限(管理后台设置): 不改表结构,复用 SystemSetting(key worktask.stage_confirm)+ SystemSettingChangeLog 审计:
| value 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
version | int | 0 | 乐观锁版本号(expected_version 比对) |
default_hours | int | 48 | 全局默认自动确认时限(小时) |
reminder_hours | int | 24 | 到期前提前提醒的提前量(小时) |
updated_at_utc | string | null | 最近更新时间 |
services / projects 新增列:
| 列 | 类型 | 说明 |
|---|---|---|
stage_confirm_hours | integer null | 节点自动确认时限(小时)。null 表示用全局默认值 |
work_tasks 新增列(快照,保证既有 commission 不受发布方后续修改影响):
| 列 | 类型 | 说明 |
|---|---|---|
stage_confirm_hours | integer null | 创建 commission 时从 service/project 快照的确认时限(小时) |
快照时机:
ServiceRequestController@accept、ProjectRequestController创建 worktask 时写入。 默认值来源:service/project 的stage_confirm_hours为 null 时回退到全局默认(SystemSetting的default_hours,默认 48);0表示不自动确认,也照常快照。
WorkTaskStage)markAsFinished 需要新增记录 confirmed_at、confirm_source,并保持现有 WorkTaskStageCompleted 事件与 isLastStage 判定不变。
实现补充(见 §19):
markAsAwaitingConfirmation/markAsRevision同时清空confirm_reminder_sent_at,保证重新提交后提醒可再次触发。- 模型新增
remaining_secondsaccessor:awaiting_confirmation且confirm_deadline_at非空时返回max(0, deadline - now);已过期返回0,其它状态或 deadline 为空返回null。confirm_deadline_at/confirmed_at/confirm_reminder_sent_at增加datetimecast。
规则:
working → awaiting_confirmation:画师上传稿件并请求确认时触发;写入 confirm_deadline_at = now + stage_confirm_hours。awaiting_confirmation → revision:客户对稿件发起修改意见时触发;清空/暂停 confirm_deadline_at。revision → awaiting_confirmation:画师上传修改稿并再次请求确认时触发;重置为完整时限(重新计算 confirm_deadline_at = now + stage_confirm_hours)。awaiting_confirmation → finished:
confirm_source=manual;confirm_deadline_at <= now(),confirm_source=auto。percent 最大判定,同 WorkTaskStage::isLastStage())不允许自动确认,只能手动确认;自动任务跳过它。is_paid=1 && pending 节点 → working;全部 finished 且付清 → worktask finished + 结算。入口:改造 POST /api/artist_center/work_task_files/create。
请求参数(新增/调整):
| 参数 | 类型 | 说明 |
|---|---|---|
work_task_id | int | 必填 |
work_task_stage_id | int | 必填,必须属于该 work_task |
upload_file_ids | int[] | 改为数组,一次挂多个文件(保留单值兼容) |
upload_file_id | int | 兼容单值入参;与 upload_file_ids 互为备选,未使用时允许显式 null |
request_confirmation | bool | 默认 false;true 时进入待确认并开始倒计时 |
规则:
work_task_stage_id 属于 work_task_id(新增)。working(或 revision 重新提交)节点上「请求确认」;finished 节点不可再挂稿件。request_confirmation=true:
awaiting_confirmation;workTask->stage_confirm_hours > 0:confirm_deadline_at = now()->addHours(workTask->stage_confirm_hours);stage_confirm_hours = 0 或最终节点:不写 deadline,仅手动确认(前端展示「需手动确认」,不展示倒计时)。request_confirmation=false:仅挂稿件,不改变节点状态(与现状一致)。WorktaskPageEventService 新事件、通知用户。实现说明(见 §19):
- 归属校验失败返回错误码
20006;节点状态不允许「请求确认」返回20007。- 目前仅对
request_confirmation=true施加「非working/revision不可请求确认」的守卫;request_confirmation=false时挂载到finished节点的行为保持改造前现状,是否收紧见 §19.4 遗留。- 接口返回结构由原来的单个稿件对象改为稿件数组(
data为列表)。
入口:改造 POST /api/work_tasks/confrim_stage_work_status(路由拼写沿用历史)。
规则(在现有锁定/事务基础上):
awaiting_confirmation > working(兼容存量无待确认态的 commission)。confirmed_at、confirm_source=manual。实现说明:共享服务
WorkTaskStageConfirmationService的选节点查询为is_paid=1 AND work_status IN (awaiting_confirmation, working) ORDER BY percent ASC; 正常推进顺序下与「awaiting 优先」等价,异常推进场景的排序收紧见 §19.4 遗留。
见 §8。
入口:复用 POST /api/work_task_file_change_requests/create,并新增节点状态联动:
awaiting_confirmation,创建修改意见后节点 → revision,并暂停(置空)confirm_deadline_at。revision,继续追加修改意见,状态不变。画师查看修改意见后,通过 §7.1 的 request_confirmation=true 重新提交修改稿,节点 revision → awaiting_confirmation 并重置为完整时限。
实现补充:该接口在本次一并补上了稿件归属校验(
work_task_file_id必须属于当前用户,越权返回404)。
新增命令 app/Console/Commands/AutoConfirmWorkTaskStage.php:
注册到调度(routes/console.php,参考 DispatchPendingCommissionResolutionsCommand):
实现补充:提醒与自动确认两个查询都额外限定
workTask.status = working, 避免 commission 取消后残留的awaiting_confirmation节点持续发提醒或刷错误日志。
将 Api\User\WorkTaskController@confirmStageWorkStatus 的核心(加锁、事务、结算、事件、通知)抽取为共享服务
App\Service\WorkTask\WorkTaskStageConfirmationService::confirm(WorkTask $workTask, string $source, ?int $specificStageId = null),
手动接口与自动任务都调用它,保证:
WorkTaskCompletionService 打款逻辑完全一致;WorkTaskStage::isLastStage()(按 percent 最大)。confirm 内二次防御(双保险)。awaiting_confirmation 且 confirm_deadline_at 非空后,在 confirm_deadline_at - reminder_hours(默认 24h)向客户发送「即将自动确认」提醒。confirm_reminder_sent_at 为空且已到提醒时点才发送,发送后写回该字段,避免重复提醒。AutoConfirmWorkTaskStage 命令(同一条命令先发提醒、再做自动确认),减少调度点。stage_confirm_hours = 0 或最终节点无 deadline → 无需提醒。实现补充:
- 提醒同时写
SystemNotificationScene::WorktaskStageAutoConfirmReminder系统通知与WorktaskPageEventListType::STAGE_AUTO_CONFIRM_REMINDER页面事件,写回 flag 前完成,正常路径下只写一次。- 提醒属 best-effort:通知 / 事件 / flag 在同一
try内,任一失败只记日志,下一轮调度重试(极端情况可能重复提醒一次)。- 提醒阶段整体失败不会阻断同一轮自动确认(命令内双层
try/catch隔离)。
| 端 | 接口 | 字段 |
|---|---|---|
| 画师发布 service | Api\Artist\ServiceController@create / @update | stage_confirm_mode(三态)+ stage_confirm_hours(仅 enable 可提交) |
| 用户发布 Open Call(project) | Api\User\ProjectController@create / @update | stage_confirm_mode(三态)+ stage_confirm_hours(仅 enable 可提交) |
| 管理后台(全局默认) | Api\Internal\StageConfirmSettingController | default_hours / reminder_hours |
发布 / 更新时用 stage_confirm_mode 显式表达选择,后端换算为既有的 stage_confirm_hours 落库(2026-09-29 变更,接口变更记录已并入 docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md):
stage_confirm_mode | stage_confirm_hours 请求约束 | 落库 stage_confirm_hours |
|---|---|---|
default | 不传该字段 | null(沿用全局默认) |
enable | 必填,整数 1 ~ 720 | 自定义值 |
disable | 不传该字段 | 0(不允许自动确认) |
stage_confirm_mode;update 不传该字段表示不修改,显式 null 非法。enable 模式出现 stage_confirm_hours 键(无论 null、0、空串、数组或其他值)返回 422;enable 缺少、越界或类型非法同样 422,不新增业务错误码(见 §11)。stage_confirm_hours 编码不变:null → 使用全局默认 default_hours(默认 48);0 → 不允许自动确认(该 service / project 的节点只接受手动确认,见 §17 决策 2);1 ~ 720 → 该 service / project 专属时限,覆盖全局默认。stage_confirm_mode:stage_confirm_hours 为 null → default、0 → disable、正数 → enable;stage_confirm_hours 字段保留且含义不变(disable 仍输出 0)。work_tasks.stage_confirm_hours(0 也照常写入),后续发布方修改 service/project 不影响已存在 commission。default 在创建时物化为当时的全局默认时限(可为 0),非 null 快照冻结;既有 null 快照的运行时回退保持现状。默认确认时限 48 小时,通过后台内部接口维护(参考 Open Call 手续费减免的实现):
| 端 | 接口 | 说明 |
|---|---|---|
| 管理后台 | POST /api/internal/system_settings/stage_confirm/detail | 读取当前默认时限与提醒提前量 |
| 管理后台 | POST /api/internal/system_settings/stage_confirm/update | 更新默认时限,走乐观锁 + 变更日志 |
SystemSetting(key worktask.stage_confirm)+ SystemSettingChangeLog 审计;实现参照 App\Service\Settings\OpenCallFeeWaiverSettingService、Api\Internal\OpenCallFeeWaiverSettingController。AuthInternalApiRequestMiddleware + X-Admin-Id/X-Admin-Name/X-Request-Id 头(见 routes/api/internalApi.php)。expected_version 不一致报 SystemSettingVersionConflict(30022),参数非法报 SystemSettingInvalid(30023)。default_hours 与 reminder_hours 均限制在 0 ~ 720。POST /api/work_tasks/info、POST /api/artist_center/work_tasks/info(本次由 GET 改为 POST,见 §13)返回的
workTaskStages 需带上新状态值及 confirm_deadline_at、confirmed_at、confirm_source,
并附带 remaining_seconds(已实现,随模型序列化自动输出)。接口变更记录已落地:
docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md。
POST /api/artist_center/work_task_files/create
upload_file_ids(数组)、request_confirmation;POST /api/artist_center/work_tasks/info
GET 改为 POST(id 走 JSON body);workTaskStages 返回节点确认相关新字段。POST /api/work_tasks/confrim_stage_work_status
working 扩展为「awaiting_confirmation 优先、working 兜底」;写入确认来源。POST /api/work_task_file_change_requests/create
revision 并暂停倒计时;新增稿件归属校验(越权 404)。POST /api/work_tasks/info
GET 改为 POST(id 走 JSON body);workTaskStages 返回节点确认相关新字段。POST /api/projects/create(及 update)
stage_confirm_mode(default / enable / disable);stage_confirm_hours 仅 enable 可提交(2026-09-29 变更,见 §9.2)。POST /api/artist_center/services/create(及 update)
stage_confirm_mode(default / enable / disable);stage_confirm_hours 仅 enable 可提交(2026-09-29 变更,见 §9.2)。POST /api/internal/system_settings/stage_confirm/detail
POST /api/internal/system_settings/stage_confirm/update
expected_version 乐观锁 + 变更日志。stage_confirm_hours(如后台需要代发代改),本次未实现。上述接口锚点与最终路由以实现为准;正式变更记录见
pipipen-docs/docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md; 发布配置契约的 2026-09-29 变更已并入pipipen-docs/docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md。
沿用 work_task 区间 20000 - 29999(app/Enums/ErrorCode.php)。PRD 初稿的建议值与最终实现:
| 枚举 | 值 | 语义 | 实现状态 |
|---|---|---|---|
WorkTaskStageNotBelongsToWorkTask | 20006 | 稿件关联的节点不属于该 commission | 已实现 |
WorkTaskStageCannotRequestConfirmation | 20007 | 当前节点状态不允许请求确认 | 已实现 |
WorkTaskStageConfirmDeadlineMissing | 20008 | 请求确认时缺少确认时限配置 | 未实现:stage_confirm_hours 为 null 时回退全局默认,无需要报错 |
WorkTaskStageCannotRevise | 20009 | 当前节点状态不允许发起修改 | 未实现:修改联动保持幂等,无守卫 |
WorkTaskStageConfirmHoursInvalid | 20010 | stage_confirm_hours 越界(非 0~720) | 未实现:用 validate min:0|max:720 返回 422 |
规则:业务校验失败统一 ValidationException::throw(ErrorCode::..., ...),不传 ->value;变更需同步文档。
后台全局默认时限的更新沿用已有 SystemSettingVersionConflict(30022)/ SystemSettingInvalid(30023)。
SystemNotificationScene)| 场景 | 值 | 说明 |
|---|---|---|
WorktaskStageAwaitingConfirmation | worktask.stage_awaiting_confirmation | 画师请求确认,通知用户 |
WorktaskStageAutoConfirmReminder | worktask.stage_auto_confirm_reminder | 到期前提醒客户 |
WorktaskStageAutoConfirmed | worktask.stage_auto_confirmed | 自动确认,通知双方 |
(复用)WorkTaskFileChangeRequestCreated | 已有 | 修改意见通知画师 |
三个新场景均已实现。注意:notification_templates 目前没有这三个场景的模板行,且未登记到
NotificationSettingService 通知开关;上线前需运营补模板/文案,否则邮件通知内容为空且用户无法关闭(见 §19.4)。
WorktaskPageEventListType)| 类型 | 值 | 说明 |
|---|---|---|
STAGE_AWAITING_CONFIRMATION | stage_awaiting_confirmation | 待确认事件(to: user) |
STAGE_AUTO_CONFIRM_REMINDER | stage_auto_confirm_reminder | 到期前提醒(to: user) |
STAGE_AUTO_CONFIRMED | stage_auto_confirmed | 自动确认事件(to: both) |
STAGE_REVISION | stage_revision | 退回修改事件(to: artist) |
四个事件类型均已实现,通过 WorktaskPageEventService 统一写入,保持与现有
eventConfirmStage / eventFileUpload 一致的 to / is_close 语义。
实现注意:
worktask_page_event_list.type是 MySQLENUM列,新增取值必须在迁移里同步ALTER TABLE ... MODIFY type ENUM(...),否则严格模式下写入会被拒绝(本次已并入节点状态迁移)。
work_status 无新枚举值、confirm_deadline_at 为空 → 自动任务天然跳过;手动确认走「working 兜底」路径,行为与现在一致。work_task_files/create 的 upload_file_id 单值入参保留,新增 upload_file_ids 数组为推荐形态;两者互为备选且都允许显式 null;request_confirmation 默认 false,不改变既有调用语义。stage_confirm_hours null → 回退默认值。confirm_source 仅新增列,不改变既有 WorkTaskStageCompleted 事件与结算判定。/api/work_tasks/info 与 /api/artist_center/work_tasks/info 由 GET 改为 POST,
id 由 query 改为 JSON body;旧调用将返回 405,所有调用方(含 pipipen-front)需同版本升级。| 阶段 | 内容 | 说明 |
|---|---|---|
| 1 | 枚举 + 迁移:扩展 work_status,新增 confirm_deadline_at/confirmed_at/confirm_source/confirm_reminder_sent_at、services.stage_confirm_hours、projects.stage_confirm_hours、work_tasks.stage_confirm_hours | 纯增列,可回滚;同一迁移内同步扩展 worktask_page_event_list.type ENUM |
| 2 | WorkTaskStage 状态迁移方法 + markAsFinished 记录来源 | 保持事件兼容 |
| 3 | 抽取 WorkTaskStageConfirmationService,改造手动确认接口 | 手动/自动共用 |
| 4 | 上传接口改造(多文件、归属校验、请求确认) | 含节点状态联动 |
| 5 | 修改意见联动 revision + 暂停倒计时 | 复用 change request 接口 |
| 6 | 定时任务 AutoConfirmWorkTaskStage + 调度注册 | 最终节点排除、提醒 + 自动确认 |
| 7 | service/project 发布接口增加 stage_confirm_hours + 快照 | 创建 commission 时写入 work_tasks |
| 8 | 通知、页面事件、ErrorCode、info 返回字段补齐 | 前端对接依据 |
| 9 | 测试 + 文档同步 | api-changes 单独提交 |
回滚:阶段 1 迁移可 down();业务代码按阶段小步提交,避免一次性大改。
回滚注意:
down()会把work_status收窄回三态,若库中仍有awaiting_confirmation/revision行, 严格模式下ALTER会报1265 Data truncated;回滚前需先处理这些行。
awaiting_confirmation,前端可见截止时间。awaiting_confirmation 节点后,节点 → finished,下一节点 → working,最终节点确认后触发结算。revision,倒计时暂停;画师重新提交后重置为完整时限并恢复倒计时。default / enable / disable,disable = 不自动确认;2026-09-29 起由 stage_confirm_mode 表达,见 §9.2),且修改发布配置不影响已存在 commission(快照生效)。reminder_hours 提前量向客户发送提醒,且同一节点只提醒一次。work_status 新值可写可读;新列默认 null;迁移 down 可回滚。request_confirmation=true/false;节点归属校验(传其它 commission 节点报 20006);finished 节点不可请求确认(20007);单值/数组字段显式 null 兼容。awaiting_confirmation;存量 working 兜底;最终节点完成触发结算;取消/退款冲突检查复用;无稿件时手动确认可用。awaiting_confirmation;最终节点被跳过;幂等(重复跑不重复结算);confirm_source=auto 落库;stage_confirm_hours=0 不进入自动确认;非进行中 commission 被跳过;提醒阶段失败不阻断自动确认。confirm_deadline_at - reminder_hours 发提醒;confirm_reminder_sent_at 写回后不再重复;stage_confirm_hours=0 不发提醒;同时写入页面事件且只写一次。awaiting_confirmation → revision 且 deadline 置空;revision → awaiting_confirmation 重置为完整时限;越权稿件返回 404。stage_confirm_hours(含 0);创建 commission 快照到 work_tasks;修改发布配置不影响旧 commission。stage_confirm 设置读写;expected_version 冲突报 30022;非法参数报 422;变更写入 SystemSettingChangeLog。to/is_close 语义与现状一致。遵循
pipipen-api/AGENTS.md:测试仅在local/testing环境、使用名称含testing的数据库执行。 后端测试落地见 §19.2(3 个测试文件、34 个用例)。
SystemSetting 实现)。stage_confirm_hours = 0:不允许自动确认(该 service / project 只接受手动确认),不是「立即自动确认」。confirm_deadline_at)。work_task_files.work_task_stage_id 单值,不做多对多。awaiting_confirmation 后不能退回 working。reminder_hours(默认 24h)提前提醒客户,且只提醒一次。work_tasks/info 由 GET 改为 POST;pipipen-api/AGENTS.md 固化
「新增/修改接口默认 POST」的约定(仅第三方回跳、下载/流、图片代理、监控/健康检查允许 GET),存量 GET 不追溯。stage_confirm_hours 越界用 validate min:0|max:720 返回 422,不新增业务错误码。work_task_file_id 属于当前用户,越权返回 404(与 list/update 口径一致)。working 状态的 commission,避免取消后残留节点持续提醒/报错。upload_file_id 与 upload_file_ids 互为备选且都允许显式 null,两者都缺失/为空仍 422。stage_confirm_mode(default / enable / disable)表达选择,stage_confirm_hours 仅 enable 可提交;mode 不落库,由既有时限推导;破坏性更新,不提供旧请求兼容层,API 与 C 端须配套发布。依据:2026-09-29 需求(任务 09-29-stage-confirm-mode-explicit),接口变更记录已并入 docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md。reminder_hours,可再调)。notification_templates 与通知开关(见 §19.4)。| 原型 / 界面 | 代码 / 数据库 |
|---|---|
| Milestone(节点) | WorkTaskStage / work_task_stages |
| commission | WorkTask / work_tasks |
| 稿件 / Work | WorkTaskFile / work_task_files + UploadFile |
| 修改意见 | WorkTaskFileChangeRequest |
| 待确认 | work_status = awaiting_confirmation |
| 需修改 | work_status = revision |
| Final Delivery | 按 percent 最大的节点(WorkTaskStage::isLastStage()) |
| 自动确认时限 | stage_confirm_hours(service/project 配置 → work_tasks 快照) |
实现仓库:
pipipen-api,分支feature/refund-preview-calculation。 关联接口变更记录:docs/pipipen/api-changes/2026-09-22_worktask_revision_batch.md。
| 提交 | 内容 |
|---|---|
42ae291f | 扩展节点状态与确认时限字段(迁移 + 模型 + 页面事件 ENUM) |
2afd5a0e | 新增节点自动确认全局默认时限后台设置 |
ac85aac9 | 补齐通知页面事件与错误码 |
7c2cd0ab | 抽取节点确认共享服务并支持自动确认 |
286b2633 | 稿件上传关联节点并支持请求确认 |
d7ebb955 | 修改意见联动节点需修改状态 |
f2bf7a7c | service 与 project 发布支持确认时限并快照 |
8ef3e6ac | 节点确认与自动确认测试 |
e875dbd4 | 兼容稿件上传接口单值字段显式为 null |
c14a8450 | 自动确认命令隔离提醒失败并跳过非进行中 commission |
59afb7b1 | 修改意见接口校验稿件归属 |
a5bcd0b6 | 到期前提醒写入页面事件 |
819befbb | 节点详情接口统一为 POST |
vendor/bin/phpunit → 928 tests / 5846 assertions 全绿。pipipen_api_testing 上验证 migrate → migrate:rollback --step=2 → migrate 可回滚。worktask_page_event_list.type 是 MySQL ENUM,新增 4 个页面事件值必须同步 ALTER(已并入迁移)。remaining_seconds 取 deadline - now(未到时为正);过期返回 0,非待确认态或 deadline 为空返回 null。markAsFinished 保持既有两个可选参数($workTask、$isLastStage)以兼容 OrderService 等调用点,
确认来源作为第三个可选参数。/api/work_tasks/confrim_stage_work_status(非 /api/user/worktask/...)、
/api/work_task_file_change_requests/create、/api/projects/create。| 级别 | 事项 |
|---|---|
| 高(发布协同) | pipipen-front 需把两个 work_tasks/info 调用从 GET + query 改为 POST + JSON body,与后端同版本发布;否则调用方 405 |
| 高(上线前置) | 3 个新通知场景缺 notification_templates 行且未登记通知开关(NotificationSettingService),邮件通知内容为空且用户无法关闭;上线前需补模板/文案 |
| 中 | 确认通知目前在事务内同步发送,邮件失败可能回滚确认与结算;建议后续改为提交后发送或走队列 |
| 中 | OrderService 阶段支付只认 working 节点,不识别 awaiting_confirmation;自动确认失败会每 5 分钟重试并刷日志 |
| 中 | finished 节点在 request_confirmation=false 时仍可挂稿件(PRD §7.1 原意是 finished 不可挂稿件),需产品确认后再收紧 |
| 低 | markAsFinished 在支付推进路径也会写 confirm_source=manual,建议后续区分来源 |
| 低 | 手动确认选节点未按「awaiting 优先于 working」显式排序(正常推进流程下等价) |
| 低 | 提醒/自动确认的幂等基于 flag 与调度 withoutOverlapping,手工并发执行可能重复提醒一次 |