- 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>
11 KiB
11 KiB
前端页面审查报告 — 习总书记重要讲话指示批示(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=2,6 字符后=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 删除清理(各脚本末步"清理"均归零)。无残留测试数据。