lxc Mac 5 years ago
parent
commit
14c7243740
  1. 6
      src/views/xm/core/xmIteration/XmIterationOverview.vue
  2. 71
      src/views/xm/core/xmMenu/XmMenuEdit.vue
  3. 663
      src/views/xm/core/xmMenu/XmMenuOverview.vue
  4. 8
      src/views/xm/core/xmProduct/XmProductOverview.vue
  5. 5
      src/views/xm/core/xmProject/XmProjectOverview.vue
  6. 19
      src/views/xm/core/xmProjectGroupState/XmProjectGroupStateMng.vue
  7. 608
      src/views/xm/core/xmProjectGroupState/XmProjectGroupStateOverview.vue
  8. 185
      src/views/xm/core/xmProjectPhase/XmProjectPhaseEdit.vue
  9. 576
      src/views/xm/core/xmProjectPhase/XmProjectPhaseOverview.vue

6
src/views/xm/core/xmIteration/XmIterationOverview.vue

@ -5,7 +5,7 @@
<el-card class="box-card" style="padding:0px ;height:100px"> <el-card class="box-card" style="padding:0px ;height:100px">
<div> <div>
<el-row style="padding:10px"> <el-row style="padding:10px">
<el-steps :active="this.xmIteration.iphase+1" align-center>
<el-steps :active="this.xmIteration.iphase+1" align-center finish-status="success">
<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>
@ -119,7 +119,7 @@
<el-col :span="8" > <el-col :span="8" >
<el-card class="box-card" style="height:425px"> <el-card class="box-card" style="height:425px">
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>所有工作项及其完成情况</span>
<span>所有工作项数量分布</span>
</div> </div>
<div> <div>
<div id="allChart" :style="{width: '100%', height: '350px'}"></div> <div id="allChart" :style="{width: '100%', height: '350px'}"></div>
@ -254,7 +254,7 @@ export default {
return this.xmIteration.taskCnt-this.xmIteration.finishTaskCnt; return this.xmIteration.taskCnt-this.xmIteration.finishTaskCnt;
}, },
taskProgress: function (){ taskProgress: function (){
return Math.round(this.xmIteration.finishTaskCnt/this.xmIteration.taskCnt*100);
return this.xmIteration.finishRate;
}, },
iterationStartTime: function (){ iterationStartTime: function (){
return this.xmIteration.startTime.substring(0,10); return this.xmIteration.startTime.substring(0,10);

71
src/views/xm/core/xmMenu/XmMenuEdit.vue

@ -1,36 +1,41 @@
<template> <template>
<section class="page-container page-full-height border padding">
<section class="page-container border padding">
<el-row class="page-main page-height-90"> <el-row class="page-main page-height-90">
<!--新增界面 XmMenu 项目故事表-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-form-item label="序号" prop="seqNo">
<el-input v-model="editForm.seqNo" placeholder="如1.0 , 1.1 , 1.1.1等" ></el-input>
</el-form-item>
<el-form-item label="故事名称" prop="menuName">
<el-input v-model="editForm.menuName" placeholder="故事名称" ></el-input>
</el-form-item>
<el-form-item label="负责人" prop="mmUserid">
<el-tag v-if="editForm.mmUserid" closable @close="clearPmUser">{{editForm.mmUsername}}</el-tag>
<el-tag v-else>未配置</el-tag>
<el-button @click="selectUser">选负责人</el-button>
</el-form-item>
<el-form-item label="需求链接" prop="demandUrl">
<el-input v-model="editForm.demandUrl" placeholder="需求链接" ></el-input>
</el-form-item>
<el-form-item label="代码链接" prop="codeUrl">
<el-input v-model="editForm.codeUrl" placeholder="代码链接" ></el-input>
</el-form-item>
<el-form-item label="设计链接" prop="designUrl">
<el-input v-model="editForm.designUrl" placeholder="设计链接" ></el-input>
</el-form-item>
<el-form-item label="操作手册链接" prop="operDocUrl">
<el-input v-model="editForm.operDocUrl" placeholder="操作手册链接" ></el-input>
</el-form-item>
<el-form-item label="概述" prop="remark">
<el-input type="textarea" v-model="editForm.remark" :autosize="{ minRows: 4, maxRows: 20}" placeholder="什么人?做什么事?,为什么?如: 作为招聘专员,我需要统计员工半年在职/离职人数,以便我能够制定招聘计划" ></el-input>
</el-form-item>
</el-form>
<el-tabs>
<el-tab-pane label="故事详情">
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-form-item label="序号" prop="seqNo">
<el-input v-model="editForm.seqNo" placeholder="如1.0 , 1.1 , 1.1.1等" ></el-input>
</el-form-item>
<el-form-item label="故事名称" prop="menuName">
<el-input v-model="editForm.menuName" placeholder="故事名称" ></el-input>
</el-form-item>
<el-form-item label="负责人" prop="mmUserid">
<el-tag v-if="editForm.mmUserid" closable @close="clearPmUser">{{editForm.mmUsername}}</el-tag>
<el-tag v-else>未配置</el-tag>
<el-button @click="selectUser">选负责人</el-button>
</el-form-item>
<el-form-item label="需求链接" prop="demandUrl">
<el-input v-model="editForm.demandUrl" placeholder="需求链接" ></el-input>
</el-form-item>
<el-form-item label="代码链接" prop="codeUrl">
<el-input v-model="editForm.codeUrl" placeholder="代码链接" ></el-input>
</el-form-item>
<el-form-item label="设计链接" prop="designUrl">
<el-input v-model="editForm.designUrl" placeholder="设计链接" ></el-input>
</el-form-item>
<el-form-item label="操作手册链接" prop="operDocUrl">
<el-input v-model="editForm.operDocUrl" placeholder="操作手册链接" ></el-input>
</el-form-item>
<el-form-item label="概述" prop="remark">
<el-input type="textarea" v-model="editForm.remark" :autosize="{ minRows: 4, maxRows: 20}" placeholder="什么人?做什么事?,为什么?如: 作为招聘专员,我需要统计员工半年在职/离职人数,以便我能够制定招聘计划" ></el-input>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="概览" lazy>
<xm-menu-overview :xm-menu="xmMenu"></xm-menu-overview>
</el-tab-pane>
</el-tabs>
<el-drawer title="选择员工" :visible.sync="userSelectVisible" size="60%" append-to-body> <el-drawer title="选择员工" :visible.sync="userSelectVisible" size="60%" append-to-body>
<users-select @confirm="onUserSelected" ref="usersSelect"></users-select> <users-select @confirm="onUserSelected" ref="usersSelect"></users-select>
</el-drawer> </el-drawer>
@ -48,6 +53,7 @@
import { editXmMenu } from '@/api/xm/core/xmMenu'; import { editXmMenu } from '@/api/xm/core/xmMenu';
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import UsersSelect from "@/views/mdp/sys/user/UsersSelect"; import UsersSelect from "@/views/mdp/sys/user/UsersSelect";
import XmMenuOverview from './XmMenuOverview.vue';
export default { export default {
@ -146,7 +152,8 @@
},//end method },//end method
components: { components: {
// 'xm-menu-edit':XmMenuEdit // 'xm-menu-edit':XmMenuEdit
UsersSelect
UsersSelect,
XmMenuOverview,
}, },
mounted() { mounted() {
this.editForm=Object.assign(this.editForm, this.xmMenu); this.editForm=Object.assign(this.editForm, this.xmMenu);

663
src/views/xm/core/xmMenu/XmMenuOverview.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() {
// domecharts
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}%)',//bname,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}%)',//bname,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>

8
src/views/xm/core/xmProduct/XmProductOverview.vue

@ -5,7 +5,7 @@
<el-card class="box-card" style="padding:0px ;height:100px"> <el-card class="box-card" style="padding:0px ;height:100px">
<div> <div>
<el-row style="padding:10px"> <el-row style="padding:10px">
<el-steps :active="this.xmProduct.pstatus+1" align-center>
<el-steps :active="this.xmProduct.pstatus+1" align-center finish-status="success">
<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>
@ -73,7 +73,7 @@
<div class="info"> <div class="info">
<div v-text="productStartTime+'~'+productEndTime"> <div v-text="productStartTime+'~'+productEndTime">
</div> </div>
<div class="title">项目计划周期</div>
<div class="title">产品计划周期</div>
</div> </div>
</div> </div>
</el-row> </el-row>
@ -115,7 +115,7 @@
<el-col :span="8" > <el-col :span="8" >
<el-card class="box-card" style="height:425px"> <el-card class="box-card" style="height:425px">
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>所有工作项及其完成情况</span>
<span>所有工作项数量分布</span>
</div> </div>
<div> <div>
<div id="allChart" :style="{width: '100%', height: '350px'}"></div> <div id="allChart" :style="{width: '100%', height: '350px'}"></div>
@ -250,7 +250,7 @@ export default {
return this.xmProduct.taskCnt-this.xmProduct.finishTaskCnt; return this.xmProduct.taskCnt-this.xmProduct.finishTaskCnt;
}, },
taskProgress: function (){ taskProgress: function (){
return Math.round(this.xmProduct.finishTaskCnt/this.xmProduct.taskCnt*100);
return this.xmProduct.finishRate;
}, },
productStartTime: function (){ productStartTime: function (){
if(this.xmProduct.planStartTime){ if(this.xmProduct.planStartTime){

5
src/views/xm/core/xmProject/XmProjectOverview.vue

@ -117,7 +117,7 @@
<el-col :span="8" > <el-col :span="8" >
<el-card class="box-card" style="height:425px"> <el-card class="box-card" style="height:425px">
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>所有工作项及其完成情况</span>
<span>所有工作项数量分布</span>
</div> </div>
<div> <div>
<div id="allChart" :style="{width: '100%', height: '350px'}"></div> <div id="allChart" :style="{width: '100%', height: '350px'}"></div>
@ -260,7 +260,6 @@
</el-col> </el-col>
</el-row> </el-row>
</el-row> </el-row>
</section> </section>
</template> </template>
@ -282,7 +281,7 @@ export default {
return this.selProject.totalTaskCnt; return this.selProject.totalTaskCnt;
}, },
taskProgress: function (){ taskProgress: function (){
return Math.round(this.selProject.totalCompleteTaskCnt/this.selProject.totalTaskCnt*100);
return this.selProject.totalProgress;
}, },
taskStartTime: function (){ taskStartTime: function (){
return this.selProject.startTime.substring(0,10); return this.selProject.startTime.substring(0,10);

19
src/views/xm/core/xmProjectGroupState/XmProjectGroupStateMng.vue

@ -9,7 +9,11 @@
<!--列表 XmProjectGroupState 功能状态表,无需前端维护所有数据由汇总统计得出--> <!--列表 XmProjectGroupState 功能状态表,无需前端维护所有数据由汇总统计得出-->
<el-table ref="table" :height="tableHeight" :data="xmProjectGroupStates" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;"> <el-table ref="table" :height="tableHeight" :data="xmProjectGroupStates" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column sortable type="index" width="45"></el-table-column> <el-table-column sortable type="index" width="45"></el-table-column>
<el-table-column prop="groupName" label="团队名称" min-width="80" ></el-table-column>
<el-table-column prop="groupName" label="团队名称" min-width="80" >
<template slot-scope="scope">
<el-link type="primary" @click="overviewVisible=true">{{scope.row.groupName}}</el-link>
</template>
</el-table-column>
<el-table-column prop="finishRate" label="总体进度" min-width="80" ></el-table-column> <el-table-column prop="finishRate" label="总体进度" min-width="80" ></el-table-column>
<el-table-column prop="planWorkload" label="计划工作量" min-width="80" ></el-table-column> <el-table-column prop="planWorkload" label="计划工作量" min-width="80" ></el-table-column>
<el-table-column prop="actWorkload" label="实际工作量" min-width="80" ></el-table-column> <el-table-column prop="actWorkload" label="实际工作量" min-width="80" ></el-table-column>
@ -34,6 +38,15 @@
</el-row> </el-row>
<el-drawer
append-to-body
title="小组概览"
:visible.sync="overviewVisible"
size="60%"
>
<xm-project-group-state-overview :xm-project-group-state="editForm"></xm-project-group-state-overview>
</el-drawer>
</section> </section>
</template> </template>
@ -43,6 +56,7 @@
import { listOption } from '@/api/mdp/meta/itemOption';// import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProjectGroupState, delXmProjectGroupState, batchDelXmProjectGroupState,loadTasksToXmProjectGroupState } from '@/api/xm/core/xmProjectGroupState'; import { listXmProjectGroupState, delXmProjectGroupState, batchDelXmProjectGroupState,loadTasksToXmProjectGroupState } from '@/api/xm/core/xmProjectGroupState';
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import XmProjectGroupStateOverview from './XmProjectGroupStateOverview.vue';
export default { export default {
computed: { computed: {
@ -92,6 +106,7 @@
/**begin 自定义属性请在下面加 请加备注**/ /**begin 自定义属性请在下面加 请加备注**/
tableHeight:300, tableHeight:300,
overviewVisible:false,
/**end 自定义属性请在上面加 请加备注**/ /**end 自定义属性请在上面加 请加备注**/
} }
},//end data },//end data
@ -218,6 +233,7 @@
}); });
}, },
rowClick: function(row, event, column){ rowClick: function(row, event, column){
this.editForm=row
this.$emit('row-click',row, event, column);// @row-click="rowClick" this.$emit('row-click',row, event, column);// @row-click="rowClick"
}, },
loadTasksToXmProjectGroupState(){ loadTasksToXmProjectGroupState(){
@ -238,6 +254,7 @@
},//end methods },//end methods
components: { components: {
XmProjectGroupStateOverview
// //
}, },
mounted() { mounted() {

608
src/views/xm/core/xmProjectGroupState/XmProjectGroupStateOverview.vue

@ -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() {
// domecharts
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}%)',//bname,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}%)',//bname,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>

185
src/views/xm/core/xmProjectPhase/XmProjectPhaseEdit.vue

@ -1,97 +1,106 @@
<template> <template>
<section class="page-container border padding"> <section class="page-container border padding">
<el-row class="page-main page-height-90"> <el-row class="page-main page-height-90">
<!--新增界面 XmProjectPhase xm_project_phase-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-row class="border padding">
<el-form-item label="阶段名称" prop="phaseName">
<el-input v-model="editForm.phaseName" placeholder="阶段名称" ></el-input>
</el-form-item>
<el-form-item label="序号" prop="seqNo">
<el-input v-model="editForm.seqNo" style="width:50%;" placeholder="排序序号,值越小越靠前,如1.0,2.0等"></el-input>
<el-checkbox true-label="1" false-label="0" v-model="editForm.milestone">标记为里程碑</el-checkbox>
</el-form-item>
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="editForm.taskType">
<el-option v-for="i in this.options.taskType" :label="i.optionName" :key="i.optionValue" :value="i.optionValue"></el-option>
</el-select>
</el-form-item>
<el-form-item label="计划类型" prop="planType">
<el-select v-model="editForm.planType">
<el-option v-for="i in this.options.planType" :label="i.optionName" :key="i.optionValue" :value="i.optionValue"></el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" rows="4" v-model="editForm.remark" placeholder="备注" ></el-input>
</el-form-item>
<el-tabs>
<el-tab-pane label="阶段计划详情">
<!--新增界面 XmProjectPhase xm_project_phase-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-row class="border padding">
<el-form-item label="阶段名称" prop="phaseName">
<el-input v-model="editForm.phaseName" placeholder="阶段名称" ></el-input>
</el-form-item>
<el-form-item label="序号" prop="seqNo">
<el-input v-model="editForm.seqNo" style="width:50%;" placeholder="排序序号,值越小越靠前,如1.0,2.0等"></el-input>
<el-checkbox true-label="1" false-label="0" v-model="editForm.milestone">标记为里程碑</el-checkbox>
</el-form-item>
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="editForm.taskType">
<el-option v-for="i in this.options.taskType" :label="i.optionName" :key="i.optionValue" :value="i.optionValue"></el-option>
</el-select>
</el-form-item>
<el-form-item label="计划类型" prop="planType">
<el-select v-model="editForm.planType">
<el-option v-for="i in this.options.planType" :label="i.optionName" :key="i.optionValue" :value="i.optionValue"></el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" rows="4" v-model="editForm.remark" placeholder="备注" ></el-input>
</el-form-item>
</el-row>
<el-tabs v-model="activeName" class="border padding">
<el-tab-pane label="工作量及人力成本" name="phaseBudgetWorkload">
<el-row>
<el-row class="padding-20 border">
<el-row class="padding">工作量计算方式<font style="color:red">总工时 = 工作日天数 * 每日工时数 * 人数 </font> </el-row>
<el-row class="padding">金额计算方式 <font style="color:red">总金额 = 总工时 * 工时单价 </font></el-row>
</el-row>
<el-row class="padding-20 border">
预计时间<el-date-picker
v-model="dateRanger"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="计划开始日期"
end-placeholder="计划完成日期"
value-format="yyyy-MM-dd"
:default-time="['00:00:00','23:59:59']"
:picker-options="pickerOptions"
></el-date-picker>
预估工期<el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetHours" :precision="2" :step="8" :min="0" placeholder="预计工时"></el-input>小时
<div class="tips"><font>工时{{autoParams.phaseBudgetHours}}小时,工作日{{autoParams.weekday}}</font></div>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">人员类型</el-col>
<el-col :span="4">人数</el-col>
<el-col :span="4">工作量(人时)</el-col>
<el-col :span="4">单价(/人时)</el-col>
<el-col :span="8">总价()</el-col>
</el-row>
<el-tabs v-model="activeName" class="border padding">
<el-tab-pane label="工作量及人力成本" name="phaseBudgetWorkload">
<el-row>
<el-row class="padding-20 border">
<el-row class="padding">工作量计算方式<font style="color:red">总工时 = 工作日天数 * 每日工时数 * 人数 </font> </el-row>
<el-row class="padding">金额计算方式 <font style="color:red">总金额 = 总工时 * 工时单价 </font></el-row>
</el-row>
<el-row class="padding-20 border">
预计时间<el-date-picker
v-model="dateRanger"
type="daterange"
align="right"
unlink-panels
range-separator="至"
start-placeholder="计划开始日期"
end-placeholder="计划完成日期"
value-format="yyyy-MM-dd"
:default-time="['00:00:00','23:59:59']"
:picker-options="pickerOptions"
></el-date-picker>
预估工期<el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetHours" :precision="2" :step="8" :min="0" placeholder="预计工时"></el-input>小时
<div class="tips"><font>工时{{autoParams.phaseBudgetHours}}小时,工作日{{autoParams.weekday}}</font></div>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">人员类型</el-col>
<el-col :span="4">人数</el-col>
<el-col :span="4">工作量(人时)</el-col>
<el-col :span="4">单价(/人时)</el-col>
<el-col :span="8">总价()</el-col>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">内购</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetInnerUserCnt" :precision="0" :step="1" :min="0" placeholder="内购人数"></el-input>
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetInnerUserWorkload}}人时</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetInnerUserPrice" :precision="0" :step="1" :min="0" placeholder="预计内部人时单价"></el-input> </el-col>
<el-col :span="8">{{this.toFixed(autoParams.phaseBudgetInnerUserAt)}},{{this.toFixed(autoParams.phaseBudgetInnerUserAt/10000)}} 万元</el-col>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">外购</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetOutUserCnt" :precision="0" :step="1" :min="0" placeholder="外购人数"></el-input>
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserWorkload}}人时</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetOutUserPrice" :precision="0" :step="1" :min="0" placeholder="预计外购人时单价"></el-input> </el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserAt }} {{autoParams.phaseBudgetOutUserAt/10000 }}万元</el-col>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">内购</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetInnerUserCnt" :precision="0" :step="1" :min="0" placeholder="内购人数"></el-input>
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetInnerUserWorkload}}人时</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetInnerUserPrice" :precision="0" :step="1" :min="0" placeholder="预计内部人时单价"></el-input> </el-col>
<el-col :span="8">{{this.toFixed(autoParams.phaseBudgetInnerUserAt)}},{{this.toFixed(autoParams.phaseBudgetInnerUserAt/10000)}} 万元</el-col>
</el-row>
<el-row class="padding-20 border">
<el-col :span="4">外购</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetOutUserCnt" :precision="0" :step="1" :min="0" placeholder="外购人数"></el-input>
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserWorkload}}人时</el-col>
<el-col :span="4"><el-input style="width:100px;" type="number" v-model="editForm.phaseBudgetOutUserPrice" :precision="0" :step="1" :min="0" placeholder="预计外购人时单价"></el-input> </el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserAt }} {{autoParams.phaseBudgetOutUserAt/10000 }}万元</el-col>
</el-row >
<el-row class="padding-20 border">
<el-col :span="4">合计</el-col>
<el-col :span="4"> {{autoParams.phaseBudgetOutUserCnt+autoParams.phaseBudgetInnerUserCnt}}
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserWorkload+autoParams.phaseBudgetInnerUserWorkload }}人时,{{ (autoParams.phaseBudgetOutUserWorkload+autoParams.phaseBudgetInnerUserWorkload)/8/20 }}人月 </el-col>
<el-col :span="4">{{ (parseFloat2(autoParams.phaseBudgetOutUserPrice) + parseFloat2(autoParams.phaseBudgetInnerUserPrice))/2}}/人时</el-col>
<el-col :span="8">{{autoParams.phaseBudgetTotalCost}} {{(autoParams.phaseBudgetTotalCost)/10000}} 万元</el-col>
</el-row>
<el-row class="padding-20 border">
总计 {{parseFloat2(editForm.phaseBudgetInnerUserAt)+parseFloat2(editForm.phaseBudgetOutUserAt)+parseFloat2(editForm.phaseBudgetNouserAt)}} <el-tag>{{this.toFixed(autoParams.phaseBudgetTotalCost/10000)}}万元</el-tag>
</el-row >
<el-row class="padding-20 border">
<el-col :span="4">合计</el-col>
<el-col :span="4"> {{autoParams.phaseBudgetOutUserCnt+autoParams.phaseBudgetInnerUserCnt}}
</el-col>
<el-col :span="4">{{autoParams.phaseBudgetOutUserWorkload+autoParams.phaseBudgetInnerUserWorkload }}人时,{{ (autoParams.phaseBudgetOutUserWorkload+autoParams.phaseBudgetInnerUserWorkload)/8/20 }}人月 </el-col>
<el-col :span="4">{{ (parseFloat2(autoParams.phaseBudgetOutUserPrice) + parseFloat2(autoParams.phaseBudgetInnerUserPrice))/2}}/人时</el-col>
<el-col :span="8">{{autoParams.phaseBudgetTotalCost}} {{(autoParams.phaseBudgetTotalCost)/10000}} 万元</el-col>
</el-row>
<el-row class="padding-20 border">
总计 {{parseFloat2(editForm.phaseBudgetInnerUserAt)+parseFloat2(editForm.phaseBudgetOutUserAt)+parseFloat2(editForm.phaseBudgetNouserAt)}} <el-tag>{{this.toFixed(autoParams.phaseBudgetTotalCost/10000)}}万元</el-tag>
</el-row>
</el-row>
</el-tab-pane>
<el-tab-pane v-if="activeName=='phaseBudgetWorkload'" label="收起" name="">
</el-tab-pane>
</el-tabs>
</el-form>
</el-row>
</el-row>
</el-tab-pane>
<el-tab-pane v-if="activeName=='phaseBudgetWorkload'" label="收起" name="">
</el-tab-pane>
</el-tabs>
</el-form>
</el-tab-pane>
<el-tab-pane label="阶段计划概览" lazy>
<xm-project-phase-overview :xm-project-phase="xmProjectPhase"></xm-project-phase-overview>
</el-tab-pane>
</el-tabs>
</el-row> </el-row>
<el-row class="page-bottom"> <el-row class="page-bottom">
<el-button @click.native="handleCancel">取消</el-button> <el-button @click.native="handleCancel">取消</el-button>
@ -105,6 +114,7 @@
import { listOption } from '@/api/mdp/meta/itemOption';// import { listOption } from '@/api/mdp/meta/itemOption';//
import { editXmProjectPhase } from '@/api/xm/core/xmProjectPhase'; import { editXmProjectPhase } from '@/api/xm/core/xmProjectPhase';
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import XmProjectPhaseOverview from './XmProjectPhaseOverview';//
export default { export default {
computed: { computed: {
@ -348,6 +358,7 @@
},//end method },//end method
components: { components: {
XmProjectPhaseOverview,
// 'xm-project-phase-edit':XmProjectPhaseEdit // 'xm-project-phase-edit':XmProjectPhaseEdit
}, },
mounted() { mounted() {

576
src/views/xm/core/xmProjectPhase/XmProjectPhaseOverview.vue

@ -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}%)',//bname,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}%)',//bname,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>
Loading…
Cancel
Save