docs(design): update Bell workflow
Harness governance / validate (push) Has been cancelled
Harness governance / validate (pull_request) Has been cancelled

This commit is contained in:
ila
2026-08-04 09:04:52 +08:00
parent 2715e557a9
commit 5251199205
+42 -145
View File
@@ -70,7 +70,7 @@
.site strong { display: block; font-size: 15px; }
.site span { color: var(--muted); font-size: 12px; }
.top-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.btn { min-height: 40px; border: 1px solid var(--line); border-radius: 9px; padding: 8px 13px; background: var(--surface-2); color: var(--text); display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-weight: 750; transition: .2s ease; }
.btn { min-height: 40px; border: 1px solid var(--line); border-radius: 9px; padding: 8px 13px; background: var(--surface-2); color: var(--text); display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-weight: 750; text-decoration: none; transition: .2s ease; }
.btn:hover { border-color: var(--primary); }
.btn:disabled { cursor: not-allowed; opacity: .5; }
.btn-primary { background: var(--primary-strong); border-color: var(--primary-strong); color: white; }
@@ -173,6 +173,14 @@
.rule-card p { margin: 0 0 14px; color: var(--muted); }
.rule-card dl { margin: 0; display: grid; grid-template-columns: 1fr auto; gap: 7px; color: var(--muted); }
.rule-card dd { margin: 0; color: var(--text); }
.rule-card-actions { margin-top: 14px; padding-top: 12px; display: flex; flex-wrap: wrap; gap: 7px; border-top: 1px solid var(--line); }
.rule-context { margin-bottom: 12px; padding: 11px 13px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border: 1px solid rgba(56,189,248,.34); border-radius: 10px; background: rgba(56,189,248,.08); }
.rule-context[hidden] { display: none; }
.rule-context p { margin: 0; color: var(--muted); }
.linked-zone { grid-column: 1/-1; padding: 11px; display: flex; align-items: center; justify-content: space-between; gap: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); }
.linked-zone strong, .linked-zone small { display: block; }
.linked-zone small { color: var(--muted); }
.workflow-note { grid-column: 1/-1; margin: 0; padding: 10px 11px; border-left: 3px solid var(--primary); background: var(--primary-soft); color: var(--muted); font-size: 12px; }
.chain-grid { grid-template-columns: minmax(0, 1.4fr) minmax(300px, .8fr); }
.chain-row { padding: 13px 14px; display: grid; grid-template-columns: 40px 1fr auto; gap: 11px; align-items: center; border-bottom: 1px solid var(--line); }
.chain-row:last-child { border-bottom: 0; }
@@ -199,6 +207,7 @@
.skeleton i:nth-child(2) { width: 72%; }
@keyframes shimmer { to { background-position: -200% 0; } }
dialog { width: min(610px, calc(100% - 28px)); max-height: 88dvh; padding: 0; border: 1px solid var(--line); border-radius: 16px; background: var(--surface); color: var(--text); box-shadow: 0 24px 80px rgba(0,0,0,.5); }
#ruleDialog { width: min(760px, calc(100% - 28px)); }
dialog::backdrop { background: rgba(4,7,15,.68); backdrop-filter: blur(4px); }
.dialog-head, .dialog-foot { padding: 14px 18px; border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.dialog-head h2 { margin: 0; font-size: 17px; }
@@ -221,150 +230,8 @@
.nav .count { position: absolute; margin: -24px 0 0 25px; }
.duty-grid { grid-template-columns: 285px minmax(390px, 1fr); }
.action-panel { grid-column: 1/-1; }
.action-scroll { max-height: none; display: grid; grid-template-columns: repeat(3, 1fr); }
.disposition { border-top: 0; border-left: 1px solid var(--line); }
}
@media (max-width: 850px) {
:root { --sidebar: 0px; }
.app { display: block; padding-bottom: 66px; }
.sidebar { display: none; }
.topbar { padding: 8px 12px; }
.site span, .top-actions .select { display: none; }
.content { padding: 12px; }
.duty-grid, .chain-grid, .chart-grid { grid-template-columns: 1fr; }
.alert-list, .action-scroll { max-height: none; }
.action-scroll { display: block; }
.disposition { border-left: 0; border-top: 1px solid var(--line); }
.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rule-grid { grid-template-columns: 1fr 1fr; }
.fact-grid { grid-template-columns: repeat(2, 1fr); }
.mobile-nav { position: fixed; z-index: 50; left: 8px; right: 8px; bottom: 8px; display: grid; grid-template-columns: repeat(5, 1fr); padding: 5px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); box-shadow: var(--shadow); }
.mobile-nav button { min-height: 48px; border: 0; border-radius: 9px; background: transparent; color: var(--muted); display: grid; place-items: center; font-size: 11px; }
.mobile-nav button.active { color: #c9c1ff; background: var(--primary-soft); }
}
@media (max-width: 560px) {
.page-head { display: grid; }
.stats, .rule-grid { grid-template-columns: 1fr; }
.form-grid { grid-template-columns: 1fr; }
.form-field.full { grid-column: auto; }
.video-stage { margin-inline: 8px; }
.fact-grid { margin-inline: 8px; }
.evidence-summary { display: grid; }
.disposition-actions { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; } }
</style>
</head>
<body>
<svg aria-hidden="true" width="0" height="0" style="position:absolute">
<symbol id="i-inbox" viewBox="0 0 24 24"><path d="M4 4h16v16H4Z"/><path d="m4 14 5-1 2 3h2l2-3 5 1"/></symbol>
<symbol id="i-event" viewBox="0 0 24 24"><path d="M6 3h12v18H6z"/><path d="M9 8h6m-6 4h6m-6 4h4"/></symbol>
<symbol id="i-rule" viewBox="0 0 24 24"><path d="M4 6h7m6 0h3M4 12h3m6 0h7M4 18h9m6 0h1"/><circle cx="14" cy="6" r="2"/><circle cx="10" cy="12" r="2"/><circle cx="16" cy="18" r="2"/></symbol>
<symbol id="i-phone" viewBox="0 0 24 24"><path d="M5 4h4l2 5-3 2a16 16 0 0 0 5 5l2-3 5 2v4c-8 2-17-7-15-15Z"/></symbol>
<symbol id="i-chart" viewBox="0 0 24 24"><path d="M4 20V9m6 11V4m6 16v-7m4 7H2"/></symbol>
<symbol id="i-shield" viewBox="0 0 24 24"><path d="m12 3 8 3v6c0 5-3 8-8 9-5-1-8-4-8-9V6Z"/><path d="m9 12 2 2 4-5"/></symbol>
<symbol id="i-search" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m20 20-4-4"/></symbol>
<symbol id="i-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></symbol>
<symbol id="i-bell" viewBox="0 0 24 24"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9"/><path d="M10 21h4"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="m5 12 4 4L19 6"/></symbol>
<symbol id="i-alert" viewBox="0 0 24 24"><path d="M12 3 2 20h20Z"/><path d="M12 9v4m0 3v.01"/></symbol>
<symbol id="i-play" viewBox="0 0 24 24"><path d="m8 5 11 7-11 7Z"/></symbol>
<symbol id="i-expand" viewBox="0 0 24 24"><path d="M8 3H3v5m13-5h5v5M8 21H3v-5m13 5h5v-5"/></symbol>
<symbol id="i-download" viewBox="0 0 24 24"><path d="M12 3v12m0 0 5-5m-5 5-5-5M4 20h16"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v6l4 2"/></symbol>
<symbol id="i-more" viewBox="0 0 24 24"><circle cx="5" cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/></symbol>
</svg>
<div class="prototype-banner">PROTOTYPE - 仅供枚举交互,非实现依据</div>
<div class="app">
<aside class="sidebar" aria-label="Bell 主导航">
<div class="brand"><div class="brand-mark">Y</div><div class="brand-copy"><strong>YoVision</strong><small>Bell · Duty Console</small></div></div>
<div class="nav-label">Operations</div>
<nav class="nav">
<button data-view="duty" aria-current="page"><svg class="icon"><use href="#i-inbox"/></svg><span>值班台</span><span class="count">6</span></button>
<button data-view="events"><svg class="icon"><use href="#i-event"/></svg><span>事件中心</span></button>
<button data-view="rules"><svg class="icon"><use href="#i-rule"/></svg><span>规则策略</span></button>
<button data-view="chains"><svg class="icon"><use href="#i-phone"/></svg><span>升级链</span></button>
<button data-view="reports"><svg class="icon"><use href="#i-chart"/></svg><span>运营报表</span></button>
<button data-view="audit"><svg class="icon"><use href="#i-shield"/></svg><span>审计日志</span></button>
</nav>
<div class="shift-card"><strong>安保值班组 · 白班</strong><span>08:00–20:00 · 4 人在线</span><div class="shift-bar"><i></i></div></div>
</aside>
<main class="main" id="main-content" tabindex="-1">
<header class="topbar">
<div class="site"><strong>青藤寄宿学校 · 值班中心</strong><span>客户侧私有实例 · 当前仅匿名安全规则</span></div>
<div class="top-actions">
<select class="select" id="stateSelect" aria-label="原型状态演示"><option value="normal">正常状态</option><option value="loading">加载中</option><option value="weak">弱网 / 证据失败</option><option value="empty">队列为空</option><option value="denied">无权限</option></select>
<button class="btn icon-btn" id="themeToggle" aria-label="切换明暗主题" title="切换明暗主题"><svg class="icon"><use href="#i-sun"/></svg></button>
<button class="btn icon-btn" aria-label="查看通知" title="查看通知"><svg class="icon"><use href="#i-bell"/></svg></button>
</div>
</header>
<div class="content">
<section class="state-layer" id="stateLayer" aria-live="polite"></section>
<section class="view active" data-page="duty">
<div class="page-head"><div><h1>实时值班台</h1><p>先确认高危预警,再查看证据与升级状态;重复投递不会生成重复处置。</p></div><div class="page-actions"><span class="badge success">值班组在线</span><button class="btn" id="muteButton">限时静默</button></div></div>
<div class="duty-grid">
<section class="card queue" aria-label="待处置预警队列">
<div class="card-head"><h2>待处置预警</h2><span class="badge danger">6 个未 ack</span></div>
<div class="queue-head"><div class="queue-tabs" role="tablist"><button class="active" role="tab" aria-selected="true">全部 9</button><button role="tab">高危 3</button><button role="tab">我的 2</button></div></div>
<div class="alert-list" id="alertList"></div>
</section>
<section class="card evidence" aria-label="事件事实与证据">
<div class="evidence-summary"><div><span class="badge danger" id="selectedSeverity">高危 · S1</span><h2 id="selectedTitle">危险区域闯入</h2><p id="selectedMeta">北围墙 01 · 23:14:08 · EVT-01J8…7A2</p></div><button class="btn icon-btn" aria-label="更多事件操作"><svg class="icon"><use href="#i-more"/></svg></button></div>
<div class="evidence-tabs" role="tablist"><button class="active" role="tab" aria-selected="true">视频片段</button><button role="tab">抓拍 2</button><button role="tab">结构化事实</button></div>
<div class="video-stage" id="videoStage">
<svg viewBox="0 0 960 540" role="img" aria-label="北围墙 01 事件视频模拟画面,匿名目标进入危险区域">
<defs><linearGradient id="bellSky" x1="0" y1="0" x2="0" y2="1"><stop stop-color="#102337"/><stop offset="1" stop-color="#060a11"/></linearGradient><pattern id="bellScan" width="8" height="8" patternUnits="userSpaceOnUse"><path d="M0 8h8" stroke="#fff" stroke-opacity=".035"/></pattern></defs>
<rect width="960" height="540" fill="url(#bellSky)"/><path d="M0 340 180 260 355 316 520 232 690 306 830 230 960 285V540H0Z" fill="#142638"/><rect y="414" width="960" height="126" fill="#111820"/><path d="M0 416h960M0 474h960" stroke="#6d8496" stroke-opacity=".48"/><path d="M150 305v235m250-240v240m280-255v255m170-280v280" stroke="#758b9d" stroke-width="4"/><polygon points="92,362 305,318 558,342 525,480 126,478" fill="#fb7185" fill-opacity=".15" stroke="#fb7185" stroke-width="4" stroke-dasharray="10 7"/><rect x="354" y="330" width="63" height="148" fill="none" stroke="#fbbf24" stroke-width="4"/><text x="354" y="319" fill="#ffe18a" font-size="17">person · 0.92</text><circle cx="385" cy="310" r="24" fill="none" stroke="#fbbf24" stroke-width="4"/><rect width="960" height="540" fill="url(#bellScan)"/><text x="26" y="38" fill="#d6e8f5" font-size="18">北围墙 01 · 事件片段</text><text x="26" y="66" fill="#91a6b8" font-size="14">事发前 8s · 事发后 12s · 匿名目标</text>
</svg>
<div class="video-controls"><button aria-label="播放片段"><svg class="icon"><use href="#i-play"/></svg></button><span class="mono">00:11 / 00:20</span><div class="timeline-bar"><i></i></div><button aria-label="全屏查看"><svg class="icon"><use href="#i-expand"/></svg></button><button aria-label="下载授权证据"><svg class="icon"><use href="#i-download"/></svg></button></div>
</div>
<div class="fact-grid">
<div class="fact"><span>规则</span><strong id="factRule">非授权人员进入</strong></div><div class="fact"><span>置信度</span><strong>0.92</strong></div><div class="fact"><span>持续时间</span><strong>8.4s</strong></div><div class="fact"><span>证据状态</span><strong style="color:var(--success)">已校验</strong></div>
</div>
<div class="privacy-note"><svg class="icon"><use href="#i-lock"/></svg><span>仅显示与本事件关联的 20 秒证据。常态录像仍在客户 NVR,本页不暴露流地址或摄像头凭据。</span></div>
</section>
<aside class="card action-panel" aria-label="预警确认与处置">
<div class="card-head"><h2>处置与升级</h2><span class="badge warning" id="ackState">等待 ack</span></div>
<div class="action-scroll">
<div class="ack-box"><button class="btn btn-primary" id="ackButton"><svg class="icon"><use href="#i-check"/></svg>确认接手</button><p id="ackHelp">一次点击确认;并发确认时会显示实际接手人,不覆盖对方结果。</p></div>
<div><div class="countdown"><svg class="icon" style="color:var(--warning);width:26px;height:26px"><use href="#i-clock"/></svg><div><strong id="countdown">01:42</strong><span>未 ack 将升级到校级负责人</span></div></div>
<div class="escalation"><h3>投递时间线</h3>
<div class="step done"><i class="step-dot"></i><strong>值班室 Web + 本地声光</strong><span>23:14:10 · 已送达</span></div>
<div class="step current"><i class="step-dot"></i><strong>值班员短信</strong><span>23:14:13 · 已送达,未确认</span></div>
<div class="step"><i class="step-dot"></i><strong>校级负责人语音</strong><span>预计 23:16:10 · 尚未发送</span></div>
</div>
</div>
<div class="disposition"><label for="outcome">处置结果</label><select class="select" id="outcome"><option value="">待选择</option><option>已现场核查,无人员受伤</option><option>已通知安保人员处理</option><option>已转交校方负责人</option></select><label for="note">处置备注</label><textarea class="textarea" id="note" placeholder="记录已采取的动作,不改写原始事件事实"></textarea><div class="disposition-actions"><button class="btn btn-danger" id="falsePositive">标记误报</button><button class="btn btn-success" id="completeAlert">完成处置</button></div></div>
</div>
</aside>
</div>
</section>
<section class="view" data-page="events">
<div class="page-head"><div><h1>事件中心</h1><p>事件是不可变事实;预警与处置结果作为关联记录单独展示。</p></div><div class="page-actions"><button class="btn"><svg class="icon"><use href="#i-download"/></svg>导出筛选结果</button></div></div>
<div class="grid stats">
<article class="card stat"><span>今日事件</span><strong>47</strong><span class="muted">较昨日 -8%</span></article><article class="card stat"><span>已触发预警</span><strong>18</strong><span class="muted">规则命中后独立创建</span></article><article class="card stat"><span>误报反馈</span><strong>5</strong><span class="muted">进入标注队列</span></article><article class="card stat"><span>证据可用率</span><strong>97.9%</strong><span class="muted">1 个片段可重试</span></article>
</div>
<article class="card"><div class="card-head"><div class="toolbar"><div class="search"><svg class="icon"><use href="#i-search"/></svg><input class="field" aria-label="搜索事件" placeholder="事件编号、点位或规则"></div><select class="select" aria-label="严重度筛选"><option>全部严重度</option><option>S1 高危</option><option>S2 重要</option></select><select class="select" aria-label="结果筛选"><option>全部结果</option><option>已处置</option><option>误报</option></select></div><span class="muted">共 47 条</span></div><div class="table-wrap"><table><thead><tr><th>事件编号</th><th>时间</th><th>点位</th><th>规则</th><th>事实</th><th>预警</th><th>结果</th><th>证据</th></tr></thead><tbody>
<tr><td class="mono">EVT-01J8…7A2</td><td>23:14:08</td><td>北围墙 01</td><td>非授权人员进入</td><td><span class="badge danger">已确认</span></td><td>Alert #1842</td><td>处置中</td><td><span class="badge success">可用</span></td></tr>
<tr><td class="mono">EVT-01J8…69P</td><td>22:48:31</td><td>宿舍东通道</td><td>区域聚集</td><td><span class="badge info">已记录</span></td><td>未触发</td><td>试运行样本</td><td><span class="badge success">可用</span></td></tr>
<tr><td class="mono">EVT-01J8…52C</td><td>22:19:04</td><td>实验楼入口</td><td>危险区域闯入</td><td><span class="badge danger">已确认</span></td><td>Alert #1839</td><td>误报</td><td><span class="badge warning">重试中</span></td></tr>
</tbody></table></div></article>
</section>
<section class="view" data-page="rules">
<div class="page-head"><div><h1>规则策略</h1><p>继承来源、试运行和正式发布清晰分开;空间区域在 Sense 编辑。</p></div><div class="page-actions"><button class="btn btn-primary">新建规则</button></div></div>
<div class="grid rule-grid">
<article class="card rule-card"><div class="rule-card-top"><span class="badge success">正式生效</span><button class="btn btn-quiet icon-btn" aria-label="更多操作"><svg class="icon"><use href="#i-more"/></svg></button></div><h2>非授权人员进入</h2><p>危险区域 × 全天 × 持续 3 秒</p><dl><dt>覆盖范围</dt><dd>4 个点位</dd><dt>继承来源</dt><dd>站点模板</dd><dt>今日命中</dt><dd>8</dd></dl></article>
<article class="card rule-card"><div class="rule-card-top"><span class="badge warning">试运行</span><button class="btn btn-quiet icon-btn" aria-label="更多操作"><svg class="icon"><use href="#i-more"/></svg></button></div><h2>区域内聚集</h2><p>人数 ≥ 6 × 持续 20 秒 × 夜间</p><dl><dt>覆盖范围</dt><dd>3 个点位</dd><dt>继承来源</dt><dd>设备覆盖</dd><dt>样本命中</dt><dd>14</dd></dl></article>
<article class="card rule-card"><div class="rule-card-top"><span class="badge violet">草稿</span><button class="btn btn-quiet icon-btn" aria-label="更多操作"><svg class="icon"><use href="#i-more"/></svg></button></div><h2>方向越线</h2><p>警戒线 A → B × 上学时段</p><dl><dt>覆盖范围</dt><dd>1 个点位</dd><dt>继承来源</dt><dd>设备草稿</dd><dt>最近修改</dt><dd>2h 前</dd></dl></article>
.action-scroll { max-height: none; display: grid; grid-template-columns: rep…4257 tokens truncated…t>覆盖范围</dt><dd>3 个点位</dd><dt>检测区域</dt><dd>3 个区域版本</dd><dt>继承来源</dt><dd>设备覆盖</dd><dt>样本命中</dt><dd>14</dd></dl><div class="rule-card-actions"><button class="btn" data-edit-rule>查看试运行</button><button class="btn btn-primary" id="publishTrialRule">正式发布</button></div></article>
<article class="card rule-card"><div class="rule-card-top"><span class="badge violet">草稿</span><button class="btn btn-quiet icon-btn" aria-label="更多操作"><svg class="icon"><use href="#i-more"/></svg></button></div><h2>方向越线</h2><p>警戒线 A → B × 上学时段</p><dl><dt>覆盖范围</dt><dd>1 个点位</dd><dt>检测区域</dt><dd>宿舍东通道 · 警戒线 v3</dd><dt>继承来源</dt><dd>设备草稿</dd><dt>最近修改</dt><dd>2h 前</dd></dl><div class="rule-card-actions"><button class="btn" data-edit-rule>继续编辑</button><a class="btn" href="../sense/index.html?view=device-detail&amp;camera=CAM-S2-011&amp;return=bell-rule">查看警戒线</a></div></article>
</div>
</section>
@@ -394,6 +261,18 @@
<nav class="mobile-nav" aria-label="移动端主导航"><button class="active" data-view="duty">值班</button><button data-view="events">事件</button><button data-view="rules">规则</button><button data-view="chains">升级</button><button data-view="reports">报表</button></nav>
<dialog id="ruleDialog" aria-labelledby="ruleTitle"><form method="dialog"><div class="dialog-head"><div><h2 id="ruleTitle">配置告警规则</h2><span class="muted">规则草稿 · 尚未正式生效</span></div><button class="btn btn-quiet icon-btn" value="cancel" aria-label="关闭对话框">×</button></div><div class="dialog-body"><div class="form-grid">
<div class="form-field"><label for="ruleScene">场景模板</label><select id="ruleScene" class="select"><option>非授权人员进入</option><option>区域内聚集</option><option>方向越线</option></select></div>
<div class="form-field"><label for="ruleScope">继承与覆盖</label><select id="ruleScope" class="select"><option>当前设备覆盖</option><option>继承站点模板</option><option>覆盖站点模板</option></select></div>
<div class="form-field"><label for="ruleCamera">摄像头</label><select id="ruleCamera" class="select"><option value="CAM-S2-001">北围墙 01</option><option value="CAM-S2-006">实验楼入口 02</option><option value="CAM-S2-011">宿舍东通道</option></select></div>
<div class="form-field"><label for="ruleZone">检测区域</label><select id="ruleZone" class="select"><option value="ZONE-007">北围墙危险区域 · v7</option><option>北围墙方向警戒线 · v3</option></select></div>
<div class="linked-zone"><span><strong>空间坐标由摄像头详情维护</strong><small>区域版本变化不会绕过规则试运行或自动正式发布。</small></span><a class="btn" id="editRuleZone" href="../sense/index.html?view=device-detail&amp;camera=CAM-S2-001&amp;return=bell-rule">编辑检测区域</a></div>
<div class="form-field"><label for="ruleSchedule">生效时段</label><select id="ruleSchedule" class="select"><option>全天</option><option>夜间 22:00–06:00</option><option>自定义课表</option></select></div>
<div class="form-field"><label for="ruleDuration">持续时间</label><select id="ruleDuration" class="select"><option>超过 3 秒</option><option>立即</option><option>超过 10 秒</option><option>超过 20 秒</option></select></div>
<div class="form-field full"><label><input id="startDryRun" type="checkbox" checked aria-label="保存后开始试运行"> 保存后开始试运行,不触发正式预警</label></div>
<p class="workflow-note">产品流程:先确认摄像头和检测区域,再配置业务条件;试运行样本达到现场评审要求后,才允许正式发布。</p>
</div></div><div class="dialog-foot"><button class="btn" value="cancel">取消</button><button class="btn btn-primary" id="saveRuleDraft" value="default">保存并开始试运行</button></div></form></dialog>
<dialog id="falseDialog" aria-labelledby="falseTitle"><form method="dialog"><div class="dialog-head"><h2 id="falseTitle">标记为误报</h2><button class="btn btn-quiet icon-btn" value="cancel" aria-label="关闭对话框">×</button></div><div class="dialog-body"><p>这只会追加事件 outcome,不会修改原始事件事实和证据。</p><div class="form-grid"><div class="form-field full"><label for="falseReason">误报原因</label><select id="falseReason" class="select" required><option value="">请选择</option><option>区域配置不准确</option><option>目标分类错误</option><option>时段策略不准确</option><option>其他</option></select></div><div class="form-field full"><label for="falseNote">补充说明(可选)</label><textarea id="falseNote" class="textarea" placeholder="便于算法团队归因,不填写真实个人信息"></textarea></div><div class="form-field full"><label><input type="checkbox" checked> 进入标注复核队列</label></div></div></div><div class="dialog-foot"><button class="btn" value="cancel">取消</button><button class="btn btn-danger" id="confirmFalse" value="default">确认标记</button></div></form></dialog>
<dialog id="muteDialog" aria-labelledby="muteTitle"><form method="dialog"><div class="dialog-head"><h2 id="muteTitle">创建限时静默</h2><button class="btn btn-quiet icon-btn" value="cancel" aria-label="关闭对话框">×</button></div><div class="dialog-body"><div class="form-grid"><div class="form-field"><label for="muteScope">影响范围</label><select id="muteScope" class="select"><option>北围墙 01 · 当前规则</option><option>北围墙区域</option></select></div><div class="form-field"><label for="muteTime">持续时间</label><select id="muteTime" class="select"><option>30 分钟</option><option>1 小时</option><option>2 小时</option><option>4 小时(上限)</option></select></div><div class="form-field full"><label for="muteCause">原因</label><textarea id="muteCause" class="textarea" required placeholder="例如:现场施工维护,已安排人工巡查"></textarea></div></div><p class="muted">到期自动恢复;S1 高危事件与设备离线运维告警不受此静默影响。</p></div><div class="dialog-foot"><button class="btn" value="cancel">取消</button><button class="btn btn-primary" id="confirmMute" value="default">确认并记录审计</button></div></form></dialog>
@@ -436,8 +315,26 @@
$('#muteButton').addEventListener('click',()=>$('#muteDialog').showModal());
$('#confirmMute').addEventListener('click',e=>{if(!$('#muteCause').value.trim()){e.preventDefault();notify('请填写静默原因。');$('#muteCause').focus();return;}notify('已创建限时静默,到期将自动恢复并通知值班组。');});
const ruleDialog = $('#ruleDialog');
function openRuleEditor() { ruleDialog.showModal(); }
$('#openRuleDialog').addEventListener('click', openRuleEditor);
$('#continueRuleDraft').addEventListener('click', openRuleEditor);
$$('[data-edit-rule]').forEach(button=>button.addEventListener('click', openRuleEditor));
$('#ruleCamera').addEventListener('change',e=>{ $('#editRuleZone').href=`../sense/index.html?view=device-detail&camera=${encodeURIComponent(e.target.value)}&return=bell-rule`; notify('已切换摄像头,请确认检测区域版本与画面仍匹配。'); });
$('#saveRuleDraft').addEventListener('click',()=>notify($('#startDryRun').checked?'规则草稿已保存并进入试运行,不会触发正式预警。':'规则草稿已保存,尚未开始试运行。'));
$('#publishTrialRule').addEventListener('click',()=>{if(confirm('正式发布后将影响 3 个点位并启动预警链。确认发布当前试运行版本?')){$('#trialBadge').className='badge success';$('#trialBadge').textContent='正式生效';notify('规则版本已正式发布,变更已记录审计并可回滚。');}});
let remain=102;
setInterval(()=>{if($('#ackState').textContent==='已 ack'||remain<=0)return;remain--;const m=String(Math.floor(remain/60)).padStart(2,'0'),s=String(remain%60).padStart(2,'0');$('#countdown').textContent=`${m}:${s}`;},1000);
const routeParams = new URLSearchParams(location.search);
if (routeParams.get('view')) switchView(routeParams.get('view'));
if (routeParams.has('camera')) {
switchView('rules'); $('#ruleContext').hidden=false;
const camera=routeParams.get('camera'); if([...$('#ruleCamera').options].some(option=>option.value===camera)) $('#ruleCamera').value=camera;
$('#editRuleZone').href=`../sense/index.html?view=device-detail&camera=${encodeURIComponent(camera)}&return=bell-rule`;
notify('已保留摄像头与检测区域上下文,可继续配置规则。');
}
</script>
</body>
</html>