Files
supervision-test-frontend-repo/qa-report/xispeak/QA_REPORT.md
T
wsmandClaude Opus 4.7 b5d3032f0c docs(xispeak): 归档前端页面 QA 审查报告并忽略 qa-tmp 临时产物
- qa-report/xispeak/QA_REPORT.md 提交入库(P0×1 / P1×4 / P2×5)
- .gitignore 忽略 qa-tmp/、__pycache__/、*.pyc,测试临时产物不入库

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-07 15:16:39 +08:00

116 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 前端页面审查报告 — 习总书记重要讲话指示批示(xispeak)
## 审查信息
- 页面/路由:`/bg/xispeak/bgXiSpeakList`(组件 `src/views/bg/xispeak/BgXiSpeakList.vue`
- 审查日期:2026-08-07
- 审查方式:frontend-page-qa skill 四阶段流程(代码静态审查 + Playwright 浏览器实测 + checklist 系统化走查)
- 环境:dev 端口 3100(mock 开启),后端 `http://localhost:8080/jeecg-boot`,账号 admin/123456
- 相关文件:
- `src/views/bg/xispeak/BgXiSpeakList.vue`(树形列表 + 查询 + 流程操作)
- `src/views/bg/xispeak/BgXiSpeak.data.ts`(列定义 + 高级查询)
- `src/views/bg/xispeak/BgXiSpeak.api.ts`(接口层)
- `src/views/bg/xispeak/components/BgXiSpeakForm.vue`(新增/编辑表单)
- `src/views/bg/xispeak/components/BgXiSpeakFeedbackForm.vue`(反馈子表单)
- `src/views/bg/xispeak/components/BgXiSpeakBPMForm.vue`(流程表单)
- `src/views/bg/xispeak/components/BgXiSpeakFeedbackViewModal.vue`(查看办理情况)
- `src/views/bg/xispeak/components/BgXiSpeakFeedbackList.vue`(孤儿组件)
- 后端 `backend/.../xispeak/controller/BgXiSpeakController.java`
## 总体结论
- **P0 × 1 P1 × 4 P2 × 5**
- 一句话总结:核心 CRUD(新增→编辑→详情→删除)、查看办理情况、批量删除、导出均可用且无 console 错误;但存在 1 个功能性 P0(**添加下级无法建立树层级,子记录退化为根记录**)与 4 个 P1(**占位文本写入业务字段、多部门筛选语义错误、JBR 批量流程部分失败状态丢失、编辑反馈覆盖部门**),不建议直接交付。
---
## P0 - 必须修复
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 逻辑/操作顺序 | **"添加下级"无法创建子节点,树形层级功能整体失效**。"添加下级"把 `{ pid: parentId }` 传入表单,但 `edit()` 对无 id 的新记录直接重置 formData 并丢弃 pid,子记录以 `pid=''` 保存(后端落库为 `pid="0"`),变成平铺根记录;父节点永远不出现展开图标,无法构建层级。 | 实测 `probe_pid.py`:添加下级保存时 add 请求体 `pid=""``probe_tree.py`rootList 返回子记录 `"pid":"0"`,父节点刷新前后均无展开图标,子行无缩进 | `BgXiSpeakForm.vue:255-262``edit()` 重置丢弃 pid)· 触发 `BgXiSpeakList.vue:543-546` / `:633` |
---
## P1 - 强烈建议
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 逻辑/表单 | **占位模板文本被硬编码为表单默认值并写入业务字段**。新增弹窗打开时"企业负责同志批示情况"已填 `经单位主要负责同时签批同意,由xx部做好贯彻落实`、"学习传达研究部署情况"已填 `x月x日召开xxxx年第x次党委会议`,提交时原样入库。用户不手动改就把占位假数据写进记录;同时这两个字段的必填校验形同虚设。 | 实测 `probe_defaults.py`:默认值截图 + 提交请求体 `elmComment=经单位主要负责同时签批同意…, status=x月x日召开xxxx年第x次党委会议`CRUD 回显列内容含占位文本 | `BgXiSpeakForm.vue:163-164` |
| 2 | 后端调用 | **牵头部门多选筛选为 AND 语义**。前端把多个部门 id 逗号拼接成 `implDept=A,B`,后端在循环里逐个 `queryWrapper.apply("FIND_IN_SET(...)")`,生成 `A AND B AND …` 条件——一条记录必须同时包含所有选中部门才命中,选 2+ 部门时几乎查不到数据。应为 OR。 | 代码路径 `BgXiSpeakController.java:94-102`(循环 apply);前端拼接 `BgXiSpeakList.vue:916-923` | `BgXiSpeakController.java:94-102` |
| 3 | 操作顺序 | **JBR 批量发起流程部分失败时状态不保存、列表不刷新**`successCount === total` 守卫放在循环内,任一部门流程发起失败则 `bpmStatus`/`supervisionCount` 不更新、不 reload,已成功的流程成为"孤儿流程"且无部分成功提示。 | `probe_flows.py` 未覆盖(需真实流程引擎);代码 `BgXiSpeakList.vue:740-793` | `BgXiSpeakList.vue:783-787` |
| 4 | 状态一致性 | **编辑反馈记录时部门被当前登录人部门无条件覆盖**`edit()` 加载记录后无条件调用 `fillDeptFromLogin()`,把 `responDeptid/responDeptname` 覆盖为登录人部门;跨部门编辑/审批他人的反馈并保存会造成部门归属数据错乱。 | 代码 `BgXiSpeakFeedbackForm.vue:294` + `230-249` | `BgXiSpeakFeedbackForm.vue:294` |
---
## P2 - 建议
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 性能/体验 | **搜索无防抖,逐字触发 rootList**。JInput `@change="searchQuery"` 每个按键发一次查询;实测输入 6 个字符新增 6 次 rootList 请求。 | `probe_flows.py`:输入前 rootList REQ=26 字符后=8 | `BgXiSpeakList.vue:12` + `:900-902` |
| 2 | 安全/整洁 | **流程表单 14 处 console.log 调试输出**,含 `@props`、流程变量、部门过滤中间结果等,生产环境泄漏调试信息。 | 代码 `BgXiSpeakBPMForm.vue:311,312,596,603,607,612,618,624,627,659,662,664,671,686` | `BgXiSpeakBPMForm.vue`14 处) |
| 3 | 逻辑 | **反馈表单日期处理死代码 + 调试日志**`value.format('YYYY-MM-DD HH:mm:ss')` 对 Date 对象调用 `.format()` 会抛 TypeError(当前 axios 返回字符串未触发,属潜在崩溃点);另有 3 处 console.log。 | `BgXiSpeakFeedbackForm.vue:281-289``value.format`);`:238,243,248` | `BgXiSpeakFeedbackForm.vue:281-289` |
| 4 | 整洁 | **List.vue 死代码**:未使用 import `JDictSelectTag`、未使用 computed `showSdwLeaderSelect`、未使用函数 `handleFormJoinChange`、line 142 import 缩进错乱。 | 全文件 grep 仅定义处出现 | `BgXiSpeakList.vue:148,202,937,142` |
| 5 | 整洁 | **孤儿组件** `BgXiSpeakFeedbackList.vue` 未被任何源码引用;`searchReset()` 调用 `formRef.value.resetFields()``formRef` 未定义,一旦被挂载使用即崩溃。 | `BgXiSpeakFeedbackList.vue:141`;全局 grep 仅 checklist 文档引用 | `BgXiSpeakFeedbackList.vue:141` |
---
## 通过项(做得好的地方)
- **CRUD 全链路正常**:新增→保存→列表回显→编辑→详情→删除全部跑通,数据一致,无 console 错误。
- **空表单校验**:9 项必填错误准确提示并指向字段,提交前整体校验 + `scrollToField` 聚焦。
- **危险操作二次确认**:单条删除 Popconfirm(含"同时删除关联流程"说明文案)、批量删除 Modal.confirm,文案清晰。
- **查看办理情况**:动态标题"反馈信息(共 N 条,已完成 N 条)",空态显示"暂无数据",接口正常。
- **批量删除**:勾选→批量操作→确认→删除成功,选中后按 ids 传递。
- **导出**`exportXls` 请求正常发出并返回 200。
- **接口契约**add/edit/delete/rootList/statusStats/withDrawXiSpeak/queryFeedbackCounts 方法、URL、参数实测全部正确。
- **权限控制**:新增/导出/模板校验/模板导入等按钮均有 `v-auth` 指令;导出走配置 URL。
- **列表列宽**:长文本列均有 `ellipsis`,操作列 `fixed: right` 不换行。
- **空响应兜底**`bgXiSpeakFeedbackList` 无 mainId 时 `Promise.resolve({})` 兜底,不崩溃(`BgXiSpeak.api.ts:117-122`)。
---
## 未覆盖项(需人工复核或真实环境验证)
- **流程发起**(发起落实措施收集流程 / 发起经办人执行反馈流程):需要真实 Flowable 引擎 + 部门审批人数据,本次未实测。JBR 部分失败场景据此推断代码逻辑,建议真实环境复测。
- **树展开真实数据**:DB 中无既有树形数据,且 P0(添加下级)导致无法生成层级,树展开仅验证到"无展开图标"。
- **导出文件内容**:headless 下导出经新窗口触发,仅确认请求 200,未核验 Excel 内容。
- **上传类按钮**(模板校验/模板导入/下载模板):未实测,依赖 `/upload` 代理(3300 端口本次未运行,产生 `ERR_PROXY_CONNECTION_FAILED`,与 xispeak 逻辑无关)。
- **多分辨率/暗黑主题**headless 固定 1440×900,视觉细节需人工复核。
- **长文本/特殊字符(含 XSS)注入、大数据量、断网异常**:未专项注入测试。
- **双账号权限/密级过滤对比**:仅使用 admin 单账号。
---
## 测试过程记录
### 操作步骤与截图
测试脚本与证据存于 `qa-tmp/xispeak/`(临时产物,gitignored;本报告为唯一提交的测试文档):
| 脚本 | 覆盖 | 截图/产物 |
|------|------|----------|
| `probe_crud2.py` | 空表单校验 → 全字段填充 → 保存 → 列表回显 → 编辑 → 详情 → 删除 | `crud_test2/shots/*.png` |
| `probe_flows.py` | 查看办理情况 → 添加下级 → 搜索逐字输入(竞态)→ 清理 | `flows_test/shots/*.png` |
| `probe_extra.py` | 父/子记录创建 → 展开 → 督办状态筛选 → 导出 | `extra_test/shots/*.png` |
| `probe_batch2.py` | 勾选 → 批量删除 → 导出请求捕获 | `batch_test2/shots/*.png` |
| `probe_tree.py` | 添加下级后展开图标(刷新前后)→ rootList hasChild 字段 | `tree_test/shots/*.png` |
| `probe_pid.py` | 添加下级 add 请求体 pid 值 | 输出见运行记录 |
| `probe_defaults.py` | 新增弹窗默认值 + 空表单校验 + 提交入参 | 输出见运行记录 |
| `probe_secret.py` / `probe_fill*.py` | 密级/责任领导/部门选择弹窗结构 | 输出见运行记录 |
### console 报错
- xispeak 业务操作全程 **0 个 error**(各脚本 console.json)。
- 唯一 error 为 `ERR_PROXY_CONNECTION_FAILED`:来自 `/upload` 代理(3300 端口 mock 服务未运行),与 xispeak 逻辑无关。
### 关键网络请求(probe_flows.py 汇总)
```
GET /jeecgboot/bg/xispeak/bgXiSpeak/statusStats 200
GET /jeecgboot/bg/xispeak/bgXiSpeak/rootList 200 (x10)
GET /jeecgboot/bg/xispeak/bgXiSpeak/loadTreeRoot 200 (x2)
GET /jeecgboot/bg/xispeak/bgXiSpeak/queryFeedbackCounts 200 (x4)
POST /jeecgboot/bg/xispeak/bgXiSpeak/add 200
GET /jeecgboot/bg/xispeak/bgXiSpeak/listBgXiSpeakFeedbackByMainId 200
POST /jeecgboot/bg/xispeak/bgXiSpeak/withDrawXiSpeak 200
DELETE /jeecgboot/bg/xispeak/bgXiSpeak/delete 200
GET /jeecgboot/bg/xispeak/bgXiSpeak/exportXls 200 (probe_batch2)
```
### 测试数据卫生
- 所有测试数据使用 `QA_TEST_` / `QA_` / `QA_BATCH` / `QA_DEFAULTS` / `QA_PARENT` / `QA_CHILD` 前缀,测试后均通过 UI 删除清理(各脚本末步"清理"均归零)。无残留测试数据。