feat: 巡检增强 / 拓扑大屏 / 远程 HTTP / portable 绿色打包
Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled

巡检模块:巡检调度器改为轮询驱动,新增每日报告存储、告警规则独立
Store、设备 Store 解耦,_executeSnapshot 补齐 DEBUG 声明,巡检中心
与告警中心页增强。

拓扑大屏:MonitoringTopologyView 扩展分组/布局控制,
useMonitoringData 重构数据流。

远程 HTTP:新增 electron/remoteHttpServer.cjs,preload/api.cjs 暴露
IPC,registerBridges 注册 netcatty:http:open 桥。

portable 绿色打包:
- electron-builder.config.cjs 恢复原始白名单(61MB app.asar),
  收集器自动追踪运行时依赖;
- portableData.cjs 重写为 .portable 标记检测;
- scripts/migratePortableLocalStorage.cjs 离线脚本把 Local Storage
  的 http://localhost:5173 origin 批量迁移为 app://netcatty;
- scripts/scanWorkspaceDeps.cjs 扫描 workspace 运行时依赖。
This commit is contained in:
2026-10-19 21:11:57 +08:00
committed by trae-solo-agent
parent 336c3afd47
commit 2e71e03d71
34 changed files with 3012 additions and 230 deletions

View File

@@ -85,6 +85,8 @@ import {
STORAGE_KEY_SHOW_TAB_NUMBER_BADGES,
STORAGE_KEY_DISABLE_TERMINAL_FONT_ZOOM,
STORAGE_KEY_PRODUCT_NAME,
STORAGE_KEY_MONITORING_DASHBOARD_TITLE,
STORAGE_KEY_REPORT_PRODUCT_NAME,
} from '../../infrastructure/config/storageKeys';
import { DEFAULT_UI_LOCALE, resolveSupportedLocale } from '../../infrastructure/config/i18n';
import {
@@ -273,10 +275,67 @@ export const useSettingsState = (options: { enableSettingsSync?: boolean; enable
const stored = readStoredString(STORAGE_KEY_UI_FONT_FAMILY);
return stored && isValidUiFontId(stored) ? stored : DEFAULT_UI_FONT_ID;
});
// 产品名称配置(用于标题栏、侧边栏 Logo 等)
const [productName, setProductName] = useState<string>(() => {
return localStorageAdapter.readString(STORAGE_KEY_PRODUCT_NAME) || '云启智能运维平台';
});
// 远程浏览器:启动时从 /api/dashboard-title 拉取产品名系列配置,写入 localStorage
useEffect(() => {
const IS_REMOTE = typeof window !== "undefined" && !!(window as any).__REMOTE_TOKEN__;
if (!IS_REMOTE) return;
const token = (window as any).__REMOTE_TOKEN__ || "";
fetch(`/api/dashboard-title?token=${encodeURIComponent(token)}`)
.then(r => r.json())
.then(d => {
let changed = false;
if (d?.productName) {
localStorageAdapter.writeString(STORAGE_KEY_PRODUCT_NAME, d.productName);
setProductName(d.productName);
changed = true;
}
if (d?.dashboardTitle) {
localStorageAdapter.writeString(STORAGE_KEY_MONITORING_DASHBOARD_TITLE, d.dashboardTitle);
changed = true;
}
if (d?.reportProductName !== undefined) {
localStorageAdapter.writeString(STORAGE_KEY_REPORT_PRODUCT_NAME, d.reportProductName);
changed = true;
}
if (changed) {
try { window.dispatchEvent(new CustomEvent('productNameChanged')); } catch {}
try { window.dispatchEvent(new CustomEvent('monitoringTitleChanged')); } catch {}
}
})
.catch(() => {});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Electron 本地:启动时从主进程读取产品名系列配置 → 恢复到 Local Storage
// 解决绿色便携版首次启动 Local Storage 空时显示旧默认值的问题
useEffect(() => {
const IS_REMOTE = typeof window !== "undefined" && !!(window as any).__REMOTE_TOKEN__;
if (IS_REMOTE) return; // 远程浏览器有上面的 effect 处理
const nc = (window as any).netcatty;
if (!nc?.inspection) return;
const localProductName = localStorageAdapter.readString(STORAGE_KEY_PRODUCT_NAME);
const needsRestore = !localProductName; // Local Storage 空才需要恢复
if (needsRestore) {
nc.inspection.getProductName?.().then((v: string) => {
if (v && v.length > 0) {
localStorageAdapter.writeString(STORAGE_KEY_PRODUCT_NAME, v);
setProductName(v);
console.info('[useSettingsState] restored productName from main:', v);
}
}).catch(() => {});
}
// dashboardTitle 和 reportProductName 在 SettingsApplicationTab 里单独恢复
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [syncConfig, setSyncConfig] = useState<SyncConfig | null>(() => localStorageAdapter.read<SyncConfig>(STORAGE_KEY_SYNC));
const [terminalThemeId, setTerminalThemeId] = useState<string>(() => localStorageAdapter.readString(STORAGE_KEY_TERM_THEME) || DEFAULT_TERMINAL_THEME);
const [followAppTerminalTheme, setFollowAppTerminalThemeState] = useState<boolean>(() => {
@@ -1171,6 +1230,11 @@ export const useSettingsState = (options: { enableSettingsSync?: boolean; enable
// Persist product name
useLayoutEffect(() => {
localStorageAdapter.writeString(STORAGE_KEY_PRODUCT_NAME, productName);
// 同步到主进程 inspection-data.json,远程浏览器 API 可读
try {
const nc = (window as any).netcatty;
nc?.inspection?.saveProductName?.(productName).catch(() => {});
} catch {}
if (persistMountedRef.current) {
notifySettingsChanged(STORAGE_KEY_PRODUCT_NAME, productName);
// 更新窗口标题栏