# PRD — 计划执行：检测项折叠展示与进程列表优化

## 概述

| 项目 | 内容 |
|------|------|
| 需求来源 | PRD_问题处理_检测项折叠展示.md |
| 计划日期 | 2026-07-20 |
| 预计工时 | 4 小时 |
| 优先级 | P2（用户体验优化） |

## 目标

1. Java/Python 进程列表正确显示在报告中
2. 检测项按模块分组，默认折叠，点击展开
3. 异常项优先展示，正常项默认隐藏

---

## Phase 1：进程列表显示修复（1小时）

### 1.1 检查 parser 过滤逻辑

**文件**：`skill/code/web/service_monitor/utils/parser.py`

**检查点**：
- `_INVALID_VALUES` 是否误过滤了进程列表值
- 值中包含 `|` 分隔符是否被正确处理

**修改**：如有过滤问题，添加白名单或调整过滤逻辑

### 1.2 确认脚本输出格式

**文件**：
- `skill/code/web/service_monitor/assets/service/28_java_check.sh`
- `skill/code/web/service_monitor/assets/service/29_python_check.sh`

**修改点**：
- 进程列表输出格式：`USER PID CPU% MEM% COMMAND`，多行用 `|` 分隔
- 确保每行不超过 200 字符（避免前端截断）

### 1.3 更新 display_names

**文件**：`skill/code/web/service_monitor/utils/display_names.py`

**新增 KEY**：
```python
"JAVA_PROCESS_COUNT": "Java容器进程总数",
"JAVA_PROCESS_LIST": "Java容器进程列表",
"JAVA_PROCESSES_DETAIL": "Java进程详情",
"PYTHON_PROCESS_COUNT": "Python容器进程总数",
"PYTHON_PROCESS_LIST": "Python容器进程列表",
"PYTHON_PROCESSES_DETAIL": "Python进程详情",
```

---

## Phase 2：报告前端折叠展示改造（2小时）

### 2.1 修改报告模板

**文件**：`skill/code/web/templates/service_monitor/report.html`

**改造思路**：

```html
<!-- 模块分组折叠 -->
{% for module in modules %}
<div class="module-section">
  <!-- 模块头部（可点击） -->
  <div class="module-header" onclick="toggleModule(this)">
    <span class="module-icon">
      {% if module.has_error %}❌{% elif module.has_warning %}⚠️{% else %}✅{% endif %}
    </span>
    <span class="module-name">{{ module.name }}</span>
    <span class="module-stats">
      异常 {{ module.error_count }} / 警告 {{ module.warning_count }} / 正常 {{ module.normal_count }}
    </span>
    <span class="toggle-icon">▼</span>
  </div>
  
  <!-- 检测项列表（默认折叠，异常项展开） -->
  <div class="module-body collapsed">
    {% for item in module.items %}
    <div class="check-item level-{{ item.level }}">
      <span class="item-name">{{ item.display_name }}</span>
      <span class="item-value">{{ item.value }}</span>
      <span class="item-level">{{ item.level_text }}</span>
    </div>
    {% endfor %}
  </div>
</div>
{% endfor %}
```

### 2.2 添加 JavaScript 折叠逻辑

```javascript
function toggleModule(header) {
  const body = header.nextElementSibling;
  const icon = header.querySelector('.toggle-icon');
  
  if (body.classList.contains('collapsed')) {
    body.classList.remove('collapsed');
    icon.textContent = '▲';
  } else {
    body.classList.add('collapsed');
    icon.textContent = '▼';
  }
}

// 页面加载时，自动展开有异常的模块
document.addEventListener('DOMContentLoaded', function() {
  document.querySelectorAll('.module-section').forEach(section => {
    const hasError = section.querySelector('.module-icon').textContent.includes('❌');
    const hasWarning = section.querySelector('.module-icon').textContent.includes('⚠️');
    
    if (hasError || hasWarning) {
      const header = section.querySelector('.module-header');
      toggleModule(header);
    }
  });
});
```

### 2.3 添加 CSS 样式

```css
.module-section {
  margin-bottom: 16px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  overflow: hidden;
}

.module-header {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  background: #f5f5f5;
  cursor: pointer;
  user-select: none;
}

.module-header:hover {
  background: #e8e8e8;
}

.module-body {
  padding: 0 16px;
  max-height: 2000px;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.module-body.collapsed {
  max-height: 0;
  padding: 0 16px;
}

.check-item {
  display: flex;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid #eee;
}

.check-item:last-child {
  border-bottom: none;
}

.check-item.level-critical { background: #fff0f0; }
.check-item.level-warning { background: #fff8e0; }
.check-item.level-normal { background: transparent; }

.toggle-icon {
  margin-left: auto;
  transition: transform 0.3s;
}
```

---

## Phase 3：进程列表特殊展示（1小时）

### 3.1 后端解析进程列表

**文件**：`skill/code/web/service_monitor/services/report_service.py`

**修改**：解析 `*_PROCESS_LIST` 类型的 KEY，转换为结构化数据

```python
def parse_process_list(value: str) -> list:
    """解析进程列表字符串为结构化数据"""
    processes = []
    for line in value.split('|'):
        parts = line.strip().split()
        if len(parts) >= 5:
            processes.append({
                'user': parts[0],
                'pid': parts[1],
                'cpu': parts[2],
                'mem': parts[3],
                'command': ' '.join(parts[4:])
            })
    return processes
```

### 3.2 前端特殊渲染

**模板修改**：

```html
{% if item.key ends with '_PROCESS_LIST' %}
<div class="process-list">
  <div class="process-summary">共 {{ item.process_count }} 个进程</div>
  <button onclick="toggleProcessList(this)">展开详情</button>
  <table class="process-table" style="display: none;">
    <thead>
      <tr><th>用户</th><th>PID</th><th>CPU%</th><th>内存%</th><th>命令</th></tr>
    </thead>
    <tbody>
      {% for proc in item.processes %}
      <tr>
        <td>{{ proc.user }}</td>
        <td>{{ proc.pid }}</td>
        <td>{{ proc.cpu }}</td>
        <td>{{ proc.mem }}</td>
        <td class="cmd">{{ proc.command }}</td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
</div>
{% else %}
<span class="item-value">{{ item.value }}</span>
{% endif %}
```

---

## 修改清单

| 阶段 | 文件 | 改动点 |
|------|------|--------|
| Phase 1 | `parser.py` | 检查过滤逻辑，确保进程列表不被过滤 |
| Phase 1 | `28_java_check.sh` | 确认进程列表输出格式 |
| Phase 1 | `29_python_check.sh` | 同上 |
| Phase 1 | `display_names.py` | 新增进程列表 KEY |
| Phase 2 | `report.html` | 折叠展示改造（HTML + CSS + JS） |
| Phase 3 | `report_service.py` | 解析进程列表为结构化数据 |

---

## 验证步骤

1. 运行全量巡检，检查 Java/Python 模块是否输出进程列表
2. 打开报告页面，确认模块默认折叠
3. 点击模块头部，确认能展开/折叠
4. 确认异常模块默认展开
5. 确认进程列表能正确展示

---

## 风险与回退

| 风险 | 影响 | 缓解措施 |
|------|------|----------|
| 进程列表值过长 | 前端渲染慢 | 限制最多显示 20 个进程 |
| JS 兼容性问题 | 旧浏览器折叠失效 | 使用原生 JS，无依赖 |
| 改动影响现有报告 | 报告展示异常 | 保留原样式作为回退 |