From 35ef0f1790539942169587ee39c700dfe388101e Mon Sep 17 00:00:00 2001 From: xcs Date: Sat, 29 Aug 2026 06:32:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(desk):=20=E4=BB=B6=E4=B8=8A=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E4=B9=8B=E5=90=8E=E5=8F=AB=E9=86=92=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=20=E2=80=94=E2=80=94=20auto=20=E6=AD=A5=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E6=96=B9=E6=89=8D=E6=9C=89=E6=9C=BA=E4=BC=9A=E6=8C=89=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E8=8D=89=E7=A8=BF=E9=93=BA=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从前只有两条回传路由调 wake;保存不是回传,于是「保存即铺格」永远等不到那一拍。 叫不醒不抬手:保存本身是成功的,不该因为叫不醒把 200 变成 500。 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet --- apps/api/src/app/__tests__/save-wake.test.ts | 40 ++++++++++++++++++++ apps/api/src/app/routes/desk.ts | 5 ++- apps/api/src/app/save-wake.ts | 26 +++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 apps/api/src/app/__tests__/save-wake.test.ts create mode 100644 apps/api/src/app/save-wake.ts diff --git a/apps/api/src/app/__tests__/save-wake.test.ts b/apps/api/src/app/__tests__/save-wake.test.ts new file mode 100644 index 0000000..b0dbbce --- /dev/null +++ b/apps/api/src/app/__tests__/save-wake.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest'; +import { taskIdSchema } from '@contracts'; +import { afterSave } from '../save-wake.ts'; + +const TASK = taskIdSchema.parse('11111111-1111-4111-8111-111111111111'); + +function spy() { + const calls: string[] = []; + return { + calls, + deps: { + views: { repush: () => { calls.push('repush'); return Promise.resolve(true); } }, + task: { wake: () => { calls.push('wake'); return Promise.resolve(true); } }, + }, + }; +} + +describe('件上保存之后', () => { + it('真落下了行:先重推件,再叫醒任务 —— 配方这才有机会按最新的草稿铺格', async () => { + const { calls, deps } = spy(); + await afterSave(deps, TASK, 3); + expect(calls).toEqual(['repush', 'wake']); + }); + + it('一行都没落下:什么也不做 —— 没变的东西不值得叫醒谁', async () => { + const { calls, deps } = spy(); + await afterSave(deps, TASK, 0); + expect(calls).toEqual([]); + }); + + it('叫醒失败不抬手:保存本身是成功的,别因为叫不醒把 200 变成 500', async () => { + const calls: string[] = []; + const deps = { + views: { repush: () => { calls.push('repush'); return Promise.resolve(true); } }, + task: { wake: () => Promise.reject(new Error('库连不上')) }, + }; + await expect(afterSave(deps, TASK, 1)).resolves.toBeUndefined(); + expect(calls).toEqual(['repush']); + }); +}); diff --git a/apps/api/src/app/routes/desk.ts b/apps/api/src/app/routes/desk.ts index 52da2b9..3e06034 100644 --- a/apps/api/src/app/routes/desk.ts +++ b/apps/api/src/app/routes/desk.ts @@ -32,6 +32,7 @@ import { assetRowsOf, keyText, listArchived, readArchived } from '../asset-archi import { landDataOrder } from '../data-order-landing.ts'; import { composeFile, isFileFormat, MIME_OF, safeFileName, type FileFormat } from '../file-compose.ts'; import { toFileDoc } from '../file-doc.ts'; +import { afterSave } from '../save-wake.ts'; import { displayLog } from './log-lines.ts'; import { pulse } from '../workers/pulse.ts'; import type { Container } from '../container.ts'; @@ -1361,8 +1362,8 @@ export function registerDeskRoutes(app: Hono, container: Container): voi return c.json(body, 409); } const saved = await applyViewTableEdits(container, taskId, parsed.data); - // 数据变了,件跟着变 —— 算出来的那些(类徽 / 分布条 / 去向)由这一次重渲重新求值 - if (saved.rows > 0) await container.views.repush(taskId); + // 数据变了,件跟着变;并叫醒任务 —— auto 步的配方这才有机会按最新的草稿铺格 + await afterSave(container, taskId, saved.rows); /* * **有行没落下就如实说** —— 保存说成功、东西却不在,是这一屏最伤人的一种谎 * (2026-08-24 用户实测:件上加的那个客户推到下一步就不见了)。 diff --git a/apps/api/src/app/save-wake.ts b/apps/api/src/app/save-wake.ts new file mode 100644 index 0000000..7656492 --- /dev/null +++ b/apps/api/src/app/save-wake.ts @@ -0,0 +1,26 @@ +/** + * **件上按了保存之后**(2026-08-29,spec §5.4)。 + * + * 两件事按序: + * ① 重推件 —— 数据变了,算出来的那些(红带缺几格 / 分布条 / 去向)得重新求值; + * ② **叫醒任务** —— auto 步的配方这才有机会按最新的草稿把该铺的行铺出来。 + * 人挑了芯片类型、按了保存,参数格就在这一下之后出现。 + * + * 从前只有两条回传路由调 `wake`;保存不是回传,于是「保存即铺格」永远等不到那一拍。 + * **叫不醒不抬手**:保存本身是成功的,不该因为叫不醒把 200 变成 500 —— + * 下一次推进器扫到它照样会跑。 + */ +import type { TaskId } from '@contracts'; + +export async function afterSave( + deps: { + readonly views: { repush(taskId: TaskId): Promise }; + readonly task: { wake(taskId: TaskId): Promise }; + }, + taskId: TaskId, + rows: number, +): Promise { + if (rows <= 0) return; + await deps.views.repush(taskId); + await deps.task.wake(taskId).catch(() => false); +}