Browse Source
Merge branch 'master' of http://www.qingqinkj.com/gitlab/qqkj/mmcloud/xm/xm-ui-web
master
Merge branch 'master' of http://www.qingqinkj.com/gitlab/qqkj/mmcloud/xm/xm-ui-web
master
9 changed files with 2139 additions and 258 deletions
-
6src/views/xm/core/xmIteration/XmIterationOverview.vue
-
71src/views/xm/core/xmMenu/XmMenuEdit.vue
-
663src/views/xm/core/xmMenu/XmMenuOverview.vue
-
8src/views/xm/core/xmProduct/XmProductOverview.vue
-
5src/views/xm/core/xmProject/XmProjectOverview.vue
-
19src/views/xm/core/xmProjectGroupState/XmProjectGroupStateMng.vue
-
608src/views/xm/core/xmProjectGroupState/XmProjectGroupStateOverview.vue
-
185src/views/xm/core/xmProjectPhase/XmProjectPhaseEdit.vue
-
576src/views/xm/core/xmProjectPhase/XmProjectPhaseOverview.vue
@ -0,0 +1,663 @@ |
|||||
|
<template> |
||||
|
<section> |
||||
|
<el-row class="page-main page-height-75" style="overflow-x: hidden;"> |
||||
|
<el-row style="margin-bottom:10px"> |
||||
|
<el-card class="box-card" style="padding:0px ;height:100px"> |
||||
|
<div> |
||||
|
<el-row style="padding:10px"> |
||||
|
<el-steps :active="this.xmMenu.menuStatus" finish-status="success" align-center> |
||||
|
<el-step title="初始"></el-step> |
||||
|
<el-step title="设计中"></el-step> |
||||
|
<el-step title="开发中"></el-step> |
||||
|
<el-step title="测试中"></el-step> |
||||
|
<el-step title="uat测试"></el-step> |
||||
|
<el-step title="已上线"></el-step> |
||||
|
<el-step title="已下线"></el-step> |
||||
|
<el-step title="已删除"></el-step> |
||||
|
</el-steps> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>故事信息</span> |
||||
|
</div> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-row> |
||||
|
<span v-text="this.xmMenu.mmUsername"></span> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span>故事管理员</span> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-col :span="8" @click=""> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(79, 140, 255);"> |
||||
|
<i class="el-icon-right"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmMenu.taskCnt"></div> |
||||
|
<div class="title">总任务量</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(255, 153, 51);"> |
||||
|
<i class="el-icon-loading"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="notStart"> |
||||
|
</div> |
||||
|
<div class="title">待完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(0, 153, 51);"> |
||||
|
<i class="el-icon-check"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmMenu.finishTaskCnt" > |
||||
|
</div> |
||||
|
<div class="title">已完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-date"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="menuStartTime+'~'+menuEndTime"> |
||||
|
</div> |
||||
|
<div class="title">故事计划周期</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-star-off"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 关联项目数: {{this.xmMenu.projectCnt}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-refresh"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 关联迭代数: {{(this.xmMenu.iterationCnt)}} </div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-alarm-clock"></i> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div class="progress-item"> |
||||
|
<el-progress :percentage="taskProgress"></el-progress> |
||||
|
<div class="title">任务进度</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>所有工作项数量分布</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div id="allChart" :style="{width: '100%', height: '350px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col> |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>项目工时</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmMenu.planWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmMenu.actWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">登记工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="workloadProgress"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">工时进度</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="remainWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">剩余工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviation"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviationRate"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差率</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">项目预计进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;margin-bottom: 20px;" :text-inside="true" :stroke-width="24" :percentage="planProgress"></el-progress> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">项目实际进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;" :text-inside="true" :stroke-width="24" :percentage="realProgress"></el-progress> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>缺陷情况</span> |
||||
|
</div> |
||||
|
<div style="'100%'"> |
||||
|
<div id="bugPieChart" :style="{width: '100%', height: '300px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>案例情况</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div id="casePie" :style="{width: '100%', height: '410px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import util from '@/common/js/util';//全局公共库 |
||||
|
//import { listOption } from '@/api/mdp/meta/itemOption';//下拉框数据查询 |
||||
|
import { mapGetters } from 'vuex' |
||||
|
|
||||
|
|
||||
|
export default { |
||||
|
computed: { |
||||
|
...mapGetters(['userInfo','roles']), |
||||
|
notStart: function() { |
||||
|
return this.xmMenu.taskCnt-this.xmMenu.finishTaskCnt; |
||||
|
}, |
||||
|
taskProgress: function (){ |
||||
|
return this.xmMenu.finishRate; |
||||
|
}, |
||||
|
menuStartTime: function (){ |
||||
|
if(this.xmMenu.planStartTime){ |
||||
|
return this.xmMenu.planStartTime.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
menuEndTime: function (){ |
||||
|
if(this.xmMenu.planEndTime){ |
||||
|
return this.xmMenu.planEndTime.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
workloadProgress:function (){ |
||||
|
return Math.round(this.xmMenu.actWorkload/this.xmMenu.planWorkload*100); |
||||
|
}, |
||||
|
deviation:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmMenu.planStartTime); |
||||
|
let endTime = new Date(this.xmMenu.planEndTime); |
||||
|
if(now<=endTime){ |
||||
|
let allDays=endTime-startTime; |
||||
|
return this.xmMenu.planWorkload - Math.round((now-startTime)/allDays*this.xmMenu.planWorkload) |
||||
|
}else{ |
||||
|
return this.xmMenu.actWorkload - this.xmMenu.planWorkload; |
||||
|
} |
||||
|
}, |
||||
|
deviationRate:function (){ |
||||
|
return Math.round(this.deviation/this.xmMenu.planWorkload*100); |
||||
|
}, |
||||
|
remainWorkload:function (){ |
||||
|
return this.xmMenu.planWorkload - this.xmMenu.actWorkload; |
||||
|
}, |
||||
|
planProgress:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmMenu.planStartTime); |
||||
|
let endTime = new Date(this.xmMenu.planEndTime); |
||||
|
if(now<=endTime){ |
||||
|
let allDays=endTime-startTime; |
||||
|
return Math.round((now-startTime)/allDays*100) |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
realProgress:function (){ |
||||
|
if(this.xmMenu.actWorkload < this.xmMenu.planWorkload){ |
||||
|
return Math.round(this.xmMenu.actWorkload/this.xmMenu.planWorkload*100) |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
xmMenuCpd(){ |
||||
|
return this.xmMenu |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
props:['xmMenu'], |
||||
|
watch:{ |
||||
|
xmMenuCpd:function(){ |
||||
|
this.drawAllBar(); |
||||
|
this.drawPieBug(); |
||||
|
this.drawCasePie(); |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
isActive:true, |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
methods:{ |
||||
|
drawAllBar() { |
||||
|
// 基于准备好的dom,初始化echarts实例 |
||||
|
let allChart = this.$echarts.init(document.getElementById("allChart")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow' |
||||
|
} |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '10%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value' |
||||
|
}, |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: ['测试案例', '任务', '缺陷'] |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
label: { |
||||
|
normal:{ |
||||
|
show: true, |
||||
|
position: 'top', |
||||
|
color:'#000000', |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
value: this.xmMenu.testCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
value: this.xmMenu.taskCnt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
value: this.xmMenu.bugCnt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
], |
||||
|
type: 'bar' |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
|
||||
|
// 绘制图表 |
||||
|
allChart.setOption(option); |
||||
|
|
||||
|
}, |
||||
|
drawPieBug() { |
||||
|
let bugPieChart = this.$echarts.init(document.getElementById("bugPieChart")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} : {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: 'vertical', |
||||
|
left: 'left', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:内部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmMenu.closedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#5470C6' |
||||
|
} |
||||
|
}, |
||||
|
name: '已关闭'}, |
||||
|
{value: this.xmMenu.resolvedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#91CC75' |
||||
|
} |
||||
|
}, |
||||
|
name: '已解决'}, |
||||
|
{value: this.xmMenu.activeBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#FAC858' |
||||
|
} |
||||
|
}, |
||||
|
name: '已激活'}, |
||||
|
{value: this.xmMenu.confirmedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#EE6666' |
||||
|
} |
||||
|
}, |
||||
|
name: '已确认'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
// 绘制图表 |
||||
|
bugPieChart.setOption(option); |
||||
|
}, |
||||
|
drawCasePie() { |
||||
|
let casePie = this.$echarts.init(document.getElementById("casePie")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} :<br/> {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
bottom: 10, |
||||
|
left: 'center', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:外部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmMenu.execCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#73C0DE' |
||||
|
} |
||||
|
}, |
||||
|
name: '测试中案例'}, |
||||
|
{value: this.xmMenu.designCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#FAC858' |
||||
|
} |
||||
|
}, |
||||
|
name: '设计中案例'}, |
||||
|
{value: this.xmMenu.finishCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#91CC75' |
||||
|
} |
||||
|
}, |
||||
|
name: '完成案例'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
|
||||
|
// 绘制图表 |
||||
|
casePie.setOption(option); |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
mounted() { |
||||
|
this.$nextTick(() => { |
||||
|
}); |
||||
|
this.drawAllBar(); |
||||
|
this.drawPieBug(); |
||||
|
this.drawCasePie(); |
||||
|
}, |
||||
|
|
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.container { |
||||
|
margin: 10px; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
padding: 10px; |
||||
|
|
||||
|
span { |
||||
|
padding-right: 15px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.icon { |
||||
|
color: #fff; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.icon2 { |
||||
|
color: #000000; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
margin-left: 5px; |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
position: relative; |
||||
|
.progress-item{ |
||||
|
position:absolute; width:80%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.card-font { |
||||
|
color: #000000; |
||||
|
font-size: 12px; |
||||
|
|
||||
|
.el-col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.calendar-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
|
||||
|
.cal-header-boxs { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
|
||||
|
.cal-header-box { |
||||
|
padding: 5px; |
||||
|
height: 45px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
|
||||
|
.box-icon { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.box-info { |
||||
|
text-align: center; |
||||
|
font-size: 12px; |
||||
|
color: #000000; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-tag:hover { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.value { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.reference { |
||||
|
margin-top: 10px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.click { |
||||
|
background: #e9f7ff; |
||||
|
} |
||||
|
|
||||
|
.calendar-box { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<style> |
||||
|
.app-container{ |
||||
|
padding: 20px; |
||||
|
padding-bottom: 0; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,608 @@ |
|||||
|
<template> |
||||
|
<section> |
||||
|
<el-row class="page-main page-height-75" style="overflow-x: hidden;"> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>团队信息</span> |
||||
|
</div> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-row> |
||||
|
<span>团队名称:</span> |
||||
|
<span v-text="this.xmProjectGroupState.groupName"></span> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-col :span="8" @click=""> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(79, 140, 255);"> |
||||
|
<i class="el-icon-right"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmProjectGroupState.taskCnt"></div> |
||||
|
<div class="title">总任务量</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(255, 153, 51);"> |
||||
|
<i class="el-icon-loading"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="notStart"> |
||||
|
</div> |
||||
|
<div class="title">待完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(0, 153, 51);"> |
||||
|
<i class="el-icon-check"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmProjectGroupState.finishTaskCnt" > |
||||
|
</div> |
||||
|
<div class="title">已完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-date"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="planStartTime+'~'+planEndTime"> |
||||
|
</div> |
||||
|
<div class="title">计划周期</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-star-off"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 汇总时间: {{this.calcTime}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-refresh"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 关联迭代数: {{(this.xmProjectGroupState.iterationCnt)}} </div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-alarm-clock"></i> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div class="progress-item"> |
||||
|
<el-progress v-if="!isNaN(finishRate)" :percentage="finishRate"></el-progress> |
||||
|
<div class="title">任务进度</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>所有工作项数量分布</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div id="allChart" :style="{width: '100%', height: '350px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12"> |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>工作量情况</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmProjectGroupState.planWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">计划工作量</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmProjectGroupState.actWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">完成工作量</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="workloadProgress"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">工作量进度</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="remainWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">剩余工作量</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviation"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviationRate"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差率</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">工作量预计进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;margin-bottom: 20px;" :text-inside="true" |
||||
|
:stroke-width="24" :percentage="planProgress"></el-progress> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">工作量实际进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;" :text-inside="true" :stroke-width="24" |
||||
|
:percentage="realProgress"></el-progress> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>缺陷情况</span> |
||||
|
</div> |
||||
|
<div style="'100%'"> |
||||
|
<div id="bugPieChart" :style="{width: '100%', height: '300px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import util from '@/common/js/util';//全局公共库 |
||||
|
//import { listOption } from '@/api/mdp/meta/itemOption';//下拉框数据查询 |
||||
|
import { mapGetters } from 'vuex' |
||||
|
|
||||
|
|
||||
|
export default { |
||||
|
computed: { |
||||
|
...mapGetters(['userInfo','roles']), |
||||
|
finishRate:function (){ |
||||
|
return parseFloat(this.xmProjectGroupState.finishRate); |
||||
|
}, |
||||
|
notStart: function() { |
||||
|
return this.xmProjectGroupState.taskCnt-this.xmProjectGroupState.finishTaskCnt; |
||||
|
}, |
||||
|
planStartTime: function (){ |
||||
|
if(this.xmProjectGroupState.planStartTime){ |
||||
|
return this.xmProjectGroupState.planStartTime.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
planEndTime: function (){ |
||||
|
if(this.xmProjectGroupState.planEndTime){ |
||||
|
return this.xmProjectGroupState.planEndTime.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
calcTime:function (){ |
||||
|
if(this.xmProjectGroupState.calcTime){ |
||||
|
return this.xmProjectGroupState.calcTime.substring(0,10); |
||||
|
}else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
workloadProgress:function (){ |
||||
|
if(this.xmProjectGroupState && this.xmProjectGroupState.actWorkload){ |
||||
|
return Math.round(this.xmProjectGroupState.actWorkload/this.xmProjectGroupState.planWorkload*100); |
||||
|
}else{ |
||||
|
return 0; |
||||
|
} |
||||
|
}, |
||||
|
deviation:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmProjectGroupState.planStartTime); |
||||
|
let endTime = new Date(this.xmProjectGroupState.planEndTime); |
||||
|
let allDays=endTime-startTime; |
||||
|
if(now<=endTime && allDays){ |
||||
|
return this.xmProjectGroupState.planWorkload - Math.round((now-startTime)/allDays*this.xmProjectGroupState.planWorkload) |
||||
|
}else{ |
||||
|
return this.xmProjectGroupState.actWorkload - this.xmProjectGroupState.planWorkload; |
||||
|
} |
||||
|
}, |
||||
|
deviationRate:function (){ |
||||
|
if(this.xmProjectGroupState.planWorkload){ |
||||
|
return Math.round(this.deviation/this.xmProjectGroupState.planWorkload*100); |
||||
|
}else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
remainWorkload:function (){ |
||||
|
return this.xmProjectGroupState.planWorkload - this.xmProjectGroupState.actWorkload; |
||||
|
}, |
||||
|
planProgress:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmProjectGroupState.planStartTime); |
||||
|
let endTime = new Date(this.xmProjectGroupState.planEndTime); |
||||
|
let allDays=endTime-startTime; |
||||
|
if(now<=endTime && allDays){ |
||||
|
return Math.round((now-startTime)/allDays*100); |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
realProgress:function (){ |
||||
|
if(this.xmProjectGroupState.actWorkload < this.xmProjectGroupState.planWorkload && this.xmProjectGroupState.planWorkload){ |
||||
|
return Math.round(this.xmProjectGroupState.actWorkload/this.xmProjectGroupState.planWorkload*100); |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
xmProjectGroupStateCpd(){ |
||||
|
return this.xmProjectGroupState |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
props:['xmProjectGroupState'], |
||||
|
watch:{ |
||||
|
xmProjectGroupStateCpd:function(){ |
||||
|
this.drawAllBar(); |
||||
|
this.drawPieBug(); |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
isActive:true, |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
methods:{ |
||||
|
drawAllBar() { |
||||
|
// 基于准备好的dom,初始化echarts实例 |
||||
|
let allChart = this.$echarts.init(document.getElementById("allChart")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'axis', |
||||
|
axisPointer: { |
||||
|
type: 'shadow' |
||||
|
} |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '3%', |
||||
|
right: '4%', |
||||
|
bottom: '10%', |
||||
|
containLabel: true |
||||
|
}, |
||||
|
yAxis: { |
||||
|
type: 'value' |
||||
|
}, |
||||
|
xAxis: { |
||||
|
type: 'category', |
||||
|
data: ['测试案例', '任务', '缺陷'] |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
label: { |
||||
|
normal:{ |
||||
|
show: true, |
||||
|
position: 'top', |
||||
|
color:'#000000', |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
value: this.xmProjectGroupState.testCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
value: this.xmProjectGroupState.taskCnt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
value: this.xmProjectGroupState.bugCnt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
], |
||||
|
type: 'bar' |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
|
||||
|
// 绘制图表 |
||||
|
allChart.setOption(option); |
||||
|
|
||||
|
}, |
||||
|
drawPieBug() { |
||||
|
let bugPieChart = this.$echarts.init(document.getElementById("bugPieChart")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} : {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: 'vertical', |
||||
|
left: 'left', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:内部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmProjectGroupState.closedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#5470C6' |
||||
|
} |
||||
|
}, |
||||
|
name: '已关闭'}, |
||||
|
{value: this.xmProjectGroupState.resolvedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#91CC75' |
||||
|
} |
||||
|
}, |
||||
|
name: '已解决'}, |
||||
|
{value: this.xmProjectGroupState.activeBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#FAC858' |
||||
|
} |
||||
|
}, |
||||
|
name: '已激活'}, |
||||
|
{value: this.xmProjectGroupState.confirmedBugs, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#EE6666' |
||||
|
} |
||||
|
}, |
||||
|
name: '已确认'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
// 绘制图表 |
||||
|
bugPieChart.setOption(option); |
||||
|
}, |
||||
|
drawCasePie() { |
||||
|
let casePie = this.$echarts.init(document.getElementById("casePie")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} :<br/> {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
bottom: 10, |
||||
|
left: 'center', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:外部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmProjectGroupState.execCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#73C0DE' |
||||
|
} |
||||
|
}, |
||||
|
name: '测试中案例'}, |
||||
|
{value: this.xmProjectGroupState.designCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#FAC858' |
||||
|
} |
||||
|
}, |
||||
|
name: '设计中案例'}, |
||||
|
{value: this.xmProjectGroupState.finishCases, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#91CC75' |
||||
|
} |
||||
|
}, |
||||
|
name: '完成案例'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
|
||||
|
// 绘制图表 |
||||
|
casePie.setOption(option); |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
mounted() { |
||||
|
this.$nextTick(() => { |
||||
|
}); |
||||
|
this.drawAllBar(); |
||||
|
this.drawPieBug(); |
||||
|
}, |
||||
|
|
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.container { |
||||
|
margin: 10px; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
padding: 10px; |
||||
|
|
||||
|
span { |
||||
|
padding-right: 15px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.icon { |
||||
|
color: #fff; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.icon2 { |
||||
|
color: #000000; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
margin-left: 5px; |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
position: relative; |
||||
|
.progress-item{ |
||||
|
position:absolute; width:80%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.card-font { |
||||
|
color: #000000; |
||||
|
font-size: 12px; |
||||
|
|
||||
|
.el-col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.value { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.click { |
||||
|
background: #e9f7ff; |
||||
|
} |
||||
|
|
||||
|
</style> |
||||
|
|
||||
|
<style> |
||||
|
.app-container{ |
||||
|
padding: 20px; |
||||
|
padding-bottom: 0; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,576 @@ |
|||||
|
<template> |
||||
|
<section> |
||||
|
<el-row class="page-main page-height-75" style="overflow-x: hidden;"> |
||||
|
<el-row style="margin-bottom:10px"> |
||||
|
<el-card class="box-card" style="padding:0px ;height:100px"> |
||||
|
<div> |
||||
|
<el-row style="padding:10px"> |
||||
|
<el-steps :active="this.xmProjectPhase.phaseStatus" finish-status="success" align-center> |
||||
|
<el-step title="初始"></el-step> |
||||
|
<el-step title="执行中"></el-step> |
||||
|
<el-step title="完工"></el-step> |
||||
|
<el-step title="关闭"></el-step> |
||||
|
<el-step title="删除中"></el-step> |
||||
|
<el-step title="已删除"></el-step> |
||||
|
<el-step title="暂停"></el-step> |
||||
|
</el-steps> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>阶段信息</span> |
||||
|
</div> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-row> |
||||
|
<span v-text="this.xmProjectPhase.mngUsername"></span> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span>阶段管理员</span> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<el-col :span="8" @click=""> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(79, 140, 255);"> |
||||
|
<i class="el-icon-right"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmProjectPhase.taskCnt"></div> |
||||
|
<div class="title">总任务量</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(255, 153, 51);"> |
||||
|
<i class="el-icon-loading"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="notStart"> |
||||
|
</div> |
||||
|
<div class="title">待完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div class="item"> |
||||
|
<div class="icon" style="background-color: rgb(0, 153, 51);"> |
||||
|
<i class="el-icon-check"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="this.xmProjectPhase.finishTaskCnt" > |
||||
|
</div> |
||||
|
<div class="title">已完成</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-date"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div v-text="phaseBeginDate+'~'+phaseEndDate"> |
||||
|
</div> |
||||
|
<div class="title">阶段计划周期</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-star-off"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 创建时间: {{this.phaseCreateDate}}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-refresh"></i> |
||||
|
</div> |
||||
|
<div class="info"> |
||||
|
<div class="title"> 关联迭代数: {{(this.xmProjectPhase.iterationCnt)}} </div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="margin-bottom:18px"> |
||||
|
<div class="item"> |
||||
|
<div class="icon2" style="background-color: rgb(204, 204, 204);"> |
||||
|
<i class="el-icon-alarm-clock"></i> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div class="progress-item"> |
||||
|
<el-progress :percentage="taskProgress"></el-progress> |
||||
|
<div class="title">任务进度</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="padding:0px ;height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>阶段工时</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmProjectPhase.phaseBudgetWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="this.xmProjectPhase.phaseActWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">登记工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="workloadProgress"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">工时进度</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row style="padding:25px;"> |
||||
|
<div class="item"> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="remainWorkload"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">剩余工时</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviation"></span> |
||||
|
<span style="font-size:5px;">h</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<div> |
||||
|
<div style="text-align:center;"> |
||||
|
<span style="font-size:24px;" v-text="deviationRate"></span> |
||||
|
<span style="font-size:5px;">%</span> |
||||
|
</div> |
||||
|
<div style="text-align:center;font-size:5px;">预估偏差率</div> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</div> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">项目预计进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;margin-bottom: 20px;" :text-inside="true" :stroke-width="24" :percentage="planProgress"></el-progress> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<span style="margin-left:20px;">项目实际进度</span> |
||||
|
<el-progress style="width: 90%;margin-left:20px;margin-top: 10px;" :text-inside="true" :stroke-width="24" :percentage="realProgress"></el-progress> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="10" style="margin-bottom:10px"> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>总预算情况</span> |
||||
|
</div> |
||||
|
<div style="'100%'"> |
||||
|
<div id="costPieChart" :style="{width: '100%', height: '300px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
<el-col :span="12" > |
||||
|
<el-card class="box-card" style="height:425px"> |
||||
|
<div slot="header" class="clearfix"> |
||||
|
<span>工作量分布</span> |
||||
|
</div> |
||||
|
<div> |
||||
|
<div id="workloadPie" :style="{width: '100%', height: '300px'}"></div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-row> |
||||
|
</section> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import util from '@/common/js/util';//全局公共库 |
||||
|
//import { listOption } from '@/api/mdp/meta/itemOption';//下拉框数据查询 |
||||
|
import { mapGetters } from 'vuex' |
||||
|
|
||||
|
|
||||
|
export default { |
||||
|
computed: { |
||||
|
...mapGetters(['userInfo','roles']), |
||||
|
notStart: function() { |
||||
|
return this.xmProjectPhase.taskCnt-this.xmProjectPhase.finishTaskCnt; |
||||
|
}, |
||||
|
taskProgress: function (){ |
||||
|
if(this.xmProjectPhase.actRate){ |
||||
|
return this.xmProjectPhase.actRate; |
||||
|
}else{ |
||||
|
return 0; |
||||
|
} |
||||
|
}, |
||||
|
phaseBeginDate: function (){ |
||||
|
if(this.xmProjectPhase.beginDate){ |
||||
|
return this.xmProjectPhase.beginDate.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
phaseEndDate: function (){ |
||||
|
if(this.xmProjectPhase.endDate){ |
||||
|
return this.xmProjectPhase.endDate.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
phaseCreateDate: function (){ |
||||
|
if(this.xmProjectPhase.ctime){ |
||||
|
return this.xmProjectPhase.ctime.substring(0,10); |
||||
|
} else{ |
||||
|
return '暂无'; |
||||
|
} |
||||
|
}, |
||||
|
workloadProgress:function (){ |
||||
|
return Math.round(this.xmProjectPhase.phaseActWorkload/this.xmProjectPhase.phaseBudgetWorkload*100); |
||||
|
}, |
||||
|
deviation:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmProjectPhase.beginDate); |
||||
|
let endTime = new Date(this.xmProjectPhase.endDate); |
||||
|
if(now<=endTime){ |
||||
|
let allDays=endTime-startTime; |
||||
|
return this.xmProjectPhase.phaseBudgetWorkload - Math.round((now-startTime)/allDays*this.xmProjectPhase.phaseBudgetWorkload) |
||||
|
}else{ |
||||
|
return this.xmProjectPhase.phaseActWorkload - this.xmProjectPhase.phaseBudgetWorkload; |
||||
|
} |
||||
|
}, |
||||
|
deviationRate:function (){ |
||||
|
return Math.round(this.deviation/this.xmProjectPhase.phaseBudgetWorkload*100); |
||||
|
}, |
||||
|
remainWorkload:function (){ |
||||
|
return this.xmProjectPhase.phaseBudgetWorkload - this.xmProjectPhase.phaseActWorkload; |
||||
|
}, |
||||
|
planProgress:function (){ |
||||
|
let now = new Date(); |
||||
|
let startTime = new Date(this.xmProjectPhase.beginDate); |
||||
|
let endTime = new Date(this.xmProjectPhase.endDate); |
||||
|
if(now<=endTime){ |
||||
|
let allDays=endTime-startTime; |
||||
|
return Math.round((now-startTime)/allDays*100) |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
realProgress:function (){ |
||||
|
if(this.xmProjectPhase.phaseActWorkload < this.xmProjectPhase.phaseBudgetWorkload){ |
||||
|
return Math.round(this.xmProjectPhase.phaseActWorkload/this.xmProjectPhase.phaseBudgetWorkload*100) |
||||
|
}else{ |
||||
|
return 100; |
||||
|
} |
||||
|
}, |
||||
|
xmProjectPhaseCpd(){ |
||||
|
return this.xmProjectPhase |
||||
|
}, |
||||
|
|
||||
|
}, |
||||
|
|
||||
|
props:['xmProjectPhase'], |
||||
|
watch:{ |
||||
|
xmProjectPhaseCpd:function(){ |
||||
|
this.drawCostPie(); |
||||
|
this.drawWorkloadPie(); |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
methods:{ |
||||
|
drawCostPie() { |
||||
|
let costPieChart = this.$echarts.init(document.getElementById("costPieChart")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} : {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: 'vertical', |
||||
|
left: 'left', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:外部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmProjectPhase.phaseBudgetNouserAt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#5470C6' |
||||
|
} |
||||
|
}, |
||||
|
name: '非人力'}, |
||||
|
{value: this.xmProjectPhase.phaseBudgetInnerUserAt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#73C0DE' |
||||
|
} |
||||
|
}, |
||||
|
name: '内部人力'}, |
||||
|
{value: this.xmProjectPhase.phaseBudgetOutUserAt, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#99CCFF' |
||||
|
} |
||||
|
}, |
||||
|
name: '外购人力'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
// 绘制图表 |
||||
|
costPieChart.setOption(option); |
||||
|
}, |
||||
|
drawWorkloadPie() { |
||||
|
let workloadPie = this.$echarts.init(document.getElementById("workloadPie")); |
||||
|
let option = { |
||||
|
tooltip: { |
||||
|
trigger: 'item', |
||||
|
formatter: '{b} : {c} ({d}%)' |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: 'vertical', |
||||
|
left: 'left', |
||||
|
}, |
||||
|
series: [ |
||||
|
{ |
||||
|
center:['55%','40%'],//饼图位置 |
||||
|
type: 'pie', |
||||
|
radius: '50%',//饼图半径大小 |
||||
|
label:{ //饼图图形上的文本标签 |
||||
|
normal:{ |
||||
|
show:true, |
||||
|
position:'outer', //标签的位置:外部 |
||||
|
textStyle : { |
||||
|
fontWeight : 100 , |
||||
|
fontSize: document.body.clientWidth / 120, //标签字体大小 |
||||
|
color: "#000000" |
||||
|
}, |
||||
|
formatter:'{b}\n{c}({d}%)',//b:name,c:value,d:占比 |
||||
|
alignTo:'edge', |
||||
|
margin:10 |
||||
|
} |
||||
|
}, |
||||
|
data: [ |
||||
|
{value: this.xmProjectPhase.phaseBudgetInnerUserWorkload, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#5470C6' |
||||
|
} |
||||
|
}, |
||||
|
name: '内部人力'}, |
||||
|
{value: this.xmProjectPhase.phaseBudgetOutUserWorkload, |
||||
|
itemStyle: { |
||||
|
normal:{ |
||||
|
color: '#73C0DE' |
||||
|
} |
||||
|
}, |
||||
|
name: '外购人力'}, |
||||
|
], |
||||
|
emphasis: { |
||||
|
itemStyle: { |
||||
|
shadowBlur: 10, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}; |
||||
|
// 绘制图表 |
||||
|
workloadPie.setOption(option); |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
mounted() { |
||||
|
this.$nextTick(() => { |
||||
|
}); |
||||
|
this.drawCostPie(); |
||||
|
this.drawWorkloadPie(); |
||||
|
}, |
||||
|
|
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.container { |
||||
|
margin: 10px; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
padding: 10px; |
||||
|
|
||||
|
span { |
||||
|
padding-right: 15px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.icon { |
||||
|
color: #fff; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.icon2 { |
||||
|
color: #000000; |
||||
|
height: 30px; |
||||
|
width: 30px; |
||||
|
border-radius: 15px; |
||||
|
text-align: center; |
||||
|
line-height: 30px; |
||||
|
font-size: 20px; |
||||
|
display: inline-block; |
||||
|
margin-right: 5px; |
||||
|
margin-left: 5px; |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
position: relative; |
||||
|
.progress-item{ |
||||
|
position:absolute; width:80%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.card-font { |
||||
|
color: #000000; |
||||
|
font-size: 12px; |
||||
|
|
||||
|
.el-col { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.calendar-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
|
||||
|
.cal-header-boxs { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
|
||||
|
.cal-header-box { |
||||
|
padding: 5px; |
||||
|
height: 45px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
|
||||
|
.box-icon { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.box-info { |
||||
|
text-align: center; |
||||
|
font-size: 12px; |
||||
|
color: #000000; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-tag:hover { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.value { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.reference { |
||||
|
margin-top: 10px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.click { |
||||
|
background: #e9f7ff; |
||||
|
} |
||||
|
|
||||
|
.calendar-box { |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<style> |
||||
|
.app-container{ |
||||
|
padding: 20px; |
||||
|
padding-bottom: 0; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue