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 运行时依赖。
130 lines
3.0 KiB
JavaScript
130 lines
3.0 KiB
JavaScript
"use strict";
|
|
|
|
/**
|
|
* 巡检结果存储
|
|
*
|
|
* 保存每次巡检的结果数据,支持按设备查询历史。
|
|
* 为避免数据量过大,仅保留最近 N 条记录(默认 1000 条)。
|
|
*/
|
|
|
|
const { STORAGE_KEY_INSPECTION_RESULTS } = require("./storageKeys.cjs");
|
|
const { INSPECTION_STATUS } = require("./types.cjs");
|
|
|
|
const MAX_RESULTS = 1000;
|
|
|
|
let _results = null;
|
|
|
|
function _ensureLoaded(readFn) {
|
|
if (_results === null) {
|
|
const raw = readFn(STORAGE_KEY_INSPECTION_RESULTS);
|
|
_results = raw ? _safeParse(raw, []) : [];
|
|
}
|
|
}
|
|
|
|
function _safeParse(text, def) {
|
|
if (text === null || text === undefined) return def;
|
|
if (typeof text === "object") return text;
|
|
try { return JSON.parse(text); }
|
|
catch { return def; }
|
|
}
|
|
|
|
function _save(writeFn) {
|
|
if (_results.length > MAX_RESULTS) {
|
|
_results = _results.slice(-MAX_RESULTS);
|
|
}
|
|
writeFn(STORAGE_KEY_INSPECTION_RESULTS, JSON.stringify(_results));
|
|
}
|
|
|
|
// ---------- 增删改查 ----------
|
|
|
|
/**
|
|
* 新增一条巡检结果
|
|
*/
|
|
function addResult(readFn, writeFn, result) {
|
|
_ensureLoaded(readFn);
|
|
|
|
const record = {
|
|
id: `result_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
job_id: result.job_id || null,
|
|
device_id: result.device_id, // host_id
|
|
catalog_id: result.catalog_id || null,
|
|
timestamp: Date.now(),
|
|
online: result.online,
|
|
status: result.status || INSPECTION_STATUS.SUCCESS,
|
|
duration_ms: result.duration_ms || 0,
|
|
metrics: result.metrics || {},
|
|
alerts: result.alerts || [],
|
|
error_message: result.error_message || null,
|
|
};
|
|
|
|
_results.push(record);
|
|
_save(writeFn);
|
|
return { ...record };
|
|
}
|
|
|
|
/**
|
|
* 获取指定设备的最近巡检结果
|
|
*/
|
|
function getLatestByDevice(readFn, hostId, limit = 20) {
|
|
_ensureLoaded(readFn);
|
|
return _results
|
|
.filter((r) => r.device_id === hostId)
|
|
.sort((a, b) => b.timestamp - a.timestamp)
|
|
.slice(0, limit);
|
|
}
|
|
|
|
/**
|
|
* 获取所有设备的最新一次巡检结果
|
|
*/
|
|
function getLatestAll(readFn) {
|
|
_ensureLoaded(readFn);
|
|
const latest = {};
|
|
for (const r of _results) {
|
|
if (!latest[r.device_id] || r.timestamp > latest[r.device_id].timestamp) {
|
|
latest[r.device_id] = r;
|
|
}
|
|
}
|
|
return Object.values(latest);
|
|
}
|
|
|
|
/**
|
|
* 获取最近 N 条结果
|
|
*/
|
|
function getRecent(readFn, limit = 50) {
|
|
_ensureLoaded(readFn);
|
|
return [..._results].sort((a, b) => b.timestamp - a.timestamp).slice(0, limit);
|
|
}
|
|
|
|
/**
|
|
* 根据时间范围查询
|
|
*/
|
|
function getByTimeRange(readFn, startTime, endTime) {
|
|
_ensureLoaded(readFn);
|
|
return _results.filter(
|
|
(r) => r.timestamp >= startTime && r.timestamp <= endTime
|
|
).sort((a, b) => b.timestamp - a.timestamp);
|
|
}
|
|
|
|
/**
|
|
* 清空结果(手动清理)
|
|
*/
|
|
function clearResults(readFn, writeFn) {
|
|
_results = [];
|
|
_save(writeFn);
|
|
}
|
|
|
|
// ---------- 重置(测试用) ----------
|
|
function _resetForTest() {
|
|
_results = null;
|
|
}
|
|
|
|
module.exports = {
|
|
addResult,
|
|
getLatestByDevice,
|
|
getLatestAll,
|
|
getRecent,
|
|
getByTimeRange,
|
|
clearResults,
|
|
_resetForTest,
|
|
};
|