"use strict"; /** * 预案模板 CRUD(方案 D7:模板不含匹配条件/双轨步骤,只含公共联动配置) * * 模板结构详见设计方案 §4.2 */ const { STORAGE_KEY_PLAN_TEMPLATES } = require("./storageKeys.cjs"); const { ALERT_LEVELS } = require("./types.cjs"); let _templates = null; function _ensureLoaded(readFn) { if (_templates === null) { const raw = readFn(STORAGE_KEY_PLAN_TEMPLATES); _templates = raw ? _safeParse(raw, []) : _getDefaultTemplates(); } } 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) { writeFn(STORAGE_KEY_PLAN_TEMPLATES, JSON.stringify(_templates)); } function _getDefaultTemplates() { const now = Date.now(); return [ { id: "tpl_level3_critical", name: "三级预案模板(严重)", level: ALERT_LEVELS.CRITICAL, builtin: true, description: "严重级别告警的公共配置:大屏红色闪烁 + 10 分钟自动升级 + 处置需确认", display: { color: "#ef4444", icon: "alert-octagon", blink: true, sound: "builtin_alarm" }, notification: { channels: ["desktop", "webhook"], recipients: [{ type: "webhook", target: "" }], repeat_interval_minutes: 5, max_repeats: 12, }, escalation_fallback: { auto_escalate_minutes: 30, escalation_target_level: ALERT_LEVELS.CRITICAL, }, remediation_defaults: { require_confirmation: true, auto_close_after_remediation_recovery: true, execution_timeout_sec: 120, }, created_at: now, updated_at: now, }, { id: "tpl_level2_warning", name: "二级预案模板(警告)", level: ALERT_LEVELS.WARNING, builtin: true, description: "警告级别告警的公共配置:大屏橙色提示 + 60 分钟自动升级", display: { color: "#f97316", icon: "alert-triangle", blink: false, sound: null }, notification: { channels: ["desktop"], recipients: [], repeat_interval_minutes: 10, max_repeats: 6, }, escalation_fallback: { auto_escalate_minutes: 60, escalation_target_level: ALERT_LEVELS.WARNING, }, remediation_defaults: { require_confirmation: false, auto_close_after_remediation_recovery: true, execution_timeout_sec: 120, }, created_at: now, updated_at: now, }, { id: "tpl_level1_info", name: "一级预案模板(提示)", level: ALERT_LEVELS.INFO, builtin: true, description: "提示级别告警的公共配置:大屏蓝色静态展示", display: { color: "#3b82f6", icon: "info", blink: false, sound: null }, notification: { channels: ["desktop"], recipients: [], repeat_interval_minutes: 0, max_repeats: 1, }, escalation_fallback: null, remediation_defaults: { require_confirmation: false, auto_close_after_remediation_recovery: true, execution_timeout_sec: 120, }, created_at: now, updated_at: now, }, ]; } // ---------- CRUD ---------- function listTemplates(readFn) { _ensureLoaded(readFn); return [..._templates]; } function getTemplate(readFn, templateId) { _ensureLoaded(readFn); return _templates.find((t) => t.id === templateId) || null; } function createTemplate(readFn, writeFn, data) { _ensureLoaded(readFn); const tpl = { id: data.id || `tpl_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`, name: data.name, level: data.level || ALERT_LEVELS.WARNING, builtin: false, description: data.description || "", display: data.display || { color: "#f97316", icon: "alert-triangle", blink: false, sound: null }, notification: data.notification || { channels: ["desktop"], recipients: [], repeat_interval_minutes: 10, max_repeats: 6 }, escalation_fallback: data.escalation_fallback || null, remediation_defaults: data.remediation_defaults || { require_confirmation: true, auto_close_after_remediation_recovery: true, execution_timeout_sec: 120 }, created_at: Date.now(), updated_at: Date.now(), }; _templates.push(tpl); _save(writeFn); return { ...tpl }; } function updateTemplate(readFn, writeFn, templateId, updates) { _ensureLoaded(readFn); const idx = _templates.findIndex((t) => t.id === templateId); if (idx === -1) return null; if (_templates[idx].builtin) return null; // 内置模板不可改 _templates[idx] = { ..._templates[idx], ...updates, updated_at: Date.now() }; _save(writeFn); return { ..._templates[idx] }; } function deleteTemplate(readFn, writeFn, templateId) { _ensureLoaded(readFn); const idx = _templates.findIndex((t) => t.id === templateId); if (idx === -1) return false; if (_templates[idx].builtin) return false; // 内置模板不可删 _templates.splice(idx, 1); _save(writeFn); return true; } function _resetForTest() { _templates = null; } module.exports = { listTemplates, getTemplate, createTemplate, updateTemplate, deleteTemplate, _resetForTest, };