diff --git a/apps/web/src/layouts/MainLayout.vue b/apps/web/src/layouts/MainLayout.vue index 57e68fc..c070691 100644 --- a/apps/web/src/layouts/MainLayout.vue +++ b/apps/web/src/layouts/MainLayout.vue @@ -99,7 +99,9 @@ import { WarningFilled, Bell, Fold, - Expand + Expand, + Connection, + SetUp } from '@element-plus/icons-vue' import { useAlertStore } from '@/stores/alertStore' import { connectAlertSocket, disconnectAlertSocket } from '@/services/mqtt.client' @@ -111,6 +113,8 @@ const alertStore = useAlertStore() const menuItems = [ { path: '/', title: '模型检测', icon: VideoCameraFilled }, + { path: '/cameras', title: '摄像头管理', icon: Connection }, + { path: '/rules', title: '规则配置', icon: SetUp }, { path: '/alerts', title: '预警列表', icon: WarningFilled } ] diff --git a/apps/web/src/router/index.js b/apps/web/src/router/index.js index 2f7d5d2..7b5e69d 100644 --- a/apps/web/src/router/index.js +++ b/apps/web/src/router/index.js @@ -1,6 +1,8 @@ import { createRouter, createWebHistory } from 'vue-router' import Home from '@/views/Home.vue' import AlertList from '@/views/AlertList.vue' +import CameraManagement from '@/views/CameraManagement.vue' +import RuleConfiguration from '@/views/RuleConfiguration.vue' import Layout from '@/layouts/MainLayout.vue' const routes = [ @@ -14,6 +16,18 @@ const routes = [ component: Home, meta: { title: '模型检测', icon: 'VideoCamera', keepAlive: true } }, + { + path: '/cameras', + name: 'CameraManagement', + component: CameraManagement, + meta: { title: '摄像头管理', icon: 'Connection', keepAlive: true } + }, + { + path: '/rules', + name: 'RuleConfiguration', + component: RuleConfiguration, + meta: { title: '规则配置', icon: 'SetUp', keepAlive: true } + }, { path: '/alerts', name: 'AlertList', @@ -29,4 +43,4 @@ const router = createRouter({ routes }) -export default router \ No newline at end of file +export default router diff --git a/apps/web/src/views/CameraManagement.vue b/apps/web/src/views/CameraManagement.vue new file mode 100644 index 0000000..ea77f2d --- /dev/null +++ b/apps/web/src/views/CameraManagement.vue @@ -0,0 +1,683 @@ + + + + + + + + + + {{ stat.label }} + {{ stat.value }} + + + + + + + + + + + + + + + + + + + + + + + + + + 刷新 + + + + 全部启动 + + + + 全部停止 + + + + 添加摄像头 + + + + + + + + + + + + + + + + {{ statusLabel(stream.status) }} + + {{ stream.stream_id }} + + + + + 启动 + + + + 停止 + + + + 配置 + + + + + + 移除 + + + + + + + {{ stream.rtsp_url }} + + + + + {{ stream.config?.model_id || '-' }} + + + + 置信度 {{ formatNumber(stream.config?.confidence) }} + + + + {{ stream.frame_count || 0 }} 帧 + + + + {{ formatLastFrame(stream.last_frame_at) }} + + + + {{ stream.error_message }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 = 每帧检测,N = 每 N+1 帧检测一次 + + + + + 取消 + + {{ editingStreamId ? '保存' : '添加' }} + + + + + + + + + diff --git a/apps/web/src/views/RuleConfiguration.vue b/apps/web/src/views/RuleConfiguration.vue new file mode 100644 index 0000000..26e040c --- /dev/null +++ b/apps/web/src/views/RuleConfiguration.vue @@ -0,0 +1,903 @@ + + + + + + + + LLM 二次判断 + + {{ llmStatus.enabled ? '已启用' : '未启用' }} + + + 熔断: {{ circuitLabel }} + + + + + + 刷新 + + + + 紧急停用 + + + + 重新启用 + + + + + + 重置统计 + + + + + + + + + Provider + {{ llmStatus.provider }} + {{ llmStatus.model || '-' }} + + + 融合策略 + {{ fusionLabel }} + + YOLO {{ formatRatio(llmStatus.fusion?.yolo_weight) }} / + LLM {{ formatRatio(llmStatus.fusion?.llm_weight) }} + + + + 触发阈值 + + {{ llmStatus.triggers?.min_consecutive_hits }} 连续帧 + + + avg≥{{ formatRatio(llmStatus.triggers?.min_avg_confidence) }} · + 冷却{{ llmStatus.triggers?.cooldown_seconds }}s + + + + 今日调用 + {{ todayCost?.call_count ?? 0 }} 次 + + 成功 {{ todayCost?.success_count ?? 0 }} / + 失败 {{ todayCost?.failure_count ?? 0 }} + + + + 今日费用 + ${{ formatCost(todayCost?.cost_usd) }} + + 预算 + {{ todayCost?.budget_usd ? `$${formatCost(todayCost.budget_usd)}` : '∞' }} + + + + + + + 最近错误率 + + {{ formatRatio(llmStatus.cost?.recent_error_rate) }} + + + 阈值 {{ formatRatio(llmStatus.cost?.error_rate_threshold) }} + + + + + + + 当前不会调用 LLM,原因:{{ llmStatus.cost.block_reason }} + + + + + + + + + + + + + + + + + + + 刷新 + + + + 热重载 + + + + 新增规则 + + + + + + + + + + + + + + + {{ severityLabel(rule.severity) }} + + {{ rule.name }} + + {{ eventTypeLabel(rule.event_type) }} + + handleToggle(rule, v)" + /> + + + + + 编辑 + + + + + + 删除 + + + + + + + {{ rule.description }} + + + + + min_conf ≥ {{ formatRatio(rule.min_confidence) }} + + + + min_area ≥ {{ rule.min_bbox_area || 0 }} + + + + 限定: {{ rule.allowed_sources.join(', ') }} + + + + 标签: {{ rule.required_labels.join(', ') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 单位:像素²,0 表示不限 + + + + + + + + + + + + + + + + + + 取消 + + {{ editingName ? '保存' : '创建' }} + + + + + + + + +