fix: self-heal broken console view (tab-closed legacy state)
This commit is contained in:
@@ -311,6 +311,11 @@ let sessionBridge: { sessions: any; conversation: any; list: any; workspaces: an
|
|||||||
const CONSOLE_ID = 'wt-console'
|
const CONSOLE_ID = 'wt-console'
|
||||||
const CONSOLE_ICON = '🖥️'
|
const CONSOLE_ICON = '🖥️'
|
||||||
|
|
||||||
|
/** 控制室布局是否健全:主窗格首格存在 console 类型标签(旧版关标签的坏存档没有它) */
|
||||||
|
function specHasConsoleTab(spec: LayoutSpec | undefined): boolean {
|
||||||
|
return !!spec?.main?.[0]?.tabs?.some((t) => t.content?.kind === 'builtin' && t.content.type === 'console')
|
||||||
|
}
|
||||||
|
|
||||||
/** 控制室默认布局:单一锁死大窗格(项目卡片网格)+ 右侧对话 */
|
/** 控制室默认布局:单一锁死大窗格(项目卡片网格)+ 右侧对话 */
|
||||||
function buildConsoleSpec(t: (key: string) => string): LayoutSpec {
|
function buildConsoleSpec(t: (key: string) => string): LayoutSpec {
|
||||||
return {
|
return {
|
||||||
@@ -1083,6 +1088,16 @@ function WorktableSection(props: any) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自愈:启动时若控制室存档是坏布局(旧版关掉控制室标签造成窗格退化成选择器),立即重建默认面板
|
||||||
|
useEffect(() => {
|
||||||
|
const saved = projects.views[CONSOLE_ID]
|
||||||
|
if (!specHasConsoleTab(saved)) {
|
||||||
|
const spec = buildConsoleSpec((k) => t(k as WorktableKey))
|
||||||
|
persistProjects((prev) => ({ ...prev, views: { ...prev.views, [CONSOLE_ID]: spec } }))
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [projects.views[CONSOLE_ID]])
|
||||||
|
|
||||||
// 子座位注册变化 → 刷新 id 序列
|
// 子座位注册变化 → 刷新 id 序列
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const sync = () => setRegisteredIds([...registryStore.ids])
|
const sync = () => setRegisteredIds([...registryStore.ids])
|
||||||
@@ -1302,7 +1317,11 @@ function buildCustomLayoutPrompt(req: string): string {
|
|||||||
|
|
||||||
/** 打开「工作台」控制室:已绑定 → 打开并切换绑定对话;explicitBound 供强制绑定流程传入刚绑定的会话 */
|
/** 打开「工作台」控制室:已绑定 → 打开并切换绑定对话;explicitBound 供强制绑定流程传入刚绑定的会话 */
|
||||||
const openConsole = useCallback((explicitBound?: string | null) => {
|
const openConsole = useCallback((explicitBound?: string | null) => {
|
||||||
const spec = projects.views[CONSOLE_ID] ?? buildConsoleSpec((k) => t(k as WorktableKey))
|
const saved = projects.views[CONSOLE_ID]
|
||||||
|
// 自愈:坏存档(旧版关掉控制室标签导致窗格退化成选择器)→ 重建默认面板并写回
|
||||||
|
const broken = !specHasConsoleTab(saved)
|
||||||
|
const spec = broken ? buildConsoleSpec((k) => t(k as WorktableKey)) : (saved as LayoutSpec)
|
||||||
|
if (broken) persistProjects((prev) => ({ ...prev, views: { ...prev.views, [CONSOLE_ID]: spec } }))
|
||||||
engineIdsRef.current.add(CONSOLE_ID)
|
engineIdsRef.current.add(CONSOLE_ID)
|
||||||
splitStore.open(spec)
|
splitStore.open(spec)
|
||||||
if (splitStore.active && splitStore.spec?.id === CONSOLE_ID) {
|
if (splitStore.active && splitStore.spec?.id === CONSOLE_ID) {
|
||||||
|
|||||||
@@ -1220,3 +1220,14 @@
|
|||||||
rgba(63,185,80,0.9) + 双层 box-shadow ✓、busy 旋转描边 #5aa0ff ✓;三阶段流程 + 主题
|
rgba(63,185,80,0.9) + 双层 box-shadow ✓、busy 旋转描边 #5aa0ff ✓;三阶段流程 + 主题
|
||||||
全 ✓;functional-diag 全 20 STEP ERROR_COUNT: 0。
|
全 ✓;functional-diag 全 20 STEP ERROR_COUNT: 0。
|
||||||
- 备注:纯客户端改动,F5 即生效。
|
- 备注:纯客户端改动,F5 即生效。
|
||||||
|
|
||||||
|
## 补记(控制室坏存档自愈:旧版「关标签」坑出不可逆状态)
|
||||||
|
|
||||||
|
- 事故:用户在被修复前点掉了控制室标签的 ✕,窗格退化成选择器并持久化进
|
||||||
|
views['wt-console'](tabs 空)——重开控制室也只显示选择器,回不去。
|
||||||
|
- 实现:specHasConsoleTab 健全性检查 + 双通道自愈:① 挂载时(useEffect 监听
|
||||||
|
views[CONSOLE_ID])发现坏存档立即重建 buildConsoleSpec 并写回;② openConsole 打开时
|
||||||
|
再查一遍,坏则重建 + persistProjects 写回。探测种子改为植入坏存档验证。
|
||||||
|
- 验证:probe-batch16 healTabs=1、healType='console' ✓,全流程 ✓;functional-diag
|
||||||
|
全 20 STEP ERROR_COUNT: 0。
|
||||||
|
- 备注:纯客户端改动,F5 即生效;用户 F5 后坏存档自动修复,点「控制室」卡片即恢复面板。
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|||||||
await send('Runtime.enable');
|
await send('Runtime.enable');
|
||||||
await send('Page.enable');
|
await send('Page.enable');
|
||||||
await send('Page.addScriptToEvaluateOnNewDocument', {
|
await send('Page.addScriptToEvaluateOnNewDocument', {
|
||||||
source: "try{ if(location.origin==='http://127.0.0.1:3080'){ localStorage.setItem('dsh.worktable.view.v1', JSON.stringify({query:'',searchOpen:false,orderBy:'manual',dock:'footer',floatTop:null,sortMigratedV2:true})); localStorage.setItem('dsh.worktable.projects.v1', JSON.stringify({order:['t-bind'],lastUsed:{},hidden:[],nameOverrides:{},iconOverrides:{},shortcuts:[],layouts:[{id:'t-bind',title:'\u7ed1\u5b9a\u6d4b\u8bd5',icon:'\ud83e\uddea',top:null,left:null,main:[{id:'p1',title:'\u5185\u5bb91',min:200,content:null,tabs:[],active:0}],leftWidth:{default:260,min:160,max:480},chatWidth:{default:360,min:240,max:600},topHeight:{default:200,min:120,max:480},chatSide:'right',chatFullHeight:false}],bindings:{},folders:{},views:{},removed:[]})); } }catch(e){}",
|
source: "try{ if(location.origin==='http://127.0.0.1:3080'){ localStorage.setItem('dsh.worktable.view.v1', JSON.stringify({query:'',searchOpen:false,orderBy:'manual',dock:'footer',floatTop:null,sortMigratedV2:true})); localStorage.setItem('dsh.worktable.projects.v1', JSON.stringify({order:['t-bind'],lastUsed:{},hidden:[],nameOverrides:{},iconOverrides:{},shortcuts:[],layouts:[{id:'t-bind',title:'\u7ed1\u5b9a\u6d4b\u8bd5',icon:'\ud83e\uddea',top:null,left:null,main:[{id:'p1',title:'\u5185\u5bb91',min:200,content:null,tabs:[],active:0}],leftWidth:{default:260,min:160,max:480},chatWidth:{default:360,min:240,max:600},topHeight:{default:200,min:120,max:480},chatSide:'right',chatFullHeight:false}],bindings:{},folders:{},views:{\"wt-console\":{\"id\":\"wt-console\",\"title\":\"kz\",\"top\":null,\"main\":[{\"id\":\"console\",\"title\":\"kz\",\"min\":240,\"tabs\":[],\"active\":0}],\"chatWidth\":{\"default\":340,\"min\":280,\"max\":600},\"topHeight\":{\"default\":200,\"min\":120,\"max\":480},\"chatSide\":\"right\"}},removed:[]})); } }catch(e){}",
|
||||||
});
|
});
|
||||||
await send('Page.navigate', { url: 'http://127.0.0.1:3080/' });
|
await send('Page.navigate', { url: 'http://127.0.0.1:3080/' });
|
||||||
const evaluate = async (expr) => {
|
const evaluate = async (expr) => {
|
||||||
@@ -45,6 +45,11 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|||||||
var vis = function(sel){ return [].slice.call(document.querySelectorAll(sel)).find(function(el){ return (getComputedStyle(el).visibility!=='hidden'&&el.getBoundingClientRect().height>0); }); };
|
var vis = function(sel){ return [].slice.call(document.querySelectorAll(sel)).find(function(el){ return (getComputedStyle(el).visibility!=='hidden'&&el.getBoundingClientRect().height>0); }); };
|
||||||
var st = window.__dshWorktable.splitStore;
|
var st = window.__dshWorktable.splitStore;
|
||||||
try {
|
try {
|
||||||
|
// 自愈验证:种子里的坏存档(控制室标签被关掉)应被挂载时修复
|
||||||
|
var seeded = JSON.parse(localStorage.getItem('dsh.worktable.projects.v1'));
|
||||||
|
var cv = seeded && seeded.views && seeded.views['wt-console'];
|
||||||
|
out.healTabs = cv && cv.main && cv.main[0] && cv.main[0].tabs ? cv.main[0].tabs.length : null;
|
||||||
|
out.healType = cv && cv.main && cv.main[0] && cv.main[0].tabs && cv.main[0].tabs[0] ? cv.main[0].tabs[0].content.type : null;
|
||||||
var cs = getComputedStyle(document.body);
|
var cs = getComputedStyle(document.body);
|
||||||
out.themeFill = cs.getPropertyValue('--dsw-alias-fill-l1').trim() || null;
|
out.themeFill = cs.getPropertyValue('--dsw-alias-fill-l1').trim() || null;
|
||||||
out.htmlDataTheme = document.documentElement.getAttribute('data-theme');
|
out.htmlDataTheme = document.documentElement.getAttribute('data-theme');
|
||||||
|
|||||||
Reference in New Issue
Block a user