Browse Source

优化

master
陈裕财 3 years ago
parent
commit
2a8e1db303
  1. 281
      src/views/xm/core/xmTestPlan/rpt/CompsCard.vue
  2. 304
      src/views/xm/core/xmTestPlan/rpt/CompsSet.vue
  3. 299
      src/views/xm/core/xmTestPlan/rpt/biz/productWorkItemDayList.vue
  4. 334
      src/views/xm/core/xmTestPlan/rpt/biz/question.vue
  5. 259
      src/views/xm/core/xmTestPlan/rpt/biz/questionAgeDist.vue
  6. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionAskUserSort.vue
  7. 334
      src/views/xm/core/xmTestPlan/rpt/biz/questionAttDist.vue
  8. 47
      src/views/xm/core/xmTestPlan/rpt/biz/questionBugReasonDist.vue
  9. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionBugSeverityDist.vue
  10. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionBugStatusDist.vue
  11. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionBugTypeDist.vue
  12. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionFuncSort.vue
  13. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionHandlerUserSort.vue
  14. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionMenuSort.vue
  15. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionPriorityDist.vue
  16. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionRepRateDist.vue
  17. 275
      src/views/xm/core/xmTestPlan/rpt/biz/questionRetestDist.vue
  18. 48
      src/views/xm/core/xmTestPlan/rpt/biz/questionSolutionDist.vue
  19. 282
      src/views/xm/core/xmTestPlan/rpt/biz/questionSort.vue
  20. 203
      src/views/xm/core/xmTestPlan/rpt/biz/testCaseToPlanCalc.vue
  21. 188
      src/views/xm/core/xmTestPlan/rpt/biz/testDayTimesCalc.vue
  22. 222
      src/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseExecStatusDist.vue
  23. 249
      src/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseUserDist.vue
  24. 10
      src/views/xm/core/xmTestPlan/rpt/common.scss
  25. BIN
      src/views/xm/core/xmTestPlan/rpt/images/area-stack.png
  26. BIN
      src/views/xm/core/xmTestPlan/rpt/images/bar.png
  27. BIN
      src/views/xm/core/xmTestPlan/rpt/images/dataset-link.png
  28. BIN
      src/views/xm/core/xmTestPlan/rpt/images/line-stack.png
  29. BIN
      src/views/xm/core/xmTestPlan/rpt/images/pie-simple.png
  30. BIN
      src/views/xm/core/xmTestPlan/rpt/images/ranjintu.png
  31. 98
      src/views/xm/core/xmTestPlan/rpt/index.scss
  32. 58
      src/views/xm/core/xmTestPlan/rpt/index.vue
  33. 1
      src/views/xm/rpt/CompsSet.vue
  34. 1
      src/views/xm/rpt/comps.js
  35. 407
      src/views/xm/rpt/testPlan/testPlanRptOverview.vue

281
src/views/xm/core/xmTestPlan/rpt/CompsCard.vue

@ -1,281 +0,0 @@
<template>
<section>
<el-row class="page-center border" v-if="printVisible==false">
<el-col :span="6" :style="{height:maxTableHeight+'px',overflow:'auto'}">
<comps-set v-if="rptConfigVisible" :comp-ids="compIds" @row-click="onCompSelect"></comps-set>
</el-col>
<el-col :span="18" :style="{height:maxTableHeight+'px',overflow:'auto'}" ref="table" class="border">
<div>
<div class="empty" v-if="compCfgList.length == 0" >
<el-empty description="暂未选择模块"></el-empty>
</div>
<div v-else>
<grid-layout
:layout.sync="compCfgList"
:col-num="layoutColNum"
:row-height="120"
:is-draggable="true"
:is-resizable="true"
:is-mirrored="false"
:vertical-compact="true"
:margin="[10, 10]"
:use-css-transforms="true"
>
<grid-item
v-for="(item,index) in compCfgList"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="index" @resize="sizeAutoChange(item)">
<component :is="item.compId" :xm-test-plan="xmTestPlan" :comp-cfg="item" :ref="item.id" @delete="doDelete" :id="item.id+'-id'"></component>
</grid-item>
</grid-layout>
</div>
</div>
</el-col>
</el-row>
<el-row v-if="printVisible" class="page-center border" style="width:1000px;">
<el-row>
<span style="float:right;"><el-button @click="printVisible=false">取消打印</el-button> <el-button v-print="'#printBody'">打印</el-button></span>
</el-row>
<el-row id="printBody">
<el-row v-for="(item,index) in compCfgList" :key="index">
<component :is="item.compId" :xm-test-plan="xmTestPlan" :comp-cfg="item" :ref="item.id" @delete="doDelete"></component>
</el-row>
</el-row>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import seq from '@/common/js/sequence';//
import VueGridLayout from 'vue-grid-layout';
import { mapGetters } from 'vuex'
import XmTestPlanMng from '@/views/xm/core/xmTestPlan/XmTestPlanMng'
import CompsSet from '@/views/xm/core/xmTestPlan/rpt/CompsSet'
import XmQuestionAgeDist from '@/views/xm/core/xmTestPlan/rpt/biz/questionAgeDist'
import xmQuestionAttDist from '@/views/xm/core/xmTestPlan/rpt/biz/questionAttDist'
import xmQuestionRetestDist from '@/views/xm/core/xmTestPlan/rpt/biz/questionRetestDist'
import xmQuestionHandlerUserSort from '@/views/xm/core/xmTestPlan/rpt/biz/questionHandlerUserSort'
import xmQuestionAskUserSort from '@/views/xm/core/xmTestPlan/rpt/biz/questionAskUserSort'
import xmQuestionMenuSort from '@/views/xm/core/xmTestPlan/rpt/biz/questionMenuSort'
import xmQuestionFuncSort from '@/views/xm/core/xmTestPlan/rpt/biz/questionFuncSort'
import xmTestPlanCaseExecStatusDist from '@/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseExecStatusDist'
import xmTestPlanCaseUserDist from '@/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseUserDist'
import xmTestCaseToPlanCalc from '@/views/xm/core/xmTestPlan/rpt/biz/testCaseToPlanCalc'
import xmTestDayTimesCalc from '@/views/xm/core/xmTestPlan/rpt/biz/testDayTimesCalc'
import xmTestRptOverview from '@/views/xm/core/xmTestPlan/xmTestRptOverview'
import { initDicts,listXmRptConfig, delXmRptConfig,editXmRptConfig,addXmRptConfig,batchDelXmRptConfig,editSomeFieldsXmRptConfig } from '@/api/xm/core/xmRptConfig';
export default {
components: {
GridLayout: VueGridLayout.GridLayout,
GridItem: VueGridLayout.GridItem,
XmTestPlanMng,
XmQuestionAgeDist,
xmQuestionAttDist,
xmQuestionHandlerUserSort,xmQuestionAskUserSort,xmQuestionMenuSort,xmQuestionFuncSort,
xmTestPlanCaseExecStatusDist,
xmTestPlanCaseUserDist,
CompsSet,
xmTestRptOverview,
xmQuestionRetestDist,
xmTestCaseToPlanCalc,
xmTestDayTimesCalc,
"xmQuestionBugReasonDist":()=>import("./biz/questionBugReasonDist.vue"),
"xmQuestionBugStatusDist":()=>import("./biz/questionBugStatusDist.vue"),
"xmQuestionBugTypeDist":()=>import("./biz/questionBugTypeDist.vue"),
"xmQuestionRepRateDist":()=>import("./biz/questionRepRateDist.vue"),
"xmQuestionBugSeverityDist":()=>import("./biz/questionBugSeverityDist.vue"),
"xmQuestionSolutionDist":()=>import("./biz/questionSolutionDist.vue"),
"xmQuestionPriorityDist":()=>import("./biz/questionPriorityDist.vue"),
"productWorkItemDayList":()=>import("./biz/productWorkItemDayList.vue"),
},
props:['xmTestPlan','rptConfigVisible'],
computed: {
...mapGetters(['userInfo']),
compIds(){
return this.compCfgList.map(k=>k.compId)
},
},
watch: {
xmRptConfig:{
handler(){
this.initCompCfgList();
},
deep:true,
},
rptConfigVisible(){
if(this.rptConfigVisible==true){
this.$nextTick(()=>{
this.compCfgList.forEach(k=>{
this.sizeAutoChange(k);
})
})
}
},
},
data() {
return {
xmRptConfig:null,
compCfgList:[],
maxTableHeight:300,
//
initCompCfg: [
{ i:0, x: 0, y: 12, w: 12, h: 6, id:'productWorkItemDayList',name:'测试计划总览',compId:'productWorkItemDayList', params:{} },
{ i:0, x: 0, y: 12, w: 12, h: 6, id:'xmTestRptOverview',name:'测试计划总览',compId:'xmTestRptOverview', params:{} },
{ i: 1, x: 0, y: 12, w: 12, h: 6, id:'xmTestCaseToPlanCalc',name:'用例规划分析', compId:'xmTestCaseToPlanCalc', },
{ i: 2, x: 0, y: 12, w: 12, h: 6, id:'xmTestDayTimesCalc',name:'用例每日执行统计', compId:'xmTestDayTimesCalc', },
{ i: 3, x: 0, y: 12, w: 12, h: 6, id:'xmTestPlanCaseExecStatusDist',name:'用例执行结果分布', compId:'xmTestPlanCaseExecStatusDist', },
{ i: 4, x: 0, y: 12, w: 12, h: 6, id:'xmTestPlanCaseUserDist',name:'用例执行人情况分布', compId:'xmTestPlanCaseUserDist', },
{ i:5, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionMenuSort',name:'缺陷需求分布', compId:'xmQuestionMenuSort', },
{ i: 6, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionFuncSort',name:'缺陷模块分布', compId:'xmQuestionFuncSort', },
{ i: 7, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionBugStatusDist',name:'缺陷状态分布',compId:'xmQuestionBugStatusDist', },
{ i:8, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionAgeDist',name:'缺陷年龄分布',compId:'xmQuestionAgeDist', params:{} },
{ i:9, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionBugReasonDist',name:'缺陷原因分布',compId:'xmQuestionBugReasonDist', params:{} },
{ i:10, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionPriorityDist',name:'缺陷紧急程度分布',compId:'xmQuestionPriorityDist', params:{} },
{ i: 11, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionAskUserSort',name:'缺陷提出人排行榜', compId:'xmQuestionAskUserSort', },
{ i: 12, x: 0, y: 12, w: 12, h: 6, id:'xmQuestionHandlerUserSort',name:'缺陷负责人排行榜',compId:'xmQuestionHandlerUserSort', },
],
//
layoutColNum: 12,
printVisible:false,
}
},
methods: {
initData(){
this.getXmRptConfig();
},
getXmRptConfig(){
if(!this.xmTestPlan){
return;
}
listXmRptConfig({bizId:this.xmTestPlan.id}).then(res=>{
this.xmRptConfig=res.data.data[0]
})
},
initCompCfgList(){
if(this.xmRptConfig && this.xmRptConfig.cfg){
var cfgJson=JSON.parse(this.xmRptConfig.cfg)
this.compCfgList=cfgJson;
}else{
this.compCfgList=JSON.parse(JSON.stringify(this.initCompCfg))
}
},
onCompSelect(comp){
if(this.compCfgList.some(k=>k.compId==comp.compId)){
var compCfg=this.compCfgList.find(k=>k.compId==comp.compId)
this.$nextTick(()=>{
this.scrollToComp(compCfg)
})
return;
}
var compCfgListTemp=JSON.parse(JSON.stringify(this.compCfgList))
compCfgListTemp.sort((i1,i2)=>{
return i2.i-i1.i
})
var maxI=(compCfgListTemp.length>0?(compCfgListTemp[0].i+1):1);
compCfgListTemp.sort((i1,i2)=>{
return i2.y-i1.y
})
var maxY=(compCfgListTemp.length>0?(compCfgListTemp[0].y+6):0);
var compCfg={i:maxI, x: 0, y: maxY, w: 12, h: 6, compId:comp.compId,name:comp.name,id:comp.compId+seq.sn(),params:{}}
this.compCfgList.push(compCfg)
this.$nextTick(()=>{
setTimeout(()=>{
this.scrollToComp(compCfg)
},100)
})
},
scrollToComp(compCfg){
var doc=document.getElementById(compCfg.id+'-id')
if(doc){
doc.scrollIntoView(false)
}
},
submitXmPrtConfig(callback){
if(this.xmRptConfig==null){
var xmRptConfig={name:this.xmTestPlan.name,bizId:this.xmTestPlan.id,cfg:[]}
var compCfgList=JSON.parse(JSON.stringify(this.compCfgList))
compCfgList.forEach(k=>{
if(this.$refs[k.id] && this.$refs[k.id][0].$refs && this.$refs[k.id][0].$refs[k.id]){
k.params=this.$refs[k.id][0].$refs[k.id].filters
}else{
k.params=this.$refs[k.id][0].filters
}
})
xmRptConfig.cfg=JSON.stringify(compCfgList)
addXmRptConfig(xmRptConfig).then(res=>{
this.xmRptConfig=xmRptConfig;
callback()
})
}else{
var xmRptConfig={id:this.xmRptConfig.id,name:this.xmTestPlan.name,bizId:this.xmTestPlan.id,cfg:[]}
var compCfgList=JSON.parse(JSON.stringify(this.compCfgList))
compCfgList.forEach(k=>{
if(this.$refs[k.id] && this.$refs[k.id][0].$refs && this.$refs[k.id][0].$refs[k.id]){
k.params=this.$refs[k.id][0].$refs[k.id].filters
}else{
k.params=this.$refs[k.id][0].filters
}
})
xmRptConfig.cfg=JSON.stringify(compCfgList)
editXmRptConfig(xmRptConfig).then(res=>{
this.xmRptConfig=xmRptConfig;
callback()
})
}
},
doDelete(compCfg){
if(this.rptConfigVisible==false){
this.$notify({ position:'bottom-left', showClose:true, message: "当前报告为预览模式,不能删除,请切换为配置报告模式", type: 'error' });
return;
}
var index=this.compCfgList.findIndex(k=>k.id==compCfg.id)
if(index>=0){
this.compCfgList.splice(index,1)
}
},
sizeAutoChange(k){
if(this.$refs[k.id] && this.$refs[k.id][0].$refs && this.$refs[k.id][0].$refs[k.id]){
this.$refs[k.id][0].$refs[k.id].sizeAutoChange();
}else{
this.$refs[k.id][0].sizeAutoChange();
}
}
},
mounted() {
this.$nextTick(() => {
this.initData();
this.maxTableHeight = util.calcTableMaxHeight(this.$refs.table.$el)
})
},
}
</script>
<style>
</style>

304
src/views/xm/core/xmTestPlan/rpt/CompsSet.vue

@ -1,304 +0,0 @@
<template>
<div class="moduleset">
<div class="nav">
<div class="nav_item" :class="{itemActive: item.isChecked}" v-for="(item, index) in compsCpd" :key="index" @click="selectItem(item, index)">
<img :src="item.icon" alt="">
<div class="desc">
<p>{{item.name}}</p>
<span>
{{item.compDesc}}
</span>
</div>
<i v-if="item.isChecked" class="el-icon-success"></i>
</div>
</div>
</div>
</template>
<script>
import img1 from '../../../../myWork/img/dsp.png'
import img2 from '../../../../myWork/img/wdrw.png'
import img3 from '../../../../myWork/img/wdxm.png'
import img4 from '../../../../myWork/img/wdcp.png'
import pieSimple from './images/pie-simple.png'
import lineStack from './images/line-stack.png'
import areaStack from './images/area-stack.png'
import ranjintu from './images/ranjintu.png'
import datasetLink from './images/dataset-link.png'
import bar from './images/bar.png'
import { mapGetters } from 'vuex'
export default {
props: ['compIds' ],
computed: {
...mapGetters(['userInfo']),
compsCpd(){
var comps=this.comps;
if(this.compIds && this.compIds.length>0){
comps.forEach(i=>{
i.isChecked=this.compIds.some(k=>k==i.compId)
})
}
return comps;
}
},
watch: {
},
data() {
return {
comps: [
{
compId: 'xmTestRptOverview',
icon: img1,
name: '报告总览',
compDesc: '测试报告总体概览,包括测试总结,测试用例总数、通过率、覆盖率、缺陷数、测试时间等',
isChecked: false,
},
{
compId: 'xmTestCaseToPlanCalc',
icon: pieSimple,
name: '用例规划分析',
compDesc: '统计用例库中规划到测试计划的用例数量情况',
isChecked: false,
},
{
compId: 'xmTestPlanCaseExecStatusDist',
icon: pieSimple,
name: '用例执行结果分布',
compDesc: '按测试用例执行结果统计,通过、失败、忽略、阻塞',
isChecked: false,
},
{
compId: 'xmTestPlanCaseUserDist',
icon: bar,
name: '测试用例成员执行结果分布',
compDesc: '统计测试用例负责人用例执行情况',
isChecked: false,
},
{
compId: 'xmTestDayTimesCalc',
icon: lineStack,
name: '每日测试次数统计',
compDesc: '统计每日执行的测试用例数',
isChecked: false,
},
{
compId: 'xmQuestionFuncSort',
icon: lineStack,
name: '缺陷模块分布',
compDesc: '统计缺陷在各个模块的分布情况',
isChecked: false,
},
{
compId: 'xmQuestionMenuSort',
icon: lineStack,
name: '缺陷故事分布',
compDesc: '统计缺陷在各个用户故事的分布情况',
isChecked: false,
},
{
compId: 'xmQuestionAskUserSort',
icon: bar,
name: '缺陷提出人排行榜',
compDesc: '统计每个提出人的缺陷总数,并按大小进行排序',
isChecked: false,
},
{
compId: 'xmQuestionHandlerUserSort',
icon: bar,
name: '缺陷负责人员排行榜',
compDesc: '统计每个负责人的缺陷总数,并按大小进行排序',
isChecked: false,
},
{
compId: 'xmQuestionRetestDist',
icon: pieSimple,
name: '缺陷回归测试分布',
compDesc: '统计回归测试的次数与缺陷数',
isChecked: false,
},
{
compId: 'xmQuestionAttDist',
icon: pieSimple,
name: '缺陷属性分布',
compDesc: '按缺陷的属性进行统计,多种属性可选择',
isChecked: false,
},
{
compId: 'xmQuestionBugStatusDist',
icon: pieSimple,
name: '缺陷状态分布',
compDesc: '按缺陷状态进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionBugReasonDist',
icon: pieSimple,
name: '缺陷原因分布',
compDesc: '按缺陷原因进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionBugTypeDist',
icon: pieSimple,
name: '缺陷类型分布',
compDesc: '按缺陷类型进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionRepRateDist',
icon: pieSimple,
name: '缺陷重现频率分布',
compDesc: '按缺陷重现频率进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionSolutionDist',
icon: pieSimple,
name: '缺陷解决方案分布',
compDesc: '按缺陷解决方案进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionBugSeverityDist',
icon: pieSimple,
name: '缺陷紧急程度分布',
compDesc: '按缺陷紧急程度进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionPriorityDist',
icon: pieSimple,
name: '缺陷优先级分布',
compDesc: '按缺陷优先级进行分组统计',
isChecked: false,
},
{
compId: 'xmQuestionAgeDist',
icon: pieSimple,
name: '缺陷年龄分布',
compDesc: '统计各个时间长度的缺陷总数',
isChecked: false,
}
],
}
},
methods: {
selectItem(item){
this.$emit("row-click",item)
}
}
}
</script>
<style lang="scss">
.moduleset .el-dialog__header {
padding: 0;
}
.moduleset .el-divider--horizontal {
margin: 0 !important;
}
</style>
<style lang="scss" scoped>
.moduleset {
.dialog-title {
font-size: 22px;
font-weight: bold;
color: #7D7D7D;
height: 68px;
p {
line-height: 68px;
margin-left: 28px;
}
}
.toolBox {
display: flex;
flex-direction: column;
.selectItem {
display: flex;
flex-direction: row;
height: 70px;
.item {
display: flex;
flex-direction: row;
margin-right: 120px;
cursor: pointer;
margin: 25px 50px 0 20px;
img {
width: 45px;
height: 45px;
}
span {
margin-left: 8px;
}
}
}
}
.nav {
overflow: auto;
display:flex;
align-items:center;
justify-content: space-between;
flex-wrap:wrap;
padding-right: 5px;
.nav_item {
height: 100px;
padding:2px;
display: flex;
flex-direction: row;
border: 2px solid #EDF0F9;
box-shadow: 0px 3px 4px 0px rgba(186, 184, 184, 0.1);
border-radius: 8px;
align-items: center;
position: relative;
cursor: pointer;
margin-top: 10px;
width:100%;
img {
object-fit:cover;
max-width: 25%;
max-height: 80%;
padding: 2px;
}
p {
font-size: 18px;
font-weight: bold;
color: #7D7D7D;
margin-bottom: 10px;
}
span {
font-size: 14px;
color: #7D7D7D;
line-height: 16px;
}
i {
position: absolute;
top: 10px;
right: 10px;
font-size: 30px;
color: #90B1F4;
}
}
.itemActive {
border: 2px solid #90B1F4;
box-shadow: 0px 3px 4px 0px rgba(186, 184, 184, 0.1);
}
}
}
</style>

299
src/views/xm/core/xmTestPlan/rpt/biz/productWorkItemDayList.vue

@ -1,299 +0,0 @@
<template>
<section>
<el-row :gutter="5" >
<el-col :span="18">
<div>
<div class="echart-box" id="productWorkItemDayList" :style="{width:'100%',height:(maxTableHeight>600?600:maxTableHeight)+'px',overflow: 'hidden'}"></div>
</div>
</el-col>
<el-col :span="6" class="border">
<el-form :model="filters" class="padding" :style="{width:'100%',maxHeight:maxTableHeight+'px',overflow: 'auto'}" ref="filtersRef">
<el-form-item label="归属产品" >
<xm-product-select v-if="!xmProductCpd || !xmProductCpd.id" ref="xmProductSelect" style="display:inline;" :auto-select="false" :link-project-id="xmProject?xmProject.id:null" @row-click="onProductSelected" :iterationId="xmIteration?xmIteration.id:null" @clear="onProductClear"></xm-product-select>
<span v-else>{{xmProductCpd.id}} <span v-if="xmProductCpd.productName"><br/>{{ xmProductCpd.productName }} </span> </span>
</el-form-item>
<el-form-item label="日期区间">
<br>
<mdp-date-range v-model="filters" value-format="yyyy-MM-dd" start-key="startBizDate" end-key="endBizDate"></mdp-date-range>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="listXmProductStateHis">查询</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
import { listXmProductStateHis } from '@/api/xm/core/xmProductStateHis';
export default {
components: {
XmProductSelect,
},
props:['xmProduct','xmProject'],
computed: {
...mapGetters([
'userInfo','roles'
]),
dataSetCpd(){
return [
['日期',...this.xmProductStateHiss.map(i=>i.bizDate)],
['未关故事',...this.xmProductStateHiss.map(i=>i.menuCnt-i.menuCloseCnt)],
['已关故事',...this.xmProductStateHiss.map(i=>i.menuCloseCnt)],
['未关任务',...this.xmProductStateHiss.map(i=>i.taskCnt-i.taskCloseCnt)],
['已关任务',...this.xmProductStateHiss.map(i=>i.taskCloseCnt)],
['未关缺陷',...this.xmProductStateHiss.map(i=>i.bugCnt-i.closedBugs)],
['已关缺陷',...this.xmProductStateHiss.map(i=>i.closedBugs)]
]
},
titleCpd(){
var preName=""
if(this.filters.testPlan && this.filters.testPlan.id){
preName=`测试计划【${this.filters.testPlan.name}`
}else if(this.filters.testCasedb && this.filters.testCasedb.id){
preName=`测试库【${this.filters.testCasedb.name}`
}else if(this.filters.iteration && this.filters.iteration.id){
preName=`迭代【${this.filters.iteration.iterationName}`
}else if(this.filters.product && this.filters.product.id){
if(this.filters.product.productName){
preName=`产品【${this.filters.product.productName}`
}else{
preName=`产品【${this.filters.product.id}`
}
}else if(this.filters.project && this.filters.project.id){
if(this.filters.project.name){
preName=`项目【${this.filters.project.name}`
}else{
preName=`项目【${this.filters.project.id}`
}
}
return preName+"产品工作项每日分布图"
},
xmProductCpd(){
if(this.xmProduct && this.xmProduct.id){
return this.xmProduct
}
return null;
}
},
watch: {
dataSetCpd(){
this.$nextTick(()=>{
this.drawCharts();
})
}
},
data() {
return {
filters:{
product:null,
project:null,
testPlan:null,
iteration:null,
testCasedb:null,
category:'',
startBizDate:'',
endBizDate:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmProductStateHiss:[],
}//end return
},//end data
methods: {
listXmProductStateHis(){
if(!this.filters.product){
this.$notify({position:'bottom-left',showClose:true,message:'请先选中产品',type:'warning'})
return;
}
var params={productId:this.filters.product.id,orderBy:'biz_date asc'}
if(this.filters.startBizDate && this.filters.endBizDate){
params.startBizDate=this.filters.startBizDate;
params.endBizDate=this.filters.endBizDate;
}
listXmProductStateHis(params).then(res=>{
this.xmProductStateHiss=res.data.tips.isOk?res.data.data:this.xmProductStateHiss;
})
},
open(){
this.visible=true;
this.filters.testPlan=this.xmTestPlan
this.filters.product=this.xmProduct
this.filters.project=this.xmProject
this.filters.iteration=this.xmIteration
this.filters.testCasedb=this.xmTestCasedb
this.xmProductStateHiss=[]
if(this.$refs['xmProductSelect'])this.$refs['xmProductSelect'].clearSelect();
this.$nextTick(()=>{
this.listXmProductStateHis();
})
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById("productWorkItemDayList"));
var that=this;
this.myChart.on('updateAxisPointer', function (event) {
const xAxisInfo = event.axesInfo[0];
if (xAxisInfo) {
const dimension = xAxisInfo.value + 1;
that.myChart.setOption({
series: {
id: 'pie',
label: {
formatter: '{b}: {@[' + dimension + ']} ({d}%)'
},
encode: {
value: dimension,
tooltip: dimension
}
}
});
}
});
this.myChart.setOption({
title: {
text: this.titleCpd,
left: 'center'
},
trigger: 'axis',
tooltip: {
trigger: 'axis',
},
barMaxWidth: 100,
toolbox: {
show: true,
top:"5%",
right:"10px",
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
legend: {
bottom: 'bottom',
},
dataset: {
source: this.dataSetCpd
},
xAxis: {
type: 'category',
},
yAxis: { gridIndex: 0 },
grid: { top: '55%' },
series: [
{ name:'未关故事',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{ name:'已关故事',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{
name:'未关任务',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{
name:'已关任务',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{ name:'未关缺陷',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{ name:'已关缺陷',
type: 'line',
seriesLayoutBy: 'row',
smooth:true,
emphasis: { focus: 'series' },
},
{
type: 'pie',
id: 'pie',
radius: '30%',
center: ['50%', '30%'],
emphasis: {
focus: 'self'
},
label: {
formatter: '{b}: {@日期} ({d}%)'
},
encode: {
itemName: '日期',
value:this.dataSetCpd[0][this.dataSetCpd[0].length-1],
tooltip: '日期'
}
}
]
});
},
onProductSelected(product){
this.filters.product=product
this.xmProductStateHiss=[];
},
onProductClear(){
this.filters.product=null
this.xmProductStateHiss=[];
},
},//end method
mounted() {
/**
initSimpleDicts('all',['demandSource','demandLvl','demandType','priority','menuStatus'] ).then(res=>{
this.dicts=res.data.data;
})
*/
this.maxTableHeight = util.calcTableMaxHeight(this.$refs.filtersRef.$el)
//this.charts();
this.open();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

334
src/views/xm/core/xmTestPlan/rpt/biz/question.vue

@ -1,334 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item label="分组属性">
<el-select v-model="filters.groupBy" @change="onXmQuestionSomeFieldsChange('groupBy',$event)" clearable>
<el-option v-for="i in this.groupBys" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷状态" prop="bugStatus">
<el-select v-model="filters.bugStatus" @change="onXmQuestionSomeFieldsChange('bugStatus',$event)" clearable>
<el-option v-for="i in this.dicts.bugStatus" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷类型" prop="bugType" >
<el-select v-model="filters.bugType" @change="onXmQuestionSomeFieldsChange('bugType',$event)" clearable>
<el-option v-for="i in this.dicts.bugType" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷原因" prop="bugReason">
<el-select v-model="filters.bugReason" @change="onXmQuestionSomeFieldsChange('bugReason',$event)" clearable>
<el-option v-for="i in this.dicts.bugReason" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="严重程度" prop="bugSeverity" >
<el-select v-model="filters.bugSeverity" @change="onXmQuestionSomeFieldsChange('bugSeverity',$event)" clearable>
<el-option v-for="i in this.dicts.bugSeverity" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority" >
<el-select v-model="filters.priority" @change="onXmQuestionSomeFieldsChange('priority',$event)" clearable>
<el-option v-for="i in dicts.priority" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="解决方案" prop="solution" >
<el-select v-model="filters.solution" @change="onXmQuestionSomeFieldsChange('solution',$event)" clearable>
<el-option v-for="i in dicts.bugSolution" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="重现频率" prop="repRate" >
<el-select v-model="filters.repRate" @change="onXmQuestionSomeFieldsChange('repRate',$event)" clearable>
<el-option v-for="i in dicts.bugRepRate" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmQuestionAttDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmQuestionAttDist } from '@/api/xm/core/xmQuestion';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','xmRptConfig','compCfg','groupBy'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmQuestionAttDistsCpd(){
if(this.xmQuestionAttDists.length==0){
return []
}else{
var itemId="";
if(this.filters.groupBy=='bug_status'){
itemId="bugStatus"
}else if(this.filters.groupBy=='bug_type'){
itemId="bugType"
}else if(this.filters.groupBy=='bug_reason'){
itemId="bugReason"
}else if(this.filters.groupBy=='bug_severity'){
itemId="bugSeverity"
}else if(this.filters.groupBy=='priority'){
itemId="priority"
} else if(this.filters.groupBy=='bug_solution'){
itemId="bugSolution"
} else if(this.filters.groupBy=='rep_rate'){
itemId="bugRepRate"
}
return this.xmQuestionAttDists.map(i=>{
var data={...i}
data.name=this.formatDict(itemId,data.name)
return data;
})
}
},
title(){
return this.groupBys.find(i=>i.id==this.filters.groupBy).name+'数量分布'
},
legendCpd(){
var itemId="";
if(this.filters.groupBy=='bug_status'){
itemId="bugStatus"
}else if(this.filters.groupBy=='bug_type'){
itemId="bugType"
}else if(this.filters.groupBy=='bug_reason'){
itemId="bugReason"
}else if(this.filters.groupBy=='bug_severity'){
itemId="bugSeverity"
}else if(this.filters.groupBy=='priority'){
itemId="priority"
} else if(this.filters.groupBy=='bug_solution'){
itemId="bugSolution"
} else if(this.filters.groupBy=='rep_rate'){
itemId="bugRepRate"
}
return this.dicts[itemId].map(i=>i.name)
},
id(){
return this.compCfg.id
},
},
watch: {
xmQuestionAttDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
groupBy:'bug_status',
planId:'',
productId:'',
projectId:'',
bugStatus:'',
bugType:'',
bugReason:'',
bugSeverity:'',
priority:'',
solution:'',
repRate:'',
},
groupBys:[
{id:'bug_status', name:'缺陷状态'},
{id:'bug_type', name:'缺陷类型'},
{id:'bug_reason', name:'缺陷原因'},
{id:'bug_severity', name:'紧急程度'},
{id:'priority', name:'优先级'},
{id:'bug_solution', name:'解决方案'},
{id:'rep_rate', name:'复现频率'},
],
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmQuestionAttDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
findMax( list ) {
var i, max = list[0];
if(list.length < 2) return max;
for (i = 0; i < list.length; i++) {
if (list[i].distBudgetWorkload > max.distBudgetWorkload) {
max = list[i];
}
}
return max;
},
open(params){
this.visible=true;
this.filters.product=params.xmProduct
this.filters.project=params.xmProject
this.filters.Product=params.xmProduct
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmQuestionAttDistsCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmQuestionAttDists=[]
},
searchXmQuestionAttDist(){
if(!this.filters.groupBy){
this.$notify({position:'bottom-left',showClose:true,message:'请选中分组属性',type:'warning'})
return
}
var params={...this.filters}
getXmQuestionAttDist(params).then(res=>{
this.xmQuestionAttDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.groupBy){
this.filters.groupBy=this.groupBy
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['bugSeverity','bugSolution','bugStatus','bugType','priority','bugRepRate','bugReason'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmQuestionAttDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

259
src/views/xm/core/xmTestPlan/rpt/biz/questionAgeDist.vue

@ -1,259 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item label="缺陷状态" prop="bugStatus">
<el-select v-model="filters.bugStatus" @change="onXmQuestionSomeFieldsChange('bugStatus',$event)" clearable>
<el-option v-for="i in this.dicts.bugStatus" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷类型" prop="bugType" >
<el-select v-model="filters.bugType" @change="onXmQuestionSomeFieldsChange('bugType',$event)" clearable>
<el-option v-for="i in this.dicts.bugType" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷原因" prop="bugReason">
<el-select v-model="filters.bugReason" @change="onXmQuestionSomeFieldsChange('bugReason',$event)" clearable>
<el-option v-for="i in this.dicts.bugReason" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="严重程度" prop="bugSeverity" >
<el-select v-model="filters.bugSeverity" @change="onXmQuestionSomeFieldsChange('bugSeverity',$event)" clearable>
<el-option v-for="i in this.dicts.bugSeverity" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority" >
<el-select v-model="filters.priority" @change="onXmQuestionSomeFieldsChange('priority',$event)" clearable>
<el-option v-for="i in dicts.priority" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="解决方案" prop="solution" >
<el-select v-model="filters.solution" @change="onXmQuestionSomeFieldsChange('solution',$event)" clearable>
<el-option v-for="i in dicts.bugSolution" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="重现频率" prop="repRate" >
<el-select v-model="filters.repRate" @change="onXmQuestionSomeFieldsChange('repRate',$event)" clearable>
<el-option v-for="i in dicts.bugRepRate" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmQuestionAgeDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmQuestionAgeDist } from '@/api/xm/core/xmQuestion';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmQuestionAgeDistsCpd(){
if(this.xmQuestionAgeDists.length==0){
return []
}else{
var datas=[]
this.xmQuestionAgeDists.forEach(i=>{
var data={...i}
data.name=this.legendCpd[i.name]
datas.push(data)
})
return datas;
}
},
title(){
return '缺陷年龄数量分布'
},
legendCpd(){
return ['0-2天','3-5天','6-7天','8-15天','16-30天','30天以上']
},
id(){
return this.compCfg.id
}
},
watch: {
xmQuestionAgeDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
productId:'',
projectId:'',
bugStatus:'',
bugType:'',
bugReason:'',
bugSeverity:'',
priority:'',
solution:'',
repRate:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmQuestionAgeDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmQuestionAgeDistsCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmQuestionAgeDists=[]
},
searchXmQuestionAgeDist(){
var params={...this.filters}
if(this.xmTestPlan && this.xmTestPlan.id){
params.planId=this.xmTestPlan.id
}
getXmQuestionAgeDist(params).then(res=>{
this.xmQuestionAgeDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
doDelete(){
this.$emit("delete",this.compCfg)
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['bugSeverity','bugSolution','bugStatus','bugType','priority','bugRepRate','bugReason'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmQuestionAgeDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionAskUserSort.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-sort :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'ask_userid'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionSort from './questionSort'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionSort},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

334
src/views/xm/core/xmTestPlan/rpt/biz/questionAttDist.vue

@ -1,334 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item label="分组属性">
<el-select v-model="filters.groupBy" @change="onXmQuestionSomeFieldsChange('groupBy',$event)" clearable>
<el-option v-for="i in this.groupBys" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷状态" prop="bugStatus">
<el-select v-model="filters.bugStatus" @change="onXmQuestionSomeFieldsChange('bugStatus',$event)" clearable>
<el-option v-for="i in this.dicts.bugStatus" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷类型" prop="bugType" >
<el-select v-model="filters.bugType" @change="onXmQuestionSomeFieldsChange('bugType',$event)" clearable>
<el-option v-for="i in this.dicts.bugType" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷原因" prop="bugReason">
<el-select v-model="filters.bugReason" @change="onXmQuestionSomeFieldsChange('bugReason',$event)" clearable>
<el-option v-for="i in this.dicts.bugReason" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="严重程度" prop="bugSeverity" >
<el-select v-model="filters.bugSeverity" @change="onXmQuestionSomeFieldsChange('bugSeverity',$event)" clearable>
<el-option v-for="i in this.dicts.bugSeverity" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority" >
<el-select v-model="filters.priority" @change="onXmQuestionSomeFieldsChange('priority',$event)" clearable>
<el-option v-for="i in dicts.priority" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="解决方案" prop="solution" >
<el-select v-model="filters.solution" @change="onXmQuestionSomeFieldsChange('solution',$event)" clearable>
<el-option v-for="i in dicts.bugSolution" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="重现频率" prop="repRate" >
<el-select v-model="filters.repRate" @change="onXmQuestionSomeFieldsChange('repRate',$event)" clearable>
<el-option v-for="i in dicts.bugRepRate" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmQuestionAttDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmQuestionAttDist } from '@/api/xm/core/xmQuestion';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','xmRptConfig','compCfg','groupBy'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmQuestionAttDistsCpd(){
if(this.xmQuestionAttDists.length==0){
return []
}else{
var itemId="";
if(this.filters.groupBy=='bug_status'){
itemId="bugStatus"
}else if(this.filters.groupBy=='bug_type'){
itemId="bugType"
}else if(this.filters.groupBy=='bug_reason'){
itemId="bugReason"
}else if(this.filters.groupBy=='bug_severity'){
itemId="bugSeverity"
}else if(this.filters.groupBy=='priority'){
itemId="priority"
} else if(this.filters.groupBy=='solution'){
itemId="bugSolution"
} else if(this.filters.groupBy=='rep_rate'){
itemId="bugRepRate"
}
return this.xmQuestionAttDists.map(i=>{
var data={...i}
data.name=this.formatDict(itemId,data.name)
return data;
})
}
},
title(){
return this.groupBys.find(i=>i.id==this.filters.groupBy).name+'数量分布'
},
legendCpd(){
var itemId="";
if(this.filters.groupBy=='bug_status'){
itemId="bugStatus"
}else if(this.filters.groupBy=='bug_type'){
itemId="bugType"
}else if(this.filters.groupBy=='bug_reason'){
itemId="bugReason"
}else if(this.filters.groupBy=='bug_severity'){
itemId="bugSeverity"
}else if(this.filters.groupBy=='priority'){
itemId="priority"
} else if(this.filters.groupBy=='solution'){
itemId="bugSolution"
} else if(this.filters.groupBy=='rep_rate'){
itemId="bugRepRate"
}
return this.dicts[itemId].map(i=>i.name)
},
id(){
return this.compCfg.id
},
},
watch: {
xmQuestionAttDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
groupBy:'bug_status',
planId:'',
productId:'',
projectId:'',
bugStatus:'',
bugType:'',
bugReason:'',
bugSeverity:'',
priority:'',
solution:'',
repRate:'',
},
groupBys:[
{id:'bug_status', name:'缺陷状态'},
{id:'bug_type', name:'缺陷类型'},
{id:'bug_reason', name:'缺陷原因'},
{id:'bug_severity', name:'紧急程度'},
{id:'priority', name:'优先级'},
{id:'solution', name:'解决方案'},
{id:'rep_rate', name:'复现频率'},
],
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmQuestionAttDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
findMax( list ) {
var i, max = list[0];
if(list.length < 2) return max;
for (i = 0; i < list.length; i++) {
if (list[i].distBudgetWorkload > max.distBudgetWorkload) {
max = list[i];
}
}
return max;
},
open(params){
this.visible=true;
this.filters.product=params.xmProduct
this.filters.project=params.xmProject
this.filters.Product=params.xmProduct
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmQuestionAttDistsCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmQuestionAttDists=[]
},
searchXmQuestionAttDist(){
if(!this.filters.groupBy){
this.$notify({position:'bottom-left',showClose:true,message:'请选中分组属性',type:'warning'})
return
}
var params={...this.filters}
getXmQuestionAttDist(params).then(res=>{
this.xmQuestionAttDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.groupBy){
this.filters.groupBy=this.groupBy
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['bugSeverity','bugSolution','bugStatus','bugType','priority','bugRepRate','bugReason'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmQuestionAttDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

47
src/views/xm/core/xmTestPlan/rpt/biz/questionBugReasonDist.vue

@ -1,47 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'bug_reason'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionBugSeverityDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'bug_severity'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionBugStatusDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'bug_status'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionBugTypeDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'bug_type'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionFuncSort.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-sort :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'func_id'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionSort from './questionSort'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionSort},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionHandlerUserSort.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-sort :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'handler_userid'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionSort from './questionSort'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionSort},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionMenuSort.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-sort :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'menu_id'" @delete="$emit('delete',$event)" />
</el-row>
</section>
</template>
<script>
import questionSort from './questionSort'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionSort},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionPriorityDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'bug_type'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionRepRateDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'rep_rate'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

275
src/views/xm/core/xmTestPlan/rpt/biz/questionRetestDist.vue

@ -1,275 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item label="缺陷状态" prop="bugStatus">
<el-select v-model="filters.bugStatus" @change="onXmQuestionSomeFieldsChange('bugStatus',$event)" clearable>
<el-option v-for="i in this.dicts.bugStatus" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷类型" prop="bugType" >
<el-select v-model="filters.bugType" @change="onXmQuestionSomeFieldsChange('bugType',$event)" clearable>
<el-option v-for="i in this.dicts.bugType" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷原因" prop="bugReason">
<el-select v-model="filters.bugReason" @change="onXmQuestionSomeFieldsChange('bugReason',$event)" clearable>
<el-option v-for="i in this.dicts.bugReason" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="严重程度" prop="bugSeverity" >
<el-select v-model="filters.bugSeverity" @change="onXmQuestionSomeFieldsChange('bugSeverity',$event)" clearable>
<el-option v-for="i in this.dicts.bugSeverity" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority" >
<el-select v-model="filters.priority" @change="onXmQuestionSomeFieldsChange('priority',$event)" clearable>
<el-option v-for="i in dicts.priority" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="解决方案" prop="solution" >
<el-select v-model="filters.solution" @change="onXmQuestionSomeFieldsChange('solution',$event)" clearable>
<el-option v-for="i in dicts.bugSolution" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="重现频率" prop="repRate" >
<el-select v-model="filters.repRate" @change="onXmQuestionSomeFieldsChange('repRate',$event)" clearable>
<el-option v-for="i in dicts.bugRepRate" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmQuestionRetestDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmQuestionRetestDist } from '@/api/xm/core/xmQuestion';
export default {
components: {
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmQuestionRetestDistsCpd(){
var def=[
{name:"1次",value:0} ,
{name:"2次",value:0} ,
{name:"3次",value:0} ,
{name:"4次",value:0} ,
{name:"5次",value:0} ,
{name:"5次以上",value:0}
]
if(this.xmQuestionRetestDists.length==0){
return def
}else{
var datas=[]
this.xmQuestionRetestDists.forEach(i=>{
var data={}
if(i.retimes>5){
data.name="5次以上"
}else{
data.name=this.legendCpd[i.retimes]
}
data.value=i.bugsNum
datas.push(data)
})
def.forEach(k=>{
if(!datas.some(i=>k.name==i.name)){
datas.push(k)
}
})
return datas;
}
},
legendCpd(){
return ["1次","2次","3次","4次","5次","5次以上"]
},
title(){
return '缺陷回归分布'
},
id(){
return this.compCfg.id
}
},
watch: {
xmQuestionRetestDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
productId:'',
projectId:'',
bugStatus:'',
bugType:'',
bugReason:'',
bugSeverity:'',
priority:'',
solution:'',
repRate:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmQuestionRetestDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmQuestionRetestDistsCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmQuestionRetestDists=[]
},
searchXmQuestionRetestDist(){
var params={...this.filters}
if(this.xmTestPlan && this.xmTestPlan.id){
params.planId=this.xmTestPlan.id
}
getXmQuestionRetestDist(params).then(res=>{
this.xmQuestionRetestDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
doDelete(){
this.$emit("delete",this.compCfg)
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
this.drawCharts();
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['bugSeverity','bugSolution','bugStatus','bugType','priority','bugRepRate','bugReason'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmQuestionRetestDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

48
src/views/xm/core/xmTestPlan/rpt/biz/questionSolutionDist.vue

@ -1,48 +0,0 @@
<template>
<section>
<el-row>
<question-att-dist :ref="compCfg.id" :xm-test-plan="xmTestPlan" :comp-cfg="compCfg" :rpt-config-visible="rptConfigVisible" :group-by="'solution'" @delete="$emit('delete',$event)"/>
</el-row>
</section>
</template>
<script>
import questionAttDist from './questionAttDist'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan','compCfg'],
components: {questionAttDist},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
sizeAutoChange(){
this.refs[this.compCfg.id].sizeAutoChange()
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

282
src/views/xm/core/xmTestPlan/rpt/biz/questionSort.vue

@ -1,282 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item label="分组属性">
<el-select v-model="groupBy" @change="onXmQuestionSomeFieldsChange('groupBy',$event)" clearable>
<el-option v-for="i in this.groupBys" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷状态" prop="bugStatus">
<el-select v-model="filters.bugStatus" @change="onXmQuestionSomeFieldsChange('bugStatus',$event)" clearable>
<el-option v-for="i in this.dicts.bugStatus" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷类型" prop="bugType" >
<el-select v-model="filters.bugType" @change="onXmQuestionSomeFieldsChange('bugType',$event)" clearable>
<el-option v-for="i in this.dicts.bugType" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="缺陷原因" prop="bugReason">
<el-select v-model="filters.bugReason" @change="onXmQuestionSomeFieldsChange('bugReason',$event)" clearable>
<el-option v-for="i in this.dicts.bugReason" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="严重程度" prop="bugSeverity" >
<el-select v-model="filters.bugSeverity" @change="onXmQuestionSomeFieldsChange('bugSeverity',$event)" clearable>
<el-option v-for="i in this.dicts.bugSeverity" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority" >
<el-select v-model="filters.priority" @change="onXmQuestionSomeFieldsChange('priority',$event)" clearable>
<el-option v-for="i in dicts.priority" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="解决方案" prop="solution" >
<el-select v-model="filters.solution" @change="onXmQuestionSomeFieldsChange('solution',$event)" clearable>
<el-option v-for="i in dicts.bugSolution" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="重现频率" prop="repRate" >
<el-select v-model="filters.repRate" @change="onXmQuestionSomeFieldsChange('repRate',$event)" clearable>
<el-option v-for="i in dicts.bugRepRate" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmQuestionSort">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row >
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmQuestionSort } from '@/api/xm/core/xmQuestion';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','compCfg','groupBy'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmQuestionSortsCpd(){
if(!this.xmQuestionSorts || this.xmQuestionSorts.length==0){
return []
}else{
return this.xmQuestionSorts.map(i=>i.value)
}
},
title(){
return this.compCfg.name
},
legendCpd(){
if(!this.xmQuestionSorts || this.xmQuestionSorts.length==0){
return []
}else{
return this.xmQuestionSorts.map(i=>i.name)
}
},
id(){
return this.compCfg.id
},
},
watch: {
xmQuestionSortsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
groupBy:'handler_userid',
},
groupBys:[
{id:'create_userid', name:'创建人'},
{id:'ask_userid', name:'提出人'},
{id:'handler_userid', name:'负责人'},
{id:'menu_id', name:'故事'},
],
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmQuestionSorts:[],
conditionBtnVisible:false,
pageInfo: {
//
total: 0, //0>0
pageSize: 20, //
count:true, //
pageNum: 1, //1
orderFields: ["value"], // ['sex','student_id']
orderDirs: ["desc"], // asc,desc ['asc','desc']
},
}//end return
},//end data
methods: {
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'axis',
},
barMaxWidth: 100,
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
xAxis: {
type: 'category',
data: this.legendCpd
},
yAxis: {
type: 'value'
},
series: [
{
data: this.xmQuestionSortsCpd,
type: 'bar',
label:{
show: true,
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmQuestionSorts=[]
},
searchXmQuestionSort(){
if(!this.filters.groupBy){
this.$notify({position:'bottom-left',showClose:true,message:'请选中分组属性',type:'warning'})
return
}
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count: this.pageInfo.count,
};
Object.assign(params,this.filters)
if (
this.pageInfo.orderFields != null &&
this.pageInfo.orderFields.length > 0
) {
let orderBys = [];
for (var i = 0; i < this.pageInfo.orderFields.length; i++) {
orderBys.push(
this.pageInfo.orderFields[i] + " " + this.pageInfo.orderDirs[i]
);
}
params.orderBy = orderBys.join(",");
}
getXmQuestionSort(params).then(res=>{
this.xmQuestionSorts=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
onIterationClear(){
this.filters.iteration=null
} ,
initData(){
if(this.groupBy){
this.filters.groupBy=this.groupBy
}
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['bugSeverity','bugSolution','bugStatus','bugType','priority','bugRepRate','bugReason'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmQuestionSort();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

203
src/views/xm/core/xmTestPlan/rpt/biz/testCaseToPlanCalc.vue

@ -1,203 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmTestCaseToPlanCalcList">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmTestCaseToPlanCalcList } from '@/api/xm/core/xmTestPlanCase';
export default {
components: {
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmTestCaseToPlanCalcListCpd(){
if(!this.xmTestCaseToPlanCalcList || this.xmTestCaseToPlanCalcList.length==0){
return []
}else{
var names=this.legendCpd;
var datas=[]
this.xmTestCaseToPlanCalcList.forEach(i=>{
var nameIndex=0;
if(i.useTimes<=2){
nameIndex=i.useTimes
}else if(i.useTimes>=3 && i.useTimes<=5){
nameIndex=3
}else if(i.useTimes>5 && i.useTimes<=10){
nameIndex=4
}else if(i.useTimes>10){
nameIndex=5
}
var data={name:names[nameIndex],value:i.caseNum}
datas.push(data)
})
return datas;
}
},
title(){
return '测试用例规划分析'
},
legendCpd(){
return ['0次','1次','2次','3-5次','5-10次','10次以上']
},
id(){
return this.compCfg.id
},
},
watch: {
xmTestCaseToPlanCalcListCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmTestCaseToPlanCalcList:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmTestCaseToPlanCalcListCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmTestCaseToPlanCalcList=[]
},
searchXmTestCaseToPlanCalcList(){
var params={...this.filters}
getXmTestCaseToPlanCalcList(params).then(res=>{
this.xmTestCaseToPlanCalcList=res.data.data
})
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
this.initData();
this.searchXmTestCaseToPlanCalcList();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

188
src/views/xm/core/xmTestPlan/rpt/biz/testDayTimesCalc.vue

@ -1,188 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmTestDayTimesList">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { mapGetters } from 'vuex'
import { getXmTestDayTimesList } from '@/api/xm/core/xmTestPlanCase';
export default {
components: {
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
datesCpd(){
if(!this.xmTestDayTimesList || this.xmTestDayTimesList.length==0){
return []
}else{
return this.xmTestDayTimesList.map(i=>i.execDate)
}
},
testDayTimesCpd(){
if(!this.xmTestDayTimesList || this.xmTestDayTimesList.length==0){
return []
}else{
return this.xmTestDayTimesList.map(i=>i.hadExec)
}
},
title(){
return '测试用例每日执行次数统计'
},
id(){
return this.compCfg.id
},
},
watch: {
testDayTimesCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmTestDayTimesList:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'axis',
},
barMaxWidth: 100,
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
xAxis: {
type: 'category',
data: this.datesCpd
},
yAxis: {
type: 'value'
},
series: [
{
name:'次数',
data: this.testDayTimesCpd,
type: 'line',
label:{
show: true,
},
smooth: true,
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmTestDayTimesList=[]
},
searchXmTestDayTimesList(){
var params={...this.filters}
getXmTestDayTimesList(params).then(res=>{
this.xmTestDayTimesList=res.data.data
})
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
this.drawCharts();
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
this.initData();
this.searchXmTestDayTimesList();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

222
src/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseExecStatusDist.vue

@ -1,222 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmTestPlanCaseExecStatusDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmTestPlanCaseExecStatusDist } from '@/api/xm/core/xmTestPlanCase';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
xmTestPlanCaseExecStatusDistsCpd(){
if(!this.xmTestPlanCaseExecStatusDists || this.xmTestPlanCaseExecStatusDists.length==0){
return []
}else{
var datas=[]
this.xmTestPlanCaseExecStatusDists.forEach(i=>{
var data={}
var itemId="testStepTcode";
data.name=this.formatDict(itemId,i.execStatus)
data.value=i.totalCnt
datas.push(data)
})
return datas;
}
},
title(){
var preName=""
return preName+ '测试用例执行结果数量分布'
},
/**0-未测,1-通过,2-受阻,3-忽略,4-失败 */
legendCpd(){
var itemId="testStepTcode";
return this.dicts[itemId].map(i=>this.formatDict(itemId,i.id))
},
id(){
return this.compCfg.id
},
},
watch: {
xmTestPlanCaseExecStatusDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
},
dicts:{testStepTcode:[]},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmTestPlanCaseExecStatusDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
saveAsImage: { show: true },
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data:this.legendCpd,
},
series: [
{
type: 'pie',
radius: '50%',
data: this.xmTestPlanCaseExecStatusDistsCpd,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter:'{b}: {c}  ({d}%)'
},
}
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmTestPlanCaseExecStatusDists=[]
},
searchXmTestPlanCaseExecStatusDist(){
var params={...this.filters}
getXmTestPlanCaseExecStatusDist(params).then(res=>{
this.xmTestPlanCaseExecStatusDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['testStepTcode'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmTestPlanCaseExecStatusDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

249
src/views/xm/core/xmTestPlan/rpt/biz/testPlanCaseUserDist.vue

@ -1,249 +0,0 @@
<template>
<section>
<el-row class="padding">
<el-popover trigger="manual" v-model="conditionBtnVisible" style="float:right;" width="300">
<el-button slot="reference" icon="el-icon-more" @click="conditionBtnVisible=!conditionBtnVisible"></el-button>
<el-row>
<el-button type="danger" icon="el-icon-delete" @click="doDelete">删除</el-button>
<el-button style="float:right;" type="text" icon="el-icon-close" @click="conditionBtnVisible=false">关闭</el-button>
</el-row>
<el-form :model="filters">
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="searchXmTestPlanCaseUserDist">查询</el-button>
</el-form-item>
</el-form>
</el-popover>
</el-row>
<el-row>
<div>
<div class="main" :id="id"
style="width:100%;height:600px;margin:0 auto;"></div>
<div class="progress"></div>
</div>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { initSimpleDicts } from '@/api/mdp/meta/item';//
import { mapGetters } from 'vuex'
import { getXmTestPlanCaseUserDist } from '@/api/xm/core/xmTestPlanCase';
import XmIterationSelect from '@/views/xm/core/components/XmIterationSelect.vue';//
import XmProductSelect from '@/views/xm/core/components/XmProductSelect';//
export default {
components: {
XmIterationSelect,XmProductSelect,
},
props:['xmTestPlan','xmRptConfig','compCfg'],
computed: {
...mapGetters([
'userInfo','roles'
]),
hadExecCpd(){
if(!this.xmTestPlanCaseUserDists ||this.xmTestPlanCaseUserDists.length==0){
return []
}else{
return this.xmTestPlanCaseUserDists.map(i=>i.hadExec)
}
},
notExecCpd(){
if(!this.xmTestPlanCaseUserDists ||this.xmTestPlanCaseUserDists.length==0){
return []
}else{
return this.xmTestPlanCaseUserDists.map(i=>i.notExec)
}
},
legendCpd(){
if(!this.xmTestPlanCaseUserDists ||this.xmTestPlanCaseUserDists.length==0){
return []
}else{
return this.xmTestPlanCaseUserDists.map(i=>i.execUsername)
}
},
xmTestPlanCaseUserDistsCpd(){
if(!this.xmTestPlanCaseUserDists || this.xmTestPlanCaseUserDists.length==0){
return []
}else{
var datas=[]
this.xmTestPlanCaseUserDists.forEach(i=>{
var data={}
var itemId="testPlanTcode";
data.name=this.formatDict(itemId,i.execStatus)
data.value=i.totalCnt
datas.push(data)
})
return datas;
}
},
title(){
var preName=""
return preName+ '测试用例按执行人分组统计'
},
id(){
return this.compCfg.id
},
},
watch: {
xmTestPlanCaseUserDistsCpd(){
this.drawCharts();
}
},
data() {
return {
filters:{
planId:'',
},
dicts:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
dateRanger:[],
maxTableHeight:300,
visible:false,
xmTestPlanCaseUserDists:[],
conditionBtnVisible:false,
}//end return
},//end data
methods: {
formatDict(itemId,val){
var dict=this.dicts[itemId]
if(dict){
var item=dict.find(i=>i.id==val)
if(item){
return item.name
}
}
return val;
},
drawCharts() {
this.myChart = this.$echarts.init(document.getElementById(this.id));
this.myChart.setOption(
{
title: {
text: this.title,
left: 'center'
},
tooltip: {
trigger: 'item',
},
barMaxWidth: 100,
toolbox: {
show: true,
right:"20px",
feature: {
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar'] },
saveAsImage: { show: true }
}
},
calculable: true,
legend: {
top:'5%',
left: 'center',
data: ['已执行', '未执行']
},
xAxis: {
type: 'category',
data: this.legendCpd
},
yAxis: {
type: 'value'
},
series: [
{
name: '已执行',
type: 'bar',
data: this.hadExecCpd,
label:{
show: true,
},
},
{
name: '未执行',
type: 'bar',
data: this.notExecCpd,
label:{
show: true,
},
},
]
}
)
},
onXmQuestionSomeFieldsChange(fieldName,$event){
this.xmTestPlanCaseUserDists=[]
},
searchXmTestPlanCaseUserDist(){
var params={...this.filters}
getXmTestPlanCaseUserDist(params).then(res=>{
this.xmTestPlanCaseUserDists=res.data.data
})
},
onProductSelected(product){
this.filters.product=product
},
onProductClear(){
this.filters.product=null
},
onIterationSelected(iteration){
this.filters.iteration=iteration
},
onIterationClear(){
this.filters.iteration=null
},
initData(){
if(this.xmTestPlan){
this.filters.productId=this.xmTestPlan.productId
this.filters.projectId=this.xmTestPlan.projectId
this.filters.planId=this.xmTestPlan.id
}
if(this.compCfg && this.compCfg.params){
Object.assign(this.filters,this.compCfg.params)
}
},
doDelete(){
this.$emit("delete",this.compCfg)
},
sizeAutoChange(){
this.myChart.resize();
}
},//end method
mounted() {
initSimpleDicts('all',['testPlanTcode'] ).then(res=>{
this.dicts=res.data.data;
})
this.initData();
this.searchXmTestPlanCaseUserDist();
//this.charts();
//this.drawCharts();
}//end mounted
}
</script>
<style scoped>
.image {
width: 100%;
display: block;
}
</style>

10
src/views/xm/core/xmTestPlan/rpt/common.scss

@ -1,10 +0,0 @@
.m_container {
width: 100%;
height: 100%;
background: rgb(238, 238, 238);
.m_content {
padding:30px 18px 18px 18px;
overflow: hidden;
position: relative;
}
}

BIN
src/views/xm/core/xmTestPlan/rpt/images/area-stack.png

Before

Width: 600  |  Height: 450  |  Size: 104 KiB

BIN
src/views/xm/core/xmTestPlan/rpt/images/bar.png

Before

Width: 600  |  Height: 450  |  Size: 63 KiB

BIN
src/views/xm/core/xmTestPlan/rpt/images/dataset-link.png

Before

Width: 600  |  Height: 450  |  Size: 146 KiB

BIN
src/views/xm/core/xmTestPlan/rpt/images/line-stack.png

Before

Width: 600  |  Height: 450  |  Size: 91 KiB

BIN
src/views/xm/core/xmTestPlan/rpt/images/pie-simple.png

Before

Width: 600  |  Height: 450  |  Size: 60 KiB

BIN
src/views/xm/core/xmTestPlan/rpt/images/ranjintu.png

Before

Width: 842  |  Height: 579  |  Size: 42 KiB

98
src/views/xm/core/xmTestPlan/rpt/index.scss

@ -1,98 +0,0 @@
.m_top {
background: #fff;
display: flex;
flex-direction: row;
height: 100px;
align-items: center;
border: 1px solid #ebeef5;
margin: 0 10px;
.m_avatar {
width: 52px;
height: 52px;
margin-left: 34px;
}
.m_msg {
margin-left: 22px;
p:nth-child(1) {
font-size: 20px;
font-weight: bold;
color: #7D7D7D;
opacity: 0.92;
}
p:nth-child(2) {
margin-top: 12px;
font-size: 14px;
font-weight: bold;
color: #7D7D7D;
opacity: 0.53;
}
}
.m_btn {
margin-left: auto;
margin-right: 20px;
}
}
.m_middle {
display: flex;
flex-direction: row;
margin-top: 20px;
height: 280px;
.m_left, .m_right {
flex: 1;
padding: 30px;
background: #fff;
border: 1px solid #ebeef5;
}
.m_left {
display: flex;
flex-direction: row;
margin-right: 10px;
margin-left: 10px;
.m_left_1 {
flex: 1.5;
p {
font-size: 18px;
margin-bottom: 20px;
}
span {
font-size: 15px;
line-height: 42px;
color: #7D7D7D;
}
}
.m_left_2 {
flex: 1;
img {
width: 100%;
margin-left: 20px;
margin-top: 10px;
}
}
}
.m_right {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-right: 10px;
.m_right_menu {
display: flex;
width: 33.3%;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 16px;
cursor: pointer;
img {
width: 58px;
height: 58px;
}
span {
margin-top: 12px;
}
}
}
}

58
src/views/xm/core/xmTestPlan/rpt/index.vue

@ -1,58 +0,0 @@
<template>
<section>
<el-row v-if="rptConfigVisible">
<span style="float:right;"> <el-button @click="rptConfigVisible=false">取消配置</el-button><el-button @click="saveXmRptConfig" type="primary">保存配置</el-button></span>
</el-row>
<el-row>
<comps-card ref="compsCard" :xm-test-plan="xmTestPlan" :rpt-config-visible="rptConfigVisible"/>
</el-row>
</section>
</template>
<script>
import NProgress from 'nprogress' // progress bar
import compsCard from './CompsCard'
import compsSet from './CompsSet'
import { mapGetters } from 'vuex'
import dayjs from 'dayjs'
export default {
props:['xmTestPlan'],
components: {compsSet, compsCard},
computed: {
...mapGetters([
'userInfo'
]),
},
watch: {
},
data() {
return {
rptConfigVisible:false,
}
},
methods: {
saveXmRptConfig(){
var callback=()=>{
this.rptConfigVisible=false;
}
this.$refs['compsCard'].submitXmPrtConfig(callback)
},
showPrint(){
this.$refs.compsCard.printVisible=true;
}
},
mounted() {
}
}
</script>
<style lang="scss" scoped>
</style>

1
src/views/xm/rpt/CompsSet.vue

@ -146,6 +146,7 @@ export default {
// //
{isChecked:false,isCurr:false,rptName:'测试计划总结',category:'测试计划级,测试级',compId:'xmTestPlanRptOverview',desc:'显示测试计划总体情况',img:pieSimple },
{isChecked:false,isCurr:false,rptName:'测试用例规划分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseToPlanCalc',desc:'显示用例被规划到测试计划中的次数统计',img:pieSimple }, {isChecked:false,isCurr:false,rptName:'测试用例规划分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseToPlanCalc',desc:'显示用例被规划到测试计划中的次数统计',img:pieSimple },
{isChecked:false,isCurr:false,rptName:'测试用例需求覆盖分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseMenuSort',initGroupBy:'menu_id',desc:'统计测试用例需求覆盖情况',img:bar }, {isChecked:false,isCurr:false,rptName:'测试用例需求覆盖分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseMenuSort',initGroupBy:'menu_id',desc:'统计测试用例需求覆盖情况',img:bar },
{isChecked:false,isCurr:false,rptName:'测试用例模块覆盖分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseFuncSort',initGroupBy:'func_id',desc:'统计测试用例覆盖各个模块的情况',img:bar }, {isChecked:false,isCurr:false,rptName:'测试用例模块覆盖分析',category:'测试级,项目级,产品级,迭代级,企业级',compId:'xmTestCaseFuncSort',initGroupBy:'func_id',desc:'统计测试用例覆盖各个模块的情况',img:bar },

1
src/views/xm/rpt/comps.js

@ -37,6 +37,7 @@ export default {
xmQuestionRetestDist:()=>import('./product/questionRetestDist.vue'), xmQuestionRetestDist:()=>import('./product/questionRetestDist.vue'),
xmTestPlanRptOverview:()=>import('./testPlan/testPlanRptOverview.vue'),
xmTestPlanCaseExecStatusDist:()=>import('./testPlan/testPlanCaseExecStatusDist.vue'), xmTestPlanCaseExecStatusDist:()=>import('./testPlan/testPlanCaseExecStatusDist.vue'),
xmTestPlanCaseUserDist:()=>import('./testPlan/testPlanCaseUserDist.vue'), xmTestPlanCaseUserDist:()=>import('./testPlan/testPlanCaseUserDist.vue'),
xmTestDayTimesCalc:()=>import('./testPlan/testDayTimesCalc.vue'), xmTestDayTimesCalc:()=>import('./testPlan/testDayTimesCalc.vue'),

407
src/views/xm/rpt/testPlan/testPlanRptOverview.vue

@ -0,0 +1,407 @@
<template>
<section class="padding">
<el-row class="padding-bottom">
<span>报告概览</span>
</el-row>
<el-row ref="table">
<el-row class="box">
<el-col :span="6" class="box-red">
<div class="box-info">
<div class="num">{{xmTestPlan.totalCases?xmTestPlan.totalCases:'0'}}</div>
<div class="label">用例数</div>
</div>
</el-col>
<el-col :span="6" class="box-blue">
<div class="box-info">
<div class="num">{{caseFuGaiLv}}%</div>
<div class="label">用例覆盖率</div>
</div>
</el-col>
<el-col :span="6" class="box-green">
<div class="box-info">
<div class="num">{{caseTongGuoLv}}%</div>
<div class="label">用例通过率</div>
</div>
</el-col>
<el-col :span="6" class="box-orange">
<div class="box-info">
<div class="num">{{xmTestPlan.bugCnt?xmTestPlan.bugCnt:0}}</div>
<div class="label">缺陷数</div>
</div>
</el-col>
</el-row>
<!--编辑界面 XmTestPlan 测试计划-->
<el-form :model="rawDatas" label-width="120px" :rules="rawDatasRules" ref="rawDatasRef" label-position="left">
<el-form-item prop="name" label-width="0px">
<el-row class="padding-bottom">
<my-input v-model="rawDatas.name" placeholder="计划名称" :maxlength="255" @change="editSomeFields(rawDatas,'name',$event)"></my-input>
</el-row>
</el-form-item>
<el-row class="padding">
<el-col :span="8">
<mdp-select-user-xm label="负责人" userid-key="cuserid" username-key="cusername" v-model="rawDatas" @change="editSomeFields(rawDatas,'cuserid',$event)"></mdp-select-user-xm>
</el-col>
<el-col :span="8">
<mdp-select-dict-x label="状态" :dict="dicts['testPlanStatus']" v-model="rawDatas.status" @change="editSomeFields(rawDatas,'status',$event)"></mdp-select-dict-x>
</el-col>
<el-col :span="8">
<mdp-select-dict-x label="测试结果" :dict="dicts['testPlanTcode']" v-model="rawDatas.tcode" @change="editSomeFields(rawDatas,'tcode',$event)"></mdp-select-dict-x>
</el-col>
</el-row>
<el-form-item label="归属测试库" prop="casedbName">
{{rawDatas.casedbName}}
</el-form-item>
<el-form-item label="归属项目" prop="projectId">
<span v-if="opType=='add'">
<xm-project-select v-if="!selProject || !selProject.id" ref="xmProjectSelect" :link-product-id="xmTestCasedb? xmTestCasedb.productId:null" @row-click="onPorjectConfirm" :auto-select="false">
<span slot="title">选择项目</span>
</xm-project-select>
<div v-else>{{rawDatas.projectName}}</div>
</span>
<div v-else>{{rawDatas.projectName}}</div>
</el-form-item>
<el-form-item label="归属产品" prop="productName">
{{rawDatas.productName}}
</el-form-item>
<el-form-item label="起止时间" prop="stime">
<mdp-date-range :auto-default="false" placeholder="选择日期" v-model="rawDatas" start-key="stime" end-key="etime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd" @change="editSomeFields(rawDatas,'stime',rawDatas)"></mdp-date-range>
</el-form-item>
</el-form>
</el-row>
<el-row class="padding-bottom">
<span>报告总结</span>
</el-row>
<el-row>
<el-input type="textarea" :rows="8" v-model="rawDatas.summaryRemark"></el-input>
</el-row>
<el-row v-if="rawDatas.summaryRemark!==rawDatasBak.summaryRemark" >
<span style="float:right;">
<el-button type="primary" @click.native="editSomeFields(rawDatas,'summaryRemark',rawDatas.summaryRemark)">提交</el-button>
</span>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import config from "@/common/config"; //import
import { initDicts, addXmTestPlan,editXmTestPlan,editSomeFieldsXmTestPlan } from '@/api/xm/core/xmTestPlan';
import { mapGetters } from 'vuex'
import XmProjectSelect from '@/views/xm/core/components/XmProjectSelect';
import MdpSelectUserXm from '@/views/xm/core/components/MdpSelectUserXm';//
export default {
name:'xmTestPlanEdit',
components: {
XmProjectSelect,MdpSelectUserXm,
},
computed: {
...mapGetters([ 'userInfo' ]),
caseFuGaiLv(){
if(!this.xmTestPlan.totalCases){
return 0
}
var okCases=parseInt(this.xmTestPlan.okCases>0?this.xmTestPlan.okCases:0)
var errCases=parseInt(this.xmTestPlan.errCases>0?this.xmTestPlan.errCases:0)
var igCases=parseInt(this.xmTestPlan.igCases>0?this.xmTestPlan.igCases:0)
var blCases=parseInt(this.xmTestPlan.blCases>0?this.xmTestPlan.blCases:0)
var totalExecs=okCases+errCases+igCases+blCases
var rate=parseInt(totalExecs/this.xmTestPlan.totalCases*100)
return rate;
},
caseTongGuoLv(){
if(!this.xmTestPlan.totalCases){
return 0
}
var okCases=parseInt(this.xmTestPlan.okCases>0?this.xmTestPlan.okCases:0)
var errCases=parseInt(this.xmTestPlan.errCases>0?this.xmTestPlan.errCases:0)
var igCases=parseInt(this.xmTestPlan.igCases>0?this.xmTestPlan.igCases:0)
var blCases=parseInt(this.xmTestPlan.blCases>0?this.xmTestPlan.blCases:0)
var totalExecs=okCases+igCases
var rate=parseInt(totalExecs/this.xmTestPlan.totalCases*100)
return rate;
}
},
props:['xmTestPlan','visible','opType','selProject','xmTestCasedb','rptDatas'],
watch: {
'xmTestPlan':function( xmTestPlan ) {
if(xmTestPlan){
this.rawDatas = {...xmTestPlan};
}
},
'visible':function(visible) {
if(visible==true){
this.initData()
}
}
},
data() {
return {
currOpType:'add',//add/edit
load:{ list: false, edit: false, del: false, add: false },//...
dicts:{
testPlanStatus:[],
testPlanTcode:[],
},// params={categoryId:'all',itemCodes:['sex']} {sex: [{id:'1',name:''},{id:'2',name:''}]}
rawDatasRules: {
},
rawDatas: {
id:'',name:'',casedbId:'',casedbName:'',projectId:'',projectName:'',cuserid:'',cusername:'',ctime:'',stime:'',etime:'',status:'',tcode:'',totalCases:'',okCases:'',errCases:'',igCases:'',blCases:'',productId:'',productName:'',flowState:'',summaryRemark:''
},
rawDatasBak: {
id:'',name:'',casedbId:'',casedbName:'',projectId:'',projectName:'',cuserid:'',cusername:'',ctime:'',stime:'',etime:'',status:'',tcode:'',totalCases:'',okCases:'',errCases:'',igCases:'',blCases:'',productId:'',productName:'',flowState:'',summaryRemark:''
},
maxTableHeight:300,
summaryRemarkEditVisible:false,
}//end return
},//end data
methods: {
...util,
// @cancel="rawDatasVisible=false"
handleCancel:function(){
this.$refs['rawDatasRef'].resetFields();
this.$emit('cancel');
},
//XmTestPlan @submit="afterEditSubmit"
saveSubmit: function () {
this.$refs.rawDatasRef.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
let params = Object.assign({}, this.rawDatas);
var func=addXmTestPlan
if(this.currOpType=='edit'){
func=editXmTestPlan
}
func(params).then((res) => {
this.load.edit=false
var tips=res.data.tips;
if(tips.isOk){
this.rawDatas=res.data.data
this.initData()
this.currOpType="edit";
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$notify({ position:'bottom-left',showClose:true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err =>this.load.edit=false);
});
}else{
this.$notify({ showClose:true, message: "表单验证不通过,请修改表单数据再提交", type: 'error' });
}
});
},
initData: function(){
if(this.xmTestPlan){
this.rawDatas = Object.assign({},this.xmTestPlan);
}
if(this.rptDatas){
this.rawDatas=Object.assign({},this.rptDatas)
}
this.rawDatasBak={...this.rawDatas}
},
editSomeFields(row,fieldName,$event){
if(this.opType=='add'){
return;
}
let params={};
params['ids']=[row].map(i=>i.id)
if(fieldName=='stime'){
params[fieldName]=$event.stime
params.etime=$event.etime
}else if(fieldName=='cuserid'){
params[fieldName]=$event[0].userid
params.cusername=$event[0].username
}else{
params[fieldName]=$event
}
var func = editSomeFieldsXmTestPlan
func(params).then(res=>{
let tips = res.data.tips;
if(tips.isOk){
this.rawDatasBak=[...this.rawDatas]
this.$emit('edit-fields',params)
}else{
Object.assign(this.rawDatas,this.rawDatasBak)
this.$notify({position:'bottom-left',showClose:true,message:tips.msg,type:tips.isOk?'success':'error'})
}
}).catch((e)=>Object.assign(this.rawDatas,this.rawDatasBak))
},
onPorjectConfirm(row){
this.rawDatas.projectId=row.id
this.rawDatas.projectName=row.name
this.rawDatas.name=this.rawDatas.projectName+'-测试计划-V1.0'
},
sizeAutoChange(){
}
},//end method
mounted() {
this.$nextTick(() => {
initDicts(this);
this.initData()
this.maxTableHeight = util.calcTableMaxHeight(this.$refs.table.$el)
});
}
}
</script>
<style lang="scss" scoped>
.box{
.box-red{
background-color: #ff75750d;
height: 100px;
border-left-width: 2px;
border-left-color: red;
border-left-style: solid;
align-items: center;
line-height: 100px;
text-align: center;
display:flex;
flex-direction: column;
.box-info{
display:flex;
flex-direction: column;
margin-top: 20px;
height: 100px;
line-height: 100px;
.label{
color: #999;
height: 30px;
line-height: 30px;
font-size: 0.875rem;
}
.num{
height: 30px;
line-height: 30px;
color:red ;
font-size: 30px;
}
}
}
.box-green{
background-color: #73d8970d;;
height: 100px;
border-left-width: 2px;
border-left-color: green;
border-left-style: solid;
align-items: center;
line-height: 100px;
text-align: center;
display:flex;
flex-direction: column;
.box-info{
display:flex;
flex-direction: column;
margin-top: 20px;
height: 100px;
line-height: 100px;
.label{
color: #999;
height: 30px;
line-height: 30px;
font-size: 0.875rem;
}
.num{
height: 30px;
line-height: 30px;
color:green ;
font-size: 30px;
}
}
}
.box-blue{
background-color: #5dcfff0d;
height: 100px;
border-left-width: 2px;
border-left-color: blue;
border-left-style: solid;
align-items: center;
line-height: 100px;
text-align: center;
display:flex;
flex-direction: column;
.box-info{
display:flex;
flex-direction: column;
margin-top: 20px;
height: 100px;
line-height: 100px;
.label{
color: #999;
height: 30px;
line-height: 30px;
font-size: 0.875rem;
}
.num{
height: 30px;
line-height: 30px;
color:blue ;
font-size: 30px;
}
}
}
.box-orange{
background-color: #ffcd5d0d;
height: 100px;
border-left-width: 2px;
border-left-color: orange;
border-left-style: solid;
align-items: center;
line-height: 100px;
text-align: center;
display:flex;
flex-direction: column;
.box-info{
display:flex;
flex-direction: column;
margin-top: 20px;
height: 100px;
line-height: 100px;
.label{
color: #999;
height: 30px;
line-height: 30px;
font-size: 0.875rem;
}
.num{
height: 30px;
line-height: 30px;
color:orange ;
font-size: 30px;
}
}
}
box-font{
font-size: 0.875rem;
}
}
</style>
Loading…
Cancel
Save