# HANDOFF — 功能测试报告模块会话交接文档

> **生成时间**: 2026-08-17
> **当前分支**: `platform-auto-test`
> **最近提交**: `ce2c75de` feat: 功能测试报告新增模板配置功能（多模板管理）
> **未提交变更**: 报告模板优化（T1-T5）+ Excel 格式适配的代码与文档尚未 git commit，部署是直接 scp 到 5.60 的（本地改动脉冲式同步，需尽快补提交）
> **状态**: ✅ 功能测试报告模块全部完成（后端服务 + API + 前端页面 + ERP 上传 + ERP 配置持久化 + **报告模板配置多模板管理** + **Excel 格式适配** + **报告模板优化（章节编号动态化 + 描述字段 + 复制功能）** + **下载/预览 500 已修复**）
> **部署状态**: ✅ 已部署至 192.168.5.60（Docker 容器 plat-auto-test-app，端口 80），前后端均已更新，**模板创建 500 错误已修复**，**模板优化（编号动态化/描述/复制）已验证通过**，**报告下载/预览 500 已修复并部署**

---

## ⚠️ 多窗口并行开发注意（功能测试报告窗口）

本窗口是**功能测试报告模块开发**，与可能的其他窗口并行开发。**必须遵守** `Docs/多窗口并行开发指南.md`：

| 项目 | 本窗口（功能测试报告） | 其他窗口 |
|------|----------------------|----------|
| 后端端口 | 8001（或 8002） | 视情况 |
| 前端端口 | 3000（或 3001） | 视情况 |
| 开发模块 | 功能测试报告 | 其他模块 |
| Git 提交 | 提交前先 `git pull` | 提交后 push |
| 数据库 | 错开写入时间 | 错开写入时间 |

---

## 一、本次任务（已完成）

### 任务：报告中心-功能测试报告模块（含 ERP 配置管理）

**参考工具**：`E:\GithubData\ubains-module-test\develop\AuxiliaryTool\FunctionalTestReportGeneration\`

**核心能力**：
1. ✅ 上传测试用例 Excel（表头第 3 行，数据第 4 行起，17 列）+ BUG 列表 Excel（表头第 1 行，数据第 2 行起，9 列）
2. ✅ 自动数据分析（用例通过率/执行率/模块分布、BUG 等级/状态/类型分布、遗留 BUG、用例-BUG 关联）
3. ✅ 生成 4 张统计图表（BUG 等级饼图、测试结果饼图、通过率柱状图、各模块 BUG 堆叠柱状图）
4. ✅ 生成 Word 报告（10 章节）和/或 Markdown 报告
5. ✅ 报告下载 + Markdown 在线预览
6. ✅ 上传报告到 ERP 系统（测试单报告 + 项目资料 + 协作文档）

### 任务 2：报告模板配置（多模板管理）— 2026-08-13 新增

**核心能力**：
1. ✅ 多模板 CRUD — 创建/编辑/删除/设为默认命名模板
2. ✅ 报告章节开关 — 10 个章节独立开关，动态编号
3. ✅ Word 样式可配置 — 字体/字号/标题字号/颜色/首行缩进
4. ✅ 图表样式可配置 — DPI/尺寸/中文字体/8 种颜色
5. ✅ 报告默认值可配置 — 测试负责人/测试人员/测试环境/系统版本/服务器地址/部署环境
6. ✅ 生成报告时下拉选择模板
7. ✅ 模板配置存储为 JSON 字段（`config` Text），与 `ErpConfig` 同模式

### 任务 3：模板创建 500 修复 + 部署 + 提交 — 2026-08-13 晚

**背景**：模板配置功能部署到 5.60 服务器（MySQL）后，创建模板报 500。

**处理过程**：
1. ✅ 定位根因 — MySQL 的 aiomysql 驱动不接受 Python dict 作为 SQL 参数（`TypeError: dict can not be used as parameter`），`_validate_config()` 返回的 dict 直接赋给了 `config` Text 列
2. ✅ 修复 — `create_template()` 和 `update_template()` 中 `json.dumps(config, ensure_ascii=False)` 序列化
3. ✅ 补全本地注册 — 本地 `main.py` import + include_router `report_template`，`models/__init__.py` import + `__all__`（服务器早已注册，本地遗漏）
4. ✅ 部署验证 — 上传修复后 `docker restart plat-auto-test-app`，创建"默认模板"（空 config 自动合并全量默认）+ "精简模板"（自定义章节开关/字体）均 200，列表返回正确，默认标记切换正常
5. ✅ Git 提交推送 — `ce2c75de`（20 文件，3118 增 / 691 删）已 push origin/platform-auto-test

**验证结果**（5.60 服务器实测）：
```
POST /templates {"name":"默认模板","is_default":true,"config":{}} → 200，自动合并完整默认配置
POST /templates {"name":"精简模板","config":{"chapters":{"attachments":false,"appendix":false},"word_style":{"font_name":"微软雅黑","font_size":10.5}}} → 200，覆盖生效
GET  /templates → 返回 [精简模板(id=2), 默认模板(id=1, is_default=true)]
```

### 任务 4：功能测试用例 Excel 格式适配 — 2026-08-17

**背景**：新的测试用例文件「大亚湾一体化会议系统测试用例-260811.xlsx」与现有模板格式存在差异：
1. **多 Sheet 结构**：文件包含 3 个 Sheet（预约会议 / 会议看板 / 会议室管理），需全部读取合并
2. **新增测试结果枚举**：Sheet 中出现 `"功能验证"` 值（语义 = 通过），映射表未识别
3. **损坏的 autoFilter XML**：Excel 文件中的 autoFilter 包含非数字/非通配符的 filter val 值，导致 openpyxl 报错

**处理过程**：
1. ✅ 编写 PRD — `Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配.md`
2. ✅ 编写计划执行文档 — `Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配_计划执行.md`
3. ✅ 实施代码改动（3 项）：

| 改动 | 文件 | 说明 |
|------|------|------|
| 多 Sheet 遍历 | `excel_reader.py` → `read_test_cases()` | `wb.active` → 遍历 `wb.sheetnames` 所有 Sheet |
| 损坏 autoFilter 自动修复 | `excel_reader.py` → 新增 `_fix_excel_auto_filter()` | 检测到 openpyxl 报错后，通过 zipfile + lxml 移除损坏的 `<autoFilter>` 元素 |
| 新增"功能验证"映射 | `excel_reader.py` → `normalize_test_result()` | `pass_aliases` 新增 `"功能验证"` |

**验证结果**：
```
3 个 Sheet 全部正确读取
  - 预约会议: 133 条
  - 会议看板: 277 条
  - 会议室管理: 77 条
  合计: 487 条，171 个模块

测试结果分布（文件 C13 列数据）：
  - 空值（公式未缓存）: 353 条
  - 未验证: 132 条
  - 存在疑问: 1 条
  - 需规未输出: 1 条

normalize_test_result("功能验证") → '通过' ✅
旧格式兼容（单 Sheet 文件）→ 正常读取 ✅
```

**⚠️ 注意**：当前文件中测试结果列（C13）大部分为空（353/487），这是因为原始 Excel 使用了公式引用而非缓存值，`data_only=True` 模式无法获取计算结果。需要填写测试结果后再上传生成报告。

### 任务 5：功能测试报告模板优化（章节编号动态化等）— 2026-08-17

**背景**：模板配置打开/关闭章节后，主章节编号（一、二…十）和子章节前缀（1.1 / 2.1…）仍按固定序号输出，关闭章节后出现跳号（如直接"一、五、六"）。

**需求文档**：`Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模板优化.md` + `_计划执行.md`（T1-T5，P0/P1）

| 范围 | 优先级 | 内容 |
|------|--------|------|
| T1 | P0 | 主章节编号动态化（一、二…按启用的章节连续编号） |
| T2 | P0 | 子章节编号动态化（前缀 `{ch_idx}.N` 跟随主章节） |
| T3 | P1 | 模板描述字段（≤200 字符，列表副标题 + 表单可编辑） |
| T4 | P1 | 模板复制功能（`POST /templates/{id}/duplicate`，名称 `_副本`/`_副本N`） |
| T5 | P0 | 向后兼容（全开时编号与改造前一致；旧模板无描述回退 `""`） |

**实施改动**（6 后端 + 2 前端文件）：

| 文件 | 改动 |
|------|------|
| `word_generator.py` | 新增 `_ZH_NUM_MAP`/`_zh_num()`，10 主章节 `_zh_num(ch_idx)` + 27 子章节 `{ch_idx}.N` |
| `markdown_generator.py` | 新增 `_ZH_NUM_MAP`/`_zh_num()`/`_title()`，同样动态化 |
| `models/report_template.py` | 新增 `description` 列（String(200)），`to_dict()`/`to_list_item()` 输出 |
| `schemas/report_template.py` | Create/Update 请求 + List/Response 增加 `description` |
| `routers/report_template.py` | create/update 支持 description；新增 duplicate 端点 |
| `database.py` | `columns_to_add` 增加 `report_templates.description`（旧库迁移） |
| `frontend/src/api/reportTemplate.ts` | description 字段 + `duplicate()` 方法 |
| `TemplateConfig.vue` | 模板描述 textarea + 列表副标题 + 复制按钮 |

**验证结果**（`临时目录/_verify_numbering.py` 全绿）：
```
PASS 1: _zh_num 工具函数（1-10 中文数字 + 超出回退阿拉伯数字）
PASS 2A: 全章节开启编号与改造前一致（一~十 / 1.1~10.4）
PASS 2B: 关闭"报告基本信息"后编号自动前移（二→一、子章节 2.1→1.1）
PASS 2C: 关闭中间章节（图表分析）编号连续无跳号（附录→九）
PASS 2D: Word 报告 34 个 Heading 编号正确（一、报告基本信息 / 1.1 报告标识 / 10.4 修订历史）
PASS 3A-3F: description 创建/更新/列表持久化 + 复制（_副本/_副本2、描述继承、is_default=False）+ 旧模板回退 ""
```
前端 `vue-tsc` 类型检查：修改文件无错误 ✅

**🚀 已部署至 5.60 服务器**（2026-08-17，paramiko scp + docker restart）：

| 部署项 | 说明 |
|--------|------|
| 后端 6 文件 | scp 覆盖到 `/data/third_party/plat-auto-test/backend/app/...` |
| 前端 dist/ | 本地 `npx vite build`（跳过 vue-tsc，因 ApiCaseList.vue 预存类型错误与本任务无关）→ 全量上传 |
| 容器重启 | `docker restart plat-auto-test-app`，重启后 `_ensure_columns()` 自动补齐 `report_templates.description` 列 |
| 服务器 API 实测 | 创建带描述 / 复制（`_副本`、`_副本2`、描述继承、is_default=False）/ 更新描述 / 列表含描述 / 旧模板回退 `""` — 全部通过 |
| 验证后状态 | 2 个模板（精简模板 id=2、默认模板 id=1 默认），测试模板已清理 |

**⚠️ 部署注意**：`npm run build` 会因 `ApiCaseList.vue` / `Execution.vue` 的预存类型错误（TS2339/TS2345 等，非本模块代码）而失败，需用 `npx vite build` 直接构建。这些类型错误待 API 测试模块窗口修复。

### 任务 6：报告下载/预览"内部服务器错误"修复 — 2026-08-17

**现象**：前端点击「下载报告」/「预览报告」提示"内部服务器错误"（HTTP 500）。

**根因**：`backend/app/routers/functional_report.py` 使用了 `FileResponse`（download 端点）和 `HTMLResponse`（preview 端点），但**未在文件顶部导入**。本地开发环境因 Starlette 顶层重导出"碰巧能跑"，但 5.60 服务器 Docker 环境的 FastAPI 版本不导出这两个类 → `NameError` → 500。

**修复**：import 区增加一行：

```python
from fastapi.responses import FileResponse, HTMLResponse
```

**验证**（5.60 服务器实测）：
- `import app.routers.functional_report` 本地通过 ✅
- scp 覆盖 + `docker restart plat-auto-test-app` ✅
- 下载/预览不存在会话 → 返回 404（不再 500）✅
- 容器日志无 NameError / Error ✅

**⚠️ 同类风险排查**：全局 grep 确认其他 router（`document.py` / `reports.py` / `security.py` / `device_sim.py`）均已正确从 `fastapi.responses` 导入或函数内局部导入，无同类问题。

**详细问题处理文档**：`Docs/PRD/功能测试/问题处理/BUG-2026-08-17-001_下载文件内部服务器错误.md`

### 参考工具 bug 修复记录

| # | 问题 | 根因 | 修复 |
|---|------|------|------|
| 1 | `generate_bug_by_module_chart` 报错 | `module_distribution` 是扁平 `Dict[str, int]`，但被当作嵌套 `Dict[str, Dict]` 使用 | 新增 `module_level_distribution: Dict[str, Dict[str, int]]` 字段，在 `analyze_bugs` 中填充 |
| 2 | 未执行用例数翻倍 | `unexecuted = unverified_cases + unverified_cases`（重复加自己） | 改为 `unverified_cases + undeveloped_cases` |
| 3 | `generate_all_charts` 无输出目录参数 | 原函数无 `charts_dir` 参数，无法指定输出路径 | 签名改为 `generate_all_charts(case_analysis, bug_analysis, charts_dir)` |
| 4 | 模块级 `ensure_directories()` 副作用 | 在 `config.py` 模块加载时自动创建目录 | 移除该调用，目录创建由服务类管理 |

---

## 二、已完成事项清单

### 2.1 后端新增文件

| 文件 | 说明 |
|------|------|
| `backend/app/services/functional/__init__.py` | 包初始化，导出所有子模块 |
| `backend/app/services/functional/config.py` | 常量配置：列索引、测试结果枚举、BUG 等级/状态、图表配置、ERP 配置、报告文件名/编号生成器 |
| `backend/app/services/functional/excel_reader.py` | Excel 读取：`TestCase`/`Bug` dataclass、`read_test_cases`(行4起)、`read_bug_list`(行2起)、结果/等级/状态归一化 |
| `backend/app/services/functional/data_analyzer.py` | 数据分析：`TestCaseAnalysis`/`BugAnalysis`/`ModuleStats` dataclass、`analyze_test_cases`、`analyze_bugs`、`link_bugs_to_cases` |
| `backend/app/services/functional/data_extractor.py` | 数据提取：IP地址、关键词、版本信息、测试人员、服务器信息、部署环境、测试负责人 |
| `backend/app/services/functional/chart_generator.py` | 图表生成：4 张图（BUG 等级饼图、测试结果饼图、通过率柱状图、各模块 BUG 堆叠柱状图）、中文字体兼容（Windows/Linux/macOS） |
| `backend/app/services/functional/word_generator.py` | Word 报告生成：10 章节完整报告（python-docx），含表格、图表嵌入 |
| `backend/app/services/functional/markdown_generator.py` | Markdown 报告生成：10 章节完整报告，含表格、图表引用 |
| `backend/app/services/functional_report_service.py` | 核心服务类：上传文件保存、数据分析和报告生成编排、会话管理 |
| `backend/app/services/erp_service.py` | ERP 上传服务：人员列表查询、姓名-ID 匹配、图片上传、报告创建（Word→HTML→图片→创建报告）、项目资料上传、协作文档上传 |
| `backend/app/schemas/functional_report.py` | Pydantic 数据模型：UploadResponse、GenerateRequest/Response、DownloadResponse、UploadToErpRequest/Response、ErpConfigResponse、ErpConfigUpdateRequest、ReportInfoResponse |
| `backend/app/routers/functional_report.py` | API 路由：7 个端点（upload/generate/download/preview/info/upload-to-erp/config） |
| `backend/app/models/report_template.py` | **2026-08-13 新增** — 报告模板 ORM 模型（id/name/is_default/config JSON/created_at/updated_at） |
| `backend/app/schemas/report_template.py` | **2026-08-13 新增** — 模板 CRUD 的 Pydantic 模型（Create/Update/ListItem/Response） |
| `backend/app/routers/report_template.py` | **2026-08-13 新增** — 模板 CRUD API 路由（6 个端点） |
| `frontend/src/api/reportTemplate.ts` | **2026-08-13 新增** — 模板 CRUD API 封装（list/get/create/update/delete/setDefault） |
| `frontend/src/views/functional-report/TemplateConfig.vue` | **2026-08-13 新增** — 模板配置管理页面（左侧模板列表 + 右侧配置表单，含章节开关/Word样式/图表样式/默认值） |

### 2.2 后端修改文件

| 文件 | 修改内容 |
|------|---------|
| `backend/app/config.py` | 新增 5 个 ERP 配置项：`ERP_API_KEY`、`ERP_BASE_URL`、`ERP_DEVELOPTESTING_ID`、`ERP_TYPE_ID`、`ERP_IMAGE_URL_PREFIX` |
| `backend/app/main.py` | 导入并注册 `functional_report.router`，前缀 `/api/functional-report`；**2026-08-13 新增**注册 `report_template.router`（前缀同） |
| `backend/requirements.txt` | 新增 4 个依赖：`python-docx`、`mammoth`、`Pillow`、`matplotlib` |
| `backend/app/models/__init__.py` | **2026-08-13 新增** `ReportTemplate` 模型注册 |
| `backend/app/services/functional/config.py` | **2026-08-13 新增** `get_default_config()` / `merge_template_config()` |
| `backend/app/services/functional/word_generator.py` | **2026-08-13 新增** `template_config` 参数（章节开关+Word样式+默认值） |
| `backend/app/services/functional/chart_generator.py` | **2026-08-13 新增** `template_config` 参数（chart_style 配置） |
| `backend/app/services/functional/markdown_generator.py` | **2026-08-13 新增** `template_config` 参数（章节开关+默认值） |
| `backend/app/services/functional_report_service.py` | **2026-08-13 新增** `template_id` 参数，加载模板配置并传递给各生成器 |
| `backend/app/schemas/functional_report.py` | **2026-08-13 新增** GenerateRequest 增加 `template_id` 字段 |
| `backend/app/routers/functional_report.py` | **2026-08-13 新增** generate 端点传入 `template_id` |
| `frontend/src/api/functionalReport.ts` | **2026-08-13 新增** `generate()` 增加 `templateId` 参数，请求体含 `template_id` |
| `frontend/src/views/functional-report/FunctionalReport.vue` | **2026-08-13 新增** 报告模板下拉选择器，`handleGenerate()` 传入模板 ID |
| `frontend/src/views/functional-report/index.vue` | **2026-08-13 修改** 注释更新为三个子页面 |
| `frontend/src/router/index.ts` | 新增 `/reports/functional` 独立路由，指向 `FunctionalReport.vue`（在 catch-all `/reports/:type?` 之前）；**2026-08-13 新增** `template-config` 子路由 |
| `frontend/src/App.vue` | **2026-08-13 新增** 菜单"模板配置"子项 + `FUNCTIONAL_LABELS` |

### 2.3 前端新增文件

| 文件 | 说明 |
|------|------|
| `frontend/src/api/functionalReport.ts` | API 封装：7 个方法（upload/generate/info/downloadUrl/previewUrl/uploadToErp/getErpConfig/updateErpConfig） |
| `frontend/src/views/functional-report/FunctionalReport.vue` | 完整页面：步骤 1 上传 Excel（拖拽双文件）、步骤 2 生成报告（项目名/格式选择）、分析摘要（7 指标）、图表预览（2×2 网格）、报告下载/预览/ERP 上传 |

### 2.4 前端修改文件

| 文件 | 修改内容 |
|------|---------|
| `frontend/src/router/index.ts` | 新增 `/reports/functional` 独立路由，指向 `FunctionalReport.vue`（在 catch-all `/reports/:type?` 之前） |

### 2.5 文档

| 文件 | 说明 |
|------|------|
| `Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模块.md` | 需求文档 |
| `Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模块_计划执行.md` | 计划执行文档 |

---

## 三、API 参考

### 端点一览

```
POST   /api/functional-report/upload       → 上传测试用例 Excel + BUG 列表 Excel
POST   /api/functional-report/generate     → 基于已上传文件生成报告（支持 template_id）
GET    /api/functional-report/download/{session_id}  → 下载报告文件
GET    /api/functional-report/preview/{session_id}   → 预览 Markdown 报告（HTML）
GET    /api/functional-report/info/{session_id}      → 获取会话报告信息
POST   /api/functional-report/upload-to-erp          → 上传报告到 ERP
GET    /api/functional-report/config       → 获取 ERP 配置（DB 优先，回退环境变量）
PUT    /api/functional-report/config       → 更新 ERP 配置（持久化到数据库）
```

### 报告模板配置端点（2026-08-13 新增，2026-08-17 扩展 description + duplicate，前缀 `/api/functional-report/templates`）

```
GET    /templates              → 获取模板列表（含默认标记 + description，不含 config）
GET    /templates/{id}         → 获取单个模板完整配置
POST   /templates              → 创建模板（首个模板自动设为默认；支持 description ≤200 字符）
PUT    /templates/{id}         → 更新模板（name/description/config/is_default 可独立更新）
DELETE /templates/{id}         → 删除模板（不允许删除最后一个）
PUT    /templates/{id}/default → 设为默认模板（全局唯一，自动切换）
POST   /templates/{id}/duplicate → 复制模板（2026-08-17 新增；名称自动 _副本/_副本N，description 与 config 继承，is_default=False）
```

**config JSON 结构**（创建/更新时与默认配置合并，`merge_template_config` 保证结构完整）：

```json
{
  "chapters": { "report_basic_info": true, "execution_summary": true, "test_scope": true,
                "case_details": true, "bug_list": true, "chart_analysis": true,
                "execution_records": true, "attachments": true, "risk_assessment": true,
                "appendix": true },
  "defaults": { "test_lead": "未填写", "tester": "未填写", "test_env": "未填写",
                "system_version": "未填写", "server_address": "未填写", "deployment_env": "未填写" },
  "word_style": { "font_name": "宋体", "font_size": 11, "title_level_1_size": 21,
                  "title_level_2_size": 19, "title_level_3_size": 17, "title_level_4_size": 15,
                  "paragraph_first_line_indent": 2, "title_color": "#000000" },
  "chart_style": { "dpi": 300, "figure_width": 10, "figure_height": 6, "chinese_font": "Microsoft YaHei",
                   "colors": { "pass": "#04AA6D", "fail": "#bb4069", "unverified": "#f0c040",
                               "undeveloped": "#dcbdbd", "bug_1": "#d32f2f", "bug_2": "#f57c00",
                               "bug_3": "#fbc02d", "bug_4": "#388e3c" } }
}
```

**Query 示例**：

```http
POST /api/functional-report/templates
{
  "name": "精简模板",
  "config": { "chapters": { "attachments": false, "appendix": false } }
}
```

生成报告时传 `template_id`：

```http
POST /api/functional-report/generate
{
  "session_id": "xxx",
  "project_name": "项目名称",
  "report_format": "docx",
  "template_id": 2
}
```

### 上传接口

```http
POST /api/functional-report/upload
Content-Type: multipart/form-data

testcase_file: <测试用例 Excel>
buglist_file: <BUG 列表 Excel>
session_id:   <可选，已有会话 ID>
```

响应：`{ session_id, testcase_path, buglist_path, message }`

### 生成接口

```http
POST /api/functional-report/generate
Content-Type: application/json

{
  "session_id": "xxx",
  "project_name": "项目名称",
  "report_format": "docx"  // docx | md | both
}
```

响应：`{ session_id, project_name, case_analysis, bug_analysis, case_bug_link_count, charts, reports }`

### ERP 上传接口

```http
POST /api/functional-report/upload-to-erp
Content-Type: application/json

{
  "session_id": "xxx",
  "report_filename": "项目名称_功能测试报告_2026年08月12日.docx",
  "developtesting_id": 397,
  "copyuser_names": ["张三", "李四"],
  "createuser_name": "王五"
}
```

响应：`{ success: true, report_id: 123, message: "..." }`

---

## 四、架构与数据流

### 目录结构

```
backend/app/services/functional/          # 核心功能模块（6 个文件，从参考工具移植）
backend/app/services/functional_report_service.py  # 服务编排层
backend/app/services/erp_service.py                # ERP 上传服务
backend/app/routers/functional_report.py           # API 路由层
backend/app/schemas/functional_report.py           # 数据模型
```

### 数据流

```
用户上传 Excel → 后端保存到 data/functional_report/{session_id}/
  → excel_reader 解析 Excel → TestCase[] / Bug[] dataclass
  → data_analyzer 分析 → TestCaseAnalysis / BugAnalysis
  → chart_generator 生成图表（读取 template_config.chart_style）→ charts/ 目录（4 张 PNG）
  → word_generator / markdown_generator 生成报告（读取 template_config 的 chapters/word_style/defaults）
  → 用户下载/预览
  → 用户触发 ERP 上传 → erp_service:
      Word → HTML(mammoth) → 逐张图片上传 ERP → 创建测试报告
      (可选) 上传项目资料 / 协作文档

模板配置数据流：
  用户创建/编辑模板 → POST/PUT /api/functional-report/templates
    → report_template.py 接收 → merge_template_config 合并配置
    → 存储到 report_templates 表的 config JSON 字段
  用户生成报告时选择模板 → POST /api/functional-report/generate 传入 template_id
    → functional_report_service.py 加载模板 → 传递给各生成器
```

### ERP 上传流程

```
erp_service.upload_report_to_erp(file_path, ...):
  1. GET /openclaw/stuff → 获取人员列表（含 ID）
  2. match_names_to_ids() → 抄送人姓名→ID 映射
  3. word_to_html_with_images():
     - mammoth 将 docx 转为 HTML
     - 提取图片 → POST /openclaw/upload/richtext → 替换为 ERP URL
  4. POST /openclaw/report → 创建测试报告

erp_service.upload_file_to_project(file_path, project_id, name):
  - POST /openclaw/upload/project → 上传项目资料

erp_service.upload_file_to_cooperation(file_path, project_id, name, group_id):
  - POST /openclaw/upload/cooperation → 上传协作文档
```

### 报告 10 章节结构

| 章节 | 编号 | 内容 |
|------|------|------|
| 测试概述 | 一 | 项目名称、测试目的、测试范围、参考文档 |
| 测试环境与资源 | 二 | 服务器信息、部署环境、测试人员、IP 地址、版本信息 |
| 测试执行情况 | 三 | 测试用例统计表、通过/失败/未执行分布 |
| 测试结果详细分析 | 四 | 各模块执行情况明细表 |
| 遗留 BUG 分析 | 五 | 遗留 BUG 统计（按等级/模块）、表格列出每个遗留 BUG |
| 关闭 BUG 分析 | 六 | 已关闭 BUG 统计表格 |
| 用例-BUG 关联分析 | 七 | 关联数量统计 |
| 测试结论与建议 | 八 | 通过率/执行率、评估结论、建议 |
| 测试统计图表 | 九 | 4 张图表插入 |
| 附录 | 十 | 测试用例清单、测试环境截图索引、参考资料 |

---

## 五、ERP 配置

ERP 配置通过环境变量管理，默认值在 `backend/app/config.py` 的 `Settings` 类中：

| 配置项 | 环境变量 | 默认值 |
|-------|---------|-------|
| ERP_API_KEY | `ERP_API_KEY` | `9adc1ce611544fae9bbbc5f6b1d6ce87` |
| ERP_BASE_URL | `ERP_BASE_URL` | `https://office.ubainsyun.com:5082/api/uerp` |
| ERP_DEVELOPTESTING_ID | `ERP_DEVELOPTESTING_ID` | `397` |
| ERP_TYPE_ID | `ERP_TYPE_ID` | `2` |
| ERP_IMAGE_URL_PREFIX | `ERP_IMAGE_URL_PREFIX` | `https://office.ubainsyun.com:5015/` |

ERP 请求参数：超时 30s，最多重试 3 次（间隔 5s），4xx 错误不重试。

### ERP 配置持久化（v2 — 2026-08-13 新增）

| 内容 | 说明 |
|------|------|
| 数据库模型 | `backend/app/models/erp_config.py` — 单行表 `erp_configs`（id=1），5 个配置字段 |
| 配置端点改造 | `GET /config` 优先读 DB，DB 空字段回退到环境变量；`PUT /config` upsert 到 DB |
| 前端配置页面 | `ErpConfig.vue` — 5 字段表单（API Key 密码框/Base URL/测试单 ID/Type ID/图片 URL 前缀），加载自动填充默认值 |
| 路由改造 | 功能测试报告改为父菜单（`/reports/functional`），含 `generate`（生成报告）和 `erp-config`（ERP 配置）两个子页面 |
| 持久化验证 | ✅ 写入 DB 后重启后端，GET 仍返回已保存值 |

---

## 六、当前数据状态

| 内容 | 状态 | 备注 |
|------|------|------|
| 后端功能模块 | ✅ 6 个文件 | 从参考工具移植，修复 2 个 bug |
| 后端服务类 | ✅ 2 个 | FunctionalReportService + ErpService |
| 后端 API 路由 | ✅ 7 个端点 | 全部注册到 main.py |
| 后端 ERP 配置模型 | ✅ 新增 | `ErpConfig`（erp_configs 表），config 端点持久化到 DB |
| 前端 API 封装 | ✅ 8 个方法 | 在 functionalReport.ts 中 |
| 前端页面 | ✅ 完成 | FunctionalReport.vue（生成报告）+ ErpConfig.vue（ERP 配置） |
| 前端路由 | ✅ 改造 | `/reports/functional` 父路由 + 2 个子路由（generate/erp-config） |
| 前端菜单 | ✅ 改造 | 功能测试报告改为父菜单，含"生成报告"/"ERP 配置"子项 |
| 前端构建 | ✅ 通过 | vue-tsc 类型检查 + Vite 构建均通过 |
| 后端导入 | ✅ 通过 | 所有模块可正常 import |
| **报告模板配置** | ✅ **2026-08-13 新增** | 完整多模板管理（CRUD + 默认模板 + 章节开关 + Word样式 + 图表样式 + 默认值） |
| **模板模型 + API** | ✅ 5 个文件 | `report_template.py`（模型/路由/ schema）+ `config.py` 工具函数 + 生成器改造 |
| **模板配置页面** | ✅ TemplateConfig.vue | 左侧模板列表 + 右侧完整配置表单，含颜色选择器/章节开关/字号设置 |
| **生成器改造** | ✅ 3 个生成器 | word_generator / chart_generator / markdown_generator 均支持 `template_config` 参数 |
| **生成报告模板选择** | ✅ FunctionalReport.vue | 新增模板下拉选择器，生成时传入 template_id |
| **部署至 5.60 服务器** | ✅ 验证通过 | Docker 容器健康运行，`GET /api/functional-report/templates` 返回 `[]` |
| **缺失文件补传** | ✅ 已修复 | `performance_output.py` / `api_preset.py` / `api_preset_schema` / `api_preset_service` 一并补传 |
| **模板创建 500 修复** | ✅ 2026-08-13 已修复 | MySQL 下 config Text 列 dict→JSON 序列化（`json.dumps`），验证创建/列表/默认标记全部正常 |
| **Git 提交推送** | ✅ `ce2c75de` | 20 个文件（3118 增 / 691 删），已 push 到 origin/platform-auto-test |
| **Excel 格式适配** | ✅ **2026-08-17 完成** | 多 Sheet 遍历 + 损坏 autoFilter 自动修复 + "功能验证"结果映射，3 Sheet 共 487 条全部读取，旧格式兼容 |

---

## 六·五、Excel 格式适配详情（2026-08-17）

### 背景与需求文档

| 文档 | 说明 |
|------|------|
| `Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配.md` | 需求文档（E1 多Sheet读取 / E2 "功能验证"映射 / E3 向后兼容 / E4 数据验证） |
| `Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配_计划执行.md` | 计划执行文档（3 个 Phase） |
| `临时目录/大亚湾一体化会议系统测试用例-260811.xlsx` | 新格式样例文件（参考文件，勿删除） |

### 代码改动

| 改动 | 文件位置 | 说明 |
|------|---------|------|
| 多 Sheet 遍历 | `excel_reader.py` `read_test_cases()` | `ws = wb.active` → `for sheet_name in wb.sheetnames:` 循环 |
| autoFilter 修复 | `excel_reader.py` 新增 `_fix_excel_auto_filter()` | 先尝试正常 `load_workbook`，失败则 zipfile 解包移除损坏 `<autoFilter>` 元素，写临时文件 |
| 结果映射 | `excel_reader.py` `normalize_test_result()` | `pass_aliases` 新增 `"功能验证"` |
| 临时文件清理 | `excel_reader.py` `read_test_cases()` 尾部 | 修复过的情况下 `os.remove(safe_path)` |

### 验证结果（2026-08-17 实测）

```
[Sheet] 预约会议   → 133 条(未验证 11)
[Sheet] 会议看板   → 277 条(未验证 44, 存在疑问 1, 需规未输出 1)
[Sheet] 会议室管理 → 77 条(未验证 77)
合计 487 条 · 171 个模块 · 3 个 Sheet 全部读取 ✅

normalize_test_result("功能验证") → '通过' ✅
旧格式回归（单 Sheet 模板文件）→ 无影响 ✅
```

**遗留说明**：C13 测试结果列 353 条为空——原始文件用公式而非缓存值，`data_only=True` 拿不到结果；需在 Excel 中填写测试结果后重新上传生成报告。

---

## 七、下次会话建议

### 待办（按优先级）

| 优先级 | 待办 | 说明 |
|--------|------|------|
| **P1** | 系统设置页 ERP 配置 | 在 Settings.vue 中增加 ERP 配置项（API Key/URL/默认测试单 ID） |
| **P1** | 部署自动检查 | 增加一个部署前自动检查脚本，检测 `routers/__init__.py` 未 export 的模块，避免容器启动失败 |
| **P2** | 前端页面加载状态细化 | 上传/生成过程中的 loading 状态、进度提示等 |
| **P2** | 报告历史管理 | 支持查看历史报告列表、删除、重新生成 |
| **P3** | 批量生成 | 支持多项目批量生成报告 |
| **P3** | 「大亚湾」Excel 实际生成报告验证 | 需先在 Excel 中补全 C13 测试结果列（当前 353/487 为空，公式未缓存），再走前端上传→生成→ERP 全流程验证 |

### 踩坑记录

| # | 现象 | 根因 | 正确做法 |
|---|------|------|---------|
| F1 | 图表生成中文乱码 | matplotlib 缺少中文字体配置 | `_setup_chinese_font()` 自动检测 Windows/Linux/macOS 字体路径 |
| F2 | ERP 图片上传失败 | 图片 URL 前缀未正确拼接 | `image_url_prefix` 确保末尾有 `/`，拼接时不重复 |
| F3 | mammoth 转换 Word 图片丢失 | 图片提取为 base64 未替换为 ERP URL | `word_to_html_with_images` 中逐张上传并替换 src |
| F4 | 路由 `/reports/functional` 被 `:type?` 捕获 | Vue Router 静态路由写在动态路由之后 | 将 `/reports/functional` 放在 `/reports/:type?` 之前 |
| F5 | 前端 `baseURL` 双重前缀 404 | axios baseURL 设为 `/api` 后路径又写 `/api/...` | baseURL 留空，路径写完整 `/api/...` |
| F6 | `updateErpConfig`/`getErpConfig` 导入报 TS 错误 | `functionalReport.ts` 导出的是对象 `functionalReportApi`，非命名导出 | 用 `functionalReportApi.getErpConfig()` 调用 |
| F7 | PUT config 后 api_key 返回空字符串 | DB 记录只更新了非空字段，空字段未回退环境变量 | GET/PUT 返回时空字段一律回退到 `settings` 默认值 |
| F8 | TypeScript `TS18048` 报错 | `config.word_style` 等字段为可选项(`?:`)，模板中访问报 undefined | `reportTemplate.ts` 中所有 config 字段改为必填（保持与后端 `get_default_config()` 结构一致） |
| F9 | TypeScript `TS7053` 报错 | `chapterOptions` 未显式声明类型，`config.chapters[key]` 索引报 any | `chapterOptions` 类型标注为 `{ key: keyof ReportTemplateConfig['chapters']; label: string }[]` |
| F10 | 部署脚本 Python SyntaxError | `replace('\', '/')` 反斜杠未转义 | 改用 `os.sep` 或 `replace('\\\\', '/')` |
| F11 | **服务器 API 路由未更新（重点）** | 部署时以为宿主机直跑 uvicorn，实际是 **Docker 容器**（`plat-auto-test-app`）在跑 | **必须 `docker restart plat-auto-test-app` 而非宿主 pkill**，且宿主 `/data/.../backend/` 是容器挂载卷，直接改文件即生效 |
| F12 | **容器启动失败 ImportError** | 服务器后端缺少本地已有的 `performance_output.py`/`api_preset.py` 及 `api_preset` schema/service（routers/__init__.py 不 export，靠 main.py 直接导入） | 补传缺失文件后再 `docker restart`，成功恢复 healthy |
| F13 | **创建模板 500 `TypeError: dict can not be used as parameter`** | MySQL 的 aiomysql 驱动不接受 Python dict 作为 SQL 参数：`_validate_config()` 返回 dict，直接赋给 `config` Text 列。SQLite 不校验类型所以本地从未报错 | 赋模型前 `json.dumps(config, ensure_ascii=False)` 序列化为 JSON 字符串（create 和 update 两处都要改），读侧 `to_dict()` 已 `json.loads` 无需改 |
| F14 | **本地 main.py 未注册 report_template 路由** | 之前只改了服务器上的 main.py（已注册），本地 `main.py` 和 `models/__init__.py` 忘记同步注册 | 本地/服务器都要注册：main.py import + include_router，models/__init__.py import + __all__ |
| F15 | **下载/预览报告 500 `NameError: FileResponse`** | `functional_report.py` 使用 `FileResponse`/`HTMLResponse` 但未导入；本地因 Starlette 顶层重导出碰巧能跑，服务器 FastAPI 版本严格不导出 | `from fastapi.responses import FileResponse, HTMLResponse` 显式导入（已修复 + 部署 + 排查其他 router 无同类问题） |

---

## 八、启动与验证

```bash
# 后端
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8001

# 前端
cd frontend
npm run dev

# 访问
# 前端: http://localhost:3000/reports/functional/generate（生成报告）
# 前端: http://localhost:3000/reports/functional/template-config（模板配置）
# 前端: http://localhost:3000/reports/functional/erp-config（ERP 配置）
# API 文档: http://localhost:8001/docs（搜 functional-report 标签）
# 健康检查: http://localhost:8001/health

# 生产环境 5.60 服务器（Docker 部署）
# 服务器: 192.168.5.60 (SSH ubains / Ubains@123)
# 部署目录: /data/third_party/plat-auto-test/（backend 挂载到容器 /app）
# 容器: plat-auto-test-app（deploy-app 镜像，uvicorn 端口 80）
# 更新代码后: sudo docker restart plat-auto-test-app（bind mount 直接生效）
# 缺失模块排查: sudo docker logs plat-auto-test-app --tail 50

# 测试用示例 Excel 文件
# 参考工具目录: E:\GithubData\ubains-module-test\develop\AuxiliaryTool\FunctionalTestReportGeneration\
# 示例文件: data/input/用例模板.xlsx, data/input/BUG列表模板.xlsx
```

---

## 九、文件完整清单

### 后端新增（15 个文件）→ 另有报告模板相关（2026-08-13）

```
backend/app/services/functional/__init__.py
backend/app/services/functional/config.py
backend/app/services/functional/excel_reader.py
backend/app/services/functional/data_analyzer.py
backend/app/services/functional/data_extractor.py
backend/app/services/functional/chart_generator.py
backend/app/services/functional/word_generator.py
backend/app/services/functional/markdown_generator.py
backend/app/services/functional_report_service.py
backend/app/services/erp_service.py
backend/app/schemas/functional_report.py
backend/app/routers/functional_report.py
backend/app/models/erp_config.py           — ERP 配置数据库模型
```

### 报告模板配置新增（2026-08-13，4 个文件）

```
backend/app/models/report_template.py       — 报告模板 ORM 模型
backend/app/schemas/report_template.py      — 模板 CRUD 的 Pydantic 模型
backend/app/routers/report_template.py      — 模板 CRUD API 路由（6 个端点）
frontend/src/api/reportTemplate.ts          — 前端模板 CRUD API 封装
frontend/src/views/functional-report/TemplateConfig.vue  — 模板配置页面
```

### 后端修改（4 个文件）→ 另有报告模板相关（2026-08-13）

```
backend/app/config.py           — 新增 ERP 配置项
backend/app/main.py             — 注册 functional_report 路由 + 2026-08-13 注册 report_template 路由
backend/requirements.txt        — 新增 python-docx/mammoth/Pillow/matplotlib
backend/app/models/__init__.py  — 注册 ErpConfig 模型 + 2026-08-13 注册 ReportTemplate 模型
```

### 后端生成器改造（2026-08-13，5 个文件）

```
backend/app/services/functional/config.py           — 新增 get_default_config() / merge_template_config()
backend/app/services/functional/word_generator.py    — 支持 template_config 参数
backend/app/services/functional/chart_generator.py   — 支持 template_config 参数
backend/app/services/functional/markdown_generator.py — 支持 template_config 参数
backend/app/services/functional_report_service.py    — 支持 template_id 参数
backend/app/schemas/functional_report.py             — GenerateRequest 增加 template_id
backend/app/routers/functional_report.py             — generate 端点传入 template_id
```

### 前端新增（4 个文件）→ 另有报告模板相关（2026-08-13）

```
frontend/src/api/functionalReport.ts
frontend/src/views/functional-report/FunctionalReport.vue
frontend/src/views/functional-report/index.vue    — 父容器组件
frontend/src/views/functional-report/ErpConfig.vue — ERP 配置页面
```

### 前端修改（2 个文件）→ 另有报告模板相关（2026-08-13）

```
frontend/src/router/index.ts    — 改为父路由 + 子路由结构；2026-08-13 新增 template-config 子路由
frontend/src/App.vue            — 菜单改为 el-sub-menu 子菜单结构；2026-08-13 新增模板配置子项
frontend/src/api/functionalReport.ts  — 2026-08-13 generate() 增加 templateId 参数
frontend/src/views/functional-report/FunctionalReport.vue  — 2026-08-13 新增模板选择下拉框
frontend/src/views/functional-report/index.vue  — 2026-08-13 注释更新
```

### 文档（6 个文件）

```
Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模块.md
Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模块_计划执行.md
Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配.md                                       — 2026-08-17 新增
Docs/PRD/功能测试/需求文档/_PRD_功能测试用例Excel适配_计划执行.md                              — 2026-08-17 新增
Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模板优化.md                                       — 2026-08-17 新增（T1-T5，P2/P3 待办项见文内 backlog）
Docs/PRD/功能测试/需求文档/_PRD_功能测试报告模板优化_计划执行.md                              — 2026-08-17 新增
```

---

## 七、待办与 Backlog

### 7.1 模板优化 P2/P3 待办（本轮未实施，见 PRD backlog）

| # | 优先级 | 内容 |
|---|--------|------|
| T6 | P2 | Word 字体下拉框（当前为文本输入，改为系统字体枚举） |
| T7 | P2 | 一键恢复默认配置按钮 |
| T8 | P3 | 图表颜色标签显示（当前仅颜色选择器，无语义标签预览） |
| T9 | P3 | 模板导出/导入（JSON 文件） |
| T10 | P3 | 报告生成页模板下拉显示章节摘要（如"精简模板（8/10 章）"） |

### 7.2 其他待办

- **P3 大亚湾真实 Excel 报告验证**：新格式用例文件（`临时目录/大亚湾一体化会议系统测试用例-260811.xlsx`）的测试结果列（C13）大部分为公式未缓存值（353/487 空），需业务方填写实际结果后再上传生成完整报告验证
- **前端类型错误**：`ApiCaseList.vue` / `Execution.vue` 存在预存 TS 类型错误（TS2339/TS2345），导致 `npm run build` 失败，当前部署用 `npx vite build` 绕过；待 API 测试模块窗口修复
- **临时脚本清理**：`临时目录/` 下有 `_fix_md_subs.py`、`_fix_md_gen.py`、`_fix_md_gen2.py`（markdown_generator 修复脚本，已完成使命）、`_verify_numbering.py`（验证脚本，可保留供回归）可择机清理

---

*本文档由功能测试报告开发窗口生成，供下一次会话快速恢复上下文。其他窗口的交接见 `HANDOFF.md`（主文档）、`HANDOFF_安全测试.md`、`HANDOFF_设备模拟.md` 等。*