Files
wsm 237a5810cf !145 docs(xispeak): 归档前端页面 QA 审查报告(用户视角)
* docs(xispeak): 归档前端页面 QA 审查报告(用户视角)
* docs(fixcontact): 归档前端页面 QA 审查报告(用户视角)
* docs(inspectTask): 归档前端页面 QA 审查报告(工程师+用户视角)
* docs(bqtakepulse): 归档前端页面 QA 审查报告(工程师+用户视角)
* docs(bgpartymatter): 归档前端页面 QA 审查报告(工程师+用户视角)
2026-08-11 07:27:58 +00:00

15 KiB
Raw Permalink Blame History

前端页面工程师视角审查报告 — 党委会/所务会事项(bgpartymatter

审查信息

  • 页面/路由:/bg/bgpartymatter/BgPartymatterList(党委会台账,菜单「党委会决策事项」);所务会复用 BgOfficematterListmeetingType=office,菜单「所务会决策事项」)
  • 审查日期:2026-08-11
  • 审查视角:前端资深工程师(浏览器实测 + 代码审查结合,覆盖 API 契约、权限、状态一致性、表单校验、性能/异常等工程师专项维度)
  • 相关文件:
    • src/views/bg/bgpartymatter/BgPartymatterList.vue
    • src/views/bg/bgpartymatter/components/BgPartymatterForm.vue
    • src/views/bg/bgpartymatter/components/BgPartymatterModal.vue
    • src/views/bg/bgpartymatter/BgPartymatter.data.tsBgPartymatter.api.ts
    • 后端:backend/supervison-java/.../bgpartymatter/controller/BgPartymatterController.javajeecg-boot-base-core/.../base/controller/JeecgController.java
  • 测试账号:admin(仅 1 个账号,多角色/多部门/多密级对比场景未覆盖,见「未覆盖项」)
  • 证据目录:qa-tmp/bgpartymatter/scripts/*.jsoneng_04~eng_09、02_modal、12_adddel_final、05_flow 等)
  • 配套文档:qa-report/bgpartymatter/QA_REPORT_UX.md(用户视角报告,可并列对比)
  • 说明:全程无头浏览器实测(Playwrightdev 端口 3100,登录走 mock、业务接口走真实后端 8080),登录账号 admin/123456。

总体结论

  • P0 × 1 P1 × 2 P2 × 7
  • 一句话总结:党委会/所务会台账的搜索、详情、流程、新增、删除都能走通且状态一致,但导出功能 100% 不可用(后端稳定 500,前端静默无任何反馈)——这是唯一的交付阻塞项,已定位到 AutoPoi 对不可变集合执行 Iterator.remove() 的根因;顶部统计标签不随筛选/增删改刷新、详情弹窗字段"看似可编辑实被透明遮罩拦截"是两大 P1 体验/一致性问题。

P0 - 必须修复

# 维度 问题描述 证据 位置
1 后端调用/功能 导出(导出 Excel)完全不可用:点击工具栏「导出」→ 无下载、无 toast、无任何反馈;后端 exportXls 稳定返回 500。党委会、所务会两页同一 exportConfig 与同一后端接口,均复现。根因(已定位):后端 JeecgController.exportXlsservice.list(queryWrapper) 的查询结果直接作为数据集合传给 AutoPoi 导出;AutoPoi ExcelExportServer.createSheet() 第 198-202 行对数据集合迭代器执行 its.next(); its.remove(); 分块清理,当数据集合为不可变集合Iterator.remove()UnsupportedOperationException;第 213 行 catch 用 e.getCause() 包裹(该异常无 cause → null),把真实原因吞掉,统一抛成 ExcelExportException: Excel导出错误,响应 trace 无 "Caused by"(与实测一致)。实测链路:0 行导出=200,任意 ≥1 行导出=500 且与字段内容无关(最小行、全字段行均失败);用与 BgPartymatter 全部 @Excel 字段一致的副本类独立复现(C:\Users\sz04\AppData\Local\Temp\ap_repro):可变 ArrayList → 成功(8704 字节),不可变集合 → 完全相同的 500。修复方向:① 前端 exportConfig 切换到后端已有的 EasyExcel 导出端点 exportXlsByEasyExcelBgPartymatterController.java:490-495,同模块 exportXlsHeaders 模板下载已实测可用,见 P0 修复建议);② 或后端导出前把数据集合复制为可变 List;③ 同时前端应把导出失败透出错误提示而非静默。 实测:exportXls 响应 HTTP 500 body ExcelExportException: Excel导出错误qa-tmp/bgpartymatter/scripts/eng_04_trace.json、eng_09 再复现 500 且 export_toasts=[]);所务会页同样 500eng_05_empty_office.json);独立复现成功/失败对比(ap_repro/MainRepro2.java vs MainReplica.java);AutoPoi 源码 ExcelExportServer.java:198-213 BgPartymatterList.vue:303-307exportConfig)、后端 BgPartymatterController.java:281-287JeecgController.java:62-88:74 service.list:86 DATA_LIST)、AutoPoi ExcelExportServer.java:198-213

P1 - 强烈建议

# 维度 问题描述 证据 位置
1 状态一致性 顶部统计标签(未开始/督办中/已完成)不随筛选、搜索、增删改刷新:搜索无结果/有结果、新增一条、删除一条后,列表数据都在变(总条数 3→4→3 正确变化),但三个统计标签始终不变(全程 未开始 3 / 督办中 0 / 已完成 0),与列表对不上,用户无法判断哪个是当前数据。根因fetchStatusStats 仅在 onMounted 调用一次;searchQuerysearchResethandleSuccess、新增/删除成功回调均未再触发统计刷新。 实测:eng_09_engineer_final.json —— 统计初始/新增后重查后/删除后重查后均为 ['未开始 3',...],而列表总条数 3→4→3events.after_api_add_reload.has_new_row=trueafter_delete.residue=0);eng_07_listdump.json —— 搜索前/搜索无结果后统计不变 BgPartymatterList.vue:100-104(标签渲染)、:446-465fetchStatusStats)、:463(仅 onMounted 调用)、:440-444searchQuery)、:509-513handleSuccess)、:789-796searchReset
2 用户体验/交互 详情弹窗字段"看似可编辑、实际点不动":详情模式下表单上方有一层透明遮罩 .jeecg-form-detail-effect(实测 1100×580 透明 divpointer-events:auto)拦截全部点击,但控件本身未灰化(下拉控件 opacity=1、cursor=pointer、肉眼无只读提示);点「密级」下拉实测不弹出;「确认」按钮被 jee-hidden 隐藏。用户反复点击无反应,误以为系统坏了/自己没点中。根因handleDetaildisableSubmit=true → JFormContainer :disabled 渲染遮罩 + Modal 隐藏确认按钮,但只读态缺视觉表达(控件未置灰、无"只读"标识)。 实测:eng_09_engineer_final.json —— detail_overlay_count=1detail_overlay_style={pointerEvents:'auto', bg:'rgba(0,0,0,0)', 1100×580}detail_select_dd_open=false(点密级下拉不弹)、detail_confirm_visible=falsedetail_enabled_inputs=602_modal.json —— 详情模式 11 只读 / 6 可编辑输入并存;关闭后页面可交互、无残留遮罩 BgPartymatterList.vue:486-490handleDetail)、BgPartymatterModal.vue:2-6jee-hidden)、BgPartymatterForm.vue:3JFormContainer :disabled)、:256disabled=formDisabled

P2 - 建议

# 维度 问题描述 证据 位置
1 反馈 新增成功无 toast:新增提交成功、列表出现新行,但没有任何"保存成功"提示;删除却有"删除成功!",反馈不一致。根因submitFormcreateMessage.success(res.message),后端返回的 res.message 为空串,success() 收到空串不渲染。 实测:eng_09_engineer_final.json 的 API add {"success":true,"message":"添加成功!"}(后端有 message 但前端未取到/为空);12_adddel_final.json —— add 无 toast、delete 有「删除成功!」 BgPartymatterForm.vue:403-411
2 表单校验文案 校验文案与字段名不一致:主办部门字段漏选时,提示「请选择责任部门」,但字段 label 是「主办部门」,用户对不上号。 实测:02_modal.json form_item_errors(含「请选择责任部门」) BgPartymatterForm.vue:232-241validator message 写死"责任部门"
3 表单校验体验 序号字段只读却报「请输入序号」:序号输入框是只读的(自动生成),但必填校验文案是「请输入序号」,用户无法手动消除该错误(实际需回去填"议题序号"触发自动生成)。 实测:02_modal.json07_formmap.json BgPartymatterForm.vue:23-26(只读)+ :228(校验"请输入序号"
4 布局/性能 表格过宽需横向拖动:21 列总宽约 2808px,可视区约 1200px,中部字段(事项目录编码/抄告单编号/密级等)需反复横拖才能看到,看漏字段风险高。 实测:.ant-table-body scrollWidth=2808、clientWidth=1200eng_02_listdata.json / 测量输出) BgPartymatter.data.ts:7-15321 列)
5 可发现性 「完成状态」筛选默认藏在「展开」折叠里:初始工具栏不显示,需点「展开」才出现,首次用户找不到状态筛选。 实测:toggle 文案"展开→收起"04_expand_filter.png BgPartymatterList.vue:39-52toggleSearchStatus 默认 false
6 空态引导 搜索无结果空态只有「暂无数据」,无"换个条件/清除筛选"引导,也无一键清空入口。 实测:eng_09 race_final 空表(03b_search_empty.png BgPartymatterList.vueBasicTable 默认空态)
7 控制台异常 列表页交互期间控制台出现 Invalid prop: type check failed for prop "onChange". Expected Function, got Array<ASelect onChange= [, ]>),以及点击「导出」时 500 触发 Unhandled error during execution of component event handler。前者疑似筛选/搜索组件把多个 handler 合并成数组传给 ASelect(组件 prop 契约不严谨);后者证明导出失败在前端是未处理异常、被静默吞掉。 实测:eng_09_engineer_final.json console19 条:5 个 app-shell Failed to resolve component + 7 条 ASelect onChange + 1 条 500 resource + 1 条 unhandled export handler 控制台证据(eng_09_engineer_final.json);export 相关 BgPartymatterList.vue:303-307

通过项(做得好的地方)

  • 列表刷新正常:新增后手动点「查询」,列表立即出现新行(总条数 3→4);删除后「查询」,行消失(4→3)。列表数据链路(list API + 查询/重置)一致、无残留。
  • 竞态安全:快速连续输入 3 个不同关键词(QA_TEST_ENG_RACE_01 → 督办 → QA_ZZZ_NO_MATCH_RACE,无间隔),最终表格与最后一个关键词一致(0 行)、无旧响应串台/残留渲染,未出现 out-of-order 覆盖。搜索即输即查无竞态问题。
  • 详情弹窗回显完整:详情标题「详情」,19 项字段回显;关闭后页面完全可交互,无残留遮罩/状态污染。
  • 模板下载可用:「下载模板」成功下载 党委会-导入模板.xlsEasyExcel exportXlsHeaders 路径,与走 AutoPoi 的「导出」形成对照——问题只在 AutoPoi 导出,不在模板)。
  • 删除链路完整:行内更多 → 删除 → 二次确认 → 「删除成功!」toast → 列表刷新。新增/删除后列表均刷新。
  • 数据分流正确:党委会(party)/所务会(office)数据严格隔离,不串台。
  • 流程弹窗可用:「再次督办」发起流程弹窗标题/部门预填正确;「查询督办流程」流程列表可打开(引用 QA_REPORT_UX.md 任务 6 实测证据)。
  • 校验覆盖:必填校验能定位到字段;序号自动生成(会议时间+议题序号联动)有效。
  • 导出 0 行场景正常:无数据时导出返回 200(进一步佐证根因只在"有数据的迭代"路径)。

未覆盖项 / 待实测(不列入 P0/P1/P2 判定)

# 项目 原因 / 现有线索
1 多角色/多部门/多密级权限对比(按钮级 v-auth 隐藏、数据权限过滤) 仅 admin 一个账号,无法对比;exportXls 接口有 @RequiresPermissions,前端按钮有 v-auth,但未用第二账号实测不同角色下的可见性/越权
2 「模板校验」「模板导入」真实文件流程(选 Excel → 校验通过/报错提示) headless 无法模拟系统文件选择框;对隐藏 input 塞 .txt 无任何 toast,结果不明确(BgPartymatterList.vue:746-784
3 后端 service.list() 返回不可变集合的具体包装层(是哪个拦截器/配置把 MP 的 selectList 结果变成不可变) 前端侧证据已足够(0 行 200 / ≥1 行 500 / 独立复现),但精确到后端哪个类包装需后端日志/断点确认;已确认 BgPartymatterServiceImpl 为纯 MP ServiceImpllist() 覆盖、JeecgController.exportXls 无包裹、运行时 AutoPoi 为 1.4.11trace 行号与源码逐行吻合)
4 「完成状态」筛选选中后的实际过滤行为(BPM 状态 dict 映射) 未单独实测(筛选在「展开」里,见 P2-5);代码走 JDictSelectTag @change="searchQuery",推断正常

测试过程记录

  • 环境:前端 dev http://127.0.0.1:3100(运行中,未动);后端 :8080/jeecg-boot(真实);登录 admin/123456(mock 登录 + 真实业务接口)。脚本见 qa-tmp/bgpartymatter/scripts/
  • 核心操作与产物
    1. eng_04_trace.py / eng_05_empty_office.py:直接导出抓 500 全量 bodyparty/office)、0 行导出对比 → eng_04_trace.jsoneng_05_empty_office.json0 行 200 / ≥1 行 500)。
    2. eng_07_listdump.py:搜索无结果前后统计标签对比 → eng_07_listdump.json(统计不变)。
    3. eng_08_token2.py:从请求头提取 X-Access-TokenlocalStorage 无 tokentoken 在内存/请求头注入)。
    4. eng_09_engineer_final.py:综合验证(登录 → 列表 → API 新增 → 查询刷新 → 快速搜索竞态 → 详情遮罩 → 导出 → 模板 → API 删除)→ eng_09_engineer_final.json
    5. 复用既有产物:02_modal.json(新增必填校验+详情字段态)、12_adddel_final.json(新增/删除 toast)、05_flow.json(流程弹窗+导出 500)、07_formmap.json(表单字段映射)。
  • 关键网络请求
    • GET /jeecgboot/bgpartymatter/bgPartymatter/list?... → 200(列表,正常)
    • POST /jeecgboot/bgpartymatter/bgPartymatter/add → 200 {"success":true}(新增)
    • DELETE /jeecgboot/bgpartymatter/bgPartymatter/delete?id=... → 200 {"success":true}(删除)
    • GET /jeecgboot/bgpartymatter/bgPartymatter/exportXls?...500(导出,P0
    • GET /jeecgboot/bgpartymatter/bgPartymatter/exportXlsHeaders?... → 200 下载 党委会-导入模板.xls(模板)
  • console 摘要5 条 app-shell Failed to resolve componentAppSearch/Notify/SettingDrawer 等,首页框架级,非本页引入);7 条 ASelect onChange 类型警告(P2-7);1 条 500 resource + 1 条 export 未处理异常(P0 佐证)。
  • 测试数据卫生:本次会话创建 QA_TEST_ENG_RACE_01 ×4(含多次中断运行残留)与既有的 QA_ENG_BISECT_* ×5、清空后测试assacas(office),已全部经删除 API 清理并复核:party/office 列表按 QA_/QA_TEST/QA_ENG 过滤均 0 残留。测试数据一律置于 qa-tmp/bgpartymatter/gitignore),不入库。