You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
9.6 KiB

<template>
<div class="container">
<div class="left-bar">
<el-card>
<el-radio-group v-model="pickedType" size="small" @change="getData">
<el-radio v-for="item in types" :key="item.value" :label="item.value" border>{{ item.name }}</el-radio>
</el-radio-group>
</el-card>
</div>
<card-container class="right-content">
<div class="select">
<el-select size="small" v-model="select.department_id" clearable placement="发起科室">
<el-option v-for="item in departments" :key="item.id" :value="item.id" :label="item.name"></el-option>
</el-select>
<el-date-picker
:value="select.date_range ? select.date_range.split('~') : []"
type="daterange"
align="right"
size="small"
unlink-panels
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
@input="e => select.date_range = e ? e.join('~') : ''">
</el-date-picker>
<el-button size="small" icon="el-icon-search" type="primary" @click="getData">搜索</el-button>
</div>
<div class="charts">
<div :style="{ visibility: pickedType === 'mixed' ? 'hidden' : '' }" id="pie-chart"></div>
<div :style="{ visibility: pickedType === 'mixed' ? '' : 'hidden' }" id="bar-chart"></div>
</div>
<div class="list">
<h4>数据明细</h4>
<vxe-table
:data="tableData">
<vxe-column field="name" :title="tableTitle"></vxe-column>
<vxe-column field="value" title="数量"></vxe-column>
<vxe-column v-if="pickedType === 'custom-model'" field="percent" title="占比" :formatter="({ cellValue }) => cellValue + '%'"></vxe-column>
</vxe-table>
</div>
</card-container>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { statistics } from '@/api/flow'
import { departmentListNoAuth } from '@/api/common'
import { debounce } from '@/utils'
export default {
data() {
return {
departments: [],
pickedType: 'custom-model',
types: [
{
value: 'custom-model',
name: '流程模块'
},
{
value: 'avg-time',
name: '平均办结时长'
},
{
value: 'mixed',
name: '流程模块+发起科室'
},
{
value: 'department',
name: '发起科室'
},
],
select: {
date_range: '',
department_id: ''
},
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
}]
},
tableData: [],
pieChart: null,
barChart: null,
$resize: null
}
},
created() {
this.getDepartments()
},
mounted() {
this.init()
this.getData()
this.$resize = debounce(() => {
if (this.pieChart) {
this.pieChart.resize()
}
if (this.barChart) {
this.barChart.resize()
}
}, 100)
window.addEventListener('resize', this.$resize)
},
beforeDestroy() {
window.removeEventListener('resize',this.$resize)
},
methods: {
init() {
this.pieChart = echarts.init(document.querySelector("#pie-chart"))
this.barChart = echarts.init(document.querySelector("#bar-chart"))
},
setOption(type,data) {
if (type === 'pie') {
this.pieChart.setOption(this.getPieOption(data))
}
if (type === 'bar') {
this.barChart.setOption(this.getBarOption(data))
}
},
getBarOption({ customModels, data, departments }) {
const title = `按${this.types.find(i => i.value === this.pickedType)?.name}统计`
let xAxis = []
let series = departments.map(dept => ({
name: dept.name,
type: 'bar',
data: []
}))
for(let key in data) {
let customModelId = Number(key.split('_')?.at(-1) ?? 0)
if(customModelId) {
xAxis.push(customModels.find(j => j.id === customModelId)?.name)
let deptData = data[key]
Object.keys(deptData).forEach((deptKey, index) => {
series[index].data.push(deptData[deptKey])
})
}
}
return {
title: {
text: title,
left: 'left'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
show: true
}
}
},
toolbox: {
show: true,
feature: {
mark: { show: true },
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
calculable: true,
legend: {
show: true,
itemGap: 5,
top: '8%',
left: '0%',
itemHeight: 8,
itemWidth: 16,
},
grid: {
top: '20%',
left: '1%',
right: '1%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: xAxis
}
],
yAxis: [
{
type: 'value',
name: '数量',
}
],
dataZoom: [
{
show: true,
start: 94,
end: 100
},
{
type: 'inside',
start: 94,
end: 100
}
],
series
}
},
getPieOption(data) {
const title = `按${this.types.find(i => i.value === this.pickedType)?.name}统计`
return {
title: {
text: title,
left: 'left'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
show: false,
},
series: [
{
name: title,
type: 'pie',
radius: ['32%','55%'],
center: ['50%', '50%'],
padAngle: 1,
itemStyle: {
borderRadius: 10
},
data,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
},
async getData() {
try {
const res = await statistics(this.pickedType, this.select)
console.log(res)
switch (this.pickedType) {
case 'custom-model':
this.setOption('pie', res.res)
this.tableData = res.res
break
case 'avg-time':
this.setOption('pie', res.res)
this.tableData = res.res
break
case 'department':
this.setOption('pie', res.res)
this.tableData = res.res
break
case 'mixed':
this.setOption('bar', res.res)
const { data, departments } = res.res
this.tableData = departments.map(dept => ({
name: dept.name,
value: (() => {
let total = 0
for (let key in data) {
total += data[key][`department_${dept.id}`] ?? 0
}
return total
})()
}))
break
}
} catch (e) {
console.error(e)
}
},
async getDepartments() {
try {
this.departments = await departmentListNoAuth()
} catch (e) {
console.error(e)
}
}
},
computed: {
tableTitle() {
switch (this.pickedType) {
case 'custom-model':
return '流程模块'
case 'avg-time':
return '办结时长'
case 'department':
return '发起部门'
case 'mixed':
return '发起部门'
}
}
},
}
</script>
<style scoped lang="scss">
.container {
display: flex;
.left-bar {
flex-basis: 22%;
}
.right-content {
flex: 1;
margin-left: 20px;
}
.select {
& > * + * {
margin-left: 8px;
}
}
.charts {
margin-top: 20px;
width: 100%;
height: 500px;
position: relative;
#pie-chart, #bar-chart{
width: 100%;
height: 500px;
position: absolute;
top: 0;
left: 0;
}
}
}
@media (max-width: 768px) {
.container {
display: inherit;
.right-content {
margin-left: 0;
margin-top: 10px;
}
}
.select {
display: flex;
flex-direction: column;
& > * {
width: 100%;
}
& > * + * {
flex: 1;
margin-left: 0!important;
margin-top: 4px;
}
}
}
::v-deep .el-radio.is-bordered+.el-radio.is-bordered {
margin-left: 0;
margin-top: 6px;
}
::v-deep .el-radio.is-bordered {
display: block;
width: 100%;
}
</style>