# HANDOFF — 服务监测模块：报告免登访问 + 监测统计 + 多项修复

> 最后更新：2026-07-22 02:00 ｜ 分支：troubleshoot-ai-assistant ｜ 负责人：czj

---

## 1. 我们在做什么

服务监测模块（service_monitor）是运行维护平台的子模块，提供目标服务器巡检、报告管理、定时任务、通知推送等功能。

本轮会话完成了三个主要任务：

1. **报告免登访问**：钉钉/企业微信通知中的报告链接，原来需要登录才能查看。用户希望点击链接直接看到报告，如果点击其他模块再跳转登录。核心价值是提升移动端体验，减少操作割裂感。

2. **监测统计模块**：新增左侧菜单"监测统计"，提供可视化统计分析页面。支持按目标服务器、日期范围筛选，展示模块健康概览（堆叠条形图）、检测项趋势分析（折线图+饼图）、高频异常检测项排行。

3. **多项问题修复**：检测项趋势图表部分检测项无法正常显示（状态类/文本类无数值数据）、JavaScript 代码残留导致 `fetchAllData` 未定义。

---

## 2. 已经完成了什么

### 2.1 报告免登访问与操作鉴权 ✅

**需求文档**：`Docs/需求文档/服务监测/PRD_需求文档_报告免登访问与操作鉴权.md`

**核心实现**：
- `report_service.py`：报告生成时自动生成 `access_token`（格式 `rpt_<32位随机hex>`）和 `access_token_expires_at`（7天有效期）
- `runner_service.py`：通知链接拼接 `?token=rpt_xxx` 参数
- `routes.py`：`page_report()` 支持 token 验证，验证通过后渲染报告页并标记 `token_auth=True`（访客模式）；`api_export_report()` 支持 token 导出
- `auth.py`：GET/POST `/login` 支持 `next` 参数，登录成功后跳转回原始页面
- `decorators.py`：`page_login_required` 重定向时携带 `next` 参数
- `login.html`：表单提交携带 `next` 参数，登录成功后跳转
- `report.html`：访客模式显示提示条、隐藏管理操作、导出链接携带 token
- `base.html`：访客模式下导航菜单点击跳转登录页，顶部显示"访客 + 登录按钮"

**验证结果**：
- 未登录点击通知链接 → 直接查看报告 ✅
- 访客模式点击其他模块 → 弹窗提示并跳转登录 ✅
- 登录后回跳到原始页面 ✅
- 218 个单元测试全绿 ✅

### 2.2 监测统计模块 ✅

**需求文档**：`Docs/需求文档/服务监测/PRD_需求文档_监测统计模块.md`

**核心实现**：
- `statistics_service.py`（新增）：统计聚合服务，包含 5 个公开函数：
  - `get_overview()`：概览摘要（总报告数、异常率、最常异常项等）
  - `get_module_stats()`：模块健康统计
  - `get_item_trend()`：检测项趋势数据（时间序列 + 状态分布）
  - `get_abnormal_items()`：高频异常检测项 TOP 10
  - `get_item_keys_for_target()`：检测项列表（按模块分组，含 `has_numeric` 标记）
- `routes.py`：新增页面路由 `/service-monitor/statistics` + 5 个 API 端点
- `base.html`：侧边栏添加"📈 监测统计"菜单项
- `statistics.html`（新增）：完整统计页面，使用 ECharts 渲染图表
  - 筛选栏：目标选择器 + 日期范围（自定义）
  - 概览卡片：4 项摘要指标
  - 模块健康概览：堆叠条形图
  - 检测项趋势分析：模块/检测项两级联动选择器 + 折线图 + 饼图
  - 高频异常检测项：水平堆叠条形图

**验证结果**：
- 统计页面正常加载 ✅
- 各 API 返回正确数据结构 ✅
- 图表正常渲染 ✅
- 218 个单元测试全绿 ✅

### 2.3 检测项趋势图表显示问题修复 ✅

**问题文档**：`Docs/需求文档/服务监测/PRD_问题处理_检测项趋势图表显示问题.md`

**问题根因**：
- 部分检测项的值是状态文本（"正常"/"异常"）、yes/no、路径等，`_extract_numeric()` 无法提取数值
- 前端收到 `value_num=null` 后折线图无数据点，但未显示任何提示

**修复内容**：
- `statistics_service.py`：`get_item_keys_for_target()` 增加 `has_numeric` 字段，标记检测项是否有数值数据
- `statistics.html`：`fetchItemTrend()` 增加三种情况处理：
  - 无数据点：显示"暂无数据"
  - 有数据点但无数值：显示友好提示"该检测项为状态/文本类型，无法绘制数值趋势图，请查看右侧状态分布"，饼图正常渲染
  - 有数值数据：正常渲染折线图 + 饼图
- 检测项选择器标注：无数值能力的检测项标注 "(状态)" 后缀

**验证结果**：
- 选择 `CPU_USAGE` 等数值项，折线图正常 ✅
- 选择 `CPU_STATUS` 等状态项，显示友好提示 + 饼图正常 ✅
- 选择器中状态项标注 "(状态)" ✅

### 2.4 JavaScript 代码残留问题修复 ✅

**问题文档**：`Docs/需求文档/服务监测/PRD_问题处理_统计页面JS错误.md`

**问题根因**：
- 编辑 `fetchItemKeys` 函数时，旧代码尾部 4 行未被删除，残留在新函数之后
- 导致 `onModuleChange`、`fetchItemTrend`、`fetchAllData` 等函数被错误嵌套，全局作用域无法访问 `fetchAllData`

**修复内容**：
- 删除第 330-333 行、第 492-494 行的残留代码
- 补回被误删的 `onModuleChange` 函数体

**验证结果**：
- 花括号平衡（124 对）✅
- 9 个关键函数全部存在 ✅
- 查询按钮点击正常工作 ✅

---

## 3. 当前卡在哪

**无卡点**。所有功能已实现、部署到 5.60、验证通过。

**当前状态**：
- 服务健康检查：status: ok, scheduler: running ✅
- 报告免登访问正常工作 ✅
- 统计模块正常工作 ✅
- 检测项趋势图表友好提示正常 ✅

---

## 4. 下一步计划

| 优先级 | 任务 | 说明 |
|--------|------|------|
| P1 | 创建 Merge Request | 访问 http://git.ubainsyun.com/bing/ubains-module-test/merge_requests/new?merge_request%5Bsource_branch%5D=troubleshoot-ai-assistant 合并到 master |
| P2 | 提交 HANDOFF.md | 本次交接文档加入 git |
| P2 | 清理测试数据 | 删除测试用的定时任务，配置 `MONITOR_ENC_KEY` 环境变量 |
| P3 | 企业微信通知链接同步 | 邮件/企业微信通知也携带 token |

---

## 5. 踩过的坑（绝对不要再踩）

### 坑 1：JavaScript 编辑时代码残留

**坑**：使用 Edit 工具替换函数时，`old_string` 未精确匹配完整范围，只替换了函数开头，尾部代码残留。导致后续函数定义在错误的闭包内，全局作用域无法访问。

**避免方法**：
- 编辑前完整阅读原代码，确保 `old_string` 匹配完整范围
- 编辑后检查花括号平衡
- 本地测试后再部署

### 坑 2：状态类检测项折线图空白无提示

**坑**：`_extract_numeric()` 对非数值（"正常"/"异常"/"yes"/"no"）返回 `(None, value)`，前端收到 `value_num=null` 后折线图无数据点，但未显示任何提示。用户以为"图表坏了"。

**避免方法**：
- 前端处理数据前检查数值情况，无数值时显示友好提示
- 饼图使用 `status` 字段，不依赖数值

### 坑 3：检测项选择器选项过多难找

**坑**：419 个检测项平铺在一个下拉框，用户难以找到目标项。

**避免方法**：
- 用两级联动：第一级选模块，第二级选检测项
- 检测项选择器按模块分组（optgroup）
- 标注无趋势能力的检测项

### 坑 4：部署后健康检查误报

**坑**：`upload_to_server.py` 结尾的 `[FAIL] Service may not be running` 是误报。服务启动需要加载索引（357 条），sleep 3 秒不够。

**避免方法**：
- 用 `curl http://192.168.5.60:8088/api/health` 权威验证
- 不要信赖部署脚本的自动检查

---

## 6. 关键文件与命令速查

### 本次修改文件

| 文件 | 改动 |
|------|------|
| `skill/code/web/service_monitor/services/report_service.py` | 新增 `access_token`/`access_token_expires_at` 生成、`validate_access_token()` |
| `skill/code/web/service_monitor/services/runner_service.py` | 通知链接拼接 token |
| `skill/code/web/service_monitor/services/statistics_service.py` | 新增 - 统计聚合服务 |
| `skill/code/web/service_monitor/services/__init__.py` | 导入 `statistics_service` |
| `skill/code/web/service_monitor/routes.py` | 页面路由 + 5 个统计 API + token 验证 |
| `skill/code/web/routes/auth.py` | next 参数回跳 |
| `skill/code/web/decorators.py` | `page_login_required` 携带 next |
| `skill/code/web/templates/login.html` | next 回跳支持 |
| `skill/code/web/templates/service_monitor/base.html` | 侧边栏菜单 + 访客模式处理 |
| `skill/code/web/templates/service_monitor/report.html` | 访客模式适配 |
| `skill/code/web/templates/service_monitor/statistics.html` | 新增 - 统计页面 |

### 新增文档

| 文件 | 说明 |
|------|------|
| `Docs/需求文档/服务监测/PRD_需求文档_报告免登访问与操作鉴权.md` | 需求文档 |
| `Docs/需求文档/服务监测/PRD_计划执行_报告免登访问与操作鉴权.md` | 计划执行文档 |
| `Docs/需求文档/服务监测/PRD_需求文档_监测统计模块.md` | 需求文档 |
| `Docs/需求文档/服务监测/PRD_计划执行_监测统计模块.md` | 计划执行文档 |
| `Docs/需求文档/服务监测/PRD_问题处理_统计页面JS错误.md` | 问题处理文档 |
| `Docs/需求文档/服务监测/PRD_计划执行_统计页面JS错误修复.md` | 计划执行文档 |
| `Docs/需求文档/服务监测/PRD_问题处理_检测项趋势图表显示问题.md` | 问题处理文档 |
| `Docs/需求文档/服务监测/PRD_计划执行_检测项趋势图表显示问题修复.md` | 计划执行文档 |

### 常用命令

```bash
# 本地启动
python skill/code/web/server.py

# 单元测试
cd skill/code && python -m pytest -v

# 部署到 5.60（用 ! 前缀执行）
! cd deploy && SSH_PASSWORD='***' python upload_to_server.py

# 健康检查
curl -s http://192.168.5.60:8088/api/health

# 测试报告免登访问
curl -s "http://192.168.5.60:8088/service-monitor/report/<id>?token=rpt_xxx"
```

### 未提交文件

- 多个 PRD 文档（需求/计划执行/问题处理）
- `skill/code/web/users.json`（仅登录统计更新）
- `HANDOFF.md`（本轮待提交）