diff --git a/.memory/worklog.json b/.memory/worklog.json index c690a9c..e600be4 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -2076,6 +2076,19 @@ "message": "auto-save 2026-05-13 18:13 (~1)", "hash": "40cf8b0", "files_changed": 1 + }, + { + "ts": "2026-05-13T18:18:55+08:00", + "type": "commit", + "message": "auto-save 2026-05-13 18:18 (~5)", + "hash": "2226198", + "files_changed": 5 + }, + { + "ts": "2026-05-13T10:19:28Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 1 项未提交变更 · 最近提交:auto-save 2026-05-13 18:18 (~5)", + "files_changed": 1 } ] } diff --git a/api/main.py b/api/main.py index 42343e2..e1ee66f 100644 --- a/api/main.py +++ b/api/main.py @@ -1209,6 +1209,12 @@ class AddElementReq(BaseModel): region: dict | None = None +class UpdateElementReq(BaseModel): + name_zh: str | None = None + name_en: str | None = None + position: str | None = None + + @app.post("/jobs/{job_id}/frames/{idx}/elements", response_model=Job) def add_element(job_id: str, idx: int, req: AddElementReq) -> Job: """加一条元素 · 若 name_en 缺则自动 zh→en 翻译""" @@ -1265,6 +1271,37 @@ def add_element(job_id: str, idx: int, req: AddElementReq) -> Job: return job +@app.patch("/jobs/{job_id}/frames/{idx}/elements/{element_id}", response_model=Job) +def update_element(job_id: str, idx: int, element_id: str, req: UpdateElementReq) -> Job: + """更新元素标签 / 英文提示。提取不准时允许用户修正,不强制重建元素。""" + job = JOBS.get(job_id) + if not job: + raise HTTPException(404, "job not found") + changed_name = "" + found = False + new_frames = [] + for f in job.frames: + if f.index == idx: + for e in f.elements: + if e.id == element_id: + found = True + if req.name_zh is not None: + name_zh = req.name_zh.strip() + if not name_zh: + raise HTTPException(400, "name_zh required") + e.name_zh = name_zh + changed_name = name_zh + if req.name_en is not None: + e.name_en = req.name_en.strip() + if req.position is not None: + e.position = req.position.strip() + new_frames.append(f) + if not found: + raise HTTPException(404, "element not found") + update(job, frames=new_frames, message=f"更新元素 · 分镜 {idx + 1} · {changed_name or element_id}") + return job + + @app.delete("/jobs/{job_id}/frames/{idx}/elements/{element_id}", response_model=Job) def delete_element(job_id: str, idx: int, element_id: str) -> Job: job = JOBS.get(job_id) diff --git a/web/lib/api.ts b/web/lib/api.ts index 31faf5b..b4fa832 100644 --- a/web/lib/api.ts +++ b/web/lib/api.ts @@ -407,6 +407,24 @@ export async function deleteElement(jobId: string, frameIdx: number, elementId: return res.json() } +export async function updateElement( + jobId: string, + frameIdx: number, + elementId: string, + body: { name_zh?: string; name_en?: string; position?: string }, +): Promise { + const res = await fetch(`${API_BASE}/jobs/${jobId}/frames/${frameIdx}/elements/${elementId}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }) + if (!res.ok) { + const txt = await res.text().catch(() => "") + throw new Error(`updateElement ${res.status} ${txt.slice(0, 300)}`) + } + return res.json() +} + export async function deleteFrame(jobId: string, frameIdx: number): Promise { const res = await fetch(`${API_BASE}/jobs/${jobId}/frames/${frameIdx}`, { method: "DELETE" }) if (!res.ok) {