Przeglądaj źródła

feat(report): 添加维修工时统计图表功能

- 在维修工时统计页面添加了柱状图和折线图展示功能
- 实现了按总维修工时降序排列的图表显示
- 添加了前20名和全部数据的切换选项
- 集成了AntV G2图表库进行数据可视化
- 优化了默认日期范围为当月避免历史数据加载
- 添加了图表数据缓存机制提升切换性能
- 实现了图表的滚动条功能处理大量分类数据
- 添加了图表销毁清理逻辑防止内存泄漏
dazhaxie 16 godzin temu
rodzic
commit
f6e9f0d64b
1 zmienionych plików z 97 dodań i 3 usunięć
  1. 97 3
      src/views/report/repairworkhour/RepairWorkHour.vue

+ 97 - 3
src/views/report/repairworkhour/RepairWorkHour.vue

@@ -42,6 +42,17 @@
         <a-button type="primary" icon="download" @click="doExport">导出</a-button>
       </div>
 
+      <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px">
+        <span style="font-weight: 600">{{ activeTab === 'user' ? '维修人工时统计图' : '设备工时统计图' }}(按总维修工时降序)</span>
+        <a-radio-group v-model="chartTop" size="small" @change="doRenderChart">
+          <a-radio-button value="top20">前20名</a-radio-button>
+          <a-radio-button value="all">全部</a-radio-button>
+        </a-radio-group>
+      </div>
+      <a-spin :spinning="chartLoading">
+        <div :id="chartContainerId" style="min-height: 400px"></div>
+      </a-spin>
+
       <s-table
         ref="table"
         size="default"
@@ -66,6 +77,8 @@
 
 <script>
 import { STable } from '@/components'
+import { Chart } from '@antv/g2'
+import moment from 'moment'
 import DetailModal from './modules/DetailModal'
 import {
   getWorkHourByUser,
@@ -90,8 +103,16 @@ export default {
         repairUserName: null,
         keyword: null
       },
-      // 维修开始时间范围
-      dateRange: [],
+      // 维修开始时间范围 默认本月,避免一次性拉取全部历史数据
+      dateRange: [moment().startOf('month'), moment().endOf('month')],
+      // 图表
+      chart: null,
+      chartLoading: false,
+      chartContainerId: 'workHourChartContainer',
+      // 图表展示范围:top20-前20名,all-全部(数据量大时默认前20,防止柱子过细/标签重叠)
+      chartTop: 'top20',
+      // 图表全量数据缓存,切换前20/全部时不重复请求
+      chartRows: [],
       // 加载数据方法 必须为 Promise 对象
       loadData: parameter => {
         const query = this.buildQuery()
@@ -188,7 +209,76 @@ export default {
       ]
     }
   },
+  mounted () {
+    this.$nextTick(() => {
+      this.loadChartData()
+    })
+  },
+  beforeDestroy () {
+    this.chart && this.chart.destroy()
+    this.chart = null
+  },
   methods: {
+    loadChartData () {
+      this.chartLoading = true
+      const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : getWorkHourBySb
+      const parameter = {
+        pageNum: 1,
+        pageSize: 500,
+        ...this.buildQuery()
+      }
+      fetchFn(parameter)
+        .then(res => {
+          const rows = (res.data && res.data.rows) || []
+          // 后端已按总维修工时降序,映射后即可直接取前20
+          this.chartRows = rows.map(r => ({
+            name: this.activeTab === 'user' ? (r.repairUserName || '-') : (r.sbName || r.sbNo || '-'),
+            totalRepairHours: Number(r.totalRepairHours || 0),
+            num: Number(r.num || 0)
+          }))
+          this.doRenderChart()
+        })
+        .finally(() => {
+          this.chartLoading = false
+        })
+    },
+    doRenderChart () {
+      let data = this.chartRows
+      if (this.chartTop === 'top20' && data.length > 20) {
+        data = data.slice(0, 20)
+      }
+      this.chart && this.chart.destroy()// 防止重复渲染
+      this.chart = null
+      if (!data.length) {
+        return
+      }
+      this.$nextTick(() => {
+        this.chart = new Chart({
+          container: this.chartContainerId,
+          autoFit: true,
+          height: 400
+        })
+        this.chart.data(data)
+        this.chart.scale({
+          totalRepairHours: { alias: '总维修工时(小时)', nice: true },
+          num: { alias: '维修次数', nice: true }
+        })
+        this.chart.axis('name', { label: { autoRotate: true, autoHide: false } })
+        this.chart.axis('totalRepairHours', { title: { offset: 40 } })
+        this.chart.axis('num', { title: { offset: 40 }, grid: null })
+        this.chart.tooltip({ shared: true, showCrosshairs: false })
+        this.chart.legend({ position: 'top-right' })
+        this.chart.interval().position('name*totalRepairHours')
+        this.chart.line().position('name*num').color('#faad14').size(2)
+        this.chart.point().position('name*num').color('#faad14').size(3).shape('circle')
+        this.chart.interaction('active-region')
+        // 全部模式下分类过多时出现横向滚动条,避免柱子过细、标签重叠
+        this.chart.option('scrollbar', {
+          type: 'horizontal'
+        })
+        this.chart.render()
+      })
+    },
     buildQuery () {
       const query = {}
       if (this.activeTab === 'user') {
@@ -209,18 +299,22 @@ export default {
     handleTabChange () {
       this.$nextTick(() => {
         this.$refs.table.refresh(true)
+        this.loadChartData()
       })
     },
     handleSearch () {
       this.$refs.table.refresh(true)
+      this.loadChartData()
     },
     resetSearchForm () {
       this.queryParam = {
         repairUserName: null,
         keyword: null
       }
-      this.dateRange = []
+      // 重置后仍默认统计本月
+      this.dateRange = [moment().startOf('month'), moment().endOf('month')]
       this.$refs.table.refresh(true)
+      this.loadChartData()
     },
     doExport () {
       const parameter = this.buildQuery()