| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- <template>
- <div class="page-header-index-wide">
- <a-card :bordered="false">
- <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-tabs>
- <div class="table-page-search-wrapper" @keyup.enter="handleSearch">
- <a-form layout="inline">
- <a-row :gutter="48">
- <a-col :md="8" :sm="24" v-if="activeTab === 'user'">
- <a-form-item label="维修人">
- <a-input v-model="queryParam.repairUserName" placeholder="请输入维修人姓名" allow-clear/>
- </a-form-item>
- </a-col>
- <a-col :md="8" :sm="24" v-else>
- <a-form-item label="设备">
- <a-input v-model="queryParam.keyword" placeholder="请输入设备名称/编号" allow-clear/>
- </a-form-item>
- </a-col>
- <a-col :md="10" :sm="24">
- <a-form-item label="维修开始时间">
- <a-range-picker
- v-model="dateRange"
- format="YYYY-MM-DD"
- style="width: 100%"
- :placeholder="['开始日期', '结束日期']"/>
- </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>
- <a-button style="margin-left: 8px" @click="resetSearchForm">重置</a-button>
- </span>
- </a-col>
- </a-row>
- </a-form>
- </div>
- <div class="table-operator">
- <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">{{ 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>
- <a-radio-button value="type">按设备类型</a-radio-button>
- </a-radio-group>
- <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>
- </span>
- </div>
- <a-spin :spinning="chartLoading">
- <div :id="chartContainerId" style="min-height: 400px"></div>
- </a-spin>
- <s-table
- ref="table"
- :key="activeTab"
- size="default"
- :rowKey="rowKey"
- :columns="columns"
- :data="loadData"
- showPagination="auto"
- >
- <span slot="action" slot-scope="record">
- <template>
- <a @click="handleDetail(record)">查看明细</a>
- <a-divider type="vertical"/>
- <a @click="doExportDetail(record)">导出明细</a>
- </template>
- </span>
- </s-table>
- </a-card>
- <detail-modal ref="detailModal"/>
- </div>
- </template>
- <script>
- import { STable } from '@/components'
- import { Chart } from '@antv/g2'
- import moment from 'moment'
- import DetailModal from './modules/DetailModal'
- import {
- getWorkHourByUser,
- getWorkHourBySb,
- exportWorkHourUser,
- exportWorkHourSb,
- exportWorkHourDetail
- } from '@/api/report/application-form'
- export default {
- name: 'RepairWorkHourReport',
- components: {
- STable,
- DetailModal
- },
- data () {
- return {
- // 当前统计维度:user-按维修人,sb-按设备
- activeTab: 'user',
- // 查询参数
- queryParam: {
- repairUserName: null,
- keyword: null
- },
- // 维修开始时间范围 默认本月,避免一次性拉取全部历史数据
- dateRange: [moment().startOf('month'), moment().endOf('month')],
- // 图表
- chart: null,
- chartLoading: false,
- chartContainerId: 'workHourChartContainer',
- // 图表展示范围:top20-前20名,all-全部(数据量大时默认前20,防止柱子过细/标签重叠)
- chartTop: 'top20',
- // 图表聚合维度(仅按设备统计Tab):sb-按设备,type-按设备类型(前端对全量数据分组)
- chartDim: 'sb',
- // 图表全量数据缓存,切换前20/全部时不重复请求
- chartRows: [],
- // 加载数据方法 必须为 Promise 对象
- loadData: parameter => {
- const query = this.buildQuery()
- parameter = {
- ...parameter,
- ...query
- }
- const fetchFn = this.activeTab === 'user' ? getWorkHourByUser : getWorkHourBySb
- return fetchFn(parameter)
- .then(res => {
- return res.data
- })
- }
- }
- },
- computed: {
- chartTitle () {
- if (this.activeTab === 'user') {
- return '维修人工时统计图'
- }
- return this.chartDim === 'type' ? '设备类型工时统计图' : '设备工时统计图'
- },
- rowKey () {
- return this.activeTab === 'user' ? 'repairUserId' : 'sbId'
- },
- columns () {
- const indexColumn = {
- title: '序号',
- checked: true,
- dataIndex: 'index',
- width: '70px',
- customRender: (text, record, index) => {
- const pagination = this.$refs.table && this.$refs.table.localPagination
- if (pagination) {
- return `${(pagination.current - 1) * pagination.pageSize + index + 1}`
- }
- return `${index + 1}`
- }
- }
- const hourRender = (text) => {
- return this.BaseTool.Object.isBlank(text) ? '0.00' : Number(text).toFixed(2)
- }
- const commonColumns = [
- {
- title: '维修次数',
- checked: true,
- dataIndex: 'num'
- },
- {
- title: '总维修工时(小时)',
- checked: true,
- dataIndex: 'totalRepairHours',
- customRender: hourRender
- },
- {
- title: '平均工时(小时)',
- checked: true,
- dataIndex: 'avgRepairHours',
- customRender: hourRender
- },
- {
- title: '总停机修复时长(小时)',
- checked: true,
- dataIndex: 'totalDealHours',
- customRender: hourRender
- },
- {
- title: '操作',
- checked: true,
- key: 'action',
- width: '180px',
- align: 'center',
- scopedSlots: { customRender: 'action' }
- }
- ]
- if (this.activeTab === 'user') {
- return [
- indexColumn,
- {
- title: '维修人',
- checked: true,
- dataIndex: 'repairUserName'
- },
- ...commonColumns
- ]
- }
- return [
- indexColumn,
- {
- title: '设备编号',
- checked: true,
- dataIndex: 'sbNo'
- },
- {
- title: '设备名称',
- checked: true,
- dataIndex: 'sbName'
- },
- {
- title: '设备类型',
- checked: true,
- dataIndex: 'sbTypeName'
- },
- ...commonColumns
- ]
- }
- },
- 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) || []
- // 保存原始行,按图表维度分组/截取统一在 doRenderChart 处理
- this.chartRows = rows
- this.doRenderChart()
- })
- .finally(() => {
- this.chartLoading = false
- })
- },
- doRenderChart () {
- let data = []
- if (this.activeTab === 'user') {
- data = this.chartRows.map(r => ({
- name: r.repairUserName || '-',
- totalRepairHours: Number(r.totalRepairHours || 0),
- num: Number(r.num || 0)
- }))
- } else if (this.chartDim === 'type') {
- // 按设备类型:前端对按设备全量数据分组汇总,次数/总工时求和,不重复请求后端
- const groupMap = {}
- this.chartRows.forEach(r => {
- const key = r.sbTypeName || '未分类'
- if (!groupMap[key]) {
- groupMap[key] = { name: key, totalRepairHours: 0, num: 0 }
- }
- groupMap[key].totalRepairHours += Number(r.totalRepairHours || 0)
- groupMap[key].num += Number(r.num || 0)
- })
- data = Object.keys(groupMap).map(key => {
- const item = groupMap[key]
- item.totalRepairHours = Math.round(item.totalRepairHours * 100) / 100
- return item
- })
- 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)
- }))
- }
- 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') {
- if (this.BaseTool.String.isNotBlank(this.queryParam.repairUserName)) {
- query.repairUserName = this.queryParam.repairUserName
- }
- } else {
- if (this.BaseTool.String.isNotBlank(this.queryParam.keyword)) {
- query.keyword = this.queryParam.keyword
- }
- }
- if (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'
- }
- return query
- },
- handleTabChange () {
- // 切换维度后图表聚合维度恢复按设备
- this.chartDim = 'sb'
- 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 = [moment().startOf('month'), moment().endOf('month')]
- this.$refs.table.refresh(true)
- this.loadChartData()
- },
- doExport () {
- const parameter = this.buildQuery()
- const exportFn = this.activeTab === 'user' ? exportWorkHourUser : exportWorkHourSb
- exportFn(parameter).then(file => {
- this.BaseTool.UPLOAD.downLoadExportExcel(file)
- })
- },
- handleDetail (record) {
- const modal = this.$refs.detailModal
- modal.base({
- type: this.activeTab,
- record: record,
- searchRepairStartTime: this.buildQuery().searchRepairStartTime,
- searchRepairEndTime: this.buildQuery().searchRepairEndTime
- })
- },
- doExportDetail (record) {
- const parameter = this.buildDetailQuery(record)
- exportWorkHourDetail(parameter).then(file => {
- this.BaseTool.UPLOAD.downLoadExportExcel(file)
- })
- },
- buildDetailQuery (record) {
- const parameter = {}
- if (this.activeTab === 'user') {
- parameter.repairUserId = record.repairUserId
- } else {
- parameter.sbId = record.sbId
- }
- const timeQuery = this.buildQuery()
- if (timeQuery.searchRepairStartTime) {
- parameter.searchRepairStartTime = timeQuery.searchRepairStartTime
- }
- if (timeQuery.searchRepairEndTime) {
- parameter.searchRepairEndTime = timeQuery.searchRepairEndTime
- }
- return parameter
- }
- }
- }
- </script>
- <style lang="less" scoped>
- </style>
|