diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index c23206d10..502d5d4a1 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -11350,29 +11350,139 @@ button.design-workspace-tree__entry:hover, color: var(--platform-text-soft, #6b7280); font-size: 12px; } +/* ============================================================ + 模型菜单的**共享样式面**(任何宿主都拿同一套观感) + ============================================================ + 选择器只用组件自带类名(`.conversation-model-select` 一族),不带宿主祖先链:工作台输入区、 + 首页输入区等**任何** `ConversationModelSelect` 实例都得到同一套浮层观感(#600 复核后的口径)。 + 宿主专属的东西——工作台输入区的锚点、与工具栏的几何关系、强度区布局——留在各自作用域; + 这里只放卡片与列表本身,两边不各抄一份。 + 观感:卡片 16px 圆角 / 12px 内边距 / 极淡描边 / 既有暖色投影 token;列表行 34px、行圆角 9px、 + hover 极淡暖底、选中是轻量 pill;滚动条 6px 且平时透明(悬停控件才显形)。 + 颜色全部取 `--platform-*` token,不引入新色值。 */ + +/* 卡片:合并形态(带强度区)用外壳当卡片,独立形态菜单自己就是卡片——两处同一套值。 + 独立形态的锚点沿用上面那条基础规则(`position: absolute; right: 0; bottom: calc(100% + 8px)`), + 不在这里重复。 */ +.conversation-model-select .conversation-model-menu-shell, +.conversation-model-select .conversation-model-menu { + display: flex; + flex-direction: column; + width: max-content; + min-width: min(260px, calc(100vw - 24px)); + max-width: min(320px, calc(100vw - 24px)); + /* 独立形态:卡片自己就是滚动区,194 = 170 行高 + 上下各 12 内边距,与合并形态同高。 */ + max-height: min(194px, calc(100vh - 24px)); + padding: 12px; + border: 1px solid var(--platform-line-soft); + border-radius: 16px; + background: var(--platform-input-fill); + box-shadow: var(--platform-desktop-hover-shadow); + overflow: auto; + scrollbar-width: thin; + scrollbar-color: var(--platform-subpanel-border) transparent; + pointer-events: auto; +} + +/* 外壳里:强度区与列表之间只留 6px;列表只负责滚动与截断,卡片观感归外壳。 + 里层这几条必须带 `!important`:基础规则里那条 `.conversation-model-menu` 用 + `background: … !important` 声明了菜单底色(它服务的是"菜单自己就是卡片"的旧形态)。 */ +.conversation-model-select .conversation-model-menu-shell { + gap: 6px; + /* 合并形态的高度由内容决定(强度区 + 列表各自的上下界已经定死), + 不再套用上面那条"卡片自己就是滚动区"的 194px 上限——那会把列表挤矮。 */ + max-height: none; +} + +.conversation-model-select + .conversation-model-menu-shell + .conversation-model-menu { + position: static !important; + width: 100% !important; + min-width: 0 !important; + max-width: none !important; + /* 170 = 5 行 × 34px:不会停在半行上;再长就滚动(细滚动条,悬停显形)。 */ + max-height: 170px !important; + padding: 0 !important; + border: 0 !important; + border-radius: 12px !important; + background: transparent !important; + box-shadow: none !important; +} + +/* 行:34px 高、9px 圆角、hover 极淡暖底,选中是轻量 pill(不做重色块)。 + 基础规则里同属性的旧值用 `!important` 声明,这里按同一档 `!important` 覆盖。 */ +.conversation-model-select .conversation-model-menu button { + min-height: 34px !important; + padding: 0 10px !important; + border-radius: 9px !important; +} + +.conversation-model-select .conversation-model-menu button:hover:not(:disabled), +.conversation-model-select .conversation-model-menu button:focus-visible { + background: var(--platform-nav-item-icon-fill) !important; + color: var(--platform-text-strong) !important; +} + +.conversation-model-select + .conversation-model-menu + button[aria-selected='true'] { + background: var(--platform-warm-bg) !important; + color: var(--platform-text-strong) !important; + font-weight: 600 !important; +} + +/* 列表宽度由卡片限定,超长模型名走省略号(旧形态靠 `width: max-content` 不截断)。 */ +.conversation-model-select .conversation-model-menu-option-main { + min-width: 0; + overflow: hidden; +} + +.conversation-model-select .conversation-model-menu-option-main > span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.conversation-model-select .conversation-model-menu::-webkit-scrollbar { + width: 6px; +} + +.conversation-model-select .conversation-model-menu::-webkit-scrollbar-track { + background: transparent; +} + +/* 静止时不画滚动条,鼠标进控件(或键盘焦点在控件内)才显形。 */ +.conversation-model-select .conversation-model-menu::-webkit-scrollbar-thumb { + border-radius: 999px; + background: transparent; +} + +.conversation-model-select:hover + .conversation-model-menu::-webkit-scrollbar-thumb, +.conversation-model-select + .conversation-model-menu:focus-within::-webkit-scrollbar-thumb { + background: var(--platform-subpanel-border); +} + .game-workbench-chat .project-chat-surface.is-direct-codex .project-chat-composer .conversation-model-select .conversation-model-menu button { + /* 只保留"抵消宿主通用按钮样式"的几何:工作台输入区的 `button` 有 28px 方块一族规则, + 尺寸 / 圆角 / 配色交给上面的共享样式面,避免宿主再抄一份观感。 */ position: static !important; display: flex !important; align-items: center !important; justify-content: space-between !important; width: 100% !important; min-width: 0 !important; - min-height: 32px !important; - height: 32px !important; margin: 0 !important; - padding: 0 9px !important; border: 0 !important; - border-radius: 6px !important; - background: transparent !important; - color: var(--platform-text-base, #374151) !important; box-shadow: none !important; font-size: 12px !important; - font-weight: 500 !important; white-space: nowrap !important; } .game-workbench-chat @@ -11393,8 +11503,6 @@ button.design-workspace-tree__entry:hover, .conversation-model-select .conversation-model-menu button[aria-selected='true'] { - background: #f3f1ee !important; - color: var(--platform-text-strong, #1f2937) !important; outline: none !important; } .conversation-model-menu-divider { @@ -13487,9 +13595,11 @@ details.design-agent-reasoning[open] 队列 chip 与提示段落的 `margin` 都写回前文各自那条规则。 */ /* ④ 思维强度**并入模型菜单**:底行只留模型触发钮一颗控件,强度区嵌在菜单顶部。 - 菜单外壳(`.conversation-model-menu-shell`)沿用原来模型菜单的锚点与朝向(贴触发钮 - 右缘、向上展开、距输入区 8px),观感按 Codex 参考图重做:大圆角、松内边距、柔和阴影 + - 极淡描边,颜色全部取 `--platform-*` 暖色 token(不引入新色值)。 + 外壳(`.conversation-model-menu-shell`)沿用原来模型菜单的锚点与朝向(贴触发钮右缘、 + 向上展开、距输入区 8px)——这是**宿主专属的几何**,留在工作台作用域。 + 卡片 / 列表的观感(圆角、内边距、阴影、描边、行高 34px、hover、选中 pill、细滚动条)已抬到 + 文件上方「模型菜单的共享样式面」一节(选择器只用 `.conversation-model-select` 一族), + 首页等宿主共用同一份,这里不再抄第二遍。 强度区里是原生 ``,自带 `role="slider"`、`aria-valuemin/max/now` 与 ←/→/Home/End,`aria-valuetext` 报中文档位名,点轨道或拖拽按 `step` 吸附到档位。 */ .game-workbench-chat @@ -13500,137 +13610,6 @@ details.design-agent-reasoning[open] right: 0; bottom: calc(100% + 8px); z-index: 20; - display: flex; - flex-direction: column; - gap: 6px; - width: max-content; - min-width: 260px; - max-width: min(320px, calc(100vw - 24px)); - padding: 12px; - border: 1px solid var(--platform-line-soft); - border-radius: 16px; - background: var(--platform-input-fill); - /* 卡片阴影用既有 token(同族暖色),不新造色值。 */ - box-shadow: var(--platform-desktop-hover-shadow); - pointer-events: auto; -} - -/* 里层菜单回到文档流:外壳已经有位置 / 描边 / 底色,列表只负责滚动与截断。 - 行高更舒展(34px)、行圆角 9px、滚动条细且平时透明(悬停卡片才显形)。 */ -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu { - position: static; - width: 100%; - min-width: 0; - max-width: none; - /* 170 = 5 行 × 34px:不会停在半行上;再长就滚动(细滚动条,悬停显形)。 */ - max-height: 170px; - overflow: auto; - padding: 0; - border: 0; - border-radius: 12px; - background: transparent; - box-shadow: none; - scrollbar-width: thin; - scrollbar-color: var(--platform-subpanel-border) transparent; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu::-webkit-scrollbar { - width: 6px; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu::-webkit-scrollbar-track { - background: transparent; -} - -/* 静止时不画滚动条,鼠标进卡片才显形("细 + 自动隐藏")。 */ -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu::-webkit-scrollbar-thumb { - border-radius: 999px; - background: transparent; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell:hover - .conversation-model-menu::-webkit-scrollbar-thumb { - background: var(--platform-subpanel-border); -} - -/* 行:34px 高、9px 圆角、hover 极淡暖底,选中是轻量 pill(不做重色块)。 - 前文那几条 `!important` 的同属性规则在这里按同一档 `!important` + 更高特异性盖回。 */ -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu - button { - min-height: 34px !important; - padding: 0 10px !important; - border-radius: 9px !important; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu - button:hover:not(:disabled), -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu - button:focus-visible { - background: var(--platform-nav-item-icon-fill) !important; - color: var(--platform-text-strong) !important; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu - button[aria-selected='true'] { - background: var(--platform-warm-bg) !important; - color: var(--platform-text-strong) !important; - font-weight: 600 !important; -} - -/* 列表宽度由外壳限定,超长模型名走省略号(原来靠 `width: max-content` 不截断)。 */ -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu-option-main { - min-width: 0; - overflow: hidden; -} - -.game-workbench-chat - .project-chat-surface.is-direct-codex - .project-chat-composer.is-direct-codex - .conversation-model-menu-shell - .conversation-model-menu-option-main - > span { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } /* 强度区:菜单顶部,与列表之间只用留白分开(不画横贯分隔线),标题左右层级分明。 */ diff --git a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts index 28e65c837..737d5a5f3 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/home.suite.ts @@ -1,6 +1,14 @@ +import { readFileSync } from 'node:fs'; + import { HOME_CREATION_AFTER_PROJECT_FAILURE } from '../../src/features/app-shell/homeCreationFailure'; import type { ProjectChatComponentProps } from '../../src/features/app-shell/model'; import { WorkspaceLauncherShell } from '../../src/features/app-shell/WorkspaceLauncher'; +import { repoPath } from '../repoPath'; +import { + declaration, + parseStyleSheet, + resolveDeclarations, +} from '../styleCascade'; import { act, App, @@ -164,6 +172,78 @@ export function registerClientHomeTests() { expect(createButton).toHaveProperty('disabled', false); }); + it('首页模型菜单复用同一套共享样式面(卡片与列表观感与工作台一致)', async () => { + // 样式面抬升前,首页这颗只命中基础规则(10px 圆角 / 5px 内边距 / 32px 行), + // 工作台那套(16px 圆角 / 12px 内边距 / 34px 行)挂在 `.game-workbench-chat …` 祖先链上。 + // 这条用例钉住"任何 ConversationModelSelect 实例都拿到同一份":断言只靠组件自带类名 + // (`.conversation-model-select …`)就能解析出卡片与列表的观感。 + const invoke = vi.fn(async (command: string) => { + if (command === 'read_game_creator_app_config') { + return { config: { selectedModelId: 'quality' } }; + } + if (command === 'load_game_creator_llm_models') { + return { + defaultModelId: 'quality', + models: [ + { id: 'quality', displayName: '高质量' }, + { id: 'fast', displayName: '快速' }, + ], + revision: 1, + }; + } + throw new Error(`unexpected invoke ${command}`); + }); + installTauriRuntime({ core: { invoke } }); + renderLauncherAt('/?launcher'); + + const modelTrigger = await screen.findByRole('button', { + name: '对话模型', + }); + fireEvent.click(modelTrigger); + const menu = await waitFor(() => { + const element = document.querySelector( + '.home-input-model-select .conversation-model-menu', + ); + expect(element).not.toBeNull(); + return element as HTMLElement; + }); + + // 组件自带类名在场:共享样式面的选择器就靠它,不需要任何宿主祖先链。 + expect(menu.classList.contains('conversation-model-menu')).toBe(true); + expect(menu.closest('.conversation-model-select')).not.toBeNull(); + expect(menu.closest('.game-workbench-chat')).toBeNull(); + + const rules = parseStyleSheet( + readFileSync( + repoPath('apps/ai-game-creator-shell/src/styles.css'), + 'utf8', + ), + ); + // 共享样式面按 `!important` 声明(要压过基础规则里同属性的旧值),断言只看最终值。 + const value = (declarations: Map, property: string) => + declaration(declarations, property).replace(/ !important$/u, ''); + const sharedCard = '.conversation-model-select .conversation-model-menu'; + const card = resolveDeclarations(rules, [sharedCard], 1440); + expect(value(card, 'border-radius')).toBe('16px'); + expect(value(card, 'padding')).toBe('12px'); + expect(value(card, 'border')).toContain('var(--platform-line-soft)'); + expect(value(card, 'box-shadow')).toContain( + 'var(--platform-desktop-hover-shadow)', + ); + + const row = resolveDeclarations(rules, [`${sharedCard} button`], 1440); + expect(value(row, 'min-height')).toBe('34px'); + expect(value(row, 'padding')).toBe('0 10px'); + expect(value(row, 'border-radius')).toBe('9px'); + + const selected = resolveDeclarations( + rules, + [`${sharedCard} button[aria-selected='true']`], + 1440, + ); + expect(value(selected, 'background')).toContain('var(--platform-warm-bg)'); + }); + it('anchors the empty home input placeholder to the editor while the page scrolls', () => { renderLauncherAt('/?launcher'); diff --git a/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts b/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts index 6b4a6daa0..94faab5da 100644 --- a/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts +++ b/apps/ai-game-creator-shell/tests/chatDialogFrameLayout.test.ts @@ -159,6 +159,11 @@ const COMPOSER_TRIGGER_BASE = '.project-chat-surface.is-direct-codex .project-chat-composer .conversation-model-trigger'; const INPUT_ACTIONS = `${COMPOSER_INPUT} .resource-reference-input-actions`; const INPUT_ACTIONS_PLAIN = `${COMPOSER} .resource-reference-input-actions`; +/** 模型菜单的共享样式面(选择器只用组件自带类名,不带宿主祖先链;首页与工作台共用)。 */ +const SHARED_CARD = '.conversation-model-select .conversation-model-menu'; +const SHARED_SHELL = + '.conversation-model-select .conversation-model-menu-shell'; +const SHARED_CARD_IN_SHELL = `${SHARED_SHELL} .conversation-model-menu`; /** 强度滑块与它那排装饰档位点(issue #600 的复核点:点被轨道压住、横向与圆钮错位)。 */ const STRENGTH_RANGE = `${COMPOSER} .project-chat-composer-strength-range`; const STRENGTH_THUMB = `${STRENGTH_RANGE}::-webkit-slider-thumb`; @@ -345,11 +350,16 @@ describe('陶泥儿对话区:Codex 三段式(顶栏 / 唯一滚动区 / 文 const select = desktopDeclarations( `${COMPOSER_CONTROLS} .conversation-model-select`, ); + // 外壳:锚点是工作台专属几何;卡片观感来自共享样式面(见下面的 `sharedCard`), + // 所以这里把"这个元素会命中的全部选择器"都传进去——只传工作台那条会漏掉搬家后的声明。 const shell = desktopDeclarations( `${COMPOSER} .conversation-model-menu-shell`, + SHARED_SHELL, ); const menuInShell = desktopDeclarations( `${COMPOSER} .conversation-model-menu-shell .conversation-model-menu`, + SHARED_CARD, + SHARED_CARD_IN_SHELL, ); const section = desktopDeclarations( `${COMPOSER} .project-chat-reasoning-effort.is-section`, @@ -357,14 +367,30 @@ describe('陶泥儿对话区:Codex 三段式(顶栏 / 唯一滚动区 / 文 const range = desktopDeclarations( `${COMPOSER} .project-chat-composer-strength-range`, ); + /** + * 共享样式面为了压过基础规则里那几条 `!important`,自己也是按 `!important` 声明的; + * 断言时只看最终值,去掉后缀。 + */ + const value = (declarations: Map, property: string) => + declaration(declarations, property).replace(/ !important$/u, ''); // 弹层锚在模型控件上、从工具条上方展开(与原来的模型菜单同一朝向,不盖输入框)。 expect(declaration(select, 'position')).toContain('relative'); expect(declaration(shell, 'position')).toBe('absolute'); expect(declaration(shell, 'bottom')).toBe('calc(100% + 8px)'); expect(declaration(shell, 'right')).toBe('0'); + // 卡片观感由共享样式面提供(与首页那颗同一份规则)。 + expect(pixelValue(shell, 'border-radius')).toBe(16); + expect(paddingBox(shell).top).toBe(12); + expect(declaration(shell, 'box-shadow')).toContain( + 'var(--platform-desktop-hover-shadow)', + ); + expect(declaration(shell, 'max-height')).toBe('none'); // 里层菜单回到文档流(位置 / 描边 / 底色归外壳),强度区是菜单顶部的一块网格,滑块占满宽度。 - expect(declaration(menuInShell, 'position')).toBe('static'); + expect(value(menuInShell, 'position')).toBe('static'); + expect(value(menuInShell, 'max-height')).toBe('170px'); + expect(value(menuInShell, 'background')).toBe('transparent'); + expect(value(menuInShell, 'border-radius')).toBe('12px'); expect(declaration(section, 'display')).toBe('grid'); expect(declaration(range, 'width')).toBe('100%'); // 底行没有第二颗强度控件:那一排的高度仍由模型触发钮(30px)决定,见上面的算式。 diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index ca9a19dc5..4d1d98059 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -12,6 +12,15 @@ - **注释与实现必须同口径(D9)**:`.resource-reference-input` 的 `min-height: 0 / padding: 0` 原先写在文件末尾那条六类规则里靠**源码顺序**盖住前面的 `min-height: 56px / padding: 0 0 4px`,与「不依赖源码顺序」的注释矛盾。现行口径:几何(内边距 / 高度下界)写回 11520 行那条六类规则,末尾那条只留网格与行距,注释同步改成"不依赖源码先后"。 - **深色主题下焦点环间隙不可靠(D3,仅记录不改代码)**:间隙色取 `--platform-input-fill`,深色主题该 token 只有 5% 不透明(`rgba(255,255,255,0.05)`),间隙会与焦点环颜色几乎一样。当前工作台根节点固定 `platform-theme--light`,走不到这条分支;将来真要启用深色主题,把间隙换成不透明 token 再验一次。 +## 2026-10-05 模型菜单的观感是组件自带的共享样式面(首页同步复用) + +- **现象**:工作台那颗 `ConversationModelSelect` 已经改成「强度区 + 模型列表」的卡片观感,但首页输入区右下角那颗(`className="home-input-model-select"`,同一个组件)还是**旧卡片**:161px 窄卡、10px 圆角、5px 内边距、32px 行高、旧灰投影。用户口径是"这个样式同步到首页里去,复用起来"。 +- **成因**:#600 那轮把卡片 / 列表的新观感全挂在 `.game-workbench-chat .project-chat-surface.is-direct-codex .project-chat-composer.is-direct-codex …` 这条**宿主祖先链**上,于是只有工作台那一处命中;同一个组件换个宿主就退回基础规则。 +- **处理(现行口径)**:卡片 / 列表 / 行 / hover / 选中 pill / 细滚动条这套观感抬到**组件自带的共享样式面**——选择器只用组件类名(`.conversation-model-select .conversation-model-menu-shell`、`.conversation-model-select .conversation-model-menu`、`… .conversation-model-menu button…`),**不带任何宿主祖先链**;宿主专属的东西(工作台输入区的锚点 `position/right/bottom/z-index`、与工具栏的几何关系、强度区布局)继续留在工作台作用域。合并形态(有外壳)与独立形态(首页/策划/画布直接渲染菜单)**同一套值**:卡 16px 圆角 / 12px 内边距 / 1px `--platform-line-soft` 描边 / `--platform-desktop-hover-shadow`;行 34px、圆角 9px、hover `--platform-nav-item-icon-fill`、选中 `--platform-warm-bg` + 600;独立形态的卡片自己就是滚动区(`max-height: 194 = 170 + 上下各 12`,与合并形态同高),外壳形态的列表 `max-height: 170`(5×34,不出现半行)。 +- **首页不加强度区**:首页那颗没有 effort 的 state / props(`view/home/index.tsx` 只传 `className` 与 `disabled`),加了等于新增一个首页从未暴露过的设置项。 +- **判据/取证**:`tests/appSurface/home.suite.ts`「首页模型菜单复用同一套共享样式面」——首页实例的 `.conversation-model-menu` 的祖先链里**没有** `.game-workbench-chat`,而只靠 `.conversation-model-select …` 就能解析出 16px 圆角 / 12px 内边距 / 34px 行;`tests/chatDialogFrameLayout.test.ts` 的外壳用例按新选择器集合更新(锚点仍来自工作台链、卡片观感来自共享面)。真机实测(无头 Chromium,同一夹具同一裁剪框):首页那颗 161×309 / 10px / 5px / 32px → **260×194 / 16px / 12px / 34px**(与工作台卡片逐项一致);工作台那颗外壳 260×262.5、内层列表 234×170、行 34/9px **前后逐值不变**。 +- **边界**:策划面与画布也复用同一个组件 → 它们的菜单观感同样变成这张卡片(有意为之;窄面板下卡片最小宽度 260px,仍受 `calc(100vw - 24px)` 与各自锚点约束)。若某个宿主需要另一套尺寸,在**该宿主作用域**里覆盖,不要再把观感抄第二份。 + ## 2026-10-04 把非素材任务塞进「生成任务」账本:taskType 维度、v1 兼容与 live 集合 - **现象**:首页「AI 项目命名」改成进「生成任务」列表后,第一次读账本(工作台打开项目就会读)就把那条还在跑的命名任务标成**失败**;随后前端的终态推进被拒(记录已终态)。