180 lines
16 KiB
HTML
180 lines
16 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="theme-color" content="#0b1117" />
|
||
<title>燧安 · 火灾预防管理平台</title>
|
||
<link rel="stylesheet" href="./styles.css" />
|
||
</head>
|
||
<body>
|
||
<div class="platform-shell">
|
||
<aside class="sidebar" id="sidebar">
|
||
<div class="brand">
|
||
<div class="brand-mark" aria-hidden="true">燧</div>
|
||
<div>
|
||
<strong>燧安</strong>
|
||
<span>火灾预防管理平台</span>
|
||
</div>
|
||
</div>
|
||
<nav class="main-nav" aria-label="主导航">
|
||
<button class="nav-item is-active" type="button" data-view="overview"><span class="nav-icon">▦</span><span>系统总览</span></button>
|
||
<button class="nav-item" type="button" data-view="inspection"><span class="nav-icon">▶</span><span>视频巡检</span></button>
|
||
<button class="nav-item" type="button" data-view="events"><span class="nav-icon">!</span><span>告警中心</span><span class="nav-count" id="pendingNavCount">0</span></button>
|
||
<button class="nav-item" type="button" data-view="risks"><span class="nav-icon">◇</span><span>风险台账</span></button>
|
||
<button class="nav-item" type="button" data-view="channels"><span class="nav-icon">⌁</span><span>通知通道</span></button>
|
||
<button class="nav-item" type="button" data-view="settings"><span class="nav-icon">⚙</span><span>系统设置</span></button>
|
||
</nav>
|
||
<div class="sidebar-footer">
|
||
<div class="system-indicator"><span id="sidebarStatusDot" class="status-dot"></span><div><strong id="sidebarStatus">连接中</strong><span>智能视觉预警服务</span></div></div>
|
||
<span class="version">YOLO11S · v0.1.0</span>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="main-area">
|
||
<header class="topbar">
|
||
<div class="topbar-left">
|
||
<button id="menuButton" class="icon-button menu-button" type="button" aria-label="展开导航">☰</button>
|
||
<div>
|
||
<p class="breadcrumb">消防安全 / <span id="viewBreadcrumb">系统总览</span></p>
|
||
<h1 id="viewTitle">系统总览</h1>
|
||
</div>
|
||
</div>
|
||
<div class="topbar-actions">
|
||
<div class="clock-block"><span>当前时间</span><strong id="currentClock">--:--:--</strong></div>
|
||
<span id="globalStatus" class="status-chip status-checking">服务检查中</span>
|
||
<button class="icon-button" type="button" data-view-jump="events" aria-label="查看告警">♢<span id="notificationDot" class="notification-dot" hidden></span></button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="content-area">
|
||
<section class="view is-active" id="view-overview" data-view-panel="overview">
|
||
<div class="hero-strip">
|
||
<div>
|
||
<p class="section-kicker">FIRE PREVENTION COMMAND CENTER</p>
|
||
<h2>今日消防安全态势</h2>
|
||
<p id="overviewMessage">正在汇总模型、告警与通知通道状态。</p>
|
||
</div>
|
||
<button class="primary-button" type="button" data-view-jump="inspection">开始视频巡检</button>
|
||
</div>
|
||
|
||
<div class="stat-grid">
|
||
<article class="stat-card"><div class="stat-head"><span>今日告警</span><span class="stat-symbol warning">!</span></div><strong id="todayEventCount">0</strong><small>系统产生的有效告警事件</small></article>
|
||
<article class="stat-card"><div class="stat-head"><span>待处置事件</span><span class="stat-symbol danger">●</span></div><strong id="pendingEventCount">0</strong><small>需要值班人员确认处理</small></article>
|
||
<article class="stat-card"><div class="stat-head"><span>模型状态</span><span class="stat-symbol success">✓</span></div><strong id="modelStatusValue" class="text-value">检查中</strong><small id="modelStatusDetail">正在读取权重状态</small></article>
|
||
<article class="stat-card"><div class="stat-head"><span>通知通道</span><span class="stat-symbol info">⌁</span></div><strong id="channelCount">0</strong><small id="channelSummary">尚未启用机器人</small></article>
|
||
</div>
|
||
|
||
<div class="overview-grid">
|
||
<article class="panel trend-panel">
|
||
<div class="panel-header"><div><p class="section-kicker">ALERT TREND</p><h3>近期告警趋势</h3></div><div class="legend"><span><i class="legend-fire"></i>火焰</span><span><i class="legend-smoke"></i>烟雾</span></div></div>
|
||
<div id="trendChart" class="trend-chart" role="img" aria-label="近期火焰和烟雾告警趋势"></div>
|
||
</article>
|
||
<article class="panel readiness-panel">
|
||
<div class="panel-header"><div><p class="section-kicker">SYSTEM READINESS</p><h3>系统就绪度</h3></div></div>
|
||
<div class="readiness-list">
|
||
<div class="readiness-item"><span>模型权重</span><strong id="readyWeights">检查中</strong></div>
|
||
<div class="readiness-item"><span>检测服务</span><strong id="readyApi">检查中</strong></div>
|
||
<div class="readiness-item"><span>企业微信</span><strong id="readyWechat">未配置</strong></div>
|
||
<div class="readiness-item"><span>飞书机器人</span><strong id="readyFeishu">未配置</strong></div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<article class="panel recent-panel">
|
||
<div class="panel-header"><div><p class="section-kicker">RECENT EVENTS</p><h3>最近告警事件</h3></div><button class="text-button" type="button" data-view-jump="events">查看全部 →</button></div>
|
||
<div id="recentEventList" class="event-list empty-list"><p>暂无告警事件。开始视频巡检后,满足连续帧条件的告警会显示在这里。</p></div>
|
||
</article>
|
||
</section>
|
||
|
||
<section class="view" id="view-inspection" data-view-panel="inspection">
|
||
<div class="page-intro"><div><p class="section-kicker">VIDEO INSPECTION</p><h2>智能视频巡检</h2><p>选择本地监控视频,系统将按设定间隔抽帧并进行烟雾、火焰识别。</p></div><span id="inspectionStatus" class="status-chip status-idle">等待视频</span></div>
|
||
<div class="inspection-grid">
|
||
<article class="panel video-panel">
|
||
<div class="video-toolbar"><div><strong id="sourceLabel">未选择视频</strong><span id="videoMeta">支持 MP4、WebM 等浏览器可播放格式</span></div><span id="videoClock">00:00 / 00:00</span></div>
|
||
<div class="media-stage">
|
||
<video id="videoPreview" controls muted playsinline hidden></video>
|
||
<div id="emptyState" class="empty-state"><div class="upload-emblem">+</div><strong>导入监控视频</strong><span>视频在浏览器本地播放,仅将抽取帧发送至检测服务</span></div>
|
||
<canvas id="overlayCanvas" aria-hidden="true"></canvas>
|
||
<div id="loadingState" class="loading-state" hidden><span class="spinner"></span>正在分析视频帧</div>
|
||
</div>
|
||
<div class="video-actions">
|
||
<label class="file-button"><input id="videoInput" type="file" accept="video/*" /><span>选择视频</span></label>
|
||
<button id="runDetectionButton" class="primary-button" type="button" disabled>开始连续检测</button>
|
||
<button id="clearButton" class="secondary-button" type="button">清除</button>
|
||
</div>
|
||
</article>
|
||
|
||
<div class="inspection-side">
|
||
<article class="panel detection-summary">
|
||
<div class="panel-header"><div><p class="section-kicker">LIVE RESULT</p><h3>实时检测摘要</h3></div><span id="lastUpdated" class="micro-copy">尚未检测</span></div>
|
||
<div class="detection-metrics">
|
||
<div><span>烟雾目标</span><strong id="smokeCount">0</strong></div>
|
||
<div><span>火焰目标</span><strong id="fireCount">0</strong></div>
|
||
<div><span>最高置信度</span><strong id="maxConfidence">--</strong></div>
|
||
<div><span>风险等级</span><strong id="riskStatus">待机</strong></div>
|
||
</div>
|
||
<div id="alertStatus" class="alert-status">机器人告警状态:检查中</div>
|
||
<div id="detectionList" class="detection-list"><p class="empty-copy">暂无检测结果</p></div>
|
||
</article>
|
||
<article class="panel inspection-settings">
|
||
<div class="panel-header"><div><p class="section-kicker">STRATEGY</p><h3>巡检策略</h3></div></div>
|
||
<label class="field-row"><span>检测间隔</span><select id="intervalSelect"><option value="500">0.5 秒</option><option value="1000" selected>1 秒</option><option value="2000">2 秒</option></select></label>
|
||
<div class="strategy-row"><span>连续确认帧</span><strong id="confirmFramesValue">3 帧</strong></div>
|
||
<div class="strategy-row"><span>告警冷却</span><strong id="cooldownValue">60 秒</strong></div>
|
||
<div class="strategy-note">连续检测到目标后才会生成告警事件,并按火焰、烟雾分别执行冷却。</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="view" id="view-events" data-view-panel="events">
|
||
<div class="page-intro"><div><p class="section-kicker">ALERT CENTER</p><h2>告警事件管理</h2><p>集中查看、确认和关闭视频巡检产生的火灾风险事件。</p></div><button id="refreshEventsButton" class="secondary-button" type="button">刷新事件</button></div>
|
||
<div class="event-stat-row"><div><span>全部事件</span><strong id="allEventsCount">0</strong></div><div><span>待处置</span><strong id="pendingEventsCount">0</strong></div><div><span>已确认</span><strong id="ackEventsCount">0</strong></div><div><span>已解决</span><strong id="resolvedEventsCount">0</strong></div></div>
|
||
<article class="panel event-table-panel">
|
||
<div class="table-toolbar"><div class="filter-group" role="group" aria-label="事件状态筛选"><button type="button" class="filter-button is-active" data-event-filter="">全部</button><button type="button" class="filter-button" data-event-filter="pending">待处置</button><button type="button" class="filter-button" data-event-filter="acknowledged">已确认</button><button type="button" class="filter-button" data-event-filter="resolved">已解决</button></div><span id="eventTableMeta">0 条记录</span></div>
|
||
<div class="table-wrap"><table class="event-table"><thead><tr><th>事件编号</th><th>时间</th><th>类型</th><th>置信度</th><th>通知通道</th><th>状态</th><th>操作</th></tr></thead><tbody id="eventTableBody"><tr><td colspan="7" class="empty-cell">暂无告警事件</td></tr></tbody></table></div>
|
||
</article>
|
||
</section>
|
||
|
||
<section class="view" id="view-risks" data-view-panel="risks">
|
||
<div class="page-intro"><div><p class="section-kicker">RISK REGISTER</p><h2>风险台账</h2><p>从模型阈值、告警策略和处置状态评估当前风险治理情况。</p></div></div>
|
||
<div class="risk-grid">
|
||
<article class="panel risk-card"><span class="risk-level high">高风险</span><h3>未处置告警事件</h3><strong id="riskPendingValue">0</strong><p>待值班人员确认的火焰或烟雾事件。</p><button class="text-button" type="button" data-view-jump="events">进入告警中心 →</button></article>
|
||
<article class="panel risk-card"><span class="risk-level medium">策略风险</span><h3>告警通知覆盖</h3><strong id="riskChannelValue">0 / 2</strong><p>建议至少启用一个机器人通知通道。</p><button class="text-button" type="button" data-view-jump="channels">检查通知通道 →</button></article>
|
||
<article class="panel risk-card"><span class="risk-level low">模型策略</span><h3>检测置信度阈值</h3><strong id="riskConfidenceValue">--</strong><p>阈值过低会增加误报,过高可能遗漏早期烟雾。</p><button class="text-button" type="button" data-view-jump="settings">查看系统参数 →</button></article>
|
||
</div>
|
||
<article class="panel checklist-panel"><div class="panel-header"><div><p class="section-kicker">PREVENTION CHECKLIST</p><h3>火灾预防工作清单</h3></div></div><div class="checklist"><label><input type="checkbox" />视频监控覆盖重点区域</label><label><input type="checkbox" />告警机器人可正常接收消息</label><label><input type="checkbox" />值班人员明确事件处置流程</label><label><input type="checkbox" />模型权重与阈值定期复核</label><label><input type="checkbox" />消防通道和设备状态已巡查</label><label><input type="checkbox" />告警事件完成闭环记录</label></div></article>
|
||
</section>
|
||
|
||
<section class="view" id="view-channels" data-view-panel="channels">
|
||
<div class="page-intro"><div><p class="section-kicker">NOTIFICATION CHANNELS</p><h2>通知通道</h2><p>管理告警触达方式。敏感凭据保存在服务端本地环境文件中。</p></div></div>
|
||
<div class="channel-grid">
|
||
<article class="panel channel-card"><div class="channel-logo wechat-logo">微</div><div class="channel-content"><div><h3>企业微信群机器人</h3><span id="wechatChannelBadge" class="channel-badge">未配置</span></div><p>告警时发送 Markdown 消息与带检测框截图。</p><code>WECHAT_WEBHOOK_URL</code></div></article>
|
||
<article class="panel channel-card"><div class="channel-logo feishu-logo">飞</div><div class="channel-content"><div><h3>飞书自定义机器人</h3><span id="feishuChannelBadge" class="channel-badge">未配置</span></div><p>告警时发送红色交互卡片,支持签名校验。</p><code>FEISHU_WEBHOOK_URL / FEISHU_SECRET</code></div></article>
|
||
</div>
|
||
<article class="panel config-guide"><div class="panel-header"><div><p class="section-kicker">CONFIGURATION</p><h3>配置说明</h3></div></div><ol><li>在企业微信或飞书群中添加自定义机器人并复制 Webhook。</li><li>将 Webhook 填入项目根目录 <code>.env</code> 对应字段。</li><li>飞书开启签名校验时,同时填写 <code>FEISHU_SECRET</code>。</li><li>重启后端服务,平台将自动显示通道启用状态。</li></ol></article>
|
||
</section>
|
||
|
||
<section class="view" id="view-settings" data-view-panel="settings">
|
||
<div class="page-intro"><div><p class="section-kicker">SYSTEM SETTINGS</p><h2>系统设置</h2><p>查看当前生效的模型和告警参数。配置修改后需重启服务。</p></div></div>
|
||
<div class="settings-grid">
|
||
<article class="panel settings-card"><div class="panel-header"><div><p class="section-kicker">MODEL</p><h3>模型配置</h3></div></div><dl><div><dt>权重文件</dt><dd id="settingWeights">--</dd></div><div><dt>输入尺寸</dt><dd id="settingImageSize">--</dd></div><div><dt>置信度阈值</dt><dd id="settingConfidence">--</dd></div><div><dt>IOU 阈值</dt><dd id="settingIou">--</dd></div></dl></article>
|
||
<article class="panel settings-card"><div class="panel-header"><div><p class="section-kicker">ALERT POLICY</p><h3>告警策略</h3></div></div><dl><div><dt>连续确认</dt><dd id="settingConfirmFrames">--</dd></div><div><dt>分类冷却</dt><dd id="settingCooldown">--</dd></div><div><dt>事件存储</dt><dd>进程内最近 500 条</dd></div><div><dt>视频处理</dt><dd>浏览器本地抽帧</dd></div></dl></article>
|
||
</div>
|
||
<article class="panel env-panel"><div class="panel-header"><div><p class="section-kicker">ENVIRONMENT</p><h3>环境变量参考</h3></div></div><pre><code>YOLO_WEIGHTS=...
|
||
YOLO_DEVICE=0
|
||
YOLO_IMGSZ=768
|
||
YOLO_CONF=0.40
|
||
YOLO_IOU=0.45
|
||
ALERT_CONFIRM_FRAMES=3
|
||
ALERT_COOLDOWN_SECONDS=60</code></pre></article>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
<div id="toastRegion" class="toast-region" aria-live="polite"></div>
|
||
<script src="./app.js" type="module"></script>
|
||
</body>
|
||
</html>
|