Browse Source

敏捷看板

master
lxc Mac 5 years ago
parent
commit
b7c1df56c9
  1. 2
      package.json
  2. 324
      src/views/xm/core/xmTask/XmTaskAgileKanban.vue
  3. 19
      src/views/xm/core/xmTask/XmTaskMng.vue

2
package.json

@ -60,7 +60,7 @@
"vue-quill-editor": "^3.0.6",
"vue-router": "3.0.1",
"vue-splitpane": "1.0.2",
"vuedraggable": "2.15.0",
"vuedraggable": "^2.24.3",
"vuex": "3.0.1",
"wl-gantt": "^1.0.4",
"xlsx": "^0.14.5"

324
src/views/xm/core/xmTask/XmTaskAgileKanban.vue

@ -0,0 +1,324 @@
<template>
<section class="menu-box">
<!-- <div class="itxst">
<div class="col">
<div class="title">A列</div>
<draggable v-model="arr1" group="site" animation="300" dragClass="dragClass" ghostClass="ghostClass" chosenClass="chosenClass" @start="onStart" @end="onEnd">
<transition-group>
<div class="item" v-for="item in arr1" :key="item.id">{{item.name}}</div>
</transition-group>
</draggable>
</div>
<div class="col">
<div class="title">B列</div>
<draggable v-model="arr2" group="site" animation="100" dragClass="dragClass" ghostClass="ghostClass" chosenClass="chosenClass" @start="onStart" @end="onEnd">
<transition-group>
<div class="item" v-for="item in arr2" :key="item.id">{{item.name}}</div>
</transition-group>
</draggable>
</div>
<div class="col">
<div class="title">C列</div>
<draggable v-model="arr3" group="c" animation="100" dragClass="dragClass" ghostClass="ghostClass" chosenClass="chosenClass" @start="onStart" @end="onEnd">
<transition-group>
<div class="item" v-for="item in arr3" :key="item.id">{{item.name}}</div>
</transition-group>
</draggable>
</div>
</div> -->
<div class="row head-row">
<div class="item">故事({{ menus.length }})</div>
<template v-for="(type, tt) in taskType">
<div class="item status" :key="tt">{{type.label}} ({{ type.number }})</div>
</template>
</div>
<div class="menu-body">
<div class="row menu—row" v-for="(menu, index) in menus" :key="index">
<div class="item item-menu">
<span>
{{menu.sortLevel}}&nbsp;
<!-- <el-dropdown @command="handleCommand" v-if=" isTaskCenter!='1' && isMy!='1'">
<span class="el-dropdown-link">
<el-button size="mini" circle><i class="el-icon-plus"></i></el-button>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'showMenu',data:menu}">+由故事创建子任务(推荐)</el-dropdown-item>
<el-dropdown-item :command="{type:'showSubAdd',data:menu}">+子任务</el-dropdown-item>
<el-dropdown-item :command="{type:'showTaskTemplate',data:menu}">+从模板批量导入子任务</el-dropdown-item>
<el-dropdown-item :command="{type:'handleDel',data:menu}" icon="el-icon-delete">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<el-tag v-if="menu.level<='2'" type="info">轻微</el-tag>
<el-tag v-else-if="menu.level=='3'" type="warning">一般</el-tag>
<el-tag v-else-if="menu.level=='4'" type="danger">紧急</el-tag>
<el-tag v-else type="danger">特急</el-tag>
<span v-for="(item ,index) in [formatExeUsernames(menu)]" :key="index">
<el-tooltip :content="item.exeUsernames" ><el-link :type="item.type" @click.stop="showExecusers(menu)">{{item.showMsg}}</el-link></el-tooltip>
</span>
<el-tooltip content="进度"><el-link style="border-radius:30px;" :type="menu.rate>=100?'success':'warning'" @click="drawerVisible=true"> {{ (menu.rate!=null?menu.rate:0)+'%'}} </el-link></el-tooltip>
<el-tooltip content="预算金额、工时"><el-tag type="info">{{parseFloat(menu.budgetCost/10000).toFixed(2)}},{{menu.budgetWorkload}}人时</el-tag></el-tooltip>
<el-link type="primary" @click.stop="showDrawer(menu)">{{menu.name}}</el-link>
</span>
</div>
<div class="item status" v-for="(type, tt) in taskType" :key="tt">
<draggable
v-model="tasks[menu.menuId][tt]"
:name="menu.menuId"
@start="onStart" @end="onEnd" :move="onMove"
:options="{group: menu.menuId}"
class="draggable"
animation="300"
scroll
>
<transition-group class="transition-group" :data-menu-id="menu.menuId" :data-task-state="type.status">
<template
v-if="tasks && tasks[menu.menuId][tt].length"
>
<div
:data-menu-id="menu.menuId"
:data-task-id="task.id"
:data-task-state="task.taskState"
class="task"
v-for="(task, t) in tasks[menu.menuId][tt]"
:key="t"
>
<span>
{{task.sortLevel}}&nbsp;
<!-- <el-dropdown @command="handleCommand" v-if=" isTaskCenter!='1' && isMy!='1'">
<span class="el-dropdown-link">
<el-button size="mini" circle><i class="el-icon-plus"></i></el-button>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{type:'showMenu',data:task}">+由故事创建子任务(推荐)</el-dropdown-item>
<el-dropdown-item :command="{type:'showSubAdd',data:task}">+子任务</el-dropdown-item>
<el-dropdown-item :command="{type:'showTaskTemplate',data:task}">+从模板批量导入子任务</el-dropdown-item>
<el-dropdown-item :command="{type:'handleDel',data:task}" icon="el-icon-delete">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<el-tag v-if="task.level<='2'" type="info">轻微</el-tag>
<el-tag v-else-if="task.level=='3'" type="warning">一般</el-tag>
<el-tag v-else-if="task.level=='4'" type="danger">紧急</el-tag>
<el-tag v-else type="danger">特急</el-tag>
<span v-for="(item ,index) in [formatExeUsernames(task)]" :key="index">
<el-tooltip :content="item.exeUsernames" ><el-link :type="item.type" @click.stop="showExecusers(task)">{{item.showMsg}}</el-link></el-tooltip>
</span>
<el-tooltip content="进度"><el-link style="border-radius:30px;" :type="task.rate>=100?'success':'warning'" @click="drawerVisible=true"> {{ (task.rate!=null?task.rate:0)+'%'}} </el-link></el-tooltip>
<el-tooltip content="预算金额、工时"><el-tag type="info">{{parseFloat(task.budgetCost/10000).toFixed(2)}},{{task.budgetWorkload}}人时</el-tag></el-tooltip>
<el-link type="primary" @click.stop="showDrawer(task)">{{task.name}}</el-link>
</span>
</div>
</template>
</transition-group>
</draggable>
</div>
</div>
</div>
</section>
</template>
<script>
import draggable from "vuedraggable";
import { editXmTask } from '@/api/xm/core/xmTask';
export default {
name: "XmTaskAgileKanban",
props: ["xmTasks"],
data() {
return {
taskType: [
{ label: "待领取", status: 0, number: 0 },
{ label: "已领取执行中", status: 1, number: 0 },
{ label: "已完工", status: 2, number: 0 },
{ label: "已结算", status: 3, number: 0 },
],
tasks: {},
drag: false,
arr1: [
{ id: 1, name: 'www.itxst.com' },
{ id: 2, name: 'www.jd.com' },
{ id: 3, name: 'www.baidu.com' },
{ id: 4, name: 'www.taobao.com' }
],
arr2: [
{ id: 1, name: 'www.google.com' },
{ id: 2, name: 'www.msn.com' },
{ id: 3, name: 'www.ebay.com' },
{ id: 4, name: 'www.yahoo.com' }
],
arr3: [
{ id: 1, name: 'item 1' },
{ id: 2, name: 'item 2' },
{ id: 3, name: 'item 3' },
{ id: 4, name: 'item 4' }
]
};
},
components: { draggable },
watch: {
tasks: {
handler(val, oldVal) {
console.log('tasks--val==', val);
console.log('tasks--oldVal==', oldVal);
},
deep: true,
immediate: true
}
},
computed: {
menus() {
let xmTasks = JSON.parse(JSON.stringify(this.xmTasks || []));
console.log('--xmTasks==', xmTasks);
let menus = [], menuIds = {}, tasks = {};
this.taskType.map(d => {
d.number = 0;
return d;
})
xmTasks.forEach((d, i) => {
if (!menus.length || !menuIds[d.menuId]) {
menus.push(d);
menuIds[d.menuId] = true;
} else {
console.log('i==', i);
}
if (!tasks[d.menuId]) {
tasks[d.menuId] = [[], [], [], []];
}
tasks[d.menuId][parseInt(d.taskState)].push(d);
this.taskType[parseInt(d.taskState)].number += 1;
});
this.tasks = tasks;
console.log('this.tasks==', this.tasks);
return menus;
},
},
methods: {
onStart(e) {
console.log('onStart--e==', e);
this.drag = true;
},
onEnd(e) {
console.log('onEnd--e==', e);
this.drag = false;
// targetEl; toEl.
let targetEl = { ...e.item.dataset };
let toEl = { ...e.to.dataset };
console.log('onEnd--targetEl==', targetEl, toEl);
if (targetEl.menuId === toEl.menuId && targetEl.taskState !== toEl.taskState) {
let task = this.xmTasks.find(d => d.id === targetEl.taskId);
console.log('onEnd--task==', task);
const params = { ...task, taskState: toEl.taskState };
editXmTask(params).then(res => {
console.log('onEnd--editXmTask--res==', res);
this.$emit('submit');
})
}
},
formatExeUsernames(row){
var exeUsernames=row.exeUsernames;
var respons={
type:'info',
executorUsername:row.executorUsername,
showMsg:'',
exeUsernames:exeUsernames,
executorUserid:row.executorUserid,
}
if(!row.executorUserid && exeUsernames){
var exeStatuss=exeUsernames.split(",")
respons.showMsg=exeStatuss.length+"人候选中"
return respons;
}else if(!row.executorUserid && !exeUsernames){
respons.showMsg="候选中"
return respons;
}
if(row.executorUserid && exeUsernames && exeUsernames.length>0){
var exeStatuss=exeUsernames.split(",").filter(i=>{
return i.indexOf(row.executorUsername)>=0
})
if(exeStatuss.length<=0){
respons.showMsg="去设置"
return respons;
}
respons.showMsg=exeStatuss.join(",")
if(respons.showMsg.indexOf('验收不过')>=0){
respons.type="danger"
}else if(respons.showMsg.indexOf('已验收')>=0){
respons.type="success"
}
}else{
respons.showMsg="去设置"
}
return respons
}
},
};
</script>
<style lang='scss' scoped>
.menu-box {
width: 100%;
overflow: scroll;
}
.row {
width: 2000px;
display: flex;
flex-direction: row;
overflow: scroll !important;
border-top: 1px solid #ccc;
.item {
width: 200px;
padding: 10px;
border-left: 1px solid #ccc;
display: flex;
flex-wrap: wrap;
&.status {
width: 450px;
}
&:last-child {
border-right: 1px solid #ccc;
}
}
&:last-child {
border-bottom: 1px solid #ccc;
}
&.head-row {
font-size: 14px;
font-weight: 500;
background: #efefef;
color: #303030;
}
&.menurow {
background: #f6f6f6;
.item-menu {
background: #ffffff;
}
.task {
width: 200px;
height: 100px;
margin: 10px 0 0 10px;
// padding: 10px;
cursor: pointer;
position: relative;
overflow: hidden;
border-radius: 3px;
// box-shadow: 0 2px 12px 0 rgb(48 48 48 / 5%), 0 2px 4px 0 rgb(48 48 48 / 10%);
background-color: #fff;
}
}
}
.draggable {
min-height: 100px;
width: 100%;
}
.transition-group {
display: flex;
flex-wrap: wrap;
min-height: 100px;
width: 100%;
}
</style>

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

@ -4,7 +4,7 @@
<el-col v-if="isTaskCenter!='1' && currentProject " :span="4" >
<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 :span="isTaskCenter!='1' && currentProject?20:24" class="padding-left">
<el-col :span="isTaskCenter!='1' && currentProject?20:24" class="padding-left" :class="{'flex-box': showAglile}">
<el-row>
<el-select v-model="selkey" placeholder="请选择任务状态" clearable @change="changeSelKey">
<el-option class="showall" value="" label="全部状态">全部状态</el-option>
@ -135,9 +135,14 @@
</el-row>
<el-button slot="reference" icon="el-icon-more" circle></el-button>
</el-popover>
<el-button type="primary" @click="showAglile = true" v-if="!showAglile">敏捷看板</el-button>
<el-button type="primary" @click="showAglile = false" v-else>表格查看</el-button>
</el-row>
<el-row class="padding-top">
<el-table v-if="!gstcVisible"
<template v-if="!gstcVisible">
<xm-task-agile-kanban v-if="showAglile" :xmTasks="xmTasks" @submit="afterEditSubmit"></xm-task-agile-kanban>
<el-table v-else
show-summary
:data="tasksTreeData"
@sort-change="sortChange"
@ -221,7 +226,8 @@
</template>
</el-table-column>
</el-table>
<el-pagination v-if="!gstcVisible" 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-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>
</template>
<xm-gantt v-if="gstcVisible" :tree-data="tasksTreeData" :project-phase="{startTime: currentProjectPhase.beginDate, endTime: currentProjectPhase.endDate}" :useRealTime="true"></xm-gantt>
</el-row>
@ -368,6 +374,7 @@
import XmTaskAdd from './XmTaskAdd';//
import XmTaskEdit from './XmTaskEdit';//
import XmTaskMngBatch from './XmTaskMngBatch';//
import XmTaskAgileKanban from './XmTaskAgileKanban';//
import { mapGetters } from 'vuex';
import xmExecuserMng from '../xmTaskExecuser/XmTaskExecuserMng';
import xmSkillMng from '../xmTaskSkill/XmTaskSkillMng';
@ -631,10 +638,10 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
],
pickerOptions: util.pickerOptions('datarange'),
/**end 自定义属性请在上面加 请加备注**/
showAglile: false
}
},//end data
methods: {
changeSelKey(index){
this.selkey = index;
this.searchXmTasks();
@ -1723,12 +1730,14 @@ import XmProjectGroupSelect from '../xmProjectGroup/XmProjectGroupSelect.vue';
components: {
'xm-task-add':XmTaskAdd,
'xm-task-edit':XmTaskEdit,
XmTaskAgileKanban,
xmExecuserMng,
xmSkillMng,
skillMng,
xmProjectPhaseMng,
xmTaskTemplateMng, XmProjectList,xmExchangeMng,xmMenuSelect,XmMenuRichDetail,XmGantt,XmTaskMngBatch,
XmProjectGroupSelect,XmProductSelect
XmProjectGroupSelect,XmProductSelect,
XmTaskAgileKanban
//
},
mounted() {

Loading…
Cancel
Save