feat: 健康监测管理端运维中心18个页面+设备管理优化+全部弹窗截图+PRD文档更新+员工端设计总览

管理端:
- 新增运维中心18个页面(终端设置×2、日常监测×9、事件监听×1、日志管理×5、SDC信息×1)
- 设备管理页深度优化:删除开关列、上传频次改输入框、新增类型配置、设备配置弹窗
- 日常监测各页面独立完善(体温状态标签、压力时间段、心率静息心率、活动总活动时长等)
- 错误日志改为sleep调用异常格式、任务日志taskFirmwareUpgrade风格、mqtt消息日志watch/设备序列号/cmd格式
- 新增43张页面及弹窗截图,PRD文档全面更新

员工端:
- 新增健康监测设计总览页面及截图
- index.html SITE_MAP同步更新
This commit is contained in:
liuyunqin
2026-06-03 10:30:35 +08:00
parent 2f7830a336
commit 871a2d46ce
86 changed files with 8758 additions and 307 deletions
+58 -1
View File
@@ -1,6 +1,63 @@
# 健康监测管理端 CHANGELOG
## [2026-05-26]
## [2026-06-03]
### 新增 — 穿戴监测运维中心 · 18个页面
- **终端设置(2页)**:默认配置、配置信息(含配置详情弹窗,JSON语法高亮展示)
- **日常监测(9页)**:心电图、血氧、体温(含状态标签)、压力(开始/结束时间)、锻炼、心率(含静息心率)、睡眠、SDC信息(含数据类型下载)、活动(含总活动时长)
- **事件监听(1页)**:事件监听列表及详情
- **日志管理(5页)**:网络切换、版本更新、错误日志(`sleep调用异常.Code=X`格式)、任务日志(含错误堆栈弹窗)、MQTT消息日志(含JSON高亮弹窗)
### 修改 — 穿戴监测设备管理页深度优化
- **tool-manage.html**:删除列表4列设备监测开关、上传频次改为输入框(默认60分钟)、新增类型配置弹窗、开关按钮左侧加"监测开关"文字说明、开关默认开启、"更多"菜单中"监测开关"更名为"设备配置"
- **monitor-spo2.html / monitor-temp.html**:表头数据值添加单位(% / ℃)
- **monitor-heartrate.html**:列表去掉数据值加粗样式
- **monitor-activity.html**:中高强度运动时间去掉加粗样式,总活动时长单位从"分钟"改为"小时",表头标注单位
- **sdc-overview.html**:详情弹窗去掉顶部渐变banner,数据类型改为纯文本
- **log-error.html**:日志内容改为`sleep调用异常.Code=2,message=Invalid parameters`格式,详情弹窗浅灰长文本展示
- **log-task.html**:任务名称改为`taskFirmwareUpgrade`代码风格,新增详情按钮,处理失败展示完整堆栈错误
- **log-mqtt.html**:主题格式改为`watch/设备序列号/cmd`,命令类型统一为cmd,请求类型统一为send
### 新增 — 全部页面截图(43张)
- 运维中心页面截图17张、各页面弹窗截图26张(设备配置、绑定、导入、通知发送、详情等)
- 更新管理端穿戴监测已修改页面截图8张
### 修改 — PRD文档更新
- 新增运维中心全部18个页面描述
- 穿戴监测结构更新,纳入运维中心子模块
- 日常监测每个页面独立说明(不再使用通用模板描述)
- 所有弹窗补充截图和字段描述
## [2026-06-02]
### 新增 — 穿戴监测运维中心 · 默认配置页面
- **`wearable/ops/terminal-default-config.html`** 终端默认配置
- 三 Tab 布局:阈值默认配置 / 上传默认配置 / 开关默认配置
- Tab 1(阈值默认配置):数据类型筛选、新增 + 通知手表操作、列表含数据类型/单位/阈值下限/阈值上限/创建时间/更新时间/操作
- Tab 2(上传默认配置):数据类型筛选、新增 + 通知手表操作、列表含数据类型/上传频率(分钟)/创建时间/更新时间/操作
- Tab 3(开关默认配置):数据类型筛选、新增 + 通知手表操作、列表含数据类型/上传开关(tag样式)/操作
- 各 Tab 均含新增/编辑弹窗和删除确认弹窗,交互完整
## [2026-06-01]
### 修改 — 穿戴监测侧边栏重构(26 个文件)
- **统一替换侧边栏折叠模式**:将所有穿戴监测页面的侧边栏从旧的 `.sidebar-group__header` / `.sidebar-sub-item` 二层结构,升级为 `.sidebar-subgroup` 三层嵌套折叠模式,与 `scale-device.html` 保持一致
- **组 Awearable/ 根目录,8 个文件)**`tool-manage.html``bind-record.html``user-data.html``exception-event.html``notification.html``dept-stat.html``personal-stat.html``dept-report.html`
- 替换旧 CSS`.sidebar-group__header``.sidebar-group__body``.sidebar-sub-item``.sidebar-divider``.sidebar-section__title`)为新 `.sidebar-subgroup__header` 等 CSS
- 替换侧边栏 HTML:运维中心改为三层嵌套 subgroup 结构(运维中心 > 终端设置/日常监测/日志管理/SDC信息 > 叶子页面)
- 替换 `toggleGroup` script 为 `toggleSubgroup` + 自动展开祖先 subgroup 的 IIFE
- **组 Bops/ 目录,18 个文件)**:`terminal-default-config.html``terminal-config-info.html``monitor-ecg.html``monitor-spo2.html``monitor-temp.html``monitor-stress.html``monitor-exercise.html``monitor-heartrate.html``monitor-sleep.html``monitor-activity.html``alarm-data.html``log-network.html``log-version.html``log-error.html``log-task.html``log-mqtt.html``sdc-overview.html``sdc-json.html`
- 完整替换 `<aside>` 块为标准三层嵌套结构,各页面仅对应 active 项不同
- 替换旧 CSS 为新 `.sidebar-subgroup__header` 等 CSS
- 替换 script 为 `toggleSubgroup` + 自动展开逻辑
### 新增 — 单位报表二级详情页面补齐
+595 -23
View File
@@ -34,8 +34,29 @@
│ ├── 告警记录
│ ├── 通知消息
│ ├── 单位数据统计
│ ├── 部门报表
── 个人数据统计
│ ├── 单位数据分析报告
── 个人数据统计
│ └── 运维中心
│ ├── 终端设置
│ │ ├── 默认配置
│ │ └── 配置信息
│ ├── 日常监测
│ │ ├── 心电图信息
│ │ ├── 血氧信息
│ │ ├── 体温信息
│ │ ├── 压力信息
│ │ ├── 锻炼信息
│ │ ├── 心率信息
│ │ ├── 睡眠信息
│ │ ├── SDC信息
│ │ └── 活动信息
│ ├── 事件监听
│ └── 日志管理
│ ├── 手表网络切换日志
│ ├── 版本更新历史
│ ├── 手表错误日志
│ ├── 任务日志
│ └── mqtt消息日志
├── 体重监测
│ ├── 体重秤设备管理 ⇄ 新增设备弹窗
│ ├── 体重秤监测数据 → 监测详情
@@ -105,9 +126,57 @@
| 20 | 告警记录 | 告警事件列表 | wearable/exception-event.html | 页面 |
| 21 | 通知消息 | 通知消息列表 | wearable/notification.html | 页面 |
| 22 | 单位数据统计 | 单位数据统计 | wearable/dept-stat.html | 页面 |
| 23 | 部门报表 | 部门报表 | wearable/dept-report.html | 页面 |
| 23 | 单位数据分析报告 | 单位数据分析报告 | wearable/dept-report.html | 页面 |
| 24 | 个人数据统计 | 个人数据统计 | wearable/personal-stat.html | 页面 |
### 运维中心 - 终端设置
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
|------|----------|-----------|------|------|
| 84 | 默认配置 | 默认配置列表 | wearable/ops/terminal-default-config.html | 页面 |
| 85 | 配置信息 | 配置信息列表 | wearable/ops/terminal-config-info.html | 页面 |
| | | 配置详情 | (弹窗) | 弹窗 |
### 运维中心 - 日常监测
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
|------|----------|-----------|------|------|
| 86 | 心电图信息 | 心电图信息列表 | wearable/ops/monitor-ecg.html | 页面 |
| 87 | 血氧信息 | 血氧信息列表 | wearable/ops/monitor-spo2.html | 页面 |
| | | 血氧详情 | (弹窗) | 弹窗 |
| 88 | 体温信息 | 体温信息列表 | wearable/ops/monitor-temp.html | 页面 |
| | | 体温详情 | (弹窗) | 弹窗 |
| 89 | 压力信息 | 压力信息列表 | wearable/ops/monitor-stress.html | 页面 |
| | | 压力详情 | (弹窗) | 弹窗 |
| 90 | 锻炼信息 | 锻炼信息列表 | wearable/ops/monitor-exercise.html | 页面 |
| 91 | 心率信息 | 心率信息列表 | wearable/ops/monitor-heartrate.html | 页面 |
| | | 心率详情 | (弹窗) | 弹窗 |
| 92 | 睡眠信息 | 睡眠信息列表 | wearable/ops/monitor-sleep.html | 页面 |
| 93 | SDC信息 | SDC信息列表 | wearable/ops/sdc-overview.html | 页面 |
| | | SDC数据详情 | (弹窗) | 弹窗 |
| 94 | 活动信息 | 活动信息列表 | wearable/ops/monitor-activity.html | 页面 |
| | | 活动详情 | (弹窗) | 弹窗 |
### 运维中心 - 事件监听
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
|------|----------|-----------|------|------|
| 95 | 事件监听 | 事件监听列表 | wearable/ops/alarm-data.html | 页面 |
### 运维中心 - 日志管理
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
|------|----------|-----------|------|------|
| 96 | 手表网络切换日志 | 网络切换日志列表 | wearable/ops/log-network.html | 页面 |
| | | 网络切换详情 | (弹窗) | 弹窗 |
| 97 | 版本更新历史 | 版本更新日志列表 | wearable/ops/log-version.html | 页面 |
| 98 | 手表错误日志 | 错误日志列表 | wearable/ops/log-error.html | 页面 |
| | | 错误日志详情 | (弹窗) | 弹窗 |
| 99 | 任务日志 | 任务日志列表 | wearable/ops/log-task.html | 页面 |
| | | 任务详情 | (弹窗) | 弹窗 |
| 100 | mqtt消息日志 | mqtt消息日志列表 | wearable/ops/log-mqtt.html | 页面 |
| | | mqtt消息详情 | (弹窗) | 弹窗 |
### 体重监测
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
@@ -178,8 +247,8 @@
| 序号 | 二级菜单 | 页面/弹窗 | 文件 | 类型 |
|------|----------|-----------|------|------|
| 82 | 系统脏数据 | 系统脏数据列表 | exception-dirty.html | 页面 |
| 83 | 结果异常 | 结果异常列表 | exception-result.html | 页面 |
| 101 | 系统脏数据 | 系统脏数据列表 | exception-dirty.html | 页面 |
| 102 | 结果异常 | 结果异常列表 | exception-result.html | 页面 |
---
@@ -542,24 +611,69 @@
![页面截图](screenshots/wearable/tool-manage.jpg)
**功能说明:** 管理穿戴监测设备的全生命周期,包括设备入库、绑定员工、换绑、报废等操作。
**功能说明:** 管理穿戴监测设备的全生命周期,包括设备入库、绑定员工、换绑、报废、设备配置等操作。
**筛选条件:** 设备编码(输入框)、所属单位(下拉)、绑定状态(下拉)、绑定员工(输入框)、员工编号(输入框)、设备厂商(下拉)、设备型号(下拉)
**表格列(多级表头)**
- 第一级:复选框、设备编码、所属单位、入库日期、厂商、设备型号、绑定状态、绑定员工、员工编号、绑定日期、设备监测开关、操作
- 设备监测开关子列:心率、血氧、压力、体温
**表格列:** 复选框、设备编码、所属单位、入库日期、厂商、设备型号、绑定状态、绑定员工、员工编号、绑定日期、操作
**业务规则:**
- 绑定状态:已绑定(绿色)、未绑定(灰色)、已报废(红色)
- 操作项根据设备状态动态显示:未绑定可"绑定员工",已绑定可"换绑/解绑",均可"报废"
- 绑定状态:已绑定(绿色)、未绑定(灰色)
- 操作项根据设备状态动态显示:未绑定可"绑定员工",已绑定可"解除绑定"
- 更多菜单包含:设备配置、删除
**交互说明:**
- 点击"新增设备"打开新增设备表单弹窗
- 点击"批量入库"打开文件上传弹窗(Excel导入)
- 点击"绑定员工"打开绑定弹窗(选择员工)
- 点击"批量入库导入"打开文件上传弹窗(Excel导入)
- 点击"查看导入任务"查看导入任务状态
- 点击"导出列表数据"导出数据
- 点击"查看导出任务"查看导出任务状态
- 点击"绑定员工"打开绑定弹窗(搜索选择员工)
- 点击"解除绑定"打开确认弹窗
- 点击"绑定记录"打开该设备的绑定历史弹窗
- 支持导出列表数据
- 点击更多菜单→"设备配置"打开设备配置弹窗
- 点击更多菜单→"删除"删除设备
**新增设备弹窗:**
![新增设备弹窗](screenshots/wearable/tool-manage/add.jpg)
**字段:** 设备编码 *、所属单位 *(下拉)、设备厂商 *(下拉)、设备型号 *(下拉)、入库日期
**绑定员工弹窗:**
![绑定员工弹窗](screenshots/wearable/tool-manage/bind.jpg)
**字段:** 设备编码(只读)、绑定员工 *(搜索选择员工卡片)、绑定日期
**解除绑定确认弹窗:**
![解除绑定确认弹窗](screenshots/wearable/tool-manage/unbind-confirm.jpg)
**字段:** 设备编码、所属单位、绑定员工
**绑定记录弹窗:**
![绑定记录弹窗](screenshots/wearable/tool-manage/bind-record.jpg)
**字段:** 顶部设备信息(设备编码、厂家、型号、入库日期、所属单位);表格列:员工姓名、工号、所属单位、绑定时间、解绑时间、状态
**批量入库弹窗:**
![批量入库弹窗](screenshots/wearable/tool-manage/import.jpg)
**字段:** 下载导入模板按钮、文件上传区域(支持 .xlsx / .xls,不超过 10MB
**设备配置弹窗:**
![设备配置弹窗](screenshots/wearable/tool-manage/monitor-switch.jpg)
**字段:**
- 顶部:设备编码信息卡 + "新增类型配置"按钮
- 监测类型卡片列表(心率/血氧/压力/体温):每个卡片含开关、阈值上下限、上传频次(输入框,单位分钟)
- 点击"新增类型配置"展开新增表单:下拉选择监测类型 + 开关 + 阈值 + 上传频次,点击"保存"追加新卡片
- 开关默认开启,开关左侧标注"监测开关"文字说明
- 开关关闭时,该卡片设置项置灰不可编辑
---
@@ -598,7 +712,9 @@
- 点击"查看详情"打开数据详情弹窗
- 支持导出列表数据
**数据详情弹窗960px宽)**
**数据详情弹窗:**
![用户数据详情弹窗](screenshots/wearable/user-data-detail.jpg)
弹窗顶部:员工信息栏(蓝色背景),展示姓名、编号、单位、部门、设备编码
@@ -639,9 +755,12 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
- 点击"查看详情"打开告警详情弹窗(含位置信息)
- 支持导出列表数据
---
**告警详情弹窗:**
### 21. 通知消息(wearable/notification.html
![告警详情弹窗](screenshots/wearable/exception-event-detail.jpg)
- 采集信息区块:员工姓名、工号、所属单位、所属部门、手机号码、设备编码、告警类型、告警值、阈值范围、告警时间、告警位置
- 位置信息区块:经度、纬度、详细地址
![页面截图](screenshots/wearable/notification.jpg)
@@ -658,16 +777,25 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
- 支持导出列表数据
**发送通知弹窗:**
![发送通知弹窗](screenshots/wearable/notification/send.jpg)
- 通知标题 *(输入框)
- 通知内容 *(多行文本域)
- 通知范围 *(单选:全员通知 / 指定员工)
- 指定员工选择(通知范围为"指定员工"时显示):左侧员工列表(支持搜索)+ 右侧已选员工列表,支持添加/移除
**通知详情弹窗:**
![通知详情弹窗](screenshots/wearable/notification/detail.jpg)
- 展示通知标题、发送时间、发送人、通知内容全文
- 通知范围为"指定员工"时,底部展示通知对象表格(员工姓名、编号、单位、部门)
**阅读统计弹窗:**
![阅读统计弹窗](screenshots/wearable/notification/read-stat.jpg)
- 顶部统计卡片:目标人数、已读人数、未读人数、阅读率
- Tab切换:已读 / 未读
- 表格列:员工姓名、员工编号、所属单位、所属部门、阅读时间(已读Tab)
@@ -687,11 +815,19 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
**员工每日明细表格列:** 序号、员工姓名、员工编号、部门名称、佩戴时长、数据上报次数、是否有异常
**交互说明:**
- 点击"是否有异常"列的"有"标签打开佩戴明细弹窗
- 支持导出列表数据
**佩戴明细弹窗:**
![佩戴明细弹窗](screenshots/wearable/dept-stat/detail.jpg)
- 顶部标题:佩戴明细 + 部门名称
- 表格列:员工姓名、员工编号、部门名称、佩戴时长、数据上报次数、是否有异常
---
### 23. 部门报表wearable/dept-report.html
### 23. 单位数据分析报告wearable/dept-report.html
![页面截图](screenshots/wearable/dept-report.jpg)
@@ -739,7 +875,443 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
---
## 五、体重监测
## 五、运维中心
### 终端设置
#### 84. 默认配置(wearable/ops/terminal-default-config.html
![页面截图](screenshots/wearable/ops/terminal-default-config.jpg)
**功能说明:** 管理穿戴设备的默认终端配置模板,支持配置模板的增删改查。
**表格列:** 配置名称、适用设备类型、创建时间、更新时间、操作
**交互说明:**
- 支持新增、编辑、删除配置
- 支持导出列表数据
---
#### 85. 配置信息(wearable/ops/terminal-config-info.html
![页面截图](screenshots/wearable/ops/terminal-config-info.jpg)
**功能说明:** 查看已下发的设备配置信息历史记录,支持按设备和时间筛选。
**筛选条件:** 设备编码(输入框)、日期范围
**表格列:** 设备编码、配置时间、配置信息(JSON预览截断)、操作
**交互说明:**
- 点击"详情"打开配置详情弹窗
- 支持导出列表数据
**配置详情弹窗:**
![配置详情弹窗](screenshots/wearable/ops/terminal-config-info-detail.jpg)
- 顶部信息:设备编码、配置时间
- 内容区:深色代码块展示完整 JSON 配置(语法高亮:key/字符串/数值/布尔值分色)
- 支持滚动查看
---
### 日常监测
#### 86. 心电图信息(wearable/ops/monitor-ecg.html
![页面截图](screenshots/wearable/ops/monitor-ecg.jpg)
**功能说明:** 查看穿戴设备采集的心电图数据记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![心电图详情弹窗](screenshots/wearable/ops/monitor-ecg-detail.jpg)
- 采集信息区块:设备编码、数据值、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 87. 血氧信息(wearable/ops/monitor-spo2.html
![页面截图](screenshots/wearable/ops/monitor-spo2.jpg)
**功能说明:** 查看穿戴设备采集的血氧饱和度数据记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值(%)、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![血氧详情弹窗](screenshots/wearable/ops/monitor-spo2-detail.jpg)
- 采集信息区块:设备编码、数据值(%)、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 88. 体温信息(wearable/ops/monitor-temp.html
![页面截图](screenshots/wearable/ops/monitor-temp.jpg)
**功能说明:** 查看穿戴设备采集的体温数据记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值(℃)、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![体温详情弹窗](screenshots/wearable/ops/monitor-temp-detail.jpg)
- 顶部渐变卡片:大字体体温值 + 体温状态标签(正常/偏低/偏高)
- 采集信息区块:设备编码、数据值(℃)、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 89. 压力信息(wearable/ops/monitor-stress.html
![页面截图](screenshots/wearable/ops/monitor-stress.jpg)
**功能说明:** 查看穿戴设备采集的压力数据记录,按时间段展示。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值(分)、开始时间、结束时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![压力详情弹窗](screenshots/wearable/ops/monitor-stress-detail.jpg)
- 采集信息区块:设备编码、数据值(分)、开始时间、结束时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 90. 锻炼信息(wearable/ops/monitor-exercise.html
![页面截图](screenshots/wearable/ops/monitor-exercise.jpg)
**功能说明:** 查看穿戴设备采集的锻炼数据记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![锻炼详情弹窗](screenshots/wearable/ops/monitor-exercise-detail.jpg)
- 采集信息区块:设备编码、数据值、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 91. 心率信息(wearable/ops/monitor-heartrate.html
![页面截图](screenshots/wearable/ops/monitor-heartrate.jpg)
**功能说明:** 查看穿戴设备采集的心率数据记录,含静息心率。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值(次/分)、静息心率(次/分)、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![心率详情弹窗](screenshots/wearable/ops/monitor-heartrate-detail.jpg)
- 采集信息区块:设备编码、数据值(次/分)、静息心率(次/分)、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 92. 睡眠信息(wearable/ops/monitor-sleep.html
![页面截图](screenshots/wearable/ops/monitor-sleep.jpg)
**功能说明:** 查看穿戴设备采集的睡眠数据记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据值、监测时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![睡眠详情弹窗](screenshots/wearable/ops/monitor-sleep-detail.jpg)
- 采集信息区块:设备编码、数据值、监测时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 93. SDC信息(wearable/ops/sdc-overview.html
![页面截图](screenshots/wearable/ops/sdc-overview.jpg)
**功能说明:** 查看 SDCSensor Data Collection)传感器数据采集汇总信息,按数据类型分组展示。
**筛选条件:** 设备编码(输入框)、数据类型(下拉:步数/距离/卡路里/爬楼高度/中高强度运动时间)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、数据类型(彩色标签)、日期、数据值、详细数据(下载)、创建日期、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 点击"下载"下载详细数据文件
- 支持导出列表数据
**详情弹窗:**
![SDC详情弹窗](screenshots/wearable/ops/sdc-overview-detail.jpg)
- 采集信息区块:设备编码、数据类型、日期、数据值、创建日期
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 94. 活动信息(wearable/ops/monitor-activity.html
![页面截图](screenshots/wearable/ops/monitor-activity.jpg)
**功能说明:** 展示员工穿戴设备采集的活动信息,包括中高强度运动时间和总活动时长。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、中高强度运动时间(分钟)、总活动时长(小时)、监测日期(年月日)、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![活动详情弹窗](screenshots/wearable/ops/monitor-activity-detail.jpg)
- 采集信息区块:设备编码、中高强度运动时间(分钟)、总活动时长(小时)、监测日期(年月日)、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
### 事件监听
#### 95. 事件监听(wearable/ops/alarm-data.html
![页面截图](screenshots/wearable/ops/alarm-data.jpg)
**功能说明:** 查看穿戴设备产生的事件监听数据。
**筛选条件:** 设备编码(输入框)、事件类型(下拉)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、事件类型、事件值、阈值范围、事件时间、创建时间、操作
**交互说明:**
- 点击"详情"打开事件详情弹窗
- 支持导出列表数据
**详情弹窗:**
![事件监听详情弹窗](screenshots/wearable/ops/alarm-data-detail.jpg)
- 采集信息区块:设备编码、事件类型、事件值、阈值范围、事件时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
### 日志管理
#### 96. 手表网络切换日志(wearable/ops/log-network.html
![页面截图](screenshots/wearable/ops/log-network.jpg)
**功能说明:** 查看穿戴设备的网络方式切换记录。
**筛选条件:** 设备编码(输入框)、网络方式(下拉:WiFi/Bluetooth)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、网络方式(标签)、更新时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![网络切换详情弹窗](screenshots/wearable/ops/log-network-detail.jpg)
- 采集信息区块:设备编码、网络方式、更新时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 97. 版本更新历史(wearable/ops/log-version.html
![页面截图](screenshots/wearable/ops/log-version.jpg)
**功能说明:** 查看穿戴设备的固件版本更新历史记录。
**筛选条件:** 设备编码(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、旧版本、新版本、更新时间、创建时间、操作
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![版本更新详情弹窗](screenshots/wearable/ops/log-version-detail.jpg)
- 采集信息区块:设备编码、旧版本、新版本、更新时间、创建时间
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 98. 手表错误日志(wearable/ops/log-error.html
![页面截图](screenshots/wearable/ops/log-error.jpg)
**功能说明:** 查看穿戴设备运行过程中产生的错误日志。
**筛选条件:** 设备编码(输入框)、日志类型(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、日志类型(Error标签)、日志时间、日志信息(超长省略)、创建时间、操作
**业务规则:**
- 日志信息格式:`sleep调用异常.Code=2,message=Invalid parameters`
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![错误日志详情弹窗](screenshots/wearable/ops/log-error-detail.jpg)
- 采集信息区块:设备编码、日志类型、日志时间、创建时间、日志信息(浅灰背景长文本完整展示)
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 99. 任务日志(wearable/ops/log-task.html
![页面截图](screenshots/wearable/ops/log-task.jpg)
**功能说明:** 查看设备任务执行日志,包括固件升级、数据同步、配置下发等任务状态。
**筛选条件:** 设备编码(输入框)、任务名称(输入框)、任务状态(下拉:未开始/进行中/已完成/处理失败)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** 设备编码、任务名称(等宽字体,如 `taskFirmwareUpgrade`)、任务状态(标签)、失败原因(超长省略)、任务开始时间、任务结束时间、操作
**业务规则:**
- 任务状态标签:未开始(橙色)、进行中(蓝色)、已完成(绿色)、处理失败(红色)
- 仅处理失败的任务显示失败原因
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![任务日志详情弹窗](screenshots/wearable/ops/log-task-detail.jpg)
- 任务信息区块:设备编码、任务名称、任务状态、任务开始时间、任务结束时间
- 失败原因区块(仅处理失败时显示):深色背景完整展示错误堆栈(`white-space: pre-wrap` 保留换行)
- 绑定员工区块:员工姓名、员工编号、所属单位、所属部门
---
#### 100. mqtt消息日志(wearable/ops/log-mqtt.html
![页面截图](screenshots/wearable/ops/log-mqtt.jpg)
**功能说明:** 查看设备与服务器之间的 MQTT 消息通信记录。
**筛选条件:** mqtt主题(输入框)、命令类型(输入框)、请求类型(输入框)、日期范围
**操作行:** 导出列表数据、查看导出任务
**表格列:** mqtt主题(`watch/设备序列号/cmd` 格式,等宽字体)、消息内容(JSON预览截断)、命令类型(cmd)、请求类型(send)、是否发送成功(成功/未得到回执标签)、创建时间、更新时间、操作
**业务规则:**
- 发送成功标签:成功(绿色)、未得到回执(橙色)
**交互说明:**
- 点击"详情"打开详情弹窗
- 支持导出列表数据
**详情弹窗:**
![mqtt消息详情弹窗](screenshots/wearable/ops/log-mqtt-detail.jpg)
- 消息信息区块:mqtt主题、命令类型、请求类型、是否发送成功、创建时间、更新时间
- 消息内容区块:深色代码块展示完整 JSON 消息(语法高亮)
---
## 六、体重监测
### 25-40. 设备管理与监测数据(4类设备×4页面)
@@ -948,7 +1520,7 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
---
## 、环境监测
## 、环境监测
环境监测模块包含4种监测类型(室内、室外、水质、花粉),每种类型均有相同的页面结构。以下以室内为例说明通用结构,并在后文补充各类型的差异点。
@@ -1175,9 +1747,9 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
---
## 、异常事件
## 、异常事件
### 82. 系统脏数据(exception-dirty.html
### 101. 系统脏数据(exception-dirty.html
![页面截图](screenshots/exception-dirty.jpg)
@@ -1192,7 +1764,7 @@ Tab标签:总览、心率、血氧、压力、睡眠、体温、锻炼、步
---
### 83. 结果异常(exception-result.html
### 102. 结果异常(exception-result.html
![页面截图](screenshots/exception-result.jpg)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 92 KiB

@@ -1,156 +0,0 @@
# 健康监测模块截图更新清单
本次代码变更涉及以下页面需要重新截图,请按照清单逐一完成。
## 一、档案模块
### 1. 个人监测数据 (archive-personal.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\archive-personal.html`
**截图保存:** `doc/screenshots/archive-personal.jpg`
**变更内容:**
- 表格新增「健康现状」列(显示A~E类标签,不同颜色)
- 表格新增「操作」列(含"详细信息"链接)
**截图要求:** 确保表格完整显示,包含新增的两列
---
### 2. 穿戴监测详情 (archive-unit-wearable-detail.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\archive-unit-wearable-detail.html`
**截图保存:** `doc/screenshots/archive-unit-wearable-detail.jpg`
**变更内容:**
- Tab标签名称变更:"异常次数" → "告警次数""异常人数" → "告警人数"
- "告警次数"Tab 新增「告警类型」筛选下拉框
- 表格列名变更:"总异常次数" → "总告警次数""最后异常时间" → "最后告警时间""异常类型" → "告警类型"
**截图要求:** 切换到"告警次数"或"告警人数"Tab,确保新名称清晰可见
---
### 3. 算法模型 (archive-algorithm.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\archive-algorithm.html`
**截图保存:** `doc/screenshots/archive-algorithm.jpg`
**变更内容:**
- 新增"新增"按钮功能(打开弹窗)
- 操作列"预览"和"编辑"功能完善
**截图要求:** 主列表页面截图即可(弹窗功能可选)
---
## 二、健康排查模块
### 4. 员工排查统计 (record-user.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\health-checkup\record-user.html`
**截图保存:** `doc/screenshots/health-checkup/record-user.jpg`
**变更内容:**
- 表格列名变更:"连续签到天数" → "连续记录天数""最新签到时间" → "最新记录时间"
- 操作列变更:"签到记录" → "排查记录"
**截图要求:** 确保表格列名清晰可见
---
### 5. 单位排查统计 (record-dept.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\health-checkup\record-dept.html`
**截图保存:** `doc/screenshots/health-checkup/record-dept.jpg`
**变更内容:**
- 筛选条件:"筛选日期" → "记录日期"
- 表格列名变更:"已签到人数" → "已记录人数""未签到人数" → "未记录人数""签到日期" → "记录日期"
**截图要求:** 确保筛选栏和表格列名都清晰可见
---
## 三、穿戴监测模块
### 6. 告警记录 (exception-event.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\wearable\exception-event.html`
**截图保存:** `doc/screenshots/wearable/exception-event.jpg`
**变更内容:**
- 侧边栏菜单名称:"异常事件" → "告警记录"
**截图要求:** 确保侧边栏菜单名称清晰可见
---
### 7. 用户数据 (user-data.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\wearable\user-data.html`
**截图保存:** `doc/screenshots/wearable/user-data.jpg`
**变更内容:**
- 侧边栏菜单名称:"异常事件" → "告警记录"
- 数据详情弹窗 → 锻炼面板表格新增「日期」列
**截图要求:** 主页面截图即可(弹窗内容可选)
---
## 四、体重监测模块
### 8. 蓝牙称设备 (bluetooth-device.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\weight\bluetooth-device.html`
**截图保存:** `doc/screenshots/weight/bluetooth-device.jpg`
**变更内容:**
- 操作列新增"成员查看"链接(位于"详情"和"编辑"之间)
**截图要求:** 确保操作列完整显示,包含新增的"成员查看"链接
---
### 9. 员工数据记录 (employee-data-record.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\weight\employee-data-record.html`
**截图保存:** `doc/screenshots/weight/employee-data-record.jpg`
**变更内容:**
- 操作列:"查看" → "详细信息"
- 测量详情弹窗样式重构(分组展示,网格布局)
**截图要求:** 主页面截图即可(弹窗样式可选)
---
## 五、环境监测模块
### 10. 室内异常报警 (indoor-exception-alarm.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\environment\indoor-exception-alarm.html`
**截图保存:** `doc/screenshots/environment/indoor-exception-alarm.jpg`
**变更内容:**
- 侧边栏移除"花粉-知识科普"菜单项
- 表格列变更:"阈值"拆分为"阈值下限"和"阈值上限"两列
**截图要求:** 确保表格列完整显示,包含拆分后的两列
---
### 11. 室外异常报警 (outdoor-exception-alarm.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\environment\outdoor-exception-alarm.html`
**截图保存:** `doc/screenshots/environment/outdoor-exception-alarm.jpg`
**变更内容:** 同室内异常报警
---
### 12. 水质异常报警 (water-exception-alarm.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\environment\water-exception-alarm.html`
**截图保存:** `doc/screenshots/environment/water-exception-alarm.jpg`
**变更内容:** 同室内异常报警
---
### 13. 花粉异常报警 (pollen-exception-alarm.html)
**文件路径:** `D:\AI\work\platform-prototype\web-admin\health-monitor\environment\pollen-exception-alarm.html`
**截图保存:** `doc/screenshots/environment/pollen-exception-alarm.jpg`
**变更内容:** 同室内异常报警
---
## 截图规范
1. **浏览器:** 使用 Chrome 浏览器,窗口最大化
2. **分辨率:** 1920×1080 或更高
3. **格式:** JPG 格式,质量 85%
4. **内容:** 确保页面主要内容完整,包含侧边栏、顶部导航、筛选栏、表格等
5. **数据:** 使用页面现有的模拟数据即可
6. **命名:** 严格按照上述文件名保存
## 完成后
所有截图完成后,PRD 文档中的截图引用路径已经正确配置,无需修改 Markdown 文件。
@@ -60,6 +60,17 @@
.date-range{display:flex;align-items:center;gap:8px;}
.date-range input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;width:150px;}
.date-range input:focus{border-color:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -96,6 +107,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="filter-bar">
@@ -251,5 +299,9 @@
</div>
</div>
</main>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -70,6 +70,17 @@
.tag-blue{background:#E6F7FF;color:var(--primary);border:1px solid #91D5FF;}
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
.toast.show{opacity:1;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -106,6 +117,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item active">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<!-- 左侧单位树 -->
@@ -228,5 +276,9 @@ function showToast(msg){
renderTree();
renderTable();
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -109,6 +109,17 @@
/* Toast */
.toast{position:fixed;top:60px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:6px;font-size:var(--font-sm);z-index:2000;opacity:0;transition:opacity .3s;pointer-events:none;}
.toast.show{opacity:1;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -145,6 +156,43 @@
<a href="dept-stat.html" class="sidebar-item active">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<!-- Tab切换:二级单位 / 三级单位 -->
@@ -527,5 +575,9 @@ document.querySelectorAll('.link').forEach(function(link) {
});
});
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -81,6 +81,17 @@
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;}
.date-range{display:flex;align-items:center;gap:8px;}
.date-range input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;width:160px;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -117,6 +128,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
@@ -420,5 +468,9 @@ function openDetail(name, empId, type) {
}
document.getElementById('detailModal').addEventListener('click', function(e){ if(e.target===this) this.classList.remove('show'); });
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -104,6 +104,17 @@
.picker-right__item .remove-btn{border:none;background:none;color:var(--text-placeholder);cursor:pointer;font-size:16px;line-height:1;}
.picker-right__item .remove-btn:hover{color:var(--danger);}
.picker-right__empty{font-size:var(--font-sm);color:var(--text-placeholder);text-align:center;padding-top:40px;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -140,6 +151,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<!-- 筛选栏 -->
@@ -622,5 +670,9 @@ document.querySelectorAll('.modal-mask').forEach(function(m){
});
});
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -0,0 +1,536 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 事件监听 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);vertical-align:middle;}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-purple{background:#F9F0FF;color:#722ED1;}
.tag-cyan{background:#E6FFFB;color:#13C2C2;}
.tag-gray{background:#F5F5F5;color:#666;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:640px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
.map-placeholder{width:100%;height:260px;background:#F0F2F5;border-radius:var(--radius-md);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden;}
.map-placeholder__grid{position:absolute;inset:0;background-image:linear-gradient(rgba(0,0,0,0.05) 1px,transparent 1px),linear-gradient(90deg,rgba(0,0,0,0.05) 1px,transparent 1px);background-size:40px 40px;}
.map-placeholder__pin{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;}
.map-placeholder__pin svg{width:32px;height:32px;filter:drop-shadow(0 2px 4px rgba(0,0,0,0.2));}
.map-placeholder__coords{font-size:var(--font-xs);color:var(--text-secondary);background:#fff;padding:4px 10px;border-radius:var(--radius-sm);border:1px solid var(--border);margin-top:6px;font-family:monospace;}
.map-placeholder__error{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;justify-content:center;}
.map-placeholder__error svg{width:40px;height:40px;color:var(--text-placeholder);}
.map-placeholder__error p{font-size:var(--font-sm);color:var(--text-placeholder);margin-top:8px;text-align:center;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item active">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">事件监听</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>事件类型</label>
<select class="filter-select">
<option>全部</option>
<option>压力</option>
<option>体温</option>
<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>
</select>
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">事件记录<small>共 156 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>事件类型</th>
<th>是否异常事件</th>
<th>数据值</th>
<th>阈值上下限</th>
<th>事件发生时间</th>
<th>详细地址</th>
<th>GPS错误信息</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-etype="stress" data-abnormal="yes" data-value="85" data-threshold="0-80" data-time="2026-06-02 08:30:15" data-addr="陕西省西安市雁塔区科技路88号" data-gps="" data-created="2026-06-02 08:30:18" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-lat="34.2265" data-lng="108.9478">
<td><span class="mono">WD-2024-001</span></td>
<td>压力</td>
<td><span class="tag tag-red"></span></td>
<td>85</td>
<td>0-80</td>
<td>2026-06-02 08:30:15</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省西安市雁塔区科技路88号</td>
<td></td>
<td>2026-06-02 08:30:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-etype="fall" data-abnormal="yes" data-value="—" data-threshold="—" data-time="2026-06-02 09:15:42" data-addr="陕西省西安市雁塔区科技路100号" data-gps="" data-created="2026-06-02 09:15:45" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-lat="34.2280" data-lng="108.9502">
<td><span class="mono">WD-2024-001</span></td>
<td>摔倒</td>
<td><span class="tag tag-red"></span></td>
<td></td>
<td></td>
<td>2026-06-02 09:15:42</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省西安市雁塔区科技路100号</td>
<td></td>
<td>2026-06-02 09:15:45</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-etype="heartrate" data-abnormal="yes" data-value="135" data-threshold="60-100" data-time="2026-06-02 10:20:08" data-addr="陕西省西安市高新区锦业路66号" data-gps="" data-created="2026-06-02 10:20:11" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-lat="34.2198" data-lng="108.8935">
<td><span class="mono">WD-2024-002</span></td>
<td>心率</td>
<td><span class="tag tag-red"></span></td>
<td>135</td>
<td>60-100</td>
<td>2026-06-02 10:20:08</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省西安市高新区锦业路66号</td>
<td></td>
<td>2026-06-02 10:20:11</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-etype="spo2" data-abnormal="yes" data-value="88" data-threshold="95-100" data-time="2026-06-02 11:05:33" data-addr="陕西省延安市宝塔区南滨路12号" data-gps="" data-created="2026-06-02 11:05:36" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站" data-lat="36.5965" data-lng="109.4943">
<td><span class="mono">WD-2024-015</span></td>
<td>血氧</td>
<td><span class="tag tag-red"></span></td>
<td>88</td>
<td>95-100</td>
<td>2026-06-02 11:05:33</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省延安市宝塔区南滨路12号</td>
<td></td>
<td>2026-06-02 11:05:36</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-etype="temp" data-abnormal="yes" data-value="38.2" data-threshold="36.0-37.3" data-time="2026-06-02 12:10:20" data-addr="陕西省榆林市榆阳区人民东路35号" data-gps="" data-created="2026-06-02 12:10:23" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-lat="38.2589" data-lng="109.7535">
<td><span class="mono">WD-2024-031</span></td>
<td>体温</td>
<td><span class="tag tag-red"></span></td>
<td>38.2</td>
<td>36.0-37.3</td>
<td>2026-06-02 12:10:20</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省榆林市榆阳区人民东路35号</td>
<td></td>
<td>2026-06-02 12:10:23</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-032" data-etype="alarm" data-abnormal="yes" data-value="—" data-threshold="—" data-time="2026-06-02 13:45:55" data-addr="陕西省榆林市榆阳区西沙路28号" data-gps="" data-created="2026-06-02 13:45:58" data-emp="刘洋" data-empcode="CQ002200" data-unit="采气一厂" data-dept="集输站" data-lat="38.2650" data-lng="109.7320">
<td><span class="mono">WD-2024-032</span></td>
<td>一键告警</td>
<td><span class="tag tag-red"></span></td>
<td></td>
<td></td>
<td>2026-06-02 13:45:55</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省榆林市榆阳区西沙路28号</td>
<td></td>
<td>2026-06-02 13:45:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-etype="location" data-abnormal="no" data-value="—" data-threshold="—" data-time="2026-06-02 14:30:10" data-addr="" data-gps="应用尚未授予定位权限" data-created="2026-06-02 14:30:13" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>定位服务开关修改</td>
<td><span class="tag tag-green"></span></td>
<td></td>
<td></td>
<td>2026-06-02 14:30:10</td>
<td></td>
<td style="color:var(--warning);">应用尚未授予定位权限</td>
<td>2026-06-02 14:30:13</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-etype="heartrate" data-abnormal="yes" data-value="55" data-threshold="60-100" data-time="2026-06-02 15:20:05" data-addr="陕西省汉中市汉台区兴汉路56号" data-gps="" data-created="2026-06-02 15:20:08" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区" data-lat="33.0775" data-lng="107.0356">
<td><span class="mono">WD-2024-060</span></td>
<td>心率</td>
<td><span class="tag tag-red"></span></td>
<td>55</td>
<td>60-100</td>
<td>2026-06-02 15:20:05</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省汉中市汉台区兴汉路56号</td>
<td></td>
<td>2026-06-02 15:20:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-etype="stress" data-abnormal="no" data-value="72" data-threshold="0-80" data-time="2026-06-02 16:05:18" data-addr="陕西省汉中市南郑区大河坎镇" data-gps="" data-created="2026-06-02 16:05:21" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区" data-lat="33.0520" data-lng="107.0180">
<td><span class="mono">WD-2024-061</span></td>
<td>压力</td>
<td><span class="tag tag-green"></span></td>
<td>72</td>
<td>0-80</td>
<td>2026-06-02 16:05:18</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省汉中市南郑区大河坎镇</td>
<td></td>
<td>2026-06-02 16:05:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-etype="fall" data-abnormal="yes" data-value="—" data-threshold="—" data-time="2026-06-02 17:30:40" data-addr="陕西省汉中市南郑区大河坎镇" data-gps="" data-created="2026-06-02 17:30:43" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区" data-lat="33.0510" data-lng="107.0165">
<td><span class="mono">WD-2024-061</span></td>
<td>摔倒</td>
<td><span class="tag tag-red"></span></td>
<td></td>
<td></td>
<td>2026-06-02 17:30:40</td>
<td style="max-width:160px;overflow:hidden;text-overflow:ellipsis;">陕西省汉中市南郑区大河坎镇</td>
<td></td>
<td>2026-06-02 17:30:43</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-etype="stress" data-abnormal="yes" data-value="92" data-threshold="0-80" data-time="2026-06-02 18:10:25" data-addr="" data-gps="位置信息获取失败" data-created="2026-06-02 18:10:28" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>压力</td>
<td><span class="tag tag-red"></span></td>
<td>92</td>
<td>0-80</td>
<td>2026-06-02 18:10:25</td>
<td></td>
<td style="color:var(--warning);">位置信息获取失败</td>
<td>2026-06-02 18:10:28</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-etype="spo2" data-abnormal="yes" data-value="90" data-threshold="95-100" data-time="2026-06-02 19:05:30" data-addr="" data-gps="定位超时" data-created="2026-06-02 19:05:33" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td>血氧</td>
<td><span class="tag tag-red"></span></td>
<td>90</td>
<td>95-100</td>
<td>2026-06-02 19:05:30</td>
<td></td>
<td style="color:var(--warning);">定位超时</td>
<td>2026-06-02 19:05:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 156 条</span>
<button class="page-btn">«</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">16</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">事件详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">事件信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>事件类型</label><span id="d-etype"></span></div>
<div class="detail-item"><label>是否异常事件</label><span id="d-abnormal"></span></div>
<div class="detail-item"><label>数据值</label><span id="d-value"></span></div>
<div class="detail-item"><label>阈值上下限</label><span id="d-threshold"></span></div>
<div class="detail-item"><label>事件发生时间</label><span id="d-time"></span></div>
<div class="detail-item"><label>详细地址</label><span id="d-addr"></span></div>
<div class="detail-item"><label>GPS错误信息</label><span id="d-gps"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
<div class="detail-section-title">位置信息</div>
<div class="map-placeholder" id="mapPlaceholder">
<div class="map-placeholder__grid"></div>
<!-- 正常定位 -->
<div class="map-placeholder__pin" id="mapPin">
<svg viewBox="0 0 32 32" fill="none">
<path d="M16 2C10.477 2 6 6.477 6 12c0 7.5 10 18 10 18s10-10.5 10-18c0-5.523-4.477-10-10-10z" fill="#FF4D4F"/>
<circle cx="16" cy="12" r="4" fill="#fff"/>
</svg>
<span class="map-placeholder__coords" id="d-coords"></span>
</div>
<!-- GPS错误状态 -->
<div class="map-placeholder__error" id="mapError" style="display:none;">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/>
<line x1="9" y1="9" x2="15" y2="12" stroke-width="2"/>
</svg>
<p id="d-mapErrorText"></p>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
// 事件类型样式映射
var ETYPE_MAP = {
stress: '压力',
temp: '体温',
heartrate:'心率',
spo2: '血氧',
fall: '摔倒',
alarm: '一键告警',
location: '定位服务开关修改'
};
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var tr = btn.closest('tr');
var d = tr.dataset;
var etype = ETYPE_MAP[d.etype] || d.etype;
var abnormalTag = d.abnormal === 'yes'
? '<span class="tag tag-red">是</span>'
: '<span class="tag tag-green">否</span>';
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-etype').textContent = etype;
document.getElementById('d-abnormal').innerHTML = abnormalTag;
document.getElementById('d-value').textContent = d.value;
document.getElementById('d-threshold').textContent = d.threshold;
document.getElementById('d-time').textContent = d.time;
document.getElementById('d-addr').textContent = d.addr || '—';
document.getElementById('d-gps').textContent = d.gps || '—';
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
// GPS错误处理:有错误信息时隐藏地图定位,显示错误状态
if (d.gps) {
document.getElementById('mapPin').style.display = 'none';
document.getElementById('mapError').style.display = 'flex';
document.getElementById('d-mapErrorText').textContent = d.gps;
} else {
document.getElementById('mapPin').style.display = 'flex';
document.getElementById('mapError').style.display = 'none';
document.getElementById('d-coords').textContent = '纬度: ' + d.lat + ' 经度: ' + d.lng;
}
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,390 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 手表错误日志 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
.log-msg{font-family:'SFMono-Regular',Consolas,Menlo,monospace;font-size:var(--font-xs);color:var(--text-secondary);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item active">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">手表错误日志</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日志类型</label>
<input class="filter-input" placeholder="请输入日志类型" style="min-width:150px;">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">错误日志<small>共 67 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>日志类型</th>
<th>日志时间</th>
<th>日志信息</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<tr data-code="WD-2024-001" data-type="Error" data-logtime="2026-06-02 08:05:30" data-logmsg="sleep调用异常.Code=2,message=Invalid parameters" data-created="2026-06-02 08:05:35" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 08:05:30</td>
<td><span class="log-msg">sleep调用异常.Code=2,message=Invalid parameters</span></td>
<td>2026-06-02 08:05:35</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-type="Error" data-logtime="2026-06-02 09:12:18" data-logmsg="sensorRead调用异常.Code=5,message=Device not responding" data-created="2026-06-02 09:12:21" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 09:12:18</td>
<td><span class="log-msg">sensorRead调用异常.Code=5,message=Device not responding</span></td>
<td>2026-06-02 09:12:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-type="Error" data-logtime="2026-06-02 07:30:44" data-logmsg="bleConnect调用异常.Code=3,message=Connection timeout" data-created="2026-06-02 07:30:47" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 07:30:44</td>
<td><span class="log-msg">bleConnect调用异常.Code=3,message=Connection timeout</span></td>
<td>2026-06-02 07:30:47</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-type="Error" data-logtime="2026-06-02 10:20:12" data-logmsg="mqttPublish调用异常.Code=7,message=Topic not found" data-created="2026-06-02 10:20:15" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 10:20:12</td>
<td><span class="log-msg">mqttPublish调用异常.Code=7,message=Topic not found</span></td>
<td>2026-06-02 10:20:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-type="Error" data-logtime="2026-06-01 22:45:08" data-logmsg="writeFlash调用异常.Code=4,message=Flash write protected" data-created="2026-06-01 22:45:11" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-01 22:45:08</td>
<td><span class="log-msg">writeFlash调用异常.Code=4,message=Flash write protected</span></td>
<td>2026-06-01 22:45:11</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-type="Error" data-logtime="2026-06-02 06:30:55" data-logmsg="adcRead调用异常.Code=1,message=Channel unavailable" data-created="2026-06-02 06:30:58" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 06:30:55</td>
<td><span class="log-msg">adcRead调用异常.Code=1,message=Channel unavailable</span></td>
<td>2026-06-02 06:30:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-type="Error" data-logtime="2026-06-02 08:15:22" data-logmsg="ppgStart调用异常.Code=2,message=Invalid parameters" data-created="2026-06-02 08:15:25" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 08:15:22</td>
<td><span class="log-msg">ppgStart调用异常.Code=2,message=Invalid parameters</span></td>
<td>2026-06-02 08:15:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-type="Error" data-logtime="2026-06-02 07:50:33" data-logmsg="firmwareUpdate调用异常.Code=6,message=Signature verification failed" data-created="2026-06-02 07:50:36" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 07:50:33</td>
<td><span class="log-msg">firmwareUpdate调用异常.Code=6,message=Signature verification failed</span></td>
<td>2026-06-02 07:50:36</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-type="Error" data-logtime="2026-06-02 09:05:40" data-logmsg="spo2Read调用异常.Code=2,message=Invalid parameters" data-created="2026-06-02 09:05:43" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 09:05:40</td>
<td><span class="log-msg">spo2Read调用异常.Code=2,message=Invalid parameters</span></td>
<td>2026-06-02 09:05:43</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-type="Error" data-logtime="2026-06-02 06:20:15" data-logmsg="gpsFix调用异常.Code=8,message=No satellites in view" data-created="2026-06-02 06:20:18" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td><span class="tag tag-red">Error</span></td>
<td>2026-06-02 06:20:15</td>
<td><span class="log-msg">gpsFix调用异常.Code=8,message=No satellites in view</span></td>
<td>2026-06-02 06:20:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 67 条</span>
<button class="page-btn">«</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">7</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">错误日志详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>日志类型</label><span id="d-type"></span></div>
<div class="detail-item"><label>日志时间</label><span id="d-logtime"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
<div class="detail-item" style="grid-column:1/-1;"><label>日志信息</label><span id="d-logmsg" style="background:#FAFAFA;border:1px solid var(--border);border-radius:var(--radius-md);padding:12px 16px;word-break:break-all;font-size:var(--font-sm);color:var(--text-primary);line-height:1.8;"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-type').innerHTML = '<span class="tag tag-red">' + d.type + '</span>';
document.getElementById('d-logtime').textContent = d.logtime;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-logmsg').textContent = d.logmsg;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,426 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - mqtt消息日志 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:160px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.msg-preview{font-family:'SFMono-Regular',Consolas,Menlo,monospace;font-size:var(--font-xs);color:var(--text-secondary);max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:640px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
.json-block{background:#1e1e1e;border-radius:var(--radius-md);padding:14px 16px;overflow:auto;max-height:300px;margin-bottom:4px;}
.json-block pre{font-family:'Consolas','SFMono-Regular',Consolas,Menlo,monospace;font-size:12px;line-height:1.6;color:#d4d4d4;white-space:pre-wrap;word-break:break-all;margin:0;}
.json-key{color:#9cdcfe;}.json-str{color:#ce9178;}.json-num{color:#b5cea8;}.json-bool{color:#569cd6;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item active">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">mqtt消息日志</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>mqtt主题</label>
<input class="filter-input" placeholder="请输入mqtt主题">
</div>
<div class="filter-item">
<label>命令类型</label>
<input class="filter-input" placeholder="请输入命令类型" style="min-width:130px;">
</div>
<div class="filter-item">
<label>请求类型</label>
<input class="filter-input" placeholder="请输入请求类型" style="min-width:130px;">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">MQTT消息<small>共 156 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>mqtt主题</th>
<th>消息内容</th>
<th>命令类型</th>
<th>请求类型</th>
<th>是否发送成功</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-topic="watch/4PMBB25A28100208/cmd" data-msg='{"deviceId":"4PMBB25A28100208","cmd":"config","params":{"heartRate":true,"bloodOxygen":true,"stress":true,"uploadInterval":60},"ts":1717315200000}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 08:00:05" data-updated="2026-06-02 08:00:08">
<td><span class="mono">watch/4PMBB25A28100208/cmd</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25A28100208","cmd":"config","params":{"heartRate":true...}}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 08:00:05</td>
<td>2026-06-02 08:00:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25A28100208/data" data-msg='{"deviceId":"4PMBB25A28100208","cmd":"syncData","dataTypes":["heartRate","spo2","temp","stress"],"startTs":1717228800000,"endTs":1717315200000}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 09:30:12" data-updated="2026-06-02 09:30:15">
<td><span class="mono">watch/4PMBB25A28100208/data</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25A28100208","cmd":"syncData","dataTypes":["heartRate","spo2","temp","stress"]...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 09:30:12</td>
<td>2026-06-02 09:30:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25A28100208/report" data-msg='{"deviceId":"4PMBB25A28100208","cmd":"heartbeat","battery":85,"signal":-65,"firmware":"2.3.1","online":true,"rssi":-58}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 10:05:20" data-updated="2026-06-02 10:05:22">
<td><span class="mono">watch/4PMBB25A28100208/report</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25A28100208","cmd":"heartbeat","battery":85,"signal":-65...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 10:05:20</td>
<td>2026-06-02 10:05:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25C39200315/cmd" data-msg='{"deviceId":"4PMBB25C39200315","cmd":"firmwareUpgrade","version":"2.3.2","url":"https://ota.health.com/fw/v2.3.2.bin","checksum":"0xAB12CD34","retry":3}' data-cmd="cmd" data-req="send" data-success="未得到回执" data-created="2026-06-02 07:45:00" data-updated="2026-06-02 07:50:00">
<td><span class="mono">watch/4PMBB25C39200315/cmd</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25C39200315","cmd":"firmwareUpgrade","version":"2.3.2"...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-orange">未得到回执</span></td>
<td>2026-06-02 07:45:00</td>
<td>2026-06-02 07:50:00</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25D40300420/data" data-msg='{"deviceId":"4PMBB25D40300420","cmd":"dataReport","dataType":"heartRate","records":[{"ts":1717228800,"hr":72},{"ts":1717228860,"hr":75},{"ts":1717228920,"hr":68}],"count":3}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 06:55:10" data-updated="2026-06-02 06:55:12">
<td><span class="mono">watch/4PMBB25D40300420/data</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25D40300420","cmd":"dataReport","dataType":"heartRate","records":[]...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 06:55:10</td>
<td>2026-06-02 06:55:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25E50400508/cmd" data-msg='{"deviceId":"4PMBB25E50400508","cmd":"sensorCalibrate","sensors":["ppg","temp","accelerometer"],"timeout":300}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 07:30:00" data-updated="2026-06-02 07:35:18">
<td><span class="mono">watch/4PMBB25E50400508/cmd</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25E50400508","cmd":"sensorCalibrate","sensors":["ppg","temp"...]}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 07:30:00</td>
<td>2026-06-02 07:35:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25F60500615/cmd" data-msg='{"deviceId":"4PMBB25F60500615","cmd":"restart","mode":"soft","delay":10}' data-cmd="cmd" data-req="send" data-success="未得到回执" data-created="2026-06-02 09:10:00" data-updated="2026-06-02 09:15:00">
<td><span class="mono">watch/4PMBB25F60500615/cmd</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25F60500615","cmd":"restart","mode":"soft","delay":10}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-orange">未得到回执</span></td>
<td>2026-06-02 09:10:00</td>
<td>2026-06-02 09:15:00</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25G70600722/event" data-msg='{"deviceId":"4PMBB25G70600722","cmd":"eventReport","eventType":"fall","timestamp":1717308000000,"confidence":0.89,"data":{"accX":-0.02,"accY":0.15,"accZ":-1.05}}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 06:20:20" data-updated="2026-06-02 06:20:22">
<td><span class="mono">watch/4PMBB25G70600722/event</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25G70600722","cmd":"eventReport","eventType":"fall"...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 06:20:20</td>
<td>2026-06-02 06:20:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25A28100208/cmd" data-msg='{"deviceId":"4PMBB25A28100208","cmd":"locationQuery","gps":true,"wifi":true,"lbs":true,"timeout":30}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-01 22:10:05" data-updated="2026-06-01 22:10:12">
<td><span class="mono">watch/4PMBB25A28100208/cmd</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25A28100208","cmd":"locationQuery","gps":true,"wifi":true...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-01 22:10:05</td>
<td>2026-06-01 22:10:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-topic="watch/4PMBB25B39200130/data" data-msg='{"deviceId":"4PMBB25B39200130","cmd":"dataReport","dataType":"spo2","records":[{"ts":1717228800,"spo2":96},{"ts":1717228860,"spo2":95},{"ts":1717228920,"spo2":97}],"count":3}' data-cmd="cmd" data-req="send" data-success="成功" data-created="2026-06-02 08:15:30" data-updated="2026-06-02 08:15:33">
<td><span class="mono">watch/4PMBB25B39200130/data</span></td>
<td><span class="msg-preview">{"deviceId":"4PMBB25B39200130","cmd":"dataReport","dataType":"spo2","records":[]...}</span></td>
<td><span class="mono">cmd</span></td>
<td>send</td>
<td><span class="tag tag-green">成功</span></td>
<td>2026-06-02 08:15:30</td>
<td>2026-06-02 08:15:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 156 条</span>
<button class="page-btn">«</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">16</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal" style="width:680px;">
<div class="modal-header">
<span class="modal-title">MQTT消息详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">消息信息</div>
<div class="detail-list">
<div class="detail-item"><label>mqtt主题</label><span class="mono" id="d-topic"></span></div>
<div class="detail-item"><label>命令类型</label><span class="mono" id="d-cmd"></span></div>
<div class="detail-item"><label>请求类型</label><span id="d-req"></span></div>
<div class="detail-item"><label>是否发送成功</label><span id="d-success"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
<div class="detail-item"><label>更新时间</label><span id="d-updated"></span></div>
</div>
<div class="detail-section-title">消息内容</div>
<div class="json-block"><pre id="d-msg"></pre></div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function syntaxHighlight(json){
try {
var obj = JSON.parse(json);
var str = JSON.stringify(obj,null,2);
return str.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,function(match){
if(/^"/.test(match)){
if(/:$/.test(match)) return '<span class="json-key">'+match+'</span>';
return '<span class="json-str">'+match+'</span>';
}
if(/true|false/.test(match)) return '<span class="json-bool">'+match+'</span>';
return '<span class="json-num">'+match+'</span>';
});
} catch(e) {
return json;
}
}
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-topic').textContent = d.topic;
document.getElementById('d-cmd').textContent = d.cmd;
document.getElementById('d-req').textContent = d.req;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-updated').textContent = d.updated;
var tagCls = d.success === '成功' ? 'tag-green' : 'tag-orange';
document.getElementById('d-success').innerHTML = '<span class="tag ' + tagCls + '">' + d.success + '</span>';
document.getElementById('d-msg').innerHTML = syntaxHighlight(d.msg);
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,381 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 手表网络切换日志 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-cyan{background:#E6FFFB;color:#13C2C2;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item active">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">手表网络切换日志</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>网络方式</label>
<select class="filter-select">
<option>全部</option>
<option>WiFi</option>
<option>Bluetooth</option>
</select>
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">网络切换日志<small>共 89 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>网络方式</th>
<th>更新时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-net="WiFi" data-update="2026-06-02 08:00:15" data-created="2026-06-02 08:00:18" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-02 08:00:15</td>
<td>2026-06-02 08:00:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-net="Bluetooth" data-update="2026-06-02 09:30:22" data-created="2026-06-02 09:30:25" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-cyan">Bluetooth</span></td>
<td>2026-06-02 09:30:22</td>
<td>2026-06-02 09:30:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-net="WiFi" data-update="2026-06-02 07:45:08" data-created="2026-06-02 07:45:11" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-02 07:45:08</td>
<td>2026-06-02 07:45:11</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-net="Bluetooth" data-update="2026-06-02 10:15:33" data-created="2026-06-02 10:15:36" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="tag tag-cyan">Bluetooth</span></td>
<td>2026-06-02 10:15:33</td>
<td>2026-06-02 10:15:36</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-net="WiFi" data-update="2026-06-01 22:10:44" data-created="2026-06-01 22:10:47" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-01 22:10:44</td>
<td>2026-06-01 22:10:47</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-net="Bluetooth" data-update="2026-06-02 06:55:12" data-created="2026-06-02 06:55:15" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-cyan">Bluetooth</span></td>
<td>2026-06-02 06:55:12</td>
<td>2026-06-02 06:55:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-net="WiFi" data-update="2026-06-02 08:20:30" data-created="2026-06-02 08:20:33" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-02 08:20:30</td>
<td>2026-06-02 08:20:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-net="WiFi" data-update="2026-06-02 07:30:18" data-created="2026-06-02 07:30:21" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-02 07:30:18</td>
<td>2026-06-02 07:30:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-net="Bluetooth" data-update="2026-06-02 09:10:55" data-created="2026-06-02 09:10:58" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td><span class="tag tag-cyan">Bluetooth</span></td>
<td>2026-06-02 09:10:55</td>
<td>2026-06-02 09:10:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-net="WiFi" data-update="2026-06-02 06:40:30" data-created="2026-06-02 06:40:33" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td><span class="tag tag-blue">WiFi</span></td>
<td>2026-06-02 06:40:30</td>
<td>2026-06-02 06:40:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 89 条</span>
<button class="page-btn">«</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">9</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">网络切换详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>网络方式</label><span id="d-net"></span></div>
<div class="detail-item"><label>更新时间</label><span id="d-update"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
var NET_TAG = {
WiFi: 'tag-blue',
Bluetooth: 'tag-cyan'
};
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
var tagCls = NET_TAG[d.net] || 'tag-blue';
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-net').innerHTML = '<span class="tag ' + tagCls + '">' + d.net + '</span>';
document.getElementById('d-update').textContent = d.update;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,409 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 任务日志 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
.fail-reason{font-size:var(--font-sm);color:var(--text-secondary);max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:120px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item active">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">任务日志</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>任务名称</label>
<input class="filter-input" placeholder="请输入任务名称" style="min-width:150px;">
</div>
<div class="filter-item">
<label>任务状态</label>
<select class="filter-select">
<option>全部</option>
<option>未开始</option>
<option>进行中</option>
<option>已完成</option>
<option>处理失败</option>
</select>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">任务日志<small>共 45 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>任务名称</th>
<th>任务状态</th>
<th>失败原因</th>
<th>任务开始时间</th>
<th>任务结束时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-task="taskFirmwareUpgrade" data-status="已完成" data-fail="" data-start="2026-06-02 08:00:00" data-end="2026-06-02 08:15:32" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="mono">taskFirmwareUpgrade</span></td>
<td><span class="tag tag-green">已完成</span></td>
<td></td>
<td>2026-06-02 08:00:00</td>
<td>2026-06-02 08:15:32</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-task="taskDataSync" data-status="进行中" data-fail="" data-start="2026-06-02 09:30:00" data-end="—" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="mono">taskDataSync</span></td>
<td><span class="tag tag-blue">进行中</span></td>
<td></td>
<td>2026-06-02 09:30:00</td>
<td></td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-task="taskSensorCalibrate" data-status="处理失败" data-fail="### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction&#10;### The error may exist in URL [jar:nested:/C:/datacenter/jeecg-module-watch-start.jar/!BOOT-INF/lib/jeecg-module-watch-biz-1.0.0.jar!/org/jeecg/modules/watch/mapper/xml/WatchDataMapper.xml]&#10;### The error may involve org.jeecg.modules.watch.mapper.WatchDataMapper.batchInsertSensorCalibrationData-Inline&#10;### The error occurred while setting parameters" data-start="2026-06-02 07:45:00" data-end="2026-06-02 07:50:15" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="mono">taskSensorCalibrate</span></td>
<td><span class="tag tag-red">处理失败</span></td>
<td><span class="fail-reason">### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded</span></td>
<td>2026-06-02 07:45:00</td>
<td>2026-06-02 07:50:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-task="taskConfigPush" data-status="已完成" data-fail="" data-start="2026-06-02 10:00:00" data-end="2026-06-02 10:02:08" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="mono">taskConfigPush</span></td>
<td><span class="tag tag-green">已完成</span></td>
<td></td>
<td>2026-06-02 10:00:00</td>
<td>2026-06-02 10:02:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-task="taskFirmwareUpgrade" data-status="未开始" data-fail="" data-start="2026-06-03 02:00:00" data-end="—" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td><span class="mono">taskFirmwareUpgrade</span></td>
<td><span class="tag tag-orange">未开始</span></td>
<td></td>
<td>2026-06-03 02:00:00</td>
<td></td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-task="taskDataSync" data-status="已完成" data-fail="" data-start="2026-06-02 06:55:00" data-end="2026-06-02 07:05:22" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="mono">taskDataSync</span></td>
<td><span class="tag tag-green">已完成</span></td>
<td></td>
<td>2026-06-02 06:55:00</td>
<td>2026-06-02 07:05:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-task="taskLogUpload" data-status="处理失败" data-fail="### Error sending request to MQTT broker&#10;### Connection refused: tcp://mqtt.health.com:1883 - broker unreachable&#10;### Caused by: java.net.ConnectException: Connection timed out&#10;### Retry count exceeded (3/3), task aborted" data-start="2026-06-02 08:20:00" data-end="2026-06-02 08:25:40" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="mono">taskLogUpload</span></td>
<td><span class="tag tag-red">处理失败</span></td>
<td><span class="fail-reason">### Error sending request to MQTT broker - Connection refused: tcp://mqtt.health.com:1883</span></td>
<td>2026-06-02 08:20:00</td>
<td>2026-06-02 08:25:40</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-task="taskConfigPush" data-status="已完成" data-fail="" data-start="2026-06-02 07:30:00" data-end="2026-06-02 07:31:45" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td><span class="mono">taskConfigPush</span></td>
<td><span class="tag tag-green">已完成</span></td>
<td></td>
<td>2026-06-02 07:30:00</td>
<td>2026-06-02 07:31:45</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-task="taskSensorCalibrate" data-status="进行中" data-fail="" data-start="2026-06-02 09:10:00" data-end="—" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td><span class="mono">taskSensorCalibrate</span></td>
<td><span class="tag tag-blue">进行中</span></td>
<td></td>
<td>2026-06-02 09:10:00</td>
<td></td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-task="taskFirmwareUpgrade" data-status="处理失败" data-fail="### Firmware upgrade failed: device battery level too low (12%)&#10;### Pre-flight check failed: minimum battery threshold is 30%&#10;### Aborting upgrade to prevent device bricking&#10;### Please charge device and retry" data-start="2026-06-02 06:40:00" data-end="2026-06-02 06:42:18" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td><span class="mono">taskFirmwareUpgrade</span></td>
<td><span class="tag tag-red">处理失败</span></td>
<td><span class="fail-reason">### Firmware upgrade failed: device battery level too low (12%) - minimum threshold is 30%</span></td>
<td>2026-06-02 06:40:00</td>
<td>2026-06-02 06:42:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 45 条</span>
<button class="page-btn">«</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">4</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal" style="width:680px;">
<div class="modal-header">
<span class="modal-title">任务详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">任务信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>任务名称</label><span id="d-task"></span></div>
<div class="detail-item"><label>任务状态</label><span id="d-status"></span></div>
<div class="detail-item"><label>任务开始时间</label><span id="d-start"></span></div>
<div class="detail-item"><label>任务结束时间</label><span id="d-end"></span></div>
<div class="detail-item" id="d-fail-row" style="display:none;grid-column:1/-1;"><label>失败原因</label><span id="d-fail" style="background:#FAFAFA;border:1px solid var(--border);border-radius:var(--radius-md);padding:12px 16px;word-break:break-all;font-size:var(--font-sm);color:var(--danger);line-height:1.8;white-space:pre-wrap;"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-task').textContent = d.task;
document.getElementById('d-status').innerHTML = d.status ? '<span class="tag tag-' + (d.status==='已完成'?'green':d.status==='进行中'?'blue':d.status==='处理失败'?'red':'orange') + '">' + d.status + '</span>' : '';
document.getElementById('d-start').textContent = d.start;
document.getElementById('d-end').textContent = d.end;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
var failRow = document.getElementById('d-fail-row');
if (d.fail && d.fail !== '') {
document.getElementById('d-fail').textContent = d.fail;
failRow.style.display = 'flex';
} else {
failRow.style.display = 'none';
}
document.getElementById('detailModal').classList.add('show');
}
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -0,0 +1,357 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 版本更新历史 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item active">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">版本更新历史</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>更新版本</label>
<input class="filter-input" placeholder="请输入版本" style="min-width:140px;">
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">版本更新记录<small>共 42 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>更新版本</th>
<th>更新时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-version="GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7" data-update="2026-06-02 08:05:10" data-created="2026-06-02 08:05:13" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7</td>
<td>2026-06-02 08:05:10</td>
<td>2026-06-02 08:05:13</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-version="GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5" data-update="2026-05-28 14:20:35" data-created="2026-05-28 14:20:38" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5</td>
<td>2026-05-28 14:20:35</td>
<td>2026-05-28 14:20:38</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-version="GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7" data-update="2026-06-01 09:30:22" data-created="2026-06-01 09:30:25" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7</td>
<td>2026-06-01 09:30:22</td>
<td>2026-06-01 09:30:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-version="GLL-AL30BCN2.2.9.600(SP40C600E98R520P280);1.0.4" data-update="2026-05-25 16:15:08" data-created="2026-05-25 16:15:11" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN2.2.9.600(SP40C600E98R520P280);1.0.4</td>
<td>2026-05-25 16:15:08</td>
<td>2026-05-25 16:15:11</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-version="GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7" data-update="2026-06-02 07:50:44" data-created="2026-06-02 07:50:47" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7</td>
<td>2026-06-02 07:50:44</td>
<td>2026-06-02 07:50:47</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-version="GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5" data-update="2026-05-30 11:05:18" data-created="2026-05-30 11:05:21" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5</td>
<td>2026-05-30 11:05:18</td>
<td>2026-05-30 11:05:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-032" data-version="GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7" data-update="2026-06-02 06:48:30" data-created="2026-06-02 06:48:33" data-emp="刘洋" data-empcode="CQ002200" data-unit="采气一厂" data-dept="集输站">
<td><span class="mono">WD-2024-032</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7</td>
<td>2026-06-02 06:48:30</td>
<td>2026-06-02 06:48:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-version="GLL-AL30BCN2.1.5.400(SP35C550E90R480P260);1.0.2" data-update="2026-05-20 10:30:55" data-created="2026-05-20 10:30:58" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN2.1.5.400(SP35C550E90R480P260);1.0.2</td>
<td>2026-05-20 10:30:55</td>
<td>2026-05-20 10:30:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-version="GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7" data-update="2026-06-02 09:10:20" data-created="2026-06-02 09:10:23" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.900(SP52C700E106R613P326);1.0.7</td>
<td>2026-06-02 09:10:20</td>
<td>2026-06-02 09:10:23</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-version="GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5" data-update="2026-05-29 15:25:10" data-created="2026-05-29 15:25:13" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td style="max-width:280px;overflow:hidden;text-overflow:ellipsis;">GLL-AL30BCN3.0.0.800(SP48C650E102R580P310);1.0.5</td>
<td>2026-05-29 15:25:10</td>
<td>2026-05-29 15:25:13</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 42 条</span>
<button class="page-btn">«</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">4</button>
<button class="page-btn">5</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">版本更新详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">更新信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>更新版本</label><span id="d-version"></span></div>
<div class="detail-item"><label>更新时间</label><span id="d-update"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var tr = btn.closest('tr');
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-version').textContent = d.version;
document.getElementById('d-update').textContent = d.update;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,385 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 活动信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item active">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">活动信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">活动记录<small>共 180 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>中高强度运动时间(分钟)</th>
<th>总活动时长(小时)</th>
<th>监测日期</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<tr data-code="WD-2024-001" data-sport="45" data-total="2.0" data-date="2026-06-02" data-created="2026-06-02 23:59:05" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>45</td>
<td>2.0</td>
<td>2026-06-02</td>
<td>2026-06-02 23:59:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-sport="38" data-total="1.6" data-date="2026-06-01" data-created="2026-06-01 23:59:08" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>38</td>
<td>1.6</td>
<td>2026-06-01</td>
<td>2026-06-01 23:59:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-sport="62" data-total="2.6" data-date="2026-06-02" data-created="2026-06-02 23:59:12" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>62</td>
<td>2.6</td>
<td>2026-06-02</td>
<td>2026-06-02 23:59:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-sport="20" data-total="1.3" data-date="2026-06-01" data-created="2026-06-01 23:59:10" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>20</td>
<td>1.3</td>
<td>2026-06-01</td>
<td>2026-06-01 23:59:10</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-sport="55" data-total="2.2" data-date="2026-06-02" data-created="2026-06-02 23:59:15" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>55</td>
<td>2.2</td>
<td>2026-06-02</td>
<td>2026-06-02 23:59:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-sport="40" data-total="1.8" data-date="2026-06-01" data-created="2026-06-01 23:59:18" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>40</td>
<td>1.8</td>
<td>2026-06-01</td>
<td>2026-06-01 23:59:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-sport="15" data-total="1.0" data-date="2026-06-02" data-created="2026-06-02 23:59:20" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>15</td>
<td>1.0</td>
<td>2026-06-02</td>
<td>2026-06-02 23:59:20</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-sport="50" data-total="2.0" data-date="2026-06-01" data-created="2026-06-01 23:59:22" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>50</td>
<td>2.0</td>
<td>2026-06-01</td>
<td>2026-06-01 23:59:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-sport="70" data-total="2.8" data-date="2026-06-02" data-created="2026-06-02 23:59:25" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>70</td>
<td>2.8</td>
<td>2026-06-02</td>
<td>2026-06-02 23:59:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-sport="32" data-total="1.5" data-date="2026-06-01" data-created="2026-06-01 23:59:28" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>32</td>
<td>1.5</td>
<td>2026-06-01</td>
<td>2026-06-01 23:59:28</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 180 条</span>
<button class="page-btn">«</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">18</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">活动详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code">WD-2024-001</span></div>
<div class="detail-item"><label>中高强度运动时间(分钟)</label><span id="d-sport">45</span></div>
<div class="detail-item"><label>总活动时长(小时)</label><span id="d-total">2.0</span></div>
<div class="detail-item"><label>监测日期</label><span id="d-date">2026-06-02</span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created">2026-06-02 23:59:05</span></div>
<div class="detail-item"><label></label><span></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp">张伟</span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode">CQ001234</span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit">采油一厂</span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept">作业一区</span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-sport').textContent = d.sport;
document.getElementById('d-total').textContent = d.total;
document.getElementById('d-date').textContent = d.date;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,569 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 心电图信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;}
.filter-input:focus{border-color:var(--primary);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;}.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);}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.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__actions{display:flex;align-items:center;gap:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);vertical-align:middle;}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:var(--radius-sm);font-size:var(--font-xs);line-height:1.6;}
.tag--success{background:rgba(82,196,26,0.1);color:var(--success);}
.tag--warning{background:rgba(250,173,20,0.12);color:var(--warning);}
.tag--danger{background:rgba(255,77,79,0.12);color:var(--danger);}
.tag--info{background:#F0F2F5;color:var(--text-secondary);}
.tag--primary{background:var(--primary-light);color:var(--primary);}
.tag--value{background:transparent;border:1px solid var(--border);color:var(--text-placeholder);font-family:monospace;padding:2px 6px;}
.symptom-tags{display:flex;flex-wrap:wrap;gap:4px;max-width:240px;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:880px;max-height:90vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.detail-section-title{font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title:first-child{margin-top:0;}
.detail-section-title::before{content:"";width:3px;height:14px;background:var(--primary);border-radius:2px;}
.detail-meta{display:grid;grid-template-columns:repeat(3,1fr);gap:12px 24px;padding:14px 16px;background:#FAFAFA;border-radius:var(--radius-md);}
.detail-meta-item{display:flex;flex-direction:column;gap:3px;}
.detail-meta-item span:first-child{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-meta-item span:last-child{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;}
.ecg-wrap{background:#0f1419;border-radius:var(--radius-md);padding:16px;}
.ecg-canvas{width:100%;height:200px;}
.ecg-canvas svg{width:100%;height:100%;display:block;}
.ecg-grid line{stroke:#1f2933;stroke-width:0.5;}
.ecg-grid line.major{stroke:#2c3a47;stroke-width:1;}
.ecg-line{fill:none;stroke:#52c41a;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;}
.ecg-axis{display:flex;justify-content:space-between;margin-top:6px;color:#6c7a89;font-size:var(--font-xs);}
.ecg-meta{display:flex;justify-content:space-between;margin-bottom:10px;color:#bfc9d4;font-size:var(--font-xs);}
.ecg-meta strong{color:#fff;font-weight:500;}
.raw-value{font-family:monospace;color:var(--text-secondary);}
.download-link{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border:1px dashed var(--border);border-radius:var(--radius-sm);cursor:pointer;color:var(--primary);font-size:var(--font-sm);transition:all .2s;text-decoration:none;}
.download-link:hover{border-color:var(--primary);background:var(--primary-light);}
.download-link svg{width:16px;height:16px;flex-shrink:0;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item active">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码" style="min-width:180px;">
</div>
<div class="filter-item">
<label>日期范围</label>
<input class="filter-input" type="date" value="2026-05-01">
<span style="color:var(--text-secondary);font-size:var(--font-sm);"></span>
<input class="filter-input" type="date" value="2026-06-02">
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">心电图信息列表 <span style="font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;">共 128 条</span></span>
<div class="table-card__actions">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8m0 0L4 6m3 3l3-3M2 11v1.5A.5.5 0 002.5 13h9a.5.5 0 00.5-.5V11" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4M4 10h5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
查看导出任务
</button>
</div>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据日期</th>
<th>测量开始时间</th>
<th>测量结束时间</th>
<th>平均心率</th>
<th>测量结果</th>
<th>用户选择症状</th>
<th>原始数据点数量</th>
<th>创建日期</th>
<th style="position:sticky;right:0;background:#FAFAFA;">操作</th>
</tr>
</thead>
<tbody id="ecgTbody"></tbody>
</table>
</div>
<div class="pagination">
<span>共 128 条</span>
<button class="page-btn">«</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">4</button>
<button class="page-btn">»</button>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal__header">
<h3>心电图详情</h3>
<button class="modal__close" onclick="closeDetail()">×</button>
</div>
<div class="modal__body">
<div class="detail-section-title">基本信息</div>
<div class="detail-meta">
<div class="detail-meta-item"><span>设备编码</span><span id="dCode"></span></div>
<div class="detail-meta-item"><span>数据日期</span><span id="dDate"></span></div>
<div class="detail-meta-item"><span>平均心率</span><span id="dHr"></span></div>
<div class="detail-meta-item"><span>测量开始时间</span><span id="dStart"></span></div>
<div class="detail-meta-item"><span>测量结束时间</span><span id="dEnd"></span></div>
<div class="detail-meta-item"><span>持续时长</span><span id="dDuration"></span></div>
<div class="detail-meta-item"><span>测量结果</span><span id="dResult"></span></div>
<div class="detail-meta-item"><span>测量结果原始值</span><span id="dResultVal"></span></div>
<div class="detail-meta-item"><span>原始数据点数量</span><span id="dPoints"></span></div>
</div>
<div class="detail-section-title">用户选择症状</div>
<div class="detail-meta" style="margin-top:14px;">
<div class="detail-meta-item">
<span>症状标签</span>
<span><div id="dSymptomLabels" style="display:flex;flex-wrap:wrap;gap:4px;"></div></span>
</div>
<div class="detail-meta-item">
<span>症状原始值</span>
<span><div id="dSymptomValues" style="display:flex;flex-wrap:wrap;gap:4px;"></div></span>
</div>
</div>
<div class="detail-section-title">心电波形</div>
<div class="ecg-wrap">
<div class="ecg-meta">
<span id="dEcgRange"></span>
</div>
<div class="ecg-canvas">
<svg viewBox="0 0 1160 200" preserveAspectRatio="none" id="ecgSvg">
<g class="ecg-grid" id="ecgGrid"></g>
<path class="ecg-line" id="ecgLine"></path>
</svg>
</div>
<div class="ecg-axis" id="ecgAxis"></div>
</div>
<div class="detail-section-title" style="margin-top:16px;">原始数据点文件</div>
<div style="padding:0 4px;">
<a class="download-link" id="dDownloadLink" onclick="downloadEcgData()">
<svg viewBox="0 0 16 16" fill="none"><path d="M8 1v9m0 0l-3-3m3 3l3-3M2 11v2.5a.5.5 0 00.5.5h11a.5.5 0 00.5-.5V11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
下载原始数据点文件
</a>
</div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeDetail()">关闭</button>
</div>
</div>
</div>
<script>
// 测量结果与样式映射(数据值参照设备协议字典)
var RESULT_MAP = {
none: { label:'无症状', value:-1, cls:'tag--info', wave:'flat' },
sinus: { label:'窦性心律', value: 0, cls:'tag--success', wave:'sinus' },
afib: { label:'房颤', value: 1, cls:'tag--danger', wave:'afib' },
pvc: { label:'室性早搏', value: 2, cls:'tag--danger', wave:'pvc' },
pac: { label:'房性早搏', value: 3, cls:'tag--warning', wave:'pac' },
high: { label:'心律过高', value: 4, cls:'tag--warning', wave:'high' },
low: { label:'心律过低', value: 5, cls:'tag--warning', wave:'low' },
uncertain:{ label:'不确定', value: 6, cls:'tag--info', wave:'uncertain' }
};
// 格式化测量结果文本
function formatResult(key) {
return RESULT_MAP[key].label;
}
// 症状字典(含原始值)
var SYMPTOM_MAP = {
none: { label:'无症状', value: 0 },
chest: { label:'胸闷', value: 1 },
dizzy: { label:'头晕', value: 2 },
fatigue: { label:'疲劳', value: 3 },
cold: { label:'感冒发烧', value: 4 },
other: { label:'其他不适', value:99 }
};
// 列表数据(覆盖 8 种测量结果)
var ecgData = [
{ code:'WD-2024-001', date:'2026-05-28', start:'09:12:34', end:'09:13:04', hr:78, result:'sinus', symptoms:['none'], points:7500, created:'2026-05-28 09:13:08' },
{ code:'WD-2024-002', date:'2026-05-28', start:'10:25:11', end:'10:25:41', hr:128, result:'high', symptoms:['chest','dizzy'], points:7500, created:'2026-05-28 10:25:46' },
{ code:'WD-2024-015', date:'2026-05-27', start:'14:30:00', end:'14:30:30', hr:92, result:'pvc', symptoms:['chest','fatigue'], points:7500, created:'2026-05-27 14:30:35' },
{ code:'WD-2024-016', date:'2026-05-27', start:'16:48:21', end:'16:48:51', hr:88, result:'pac', symptoms:['dizzy'], points:7500, created:'2026-05-27 16:48:55' },
{ code:'WD-2024-031', date:'2026-05-26', start:'08:05:12', end:'08:05:42', hr:72, result:'sinus', symptoms:['none'], points:7500, created:'2026-05-26 08:05:46' },
{ code:'WD-2024-032', date:'2026-05-26', start:'12:18:55', end:'12:19:25', hr:86, result:'uncertain', symptoms:['cold','other'], points:7320, created:'2026-05-26 12:19:30' },
{ code:'WD-2024-048', date:'2026-05-25', start:'07:42:08', end:'07:42:38', hr:55, result:'low', symptoms:['fatigue'], points:7500, created:'2026-05-25 07:42:42' },
{ code:'WD-2024-049', date:'2026-05-25', start:'19:55:30', end:'19:56:00', hr:142, result:'afib', symptoms:['chest','dizzy','other'], points:7500, created:'2026-05-25 19:56:05' },
{ code:'WD-2024-060', date:'2026-05-24', start:'13:22:17', end:'13:22:47', hr:74, result:'none', symptoms:['none'], points:7500, created:'2026-05-24 13:22:51' },
{ code:'WD-2024-061', date:'2026-05-24', start:'21:08:44', end:'21:09:14', hr:74, result:'sinus', symptoms:['none'], points:7500, created:'2026-05-24 21:09:18' }
];
// 渲染列表
function renderTable() {
var tbody = document.getElementById('ecgTbody');
tbody.innerHTML = '';
ecgData.forEach(function(row, i) {
var rs = RESULT_MAP[row.result];
var symptomsHtml = '<div class="symptom-tags">' + row.symptoms.map(function(s){
var sm = SYMPTOM_MAP[s];
var cls = (s === 'none') ? 'tag--info' : 'tag--primary';
return '<span class="tag ' + cls + '">' + sm.label + '</span>';
}).join('') + '</div>';
var tr = document.createElement('tr');
tr.innerHTML =
'<td><span style="font-family:monospace">' + row.code + '</span></td>' +
'<td>' + row.date + '</td>' +
'<td>' + row.start + '</td>' +
'<td>' + row.end + '</td>' +
'<td>' + row.hr + ' bpm</td>' +
'<td><span class="tag ' + rs.cls + '">' + formatResult(row.result) + '</span></td>' +
'<td>' + symptomsHtml + '</td>' +
'<td>' + row.points.toLocaleString() + '</td>' +
'<td>' + row.created + '</td>' +
'<td style="position:sticky;right:0;background:#fff;"><span class="link" onclick="openDetail(' + i + ')">详情</span></td>';
tbody.appendChild(tr);
});
}
// 生成心电网格
function buildGrid() {
var html = '';
for (var x = 0; x <= 1160; x += 29) {
html += '<line x1="'+x+'" y1="0" x2="'+x+'" y2="200"' + (x % 145 === 0 ? ' class="major"' : '') + '/>';
}
for (var y = 0; y <= 200; y += 20) {
html += '<line x1="0" y1="'+y+'" x2="1160" y2="'+y+'"' + (y % 100 === 0 ? ' class="major"' : '') + '/>';
}
document.getElementById('ecgGrid').innerHTML = html;
}
// 生成 30 秒心电波形(不同测量结果走不同模式)
function generateEcgPath(type, hr) {
var w = 1160, h = 200, cy = h / 2;
var pts = [];
var cycles = Math.max(6, Math.round(hr / 2));
for (var i = 0; i <= w; i += 1.2) {
var phase = (i / w) * cycles * Math.PI * 2;
var seg = phase % (Math.PI * 2);
var y = cy;
if (type === 'pvc') {
// 大部分窦性,中间插一个宽 QRS(室性早搏)
var pvcZone = (i > w * 0.42 && i < w * 0.52);
if (pvcZone) {
if (seg > 2.5 && seg < 3.4) y = cy - 75;
else if (seg > 3.4 && seg < 3.9) y = cy + 35;
else y = cy + Math.sin(seg) * 6;
} else {
if (seg > 2.7 && seg < 2.9) y = cy + 6;
else if (seg > 2.9 && seg < 3.05) y = cy - 55;
else if (seg > 3.05 && seg < 3.2) y = cy + 18;
else if (seg > 3.2 && seg < 3.5) y = cy - 3;
else y = cy + Math.sin(seg * 0.3) * 1.5;
}
} else if (type === 'pac') {
// 房性早搏:节律不齐,部分 P 波形态异常
var pacZone = (i > w * 0.55 && i < w * 0.62);
if (pacZone) {
if (seg > 2.3 && seg < 2.6) y = cy - 8;
else if (seg > 2.9 && seg < 3.05) y = cy - 50;
else if (seg > 3.05 && seg < 3.2) y = cy + 15;
else y = cy;
} else {
if (seg > 2.7 && seg < 2.9) y = cy + 6;
else if (seg > 2.9 && seg < 3.05) y = cy - 55;
else if (seg > 3.05 && seg < 3.2) y = cy + 18;
else y = cy + Math.sin(seg * 0.3) * 1.5;
}
} else if (type === 'afib') {
// 房颤:P 波消失,R-R 间期绝对不齐,基线颤动
var jitter = (Math.random() - 0.5) * 8;
if (seg > 2.85 && seg < 3.0) y = cy - 50 + jitter;
else if (seg > 3.0 && seg < 3.15) y = cy + 16 + jitter;
else y = cy + jitter + Math.sin(seg * 2.4) * 4;
} else if (type === 'high') {
if (seg > 2.7 && seg < 2.85) y = cy + 6;
else if (seg > 2.85 && seg < 2.98) y = cy - 65;
else if (seg > 2.98 && seg < 3.1) y = cy + 22;
else if (seg > 3.1 && seg < 3.35) y = cy - 4;
else y = cy + Math.sin(seg * 0.3) * 2;
} else if (type === 'low') {
// 心律过低:节律稀疏,QRS 间隔拉长(用更少的 cycles)
var slowCycles = Math.max(3, Math.round(hr / 2));
var sPhase = (i / w) * slowCycles * Math.PI * 2;
var sSeg = sPhase % (Math.PI * 2);
if (sSeg > 2.7 && sSeg < 2.9) y = cy + 5;
else if (sSeg > 2.9 && sSeg < 3.05) y = cy - 50;
else if (sSeg > 3.05 && sSeg < 3.2) y = cy + 16;
else if (sSeg > 3.2 && sSeg < 3.5) y = cy - 2;
else y = cy + Math.sin(sSeg * 0.3) * 1.2;
} else if (type === 'flat') {
// 无症状:基线轻微波动
y = cy + Math.sin(i * 0.05) * 1.2 + (Math.random() - 0.5) * 0.6;
} else if (type === 'uncertain') {
var noise = (Math.random() - 0.5) * 6;
if (seg > 2.8 && seg < 3.0) y = cy - 35 + noise;
else if (seg > 3.0 && seg < 3.15) y = cy + 12 + noise;
else y = cy + noise;
} else {
// sinus 窦性
if (seg > 2.7 && seg < 2.9) y = cy + 5;
else if (seg > 2.9 && seg < 3.05) y = cy - 58;
else if (seg > 3.05 && seg < 3.2) y = cy + 18;
else if (seg > 3.2 && seg < 3.5) y = cy - 3;
else if (seg > 4.0 && seg < 4.4) y = cy + 8;
else y = cy + Math.sin(seg * 0.3) * 1.5;
}
pts.push(i.toFixed(1) + ',' + y.toFixed(1));
}
return 'M' + pts.join(' L');
}
// 时间轴
function buildAxis(start) {
var html = '';
// 起始时间秒解析
var parts = start.split(':');
var baseSec = (+parts[0])*3600 + (+parts[1])*60 + (+parts[2]);
for (var s = 0; s <= 30; s += 5) {
var t = baseSec + s;
var hh = String(Math.floor(t/3600)).padStart(2,'0');
var mm = String(Math.floor((t%3600)/60)).padStart(2,'0');
var ss = String(t%60).padStart(2,'0');
html += '<span>' + hh+':'+mm+':'+ss + '</span>';
}
document.getElementById('ecgAxis').innerHTML = html;
}
// 打开详情
function openDetail(idx) {
var row = ecgData[idx];
var rs = RESULT_MAP[row.result];
currentDownloadIdx = idx;
document.getElementById('dCode').textContent = row.code;
document.getElementById('dDate').textContent = row.date;
document.getElementById('dHr').textContent = row.hr + ' bpm';
document.getElementById('dStart').textContent = row.start;
document.getElementById('dEnd').textContent = row.end;
document.getElementById('dDuration').textContent = '30 秒';
document.getElementById('dResult').innerHTML = '<span class="tag ' + rs.cls + '">' + formatResult(row.result) + '</span>';
document.getElementById('dResultVal').textContent = rs.value;
document.getElementById('dPoints').textContent = row.points.toLocaleString() + ' 点';
document.getElementById('dEcgRange').textContent = row.start + ' - ' + row.end;
// 症状标签 + 症状原始值(各自独立区域,支持多个值)
document.getElementById('dSymptomLabels').innerHTML = row.symptoms.map(function(s){
var sm = SYMPTOM_MAP[s];
var cls = (s === 'none') ? 'tag--info' : 'tag--primary';
return '<span class="tag ' + cls + '">' + sm.label + '</span>';
}).join('');
document.getElementById('dSymptomValues').innerHTML = row.symptoms.map(function(s){
var sm = SYMPTOM_MAP[s];
return '<span class="tag tag--value">' + sm.value + '</span>';
}).join('');
// 波形 + 时间轴
buildGrid();
document.getElementById('ecgLine').setAttribute('d', generateEcgPath(rs.wave, row.hr));
buildAxis(row.start);
document.getElementById('detailModal').classList.add('show');
}
function closeDetail() {
document.getElementById('detailModal').classList.remove('show');
}
// 下载原始数据点文件(CSV 格式)
var currentDownloadIdx = -1;
function downloadEcgData() {
if (currentDownloadIdx < 0) return;
var row = ecgData[currentDownloadIdx];
// 生成模拟心电原始数据(正弦波 + 噪声模拟 ECG 信号)
var lines = ['时间(ms),幅值(uV)'];
var duration = 30000; // 30 秒
var sampleRate = 250; // 250 Hz
var totalSamples = duration / 1000 * sampleRate;
for (var i = 0; i < totalSamples; i++) {
var t = i / sampleRate * 1000; // ms
// 模拟 ECG 信号(简化 QRS 复合波)
var phase = (i / totalSamples) * (row.hr / 2) * Math.PI * 2;
var seg = phase % (Math.PI * 2);
var amp = 0;
if (seg > 2.7 && seg < 2.9) amp = 50 + (Math.random() - 0.5) * 10;
else if (seg > 2.9 && seg < 3.05) amp = 950 + (Math.random() - 0.5) * 40;
else if (seg > 3.05 && seg < 3.2) amp = -200 + (Math.random() - 0.5) * 30;
else if (seg > 3.2 && seg < 3.5) amp = 30 + (Math.random() - 0.5) * 8;
else amp = (Math.random() - 0.5) * 15;
lines.push(t.toFixed(1) + ',' + Math.round(amp));
}
var blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8;' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'ecg_raw_' + row.code + '_' + row.date + '_' + row.start.replace(/:/g,'') + '.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
document.getElementById('detailModal').addEventListener('click', function(e){ if(e.target===this) closeDetail(); });
renderTable();
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -0,0 +1,443 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 锻炼信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-purple{background:#F9F0FF;color:#722ED1;}
.tag-cyan{background:#E6FFFB;color:#13C2C2;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item active">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">锻炼信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>记录ID</label>
<input class="filter-input" placeholder="请输入记录ID" style="min-width:140px;">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">锻炼记录<small>共 186 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>记录ID</th>
<th>运动类型</th>
<th>运动距离(km)</th>
<th>消耗卡路里(千卡)</th>
<th>开始时间</th>
<th>结束时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-id="EX20260602001" data-type="walking" data-dist="2.35" data-cal="128" data-start="2026-06-02 06:30:00" data-end="2026-06-02 07:00:00" data-created="2026-06-02 07:00:05" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="mono">EX20260602001</span></td>
<td>步行</td>
<td>2.35</td>
<td>128</td>
<td>2026-06-02 06:30:00</td>
<td>2026-06-02 07:00:00</td>
<td>2026-06-02 07:00:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-id="EX20260601002" data-type="running" data-dist="5.12" data-cal="420" data-start="2026-06-01 17:30:00" data-end="2026-06-01 18:00:00" data-created="2026-06-01 18:00:08" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="mono">EX20260601002</span></td>
<td>跑步</td>
<td>5.12</td>
<td>420</td>
<td>2026-06-01 17:30:00</td>
<td>2026-06-01 18:00:00</td>
<td>2026-06-01 18:00:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-id="EX20260602003" data-type="cycling" data-dist="12.80" data-cal="385" data-start="2026-06-02 07:00:00" data-end="2026-06-02 07:45:00" data-created="2026-06-02 07:45:06" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="mono">EX20260602003</span></td>
<td>骑行</td>
<td>12.80</td>
<td>385</td>
<td>2026-06-02 07:00:00</td>
<td>2026-06-02 07:45:00</td>
<td>2026-06-02 07:45:06</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-id="EX20260601004" data-type="walking" data-dist="1.50" data-cal="82" data-start="2026-06-01 12:00:00" data-end="2026-06-01 12:20:00" data-created="2026-06-01 12:20:04" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站">
<td><span class="mono">WD-2024-015</span></td>
<td><span class="mono">EX20260601004</span></td>
<td>步行</td>
<td>1.50</td>
<td>82</td>
<td>2026-06-01 12:00:00</td>
<td>2026-06-01 12:20:00</td>
<td>2026-06-01 12:20:04</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-id="EX20260602005" data-type="swimming" data-dist="1.00" data-cal="520" data-start="2026-06-02 19:00:00" data-end="2026-06-02 19:40:00" data-created="2026-06-02 19:40:10" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="mono">EX20260602005</span></td>
<td>游泳</td>
<td>1.00</td>
<td>520</td>
<td>2026-06-02 19:00:00</td>
<td>2026-06-02 19:40:00</td>
<td>2026-06-02 19:40:10</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-032" data-id="EX20260601006" data-type="running" data-dist="3.20" data-cal="265" data-start="2026-06-01 06:15:00" data-end="2026-06-01 06:35:00" data-created="2026-06-01 06:35:05" data-emp="刘洋" data-empcode="CQ002200" data-unit="采气一厂" data-dept="集输站">
<td><span class="mono">WD-2024-032</span></td>
<td><span class="mono">EX20260601006</span></td>
<td>跑步</td>
<td>3.20</td>
<td>265</td>
<td>2026-06-01 06:15:00</td>
<td>2026-06-01 06:35:00</td>
<td>2026-06-01 06:35:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-id="EX20260602007" data-type="climbing" data-dist="0.80" data-cal="195" data-start="2026-06-02 09:00:00" data-end="2026-06-02 10:30:00" data-created="2026-06-02 10:30:08" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td><span class="mono">EX20260602007</span></td>
<td>爬山</td>
<td>0.80</td>
<td>195</td>
<td>2026-06-02 09:00:00</td>
<td>2026-06-02 10:30:00</td>
<td>2026-06-02 10:30:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-id="EX20260601008" data-type="cycling" data-dist="8.50" data-cal="290" data-start="2026-06-01 16:00:00" data-end="2026-06-01 16:30:00" data-created="2026-06-01 16:30:05" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td><span class="mono">EX20260601008</span></td>
<td>骑行</td>
<td>8.50</td>
<td>290</td>
<td>2026-06-01 16:00:00</td>
<td>2026-06-01 16:30:00</td>
<td>2026-06-01 16:30:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-id="EX20260602009" data-type="walking" data-dist="3.10" data-cal="168" data-start="2026-06-02 18:00:00" data-end="2026-06-02 18:40:00" data-created="2026-06-02 18:40:06" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td><span class="mono">EX20260602009</span></td>
<td>步行</td>
<td>3.10</td>
<td>168</td>
<td>2026-06-02 18:00:00</td>
<td>2026-06-02 18:40:00</td>
<td>2026-06-02 18:40:06</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-id="EX20260601010" data-type="running" data-dist="6.00" data-cal="498" data-start="2026-06-01 06:00:00" data-end="2026-06-01 06:36:00" data-created="2026-06-01 06:36:08" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区">
<td><span class="mono">WD-2024-061</span></td>
<td><span class="mono">EX20260601010</span></td>
<td>跑步</td>
<td>6.00</td>
<td>498</td>
<td>2026-06-01 06:00:00</td>
<td>2026-06-01 06:36:00</td>
<td>2026-06-01 06:36:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 186 条</span>
<button class="page-btn">«</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">19</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">锻炼详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>记录ID</label><span class="mono" id="d-id"></span></div>
<div class="detail-item"><label>运动类型</label><span id="d-type"></span></div>
<div class="detail-item"><label>运动距离(km)</label><span id="d-dist"></span></div>
<div class="detail-item"><label>消耗卡路里(千卡)</label><span id="d-cal"></span></div>
<div class="detail-item"><label>开始时间</label><span id="d-start"></span></div>
<div class="detail-item"><label>结束时间</label><span id="d-end"></span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
// 运动类型字典
var TYPE_MAP = {
walking: '步行',
running: '跑步',
cycling: '骑行',
swimming: '游泳',
climbing: '爬山'
};
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
var typeName = TYPE_MAP[d.type] || d.type;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-id').textContent = d.id;
document.getElementById('d-type').textContent = typeName;
document.getElementById('d-dist').textContent = d.dist;
document.getElementById('d-cal').textContent = d.cal;
document.getElementById('d-start').textContent = d.start;
document.getElementById('d-end').textContent = d.end;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,385 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 心率信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item active">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">心率信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">心率记录<small>共 960 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据值(次/分)</th>
<th>静息心率(次/分)</th>
<th>监测时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<tr data-code="WD-2024-001" data-value="78" data-rest="62" data-monitor="2026-06-02 08:01:22" data-created="2026-06-02 08:01:25" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>78</td>
<td>62</td>
<td>2026-06-02 08:01:22</td>
<td>2026-06-02 08:01:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-value="85" data-rest="63" data-monitor="2026-06-02 09:01:18" data-created="2026-06-02 09:01:21" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>85</span></td>
<td>63</td>
<td>2026-06-02 09:01:18</td>
<td>2026-06-02 09:01:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="92" data-rest="68" data-monitor="2026-06-02 08:05:44" data-created="2026-06-02 08:05:47" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>92</span></td>
<td>68</td>
<td>2026-06-02 08:05:44</td>
<td>2026-06-02 08:05:47</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="88" data-rest="67" data-monitor="2026-06-02 09:05:40" data-created="2026-06-02 09:05:43" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>88</span></td>
<td>67</td>
<td>2026-06-02 09:05:40</td>
<td>2026-06-02 09:05:43</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="75" data-rest="60" data-monitor="2026-06-02 08:12:03" data-created="2026-06-02 08:12:06" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>75</span></td>
<td>60</td>
<td>2026-06-02 08:12:03</td>
<td>2026-06-02 08:12:06</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="80" data-rest="61" data-monitor="2026-06-02 09:12:01" data-created="2026-06-02 09:12:04" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>80</span></td>
<td>61</td>
<td>2026-06-02 09:12:01</td>
<td>2026-06-02 09:12:04</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="105" data-rest="72" data-monitor="2026-06-02 07:58:11" data-created="2026-06-02 07:58:14" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>105</span></td>
<td>72</td>
<td>2026-06-02 07:58:11</td>
<td>2026-06-02 07:58:14</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="76" data-rest="70" data-monitor="2026-06-02 08:58:09" data-created="2026-06-02 08:58:12" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>76</span></td>
<td>70</td>
<td>2026-06-02 08:58:09</td>
<td>2026-06-02 08:58:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="82" data-rest="58" data-monitor="2026-06-02 08:20:55" data-created="2026-06-02 08:20:58" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>82</span></td>
<td>58</td>
<td>2026-06-02 08:20:55</td>
<td>2026-06-02 08:20:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="110" data-rest="59" data-monitor="2026-06-02 09:20:52" data-created="2026-06-02 09:20:55" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>110</span></td>
<td>59</td>
<td>2026-06-02 09:20:52</td>
<td>2026-06-02 09:20:55</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 960 条</span>
<button class="page-btn">«</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">96</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">心率详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code">WD-2024-001</span></div>
<div class="detail-item"><label>数据值(次/分)</label><span id="d-value">78</span></div>
<div class="detail-item"><label>静息心率(次/分)</label><span id="d-rest">62</span></div>
<div class="detail-item"><label>监测时间</label><span id="d-monitor">2026-06-02 08:01:22</span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created">2026-06-02 08:01:25</span></div>
<div class="detail-item"><label></label><span></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp">张伟</span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode">CQ001234</span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit">采油一厂</span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept">作业一区</span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-value').textContent = d.value;
document.getElementById('d-rest').textContent = d.rest;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('d-monitor').textContent = d.monitor;
document.getElementById('d-created').textContent = d.created;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,495 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 睡眠信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;--purple:#722ED1;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-purple{background:#F9F0FF;color:#722ED1;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:720px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-banner{background:linear-gradient(135deg,#F9F0FF 0%,#DEE8FC 100%);border-radius:var(--radius-md);padding:18px 20px;margin-bottom:20px;display:flex;align-items:center;gap:16px;}
.detail-banner__icon{width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,0.6);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.detail-banner__main{flex:1;}
.detail-banner__title{font-size:var(--font-base);font-weight:600;color:var(--purple);line-height:1;}
.detail-banner__sub{font-size:var(--font-xs);color:var(--text-secondary);margin-top:6px;}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
/* Tab 切换 */
.tab-nav{display:flex;gap:0;border-bottom:2px solid var(--border);margin-bottom:16px;}
.tab-btn{padding:10px 20px;font-size:var(--font-sm);color:var(--text-secondary);background:none;border:none;cursor:pointer;position:relative;transition:all .2s;}
.tab-btn:hover{color:var(--primary);}
.tab-btn.active{color:var(--primary);font-weight:600;}
.tab-btn.active::after{content:'';position:absolute;left:20px;right:20px;bottom:-2px;height:2px;background:var(--primary);border-radius:1px;}
.tab-pane{display:none;}
.tab-pane.active{display:block;}
/* 详情弹窗内子表格 */
.sub-table{width:100%;border-collapse:collapse;white-space:nowrap;}
.sub-table th{background:#FAFAFA;padding:8px 12px;text-align:left;font-size:var(--font-xs);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
.sub-table td{padding:10px 12px;font-size:var(--font-xs);color:var(--text-primary);border-bottom:1px solid var(--border);}
.sub-table tbody tr:last-child td{border-bottom:none;}
.sub-table tbody tr:hover{background:#F8FBFF;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item active">睡眠信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">睡眠信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">睡眠记录<small>共 96 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据日期</th>
<th>是否有睡眠数据</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-date="2026-06-02" data-has="yes" data-created="2026-06-02 07:05:10" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-sleep="456" data-bed="23:15" data-wake="07:31" data-fall="18" data-eff="91" data-score="82" data-raw-score="78.5" data-snore="2">
<td><span class="mono">WD-2024-001</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-02 07:05:10</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-date="2026-06-01" data-has="yes" data-created="2026-06-01 07:02:08" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-sleep="390" data-bed="22:50" data-wake="05:20" data-fall="25" data-eff="87" data-score="75" data-raw-score="71.2" data-snore="5">
<td><span class="mono">WD-2024-001</span></td>
<td>2026-06-01</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-01 07:02:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-date="2026-06-02" data-has="no" data-created="2026-06-02 07:10:15" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-red"></span></td>
<td>2026-06-02 07:10:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-date="2026-06-02" data-has="yes" data-created="2026-06-02 06:55:20" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站" data-sleep="420" data-bed="23:30" data-wake="06:30" data-fall="12" data-eff="95" data-score="88" data-raw-score="85.3" data-snore="1">
<td><span class="mono">WD-2024-015</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-02 06:55:20</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-date="2026-06-02" data-has="yes" data-created="2026-06-02 07:15:33" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-sleep="370" data-bed="00:10" data-wake="06:20" data-fall="30" data-eff="78" data-score="65" data-raw-score="62.1" data-snore="8">
<td><span class="mono">WD-2024-031</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-02 07:15:33</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-032" data-date="2026-06-01" data-has="yes" data-created="2026-06-01 06:48:12" data-emp="刘洋" data-empcode="CQ002200" data-unit="采气一厂" data-dept="集输站" data-sleep="480" data-bed="22:00" data-wake="06:00" data-fall="10" data-eff="93" data-score="90" data-raw-score="88.7" data-snore="0">
<td><span class="mono">WD-2024-032</span></td>
<td>2026-06-01</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-01 06:48:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-date="2026-06-02" data-has="yes" data-created="2026-06-02 07:20:45" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站" data-sleep="310" data-bed="00:45" data-wake="05:55" data-fall="40" data-eff="72" data-score="58" data-raw-score="55.6" data-snore="12">
<td><span class="mono">WD-2024-048</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-02 07:20:45</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-date="2026-06-02" data-has="no" data-created="2026-06-02 07:30:18" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-red"></span></td>
<td>2026-06-02 07:30:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-date="2026-06-02" data-has="yes" data-created="2026-06-02 07:08:25" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区" data-sleep="445" data-bed="23:00" data-wake="06:25" data-fall="15" data-eff="90" data-score="85" data-raw-score="81.9" data-snore="3">
<td><span class="mono">WD-2024-061</span></td>
<td>2026-06-02</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-02 07:08:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-061" data-date="2026-06-01" data-has="yes" data-created="2026-06-01 06:52:30" data-emp="孙丽" data-empcode="CQ003050" data-unit="采气二厂" data-dept="作业四区" data-sleep="400" data-bed="23:20" data-wake="06:00" data-fall="20" data-eff="86" data-score="79" data-raw-score="76.4" data-snore="4">
<td><span class="mono">WD-2024-061</span></td>
<td>2026-06-01</td>
<td><span class="tag tag-green"></span></td>
<td>2026-06-01 06:52:30</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 96 条</span>
<button class="page-btn">«</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">10</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">睡眠详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-banner">
<div class="detail-banner__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#722ED1" stroke-width="2" stroke-linecap="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
</div>
<div class="detail-banner__main">
<div class="detail-banner__title" id="d-banner-title"></div>
<div class="detail-banner__sub" id="d-banner-sub"></div>
</div>
</div>
<!-- Tab 切换 -->
<div class="tab-nav" id="tabNav">
<button class="tab-btn active" data-tab="result" onclick="switchTab(this)">当天睡眠结果</button>
<button class="tab-btn" data-tab="minute" onclick="switchTab(this)">睡眠每分钟状态</button>
</div>
<!-- Tab 1: 当天睡眠结果 -->
<div class="tab-pane active" id="tab-result">
<table class="sub-table">
<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 id="resultTbody"></tbody>
</table>
<div id="noDataTip" style="text-align:center;padding:30px 0;color:var(--text-placeholder);display:none;">该日期无睡眠数据</div>
</div>
<!-- Tab 2: 睡眠每分钟状态 -->
<div class="tab-pane" id="tab-minute">
<table class="sub-table">
<thead>
<tr>
<th style="width:160px;">开始时间</th>
<th style="width:160px;">结束时间</th>
<th>睡眠状态</th>
</tr>
</thead>
<tbody id="minuteTbody"></tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
// 模拟睡眠每分钟状态数据
var MINUTE_DATA = [
{ start:'23:15', end:'23:30', status:'清醒' },
{ start:'23:30', end:'00:00', status:'浅睡' },
{ start:'00:00', end:'01:30', status:'深睡' },
{ start:'01:30', end:'02:00', status:'浅睡' },
{ start:'02:00', end:'03:00', status:'深睡' },
{ start:'03:00', end:'03:15', status:'清醒' },
{ start:'03:15', end:'04:00', status:'浅睡' },
{ start:'04:00', end:'05:30', status:'深睡' },
{ start:'05:30', end:'06:30', status:'浅睡' },
{ start:'06:30', end:'07:00', status:'清醒' }
];
var STATUS_TAG = { '清醒':'tag-orange', '浅睡':'tag-blue', '深睡':'tag-purple' };
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function switchTab(btn){
document.querySelectorAll('#tabNav .tab-btn').forEach(function(t){t.classList.remove('active');});
btn.classList.add('active');
document.querySelectorAll('.tab-pane').forEach(function(p){p.classList.remove('active');});
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
}
function openDetail(btn){
var tr = btn.closest('tr');
var d = tr.dataset;
// 顶部卡片
document.getElementById('d-banner-title').textContent = d.code + ' · ' + d.date;
document.getElementById('d-banner-sub').textContent = '创建时间:' + d.created;
if (d.has === 'no') {
// 无数据:隐藏表格,显示提示
document.getElementById('resultTbody').innerHTML = '';
document.getElementById('noDataTip').style.display = 'block';
document.getElementById('minuteTbody').innerHTML = '';
return;
}
// Tab 1: 睡眠结果
document.getElementById('noDataTip').style.display = 'none';
var resultTbody = document.getElementById('resultTbody');
var valid = '有效';
var validTag = '<span class="tag tag-green">有效</span>';
resultTbody.innerHTML =
'<tr>' +
'<td>' + d.sleep + '</td>' +
'<td>' + (parseInt(d.fall) > 0 ? formatBedTime(d.bed, d.fall) : d.bed) + '</td>' +
'<td>' + d.wake + '</td>' +
'<td>' + d.bed + '</td>' +
'<td>' + d.eff + '</td>' +
'<td>' + d.fall + '</td>' +
'<td>' + d.score + '</td>' +
'<td>' + d.rawScore + '</td>' +
'<td>' + d.snore + '</td>' +
'<td>' + validTag + '</td>' +
'</tr>';
// Tab 2: 每分钟状态(模拟数据)
var minTbody = document.getElementById('minuteTbody');
minTbody.innerHTML = '';
MINUTE_DATA.forEach(function(row){
var tagCls = STATUS_TAG[row.status] || 'tag-blue';
minTbody.innerHTML +=
'<tr>' +
'<td class="mono">' + row.start + '</td>' +
'<td class="mono">' + row.end + '</td>' +
'<td><span class="tag ' + tagCls + '">' + row.status + '</span></td>' +
'</tr>';
});
}
// 根据上床时间和入睡潜伏期计算入睡时间点
function formatBedTime(bedTime, fallMin) {
var parts = bedTime.split(':');
var h = parseInt(parts[0]), m = parseInt(parts[1]) + parseInt(fallMin);
if (m >= 60) { h += Math.floor(m / 60); m = m % 60; }
if (h >= 24) h = h - 24;
return String(h).padStart(2,'0') + ':' + String(m).padStart(2,'0');
}
</script>
</body>
</html>
@@ -0,0 +1,369 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 血氧信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.val-strong{font-weight:600;color:var(--primary);}
.val-warn{font-weight:600;color:var(--warning);}
.val-danger{font-weight:600;color:var(--danger);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-banner{background:linear-gradient(135deg,#E6F7FF 0%,#BAE7FF 100%);border-radius:var(--radius-md);padding:18px 20px;margin-bottom:20px;display:flex;align-items:center;gap:16px;}
.detail-banner__icon{width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,0.6);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.detail-banner__main{flex:1;}
.detail-banner__value{font-size:32px;font-weight:700;color:var(--primary);line-height:1;}
.detail-banner__value .unit{font-size:var(--font-base);font-weight:500;color:var(--text-secondary);margin-left:6px;}
.detail-banner__sub{font-size:var(--font-xs);color:var(--text-secondary);margin-top:6px;}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-list--single{grid-template-columns:1fr;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item active">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">血氧信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">血氧记录<small>共 1,286 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据值(%)</th>
<th>监测时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<tr data-code="WD-2024-001" data-value="98" data-monitor="2026-06-02 14:25:30" data-created="2026-06-02 14:25:35" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-source="自动采集" data-quality="优">
<td><span class="mono">WD-2024-001</span></td>
<td>98</td>
<td>2026-06-02 14:25:30</td>
<td>2026-06-02 14:25:35</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-value="97" data-monitor="2026-06-02 14:10:30" data-created="2026-06-02 14:10:32" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-source="自动采集" data-quality="优">
<td><span class="mono">WD-2024-001</span></td>
<td>97</td>
<td>2026-06-02 14:10:30</td>
<td>2026-06-02 14:10:32</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="93" data-monitor="2026-06-02 13:55:18" data-created="2026-06-02 13:55:22" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-source="自动采集" data-quality="良">
<td><span class="mono">WD-2024-002</span></td>
<td>93</td>
<td>2026-06-02 13:55:18</td>
<td>2026-06-02 13:55:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="89" data-monitor="2026-06-02 13:40:55" data-created="2026-06-02 13:40:58" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-source="自动采集" data-quality="差" data-alarm="1">
<td><span class="mono">WD-2024-031</span></td>
<td>89</td>
<td>2026-06-02 13:40:55</td>
<td>2026-06-02 13:40:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-value="98" data-monitor="2026-06-02 13:25:12" data-created="2026-06-02 13:25:14" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-source="自动采集" data-quality="优">
<td><span class="mono">WD-2024-001</span></td>
<td>98</td>
<td>2026-06-02 13:25:12</td>
<td>2026-06-02 13:25:14</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="96" data-monitor="2026-06-02 13:10:45" data-created="2026-06-02 13:10:48" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-source="自动采集" data-quality="优">
<td><span class="mono">WD-2024-002</span></td>
<td>96</td>
<td>2026-06-02 13:10:45</td>
<td>2026-06-02 13:10:48</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-016" data-value="94" data-monitor="2026-06-02 12:55:08" data-created="2026-06-02 12:55:11" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站" data-source="自动采集" data-quality="良">
<td><span class="mono">WD-2024-016</span></td>
<td>94</td>
<td>2026-06-02 12:55:08</td>
<td>2026-06-02 12:55:11</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="95" data-monitor="2026-06-02 12:40:20" data-created="2026-06-02 12:40:23" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-source="自动采集" data-quality="良">
<td><span class="mono">WD-2024-031</span></td>
<td>95</td>
<td>2026-06-02 12:40:20</td>
<td>2026-06-02 12:40:23</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 1,286 条</span>
<button class="page-btn">«</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">129</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">血氧详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code">WD-2024-001</span></div>
<div class="detail-item"><label>数据值</label><span id="d-value">98</span></div>
<div class="detail-item"><label>监测时间</label><span id="d-monitor">2026-06-02 14:25:30</span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created">2026-06-02 14:25:35</span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp">张伟</span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode">CQ001234</span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit">采油一厂</span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept">作业一区</span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-value').textContent = d.value;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('d-monitor').textContent = d.monitor;
document.getElementById('d-created').textContent = d.created;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,386 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 压力信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item active">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">压力信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">压力记录<small>共 512 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据值</th>
<th>开始时间</th>
<th>结束时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<!-- 绑定员工信息通过 data-* 属性保存 -->
<tr data-code="WD-2024-001" data-value="45" data-start="2026-06-02 08:00:00" data-end="2026-06-02 08:15:00" data-created="2026-06-02 08:15:05" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>45</td>
<td>2026-06-02 08:00:00</td>
<td>2026-06-02 08:15:00</td>
<td>2026-06-02 08:15:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-value="62" data-start="2026-06-02 09:00:00" data-end="2026-06-02 09:15:00" data-created="2026-06-02 09:15:03" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区">
<td><span class="mono">WD-2024-001</span></td>
<td>62</td>
<td>2026-06-02 09:00:00</td>
<td>2026-06-02 09:15:00</td>
<td>2026-06-02 09:15:03</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="78" data-start="2026-06-02 08:05:00" data-end="2026-06-02 08:20:00" data-created="2026-06-02 08:20:04" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>78</td>
<td>2026-06-02 08:05:00</td>
<td>2026-06-02 08:20:00</td>
<td>2026-06-02 08:20:04</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="55" data-start="2026-06-02 09:05:00" data-end="2026-06-02 09:20:00" data-created="2026-06-02 09:20:02" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区">
<td><span class="mono">WD-2024-002</span></td>
<td>55</td>
<td>2026-06-02 09:05:00</td>
<td>2026-06-02 09:20:00</td>
<td>2026-06-02 09:20:02</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="35" data-start="2026-06-02 08:10:00" data-end="2026-06-02 08:25:00" data-created="2026-06-02 08:25:06" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>35</td>
<td>2026-06-02 08:10:00</td>
<td>2026-06-02 08:25:00</td>
<td>2026-06-02 08:25:06</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="50" data-start="2026-06-02 09:10:00" data-end="2026-06-02 09:25:00" data-created="2026-06-02 09:25:04" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站">
<td><span class="mono">WD-2024-031</span></td>
<td>50</td>
<td>2026-06-02 09:10:00</td>
<td>2026-06-02 09:25:00</td>
<td>2026-06-02 09:25:04</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="85" data-start="2026-06-02 07:55:00" data-end="2026-06-02 08:10:00" data-created="2026-06-02 08:10:03" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>85</td>
<td>2026-06-02 07:55:00</td>
<td>2026-06-02 08:10:00</td>
<td>2026-06-02 08:10:03</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="42" data-start="2026-06-02 08:55:00" data-end="2026-06-02 09:10:00" data-created="2026-06-02 09:10:02" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站">
<td><span class="mono">WD-2024-048</span></td>
<td>42</td>
<td>2026-06-02 08:55:00</td>
<td>2026-06-02 09:10:00</td>
<td>2026-06-02 09:10:02</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="30" data-start="2026-06-02 08:20:00" data-end="2026-06-02 08:35:00" data-created="2026-06-02 08:35:05" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>30</td>
<td>2026-06-02 08:20:00</td>
<td>2026-06-02 08:35:00</td>
<td>2026-06-02 08:35:05</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="68" data-start="2026-06-02 09:20:00" data-end="2026-06-02 09:35:00" data-created="2026-06-02 09:35:03" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区">
<td><span class="mono">WD-2024-060</span></td>
<td>68</td>
<td>2026-06-02 09:20:00</td>
<td>2026-06-02 09:35:00</td>
<td>2026-06-02 09:35:03</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 512 条</span>
<button class="page-btn">«</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">52</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">压力详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code">WD-2024-001</span></div>
<div class="detail-item"><label>数据值</label><span id="d-value">45</span></div>
<div class="detail-item"><label>开始时间</label><span id="d-start">2026-06-02 08:00:00</span></div>
<div class="detail-item"><label>结束时间</label><span id="d-end">2026-06-02 08:15:00</span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created">2026-06-02 08:15:05</span></div>
<div class="detail-item"><label></label><span></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp">张伟</span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode">CQ001234</span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit">采油一厂</span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept">作业一区</span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-value').textContent = d.value;
document.getElementById('d-start').textContent = d.start;
document.getElementById('d-end').textContent = d.end;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,385 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 体温信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.val-normal{font-weight:600;color:var(--success);}
.val-warn{font-weight:600;color:var(--warning);}
.val-danger{font-weight:600;color:var(--danger);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-red{background:#FFF1F0;color:#FF4D4F;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-banner{background:linear-gradient(135deg,#E6F7FF 0%,#BAE7FF 100%);border-radius:var(--radius-md);padding:18px 20px;margin-bottom:20px;display:flex;align-items:center;gap:16px;}
.detail-banner__icon{width:48px;height:48px;border-radius:50%;background:rgba(255,255,255,0.6);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.detail-banner__main{flex:1;}
.detail-banner__value{font-size:32px;font-weight:700;color:var(--primary);line-height:1;}
.detail-banner__value .unit{font-size:var(--font-base);font-weight:500;color:var(--text-secondary);margin-left:6px;}
.detail-banner__sub{font-size:var(--font-xs);color:var(--text-secondary);margin-top:6px;}
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item active">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">体温信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">体温记录<small>共 248 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据值(℃)</th>
<th>监测时间</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody">
<!-- 绑定员工信息通过 data-* 属性保存 -->
<tr data-code="WD-2024-001" data-value="36.5" data-monitor="2026-06-02 08:01:22" data-created="2026-06-02 08:01:25" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-001</span></td>
<td>36.5</td>
<td>2026-06-02 08:01:22</td>
<td>2026-06-02 08:01:25</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-value="36.7" data-monitor="2026-06-02 09:01:18" data-created="2026-06-02 09:01:21" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-001</span></td>
<td>36.7</td>
<td>2026-06-02 09:01:18</td>
<td>2026-06-02 09:01:21</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="37.8" data-monitor="2026-06-02 08:05:44" data-created="2026-06-02 08:05:47" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-min="36.0" data-max="37.3" data-alarm="1">
<td><span class="mono">WD-2024-002</span></td>
<td>37.8</td>
<td>2026-06-02 08:05:44</td>
<td>2026-06-02 08:05:47</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-value="36.9" data-monitor="2026-06-02 09:05:40" data-created="2026-06-02 09:05:43" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-002</span></td>
<td>36.9</td>
<td>2026-06-02 09:05:40</td>
<td>2026-06-02 09:05:43</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="36.4" data-monitor="2026-06-02 08:12:03" data-created="2026-06-02 08:12:06" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-031</span></td>
<td>36.4</td>
<td>2026-06-02 08:12:03</td>
<td>2026-06-02 08:12:06</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-value="36.6" data-monitor="2026-06-02 09:12:01" data-created="2026-06-02 09:12:04" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-031</span></td>
<td>36.6</td>
<td>2026-06-02 09:12:01</td>
<td>2026-06-02 09:12:04</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="35.8" data-monitor="2026-06-02 07:58:11" data-created="2026-06-02 07:58:14" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站" data-min="36.0" data-max="37.3" data-alarm="1">
<td><span class="mono">WD-2024-048</span></td>
<td>35.8</td>
<td>2026-06-02 07:58:11</td>
<td>2026-06-02 07:58:14</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-value="36.2" data-monitor="2026-06-02 08:58:09" data-created="2026-06-02 08:58:12" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-048</span></td>
<td>36.2</td>
<td>2026-06-02 08:58:09</td>
<td>2026-06-02 08:58:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="36.8" data-monitor="2026-06-02 08:20:55" data-created="2026-06-02 08:20:58" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区" data-min="36.0" data-max="37.3">
<td><span class="mono">WD-2024-060</span></td>
<td>36.8</td>
<td>2026-06-02 08:20:55</td>
<td>2026-06-02 08:20:58</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-060" data-value="38.1" data-monitor="2026-06-02 09:20:52" data-created="2026-06-02 09:20:55" data-emp="赵强" data-empcode="CQ003010" data-unit="采气二厂" data-dept="作业三区" data-min="36.0" data-max="37.3" data-alarm="1">
<td><span class="mono">WD-2024-060</span></td>
<td>38.1</td>
<td>2026-06-02 09:20:52</td>
<td>2026-06-02 09:20:55</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 248 条</span>
<button class="page-btn">«</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">25</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">体温详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code">WD-2024-001</span></div>
<div class="detail-item"><label>数据值</label><span id="d-value-display">36.5 ℃</span></div>
<div class="detail-item"><label>监测时间</label><span id="d-monitor">2026-06-02 08:01:22</span></div>
<div class="detail-item"><label>创建时间</label><span id="d-created">2026-06-02 08:01:25</span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp">张伟</span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode">CQ001234</span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit">采油一厂</span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept">作业一区</span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var td = btn.parentElement;
var tr = td.parentElement;
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('d-monitor').textContent = d.monitor;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-value-display').textContent = d.value + ' ℃';
document.getElementById('detailModal').classList.add('show');
}
</script>
</body>
</html>
@@ -0,0 +1,417 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - SDC信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* 页头 */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* 筛选 */
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;min-width:180px;}
.filter-input:focus{border-color:var(--primary);}
.date-range{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;height:36px;background:#fff;}
.date-range input{border:none;outline:none;font-size:var(--font-sm);color:var(--text-primary);height:34px;width:140px;}
.date-range .sep{color:var(--text-placeholder);font-size:var(--font-sm);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
/* 操作行 */
.action-bar{display:flex;gap:8px;align-items:center;margin-bottom:12px;}
/* 表格 */
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__title small{font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;margin-left:8px;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.mono{font-family:'SFMono-Regular',Consolas,Menlo,monospace;color:var(--text-primary);}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-blue{background:#E6F7FF;color:#1890FF;}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-orange{background:#FFF7E6;color:#FAAD14;}
.tag-purple{background:#F9F0FF;color:#722ED1;}
.tag-cyan{background:#E6FFFB;color:#13C2C2;}
/* 分页 */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:90px;}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
/* 详情弹窗专属 */
.detail-list{display:grid;grid-template-columns:1fr 1fr;gap:14px 24px;}
.detail-item{display:flex;flex-direction:column;gap:4px;}
.detail-item label{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-item span{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;word-break:break-all;}
.detail-section-title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);margin:18px 0 10px;display:flex;align-items:center;gap:6px;}
.detail-section-title::before{content:'';width:3px;height:14px;background:var(--primary);border-radius:2px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item active">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="page-header">
<div class="page-title">SDC信息</div>
</div>
<!-- 筛选 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码">
</div>
<div class="filter-item">
<label>数据类型</label>
<select class="filter-select" style="min-width:150px;">
<option>全部</option>
<option>步数</option>
<option>距离</option>
<option>卡路里</option>
<option>爬楼高度</option>
<option>中高强度运动时间</option>
</select>
</div>
<div class="filter-item">
<label>日期范围</label>
<div class="date-range">
<input type="date" value="2026-05-26">
<span class="sep"></span>
<input type="date" value="2026-06-02">
</div>
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 操作行 -->
<div class="action-bar">
<button class="btn btn-default">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1v8M3.5 5.5L7 9l3.5-3.5M2 12h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
导出列表数据
</button>
<button class="btn btn-default">查看导出任务</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">SDC数据列表<small>共 325 条</small></span>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>数据类型</th>
<th>日期</th>
<th>数据值</th>
<th>详细数据</th>
<th>创建日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr data-code="WD-2024-001" data-type="steps" data-date="2026-06-02" data-value="12580" data-created="2026-06-02 07:05:10" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-label="步数" data-unit-label="步">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-blue">步数</span></td>
<td>2026-06-02</td>
<td>12580</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:05:10</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-type="distance" data-date="2026-06-02" data-value="8.65" data-created="2026-06-02 07:05:12" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-label="距离" data-unit-label="km">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-green">距离</span></td>
<td>2026-06-02</td>
<td>8.65</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:05:12</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-type="calories" data-date="2026-06-02" data-value="485" data-created="2026-06-02 07:05:14" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-label="卡路里" data-unit-label="千卡">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-orange">卡路里</span></td>
<td>2026-06-02</td>
<td>485</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:05:14</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-type="floors" data-date="2026-06-02" data-value="18" data-created="2026-06-02 07:05:16" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-label="爬楼高度" data-unit-label="层">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-purple">爬楼高度</span></td>
<td>2026-06-02</td>
<td>18</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:05:16</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-001" data-type="mvpa" data-date="2026-06-02" data-value="45" data-created="2026-06-02 07:05:18" data-emp="张伟" data-empcode="CQ001234" data-unit="采油一厂" data-dept="作业一区" data-label="中高强度运动时间" data-unit-label="分钟">
<td><span class="mono">WD-2024-001</span></td>
<td><span class="tag tag-cyan">中高强度运动时间</span></td>
<td>2026-06-02</td>
<td>45</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:05:18</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-002" data-type="steps" data-date="2026-06-02" data-value="9850" data-created="2026-06-02 07:10:08" data-emp="李建国" data-empcode="CQ001235" data-unit="采油一厂" data-dept="作业二区" data-label="步数" data-unit-label="步">
<td><span class="mono">WD-2024-002</span></td>
<td><span class="tag tag-blue">步数</span></td>
<td>2026-06-02</td>
<td>9850</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:10:08</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-015" data-type="steps" data-date="2026-06-02" data-value="7230" data-created="2026-06-02 06:55:15" data-emp="王芳" data-empcode="CQ001520" data-unit="采气一厂" data-dept="采气站" data-label="步数" data-unit-label="步">
<td><span class="mono">WD-2024-015</span></td>
<td><span class="tag tag-blue">步数</span></td>
<td>2026-06-02</td>
<td>7230</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 06:55:15</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-type="distance" data-date="2026-06-02" data-value="5.32" data-created="2026-06-02 07:15:20" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-label="距离" data-unit-label="km">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-green">距离</span></td>
<td>2026-06-02</td>
<td>5.32</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:15:20</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-031" data-type="calories" data-date="2026-06-02" data-value="320" data-created="2026-06-02 07:15:22" data-emp="王磊" data-empcode="CQ002101" data-unit="采气一厂" data-dept="集气站" data-label="卡路里" data-unit-label="千卡">
<td><span class="mono">WD-2024-031</span></td>
<td><span class="tag tag-orange">卡路里</span></td>
<td>2026-06-02</td>
<td>320</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:15:22</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
<tr data-code="WD-2024-048" data-type="mvpa" data-date="2026-06-02" data-value="28" data-created="2026-06-02 07:20:35" data-emp="陈晓明" data-empcode="CQ001500" data-unit="采油二厂" data-dept="注水站" data-label="中高强度运动时间" data-unit-label="分钟">
<td><span class="mono">WD-2024-048</span></td>
<td><span class="tag tag-cyan">中高强度运动时间</span></td>
<td>2026-06-02</td>
<td>28</td>
<td><button class="btn-link" onclick="downloadDetail(this)">下载</button></td>
<td>2026-06-02 07:20:35</td>
<td><button class="btn-link" onclick="openDetail(this)">详情</button></td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 325 条</span>
<button class="page-btn">«</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">33</button>
<button class="page-btn">»</button>
<select class="filter-select">
<option>10条/页</option>
<option>20条/页</option>
<option>50条/页</option>
</select>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal-header">
<span class="modal-title">SDC数据详情</span>
<button class="modal-close" onclick="closeModal('detailModal')"></button>
</div>
<div class="modal-body">
<div class="detail-section-title">采集信息</div>
<div class="detail-list">
<div class="detail-item"><label>设备编码</label><span class="mono" id="d-code"></span></div>
<div class="detail-item"><label>数据类型</label><span id="d-type"></span></div>
<div class="detail-item"><label>日期</label><span id="d-date"></span></div>
<div class="detail-item"><label>数据值</label><span id="d-value"></span></div>
<div class="detail-item"><label>创建日期</label><span id="d-created"></span></div>
</div>
<div class="detail-section-title">绑定员工</div>
<div class="detail-list">
<div class="detail-item"><label>员工姓名</label><span id="d-emp"></span></div>
<div class="detail-item"><label>员工编号</label><span class="mono" id="d-empcode"></span></div>
<div class="detail-item"><label>所属单位</label><span id="d-unit"></span></div>
<div class="detail-item"><label>所属部门</label><span id="d-dept"></span></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('detailModal')">关闭</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
function closeModal(id){document.getElementById(id).classList.remove('show');}
document.querySelectorAll('.modal-mask').forEach(function(m){m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});});
function openDetail(btn){
var tr = btn.closest('tr');
var d = tr.dataset;
document.getElementById('d-code').textContent = d.code;
document.getElementById('d-type').textContent = d.label;
document.getElementById('d-type').textContent = d.label;
document.getElementById('d-date').textContent = d.date;
document.getElementById('d-value').textContent = d.value;
document.getElementById('d-created').textContent = d.created;
document.getElementById('d-emp').textContent = d.emp;
document.getElementById('d-empcode').textContent = d.empcode;
document.getElementById('d-unit').textContent = d.unit;
document.getElementById('d-dept').textContent = d.dept;
document.getElementById('detailModal').classList.add('show');
}
function downloadDetail(btn){
var tr = btn.closest('tr');
var d = tr.dataset;
alert('下载 ' + d.code + ' ' + d.label + ' ' + d.date + ' 的详细数据文件');
}
</script>
</body>
</html>
@@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 配置信息 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-section__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
.filter-bar{background:#fff;border-radius:var(--radius-md);padding:20px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;}
.filter-input:focus{border-color:var(--primary);}
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;}.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);}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
.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;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.json-preview{font-family:monospace;font-size:var(--font-xs);color:var(--text-secondary);max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;}
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:640px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.detail-meta{display:grid;grid-template-columns:1fr 1fr;gap:8px 24px;margin-bottom:20px;padding:14px 16px;background:#FAFAFA;border-radius:var(--radius-md);}
.detail-meta-item{display:flex;flex-direction:column;gap:2px;}
.detail-meta-item span:first-child{font-size:var(--font-xs);color:var(--text-placeholder);}
.detail-meta-item span:last-child{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;}
.json-block{background:#1e1e1e;border-radius:var(--radius-md);padding:16px;overflow:auto;max-height:400px;}
.json-block pre{font-family:'Consolas','Courier New',monospace;font-size:13px;line-height:1.6;color:#d4d4d4;white-space:pre;margin:0;}
.json-key{color:#9cdcfe;}.json-str{color:#ce9178;}.json-num{color:#b5cea8;}.json-bool{color:#569cd6;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item active">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<label>设备编码</label>
<input class="filter-input" placeholder="请输入设备编码" style="min-width:180px;">
</div>
<div class="filter-item">
<label>日期范围</label>
<input class="filter-input" type="date" value="2026-05-01">
<span style="color:var(--text-secondary);font-size:var(--font-sm);"></span>
<input class="filter-input" type="date" value="2026-06-02">
</div>
<button class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="4.5" stroke="currentColor" stroke-width="1.5"/><path d="M10.5 10.5l2 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
查询
</button>
<button class="btn btn-default">重置</button>
</div>
<!-- 表格 -->
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">配置信息列表 <span style="font-size:var(--font-sm);color:var(--text-secondary);font-weight:400;">共 36 条</span></span>
<button class="btn btn-default">导出列表数据</button>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>设备编码</th>
<th>配置时间</th>
<th>配置信息</th>
<th>操作</th>
</tr>
</thead>
<tbody id="configTbody"></tbody>
</table>
</div>
<div class="pagination">
<span>共 36 条</span>
<button class="page-btn">«</button>
<button class="page-btn active">1</button>
<button class="page-btn">2</button>
<button class="page-btn">3</button>
<button class="page-btn">4</button>
<button class="page-btn">»</button>
</div>
</div>
</main>
<!-- 详情弹窗 -->
<div class="modal-mask" id="detailModal">
<div class="modal">
<div class="modal__header">
<h3>配置详情</h3>
<button class="modal__close" onclick="closeDetail()">×</button>
</div>
<div class="modal__body">
<div class="detail-meta">
<div class="detail-meta-item"><span>设备编码</span><span id="dCode"></span></div>
<div class="detail-meta-item"><span>配置时间</span><span id="dTime"></span></div>
</div>
<div class="json-block"><pre id="dJson"></pre></div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeDetail()">关闭</button>
</div>
</div>
</div>
<script>
var configData = [
{ code:'WD-2024-001', time:'2026-05-28 09:12:34', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:true,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:false,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.1", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-002', time:'2026-05-28 09:15:02', json:{ heartRate:{enabled:true,minThreshold:55,maxThreshold:110,uploadInterval:30}, bloodOxygen:{enabled:true,minThreshold:88,maxThreshold:100,uploadInterval:60}, stress:{enabled:false,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:true,minThreshold:36.0,maxThreshold:37.5,uploadInterval:120}, firmwareVersion:"2.3.1", networkMode:"WiFi", syncInterval:600 } },
{ code:'WD-2024-015', time:'2026-05-27 14:30:11', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:false,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:false,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:false,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.2.9", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-016', time:'2026-05-27 14:31:45', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:true,minThreshold:0,maxThreshold:75,uploadInterval:60}, temperature:{enabled:true,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.0", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-031', time:'2026-05-26 10:05:58', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:true,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:false,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.1", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-032', time:'2026-05-26 10:08:22', json:{ heartRate:{enabled:false,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:false,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:false,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:false,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.1.5", networkMode:"WiFi", syncInterval:600 } },
{ code:'WD-2024-048', time:'2026-05-25 16:44:09', json:{ heartRate:{enabled:true,minThreshold:65,maxThreshold:95,uploadInterval:30}, bloodOxygen:{enabled:true,minThreshold:92,maxThreshold:100,uploadInterval:30}, stress:{enabled:true,minThreshold:0,maxThreshold:70,uploadInterval:30}, temperature:{enabled:true,minThreshold:36.1,maxThreshold:37.2,uploadInterval:30}, firmwareVersion:"2.3.1", networkMode:"4G", syncInterval:180 } },
{ code:'WD-2024-049', time:'2026-05-25 16:46:33', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:false,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:true,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.0", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-060', time:'2026-05-24 08:20:17', json:{ heartRate:{enabled:true,minThreshold:60,maxThreshold:100,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:90,maxThreshold:100,uploadInterval:60}, stress:{enabled:true,minThreshold:0,maxThreshold:80,uploadInterval:60}, temperature:{enabled:true,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.1", networkMode:"4G", syncInterval:300 } },
{ code:'WD-2024-061', time:'2026-05-24 08:22:45', json:{ heartRate:{enabled:true,minThreshold:58,maxThreshold:105,uploadInterval:60}, bloodOxygen:{enabled:true,minThreshold:89,maxThreshold:100,uploadInterval:60}, stress:{enabled:true,minThreshold:0,maxThreshold:85,uploadInterval:60}, temperature:{enabled:false,minThreshold:36.0,maxThreshold:37.3,uploadInterval:60}, firmwareVersion:"2.3.1", networkMode:"4G", syncInterval:300 } }
];
function renderTable() {
var tbody = document.getElementById('configTbody');
tbody.innerHTML = '';
configData.forEach(function(row, i) {
var jsonStr = JSON.stringify(row.json);
var tr = document.createElement('tr');
tr.innerHTML =
'<td><span style="font-family:monospace">' + row.code + '</span></td>' +
'<td>' + row.time + '</td>' +
'<td><span class="json-preview">' + jsonStr + '</span></td>' +
'<td><span class="link" onclick="openDetail(' + i + ')">详情</span></td>';
tbody.appendChild(tr);
});
}
function syntaxHighlight(json) {
var str = JSON.stringify(json, null, 2);
return str.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
if (/^"/.test(match)) {
if (/:$/.test(match)) return '<span class="json-key">' + match + '</span>';
return '<span class="json-str">' + match + '</span>';
}
if (/true|false/.test(match)) return '<span class="json-bool">' + match + '</span>';
return '<span class="json-num">' + match + '</span>';
});
}
function openDetail(idx) {
var row = configData[idx];
document.getElementById('dCode').textContent = row.code;
document.getElementById('dTime').textContent = row.time;
document.getElementById('dJson').innerHTML = syntaxHighlight(row.json);
document.getElementById('detailModal').classList.add('show');
}
function closeDetail() {
document.getElementById('detailModal').classList.remove('show');
}
document.getElementById('detailModal').addEventListener('click', function(e){ if(e.target===this) closeDetail(); });
renderTable();
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -0,0 +1,722 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康监测 - 默认配置 | 健康长庆原型</title>
<style>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);--shadow-md:0 4px 12px rgba(0,0,0,0.12);
}
/* ── Top bar ── */
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
/* ── Sidebar ── */
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
.sidebar-item.active{color:#fff;background:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
/* ── Main ── */
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
/* ── Page header ── */
.page-header{margin-bottom:20px;}
.page-title{font-size:var(--font-lg);font-weight:600;color:var(--text-primary);}
/* ── Tabs ── */
.tabs{display:flex;gap:0;background:#fff;border-radius:var(--radius-md) var(--radius-md) 0 0;border-bottom:1px solid var(--border);box-shadow:var(--shadow-sm);padding:0 24px;}
.tab-btn{padding:14px 20px;font-size:var(--font-sm);color:var(--text-secondary);cursor:pointer;border:none;background:none;border-bottom:2px solid transparent;margin-bottom:-1px;transition:all .2s;}
.tab-btn:hover{color:var(--primary);}
.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary);font-weight:500;}
.tab-panel{display:none;}
.tab-panel.active{display:block;}
/* ── Filter bar ── */
.filter-bar{background:#fff;padding:20px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.filter-select{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;min-width:140px;}
.filter-select:focus{border-color:var(--primary);}
/* ── Buttons ── */
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;}
.btn-primary{background:var(--primary);color:#fff;border:1px solid var(--primary);}.btn-primary:hover{background:#40a9ff;border-color:#40a9ff;}
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
.btn-purple{background:#fff;color:#722ED1;border:1px solid #722ED1;}.btn-purple:hover{background:#F9F0FF;}
.btn-sm{height:28px;padding:0 10px;font-size:var(--font-xs);}
.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link:hover{color:#40a9ff;}
.btn-link-danger{background:none;border:none;color:var(--danger);cursor:pointer;font-size:var(--font-sm);padding:0 4px;}.btn-link-danger:hover{color:#ff7875;}
/* ── Table card ── */
.table-card{background:#fff;border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-sm);}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:14px 24px;border-bottom:1px solid var(--border);}
.table-card__actions{display:flex;gap:8px;align-items:center;}
.table-card__content{overflow-x:auto;}
table{width:100%;border-collapse:collapse;white-space:nowrap;}
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);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
/* ── Tags ── */
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:#52C41A;}
.tag-gray{background:#F5F5F5;color:#666;}
/* ── Pagination ── */
.pagination{display:flex;align-items:center;justify-content:flex-end;padding:16px 24px;gap:8px;border-top:1px solid var(--border);}
.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);display:inline-flex;align-items:center;justify-content:center;transition:all .2s;}
.page-btn:hover,.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary);}
/* ── Modal ── */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:480px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:18px;color:var(--text-secondary);border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;transition:all .15s;}
.modal-close:hover{background:#F5F5F5;color:var(--text-primary);}
.modal-body{padding:24px;}
.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 24px;border-top:1px solid var(--border);}
.form-item{margin-bottom:20px;}
.form-label{display:block;font-size:var(--font-sm);color:var(--text-primary);margin-bottom:6px;font-weight:500;}
.form-label .required{color:var(--danger);margin-left:2px;}
.form-input{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff;}
.form-input:focus{border-color:var(--primary);}
.form-select{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;cursor:pointer;}
.form-select:focus{border-color:var(--primary);}
/* Delete confirm modal */
.confirm-modal{width:400px;}
.confirm-icon{width:48px;height:48px;background:#FFF7E6;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 16px;font-size:24px;}
.confirm-title{text-align:center;font-size:var(--font-base);font-weight:600;margin-bottom:8px;}
.confirm-desc{text-align:center;font-size:var(--font-sm);color:var(--text-secondary);}
/* Input with unit suffix */
.input-suffix-wrap{display:flex;align-items:center;gap:0;}
.input-suffix-wrap .form-input{border-radius:var(--radius-sm) 0 0 var(--radius-sm);flex:1;}
.input-suffix{height:36px;padding:0 10px;background:#FAFAFA;border:1px solid var(--border);border-left:none;border-radius:0 var(--radius-sm) var(--radius-sm) 0;font-size:var(--font-sm);color:var(--text-secondary);display:flex;align-items:center;white-space:nowrap;}
</style>
</head>
<body>
<!-- ── Top navigation bar ── -->
<div class="top-bar">
<div class="top-bar__logo">
<svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg>
健康监测
</div>
<nav class="top-bar__nav">
<a href="../../archive-personal.html">档案</a>
<a href="../../crowd-status-employee.html">健康现状</a>
<a href="../../health-checkup/survey-category.html">健康排查</a>
<a href="../tool-manage.html" class="active">穿戴监测</a>
<a href="../../weight/scale-device.html">体重监测</a>
<a href="../../environment/indoor-device-list.html">环境监测</a>
<a href="../../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span>系统管理员 ▾</span>
</div>
</div>
<!-- ── Left sidebar ── -->
<aside class="sidebar">
<div class="sidebar-menu__title">穿戴监测</div>
<a href="../tool-manage.html" class="sidebar-item">设备管理</a>
<a href="../bind-record.html" class="sidebar-item">绑定记录</a>
<a href="../user-data.html" class="sidebar-item">用户数据</a>
<a href="../exception-event.html" class="sidebar-item">告警记录</a>
<a href="../notification.html" class="sidebar-item">通知消息</a>
<a href="../dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="../personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="../dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
运维中心
</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
终端设置
</div>
<div class="sidebar-subgroup__body">
<a href="terminal-default-config.html" class="sidebar-item active">默认配置</a>
<a href="terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
日常监测
</div>
<div class="sidebar-subgroup__body">
<a href="monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
日志管理
</div>
<div class="sidebar-subgroup__body">
<a href="log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="log-version.html" class="sidebar-item">版本更新历史</a>
<a href="log-error.html" class="sidebar-item">手表错误日志</a>
<a href="log-task.html" class="sidebar-item">任务日志</a>
<a href="log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<!-- ── Main content ── -->
<main class="main">
<div class="page-header">
<div class="page-title">默认配置</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab-btn active" onclick="switchTab(0)">阈值默认配置</button>
<button class="tab-btn" onclick="switchTab(1)">上传默认配置</button>
<button class="tab-btn" onclick="switchTab(2)">开关默认配置</button>
</div>
<!-- ===== TAB 1: 阈值默认配置 ===== -->
<div class="tab-panel active" id="tab-panel-0">
<!-- Filter bar -->
<div class="filter-bar">
<div class="filter-item">
<label>数据类型</label>
<select class="filter-select">
<option>全部</option>
<option>体温</option>
<option>血氧</option>
<option>心率</option>
<option>压力</option>
<option>步数</option>
<option>睡眠</option>
</select>
</div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
</div>
<!-- Table card -->
<div class="table-card">
<div class="table-card__header">
<div class="table-card__actions">
<button class="btn btn-primary" onclick="openModal('modal-threshold-edit', '新增阈值配置')">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
新增
</button>
<button class="btn btn-purple">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1L9 5h4l-3.3 2.4 1.3 4L7 9 3 11.4l1.3-4L1 5h4z" fill="#722ED1"/></svg>
通知手表
</button>
</div>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>数据类型</th>
<th>单位</th>
<th>阈值下限</th>
<th>阈值上限</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>体温</td>
<td></td>
<td>36.0</td>
<td>37.5</td>
<td>2025-01-10 09:00:00</td>
<td>2025-03-15 14:22:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-threshold-edit','编辑阈值配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>血氧</td>
<td>%</td>
<td>90</td>
<td>100</td>
<td>2025-01-10 09:05:00</td>
<td>2025-03-15 14:23:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-threshold-edit','编辑阈值配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>心率</td>
<td>次/分</td>
<td>60</td>
<td>100</td>
<td>2025-01-10 09:10:00</td>
<td>2025-03-15 14:24:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-threshold-edit','编辑阈值配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>压力</td>
<td></td>
<td>0</td>
<td>80</td>
<td>2025-01-10 09:15:00</td>
<td>2025-03-15 14:25:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-threshold-edit','编辑阈值配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>步数</td>
<td></td>
<td>0</td>
<td>20000</td>
<td>2025-01-10 09:20:00</td>
<td>2025-03-15 14:26:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-threshold-edit','编辑阈值配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 5 条</span>
<button class="page-btn"></button>
<button class="page-btn active">1</button>
<button class="page-btn"></button>
</div>
</div>
</div>
<!-- ===== TAB 2: 上传默认配置 ===== -->
<div class="tab-panel" id="tab-panel-1">
<!-- Filter bar -->
<div class="filter-bar">
<div class="filter-item">
<label>数据类型</label>
<select class="filter-select">
<option>全部</option>
<option>体温</option>
<option>血氧</option>
<option>心率</option>
<option>压力</option>
<option>步数</option>
<option>睡眠</option>
</select>
</div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
</div>
<!-- Table card -->
<div class="table-card">
<div class="table-card__header">
<div class="table-card__actions">
<button class="btn btn-primary" onclick="openModal('modal-upload-edit','新增上传配置')">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
新增
</button>
<button class="btn btn-purple">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1L9 5h4l-3.3 2.4 1.3 4L7 9 3 11.4l1.3-4L1 5h4z" fill="#722ED1"/></svg>
通知手表
</button>
</div>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>数据类型</th>
<th>上传频率(分钟)</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>体温</td>
<td>5</td>
<td>2025-01-10 09:00:00</td>
<td>2025-03-15 14:22:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-upload-edit','编辑上传配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>血氧</td>
<td>5</td>
<td>2025-01-10 09:05:00</td>
<td>2025-03-15 14:23:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-upload-edit','编辑上传配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>心率</td>
<td>1</td>
<td>2025-01-10 09:10:00</td>
<td>2025-03-15 14:24:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-upload-edit','编辑上传配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>压力</td>
<td>10</td>
<td>2025-01-10 09:15:00</td>
<td>2025-03-15 14:25:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-upload-edit','编辑上传配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>步数</td>
<td>30</td>
<td>2025-01-10 09:20:00</td>
<td>2025-03-15 14:26:00</td>
<td>
<button class="btn-link" onclick="openModal('modal-upload-edit','编辑上传配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="pagination">
<span>共 5 条</span>
<button class="page-btn"></button>
<button class="page-btn active">1</button>
<button class="page-btn"></button>
</div>
</div>
</div>
<!-- ===== TAB 3: 开关默认配置 ===== -->
<div class="tab-panel" id="tab-panel-2">
<!-- Filter bar -->
<div class="filter-bar">
<div class="filter-item">
<label>数据类型</label>
<select class="filter-select">
<option>全部</option>
<option>体温</option>
<option>血氧</option>
<option>心率</option>
<option>压力</option>
<option>步数</option>
<option>睡眠</option>
</select>
</div>
<button class="btn btn-primary">查询</button>
<button class="btn btn-default">重置</button>
</div>
<!-- Table card -->
<div class="table-card">
<div class="table-card__header">
<div class="table-card__actions">
<button class="btn btn-primary" onclick="openModal('modal-switch-edit','新增开关配置')">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
新增
</button>
<button class="btn btn-purple">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1L9 5h4l-3.3 2.4 1.3 4L7 9 3 11.4l1.3-4L1 5h4z" fill="#722ED1"/></svg>
通知手表
</button>
</div>
</div>
<div class="table-card__content">
<table>
<thead>
<tr>
<th>数据类型</th>
<th>上传开关</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>体温</td>
<td><span class="tag tag-green">开启</span></td>
<td>
<button class="btn-link" onclick="openModal('modal-switch-edit','编辑开关配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>血氧</td>
<td><span class="tag tag-green">开启</span></td>
<td>
<button class="btn-link" onclick="openModal('modal-switch-edit','编辑开关配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>心率</td>
<td><span class="tag tag-green">开启</span></td>
<td>
<button class="btn-link" onclick="openModal('modal-switch-edit','编辑开关配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>压力</td>
<td><span class="tag tag-gray">关闭</span></td>
<td>
<button class="btn-link" onclick="openModal('modal-switch-edit','编辑开关配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
<tr>
<td>步数</td>
<td><span class="tag tag-green">开启</span></td>
<td>
<button class="btn-link" onclick="openModal('modal-switch-edit','编辑开关配置')">编辑</button>
<button class="btn-link-danger" onclick="openModal('modal-delete-confirm')">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</main>
<!-- ===== MODAL: 阈值配置编辑/新增 ===== -->
<div class="modal-mask" id="modal-threshold-edit">
<div class="modal">
<div class="modal-header">
<span class="modal-title" id="modal-threshold-edit-title">编辑阈值配置</span>
<button class="modal-close" onclick="closeModal('modal-threshold-edit')"></button>
</div>
<div class="modal-body">
<div class="form-item">
<label class="form-label">数据类型<span class="required">*</span></label>
<select class="form-select" id="threshold-type" onchange="onThresholdTypeChange()">
<option value="体温">体温</option>
<option value="血氧">血氧</option>
<option value="心率">心率</option>
<option value="压力">压力</option>
<option value="步数">步数</option>
<option value="睡眠">睡眠</option>
</select>
</div>
<div class="form-item">
<label class="form-label">单位</label>
<input class="form-input" id="threshold-unit" type="text" value="℃" readonly style="background:#FAFAFA;color:var(--text-secondary);cursor:not-allowed;">
</div>
<div class="form-item">
<label class="form-label">阈值下限<span class="required">*</span></label>
<input class="form-input" id="threshold-min" type="number" placeholder="请输入阈值下限" value="36.0">
</div>
<div class="form-item">
<label class="form-label">阈值上限<span class="required">*</span></label>
<input class="form-input" id="threshold-max" type="number" placeholder="请输入阈值上限" value="37.5">
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('modal-threshold-edit')">取消</button>
<button class="btn btn-primary" onclick="closeModal('modal-threshold-edit')">确定</button>
</div>
</div>
</div>
<!-- ===== MODAL: 上传频率编辑/新增 ===== -->
<div class="modal-mask" id="modal-upload-edit">
<div class="modal">
<div class="modal-header">
<span class="modal-title" id="modal-upload-edit-title">编辑上传配置</span>
<button class="modal-close" onclick="closeModal('modal-upload-edit')"></button>
</div>
<div class="modal-body">
<div class="form-item">
<label class="form-label">数据类型<span class="required">*</span></label>
<select class="form-select">
<option>体温</option>
<option>血氧</option>
<option>心率</option>
<option>压力</option>
<option>步数</option>
<option>睡眠</option>
</select>
</div>
<div class="form-item">
<label class="form-label">上传频率<span class="required">*</span></label>
<div class="input-suffix-wrap">
<input class="form-input" type="number" placeholder="请输入上传频率" value="5" min="1">
<span class="input-suffix">分钟</span>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('modal-upload-edit')">取消</button>
<button class="btn btn-primary" onclick="closeModal('modal-upload-edit')">确定</button>
</div>
</div>
</div>
<!-- ===== MODAL: 开关编辑/新增 ===== -->
<div class="modal-mask" id="modal-switch-edit">
<div class="modal">
<div class="modal-header">
<span class="modal-title" id="modal-switch-edit-title">编辑开关配置</span>
<button class="modal-close" onclick="closeModal('modal-switch-edit')"></button>
</div>
<div class="modal-body">
<div class="form-item">
<label class="form-label">数据类型<span class="required">*</span></label>
<select class="form-select">
<option>体温</option>
<option>血氧</option>
<option>心率</option>
<option>压力</option>
<option>步数</option>
<option>睡眠</option>
</select>
</div>
<div class="form-item">
<label class="form-label">上传开关<span class="required">*</span></label>
<select class="form-select">
<option value="1">开启</option>
<option value="0">关闭</option>
</select>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('modal-switch-edit')">取消</button>
<button class="btn btn-primary" onclick="closeModal('modal-switch-edit')">确定</button>
</div>
</div>
</div>
<!-- ===== MODAL: 删除确认 ===== -->
<div class="modal-mask" id="modal-delete-confirm">
<div class="modal confirm-modal">
<div class="modal-body" style="padding:32px 24px 24px;">
<div class="confirm-icon"></div>
<div class="confirm-title">确认删除</div>
<div class="confirm-desc">删除后无法恢复,确认要删除该条配置吗?</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" onclick="closeModal('modal-delete-confirm')">取消</button>
<button class="btn" style="background:var(--danger);color:#fff;border:1px solid var(--danger);" onclick="closeModal('modal-delete-confirm')">确认删除</button>
</div>
</div>
</div>
<script>
/* ── Tab switching ── */
var tabPanels = document.querySelectorAll('.tab-panel');
var tabBtns = document.querySelectorAll('.tab-btn');
function switchTab(idx) {
tabBtns.forEach(function(b, i) { b.classList.toggle('active', i === idx); });
tabPanels.forEach(function(p, i) { p.classList.toggle('active', i === idx); });
}
/* ── Sidebar subgroup toggle ── */
function toggleSubgroup(h) { h.parentElement.classList.toggle('open'); }
/* ── Auto-expand active sidebar items ── */
(function() {
var a = document.querySelector('.sidebar-item.active');
if (!a) return;
var el = a.parentElement;
while (el) {
if (el.classList && el.classList.contains('sidebar-subgroup')) el.classList.add('open');
el = el.parentElement;
}
})();
/* ── Modal helpers ── */
function openModal(id, title) {
var mask = document.getElementById(id);
if (!mask) return;
if (title) {
var titleEl = document.getElementById(id + '-title');
if (titleEl) titleEl.textContent = title;
}
mask.classList.add('show');
}
function closeModal(id) {
var mask = document.getElementById(id);
if (mask) mask.classList.remove('show');
}
/* Close on backdrop click */
document.querySelectorAll('.modal-mask').forEach(function(mask) {
mask.addEventListener('click', function(e) {
if (e.target === mask) mask.classList.remove('show');
});
});
/* ── 阈值配置:数据类型 → 单位/默认上下限 联动 ── */
var THRESHOLD_TYPE_MAP = {
'体温': { unit: '℃', min: '36.0', max: '37.5' },
'血氧': { unit: '%', min: '90', max: '100' },
'心率': { unit: '次/分', min: '60', max: '100' },
'压力': { unit: '分', min: '0', max: '80' },
'步数': { unit: '步', min: '0', max: '20000' },
'睡眠': { unit: '小时', min: '4', max: '10' }
};
function onThresholdTypeChange() {
var sel = document.getElementById('threshold-type');
var cfg = THRESHOLD_TYPE_MAP[sel.value];
if (!cfg) return;
document.getElementById('threshold-unit').value = cfg.unit;
document.getElementById('threshold-min').value = cfg.min;
document.getElementById('threshold-max').value = cfg.max;
}
</script>
</body>
</html>
@@ -65,6 +65,17 @@
.date-range input{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;width:140px;}
/* 说明框 */
.info-tip{display:flex;align-items:flex-start;gap:8px;padding:10px 16px;background:#F0F7FF;border-radius:var(--radius-md);margin-bottom:16px;border:1px solid #BAE0FF;font-size:var(--font-xs);color:#0958D9;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -101,6 +112,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item active">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
@@ -387,5 +435,9 @@ document.querySelectorAll('.link').forEach(function(link) {
link.addEventListener('click', function() { openDetailModal(this.closest('tr')); });
});
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
+245 -126
View File
@@ -150,6 +150,17 @@
.monitor-setting-field label{font-size:var(--font-xs);color:var(--text-secondary);}
.monitor-setting-field .form-control{height:34px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;font-size:var(--font-sm);outline:none;}
.monitor-setting-field .form-control:focus{border-color:var(--primary);}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -188,6 +199,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
@@ -278,24 +326,17 @@
<table>
<thead>
<tr>
<th rowspan="2"><input type="checkbox"></th>
<th rowspan="2">设备编码</th>
<th rowspan="2">所属单位</th>
<th rowspan="2">入库日期</th>
<th rowspan="2">厂商</th>
<th rowspan="2">设备型号</th>
<th rowspan="2">绑定状态</th>
<th rowspan="2">绑定员工</th>
<th rowspan="2">员工编号</th>
<th rowspan="2">绑定日期</th>
<th colspan="4" style="text-align:center;">设备监测开关</th>
<th rowspan="2">操作</th>
</tr>
<tr>
<th>心率</th>
<th>血氧</th>
<th>压力</th>
<th>体温</th>
<th><input type="checkbox"></th>
<th>设备编码</th>
<th>所属单位</th>
<th>入库日期</th>
<th>厂商</th>
<th>设备型号</th>
<th>绑定状态</th>
<th>绑定员工</th>
<th>员工编号</th>
<th>绑定日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@@ -310,16 +351,12 @@
<td>张伟</td>
<td><span style="font-family:monospace;color:var(--text-secondary)">CQ001234</span></td>
<td>2024-03-01</td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td>
<span class="link" onclick="openUnbindConfirm('WD-2024-001','采油一厂','张伟')">解除绑定</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="link" onclick="openBindRecord('WD-2024-001')">绑定记录</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-001')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-001')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
</td>
</tr>
<tr>
@@ -333,16 +370,12 @@
<td>李建国</td>
<td><span style="font-family:monospace;color:var(--text-secondary)">CQ001235</span></td>
<td>2024-03-05</td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-green">开启</span></td>
<td>
<span class="link" onclick="openUnbindConfirm('WD-2024-002','采油一厂','李建国')">解除绑定</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="link" onclick="openBindRecord('WD-2024-002')">绑定记录</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-002')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-002')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
</td>
</tr>
<tr>
@@ -356,16 +389,12 @@
<td></td>
<td></td>
<td></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td>
<span class="link" onclick="openBindModal('WD-2024-015','')">绑定员工</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="link" onclick="openBindRecord('WD-2024-015')">绑定记录</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-015')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-015')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
</td>
</tr>
<tr>
@@ -379,16 +408,12 @@
<td></td>
<td></td>
<td></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td>
<span class="link" onclick="openBindModal('WD-2024-016','')">绑定员工</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="link" onclick="openBindRecord('WD-2024-016')">绑定记录</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-016')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-016')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
</td>
</tr>
<tr>
@@ -402,16 +427,12 @@
<td>王磊</td>
<td><span style="font-family:monospace;color:var(--text-secondary)">CQ002101</span></td>
<td>2024-04-01</td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-green">开启</span></td>
<td><span class="tag tag-gray">关闭</span></td>
<td>
<span class="link" onclick="openUnbindConfirm('WD-2024-031','采气一厂','王磊')">解除绑定</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="link" onclick="openBindRecord('WD-2024-031')">绑定记录</span>
<span style="color:var(--border);margin:0 4px;">|</span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-031')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch('WD-2024-031')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>
</td>
</tr>
</tbody>
@@ -651,22 +672,31 @@
<div class="modal-mask" id="monitorSwitchModal">
<div class="modal" style="width:680px;">
<div class="modal__header">
<h3>监测开关设置</h3>
<h3>备配</h3>
<button class="modal__close" onclick="closeModal('monitorSwitchModal')">×</button>
</div>
<div class="modal__body">
<div style="background:#F0F7FF;border:1px solid #BAE0FF;border-radius:var(--radius-md);padding:12px 16px;margin-bottom:20px;">
<span style="font-size:var(--font-sm);color:#0958D9;">设备编码:<strong id="msDeviceCode">WD-2024-001</strong></span>
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:20px;">
<div style="background:#F0F7FF;border:1px solid #BAE0FF;border-radius:var(--radius-md);padding:10px 16px;flex-shrink:0;">
<span style="font-size:var(--font-sm);color:#0958D9;">设备编码:<strong id="msDeviceCode">WD-2024-001</strong></span>
</div>
<button class="btn btn-default btn-sm" onclick="showAddTypeForm()">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M6 1v10M1 6h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
新增类型配置
</button>
</div>
<div class="monitor-setting-list">
<div class="monitor-setting-list" id="monitorSettingList">
<!-- 心率 -->
<div class="monitor-setting-item" data-key="heart">
<div class="monitor-setting-item__header">
<span class="monitor-setting-item__label">❤️ 心率监测</span>
<label class="switch">
<input type="checkbox" id="msSwitch_heart" onchange="onMonitorSwitchChange('heart')">
<span class="switch__slider"></span>
</label>
<span class="monitor-setting-item__label">心率监测</span>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>
<label class="switch">
<input type="checkbox" id="msSwitch_heart" checked onchange="onMonitorSwitchChange('heart')">
<span class="switch__slider"></span>
</label>
</div>
</div>
<div class="monitor-setting-item__body" id="msBody_heart">
<div class="monitor-setting-row">
@@ -679,14 +709,8 @@
<input class="form-control" type="number" id="msMax_heart" value="100" placeholder="上限">
</div>
<div class="monitor-setting-field">
<label>上传频次</label>
<select class="form-control" id="msFreq_heart">
<option value="1">每1分钟</option>
<option value="5" selected>每5分钟</option>
<option value="10">每10分钟</option>
<option value="30">每30分钟</option>
<option value="60">每60分钟</option>
</select>
<label>上传频次(分钟)</label>
<input class="form-control" type="number" id="msFreq_heart" value="60" min="1" placeholder="请输入分钟数">
</div>
</div>
</div>
@@ -694,11 +718,14 @@
<!-- 血氧 -->
<div class="monitor-setting-item" data-key="oxygen">
<div class="monitor-setting-item__header">
<span class="monitor-setting-item__label">🫁 血氧监测</span>
<label class="switch">
<input type="checkbox" id="msSwitch_oxygen" onchange="onMonitorSwitchChange('oxygen')">
<span class="switch__slider"></span>
</label>
<span class="monitor-setting-item__label">血氧监测</span>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>
<label class="switch">
<input type="checkbox" id="msSwitch_oxygen" checked onchange="onMonitorSwitchChange('oxygen')">
<span class="switch__slider"></span>
</label>
</div>
</div>
<div class="monitor-setting-item__body" id="msBody_oxygen">
<div class="monitor-setting-row">
@@ -711,14 +738,8 @@
<input class="form-control" type="number" id="msMax_oxygen" value="100" placeholder="上限">
</div>
<div class="monitor-setting-field">
<label>上传频次</label>
<select class="form-control" id="msFreq_oxygen">
<option value="1">每1分钟</option>
<option value="5" selected>每5分钟</option>
<option value="10">每10分钟</option>
<option value="30">每30分钟</option>
<option value="60">每60分钟</option>
</select>
<label>上传频次(分钟)</label>
<input class="form-control" type="number" id="msFreq_oxygen" value="60" min="1" placeholder="请输入分钟数">
</div>
</div>
</div>
@@ -726,11 +747,14 @@
<!-- 压力 -->
<div class="monitor-setting-item" data-key="stress">
<div class="monitor-setting-item__header">
<span class="monitor-setting-item__label">🧠 压力监测</span>
<label class="switch">
<input type="checkbox" id="msSwitch_stress" onchange="onMonitorSwitchChange('stress')">
<span class="switch__slider"></span>
</label>
<span class="monitor-setting-item__label">压力监测</span>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>
<label class="switch">
<input type="checkbox" id="msSwitch_stress" checked onchange="onMonitorSwitchChange('stress')">
<span class="switch__slider"></span>
</label>
</div>
</div>
<div class="monitor-setting-item__body" id="msBody_stress">
<div class="monitor-setting-row">
@@ -743,14 +767,8 @@
<input class="form-control" type="number" id="msMax_stress" value="80" placeholder="上限">
</div>
<div class="monitor-setting-field">
<label>上传频次</label>
<select class="form-control" id="msFreq_stress">
<option value="1">每1分钟</option>
<option value="5" selected>每5分钟</option>
<option value="10">每10分钟</option>
<option value="30">每30分钟</option>
<option value="60">每60分钟</option>
</select>
<label>上传频次(分钟)</label>
<input class="form-control" type="number" id="msFreq_stress" value="60" min="1" placeholder="请输入分钟数">
</div>
</div>
</div>
@@ -758,11 +776,14 @@
<!-- 体温 -->
<div class="monitor-setting-item" data-key="temp">
<div class="monitor-setting-item__header">
<span class="monitor-setting-item__label">🌡️ 体温监测</span>
<label class="switch">
<input type="checkbox" id="msSwitch_temp" onchange="onMonitorSwitchChange('temp')">
<span class="switch__slider"></span>
</label>
<span class="monitor-setting-item__label">体温监测</span>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>
<label class="switch">
<input type="checkbox" id="msSwitch_temp" checked onchange="onMonitorSwitchChange('temp')">
<span class="switch__slider"></span>
</label>
</div>
</div>
<div class="monitor-setting-item__body" id="msBody_temp">
<div class="monitor-setting-row">
@@ -775,18 +796,55 @@
<input class="form-control" type="number" id="msMax_temp" value="37.3" step="0.1" placeholder="上限">
</div>
<div class="monitor-setting-field">
<label>上传频次</label>
<select class="form-control" id="msFreq_temp">
<option value="1">每1分钟</option>
<option value="5" selected>每5分钟</option>
<option value="10">每10分钟</option>
<option value="30">每30分钟</option>
<option value="60">每60分钟</option>
</select>
<label>上传频次(分钟)</label>
<input class="form-control" type="number" id="msFreq_temp" value="60" min="1" placeholder="请输入分钟数">
</div>
</div>
</div>
</div>
<!-- 动态新增的类型配置卡片 -->
<div id="addTypeFormContainer" style="display:none;">
<div class="monitor-setting-item" style="border-color:var(--primary);">
<div class="monitor-setting-item__header" style="background:#F0F7FF;">
<select class="form-control filter-select" id="newTypeSelect" style="height:32px;font-weight:600;font-size:var(--font-sm);min-width:140px;" onchange="onNewTypeChange()">
<option value="">请选择监测类型</option>
<option value="heart">心率监测</option>
<option value="oxygen">血氧监测</option>
<option value="stress">压力监测</option>
<option value="temp">体温监测</option>
<option value="steps">步数监测</option>
<option value="sleep">睡眠监测</option>
</select>
<div style="display:flex;align-items:center;gap:8px;">
<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>
<label class="switch">
<input type="checkbox" id="newTypeSwitch" onchange="onNewTypeSwitchChange()">
<span class="switch__slider"></span>
</label>
</div>
</div>
<div class="monitor-setting-item__body" id="newTypeBody">
<div class="monitor-setting-row">
<div class="monitor-setting-field">
<label id="newTypeMinLabel">阈值下限</label>
<input class="form-control" type="number" id="newTypeMin" placeholder="下限">
</div>
<div class="monitor-setting-field">
<label id="newTypeMaxLabel">阈值上限</label>
<input class="form-control" type="number" id="newTypeMax" placeholder="上限">
</div>
<div class="monitor-setting-field">
<label>上传频次(分钟)</label>
<input class="form-control" type="number" id="newTypeFreq" value="60" min="1" placeholder="请输入分钟数">
</div>
</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border);">
<button class="btn btn-default btn-sm" onclick="cancelAddType()">取消</button>
<button class="btn btn-primary btn-sm" onclick="saveAddType()">保存</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal__footer">
@@ -902,7 +960,7 @@ function doBind() {
'<span style="color:var(--border);margin:0 4px;">|</span>' +
'<span class="link" onclick="openBindRecord(\'' + bindTargetCode + '\')">绑定记录</span>' +
'<span style="color:var(--border);margin:0 4px;">|</span>' +
'<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch(\'' + bindTargetCode + '\')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>';
'<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch(\'' + bindTargetCode + '\')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>';
}
});
selectedEmp = null;
@@ -936,7 +994,7 @@ function doUnbind() {
'<span style="color:var(--border);margin:0 4px;">|</span>' +
'<span class="link" onclick="openBindRecord(\'' + unbindTarget.code + '\')">绑定记录</span>' +
'<span style="color:var(--border);margin:0 4px;">|</span>' +
'<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch(\'' + unbindTarget.code + '\')">监测开关</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>';
'<span class="more-wrap"><span class="more-btn" onclick="toggleMore(this)">更多 ▾</span><div class="more-dropdown"><div class="more-dropdown-item" onclick="openMonitorSwitch(\'' + unbindTarget.code + '\')">设备配置</div><div class="more-dropdown-item danger" onclick="void(0)">删除</div></div></span>';
}
});
unbindTarget = null;
@@ -968,25 +1026,11 @@ document.querySelectorAll('.modal-mask').forEach(function(m){
});
/* 监测开关弹窗逻辑 */
var msTargetCode = '';
var msKeys = ['heart','oxygen','stress','temp'];
// 表格中第11~14列对应心率、血氧、压力、体温(td索引10~13)
var msColMap = { heart:10, oxygen:11, stress:12, temp:13 };
function openMonitorSwitch(code) {
msTargetCode = code;
document.getElementById('msDeviceCode').textContent = code;
// 关闭更多下拉
if (activeDropdown) { document.body.removeChild(activeDropdown); activeDropdown = null; }
document.querySelectorAll('.more-dropdown.show').forEach(function(d){ d.classList.remove('show'); });
// 从表格读取当前开关状态
var row = findRowByCode(code);
if (row) {
msKeys.forEach(function(key) {
var td = row.querySelectorAll('td')[msColMap[key]];
var isOn = td && td.textContent.trim() === '开启';
document.getElementById('msSwitch_' + key).checked = isOn;
onMonitorSwitchChange(key);
});
}
document.getElementById('monitorSwitchModal').classList.add('show');
}
function onMonitorSwitchChange(key) {
@@ -1007,19 +1051,94 @@ function findRowByCode(code) {
return null;
}
function saveMonitorSwitch() {
var row = findRowByCode(msTargetCode);
if (!row) { closeModal('monitorSwitchModal'); return; }
msKeys.forEach(function(key) {
var isOn = document.getElementById('msSwitch_' + key).checked;
var td = row.querySelectorAll('td')[msColMap[key]];
if (isOn) {
td.innerHTML = '<span class="tag tag-green">开启</span>';
} else {
td.innerHTML = '<span class="tag tag-gray">关闭</span>';
}
});
closeModal('monitorSwitchModal');
}
/* 新增类型配置 */
var typeUnitMap = {
heart: { min: '阈值下限(次/分)', max: '阈值上限(次/分)', minVal: 60, maxVal: 100 },
oxygen: { min: '阈值下限(%', max: '阈值上限(%', minVal: 90, maxVal: 100 },
stress: { min: '阈值下限(分)', max: '阈值上限(分)', minVal: 0, maxVal: 80 },
temp: { min: '阈值下限(℃)', max: '阈值上限(℃)', minVal: 36.0,maxVal: 37.3 },
steps: { min: '阈值下限(步)', max: '阈值上限(步)', minVal: 0, maxVal: 20000},
sleep: { min: '阈值下限(小时)', max: '阈值上限(小时)', minVal: 4, maxVal: 10 }
};
function showAddTypeForm() {
var c = document.getElementById('addTypeFormContainer');
c.style.display = 'block';
document.getElementById('newTypeSelect').value = '';
document.getElementById('newTypeSwitch').checked = false;
document.getElementById('newTypeBody').classList.remove('disabled');
document.getElementById('newTypeMin').value = '';
document.getElementById('newTypeMax').value = '';
document.getElementById('newTypeFreq').value = 60;
document.getElementById('newTypeMinLabel').textContent = '阈值下限';
document.getElementById('newTypeMaxLabel').textContent = '阈值上限';
c.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
function onNewTypeChange() {
var val = document.getElementById('newTypeSelect').value;
var cfg = typeUnitMap[val];
if (cfg) {
document.getElementById('newTypeMinLabel').textContent = cfg.min;
document.getElementById('newTypeMaxLabel').textContent = cfg.max;
document.getElementById('newTypeMin').value = cfg.minVal;
document.getElementById('newTypeMax').value = cfg.maxVal;
} else {
document.getElementById('newTypeMinLabel').textContent = '阈值下限';
document.getElementById('newTypeMaxLabel').textContent = '阈值上限';
document.getElementById('newTypeMin').value = '';
document.getElementById('newTypeMax').value = '';
}
}
function onNewTypeSwitchChange() {
var checked = document.getElementById('newTypeSwitch').checked;
var body = document.getElementById('newTypeBody');
checked ? body.classList.remove('disabled') : body.classList.add('disabled');
}
function cancelAddType() {
document.getElementById('addTypeFormContainer').style.display = 'none';
}
function saveAddType() {
var typeVal = document.getElementById('newTypeSelect').value;
var typeText = document.getElementById('newTypeSelect').options[document.getElementById('newTypeSelect').selectedIndex].text;
if (!typeVal) { alert('请选择监测类型'); return; }
var isOn = document.getElementById('newTypeSwitch').checked;
var minVal = document.getElementById('newTypeMin').value;
var maxVal = document.getElementById('newTypeMax').value;
var freqVal = document.getElementById('newTypeFreq').value || 60;
var minLabel = document.getElementById('newTypeMinLabel').textContent;
var maxLabel = document.getElementById('newTypeMaxLabel').textContent;
var switchId = 'msSwitch_custom_' + Date.now();
var bodyId = 'msBody_custom_' + Date.now();
var card = document.createElement('div');
card.className = 'monitor-setting-item';
card.innerHTML =
'<div class="monitor-setting-item__header">' +
'<span class="monitor-setting-item__label">' + typeText + '</span>' +
'<div style="display:flex;align-items:center;gap:8px;">' +
'<span style="font-size:var(--font-xs);color:var(--text-secondary);">监测开关</span>' +
'<label class="switch">' +
'<input type="checkbox" id="' + switchId + '"' + (isOn ? ' checked' : '') + ' onchange="(function(id){var b=document.getElementById(\'b\'+id);b&&(this.checked?b.classList.remove(\'disabled\'):b.classList.add(\'disabled\'))}).call(this,\'' + bodyId + '\')">' +
'<span class="switch__slider"></span>' +
'</label>' +
'</div>' +
'</div>' +
'<div class="monitor-setting-item__body' + (isOn ? '' : ' disabled') + '" id="b' + bodyId + '">' +
'<div class="monitor-setting-row">' +
'<div class="monitor-setting-field"><label>' + minLabel + '</label><input class="form-control" type="number" value="' + minVal + '"></div>' +
'<div class="monitor-setting-field"><label>' + maxLabel + '</label><input class="form-control" type="number" value="' + maxVal + '"></div>' +
'<div class="monitor-setting-field"><label>上传频次(分钟)</label><input class="form-control" type="number" value="' + freqVal + '" min="1"></div>' +
'</div>' +
'</div>';
var container = document.getElementById('addTypeFormContainer');
document.getElementById('monitorSettingList').insertBefore(card, container);
container.style.display = 'none';
}
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>
@@ -113,6 +113,17 @@
.metric-summary__unit{font-size:var(--font-xs);color:var(--text-secondary);}
.metric-summary__label{font-size:var(--font-xs);color:var(--text-secondary);margin-top:2px;}
.tab-panel{min-height:200px;}
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
.sidebar-subgroup__body{display:none;}
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
.sidebar-subgroup__body>.sidebar-item{padding-left:36px;font-size:12px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__header{padding-left:36px;}
.sidebar-subgroup__body>.sidebar-subgroup>.sidebar-subgroup__body>.sidebar-item{padding-left:52px;font-size:12px;}
</style>
</head>
<body>
@@ -149,6 +160,43 @@
<a href="dept-stat.html" class="sidebar-item">单位数据统计</a>
<a href="personal-stat.html" class="sidebar-item">个人数据统计</a>
<a href="dept-report.html" class="sidebar-item">单位数据分析报告</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 运维中心</div>
<div class="sidebar-subgroup__body">
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 终端设置</div>
<div class="sidebar-subgroup__body">
<a href="ops/terminal-default-config.html" class="sidebar-item">默认配置</a>
<a href="ops/terminal-config-info.html" class="sidebar-item">配置信息</a>
</div>
</div>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日常监测</div>
<div class="sidebar-subgroup__body">
<a href="ops/monitor-ecg.html" class="sidebar-item">心电图信息</a>
<a href="ops/monitor-spo2.html" class="sidebar-item">血氧信息</a>
<a href="ops/monitor-temp.html" class="sidebar-item">体温信息</a>
<a href="ops/monitor-stress.html" class="sidebar-item">压力信息</a>
<a href="ops/monitor-exercise.html" class="sidebar-item">锻炼信息</a>
<a href="ops/monitor-heartrate.html" class="sidebar-item">心率信息</a>
<a href="ops/monitor-sleep.html" class="sidebar-item">睡眠信息</a>
<a href="ops/sdc-overview.html" class="sidebar-item">SDC信息</a>
<a href="ops/monitor-activity.html" class="sidebar-item">活动信息</a>
</div>
</div>
<a href="ops/alarm-data.html" class="sidebar-item">事件监听</a>
<div class="sidebar-subgroup">
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)"><svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg> 日志管理</div>
<div class="sidebar-subgroup__body">
<a href="ops/log-network.html" class="sidebar-item">手表网络切换日志</a>
<a href="ops/log-version.html" class="sidebar-item">版本更新历史</a>
<a href="ops/log-error.html" class="sidebar-item">手表错误日志</a>
<a href="ops/log-task.html" class="sidebar-item">任务日志</a>
<a href="ops/log-mqtt.html" class="sidebar-item">mqtt消息日志</a>
</div>
</div>
</div>
</div>
</aside>
<main class="main">
<div class="filter-bar">
@@ -754,5 +802,9 @@ function renderEcgChart() {
}
document.getElementById('ecgDetailModal').addEventListener('click', function(e){ if(e.target===this) this.classList.remove('show'); });
</script>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var el=a.parentElement;while(el){if(el.classList&&el.classList.contains('sidebar-subgroup'))el.classList.add('open');el=el.parentElement;}})();
</script>
</body>
</html>