# Task Images Migration Notes(前端迁移说明) > 对应后端 spec 0004 / ADR-0005。最后更新 2026-07-18。 > 后端 schema 改动以 Swagger 为准;本文件只记录 Swagger 不会告诉前端 > 的行为 / 业务规则 / 跨实体不变量。两边不要互相重复——改了 schema > 同步改 Swagger,改了行为同步改本文档。 ## TL;DR - 作业图片已经从 `stdt_tasks` 解耦到独立的 `stdt_task_images` 表 - 任务响应里的 25 个 `image_XX` 字段、旧的 `/api/tasks//images//` 端点全部消失 - 现在用子资源 API:`/api/tasks//images/...`,schema 见 Swagger ## 必须改的代码 ### 任务响应里没有图片字段了 `GET /api/tasks//` 返回的对象**不再包含** `image_01..image_05` × {binary, mime_type, file_name, key, etag} 这 25 个字段。前端如果直接读 `task.image_01` 之类会拿到 `undefined`。 要拿图片: 1. `GET /api/tasks//images/` 拿列表(每项含 `id` 和元数据, 但**不含**二进制) 2. 按需 `GET /api/tasks//images//content/` 拿字节流 ### 旧的"按槽位"端点没了 `GET /api/tasks//images//`(`image_index` 取 1-5)已 删除,直接返回 404。前端代码里如果还有这种调用,改成 `` (BIGSERIAL,从列表响应里取 `id` 字段)。 ### 上限 5 → 20 每张任务最多 20 张图,由后端在 POST 时校验。超过返回 400,错误体 含 `"soft cap is 20"`。前端 UI 限制同步调整。 ### 删除图片改用 HTTP DELETE 以前在 `PATCH /api/tasks//` body 里塞 `delete_image_03: true` 之类 的布尔字段;现在直接 `DELETE /api/tasks//images//`。 ## 必须知道的行为(Swagger 不会告诉你) ### 列表端点过滤软删行 所有 `GET /api//` 列表自动排除 `deleted_flag='Y'` 的行——包 括任务、图片、学生等所有走 `AuditedListCreateView` 基类的实体。前端 如果遇到"刚 POST 立刻 GET 列表找不到"的情况:要么是这行被软删了 (DELETE 不会真删,row 还在 DB 里),要么是真创建失败(看 HTTP 状 态码区分)。 ### 图片 DELETE 是软删 `DELETE /api/tasks//images//` 不会真删 row——只是 把 `deleted_flag` 翻成 `Y`。DB 里 row 还在,COS 上对象也不动。前端 目前**没有 API 能恢复已软删的图片**,要恢复只能改 DB。 ### 任务软删不影响图片(ADR-0004) `DELETE /api/tasks//` **不会**级联软删图片。前端不要写"删任务时 连带删图"的逻辑——反过来才是对的:任务删了之后图片 row 还在 `deleted_flag='N'`。 ### 图片 PATCH 几乎只读 `PATCH /api/tasks//images//` 只能改 `file_name`。 改 `mime_type` / `key` / `etag` / `size_bytes` / `task_id` / `tenant_id` 全部 400。**换图走 DELETE + CREATE**。 ### 审计字段后端自动填 `created_by` / `creation_date` / `last_updated_by` / `last_update_date` 后端自动写。前端不要 PATCH 这些字段。 ## 可能踩的坑 ### 缓存的 image_index 全失效 前端如果按 1-5 槽位缓存过图片 ID,必须清掉换成 image_id(从列表 响应里取)。`image_id` 是 BIGSERIAL,全局稳定不重用(被软删的图 片的 id 也不会被新图复用)。 ### /content/ 返回二进制流 `Content-Type` 是真实 mime(如 `image/png`),`Content-Disposition: inline; filename="..."`。前端以前手动拼 `data:image/png;base64,...` 的逻辑,可以直接换成 `` 走浏览器缓存。 ### LAN 网关不变(跟 spec 0004 无关) LAN 写路径仍然返回 `created_by = "lan_guest"`。如果前端有"上传者 用户名"展示逻辑,注意 LAN 来源的图可能没有真实用户。 ## 怎么验证 迁移完成后跑这三条冒烟: 1. **image_id 稳定**:连续两次 `GET /api/tasks//images/`,同一 张图的 `id` 不变 2. **软删独立**:`DELETE /api/tasks//images//` 之后再 `GET /api/tasks//`,任务还在 3. **上限**:连续 POST 第 21 张图返回 400,错误体含 `"soft cap is 20"` ## 跟 Swagger 的边界 | 内容 | 谁负责 | |---|---| | URL 路径 / HTTP method | Swagger | | 字段名 / 类型 / required / read-only | Swagger | | 错误状态码 | Swagger | | 行为 / 不变量 / 业务规则 | 本文档 | | 跨实体契约(如 ADR-0004) | 本文档 | | 软删 / 审计等通用机制 | 本文档 | 不要在本文档里复述 Swagger 已经覆盖的内容;反过来 Swagger 不该出现 "this endpoint soft-deletes" 这种行为描述。