guarantee-lsq 2 هفته پیش
والد
کامیت
0aaffd1c73

+ 66 - 0
src/api/report/application-form.js

@@ -250,6 +250,38 @@ export function getWorkHourBySb (parameter) {
 }
 
 /**
+ * 维修工时统计:按月度统计所有设备的单次平均维修工时
+ * parameter: { yearMonth(YYYY-MM 必填), keyword, pageNum, pageSize }
+ * @param parameter
+ * @returns {*}
+ */
+export function getWorkHourByMonth (parameter) {
+  return axios({
+    url: '/report/repair/workhour/month?' + stringify(parameter),
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8'
+    }
+  })
+}
+
+/**
+ * 维修工时统计明细:按月度统计所有设备的单次平均维修工时(某设备/某维修人当月报修单列表)
+ * parameter: { yearMonth(YYYY-MM 必填), repairUserId, sbId }
+ * @param parameter
+ * @returns {*}
+ */
+export function getWorkHourMonthDetail (parameter) {
+  return axios({
+    url: '/report/repair/workhour/month/detail?' + stringify(parameter),
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8'
+    }
+  })
+}
+
+/**
  * 维修工时统计明细:某维修人或某设备已完成维修的报修单列表
  * parameter: { repairUserId, sbId, searchRepairStartTime, searchRepairEndTime }
  * @param parameter
@@ -298,6 +330,40 @@ export function exportWorkHourSb (parameter) {
 }
 
 /**
+ * 维修工时统计导出:按月度统计
+ * parameter: { yearMonth(YYYY-MM 必填), keyword }
+ * @param parameter
+ * @returns {*}
+ */
+export function exportWorkHourMonth (parameter) {
+  return axios({
+    url: '/report/repair/workhour/export/month?' + stringify(parameter),
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8'
+    },
+    responseType: 'blob'
+  })
+}
+
+/**
+ * 维修工时统计明细导出:按月度统计
+ * parameter: { yearMonth(YYYY-MM 必填), sbId, repairUserId }
+ * @param parameter
+ * @returns {*}
+ */
+export function exportWorkHourMonthDetail (parameter) {
+  return axios({
+    url: '/report/repair/workhour/month/export/detail?' + stringify(parameter),
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8'
+    },
+    responseType: 'blob'
+  })
+}
+
+/**
  * 维修工时统计明细导出
  * @param parameter
  * @returns {*}

+ 68 - 29
src/views/report/repairworkhour/RepairWorkHour.vue

@@ -4,6 +4,7 @@
       <a-tabs v-model="activeTab" @change="handleTabChange">
         <a-tab-pane tab="按维修人统计" key="user"></a-tab-pane>
         <a-tab-pane tab="按设备统计" key="sb"></a-tab-pane>
+        <a-tab-pane tab="按月度统计(设备平均维修工时)" key="month"></a-tab-pane>
       </a-tabs>
 
       <div class="table-page-search-wrapper" @keyup.enter="handleSearch">
@@ -19,7 +20,7 @@
                 <a-input v-model="queryParam.keyword" placeholder="请输入设备名称/编号" allow-clear/>
               </a-form-item>
             </a-col>
-            <a-col :md="10" :sm="24">
+            <a-col :md="10" :sm="24" v-if="activeTab !== 'month'">
               <a-form-item label="维修开始时间">
                 <a-range-picker
                   v-model="dateRange"
@@ -28,6 +29,15 @@
                   :placeholder="['开始日期', '结束日期']"/>
               </a-form-item>
             </a-col>
+            <a-col :md="10" :sm="24" v-else>
+              <a-form-item label="统计月份">
+                <a-month-picker
+                  v-model="queryParam.yearMonth"
+                  format="YYYY-MM"
+                  placeholder="选择月份"
+                  style="width: 100%"/>
+              </a-form-item>
+            </a-col>
             <a-col :md="6" :sm="24">
               <span class="table-page-search-submitButtons">
                 <a-button type="primary" @click="handleSearch">查询</a-button>
@@ -43,7 +53,7 @@
       </div>
 
       <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px">
-        <span style="font-weight: 600">{{ chartTitle }}(按总维修工时降序)</span>
+        <span style="font-weight: 600">{{ chartTitle }}(按平均工时降序)</span>
         <span>
           <a-radio-group v-if="activeTab === 'sb'" v-model="chartDim" size="small" style="margin-right: 8px" @change="doRenderChart">
             <a-radio-button value="sb">按设备</a-radio-button>
@@ -90,8 +100,11 @@ import DetailModal from './modules/DetailModal'
 import {
   getWorkHourByUser,
   getWorkHourBySb,
+  getWorkHourByMonth,
   exportWorkHourUser,
   exportWorkHourSb,
+  exportWorkHourMonth,
+  exportWorkHourMonthDetail,
   exportWorkHourDetail
 } from '@/api/report/application-form'
 
@@ -103,12 +116,14 @@ export default {
   },
   data () {
     return {
-      // 当前统计维度:user-按维修人,sb-按设备
+      // 当前统计维度:user-按维修人,sb-按设备,month-按月度统计
       activeTab: 'user',
       // 查询参数
       queryParam: {
         repairUserName: null,
-        keyword: null
+        keyword: null,
+        // 月度统计 Tab 使用:a-month-picker 的 moment 值
+        yearMonth: moment()
       },
       // 维修开始时间范围 默认本月,避免一次性拉取全部历史数据
       dateRange: [moment().startOf('month'), moment().endOf('month')],
@@ -129,7 +144,7 @@ export default {
           ...parameter,
           ...query
         }
-        const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : getWorkHourBySb
+        const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : (this.activeTab === 'month' ? getWorkHourByMonth : getWorkHourBySb)
         return fetchFn(parameter)
           .then(res => {
             return res.data
@@ -140,9 +155,12 @@ export default {
   computed: {
     chartTitle () {
       if (this.activeTab === 'user') {
-        return '维修人工时统计图'
+        return '维修人平均工时统计图'
+      }
+      if (this.activeTab === 'month') {
+        return this.chartDim === 'type' ? '设备类型月度平均工时统计图' : '设备月度平均工时统计图'
       }
-      return this.chartDim === 'type' ? '设备类型工时统计图' : '设备工时统计图'
+      return this.chartDim === 'type' ? '设备类型平均工时统计图' : '设备平均工时统计图'
     },
     rowKey () {
       return this.activeTab === 'user' ? 'repairUserId' : 'sbId'
@@ -208,7 +226,7 @@ export default {
           ...commonColumns
         ]
       }
-      return [
+      const sbColumns = [
         indexColumn,
         {
           title: '设备编号',
@@ -227,6 +245,11 @@ export default {
         },
         ...commonColumns
       ]
+      // 月度统计不展示总停机修复时长
+      if (this.activeTab === 'month') {
+        return sbColumns.filter(c => c.dataIndex !== 'totalDealHours')
+      }
+      return sbColumns
     }
   },
   mounted () {
@@ -241,7 +264,7 @@ export default {
   methods: {
     loadChartData () {
       this.chartLoading = true
-      const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : getWorkHourBySb
+      const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : (this.activeTab === 'month' ? getWorkHourByMonth : getWorkHourBySb)
       const parameter = {
         pageNum: 1,
         pageSize: 500,
@@ -263,8 +286,7 @@ export default {
       if (this.activeTab === 'user') {
         data = this.chartRows.map(r => ({
           name: r.repairUserName || '-',
-          totalRepairHours: Number(r.totalRepairHours || 0),
-          num: Number(r.num || 0)
+          avgRepairHours: Number(r.avgRepairHours || 0)
         }))
       } else if (this.chartDim === 'type') {
         // 按设备类型:前端对按设备全量数据分组汇总,次数/总工时求和,不重复请求后端
@@ -279,18 +301,19 @@ export default {
         })
         data = Object.keys(groupMap).map(key => {
           const item = groupMap[key]
-          item.totalRepairHours = Math.round(item.totalRepairHours * 100) / 100
-          return item
+          // 分组平均工时 = 组内总工时 / 组内次数(保留2位)
+          const avg = item.num ? Math.round((item.totalRepairHours / item.num) * 100) / 100 : 0
+          return { name: item.name, avgRepairHours: avg }
         })
-        data.sort((a, b) => b.totalRepairHours - a.totalRepairHours)
       } else {
         // 设备维度用名称(编号)区分同名设备
         data = this.chartRows.map(r => ({
           name: (r.sbName || '-') + '(' + (r.sbNo || '-') + ')',
-          totalRepairHours: Number(r.totalRepairHours || 0),
-          num: Number(r.num || 0)
+          avgRepairHours: Number(r.avgRepairHours || 0)
         }))
       }
+      // 柱状图为平均工时,统一按平均工时降序
+      data.sort((a, b) => b.avgRepairHours - a.avgRepairHours)
       if (this.chartTop === 'top20' && data.length > 20) {
         data = data.slice(0, 20)
       }
@@ -307,17 +330,14 @@ export default {
         })
         this.chart.data(data)
         this.chart.scale({
-          totalRepairHours: { alias: '总维修工时(小时)', nice: true },
-          num: { alias: '维修次数', nice: true }
+          avgRepairHours: { 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.axis('avgRepairHours', { title: { offset: 40 } })
         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.interval().position('name*avgRepairHours')
         this.chart.interaction('active-region')
         // 全部模式下分类过多时出现横向滚动条,避免柱子过细、标签重叠
         this.chart.option('scrollbar', {
@@ -332,12 +352,20 @@ export default {
         if (this.BaseTool.String.isNotBlank(this.queryParam.repairUserName)) {
           query.repairUserName = this.queryParam.repairUserName
         }
+      } else if (this.activeTab === 'month') {
+        // 月度统计:后端按 yearMonth(YYYY-MM) 转当月起止时间
+        if (this.queryParam.yearMonth) {
+          query.yearMonth = this.queryParam.yearMonth.format('YYYY-MM')
+        }
+        if (this.BaseTool.String.isNotBlank(this.queryParam.keyword)) {
+          query.keyword = this.queryParam.keyword
+        }
       } else {
         if (this.BaseTool.String.isNotBlank(this.queryParam.keyword)) {
           query.keyword = this.queryParam.keyword
         }
       }
-      if (this.dateRange && this.dateRange.length === 2) {
+      if (this.activeTab !== 'month' && this.dateRange && this.dateRange.length === 2) {
         query.searchRepairStartTime = this.dateRange[0].format('YYYY-MM-DD') + ' 00:00:00'
         query.searchRepairEndTime = this.dateRange[1].format('YYYY-MM-DD') + ' 23:59:59'
       }
@@ -358,7 +386,8 @@ export default {
     resetSearchForm () {
       this.queryParam = {
         repairUserName: null,
-        keyword: null
+        keyword: null,
+        yearMonth: moment()
       }
       // 重置后仍默认统计本月
       this.dateRange = [moment().startOf('month'), moment().endOf('month')]
@@ -367,23 +396,26 @@ export default {
     },
     doExport () {
       const parameter = this.buildQuery()
-      const exportFn = this.activeTab === 'user' ? exportWorkHourUser : exportWorkHourSb
+      const exportFn = this.activeTab === 'user' ? exportWorkHourUser : (this.activeTab === 'month' ? exportWorkHourMonth : exportWorkHourSb)
       exportFn(parameter).then(file => {
         this.BaseTool.UPLOAD.downLoadExportExcel(file)
       })
     },
     handleDetail (record) {
       const modal = this.$refs.detailModal
+      const query = this.buildQuery()
       modal.base({
         type: this.activeTab,
         record: record,
-        searchRepairStartTime: this.buildQuery().searchRepairStartTime,
-        searchRepairEndTime: this.buildQuery().searchRepairEndTime
+        yearMonth: query.yearMonth,
+        searchRepairStartTime: query.searchRepairStartTime,
+        searchRepairEndTime: query.searchRepairEndTime
       })
     },
     doExportDetail (record) {
       const parameter = this.buildDetailQuery(record)
-      exportWorkHourDetail(parameter).then(file => {
+      const exportFn = this.activeTab === 'month' ? exportWorkHourMonthDetail : exportWorkHourDetail
+      exportFn(parameter).then(file => {
         this.BaseTool.UPLOAD.downLoadExportExcel(file)
       })
     },
@@ -395,6 +427,13 @@ export default {
         parameter.sbId = record.sbId
       }
       const timeQuery = this.buildQuery()
+      if (this.activeTab === 'month') {
+        // 月度明细导出:传 yearMonth(YYYY-MM),后端转当月起止时间
+        if (timeQuery.yearMonth) {
+          parameter.yearMonth = timeQuery.yearMonth
+        }
+        return parameter
+      }
       if (timeQuery.searchRepairStartTime) {
         parameter.searchRepairStartTime = timeQuery.searchRepairStartTime
       }

+ 13 - 8
src/views/report/repairworkhour/modules/DetailModal.vue

@@ -32,7 +32,7 @@
 </template>
 
 <script>
-import { getWorkHourDetail, exportWorkHourDetail } from '@/api/report/application-form'
+import { getWorkHourDetail, getWorkHourMonthDetail, exportWorkHourDetail, exportWorkHourMonthDetail } from '@/api/report/application-form'
 
 export default {
   name: 'WorkHourDetailModal',
@@ -55,7 +55,7 @@ export default {
           title: '序号',
           dataIndex: 'index',
           checked: true,
-          width: '60px',
+          width: '80px',
           customRender: (text, record, index) => {
             return `${index + 1}`
           }
@@ -63,7 +63,7 @@ export default {
         {
           title: '报修单号',
           checked: true,
-          width: '140px',
+          width: '200px',
           dataIndex: 'no'
         },
         {
@@ -105,14 +105,14 @@ export default {
         {
           title: '维修耗时(小时)',
           checked: true,
-          width: '110px',
+          width: '130px',
           dataIndex: 'repairMinutes',
           scopedSlots: { customRender: 'hours' }
         },
         {
           title: '停机修复时长(小时)',
           checked: true,
-          width: '130px',
+          width: '160px',
           dataIndex: 'dealMinutes',
           scopedSlots: { customRender: 'hours' }
         },
@@ -121,7 +121,6 @@ export default {
           checked: true,
           width: '100px',
           dataIndex: 'status',
-          fixed: 'right',
           scopedSlots: { customRender: 'status' }
         }
       ]
@@ -143,6 +142,10 @@ export default {
         this.queryParam.sbId = record.sbId
         this.modalTitle = '维修工单明细 - ' + (record.sbName || record.sbNo || '')
       }
+      // 月度统计:传 yearMonth(YYYY-MM),后端转当月起止时间
+      if (params.yearMonth) {
+        this.queryParam.yearMonth = params.yearMonth
+      }
       if (params.searchRepairStartTime) {
         this.queryParam.searchRepairStartTime = params.searchRepairStartTime
       }
@@ -153,7 +156,8 @@ export default {
     },
     loadData () {
       this.loading = true
-      getWorkHourDetail(this.queryParam)
+      const fetchFn = this.type === 'month' ? getWorkHourMonthDetail : getWorkHourDetail
+      fetchFn(this.queryParam)
         .then(res => {
           this.data = res.data || []
         })
@@ -166,7 +170,8 @@ export default {
     },
     doExportDetail () {
       this.confirmLoading = true
-      exportWorkHourDetail(this.queryParam)
+      const fetchFn = this.type === 'month' ? exportWorkHourMonthDetail : exportWorkHourDetail
+      fetchFn(this.queryParam)
         .then(file => {
           this.BaseTool.UPLOAD.downLoadExportExcel(file)
         })