Browse Source

Merge remote-tracking branch 'origin/master'

master
chentaiyu 5 years ago
parent
commit
9b69c50b44
  1. 4
      config/index.js
  2. 30
      src/api/xm/core/xmIterationProductLink.js
  3. 30
      src/api/xm/core/xmProductProjectLink.js
  4. 33
      src/router/routes_xm.js
  5. 6
      src/styles/mdp.scss
  6. 2
      src/views/xm/core/xmIteration/XmIterationAdd.vue
  7. 46
      src/views/xm/core/xmIteration/XmIterationForProjectComplex.vue
  8. 444
      src/views/xm/core/xmIteration/XmIterationInfo.vue
  9. 61
      src/views/xm/core/xmIteration/XmIterationInfoRoute.vue
  10. 112
      src/views/xm/core/xmIteration/XmIterationMng.vue
  11. 3
      src/views/xm/core/xmIteration/XmIterationSelect.vue
  12. 123
      src/views/xm/core/xmIterationProductLink/XmIterationProductLinkAdd.vue
  13. 118
      src/views/xm/core/xmIterationProductLink/XmIterationProductLinkEdit.vue
  14. 252
      src/views/xm/core/xmIterationProductLink/XmIterationProductLinkMng.vue
  15. 42
      src/views/xm/core/xmMenu/XmMenuMng.vue
  16. 2
      src/views/xm/core/xmProduct/XmProductAdd.vue
  17. 174
      src/views/xm/core/xmProduct/XmProductForProjectComplex.vue
  18. 445
      src/views/xm/core/xmProduct/XmProductInfo.vue
  19. 61
      src/views/xm/core/xmProduct/XmProductInfoRoute.vue
  20. 279
      src/views/xm/core/xmProduct/XmProductMng.vue
  21. 699
      src/views/xm/core/xmProduct/XmProductOverview.vue
  22. 130
      src/views/xm/core/xmProduct/XmProductOverviewComplex.vue
  23. 73
      src/views/xm/core/xmProduct/XmProductProjectForLink.vue
  24. 18
      src/views/xm/core/xmProduct/XmProductSelect.vue
  25. 123
      src/views/xm/core/xmProductProjectLink/XmProductProjectLinkAdd.vue
  26. 118
      src/views/xm/core/xmProductProjectLink/XmProductProjectLinkEdit.vue
  27. 252
      src/views/xm/core/xmProductProjectLink/XmProductProjectLinkMng.vue
  28. 356
      src/views/xm/core/xmProject/XmProjectForLink.vue
  29. 18
      src/views/xm/core/xmProject/XmProjectInfo.vue
  30. 0
      src/views/xm/core/xmProject/XmProjectOverviewComplex.vue
  31. 9
      src/views/xm/core/xmProjectPhase/XmProjectPhaseMng.vue
  32. 10
      src/views/xm/core/xmProjectPhase/XmProjectPhaseSelect.vue
  33. 38
      src/views/xm/core/xmQuestion/XmQuestionMng.vue
  34. 14
      src/views/xm/core/xmTask/XmTaskMng.vue

4
config/index.js

@ -11,7 +11,7 @@ module.exports = {
assetsSubDirectory: 'static', assetsSubDirectory: 'static',
assetsPublicPath: '/', assetsPublicPath: '/',
proxyTable: { proxyTable: {
/**
'/api/m1/xm': { '/api/m1/xm': {
target: 'http://localhost:7067', target: 'http://localhost:7067',
changeOrigin: true, changeOrigin: true,
@ -19,7 +19,7 @@ module.exports = {
'^/api/m1/xm': '/xm' '^/api/m1/xm': '/xm'
} }
}, },
/**
'/api/m1/workflow': { '/api/m1/workflow': {
target: 'http://localhost:7080', target: 'http://localhost:7080',
changeOrigin: true, changeOrigin: true,

30
src/api/xm/core/xmIterationProductLink.js

@ -0,0 +1,30 @@
import axios from '@/utils/request'
import config from '@/common/config'
let base = config.getCoreBasePath();
/**
* 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表
*1 默认只开放普通查询所有查询只要上传 分页参数 {currentPage:当前页码从1开始,pageSize:每页记录数,total:总记录数如果是0后台会自动计算总记录数非0不会自动计算}后台都会自动按分页查询 其它 api用到再打开没用到的api请注释掉
*2 查询新增修改的参数格式 params={iterationId:'迭代表主键 主键',productId:'产品表主键 主键',ctime:'创建时间',cuserid:'创建人编号',cusername:'创建人姓名',linkStatus:'关联状态1关联0取消关联'}
**/
//普通查询 条件之间and关系
export const listXmIterationProductLink = params => { return axios.get(`${base}/xm/core/xmIterationProductLink/list`, { params: params }); };
//模糊查询迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表 条件之间or关系
//export const listXmIterationProductLinkKey = params => { return axios.get(`${base}/xm/core/xmIterationProductLink/listKey`, { params: params }); };
//删除一条迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表 params={iterationId:'迭代表主键 主键',productId:'产品表主键 主键'}
export const delXmIterationProductLink = params => { return axios.post(`${base}/xm/core/xmIterationProductLink/del`,params); };
//批量删除迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表 params=[{iterationId:'迭代表主键 主键',productId:'产品表主键 主键'}]
export const batchDelXmIterationProductLink = params => { return axios.post(`${base}/xm/core/xmIterationProductLink/batchDel`, params); };
//修改一条迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表记录
export const editXmIterationProductLink = params => { return axios.post(`${base}/xm/core/xmIterationProductLink/edit`, params); };
//新增一条迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表
export const addXmIterationProductLink = params => { return axios.post(`${base}/xm/core/xmIterationProductLink/add`, params); };

30
src/api/xm/core/xmProductProjectLink.js

@ -0,0 +1,30 @@
import axios from '@/utils/request'
import config from '@/common/config'
let base = config.getCoreBasePath();
/**
* 产品与项目的关联关系表一般由产品经理挂接项目到产品上
*1 默认只开放普通查询所有查询只要上传 分页参数 {currentPage:当前页码从1开始,pageSize:每页记录数,total:总记录数如果是0后台会自动计算总记录数非0不会自动计算}后台都会自动按分页查询 其它 api用到再打开没用到的api请注释掉
*2 查询新增修改的参数格式 params={projectId:'项目表中的主键 主键',productId:'产品表中的主键 主键',ctime:'创建时间',cuserid:'创建人编号',cusername:'创建人姓名',linkStatus:'关联状态1关联0取消关联'}
**/
//普通查询 条件之间and关系
export const listXmProductProjectLink = params => { return axios.get(`${base}/xm/core/xmProductProjectLink/list`, { params: params }); };
//模糊查询产品与项目的关联关系表,一般由产品经理挂接项目到产品上 条件之间or关系
//export const listXmProductProjectLinkKey = params => { return axios.get(`${base}/xm/core/xmProductProjectLink/listKey`, { params: params }); };
//删除一条产品与项目的关联关系表,一般由产品经理挂接项目到产品上 params={projectId:'项目表中的主键 主键',productId:'产品表中的主键 主键'}
export const delXmProductProjectLink = params => { return axios.post(`${base}/xm/core/xmProductProjectLink/del`,params); };
//批量删除产品与项目的关联关系表,一般由产品经理挂接项目到产品上 params=[{projectId:'项目表中的主键 主键',productId:'产品表中的主键 主键'}]
export const batchDelXmProductProjectLink = params => { return axios.post(`${base}/xm/core/xmProductProjectLink/batchDel`, params); };
//修改一条产品与项目的关联关系表,一般由产品经理挂接项目到产品上记录
export const editXmProductProjectLink = params => { return axios.post(`${base}/xm/core/xmProductProjectLink/edit`, params); };
//新增一条产品与项目的关联关系表,一般由产品经理挂接项目到产品上
export const addXmProductProjectLink = params => { return axios.post(`${base}/xm/core/xmProductProjectLink/add`, params); };

33
src/router/routes_xm.js

@ -16,7 +16,7 @@ export default {
// leaf: true,//只有一个节点 // leaf: true,//只有一个节点
children: [ children: [
{ path: 'xmProject/XmProjectAdd', component: _import('xm/core/xmProject/XmProjectAdd'), name: 'xmProjectAdd', meta: { title: '项目立项' }},
{ path: 'xmProject/XmProjectAdd', component: _import('xm/core/xmProject/XmProjectAdd'), name: 'xmProjectAdd',hidden:true, meta: { title: '项目立项' }},
{ path: 'xmProject/XmProjectAllMng', component: _import('xm/core/xmProject/XmProjectAllMng'), name: 'xmProjectAllMng', meta: { title: '项目总览' }}, { path: 'xmProject/XmProjectAllMng', component: _import('xm/core/xmProject/XmProjectAllMng'), name: 'xmProjectAllMng', meta: { title: '项目总览' }},
{ path: 'xmProject/XmProjectMng', component: _import('xm/core/xmProject/XmProjectMng'), name: 'xmProjectMng', meta: { title: '项目(我的)' }}, { path: 'xmProject/XmProjectMng', component: _import('xm/core/xmProject/XmProjectMng'), name: 'xmProjectMng', meta: { title: '项目(我的)' }},
{ path: 'xmProjectState/XmCockpit', name: 'XmCockpit', meta: { title: '领导驾驶舱' ,openTab:true,outUrl:'${curlDomain}/xm/'+process.env.VERSION+'/#/datav/xm/branch/branchDatavFullScreen'}}, { path: 'xmProjectState/XmCockpit', name: 'XmCockpit', meta: { title: '领导驾驶舱' ,openTab:true,outUrl:'${curlDomain}/xm/'+process.env.VERSION+'/#/datav/xm/branch/branchDatavFullScreen'}},
@ -77,23 +77,46 @@ export default {
] ]
}, },
{
path: '/xm/core/xmProduct/XmProductInfoRoute',
component: _import('xm/core/xmProduct/XmProductInfoRoute'),
name: 'XmProductInfoRoute',
iconCls: 'fa el-icon-menu',
meta: {
title: '产品管理',
icon: 'project',
hidden:true
},
},
{ {
path: '/xm/core', path: '/xm/core',
component: Layout, component: Layout,
name: '用户故事',
name: '产品管理',
iconCls: 'fa el-icon-menu', iconCls: 'fa el-icon-menu',
meta: { meta: {
title: '用户故事',
title: '产品管理',
icon: 'project' icon: 'project'
}, },
// leaf: true,//只有一个节点 // leaf: true,//只有一个节点
children: [ children: [
{ path: 'xmProduct/XmProductMng', component: _import('xm/core/xmProduct/XmProductMng'), name: 'XmProductMng', meta: { title: '产品管理' }},
{ path: 'xmProduct/XmProductMng', component: _import('xm/core/xmProduct/XmProductMng'), name: 'XmProductMng', meta: { title: '产品管理' }},
{ path: 'xmMenu/XmMenuMng', component: _import('xm/core/xmMenu/XmMenuMng'), name: 'XmMenuMng', meta: { title: '故事管理' }}, { path: 'xmMenu/XmMenuMng', component: _import('xm/core/xmMenu/XmMenuMng'), name: 'XmMenuMng', meta: { title: '故事管理' }},
{ path: 'xmMenuExchange/XmMenuExchangeMng', component: _import('xm/core/xmMenuExchange/XmMenuExchangeMng'), name: 'XmMenuExchangeMng', meta: { title: '互动评论' }}, { path: 'xmMenuExchange/XmMenuExchangeMng', component: _import('xm/core/xmMenuExchange/XmMenuExchangeMng'), name: 'XmMenuExchangeMng', meta: { title: '互动评论' }},
{ path: 'xmMenuTemplate/XmMenuTemplateMng', component: _import('xm/core/xmMenuTemplate/XmMenuTemplateMng'), name: 'XmMenuTemplateMng', meta: { title: '故事模板' }}, { path: 'xmMenuTemplate/XmMenuTemplateMng', component: _import('xm/core/xmMenuTemplate/XmMenuTemplateMng'), name: 'XmMenuTemplateMng', meta: { title: '故事模板' }},
] ]
},,
{
path: '/xm/core/xmIteration/XmIterationInfoRoute',
component: _import('xm/core/xmIteration/XmIterationInfoRoute'),
name: 'XmIterationInfoRoute',
iconCls: 'fa el-icon-menu',
meta: {
title: '迭代管理',
icon: 'project',
hidden:true
},
}, },
{ {
path: '/xm/core', path: '/xm/core',
@ -106,7 +129,7 @@ export default {
}, },
// leaf: true,//只有一个节点 // leaf: true,//只有一个节点
children: [ children: [
{ path: 'xmIteration/XmIterationMng', component: _import('xm/core/xmIteration/XmIterationMng'), name: 'XmIterationMng', meta: { title: '迭代管理' }},
{ path: 'xmIteration/XmIterationMng', component: _import('xm/core/xmIteration/XmIterationMng'), name: 'XmIterationMng', meta: { title: '迭代管理' }},
{ path: 'xmIterationMenu/XmIterationMenuMng', component: _import('xm/core/xmIterationMenu/XmIterationMenuMng'), name: 'XmIterationMenuMng', meta: { title: '故事迭代' }}, { path: 'xmIterationMenu/XmIterationMenuMng', component: _import('xm/core/xmIterationMenu/XmIterationMenuMng'), name: 'XmIterationMenuMng', meta: { title: '故事迭代' }},
] ]
} }

6
src/styles/mdp.scss

@ -165,14 +165,14 @@
.tips{ .tips{
position:absolute; position:absolute;
font-size: 10px;
bottom: 0px;
font-size: 14px;
bottom: -10px;
color: red; color: red;
padding-left: 10px; padding-left: 10px;
flex: 0 0 auto; flex: 0 0 auto;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
align-items: center;
align-items: bottom;
overflow-x: hidden; overflow-x: hidden;
} }

2
src/views/xm/core/xmIteration/XmIterationAdd.vue

@ -128,7 +128,7 @@
var tips=res.data.tips; var tips=res.data.tips;
if(tips.isOk){ if(tips.isOk){
this.$refs['addForm'].resetFields(); this.$refs['addForm'].resetFields();
this.$emit('submit');// @submit="afterAddSubmit"
this.$emit('submit',res.data.data);// @submit="afterAddSubmit"
} }
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error' }); this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.add=false); }).catch( err => this.load.add=false);

src/views/xm/core/xmIteration/XmIterationComplex.vue → src/views/xm/core/xmIteration/XmIterationForProjectComplex.vue

444
src/views/xm/core/xmIteration/XmIterationInfo.vue

@ -0,0 +1,444 @@
<template>
<section class="page-container page-full-height">
<el-row>
<el-menu :default-active="infotype" mode="horizontal" @select="setInfotype" class="menus" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
<el-menu-item index="迭代概览" >
<span slot="title" >
<span slot="title" @click.stop="goBack"><i class="el-icon-back" ></i></span>
<i class="el-icon-s-data"></i>
<font v-if="xmIteration.iterationName.length>=10">{{xmIteration.iterationName.substring(0,10)}}</font>
<font type="danger" v-else>{{xmIteration.iterationName}}</font>
概览
</span>
</el-menu-item>
<el-menu-item label="项目" index="项目">
<span slot="title"><i class="el-icon-document"></i>项目</span>
</el-menu-item>
<el-menu-item index="产品">
<span slot="title"><i class="el-icon-s-flag"></i>产品</span>
</el-menu-item>
<el-menu-item label="故事" index="用户故事">
<span slot="title"><i class="el-icon-document"></i>故事</span>
</el-menu-item>
<el-menu-item index="任务">
<span slot="title"><i class="el-icon-s-operation"></i>任务</span>
</el-menu-item>
<el-menu-item index="缺陷">
<span slot="title"><i class="el-icon-question"></i>缺陷</span>
</el-menu-item>
<el-menu-item index="团队">
<span slot="title"><i class="el-icon-user-solid"></i>团队</span>
</el-menu-item>
<el-menu-item index="文档">
<span slot="title"><i class="el-icon-document"></i>文档</span>
</el-menu-item>
<el-submenu index="规划与里程碑">
<template slot="title">规划与里程碑 </template>
<el-menu-item index="阶段计划及里程碑">
<span slot="title"><i class="el-icon-odometer"></i>阶段计划及里程碑</span>
</el-menu-item>
<el-menu-item index="测试计划">
<span slot="title"><i class="el-icon-odometer"></i>测试计划</span>
</el-menu-item>
</el-submenu >
<el-menu-item index="项目监控" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-video-camera"></i>项目监控</span>
</el-menu-item>
<el-menu-item index="故事监控" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-video-camera"></i>故事监控</span>
</el-menu-item>
<el-menu-item index="合同管理" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-s-data"></i>合同管理</span>
</el-menu-item>
<el-menu-item index="预算" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-coin"></i>预算</span>
</el-menu-item>
<el-menu-item index="费用" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-coin"></i>费用</span>
</el-menu-item>
<el-menu-item index="考核" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-view"></i>考核</span>
</el-menu-item>
<el-menu-item index="日志" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-edit-outline"></i>日志</span>
</el-menu-item>
<el-menu-item index="环境清单" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-setting"></i>环境清单</span>
</el-menu-item>
<el-menu-item index="风险" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-question"></i>风险</span>
</el-menu-item>
<el-submenu index="更多">
<template slot="title">更多 </template>
<el-menu-item index="故事监控" >
<span slot="title"><i class="el-icon-video-camera"></i>故事监控</span>
</el-menu-item>
<el-menu-item index="项目监控">
<span slot="title"><i class="el-icon-video-camera"></i>项目监控</span>
</el-menu-item>
<el-menu-item index="预算">
<span slot="title"><i class="el-icon-coin"></i>预算</span>
</el-menu-item>
<el-menu-item index="费用">
<span slot="title"><i class="el-icon-coin"></i>费用</span>
</el-menu-item>
<el-menu-item index="考核">
<span slot="title"><i class="el-icon-view"></i>考核</span>
</el-menu-item>
<el-menu-item index="日志">
<span slot="title"><i class="el-icon-edit-outline"></i>日志</span>
</el-menu-item>
<el-menu-item index="合同管理">
<span slot="title"><i class="el-icon-s-data"></i>合同管理</span>
</el-menu-item>
<el-menu-item index="环境清单">
<span slot="title"><i class="el-icon-setting"></i>环境清单</span>
</el-menu-item>
<el-menu-item index="风险">
<span slot="title"><i class="el-icon-question"></i>风险</span>
</el-menu-item>
<el-menu-item index="论坛">
<span slot="title"><i class="el-icon-date"></i>论坛</span>
</el-menu-item>
<el-menu-item index="即聊">
<span slot="title"><i class="el-icon-date"></i>即聊</span>
</el-menu-item>
<el-menu-item index="客服">
<span slot="title"><i class="el-icon-date"></i>客服</span>
</el-menu-item>
</el-submenu>
</el-menu>
<xm-project-overview-complex v-if="infotype=='项目概览'" :xm-iteration="xmIteration"></xm-project-overview-complex>
<xm-project-for-link v-if="infotype=='项目'" ref="xmProjectForLink" :xm-iteration="xmIteration"></xm-project-for-link>
<xm-product-for-project-complex v-if="infotype=='产品'" ref="xmProductComplex" :xm-iteration="xmIteration"></xm-product-for-project-complex>
<xm-menu-mng v-if="infotype=='用户故事'" :xm-iteration="xmIteration"></xm-menu-mng>
<xm-task-mng v-if="infotype=='任务'" ref="xmTaskMng" :xm-iteration="xmIteration" ></xm-task-mng>
<xm-question v-if="infotype=='缺陷'" :qtype="'bug'" :xm-iteration='xmIteration' ref="xmQuestion"></xm-question>
<xm-group-mng v-if="infotype=='团队'" :xm-iteration="xmIteration"></xm-group-mng>
<xm-file-mng v-if="infotype=='文档'" :xm-iteration="xmIteration"></xm-file-mng>
<xm-project-phase-mng v-if="infotype=='阶段计划及里程碑'" ref="xmProjectPhaseMng" :xm-iteration="xmIteration" ></xm-project-phase-mng>
<xm-test-case-exec-mng v-if="infotype=='测试计划'" :visible="infotype=='测试计划'" :xm-iteration='xmIteration' ref="xmQuestion"></xm-test-case-exec-mng>
<xm-menu-with-plan v-if="infotype=='故事监控'" ref="xmMenuWithPlan" :xm-iteration="xmIteration"></xm-menu-with-plan>
<xm-project-state-mng v-if="infotype=='项目监控'" :xm-iteration="xmIteration"></xm-project-state-mng>
<xm-budget v-if="infotype=='预算'" :xm-iteration="xmIteration"></xm-budget>
<xm-cost v-if="infotype=='费用'" :xm-iteration="xmIteration"></xm-cost>
<xm-project-kpi v-if="infotype=='考核'" :xm-iteration="xmIteration"></xm-project-kpi>
<xm-record v-if="infotype=='日志'" :visible="infotype=='日志'" :xm-iteration="xmIteration"></xm-record>
<xm-contract v-if="infotype=='合同管理'" :xm-iteration="xmIteration"></xm-contract>
<xm-env-list v-if="infotype=='环境清单'" :xm-iteration="xmIteration"></xm-env-list>
<xm-question v-if="infotype=='风险'" :qtype="'risk'" :xm-iteration='xmIteration' ref="xmRisk"></xm-question>
<el-drawer title="选中团队成员" :visible.sync="groupUserVisible" size="50%" append-to-body :close-on-click-modal="false">
<xm-project-group-select :xm-iteration="xmIteration" :visible="groupUserVisible" is-select-multi-user="1" @user-confirm="onUserSelected"></xm-project-group-select>
</el-drawer>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
//import Sticky from '@/components/Sticky' // header
//import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProject,editStatus , delXmProject, batchDelXmProject } from '@/api/xm/core/xmProject';
import XmProjectAdd from '../xmProject/XmProjectAdd';//
import XmProjectEdit from '../xmProject/XmProjectEdit';//
import { mapGetters } from 'vuex';
import xmTaskMng from '../xmTask/XmTaskMng';
import xmGroupMng from '../xmProjectGroup/XmProjectGroupMng';
import xmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect';
import xmExchange from '../xmExchange/XmExchangeMng';
import xmQuestion from '../xmQuestion/XmQuestionMng';
import xmFileMng from '../xmFile/XmFileMng';
import xmDetail from '../xmProject/XmProjectDetail';
import xmProjectKpi from '../xmProjectKpi/XmProjectKpiMng';
import xmRecord from '../xmRecord/XmRecordMng';
import xmCost from '../xmProject/XmProjectCost';
import xmBudget from '../xmProject/XmProjectBudgetCost';
import xmContract from '../xmProjectContract/XmProjectContractMng';
import xmEnvList from '../xmProjectEnvList/XmProjectEnvListMng';
import xmProjectPhaseMng from '../xmProjectPhase/XmProjectPhaseMng';
import xmMenuMng from '../xmMenu/XmMenuMng';
import xmMenuWithPlan from '../xmMenu/XmMenuWithPlan';
import xmProjectStateMng from '../xmProjectState/XmProjectStateMng';
import xmTestCaseExecMng from '../xmTestCaseExec/XmTestCaseExecMng';
import XmIterationForProjectComplex from '../xmIteration/XmIterationForProjectComplex.vue';
import XmProjectOverviewComplex from '../xmProject/XmProjectOverviewComplex.vue';
import XmProductForProjectComplex from '../xmProduct/XmProductForProjectComplex.vue';
import XmProjectForLink from '../xmProject/XmProjectForLink.vue';
export default {
props: ["xmIteration","visible"],
computed: {
...mapGetters([
'userInfo','roles'
]),
},
watch:{
xmIteration:function(xmIteration){
var oldInfotype=this.infotype
this.infotype=''
this.$nextTick(()=>{
this.infotype=oldInfotype
})
}
},
data() {
return {
platformViewVisible:false,
tabPosition:'left',
infotype:"迭代概览",
load:{list:false,edit:false},
groupUserVisible:false,
exportArr: ['任务', '阶段计划', '故事监控']
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
afterEditSubmit:function(project){
this.$emit("submit",project)
},
toArchive:function(){
this.$router.push({
path: "/mdp/arc/mate/archive/ArchiveMng"
});
},
toIm:function(){
this.groupUserVisible=true
},
toHelpMe:function(){
this.$router.push({
path: "/mdp/im/messages/crmChat",
query:{
categoryId:'css',
sendContent:'咨询'
}
});
},
handleMenuSelect(menuId){
this.infotype=menuId
},
onUserSelected:function(users){
if(this.groupUserVisible==true){
var query={}
if(users){
if( users.length==1 ){
var user=users[0]
query.toUserid=user.userid
query.toUsername=user.username
query.msgType="prichat"
}else if( users.length >=2 ){
query.users=JSON.stringify(users.map(i=>{return {userid:i.userid,username:i.username}}))
query.categoryId="common"
query.msgType="group"
}
}
this.$router.push({
path: "/mdp/im/messages/messageChat",
query: query
});
}
},
setInfotype(infotype){
this.infotype=infotype;
},
handleExport() {
this.downloadLoading = true
let list = [];
let header = [];
let keyList = [];
let pageNum = 1;
let infotypeKey = '';
if (this.infotype === '任务') {
header = ['序号', '任务名称', '故事', '预算(万)', '工作量(人时)', '执行人', '进度', '任务开始时间', '任务结束时间', '任务技能需求'];
keyList = ['sortLevel', 'name', 'menuName', 'budgetCost', 'budgetWorkload', 'exeUsernames', 'rate', 'startTime', 'endTime', 'taskSkillNames'];
list = this.$refs.xmTaskMng.tasksTreeData;
pageNum = this.$refs.xmTaskMng.pageInfo.pageNum;
} else if (this.infotype === '阶段计划') {
header = ['序号', '阶段名称', '开始时间', '结束时间', '进度(%)', '状态', '计划人数', '实际人数', '计划工期', '实际工期', '计划工作量(人时)', '实际工作量(人时)', '计划非人力成本(元)', '实际非人力成本(元)', '计划内购人力成本(元)', '实际内购人力成本(元)', '计划外购人力成本(元)', '实际外购人力成本(元)', '计划成本合计(元)', '实际成本合计(元)', '审批状态', '备注'];
keyList = ['seqNo', 'phaseName', 'beginDate', 'endDate', 'actRate', 'phaseStatus', 'phaseBudgetOutUserCnt', 'actStaffNu', 'phaseBudgetHours', 'actHours', 'phaseBudgetWorkload', 'phaseActWorkload', 'phaseBudgetNouserAt', 'actNouserAt', 'phaseBudgetInnerUserAt', 'actInnerUserAt', 'phaseBudgetOutUserAt', 'actOutUserAt', 'phaseBudgetCostAt', 'actCostAt', 'bizFlowState', 'remark'];
list = this.$refs.xmProjectPhaseMng.projectPhaseTreeData;
pageNum = this.$refs.xmProjectPhaseMng.pageInfo.pageNum;
} else if (this.infotype === '故事监控') {
header = ['序号', '故事名称', '计划状态', '负责人', '上线时间', '计划开始时间', '实际开始时间', '计划结束时间', '实际结束时间', '计划工作量(人时)', '实际工作量(人时)', '计划成本(元)', '实际成本(元)', '总体完成比例%', '需求完成比例%', '设计完成比例%', '开发完成比例%', 'sit完成比例%', 'uat完成比例%', '上线状态'];
keyList = ['seqNo', 'menuName', 'planStatus', 'chargeUsername', 'onlineTime', 'planStartTime', 'actStartTime', 'planEndTime', 'actEndTime', 'planWorkload', 'actWorkload', 'planCostAmount', 'actCostAmount', 'finishRate', 'demandRate', 'designRate', 'devRate', 'sitRate', 'uatRate', 'onlineStatus'];
list = this.$refs.xmMenuWithPlan.xmMenusTreeData;
pageNum = this.$refs.xmMenuWithPlan.pageInfo.pageNum;
}
const filename = `${this.xmIteration.iterationName}_${this.infotype}_第${pageNum}`;
const data = this.formatJson(keyList, list);
import('@/vendor/Export2Excel').then(excel => {
excel.export_json_to_excel({
header,
data,
filename,
// autoWidth: this.autoWidth,
bookType: 'xlsx'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData, dataList = []) {
if (this.infotype == '任务') {
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
return v[j];
})
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
} else if (this.infotype == '阶段计划') {
const bizFlowStateDict = {
0: '未发审',
1: '审核中',
2: '已通过',
3: '未通过',
4: '已取消'
}
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
if(j == 'phaseStatus') {
return this.$refs.xmProjectPhaseMng.formateOption('xmPhaseStatus', v.phaseStatus);
} else if(j == 'bizFlowState') {
return `${bizFlowStateDict[parseInt(v[j]) || 0]}`;
} else {
return v[j];
}
})
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
} else if (this.infotype == '故事监控') {
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
if(j == 'planStatus') {
key = 'xmMenuPlanStatus';
} else if(j == 'onlineStatus') {
return parseInt(v[j]) ? '已上线' : '未上线';
} else {
return v[j];
}
const options = this.$refs.xmMenuWithPlan.options;
if(options[key]==undefined || options[key]==null || options[key].length==0 ){
return v[j];
}
var rowData=options[key].filter(i=>i.optionValue==v[j])
if(rowData.length>0){
return rowData[0].optionName
}else{
return v[j];
}
});
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
}
},
getDateString(dateStr){
if(dateStr==null || dateStr=="" || dateStr==undefined){
return ""
}else{
return dateStr.substr(0,10);
}
},
goBack(){
this.$router.back()
}
},//end methods
components: {
xmTaskMng,
xmProjectPhaseMng,
xmGroupMng,
xmExchange,
xmQuestion,
xmFileMng,
xmDetail,
xmProjectKpi,
xmRecord,
xmCost,
xmBudget,
xmContract,
xmEnvList,
xmMenuMng,
xmMenuWithPlan,
xmProjectStateMng,
xmTestCaseExecMng,
xmProjectGroupSelect,
XmIterationForProjectComplex,
XmProjectOverviewComplex,
XmProductForProjectComplex,
XmProjectForLink,
//
},
mounted() {
this.$nextTick(() => {
});
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.menus{
.el-menu-item{
padding-left: 0px !important;
}
}
/* 超过宽度则用...代替 */
.truncate{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

61
src/views/xm/core/xmIteration/XmIterationInfoRoute.vue

@ -0,0 +1,61 @@
<template>
<section>
<xm-iteration-info v-if="xmIteration" :xm-iteration="xmIteration" :visible="showInfo"></xm-iteration-info>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { mapGetters } from 'vuex';
import XmIterationInfo from './XmIterationInfo'
export default {
computed: {
...mapGetters([
'userInfo','roles'
]),
},
watch:{
},
data() {
return {
xmIteration:null,
showInfo:false,
}
},//end data
methods: {
},//end methods
components: {
XmIterationInfo,
//
},
activated(){
if(this.$route.params && this.$route.params.id){
this.xmIteration=this.$route.params
this.showInfo=true;
localStorage.setItem('xm-iteration-info-route',JSON.stringify(this.xmIteration));
}else{
this.xmIteration=JSON.parse(localStorage.getItem("xm-iteration-info-route"))
this.showInfo=true;
}
},
mounted() {
if(this.$route.params && this.$route.params.id){
this.xmIteration=this.$route.params
this.showInfo=true;
localStorage.setItem('xm-iteration-info-route',JSON.stringify(this.xmIteration));
}else{
this.xmIteration=JSON.parse(localStorage.getItem("xm-iteration-info-route"))
this.showInfo=true;
}
}
}
</script>
<style scoped>
</style>

112
src/views/xm/core/xmIteration/XmIterationMng.vue

@ -26,7 +26,9 @@
title="" title=""
width="400" width="400"
trigger="click" > trigger="click" >
<el-divider content-position="left"><strong>查询条件</strong></el-divider>
<el-row> <el-row>
<el-col :span="24" style="padding-top:5px;"> <el-col :span="24" style="padding-top:5px;">
<font class="more-label-font"> <font class="more-label-font">
迭代查询范围 迭代查询范围
@ -68,6 +70,12 @@
<el-checkbox v-model="gstcVisible">甘特图</el-checkbox> <el-checkbox v-model="gstcVisible">甘特图</el-checkbox>
</el-col> </el-col>
</el-row> </el-row>
<el-divider content-position="left"><strong>更多操作</strong></el-divider>
<el-row>
<el-col :span="24" style="padding-top:5px;">
<el-button v-if="xmProduct" size="mini" icon="el-icon-plus" @click="iterationSelectVisible=true">将更多迭代加入产品<strong>{{xmProduct.productName}}</strong></el-button>
</el-col>
</el-row>
<el-button slot="reference" icon="el-icon-more" circle></el-button> <el-button slot="reference" icon="el-icon-more" circle></el-button>
</el-popover> </el-popover>
</el-row> </el-row>
@ -77,7 +85,7 @@
<el-table-column type="selection" aria-disabled width="55"></el-table-column> <el-table-column type="selection" aria-disabled width="55"></el-table-column>
<el-table-column prop="iterationName" label="迭代名称" min-width="160" show-overflow-tooltip> <el-table-column prop="iterationName" label="迭代名称" min-width="160" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{scope.row.seqNo}} &nbsp;&nbsp;<el-link type="primary" @click="showEdit( scope.row,scope.$index)"> {{scope.row.iterationName}} </el-link></span>
<span>{{scope.row.seqNo}} &nbsp;&nbsp;<el-link type="primary" @click="intoInfo( scope.row,scope.$index)"> {{scope.row.iterationName}} </el-link></span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="finishRate" label="总进度" min-width="80" > <el-table-column prop="finishRate" label="总进度" min-width="80" >
@ -93,13 +101,8 @@
<el-table-column prop="actWorkload" label="实际工作量" min-width="80" show-overflow-tooltip></el-table-column> <el-table-column prop="actWorkload" label="实际工作量" min-width="80" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="400" fixed="right"> <el-table-column label="操作" width="400" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="primary" @click="showSubAdd( scope.row,scope.$index)" icon="el-icon-plus"></el-button>
<el-button type="warning" @click="loadTasksToXmIterationState( scope.row)" icon="el-icon-s-data">刷新</el-button>
<el-button type="success" @click="showIterationState( scope.row)" icon="el-icon-s-data">报告</el-button>
<el-tooltip v-if="xmProduct" :content="'将迭代与'+ xmProduct.productName + '脱钩'"><el-button @click="doDelXmIterationProductLink( scope.row,scope.$index)" icon="el-icon-remove-outline">与产品脱钩</el-button></el-tooltip>
<el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="el-icon-delete"></el-button> <el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="el-icon-delete"></el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -120,6 +123,10 @@
<el-drawer title="迭代报告" :visible.sync="iterationStateVisible" fullscreen append-to-body :close-on-click-modal="false"> <el-drawer title="迭代报告" :visible.sync="iterationStateVisible" fullscreen append-to-body :close-on-click-modal="false">
<xm-iteration-state-mng :xm-iteration="editForm" :visible="iterationStateVisible" @cancel="iterationStateVisible=false"></xm-iteration-state-mng> <xm-iteration-state-mng :xm-iteration="editForm" :visible="iterationStateVisible" @cancel="iterationStateVisible=false"></xm-iteration-state-mng>
</el-drawer> </el-drawer>
<el-drawer title="迭代报告" :visible.sync="iterationSelectVisible" fullscreen append-to-body :close-on-click-modal="false">
<xm-iteration-select @row-click="onXmIterationSelect"></xm-iteration-select>
</el-drawer>
</el-row> </el-row>
</section> </section>
</template> </template>
@ -129,12 +136,15 @@
import config from '@/common/config';// import config from '@/common/config';//
import { listOption } from '@/api/mdp/meta/itemOption';// import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmIteration,listXmIterationWithState, delXmIteration, batchDelXmIteration,loadTasksToXmIterationState } from '@/api/xm/core/xmIteration'; import { listXmIteration,listXmIterationWithState, delXmIteration, batchDelXmIteration,loadTasksToXmIterationState } from '@/api/xm/core/xmIteration';
import { addXmIterationProductLink,delXmIterationProductLink } from '@/api/xm/core/xmIterationProductLink';
import XmIterationAdd from './XmIterationAdd';// import XmIterationAdd from './XmIterationAdd';//
import XmIterationEdit from './XmIterationEdit';// import XmIterationEdit from './XmIterationEdit';//
import XmIterationStateMng from '../xmIterationState/XmIterationStateMng';// import XmIterationStateMng from '../xmIterationState/XmIterationStateMng';//
import XmGantt from '../components/xm-gantt'; import XmGantt from '../components/xm-gantt';
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import XmIterationSelect from './XmIterationSelect.vue';
export default { export default {
computed: { computed: {
@ -146,12 +156,18 @@
return this.translateDataToTree(this.xmIterations); return this.translateDataToTree(this.xmIterations);
}, },
}, },
props:['productId','menuId','visible'],
props:['xmProduct','selProject','menuId','visible'],
watch:{ watch:{
visible:function(visible){ visible:function(visible){
if(visible==true){ if(visible==true){
this.getXmIterations(); this.getXmIterations();
} }
},
xmProduct:function(){
this.getXmIterations();
},
selProject:function(){
this.getXmIterations();
} }
}, },
data() { data() {
@ -207,17 +223,18 @@
/**begin 自定义属性请在下面加 请加备注**/ /**begin 自定义属性请在下面加 请加备注**/
valueChangeRows:[], valueChangeRows:[],
parentIteration:null, parentIteration:null,
iterationStateVisible:false,
gstcVisible:false,
tableHeight:300,
ganrrColumns: {
children: 'children',
name: 'iterationName',
id: 'id',
pid: 'pid',
startDate: 'startTime',
endDate: 'endTime',
}
iterationStateVisible:false,
iterationSelectVisible:false,
gstcVisible:false,
tableHeight:300,
ganrrColumns: {
children: 'children',
name: 'iterationName',
id: 'id',
pid: 'pid',
startDate: 'startTime',
endDate: 'endTime',
}
/**end 自定义属性请在上面加 请加备注**/ /**end 自定义属性请在上面加 请加备注**/
} }
},//end data },//end data
@ -270,13 +287,16 @@
if(this.filters.key){ if(this.filters.key){
params.key= "%"+this.filters.key+"%" params.key= "%"+this.filters.key+"%"
} }
if(this.productId){
params.productId=this.productId
if(this.xmProduct){
params.productId=this.xmProduct.id
}
if(this.selProject){
params.projectId=this.selProject.id
} }
if(this.menuId){ if(this.menuId){
params.menuId=this.menuId params.menuId=this.menuId
} }
if( !this.menuId && !this.productId ){
if( !this.menuId && !this.xmProduct && !this.selProject){
params.queryScope=this.filters.queryScope params.queryScope=this.filters.queryScope
if(this.filters.queryScope=='iterationId'){ if(this.filters.queryScope=='iterationId'){
if(!this.filters.id){ if(!this.filters.id){
@ -329,14 +349,25 @@
this.addFormVisible = true; this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm); //this.addForm=Object.assign({}, this.editForm);
}, },
afterAddSubmit(){
afterAddSubmit(xmIteration){
this.addFormVisible=false; this.addFormVisible=false;
this.pageInfo.count=true; this.pageInfo.count=true;
this.getXmIterations();
if(this.xmProduct){//
this.onXmIterationSelect(xmIteration);
}else{
this.getXmIterations();
}
}, },
afterEditSubmit(){ afterEditSubmit(){
this.editFormVisible=false; this.editFormVisible=false;
}, },
//info
intoInfo(row) {
this.editForm = row;
this.$router.push({ name:'XmIterationInfoRoute', params: row })
//this.showInfo = true;
},
//xmIteration //xmIteration
selsChange: function (sels) { selsChange: function (sels) {
this.sels = sels; this.sels = sels;
@ -467,13 +498,42 @@
return cellValue; return cellValue;
} }
}, },
/**end 自定义函数请在上面加**/
onXmIterationSelect:function(row){
var xmIteration=row;
var xmProduct=this.xmProduct;
this.$confirm('确认将产品【'+xmProduct.productName+'】加入迭代计划【'+xmIteration.iterationName+'】吗?', '提示', {
type: 'warning'
}).then(()=>{
addXmIterationProductLink({iterationId:xmIteration.id,productId:xmProduct.id}).then(res=>{
var tips =res.data.tips;
if(tips.isOk){
this.getXmIterations();
}
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error'});
})
})
},
doDelXmIterationProductLink(row){
var xmIteration=row;
var xmProduct=this.xmProduct;
this.$confirm('确认将产品【'+xmProduct.productName+'】与迭代【'+xmIteration.iterationName+'】进行脱钩吗?脱钩后,产品与迭代互相查看不到对方信息。', '提示', {
type: 'warning'
}).then(()=>{
delXmIterationProductLink({iterationId:xmIteration.id,productId:xmProduct.id}).then(res=>{
var tips =res.data.tips;
if(tips.isOk){
this.getXmIterations();
}
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error'});
})
})
}
},//end methods },//end methods
components: { components: {
'xm-iteration-add':XmIterationAdd, 'xm-iteration-add':XmIterationAdd,
'xm-iteration-edit':XmIterationEdit, 'xm-iteration-edit':XmIterationEdit,
XmIterationStateMng,XmGantt, XmIterationStateMng,XmGantt,
XmIterationSelect,
// //
}, },
mounted() { mounted() {

3
src/views/xm/core/xmIteration/XmIterationSelect.vue

@ -98,6 +98,9 @@
this.clearSelectIteration(); this.clearSelectIteration();
this.getXmIterations(); this.getXmIterations();
} }
},
productId:function(){
this.getXmIterations();
} }
}, },
data() { data() {

123
src/views/xm/core/xmIterationProductLink/XmIterationProductLinkAdd.vue

@ -0,0 +1,123 @@
<template>
<section>
<el-row>
<!--新增界面 XmIterationProductLink 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表-->
<el-form :model="addForm" label-width="120px" :rules="addFormRules" ref="addForm">
<el-form-item label="迭代表主键" prop="iterationId">
<el-input v-model="addForm.iterationId" placeholder="迭代表主键" ></el-input>
</el-form-item>
<el-form-item label="产品表主键" prop="productId">
<el-input v-model="addForm.productId" placeholder="产品表主键" ></el-input>
</el-form-item>
<el-form-item label="创建时间" prop="ctime">
<el-date-picker type="date" placeholder="选择日期" v-model="addForm.ctime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item label="创建人编号" prop="cuserid">
<el-input v-model="addForm.cuserid" placeholder="创建人编号" ></el-input>
</el-form-item>
<el-form-item label="创建人姓名" prop="cusername">
<el-input v-model="addForm.cusername" placeholder="创建人姓名" ></el-input>
</el-form-item>
<el-form-item label="关联状态1关联0取消关联" prop="linkStatus">
<el-input v-model="addForm.linkStatus" placeholder="关联状态1关联0取消关联" ></el-input>
</el-form-item>
<el-form-item>
<el-col :span="24" :offset="8">
<el-button @click.native="handleCancel">取消</el-button>
<el-button v-loading="load.add" type="primary" @click.native="addSubmit" :disabled="load.add==true">提交</el-button>
</el-col>
</el-form-item>
</el-form>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { addXmIterationProductLink } from '@/api/xm/core/xmIterationProductLink';
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo'
])
},
props:['xmIterationProductLink','visible'],
watch: {
'xmIterationProductLink':function( xmIterationProductLink ) {
this.addForm = xmIterationProductLink;
},
'visible':function(visible) {
if(visible==true){
//
}
}
},
data() {
return {
options:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
addFormRules: {
iterationId: [
//{ required: true, message: '', trigger: 'blur' }
]
},
//
addForm: {
iterationId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
}
/**begin 在下面加自定义属性,记得补上面的一个逗号**/
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
// @cancel="addFormVisible=false"
handleCancel:function(){
this.$refs['addForm'].resetFields();
this.$emit('cancel');
},
//XmIterationProductLink @submit="afterAddSubmit"
addSubmit: function () {
this.$refs.addForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.add=true
let params = Object.assign({}, this.addForm);
addXmIterationProductLink(params).then((res) => {
this.load.add=false
var tips=res.data.tips;
if(tips.isOk){
this.$refs['addForm'].resetFields();
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.add=false);
});
}
});
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
/**end 在上面加自定义方法**/
},//end method
components: {
// 'xm-iteration-product-link-edit':XmIterationProductLinkEdit
},
mounted() {
this.addForm=Object.assign(this.addForm, this.xmIterationProductLink);
/**在下面写其它函数***/
}//end mounted
}
</script>
<style scoped>
</style>

118
src/views/xm/core/xmIterationProductLink/XmIterationProductLinkEdit.vue

@ -0,0 +1,118 @@
<template>
<section>
<el-row>
<!--编辑界面 XmIterationProductLink 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-form-item label="迭代表主键" prop="iterationId">
<el-input v-model="editForm.iterationId" placeholder="迭代表主键"></el-input>
</el-form-item>
<el-form-item label="产品表主键" prop="productId">
<el-input v-model="editForm.productId" placeholder="产品表主键"></el-input>
</el-form-item>
<el-form-item label="创建时间" prop="ctime">
<el-date-picker type="date" placeholder="选择日期" v-model="editForm.ctime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item label="创建人编号" prop="cuserid">
<el-input v-model="editForm.cuserid" placeholder="创建人编号"></el-input>
</el-form-item>
<el-form-item label="创建人姓名" prop="cusername">
<el-input v-model="editForm.cusername" placeholder="创建人姓名"></el-input>
</el-form-item>
<el-form-item label="关联状态1关联0取消关联" prop="linkStatus">
<el-input v-model="editForm.linkStatus" placeholder="关联状态1关联0取消关联"></el-input>
</el-form-item>
<el-form-item>
<el-col :span="24" :offset="8">
<el-button @click.native="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click.native="editSubmit" :disabled="load.edit==true">提交</el-button>
</el-col>
</el-form-item>
</el-form>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { editXmIterationProductLink } from '@/api/xm/core/xmIterationProductLink';
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo'
])
},
props:['xmIterationProductLink','visible'],
watch: {
'xmIterationProductLink':function( xmIterationProductLink ) {
this.editForm = xmIterationProductLink;
},
'visible':function(visible) {
if(visible==true){
//
}
}
},
data() {
return {
options:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
editFormRules: {
iterationId: [
//{ required: true, message: '', trigger: 'blur' }
]
},
// XmIterationProductLink
editForm: {
iterationId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
}
/**begin 在下面加自定义属性,记得补上面的一个逗号**/
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
// @cancel="editFormVisible=false"
handleCancel:function(){
this.$refs['editForm'].resetFields();
this.$emit('cancel');
},
//XmIterationProductLink @submit="afterEditSubmit"
editSubmit: function () {
this.$refs.editForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
let params = Object.assign({}, this.editForm);
editXmIterationProductLink(params).then((res) => {
this.load.edit=false
var tips=res.data.tips;
if(tips.isOk){
this.$refs['editForm'].resetFields();
this.$emit('submit');// @submit="afterEditSubmit"
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err =>this.load.edit=false);
});
}
});
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
/**end 在上面加自定义方法**/
},//end method
components: {
// 'xm-iteration-product-link-edit':XmIterationProductLinkEdit
},
mounted() {
this.editForm=Object.assign(this.editForm, this.xmIterationProductLink);
}
}
</script>
<style scoped>
</style>

252
src/views/xm/core/xmIterationProductLink/XmIterationProductLinkMng.vue

@ -0,0 +1,252 @@
<template>
<section class="app-container">
<el-row>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询">
<template slot="append">
<el-button v-loading="load.list" :disabled="load.list==true" @click="searchXmIterationProductLinks" icon="el-icon-search">查询</el-button>
</template>
</el-input>
<el-button type="primary" @click="showAdd" icon="el-icon-plus" circle> </el-button>
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length===0 || load.del==true" icon="el-icon-delete" circle></el-button>
</el-row>
<el-row style="padding-top:10px;">
<!--列表 XmIterationProductLink 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表-->
<el-table ref="xmIterationProductLink" :data="xmIterationProductLinks" :max-height="maxTableHeight" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column sortable type="index" width="55"></el-table-column>
<el-table-column prop="iterationId" label="迭代表主键" min-width="80" ></el-table-column>
<el-table-column prop="productId" label="产品表主键" min-width="80" ></el-table-column>
<el-table-column prop="ctime" label="创建时间" min-width="80" ></el-table-column>
<el-table-column prop="cuserid" label="创建人编号" min-width="80" ></el-table-column>
<el-table-column prop="cusername" label="创建人姓名" min-width="80" ></el-table-column>
<el-table-column prop="linkStatus" label="关联状态1关联0取消关联" min-width="80" ></el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template slot="header">
<el-button @click="showAdd" icon="el-icon-plus" circle> </el-button>
</template>
<template scope="scope">
<el-button type="primary" @click="showEdit( scope.row,scope.$index)" icon="el-icon-edit" circle></el-button>
<el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="el-icon-delete" circle></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10,20, 50, 100, 500]" :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;"></el-pagination>
<!--编辑 XmIterationProductLink 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表界面-->
<el-dialog title="编辑迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表" :visible.sync="editFormVisible" width="50%" append-to-body :close-on-click-modal="false">
<xm-iteration-product-link-edit :xm-iteration-product-link="editForm" :visible="editFormVisible" @cancel="editFormVisible=false" @submit="afterEditSubmit"></xm-iteration-product-link-edit>
</el-dialog>
<!--新增 XmIterationProductLink 迭代表与产品表的关联关系一般由迭代管理员将迭代挂接到产品表界面-->
<el-dialog title="新增迭代表与产品表的关联关系,一般由迭代管理员将迭代挂接到产品表" :visible.sync="addFormVisible" width="50%" append-to-body :close-on-click-modal="false">
<xm-iteration-product-link-add :xm-iteration-product-link="addForm" :visible="addFormVisible" @cancel="addFormVisible=false" @submit="afterAddSubmit"></xm-iteration-product-link-add>
</el-dialog>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import config from '@/common/config';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmIterationProductLink, delXmIterationProductLink, batchDelXmIterationProductLink } from '@/api/xm/core/xmIterationProductLink';
import XmIterationProductLinkAdd from './XmIterationProductLinkAdd';//
import XmIterationProductLinkEdit from './XmIterationProductLinkEdit';//
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo','workSpace'
])
},
data() {
return {
filters: {
key: ''
},
xmIterationProductLinks: [],//
pageInfo:{//
total:0,//0>0
pageSize:10,//
count:false,//
pageNum:1,//1
orderFields:[],// ['sex','student_id']
orderDirs:[]// asc,desc ['asc','desc']
},
load:{ list: false, edit: false, del: false, add: false },//...
sels: [],//
options:{
//sex:[],
},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
addFormVisible: false,//xmIterationProductLink
//xmIterationProductLink
addForm: {
iterationId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
},
editFormVisible: false,//
//xmIterationProductLink
editForm: {
iterationId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
},
maxTableHeight:300,
}
},//end data
methods: {
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
this.getXmIterationProductLinks();
},
handleCurrentChange(pageNum) {
this.pageInfo.pageNum = pageNum;
this.getXmIterationProductLinks();
},
// obj.order=ascending/descending, asc/desc ; obj.prop=,
sortChange( obj ){
if(obj.order==null){
this.pageInfo.orderFields=[];
this.pageInfo.orderDirs=[];
}else{
var dir='asc';
if(obj.order=='ascending'){
dir='asc'
}else{
dir='desc';
}
this.pageInfo.orderFields=[util.toLine(obj.prop)];
this.pageInfo.orderDirs=[dir];
}
this.getXmIterationProductLinks();
},
searchXmIterationProductLinks(){
this.pageInfo.count=true;
this.getXmIterationProductLinks();
},
// XmIterationProductLink
getXmIterationProductLinks() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count:this.pageInfo.count
};
if(this.pageInfo.orderFields!=null && this.pageInfo.orderFields.length>0){
let orderBys=[];
for(var i=0;i<this.pageInfo.orderFields.length;i++){
orderBys.push(this.pageInfo.orderFields[i]+" "+this.pageInfo.orderDirs[i])
}
params.orderBy= orderBys.join(",")
}
if(this.filters.key){
params.key="%"+this.filters.key+"%"
}
this.load.list = true;
listXmIterationProductLink(params).then((res) => {
var tips=res.data.tips;
if(tips.isOk){
this.pageInfo.total = res.data.total;
this.pageInfo.count=false;
this.xmIterationProductLinks = res.data.data;
}else{
this.$message({ message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
// XmIterationProductLink
showEdit: function ( row,index ) {
this.editFormVisible = true;
this.editForm = Object.assign({}, row);
},
// XmIterationProductLink
showAdd: function () {
this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm);
},
afterAddSubmit(){
this.addFormVisible=false;
this.pageInfo.count=true;
this.getXmIterationProductLinks();
},
afterEditSubmit(){
this.editFormVisible=false;
},
//xmIterationProductLink
selsChange: function (sels) {
this.sels = sels;
},
//xmIterationProductLink
handleDel: function (row,index) {
this.$confirm('确认删除该记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
let params = { iterationId: row.iterationId };
delXmIterationProductLink(params).then((res) => {
this.load.del=false;
var tips=res.data.tips;
if(tips.isOk){
this.pageInfo.count=true;
this.getXmIterationProductLinks();
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.del=false );
});
},
//xmIterationProductLink
batchDel: function () {
this.$confirm('确认删除选中记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
batchDelXmIterationProductLink(this.sels).then((res) => {
this.load.del=false;
var tips=res.data.tips;
if( tips.isOk ){
this.pageInfo.count=true;
this.getXmIterationProductLinks();
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error'});
}).catch( err => this.load.del=false );
});
},
rowClick: function(row, event, column){
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
/**begin 自定义函数请在下面加**/
/**end 自定义函数请在上面加**/
},//end methods
components: {
'xm-iteration-product-link-add':XmIterationProductLinkAdd,
'xm-iteration-product-link-edit':XmIterationProductLinkEdit,
},
mounted() {
this.$nextTick(() => {
this.getXmIterationProductLinks();
var clientRect=this.$refs.xmIterationProductLink.$el.getBoundingClientRect();
var subHeight=65/1000 * window.innerHeight;
this.maxTableHeight = window.innerHeight -clientRect.y - this.$refs.xmIterationProductLink.$el.offsetTop-subHeight;
});
/**
listOption([{categoryId:'all',itemCode:'sex'},{categoryId:'all',itemCode:'grade'}] ).then(res=>{
if(res.data.tips.isOk){
this.options=res.data.data
}
});
**/
}
}
</script>
<style scoped>
</style>

42
src/views/xm/core/xmMenu/XmMenuMng.vue

@ -1,11 +1,11 @@
<template> <template>
<section class="padding"> <section class="padding">
<el-row v-if=" !batchEditVisible"> <el-row v-if=" !batchEditVisible">
<el-col :span="6">
<xm-product-mng :sel-project="selProject" @row-click="onProductSelected" ref="xmProductMng" :simple="true"></xm-product-mng>
<el-col :span="5" v-if="!xmProduct">
<xm-product-mng :sel-project="selProject" @row-click="onProductSelected" ref="xmProductMng" :xm-iteration="xmIteration" :simple="true"></xm-product-mng>
</el-col> </el-col>
<el-col :span="18" class="padding-left">
<el-row >
<el-col :span="xmProduct?24:19" class="padding-left">
<el-row>
<el-select v-model="filters.taskFilterType" placeholder="是否分配了任务?" clearable > <el-select v-model="filters.taskFilterType" placeholder="是否分配了任务?" clearable >
<el-option value="not-join" label="未分配任何任务的故事"></el-option> <el-option value="not-join" label="未分配任何任务的故事"></el-option>
<el-option value="join" label="已分配任务的故事"></el-option> <el-option value="join" label="已分配任务的故事"></el-option>
@ -24,14 +24,11 @@
:picker-options="pickerOptions" :picker-options="pickerOptions"
></el-date-picker> ></el-date-picker>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询" clearable> <el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询" clearable>
<template slot="append">
<el-button type="primary" v-loading="load.list" :disabled="load.list==true" v-on:click="searchXmMenus" icon="el-icon-search"></el-button>
</template>
</el-input> </el-input>
<el-button type="primary" v-loading="load.list" :disabled="load.list==true" v-on:click="searchXmMenus" icon="el-icon-search"></el-button>
<el-button type="primary" @click="showAdd" icon="el-icon-plus">故事</el-button>
<el-button @click="toBatchEdit" icon="el-icon-edit">修改</el-button>
<el-button v-if="!selProject&&!xmIteration" type="primary" @click="showAdd" icon="el-icon-plus">故事</el-button>
<el-button v-if="!selProject&&!xmIteration" @click="toBatchEdit" icon="el-icon-edit">修改</el-button>
<el-popover <el-popover
placement="top-start" placement="top-start"
title="" title=""
@ -90,8 +87,8 @@
</el-row> </el-row>
<el-button slot="reference" icon="el-icon-more" circle></el-button> <el-button slot="reference" icon="el-icon-more" circle></el-button>
</el-popover> </el-popover>
</el-row>
</el-row>
<el-row class="padding-top"> <el-row class="padding-top">
<el-table size="mini" stripe fit border ref="table" :height="tableHeight" :data="xmMenusTreeData" default-expand-all row-key="menuId" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" @sort-change="sortChange" highlight-current-row v-loading="load.list" @selection-change="selsChange" @row-click="rowClick"> <el-table size="mini" stripe fit border ref="table" :height="tableHeight" :data="xmMenusTreeData" default-expand-all row-key="menuId" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" @sort-change="sortChange" highlight-current-row v-loading="load.list" @selection-change="selsChange" @row-click="rowClick">
<el-table-column sortable type="selection" width="40"></el-table-column> <el-table-column sortable type="selection" width="40"></el-table-column>
@ -113,7 +110,7 @@
<el-tag slot="reference" icon="el-icon-chat-line-square">描述</el-tag> <el-tag slot="reference" icon="el-icon-chat-line-square">描述</el-tag>
</el-popover> </el-popover>
<el-button size="mini" type="primary" @click="showSubAdd( scope.row,scope.$index)" icon="el-icon-plus" circle></el-button>
<el-button v-if="!selProject&&!xmIteration" size="mini" type="primary" @click="showSubAdd( scope.row,scope.$index)" icon="el-icon-plus" circle></el-button>
<el-popover style="padding-left:10px;" <el-popover style="padding-left:10px;"
v-if="isPmUser" v-if="isPmUser"
@ -227,7 +224,7 @@
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
export default { export default {
props:['selProject','xmIteration'],
props:['selProject','xmIteration','xmProduct'],
computed: { computed: {
...mapGetters([ ...mapGetters([
'userInfo','roles' 'userInfo','roles'
@ -263,6 +260,13 @@
if(product==null){ if(product==null){
this.productVisible=true; this.productVisible=true;
} }
},
xmIteration:function(){
this.getXmMenus()
},
xmProduct:function(){
this.filters.product=this.xmProduct
this.getXmMenus()
} }
}, },
data() { data() {
@ -366,7 +370,7 @@
} }
params.orderBy= orderBys.join(",") params.orderBy= orderBys.join(",")
} }
if( this.filters.product!==null && this.filters.product.id!=''){
if( this.filters.product && this.filters.product.id){
params.productId=this.filters.product.id params.productId=this.filters.product.id
}else { }else {
this.$message({showClose: true, message: "请先选择产品", type: 'success' }); this.$message({showClose: true, message: "请先选择产品", type: 'success' });
@ -415,7 +419,11 @@
this.load.list = false; this.load.list = false;
} }
this.load.list = true; this.load.list = true;
listXmMenuWithPlan(params).then( callback ).catch( err => this.load.list = false );
if(!this.selProject){
listXmMenuWithState(params).then( callback ).catch( err => this.load.list = false );
}else{
listXmMenuWithPlan(params).then( callback ).catch( err => this.load.list = false );
}
}, },
// XmMenu xm_project_menu // XmMenu xm_project_menu
@ -810,6 +818,10 @@
// //
}, },
mounted() { mounted() {
this.filters.product=this.xmProduct
if(this.xmProduct){
this.productVisible=false;
}
this.$nextTick(() => { this.$nextTick(() => {
var clientRect=this.$refs.table.$el.getBoundingClientRect(); var clientRect=this.$refs.table.$el.getBoundingClientRect();
var subHeight=70/1000 * window.innerHeight; var subHeight=70/1000 * window.innerHeight;

2
src/views/xm/core/xmProduct/XmProductAdd.vue

@ -108,7 +108,7 @@
var tips=res.data.tips; var tips=res.data.tips;
if(tips.isOk){ if(tips.isOk){
//this.$refs['addForm'].resetFields(); //this.$refs['addForm'].resetFields();
this.$emit('submit');// @submit="afterAddSubmit"
this.$emit('submit',res.data.data);// @submit="afterAddSubmit"
} }
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error' }); this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.add=false); }).catch( err => this.load.add=false);

174
src/views/xm/core/xmProduct/XmProductForProjectComplex.vue

@ -0,0 +1,174 @@
<template>
<section class="page-container border">
<el-row>
<el-col :span="productVisible==true?3:0" >
<xm-product-select :sel-project="selProject" @row-click="onProductRowClick" @clear-select="onProductClearSelect"></xm-product-select>
</el-col>
<el-col :span="productVisible==true?21:24" >
<el-tabs type="border-card" :v-model="showPanel" activate-name="productOverview" @tab-click="tabClick">
<el-tab-pane label="产品概览" name="productOverview">
<span v-show="productVisible==true" slot="label" ><i class="el-icon-d-arrow-left" @click.stop="productVisible=false"></i> 产品概览</span>
<span v-show="productVisible==false" slot="label" ><i class="el-icon-d-arrow-right" @click.stop="productVisible=true"></i> 产品概览</span>
</el-tab-pane>
<el-tab-pane label="迭代" name="iterations">
<xm-iteration-mng v-show=" xmProduct && showPanel=='iterations'" :xm-product="xmProduct" :sel-project="selProject"></xm-iteration-mng>
</el-tab-pane>
<el-tab-pane label="项目" lazy name="projects">
<xm-product-project-for-link v-show="xmProduct && showPanel=='projects'" :xm-product="xmProduct" :sel-project="selProject"></xm-product-project-for-link>
</el-tab-pane>
<el-tab-pane label="故事" lazy name="menus" >
<xm-menu-mng v-show="xmProduct && showPanel=='menus'" :xm-product="xmProduct" :sel-project="selProject"></xm-menu-mng>
</el-tab-pane>
<el-tab-pane label="任务" lazy name="tasks" >
<xm-task-mng v-show="xmProduct && showPanel=='tasks'" :xm-product="xmProduct" :sel-project="selProject"></xm-task-mng>
</el-tab-pane>
<el-tab-pane label="缺陷" lazy name="bugs" >
<xm-question-mng v-show="xmProduct && showPanel=='bugs'" :xm-product="xmProduct" :sel-project="selProject"></xm-question-mng>
</el-tab-pane>
</el-tabs>
<el-row>
</el-row>
</el-col>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import config from '@/common/config';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import XmIterationMng from '../xmIteration/XmIterationMng.vue'
import XmMenuMng from '../xmMenu/XmMenuMng.vue'
import XmIterationStateShow from '../xmIterationState/XmIterationStateShow.vue'
import { mapGetters } from 'vuex'
import XmProductMng from './XmProductMng.vue';
import XmTaskMng from '../xmTask/XmTaskMng.vue';
import XmQuestionMng from '../xmQuestion/XmQuestionMng.vue';
import XmProjectList from '../xmProject/XmProjectList.vue';
import XmProjectForLink from '../xmProject/XmProjectForLink.vue';
import XmProductSelect from './XmProductSelect.vue';
import XmProductProjectForLink from './XmProductProjectForLink.vue';
export default {
computed: {
...mapGetters([
'userInfo','roles'
]),
},
props:['visible','selProject'],
watch:{
visible:function(visible){
if(visible==true){
}
}
},
data() {
return{
xmProduct:null,
showPanel:'iterations',//menus,tasks,bugs,iterationStateShow
topModules:
[
{
moduleName:"项目",
topModuleId:'xm',
link:"/xm/core/xmProject/XmProjectMng",
icon: require("@/assets/image/platform/module-project.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
},
{
moduleName:"产品",
topModuleId:'xm',
link:"/xm/core/xmProduct/XmProductMng",
icon: require("@/assets/image/platform/module-marketing.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
},
{
moduleName:"故事",
topModuleId:'xm',
link:"/xm/core/xmMenu/XmMenuMng",
icon: require("@/assets/image/platform/module-intelligentForms.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
},
{
moduleName:"迭代",
topModuleId:'xm',
link:"/xm/core/xmIteration/XmIterationMng",
icon: require("@/assets/image/platform/module-iteration.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
},
{
moduleName:"任务",
topModuleId:'xm',
link:"/xm/core/xmTask/XmMyTaskCenter",
icon: require("@/assets/image/platform/module-task.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
},
{
moduleName:"缺陷",
topModuleId:'xm',
link:"/xm/core/xmQuestion/XmQuestionMng",
icon: require("@/assets/image/platform/anti-fake.png"),
isHighlight:false,
moduleType : '1' // 1- 2-
}
],
productVisible:true,
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
/**end 自定义函数请在上面加**/
onProductRowClick(xmProduct){
this.xmProduct=xmProduct
},
onProductClearSelect(){
this.iteration=null;
},
tabClick(tab){
this.showPanel=tab.name
}
},//end methods
components: {
//
XmIterationMng,
XmMenuMng,
XmIterationStateShow,
XmProductMng,
XmTaskMng,
XmQuestionMng,
XmProductSelect,
XmProjectList,
XmProjectForLink,
XmProductProjectForLink,
},
mounted() {
this.$nextTick(() => {
});
}
}
</script>
<style scoped>
.more-label-font{
text-align:center;
float:left;
padding-top:5px;
}
</style>

445
src/views/xm/core/xmProduct/XmProductInfo.vue

@ -0,0 +1,445 @@
<template>
<section class="page-container page-full-height">
<el-row>
<el-menu :default-active="infotype" mode="horizontal" @select="setInfotype" class="menus" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b">
<el-menu-item index="产品概览" >
<span slot="title" >
<span slot="title" @click.stop="goBack"><i class="el-icon-back" ></i></span>
<i class="el-icon-s-data"></i>
<font v-if="xmProduct.productName.length>=10">{{xmProduct.productName.substring(0,10)}}</font>
<font type="danger" v-else>{{xmProduct.productName}}</font>
概览
</span>
</el-menu-item>
<el-menu-item index="迭代">
<span slot="title"><i class="el-icon-document-copy"></i>迭代</span>
</el-menu-item>
<el-menu-item label="项目" index="项目">
<span slot="title"><i class="el-icon-document"></i>项目</span>
</el-menu-item>
<el-menu-item label="故事" index="用户故事">
<span slot="title"><i class="el-icon-document"></i>故事</span>
</el-menu-item>
<el-menu-item index="任务">
<span slot="title"><i class="el-icon-s-operation"></i>任务</span>
</el-menu-item>
<el-menu-item index="缺陷">
<span slot="title"><i class="el-icon-question"></i>缺陷</span>
</el-menu-item>
<el-menu-item index="团队">
<span slot="title"><i class="el-icon-user-solid"></i>团队</span>
</el-menu-item>
<el-menu-item index="文档">
<span slot="title"><i class="el-icon-document"></i>文档</span>
</el-menu-item>
<el-submenu index="规划与里程碑">
<template slot="title">规划与里程碑 </template>
<el-menu-item index="阶段计划及里程碑">
<span slot="title"><i class="el-icon-odometer"></i>阶段计划及里程碑</span>
</el-menu-item>
<el-menu-item index="测试计划">
<span slot="title"><i class="el-icon-odometer"></i>测试计划</span>
</el-menu-item>
</el-submenu >
<el-menu-item index="项目监控" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-video-camera"></i>项目监控</span>
</el-menu-item>
<el-menu-item index="故事监控" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-video-camera"></i>故事监控</span>
</el-menu-item>
<el-menu-item index="合同管理" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-s-data"></i>合同管理</span>
</el-menu-item>
<el-menu-item index="预算" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-coin"></i>预算</span>
</el-menu-item>
<el-menu-item index="费用" class="hidden-md-and-down">
<span slot="title"><i class="el-icon-coin"></i>费用</span>
</el-menu-item>
<el-menu-item index="考核" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-view"></i>考核</span>
</el-menu-item>
<el-menu-item index="日志" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-edit-outline"></i>日志</span>
</el-menu-item>
<el-menu-item index="环境清单" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-setting"></i>环境清单</span>
</el-menu-item>
<el-menu-item index="风险" class="hidden-lg-and-down">
<span slot="title"><i class="el-icon-question"></i>风险</span>
</el-menu-item>
<el-submenu index="更多">
<template slot="title">更多 </template>
<el-menu-item index="故事监控" >
<span slot="title"><i class="el-icon-video-camera"></i>故事监控</span>
</el-menu-item>
<el-menu-item index="项目监控">
<span slot="title"><i class="el-icon-video-camera"></i>项目监控</span>
</el-menu-item>
<el-menu-item index="预算">
<span slot="title"><i class="el-icon-coin"></i>预算</span>
</el-menu-item>
<el-menu-item index="费用">
<span slot="title"><i class="el-icon-coin"></i>费用</span>
</el-menu-item>
<el-menu-item index="考核">
<span slot="title"><i class="el-icon-view"></i>考核</span>
</el-menu-item>
<el-menu-item index="日志">
<span slot="title"><i class="el-icon-edit-outline"></i>日志</span>
</el-menu-item>
<el-menu-item index="合同管理">
<span slot="title"><i class="el-icon-s-data"></i>合同管理</span>
</el-menu-item>
<el-menu-item index="环境清单">
<span slot="title"><i class="el-icon-setting"></i>环境清单</span>
</el-menu-item>
<el-menu-item index="风险">
<span slot="title"><i class="el-icon-question"></i>风险</span>
</el-menu-item>
<el-menu-item index="论坛">
<span slot="title"><i class="el-icon-date"></i>论坛</span>
</el-menu-item>
<el-menu-item index="即聊">
<span slot="title"><i class="el-icon-date"></i>即聊</span>
</el-menu-item>
<el-menu-item index="客服">
<span slot="title"><i class="el-icon-date"></i>客服</span>
</el-menu-item>
</el-submenu>
</el-menu>
<xm-product-overview-complex v-if="infotype=='产品概览'" :xm-product="xmProduct"></xm-product-overview-complex>
<xm-iteration-for-project-complex v-if="infotype=='迭代'" ref="xmIterationMng" :xm-product="xmProduct"></xm-iteration-for-project-complex>
<xm-project-for-link v-if="infotype=='项目'" ref="xmProjectForLink" :xm-product="xmProduct"></xm-project-for-link>
<xm-menu-mng v-if="infotype=='用户故事'" :xm-product="xmProduct"></xm-menu-mng>
<xm-task-mng v-if="infotype=='任务'" ref="xmTaskMng" :xm-product="xmProduct" ></xm-task-mng>
<xm-question v-if="infotype=='缺陷'" :qtype="'bug'" :xm-product='xmProduct' ref="xmQuestion"></xm-question>
<xm-group-mng v-if="infotype=='团队'" :xm-product="xmProduct"></xm-group-mng>
<xm-file-mng v-if="infotype=='文档'" :xm-product="xmProduct"></xm-file-mng>
<xm-project-phase-mng v-if="infotype=='阶段计划及里程碑'" ref="xmProjectPhaseMng" :xm-product="xmProduct" ></xm-project-phase-mng>
<xm-test-case-exec-mng v-if="infotype=='测试计划'" :visible="infotype=='测试计划'" :xm-product='xmProduct' ref="xmQuestion"></xm-test-case-exec-mng>
<xm-menu-with-plan v-if="infotype=='故事监控'" ref="xmMenuWithPlan" :xm-product="xmProduct"></xm-menu-with-plan>
<xm-project-state-mng v-if="infotype=='项目监控'" :xm-product="xmProduct"></xm-project-state-mng>
<xm-budget v-if="infotype=='预算'" :xm-product="xmProduct"></xm-budget>
<xm-cost v-if="infotype=='费用'" :xm-product="xmProduct"></xm-cost>
<xm-project-kpi v-if="infotype=='考核'" :xm-product="xmProduct"></xm-project-kpi>
<xm-record v-if="infotype=='日志'" :visible="infotype=='日志'" :xm-product="xmProduct"></xm-record>
<xm-contract v-if="infotype=='合同管理'" :xm-product="xmProduct"></xm-contract>
<xm-env-list v-if="infotype=='环境清单'" :xm-product="xmProduct"></xm-env-list>
<xm-question v-if="infotype=='风险'" :qtype="'risk'" :xm-product='xmProduct' ref="xmRisk"></xm-question>
<el-drawer title="选中团队成员" :visible.sync="groupUserVisible" size="50%" append-to-body :close-on-click-modal="false">
<xm-project-group-select :xm-product="xmProduct" :visible="groupUserVisible" is-select-multi-user="1" @user-confirm="onUserSelected"></xm-project-group-select>
</el-drawer>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
//import Sticky from '@/components/Sticky' // header
//import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProject,editStatus , delXmProject, batchDelXmProject } from '@/api/xm/core/xmProject';
import XmProjectAdd from '../xmProject/XmProjectAdd';//
import XmProjectEdit from '../xmProject/XmProjectEdit';//
import { mapGetters } from 'vuex';
import xmTaskMng from '../xmTask/XmTaskMng';
import xmGroupMng from '../xmProjectGroup/XmProjectGroupMng';
import xmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect';
import xmExchange from '../xmExchange/XmExchangeMng';
import xmQuestion from '../xmQuestion/XmQuestionMng';
import xmFileMng from '../xmFile/XmFileMng';
import xmDetail from '../xmProject/XmProjectDetail';
import xmProjectKpi from '../xmProjectKpi/XmProjectKpiMng';
import xmRecord from '../xmRecord/XmRecordMng';
import xmCost from '../xmProject/XmProjectCost';
import xmBudget from '../xmProject/XmProjectBudgetCost';
import xmContract from '../xmProjectContract/XmProjectContractMng';
import xmEnvList from '../xmProjectEnvList/XmProjectEnvListMng';
import xmProjectPhaseMng from '../xmProjectPhase/XmProjectPhaseMng';
import xmMenuMng from '../xmMenu/XmMenuMng';
import xmMenuWithPlan from '../xmMenu/XmMenuWithPlan';
import xmProjectStateMng from '../xmProjectState/XmProjectStateMng';
import xmTestCaseExecMng from '../xmTestCaseExec/XmTestCaseExecMng';
import XmIterationForProjectComplex from '../xmIteration/XmIterationForProjectComplex.vue';
import XmProductOverviewComplex from '../xmProduct/XmProductOverviewComplex.vue';
import XmProductForProjectComplex from './XmProductForProjectComplex.vue';
import XmProjectForLink from '../xmProject/XmProjectForLink.vue';
export default {
props: ["xmProduct","visible"],
computed: {
...mapGetters([
'userInfo','roles'
]),
},
watch:{
xmProduct:function(xmProduct){
var oldInfotype=this.infotype
this.infotype=''
this.$nextTick(()=>{
this.infotype=oldInfotype
})
}
},
data() {
return {
platformViewVisible:false,
tabPosition:'left',
infotype:"项目概览",
load:{list:false,edit:false},
groupUserVisible:false,
exportArr: ['任务', '阶段计划', '故事监控']
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
afterEditSubmit:function(project){
this.$emit("submit",project)
},
toArchive:function(){
this.$router.push({
path: "/mdp/arc/mate/archive/ArchiveMng"
});
},
toIm:function(){
this.groupUserVisible=true
},
toHelpMe:function(){
this.$router.push({
path: "/mdp/im/messages/crmChat",
query:{
categoryId:'css',
sendContent:'咨询'
}
});
},
handleMenuSelect(menuId){
this.infotype=menuId
},
onUserSelected:function(users){
if(this.groupUserVisible==true){
var query={}
if(users){
if( users.length==1 ){
var user=users[0]
query.toUserid=user.userid
query.toUsername=user.username
query.msgType="prichat"
}else if( users.length >=2 ){
query.users=JSON.stringify(users.map(i=>{return {userid:i.userid,username:i.username}}))
query.categoryId="common"
query.msgType="group"
}
}
this.$router.push({
path: "/mdp/im/messages/messageChat",
query: query
});
}
},
setInfotype(infotype){
this.infotype=infotype;
},
handleExport() {
this.downloadLoading = true
let list = [];
let header = [];
let keyList = [];
let pageNum = 1;
let infotypeKey = '';
if (this.infotype === '任务') {
header = ['序号', '任务名称', '故事', '预算(万)', '工作量(人时)', '执行人', '进度', '任务开始时间', '任务结束时间', '任务技能需求'];
keyList = ['sortLevel', 'name', 'menuName', 'budgetCost', 'budgetWorkload', 'exeUsernames', 'rate', 'startTime', 'endTime', 'taskSkillNames'];
list = this.$refs.xmTaskMng.tasksTreeData;
pageNum = this.$refs.xmTaskMng.pageInfo.pageNum;
} else if (this.infotype === '阶段计划') {
header = ['序号', '阶段名称', '开始时间', '结束时间', '进度(%)', '状态', '计划人数', '实际人数', '计划工期', '实际工期', '计划工作量(人时)', '实际工作量(人时)', '计划非人力成本(元)', '实际非人力成本(元)', '计划内购人力成本(元)', '实际内购人力成本(元)', '计划外购人力成本(元)', '实际外购人力成本(元)', '计划成本合计(元)', '实际成本合计(元)', '审批状态', '备注'];
keyList = ['seqNo', 'phaseName', 'beginDate', 'endDate', 'actRate', 'phaseStatus', 'phaseBudgetOutUserCnt', 'actStaffNu', 'phaseBudgetHours', 'actHours', 'phaseBudgetWorkload', 'phaseActWorkload', 'phaseBudgetNouserAt', 'actNouserAt', 'phaseBudgetInnerUserAt', 'actInnerUserAt', 'phaseBudgetOutUserAt', 'actOutUserAt', 'phaseBudgetCostAt', 'actCostAt', 'bizFlowState', 'remark'];
list = this.$refs.xmProjectPhaseMng.projectPhaseTreeData;
pageNum = this.$refs.xmProjectPhaseMng.pageInfo.pageNum;
} else if (this.infotype === '故事监控') {
header = ['序号', '故事名称', '计划状态', '负责人', '上线时间', '计划开始时间', '实际开始时间', '计划结束时间', '实际结束时间', '计划工作量(人时)', '实际工作量(人时)', '计划成本(元)', '实际成本(元)', '总体完成比例%', '需求完成比例%', '设计完成比例%', '开发完成比例%', 'sit完成比例%', 'uat完成比例%', '上线状态'];
keyList = ['seqNo', 'menuName', 'planStatus', 'chargeUsername', 'onlineTime', 'planStartTime', 'actStartTime', 'planEndTime', 'actEndTime', 'planWorkload', 'actWorkload', 'planCostAmount', 'actCostAmount', 'finishRate', 'demandRate', 'designRate', 'devRate', 'sitRate', 'uatRate', 'onlineStatus'];
list = this.$refs.xmMenuWithPlan.xmMenusTreeData;
pageNum = this.$refs.xmMenuWithPlan.pageInfo.pageNum;
}
const filename = `${this.xmProduct.productName}_${this.infotype}_第${pageNum}`;
const data = this.formatJson(keyList, list);
import('@/vendor/Export2Excel').then(excel => {
excel.export_json_to_excel({
header,
data,
filename,
// autoWidth: this.autoWidth,
bookType: 'xlsx'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData, dataList = []) {
if (this.infotype == '任务') {
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
return v[j];
})
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
} else if (this.infotype == '阶段计划') {
const bizFlowStateDict = {
0: '未发审',
1: '审核中',
2: '已通过',
3: '未通过',
4: '已取消'
}
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
if(j == 'phaseStatus') {
return this.$refs.xmProjectPhaseMng.formateOption('xmPhaseStatus', v.phaseStatus);
} else if(j == 'bizFlowState') {
return `${bizFlowStateDict[parseInt(v[j]) || 0]}`;
} else {
return v[j];
}
})
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
} else if (this.infotype == '故事监控') {
jsonData.forEach(v => {
const row = filterVal.map(j => {
let key = '';
if(j == 'planStatus') {
key = 'xmMenuPlanStatus';
} else if(j == 'onlineStatus') {
return parseInt(v[j]) ? '已上线' : '未上线';
} else {
return v[j];
}
const options = this.$refs.xmMenuWithPlan.options;
if(options[key]==undefined || options[key]==null || options[key].length==0 ){
return v[j];
}
var rowData=options[key].filter(i=>i.optionValue==v[j])
if(rowData.length>0){
return rowData[0].optionName
}else{
return v[j];
}
});
dataList.push(row);
if (v.children && v.children.length) {
dataList = this.formatJson(filterVal, v.children, dataList);
}
})
return dataList;
}
},
getDateString(dateStr){
if(dateStr==null || dateStr=="" || dateStr==undefined){
return ""
}else{
return dateStr.substr(0,10);
}
},
goBack(){
this.$router.back()
}
},//end methods
components: {
xmTaskMng,
xmProjectPhaseMng,
xmGroupMng,
xmExchange,
xmQuestion,
xmFileMng,
xmDetail,
xmProjectKpi,
xmRecord,
xmCost,
xmBudget,
xmContract,
xmEnvList,
xmMenuMng,
xmMenuWithPlan,
xmProjectStateMng,
xmTestCaseExecMng,
xmProjectGroupSelect,
XmIterationForProjectComplex,
XmProductOverviewComplex,
XmProductForProjectComplex,
XmProjectForLink,
//
},
mounted() {
this.$nextTick(() => {
});
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.menus{
.el-menu-item{
padding-left: 0px !important;
}
}
/* 超过宽度则用...代替 */
.truncate{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

61
src/views/xm/core/xmProduct/XmProductInfoRoute.vue

@ -0,0 +1,61 @@
<template>
<section>
<xm-product-info v-if="xmProduct" :xm-product="xmProduct" :visible="showInfo"></xm-product-info>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { mapGetters } from 'vuex';
import XmProductInfo from './XmProductInfo'
export default {
computed: {
...mapGetters([
'userInfo','roles'
]),
},
watch:{
},
data() {
return {
xmProduct:null,
showInfo:false,
}
},//end data
methods: {
},//end methods
components: {
XmProductInfo,
//
},
activated(){
if(this.$route.params && this.$route.params.id){
this.xmProduct=this.$route.params
this.showInfo=true;
localStorage.setItem('xm-product-info-route',JSON.stringify(this.xmProduct));
}else{
this.xmProduct=JSON.parse(localStorage.getItem("xm-product-info-route"))
this.showInfo=true;
}
},
mounted() {
if(this.$route.params && this.$route.params.id){
this.xmProduct=this.$route.params
this.showInfo=true;
localStorage.setItem('xm-product-info-route',JSON.stringify(this.xmProduct));
}else{
this.xmProduct=JSON.parse(localStorage.getItem("xm-product-info-route"))
this.showInfo=true;
}
}
}
</script>
<style scoped>
</style>

279
src/views/xm/core/xmProduct/XmProductMng.vue

@ -5,10 +5,10 @@
<el-option :label="userInfo.branchName+'机构下所有的产品'" value="branchId"></el-option> <el-option :label="userInfo.branchName+'机构下所有的产品'" value="branchId"></el-option>
<el-option label="我相关的产品" value="compete"></el-option> <el-option label="我相关的产品" value="compete"></el-option>
<el-option label="按产品编号精确查找" value="productId"></el-option> <el-option label="按产品编号精确查找" value="productId"></el-option>
<el-option label="后台智能匹配" value=""></el-option>
</el-select> </el-select>
<el-input v-if="filters.queryScope=='productId'" style="width:20%;" v-model="filters.id" placeholder="输入产品编号" @keyup.enter.native="searchXmProducts"> <el-input v-if="filters.queryScope=='productId'" style="width:20%;" v-model="filters.id" placeholder="输入产品编号" @keyup.enter.native="searchXmProducts">
</el-input> </el-input>
<el-date-picker v-show="!selProject&&filters.queryScope!='productId'" <el-date-picker v-show="!selProject&&filters.queryScope!='productId'"
v-model="dateRanger" v-model="dateRanger"
type="daterange" type="daterange"
@ -28,31 +28,30 @@
<el-button v-loading="load.list" :disabled="load.list==true" v-on:click="searchXmProducts" icon="el-icon-search"></el-button> <el-button v-loading="load.list" :disabled="load.list==true" v-on:click="searchXmProducts" icon="el-icon-search"></el-button>
</template> </template>
</el-input> </el-input>
<el-button type="primary" @click="showAdd" icon="el-icon-plus">产品</el-button>
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length===0 || load.del==true" icon="el-icon-delete"></el-button>
<el-button v-if="xmIteration" icon="el-icon-plus" @click="productSelectVisible=true">将更多产品加入迭代<strong>{{xmIteration.iterationName}}</strong></el-button>
<el-button type="primary" @click="showAdd" icon="el-icon-plus" v-if="!xmIteration">产品</el-button>
<el-popover <el-popover
placement="top-start" placement="top-start"
title="" title=""
width="400"
width="500"
trigger="click" > trigger="click" >
<el-divider content-position="left"><strong>查询条件</strong></el-divider>
<el-row> <el-row>
<el-col :span="24" style="padding-top:5px;"> <el-col :span="24" style="padding-top:5px;">
<font class="more-label-font"> <font class="more-label-font">
产品查询范围 产品查询范围
</font> </font>
<el-select size="mini" v-model="filters.queryScope" style="width:100%;" placeholder="产品查询范围"> <el-select size="mini" v-model="filters.queryScope" style="width:100%;" placeholder="产品查询范围">
<el-option :label="userInfo.branchName+'机构下所有的产品'" value="branchId"></el-option>
<el-option :label="userInfo.branchName+'机构下的产品'" value="branchId"></el-option>
<el-option label="我相关的产品" value="compete"></el-option> <el-option label="我相关的产品" value="compete"></el-option>
<el-option label="按产品编号精确查找" value="productId"></el-option> <el-option label="按产品编号精确查找" value="productId"></el-option>
<el-option label="后台智能匹配" value=""></el-option>
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="24" style="padding-top:5px;"> <el-col :span="24" style="padding-top:5px;">
<el-input v-if="filters.queryScope=='productId'" size="mini" v-model="filters.id" style="width:100%;" placeholder="输入产品编号" @keyup.enter.native="searchXmProducts"> <el-input v-if="filters.queryScope=='productId'" size="mini" v-model="filters.id" style="width:100%;" placeholder="输入产品编号" @keyup.enter.native="searchXmProducts">
</el-input> </el-input>
</el-col> </el-col>
<el-col v-show="!selProject&&filters.queryScope!='productId'" :span="24" style="padding-top:5px;"> <el-col v-show="!selProject&&filters.queryScope!='productId'" :span="24" style="padding-top:5px;">
<font class="more-label-font">创建时间:</font> <font class="more-label-font">创建时间:</font>
<el-date-picker <el-date-picker
@ -68,7 +67,6 @@
:picker-options="pickerOptions" :picker-options="pickerOptions"
></el-date-picker> ></el-date-picker>
</el-col> </el-col>
<el-col :span="24" style="padding-top:5px;"> <el-col :span="24" style="padding-top:5px;">
<font class="more-label-font"> <font class="more-label-font">
产品名称: 产品名称:
@ -84,13 +82,66 @@
<el-button size="mini" v-else @click="selectFiltersPmUser()">选责任人</el-button> <el-button size="mini" v-else @click="selectFiltersPmUser()">选责任人</el-button>
<el-button size="mini" @click="setFiltersPmUserAsMySelf()">我的</el-button> <el-button size="mini" @click="setFiltersPmUserAsMySelf()">我的</el-button>
</el-col> </el-col>
<el-col :span="24" style="padding-top:5px;">
<el-col v-if="selProject" :span="24" style="padding-top:5px;">
<font class="more-label-font">
项目 <el-tag v-if="selProject">{{selProject?selProject.name:''}}</el-tag>
</font>
</el-col>
<el-col v-if="xmIteration" :span="24" style="padding-top:5px;">
<font class="more-label-font">
迭代 <el-tag v-if="xmIteration">{{xmIteration.iterationName}}</el-tag>
</font>
</el-col>
<el-col :span="24" style="padding-top:10px;">
<el-button type="primary" size="mini" @click="searchXmProducts" >查询</el-button> <el-button type="primary" size="mini" @click="searchXmProducts" >查询</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-divider content-position="left"><strong>更多操作</strong></el-divider>
<el-row>
<el-col :span="24" style="padding-top:5px;">
<el-button v-if="xmIteration" size="mini" icon="el-icon-plus" @click="productSelectVisible=true">将更多产品加入迭代<strong>{{xmIteration.iterationName}}</strong></el-button>
</el-col>
</el-row>
<el-button slot="reference" icon="el-icon-more" circle></el-button> <el-button slot="reference" icon="el-icon-more" circle></el-button>
</el-popover> </el-popover>
</el-row> </el-row>
<el-row class="page-main page-height-80">
<!--列表 XmProject xm_project-->
<el-row v-show="showType" v-loading="load.list">
<el-col v-cloak v-for="(p,i) in xmProducts" :key="i" :xl="4" :lg="6" :md="8" :sm="12">
<el-card @click.native="intoInfo(p,i)" class="project-card" shadow="always">
<div class="project-name" title="这是产品名称">{{p.productName}}</div>
<div class="project-id eui-text-truncate">{{p.code}}</div>
<div class="project-info">
<div class="info-item">
<span class="item-total">{{p.totalBugCnt==null?0:p.totalBugCnt}}</span>
<span class="item-type">缺陷</span>
</div>
<div class="info-item">
<span class="item-total">{{p.totalFileCnt==null?0:p.totalFileCnt}}</span>
<span class="item-type">文档</span>
</div>
<div class="info-task">
<span>
<span class="item-total finish-task">{{p.totalCompleteTaskCnt==null?0:p.totalCompleteTaskCnt}}</span>
<span style="margin: 0 .25rem !important;">/</span>
<span class="item-type total-task">{{p.totalTaskCnt==null?0:p.totalTaskCnt}}</span>
</span>
<span class="item-type">任务完成</span>
</div>
</div>
<div class="project-rate">
<el-progress :percentage="(p.totalProgress==null?0:p.totalProgress)"></el-progress>
</div>
<div class="project-footer">
<div class="project-type">{{p.xmType}}</div>
<!--<div class="project-period">{{p.startTime.substr(0,10)}} ~{{p.endTime.substr(0,10)}}</div>-->
</div>
</el-card>
</el-col>
</el-row>
</el-row>
<el-row class="padding-top"> <el-row class="padding-top">
<!--列表 XmProduct 产品表--> <!--列表 XmProduct 产品表-->
<el-table ref="table" :height="tableHeight" :data="xmProducts" @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="xmProducts" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
@ -110,7 +161,7 @@
<el-table-column prop="actWorkload" label="实际工作量.人时" width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="actWorkload" label="实际工作量.人时" width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="200" fixed="right"> <el-table-column label="操作" width="200" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="primary" @click="toIterationList(scope.row)" icon="el-icon-document">迭代计划</el-button>
<el-tooltip v-if="xmIteration" :content="'将产品与迭代【'+ xmIteration.iterationName + '】脱钩'"><el-button @click="doDelXmIterationProductLink( scope.row,scope.$index)" icon="el-icon-remove-outline">与迭代脱钩</el-button></el-tooltip>
<el-popover <el-popover
placement="top-start" placement="top-start"
title="" title=""
@ -118,20 +169,23 @@
trigger="click" > trigger="click" >
<el-row> <el-row>
<el-col :span="24" style="padding-top:12px;"> <el-col :span="24" style="padding-top:12px;">
<el-button type="warning" @click="loadTasksToXmProductState(scope.row)" icon="el-icon-s-data">执行统计任务</el-button>
<el-button type="warning" @click="loadTasksToXmProductState(scope.row)" icon="el-icon-s-data">从任务汇总统计进度</el-button>
</el-col> </el-col>
<el-col :span="24" style="padding-top:12px;"> <el-col :span="24" style="padding-top:12px;">
<el-button type="warning" @click="showProductState(scope.row)" icon="el-icon-s-data">产品报告</el-button> <el-button type="warning" @click="showProductState(scope.row)" icon="el-icon-s-data">产品报告</el-button>
</el-col> </el-col>
<el-col :span="24" class="hidden-lg-and-up" style="padding-top:12px;">
<el-button type="success" @click="toProjectList(scope.row)" icon="el-icon-document">关联项目查询</el-button>
<el-col :span="24" style="padding-top:12px;">
<el-button type="primary" @click="toIterationList(scope.row)" icon="el-icon-document">关联迭代计划查询</el-button>
</el-col> </el-col>
<el-col :span="24" class="hidden-lg-and-up" style="padding-top:12px;">
<el-button type="success" @click="toIterationList(scope.row)" icon="el-icon-document">迭代计划管理</el-button>
<el-col :span="24" style="padding-top:12px;">
<el-button type="success" @click="toProjectList(scope.row)" icon="el-icon-document">关联项目查询</el-button>
</el-col> </el-col>
<el-col :span="24" style="padding-top:12px;"> <el-col :span="24" style="padding-top:12px;">
<el-button type="success" @click="toTaskList(scope.row)" icon="el-icon-tickets">关联任务查询</el-button> <el-button type="success" @click="toTaskList(scope.row)" icon="el-icon-tickets">关联任务查询</el-button>
</el-col> </el-col>
<el-col :span="24" style="padding-top:12px;">
<el-button type="danger" v-loading="load.del" @click="handleDel(scope.row)" :disabled="load.del==true" icon="el-icon-delete">删除</el-button>
</el-col>
</el-row> </el-row>
<el-button slot="reference" icon="el-icon-more" circle></el-button> <el-button slot="reference" icon="el-icon-more" circle></el-button>
</el-popover> </el-popover>
@ -164,6 +218,16 @@
<el-drawer title="选择员工" :visible.sync="selectFiltersPmUserVisible" size="60%" append-to-body> <el-drawer title="选择员工" :visible.sync="selectFiltersPmUserVisible" size="60%" append-to-body>
<users-select @confirm="onFiltersPmUserSelected" ref="usersSelect"></users-select> <users-select @confirm="onFiltersPmUserSelected" ref="usersSelect"></users-select>
</el-drawer> </el-drawer>
<el-drawer title="选择项目" :visible.sync="projectVisible" size="60%" append-to-body>
<xm-project-list @select="onProjectSelected"></xm-project-list>
</el-drawer>
<el-drawer title="选择产品" :visible.sync="productSelectVisible" size="60%" append-to-body>
<xm-product-select @row-click="onXmProductSelect"></xm-product-select>
</el-drawer>
<el-drawer title="迭代报告" :visible.sync="iterationSelectVisible" fullscreen append-to-body :close-on-click-modal="false">
<xm-iteration-select @row-click="onXmIterationSelect"></xm-iteration-select>
</el-drawer>
</section> </section>
</template> </template>
@ -172,6 +236,7 @@
//import Sticky from '@/components/Sticky' // header //import Sticky from '@/components/Sticky' // header
//import { listOption } from '@/api/mdp/meta/itemOption';// //import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProduct,listXmProductWithState, delXmProduct, batchDelXmProduct } from '@/api/xm/core/xmProduct'; import { listXmProduct,listXmProductWithState, delXmProduct, batchDelXmProduct } from '@/api/xm/core/xmProduct';
import { addXmIterationProductLink,delXmIterationProductLink } from '@/api/xm/core/xmIterationProductLink';
import { loadTasksToXmProductState } from '@/api/xm/core/xmProductState'; import { loadTasksToXmProductState } from '@/api/xm/core/xmProductState';
import XmProductAdd from './XmProductAdd';// import XmProductAdd from './XmProductAdd';//
import XmProductEdit from './XmProductEdit';// import XmProductEdit from './XmProductEdit';//
@ -180,14 +245,25 @@
import XmProductStateMng from '../xmProductState/XmProductStateMng';// import XmProductStateMng from '../xmProductState/XmProductStateMng';//
import UsersSelect from "@/views/mdp/sys/user/UsersSelect"; import UsersSelect from "@/views/mdp/sys/user/UsersSelect";
import XmProjectList from '../xmProject/XmProjectList.vue';
import XmIterationSelect from '../xmIteration/XmIterationSelect.vue';
import XmProductSelect from './XmProductSelect.vue';
export default { export default {
props:['selProject'],
props:['selProject','xmIteration'],
computed: { computed: {
...mapGetters([ ...mapGetters([
'userInfo','roles' 'userInfo','roles'
]) ])
}, },
watch:{
selProject:function(){
this.getXmProducts();
},
xmIteration:function(){
this.getXmProducts();
}
},
data() { data() {
const beginDate = new Date(); const beginDate = new Date();
const endDate = new Date(); const endDate = new Date();
@ -224,6 +300,7 @@
id:'',productName:'',branchId:'',remark:'' id:'',productName:'',branchId:'',remark:''
}, },
iterationVisible:false, iterationVisible:false,
iterationSelectVisible:false,
productStateVisible:false, productStateVisible:false,
selectFiltersPmUserVisible:false, selectFiltersPmUserVisible:false,
tableHeight:300, tableHeight:300,
@ -232,6 +309,9 @@
util.formatDate.format(endDate, "yyyy-MM-dd") util.formatDate.format(endDate, "yyyy-MM-dd")
], ],
pickerOptions: util.pickerOptions('datarange'), pickerOptions: util.pickerOptions('datarange'),
projectVisible:false,
productSelectVisible:false,
showType:true,
/**begin 自定义属性请在下面加 请加备注**/ /**begin 自定义属性请在下面加 请加备注**/
/**end 自定义属性请在上面加 请加备注**/ /**end 自定义属性请在上面加 请加备注**/
@ -308,9 +388,8 @@
} }
if(this.filters.queryScope=="branchId"){ if(this.filters.queryScope=="branchId"){
params.branchId=this.userInfo.branchId params.branchId=this.userInfo.branchId
params.projectId=null;
} }
if(!this.selProject && this.filters.queryScope!='productId'){
if(!this.selProject && !this.xmIteration && this.filters.queryScope!='productId' && this.filters.queryScope!='compete'){
if(!this.dateRanger || this.dateRanger.length==0){ if(!this.dateRanger || this.dateRanger.length==0){
this.$message({showClose: true, message: "创建日期范围不能为空", type: 'error' }); this.$message({showClose: true, message: "创建日期范围不能为空", type: 'error' });
return; return;
@ -318,7 +397,9 @@
params.ctimeStart=this.dateRanger[0]+" 00:00:00" params.ctimeStart=this.dateRanger[0]+" 00:00:00"
params.ctimeEnd=this.dateRanger[1]+" 23:59:59" params.ctimeEnd=this.dateRanger[1]+" 23:59:59"
} }
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
if(this.filters.key!==""){ if(this.filters.key!==""){
params.key="%"+this.filters.key+"%" params.key="%"+this.filters.key+"%"
} }
@ -356,15 +437,26 @@
this.addFormVisible = true; this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm); //this.addForm=Object.assign({}, this.editForm);
}, },
afterAddSubmit(){
afterAddSubmit(xmProduct){
this.addFormVisible=false; this.addFormVisible=false;
this.pageInfo.count=true; this.pageInfo.count=true;
this.getXmProducts();
if(this.xmIteration){//
this.onXmProductSelect(xmProduct);
}else{
this.getXmProducts();
}
}, },
afterEditSubmit(){ afterEditSubmit(){
this.editFormVisible=false; this.editFormVisible=false;
this.getXmProducts() this.getXmProducts()
}, },
//info
intoInfo(row) {
this.editForm = row;
this.$router.push({ name:'XmProductInfoRoute', params: row })
//this.showInfo = true;
},
//xmProduct //xmProduct
selsChange: function (sels) { selsChange: function (sels) {
this.sels = sels; this.sels = sels;
@ -455,8 +547,45 @@
setFiltersPmUserAsMySelf(){ setFiltersPmUserAsMySelf(){
this.filters.pmUser=this.userInfo; this.filters.pmUser=this.userInfo;
this.searchXmProducts(); this.searchXmProducts();
},
onProjectSelected(projects){
},
onXmIterationSelect(){
}, },
/**end 自定义函数请在上面加**/ /**end 自定义函数请在上面加**/
onXmProductSelect:function(row){
var xmIteration=this.xmIteration;
var xmProduct=row;
this.$confirm('确认将产品【'+xmProduct.productName+'】加入迭代计划【'+xmIteration.iterationName+'】吗?', '提示', {
type: 'warning'
}).then(()=>{
addXmIterationProductLink({iterationId:xmIteration.id,productId:xmProduct.id}).then(res=>{
var tips =res.data.tips;
if(tips.isOk){
this.getXmProducts();
}
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error'});
})
})
},
doDelXmIterationProductLink(row){
var xmIteration=this.xmIteration;
var xmProduct=row;
this.$confirm('确认将产品【'+xmProduct.productName+'】与迭代【'+xmIteration.iterationName+'】进行脱钩吗?脱钩后,产品下的所有故事将从本迭代计划一并移出。', '提示', {
type: 'warning'
}).then(()=>{
delXmIterationProductLink({iterationId:xmIteration.id,productId:xmProduct.id}).then(res=>{
var tips =res.data.tips;
if(tips.isOk){
this.getXmProducts();
}
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error'});
})
})
}
/**end 自定义函数请在上面加**/
},//end methods },//end methods
components: { components: {
@ -465,6 +594,9 @@
XmIterationMng, XmIterationMng,
XmProductStateMng, XmProductStateMng,
UsersSelect, UsersSelect,
XmProjectList,
XmIterationSelect,
XmProductSelect,
// //
}, },
mounted() { mounted() {
@ -492,3 +624,106 @@
float: right; float: right;
} }
</style> </style>
<style scoped>
.project-card{
font-size: 12px;
color: #999;
margin: 10px 12px;
}
.project-card:hover{
border-color: #00abfc;
}
.project-card >>> .el-card__body{
padding: 20px 15px 10px;
}
.project-name{
font-size: 16px;
font-weight: 700;
color: #333;
height: 24px;
}
.project-id{
margin-top: 4px;
height: 18px;
}
.project-info{
display: flex;
margin-top: 8px;
}
.project-info>div{
display: flex;
flex-direction: column;
}
.info-item{
width: 15%;
text-align: center;
}
.info-item >>> span{
display: block;
}
.item-total{
font-size: 18px;
color: #666;
}
.info-task{
padding-left: 20px;
width: 70%;
border-left: 1px solid #efefef;
}
.finish-task{
color: #00abfc !important;
}
.project-rate{
margin: 15px 0;
}
.project-rate>.el-progress{
display: flex;
align-items: center;
}
.project-rate >>> .el-progress-bar{
padding-right: 0;
margin-right: 0;
}
.project-rate >>> .el-progress__text{
margin-left: 5px;
}
.project-footer{
display: flex;
}
.project-footer>div{
width: 30%;
}
.project-footer>div:not(:first-child){
width: 70%;
}
.project-period{
text-align: right;
}
@media only screen and (max-height: 2400px) {
.project-box{
max-height: 1600x;
overflow-y: auto;
}
}
@media only screen and (max-height: 1200px) {
.project-box{
max-height: 800px;
overflow-y: auto;
}
}
@media only screen and (max-height: 980px) {
.project-box{
max-height: 600px;
overflow-y: auto;
}
}
@media only screen and (max-height: 640px) {
.project-box{
max-height: 300px;
overflow-y: auto;
}
}
</style>

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

@ -0,0 +1,699 @@
<template>
<section class="page-container padding">
<!-- <el-row class="page-header page-height-10">
<el-col :xs="22" :sm="22" :md="23" :lg="23" :xl="23">
<span >项目总览</span>
</el-col>
</el-row>-->
<el-row class="page-main page-height-75" style="overflow-x: hidden;">
<el-row :gutter="10" style="margin-bottom:10px">
<el-col :span="8" >
<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="taskMng"></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="totalTask"></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="finish" >
</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="taskStartTime+'~'+taskEndTime">
</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.xmProjectState.menuCnt}}</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.xmProjectState.iterationCnt==null?0:this.xmProjectState.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="info">
<el-progress v-if="progress1" :percentage="progress1"></el-progress>
</div>
<div class="title">任务进度</div>
</div>
</div>
</el-row>
</el-card>
</el-col>
<el-col :span="8" >
<el-card class="box-card" style="height:425px">
<div slot="header" class="clearfix">
<span>所有工作项及其完成情况</span>
</div>
<div>
<div id="allChart" :style="{width: '425px', height: '350px'}"></div>
</div>
</el-card>
</el-col>
<el-col :span="8" >
<el-card class="box-card" style="height:425px">
<div slot="header" class="clearfix">
<span>缺陷情况</span>
</div>
<div>
<div id="bugPieChart" :style="{width: '440px', height: '400px'}"></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>
<div id="taskChart" :style="{width: '630px', height: '320px'}"></div>
</div>
</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.xmProjectState.totalPlanWorkload"></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.xmProjectState.totalActWorkload"></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: 600px;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: 600px;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 style="margin-bottom:10px">
<el-card class="box-card" style="padding:0px ;height:200px">
<div slot="header" class="clearfix" style="margin-bottom:10px">
<span>项目阶段</span>
</div>
<div>
<el-row style="padding:10px">
<el-steps :active="calcProjectStatusStep" finish-status="success">
<el-step v-for="(i,index) in options['projectStatus']" :title="i.optionName" :key="index">
<el-row slot="title" @click.native.stop="editForm.status=i.optionValue">
{{i.optionName}}
</el-row>
</el-step>
</el-steps>
</el-row>
</div>
</el-card>
</el-row>
</el-row>
</section>
</template>
<script>
import util from "@/common/js/util"; //
//import Sticky from "@/components/Sticky"; // header
import { mapGetters } from "vuex";
import { listXmProjectState } from '@/api/xm/core/xmProjectState';
import { listOption } from '@/api/mdp/meta/itemOption';//
export default {
computed: {
...mapGetters(["userInfo"]),
finish: function (){
return this.xmProjectState.totalCompleteTaskCnt;
},
notStart: function() {
return this.xmProjectState.totalTaskCnt-this.xmProjectState.totalCompleteTaskCnt;
},
totalTask: function() {
return this.xmProjectState.totalTaskCnt;
},
progress1: function (){
return Math.round(this.xmProjectState.totalCompleteTaskCnt/this.xmProjectState.totalTaskCnt*100);
},
taskStartTime: function (){
return this.selProject.startTime.substring(0,10);
},
taskEndTime: function (){
return this.selProject.endTime.substring(0,10);
},
taskMng: function (){
return this.selProject.createUsername;
},
workloadProgress:function (){
return Math.round(this.xmProjectState.totalActWorkload/this.xmProjectState.totalPlanWorkload*100);
},
deviation:function (){
let now = new Date();
let taskStartTime = new Date(this.selProject.startTime);
let taskEndTime = new Date(this.selProject.endTime);
if(now<=taskEndTime){
let allDays=taskEndTime-taskStartTime;
return this.xmProjectState.totalActWorkload - Math.round((now-taskStartTime)/allDays*this.xmProjectState.totalPlanWorkload)
}else{
return this.xmProjectState.totalActWorkload - this.xmProjectState.totalPlanWorkload;
}
},
deviationRate:function (){
return Math.round(this.deviation/this.xmProjectState.totalPlanWorkload*100);
},
remainWorkload:function (){
return this.xmProjectState.totalPlanWorkload - this.xmProjectState.totalActWorkload;
},
planProgress:function (){
let now = new Date();
let taskStartTime = new Date(this.selProject.startTime);
let taskEndTime = new Date(this.selProject.endTime);
if(now<=taskEndTime){
let allDays=taskEndTime-taskStartTime;
return Math.round((now-taskStartTime)/allDays*100)
}else{
return 100;
}
},
realProgress:function (){
if(this.xmProjectState.totalActWorkload < this.xmProjectState.totalPlanWorkload){
return Math.round(this.xmProjectState.totalActWorkload/this.xmProjectState.totalPlanWorkload*100)
}else{
return 100;
}
},
xmProjectStateCpd(){
return this.xmProjectState
},
calcProjectStatusStep(){
if(this.options['projectStatus'] && this.selProject){
var index=this.options['projectStatus'].findIndex(i=>{
if(i.optionValue==this.selProject.status){
return true;
}else{
return false;
}
})
return index+1;
}else{
return 0;
}
}
},
props:['selProject'],
watch:{
xmProjectStateCpd:function(){
this.drawAllBar();
this.drawTaskByDate();
this.drawPieBug();
}
},
data() {
return {
isActive: true,
load:{ list: false},
xmProjectState: [],//
options:{
projectType:[],
urgencyLevel:[],
priority:[],
projectStatus:[],
},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
};
},
methods:{
//xmProjectsTate
getXmProjectState(){
let params = {
projectId:this.selProject.id,
branchId:this.userInfo.branchId
};
this.load.list = true;
listXmProjectState(params).then((res) => {
let tips=res.data.tips;
if(tips.isOk){
this.xmProjectState = res.data.data[0];
}else{
this.$message({showClose: true, message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
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: [
{
data: [
{
value: this.xmProjectState.menuCnt,
itemStyle: {
normal:{
color: '#99CCFF'
}
}
},
{
value: this.xmProjectState.totalTaskCnt,
itemStyle: {
normal:{
color: '#99CCFF'
}
}
},
{
value: this.xmProjectState.totalBugCnt,
itemStyle: {
normal:{
color: '#99CCFF'
}
}
},
],
type: 'bar'
}
]
};
//
allChart.setOption(option);
},
drawTaskByDate() {
let taskChart = this.$echarts.init(document.getElementById("taskChart"));
let option = {
tooltip: {
trigger: 'axis'
},
color:['rgb(0, 153, 255)','#6699CC'],
legend: {
data: ['未开始', '进行中']
},
grid: {
left: '1%',
right: '3%',
bottom: '5%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [
{
name: '未开始',
type: 'line',
//stack: '',
data: [120, 132, 101, 134, 90, 230, 210],
areaStyle: {
normal:{
color:"rgb(153, 204, 255)" , //线
}
},
lineStyle:{
normal:{
color:'rgb(0, 153, 255)'
}
},
},
{
name: '进行中',
type: 'line',
//stack: '',
data: [220, 182, 191, 234, 290, 330, 310],
areaStyle: {
normal:{
color:"rgb(153, 204, 255)", //线
}
},
lineStyle:{
normal:{
color:'#6699CC'
}
},
},
],
};
//
taskChart.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: '68%',
data: [
{value: this.xmProjectState.totalClosedBugCnt,
itemStyle: {
normal:{
color: '#5470C6'
}
},
name: '已关闭'},
{value: this.xmProjectState.totalResolvedBugCnt,
itemStyle: {
normal:{
color: '#91CC75'
}
},
name: '已解决'},
{value: this.xmProjectState.totalActiveBugCnt,
itemStyle: {
normal:{
color: '#FAC858'
}
},
name: '已激活'},
{value: this.xmProjectState.totalConfirmedBugCnt,
itemStyle: {
normal:{
color: '#EE6666'
}
},
name: '已确认'},
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
//
bugPieChart.setOption(option);
}
},
mounted() {
this.$nextTick(() => {
this.getXmProjectState();
});
listOption([{categoryId:'all',itemCode:'projectType'},{categoryId:'all',itemCode:'urgencyLevel'},{categoryId:'all',itemCode:'priority'},{categoryId:'all',itemCode:'projectStatus'}] ).then(res=>{
if(res.data.tips.isOk){
this.options['projectType']=res.data.data.projectType
this.options['urgencyLevel']=res.data.data.urgencyLevel
this.options['priority']=res.data.data.priority
this.options['projectStatus']=res.data.data.projectStatus
}
});
},
};
</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;
}
.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;
}
.el-progress {
width: 350px;
}
.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>

130
src/views/xm/core/xmProduct/XmProductOverviewComplex.vue

@ -0,0 +1,130 @@
<template>
<section class="page-container page-height-90 padding-left padding-right">
<el-menu mode="horizontal" default-active="overiew" @select="onMenuToolBarSelect">
<el-menu-item index="overiew">
<span slot="title">项目概览</span>
</el-menu-item>
<el-menu-item index="detail">
<span slot="title">项目详情</span>
</el-menu-item>
<el-submenu index="project-change">
<template slot="title">
<span slot="title">项目变更</span>
</template>
<el-menu-item index="project-change-base-info">
<span slot="title">基础信息修改</span>
</el-menu-item>
<el-menu-item index="project-change-start">
<span slot="title">立项申请</span>
</el-menu-item>
<el-menu-item index="project-change-budget">
<span slot="title">预算+-</span>
</el-menu-item>
<el-menu-item index="project-change-cost">
<span slot="title">成本+-</span>
</el-menu-item>
<el-menu-item index="project-change-collection">
<span slot="title">收款</span>
</el-menu-item>
<el-menu-item index="project-change-conclusion">
<span slot="title">结项申请</span>
</el-menu-item>
<el-menu-item index="project-change-suspend">
<span slot="title">暂停申请</span>
</el-menu-item>
<el-menu-item index="project-change-activation">
<span slot="title">激活申请</span>
</el-menu-item>
<el-menu-item index="project-change-to-after-sales">
<span slot="title">转售后申请</span>
</el-menu-item>
<el-menu-item index="project-change-new-pm">
<span slot="title">项目经理变更申请</span>
</el-menu-item>
<el-menu-item index="project-change-new-leader">
<span slot="title">组长变更申请</span>
</el-menu-item>
</el-submenu>
<el-submenu index="menu-change">
<template slot="title">
<span slot="title">需求变更</span>
</template>
<el-menu-item index="menu-change-review">
<span slot="title">需求评审</span>
</el-menu-item>
<el-menu-item index="menu-change-border-review">
<span slot="title">需求边界异动</span>
</el-menu-item>
</el-submenu>
<el-submenu index="iteration-change">
<template slot="title">
<span slot="title">迭代变更</span>
</template>
<el-menu-item index="iteration-change-review">
<span slot="title">迭代计划评审</span>
</el-menu-item>
<el-menu-item index="iteration-change-border-review">
<span slot="title">迭代上线申请</span>
</el-menu-item>
</el-submenu>
<el-submenu index="phase-change">
<template slot="title">
<span slot="title">阶段计划变更</span>
</template>
<el-menu-item index="phase-change-review">
<span slot="title">计划评审</span>
</el-menu-item>
<el-menu-item index="phase-change-border-review">
<span slot="title">预算变更</span>
</el-menu-item>
</el-submenu>
</el-menu>
<xm-product-overview v-if="showPanelName=='overiew'" :xm-product="xmProduct"></xm-product-overview>
<xm-product-edit v-if="showPanelName=='detail'" :xm-product="xmProduct"></xm-product-edit>
</section>
</template>
<script>
import util from "@/common/js/util"; //
//import Sticky from "@/components/Sticky"; // header
import { mapGetters } from "vuex";
import { listXmProjectState } from '@/api/xm/core/xmProductState';
import XmProductOverview from './XmProductOverview.vue';
import XmProductEdit from './XmProductEdit.vue';
export default {
components: { XmProductOverview, XmProductEdit },
computed: {
...mapGetters(["userInfo"]),
},
props:['selProject'],
watch:{
},
data() {
return {
showPanelName:'overiew'
};
},
methods:{
onMenuToolBarSelect(menuIndex){
this.showPanelName=menuIndex;
}
},
mounted() {
this.$nextTick(() => {
});
},
};
</script>
<style scoped lang="scss">
</style>

73
src/views/xm/core/xmProduct/XmProductProjectForLink.vue

@ -0,0 +1,73 @@
<template>
<section>
<el-row v-if="selProject!=null">
<el-button icon="el-icon-zoom-out" @click="doDelXmProductProjectLink">
将项目<strong>{{selProject.name}}</strong>与产品<strong>{{xmProduct.productName}}</strong>脱钩
</el-button>
</el-row>
<el-row v-else>
<xm-project-for-link :xm-product="xmProduct"></xm-project-for-link>
</el-row>
</section>
</template>
<script>
import Vue from 'vue'
import util from '@/common/js/util';//
//import Sticky from '@/components/Sticky' // header
import config from "@/common/config"; //
//import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProject, } from '@/api/xm/core/xmProject';
import { mapGetters } from 'vuex'
import XmProjectForLink from '../xmProject/XmProjectForLink.vue';
import { delXmProductProjectLink, batchDelXmProductProjectLink } from '@/api/xm/core/xmProductProjectLink';
export default {
props:['xmProduct','selProject'],
computed: {
...mapGetters([
'userInfo','roles'
]),
},
data() {
return {
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
doDelXmProductProjectLink(){
var xmProduct=this.xmProduct;
var selProject=this.selProject;
this.$confirm('确认将产品【'+xmProduct.productName+'】与项目【'+selProject.projectName+'】进行脱钩吗?脱钩后,项目试图中将看不到该产品信息', '提示', {
type: 'warning'
}).then(()=>{
var params={productId:xmProduct.id,projectId:selProject.id}
delXmProductProjectLink(params).then(res=>{
var tips = res.data.tips;
if(tips.isOk){
this.$message({showClose: true, message: "脱钩成功", type: 'success' });
}
});
})
}
/**end 自定义函数请在上面加**/
},//end methods
components: {
XmProjectForLink,
//
},
mounted() {
}
}
</script>
<style scoped>
</style>

18
src/views/xm/core/xmProduct/XmProductSelect.vue

@ -102,12 +102,21 @@
export default { export default {
props:['isSelectProduct','selProject'],
props:['isSelectProduct','selProject','xmIteration'],
computed: { computed: {
...mapGetters([ ...mapGetters([
'userInfo','roles' 'userInfo','roles'
]) ])
}, },
watch:{
xmIteration(){
this.getXmProducts();
},
selProject(){
this.getXmProducts();
}
},
data() { data() {
const beginDate = new Date(); const beginDate = new Date();
const endDate = new Date(); const endDate = new Date();
@ -208,6 +217,11 @@
if(this.selProject){ if(this.selProject){
params.projectId=this.selProject.id params.projectId=this.selProject.id
} }
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
params.queryScope=this.filters.queryScope params.queryScope=this.filters.queryScope
if(this.filters.queryScope=='productId'){ if(this.filters.queryScope=='productId'){
if(!this.filters.id){ if(!this.filters.id){
@ -221,7 +235,7 @@
params.branchId=this.userInfo.branchId params.branchId=this.userInfo.branchId
params.projectId=null; params.projectId=null;
} }
if(!this.selProject && this.filters.queryScope!='productId'){
if(!this.selProject && !this.xmIteration && this.filters.queryScope!='productId'){
if(!this.dateRanger || this.dateRanger.length==0){ if(!this.dateRanger || this.dateRanger.length==0){
this.$message({showClose: true, message: "创建日期范围不能为空", type: 'error' }); this.$message({showClose: true, message: "创建日期范围不能为空", type: 'error' });
return; return;

123
src/views/xm/core/xmProductProjectLink/XmProductProjectLinkAdd.vue

@ -0,0 +1,123 @@
<template>
<section>
<el-row>
<!--新增界面 XmProductProjectLink 产品与项目的关联关系表一般由产品经理挂接项目到产品上-->
<el-form :model="addForm" label-width="120px" :rules="addFormRules" ref="addForm">
<el-form-item label="项目表中的主键" prop="projectId">
<el-input v-model="addForm.projectId" placeholder="项目表中的主键" ></el-input>
</el-form-item>
<el-form-item label="产品表中的主键" prop="productId">
<el-input v-model="addForm.productId" placeholder="产品表中的主键" ></el-input>
</el-form-item>
<el-form-item label="创建时间" prop="ctime">
<el-date-picker type="date" placeholder="选择日期" v-model="addForm.ctime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item label="创建人编号" prop="cuserid">
<el-input v-model="addForm.cuserid" placeholder="创建人编号" ></el-input>
</el-form-item>
<el-form-item label="创建人姓名" prop="cusername">
<el-input v-model="addForm.cusername" placeholder="创建人姓名" ></el-input>
</el-form-item>
<el-form-item label="关联状态1关联0取消关联" prop="linkStatus">
<el-input v-model="addForm.linkStatus" placeholder="关联状态1关联0取消关联" ></el-input>
</el-form-item>
<el-form-item>
<el-col :span="24" :offset="8">
<el-button @click.native="handleCancel">取消</el-button>
<el-button v-loading="load.add" type="primary" @click.native="addSubmit" :disabled="load.add==true">提交</el-button>
</el-col>
</el-form-item>
</el-form>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { addXmProductProjectLink } from '@/api/xm/core/xmProductProjectLink';
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo'
])
},
props:['xmProductProjectLink','visible'],
watch: {
'xmProductProjectLink':function( xmProductProjectLink ) {
this.addForm = xmProductProjectLink;
},
'visible':function(visible) {
if(visible==true){
//
}
}
},
data() {
return {
options:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
addFormRules: {
projectId: [
//{ required: true, message: '', trigger: 'blur' }
]
},
//
addForm: {
projectId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
}
/**begin 在下面加自定义属性,记得补上面的一个逗号**/
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
// @cancel="addFormVisible=false"
handleCancel:function(){
this.$refs['addForm'].resetFields();
this.$emit('cancel');
},
//XmProductProjectLink @submit="afterAddSubmit"
addSubmit: function () {
this.$refs.addForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.add=true
let params = Object.assign({}, this.addForm);
addXmProductProjectLink(params).then((res) => {
this.load.add=false
var tips=res.data.tips;
if(tips.isOk){
this.$refs['addForm'].resetFields();
this.$emit('submit');// @submit="afterAddSubmit"
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.add=false);
});
}
});
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
/**end 在上面加自定义方法**/
},//end method
components: {
// 'xm-product-project-link-edit':XmProductProjectLinkEdit
},
mounted() {
this.addForm=Object.assign(this.addForm, this.xmProductProjectLink);
/**在下面写其它函数***/
}//end mounted
}
</script>
<style scoped>
</style>

118
src/views/xm/core/xmProductProjectLink/XmProductProjectLinkEdit.vue

@ -0,0 +1,118 @@
<template>
<section>
<el-row>
<!--编辑界面 XmProductProjectLink 产品与项目的关联关系表一般由产品经理挂接项目到产品上-->
<el-form :model="editForm" label-width="120px" :rules="editFormRules" ref="editForm">
<el-form-item label="项目表中的主键" prop="projectId">
<el-input v-model="editForm.projectId" placeholder="项目表中的主键"></el-input>
</el-form-item>
<el-form-item label="产品表中的主键" prop="productId">
<el-input v-model="editForm.productId" placeholder="产品表中的主键"></el-input>
</el-form-item>
<el-form-item label="创建时间" prop="ctime">
<el-date-picker type="date" placeholder="选择日期" v-model="editForm.ctime" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item label="创建人编号" prop="cuserid">
<el-input v-model="editForm.cuserid" placeholder="创建人编号"></el-input>
</el-form-item>
<el-form-item label="创建人姓名" prop="cusername">
<el-input v-model="editForm.cusername" placeholder="创建人姓名"></el-input>
</el-form-item>
<el-form-item label="关联状态1关联0取消关联" prop="linkStatus">
<el-input v-model="editForm.linkStatus" placeholder="关联状态1关联0取消关联"></el-input>
</el-form-item>
<el-form-item>
<el-col :span="24" :offset="8">
<el-button @click.native="handleCancel">取消</el-button>
<el-button v-loading="load.edit" type="primary" @click.native="editSubmit" :disabled="load.edit==true">提交</el-button>
</el-col>
</el-form-item>
</el-form>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { editXmProductProjectLink } from '@/api/xm/core/xmProductProjectLink';
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo'
])
},
props:['xmProductProjectLink','visible'],
watch: {
'xmProductProjectLink':function( xmProductProjectLink ) {
this.editForm = xmProductProjectLink;
},
'visible':function(visible) {
if(visible==true){
//
}
}
},
data() {
return {
options:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
load:{ list: false, edit: false, del: false, add: false },//...
editFormRules: {
projectId: [
//{ required: true, message: '', trigger: 'blur' }
]
},
// XmProductProjectLink
editForm: {
projectId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
}
/**begin 在下面加自定义属性,记得补上面的一个逗号**/
/**end 在上面加自定义属性**/
}//end return
},//end data
methods: {
// @cancel="editFormVisible=false"
handleCancel:function(){
this.$refs['editForm'].resetFields();
this.$emit('cancel');
},
//XmProductProjectLink @submit="afterEditSubmit"
editSubmit: function () {
this.$refs.editForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.load.edit=true
let params = Object.assign({}, this.editForm);
editXmProductProjectLink(params).then((res) => {
this.load.edit=false
var tips=res.data.tips;
if(tips.isOk){
this.$refs['editForm'].resetFields();
this.$emit('submit');// @submit="afterEditSubmit"
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err =>this.load.edit=false);
});
}
});
},
/**begin 在下面加自定义方法,记得补上面的一个逗号**/
/**end 在上面加自定义方法**/
},//end method
components: {
// 'xm-product-project-link-edit':XmProductProjectLinkEdit
},
mounted() {
this.editForm=Object.assign(this.editForm, this.xmProductProjectLink);
}
}
</script>
<style scoped>
</style>

252
src/views/xm/core/xmProductProjectLink/XmProductProjectLinkMng.vue

@ -0,0 +1,252 @@
<template>
<section class="app-container">
<el-row>
<el-input v-model="filters.key" style="width: 20%;" placeholder="模糊查询">
<template slot="append">
<el-button v-loading="load.list" :disabled="load.list==true" @click="searchXmProductProjectLinks" icon="el-icon-search">查询</el-button>
</template>
</el-input>
<el-button type="primary" @click="showAdd" icon="el-icon-plus" circle> </el-button>
<el-button type="danger" v-loading="load.del" @click="batchDel" :disabled="this.sels.length===0 || load.del==true" icon="el-icon-delete" circle></el-button>
</el-row>
<el-row style="padding-top:10px;">
<!--列表 XmProductProjectLink 产品与项目的关联关系表一般由产品经理挂接项目到产品上-->
<el-table ref="xmProductProjectLink" :data="xmProductProjectLinks" :max-height="maxTableHeight" @sort-change="sortChange" highlight-current-row v-loading="load.list" border @selection-change="selsChange" @row-click="rowClick" style="width: 100%;">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column sortable type="index" width="55"></el-table-column>
<el-table-column prop="projectId" label="项目表中的主键" min-width="80" ></el-table-column>
<el-table-column prop="productId" label="产品表中的主键" min-width="80" ></el-table-column>
<el-table-column prop="ctime" label="创建时间" min-width="80" ></el-table-column>
<el-table-column prop="cuserid" label="创建人编号" min-width="80" ></el-table-column>
<el-table-column prop="cusername" label="创建人姓名" min-width="80" ></el-table-column>
<el-table-column prop="linkStatus" label="关联状态1关联0取消关联" min-width="80" ></el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template slot="header">
<el-button @click="showAdd" icon="el-icon-plus" circle> </el-button>
</template>
<template scope="scope">
<el-button type="primary" @click="showEdit( scope.row,scope.$index)" icon="el-icon-edit" circle></el-button>
<el-button type="danger" @click="handleDel(scope.row,scope.$index)" icon="el-icon-delete" circle></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10,20, 50, 100, 500]" :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;"></el-pagination>
<!--编辑 XmProductProjectLink 产品与项目的关联关系表一般由产品经理挂接项目到产品上界面-->
<el-dialog title="编辑产品与项目的关联关系表,一般由产品经理挂接项目到产品上" :visible.sync="editFormVisible" width="50%" append-to-body :close-on-click-modal="false">
<xm-product-project-link-edit :xm-product-project-link="editForm" :visible="editFormVisible" @cancel="editFormVisible=false" @submit="afterEditSubmit"></xm-product-project-link-edit>
</el-dialog>
<!--新增 XmProductProjectLink 产品与项目的关联关系表一般由产品经理挂接项目到产品上界面-->
<el-dialog title="新增产品与项目的关联关系表,一般由产品经理挂接项目到产品上" :visible.sync="addFormVisible" width="50%" append-to-body :close-on-click-modal="false">
<xm-product-project-link-add :xm-product-project-link="addForm" :visible="addFormVisible" @cancel="addFormVisible=false" @submit="afterAddSubmit"></xm-product-project-link-add>
</el-dialog>
</el-row>
</section>
</template>
<script>
import util from '@/common/js/util';//
import config from '@/common/config';//
import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProductProjectLink, delXmProductProjectLink, batchDelXmProductProjectLink } from '@/api/xm/core/xmProductProjectLink';
import XmProductProjectLinkAdd from './XmProductProjectLinkAdd';//
import XmProductProjectLinkEdit from './XmProductProjectLinkEdit';//
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'userInfo','workSpace'
])
},
data() {
return {
filters: {
key: ''
},
xmProductProjectLinks: [],//
pageInfo:{//
total:0,//0>0
pageSize:10,//
count:false,//
pageNum:1,//1
orderFields:[],// ['sex','student_id']
orderDirs:[]// asc,desc ['asc','desc']
},
load:{ list: false, edit: false, del: false, add: false },//...
sels: [],//
options:{
//sex:[],
},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
addFormVisible: false,//xmProductProjectLink
//xmProductProjectLink
addForm: {
projectId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
},
editFormVisible: false,//
//xmProductProjectLink
editForm: {
projectId:'',productId:'',ctime:'',cuserid:'',cusername:'',linkStatus:''
},
maxTableHeight:300,
}
},//end data
methods: {
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
this.getXmProductProjectLinks();
},
handleCurrentChange(pageNum) {
this.pageInfo.pageNum = pageNum;
this.getXmProductProjectLinks();
},
// obj.order=ascending/descending, asc/desc ; obj.prop=,
sortChange( obj ){
if(obj.order==null){
this.pageInfo.orderFields=[];
this.pageInfo.orderDirs=[];
}else{
var dir='asc';
if(obj.order=='ascending'){
dir='asc'
}else{
dir='desc';
}
this.pageInfo.orderFields=[util.toLine(obj.prop)];
this.pageInfo.orderDirs=[dir];
}
this.getXmProductProjectLinks();
},
searchXmProductProjectLinks(){
this.pageInfo.count=true;
this.getXmProductProjectLinks();
},
// XmProductProjectLink
getXmProductProjectLinks() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count:this.pageInfo.count
};
if(this.pageInfo.orderFields!=null && this.pageInfo.orderFields.length>0){
let orderBys=[];
for(var i=0;i<this.pageInfo.orderFields.length;i++){
orderBys.push(this.pageInfo.orderFields[i]+" "+this.pageInfo.orderDirs[i])
}
params.orderBy= orderBys.join(",")
}
if(this.filters.key){
params.key="%"+this.filters.key+"%"
}
this.load.list = true;
listXmProductProjectLink(params).then((res) => {
var tips=res.data.tips;
if(tips.isOk){
this.pageInfo.total = res.data.total;
this.pageInfo.count=false;
this.xmProductProjectLinks = res.data.data;
}else{
this.$message({ message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
// XmProductProjectLink
showEdit: function ( row,index ) {
this.editFormVisible = true;
this.editForm = Object.assign({}, row);
},
// XmProductProjectLink
showAdd: function () {
this.addFormVisible = true;
//this.addForm=Object.assign({}, this.editForm);
},
afterAddSubmit(){
this.addFormVisible=false;
this.pageInfo.count=true;
this.getXmProductProjectLinks();
},
afterEditSubmit(){
this.editFormVisible=false;
},
//xmProductProjectLink
selsChange: function (sels) {
this.sels = sels;
},
//xmProductProjectLink
handleDel: function (row,index) {
this.$confirm('确认删除该记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
let params = { projectId: row.projectId };
delXmProductProjectLink(params).then((res) => {
this.load.del=false;
var tips=res.data.tips;
if(tips.isOk){
this.pageInfo.count=true;
this.getXmProductProjectLinks();
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error' });
}).catch( err => this.load.del=false );
});
},
//xmProductProjectLink
batchDel: function () {
this.$confirm('确认删除选中记录吗?', '提示', {
type: 'warning'
}).then(() => {
this.load.del=true;
batchDelXmProductProjectLink(this.sels).then((res) => {
this.load.del=false;
var tips=res.data.tips;
if( tips.isOk ){
this.pageInfo.count=true;
this.getXmProductProjectLinks();
}
this.$message({ message: tips.msg, type: tips.isOk?'success':'error'});
}).catch( err => this.load.del=false );
});
},
rowClick: function(row, event, column){
this.$emit('row-click',row, event, column);// @row-click="rowClick"
},
/**begin 自定义函数请在下面加**/
/**end 自定义函数请在上面加**/
},//end methods
components: {
'xm-product-project-link-add':XmProductProjectLinkAdd,
'xm-product-project-link-edit':XmProductProjectLinkEdit,
},
mounted() {
this.$nextTick(() => {
this.getXmProductProjectLinks();
var clientRect=this.$refs.xmProductProjectLink.$el.getBoundingClientRect();
var subHeight=65/1000 * window.innerHeight;
this.maxTableHeight = window.innerHeight -clientRect.y - this.$refs.xmProductProjectLink.$el.offsetTop-subHeight;
});
/**
listOption([{categoryId:'all',itemCode:'sex'},{categoryId:'all',itemCode:'grade'}] ).then(res=>{
if(res.data.tips.isOk){
this.options=res.data.data
}
});
**/
}
}
</script>
<style scoped>
</style>

356
src/views/xm/core/xmProject/XmProjectForLink.vue

@ -0,0 +1,356 @@
<template>
<section>
<el-row>
<el-input v-model="filters.key" style="width:30%;" placeholder="请输入关键字进行查找项目">
<template slot="append">
<el-button @click="searchXmProjects" icon="el-icon-search"></el-button>
</template>
</el-input>
<el-button icon="el-icon-plus" @click="xmProjectListVisible=true" v-if="!xmIteration">
加入更多项目到产品中
</el-button>
</el-row>
<el-row class="page-main page-height-90">
<el-table ref="table" :height="tableHeight" stripe :data="xmProjects" highlight-current-row v-loading="load.list" style="width: 100%;">
<el-table-column type="index" label="序号" width="55" ></el-table-column>
<el-table-column prop="code" label="项目编号" min-width="80" ></el-table-column>
<el-table-column prop="name" label="标题名称" min-width="80" ></el-table-column>
<el-table-column label="操作" width="245" fixed="right">
<template slot-scope="scope">
<el-button-group>
<el-button v-if="!xmIteration" size="mini" type="primary" @click.stop="doDelXmProductProjectLink(scope.row)" >移出产品</el-button>
</el-button-group>
<!-- <el-button style="width:100%;" slot="reference" class="see-more" type="text" icon="el-icon-more"></el-button>
</el-popover> -->
</template>
</el-table-column>
</el-table>
<el-pagination layout="total, sizes, prev, pager, next" @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10,20, 50, 100, 500]" :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" style="float:right;"></el-pagination>
</el-row>
<el-drawer title="选择项目" :visible.sync="xmProjectListVisible" size="60%" append-to-body>
<xm-project-list @project-confirm="onXmProjectSelect"></xm-project-list>
</el-drawer>
</section>
</template>
<script>
import Vue from 'vue'
import util from '@/common/js/util';//
//import Sticky from '@/components/Sticky' // header
import config from "@/common/config"; //
//import { listOption } from '@/api/mdp/meta/itemOption';//
import { listXmProject, } from '@/api/xm/core/xmProject';
import { mapGetters } from 'vuex'
import { delXmProductProjectLink, addXmProductProjectLink,batchDelXmProductProjectLink } from '@/api/xm/core/xmProductProjectLink';
import XmProjectList from './XmProjectList.vue';
export default {
props:['xmProduct','xmIteration'],
computed: {
...mapGetters([
'userInfo','roles'
]),
},
watch:{
xmProduct:function(){
this.getXmProjects();
},
xmIteration:function(){
this.getXmProjects();
}
},
data() {
return {
filters: {
key: ''
},
xmProjects: [],//
pageInfo:{//
total:0,//0>0
pageSize:10,//
count:false,//
pageNum:1,//1
orderFields:['create_time'],// ['sex','student_id']
orderDirs:['desc']// asc,desc ['asc','desc']
},
load:{ list: false, edit: false, del: false, add: false },//...
sels: [],//
options:{},// params=[{categoryId:'0001',itemCode:'sex'}] {'sex':[{optionValue:'1',optionName:'',seqOrder:'1',fp:'',isDefault:'0'},{optionValue:'2',optionName:'',seqOrder:'2',fp:'',isDefault:'0'}]}
addFormVisible: false,//xmProject
//xmProject
addForm: {
id:'',code:'',name:'',xmType:'',startTime:'',endTime:'',urgent:'',priority:'',description:'',createUserid:'',createUsername:'',createTime:'',assess:'',assessRemarks:'',status:'',branchId:'',planTotalCost:'',bizProcInstId:'',bizFlowState:'',planNouserAt:'',planInnerUserAt:'',planOutUserAt:'',locked:'',baseTime:'',baseRemark:'',baselineId:'',planWorkload:'',totalReceivables:'',budgetMarginRate:'',contractAmt:'',planInnerUserPrice:'',budgetOutUserPrice:'',planOutUserCnt:'',planInnerUserCnt:'',planWorkingHours:''
},
editFormVisible: false,//
tableHeight:300,
//xmProject
editForm: {
id:'',code:'',name:'',xmType:'',startTime:'',endTime:'',urgent:'',priority:'',description:'',createUserid:'',createUsername:'',createTime:'',assess:'',assessRemarks:'',status:'',branchId:'',planTotalCost:'',bizProcInstId:'',bizFlowState:'',planNouserAt:'',planInnerUserAt:'',planOutUserAt:'',locked:'',baseTime:'',baseRemark:'',baselineId:'',planWorkload:'',totalReceivables:'',budgetMarginRate:'',contractAmt:'',planInnerUserPrice:'',budgetOutUserPrice:'',planOutUserCnt:'',planInnerUserCnt:'',planWorkingHours:''
},
xmProjectListVisible:false,
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
methods: {
handleSizeChange(pageSize) {
this.pageInfo.pageSize=pageSize;
this.getXmProjects();
},
handleCurrentChange(pageNum) {
this.pageInfo.pageNum = pageNum;
this.getXmProjects();
},
// obj.order=ascending/descending, asc/desc ; obj.prop=,
sortChange( obj ){
var dir='asc';
if(obj.order=='ascending'){
dir='asc'
}else{
dir='desc';
}
if(obj.prop=='xxx'){
this.pageInfo.orderFields=['xxx'];
this.pageInfo.orderDirs=[dir];
}
this.getXmProjects();
},
searchXmProjects(){
this.pageInfo.count=true;
this.getXmProjects();
},
// XmProject xm_project
getXmProjects() {
let params = {
pageSize: this.pageInfo.pageSize,
pageNum: this.pageInfo.pageNum,
total: this.pageInfo.total,
count:this.pageInfo.count,
};
if(this.xmProduct){
params.productId=this.xmProduct.id
}
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
if(this.filters.key){
params.key='%'+this.filters.key+'%'
}
this.load.list = true;
if(this.pageInfo.orderFields!=null && this.pageInfo.orderFields.length>0){
let orderBys=[];
for(var i=0;i<this.pageInfo.orderFields.length;i++){
orderBys.push(this.pageInfo.orderFields[i]+" "+this.pageInfo.orderDirs[i])
}
params.orderBy= orderBys.join(",")
}
params.branchId = this.userInfo.branchId;
listXmProject(params).then((res) => {
var tips=res.data.tips;
if(tips.isOk){
console.log(res.data);
this.pageInfo.total = res.data.total;
this.pageInfo.count=false;
this.xmProjects = res.data.data;
}else{
this.$message({showClose: true, message: tips.msg, type: 'error' });
}
this.load.list = false;
}).catch( err => this.load.list = false );
},
selectProject:function(row){
this.editForm=row
this.$emit('project-confirm',this.editForm);
},
/**end 自定义函数请在上面加**/
onXmProjectSelect:function(row){
var xmProject=row;
var xmProduct=this.xmProduct;
this.$confirm('确认将项目【'+xmProject.name+'】加入产品【'+xmProduct.productName+'】吗?', '提示', {
type: 'warning'
}).then(()=>{
addXmProductProjectLink({projectId:xmProject.id,productId:xmProduct.id}).then(res=>{
var tips =res.data.tips;
if(tips.isOk){
this.getXmProjects();
}
this.$message({showClose: true, message: tips.msg, type: tips.isOk?'success':'error'});
})
})
},
doDelXmProductProjectLink(row){
var xmProduct=this.xmProduct;
var selProject=row;
this.$confirm('确认将项目【'+selProject.projectName+'】从产品【'+xmProduct.productName+'】移出吗?移出后,项目试图中将看不到该产品信息', '提示', {
type: 'warning'
}).then(()=>{
var params={productId:xmProduct.id,projectId:selProject.id}
delXmProductProjectLink(params).then(res=>{
var tips = res.data.tips;
if(tips.isOk){
this.getXmProjects();
this.$message({showClose: true, message: "移出成功", type: 'success' });
}
});
})
}
/**end 自定义函数请在上面加**/
},//end methods
components: {
XmProjectList
//
},
mounted() {
this.$nextTick(() => {
var clientRect=this.$refs.table.$el.getBoundingClientRect();
var subHeight=70/1000 * window.innerHeight;
this.tableHeight = window.innerHeight -clientRect.y - this.$refs.table.$el.offsetTop-subHeight;
this.showInfo = false;
this.getXmProjects();
});
}
}
</script>
<style scoped>
* >>> .sub-navbar{
background: #fafbfc;
}
.changebtn{
float: right;
padding: 0 10px;
display: flex;
align-items: center;
line-height: 0;
height: 100%;
}
.changebtn > button{
padding: 0;
border: 0;
color: #333;
}
.changebtn >>> i::before{
font-size:20px;
}
.changebtn-active{
color: #409EFF !important;
}
.app-container{
padding: 10px;
}
.el-menu-demo{
border: 0 !important;
height: 50px;
background-color: #fafbfc;
}
.el-menu-demo>.el-menu-item,
.el-menu-demo>.el-submenu >>> .el-submenu__title{
height: 100%;
line-height: 50px;
color: #909399;
}
.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,
.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,
.el-menu--horizontal>.el-submenu .el-submenu__title:hover{
background-color: transparent;
}
.project-card{
font-size: 12px;
color: #999;
margin: 10px 12px;
}
.project-card:hover{
border-color: #00abfc;
}
.project-card >>> .el-card__body{
padding: 20px 15px 10px;
}
.project-name{
font-size: 16px;
font-weight: 700;
color: #333;
height: 24px;
}
.project-id{
margin-top: 4px;
height: 18px;
}
.project-info{
display: flex;
margin-top: 8px;
}
.project-info>div{
display: flex;
flex-direction: column;
}
.info-item{
width: 15%;
text-align: center;
}
.info-item >>> span{
display: block;
}
.item-total{
font-size: 18px;
color: #666;
}
.info-task{
padding-left: 20px;
width: 70%;
border-left: 1px solid #efefef;
}
.finish-task{
color: #00abfc !important;
}
.project-rate{
margin: 15px 0;
}
.project-rate>.el-progress{
display: flex;
align-items: center;
}
.project-rate >>> .el-progress-bar{
padding-right: 0;
margin-right: 0;
}
.project-rate >>> .el-progress__text{
margin-left: 5px;
}
.project-footer{
display: flex;
}
.project-footer>div{
width: 30%;
}
.project-footer>div:not(:first-child){
width: 70%;
}
.project-period{
text-align: right;
}
.see-more > i{
background:#000;
}
/* 超过宽度则用...代替 */
.truncate{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[v-cloak]{
display: none;
}
</style>

18
src/views/xm/core/xmProject/XmProjectInfo.vue

@ -141,9 +141,9 @@
</el-submenu> </el-submenu>
</el-menu> </el-menu>
<xm-project-overiew-complex v-if="infotype=='项目概览'" :sel-project="selProject"></xm-project-overiew-complex>
<xm-iteration-complex v-if="infotype=='迭代'" ref="xmIterationMng" :sel-project="selProject" ></xm-iteration-complex>
<xm-product-mng v-if="infotype=='产品'" ref="xmProductMng" :sel-project="selProject" ></xm-product-mng>
<xm-project-overview-complex v-if="infotype=='项目概览'" :sel-project="selProject"></xm-project-overview-complex>
<xm-iteration-for-project-complex v-if="infotype=='迭代'" ref="xmIterationMng" :sel-project="selProject"></xm-iteration-for-project-complex>
<xm-product-for-project-complex v-if="infotype=='产品'" ref="xmProductComplex" :sel-project="selProject"></xm-product-for-project-complex>
<xm-menu-mng v-if="infotype=='用户故事'" :sel-project="selProject"></xm-menu-mng> <xm-menu-mng v-if="infotype=='用户故事'" :sel-project="selProject"></xm-menu-mng>
<xm-task-mng v-if="infotype=='任务'" ref="xmTaskMng" :sel-project="selProject" ></xm-task-mng> <xm-task-mng v-if="infotype=='任务'" ref="xmTaskMng" :sel-project="selProject" ></xm-task-mng>
<xm-question v-if="infotype=='缺陷'" :qtype="'bug'" :sel-project='selProject' ref="xmQuestion"></xm-question> <xm-question v-if="infotype=='缺陷'" :qtype="'bug'" :sel-project='selProject' ref="xmQuestion"></xm-question>
@ -194,9 +194,9 @@
import xmMenuWithPlan from '../xmMenu/XmMenuWithPlan'; import xmMenuWithPlan from '../xmMenu/XmMenuWithPlan';
import xmProjectStateMng from '../xmProjectState/XmProjectStateMng'; import xmProjectStateMng from '../xmProjectState/XmProjectStateMng';
import xmTestCaseExecMng from '../xmTestCaseExec/XmTestCaseExecMng'; import xmTestCaseExecMng from '../xmTestCaseExec/XmTestCaseExecMng';
import xmProductMng from '../xmProduct/XmProductMng';
import XmIterationComplex from '../xmIteration/XmIterationComplex.vue';
import XmProjectOveriewComplex from './XmProjectOveriewComplex.vue';
import XmIterationForProjectComplex from '../xmIteration/XmIterationForProjectComplex.vue';
import XmProjectOverviewComplex from './XmProjectOverviewComplex.vue';
import XmProductForProjectComplex from '../xmProduct/XmProductForProjectComplex.vue';
export default { export default {
@ -416,9 +416,9 @@
xmProjectStateMng, xmProjectStateMng,
xmTestCaseExecMng, xmTestCaseExecMng,
xmProjectGroupSelect, xmProjectGroupSelect,
XmIterationComplex,
xmProductMng,
XmProjectOveriewComplex,
XmIterationForProjectComplex,
XmProjectOverviewComplex,
XmProductForProjectComplex,
// //
}, },
mounted() { mounted() {

src/views/xm/core/xmProject/XmProjectOveriewComplex.vue → src/views/xm/core/xmProject/XmProjectOverviewComplex.vue

9
src/views/xm/core/xmProjectPhase/XmProjectPhaseMng.vue

@ -294,10 +294,9 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
} }
}, },
props:['selProject'],
props:['selProject','xmIteration'],
watch:{ watch:{
selProject:function(selProject,old){ selProject:function(selProject,old){
console.log('this.selProject==', selProject);
if(!selProject){ if(!selProject){
this.xmProjectPhases=[] this.xmProjectPhases=[]
@ -307,6 +306,9 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
this.searchXmProjectPhases(); this.searchXmProjectPhases();
} }
} }
},
xmIteration(){
this.searchXmProjectPhases()
} }
}, },
data() { data() {
@ -419,6 +421,9 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
params.projectId=this.selProject.id params.projectId=this.selProject.id
} }
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
this.load.list = true; this.load.list = true;
listXmProjectPhase(params).then((res) => { listXmProjectPhase(params).then((res) => {
var tips=res.data.tips; var tips=res.data.tips;

10
src/views/xm/core/xmProjectPhase/XmProjectPhaseSelect.vue

@ -49,10 +49,9 @@
}, },
}, },
props:['selProject'],
props:['selProject','xmIteration'],
watch:{ watch:{
selProject:function(selProject,old){ selProject:function(selProject,old){
console.log('this.selProject==', selProject);
if(!selProject){ if(!selProject){
this.xmProjectPhases=[] this.xmProjectPhases=[]
@ -62,6 +61,9 @@
this.searchXmProjectPhases(); this.searchXmProjectPhases();
} }
} }
},
xmIteration(){
this.searchXmProjectPhases();
} }
}, },
data() { data() {
@ -172,6 +174,10 @@
if(this.selProject!=null && this.selProject!=undefined){ if(this.selProject!=null && this.selProject!=undefined){
params.projectId=this.selProject.id params.projectId=this.selProject.id
}
if(this.xmIteration!=null && this.xmIteration!=undefined){
params.iterationId=this.xmIteration.id
} }
this.load.list = true; this.load.list = true;
listXmProjectPhase(params).then((res) => { listXmProjectPhase(params).then((res) => {

38
src/views/xm/core/xmQuestion/XmQuestionMng.vue

@ -153,8 +153,8 @@
</el-tooltip> </el-tooltip>
<el-button icon="el-icon-upload2" v-if="!scope.row.flowState" type="text" @click="handleCommand({type:'sendToProcessApprova',data:scope.row,bizKey:'xm_question_up_approva'})">{{qtype=='risk'?'升级':'升级'}}</el-button> <el-button icon="el-icon-upload2" v-if="!scope.row.flowState" type="text" @click="handleCommand({type:'sendToProcessApprova',data:scope.row,bizKey:'xm_question_up_approva'})">{{qtype=='risk'?'升级':'升级'}}</el-button>
</span> </span>
<el-badge :value="getBadge(scope.row)">
<el-link type="primary" @click="showEdit(scope.row)">{{scope.row.name}}</el-link>
<el-badge :value="getBadge(scope.row)" type="warning">
<el-link type="primary" @click="showEdit(scope.row)">{{scope.row.name}}</el-link>
</el-badge> </el-badge>
</span> </span>
</div> </div>
@ -213,18 +213,20 @@
'userInfo','roles' 'userInfo','roles'
]), ]),
}, },
props: ["selProject",'qtype','xmTestCaseExec','xmTestCase','visible'],
props: ["selProject",'qtype','xmTestCaseExec','xmTestCase','xmIteration','xmProduct'],
watch:{ watch:{
selProject:function(selProject){ selProject:function(selProject){
this.filters.selProject=this.selProject this.filters.selProject=this.selProject
//this.getXmQuestions(); //this.getXmQuestions();
}, },
visible(visible){
if(visible==true){
this.getXmQuestions();
}
qtype:function(){
this.getXmQuestions()
}, },
qtype(){
xmIteration:function(){
this.getXmQuestions()
},
xmProduct:function(){
this.filters.product=this.xmProduct
this.getXmQuestions() this.getXmQuestions()
} }
}, },
@ -449,6 +451,9 @@
if(this.xmTestCase){ if(this.xmTestCase){
params.caseId=this.xmTestCase.id params.caseId=this.xmTestCase.id
} }
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
if(this.filters.key){ if(this.filters.key){
params.key='%'+this.filters.key+'%' params.key='%'+this.filters.key+'%'
@ -874,7 +879,15 @@
} }
if(row.handlerUsername){ if(row.handlerUsername){
if(row.lremark){ if(row.lremark){
msg='已指派给'+row.handlerUsername+','+row.lremark
var lremark=row.lremark;
lremark=lremark.replace(/<\w?>/g,"");
lremark=lremark.replace(/<\/\w?>/g,"");
if(lremark.length<=10){
msg='已指派给'+row.handlerUsername+','+lremark
}else{
msg='已指派给'+row.handlerUsername+','+lremark.substr(0,10)+"..."
}
}else{ }else{
msg='已指派给'+row.handlerUsername; msg='已指派给'+row.handlerUsername;
} }
@ -895,6 +908,9 @@
if(this.selProject){ if(this.selProject){
this.filters.selProject=this.selProject this.filters.selProject=this.selProject
} }
if(this.xmProduct){
this.filters.product=this.xmProduct
}
this.filters.handlerUserid=this.userInfo.userid; this.filters.handlerUserid=this.userInfo.userid;
this.filters.handlerUsername=this.userInfo.username; this.filters.handlerUsername=this.userInfo.username;
this.$nextTick(() => { this.$nextTick(() => {
@ -932,4 +948,8 @@
margin-top: 7px; margin-top: 7px;
padding-bottom: 10px; padding-bottom: 10px;
} }
.badge-item {
margin-top: 10px;
margin-right: 40px;
}
</style> </style>

14
src/views/xm/core/xmTask/XmTaskMng.vue

@ -2,7 +2,7 @@
<section class="padding"> <section class="padding">
<el-row v-show="batchEditVisible==false"> <el-row v-show="batchEditVisible==false">
<el-col v-if="isTaskCenter!='1' && currentProject " :span="4" > <el-col v-if="isTaskCenter!='1' && currentProject " :span="4" >
<xm-project-phase-mng :sel-project="currentProject" :simple="true" @row-click="projectPhaseRowClick" @clear-select="clearSelectPhase"></xm-project-phase-mng>
<xm-project-phase-mng :sel-project="currentProject" :xm-iteration="xmIteration" :simple="true" @row-click="projectPhaseRowClick" @clear-select="clearSelectPhase"></xm-project-phase-mng>
</el-col> </el-col>
<el-col :span="isTaskCenter!='1' && currentProject?20:24" class="padding-left"> <el-col :span="isTaskCenter!='1' && currentProject?20:24" class="padding-left">
<el-row> <el-row>
@ -56,7 +56,7 @@
<el-button v-if=" isTaskCenter!='1' && isMy!='1'" @click="showAdd" icon="el-icon-plus">直接创建</el-button> <el-button v-if=" isTaskCenter!='1' && isMy!='1'" @click="showAdd" icon="el-icon-plus">直接创建</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-button slot="reference" v-if=" isTaskCenter!='1' && isMy!='1'" type="primary" icon="el-icon-plus" circle></el-button>
<el-button slot="reference" v-if=" isTaskCenter!='1' && isMy!='1' && !xmProduct && !xmIteration" type="primary" icon="el-icon-plus" circle></el-button>
</el-popover> </el-popover>
<el-popover <el-popover
@ -518,7 +518,7 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
} }
}, },
props: ["selProject","isTaskCenter","isMy",'menuId','menuName','xmProduct'],
props: ["selProject","isTaskCenter","isMy",'menuId','menuName','xmProduct',"xmIteration"],
watch: { watch: {
"selProject": function(oval,val) { "selProject": function(oval,val) {
this.filters.selProject=this.selProject; this.filters.selProject=this.selProject;
@ -534,6 +534,10 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
}, },
'xmProduct':function(){ 'xmProduct':function(){
this.filters.product=this.xmProduct; this.filters.product=this.xmProduct;
this.getXmTasks();
},
xmIteration:function(){
this.getXmTasks();
} }
}, },
data() { data() {
@ -765,7 +769,9 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
if(this.filters.product){ if(this.filters.product){
params.productId=this.filters.product.id params.productId=this.filters.product.id
} }
if(this.xmIteration){
params.iterationId=this.xmIteration.id
}
params.createTimeStart=this.dateRanger[0]+" 00:00:00" params.createTimeStart=this.dateRanger[0]+" 00:00:00"
params.createTimeEnd=this.dateRanger[1]+" 23:59:59" params.createTimeEnd=this.dateRanger[1]+" 23:59:59"
getTask(params).then((res) => { getTask(params).then((res) => {

Loading…
Cancel
Save