Selaa lähdekoodia

Merge branch 'http_mock' into pern

qinzhipeng_v 5 vuotta sitten
vanhempi
sitoutus
88b6336410

+ 1 - 0
package.json

@@ -36,6 +36,7 @@
     "html2canvas": "^1.0.0-rc.3",
     "js-cookie": "2.2.0",
     "jspdf": "^1.5.3",
+    "moment": "^2.25.3",
     "normalize.css": "7.0.0",
     "nprogress": "0.2.0",
     "path-to-regexp": "2.4.0",

+ 51 - 0
src/api/defectStatistics.js

@@ -0,0 +1,51 @@
+import request from '@/utils/request'
+import { TeamManagement } from '@/apiConfig/api'
+
+// 顶部数据
+export function getSummary(data) {
+  return request({
+    url: TeamManagement + '/bug/getSummary',
+    method: 'post',
+    data
+  })
+}
+// 获取缺陷分布数据
+export function getDistributeData(data) {
+  return request({
+    url: TeamManagement + '/bug/getDistributeData',
+    method: 'post',
+    data
+  })
+}
+// 平均修复时长头部数据
+export function getRepairTimeSumData(data) {
+  return request({
+    url: TeamManagement + '/bug/getRepairTimeSumData',
+    method: 'post',
+    data
+  })
+}
+// 平均修复时长表数据
+export function getRepairTimeDetailData(data) {
+  return request({
+    url: TeamManagement + '/bug/getRepairTimeDetailData',
+    method: 'post',
+    data
+  })
+}
+// 获取模块数据
+export function getModuleDistributeData(data) {
+  return request({
+    url: TeamManagement + '/bug/getModuleDistributeData',
+    method: 'post',
+    data
+  })
+}
+// 获取人员数据
+export function getMemberDistributeData(data) {
+  return request({
+    url: TeamManagement + '/bug/getMemberDistributeData',
+    method: 'post',
+    data
+  })
+}

+ 1 - 1
src/api/projectIndex.js

@@ -2,7 +2,7 @@
 import request from '@/utils/request'
 import { TeamManagement } from '@/apiConfig/api'
 
-// 新建团队
+// 获取项目列表
 export function projectList(data) {
   return request({
     url: TeamManagement + `/project/list`,

BIN
src/assets/defect_images/add.png


BIN
src/assets/defect_images/reopen.png


BIN
src/assets/defect_images/repair.png


BIN
src/assets/defect_images/rise.png


BIN
src/assets/defect_images/slow.png


BIN
src/assets/defect_images/数据1.png


BIN
src/assets/defect_images/数据2.png


BIN
src/assets/defect_images/数据3.png


+ 49 - 0
src/components/chart/normalEchart.vue

@@ -0,0 +1,49 @@
+<template>
+  <div :id="chartId" style="width: 100%;height: 100%" />
+</template>
+
+<script>
+import echarts from 'echarts'
+
+export default {
+  name: 'Echarts',
+  props: {
+    chartId: {
+      type: String,
+      default: 'myChart',
+      required: false
+    },
+    option: {
+      type: Object,
+      default: null,
+      required: false
+    }
+  },
+  data() {
+    return {}
+  },
+  watch: {
+    option: {
+      handler(newValue, oldValue) {
+        const myChart = echarts.init(document.getElementById(this.chartId))
+        myChart.clear()
+        this.drawLine()
+      },
+      deep: true
+    }
+  },
+  mounted() {
+    this.drawLine()
+  },
+  methods: {
+    drawLine() {
+      const myChart = echarts.init(document.getElementById(this.chartId))
+      myChart.setOption(this.option)
+    }
+  }
+}
+</script>
+
+<style>
+
+</style>

+ 1 - 1
src/layout/components/AppMain.vue

@@ -28,7 +28,7 @@ export default {
   overflow: hidden;
 }
 .fixed-header+.app-main {
-  padding-top: 50px;
+  padding-top: 55px;
 }
 </style>
 

+ 9 - 2
src/router/index.js

@@ -450,10 +450,17 @@ export const constantRoutes = [{
   meta: { title: '统计分析', icon: '质量度量' },
   children: [{
     path: 'qualityMeasurement',
-    name: '质量大盘',
+    name: '老版统计',
     component: () =>
       import('@/views/quality/qualityMeasurement.vue'),
-    meta: { title: '统计分析' }
+    meta: { title: '老版统计' }
+  },
+  {
+    path: 'defectStatistics',
+    name: '缺陷统计',
+    component: () =>
+      import('@/views/quality/defectStatistics.vue'),
+    meta: { title: '缺陷统计' }
   },
   {
     path: 'qualityProcess',

+ 785 - 0
src/views/quality/defectStatistics.vue

@@ -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>