|
@@ -0,0 +1,785 @@
|
|
|
+<template>
|
|
|
+ <el-container class="defect-container">
|
|
|
+ <el-header class="defect-main" style="height: auto;">
|
|
|
+ <el-form :model="defectForm" class="demo-form-inline" :inline="true">
|
|
|
+ <el-form-item label="时间:">
|
|
|
+ <div class="date-select">
|
|
|
+ <span :class="[dateType==='week'?'date-active':'']" class="date-item" @click.stop="dateType='week';setDate('week')">本周</span>
|
|
|
+ <span :class="[dateType==='month'?'date-active':'']" class="date-item" @click.stop="dateType='month';setDate('month')">本月</span>
|
|
|
+ <span :class="[dateType==='year'?'date-active':'']" class="date-item" @click.stop="dateType='year';setDate('year')">本年</span>
|
|
|
+ </div>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="stratAndEnd"
|
|
|
+ type="daterange"
|
|
|
+ align="right"
|
|
|
+ unlink-panels
|
|
|
+ range-separator="至"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ size="small"
|
|
|
+ value-format="yyyy.MM.dd"
|
|
|
+ :default-time="['00:00:00','23:59:59']"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <el-form :model="defectForm" class="demo-form-inline" :inline="true">
|
|
|
+ <el-form-item label="团队:">
|
|
|
+ <el-select
|
|
|
+ v-model="defectForm.team"
|
|
|
+ placeholder="请选择"
|
|
|
+ size="small"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ multiple
|
|
|
+ >
|
|
|
+ <el-option-group
|
|
|
+ v-for="group in teamOptions"
|
|
|
+ :key="group.label"
|
|
|
+ :label="group.label"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in group.options"
|
|
|
+ :key="item.teamId"
|
|
|
+ :label="item.teamName"
|
|
|
+ :value="item.teamId"
|
|
|
+ />
|
|
|
+ </el-option-group>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="模块:">
|
|
|
+ <el-cascader
|
|
|
+ v-model="defectForm.moduleIds"
|
|
|
+ size="small"
|
|
|
+ clearable
|
|
|
+ collapse-tags
|
|
|
+ :props="{ multiple: true }"
|
|
|
+ :options="moduleList"
|
|
|
+ placeholder="请选择"
|
|
|
+ @click.native="bugDataGet"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" size="mini" @click="onSubmit">查询</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div class="data-total">
|
|
|
+ <div v-for="(item,index) in Summary" :key="'Summary'+index" class="data-item" :class="['item'+ (index + 1)]">
|
|
|
+ <article>
|
|
|
+ <div class="item-top">
|
|
|
+ <div class="item-circle">
|
|
|
+ <img v-show="index === 0" src="../../../src/assets/defect_images/add.png">
|
|
|
+ <img v-show="index === 1" src="../../../src/assets/defect_images/repair.png">
|
|
|
+ <img v-show="index === 2" src="../../../src/assets/defect_images/reopen.png">
|
|
|
+ </div>
|
|
|
+ <span>{{ item.label }}</span>
|
|
|
+ <el-tooltip v-if="index === 0" class="item" effect="dark" content="统计时间区间内,新增的缺陷的数量" placement="top-start">
|
|
|
+ <i class="el-icon-info" />
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip v-if="index === 1" class="item" effect="dark" content="统计时间区间内,缺陷执行过更新状态为“已完成”的操作并且当前缺陷状态是“已完成”的缺陷数量" placement="top-start">
|
|
|
+ <i class="el-icon-info" />
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip v-if="index === 2" class="item" effect="dark" content="统计时间区间内,缺陷执行过更新状态为“Reopen”的操作并且当前缺陷状态为任意状态的缺陷数量" placement="top-start">
|
|
|
+ <i class="el-icon-info" />
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <div class="item-title">{{ item.total }}</div>
|
|
|
+ <div class="item-line" />
|
|
|
+ <div v-show="Number(item.relativeRatio)>=0" class="item-up">环比:<i class="el-icon-caret-top" />{{ item.relativeRatio }}%</div>
|
|
|
+ <div v-show="Number(item.relativeRatio)<0" class="item-down">环比:<i class="el-icon-caret-bottom" />{{ item.relativeRatio.substring(1,item.relativeRatio.length) }}%</div>
|
|
|
+ <div v-show="item.relativeRatio === '--'" class="item-down">环比:{{ item.relativeRatio }}%</div>
|
|
|
+ </article>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-header>
|
|
|
+ <el-main class="charts-main">
|
|
|
+ <el-tabs v-model="activeName" @tab-click="tabChange">
|
|
|
+ <el-tab-pane name="first">
|
|
|
+ <span slot="label" class="tab-item">新增缺陷</span>
|
|
|
+ </el-tab-pane>
|
|
|
+ <el-tab-pane name="second">
|
|
|
+ <span slot="label" class="tab-item">累计修复缺陷</span>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ <div class="chart-item">
|
|
|
+ <h3>分布图</h3>
|
|
|
+ <el-row type="flex" align="middle">
|
|
|
+ <el-col :span="4">
|
|
|
+ <el-select v-model="defectStatus" placeholder="缺陷状态" size="small" @change="defectStatusChange">
|
|
|
+ <el-option
|
|
|
+ v-for="item in defectStatusList"
|
|
|
+ :key="item.code"
|
|
|
+ :disabled="activeTab === 2&&item.code === 1"
|
|
|
+ :label="item.label"
|
|
|
+ :value="item.code"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="4" :offset="16" class="col-flex">
|
|
|
+ <div class="bar-pie" :class="[barOrPie==='bar'?'active':'']" @click="changeBarOrPie('bar')">柱状图</div>
|
|
|
+ <div class="bar-pie" :class="[barOrPie==='pie'?'active':'']" @click="changeBarOrPie('pie')">环状图</div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row type="flex" align="middle">
|
|
|
+ <el-col :span="24">
|
|
|
+ <div class="chart-contain">
|
|
|
+ <normal-echart v-if="echartsOption1" :chart-id="'chartFirst'" :option="echartsOption1" />
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="chart-item">
|
|
|
+ <h3>平均修复时长</h3>
|
|
|
+ <el-row type="flex" align="middle">
|
|
|
+ <div class="repair-list">
|
|
|
+ <div v-for="(item, index) in repairTimeList" :key="'time'+index" class="repair-item" :class="[Number(item.relativeRatio)<0?'repair-slow':'repair-rise']">
|
|
|
+ <div class="repair-item-point" :class="['point'+index]" />
|
|
|
+ <span>{{ item.label }}</span>
|
|
|
+ <div class="repair-time">{{ item.total }}</div>
|
|
|
+ <div v-show="Number(item.relativeRatio)>=0" class="repair-up">环比:<i class="el-icon-caret-top" /><span>{{ item.relativeRatio }}%</span></div>
|
|
|
+ <div v-show="Number(item.relativeRatio)<0" class="repair-down">环比:<i class="el-icon-caret-bottom" /><span>{{ item.relativeRatio.substring(1,item.relativeRatio.length) }}%</span></div>
|
|
|
+ <div v-show="item.relativeRatio === '--'" class="repair-up">环比:<span>{{ item.relativeRatio }}%</span></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-row>
|
|
|
+ <el-row type="flex" align="middle">
|
|
|
+ <el-col :span="4" :offset="20" class="col-flex">
|
|
|
+ <div class="bar-line" :class="[barOrLine==='line'?'active':'']" @click="changeBarOrLine('line')">折线图</div>
|
|
|
+ <div class="bar-line" :class="[barOrLine==='bar'?'active':'']" @click="changeBarOrLine('bar')">柱状图</div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row type="flex" align="middle">
|
|
|
+ <el-col :span="24">
|
|
|
+ <div class="chart-contain">
|
|
|
+ <normal-echart v-if="echartsOption2" :chart-id="'chartSecond'" :option="echartsOption2" />
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="chart-item">
|
|
|
+ <h3>模块分布</h3>
|
|
|
+ <el-table
|
|
|
+ :data="moduleData"
|
|
|
+ style="width: 100%;margin-bottom: 20px;"
|
|
|
+ row-key="id"
|
|
|
+ :border="false"
|
|
|
+ :max-height="350"
|
|
|
+ :tree-props="{children: 'childModuleDatas', hasChildren: 'hasChildren'}"
|
|
|
+ :header-cell-style="{background:'#FAFAFA',color: '#444444'}"
|
|
|
+ class="repair-table"
|
|
|
+ @sort-change="moduleTableSortChange"
|
|
|
+ >
|
|
|
+ <el-table-column prop="name" label="模块" />
|
|
|
+ <el-table-column v-if="activeTab=== 1" prop="repair" label="新增" sortable="custom" show-overflow-tooltip>
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item1 repair-span">{{ scope.row.newData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.newData.detail[0].label }}:{{ scope.row.newData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.newData.detail[1].label }}:{{ scope.row.newData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="isRepair" label="累计修复" sortable="custom">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item2 repair-span2">{{ scope.row.repairData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.repairData.detail[0].label }}:{{ scope.row.repairData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.repairData.detail[1].label }}:{{ scope.row.repairData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="time" label="平均修复时长">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item3 repair-span">{{ scope.row.repairTimeAvgData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.repairTimeAvgData.detail[0].label }}:{{ scope.row.repairTimeAvgData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.repairTimeAvgData.detail[1].label }}:{{ scope.row.repairTimeAvgData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div class="chart-item">
|
|
|
+ <h3>责任人</h3>
|
|
|
+ <el-table
|
|
|
+ :data="memberData"
|
|
|
+ style="width: 100%;margin-bottom: 20px;"
|
|
|
+ row-key="id"
|
|
|
+ :border="false"
|
|
|
+ :max-height="350"
|
|
|
+ :tree-props="{children: 'childModuleDatas', hasChildren: 'hasChildren'}"
|
|
|
+ :header-cell-style="{background:'#FAFAFA',color: '#444444'}"
|
|
|
+ class="repair-table"
|
|
|
+ @sort-change="memberTableSortChange"
|
|
|
+ >
|
|
|
+ <el-table-column prop="name" label="姓名" />
|
|
|
+ <el-table-column v-if="activeTab=== 1" prop="repair" label="新增" sortable="custom" show-overflow-tooltip>
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item1 repair-span">{{ scope.row.newData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.newData.detail[0].label }}:{{ scope.row.newData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.newData.detail[1].label }}:{{ scope.row.newData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="isRepair" label="累计修复" sortable="custom">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item2 repair-span2">{{ scope.row.repairData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.repairData.detail[0].label }}:{{ scope.row.repairData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.repairData.detail[1].label }}:{{ scope.row.repairData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="time" label="平均修复时长">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span class="table-repair-item3 repair-span">{{ scope.row.repairTimeAvgData.total }}</span>/
|
|
|
+ <span class="repair-span">{{ scope.row.repairTimeAvgData.detail[0].label }}:{{ scope.row.repairTimeAvgData.detail[0].total }}</span>
|
|
|
+ <span class="repair-span">{{ scope.row.repairTimeAvgData.detail[1].label }}:{{ scope.row.repairTimeAvgData.detail[1].total }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </el-main>
|
|
|
+ </el-container>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import moment from 'moment'
|
|
|
+moment.locale('zh-cn')
|
|
|
+import { settingQueryBizModuleList } from '@/api/defectManage'
|
|
|
+import { teamQueryTeamInfoList } from '@/api/configure'
|
|
|
+import { getSummary, getDistributeData, getRepairTimeSumData, getRepairTimeDetailData, getModuleDistributeData, getMemberDistributeData } from '@/api/defectStatistics'
|
|
|
+import normalEchart from '@/components/chart/normalEchart'
|
|
|
+export default {
|
|
|
+ components: { normalEchart },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ echartsOption1: null,
|
|
|
+ echartsOption2: null,
|
|
|
+ teamOptions: [],
|
|
|
+ defectForm: {}, // 筛选表单
|
|
|
+ stratAndEnd: [], // 开始结束日期
|
|
|
+ dateType: 'week', // 时间选择类型
|
|
|
+ teamsOptions: [{ code: 1, label: '团队' }],
|
|
|
+ modulesOptions: [{ code: 1, label: '模块' }],
|
|
|
+ moduleList: [], // 模块列表
|
|
|
+ activeName: 'first',
|
|
|
+ activeTab: 1,
|
|
|
+ defectStatus: 1, // 缺陷状态
|
|
|
+ barOrPie: 'bar', // 柱状图or饼图
|
|
|
+ barOrLine: 'line', // 柱状图or折线
|
|
|
+ defectStatusList: [ // 缺陷状态列表
|
|
|
+ { code: 1, label: '缺陷状态' },
|
|
|
+ { code: 2, label: '缺陷等级' },
|
|
|
+ { code: 3, label: '端类型' },
|
|
|
+ { code: 4, label: '优先级' },
|
|
|
+ { code: 5, label: '发现方式' },
|
|
|
+ { code: 6, label: '发现阶段' },
|
|
|
+ { code: 7, label: '缺陷类型' }
|
|
|
+ ],
|
|
|
+ repairTimeList: [],
|
|
|
+ Summary: [], // 顶部数据
|
|
|
+ chart1Data: null, // 图表1数据
|
|
|
+ chart2Data: null, // 图表2数据
|
|
|
+ moduleSort: 2, // 模块数据排序
|
|
|
+ moduleData: [], // 模块数据
|
|
|
+ memberSort: 2, // 责任人数据排序
|
|
|
+ memberData: [] // 责任人数据
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.$store.state.data.status = true
|
|
|
+ this.setDate(this.dateType)
|
|
|
+ this.getTeamList()
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.onSubmit()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onSubmit() {
|
|
|
+ this.getSummary()
|
|
|
+ this.defectStatusChange()
|
|
|
+ this.getRepairTimeSumData()
|
|
|
+ this.getRepairTimeDetailData()
|
|
|
+ this.getModuleDistributeData()
|
|
|
+ this.getMemberDistributeData()
|
|
|
+ },
|
|
|
+ async getTeamList() {
|
|
|
+ const myRes = await teamQueryTeamInfoList({ type: 0 })
|
|
|
+ const allRes = await teamQueryTeamInfoList({ type: 1 })
|
|
|
+ this.teamOptions = [{
|
|
|
+ label: '我的团队',
|
|
|
+ options: [...myRes.data.list]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '全部团队',
|
|
|
+ options: [...allRes.data.list]
|
|
|
+ }]
|
|
|
+ },
|
|
|
+ async bugDataGet() { // 所属模块
|
|
|
+ const res = await settingQueryBizModuleList(Number(localStorage.getItem('bizId')))
|
|
|
+ this.moduleList = this.handlerModules(res.data)
|
|
|
+ },
|
|
|
+ handlerModules(arr) {
|
|
|
+ return arr.map(item => ({
|
|
|
+ ...item,
|
|
|
+ value: item.id,
|
|
|
+ label: item.moduleName,
|
|
|
+ children: item.childModules.length ? this.handlerModules(item.childModules) : null
|
|
|
+ }))
|
|
|
+ },
|
|
|
+ setDate(type) { // 日期筛选
|
|
|
+ let startDate = null
|
|
|
+ let endDate = null
|
|
|
+ switch (type) {
|
|
|
+ case 'week':
|
|
|
+ startDate = moment().startOf('week').format('YYYY.MM.DD')
|
|
|
+ endDate = moment().endOf('week').format('YYYY.MM.DD')
|
|
|
+ break
|
|
|
+ case 'month':
|
|
|
+ startDate = moment().startOf('month').format('YYYY.MM.DD')
|
|
|
+ endDate = moment().endOf('month').format('YYYY.MM.DD')
|
|
|
+ break
|
|
|
+ case 'year':
|
|
|
+ startDate = moment().startOf('year').format('YYYY.MM.DD')
|
|
|
+ endDate = moment().endOf('year').format('YYYY.MM.DD')
|
|
|
+ break
|
|
|
+ }
|
|
|
+ this.stratAndEnd = [startDate, endDate]
|
|
|
+ this.onSubmit()
|
|
|
+ },
|
|
|
+ tabChange() { // tab变动
|
|
|
+ if (this.defectStatus === 1) { // 累计修复中,没有缺陷状态
|
|
|
+ this.defectStatus = 2
|
|
|
+ }
|
|
|
+ this.activeName === 'first' ? this.activeTab = 1 : this.activeTab = 2
|
|
|
+ this.defectStatusChange()
|
|
|
+ this.getRepairTimeSumData()
|
|
|
+ this.getRepairTimeDetailData()
|
|
|
+ this.getModuleDistributeData()
|
|
|
+ this.getMemberDistributeData()
|
|
|
+ },
|
|
|
+ async getSummary() { // 获取顶部数据
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null
|
|
|
+ }
|
|
|
+ const res = await getSummary(params)
|
|
|
+ this.Summary = res.data || []
|
|
|
+ },
|
|
|
+ async defectStatusChange() { // 分布图状态变动
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ type: this.activeTab,
|
|
|
+ distributeType: this.defectStatus,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null
|
|
|
+ }
|
|
|
+ const res = await getDistributeData(params)
|
|
|
+ this.chart1Data = res.data || []
|
|
|
+ this.changeBarOrPie(this.barOrPie)
|
|
|
+ },
|
|
|
+ changeBarOrPie(type) { // 饼图柱状图切换
|
|
|
+ this.barOrPie = type
|
|
|
+ if (type === 'bar') {
|
|
|
+ this.echartsOption1 = {
|
|
|
+ color: ['#3AA1FF'],
|
|
|
+ tooltip: { trigger: 'axis', axisPointer: { type: 'line' }}, // 默认为直线,可选为:'line' | 'shadow'
|
|
|
+ grid: { left: '0', right: '0', top: '5%', bottom: '0', containLabel: true },
|
|
|
+ xAxis: [{ type: 'category', data: this.chart1Data.xaxis, axisTick: { alignWithLabel: true }}],
|
|
|
+ yAxis: [{ type: 'value', axisLine: { show: false }, splitLine: { lineStyle: { type: 'dashed' }}}],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '缺陷数量', type: 'bar', barWidth: '20px', data: this.chart1Data.yaxis[0] && this.chart1Data.yaxis[0].data || [],
|
|
|
+ itemStyle: { normal: { label: { show: true, formatter: '{c}', position: 'top' }}}
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const newArr = this.chart1Data.xaxis.map((item, index) => {
|
|
|
+ return {
|
|
|
+ value: this.chart1Data.yaxis[0] && this.chart1Data.yaxis[0].data[index] || null,
|
|
|
+ name: item
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.echartsOption1 = {
|
|
|
+ color: ['#1890FF', '#13C2C2', '#2FC25B', '#FACC14', '#F04864', '#8543E0'],
|
|
|
+ grid: { left: '0', right: '0', top: '3%', bottom: '0' },
|
|
|
+ tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c} ({d}%)' },
|
|
|
+ legend: { orient: 'vertical', left: 'right', top: 'center', data: this.chart1Data.xaxis },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '缺陷数量', type: 'pie', radius: ['45%', '60%'], right: '30%', label: { position: 'outer', alignTo: 'edge', margin: 20 }, data: newArr,
|
|
|
+ itemStyle: { normal: { label: { show: true, formatter: '{b} : {c} ({d}%)' }, labelLine: { show: true }}}
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getRepairTimeSumData() { // 平均修复时长头部数据
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ type: this.activeTab,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null
|
|
|
+ }
|
|
|
+ const res = await getRepairTimeSumData(params)
|
|
|
+ this.repairTimeList = res.data || []
|
|
|
+ },
|
|
|
+ async getRepairTimeDetailData() { // 平均修复时长表数据
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ type: this.activeTab,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null
|
|
|
+ }
|
|
|
+ const res = await getRepairTimeDetailData(params)
|
|
|
+ this.chart2Data = res.data || []
|
|
|
+ this.changeBarOrLine(this.barOrLine)
|
|
|
+ },
|
|
|
+ changeBarOrLine(type) { // 柱状图折线图切换
|
|
|
+ this.barOrLine = type
|
|
|
+ const newArr = this.chart2Data.yaxis.filter(item => { return item.name !== '全部' })
|
|
|
+ const colorArr = ['#3AA1FF', '#4ECB73', '#975FE5', '#FBD437', '#13C2C2']
|
|
|
+ if (type === 'line') {
|
|
|
+ this.echartsOption2 = {
|
|
|
+ color: colorArr,
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: { type: 'line' },
|
|
|
+ formatter: params => {
|
|
|
+ let total = 0
|
|
|
+ let backString = ``
|
|
|
+ params.map((item, index) => {
|
|
|
+ total = total + item.value
|
|
|
+ backString = backString + `<span style="color: ${colorArr[index] || ''}">${item.seriesName}</span>:${item.value}%</br>`
|
|
|
+ })
|
|
|
+ total = total.toFixed(2)
|
|
|
+ backString = backString + `<span style="color: #F04864">总和</span>:${total}%`
|
|
|
+ return backString
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: { data: newArr.map(item => { return item.name }), left: 10, top: 0 },
|
|
|
+ grid: { left: '0', right: '0', top: '8%', bottom: '0', containLabel: true },
|
|
|
+ xAxis: { type: 'category', data: this.chart2Data.xaxis },
|
|
|
+ yAxis: { type: 'value', axisLine: { show: false }, splitLine: { lineStyle: { type: 'dashed' }}, axisLabel: { formatter: '{value} %' }},
|
|
|
+ series: newArr.map(item => ({ ...item, type: 'line', smooth: true }))
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.echartsOption2 = {
|
|
|
+ color: colorArr,
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: { type: 'line' },
|
|
|
+ formatter: params => {
|
|
|
+ let total = 0
|
|
|
+ let backString = ``
|
|
|
+ params.map((item, index) => {
|
|
|
+ total = total + item.value
|
|
|
+ backString = backString + `<span style="color: ${colorArr[index] || ''}">${item.seriesName}</span>:${item.value}%</br>`
|
|
|
+ })
|
|
|
+ total = total.toFixed(2)
|
|
|
+ backString = backString + `<span style="color: #F04864">总和</span>:${total}%`
|
|
|
+ return backString
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: { data: newArr.map(item => { return item.name }), left: 0, top: 0 },
|
|
|
+ grid: { left: '0', right: '0', top: '8%', bottom: '0', containLabel: true },
|
|
|
+ xAxis: { type: 'category', data: this.chart2Data.xaxis, axisTick: { alignWithLabel: true }},
|
|
|
+ yAxis: { type: 'value', axisLine: { show: false }, splitLine: { lineStyle: { type: 'dashed' }}, axisLabel: { formatter: '{value} %' }},
|
|
|
+ series: newArr.map(item => ({ ...item, type: 'bar', stack: '总和', barWidth: '20px' }))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async getModuleDistributeData() { // 获取模块数据
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null,
|
|
|
+ type: this.activeTab,
|
|
|
+ sortType: this.moduleSort
|
|
|
+ }
|
|
|
+ const res = await getModuleDistributeData(params)
|
|
|
+ this.moduleData = res.data || []
|
|
|
+ },
|
|
|
+ moduleTableSortChange(column) { // 模块table排序变动
|
|
|
+ if (column.prop === 'repair') {
|
|
|
+ column.order === 'ascending' ? this.moduleSort = 1 : this.moduleSort = 2
|
|
|
+ } else {
|
|
|
+ column.order === 'ascending' ? this.moduleSort = 3 : this.moduleSort = 4
|
|
|
+ }
|
|
|
+ this.getModuleDistributeData()
|
|
|
+ },
|
|
|
+ async getMemberDistributeData() { // 获取责任人数据
|
|
|
+ const moduleIds = this.defectForm.moduleIds
|
|
|
+ const params = {
|
|
|
+ startTime: this.stratAndEnd[0] || null,
|
|
|
+ endTime: this.stratAndEnd[1] || null,
|
|
|
+ bizId: Number(localStorage.getItem('bizId')),
|
|
|
+ teamIds: this.defectForm.team || null,
|
|
|
+ moduleIds: moduleIds && moduleIds.length > 0 ? moduleIds : null,
|
|
|
+ type: this.activeTab,
|
|
|
+ sortType: this.memberSort
|
|
|
+ }
|
|
|
+ const res = await getMemberDistributeData(params)
|
|
|
+ this.memberData = res.data || []
|
|
|
+ },
|
|
|
+ memberTableSortChange(column) { // 责任人table排序变动
|
|
|
+ if (column.prop === 'repair') {
|
|
|
+ column.order === 'ascending' ? this.memberSort = 1 : this.memberSort = 2
|
|
|
+ } else {
|
|
|
+ column.order === 'ascending' ? this.memberSort = 3 : this.memberSort = 4
|
|
|
+ }
|
|
|
+ this.getMemberDistributeData()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.defect-container {
|
|
|
+ width: 100%;
|
|
|
+ height:100%;
|
|
|
+ background:#F2F3F6;
|
|
|
+ display: inline-block;
|
|
|
+ color: #666666;
|
|
|
+ h3 {
|
|
|
+ font-size: 18px;
|
|
|
+ margin: 40px 0 20px 0;
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+ .defect-main {
|
|
|
+ padding: 20px 20px 0 20px;
|
|
|
+ height:100%;
|
|
|
+ width: calc(100%-60px);
|
|
|
+ background:#ffffff;
|
|
|
+ margin: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ .date-select {
|
|
|
+ line-height: 20px;
|
|
|
+ display: inline-block;
|
|
|
+ .date-item {
|
|
|
+ display: inline-block;
|
|
|
+ width: 40px;
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 2px;
|
|
|
+ }
|
|
|
+ .date-active {
|
|
|
+ color: #FFFFFF;
|
|
|
+ background-color: #409EFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .data-total {
|
|
|
+ display: flex;
|
|
|
+ width: 94%;
|
|
|
+ margin: auto;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding-bottom: 40px;
|
|
|
+ ul,li{
|
|
|
+ padding:0;margin:0;list-style:none
|
|
|
+ }
|
|
|
+ .data-item {
|
|
|
+ position: relative;
|
|
|
+ width: 27%;
|
|
|
+ border-radius: 8px;
|
|
|
+ article {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ color: #FFFFFF;
|
|
|
+ }
|
|
|
+ .item-top {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10px 20px;
|
|
|
+ font-size: 13px;
|
|
|
+ .item-circle {
|
|
|
+ height: 36px;
|
|
|
+ width: 36px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background:rgba(255,255,255,0.24);
|
|
|
+ margin-right: 10px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ img {
|
|
|
+ height: 20px;
|
|
|
+ width: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ span {
|
|
|
+ margin-right: 5px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .item-line {
|
|
|
+ width: 100%;
|
|
|
+ border-bottom:1px solid rgba(255,255,255,0.2);
|
|
|
+ }
|
|
|
+ .item-title {
|
|
|
+ font-size: 40px;
|
|
|
+ padding: 5% 20px;
|
|
|
+ }
|
|
|
+ .item-up,.item-down {
|
|
|
+ font-size: 13px;
|
|
|
+ padding: 10px 20px 0 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+ .item-up i {
|
|
|
+ color:#F32850
|
|
|
+ }
|
|
|
+ .item-down i {
|
|
|
+ color:#9FFF39
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .item1 {
|
|
|
+ background-image: url('../../../src/assets/defect_images/数据1.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: 50% 50%;
|
|
|
+ box-shadow:0px 50px 24px -25px rgba(64,137,255,0.30);
|
|
|
+ }
|
|
|
+ .item2 {
|
|
|
+ background-image: url('../../../src/assets/defect_images/数据2.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: 50% 50%;
|
|
|
+ box-shadow:0px 50px 24px -25px rgba(78,188,250,0.40);
|
|
|
+ }
|
|
|
+ .item3 {
|
|
|
+ background-image: url('../../../src/assets/defect_images/数据3.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: 50% 50%;
|
|
|
+ box-shadow:0px 50px 24px -25px rgba(255,136,134,0.30);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .charts-main {
|
|
|
+ padding-bottom: 20px;
|
|
|
+ width:calc(100%-60px);
|
|
|
+ background:#ffffff;
|
|
|
+ margin: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ /deep/.el-tabs__header {
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ .chart-item {
|
|
|
+ padding: 0 20px;
|
|
|
+ .col-flex {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+ .repair-list {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+ .repair-item {
|
|
|
+ position: relative;
|
|
|
+ width: 15%;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: bold;
|
|
|
+ padding: 11px 17px 6px 17px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ color: #909399;
|
|
|
+ margin-bottom: 40px;
|
|
|
+ background:rgba(255,255,255,1);
|
|
|
+ box-shadow:0px 2px 8px rgba(0,0,0,0.15);
|
|
|
+ border-radius: 4px;
|
|
|
+ .repair-time {
|
|
|
+ color: #303133;
|
|
|
+ font-size: 18px;
|
|
|
+ margin:25px 0;
|
|
|
+ }
|
|
|
+ .repair-item-point {
|
|
|
+ position: absolute;
|
|
|
+ top: 15px;
|
|
|
+ left: 6px;
|
|
|
+ width: 6px;
|
|
|
+ height: 6px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ .point1 {
|
|
|
+ background-color: #1890FF;
|
|
|
+ }
|
|
|
+ .point2 {
|
|
|
+ background-color: #52C41A;
|
|
|
+ }
|
|
|
+ .point3 {
|
|
|
+ background-color: #D675F0;
|
|
|
+ }
|
|
|
+ .point4 {
|
|
|
+ background-color: #ECAD00;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .repair-rise {
|
|
|
+ background-image: url('../../../src/assets/defect_images/rise.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: center;
|
|
|
+ }
|
|
|
+ .repair-slow {
|
|
|
+ background-image: url('../../../src/assets/defect_images/slow.png');
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-position: center;
|
|
|
+ }
|
|
|
+ .repair-up i , .repair-up span{
|
|
|
+ color:#F32850
|
|
|
+ }
|
|
|
+ .repair-down i, .repair-down span {
|
|
|
+ color:#9FFF39
|
|
|
+ }
|
|
|
+ .bar-pie,.bar-line {
|
|
|
+ font-size: 14px;
|
|
|
+ width: 40%;
|
|
|
+ display: inline-block;
|
|
|
+ padding: 6px 10px;
|
|
|
+ margin-left: 5%;
|
|
|
+ color: #50A6FF;
|
|
|
+ border: 1px solid #50A6FF;
|
|
|
+ border-radius: 4px;
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ .active {
|
|
|
+ color: #ffffff;
|
|
|
+ background: #50A6FF;
|
|
|
+ }
|
|
|
+ .repair-span {
|
|
|
+ padding-right: 5px;
|
|
|
+ }
|
|
|
+ .table-repair-item1 {
|
|
|
+ color:#4089FF;
|
|
|
+ }
|
|
|
+ .table-repair-item2 {
|
|
|
+ color:#47D4D5
|
|
|
+ }
|
|
|
+ .table-repair-item3 {
|
|
|
+ color:#FD978A
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .chart-contain {
|
|
|
+ height: 400px;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.tab-item {
|
|
|
+ padding: 0 20px;
|
|
|
+}
|
|
|
+/deep/.el-tabs__item {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+.el-cascader {
|
|
|
+ width: auto;
|
|
|
+}
|
|
|
+/deep/ .el-tabs__nav-wrap::after{
|
|
|
+ height: 1px;
|
|
|
+ background-color: #999999;
|
|
|
+ opacity: 0.2;
|
|
|
+}
|
|
|
+</style>
|