wangziqian 5 жил өмнө
parent
commit
408cb0ce0b

+ 8 - 0
src/api/statisticsApi/requireStatistics.js

@@ -9,3 +9,11 @@ export function getDistributeData(data) {
     data
   })
 }
+// 状态停留时长分布
+export function getStatusStayData(data) {
+  return request({
+    url: TeamManagement + '/requirement/getStatusStayData',
+    method: 'post',
+    data
+  })
+}

+ 140 - 0
src/views/quality/components/distributionChart.vue

@@ -0,0 +1,140 @@
+<template>
+  <section>
+    <div class="chart-contain">
+      <el-row type="flex" align="middle">
+        <el-col :span="4">
+          <el-select v-model="curStatus" size="small" @change="statusChange">
+            <el-option
+              v-for="item in statusList"
+              :key="item.code"
+              :label="item.label"
+              :value="item.code"
+            />
+          </el-select>
+        </el-col>
+        <el-col :span="4" :offset="16" 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>
+      <normal-echart v-if="echartsOption" :chart-id="id" :option="echartsOption" />
+    </div>
+  </section>
+</template>
+<script>
+import normalEchart from '@/components/chart/normalEchart'
+export default {
+  components: { normalEchart },
+  props: {
+    id: {
+      type: String,
+      default: 'distribute-chart',
+      required: false
+    },
+    statusList: {
+      type: Array,
+      default: () => [],
+      required: true
+    },
+    chartData: {
+      type: Object,
+      default: () => null,
+      required: false
+    },
+    status: {
+      type: Number,
+      default: NaN,
+      required: true
+    }
+  },
+  data() {
+    return {
+      echartsOption: null,
+      curStatus: 1, // 当前状态
+      barOrPie: 'bar' // 柱状图or饼图
+    }
+  },
+  watch: {
+    chartData: {
+      handler(newV) {
+        this.changeBarOrPie(this.barOrPie)
+      },
+      deep: true
+    },
+    status: {
+      handler(newV) {
+        this.status = newV
+      },
+      immediate: true
+    }
+  },
+  mounted() {
+    this.changeBarOrPie(this.barOrPie)
+  },
+  methods: {
+    statusChange(e) {
+      this.$emit('update:status', e)
+      this.$emit('change')
+    },
+    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: 40 }, 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 }}}
+          }]
+        }
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.chart-contain {
+  position: relative;
+  height: 400px;
+  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>

+ 4 - 4
src/views/quality/components/statusChart.vue

@@ -1,10 +1,10 @@
 <template>
   <section>
-    <div class="control">
-      <div class="pile-line" :class="[pileOrLine==='pile'?'active':'']" @click="changePileOrLine('pile')">堆叠面积图</div>
-      <div class="pile-line" :class="[pileOrLine==='line'?'active':'']" @click="changePileOrLine('line')">折线图</div>
-    </div>
     <div class="chart-contain">
+      <div class="control">
+        <div class="pile-line" :class="[pileOrLine==='pile'?'active':'']" @click="changePileOrLine('pile')">堆叠面积图</div>
+        <div class="pile-line" :class="[pileOrLine==='line'?'active':'']" @click="changePileOrLine('line')">折线图</div>
+      </div>
       <normal-echart v-if="echartsOption" :chart-id="id" :option="echartsOption" />
     </div>
   </section>

+ 1 - 1
src/views/quality/components/tendencyChart.vue

@@ -17,7 +17,7 @@ export default {
     },
     chartData: {
       type: Object,
-      default: null,
+      default: () => null,
       required: false
     }
   },

+ 76 - 32
src/views/quality/requireStatistics.vue

@@ -1,7 +1,7 @@
 <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 :model="chartForm" 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>
@@ -23,10 +23,10 @@
           />
         </el-form-item>
       </el-form>
-      <el-form :model="defectForm" class="demo-form-inline" :inline="true">
+      <el-form :model="chartForm" class="demo-form-inline" :inline="true">
         <el-form-item label="责任团队:">
           <el-select
-            v-model="defectForm.team"
+            v-model="chartForm.team"
             placeholder="请选择"
             size="small"
             clearable
@@ -47,16 +47,20 @@
             </el-option-group>
           </el-select>
         </el-form-item>
-        <el-form-item label="模块:">
+        <el-form-item label="需求方向:">
           <el-cascader
-            v-model="defectForm.moduleIds"
+            v-model="chartForm.rqmtOrntIds"
             size="small"
             clearable
             collapse-tags
-            :props="{ multiple: true }"
+            :props="{
+              value: 'id',
+              label: 'rqmtOrntName',
+              children: 'childRqmtOrnts',
+              multiple: true
+            }"
             :options="moduleList"
             placeholder="请选择"
-            @click.native="bugDataGet"
           />
         </el-form-item>
         <el-form-item>
@@ -97,11 +101,11 @@
         <h3>状态累积流量图</h3>
         <status-chart />
       </div>
-      <el-tabs v-model="activeName" class="tab-change">
-        <el-tab-pane name="first">
+      <el-tabs v-model="activeTab" class="tab-change">
+        <el-tab-pane name="1">
           <span slot="label" class="tab-item">累计新增</span>
         </el-tab-pane>
-        <el-tab-pane name="second">
+        <el-tab-pane name="2">
           <span slot="label" class="tab-item">累计上线</span>
         </el-tab-pane>
       </el-tabs>
@@ -124,24 +128,38 @@
           <span>仅统计状态已变更“已排期”且排期不为空的任务;横坐标表示任务交付日期,纵坐标代表研发交付周期(研发、联调、上线类型排期的总周期)</span>
         </div>
       </div>
+      <div class="chart-item">
+        <h3>需求分布图</h3>
+        <distribution-chart
+          :chart-data="distributeData"
+          :status-list="distributeStatusList"
+          :status.sync="distributeStatus"
+          @change="getDistributeData()"
+        />
+      </div>
     </el-main>
   </el-container>
 </template>
 <script>
 import moment from 'moment'
 moment.locale('zh-cn')
-import { settingQueryBizModuleList } from '@/api/defectManage'
+import { settingQueryBizRqmtOrntList } from '@/api/requirement'
 import { teamQueryTeamInfoList } from '@/api/configure'
 import {
   getSummary,
   getBugCountTrend,
   getRepairTimeSumData
 } from '@/api/defectStatistics'
+import {
+  getDistributeData,
+  getStatusStayData
+} from '@/api/statisticsApi/requireStatistics'
 import statusChart from './components/statusChart'
 import tendencyChart from './components/tendencyChart'
 import cycleStatistic from './components/cycleStatistic'
+import distributionChart from './components/distributionChart'
 export default {
-  components: { statusChart, tendencyChart, cycleStatistic },
+  components: { statusChart, tendencyChart, cycleStatistic, distributionChart },
   data() {
     return {
       bugCountTimeType: 1, // 获取趋缺陷势图数据接口入参:1本周 2本月 3本年
@@ -151,26 +169,36 @@ export default {
         { code: 3, label: '年' }
       ],
       teamOptions: [], // 团队列表
-      defectForm: {}, // 筛选表单
+      chartForm: {}, // 筛选表单
       stratAndEnd: [], // 开始结束日期
       dateType: 'week', // 时间选择类型
-      moduleList: [], // 模块列表
+      moduleList: [], // 需求方向列表
       Summary: [], // 顶部数据
-      activeName: 'first', // tab标签
+      activeTab: '1', // tab标签
       tendencyData: null, // 趋势图数据
-      cycleData: [] // 周期统计数据
+      cycleData: [], // 周期统计数据
+      distributeStatus: 1, // 需求分布图需求状态
+      distributeStatusList: [
+        { code: 1, label: '需求状态' },
+        { code: 2, label: '需求等级' },
+        { code: 3, label: '需求类型' },
+        { code: 4, label: 'pm' },
+        { code: 5, label: '跟版客户端' }
+      ], // 需求分布图需求状态列表
+      distributeData: null // 需求分布图数据
     }
   },
   computed: {
     globalParams: { // 通用接口参数
       get() {
-        const moduleIds = this.defectForm.moduleIds
+        const rqmtOrntIds = this.chartForm.rqmtOrntIds
+        const team = this.chartForm.team
         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
+          teamIds: team && team.length > 0 ? team : null,
+          rqmtOrntIds: rqmtOrntIds && rqmtOrntIds.length > 0 ? rqmtOrntIds : null
         }
         return params
       }
@@ -180,6 +208,7 @@ export default {
     this.$store.state.data.status = true
     this.setDate(this.dateType)
     this.getTeamList()
+    this.getRequireDirection()
   },
   mounted() {
     this.onSubmit()
@@ -189,6 +218,7 @@ export default {
       this.getSummary()
       this.defectTrendTimeChange()
       this.getCycleData()
+      this.getDistributeData()
     },
     setDate(type) { // 日期筛选
       let startDate = null
@@ -213,17 +243,17 @@ export default {
       this.stratAndEnd = [startDate, endDate]
       this.onSubmit()
     },
-    async bugDataGet() { // 所属模块
-      const res = await settingQueryBizModuleList(Number(localStorage.getItem('bizId')))
-      this.moduleList = this.handlerModules(res.data)
+    async getRequireDirection() { // 需求方向列表
+      const res = await settingQueryBizRqmtOrntList(Number(localStorage.getItem('bizId')))
+      if (res.code === 200) {
+        this.moduleList = this.getRequireData(res.data)
+      }
     },
-    handlerModules(arr) { // 模块数据处理
-      return arr.map(item => ({
-        ...item,
-        value: item.id,
-        label: item.moduleName,
-        children: item.childModules.length ? this.handlerModules(item.childModules) : null
-      }))
+    getRequireData(data) {
+      for (let i = 0; i < data.length; i++) {
+        data[i].childRqmtOrnts.length < 1 ? delete data[i].childRqmtOrnts : this.getRequireData(data[i].childRqmtOrnts)
+      }
+      return data
     },
     async getTeamList() { // 获取我的团队和所有团队
       const myRes = await teamQueryTeamInfoList({ type: 0 })// 我的团队
@@ -238,13 +268,13 @@ export default {
       if (res.code === 200) this.Summary = res.data || []
     },
     async defectTrendTimeChange() { // 趋势图日期变动
-      const moduleIds = this.defectForm.moduleIds
+      const rqmtOrntIds = this.chartForm.rqmtOrntIds
       const params = {
         beginTime: 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,
+        teamIds: this.chartForm.team || null,
+        rqmtOrntIds: rqmtOrntIds && rqmtOrntIds.length > 0 ? rqmtOrntIds : null,
         timeType: this.bugCountTimeType
       }
       const res = await getBugCountTrend(params)
@@ -257,6 +287,20 @@ export default {
       }
       const res = await getRepairTimeSumData(params)
       if (res.code === 200) this.cycleData = res.data
+    },
+    async getDistributeData() { // 获取需求统计
+      const params = {
+        ...this.globalParams,
+        type: Number(this.activeTab),
+        distributeType: this.distributeStatus
+      }
+      const res = await getDistributeData(params)
+      if (res.code === 200) {
+        this.distributeData = res.data
+      }
+    },
+    async getStatusStayData() { // 状态停留时长分布
+
     }
   }
 }