Browse Source

需求看板

master
陈裕财 3 years ago
parent
commit
bdbbe4c2b8
  1. 16
      src/api/xm/core/xmMenu.js
  2. 700
      src/views/xm/core/xmMenu/XmMenuAgileKanbanUser.vue
  3. 19
      src/views/xm/core/xmMenu/XmMenuMng.vue
  4. 716
      src/views/xm/core/xmTask/XmTaskAgileKanbanUser.vue
  5. 21
      src/views/xm/core/xmTask/XmTaskMng.vue

16
src/api/xm/core/xmMenu.js

@ -1,5 +1,5 @@
import axios from '@/utils/request'
import axios from '@/utils/request'
import { getDicts,initSimpleDicts,initComplexDicts } from '@/api/mdp/meta/item';//字典表
import config from '@/common/config'
let base = config.getCoreBasePath();
@ -53,3 +53,15 @@ export const getXmMenuAttDist = params => { return axios.get(`${base}/xm/core/xm
export const getXmMenuAgeDist = params => { return axios.get(`${base}/xm/core/xmMenu/getXmMenuAgeDist`, { params: params }); };
export const getXmMenuSort = params => { return axios.get(`${base}/xm/core/xmMenu/getXmMenuSort`, { params: params }); };
/**-------------------------前端mng|add|edit界面公共函数---------------请写在下面----------------------------------------------- */
//初始化页面上的字典
export const initDicts = (that) => {
var itemCodes=['menuStatus','demandSource','demandLvl','demandType','priority','dclass'];//在此添加要加载的字典 如['sex','grade','lvl']
if(itemCodes.length>0){
initSimpleDicts('all',itemCodes).then(res=>{
Object.assign(that.dicts,res.data.data)
});
}
};

700
src/views/xm/core/xmMenu/XmMenuAgileKanbanUser.vue

@ -0,0 +1,700 @@
<template>
<section class="menu-box">
<el-table
ref="table"
:data="usersCpd"
header-cell-class-name="head-row"
border
:height="tableHeight"
style="width: 100%"
>
<el-table-column
:label="'负责人 (' + users.length + ')'"
class-name="menu-name"
width="200"
>
<template slot-scope="scope">
<div class="menu">
<div class="icon" style="background-color: rgb(79, 140, 255);">
<i class="el-icon-document"></i>
</div>
<el-link type="primary" @click="showMenuEdit(scope.row)">{{
scope.row.mmUsername
}}</el-link>
</div>
</template>
</el-table-column>
<template v-for="(type, tt) in statusCpd" style="min-width:200px;">
<el-table-column
:label="type.label + '(' + type.number + ')'"
:key="tt"
width="250"
>
<template slot-scope="scope">
<el-row class="my-cell-bar">
<el-button
icon="el-icon-plus"
@click="showAddMenu(scope.row, type)"
type="primary"
plain
>故事</el-button
>
</el-row>
<draggable
:name="scope.row.mmUserid"
:sort="false"
@start="onStart"
@end="onEnd"
@move="onMove"
:options="{ group: scope.row.mmUserid }"
class="draggable"
animation="300"
scroll
scrollSensitivity="80"
scrollSpeed="80"
>
<transition-group
class="transition-group"
:data-mm-userid="scope.row.mmUserid"
:data-menu-state="type.status"
>
<!-- <template v-if="drag.mmUserid && drag.mmUserid === scope.row.mmUserid && drag.status !== type.status">
<div class="drag-to-box">{{type.label}}</div>
</template> -->
<template v-if="menus && menusCpd[scope.row.mmUserid][tt].length">
<div @click.stop="showMenuEdit(menu)"
:data-mm-userid="scope.row.mmUserid"
:data-menu-id="menu.menuId"
:data-menu-state="menu.status"
class="menu"
v-for="(menu, t) in menus[scope.row.mmUserid][tt]"
:key="menu.menuId + t"
>
<el-row>
<el-tag
title="优先级"
v-for="(item, index) in formatDictsWithClass(
dicts,
'priority',
menu.level
)"
:key="menu.menuId + index"
:type="item.className"
>{{ item.menuName }}</el-tag
>
<el-tag
title="进度"
style="border-radius: 30px"
:type="menu.rate >= 100 ? 'success' : 'warning'"
>
{{ (menu.rate != null ? menu.rate : 0) + "%" }}
</el-tag>
<span class="my-cell-bar"><el-button size="mini" type="danger" icon="el-icon-delete" plain @click.stop="handleDel(menu,tt)"></el-button></span>
</el-row>
<el-row>
<span title="负责人" class="label-font-color">
{{
menu.mmUsername
? menu.mmUsername
: "未设置负责人"
}}
</span>
</el-row>
<el-row>
<div class="title">{{ menu.menuName }}</div>
</el-row>
</div>
</template>
</transition-group>
</draggable>
</template>
</el-table-column>
</template>
</el-table>
<el-dialog
title="编辑故事"
:visible.sync="editFormVisible"
:with-header="false"
fullscreen
append-to-body
:close-on-click-modal="false"
>
<xm-menu-edit
:xm-project="
editForm && editForm.productId ? { id: editForm.productId } : null
"
:xm-menu="editForm"
:visible="editFormVisible"
@cancel="editFormVisible = false"
@after-add-submit="afterExecEditSubmit"
@after-edit-submit="afterExecEditSubmit"
@submit="afterEditSubmit"
></xm-menu-edit>
</el-dialog>
<el-dialog
title="新增故事"
:visible.sync="addFormVisible"
append-to-body
modal-append-to-body
>
<el-form :model="addForm" :rules="addFormRules" ref="addForm">
<el-form-item label="上级计划" prop="parentMenuname">
{{ addForm.parentMenuname ? addForm.parentMenuname : "无上级" }}
<el-button
@click="selectParentMenuVisible = true"
title="选择上级计划"
type="text"
icon="el-icon-upload2"
>
选择上级计划
</el-button>
</el-form-item>
<el-form-item label="故事名称" prop="name">
<template slot="label">
<div class="icon" style="background-color: #1cc7ea">
<i class="el-icon-s-operation"></i>
</div>
故事名称
</template>
<el-input v-model="addForm.menuName" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">关闭</el-button>
<el-button type="primary" @click="addXmMenu"> </el-button>
</div>
</el-dialog>
<el-dialog append-to-body title="需求明细" :visible.sync="menuDetailVisible" width="80%" top="20px" :close-on-click-modal="false">
<xm-menu-edit :visible="menuDetailVisible" op-type="edit" :xm-menu="editForm" ></xm-menu-edit>
</el-dialog>
</section>
</template>
<script>
import util from "@/common/js/util"; //
import draggable from "vuedraggable";
import { initDicts, editXmMenuSomeFields, addMenu,delXmMenu } from "@/api/xm/core/xmMenu";
import XmMenuEdit from "./XmMenuEdit"; //
import XmEpicFeaturesSelect from "../xmMenu/XmEpicFeaturesSelect.vue";
import { mapGetters } from "vuex";
export default {
name: "XmMenuAgileKanban",
props: ["xmMenus", "tableHeight", "xmProduct"],
data() {
return {
load:{add:false,edit:false,list:false,del:false},
editForm: {
id: "",
name: "",
parentMenuid: "",
parentMenuname: "",
productId: "",
projectName: "",
level: "",
sortLevel: "",
mmUserid: "",
mmUsername: "",
preMenuid: "",
preMenuname: "",
startTime: "",
endTime: "",
milestone: "",
description: "",
remarks: "",
createUserid: "",
createUsername: "",
createTime: "",
rate: 0,
budgetAt: 0,
budgetWorkload: 0,
actAt: 0,
actWorkload: 0,
status: "0",
menuType: "4",
menuClass: "",
toMenuCenter: "0",
actStartTime: "",
actEndTime: "",
bizProcInstId: "",
bizFlowState: "",
phaseId: "",
phaseName: "",
menuSkillNames: "",
exeUsernames: "",
menuSkillIds: "",
exeUserids: "",
menuOut: "0",
planType: "w2",
settleSchemel: "1",
menuId: "",
menuName: "",
productId: "",
cbranchId: "",
cdeptid: "",
tagIds: "",
tagNames: "",
ntype: "",
childrenCnt: "",
ltime: "",
pidPaths: "",
lvl: "",
isTpl: "",
keyPath: "",
uniInnerPrice: 80,
uniOutPrice: 100,
calcType: "",
ptype: "",
wtype: "",
bctrl: "",
initWorkload: "",
shareFee: "",
oshare: "",
crowd: "",
browseUsers: "",
execUsers: "",
cityId: "",
cityName: "",
regionType: "",
browseTimes: "",
capaLvls: "",
tranMode: "",
supRequires: "",
hot: "0",
top: "0",
urgent: "0",
crmSup: "0",
bidStep: "0",
interestLvls: "",
filePaths: "",
estate: "0",
efunds: 0,
etoPlatTime: "",
etoDevTime: "",
ebackTime: "",
topStime: "",
topEtime: "",
hotStime: "",
hotEtime: "",
urgentStime: "",
urgentEtime: "",
},
addForm: {
id: "",
name: "",
parentMenuid: "",
parentMenuname: "",
productId: "",
projectName: "",
level: "",
sortLevel: "",
mmUserid: "",
mmUsername: "",
preMenuid: "",
preMenuname: "",
startTime: "",
endTime: "",
milestone: "",
description: "",
remarks: "",
createUserid: "",
createUsername: "",
createTime: "",
rate: 0,
budgetAt: 0,
budgetWorkload: 0,
actAt: 0,
actWorkload: 0,
status: "0",
menuType: "4",
menuClass: "",
toMenuCenter: "0",
actStartTime: "",
actEndTime: "",
bizProcInstId: "",
bizFlowState: "",
phaseId: "",
phaseName: "",
menuSkillNames: "",
exeUsernames: "",
menuSkillIds: "",
exeUserids: "",
menuOut: "0",
planType: "w2",
settleSchemel: "1",
menuId: "",
menuName: "",
productId: "",
cbranchId: "",
cdeptid: "",
tagIds: "",
tagNames: "",
ntype: "",
childrenCnt: "",
ltime: "",
pidPaths: "",
lvl: "",
isTpl: "",
keyPath: "",
uniInnerPrice: 80,
uniOutPrice: 100,
calcType: "",
ptype: "",
wtype: "",
bctrl: "",
initWorkload: "",
shareFee: "",
oshare: "",
crowd: "",
browseUsers: "",
execUsers: "",
cityId: "",
cityName: "",
regionType: "",
browseTimes: "",
capaLvls: "",
tranMode: "",
supRequires: "",
hot: "0",
top: "0",
urgent: "0",
crmSup: "0",
bidStep: "0",
interestLvls: "",
filePaths: "",
estate: "0",
efunds: 0,
etoPlatTime: "",
etoDevTime: "",
ebackTime: "",
topStime: "",
topEtime: "",
hotStime: "",
hotEtime: "",
urgentStime: "",
urgentEtime: "",
},
addFormRules: {
name: [
{ required: true, message: "故事名称不能为空", trigger: "change" },
{
min: 2,
max: 150,
message: "长度在 2 到 150 个字符",
trigger: "change",
}, //
],
},
editFormVisible: false,
addFormVisible: false,
selectParentMenuVisible: false,
menuDetailVisible:false,
status: [
{ label: "打开", status: "0", number: 0 },
{ label: "进行中", status: "1", number: 0 },
{ label: "已完工", status: "2", number: 0 },
{ label: "已关闭", status: "3", number: 0 },
],
statusInit: [],
dicts: {
priority: [],
menuType: [],
planType: [],
xmMenuSettleSchemel: [],
status: [],
xm_plan_lvl: [],
},
menus: {},
users: [],
drag: {
menuId: "",
state: "",
},
};
},
components: { draggable, XmMenuEdit, XmEpicFeaturesSelect,XmMenuEdit },
watch: {
xmMenus() {
this.initData();
},
},
computed: {
...mapGetters(["userInfo", "roles"]),
usersCpd() {
return this.users;
},
menusCpd() {
return this.menus;
},
statusCpd() {
return this.status;
},
},
methods: {
...util,
onMove(e) {
console.log("onMove--e==", e);
let targetEl = { ...e.dragged.dataset };
let toEl = { ...e.to.dataset };
if (
targetEl.mmUserid === toEl.mmUserid &&
targetEl.status != toEl.status
) {
console.log("onMove--true");
return true;
}
console.log("onMove--false");
return false;
},
onStart(e) {
console.log("onStart--e==", e);
let targetEl = { ...e.item.dataset };
this.drag = { ...targetEl };
console.log("onStart--targetEl==", targetEl);
},
onEnd(e) {
console.log("onEnd--e==", e);
this.drag = {};
// targetEl; toEl.
let targetEl = { ...e.item.dataset };
let toEl = { ...e.to.dataset };
if (
targetEl.mmUserid === toEl.mmUserid &&
targetEl.status != toEl.status
) {
let menu = this.xmMenus.find((d) => d.menuId === targetEl.menuId);
let menuIndex = this.xmMenus.findIndex((d) => d.menuId === targetEl.menuId);
//const params = { ...menu, status: toEl.status };
const params = { ids: [menu.menuId], status: toEl.status };
editXmMenuSomeFields(params).then((res) => {
//this.$emit('submit');
var tips = res.data.tips;
if (tips.isOk) {
var statusIndex = this.getMenuStateIndex(menu.status);
this.status[statusIndex].number =
this.status[statusIndex].number - 1;
var toMenuStateIndex = this.getMenuStateIndex(params.status);
this.status[toMenuStateIndex].number =
this.status[toMenuStateIndex].number + 1;
menu.status = params.status;
this.$set(this.xmMenus, menuIndex, menu);
} else {
this.$notify({
position: "bottom-left",
showClose: true,
message: tips.msg,
type: "error",
});
}
return res.data.tips.isOk;
});
} else {
return false;
}
},
initData() {
var xmMenus = this.xmMenus;
this.status = JSON.parse(JSON.stringify(this.statusInit));
let users = [],
userids = {},
menus = {};
xmMenus.forEach((d, i) => {
if (!d.mmUserid) {
d.mmUserid = "noExecutorUserid";
d.mmUsername = "未设置负责人";
}
if (!users.length || !userids[d.mmUserid]) {
users.push(d);
userids[d.mmUserid] = true;
}
if (!menus[d.mmUserid]) {
menus[d.mmUserid] = [[], [], [], [], [], []];
}
var statusIndex = this.getMenuStateIndex(d.status);
menus[d.mmUserid][statusIndex].push(d);
this.status[statusIndex].number += 1;
});
this.menus = menus;
users.sort((v1,v2)=>{
return v1.mmUserid<v2.mmUserid
})
this.users = users;
},
showMenuEdit(menu) {
this.editForm = menu;
this.editFormVisible = true;
},
afterEditSubmit(menu) {
let menuIndex = this.xmMenus.findIndex((d) => d.menuId === menu.menuId);
this.$set(this.xmMenus, menuIndex, menu);
},
getMenuStateIndex(status) {
return this.status.findIndex((i) => i.status == status);
},
afterExecEditSubmit() {},
showMenuEdit(menu){
this.editForm=menu;
if(menu.mmUserid=='noExecutorUserid'||!menu.mmUserid){
this.$notify({
position: "bottom-left",
showClose: true,
message: '没有关联故事故事',
type: "error",
});
return;
}
this.menuDetailVisible=true;
},
addXmMenu() {
this.load.add=true;
this.$refs.addForm.validate().then((valid) => {
var menu = { ...this.addForm };
addMenu(menu)
.then((res) => {
this.load.add = false;
var tips = res.data.tips;
if (tips.isOk) {
//this.$emit("submit", res.data.data); // @submit="afterAddSubmit"
this.xmMenus.push(res.data.data);
}
this.$notify({
position: "bottom-left",
showClose: true,
message: tips.msg,
type: tips.isOk ? "success" : "error",
});
})
.catch((err) => (this.load.add = false));
});
},
onSelectedParentMenu(menu) {
this.addForm.parentMenuid = menu.menuId;
this.addForm.parentMenuname = menu.menuName;
this.selectParentMenuVisible = false;
},
showAddMenu(menu, type) {
this.addForm.menuId = menu.menuId;
this.addForm.menuName = menu.menuName;
this.addForm.productId = menu.productId;
this.addForm.status = type.status;
this.addForm.productId = menu.productId;
this.addForm.parentMenuid = menu.parentMenuid;
this.addForm.parentMenuname = menu.parentMenuname;
this.addForm.priority = menu.priority;
this.addForm.sortLevel = menu.sortLevel;
this.addForm.verNum = menu.verNum;
this.addForm.pverNum = menu.pverNum;
this.addForm.createUserid = this.userInfo.userid;
this.addForm.createUsername = this.userInfo.username;
this.addForm.qtype = "1";
this.addForm.ntype = "0";
this.addForm.ptype = "0";
this.addFormVisible = true;
},
//xmMenu
handleDel: function (row, index) {
this.$confirm("确认删除该记录吗?", "提示", {
type: "warning",
}).then(() => {
this.load.del = true;
let params = Object.assign({}, row);
delXmMenu(params)
.then((res) => {
this.load.del = false;
var tips = res.data.tips;
if (tips.isOk) {
var index=this.xmMenus.findIndex(k=>k.menuId==row.menuId)
this.xmMenus.splice(index,1)
}
this.$notify({
showClose: true,
message: tips.msg,
type: tips.isOk ? "success" : "error",
});
})
.catch((err) => (this.load.del = false));
});
},
},
mounted() {
initDicts(this);
this.statusInit = JSON.parse(JSON.stringify(this.status));
this.initData();
},
};
</script>
<style lang='scss' scoped>
.menu-box {
height: 100%;
width: 100%;
overflow: hidden;
}
.draggable {
display: flex;
flex-wrap: wrap;
min-height: 100px;
width: 100%;
}
.el-table {
/deep/ .el-table__row {
background: #f6f6f6;
.menu-name {
background: #fff !important;
}
td {
height: 100%;
vertical-align: top;
}
}
}
.transition-group {
width: 100%;
cursor: pointer;
.menu {
min-height: 100px;
background: #fff;
margin: 0px 0px 10px 0px;
padding: 5px;
}
}
.my-cell-bar {
visibility: hidden;
float: right;
}
.el-table__row td:hover {
cursor: pointer;
.my-cell-bar {
visibility: visible;
.u-btn {
float: right;
}
}
.my-cell-text {
display: none;
}
}
.title {
height: 40px;
overflow: hidden; //
text-overflow: ellipsis; //
display: -webkit-box; //
//
-webkit-line-clamp: 2; //
-webkit-box-orient: vertical; //
//
}
</style>

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

@ -38,6 +38,15 @@
<el-button type="danger" @click="batchDel" icon="el-icon-delete" title="删除">删除</el-button>
</el-row>
<el-row>
<font class="more-label-font">显示方式:</font
>
<span class="more-label-font">
<el-radio v-model="displayType" label="agileUser">故事看板</el-radio>
<el-radio v-model="displayType" label="table">列表</el-radio>
</span>
</el-row>
<el-divider></el-divider>
<el-row>
<font class="more-label-font">
@ -213,8 +222,8 @@
<xm-table-config class="hidden-lg-and-down" ref="tableConfig" style="display:inline;" :table="$refs.table"></xm-table-config>
</span>
</el-row>
<el-row>
</el-row>
<el-row v-if="displayType=='table'">
<el-table element-loading-text="努力加载中" element-loading-spinner="el-icon-loading" :cell-style="cellStyleCalc" :expand-row-keys="expandRowKeysCpd" :header-cell-style="cellStyleCalc" :row-style="{height:'60px'}" stripe fit border ref="table" :height="maxTableHeight" :data="xmMenusTreeData" current-row-key="menuId" row-key="menuId" @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>
@ -344,6 +353,9 @@
</el-row>
<el-row v-else-if="displayType=='agileUser'">
<xm-menu-agile-kanban-user :xm-menus="xmMenus" :xm-product="xmProduct" ref="table" :table-height="maxTableHeight"></xm-menu-agile-kanban-user>
</el-row>
<!--编辑 XmMenu xm_project_menu界面-->
<el-dialog title="编辑故事" :visible.sync="editFormVisible" :with-header="false" width="90%" top="20px" append-to-body :close-on-click-modal="false" >
<xm-menu-edit :xm-menu="editForm" :sel-project="selProject" :visible="editFormVisible" @cancel="editFormVisible=false" @submit="afterEditSubmit" @add-sub-menu="onAddSubMenu" @edit-fields="onEditSomeFields"></xm-menu-edit>
@ -422,6 +434,7 @@
import UsersSelect from "@/views/mdp/sys/user/UsersSelect";
import XmEpicFeaturesSelect from "../xmMenu/XmEpicFeaturesSelect";
import XmMenuAgileKanbanUser from "../xmMenu/XmMenuAgileKanbanUser";
import TagDialog from "@/views/mdp/arc/tag/TagDialog";
import {sn} from '@/common/js/sequence'
@ -547,6 +560,7 @@
/**begin 自定义属性请在下面加 请加备注**/
expandRowKeysCpd:[],
moreVisible:false,
displayType:'table'
/**end 自定义属性请在上面加 请加备注**/
}
},//end data
@ -1324,6 +1338,7 @@
XmGroupDialog,
XmIterationSelect,
MdpSelectUserXm,
XmMenuAgileKanbanUser,
//
},
mounted() {

716
src/views/xm/core/xmTask/XmTaskAgileKanbanUser.vue

@ -0,0 +1,716 @@
<template>
<section class="menu-box">
<el-table
ref="table"
:data="usersCpd"
header-cell-class-name="head-row"
border
:height="tableHeight"
style="width: 100%"
>
<el-table-column
:label="'执行人 (' + users.length + ')'"
class-name="menu-name"
width="200"
>
<template slot-scope="scope">
<div class="menu">
<div class="icon" style="background-color: rgb(79, 140, 255);">
<i class="el-icon-document"></i>
</div>
<el-link type="primary" @click="showMenuEdit(scope.row)">{{
scope.row.executorUsername
}}</el-link>
</div>
</template>
</el-table-column>
<template v-for="(type, tt) in taskStateCpd" style="min-width:200px;">
<el-table-column
:label="type.label + '(' + type.number + ')'"
:key="tt"
width="250"
>
<template slot-scope="scope">
<el-row class="my-cell-bar">
<el-button
icon="el-icon-plus"
@click="showAddTask(scope.row, type)"
type="primary"
plain
>任务</el-button
>
</el-row>
<draggable
:name="scope.row.executorUserid"
:sort="false"
@start="onStart"
@end="onEnd"
@move="onMove"
:options="{ group: scope.row.executorUserid }"
class="draggable"
animation="300"
scroll
scrollSensitivity="80"
scrollSpeed="80"
>
<transition-group
class="transition-group"
:data-executor-userid="scope.row.executorUserid"
:data-task-state="type.status"
>
<!-- <template v-if="drag.executorUserid && drag.executorUserid === scope.row.executorUserid && drag.taskState !== type.status">
<div class="drag-to-box">{{type.label}}</div>
</template> -->
<template v-if="tasks && tasksCpd[scope.row.executorUserid][tt].length">
<div @click.stop="showTaskEdit(task)"
:data-executor-userid="scope.row.executorUserid"
:data-task-id="task.id"
:data-task-state="task.taskState"
class="task"
v-for="(task, t) in tasks[scope.row.executorUserid][tt]"
:key="task.id + t"
>
<el-row>
<el-tag
title="优先级"
v-for="(item, index) in formatDictsWithClass(
dicts,
'priority',
task.level
)"
:key="task.id + index"
:type="item.className"
>{{ item.name }}</el-tag
>
<el-tag
title="进度"
style="border-radius: 30px"
:type="task.rate >= 100 ? 'success' : 'warning'"
>
{{ (task.rate != null ? task.rate : 0) + "%" }}
</el-tag>
<span class="my-cell-bar"><el-button size="mini" type="danger" icon="el-icon-delete" plain @click.stop="handleDel(task,tt)"></el-button></span>
</el-row>
<el-row>
<span title="执行人" class="label-font-color">
{{
task.executorUsername
? task.executorUsername
: "未设置执行人"
}}
</span>
</el-row>
<el-row>
<div class="title">{{ task.name }}</div>
</el-row>
</div>
</template>
</transition-group>
</draggable>
</template>
</el-table-column>
</template>
</el-table>
<el-dialog
title="编辑任务"
:visible.sync="editFormVisible"
:with-header="false"
fullscreen
append-to-body
:close-on-click-modal="false"
>
<xm-task-edit
:xm-project="
editForm && editForm.projectId ? { id: editForm.projectId } : null
"
:xm-task="editForm"
:visible="editFormVisible"
@cancel="editFormVisible = false"
@after-add-submit="afterExecEditSubmit"
@after-edit-submit="afterExecEditSubmit"
@submit="afterEditSubmit"
></xm-task-edit>
</el-dialog>
<el-dialog
title="新增任务"
:visible.sync="addFormVisible"
append-to-body
modal-append-to-body
>
<el-form :model="addForm" :rules="addFormRules" ref="addForm">
<el-form-item label="上级计划" prop="parentTaskname">
{{ addForm.parentTaskname ? addForm.parentTaskname : "无上级" }}
<el-button
@click="selectParentTaskVisible = true"
title="选择上级计划"
type="text"
icon="el-icon-upload2"
>
选择上级计划
</el-button>
</el-form-item>
<el-form-item label="任务名称" prop="name">
<template slot="label">
<div class="icon" style="background-color: #1cc7ea">
<i class="el-icon-s-operation"></i>
</div>
任务名称
</template>
<el-input v-model="addForm.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">关闭</el-button>
<el-button type="primary" @click="addXmTask"> </el-button>
</div>
</el-dialog>
<el-dialog
title="选择新的上级计划"
append-to-body
:visible.sync="selectParentTaskVisible"
width="60%"
top="20px"
>
<xm-phase-select
:sel-project="selProject"
@select="onSelectedParentTask"
></xm-phase-select>
</el-dialog>
<el-dialog append-to-body title="需求明细" :visible.sync="menuDetailVisible" width="80%" top="20px" :close-on-click-modal="false">
<xm-menu-edit :visible="menuDetailVisible" :reload="true" :xm-menu="{menuId:editForm.menuId,menuName:editForm.menuName}" ></xm-menu-edit>
</el-dialog>
</section>
</template>
<script>
import util from "@/common/js/util"; //
import draggable from "vuedraggable";
import { initDicts, editXmTaskSomeFields, addTask,delXmTask } from "@/api/xm/core/xmTask";
import XmTaskEdit from "./XmTaskEdit"; //
import XmPhaseSelect from "../xmTask/XmPhaseSelect.vue";
import XmMenuEdit from '../xmMenu/XmMenuEdit.vue';
import { mapGetters } from "vuex";
export default {
name: "XmTaskAgileKanban",
props: ["xmTasks", "tableHeight", "selProject"],
data() {
return {
load:{add:false,edit:false,list:false,del:false},
editForm: {
id: "",
name: "",
parentTaskid: "",
parentTaskname: "",
projectId: "",
projectName: "",
level: "",
sortLevel: "",
executorUserid: "",
executorUsername: "",
preTaskid: "",
preTaskname: "",
startTime: "",
endTime: "",
milestone: "",
description: "",
remarks: "",
createUserid: "",
createUsername: "",
createTime: "",
rate: 0,
budgetAt: 0,
budgetWorkload: 0,
actAt: 0,
actWorkload: 0,
taskState: "0",
taskType: "4",
taskClass: "",
toTaskCenter: "0",
actStartTime: "",
actEndTime: "",
bizProcInstId: "",
bizFlowState: "",
phaseId: "",
phaseName: "",
taskSkillNames: "",
exeUsernames: "",
taskSkillIds: "",
exeUserids: "",
taskOut: "0",
planType: "w2",
settleSchemel: "1",
menuId: "",
menuName: "",
productId: "",
cbranchId: "",
cdeptid: "",
tagIds: "",
tagNames: "",
ntype: "",
childrenCnt: "",
ltime: "",
pidPaths: "",
lvl: "",
isTpl: "",
keyPath: "",
uniInnerPrice: 80,
uniOutPrice: 100,
calcType: "",
ptype: "",
wtype: "",
bctrl: "",
initWorkload: "",
shareFee: "",
oshare: "",
crowd: "",
browseUsers: "",
execUsers: "",
cityId: "",
cityName: "",
regionType: "",
browseTimes: "",
capaLvls: "",
tranMode: "",
supRequires: "",
hot: "0",
top: "0",
urgent: "0",
crmSup: "0",
bidStep: "0",
interestLvls: "",
filePaths: "",
estate: "0",
efunds: 0,
etoPlatTime: "",
etoDevTime: "",
ebackTime: "",
topStime: "",
topEtime: "",
hotStime: "",
hotEtime: "",
urgentStime: "",
urgentEtime: "",
},
addForm: {
id: "",
name: "",
parentTaskid: "",
parentTaskname: "",
projectId: "",
projectName: "",
level: "",
sortLevel: "",
executorUserid: "",
executorUsername: "",
preTaskid: "",
preTaskname: "",
startTime: "",
endTime: "",
milestone: "",
description: "",
remarks: "",
createUserid: "",
createUsername: "",
createTime: "",
rate: 0,
budgetAt: 0,
budgetWorkload: 0,
actAt: 0,
actWorkload: 0,
taskState: "0",
taskType: "4",
taskClass: "",
toTaskCenter: "0",
actStartTime: "",
actEndTime: "",
bizProcInstId: "",
bizFlowState: "",
phaseId: "",
phaseName: "",
taskSkillNames: "",
exeUsernames: "",
taskSkillIds: "",
exeUserids: "",
taskOut: "0",
planType: "w2",
settleSchemel: "1",
menuId: "",
menuName: "",
productId: "",
cbranchId: "",
cdeptid: "",
tagIds: "",
tagNames: "",
ntype: "",
childrenCnt: "",
ltime: "",
pidPaths: "",
lvl: "",
isTpl: "",
keyPath: "",
uniInnerPrice: 80,
uniOutPrice: 100,
calcType: "",
ptype: "",
wtype: "",
bctrl: "",
initWorkload: "",
shareFee: "",
oshare: "",
crowd: "",
browseUsers: "",
execUsers: "",
cityId: "",
cityName: "",
regionType: "",
browseTimes: "",
capaLvls: "",
tranMode: "",
supRequires: "",
hot: "0",
top: "0",
urgent: "0",
crmSup: "0",
bidStep: "0",
interestLvls: "",
filePaths: "",
estate: "0",
efunds: 0,
etoPlatTime: "",
etoDevTime: "",
ebackTime: "",
topStime: "",
topEtime: "",
hotStime: "",
hotEtime: "",
urgentStime: "",
urgentEtime: "",
},
addFormRules: {
name: [
{ required: true, message: "任务名称不能为空", trigger: "change" },
{
min: 2,
max: 150,
message: "长度在 2 到 150 个字符",
trigger: "change",
}, //
],
},
editFormVisible: false,
addFormVisible: false,
selectParentTaskVisible: false,
menuDetailVisible:false,
taskState: [
{ label: "待领取", status: "0", number: 0 },
{ label: "执行中", status: "1", number: 0 },
{ label: "已完工", status: "2", number: 0 },
{ label: "已验收", status: "3", number: 0 },
{ label: "已结算", status: "4", number: 0 },
{ label: "已关闭", status: "9", number: 0 },
],
taskStateInit: [],
dicts: {
priority: [],
taskType: [],
planType: [],
xmTaskSettleSchemel: [],
taskState: [],
xm_plan_lvl: [],
},
tasks: {},
users: [],
drag: {
menuId: "",
state: "",
},
};
},
components: { draggable, XmTaskEdit, XmPhaseSelect,XmMenuEdit },
watch: {
xmTasks() {
this.initData();
},
},
computed: {
...mapGetters(["userInfo", "roles"]),
usersCpd() {
return this.users;
},
tasksCpd() {
return this.tasks;
},
taskStateCpd() {
return this.taskState;
},
},
methods: {
...util,
onMove(e) {
console.log("onMove--e==", e);
let targetEl = { ...e.dragged.dataset };
let toEl = { ...e.to.dataset };
if (
targetEl.executorUserid === toEl.executorUserid &&
targetEl.taskState != toEl.taskState
) {
console.log("onMove--true");
return true;
}
console.log("onMove--false");
return false;
},
onStart(e) {
console.log("onStart--e==", e);
let targetEl = { ...e.item.dataset };
this.drag = { ...targetEl };
console.log("onStart--targetEl==", targetEl);
},
onEnd(e) {
console.log("onEnd--e==", e);
this.drag = {};
// targetEl; toEl.
let targetEl = { ...e.item.dataset };
let toEl = { ...e.to.dataset };
if (
targetEl.executorUserid === toEl.executorUserid &&
targetEl.taskState != toEl.taskState
) {
let task = this.xmTasks.find((d) => d.id === targetEl.taskId);
let taskIndex = this.xmTasks.findIndex((d) => d.id === targetEl.taskId);
//const params = { ...task, taskState: toEl.taskState };
const params = { ids: [task.id], taskState: toEl.taskState };
editXmTaskSomeFields(params).then((res) => {
//this.$emit('submit');
var tips = res.data.tips;
if (tips.isOk) {
var taskStateIndex = this.getTaskStateIndex(task.taskState);
this.taskState[taskStateIndex].number =
this.taskState[taskStateIndex].number - 1;
var toTaskStateIndex = this.getTaskStateIndex(params.taskState);
this.taskState[toTaskStateIndex].number =
this.taskState[toTaskStateIndex].number + 1;
task.taskState = params.taskState;
this.$set(this.xmTasks, taskIndex, task);
} else {
this.$notify({
position: "bottom-left",
showClose: true,
message: tips.msg,
type: "error",
});
}
return res.data.tips.isOk;
});
} else {
return false;
}
},
initData() {
var xmTasks = this.xmTasks;
this.taskState = JSON.parse(JSON.stringify(this.taskStateInit));
let users = [],
userids = {},
tasks = {};
xmTasks.forEach((d, i) => {
if (!d.executorUserid) {
d.executorUserid = "noExecutorUserid";
d.executorUsername = "未设置执行人";
}
if (!users.length || !userids[d.executorUserid]) {
users.push(d);
userids[d.executorUserid] = true;
}
if (!tasks[d.executorUserid]) {
tasks[d.executorUserid] = [[], [], [], [], [], []];
}
var taskStateIndex = this.getTaskStateIndex(d.taskState);
tasks[d.executorUserid][taskStateIndex].push(d);
this.taskState[taskStateIndex].number += 1;
});
this.tasks = tasks;
users.sort((v1,v2)=>{
return v1.executorUserid<v2.executorUserid
})
this.users = users;
},
showTaskEdit(task) {
this.editForm = task;
this.editFormVisible = true;
},
afterEditSubmit(task) {
let taskIndex = this.xmTasks.findIndex((d) => d.id === task.id);
this.$set(this.xmTasks, taskIndex, task);
},
getTaskStateIndex(taskState) {
return this.taskState.findIndex((i) => i.status == taskState);
},
afterExecEditSubmit() {},
showMenuEdit(task){
this.editForm=task;
if(task.executorUserid=='noExecutorUserid'||!task.executorUserid){
this.$notify({
position: "bottom-left",
showClose: true,
message: '没有关联任务故事',
type: "error",
});
return;
}
this.menuDetailVisible=true;
},
addXmTask() {
this.load.add=true;
this.$refs.addForm.validate().then((valid) => {
var task = { ...this.addForm };
addTask(task)
.then((res) => {
this.load.add = false;
var tips = res.data.tips;
if (tips.isOk) {
//this.$emit("submit", res.data.data); // @submit="afterAddSubmit"
this.xmTasks.push(res.data.data);
}
this.$notify({
position: "bottom-left",
showClose: true,
message: tips.msg,
type: tips.isOk ? "success" : "error",
});
})
.catch((err) => (this.load.add = false));
});
},
onSelectedParentTask(task) {
this.addForm.parentTaskid = task.id;
this.addForm.parentTaskname = task.name;
this.selectParentTaskVisible = false;
},
showAddTask(task, type) {
this.addForm.menuId = task.menuId;
this.addForm.menuName = task.menuName;
this.addForm.productId = task.productId;
this.addForm.taskState = type.status;
this.addForm.projectId = task.projectId;
this.addForm.parentTaskid = task.parentTaskid;
this.addForm.parentTaskname = task.parentTaskname;
this.addForm.priority = task.priority;
this.addForm.sortLevel = task.sortLevel;
this.addForm.verNum = task.verNum;
this.addForm.pverNum = task.pverNum;
this.addForm.createUserid = this.userInfo.userid;
this.addForm.createUsername = this.userInfo.username;
this.addForm.qtype = "1";
this.addForm.ntype = "0";
this.addForm.ptype = "0";
this.addFormVisible = true;
},
//xmTask
handleDel: function (row, index) {
this.$confirm("确认删除该记录吗?", "提示", {
type: "warning",
}).then(() => {
this.load.del = true;
let params = Object.assign({}, row);
delXmTask(params)
.then((res) => {
this.load.del = false;
var tips = res.data.tips;
if (tips.isOk) {
var index=this.xmTasks.findIndex(k=>k.id==row.id)
this.xmTasks.splice(index,1)
}
this.$notify({
showClose: true,
message: tips.msg,
type: tips.isOk ? "success" : "error",
});
})
.catch((err) => (this.load.del = false));
});
},
},
mounted() {
initDicts(this);
this.taskStateInit = JSON.parse(JSON.stringify(this.taskState));
this.initData();
},
};
</script>
<style lang='scss' scoped>
.menu-box {
height: 100%;
width: 100%;
overflow: hidden;
}
.draggable {
display: flex;
flex-wrap: wrap;
min-height: 100px;
width: 100%;
}
.el-table {
/deep/ .el-table__row {
background: #f6f6f6;
.menu-name {
background: #fff !important;
}
td {
height: 100%;
vertical-align: top;
}
}
}
.transition-group {
width: 100%;
cursor: pointer;
.task {
min-height: 100px;
background: #fff;
margin: 0px 0px 10px 0px;
padding: 5px;
}
}
.my-cell-bar {
visibility: hidden;
float: right;
}
.el-table__row td:hover {
cursor: pointer;
.my-cell-bar {
visibility: visible;
.u-btn {
float: right;
}
}
.my-cell-text {
display: none;
}
}
.title {
height: 40px;
overflow: hidden; //
text-overflow: ellipsis; //
display: -webkit-box; //
//
-webkit-line-clamp: 2; //
-webkit-box-orient: vertical; //
//
}
</style>

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

@ -91,8 +91,9 @@
>
<span class="more-label-font">
<el-radio v-model="displayType" label="grant" >甘特图</el-radio>
<el-radio v-model="displayType" label="agile">敏捷看板</el-radio>
<el-radio v-model="displayType" label="table">表格</el-radio>
<el-radio v-model="displayType" label="agile">故事分组</el-radio>
<el-radio v-model="displayType" label="agileUser">执行人分组</el-radio>
<el-radio v-model="displayType" label="table">列表</el-radio>
</span>
</el-row>
<el-divider></el-divider>
@ -316,15 +317,22 @@
</el-row>
<el-row ref="table">
<template v-if="displayType != 'grant'">
<template v-if="displayType!='grant'">
<xm-task-agile-kanban
:tableHeight="tableHeight"
v-if="displayType == 'agile'"
:xmTasks="xmTasks"
@submit="afterEditSubmit"
></xm-task-agile-kanban>
<xm-task-agile-kanban-user
:tableHeight="tableHeight"
v-else-if="displayType == 'agileUser'"
:xmTasks="xmTasks"
@submit="afterEditSubmit"
></xm-task-agile-kanban-user>
<el-table class="task-table"
v-else
v-else-if="displayType=='table'"
element-loading-text="努力加载中" element-loading-spinner="el-icon-loading"
:data="tasksTreeData"
@sort-change="sortChange"
@ -541,8 +549,7 @@
style="float: right;"
></el-pagination>
</template>
<xm-gantt
v-if="displayType == 'grant'"
<xm-gantt v-else-if="displayType == 'grant'"
:tree-data="tasksTreeData"
:useRealTime="true"
></xm-gantt>
@ -874,6 +881,7 @@ import {
import XmTaskAdd from "./XmTaskAdd"; //
import XmTaskEdit from "./XmTaskEdit"; //
import XmTaskAgileKanban from "./XmTaskAgileKanban"; //
import XmTaskAgileKanbanUser from "./XmTaskAgileKanbanUser"; //
import { mapGetters } from "vuex";
import xmExecuserMng from "../xmTaskExecuser/XmTaskExecuserForTask";
import xmSkillMng from "../xmTaskSkill/XmTaskSkillMng";
@ -2179,6 +2187,7 @@ export default {
"xm-task-add": XmTaskAdd,
"xm-task-edit": XmTaskEdit,
XmTaskAgileKanban,
XmTaskAgileKanbanUser,
xmExecuserMng,
xmSkillMng,
skillMng,

Loading…
Cancel
Save