# 前端页面审查报告 — 我为四所把把脉(bg/bqtakepulse/BgTakepulseList) ## 审查信息 - 页面/路由:`http://127.0.0.1:3100/bg/bqtakepulse/BgTakepulseList`(我为四所把把脉 台账列表) - 审查日期:2026-08-11 - 审查视角:资深前端工程师(frontend-page-qa,浏览器实测 + 代码审查结合) - 相关文件: - `src/views/bg/bqtakepulse/BgTakepulseList.vue` - `src/views/bg/bqtakepulse/components/BgTakepulseForm.vue`、`BgTakepulseModal.vue`、`BgTakepulseBPMForm.vue` - `src/views/bg/bqtakepulse/BgTakepulse.api.ts`、`BgTakepulse.data.ts` - `src/components/Form/src/jeecg/components/SzSelectDept.vue`、`modal/SzDeptSelectModal.vue` - `src/components/Form/src/jeecg/hooks/useTreeBiz.ts` - `src/components/semri/userComponent/DeptRoleUserSelectRadioGroup.vue` - `src/hooks/system/useMethods.ts`(导出) - 后端:`BgTakepulseController.java`、`BgPartymatterController.java`、`BgXiSpeakController.java`(导出 500 交叉验证) - 测试账号:`admin` / `123456`(mock,唯一账号) - 证据目录:`qa-tmp/bqtakepulse/`(eng_screens/ + scripts/eng*_steps.txt / eng*_api.json / eng*_console.json) > 说明:本报告为工程师视角,先读代码建立假设再浏览器实测。所有 P0/P1 均来自浏览器实测证据;标注「代码推断,待实测」的项只计入 P2(未实测到或实测被 P0 阻断)。 > 视觉维度:以 DOM 结构 + `getComputedStyle` 计算样式评估,**视觉细节需人工复核**(本环境 Read 图片返回 Unsupported,未直接判读截图)。 ## 总体结论 - **P0 × 1 | P1 × 2 | P2 × 9** - 一句话总结:**「新增」链路被部门树选择失效阻断(P0)**——牵头部门必填但部门树弹窗点选后无法回写值,导致一条新记录都建不出来、查询区也无法按部门筛选;导出 Excel 三个模块全量 500(后端 AutoPoi 共享缺陷)且前端静默吞错无提示;顶部统计标签不随搜索/增删改刷新。页面**当前不建议交付**,需先修 P0。 - 与 UX 报告(`QA_REPORT_UX.md`,P0×0/P1×2/P2×6)对比:UX 报告漏掉了**部门树无法回写(P0)**与**统计标签不刷新(P1)**两条——前者是会把用户直接卡死的关键缺陷,工程师视角通过代码(`useTreeBiz.onSelect` 守卫)定位并实测确认。 ## P0 - 必须修复 | # | 维度 | 问题描述 | 证据 | 位置 | |---|------|---------|------|------| | 1 | 逻辑合理性 / 用户流程 | **部门树弹窗点选后无法回写表单值,新建记录被彻底阻断**。新增弹窗与查询区的「牵头部门」「协办部门」打开部门树后:树节点无复选框、点击节点(如 QLS)仅高亮(`ant-tree-node-selected`),点「确认」后表单输入框仍为空,值不回写。牵头部门为必填项(空表单提交提示「请选择牵头部门」)→ **用户无法通过校验,一条新记录都建不出来**;查询区同样无法按部门筛选。 | 实测:`engC_steps.txt`(点击 QLS→`sel:true`;确认后 input `value:""`);`engB_steps.txt:8-12`(确认后牵头部门仍「请选择」);截图 `engC_query_vs_form_tree.png`(树无复选框)、`engC_dept_after_confirm.png`;提交校验报错含「请选择牵头部门」(`engB_steps.txt`) | 前端:`BgTakepulseForm.vue:69,74`、`BgTakepulseList.vue:28,36`(`` 未传 `checkable`);`SzDeptSelectModal.vue`;**根因** `useTreeBiz.ts:79-89 onSelect` 守卫 `if (props.checkable == false)`——`checkable` 未传默认 `undefined`,`undefined == false` 为 `false`,分支永不执行,`checkedKeys` 恒空;`getSelectTreeData`(`:238-249`)只读 `checkedKeys/selectRows` → 确认回传空值。该部门组件改造由 commit `e852ebd`(czh-20260612「完成部门组件改造…目前已经把把把脉的组件替换」)引入 | | | | **修复建议**:给 `SzSelectDept` 传 `checkable`(复选框树),或令 `SzDeptSelectModal` 内部 `checkable` 恒为 `true`;并修正 `useTreeBiz.onSelect` 对 `checkable === undefined` 的守卫逻辑(按「非 checkable 即 select 模式」处理)。修复后回归:新增弹窗选部门→确认→值回写→提交成功;查询区选部门→列表按部门过滤。 | | | ## P1 - 强烈建议 | # | 维度 | 问题描述 | 证据 | 位置 | |---|------|---------|------|------| | 1 | 后端调用 / 用户体验 | **导出 Excel 全部 500,且前端无任何错误提示**。三个模块(bqtakepulse / bgpartymatter / xispeak)`exportXls` 均返回 HTTP 500:`org.jeecgframework.poi.exception.excel.ExcelExportException: Excel导出错误`(AutoPoi/JeecgEntityExcelView 路径);同一列表 EasyExcel 路径 `exportXlsHeaders` 正常(200/xlsx)。前端 `useMethods.exportXls` 无 `try/catch`、`errorMessageMode` 默认 `'none'`、`FileReader` 的 "success" 判断是死代码 → 用户点「导出」后无响应、无提示,表现为「卡死」。 | 实测:`engA_batch_export.json`(三模块均 500 + 异常类名);`exportXlsHeaders` 200(`engA_steps.txt`);截图 `engA_list.png`;UX 报告同样实测到(`walk14/15_log.txt` 500×2) | 后端:`BgTakepulseController.java:366-401 exportXls`(`JeecgEntityExcelView` + AutoPoi);前端:`src/hooks/system/useMethods.ts:23-55`、`useListPage.ts:66-117`;表头「导出」按钮 `BgTakepulseList.vue:53` | | | | **根因(后端共享,本次仅报告不改后端)**:AutoPoi 1.4.11 与 POI 版本不兼容(源码 `ExcelExportServer.createSheet:213` 抛 `ExcelExportException`,`e.getCause()` 为 null,具体堆栈在后端 IntelliJ 控制台不可读)。**前端修复建议**:`useMethods.exportXls` 加 `try/catch`,失败 `createMessage.error('导出失败,请稍后重试')`;后端排查 AutoPoi/POI 版本或迁移 EasyExcel 导出。 | | | | 2 | 状态一致性 | **顶部统计标签(未开始/督办中/已完成)不随搜索、重置、增删改刷新**。`statusStats` 仅在 `onMounted` 调用一次:实测搜索无命中(rows=0)后标签仍显示全量「未开始 0 / 督办中 1(已逾期 0)/ 已完成 0」;重置、删除后同样不更新。用户看到的是与列表/筛选结果矛盾的过期统计。 | 实测:`eng2_steps.txt:70-71`(无命中搜索 stats 不变、rows=0);`engA_steps.txt`(statusStats 调用数 初始后=1、搜索后=1、重置后=1,仅 mount 一次) | `BgTakepulseList.vue:383-385`(`onMounted(() => fetchStatusStats())`);`searchQuery:360-364`、`searchReset`、`handleSuccess` 均未调用 | | | | **修复建议**:在 `searchQuery` / `searchReset` / `handleSuccess`(增删改后)里调用 `fetchStatusStats()`,与 xispeak 已实现的「统计标签随搜索/筛选/增删改同步刷新」保持一致。 | | | ## P2 - 建议 | # | 维度 | 问题描述 | 证据 | 位置 | |---|------|---------|------|------| | 1 | 用户体验 | **保存成功无任何提示**(代码推断,待实测)。`submitForm` → `saveOrUpdate` → `emit('success')`,无 `createMessage.success`;`BgTakepulseModal.submitSuccess` 同样无 toast。用户保存成功看不到反馈。(因 P0 部门树问题无法走通完整保存,未实测) | 代码:`BgTakepulseForm.vue:391-399`、`BgTakepulseModal.vue:43-46` | 同上 | | 2 | 数据源 | **所办领导选项显示为内部编码**(`bg_ld_01` / `dd_ld_02`),用户看不出审批人是谁。`queryUserRoleComponentData` 返回的 `realname` 字段就是编码,`DeptRoleUserSelectRadioGroup` 直接渲染 `realname`。根因在数据(用户表 realname 存了编码),前端照实渲染。 | 实测:`engB_steps.txt:16`(`queryUserRoleComponentData: [{"username":"dd_ld_02","realname":"dd_ld_02"},{"username":"bg_ld_01","realname":"bg_ld_01"}]`) | `DeptRoleUserSelectRadioGroup.vue:4` | | 3 | 数据源 | **部门树节点名称为缩写**:QLS、SLD、BG部、DQ部、SZHZX、RH、JJ、DD,非部门全称,用户选部门靠猜。数据来自 `queryTreeList` → `sys_depart.depart_name`。 | 实测:`engC_steps.txt`(部门树弹窗节点)、`engB_steps.txt`、截图 `engB_dept_tree.png` | `SzDeptSelectModal.vue`(数据源) | | 4 | 用户体验 | **点击意见主题标题同时触发行展开与详情弹窗**。标题 `` 的 `@click="handleDetail"` 未阻止冒泡,表格 `expandRowByClick: true` → 点标题「办理情况」反馈区被一起展开 + 详情弹窗打开,与用户看详情意图冲突。 | 实测:`engD_steps.txt`(点 assac 标题后 `expanded=1` 且 `modals=['详情']`);截图 `engD_title_click.png` | `BgTakepulseList.vue:86`(title a)、`:220`(`expandRowByClick: true`) | | 5 | 表单校验 | **牵头部门必填但无红色星号**(代码推断,待实测)。`responDeptid` 的 `validatorRules` 仅自定义 validator(值为空时 reject「请选择牵头部门」),无 `required: true` → 表单不渲染必填星号,用户提交失败才知道必填。 | 实测:`eng2_steps.txt:152`(空表单校验错误含「请选择牵头部门」);代码:`BgTakepulseForm.vue:260-269` | `BgTakepulseForm.vue:68-71` | | 6 | 逻辑合理性 | **bpmStatus 为空时下拉同时出现「发起督办流程」与「再次督办」**(代码推断,待实测)。`getDropDownAction` 用 `record.bpmStatus=='1'||!record.bpmStatus` 与 `record.bpmStatus=='2'||!record.bpmStatus` 两个独立 if:从未发起过流程(bpmStatus 空)的记录两个入口都会显示,且二者都走 `handleProcess`(功能重复、用户困惑)。 | 代码:`BgTakepulseList.vue:474-485`;`eng2_steps.txt:143`(assac bpmStatus='2' 仅显示「再次督办」,空值分支未被实测到) | `BgTakepulseList.vue:474-485` | | 7 | 后端调用(性能) | **搜索框每键触发查询,快速筛选产生大量重复请求且无序号守卫**。`JInput @change="searchQuery"` 每键入一次发一次 `/list` 请求;实测快速切筛选(assac→ZZZ→assac)触发 14 次 `/list` 请求,存在旧响应覆盖新结果的竞态风险(最终状态正确,但冗余明显)。 | 实测:`eng2_steps.txt:140`(竞态期间 /list 14 次)、`eng3_api.json`(相邻两次同 query 重复请求) | `BgTakepulseList.vue:12`(`JInput @change="searchQuery"`) | | 8 | 美观 / 表格 | **25 列宽 3848px 横向滚动,仅「操作」列固定右,「完成状态」(第 24 列)等关键列不固定**,横向滚动时无法对照查看。建议固定右侧「完成状态 / 操作」两列。 | 实测:`eng2_steps.txt:137`(`contentScrollW=3848, contentClientW=1200, fixRight=['操作'], fixLeft=[]`);`BgTakepulse.data.ts` 24 列(含反馈子表共 25) | `BgTakepulseList.vue:223-226`(`actionColumn.fixed:'right'`)、`BgTakepulse.data.ts` | | 9 | 控制台告警 | **BaseSelect/VcSelect/ASelect 组件 prop 类型告警泛滥**:控制台大量 `[Vue warn]: Invalid prop: type check failed for prop "onChange"/"onClick". Expected Function, got Array`(牵头/协办部门选择框)。另有布局组件未解析告警(AppSearch/Notify/AppLocalePicker/SettingDrawer/Aide,框架级、非本页)。 | 实测:`eng2_console.json`(157KB 告警,`onChange/onClick Expected Function got Array` 重复出现) | 部门选择组件(`BaseSelect`/`VcSelect` 封装对 `onChange/onClick` 传参类型错误) | ## 通过项(做得好的地方) - 登录、列表加载、数据回显正常;行数据正确。 - 行状态配色生效:首行 `class="... status-row-2"`(`eng2_steps.txt:145`)。 - 删除有 popconfirm 二次确认(「是否确认删除」),下拉菜单(详情/删除/查询督办流程/再次督办)正常渲染(`eng2_steps.txt:142-148`)。 - 空表单提交校验错误提示清晰且定位到字段:请选择年份 / 请选择密级 / 请输入意见主题 / 请选择牵头部门(`eng2_steps.txt:152`)。 - 密级字典选项正常(非密/内部/秘密/机密);年份选择器可用(`engB_steps.txt`)。 - 「是否需要所办领导审批」开关正确联动「所办领导」字段显隐,不需要时自动清空历史值(`showSupDeptLeader` + `clearSupDeptLeaderIfNotNeeded`,`BgTakepulseForm.vue:253,302-310`)。 - 竞态测试最终列表状态正确(快速切筛选后 rows=1,无脏数据落库)。 - 导出 EasyExcel 路径(`exportXlsHeaders`)接口正常(200)。 ## 未覆盖项(受账号/数据限制) - **权限多账号对比**:仅有 `admin`,不同角色/密级/部门下的按钮显隐(`v-auth`)、数据范围、只读态未验证。 - **完整「新建→保存成功」链路**:被 P0 部门树阻断,无法走通;「保存无 toast」仅代码推断(P2)。 - **详情编辑保存、模板导入、发起/再次督办流程提交**:为避免产生真实流程实例 / 改动真实数据,未执行提交类操作。 - **视觉细节**:本环境无法直接判读截图,美观/响应式/暗黑主题以 DOM + 计算样式评估,**需人工复核**。 ## 测试过程记录 - **脚本**:`qa-tmp/bqtakepulse/scripts/eng_probe.py`(初始探针)、`eng_probe2.py`(状态一致性/删除/下拉/固定列/竞态)、`eng_probe3.py`(清空搜索 title=** / QA_TEST 建删)、`eng_probeA.py`(批量导出 500 交叉验证 + statusStats 时机 + 数据源)、`eng_probeB.py`(新建表单/所办领导编码/保存无 toast)、`eng_probeC.py`(部门树选择实证)、`eng_probeD.py`(标题点击展开)。 - **截图**:`qa-tmp/bqtakepulse/eng_screens/`(`eng_02_list_initial.png`、`engA_list.png`、`engB_*.png`、`engC_query_vs_form_tree.png`、`engC_dept_after_confirm.png`、`engD_title_click.png`、`eng2_dropdown.png`、`eng2_new_validation.png` 等)。 - **网络记录**:`engA_batch_export.json`(导出 500×3 + 异常类)、`engB_api.json`、`eng2_api.json`、`eng3_api.json`(`title=**` 清空搜索行为:输入 `assac` 后清空回车发 `title=**`,返回全部)。 - **console**:`eng2_console.json`、`engB_console.json`(0 error、87+ warning,主要两类:`onChange/onClick Expected Function got Array` 与布局组件未解析)。 - **关键实测结论**: 1. 导出 `exportXls`:bqtakepulse/bgpartymatter/xispeak 均 500 `ExcelExportException`;`exportXlsHeaders` 200 → AutoPoi 导出路径全局失效(后端根因)。 2. `statusStats`:mount 调 1 次,搜索/重置后不再调用,统计标签与列表结果不一致。 3. 部门树弹窗:点节点仅高亮、确认后值不回写(P0 根因)。 4. 所办领导:`queryUserRoleComponentData` realname 为编码。 5. 标题点击:同时展开行 + 打开详情弹窗。 6. 竞态:3 次筛选触发 14 次 `/list` 请求。 - **测试数据卫生**:尝试创建 `QA_TEST_PULSE_ENG_*` 记录,被部门树 P0 阻断未创建成功;全流程未对真实数据做增删改,**无残留数据**。 ## 修复优先级建议 1. 先修 P0(部门树选择回写)——否则「新增」功能完全不可用。 2. 同步修 P1:导出失败前端提示(后端 AutoPoi 单独提缺陷);统计标签随筛选/增删改刷新。 3. P2 按性价比排:所办领导/部门树数据源补全名称 → 标题点击 stopPropagation → 搜索防抖/序号守卫 → 固定完成状态列。