feat: 营养边缘服务原型迭代 + 西安应急大屏 v2/v3 双版本
- 营养边缘服务:新增《缓存中转服务器产品需求说明书》及导航入口;重构数据下发详情页(抽屉式接收轨迹+终端应用明细弹窗);告警中心/下发管理/上报管理/服务器管理/服务器详情统一补齐分页与列调整 - 西安应急大屏:新增 v2 版本(路径规划+统计胶囊悬浮化+图层位置调整)与 v3 版本(顶部 KPI 条+24h 趋势折线+横向条形图+环形组合图等图表化重构),全部纯内联 SVG;同步更新 CHANGELOG Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
65372009fe
commit
23205ddd1b
@@ -893,6 +893,11 @@ const PROJECT_DOCS = [
|
||||
title: '缓存中转服务器功能架构与数据流转方案',
|
||||
file: 'web-admin/nutrition/doc/缓存中转服务器功能架构与数据流转方案.md',
|
||||
desc: '营养管理服务云端主服务与食堂边缘节点服务的架构、数据流转和接口方案。'
|
||||
},
|
||||
{
|
||||
title: '缓存中转服务器产品需求说明书',
|
||||
file: 'web-admin/nutrition/doc/缓存中转服务器产品需求说明书.md',
|
||||
desc: '缓存中转服务器的业务目标、功能范围、页面与交互需求说明。'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,5 +1,65 @@
|
||||
# 应急大屏 - 变更记录
|
||||
|
||||
## [2026-06-25] feat: 西安应急中心大屏 v3 - 图表化重构 + 顶部 KPI 条 + 双栏可视化升级
|
||||
|
||||
### 新增(v3 文件 `xian-center/index-v3.html`,v1/v2 保持不变)
|
||||
- **顶部 KPI 条**:标题栏下方新增 5 个全局指标卡片(在线监测设备 1,286 台 / 今日告警 109 次 / 待处理 7 件 / 已处理 102 件 / 平均响应时长 4.2 分钟),每张卡片含图标、数值、标签、右上角趋势箭头(↑↓)
|
||||
- **穿戴告警 24h 趋势折线图**:纯内联 SVG 绘制,3 条折线(心率/压力/血氧异常)按 0-23 小时分布,含网格虚线与 X 轴时间标签、底部图例
|
||||
- **应急重点人员 TOP5 横向条形图**:替代原列表,TOP1/TOP2/TOP3 用红/黄/蓝三色高亮,其余统一蓝色,右端白色竖线 + 阴影
|
||||
- **图表 CSS 模块**:`.kpi-bar` / `.alarm-combo` / `.trend-chart` / `.service-combo` / `.bar-rank` / `.ai-risk-rings` 等组件样式
|
||||
|
||||
### 变更
|
||||
- **左栏重构**(4 个面板,重新分配高度 152+148+237+232):
|
||||
- 「穿戴告警分布」升级为**柱状+玫瑰环形组合图**:左侧保留 6 类横向柱状图(标签精简为 2-3 字),右侧新增 6 段占比环形图(按数值占比分段,中央显示告警总数 109)
|
||||
- 「告警 24h 趋势」面板(见上)
|
||||
- 「穿戴告警事件」**保留**滚动列表 + 点击触发急救路线交互,高度调整为 flex:1 自适应
|
||||
- 「心脑血管预警(AI)」**保留**列表 + 点击触发急救提示书交互;摘要数字升级为 3 个**迷你环形图**(高危 3 / 中危 5 / 低危 12,按占比绘制弧长)
|
||||
- **右栏重构**(3 个面板,重新分配高度 158+467+156):
|
||||
- 「应急服务数据」升级为**中央环形+类型列表组合图**:左侧环形图(中央累计受理 3,562 + 三类服务按 22.96%/65.31%/11.73% 占比分段),右侧 3 项明细列表(视频 45 / 电话 128 / 120 拨打 23,含占比百分比)
|
||||
- 「应急求助事件」**保留**滚动列表 + 点击触发急救路线交互
|
||||
- 「应急重点人员 TOP5」改用横向条形图(见上)
|
||||
- **布局调整**:`.main` 高度由 `calc(100vh - 64px)` 改为 `calc(100vh - 64px - 64px)`(为顶部 KPI 条让出 64px);`.side` 宽度由 320px 改为 340px
|
||||
- **响应式**:`@media(max-width:1440px)` 同步调整 `.side` 宽度为 280px、KPI 数字字号降为 16px
|
||||
|
||||
### 保留(不动)
|
||||
- 中间地图整体(资源 Tab / 路径规划 / 急救路线 / 资源面板 / 急救提示书 / 图层切换 / 接听状态 / 资源统计胶囊)
|
||||
- 3 类告警弹窗(穿戴告警 / 应急求助 / 心脑血管预警)及其触发按钮
|
||||
- 3 类记录列表弹窗(穿戴告警 / 心脑血管预警 / 应急求助 记录)及「查看更多」「历史记录」入口
|
||||
- 所有 v2 既有 JS 交互函数
|
||||
|
||||
### 技术约束
|
||||
- 全部图表使用**纯内联 SVG** 绘制(stroke-dasharray 控制环形占比、polyline 绘制折线),不引入任何外部图表库
|
||||
- 严格遵守墨刀导入兼容约束(无外部引用、内联 SVG、简洁 DOM)
|
||||
|
||||
## [2026-06-25] feat: 西安应急中心大屏 - 路径规划 + 统计胶囊悬浮化 + 图层位置调整
|
||||
|
||||
### 新增
|
||||
- **路径规划功能**:地图上方 Tab 栏在 AED 之后追加「路径规划」Tab,点击后在 Tab 栏下方展开规划面板
|
||||
- 起点下拉(12 个备选点:当前位置/3 医疗点/4 医院/2 救护车/2 AED)
|
||||
- 终点下拉(同上,默认选中采油三厂医疗点)
|
||||
- 「路径规划」按钮:在地图上绘制带动画的青色虚线弧形路径,并标注起/终点圆点
|
||||
- 「清除」按钮:清除已绘制路径
|
||||
- 规划完成后右上角显示路线信息卡片(总距离、预计用时,按 viewBox 距离 Mock 换算)
|
||||
- **独立 SVG 层** `.plan-route-svg`:与急救路线 `.route-svg` 完全解耦,互不影响
|
||||
- **JS**:`PLAN_POINTS` 坐标映射 + `toggleRoutePlan()` / `executeRoutePlan()` / `clearRoutePlan()`;`switchTab()` 末尾联动关闭规划面板并清除路径
|
||||
|
||||
### 变更
|
||||
- **统计卡片悬浮化**:`.res-stat-row` 从 `.center` 末尾移入 `.map-wrap` 内部,改为绝对定位悬浮胶囊
|
||||
- 位置:地图底部居中、`bottom:24px`,与底部边缘留有间距,不再贴合
|
||||
- 样式:玻璃质感胶囊容器(圆角 24px + 模糊背景 + 阴影 + 装饰角),内部三张小卡片(图标 28px + 数字 18px + 标签 10px),卡片间以竖线分隔
|
||||
- **图层切换移位**:`.map-layer` 由原来右下角(`bottom:12px;right:178px`)移至地图右上角(`top:12px;right:12px`),与顶部居中的 `.res-tabs` 不冲突
|
||||
|
||||
## [2026-06-25] refactor: 西安应急中心大屏 - 中间区域统计卡片改造
|
||||
|
||||
### 变更
|
||||
- **移除**:中间地图区域顶部的 KPI 核心指标卡片行(穿戴设备总数/今日穿戴报警数/今日应急求助数/平均响应时长)及其对应 `.kpi-row/.kpi-card*` CSS
|
||||
- **新增**:地图下方资源统计卡片行 `.res-stat-row`,默认隐藏,点击地图上方医疗点/救护车/AED Tab 时切换显示对应三组统计卡片
|
||||
- 医疗点:医疗点总数(3)/ 覆盖人数(2,860)/ 医护人员(28)
|
||||
- 救护车:急救型救护车(5)/ 转运型救护车(3)/ 出勤次数(128)
|
||||
- AED:在线设备(18)/ 离线设备(2)/ 使用次数(36)
|
||||
- **新增**:`RES_STAT_CONFIG` 数据映射 + `updateResStatRow(type)` 函数,由 `switchTab()` 调用同步刷新卡片内容
|
||||
- **样式**:复用深色玻璃质感卡片风格,含图标、数值、标签、装饰角;图标颜色按主题色(青/绿/橙/红)区分
|
||||
|
||||
## [2026-06-23] feat: 新增西安应急中心大屏原型
|
||||
|
||||
### 新增
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
||||
# 缓存中转服务器产品需求说明书
|
||||
|
||||
> 版本:v0.1 产品交付
|
||||
> 日期:2026-06-24
|
||||
> 范围:营养管理云端主服务、食堂边缘服务器、现场终端设备
|
||||
> 参考:`缓存中转服务器功能架构与数据流转方案.md`、`营养管理功能说明.md`、营养管理后台原型 `web-admin/nutrition`
|
||||
|
||||
## 1. 需求概述
|
||||
|
||||
缓存中转服务器是部署在食堂现场的边缘服务节点,用于承接营养管理后台在食堂现场的设备接入、业务缓存、任务下发、数据上报、断网续用和异常补偿能力。
|
||||
|
||||
本需求文档面向研发交付,此文档中将重点说明:
|
||||
|
||||
1. 边缘服务器需要支撑哪些营养管理后台业务场景。
|
||||
2. 每个业务场景中哪些数据由云端服务器下发,哪些数据由边缘服务器上报。
|
||||
3. 云端下发以及边缘服务器数据上报的触发规则、频率、版本控制和失败补偿要求。
|
||||
4. 边缘服务器数据流转服务能力与云端管理端可见功能的边界。
|
||||
|
||||
## 2. 产品目标
|
||||
|
||||
| 目标 | 说明 |
|
||||
|---|---|
|
||||
| 现场业务不中断 | 云端网络异常时,食堂现场终端仍可查询已缓存资料和任务,并继续记录现场业务数据 |
|
||||
| 数据不丢失 | 现场终端产生的数据先写入边缘服务器,本地保存成功后再异步同步云端 |
|
||||
| 下发可追踪 | 云端下发的基础资料、任务、配置、文件、升级包需要有接收状态、应用状态、失败原因 |
|
||||
| 补传可恢复 | 网络恢复后,边缘服务器可按业务发生时间顺序补传未同步数据 |
|
||||
| 异常可处置 | 云端管理端能查看节点、设备、上报、下发、文件、任务等异常,并提供重试、补发、忽略、人工处理入口 |
|
||||
|
||||
## 3. 角色与职责
|
||||
|
||||
| 角色 | 职责 |
|
||||
|---|------------------------------------------------------|
|
||||
| 云端系统管理员 | 管理食堂、人员、设备、字典、菜品、任务、规则、升级包,查看边缘节点运行状态 |
|
||||
| 食堂运营人员 | 制定食谱、餐品、营养标准、生产计划、食堂开餐、取餐、上餐、余量、终端状态和异常处置,查看生产任务执行结果 |
|
||||
| 供应链人员 | 管理种采、采购、入库、检测、仓储、净菜加工、配送等现场业务 |
|
||||
| 运维人员 | 负责边缘服务器部署、网络、磁盘、服务、设备接入、升级和故障恢复 |
|
||||
| 现场终端设备 | 通过边缘服务器获取任务和资料,执行称重、识别、结算、取餐、上餐、打印、日志上报 |
|
||||
|
||||
## 4. 总体职责边界
|
||||
|
||||
| 层级 | 职责定位 | 负责内容 | 不负责内容 |
|
||||
|--------|---|-----------------------------------------|---|
|
||||
| 云端主服务 | 全局权威中心 | 主数据维护、任务生成、策略配置、跨食堂统计、异常监管、最终数据归档落库 | 直接访问食堂内网设备、依赖实时网络完成现场作业 |
|
||||
| 边缘服务器 | 食堂现场业务连续性保障节点 | 本地缓存、终端接入、本地写入、上行补传、下行应用、文件缓存、设备状态、异常告警 | 全局主数据最终编辑、跨食堂审批、长期历史分析、大模型推理 |
|
||||
| 现场终端设备 | 业务执行和采集终端 | 称重、菜品识别、取餐、入库、食材加工、结算、组配、烹制、上餐、打印、日志采集 | 全局业务规则判断、跨食堂数据查询、云端统计分析 |
|
||||
|
||||
## 5. 功能清单
|
||||
|
||||
本章按能力类型划分,而不是按后台全部菜单机械展开。边缘服务器只承载需要现场硬件、现场终端、弱网连续作业、本地采集或本地任务执行的业务;纯后台维护、统计分析、模型配置、报表查询类功能不下沉到边缘节点。
|
||||
|
||||
### 5.1 云端后台运维监控功能 [详见原型界面]
|
||||
|
||||
| 分类 | 功能 | 说明 |
|
||||
|---|---|---|
|
||||
| 边缘服务器管理 | 节点列表 | 按食堂查看边缘服务器名称、编号、在线状态、健康状态、版本、最近心跳、所属位置 |
|
||||
| 边缘服务器管理 | 节点详情 | 查看基础信息、资源状态、运行检查项、设备清单、上报记录、下发记录、告警记录、运行日志 |
|
||||
| 边缘服务器管理 | 资源监控 | 展示 CPU、内存、磁盘、网络、服务进程、文件缓存容量、同步积压量 |
|
||||
| 数据上报管理 | 上报日志 | 查看边缘服务器上报数据类型、业务编号、来源设备、产生时间、最近上报时间、上报状态 |
|
||||
| 数据上报管理 | 失败处理 | 支持查看失败原因、重试次数、中心受理状态、关联告警,并可发起手动重试 |
|
||||
| 数据下发管理 | 下发任务 | 支持基础资料、人脸增量、生产任务、配置同步、升级任务等下发任务的创建、查询、导出 |
|
||||
| 数据下发管理 | 下发详情 | 查看目标边缘服务器接收状态、终端应用状态、失败原因、任务轨迹,支持补发和强制重试 |
|
||||
| 异常告警中心 | 告警聚合 | 聚合服务器异常、设备异常、上报失败、下发失败、文件失败、同步积压等告警 |
|
||||
| 异常告警中心 | 告警处置 | 支持按等级、状态、食堂、服务器、影响对象筛选,支持标记处理中、忽略、查看关联记录 |
|
||||
| 运维策略配置 | 策略参数 | 配置心跳周期、重试次数、死信阈值、磁盘阈值、文件保留周期、告警等级规则 |
|
||||
|
||||
### 5.2 边缘服务器基础能力清单
|
||||
|
||||
| 能力域 | 功能要求 | 关键状态 |
|
||||
|-----------|--------------------------------------------------------------------------|--------------------|
|
||||
| 终端设备接入 | 负责现场所有终端设置的接入(注册、认证、心跳、数据交互、时间同步、设备绑定查询),理论上所有的终端设备只需和边缘服务器节点互通不和云端服务器直连 | 未注册、已注册、在线、离线、异常 |
|
||||
| 本地业务API服务 | 为终端设备提供基础资料查询、任务领取、业务数据上报、文件下载、日志上传接口 | 正常、限流、不可用 |
|
||||
| 本地缓存库 | 按食堂隔离保存所有业务主数据、任务、流水、文件索引、同步控制数据 | 有效、过期、待清理 |
|
||||
| 下行 Inbox | 接收云端下发消息,完成幂等校验、版本校验、签名校验、应用入库 | 待处理、处理中、已应用、失败、已忽略 |
|
||||
| 上行 Outbox | 保存现场业务事件,按业务发生时间或特定频率上传云端 | 待同步、同步中、已同步、失败、死信 |
|
||||
| 文件缓存 | 缓存升级包、人脸图片、过程图片、视频索引、日志文件 | 待下载、已缓存、校验失败、过期 |
|
||||
| 任务状态引擎 | 管理现场任务领取、开始、完成、异常、取消、补录 | 待执行、执行中、已完成、异常、已取消 |
|
||||
| 断网续用 | 云边断连时允许终端继续查询已缓存数据并写入现场数据 | 在线、弱网、断网、恢复中 |
|
||||
| 冲突处理 | 处理旧版本下发、重复上报、任务变更、断网补传冲突 | 已处理、需人工、已忽略 |
|
||||
| 健康监控 | 采集节点资源、服务状态、设备状态、同步积压 | 正常、告警、严重 |
|
||||
| 告警生成 | 根据规则生成本地告警并上报云端 | 待处理、处理中、已恢复、已忽略 |
|
||||
| 心跳机制 | 边缘服务器需要长期与云端服务器维持心跳机制保持连接活性检测连接问题,与终端设置保持心跳机制确定设备在线状态 | 在线、故障、离线 |
|
||||
|
||||
### 5.3 业务支持功能清单
|
||||
|
||||
业务支持功能只覆盖需要现场硬件、现场终端、本地任务执行、本地采集或弱网连续作业的后台二级菜单。云端只把现场执行所需的资料、任务、规则、配置或文件下发到边缘服务器,边缘服务器只上报现场产生的业务流水、设备状态、执行结果和异常事件。
|
||||
|
||||
| 功能菜单 | 云端下发数据 | 下发规则说明 | 边缘数据上报 | 上报规则说明 |
|
||||
|-----------|----------------------------------|-------------------------------------------------------------------------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 食物成分 | 食材编码、食物成分项、营养素含量、单位换算、适用状态、净菜类型等 | 1. 食物成分信息调整后实时增量下发。<br>2. 新部署边缘节点执行全量初始化下发。 | 暂无 | 暂无 |
|
||||
| 餐品总库 | 餐品编码、餐品名称、餐品组成、食材用量、营养指标、餐品规格等 | 1. 餐品发布、调整、停用后实时增量下发。<br>2. 新部署边缘节点执行全量初始化下发。 | 菜品研发(味养创新) | 1.新研发菜品数据实时增量上报; |
|
||||
| 用户管理 | 用户、部门、权限、人脸特征、人员状态、会员标识 | 1. 人员、人脸、会员等级、权限变更后实时增量下发。<br>2. 每日低峰执行一次全量一致性校验。<br>3. 人员停用或权限回收需立即下发。 | 新用户注册、人脸录入、会员充值等 | 1. 有新用户注册、人脸录入时实时增量上传。<br>2.会员充值操作必须以云端响应状态为准,边缘服务器节点不能私自改变充值状态,弱网、断网、服务器连接异常的情况下不允许充值操作或标记为充值失败。 |
|
||||
| 取餐管理 | 暂无 | 暂无 | 取餐记录、取餐核销、结算信息、用餐明细等 | 1. 取餐结算完成后立即写入边缘节点本地库。<br>2. 就餐数据3分钟一次定时增量上传。<br>3. 重复核销、异常核销需优先上报并生成告警。<br>4. 如若使用本系统的支付结算必须以云端响应状态为准,边缘服务器节点不能私自改变结算状态,弱网、断网、服务器连接异常的情况下不允许结算操作或标记为结算失败。<br>5. 支付和退款结果按交易唯一键幂等上报。 |
|
||||
| 终端管理 | 设备档案、绑定关系、业务配置、升级任务、升级包元数据 | 1. 设备绑定和业务配置变更后实时下发。<br>2. 新部署边缘节点执行按食堂全量初始化下发。 | 设备状态、运行日志、升级结果、设备异常 | 1. 设备状态每30分钟周期上报。<br>2. 设备异常、升级失败、配置应用失败需立即上报。<br>3. 异常日志优先上报。 |
|
||||
| 供商管理 | 内部供应商、外部供应商、供应商资质 | 1. 供应商信息发生变更后实时增量下发。<br>2. 升级任务按运维指定时间窗下发。<br>3. 供应商资质变更后实时增量下发。 | 暂无 | 暂无 |
|
||||
| 采供管理 | 采购单信息、采购单明细 | 1. 产生新的采购单后实时增量下发。<br>2. 采购单状态变更后实时下发(如取消,接单,发货等)。 | 设备新增采购单 | 1. 毛菜入库的无订单验收需要同步新建采购单,新建后实时上报至云端服务。 |
|
||||
| 仓储管理 | 仓库档案、区域信息 | 1. 仓库信息和区域信息变更后实时下发。<br>2. 新部署边缘节点执行按食堂全量初始化下发。 | 暂无 | 暂无 |
|
||||
| 毛菜入库 | 入库单、采购单、供应商、食材档案 | 1. 采购单、供应商、食材档案等信息已在其他模块中明确了下发规则。 | 称重记录、入库批次、质检状态、现场照片、操作员、设备编号 | 1. 验收称重完成后实时增量上报。<br>2. 入库批次、称重记录、质检状态按同一业务唯一键上报。 |
|
||||
| 净菜加工 | 加工任务、净菜类型、加工规格 | 1. 加工任务生成后实时下发。<br>2. 净菜类型已在食物成分模块明确下发规则。 | 毛菜加工、净菜加工、毛重、净重、出净率 | 1. 从毛菜加工开始、称重、完成节点分别写入边缘节点本地库。<br>2. 加工完成后汇总毛重、净重、出净率和损耗实时上报至云端服务。<br>3. 过程图片或者视频按文件队列异步补传。 |
|
||||
| 净菜入库 | 人工录入的入库信息、入库信息在后台被修改 | 1.后台人工录入的净菜入库信息需要实时下发至边缘节点服务器。<br>2. 入库信息在后台被手动编辑、删除、出库等信息需实时下发。 | 入库记录、库位绑定、入库重量 | 1. 入库完成后实时增量上报。 |
|
||||
| 净菜包装 | 包装任务、包装规格、溯源码规则 | 1. 包装任务生成后实时下发。。<br>2. 包装任务变更后增量下发。 | 包装批次、包装重量、组配信息、设备信息 | 1. 包装、称重、打标节点单菜品包装完成先记录与边缘服务器本地库。<br>2. 整个订单包装完成后实时上报云端。 |
|
||||
| 净菜内供、净菜外售 | 内供订单、外售订单 | 1. 内供或内功订单产生后实时下发。<br>2. 配送计划变更后实时补发。<br>3. 订单状态变更后实时下发(如取消订单)。 | 暂无 | 暂无 |
|
||||
| 净菜进柜 | 暂无 | 暂不考虑后台手动添加的进柜记录同步至边缘节点,理论上进柜记录都是从设备端主动发起 | 进柜记录、格口占用、取放记录、柜体异常、重量变更 | 1. 进柜、取出等操作实时上报。<br>2. 格口占用变化需实时上报。。 |
|
||||
| 净菜组配 | 组配任务、餐品规格、份数、食材明细、标准用量、差异阈值 | 1. 组配任务发布后实时下发。<br>2. 餐品规格和标准用量按餐品版本下发(餐品总库)。 | 任务状态、称重明细、实际用量、设备编号、操作员、完成状态 | 1. 任务完成后汇总称重明细和完成状态上报。 |
|
||||
| 按单烹制 | 烹制任务、餐品、需求份数、食材明细、工艺要求、温度阈值 | 1. 烹制任务发布后实时下发。<br>2. 任务调整后实时补发到后厨终端。<br>3. 工艺要求和温度阈值按版本发布后下发(餐品总库)。 | 开始/完成、厨师、生重、熟重、生熟比、温度过程、质量结果 | 1. 边缘节点服务器实时记录烹制过程,烹制完成后一次性实时上报至云端服务器。 |
|
||||
| 食谱管理 | 当周食谱数据、餐品数据、食谱状态 | 1. 后台周食谱生成后实时下发。<br>2. 食谱调整后实时下发。 | 暂无 | 暂无 |
|
||||
| 上餐监控 | 暂无 | 暂无(食谱、餐品、设备数据均已在其他模块下发) | 上餐时间、出锅温度、上餐重量、补餐记录、余量记录 | 1. 开餐信息实时上报。<br>2.补餐、余量监控等信息可3分钟周期性上报。 |
|
||||
| 餐线管理 | 餐线档案、档口信息、餐线终端绑定、餐线状态规则 | 1.新增餐线或档案变更后实时下发。<br>2. 新部署边缘节点执行按食堂全量初始化下发; | 餐线状态、档口终端状态、餐线异常、终端应用回执 | 1. 餐线状态、监测信息按3分钟周期上报。<br>2. 档口终端离线或餐线异常需立即上报。 |
|
||||
| 营养点餐 | 点餐订单、餐品信息、餐品价格、营养指标、点餐规则 | 1. 点餐订单创建或变更后实时下发。 | 暂无 | 暂无 |
|
||||
| 余量处置 | 暂无 | 暂无 | 余量重量、处置方式、领取明细、捐赠记录、废弃记录 | 1. 称重、领取、捐赠、废弃节点分别写入边缘。<br>2. 员工福利领取需按人员和批次做幂等上报。<br>3. 废弃记录和异常处置需优先上报。 |
|
||||
| 食安监控 | 留样规则、证件规则、能耗阈值、摄像头档案、水电气设备 | 1. 预警规则变更、设备档案信息变更、人员证件信息变更后实时下发。<br>2. 新部署边缘节点执行按食堂全量初始化下发; | 留样记录、巡检记录、证件状态、能耗数据、视频索引、设备数据 | 1. 留样、巡检、证件检查完成后立即上报业务结果。<br>2. 能耗数据按配置30分钟一次周期上报,越界数据立即上报。<br>3. 视频只上报索引和关键事件,原文件按存储策略处理。 |
|
||||
|
||||
|
||||
## 6. 核心同步规则
|
||||
|
||||
### 6.1 云端下发规则
|
||||
|
||||
1. 基础主数据以云端为权威来源,边缘服务器只缓存和应用,不作为最终编辑源。
|
||||
2. 所有下发数据必须包含业务类型、业务编号、版本号、更新时间、食堂范围、幂等键。
|
||||
3. 边缘服务器收到旧版本数据时不得覆盖本地较新版本,应记录为已忽略。
|
||||
4. 支持全量初始化、实时增量下发、指定范围补发、定时校验四种方式。
|
||||
5. 文件类数据下发时只传元数据,文件由边缘服务器通过 HTTP 或对象存储地址下载。
|
||||
6. 所有的数据下发记录都要做到有迹可循,下发失败需追溯到失败原因。
|
||||
|
||||
### 6.2 边缘上报规则
|
||||
|
||||
1. 现场终端产生的业务数据必须先写入边缘服务器本地再上传至云端服务器。
|
||||
2. 边缘服务器本地写入成功后,终端设备即可得到成功反馈。
|
||||
3. 上行同步失败不得阻塞现场作业。
|
||||
4. 上行数据必须具备业务唯一键,云端按唯一键做幂等入库。
|
||||
5. 网络恢复后,边缘服务器按业务发生时间顺序补传。
|
||||
6. 多次失败后进入死信队列,并在云端异常告警中心生成待处理告警。
|
||||
7. 所有的上传记录都要做到有迹可循,上报失败需追溯到失败原因。
|
||||
|
||||
## 7. 业务流程
|
||||
|
||||
### 7.1 云端下发到边缘服务器
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 云端管理端/业务服务
|
||||
participant Sync as 云端同步编排
|
||||
participant Edge as 边缘服务器
|
||||
participant Device as 现场终端
|
||||
|
||||
Admin->>Sync: 发布资料/任务/配置/文件元数据
|
||||
Sync->>Edge: 推送下发消息
|
||||
Edge->>Edge: 校验签名、版本、幂等键
|
||||
Edge->>Edge: 写入 Inbox 并应用到本地业务表
|
||||
Edge-->>Sync: 返回接收与应用结果
|
||||
Device->>Edge: 查询本地资料或任务
|
||||
Edge-->>Device: 返回可执行数据
|
||||
```
|
||||
|
||||
### 7.2 现场数据上报到云端
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Device as 现场终端
|
||||
participant Edge as 边缘服务器
|
||||
participant Sync as 云端同步编排
|
||||
participant Cloud as 云端业务服务
|
||||
|
||||
Device->>Edge: 上报现场业务数据
|
||||
Edge->>Edge: 写本地业务表和 Outbox
|
||||
Edge-->>Device: 返回现场操作成功
|
||||
Edge->>Sync: 异步补传 Outbox 事件
|
||||
Sync->>Cloud: 幂等校验并入库
|
||||
Sync-->>Edge: 返回同步回执
|
||||
Edge->>Edge: 更新同步状态
|
||||
```
|
||||
|
||||
### 7.3 断网续用与恢复补传
|
||||
|
||||
1. 云端与边缘服务器断连后,边缘服务器状态变为断网或弱网。
|
||||
2. 现场终端继续访问边缘服务器,使用已缓存的任务和资料。
|
||||
3. 新产生的数据继续写入本地业务表和 Outbox。
|
||||
4. 断网期间不允许现场修改全局主数据,仅允许产生现场流水和任务过程数据。
|
||||
5. 网络恢复后,边缘服务器先同步心跳和积压概况,再按业务时间补传 Outbox。
|
||||
6. 云端按业务唯一键幂等入库,失败数据进入重试或死信队列。
|
||||
|
||||
## 8. 状态定义
|
||||
|
||||
### 8.1 下发任务状态
|
||||
|
||||
| 状态 | 说明 |
|
||||
|---|---|
|
||||
| 待执行 | 任务已创建但未到执行时间 |
|
||||
| 下发中 | 云端正在向目标边缘服务器下发 |
|
||||
| 已接收 | 边缘服务器已接收任务 |
|
||||
| 应用中 | 边缘服务器或终端正在应用 |
|
||||
| 已完成 | 所有目标边缘服务器和终端均应用成功 |
|
||||
| 部分失败 | 部分目标失败,可补发或重试 |
|
||||
| 已失败 | 全部目标失败或超过重试阈值 |
|
||||
| 已取消 | 用户或系统取消任务 |
|
||||
|
||||
### 8.2 上报状态
|
||||
|
||||
| 状态 | 说明 |
|
||||
|---|---|
|
||||
| 待同步 | 已写入边缘本地库,尚未上报云端 |
|
||||
| 同步中 | 正在上报云端 |
|
||||
| 已同步 | 云端已受理并返回成功回执 |
|
||||
| 待重试 | 上报失败但未超过重试阈值 |
|
||||
| 上报失败 | 超过重试阈值或明确不可恢复 |
|
||||
| 死信 | 进入人工处理队列 |
|
||||
|
||||
### 8.3 告警状态
|
||||
|
||||
| 状态 | 说明 |
|
||||
|---|---|
|
||||
| 待处理 | 告警已生成,尚未指派或处理 |
|
||||
| 处理中 | 已有人处理或系统正在补偿 |
|
||||
| 已恢复 | 告警条件消失,业务恢复正常 |
|
||||
| 已忽略 | 经确认不需要处理 |
|
||||
|
||||
## 9. 异常处理要求
|
||||
|
||||
| 异常场景 | 处理要求 |
|
||||
|--------|---------------------------------------|
|
||||
| 云边断连 | 云端标记节点离线;边缘继续本地作业;恢复后补传 |
|
||||
| 设备离线 | 边缘记录设备离线;云端生成设备异常告警;恢复后上报恢复记录 |
|
||||
| 下发失败 | 记录失败阶段、失败原因、目标边缘服务器、目标终端;支持自动重试和人工补发 |
|
||||
| 上报失败 | 保留原始业务数据和失败原因;支持手动重试;达到阈值进入死信 |
|
||||
| 文件下载失败 | 不影响业务流水保存;保留待下载状态;支持重新下载 |
|
||||
| 磁盘不足 | 优先保障业务流水和同步控制数据;限制大文件缓存;生成严重告警 |
|
||||
| 版本冲突 | 旧版本不覆盖新版本;任务已开始后不直接覆盖现场任务 |
|
||||
| 重复上报 | 云端按业务唯一键幂等处理,边缘保留同步回执 |
|
||||
| 失败重试 | 数据上报和数据下发失败后至少要进行一次重试操作,重试成功后同步修改数据状态 |
|
||||
|
||||
## 10. 数据保留策略
|
||||
|
||||
| 数据类型 | 边缘服务器保留建议 | 云端保留建议 |
|
||||
|---|---|---|
|
||||
| 基础资料 | 最新有效版本和上一版本 | 长期保留 |
|
||||
| 人脸特征 | 本食堂有效数据,删除标记需保留同步周期 | 长期保留 |
|
||||
| 当日生产任务 | 完整任务和过程状态 | 长期保留 |
|
||||
| 现场流水 | 7 到 30 天,可配置 | 长期保留或归档 |
|
||||
| 同步控制数据 | 至少保留最近 30 天或未完成数据 | 长期保留关键轨迹 |
|
||||
| 设备日志 | 7 到 30 天,可配置 | 按需上传 |
|
||||
| 图片/视频/附件 | 按容量和业务规则保留 | 按合规和存储策略保留 |
|
||||
| 升级包 | 当前版本和上一版本 | 长期保留可用版本 |
|
||||
|
||||
## 11. 产品验收标准
|
||||
|
||||
| 验收项 | 验收标准 |
|
||||
|---|-----------------------------------------------|
|
||||
| 新节点初始化 | 新增边缘服务器后,可完成食堂基础资料、人脸、设备、餐品、食谱、字典、当日任务的全量初始化 |
|
||||
| 基础资料下发 | 云端修改员工、设备、餐品、食谱、字典后,指定边缘服务器可收到并应用,云端可查看结果 |
|
||||
| 生产任务下发 | 食谱、净菜订单、组配、烹制、上餐任务可下发到对应食堂边缘服务器并被终端查询 |
|
||||
| 现场数据上报 | 入库、称重、组配、烹制、上餐、取餐、消费、余量等数据可先写边缘并异步同步云端 |
|
||||
| 断网续用 | 云边断连后,终端仍可查询已缓存任务并继续上报现场数据到边缘服务器 |
|
||||
| 网络恢复补传 | 网络恢复后,断网期间产生的数据可自动补传,云端不产生重复业务数据 |
|
||||
| 下发异常处理 | 下发失败、部分失败、终端应用失败可在云端查看失败原因,并支持重试或补发 |
|
||||
| 上报异常处理 | 上报失败可在数据上报管理中查看,支持手动重试,超过阈值生成告警 |
|
||||
| 设备状态监管 | 云端可查看边缘服务器下设备在线、离线、版本、业务场景、最近活跃时间 |
|
||||
| 文件缓存分发 | 升级包、人脸图片、过程图片等文件不通过 MQ 传输正文,边缘服务器可下载、校验、缓存和分发 |
|
||||
|
||||
## 12. 技术附录
|
||||
|
||||
### 12.1 推荐通信方式
|
||||
|
||||
| 方式 | 用途 | 说明 |
|
||||
|---|---|---|
|
||||
| MQ | 云端与边缘服务器主同步链路 | 边缘服务器主动连接云端 Broker,适合内网场景 |
|
||||
| HTTP Pull | MQ 不可用时的兜底拉取 | 边缘服务器定时拉取下行消息 |
|
||||
| HTTP Push | 上行积压补传 | 边缘服务器批量补传 Outbox |
|
||||
| HTTP/Object Storage | 文件下载和上传 | 文件不通过 MQ 传输正文 |
|
||||
|
||||
### 12.2 通用消息字段
|
||||
|
||||
| 字段 | 说明 |
|
||||
|---|---|
|
||||
| messageId | 消息唯一编号 |
|
||||
| direction | UP 或 DOWN |
|
||||
| canteenId | 食堂编号 |
|
||||
| edgeNodeId | 边缘服务器编号 |
|
||||
| bizType | 业务类型 |
|
||||
| bizId | 业务编号 |
|
||||
| version | 业务版本 |
|
||||
| occurredAt | 业务发生时间 |
|
||||
| sentAt | 消息发送时间 |
|
||||
| traceId | 全链路追踪编号 |
|
||||
| payload | 业务载荷 |
|
||||
| signature | 签名 |
|
||||
@@ -65,7 +65,17 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid var(--border);}
|
||||
.table-card__title{font-size:var(--font-base);font-weight:600;}
|
||||
.table-wrap{overflow-x:auto;}
|
||||
.table-wrap table{min-width:1560px;}
|
||||
.table-wrap table{min-width:1320px;}
|
||||
.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;border-top:1px solid var(--border);background:#fff;}
|
||||
.pagination__total{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.pagination__pager{display:flex;align-items:center;gap:6px;}
|
||||
.pagination__pager button{min-width:32px;height:32px;padding:0 8px;border:1px solid var(--border);background:#fff;border-radius:var(--radius-sm);font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;}
|
||||
.pagination__pager button:hover:not(:disabled){color:var(--primary);border-color:var(--primary);}
|
||||
.pagination__pager button.active{background:var(--primary);color:#fff;border-color:var(--primary);}
|
||||
.pagination__pager button:disabled{color:var(--text-placeholder);cursor:not-allowed;background:#F5F5F5;}
|
||||
.pagination__pager .ellipsis{border:none;background:transparent;cursor:default;}
|
||||
.pagination__jump{display:flex;align-items:center;gap:6px;font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.pagination__jump input{width:48px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);text-align:center;font-size:var(--font-sm);outline:none;}
|
||||
table{width:100%;border-collapse:collapse;}
|
||||
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);white-space:nowrap;vertical-align:middle;}
|
||||
@@ -122,16 +132,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<section class="page-header">
|
||||
<div>
|
||||
<div class="page-header__title">异常告警中心</div>
|
||||
<div class="page-header__desc">统一收拢数据上报失败、数据下发失败、服务器异常、设备异常等边缘服务器运行告警,并提供差异化详情查看入口。</div>
|
||||
</div>
|
||||
<div class="page-header__actions">
|
||||
<button class="btn btn-default" onclick="showToast('正在导出异常告警')">导出告警</button>
|
||||
<button class="btn btn-primary" onclick="showToast('已刷新最新告警状态')">刷新状态</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stats-grid">
|
||||
<div class="stat-card"><div class="stat-card__value">48</div><div class="stat-card__label">当日告警总数</div><div class="stat-card__hint">已去重的事件级告警</div></div>
|
||||
@@ -173,7 +173,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="filter-item"><label>当前状态</label><select class="filter-select"><option>全部</option><option>待处理</option><option>处理中</option><option>已恢复</option><option>已忽略</option></select></div>
|
||||
<div class="filter-item"><label>所属食堂</label><select class="filter-select"><option>全部</option><option>采气一厂食堂</option><option>炼化中心食堂</option><option>总部一号食堂</option></select></div>
|
||||
<div class="filter-item"><label>发生日期</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>关键字</label><input class="filter-input" placeholder="告警编号 / 服务器 / 设备"></div>
|
||||
<button class="btn btn-primary" onclick="showToast('已按条件刷新告警列表')">查询</button>
|
||||
<button class="btn btn-default" onclick="showToast('已重置筛选条件')">重置</button>
|
||||
</section>
|
||||
@@ -182,7 +181,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__header"><div class="table-card__title">边缘服务器异常告警列表</div><button class="btn btn-default" onclick="showToast('已批量标记为处理中')">批量标记处理中</button></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>告警编号</th><th>告警类型</th><th>告警主题</th><th>等级</th><th>所属食堂</th><th>边缘服务器</th><th>影响对象</th><th>影响业务</th><th>首次发生</th><th>最近发生</th><th>当前状态</th><th>处理人</th><th>操作</th></tr></thead>
|
||||
<thead><tr><th>告警编号</th><th>告警类型</th><th>告警主题</th><th>等级</th><th>所属食堂</th><th>边缘服务器</th><th>业务类型</th><th>告警时间</th><th>当前状态</th><th>处理人</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ALM-20260624-078</td>
|
||||
@@ -191,9 +190,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<td><span class="tag tag-orange">警告</span></td>
|
||||
<td>采气一厂食堂</td>
|
||||
<td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td>
|
||||
<td>MEAL-20260624-0178</td>
|
||||
<td><a class="link" href="edge-report-management.html">数据上报</a></td>
|
||||
<td>2026-06-24 08:45:00</td>
|
||||
<td>数据上报</td>
|
||||
<td>2026-06-24 09:18:33</td>
|
||||
<td><span class="tag tag-blue">处理中</span></td>
|
||||
<td>运维张工</td>
|
||||
@@ -206,9 +203,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<td><span class="tag tag-red">严重</span></td>
|
||||
<td>炼化中心食堂</td>
|
||||
<td><a class="link" href="edge-server-detail.html">炼化中心餐线服务器</a></td>
|
||||
<td>UPG-20260624-002</td>
|
||||
<td><a class="link" href="edge-dispatch-management.html">数据下发</a></td>
|
||||
<td>2026-06-24 11:06:12</td>
|
||||
<td>数据下发</td>
|
||||
<td>2026-06-24 11:18:20</td>
|
||||
<td><span class="tag tag-orange">待处理</span></td>
|
||||
<td>未指派</td>
|
||||
@@ -221,9 +216,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<td><span class="tag tag-red">严重</span></td>
|
||||
<td>炼化中心食堂</td>
|
||||
<td><a class="link" href="edge-server-detail.html">炼化中心餐线服务器</a></td>
|
||||
<td>EDGE-CQ-024</td>
|
||||
<td>接入、上报、下发全链路</td>
|
||||
<td>2026-06-24 08:54:09</td>
|
||||
<td>2026-06-24 09:21:20</td>
|
||||
<td><span class="tag tag-orange">待处理</span></td>
|
||||
<td>未指派</td>
|
||||
@@ -236,9 +229,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<td><span class="tag tag-orange">警告</span></td>
|
||||
<td>采气一厂食堂</td>
|
||||
<td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td>
|
||||
<td>LINE-SCALE-002</td>
|
||||
<td>称重采集、就餐校验</td>
|
||||
<td>2026-06-24 08:42:00</td>
|
||||
<td>2026-06-24 09:12:00</td>
|
||||
<td><span class="tag tag-orange">待处理</span></td>
|
||||
<td>运维李工</td>
|
||||
@@ -251,9 +242,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<td><span class="tag tag-green">提醒</span></td>
|
||||
<td>总部一号食堂</td>
|
||||
<td><a class="link" href="edge-server-detail.html">总部一号食堂服务器</a></td>
|
||||
<td>FACE-TERM-003</td>
|
||||
<td>人脸识别、就餐放行</td>
|
||||
<td>2026-06-24 07:48:12</td>
|
||||
<td>2026-06-24 08:01:30</td>
|
||||
<td><span class="tag tag-green">已恢复</span></td>
|
||||
<td>平台自动恢复</td>
|
||||
@@ -262,6 +251,19 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<div class="pagination__total">共 48 条 · 每页 10 条 · 第 1 / 5 页</div>
|
||||
<div class="pagination__pager">
|
||||
<button onclick="showToast('已跳至上一页')" disabled>‹ 上一页</button>
|
||||
<button class="active" onclick="showToast('已跳至第 1 页')">1</button>
|
||||
<button onclick="showToast('已跳至第 2 页')">2</button>
|
||||
<button onclick="showToast('已跳至第 3 页')">3</button>
|
||||
<button onclick="showToast('已跳至第 4 页')">4</button>
|
||||
<button onclick="showToast('已跳至第 5 页')">5</button>
|
||||
<button onclick="showToast('已跳至下一页')">下一页 ›</button>
|
||||
</div>
|
||||
<div class="pagination__jump">跳至<input type="number" value="1" min="1" max="5">页</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -285,6 +287,8 @@ var alarmDetails={
|
||||
['边缘服务器','采气一厂后厨服务器'],
|
||||
['当前状态','处理中'],
|
||||
['关联业务单号','MEAL-20260624-0178'],
|
||||
['首次发生','2026-06-24 08:45:00'],
|
||||
['最近发生','2026-06-24 09:18:33'],
|
||||
['处理人','运维张工']
|
||||
],
|
||||
sections:[
|
||||
@@ -324,6 +328,8 @@ var alarmDetails={
|
||||
['边缘服务器','炼化中心餐线服务器'],
|
||||
['当前状态','待处理'],
|
||||
['关联任务','UPG-20260624-002'],
|
||||
['首次发生','2026-06-24 11:06:12'],
|
||||
['最近发生','2026-06-24 11:18:20'],
|
||||
['处理人','未指派']
|
||||
],
|
||||
sections:[
|
||||
@@ -364,6 +370,8 @@ var alarmDetails={
|
||||
['边缘服务器','炼化中心餐线服务器'],
|
||||
['当前状态','待处理'],
|
||||
['服务器编号','EDGE-CQ-024'],
|
||||
['首次发生','2026-06-24 08:54:09'],
|
||||
['最近发生','2026-06-24 09:21:20'],
|
||||
['处理人','未指派']
|
||||
],
|
||||
sections:[
|
||||
@@ -403,6 +411,8 @@ var alarmDetails={
|
||||
['边缘服务器','采气一厂后厨服务器'],
|
||||
['当前状态','待处理'],
|
||||
['设备编号','LINE-SCALE-002'],
|
||||
['首次发生','2026-06-24 08:42:00'],
|
||||
['最近发生','2026-06-24 09:12:00'],
|
||||
['处理人','运维李工']
|
||||
],
|
||||
sections:[
|
||||
@@ -442,6 +452,8 @@ var alarmDetails={
|
||||
['边缘服务器','总部一号食堂服务器'],
|
||||
['当前状态','已恢复'],
|
||||
['设备编号','FACE-TERM-003'],
|
||||
['首次发生','2026-06-24 07:48:12'],
|
||||
['最近发生','2026-06-24 08:01:30'],
|
||||
['处理人','平台自动恢复']
|
||||
],
|
||||
sections:[
|
||||
|
||||
@@ -72,6 +72,48 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.link:hover{color:#40a9ff;}
|
||||
.toast{position:fixed;top:76px;left:50%;transform:translateX(-50%) translateY(-12px);background:#fff;border-left:4px solid var(--primary);box-shadow:var(--shadow-md);padding:10px 18px;border-radius:var(--radius-sm);font-size:var(--font-sm);opacity:0;pointer-events:none;transition:all .25s;z-index:1200;}
|
||||
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
|
||||
.action-links{display:flex;align-items:center;gap:8px;}
|
||||
.td-actions{min-width:220px;}
|
||||
.drawer-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:none;}
|
||||
.drawer-mask.show{display:block;}
|
||||
.drawer{position:absolute;right:0;top:0;bottom:0;width:560px;background:#fff;box-shadow:-6px 0 24px rgba(0,0,0,.12);display:flex;flex-direction:column;}
|
||||
.drawer__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);}
|
||||
.drawer__title{font-size:var(--font-lg);font-weight:600;}
|
||||
.drawer__close{border:none;background:none;font-size:22px;cursor:pointer;color:var(--text-placeholder);}
|
||||
.drawer__body{padding:20px 24px;overflow-y:auto;flex:1;}
|
||||
.detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 18px;}
|
||||
.detail-item{display:flex;flex-direction:column;gap:3px;}
|
||||
.detail-label{font-size:var(--font-xs);color:var(--text-placeholder);}
|
||||
.detail-value{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.section-title{font-size:var(--font-sm);font-weight:600;margin:16px 0 10px;padding-left:8px;border-left:3px solid var(--primary);}
|
||||
.trace-panel{margin-top:14px;}
|
||||
.trace-summary{display:flex;align-items:center;justify-content:space-between;background:#F8FBFF;border:1px solid #D6E9FF;border-radius:var(--radius-sm);padding:10px 12px;margin-bottom:12px;font-size:var(--font-sm);}
|
||||
.trace-summary__meta{color:var(--text-secondary);}
|
||||
.trace-timeline{position:relative;padding-left:24px;}
|
||||
.trace-timeline::before{content:'';position:absolute;left:7px;top:6px;bottom:6px;width:2px;background:#D9E6F7;}
|
||||
.trace-step{position:relative;margin-bottom:14px;}
|
||||
.trace-step__dot{position:absolute;left:-24px;top:4px;width:16px;height:16px;border-radius:50%;background:#fff;border:2px solid var(--primary);box-shadow:0 0 0 3px #E6F7FF;}
|
||||
.trace-step__dot--success{border-color:var(--success);box-shadow:0 0 0 3px #F6FFED;}
|
||||
.trace-step__dot--warning{border-color:var(--warning);box-shadow:0 0 0 3px #FFF7E6;}
|
||||
.trace-step__dot--gray{border-color:#BFBFBF;box-shadow:0 0 0 3px #F5F5F5;}
|
||||
.trace-step__dot--danger{border-color:var(--danger);box-shadow:0 0 0 3px #FFF1F0;}
|
||||
.trace-step__card{background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);padding:12px 14px;box-shadow:var(--shadow-sm);}
|
||||
.trace-step__head{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:var(--font-sm);font-weight:600;margin-bottom:6px;}
|
||||
.trace-step__time{font-size:var(--font-xs);color:var(--text-placeholder);white-space:nowrap;}
|
||||
.trace-step__desc{font-size:var(--font-sm);color:var(--text-secondary);line-height:1.6;}
|
||||
.log-panel{margin-top:12px;}
|
||||
.log-row{display:flex;align-items:center;gap:8px;padding:8px 0;border-bottom:1px dashed var(--border);font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.log-row__time{color:var(--text-placeholder);min-width:150px;white-space:nowrap;}
|
||||
.log-row__stage{min-width:120px;color:var(--text-secondary);}
|
||||
.log-row__desc{flex:1;}
|
||||
.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:none;align-items:center;justify-content:center;}
|
||||
.modal-mask.show{display:flex;}
|
||||
.modal{width:720px;max-height:80vh;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);display:flex;flex-direction:column;overflow:hidden;}
|
||||
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:18px 24px;border-bottom:1px solid var(--border);}
|
||||
.modal__title{font-size:var(--font-lg);font-weight:600;}
|
||||
.modal__close{border:none;background:none;font-size:22px;cursor:pointer;color:var(--text-placeholder);}
|
||||
.modal__body{padding:18px 24px;overflow-y:auto;flex:1;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 24px 18px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -92,10 +134,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<main class="main">
|
||||
<div class="breadcrumb"><a href="edge-dispatch-management.html">数据下发管理</a> / 数据下发详情</div>
|
||||
|
||||
<section class="page-header">
|
||||
<div><div class="page-header__title">FACE-BATCH-0624-04</div><div class="page-header__desc">人脸增量任务 · 单次下发 · 目标为采气一厂食堂边缘服务器,需跟踪每台边缘服务器接收与终端应用情况。</div></div>
|
||||
<div class="page-header__actions"><button class="btn btn-default" onclick="location.href='edge-alert-center.html'">查看告警</button><button class="btn btn-default" onclick="showToast('已生成补发任务草稿')">生成补发任务</button><button class="btn btn-primary" onclick="showToast('已发起强制重试')">强制重试</button></div>
|
||||
</section>
|
||||
|
||||
<section class="stats-grid">
|
||||
<div class="stat-card"><div class="stat-card__value">1</div><div class="stat-card__label">目标服务器</div></div>
|
||||
@@ -121,77 +159,245 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tabs">
|
||||
<div class="tab active" onclick="switchTab('receive',this)">服务器接收情况</div>
|
||||
<div class="tab" onclick="switchTab('terminal',this)">终端应用情况</div>
|
||||
<div class="tab" onclick="switchTab('fail',this)">失败明细</div>
|
||||
<div class="tab" onclick="switchTab('log',this)">执行日志</div>
|
||||
</section>
|
||||
|
||||
<section id="receive" class="tab-panel active">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>边缘服务器</th><th>所属食堂</th><th>接收状态</th><th>接收时间</th><th>应用状态</th><th>应用完成时间</th><th>剩余终端</th><th>关联告警</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td><td>采气一厂食堂</td><td><span class="tag tag-green">已接收</span></td><td>2026-06-24 08:40:12</td><td><span class="tag tag-orange">部分待应用</span></td><td>—</td><td>2 台</td><td><a class="link" href="edge-alert-center.html">1 条</a></td><td class="td-actions"><a class="link" onclick="showToast('已打开接收轨迹')">接收轨迹</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<section class="card" style="margin-bottom:16px;">
|
||||
<div class="card__header">
|
||||
<div class="card__title">服务器接收情况</div>
|
||||
<span class="tag tag-orange">进行中</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="terminal" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>终端设备</th><th>设备编号</th><th>应用状态</th><th>应用时间</th><th>失败原因</th><th>当前版本</th><th>操作</th></tr></thead>
|
||||
<thead><tr><th>边缘服务器</th><th>所属食堂</th><th>受理状态</th><th>接收状态</th><th>接收时间</th><th>应用状态</th><th>应用完成时间</th><th>剩余终端</th><th>关联告警</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>人脸识别终端 01</td><td>FACE-TERM-001</td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 08:41:12</td><td>—</td><td>v3.2.0</td><td class="td-actions"><a class="link" onclick="showToast('已查看终端回执')">终端回执</a></td></tr>
|
||||
<tr><td>人脸识别终端 02</td><td>FACE-TERM-002</td><td><span class="tag tag-orange">待应用</span></td><td>—</td><td>终端离线</td><td>v3.2.0</td><td class="td-actions"><a class="link" onclick="showToast('已发送重新通知')">重新通知</a></td></tr>
|
||||
<tr><td>人脸识别终端 03</td><td>FACE-TERM-003</td><td><span class="tag tag-orange">待应用</span></td><td>—</td><td>终端忙碌中</td><td>v3.2.0</td><td class="td-actions"><a class="link" onclick="showToast('已加入终端重试队列')">加入重试</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="fail" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>对象层级</th><th>对象名称</th><th>失败阶段</th><th>失败原因</th><th>最近处理时间</th><th>建议动作</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>终端设备</td><td>人脸识别终端 02</td><td>终端应用</td><td>终端离线,未获取到增量包</td><td>2026-06-24 09:12:10</td><td>待上线后重新通知</td><td class="td-actions"><a class="link" onclick="showToast('已重新通知终端')">重新通知</a></td></tr>
|
||||
<tr><td>终端设备</td><td>人脸识别终端 03</td><td>终端应用</td><td>本地特征库忙碌,应用超时</td><td>2026-06-24 09:08:22</td><td>延后 5 分钟自动重试</td><td class="td-actions"><a class="link" onclick="showToast('已调整重试策略')">调整策略</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="log" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>时间</th><th>执行阶段</th><th>处理结果</th><th>说明</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>2026-06-24 08:40:12</td><td>边缘服务器接收</td><td><span class="tag tag-green">成功</span></td><td>采气一厂后厨服务器完成批次接收与校验</td><td class="td-actions"><a class="link" onclick="showToast('已复制批次轨迹编号')">复制轨迹号</a></td></tr>
|
||||
<tr><td>2026-06-24 08:41:12</td><td>终端应用</td><td><span class="tag tag-green">部分完成</span></td><td>1 台终端完成应用,2 台待应用</td><td class="td-actions"><a class="link" href="edge-server-detail.html">服务器详情</a></td></tr>
|
||||
<tr><td>2026-06-24 09:12:10</td><td>异常补偿</td><td><span class="tag tag-orange">处理中</span></td><td>系统已对离线终端触发重连检测</td><td class="td-actions"><a class="link" href="edge-alert-center.html">查看告警</a></td></tr>
|
||||
<tr>
|
||||
<td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td>
|
||||
<td>采气一厂食堂</td>
|
||||
<td><span class="tag tag-green">已受理</span></td>
|
||||
<td><span class="tag tag-green">已接收</span></td>
|
||||
<td>2026-06-24 08:40:12</td>
|
||||
<td><a class="link" onclick="openTerminalModal('采气一厂后厨服务器')">4 / 8</a></td>
|
||||
<td>—</td>
|
||||
<td>4 台</td>
|
||||
<td><a class="link" href="edge-alert-center.html">1 条</a></td>
|
||||
<td class="td-actions"><div class="action-links"><a class="link" onclick="openReceiveTrace('采气一厂后厨服务器')">接收轨迹</a><a class="link" onclick="openDispatchLog('采气一厂后厨服务器')">查看日志</a><a class="link" onclick="showToast('已对该服务器发起强制重试')">强制重试</a></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="link" href="edge-server-detail.html">炼化中心餐线服务器</a></td>
|
||||
<td>炼化中心食堂</td>
|
||||
<td><span class="tag tag-green">已受理</span></td>
|
||||
<td><span class="tag tag-green">已接收</span></td>
|
||||
<td>2026-06-24 08:40:15</td>
|
||||
<td><a class="link" onclick="openTerminalModal('炼化中心餐线服务器')">8 / 8</a></td>
|
||||
<td>2026-06-24 08:42:30</td>
|
||||
<td>0 台</td>
|
||||
<td>—</td>
|
||||
<td class="td-actions"><div class="action-links"><a class="link" onclick="openReceiveTrace('炼化中心餐线服务器')">接收轨迹</a><a class="link" onclick="openDispatchLog('炼化中心餐线服务器')">查看日志</a><a class="link" onclick="showToast('已对该服务器发起强制重试')">强制重试</a></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="link" href="edge-server-detail.html">总部一号食堂服务器</a></td>
|
||||
<td>总部一号食堂</td>
|
||||
<td><span class="tag tag-red">拒绝受理</span></td>
|
||||
<td><span class="tag tag-gray">未接收</span></td>
|
||||
<td>—</td>
|
||||
<td><a class="link" onclick="openTerminalModal('总部一号食堂服务器')">0 / 6</a></td>
|
||||
<td>—</td>
|
||||
<td>6 台</td>
|
||||
<td><a class="link" href="edge-alert-center.html">2 条</a></td>
|
||||
<td class="td-actions"><div class="action-links"><a class="link" onclick="openReceiveTrace('总部一号食堂服务器')">接收轨迹</a><a class="link" onclick="openDispatchLog('总部一号食堂服务器')">查看日志</a><a class="link" onclick="showToast('已对该服务器发起强制重试')">强制重试</a></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div class="drawer-mask" id="drawerMask">
|
||||
<div class="drawer">
|
||||
<div class="drawer__header"><div class="drawer__title" id="drawerTitle">接收轨迹</div><button class="drawer__close" onclick="closeDrawer()">×</button></div>
|
||||
<div class="drawer__body">
|
||||
<div class="detail-grid" id="detailGrid">
|
||||
<div class="detail-item"><div class="detail-label">边缘服务器</div><div class="detail-value" id="detailServer">采气一厂后厨服务器</div></div>
|
||||
<div class="detail-item"><div class="detail-label">所属食堂</div><div class="detail-value" id="detailCanteen">采气一厂食堂</div></div>
|
||||
<div class="detail-item"><div class="detail-label">任务编号</div><div class="detail-value">FACE-BATCH-0624-04</div></div>
|
||||
<div class="detail-item"><div class="detail-label">数据版本</div><div class="detail-value">FACE-VER-20260624-04</div></div>
|
||||
</div>
|
||||
<div class="section-title" id="logTitle">下发日志</div>
|
||||
<div class="log-panel" id="logPanel">
|
||||
<div class="log-row"><span class="log-row__time">2026-06-24 08:40:12</span><span class="log-row__stage"><span class="tag tag-green">成功</span> 边缘服务器接收</span><span class="log-row__desc">采气一厂后厨服务器完成批次接收与校验。</span></div>
|
||||
<div class="log-row"><span class="log-row__time">2026-06-24 08:41:12</span><span class="log-row__stage"><span class="tag tag-green">部分完成</span> 终端应用</span><span class="log-row__desc">4 台终端完成应用,4 台待应用。</span></div>
|
||||
<div class="log-row"><span class="log-row__time">2026-06-24 09:12:10</span><span class="log-row__stage"><span class="tag tag-orange">处理中</span> 异常补偿</span><span class="log-row__desc">系统已对离线终端触发重连检测。</span></div>
|
||||
</div>
|
||||
<div class="trace-panel" id="tracePanel" style="display:none;">
|
||||
<div class="trace-summary">
|
||||
<span>业务编号 <strong id="traceBizId">FACE-BATCH-0624-04</strong></span>
|
||||
<span class="trace-summary__meta">中心服务器当前状态:部分服务器已回执</span>
|
||||
</div>
|
||||
<div class="trace-timeline">
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--success"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>中心服务器下发</span><span class="trace-step__time">2026-06-24 08:40:00</span></div>
|
||||
<div class="trace-step__desc">批次下发任务创建,推送到目标边缘服务器队列。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--success"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>边缘服务器接收</span><span class="trace-step__time">2026-06-24 08:40:12</span></div>
|
||||
<div class="trace-step__desc">完成批次接收与签名校验,写入本地缓存。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--warning"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>终端应用</span><span class="trace-step__time">2026-06-24 08:41:12</span></div>
|
||||
<div class="trace-step__desc">4 台终端完成应用,4 台待应用,正在异步分发。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--gray"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>异常补偿</span><span class="trace-step__time">处理中</span></div>
|
||||
<div class="trace-step__desc">系统对离线终端触发重连检测,等待下一次回执。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>回执确认</span><span class="trace-step__time">--</span></div>
|
||||
<div class="trace-step__desc">全部终端回执后将关闭重试并同步更新下发状态。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="terminalModal">
|
||||
<div class="modal">
|
||||
<div class="modal__header"><div class="modal__title">终端应用明细</div><button class="modal__close" onclick="closeTerminalModal()">×</button></div>
|
||||
<div class="modal__body">
|
||||
<div class="detail-grid" style="margin-bottom:14px;">
|
||||
<div class="detail-item"><div class="detail-label">边缘服务器</div><div class="detail-value" id="terminalServer">采气一厂后厨服务器</div></div>
|
||||
<div class="detail-item"><div class="detail-label">应用进度</div><div class="detail-value" id="terminalProgress">4 / 8</div></div>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>终端设备</th><th>设备编号</th><th>应用状态</th><th>应用时间</th><th>错误信息</th></tr></thead>
|
||||
<tbody id="terminalTbody">
|
||||
<tr><td>人脸识别终端 01</td><td>FACE-TERM-001</td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 08:41:12</td><td>—</td></tr>
|
||||
<tr><td>人脸识别终端 02</td><td>FACE-TERM-002</td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 08:41:18</td><td>—</td></tr>
|
||||
<tr><td>人脸识别终端 03</td><td>FACE-TERM-003</td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 08:41:25</td><td>—</td></tr>
|
||||
<tr><td>人脸识别终端 04</td><td>FACE-TERM-004</td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 08:41:33</td><td>—</td></tr>
|
||||
<tr><td>人脸识别终端 05</td><td>FACE-TERM-005</td><td><span class="tag tag-orange">待应用</span></td><td>—</td><td>终端离线,等待重连</td></tr>
|
||||
<tr><td>人脸识别终端 06</td><td>FACE-TERM-006</td><td><span class="tag tag-orange">待应用</span></td><td>—</td><td>本地特征库忙碌,应用超时</td></tr>
|
||||
<tr><td>人脸识别终端 07</td><td>FACE-TERM-007</td><td><span class="tag tag-red">应用失败</span></td><td>—</td><td>增量包校验失败:签名不匹配</td></tr>
|
||||
<tr><td>人脸识别终端 08</td><td>FACE-TERM-008</td><td><span class="tag tag-gray">未触发</span></td><td>—</td><td>排队中,等待上一轮应用结束</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeTerminalModal()">关闭</button>
|
||||
<button class="btn btn-primary" onclick="showToast('已对未完成终端发起重新通知')">重新通知未完成</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast">操作已完成</div>
|
||||
<script>
|
||||
function switchTab(id,el){
|
||||
document.querySelectorAll('.tab').forEach(function(tab){tab.classList.remove('active');});
|
||||
document.querySelectorAll('.tab-panel').forEach(function(panel){panel.classList.remove('active');});
|
||||
el.classList.add('active');
|
||||
document.getElementById(id).classList.add('active');
|
||||
}
|
||||
// 服务器元数据
|
||||
var serverMeta={
|
||||
'采气一厂后厨服务器':{canteen:'采气一厂食堂',progress:'4 / 8'},
|
||||
'炼化中心餐线服务器':{canteen:'炼化中心食堂',progress:'8 / 8'},
|
||||
'总部一号食堂服务器':{canteen:'总部一号食堂',progress:'0 / 6'}
|
||||
};
|
||||
// 终端应用明细数据
|
||||
var terminalData={
|
||||
'采气一厂后厨服务器':[
|
||||
{name:'人脸识别终端 01',code:'FACE-TERM-001',status:'done',time:'2026-06-24 08:41:12',err:'—'},
|
||||
{name:'人脸识别终端 02',code:'FACE-TERM-002',status:'done',time:'2026-06-24 08:41:18',err:'—'},
|
||||
{name:'人脸识别终端 03',code:'FACE-TERM-003',status:'done',time:'2026-06-24 08:41:25',err:'—'},
|
||||
{name:'人脸识别终端 04',code:'FACE-TERM-004',status:'done',time:'2026-06-24 08:41:33',err:'—'},
|
||||
{name:'人脸识别终端 05',code:'FACE-TERM-005',status:'pending',time:'—',err:'终端离线,等待重连'},
|
||||
{name:'人脸识别终端 06',code:'FACE-TERM-006',status:'pending',time:'—',err:'本地特征库忙碌,应用超时'},
|
||||
{name:'人脸识别终端 07',code:'FACE-TERM-007',status:'fail',time:'—',err:'增量包校验失败:签名不匹配'},
|
||||
{name:'人脸识别终端 08',code:'FACE-TERM-008',status:'idle',time:'—',err:'排队中,等待上一轮应用结束'}
|
||||
],
|
||||
'炼化中心餐线服务器':[
|
||||
{name:'人脸识别终端 01',code:'FACE-TERM-101',status:'done',time:'2026-06-24 08:40:35',err:'—'},
|
||||
{name:'人脸识别终端 02',code:'FACE-TERM-102',status:'done',time:'2026-06-24 08:40:42',err:'—'},
|
||||
{name:'人脸识别终端 03',code:'FACE-TERM-103',status:'done',time:'2026-06-24 08:40:50',err:'—'},
|
||||
{name:'人脸识别终端 04',code:'FACE-TERM-104',status:'done',time:'2026-06-24 08:40:58',err:'—'},
|
||||
{name:'人脸识别终端 05',code:'FACE-TERM-105',status:'done',time:'2026-06-24 08:41:10',err:'—'},
|
||||
{name:'人脸识别终端 06',code:'FACE-TERM-106',status:'done',time:'2026-06-24 08:41:55',err:'—'},
|
||||
{name:'人脸识别终端 07',code:'FACE-TERM-107',status:'done',time:'2026-06-24 08:42:12',err:'—'},
|
||||
{name:'人脸识别终端 08',code:'FACE-TERM-108',status:'done',time:'2026-06-24 08:42:30',err:'—'}
|
||||
],
|
||||
'总部一号食堂服务器':[
|
||||
{name:'人脸识别终端 01',code:'FACE-TERM-201',status:'idle',time:'—',err:'服务器未接收,等待受理'},
|
||||
{name:'人脸识别终端 02',code:'FACE-TERM-202',status:'idle',time:'—',err:'服务器未接收,等待受理'},
|
||||
{name:'人脸识别终端 03',code:'FACE-TERM-203',status:'idle',time:'—',err:'服务器未接收,等待受理'},
|
||||
{name:'人脸识别终端 04',code:'FACE-TERM-204',status:'idle',time:'—',err:'服务器未接收,等待受理'},
|
||||
{name:'人脸识别终端 05',code:'FACE-TERM-205',status:'idle',time:'—',err:'服务器未接收,等待受理'},
|
||||
{name:'人脸识别终端 06',code:'FACE-TERM-206',status:'idle',time:'—',err:'服务器未接收,等待受理'}
|
||||
]
|
||||
};
|
||||
function showToast(text){
|
||||
var toast=document.getElementById('toast');
|
||||
toast.textContent=text;
|
||||
toast.classList.add('show');
|
||||
setTimeout(function(){toast.classList.remove('show');},1800);
|
||||
}
|
||||
// 打开接收轨迹抽屉(沿用 edge-report-management.html 上报轨迹时间线模式)
|
||||
function openReceiveTrace(serverName){
|
||||
var meta=serverMeta[serverName]||{canteen:'—',progress:'—'};
|
||||
document.getElementById('drawerTitle').textContent='接收轨迹';
|
||||
document.getElementById('detailServer').textContent=serverName;
|
||||
document.getElementById('detailCanteen').textContent=meta.canteen;
|
||||
document.getElementById('detailGrid').style.display='grid';
|
||||
document.getElementById('tracePanel').style.display='block';
|
||||
document.getElementById('logTitle').style.display='none';
|
||||
document.getElementById('logPanel').style.display='none';
|
||||
document.getElementById('drawerMask').classList.add('show');
|
||||
}
|
||||
// 打开下发日志抽屉
|
||||
function openDispatchLog(serverName){
|
||||
var meta=serverMeta[serverName]||{canteen:'—',progress:'—'};
|
||||
document.getElementById('drawerTitle').textContent='下发日志';
|
||||
document.getElementById('detailServer').textContent=serverName;
|
||||
document.getElementById('detailCanteen').textContent=meta.canteen;
|
||||
document.getElementById('detailGrid').style.display='grid';
|
||||
document.getElementById('tracePanel').style.display='none';
|
||||
document.getElementById('logTitle').style.display='block';
|
||||
document.getElementById('logPanel').style.display='block';
|
||||
document.getElementById('drawerMask').classList.add('show');
|
||||
}
|
||||
function closeDrawer(){
|
||||
document.getElementById('drawerMask').classList.remove('show');
|
||||
}
|
||||
// 终端应用明细弹窗
|
||||
function renderTerminalStatus(status){
|
||||
if(status==='done'){return '<span class="tag tag-green">已完成</span>';}
|
||||
if(status==='pending'){return '<span class="tag tag-orange">待应用</span>';}
|
||||
if(status==='fail'){return '<span class="tag tag-red">应用失败</span>';}
|
||||
return '<span class="tag tag-gray">未触发</span>';
|
||||
}
|
||||
function openTerminalModal(serverName){
|
||||
var meta=serverMeta[serverName]||{canteen:'—',progress:'—'};
|
||||
var list=terminalData[serverName]||[];
|
||||
document.getElementById('terminalServer').textContent=serverName;
|
||||
document.getElementById('terminalProgress').textContent=meta.progress;
|
||||
var tbody=document.getElementById('terminalTbody');
|
||||
tbody.innerHTML='';
|
||||
list.forEach(function(item){
|
||||
var tr=document.createElement('tr');
|
||||
tr.innerHTML='<td>'+item.name+'</td><td>'+item.code+'</td><td>'+renderTerminalStatus(item.status)+'</td><td>'+item.time+'</td><td>'+item.err+'</td>';
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
document.getElementById('terminalModal').classList.add('show');
|
||||
}
|
||||
function closeTerminalModal(){
|
||||
document.getElementById('terminalModal').classList.remove('show');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -26,11 +26,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.mi{display:inline-block;width:20px;text-align:center;filter:grayscale(1);opacity:.75;margin-right:2px;}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.page-header{display:flex;align-items:center;justify-content:space-between;background:#fff;border-radius:var(--radius-md);padding:18px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);}
|
||||
.page-header__title{font-size:var(--font-xl);font-weight:700;}
|
||||
.page-header__desc{margin-top:6px;font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-header__actions{display:flex;gap:8px;}
|
||||
.stats-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px;}
|
||||
.stats-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px;}
|
||||
.stat-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 18px;}
|
||||
.stat-card__value{font-size:var(--font-xxl);font-weight:700;line-height:1;}
|
||||
.stat-card__label{font-size:var(--font-sm);color:var(--text-secondary);margin-top:8px;}
|
||||
@@ -78,9 +74,14 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.form-input,.form-select,.form-textarea{border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;font-size:var(--font-sm);outline:none;background:#fff;}
|
||||
.form-textarea{min-height:96px;resize:none;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:0 24px 20px;}
|
||||
.tip-card{margin-top:16px;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 20px;}
|
||||
.tip-title{font-size:var(--font-base);font-weight:600;margin-bottom:10px;}
|
||||
.tip-list{display:flex;flex-direction:column;gap:8px;font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.action-links{display:flex;align-items:center;gap:8px;}
|
||||
.td-actions{min-width:170px;}
|
||||
.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--border);font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.pagination__controls{display:flex;align-items:center;gap:8px;}
|
||||
.page-btn{min-width:32px;height:32px;padding:0 10px;border:1px solid var(--border);background:#fff;border-radius:var(--radius-sm);font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;}
|
||||
.page-btn.active{border-color:var(--primary);background:var(--primary);color:#fff;}
|
||||
.page-btn:disabled{background:#F5F5F5;color:var(--text-placeholder);cursor:not-allowed;}
|
||||
.page-size{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 8px;background:#fff;color:var(--text-secondary);}
|
||||
.toast{position:fixed;top:76px;left:50%;transform:translateX(-50%) translateY(-12px);background:#fff;border-left:4px solid var(--primary);box-shadow:var(--shadow-md);padding:10px 18px;border-radius:var(--radius-sm);font-size:var(--font-sm);opacity:0;pointer-events:none;transition:all .25s;z-index:1200;}
|
||||
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
|
||||
</style>
|
||||
@@ -101,18 +102,11 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<section class="page-header">
|
||||
<div><div class="page-header__title">数据下发管理</div><div class="page-header__desc">管理中心服务器向边缘服务器发起的全部数据下发任务,支持新建单次、定时等下发方式,并跟踪每台服务器的接收与应用情况。</div></div>
|
||||
<div class="page-header__actions"><button class="btn btn-default" onclick="showToast('正在导出下发任务')">导出任务</button><button class="btn btn-primary" onclick="openModal()">新建任务</button></div>
|
||||
</section>
|
||||
|
||||
<section class="stats-grid">
|
||||
<div class="stat-card"><div class="stat-card__value">126</div><div class="stat-card__label">当日下发任务</div><div class="stat-card__hint">中心服务器发起</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value" style="color:var(--success)">108</div><div class="stat-card__label">已完成任务</div><div class="stat-card__hint">成功到达目标服务器</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value" style="color:var(--warning)">12</div><div class="stat-card__label">进行中任务</div><div class="stat-card__hint">含定时待执行</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value" style="color:var(--danger)">6</div><div class="stat-card__label">失败任务</div><div class="stat-card__hint">需补发或重试</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value">28</div><div class="stat-card__label">待接收服务器</div><div class="stat-card__hint">来自 4 个任务</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value">97.4%</div><div class="stat-card__label">当日完成率</div><div class="stat-card__hint">较昨日 +0.9%</div></div>
|
||||
</section>
|
||||
|
||||
<section class="filter-bar">
|
||||
@@ -127,26 +121,37 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</section>
|
||||
|
||||
<section class="table-card">
|
||||
<div class="table-card__header"><div class="table-card__title">中心服务器下发任务列表</div><button class="btn btn-default" onclick="showToast('已切换为仅看失败任务')">仅看失败</button></div>
|
||||
<div class="table-card__header">
|
||||
<div class="table-card__title">中心服务器下发任务列表</div>
|
||||
<div class="page-header__actions" style="display:flex;gap:8px;">
|
||||
<button class="btn btn-default" onclick="showToast('已切换为仅看失败任务')">仅看失败</button>
|
||||
<button class="btn btn-default" onclick="showToast('正在导出下发任务')">导出任务</button>
|
||||
<button class="btn btn-primary" onclick="openModal()">新建任务</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>任务编号</th><th>下发类型</th><th>下发方式</th><th>目标范围</th><th>计划执行时间</th><th>发起人</th><th>当前状态</th><th>完成服务器</th><th>失败服务器</th><th>关联告警</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>FACE-BATCH-0624-04</td><td>人脸增量</td><td><span class="tag tag-blue">单次</span></td><td>采气一厂食堂 1 台</td><td>2026-06-24 08:40:00</td><td>系统自动</td><td><span class="tag tag-orange">进行中</span></td><td>0 / 1</td><td>0</td><td><a class="link" href="edge-alert-center.html">1 条</a></td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
<tr><td>CFG-PUSH-0624-01</td><td>配置同步</td><td><span class="tag tag-blue">定时</span></td><td>全部食堂 28 台</td><td>每天 06:00</td><td>平台运营</td><td><span class="tag tag-green">已完成</span></td><td>28 / 28</td><td>0</td><td>—</td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
<tr><td>UPG-20260624-002</td><td>升级任务</td><td><span class="tag tag-blue">单次</span></td><td>炼化中心食堂 2 台</td><td>2026-06-24 11:00:00</td><td>运维李工</td><td><span class="tag tag-red">部分失败</span></td><td>1 / 2</td><td>1</td><td><a class="link" href="edge-alert-center.html">2 条</a></td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
<tr><td>TASK-20260624-021</td><td>生产任务</td><td><span class="tag tag-blue">立即</span></td><td>总部一号食堂 1 台</td><td>2026-06-24 09:12:00</td><td>营养运营</td><td><span class="tag tag-green">已完成</span></td><td>1 / 1</td><td>0</td><td>—</td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
<tr><td>FACE-BATCH-0624-04</td><td>人脸增量</td><td><span class="tag tag-blue">单次</span></td><td>采气一厂食堂 1 台</td><td>2026-06-24 08:40:00</td><td>系统自动</td><td><span class="tag tag-orange">进行中</span></td><td>0 / 1</td><td>0</td><td><a class="link" href="edge-alert-center.html">1 条</a></td><td class="td-actions"><div class="action-links"><a class="link" href="edge-dispatch-detail.html">查看详情</a></div></td></tr>
|
||||
<tr><td>CFG-PUSH-0624-01</td><td>配置同步</td><td><span class="tag tag-blue">定时</span></td><td>全部食堂 28 台</td><td>每天 06:00</td><td>平台运营</td><td><span class="tag tag-green">已完成</span></td><td>28 / 28</td><td>0</td><td>—</td><td class="td-actions"><div class="action-links"><a class="link" href="edge-dispatch-detail.html">查看详情</a></div></td></tr>
|
||||
<tr><td>UPG-20260624-002</td><td>升级任务</td><td><span class="tag tag-blue">单次</span></td><td>炼化中心食堂 2 台</td><td>2026-06-24 11:00:00</td><td>运维李工</td><td><span class="tag tag-red">部分失败</span></td><td>1 / 2</td><td>1</td><td><a class="link" href="edge-alert-center.html">2 条</a></td><td class="td-actions"><div class="action-links"><a class="link" href="edge-dispatch-detail.html">查看详情</a></div></td></tr>
|
||||
<tr><td>TASK-20260624-021</td><td>生产任务</td><td><span class="tag tag-blue">立即</span></td><td>总部一号食堂 1 台</td><td>2026-06-24 09:12:00</td><td>营养运营</td><td><span class="tag tag-green">已完成</span></td><td>1 / 1</td><td>0</td><td>—</td><td class="td-actions"><div class="action-links"><a class="link" href="edge-dispatch-detail.html">查看详情</a></div></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tip-card">
|
||||
<div class="tip-title">调度规则提示</div>
|
||||
<div class="tip-list">
|
||||
<div>1. 单次任务适合临时下发,如补发人脸增量、紧急生产任务。</div>
|
||||
<div>2. 定时任务适合每日配置、基础资料、规则包等固定时间同步。</div>
|
||||
<div>3. 对已成功服务器默认不重复覆盖,需强制覆盖时应在任务策略中明确指定。</div>
|
||||
<div class="pagination">
|
||||
<span>共 126 条,每页显示 10 条</span>
|
||||
<div class="pagination__controls">
|
||||
<button class="page-btn" disabled>上一页</button>
|
||||
<button class="page-btn active">1</button>
|
||||
<button class="page-btn">2</button>
|
||||
<button class="page-btn">3</button>
|
||||
<button class="page-btn">...</button>
|
||||
<button class="page-btn">13</button>
|
||||
<button class="page-btn">下一页</button>
|
||||
<select class="page-size"><option>10 条/页</option><option>20 条/页</option><option>50 条/页</option></select>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -28,7 +28,6 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.page-header{display:flex;align-items:center;justify-content:space-between;background:#fff;border-radius:var(--radius-md);padding:18px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);}
|
||||
.page-header__title{font-size:var(--font-xl);font-weight:700;}
|
||||
.page-header__desc{margin-top:6px;font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-header__meta{font-size:var(--font-sm);color:var(--text-placeholder);}
|
||||
.stats-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px;}
|
||||
.stat-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 18px;}
|
||||
@@ -49,7 +48,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
|
||||
.table-card__title{font-size:var(--font-base);font-weight:600;}
|
||||
.table-wrap{overflow-x:auto;}
|
||||
.table-wrap table{min-width:1640px;}
|
||||
.table-wrap table{min-width:1720px;}
|
||||
table{width:100%;border-collapse:collapse;}
|
||||
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);white-space:nowrap;vertical-align:middle;}
|
||||
@@ -65,6 +64,14 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.tag-gray{background:#F5F5F5;color:#999;}
|
||||
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);text-decoration:none;}
|
||||
.link:hover{color:#40a9ff;}
|
||||
.action-links{display:flex;align-items:center;gap:8px;}
|
||||
.td-actions{min-width:210px;}
|
||||
.pagination{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-top:1px solid var(--border);font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.pagination__controls{display:flex;align-items:center;gap:8px;}
|
||||
.page-btn{min-width:32px;height:32px;padding:0 10px;border:1px solid var(--border);background:#fff;border-radius:var(--radius-sm);font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;}
|
||||
.page-btn.active{border-color:var(--primary);background:var(--primary);color:#fff;}
|
||||
.page-btn:disabled{background:#F5F5F5;color:var(--text-placeholder);cursor:not-allowed;}
|
||||
.page-size{height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 8px;background:#fff;color:var(--text-secondary);}
|
||||
.drawer-mask{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:none;}
|
||||
.drawer-mask.show{display:block;}
|
||||
.drawer{position:absolute;right:0;top:0;bottom:0;width:560px;background:#fff;box-shadow:-6px 0 24px rgba(0,0,0,.12);display:flex;flex-direction:column;}
|
||||
@@ -77,6 +84,20 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.detail-label{font-size:var(--font-xs);color:var(--text-placeholder);}
|
||||
.detail-value{font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.section-title{font-size:var(--font-sm);font-weight:600;margin:16px 0 10px;padding-left:8px;border-left:3px solid var(--primary);}
|
||||
.trace-panel{display:none;margin-top:14px;}
|
||||
.trace-summary{display:flex;align-items:center;justify-content:space-between;background:#F8FBFF;border:1px solid #D6E9FF;border-radius:var(--radius-sm);padding:10px 12px;margin-bottom:12px;font-size:var(--font-sm);}
|
||||
.trace-summary__meta{color:var(--text-secondary);}
|
||||
.trace-timeline{position:relative;padding-left:24px;}
|
||||
.trace-timeline::before{content:'';position:absolute;left:7px;top:6px;bottom:6px;width:2px;background:#D9E6F7;}
|
||||
.trace-step{position:relative;margin-bottom:14px;}
|
||||
.trace-step__dot{position:absolute;left:-24px;top:4px;width:16px;height:16px;border-radius:50%;background:#fff;border:2px solid var(--primary);box-shadow:0 0 0 3px #E6F7FF;}
|
||||
.trace-step__dot--success{border-color:var(--success);box-shadow:0 0 0 3px #F6FFED;}
|
||||
.trace-step__dot--warning{border-color:var(--warning);box-shadow:0 0 0 3px #FFF7E6;}
|
||||
.trace-step__dot--gray{border-color:#BFBFBF;box-shadow:0 0 0 3px #F5F5F5;}
|
||||
.trace-step__card{background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);padding:12px 14px;box-shadow:var(--shadow-sm);}
|
||||
.trace-step__head{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:var(--font-sm);font-weight:600;margin-bottom:6px;}
|
||||
.trace-step__time{font-size:var(--font-xs);color:var(--text-placeholder);white-space:nowrap;}
|
||||
.trace-step__desc{font-size:var(--font-sm);color:var(--text-secondary);line-height:1.6;}
|
||||
.toast{position:fixed;top:76px;left:50%;transform:translateX(-50%) translateY(-12px);background:#fff;border-left:4px solid var(--primary);box-shadow:var(--shadow-md);padding:10px 18px;border-radius:var(--radius-sm);font-size:var(--font-sm);opacity:0;pointer-events:none;transition:all .25s;z-index:1200;}
|
||||
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
|
||||
</style>
|
||||
@@ -97,11 +118,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<section class="page-header">
|
||||
<div><div class="page-header__title">数据上报管理</div><div class="page-header__desc">从全局视角查看所有边缘服务器的数据上报日志,定位上报失败、重试、延迟和数据回传中断问题。</div></div>
|
||||
<div class="page-header__meta">最近刷新:2026-06-24 09:26:00</div>
|
||||
</section>
|
||||
|
||||
<section class="stats-grid">
|
||||
<div class="stat-card"><div class="stat-card__value">4,286</div><div class="stat-card__label">当日上报总量</div><div class="stat-card__hint">全部服务器汇总</div></div>
|
||||
<div class="stat-card"><div class="stat-card__value" style="color:var(--success)">4,102</div><div class="stat-card__label">上报成功</div><div class="stat-card__hint">成功率 95.7%</div></div>
|
||||
@@ -117,7 +133,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="filter-item"><label>数据类型</label><select class="filter-select"><option>全部</option><option>就餐流水</option><option>称重记录</option><option>设备日志</option><option>监控图片</option></select></div>
|
||||
<div class="filter-item"><label>上报状态</label><select class="filter-select"><option>全部</option><option>已上报</option><option>待重试</option><option>上报失败</option></select></div>
|
||||
<div class="filter-item"><label>发生时间</label><input class="filter-input" type="date"></div>
|
||||
<div class="filter-item"><label>关键字</label><input class="filter-input" placeholder="业务编号 / 设备编号"></div>
|
||||
<button class="btn btn-primary" onclick="showToast('已刷新上报日志')">查询</button>
|
||||
<button class="btn btn-default" onclick="showToast('正在导出上报日志')">导出日志</button>
|
||||
</section>
|
||||
@@ -126,40 +141,90 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="table-card__header"><div class="table-card__title">边缘服务器上报日志</div><button class="btn btn-default" onclick="showToast('已筛选高风险上报记录')">仅看异常</button></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>食堂</th><th>边缘服务器</th><th>数据类型</th><th>业务编号</th><th>来源设备</th><th>产生时间</th><th>最近上报时间</th><th>上报状态</th><th>中心服务器受理状态</th><th>重试次数</th><th>失败原因</th><th>关联告警</th><th>操作</th></tr></thead>
|
||||
<thead><tr><th>食堂</th><th>边缘服务器</th><th>业务类型</th><th>业务编号</th><th>产生时间</th><th>上报时间</th><th>上报状态</th><th>中心服务器受理状态</th><th>重试次数</th><th>失败原因</th><th>关联告警</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>炼化中心食堂</td><td><a class="link" href="edge-server-detail.html">炼化中心餐线服务器</a></td><td>就餐流水</td><td>MEAL-20260624-0781</td><td>结算终端 01</td><td>2026-06-24 08:21:18</td><td>2026-06-24 09:21:20</td><td><span class="tag tag-red">上报失败</span></td><td><span class="tag tag-gray">未受理</span></td><td>8</td><td>服务器离线,等待恢复</td><td><a class="link" href="edge-alert-center.html">ALM-20260624-091</a></td><td class="td-actions"><a class="link" onclick="openDrawer('MEAL-20260624-0781')">查看详情</a></td></tr>
|
||||
<tr><td>采气一厂食堂</td><td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td><td>称重记录</td><td>WEIGH-20260624-0148</td><td>餐线营养秤 02</td><td>2026-06-24 08:42:03</td><td>2026-06-24 09:18:33</td><td><span class="tag tag-orange">待重试</span></td><td><span class="tag tag-orange">受理超时</span></td><td>3</td><td>MQ 连接超时</td><td><a class="link" href="edge-alert-center.html">ALM-20260624-078</a></td><td class="td-actions"><a class="link" onclick="openDrawer('WEIGH-20260624-0148')">查看详情</a></td></tr>
|
||||
<tr><td>总部一号食堂</td><td><a class="link" href="edge-server-detail.html">总部一号食堂服务器</a></td><td>设备日志</td><td>LOG-20260624-0311</td><td>组配秤 03</td><td>2026-06-24 09:05:48</td><td>2026-06-24 09:06:03</td><td><span class="tag tag-green">已上报</span></td><td><span class="tag tag-green">已受理</span></td><td>0</td><td>—</td><td>—</td><td class="td-actions"><a class="link" onclick="openDrawer('LOG-20260624-0311')">查看详情</a></td></tr>
|
||||
<tr><td>输气站小食堂</td><td><a class="link" href="edge-server-detail.html">输气站小食堂服务器</a></td><td>监控图片</td><td>IMG-20260624-0096</td><td>后厨摄像头 01</td><td>2026-06-24 08:58:27</td><td>2026-06-24 09:00:11</td><td><span class="tag tag-green">已上报</span></td><td><span class="tag tag-blue">受理中</span></td><td>0</td><td>—</td><td>—</td><td class="td-actions"><a class="link" onclick="openDrawer('IMG-20260624-0096')">查看详情</a></td></tr>
|
||||
<tr><td>炼化中心食堂</td><td><a class="link" href="edge-server-detail.html">炼化中心餐线服务器</a></td><td>餐线结算</td><td>MEAL-20260624-0781</td><td>2026-06-24 08:21:18</td><td>2026-06-24 09:21:20</td><td><span class="tag tag-red">上报失败</span></td><td><span class="tag tag-gray">未受理</span></td><td>8</td><td>服务器离线,等待恢复</td><td><a class="link" href="edge-alert-center.html">ALM-20260624-091</a></td><td class="td-actions"><div class="action-links"><a class="link" onclick="openDrawer('MEAL-20260624-0781')">查看详情</a><a class="link" onclick="openLogDrawer('MEAL-20260624-0781')">查看日志</a><a class="link" onclick="openTraceDrawer('MEAL-20260624-0781')">上报轨迹</a></div></td></tr>
|
||||
<tr><td>采气一厂食堂</td><td><a class="link" href="edge-server-detail.html">采气一厂后厨服务器</a></td><td>营养称重</td><td>WEIGH-20260624-0148</td><td>2026-06-24 08:42:03</td><td>2026-06-24 09:18:33</td><td><span class="tag tag-orange">待重试</span></td><td><span class="tag tag-orange">受理超时</span></td><td>3</td><td>MQ 连接超时</td><td><a class="link" href="edge-alert-center.html">ALM-20260624-078</a></td><td class="td-actions"><div class="action-links"><a class="link" onclick="openDrawer('WEIGH-20260624-0148')">查看详情</a><a class="link" onclick="openLogDrawer('WEIGH-20260624-0148')">查看日志</a><a class="link" onclick="openTraceDrawer('WEIGH-20260624-0148')">上报轨迹</a></div></td></tr>
|
||||
<tr><td>总部一号食堂</td><td><a class="link" href="edge-server-detail.html">总部一号食堂服务器</a></td><td>设备运行</td><td>LOG-20260624-0311</td><td>2026-06-24 09:05:48</td><td>2026-06-24 09:06:03</td><td><span class="tag tag-green">已上报</span></td><td><span class="tag tag-green">已受理</span></td><td>0</td><td>—</td><td>—</td><td class="td-actions"><div class="action-links"><a class="link" onclick="openDrawer('LOG-20260624-0311')">查看详情</a><a class="link" onclick="openLogDrawer('LOG-20260624-0311')">查看日志</a><a class="link" onclick="openTraceDrawer('LOG-20260624-0311')">上报轨迹</a></div></td></tr>
|
||||
<tr><td>输气站小食堂</td><td><a class="link" href="edge-server-detail.html">输气站小食堂服务器</a></td><td>图像采集</td><td>IMG-20260624-0096</td><td>2026-06-24 08:58:27</td><td>2026-06-24 09:00:11</td><td><span class="tag tag-green">已上报</span></td><td><span class="tag tag-blue">受理中</span></td><td>0</td><td>—</td><td>—</td><td class="td-actions"><div class="action-links"><a class="link" onclick="openDrawer('IMG-20260624-0096')">查看详情</a><a class="link" onclick="openLogDrawer('IMG-20260624-0096')">查看日志</a><a class="link" onclick="openTraceDrawer('IMG-20260624-0096')">上报轨迹</a></div></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<span>共 286 条,每页显示 10 条</span>
|
||||
<div class="pagination__controls">
|
||||
<button class="page-btn" disabled>上一页</button>
|
||||
<button class="page-btn active">1</button>
|
||||
<button class="page-btn">2</button>
|
||||
<button class="page-btn">3</button>
|
||||
<button class="page-btn">...</button>
|
||||
<button class="page-btn">29</button>
|
||||
<button class="page-btn">下一页</button>
|
||||
<select class="page-size"><option>10 条/页</option><option>20 条/页</option><option>50 条/页</option></select>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div class="drawer-mask" id="drawerMask">
|
||||
<div class="drawer">
|
||||
<div class="drawer__header"><div class="drawer__title">上报日志详情</div><button class="drawer__close" onclick="closeDrawer()">×</button></div>
|
||||
<div class="drawer__header"><div class="drawer__title" id="drawerTitle">上报日志详情</div><button class="drawer__close" onclick="closeDrawer()">×</button></div>
|
||||
<div class="drawer__body">
|
||||
<div class="detail-grid">
|
||||
<div class="detail-grid" id="detailGrid">
|
||||
<div class="detail-item"><div class="detail-label">业务编号</div><div class="detail-value" id="detailBizId">WEIGH-20260624-0148</div></div>
|
||||
<div class="detail-item"><div class="detail-label">边缘服务器</div><div class="detail-value">采气一厂后厨服务器</div></div>
|
||||
<div class="detail-item"><div class="detail-label">数据类型</div><div class="detail-value">称重记录</div></div>
|
||||
<div class="detail-item"><div class="detail-label">来源设备</div><div class="detail-value">餐线营养秤 02</div></div>
|
||||
<div class="detail-item"><div class="detail-label">业务类型</div><div class="detail-value">营养称重</div></div>
|
||||
<div class="detail-item"><div class="detail-label">产生时间</div><div class="detail-value">2026-06-24 08:42:03</div></div>
|
||||
<div class="detail-item"><div class="detail-label">当前状态</div><div class="detail-value"><span class="tag tag-orange">待重试</span></div></div>
|
||||
</div>
|
||||
<div class="section-title">处理轨迹</div>
|
||||
<div class="detail-item"><div class="detail-value">09:18:33 第 3 次重试失败,原因:MQ 连接超时。</div></div>
|
||||
<div class="detail-item"><div class="detail-value">09:05:21 第 2 次重试失败,边缘服务器已切换备用通道。</div></div>
|
||||
<div class="detail-item"><div class="detail-value">08:42:04 首次写入边缘本地库成功,等待异步上传。</div></div>
|
||||
<div class="section-title">处理动作</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<div class="section-title" id="trackTitle">处理轨迹</div>
|
||||
<div class="detail-item"><div class="detail-value" id="logLine1">09:18:33 第 3 次重试失败,原因:MQ 连接超时。</div></div>
|
||||
<div class="detail-item"><div class="detail-value" id="logLine2">09:05:21 第 2 次重试失败,边缘服务器已切换备用通道。</div></div>
|
||||
<div class="detail-item"><div class="detail-value" id="logLine3">08:42:04 首次写入边缘本地库成功,等待异步上传。</div></div>
|
||||
<div class="detail-item"><div class="detail-value" id="logLine4">08:42:05 回执确认待中心服务器返回,轨迹进入收敛状态。</div></div>
|
||||
<div class="section-title" id="actionTitle">处理动作</div>
|
||||
<div id="actionPanel" style="display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<button class="btn btn-primary" onclick="showToast('已加入手动重试队列')">手动重试</button>
|
||||
<button class="btn btn-default" onclick="location.href='edge-server-detail.html'">服务器详情</button>
|
||||
<button class="btn btn-default" onclick="location.href='edge-alert-center.html'">查看告警</button>
|
||||
</div>
|
||||
<div class="trace-panel" id="tracePanel">
|
||||
<div class="trace-summary">
|
||||
<span>业务编号 <strong id="traceBizId">WEIGH-20260624-0148</strong></span>
|
||||
<span class="trace-summary__meta">中心服务器当前状态:等待回执</span>
|
||||
</div>
|
||||
<div class="trace-timeline">
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--success"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>边缘服务器上报</span><span class="trace-step__time">2026-06-24 08:42:04</span></div>
|
||||
<div class="trace-step__desc">本地缓存写入完成,开始向 MQ 发送上报消息。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--warning"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>MQ 接收消息</span><span class="trace-step__time">2026-06-24 09:18:33</span></div>
|
||||
<div class="trace-step__desc">消息进入重试队列,当前处于重发等待状态。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot trace-step__dot--gray"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>云端服务器受理消息</span><span class="trace-step__time">待确认</span></div>
|
||||
<div class="trace-step__desc">中心服务器尚未返回受理结果,等待下一次轮询。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trace-step">
|
||||
<span class="trace-step__dot"></span>
|
||||
<div class="trace-step__card">
|
||||
<div class="trace-step__head"><span>回执确认</span><span class="trace-step__time">--</span></div>
|
||||
<div class="trace-step__desc">收到回执后将关闭重试并同步更新上报状态。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,6 +239,55 @@ function showToast(text){
|
||||
}
|
||||
function openDrawer(bizId){
|
||||
document.getElementById('detailBizId').textContent=bizId;
|
||||
document.getElementById('drawerTitle').textContent='上报日志详情';
|
||||
document.getElementById('trackTitle').textContent='处理轨迹';
|
||||
document.getElementById('detailGrid').style.display='grid';
|
||||
document.getElementById('tracePanel').style.display='none';
|
||||
document.getElementById('trackTitle').style.display='block';
|
||||
document.getElementById('logLine1').style.display='block';
|
||||
document.getElementById('logLine2').style.display='block';
|
||||
document.getElementById('logLine3').style.display='block';
|
||||
document.getElementById('logLine4').style.display='block';
|
||||
document.getElementById('logLine1').innerHTML='09:18:33 第 3 次重试失败,原因:MQ 连接超时。';
|
||||
document.getElementById('logLine2').innerHTML='09:05:21 第 2 次重试失败,边缘服务器已切换备用通道。';
|
||||
document.getElementById('logLine3').innerHTML='08:42:04 首次写入边缘本地库成功,等待异步上传。';
|
||||
document.getElementById('logLine4').innerHTML='08:42:05 回执确认待中心服务器返回,轨迹进入收敛状态。';
|
||||
document.getElementById('actionTitle').style.display='block';
|
||||
document.getElementById('actionPanel').style.display='flex';
|
||||
document.getElementById('drawerMask').classList.add('show');
|
||||
}
|
||||
function openLogDrawer(bizId){
|
||||
document.getElementById('detailBizId').textContent=bizId;
|
||||
document.getElementById('drawerTitle').textContent='服务器错误日志';
|
||||
document.getElementById('trackTitle').textContent='错误日志信息';
|
||||
document.getElementById('detailGrid').style.display='grid';
|
||||
document.getElementById('tracePanel').style.display='none';
|
||||
document.getElementById('trackTitle').style.display='block';
|
||||
document.getElementById('logLine1').style.display='block';
|
||||
document.getElementById('logLine2').style.display='block';
|
||||
document.getElementById('logLine3').style.display='block';
|
||||
document.getElementById('logLine4').style.display='block';
|
||||
document.getElementById('logLine1').innerHTML='09:18:33 <span class="tag tag-red">ERROR</span> mq-producer 发送消息超时,topic=edge.report.upload,retry=3。';
|
||||
document.getElementById('logLine2').innerHTML='09:05:21 <span class="tag tag-orange">WARN</span> edge-uploader 备用通道切换完成,等待队列重新投递。';
|
||||
document.getElementById('logLine3').innerHTML='08:42:04 <span class="tag tag-blue">INFO</span> local-store 写入本地缓存成功,payload 校验通过。';
|
||||
document.getElementById('logLine4').innerHTML='08:42:05 <span class="tag tag-red">ERROR</span> server-log 解析失败,无法生成本地错误摘要。';
|
||||
document.getElementById('actionTitle').style.display='none';
|
||||
document.getElementById('actionPanel').style.display='none';
|
||||
document.getElementById('drawerMask').classList.add('show');
|
||||
}
|
||||
function openTraceDrawer(bizId){
|
||||
document.getElementById('detailBizId').textContent=bizId;
|
||||
document.getElementById('drawerTitle').textContent='上报轨迹';
|
||||
document.getElementById('traceBizId').textContent=bizId;
|
||||
document.getElementById('detailGrid').style.display='none';
|
||||
document.getElementById('tracePanel').style.display='block';
|
||||
document.getElementById('trackTitle').style.display='none';
|
||||
document.getElementById('logLine1').style.display='none';
|
||||
document.getElementById('logLine2').style.display='none';
|
||||
document.getElementById('logLine3').style.display='none';
|
||||
document.getElementById('logLine4').style.display='none';
|
||||
document.getElementById('actionTitle').style.display='none';
|
||||
document.getElementById('actionPanel').style.display='none';
|
||||
document.getElementById('drawerMask').classList.add('show');
|
||||
}
|
||||
function closeDrawer(){
|
||||
|
||||
@@ -37,8 +37,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}
|
||||
.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
.summary-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:16px;}
|
||||
.summary-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 18px;}
|
||||
.summary-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:16px;}
|
||||
.summary-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 18px;border:1px solid transparent;cursor:pointer;transition:all .2s;}
|
||||
.summary-card:hover{border-color:var(--primary);transform:translateY(-1px);}
|
||||
.summary-card__value{font-size:var(--font-xxl);font-weight:700;line-height:1;}
|
||||
.summary-card__label{font-size:var(--font-sm);color:var(--text-secondary);margin-top:8px;}
|
||||
.summary-card__hint{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:8px;}
|
||||
@@ -112,23 +113,13 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<main class="main">
|
||||
<div class="breadcrumb"><a href="edge-server-management.html">边缘服务器管理</a> / 边缘服务器详情</div>
|
||||
|
||||
<section class="page-header">
|
||||
<div>
|
||||
<div class="page-header__title">采气一厂后厨服务器</div>
|
||||
<div class="page-header__desc">EDGE-CQ-017 · 采气一厂食堂 · 后厨机房 · 当前处于告警状态,重点关注上报成功率下降与连接抖动。</div>
|
||||
</div>
|
||||
<div class="page-header__actions">
|
||||
<button class="btn btn-default" onclick="location.href='edge-report-management.html'">查看上报记录</button>
|
||||
<button class="btn btn-default" onclick="location.href='edge-dispatch-management.html'">查看下发任务</button>
|
||||
<button class="btn btn-primary" onclick="location.href='edge-alert-center.html'">查看关联告警</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="summary-grid">
|
||||
<div class="summary-card"><div class="summary-card__value" style="color:var(--warning)">80 / 90</div><div class="summary-card__label">当日上报统计</div><div class="summary-card__hint">成功率 88.9%</div></div>
|
||||
<div class="summary-card"><div class="summary-card__value">3 / 3</div><div class="summary-card__label">当日下发统计</div><div class="summary-card__hint">全部任务已接收</div></div>
|
||||
<div class="summary-card"><div class="summary-card__value" style="color:var(--danger)">3</div><div class="summary-card__label">当日告警</div><div class="summary-card__hint">1 条未恢复</div></div>
|
||||
<div class="summary-card"><div class="summary-card__value">12 / 18</div><div class="summary-card__label">设备在线 / 绑定设备</div><div class="summary-card__hint">餐线设备离线 2 台</div></div>
|
||||
<!-- [交互] 点击跳转至: edge-report-management.html -->
|
||||
<div class="summary-card" onclick="location.href='edge-report-management.html'"><div class="summary-card__value" style="color:var(--warning)">80 / 90</div><div class="summary-card__label">当日上报统计</div><div class="summary-card__hint">成功率 88.9%</div></div>
|
||||
<!-- [交互] 点击跳转至: edge-dispatch-management.html -->
|
||||
<div class="summary-card" onclick="location.href='edge-dispatch-management.html'"><div class="summary-card__value">3 / 3</div><div class="summary-card__label">当日下发统计</div><div class="summary-card__hint">全部任务已接收</div></div>
|
||||
<!-- [交互] 点击跳转至: edge-alert-center.html -->
|
||||
<div class="summary-card" onclick="location.href='edge-alert-center.html'"><div class="summary-card__value" style="color:var(--danger)">3</div><div class="summary-card__label">当日告警</div><div class="summary-card__hint">1 条未恢复</div></div>
|
||||
</section>
|
||||
|
||||
<section class="overview-grid">
|
||||
@@ -141,8 +132,7 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<div class="info-item"><div class="info-label">所属食堂</div><div class="info-value">采气一厂食堂</div></div>
|
||||
<div class="info-item"><div class="info-label">部署位置</div><div class="info-value">后厨机房</div></div>
|
||||
<div class="info-item"><div class="info-label">服务器 IP</div><div class="info-value">10.18.32.17</div></div>
|
||||
<div class="info-item"><div class="info-label">服务版本</div><div class="info-value">v2.3.0</div></div>
|
||||
<div class="info-item"><div class="info-label">配置版本</div><div class="info-value">CFG-20260624-02</div></div>
|
||||
<div class="info-item"><div class="info-label">远程连接</div><div class="info-value">向日葵:3688595/F154SI</div></div>
|
||||
<div class="info-item"><div class="info-label">安装时间</div><div class="info-value">2026-05-12 09:20</div></div>
|
||||
<div class="info-item"><div class="info-label">最近启动</div><div class="info-value">2026-06-24 06:11</div></div>
|
||||
<div class="info-item"><div class="info-label">最近心跳</div><div class="info-value">2026-06-24 09:17:58</div></div>
|
||||
@@ -167,8 +157,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<section class="tabs">
|
||||
<div class="tab active" onclick="switchTab('overview',this)">运行概览</div>
|
||||
<div class="tab" onclick="switchTab('devices',this)">设备接入</div>
|
||||
<div class="tab" onclick="switchTab('report',this)">数据上报</div>
|
||||
<div class="tab" onclick="switchTab('dispatch',this)">数据下发</div>
|
||||
<div class="tab" onclick="switchTab('alert',this)">告警记录</div>
|
||||
<div class="tab" onclick="switchTab('log',this)">运行日志</div>
|
||||
</section>
|
||||
@@ -215,30 +203,6 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="report" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>数据类型</th><th>业务编号</th><th>来源设备</th><th>产生时间</th><th>上报状态</th><th>失败次数</th><th>最近处理时间</th><th>失败原因</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>就餐流水</td><td>MEAL-20260624-0178</td><td>结算终端 01</td><td>2026-06-24 08:11:04</td><td><span class="tag tag-orange">待重试</span></td><td>3</td><td>2026-06-24 09:08:33</td><td>MQ 连接超时</td><td class="td-actions"><a class="link" href="edge-report-management.html">查看全量</a></td></tr>
|
||||
<tr><td>称重记录</td><td>WEIGH-20260624-0148</td><td>餐线营养秤 02</td><td>2026-06-24 08:42:03</td><td><span class="tag tag-green">已上报</span></td><td>0</td><td>2026-06-24 08:42:19</td><td>—</td><td class="td-actions"><a class="link" onclick="showToast('已定位到上报轨迹')">查看轨迹</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="dispatch" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>任务编号</th><th>下发类型</th><th>下发方式</th><th>发起时间</th><th>接收状态</th><th>应用状态</th><th>完成时间</th><th>失败原因</th><th>操作</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>FACE-BATCH-0624-04</td><td>人脸增量</td><td>单次</td><td>2026-06-24 08:40:00</td><td><span class="tag tag-green">已接收</span></td><td><span class="tag tag-orange">部分待应用</span></td><td>—</td><td>2 台终端尚未回执</td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
<tr><td>CFG-PUSH-0624-01</td><td>配置同步</td><td>定时</td><td>2026-06-24 06:00:00</td><td><span class="tag tag-green">已接收</span></td><td><span class="tag tag-green">已完成</span></td><td>2026-06-24 06:02:14</td><td>—</td><td class="td-actions"><a class="link" href="edge-dispatch-detail.html">查看详情</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="alert" class="tab-panel">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
|
||||
@@ -30,7 +30,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.page-header__title{font-size:var(--font-xl);font-weight:700;color:var(--text-primary);}
|
||||
.page-header__desc{margin-top:6px;font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-header__meta{font-size:var(--font-sm);color:var(--text-placeholder);}
|
||||
.stats-row{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px;}
|
||||
.stats-row{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:16px;}
|
||||
.stat-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 18px;border:1px solid transparent;transition:all .2s;cursor:pointer;}
|
||||
.stat-card:hover{border-color:var(--primary);transform:translateY(-1px);}
|
||||
.stat-card__value{font-size:var(--font-xxl);font-weight:700;line-height:1;color:var(--text-primary);}
|
||||
@@ -52,7 +52,8 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
|
||||
.table-card__title{font-size:var(--font-base);font-weight:600;}
|
||||
.table-card__content{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;}
|
||||
.table-card__content table{min-width:1420px;}
|
||||
.table-card__actions{display:flex;align-items:center;gap:8px;}
|
||||
.table-card__content table{min-width:1720px;}
|
||||
table{width:100%;border-collapse:collapse;}
|
||||
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);white-space:nowrap;}
|
||||
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);white-space:nowrap;vertical-align:middle;}
|
||||
@@ -68,6 +69,16 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.tag-gray{background:#F5F5F5;color:#999;}
|
||||
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);text-decoration:none;}
|
||||
.link:hover{color:#40a9ff;}
|
||||
.link+.link{margin-left:12px;}
|
||||
.td-actions{white-space:nowrap;}
|
||||
/* 胶囊开关:启动/停用 */
|
||||
.switch{position:relative;display:inline-block;width:44px;height:22px;cursor:pointer;vertical-align:middle;}
|
||||
.switch__track{position:absolute;inset:0;background:#E8E8E8;border-radius:11px;transition:background .2s;}
|
||||
.switch__thumb{position:absolute;top:2px;left:2px;width:18px;height:18px;background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,0.2);transition:left .2s;}
|
||||
.switch--on .switch__track{background:var(--primary);}
|
||||
.switch--on .switch__thumb{left:24px;}
|
||||
.switch__label{margin-left:8px;font-size:var(--font-xs);color:var(--text-secondary);vertical-align:middle;}
|
||||
.switch--on+.switch__label{color:var(--primary);}
|
||||
.server-name{font-weight:600;color:var(--primary);}
|
||||
.server-sub{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:3px;}
|
||||
.metric-warning{color:var(--warning);font-weight:600;}
|
||||
@@ -76,6 +87,25 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
.pagination span{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.page-btn{width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;cursor:pointer;font-size:var(--font-sm);}
|
||||
.page-btn.active,.page-btn:hover{background:var(--primary);border-color:var(--primary);color:#fff;}
|
||||
.modal-mask{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:1000;align-items:center;justify-content:center;}
|
||||
.modal-mask.show{display:flex;}
|
||||
.modal{width:760px;max-height:86vh;background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-md);display:flex;flex-direction:column;overflow:hidden;}
|
||||
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
|
||||
.modal__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);}
|
||||
.modal__close{width:28px;height:28px;border:none;background:transparent;border-radius:var(--radius-sm);font-size:22px;line-height:1;cursor:pointer;color:var(--text-placeholder);}
|
||||
.modal__close:hover{background:#F5F5F5;color:var(--text-primary);}
|
||||
.modal__body{padding:22px 24px;overflow-y:auto;}
|
||||
.modal__footer{display:flex;justify-content:flex-end;gap:8px;padding:14px 24px;border-top:1px solid var(--border);}
|
||||
.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px 20px;}
|
||||
.form-item{display:flex;flex-direction:column;gap:6px;}
|
||||
.form-item--full{grid-column:1 / -1;}
|
||||
.form-label{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.form-label.required::before{content:"*";color:var(--danger);margin-right:4px;}
|
||||
.form-input,.form-select,.form-textarea{width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);font-size:var(--font-sm);outline:none;background:#fff;}
|
||||
.form-input,.form-select{height:36px;padding:0 12px;}
|
||||
.form-textarea{height:72px;padding:10px 12px;resize:none;font-family:inherit;}
|
||||
.form-input:focus,.form-select:focus,.form-textarea:focus{border-color:var(--primary);}
|
||||
.form-tip{font-size:var(--font-xs);color:var(--text-placeholder);line-height:1.5;}
|
||||
.toast{position:fixed;top:76px;left:50%;transform:translateX(-50%) translateY(-12px);background:#fff;border-left:4px solid var(--primary);box-shadow:var(--shadow-md);padding:10px 18px;border-radius:var(--radius-sm);font-size:var(--font-sm);opacity:0;pointer-events:none;transition:all .25s;z-index:1200;}
|
||||
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
|
||||
</style>
|
||||
@@ -112,30 +142,18 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<section class="page-header">
|
||||
<div>
|
||||
<div class="page-header__title">边缘服务器管理</div>
|
||||
<div class="page-header__desc">按食堂维度集中查看边缘服务器在线状态、当日上报统计、当日下发统计和当日告警情况,作为服务器运行管理总入口。</div>
|
||||
</div>
|
||||
<div class="page-header__meta">数据更新时间:2026-06-24 09:18:26</div>
|
||||
</section>
|
||||
|
||||
<section class="stats-row">
|
||||
<div class="stat-card" onclick="quickFilter('全部服务器')"><div class="stat-card__value">28</div><div class="stat-card__label">接入服务器数</div><div class="stat-card__hint">覆盖 16 个食堂</div></div>
|
||||
<div class="stat-card" onclick="quickFilter('在线服务器')"><div class="stat-card__value" style="color:var(--success)">24</div><div class="stat-card__label">在线服务器</div><div class="stat-card__hint">近 3 分钟有心跳</div></div>
|
||||
<div class="stat-card" onclick="quickFilter('离线服务器')"><div class="stat-card__value" style="color:var(--danger)">2</div><div class="stat-card__label">离线服务器</div><div class="stat-card__hint">需运维优先处理</div></div>
|
||||
<div class="stat-card" onclick="quickFilter('高风险服务器')"><div class="stat-card__value" style="color:var(--warning)">4</div><div class="stat-card__label">高风险服务器</div><div class="stat-card__hint">告警或统计异常</div></div>
|
||||
<div class="stat-card" onclick="quickFilter('上报异常服务器')"><div class="stat-card__value" style="color:var(--warning)">3</div><div class="stat-card__label">上报异常服务器</div><div class="stat-card__hint">当日成功率低于 95%</div></div>
|
||||
<div class="stat-card" onclick="quickFilter('当日有告警')"><div class="stat-card__value" style="color:var(--danger)">17</div><div class="stat-card__label">当日告警总数</div><div class="stat-card__hint">含服务器、设备、上报、下发</div></div>
|
||||
</section>
|
||||
|
||||
<section class="filter-bar">
|
||||
<div class="filter-item"><label>所属区域</label><select class="filter-select"><option>全部</option><option>CQ一区</option><option>CQ二区</option><option>CQ三厂</option></select></div>
|
||||
<div class="filter-item"><label>所属食堂</label><select class="filter-select"><option>全部</option><option>总部一号食堂</option><option>采气一厂食堂</option><option>炼化中心食堂</option></select></div>
|
||||
<div class="filter-item"><label>在线状态</label><select class="filter-select"><option>全部</option><option>在线</option><option>离线</option><option>异常</option></select></div>
|
||||
<div class="filter-item"><label>健康状态</label><select class="filter-select"><option>全部</option><option>正常</option><option>告警</option><option>严重</option></select></div>
|
||||
<div class="filter-item"><label>服务版本</label><select class="filter-select"><option>全部</option><option>v2.3.1</option><option>v2.3.0</option><option>v2.2.8</option></select></div>
|
||||
<div class="filter-item"><label>关键字</label><input class="filter-input" type="text" placeholder="服务器名称 / 编号 / 食堂"></div>
|
||||
<button class="btn btn-primary" onclick="showToast('已按条件刷新边缘服务器列表')">查询</button>
|
||||
<button class="btn btn-default" onclick="showToast('已重置筛选条件')">重置</button>
|
||||
</section>
|
||||
@@ -143,7 +161,11 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<section class="table-card">
|
||||
<div class="table-card__header">
|
||||
<div class="table-card__title">边缘服务器清单</div>
|
||||
<div><button class="btn btn-default" onclick="showToast('正在导出边缘服务器清单')">导出清单</button></div>
|
||||
<div class="table-card__actions">
|
||||
<button class="btn btn-default" onclick="showToast('正在导出边缘服务器清单')">导出清单</button>
|
||||
<!-- [交互] 点击打开弹窗: 新增服务器 -->
|
||||
<button class="btn btn-primary" onclick="openServerModal()">新增服务器</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
@@ -151,14 +173,16 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<tr>
|
||||
<th>服务器名称</th>
|
||||
<th>所属食堂</th>
|
||||
<th>部署位置</th>
|
||||
<th>服务器 IP</th>
|
||||
<th>在线状态</th>
|
||||
<th>健康状态</th>
|
||||
<th>服务版本</th>
|
||||
<th>当日上报统计</th>
|
||||
<th>当日下发统计</th>
|
||||
<th>当日告警统计</th>
|
||||
<th>最近心跳时间</th>
|
||||
<th>最后上报成功</th>
|
||||
<th>启动/停用</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -166,67 +190,77 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
<tr>
|
||||
<td><div class="server-name">总部一号食堂服务器</div><div class="server-sub">EDGE-CQ-001</div></td>
|
||||
<td>总部一号食堂</td>
|
||||
<td>主楼一层机房</td>
|
||||
<td>10.18.32.01</td>
|
||||
<td><span class="tag tag-green">在线</span></td>
|
||||
<td><span class="tag tag-green">正常</span></td>
|
||||
<td>v2.3.1</td>
|
||||
<td>90 / 90</td>
|
||||
<td>3 / 3</td>
|
||||
<td>0</td>
|
||||
<td>2026-06-24 09:18:10</td>
|
||||
<td>2026-06-24 09:17:43</td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a></td>
|
||||
<td><span class="switch switch--on" onclick="toggleSwitch(this)"><span class="switch__track"></span><span class="switch__thumb"></span></span><span class="switch__label">启动</span></td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a><a class="link" onclick="openServerModal('edit')">编辑</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="server-name">采气一厂后厨服务器</div><div class="server-sub">EDGE-CQ-017</div></td>
|
||||
<td>采气一厂食堂</td>
|
||||
<td>后厨机房</td>
|
||||
<td>10.18.32.17</td>
|
||||
<td><span class="tag tag-orange">异常</span></td>
|
||||
<td><span class="tag tag-orange">告警</span></td>
|
||||
<td>v2.3.0</td>
|
||||
<td><span class="metric-warning">80 / 90</span></td>
|
||||
<td>3 / 3</td>
|
||||
<td><span class="metric-warning">3</span></td>
|
||||
<td>2026-06-24 09:17:58</td>
|
||||
<td>2026-06-24 08:41:11</td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a></td>
|
||||
<td><span class="switch switch--on" onclick="toggleSwitch(this)"><span class="switch__track"></span><span class="switch__thumb"></span></span><span class="switch__label">启动</span></td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a><a class="link" onclick="openServerModal('edit')">编辑</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="server-name">炼化中心餐线服务器</div><div class="server-sub">EDGE-CQ-024</div></td>
|
||||
<td>炼化中心食堂</td>
|
||||
<td>餐线弱电柜</td>
|
||||
<td>10.18.32.24</td>
|
||||
<td><span class="tag tag-red">离线</span></td>
|
||||
<td><span class="tag tag-red">严重</span></td>
|
||||
<td>v2.2.8</td>
|
||||
<td><span class="metric-danger">56 / 90</span></td>
|
||||
<td><span class="metric-danger">1 / 4</span></td>
|
||||
<td><span class="metric-danger">8</span></td>
|
||||
<td>2026-06-24 08:54:09</td>
|
||||
<td>2026-06-24 08:12:18</td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a></td>
|
||||
<td><span class="switch" onclick="toggleSwitch(this)"><span class="switch__track"></span><span class="switch__thumb"></span></span><span class="switch__label">停用</span></td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a><a class="link" onclick="openServerModal('edit')">编辑</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="server-name">输气站小食堂服务器</div><div class="server-sub">EDGE-CQ-032</div></td>
|
||||
<td>输气站小食堂</td>
|
||||
<td>收银台机柜</td>
|
||||
<td>10.18.32.32</td>
|
||||
<td><span class="tag tag-green">在线</span></td>
|
||||
<td><span class="tag tag-orange">告警</span></td>
|
||||
<td>v2.3.1</td>
|
||||
<td><span class="metric-warning">72 / 80</span></td>
|
||||
<td>2 / 2</td>
|
||||
<td>1</td>
|
||||
<td>2026-06-24 09:18:02</td>
|
||||
<td>2026-06-24 08:50:33</td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a></td>
|
||||
<td><span class="switch switch--on" onclick="toggleSwitch(this)"><span class="switch__track"></span><span class="switch__thumb"></span></span><span class="switch__label">启动</span></td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a><a class="link" onclick="openServerModal('edit')">编辑</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="server-name">培训中心食堂服务器</div><div class="server-sub">EDGE-CQ-041</div></td>
|
||||
<td>培训中心食堂</td>
|
||||
<td>后勤办公室</td>
|
||||
<td>10.18.32.41</td>
|
||||
<td><span class="tag tag-green">在线</span></td>
|
||||
<td><span class="tag tag-green">正常</span></td>
|
||||
<td>v2.3.1</td>
|
||||
<td>84 / 84</td>
|
||||
<td>2 / 2</td>
|
||||
<td>0</td>
|
||||
<td>2026-06-24 09:18:14</td>
|
||||
<td>2026-06-24 09:14:41</td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a></td>
|
||||
<td><span class="switch switch--on" onclick="toggleSwitch(this)"><span class="switch__track"></span><span class="switch__thumb"></span></span><span class="switch__label">启动</span></td>
|
||||
<td class="td-actions"><a class="link" href="edge-server-detail.html">查看详情</a><a class="link" onclick="openServerModal('edit')">编辑</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -242,6 +276,34 @@ tbody tr:hover td.td-actions{background:#F8FBFF;}
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- 新增服务器弹窗 -->
|
||||
<div class="modal-mask" id="serverModal" onclick="if(event.target===this)closeServerModal()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<div class="modal__title">新增服务器</div>
|
||||
<button class="modal__close" onclick="closeServerModal()">×</button>
|
||||
</div>
|
||||
<div class="modal__body">
|
||||
<div class="form-grid">
|
||||
<div class="form-item"><label class="form-label required">服务器名称</label><input class="form-input" id="serverName" type="text" value="采气二厂后厨服务器"></div>
|
||||
<div class="form-item"><label class="form-label required">服务器编号</label><input class="form-input" id="serverCode" type="text" value="EDGE-CQ-052"></div>
|
||||
<div class="form-item"><label class="form-label required">所属食堂</label><select class="form-select" id="serverCanteen"><option>采气二厂食堂</option><option>总部一号食堂</option><option>采气一厂食堂</option><option>炼化中心食堂</option><option>培训中心食堂</option></select></div>
|
||||
<div class="form-item"><label class="form-label required">部署位置</label><input class="form-input" type="text" value="后厨机房"></div>
|
||||
<div class="form-item"><label class="form-label required">服务器 IP</label><input class="form-input" type="text" value="10.18.32.52"></div>
|
||||
<div class="form-item"><label class="form-label required">远程连接</label><input class="form-input" type="text" value="向日葵:3688595/F154SI"></div>
|
||||
<div class="form-item"><label class="form-label required">初始健康状态</label><select class="form-select"><option>正常</option><option>告警</option><option>严重</option></select></div>
|
||||
<div class="form-item"><label class="form-label">本地数据库</label><select class="form-select"><option>正常</option><option>待初始化</option><option>异常</option></select></div>
|
||||
<div class="form-item"><label class="form-label">消息连接</label><select class="form-select"><option>正常</option><option>待联调</option><option>间歇抖动</option></select></div>
|
||||
<div class="form-item form-item--full"><label class="form-label">备注</label><textarea class="form-textarea" placeholder="填写部署说明、负责人或联调注意事项">新服务器上线后需完成心跳联调、上报通道验证和下发任务回执校验。</textarea><div class="form-tip">字段与清单、详情页保持一致:服务器名称、编号、所属食堂、部署位置、IP、服务版本、配置版本、运行状态。</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeServerModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="saveServer()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast">操作已完成</div>
|
||||
<script>
|
||||
function showToast(text){
|
||||
@@ -253,6 +315,33 @@ function showToast(text){
|
||||
function quickFilter(type){
|
||||
showToast('已切换到“'+type+'”视角');
|
||||
}
|
||||
function openServerModal(mode){
|
||||
var modal=document.getElementById('serverModal');
|
||||
var titleEl=modal.querySelector('.modal__title');
|
||||
titleEl.textContent= mode==='edit' ? '编辑服务器' : '新增服务器';
|
||||
modal.classList.add('show');
|
||||
}
|
||||
// 切换胶囊开关:启动/停用
|
||||
function toggleSwitch(el){
|
||||
var isOn=el.classList.toggle('switch--on');
|
||||
var label=el.nextElementSibling;
|
||||
if(label && label.classList.contains('switch__label')){
|
||||
label.textContent=isOn ? '启动' : '停用';
|
||||
}
|
||||
showToast(isOn ? '已启动该边缘服务器的心跳与上报通道' : '已停用该边缘服务器,停止心跳与上报');
|
||||
}
|
||||
function closeServerModal(){
|
||||
document.getElementById('serverModal').classList.remove('show');
|
||||
}
|
||||
function saveServer(){
|
||||
var name=document.getElementById('serverName').value || '新服务器';
|
||||
var code=document.getElementById('serverCode').value || '未填写编号';
|
||||
closeServerModal();
|
||||
showToast('已新增“'+name+'”('+code+')');
|
||||
}
|
||||
document.addEventListener('keydown',function(event){
|
||||
if(event.key==='Escape'){closeServerModal();}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user