!145 docs(xispeak): 归档前端页面 QA 审查报告(用户视角)

* docs(xispeak): 归档前端页面 QA 审查报告(用户视角)
* docs(fixcontact): 归档前端页面 QA 审查报告(用户视角)
* docs(inspectTask): 归档前端页面 QA 审查报告(工程师+用户视角)
* docs(bqtakepulse): 归档前端页面 QA 审查报告(工程师+用户视角)
* docs(bgpartymatter): 归档前端页面 QA 审查报告(工程师+用户视角)
This commit is contained in:
wsm
2026-08-11 07:27:58 +00:00
parent 33dfb1ca9b
commit 237a5810cf
8 changed files with 751 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
# 前端页面审查报告 — 巡视整改提升工作台账(DqInspectTaskList
## 审查信息
- 页面/路由:`/dq/inspectTask/DqInspectTaskList`(巡视整改提升工作台账)
- 审查日期:2026-08-11
- 审查视角:**资深前端工程师**(浏览器实测 + 代码审查结合)
- 审查账号:admin(mock 登录,其余接口打真实后端 8080)
- 相关文件:
- `src/views/dq/inspectTask/DqInspectTaskList.vue`
- `src/views/dq/inspectTask/components/DqInspectTaskForm.vue``DqInspectTaskModal.vue``DqInspectTaskFlowScheduleStartModal.vue`
- `src/views/dq/inspectTask/DqInspectTask.data.ts``DqInspectTask.api.ts`
- `src/components/semri/userComponent/DeptRoleUserSelectDropDown.vue`
- `src/components/Modal/src/BasicModal.vue``src/components/Modal/src/components/ModalClose.vue`
- 后端契约:`jeecg-module-supervision/.../DqInspectTaskController.java``DqInspectTaskMapper.xml``jeecg-module-system/.../tasktask/TaskTaskController.java``TaskTaskServiceImpl.java`
- 证据目录:`qa-tmp/inspectTask/`(截图 `screenshots/`、脚本/记录 `scripts/``artifacts/`
- 关联报告:`qa-report/inspectTask/QA_REPORT_UX.md`(用户视角,可并列对比)
## 总体结论
- **P0 × 1 P1 × 4 P2 × 7**
- 一句话总结:核心增删改查/详情/流程查看可走通,但**整改措施搜索框完全失效(P0)**——后端 ledger 自定义 SQL 对前端 `*like*` 通配符二次包裹导致永远查不到、清空也不恢复;另有责任领导列误绑/详情占位符(共享组件 watch 清值竞态)、流程操作不随状态且后端无守卫、分管所领导筛选被列表忽略等 4 个 P1,不建议按当前状态交付,需先修复 P0。
---
## P0 - 必须修复
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 后端调用/功能错误 | **「整改措施」搜索框完全失效**。列表页 JInput `type="like"` 把输入值包装成 `*wqdwqd*` 发到后端,但后端台账自定义 SQL 又做了一次 `concat('%', value, '%')`,实际生成 `improve_measure like '%*wqdwqd*%'`——带字面量星号,任何真实值都匹配不到,搜索永远返回 0 行;**清空输入框时发送 `improveMeasure=**`(空值仍被包一层星号)→ 列表继续保持空**,直到点「重置」。期间顶部统计标签仍显示「督办中 1」,列表(0) 与统计(1) 自相矛盾,用户误以为数据丢了。 | 实测 `artifacts/eng_02_api_bodies.json`ledgerList?improveMeasure=*wqdwqd* → records:[] total:0,同参数 statusStats → inProgress:1);实测 `artifacts/eng_10_search_bug.json`(输入 wqdwqd → row_count:0;清空 → 请求 improveMeasure=** 仍 0 行);截图 `screenshots/eng_15_final_list.png` | 前端 `DqInspectTaskList.vue:9``JInput type="like" @change="reload"`);后端 `DqInspectTaskMapper.xml:50-52``t.improve_measure like concat('%', #{task.improveMeasure}, '%')` |
**技术根因**`DqInspectTaskMapper.xml``queryLedgerPage` 是手写 SQL,它的 like 分支假定前端传**普通值**;而 JInput `type="like"` 走 Jeecg QueryGenerator 的 `*...*` 约定传通配符。两者叠加 = 二次包裹。`statusStats` 接口用 QueryGenerator 直查实体(`*``%` 正确转换)所以能匹配,于是列表与统计对同一筛选结果不一致。
**修复建议**:二者取其一——(a) 前端 `DqInspectTaskList.vue:9` 去掉 `type="like"`(改普通输入,由 XML `concat('%',…,'%')` 负责模糊);或 (b) 后端 XML 把值里的 `*` 转成 `%` 再包裹,并兜底空值时不发该条件(避免 `**`)。建议同时做 (b) 的空值判断,彻底解决"清空后列表空"。
---
## P1 - 强烈建议修复
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 逻辑/数据显示 | **列表「措施责任领导」列误绑 `measureResDept_dictText`**:该列与「措施责任部门」列显示完全相同的部门名「DD」,真实责任领导 `dd_ld_02` 看不到。后端已正确返回 `measureResLeader_dictText=dd_ld_02`。 | 实测 `artifacts/eng_01_rows.json`(第 7、8 列均为 "DD");`artifacts/eng_02_api_bodies.json`ledgerList 响应含 measureResLeader_dictText=dd_ld_02);截图 `04_list.png` | `DqInspectTask.data.ts:255-258`(措施责任领导列 `dataIndex: 'measureResDept_dictText'`,应为 `'measureResLeader_dictText'` |
| 2 | 状态一致性/竞态 | **详情/编辑弹窗「措施责任领导」显示占位符「请选择措施责任领导」**:后端已赋值 `measureResLeader=dd_ld_02` 且该下拉能查到 `dd_ld_02`,但 select 值为空。根因是 `DeptRoleUserSelectDropDown` 的 watch 在 deptId/roleId 变化时**无条件 `modelValue.value = ''`**:详情加载先赋 `measureResDept``measureResDeptId` computed 变化 → watch 触发 → 把刚加载的 `measureResLeader` 清掉(数据加载与 watch 的竞态)。因 `measureResLeader` 是动态 deptId,全表单只有它中招;`chargeLeaderId` 的 deptId 是静态常量不触发 watch,故正常。**编辑模式同路径也会被清空**(必填校验会拦下提交,不致静默丢数据,但每次编辑都要重选)。 | 实测 `artifacts/eng_09_leader_rootcause.json`queryUserRoleComponentData 对 measureResLeader 下拉返回 records 含 dd_ld_02 `has_dd_ld_02:true`,但 select `value_input:""``selection_items:[]`、placeholder_shown:true;对照 `chargeLeader_selection:["所领导01"]` 正常);`artifacts/probe_querybyid.json`queryById.result.measureResLeader=`dd_ld_02`);截图 `eng_09_detail_modal.png``60_detail_values.png` | `src/components/semri/userComponent/DeptRoleUserSelectDropDown.vue:63-69``watch(() => [props.deptId, props.roleId], () => { modelValue.value = ''; fetchUserList(); })`);使用处 `DqInspectTaskForm.vue:86-92``:deptId="measureResDeptId"` 动态) |
| 3 | 状态流转/后端调用 | **流程操作菜单不随任务状态变化,督办中任务也能「发起巡视整改流程/发起销号流程」→ 有创建重复/错误流程实例风险**。前端 `getFlowMenuList` 按状态显隐的 `if` 全被注释掉(388-421 行),所有记录都展示两个发起项;实测督办中(bpmStatus=2, completedStage=1)记录两项均可见、弹窗可打开。**后端 `singleFlowStart` 无任何业务状态守卫**`validateBusinessParams` 只校验 flowCode/businessId/formUrl 非空,提交会无条件新建 TaskTask 并 `startMutilProcess` 启动新 Flowable 流程实例。**为保护真实流程数据未点「提交」,创建重复实例为代码确认+实测入口,未实测触发**。 | 实测 `artifacts/eng_06_flow.json`(督办中记录 flow_menu_items=[发起巡视整改流程,发起销号流程,查询督办流程];弹窗可打开);后端代码 `TaskTaskServiceImpl.java:55-75,133-152`singleFlowStart 无守卫、validateBusinessParams 仅非空校验);`TaskTaskController.java:127-140`flow-schedules 无业务状态校验) | 前端 `DqInspectTaskList.vue:388-421``getFlowMenuList`,条件判断被注释);发起 `handleFlowScheduleConfirm` 491-524 行;后端 `TaskTaskServiceImpl.singleFlowStart` |
| 4 | 后端调用/状态一致性 | **查询筛选对台账列表部分失效:分管所领导筛选被列表忽略,且统计与列表不一致**。自定义 SQL `queryLedgerPage` 只实现了 improveMeasure/measureResLeader/measureResDept/problemId/completedStage/bpmStatus 6 个字段的子句,**没有 `charge_leader_id` 子句**;实测筛选「分管所领导=所党委01(无该领导记录)」列表仍显示全部 2 行(筛选被吞),而 `statusStats` 用 QueryGenerator 会应用该条件 → 统计归零、列表全量,自相矛盾。同机制下,高级查询暴露的 19 个字段里 13 个(targetNode/deadline/secretLevel 等)在列表侧同样无效(代码推断,与 chargeLeader 同路径)。 | 实测 `artifacts/eng_11_cleanup_filters.json`filter_chargeLeader_sdw01 → row_count:2,筛选被忽略);后端 `DqInspectTaskMapper.xml:49-68``<if test>` 仅 6 个字段);`DqInspectTaskController.java:98-107`ledgerList 透传 QueryGenerator 生成的实体条件) | 后端 `DqInspectTaskMapper.xml:49-68``DqInspectTask.data.ts:174-208`superQuerySchema 19 字段) |
---
## P2 - 建议
| # | 维度 | 问题描述 | 证据 | 位置 |
|---|------|---------|------|------|
| 1 | 用户体验/共享组件 | **弹窗关闭 X 与全屏图标紧邻易误触**:关闭按钮容器 86×34px 内先渲染 36×36 的全屏图标、再渲染约 26×36 的关闭 glyph,二者仅 12px 间距;`BasicModal.handleCancel` 又对容器 class`-close--custom`)点击直接 return 不关闭,于是点在图标间隙/偏左会触发全屏而非关闭。实测点击关闭区中心命中 `anticon-fullscreen`(弹窗未关),仅点最右侧 26×36 的 glyph 才关闭。该组件为全局共享,所有弹窗都受影响。 | 实测 `artifacts/probe_x_realmouse.json`center 命中 fullscreenafter_real_click_center=1 未关;glyph 26×36 点击后=0 关闭);`artifacts/probe_x_glyph.json`icons=[fullscreen,close]bbox 分别为 36×36、26×36 | `src/components/Modal/src/components/ModalClose.vue``--can-full``margin-left:12px`、glyph padding);`src/components/Modal/src/BasicModal.vue:203-215`handleCancel 过滤容器 class |
| 2 | 文案 | **删除确认文案笼统**:单删 popConfirm title 仅「是否确认删除」,批删 createConfirm content「是否删除选中数据」,未说明是否连带删除关联反馈记录/流程,用户无法评估影响。(UX 报告 P2#7 并列) | `artifacts/delete_popconfirm.txt`;截图 `61_t8_delete_confirm.png` | `DqInspectTaskList.vue:437``DqInspectTask.api.ts:82-93` |
| 3 | 空态 | **空数据无引导**:无「清除筛选/去新建」出口,只有 ant-empty 默认「暂无数据」;在搜索失效场景(P0#1)下尤其误导。(UX 报告 P2#4 并列) | `artifacts/empty_state_html.html`;截图 `17_t1b_filter_done.png` | 列表空态(BasicTable 默认 empty |
| 4 | 可学习性 | **发起弹窗「立即发起/重复发起」无解释**:两者区别、何时选「重复发起」没有任何说明,业务用户凭感觉选。(UX 报告 P2#5 并列) | `artifacts/flow_start_modal.txt`;截图 `50_t3_flow_start_modal.png` | `DqInspectTaskFlowScheduleStartModal.vue:4-9` |
| 5 | 可学习性 | **高级查询字段名技术化**superQuerySchema 多个 title 带「ID」「流程实例ID」等后缀,业务用户无法理解。 | `artifacts/superquery_modal.txt``DqInspectTask.data.ts:175-193` | `DqInspectTask.data.ts` superQuerySchema |
| 6 | 视觉 | **状态行底色浅粉彩近白**`status-row-2` 底色 `#fff1f0`(督办中)、`status-row-1` `#fffbe6`,肉眼几乎看不出,状态辨识价值为零;对色弱用户更不可用。(UX 报告 P2#9vision+DOM 已复核) | `artifacts/rowcolors_probe.json`td 背景 rgb(255,241,240));CSS `DqInspectTaskList.vue:643-651`;截图 `04_list.png` | `DqInspectTaskList.vue:643-651` |
| 7 | 性能/console | **`DeptRoleUserSelectDropDown` 未声明 emits 导致控制台 `onChange` 类型警告**:组件没写 `emits`,父级 `@change="reload"` 被当作 fallthrough 属性落到根 `a-select`,与组件内部 `onChange` 合并成数组 → `Invalid prop: type check failed for prop "onChange". Expected Function, got Array`,控制台持续刷警告;功能上父级 reload 仍会触发,但属隐患(若将来 antd 校验更严或改传参方式会坏)。 | 实测 `artifacts/eng_15_final.json`console_errors_warnings 含该警告);`eng_01_console.json` | `DeptRoleUserSelectDropDown.vue`(缺 `emits: ['change']`);使用处 `DqInspectTaskList.vue:14` |
---
## 通过项(做得好的地方)
- **表单校验体验**:空提交一次列出 7 条明确必填提示(`DqInspectTaskForm.vue:246-255`:请选择具体问题/密级/整改措施/完成时限/措施责任部门/措施责任领导/分管所领导/党群领导审批),且提交失败会 `scrollToField` 定位到首错字段(353-367 行)。
- **防误删**:单删/批删均有二次确认(popConfirm + `createConfirm`),批量删除需先勾选行。
- **状态统计随筛选/操作刷新**`afterFetch → fetchStatusStats` 复用当前 `queryParam`,实测按 `bpmStatus=3` 筛选时统计同步归零、按 `bpmStatus=2` 时统计正常(`eng_02_api_bodies.json`);操作成功后 `handleSuccess → reload` 刷新列表与统计。
- **台账合并单元格实现正确**`calcLedgerRowSpan` 在**当前页内**计算问题分类/面上/具体问题的 rowSpan,避免跨页合并导致分页不可控(`DqInspectTaskList.vue:353-365`)。
- **API 契约整体一致**:列表 `GET ledgerList`、详情 `GET queryById`、删除 `DELETE delete/deleteBatch`id 拼 URL)、保存 `POST add/edit`、状态统计 `GET statusStats`、发起流程 `POST tasktask/taskTask/flow-schedules`RecurringTaskDTO{taskTask,intervalType,startCount})——与后端 Controller 参数绑定一一对应。
- **流程查看能力完整**:「查询督办流程」弹窗含审批历史/流程图/查询当前办理人/修改信息/删除流程入口(实测 `eng_06_flow.json` query_process_modal)。
- **详情字段回显**:除「措施责任领导」外,具体问题/密级/完成时限/分管所领导等均正确回显(`eng_05_detail.json`)。
- **测试数据卫生**:本次仅复用既有只读记录做验证;清理了上一轮 eng 残留的 `QA_TEST_整改措施_0/_1``eng_13_cleanup_ui`DELETE id=2087061887133655042),最终列表 1 条原始数据、无 QA_TEST_ 残留(`eng_15_final.json`)。
---
## 测试过程记录
### 操作步骤与截图
1. 登录 `/user/login`admin/123456)→ 进列表页(`screenshots/eng_15_final_list.png`,最终干净态:1 条「wqdwqd/督办中」,统计 未开始0/督办中1/已完成0)。
2. 整改措施输入 `wqdwqd` 查询 → 列表 0 行;清空输入 → 仍 0 行(请求带 `improveMeasure=**`)→ 确认搜索失效(`artifacts/eng_10_search_bug.json`)。
3. 分管所领导选「所党委01」→ 列表仍显示全部行(筛选被忽略,`artifacts/eng_11_cleanup_filters.json`)。
4. 打开记录详情弹窗 → 「措施责任领导」占位符、value 为空;下拉查询返回 dd_ld_02 但未选中(`artifacts/eng_09_leader_rootcause.json`,截图 `eng_09_detail_modal.png`)。
5. 督办中记录「流程操作」下拉 → 三项全显示,发起整改/销号弹窗均可打开(`artifacts/eng_06_flow.json`;未点提交)。
6. 复用 UX 轮证据:关闭按钮 X 误触(`probe_x_realmouse.json`/`probe_x_glyph.json`)、删除确认(`delete_popconfirm.txt`)、空态(`empty_state_html.html`)。
7. 清理残留 `QA_TEST_整改措施_1``scripts/eng_13_cleanup_ui.py`DELETE 成功,QA_TEST 计数归 0)。
### console 报错/警告列表(`artifacts/eng_15_final.json`
- `error: Failed to load resource: net::ERR_CONNECTION_CLOSED`(单个资源,多为 iconify/后台请求,影响小)
- `warning: [Vue warn] Failed to resolve component: AppSearch/Notify/AppLocalePicker/SettingDrawer/Aide`(全局布局头部组件解析警告,与本页无关,框架级噪音)
- `warning: [Vue warn] Invalid prop: type check failed for prop "onChange". Expected Function, got Array` at `<DeptRoleUserSelectDropDown>`**本页相关,P2#7**
### 关键网络请求(方法/URL/状态码)
- `POST /sys/login` → 200mock
- `GET /dqinspecttask/dqInspectTask/ledgerList?column=createTime&order=desc&pageNo=1&pageSize=12[&improveMeasure=*wqdwqd*]` → 200(搜索参数下 records:[]
- `GET /dqinspecttask/dqInspectTask/statusStats[?improveMeasure=*wqdwqd*]` → 200(同参数 inProgress:1,与列表不一致)
- `GET /dqinspecttask/dqInspectTask/queryById?id=2085316903091015681` → 200measureResLeader=dd_ld_02
- `GET /sys/user/queryUserRoleComponentData?departId=2044677731423850498&roleId=2044680793306591234...` → 200(返回 dd_ld_02/dd_ld_01,共 2 条)
- `GET /tasktask/taskTask/queryByBusinessId?businessId=...` → 200(流程列表)
- `DELETE /dqinspecttask/dqInspectTask/delete?id=2087061887133655042` → 200(清理 QA_TEST
### 待实测 / 未覆盖(明确标注,不进 P0/P1 判定)
| 项目 | 状态 | 说明 |
|------|------|------|
| 发起流程「提交」是否真创建重复流程实例 | **代码确认 + 实测入口,未实测提交** | 前端菜单无条件显示 + 后端 `singleFlowStart` 无业务守卫(`TaskTaskServiceImpl.java:55-75,133-152`);为保护真实流程数据未点提交,重复实例风险为代码路径推断,建议后端侧加状态/幂等校验 |
| 删除是否级联删除关联反馈/流程记录 | 代码推断,待实测 | 仅确认有二次确认弹窗;未点「确定」,后端删除行为需工程师侧补测 |
| 高级查询非 6 字段(targetNode 等)对列表失效 | 代码推断 | XML `queryLedgerPage` 仅 6 个 `<if>` 子句,与 chargeLeader(已实测忽略)同机制 |
| 加载态/后端错误态(断网/500/超时) | 未实测 | 依赖 BasicTable 默认 loading/empty,未发现自定义错误兜底 |
| 权限按钮显隐(非 admin 角色) | **未覆盖** | 仅 admin 账号;按钮均有 `v-auth` 指令(`dqinspecttask:dq_inspect_task:add/exportXls/importExcel/deleteBatch`),但无法对比验证不同角色显隐 |
| 特殊字符/超长文本/快速连点/双标签页并发 | 未实测 | 边界输入本轮未覆盖 |
| 不同分辨率/小屏适配 | 未实测 | 默认 1440 视口 |
---
*报告按工程师视角分级(P0/P1/P2),证据均来自浏览器实测(截图/网络响应/模态/DOM)或 `file:line` 代码定位;代码推断项已明确标注"代码推断,待实测",未计入 P0/P1。与 `QA_REPORT_UX.md` 重叠问题并列呈现,并补充技术根因与修复建议。测试未创建任何新业务数据,清理了上一轮 QA_TEST_ 残留,无残留入库。*