wangziqian 5 éve
szülő
commit
5bdf79743c

+ 1 - 0
package.json

@@ -15,6 +15,7 @@
     "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
   },
   "dependencies": {
+    "@antv/data-set": "^0.11.5",
     "@didi/omega-tracker": "^2.2.8",
     "@fullcalendar/bootstrap": "^4.4.0",
     "@fullcalendar/core": "^4.4.0",

+ 26 - 2
src/api/statisticsApi/requireStatistics.js

@@ -10,9 +10,17 @@ export function getSummary(data) {
   })
 }
 // 需求状态累计流图
-export function CumulativeFlowDiagram(data) {
+export function getCumulativeFlowDiagram(data) {
   return request({
-    url: TeamManagement + '/requirement/CumulativeFlowDiagram',
+    url: TeamManagement + '/requirement/getCumulativeFlowDiagram',
+    method: 'post',
+    data
+  })
+}
+// 需求趋势图
+export function getRequireCountTrend(data) {
+  return request({
+    url: TeamManagement + '/requirement/getRequireCountTrend',
     method: 'post',
     data
   })
@@ -25,6 +33,22 @@ export function getOrntDistributeData(data) {
     data
   })
 }
+// 需求周期统计
+export function getRequirePeriodicData(data) {
+  return request({
+    url: TeamManagement + '/requirement/getRequirePeriodicData',
+    method: 'post',
+    data
+  })
+}
+// 研发交付周期分布图
+export function getRequireRdDeliveryPeriodicData(data) {
+  return request({
+    url: TeamManagement + '/requirement/getRequireRdDeliveryPeriodicData',
+    method: 'post',
+    data
+  })
+}
 // 需求分布图
 export function getDistributeData(data) {
   return request({

+ 177 - 0
src/components/chart/antvChart.vue

@@ -0,0 +1,177 @@
+<template>
+  <div :id="id" class="antv-chart" />
+</template>
+<script>
+import DataSet from '@antv/data-set'
+import { Chart } from '@antv/g2'
+export default {
+  props: {
+    id: {
+      type: String,
+      default: 'antv-chart',
+      required: false
+    },
+    option: {
+      type: Object,
+      default: () => null,
+      required: false
+    },
+    data: {
+      type: Object,
+      default: () => null,
+      required: true
+    }
+  },
+  data() {
+    return {
+      chart: null,
+      ds: null
+    }
+  },
+  watch: {
+    option: {
+      handler(newValue, oldValue) {
+        this.$nextTick(() => {
+          this.changeChart()
+        })
+      },
+      deep: true
+    },
+    data: {
+      handler(newValue, oldValue) {
+        this.$nextTick(() => {
+          this.changeChart()
+        })
+      },
+      deep: true
+    }
+  },
+  mounted() {
+    this.initChart1()
+  },
+  methods: {
+    initChart() {
+      fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/flare.json')
+        .then((res) => res.json())
+        .then((data) => {
+          const ds = new DataSet()
+          const dv = ds.createView().source(data, {
+            type: 'hierarchy'
+          })
+          dv.transform({
+            type: 'hierarchy.partition'
+          })
+          const chart = new Chart({
+            container: this.id,
+            autoFit: true,
+            height: 500,
+            padding: 0
+          })
+          chart.data(
+            dv.getAllNodes().map((node) => ({
+              name: node.data.name,
+              value: node.value,
+              depth: node.depth,
+              x: node.x,
+              y: node.y
+            }))
+          )
+          console.log(dv.getAllNodes().map((node) => ({
+            name: node.data.name,
+            value: node.value,
+            depth: node.depth,
+            x: node.x,
+            y: node.y
+          })))
+          chart.scale({
+            x: { nice: true },
+            y: { nice: true }
+          })
+          chart.tooltip({
+            showTitle: false,
+            showMarkers: false
+          })
+          chart.axis(false)
+          chart.legend(false)
+          chart
+            .polygon()
+            .position('x*y')
+            .color('name')
+          chart.interaction('element-active')
+          chart.render()
+        })
+    },
+    initChart1() {
+      const ds = new DataSet()
+      const dv = ds.createView().source(this.data, {
+        type: 'hierarchy'
+      })
+      dv.transform({
+        type: 'hierarchy.partition'
+      })
+      const chart = new Chart({
+        container: this.id,
+        autoFit: true,
+        height: 400,
+        padding: 0
+      })
+      chart.data(
+        dv.getAllNodes().map((node) => {
+          if (node) {
+            return {
+              name: node.data.name,
+              value: node.data.count,
+              depth: node.depth,
+              x: node.x,
+              y: node.y
+            }
+          }
+        })
+      )
+      console.log(dv.getAllNodes().map((node) => {
+        if (node) {
+          return {
+            name: node.data.name,
+            value: node.data.count,
+            depth: node.depth,
+            x: node.x,
+            y: node.y
+          }
+        }
+      }))
+      chart.scale({
+        x: { nice: true },
+        y: { nice: true }
+      })
+      chart.tooltip({
+        showTitle: false,
+        showMarkers: false
+      })
+      chart.axis(false)
+      chart.legend(false)
+      chart
+        .polygon()
+        .position('x*y')
+        .color('name')
+      chart.interaction('element-active')
+      chart.render()
+    },
+    changeChart() {
+      console.log(this.data)
+      const dv = this.ds.createView().source(this.data, {
+        type: 'hierarchy'
+      })
+      dv.transform({
+        type: 'hierarchy.partition'
+      })
+      this.chart.changeData(dv.getAllNodes().map((node) => ({
+        name: node.data.name,
+        value: node.count,
+        depth: node.depth,
+        x: node.x,
+        y: node.y
+      })))
+    }
+  }
+}
+</script>

+ 6 - 71
src/views/quality/components/belongChart.vue

@@ -1,22 +1,14 @@
 <template>
   <section>
-    <div class="control">
-      <el-row type="flex" align="middle">
-        <el-col :span="4" :offset="20" class="col-flex-end">
-          <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>
-    </div>
     <div class="chart-contain">
-      <normal-echart v-if="echartsOption" :chart-id="id" :option="echartsOption" />
+      <antv-chart v-if="chartData" :data="chartData" />
     </div>
   </section>
 </template>
 <script>
-import normalEchart from '@/components/chart/normalEchart'
+import antvChart from '@/components/chart/antvChart'
 export default {
-  components: { normalEchart },
+  components: { antvChart },
   props: {
     id: {
       type: String,
@@ -31,55 +23,19 @@ export default {
   },
   data() {
     return {
-      echartsOption: null,
-      barOrPie: 'bar' // 柱状图or饼图
+      echartsOption: null
     }
   },
   watch: {
     chartData: {
       handler(newV) {
-        this.changeBarOrPie(this.barOrPie)
+        this.chartData = newV
       },
       deep: true,
       immediate: true
     }
   },
-  methods: {
-    changeBarOrPie(type) { // 饼图柱状图切换
-      this.barOrPie = type
-      if (!this.chartData) return
-      if (type === 'bar') {
-        this.echartsOption = {
-          color: ['#3AA1FF'],
-          tooltip: { trigger: 'axis', axisPointer: { type: 'line' }}, // 默认为直线,可选为:'line' | 'shadow'
-          grid: { left: '0', right: '0', top: '10%', bottom: '0', containLabel: true },
-          xAxis: [{ type: 'category', data: this.chartData.xaxis, axisLabel: { interval: 0, rotate: 0 }, axisTick: { alignWithLabel: true }}],
-          yAxis: [{ type: 'value', axisLine: { show: false }, splitLine: { lineStyle: { type: 'dashed' }}}],
-          series: [{
-            name: '数量', type: 'bar', barWidth: '20px', data: this.chartData.yaxis[0] && this.chartData.yaxis[0].data || [],
-            itemStyle: { normal: { label: { show: true, formatter: '{c}', position: 'top' }}}
-          }]
-        }
-      } else {
-        const newArr = this.chartData.xaxis.map((item, index) => {
-          return {
-            value: this.chartData.yaxis[0] && this.chartData.yaxis[0].data[index] || null,
-            name: item
-          }
-        })
-        this.echartsOption = {
-          color: ['#1890FF', '#13C2C2', '#2FC25B', '#FACC14', '#F04864', '#8543E0'],
-          grid: { left: '0', right: '0', top: '5%', bottom: '0' },
-          tooltip: { trigger: 'item', formatter: '{a} <br/>{b} : {c} ({d}%)' },
-          legend: { orient: 'vertical', left: 'right', top: 'center', data: this.chartData.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 }}}
-          }]
-        }
-      }
-    }
-  }
+  methods: {}
 }
 </script>
 <style lang="scss" scoped>
@@ -89,25 +45,4 @@ export default {
   width: 84%;
   margin: 20px auto;
 }
-.control{
-  width: 84%;
-  margin: auto;
-  margin-top: 20px;
-}
-.bar-pie {
-  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;
-}
 </style>

+ 10 - 10
src/views/quality/components/cycleStatistic.vue

@@ -5,10 +5,10 @@
         <div v-for="(item, index) in chartData" :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 class="repair-time">{{ item.countStr }}</div>
+          <div v-show="Number(item.chainRatio)>=0" class="repair-up">环比:<i class="el-icon-caret-top" /><span>{{ item.chainRatio }}%</span></div>
+          <div v-show="Number(item.chainRatio)<0" class="repair-down">环比:<i class="el-icon-caret-bottom" /><span>{{ item.chainRatio.substring(1,item.chainRatio.length) }}%</span></div>
+          <div v-show="item.chainRatio === '--'" class="repair-up">环比:<span>{{ item.chainRatio }}%</span></div>
         </div>
       </div>
     </el-row>
@@ -42,7 +42,7 @@ export default {
   margin: 20px auto;
   .repair-item {
     position: relative;
-    width: 15%;
+    width: 20%;
     font-size: 12px;
     font-weight: bold;
     padding: 11px 17px 6px 17px;
@@ -59,22 +59,22 @@ export default {
     }
     .repair-item-point {
       position: absolute;
-      top: 15px;
+      top: 18px;
       left: 6px;
       width: 6px;
       height: 6px;
       border-radius: 50%;
     }
-    .point1 {
+    .point0 {
       background-color: #1890FF;
     }
-    .point2 {
+    .point1 {
       background-color: #52C41A;
     }
-    .point3 {
+    .point2 {
       background-color: #D675F0;
     }
-    .point4 {
+    .point3 {
       background-color: #ECAD00;
     }
   }

+ 102 - 0
src/views/quality/components/developmentCycle.vue

@@ -0,0 +1,102 @@
+<template>
+  <section>
+    <div class="chart-contain">
+      <normal-echart v-if="echartsOption" :chart-id="id" :option="echartsOption" />
+    </div>
+  </section>
+</template>
+<script>
+import normalEchart from '@/components/chart/normalEchart'
+import echarts from 'echarts'
+export default {
+  components: { normalEchart },
+  props: {
+    id: {
+      type: String,
+      default: 'develop-cycle-chart',
+      required: false
+    },
+    chartData: {
+      type: Array,
+      default: () => [],
+      required: false
+    }
+  },
+  data() {
+    return {
+      echartsOption: null
+    }
+  },
+  watch: {
+    chartData: {
+      handler(newV) {
+        this.setChart()
+      },
+      deep: true,
+      immediate: true
+    },
+    timeType: {
+      handler(newV) {
+        this.timeType = newV
+      },
+      immediate: true
+    }
+  },
+  methods: {
+    setChart() {
+      this.echartsOption = {
+        grid: { left: '0%', right: '5%', bottom: '0%', top: '10%', containLabel: true },
+        tooltip: {
+          showDelay: 0,
+          formatter: function(params) {
+            return `日期:${params.data[0]}<br/> 周期:${params.data[1]}`
+          },
+          axisPointer: {
+            show: true,
+            type: 'cross',
+            lineStyle: {
+              type: 'dashed',
+              width: 1
+            }
+          }
+        },
+        xAxis: {
+          type: 'time'
+
+        },
+        yAxis: {
+          type: 'value'
+        },
+        series: [{
+          name: '',
+          data: this.chartData,
+          type: 'scatter',
+          symbolSize: 10,
+          itemStyle: {
+            shadowBlur: 10,
+            shadowColor: 'rgba(25, 100, 150, 0.5)',
+            shadowOffsetY: 5,
+            color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [{
+              offset: 0,
+              color: 'rgb(129, 227, 238)'
+            }, {
+              offset: 1,
+              color: 'rgb(25, 183, 207)'
+            }])
+          }
+        }]
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.chart-contain {
+  position: relative;
+  height: 400px;
+  width: 84%;
+  margin: auto;
+  margin-top: 20px;
+}
+</style>
+

+ 14 - 2
src/views/quality/components/distributionChart.vue

@@ -7,6 +7,7 @@
             <el-option
               v-for="item in statusList"
               :key="item.code"
+              :disabled="activeTab === '2'&&item.code === 1"
               :label="item.label"
               :value="item.code"
             />
@@ -47,6 +48,11 @@ export default {
       type: Number,
       default: NaN,
       required: true
+    },
+    activeTab: {
+      type: String,
+      default: '1',
+      required: false
     }
   },
   data() {
@@ -66,7 +72,13 @@ export default {
     },
     status: {
       handler(newV) {
-        this.status = newV
+        this.curStatus = newV
+      },
+      immediate: true
+    },
+    activeTab: {
+      handler(newV) {
+        this.activeTab = newV
       },
       immediate: true
     }
@@ -76,7 +88,7 @@ export default {
   },
   methods: {
     statusChange(e) {
-      this.$emit('update:status', e)
+      this.$emit('update:status', this.curStatus)
       this.$emit('change')
     },
     changeBarOrPie(type) { // 饼图柱状图切换

+ 26 - 0
src/views/quality/components/moduleDistribute.vue

@@ -0,0 +1,26 @@
+<template>
+  <section />
+</template>
+<script>
+export default {
+  props: {
+    chartData: {
+      type: Object,
+      default: () => null,
+      required: false
+    }
+  },
+  watch: {
+    chartData: {
+      handler(newV) {
+        console.log(newV)
+      }
+    },
+    deep: true,
+    immediate: true
+  }
+}
+</script>
+<style scoped lang="scss">
+
+</style>

+ 77 - 48
src/views/quality/requireStatistics.vue

@@ -102,7 +102,7 @@
         <h3>状态累积流量图</h3>
         <status-chart :chart-data="cumulativeData" />
       </div>
-      <el-tabs v-model="activeTab" class="tab-change">
+      <el-tabs v-model="activeTab" class="tab-change" @tab-click="onSubmit">
         <el-tab-pane name="1">
           <span slot="label" class="tab-item">累计新增</span>
         </el-tab-pane>
@@ -114,10 +114,6 @@
         <h3>新增趋势图</h3>
         <tendency-chart :chart-data="tendencyData" />
       </div>
-      <div class="chart-item">
-        <h3>所属需求方向分布图</h3>
-        <belong-chart :chart-data="orntDistributeData" />
-      </div>
       <div class="chart-item">
         <h3>周期统计<span>(根据排期计算)</span></h3>
         <div class="chart-item-tip">
@@ -132,6 +128,7 @@
           <i class="el-icon-warning-outline" />
           <span>仅统计状态已变更“已排期”且排期不为空的任务;横坐标表示任务交付日期,纵坐标代表研发交付周期(研发、联调、上线类型排期的总周期)</span>
         </div>
+        <development-cycle :chart-data="developmentCycleData" />
       </div>
       <div class="chart-item">
         <h3>需求分布图</h3>
@@ -139,6 +136,7 @@
           :chart-data="distributeData"
           :status-list="distributeStatusList"
           :status.sync="distributeStatus"
+          :active-tab="activeTab"
           @change="getDistributeData()"
         />
       </div>
@@ -146,6 +144,10 @@
         <h3>状态停留分布图</h3>
         <status-stay-chart :chart-data="statusStayData" />
       </div>
+      <!-- <div class="chart-item">
+        <h3>需求方向分布图</h3>
+        <belong-chart :chart-data="orntDistributeData" />
+      </div> -->
     </el-main>
   </el-container>
 </template>
@@ -154,13 +156,12 @@ import moment from 'moment'
 moment.locale('zh-cn')
 import { settingQueryBizRqmtOrntList } from '@/api/requirement'
 import { teamQueryTeamInfoList } from '@/api/configure'
-import {
-  getBugCountTrend,
-  getRepairTimeSumData
-} from '@/api/defectStatistics'
 import {
   getSummary,
-  CumulativeFlowDiagram,
+  getCumulativeFlowDiagram,
+  getRequireCountTrend,
+  getRequirePeriodicData,
+  getRequireRdDeliveryPeriodicData,
   getDistributeData,
   getStatusStayData,
   getOrntDistributeData
@@ -168,17 +169,19 @@ import {
 import statusChart from './components/statusChart'
 import tendencyChart from './components/tendencyChart'
 import cycleStatistic from './components/cycleStatistic'
+import developmentCycle from './components/developmentCycle'
 import distributionChart from './components/distributionChart'
 import statusStayChart from './components/statusStayChart'
-import belongChart from './components/belongChart'
+// import belongChart from './components/belongChart'
 export default {
   components: {
     statusChart,
     tendencyChart,
     cycleStatistic,
+    developmentCycle,
     distributionChart,
-    statusStayChart,
-    belongChart
+    statusStayChart
+    // belongChart
   },
   data() {
     return {
@@ -198,6 +201,7 @@ export default {
       cumulativeData: null, // 需求状态累计流数据
       tendencyData: null, // 趋势图数据
       cycleData: [], // 周期统计数据
+      developmentCycleData: [], // 研发交付周期分布数据
       distributeStatus: 1, // 需求分布图需求状态
       distributeStatusList: [
         { code: 1, label: '需求状态' },
@@ -208,7 +212,8 @@ export default {
       ], // 需求分布图需求状态列表
       orntDistributeData: null, // 所属需求方向数据
       distributeData: null, // 需求分布图数据
-      statusStayData: null // 状态停留图数据
+      statusStayData: null, // 状态停留图数据
+      moduleDistribute: null // 模块分布图数据
     }
   },
   computed: {
@@ -225,6 +230,26 @@ export default {
         }
         return params
       }
+    },
+    timeType: {
+      get() {
+        let timeType = 0
+        switch (this.dateType) {
+          case 'week':
+            timeType = 1
+            break
+          case 'month':
+            timeType = 2
+            break
+          case 'year':
+            timeType = 3
+            break
+          default:
+            timeType = 0
+            break
+        }
+        return timeType
+      }
     }
   },
   created() {
@@ -238,10 +263,14 @@ export default {
   },
   methods: {
     onSubmit() {
+      if (this.activeTab === '2' && this.distributeStatus === 1) {
+        this.distributeStatus = 2
+      }
       this.getSummary()
       this.getCumulativeFlowDiagram()
-      this.defectTrendTimeChange()
+      this.getRequireCountTrend()
       this.getCycleData()
+      this.getDevelopmentCycle()
       this.getOrntDistributeData()
       this.getDistributeData()
       this.getStatusStayData()
@@ -293,51 +322,40 @@ export default {
       const res = await getSummary(this.globalParams)
       if (res.code === 200) this.Summary = res.data || []
     },
-    async defectTrendTimeChange() { // 趋势图日期变动
-      const rqmtOrntIds = this.chartForm.rqmtOrntIds
+    async getRequireCountTrend() { // 趋势图日期变动
       const params = {
-        beginTime: this.stratAndEnd[0] || null,
-        endTime: this.stratAndEnd[1] || null,
-        bizId: Number(localStorage.getItem('bizId')),
-        teamIds: this.chartForm.team || null,
-        rqmtOrntIds: rqmtOrntIds && rqmtOrntIds.length > 0 ? rqmtOrntIds : null,
-        timeType: this.bugCountTimeType
+        ...this.globalParams,
+        type: Number(this.activeTab),
+        timeType: this.timeType
       }
-      const res = await getBugCountTrend(params)
+      const res = await getRequireCountTrend(params)
       if (res.code === 200) this.tendencyData = res.data
     },
     async getCumulativeFlowDiagram() { // 需求状态累计流图
-      let timeType = 0
-      switch (this.dateType) {
-        case 'week':
-          timeType = 1
-          break
-        case 'month':
-          timeType = 2
-          break
-        case 'year':
-          timeType = 3
-          break
-        default:
-          timeType = 0
-          break
-      }
       const params = {
         ...this.globalParams,
-        timeType: timeType
+        timeType: this.timeType
       }
-      const res = await CumulativeFlowDiagram(params)
+      const res = await getCumulativeFlowDiagram(params)
       if (res.code === 200) this.cumulativeData = res.data
     },
     async getCycleData() { // 周期统计数据
       const params = {
         ...this.globalParams,
-        type: 1
+        type: Number(this.activeTab)
       }
-      const res = await getRepairTimeSumData(params)
+      const res = await getRequirePeriodicData(params)
       if (res.code === 200) this.cycleData = res.data
     },
-    async getDistributeData() { // 获取需求统计
+    async getDevelopmentCycle() { // 获取研发交付周期分布数据
+      const params = {
+        ...this.globalParams,
+        type: Number(this.activeTab)
+      }
+      const res = await getRequireRdDeliveryPeriodicData(params)
+      if (res.code === 200) this.developmentCycleData = res.data
+    },
+    async getDistributeData() { // 获取需求分布图
       const params = {
         ...this.globalParams,
         type: Number(this.activeTab),
@@ -360,12 +378,23 @@ export default {
         type: Number(this.activeTab)
       }
       const res = await getOrntDistributeData(params)
-      if (res.code === 200) {
-        this.orntDistributeData = {
-          xaxis: res.data.map(item => item.name),
-          yaxis: [{ data: res.data.map(item => item.count) }]
+      if (res.code === 200) this.orntDistributeData = this.handlerData(res.data)
+    },
+    handlerData(arr) { // 处理需求方向分布图数据
+      let num = 0
+      const bfs = (arr) => {
+        for (const item of arr) {
+          item.count++
+          num = num + item.count
+          if (item.children && item.children.length > 0) {
+            bfs(item.children)
+          } else {
+            delete item.children
+          }
         }
       }
+      bfs(arr)
+      return { children: arr, name: '总量', count: num }
     }
   }
 }