diff --git a/01_content/src/client/index.tsx b/01_content/src/client/index.tsx index 4a7e65e..3e323e6 100644 --- a/01_content/src/client/index.tsx +++ b/01_content/src/client/index.tsx @@ -788,6 +788,10 @@ function WorktableSection(props: any) { if (ovr) icon.setAttribute('data-wt-icon', ovr) else icon.removeAttribute('data-wt-icon') } + // 选中态统一由工作台判定(引擎打开的项目高亮;未打开时若引擎空闲则保留卡片自带状态, + // 兼容自带分栏实现的插件) + if (activeSplitId === id) el.setAttribute('data-on', 'true') + else if (activeSplitId != null) el.setAttribute('data-on', 'false') } else { el.removeAttribute('data-wt-id') } @@ -797,7 +801,7 @@ function WorktableSection(props: any) { const mo = new MutationObserver(sync) mo.observe(document.body, { childList: true, subtree: true }) return () => mo.disconnect() - }, [aliveRegisteredIds, projects.iconOverrides]) + }, [aliveRegisteredIds, projects.iconOverrides, activeSplitId]) useEffect(() => { const onDocClick = (e: MouseEvent) => { diff --git a/02_process/worklogs/2026-08-16_worktable-v2.md b/02_process/worklogs/2026-08-16_worktable-v2.md index 4266b88..469cbe9 100644 --- a/02_process/worklogs/2026-08-16_worktable-v2.md +++ b/02_process/worklogs/2026-08-16_worktable-v2.md @@ -639,12 +639,14 @@ 原生视图内部是浏览器扩展页,插件注入不了按钮、拦不到鼠标,也驱动不了内部滚动—— 向用户如实说明后按指示回退);② 视图选项改名「设置」,点开直接内嵌「排序方式 + 管理项目 展开列表」,不再二次点击;③ 管理项目里给现有项目加「变更视图」:换预设拓扑, -## 补记(site 路由 rootToken 未解码修复) +## 补记(卡片选中态统一判定) -- 用户重启后实测:点 index.html 返回 {"error":"not found"}(路由已生效,文件解析失败)。 -- 根因:rootToken(encodeURIComponent 编码的目录)直接 pathResolve,未 decodeURIComponent, - 解析成带 %3A%5C 字面量的错误路径 → stat 空 → not found。rel 段当时有 decode,root 段漏了。 -- 修复:rootToken = decodeURIComponent(segs.shift())。 -- 验证:node 单测模拟解析逻辑——旅行 Atlas dist/index.html、dist/assets/index-*.js、 - fixture-site/index.html、fixture-site/assets/app.js 四条全部命中真实文件且沙箱判定 inside=true。 -- 备注:服务端改动,需用户再重启一次 dsh web 生效。 +- 用户反馈:旅行 Atlas 卡片选中后没有高亮边(其他 3 个项目都有);新建项目也要有。 +- 根因:ta_card 的 data-on 由它自己插件控制(自有引擎状态);用视图覆盖走工作台引擎打开时 + 两边状态对不上 → 不高亮。 +- 处理:DOM 桥 sync 里选中态统一由工作台判定——activeSplitId===id → data-on=true; + 引擎开着别的 → false;引擎空闲(activeSplitId=null)→ 不动(保留卡片自带状态, + 兼容自带分栏插件的打开态)。通用规则覆盖所有注册项目与新建项目。 +- 验证(functional-diag STEP13):布局打开时 ta/pr 卡 false;旅行设置视图覆盖后点卡片 → + engineSpecId=travelatlas 且 taOnAfterOpen=true;全 STEP 回归 ERROR_COUNT: 0。 +- 备注:纯客户端改动,F5 即生效。 diff --git a/04_test/functional-diag.cjs b/04_test/functional-diag.cjs index ae5d7ed..973860a 100644 --- a/04_test/functional-diag.cjs +++ b/04_test/functional-diag.cjs @@ -333,6 +333,47 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); })()`); console.log('STEP12:', JSON.stringify(step12)); + // 选中态统一:引擎打开的项目卡片高亮(含视图覆盖打开的常驻项目);新建项目同规则 + const step13 = await evaluate(`(async function(){ + var out={}; + try{ + var st=window.__dshWorktable.splitStore; + var ta=document.querySelector('.dsh-wt_projects .ta_card'); + var pr=document.querySelector('.dsh-wt_projects .pr_card'); + // 布局项目打开 → 常驻卡 data-on=false + st.open({id:'t-layout',title:'L',top:null,main:[{id:'p1',title:'1',min:200,content:null}],chatWidth:{default:320,min:240,max:600}}); + await new Promise(function(r){setTimeout(r,400)}); + out.taOnWhenLayoutOpen=ta?ta.getAttribute('data-on'):null; + out.prOnWhenLayoutOpen=pr?pr.getAttribute('data-on'):null; + st.close(); + await new Promise(function(r){setTimeout(r,300)}); + // 给旅行设置视图覆盖(走 UI:设置 → 旅行行 🧩 → 2h) + var btn=document.querySelector('.dsh-wt_actions .dsh-wt_iconBtn:nth-child(2)'); + if(btn){ btn.click(); } + await new Promise(function(r){setTimeout(r,300)}); + var rows=document.querySelectorAll('.dsh-wt_settings .dsh-wt_manageRow:not(.dsh-wt_manageRowSc):not(.dsh-wt_manageRowRemoved)'); + var taRow=rows[1]; + var puzzle=taRow&&taRow.querySelectorAll('.dsh-wt_manageBtn')[taRow.querySelectorAll('.dsh-wt_manageBtn').length-2]; + if(puzzle){ puzzle.click(); } + await new Promise(function(r){setTimeout(r,300)}); + var presets=document.querySelectorAll('.dsh-wt_presets .dsh-wt_preset'); + if(presets[0]){ presets[0].click(); } + await new Promise(function(r){setTimeout(r,400)}); + var bd=document.querySelector('.dsh-wt_popBackdrop'); + if(bd){ bd.click(); } + await new Promise(function(r){setTimeout(r,300)}); + // 点旅行卡片 → 视图覆盖 → 引擎打开 → 卡片高亮 + if(ta){ ta.click(); } + await new Promise(function(r){setTimeout(r,500)}); + out.taOnAfterOpen=ta?ta.getAttribute('data-on'):null; + out.engineSpecId=st.spec?st.spec.id:null; + st.close(); + await new Promise(function(r){setTimeout(r,300)}); + }catch(err){ out.err=String(err) } + return JSON.stringify(out); + })()`); + console.log('STEP13:', JSON.stringify(step13)); + const errors = events.filter((e) => { // 站点路由属新增服务端能力:运行中的服务器未重启前该 404 属预期(重启后移除本过滤) const ent = e.method === 'Log.entryAdded' ? e.params.entry : null;