testProjectConfiguration性能改造操作手册.md 12 KB

testProjectConfiguration 页面性能改造操作手册

适用范围:前端 beiHai-ui / 后端 beiHai-lims 改造目标:页面打开 20 秒 → 2~3 秒以内 说明:本手册只写「怎么改」,每个改动都给出文件路径、行号、改前/改后代码。按编号顺序执行即可,做完 1~3 步就能砍掉绝大部分耗时。


📋 改动清单总览

步骤 改动 收益 风险
1 3 个弹窗子组件懒加载(v-if) 砍掉约 14 个首屏请求(最大收益) 中(需同步改子组件 watch)
2 删除死代码 gettestItemNameTypeList 少 1 个全量请求 极低
3 getList() 改为打开弹窗时才调用 首屏少 1 个 500 条请求 极低
4 勾选/点击行加防抖 避免子表请求风暴 低
5 子表 pageSize 990 → 50 减少每次交互的数据量 低
6 表格瘦身(去 sortable/show-summary) 减少渲染开销 低(视觉略有变化)
7 后端补索引(必须做) 生产库数据量大时兜底 低(上线前 DBA 评估)
8 后端字典查询 pageSize 调小 减少全量传输 低
9 后端关闭 SQL 日志输出 减少日志 IO 极低

⚠️ 先备份再动手:每个文件修改前先复制一份,例如 testProjectConfiguration.vue.bak。改完用 npm run dev 起本地验证。


第 1 步:3 个弹窗子组件懒加载(核心改动,必须做)

弹窗子组件 alertComponents / alertComponents3 / alertComponents4 目前页面一打开就被实例化,各自 mounted 里发 5~7 个请求。改成「第一次打开弹窗时才创建组件」。

1.1 父组件加 v-if

文件:src/views/standardManagement/components/testProjectConfiguration/testProjectConfiguration.vue 位置:第 320~323 行

改前:

<div is="alertComponets" :showFlag="showFlag" :Params="Params" @refresh='refresh'></div>
<!-- <div is="alertComponets2" :showFlag="showFlag2" :Params="Params2" @refresh='refresh2'></div> -->
<div is="alertComponets3" :showFlag="showFlag3" :Params="Params3" @refresh='refresh2'></div>
<div is="alertComponets4" :showFlag="showFlag4" :Params="Params5" :Params2="Params4" @refresh='refresh3'></div>

改后:

<div v-if="showFlag" is="alertComponets" :showFlag="showFlag" :Params="Params" @refresh='refresh'></div>
<!-- <div v-if="showFlag2" is="alertComponets2" :showFlag="showFlag2" :Params="Params2" @refresh='refresh2'></div> -->
<div v-if="showFlag3" is="alertComponets3" :showFlag="showFlag3" :Params="Params3" @refresh='refresh2'></div>
<div v-if="showFlag4" is="alertComponets4" :showFlag="showFlag4" :Params="Params5" :Params2="Params4" @refresh='refresh3'></div>

1.2 三个子组件 watch 加 immediate(⚠️ 必须同步改,否则弹窗打不开)

原因:子组件通过 watch: { showFlag } 打开弹窗。加 v-if 后,组件首次创建时 showFlag 已经是 true,watch 默认不触发首次值,弹窗会打不开。必须加 immediate: true。

文件 1:src/views/standardManagement/components/testProjectConfiguration/alertComponents.vue 位置:第 456~459 行

改前:

watch: {
  showFlag (arg) {
    this.dialogTableVisible = true;
  }
},

改后:

watch: {
  showFlag: {
    handler (arg) {
      this.dialogTableVisible = true;
    },
    immediate: true
  }
},

文件 2:alertComponents3.vue,第 412~416 行 —— 同样改法(结构一致,照上面抄)。

文件 3:alertComponents4.vue,第 171~189 行 —— 同样改法(注意它 watch 里可能还有别的逻辑,只把 showFlag 这个 handler 包成对象 + immediate: true)。

1.3 验证

npm run dev
  1. 打开测试项目配置页 → 打开浏览器 DevTools Network,刷新页面
  2. 观察首屏请求数量:应从 ~19 个降到 ~4 个(只剩父组件的字典 + 主表分页 + 3 个 addScreen)
  3. 点击「新增」按钮 → 弹窗应正常打开,此时才出现弹窗的字典请求(正常现象)
  4. 连续开/关弹窗 2~3 次,确认不报错

第 2 步:删除死代码 gettestItemNameTypeList

该请求拉取全部测试项目,结果存入 testItemNameType,但模板里从未使用(页面下拉用的是 itemTypeNameType,来自另一个接口)。纯浪费。

文件:testProjectConfiguration.vue

改动 2.1:删掉第 422 行的调用

this.gettestItemNameTypeList();   // ← 删除这一行

改动 2.2:删掉第 430~435 行的方法定义

gettestItemNameTypeList () {
   this.axios.get('pass/baseManagement/v1/limsstdtestitems/'+ '?validFlag=1')
        .then(res => {
          this.testItemNameType = res.data.list;
        })
},

(可一并删掉 data 里第 395 行的 testItemNameType: [],不删也无害)


第 3 步:getList() 改为弹窗打开时才调用

getList() 查询分析项目(pageSize=500),数据只在「新增分析项目」弹窗里用,但目前页面一打开就拉。

文件:testProjectConfiguration.vue

改动 3.1:删掉第 418 行的 mounted 调用

this.getList()   // ← 删除这一行

改动 3.2:在 addData2()(第 626~633 行)里补上调用

改前:

addData2 () {
  let _this = this;
  if (_this.multipleSelection.length !== 1) {
    this.$message.warning('请选择一条测试项目数据!');
    return
  }
  this.dialogTableVisible = true
},

改后:

addData2 () {
  let _this = this;
  if (_this.multipleSelection.length !== 1) {
    this.$message.warning('请选择一条测试项目数据!');
    return
  }
  this.getList();          // ← 新增:弹窗打开时才加载分析项目列表
  this.dialogTableVisible = true
},

第 4 步:勾选/点击行加防抖(可选但建议)

当前点击/勾选任意一行,立刻触发 2 个 pageSize=990 的子表查询;多选时连续触发。

文件:testProjectConfiguration.vue 位置:第 799~807 行(handleSelectionChange)、第 846~858 行(handleCurrentChange)

改法:把两个方法里的 getDataList2/getDataList3 调用替换为防抖调用,并新增一个防抖方法。

handleSelectionChange 改后:

handleSelectionChange (val) {
  this.multipleSelection = val;
  if (val.length > 0) {
    this.testItemNo = val[val.length-1].testItemNo
    this.curItemTypeCode = val[val.length-1].itemTypeCode;
    this.debounceLoadSub(this.testItemNo);
  }
},

handleCurrentChange 改后(顺手修复 val 为 null 时的报错):

handleCurrentChange (val) {
  this.curItemTypeCode = ''
  if (val){
    this.curItemTypeCode = val.itemTypeCode;
  }
  if (!val || val.testItemNo === null) {
    this.testItemNo = '';
  } else {
    this.testItemNo = val.testItemNo;
  }
  this.debounceLoadSub(this.testItemNo);
},

在 methods 里新增防抖方法(放在 getDataList2 前面即可):

debounceLoadSub (testItemNo) {
  clearTimeout(this._subTimer);
  this._subTimer = setTimeout(() => {
    this.getDataList2(testItemNo);
    this.getDataList3(testItemNo);
  }, 300);
},

第 5 步:子表 pageSize 990 → 50,恢复分页

文件:testProjectConfiguration.vue 位置:第 370~379 行

改前:

page2: {
  pageSize: 990,
  pageNum: 1,
  totalPage: 0
},
page3: {
  pageSize: 990,
  pageNum: 1,
  totalPage: 0
},

改后:

page2: {
  pageSize: 50,
  pageNum: 1,
  totalPage: 0
},
page3: {
  pageSize: 50,
  pageNum: 1,
  totalPage: 0
},

建议同时恢复被注释的分页组件:第 136~141 行有被注释的 <el-pagination>(数据是 page2),恢复它并复制一份给 page3 的表格,这样子表才能翻页查看完整数据(因为 pageSize 变小了)。


第 6 步:表格瘦身(降低渲染开销,工作量中等)

三个表格共约 69 列,每列都带 sortable + show-overflow-tooltip,且都开 show-summary 合计行 + :icore-filter-flag。show-overflow-tooltip 会给每个单元格注册 tooltip 实例,50 行 × 25 列 = 1250 个,是渲染大头。

6.1 去掉每列 sortable(只保留 1~2 个关键列)

主表(第 41~65 行)、分析项目表(第 98~133 行)、方法标准表(约第 163 行起):批量把每列开头的 sortable 删掉。

示例:

<!-- 改前 -->
<el-table-column sortable :show-overflow-tooltip="true" min-width="120px" prop="testItemNo" label="测试项目编号" align="center"></el-table-column>
<!-- 改后(保留 testItemNo / testItemName 两列的 sortable,其余删除) -->
<el-table-column sortable :show-overflow-tooltip="true" min-width="120px" prop="testItemNo" label="测试项目编号" align="center"></el-table-column>
<el-table-column :show-overflow-tooltip="true" min-width="120px" prop="testItemName" label="测试项目名称" align="center"></el-table-column>

6.2 去掉 show-summary 合计行

getSummaries 只统计了「合计 + 行数」,价值低。三处表格的 :summary-method="getSummaries" show-summary(第 38、94、160 行)直接删除,getSummaries 方法(第 436~448 行)也可删。

6.3 (可选)el-tabs 加 lazy

第 76 行 <el-tabs v-model="activeName" type="card" @tab-click="handleClick"> 改为 <el-tabs v-model="activeName" type="card" @tab-click="handleClick" lazy>,让非激活 tab 延迟渲染。


第 7 步:后端补索引(生产环境必须做)

文件:后端库执行 DDL(需 DBA / 维护窗口评估执行,仅 SELECT 查询无风险)

-- 子表按 TEST_ITEM_NO 查询是高频路径,当前全表扫描
CREATE INDEX IDX_TID_TESTITEMNO  ON LIMS_STD_TEST_ITEM_D (TEST_ITEM_NO);
CREATE INDEX IDX_TMATCH_TESTITEMNO ON LIMS_STD_TEST_MATCH (TEST_ITEM_NO);
-- 两个主表 ORDER BY CREATE_TIME DESC 无索引,每次全表排序
CREATE INDEX IDX_TITEM_CREATETIME ON LIMS_STD_TEST_ITEM (CREATE_TIME);
CREATE INDEX IDX_ANLY_CREATETIME ON LIMS_STD_ANLY_ITEM (CREATE_TIME);
-- 列表页常见过滤条件
CREATE INDEX IDX_TITEM_VALIDFLAG  ON LIMS_STD_TEST_ITEM (VALID_FLAG);

第 8 步:字典查询 pageSize 调小

子组件里的全量字典查询(pageSize: 9999 / 99999)虽然做了第 1 步后只在打开弹窗时发,但值仍过大,建议调小:

  • alertComponents.vue 第 312 行:pageSize:9999 → pageSize:500(规则下拉,271 条数据)
  • alertComponents.vue 第 340 行:pageSize:99999 → pageSize:100(岗位下拉,仅 12 条)
  • alertComponents3.vue 第 315 / 340 / 355 / 367 行:pageSize:9999 → pageSize:500(分析项目 / 单位 / 修约规则 / 公式)

第 9 步:后端关闭 SQL 日志输出

文件:beiHai-lims/lims-base/src/main/resources/application.properties

改前:

logging.level.com.steerinfo=DEBUG
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

改后:

logging.level.com.steerinfo=INFO
mybatis.configuration.log-impl=org.apache.ibatis.logging.nologging.NoLoggingImpl

注意:三个模块(lims-base / lims-api / lims-test)可能都有各自的 application.properties,生产环境每个都改。


✅ 验收标准

改完 1~3 步后:

指标 改前 改后预期
首屏请求数 ~19 个 ~4 个
页面渲染完成 ~20 秒 2~3 秒
勾选/点击行 2 个 990 条请求 防抖后 2 个 50 条请求

验证方法:

  1. DevTools Network 面板看首屏请求数量和耗时分布(改前先录一份对比)
  2. 若首屏仍有慢请求,看「Waiting (TTFB)」高还是「Content Download」高,分别对应后端慢 / 响应体大
  3. 生产库验证前,先确认第 7 步索引已执行

⚠️ 注意事项汇总

  1. 第 1 步的 1.2 是强制配套:只加 v-if 不改 watch,弹窗会打不开(watch 不触发首次值)
  2. 先备份:cp testProjectConfiguration.vue testProjectConfiguration.vue.bak(三个子组件同理)
  3. 第 6 步表格瘦身是「锦上添花」,如果 1~5 步做完首屏已经达标,可暂缓
  4. 索引 DDL 建议在低峰期由 DBA 执行,先 EXPLAIN 验证子表查询从 FULL SCAN 变为 INDEX RANGE SCAN
  5. 所有前端改动都在 src/views/standardManagement/components/testProjectConfiguration/ 目录内,后端改动在 beiHai-lims,互不冲突