快速添加任务

This commit is contained in:
kuaifan 2021-06-17 16:19:58 +08:00
parent f047ed2a82
commit 225f143b21
9 changed files with 240 additions and 68 deletions

View File

@ -329,10 +329,7 @@ class ProjectTask extends AbstractModel
$subtask['parent_id'] = $task->id;
$subtask['project_id'] = $task->project_id;
$subtask['column_id'] = $task->column_id;
$result = self::addTask($subtask);
if (Base::isError($result)) {
return $result;
}
self::addTask($subtask);
}
}
$task->addLog("创建{任务}" . $task->name);

View File

@ -8,9 +8,11 @@
</div>
<ButtonGroup class="calendar-arrow" size="small">
<Button @click="preMonth"><Icon type="ios-arrow-back"></Icon></Button>
<Button @click="curMonth">{{$L('今天')}}</Button>
<Button @click="afterMonth"><Icon type="ios-arrow-forward"></Icon></Button>
</ButtonGroup>
<ButtonGroup class="calendar-arrow" size="small">
<Button @click="curMonth">{{$L('今天')}}</Button>
</ButtonGroup>
<ButtonGroup class="calendar-view">
<Button @click="setView('day')" :type="calendarView == 'day' ? 'primary' : 'default'">{{$L('日')}}</Button>
<Button @click="setView('week')" :type="calendarView == 'week' ? 'primary' : 'default'">{{$L('周')}}</Button>

View File

@ -240,18 +240,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow :list="myList" :color-list="taskColorList" @command="dropTask"/>
<div @click="addTaskOpen(0)">
<Row class="task-row">
<Col span="12" class="row-add">
<Icon type="ios-add" /> {{$L('添加任务')}}
</Col>
<Col span="3"></Col>
<Col span="3"></Col>
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
</div>
<TaskRow :list="myList" open-key="my" :color-list="taskColorList" @command="dropTask" fast-add-task/>
</div>
<!--未完成任务-->
<div v-if="projectDetail.task_num > 0" :class="['project-table-body', !taskUndoneShow ? 'project-table-hide' : '']">
@ -266,7 +255,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow :list="undoneList" :color-list="taskColorList" @command="dropTask"/>
<TaskRow :list="undoneList" open-key="undone" :color-list="taskColorList" @command="dropTask"/>
</div>
<!--已完成任务-->
<div v-if="projectDetail.task_num > 0" :class="['project-table-body', !taskCompletedShow ? 'project-table-hide' : '']">
@ -281,7 +270,7 @@
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<TaskRow :list="completedList" :color-list="taskColorList" @command="dropTask"/>
<TaskRow :list="completedList" open-key="completed" :color-list="taskColorList" @command="dropTask"/>
</div>
</div>
@ -796,6 +785,7 @@ export default {
if (index > -1) {
this.projectDetail.project_column.splice(index, 1);
}
this.$store.dispatch("getProjectOne", column.project_id);
}).catch(({msg}) => {
$A.modalError(msg, 301);
this.$set(column, 'loading', false);

View File

@ -1,5 +1,43 @@
<template>
<div :class="['task-add-simple', active ? 'active' : '']" @mouseenter="mouseEnter=true" @mouseleave="mouseEnter=false">
<Row v-if="rowMode" class="task-add-row">
<Col span="12" :class="['row-add', active ? 'active' : '']">
<div class="add-input" @mouseenter="mouseEnter=true" @mouseleave="mouseEnter=false">
<Input
v-model="addData.name"
ref="input"
type="textarea"
:rows="1"
:autosize="{ minRows: 1, maxRows: 3 }"
:maxlength="255"
:placeholder="$L(typeName + '描述,回车创建')"
@on-focus="onFocus=true"
@on-blur="onFocus=false"
@on-keydown="onKeydown"/>
<div v-if="parentId == 0" class="priority">
<ul>
<li v-for="(item, key) in taskPriority" :key="key">
<ETooltip v-if="active" :content="item.name + ' (' + item.days + $L('天') + ')'">
<i
class="iconfont"
:style="{color:item.color}"
v-html="addData.p_name == item.name ? '&#xe61d;' : '&#xe61c;'"
@click="choosePriority(item)"></i>
</ETooltip>
</li>
</ul>
<Icon type="md-settings" @click="onPriority"/>
</div>
</div>
<div class="add-btn" @click="openAdd">
<Icon class="add-icon" type="md-add" />{{$L('添加' + typeName)}}
</div>
</Col>
<Col span="3"></Col>
<Col span="3"></Col>
<Col span="3"></Col>
<Col span="3"></Col>
</Row>
<div v-else :class="['task-add-simple', active ? 'active' : '']" @mouseenter="mouseEnter=true" @mouseleave="mouseEnter=false">
<Input
v-model="addData.name"
ref="input"
@ -7,12 +45,12 @@
:rows="2"
:autosize="{ minRows: 2, maxRows: 3 }"
:maxlength="255"
:placeholder="$L('任务描述,回车创建')"
:placeholder="$L(typeName + '描述,回车创建')"
@on-focus="onFocus=true"
@on-blur="onFocus=false"
@on-keydown="onKeydown"></Input>
@on-keydown="onKeydown"/>
<div class="add-placeholder" @click="openAdd">
<Icon type="md-add" />{{$L('添加任务')}}
<Icon type="md-add" />{{$L('添加' + typeName)}}
</div>
<div class="priority">
<ul>
@ -37,11 +75,17 @@ import {mapState} from "vuex";
export default {
name: "TaskAddSimple",
props: {
parentId: {
type: Number,
default: 0
},
projectId: {
default: ''
type: Number,
default: 0
},
columnId: {
default: ''
type: Number,
default: 0
},
addTop: {
type: Boolean,
@ -50,6 +94,10 @@ export default {
autoActive: {
type: Boolean,
default: false
},
rowMode: {
type: Boolean,
default: false
}
},
data() {
@ -77,7 +125,11 @@ export default {
},
computed: {
...mapState(['userId', 'taskPriority']),
...mapState(['userId', 'taskPriority', 'projectDetail']),
typeName() {
return (this.parentId > 0 ? '子任务' : '任务');
}
},
watch: {
@ -96,11 +148,18 @@ export default {
methods: {
getData() {
this.addData.project_id = this.projectId;
this.addData.column_id = this.columnId;
this.addData.owner = [this.userId];
this.addData.top = this.addTop ? 1 : 0;
return $A.cloneJSON(this.addData);
if (this.parentId > 0) {
return {
task_id: this.parentId,
name: this.addData.name,
}
} else {
this.addData.project_id = this.projectId || this.projectDetail.id;
this.addData.column_id = this.columnId || '';
this.addData.owner = [this.userId];
this.addData.top = this.addTop ? 1 : 0;
return $A.cloneJSON(this.addData);
}
},
openAdd() {
@ -141,7 +200,8 @@ export default {
return;
}
this.loadIng++;
this.$store.dispatch("taskAdd", this.getData()).then(({msg}) => {
let type = this.parentId > 0 ? 'taskAddSub' : 'taskAdd';
this.$store.dispatch(type, this.getData()).then(({msg}) => {
$A.messageSuccess(msg);
this.loadIng--;
this.active = false;
@ -167,7 +227,9 @@ export default {
this.$set(this.addData, 'p_level', item.priority)
this.$set(this.addData, 'p_name', item.name)
this.$set(this.addData, 'p_color', item.color)
this.$refs.input.focus()
this.$nextTick(() => {
this.$refs.input.focus();
});
},
defaultPriority() {

View File

@ -5,19 +5,18 @@
<em v-if="item.p_name && item.parent_id === 0" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
<Col span="12" :class="['row-name', item.complete_at ? 'complete' : '']">
<Icon
v-if="item.sub_num > 0"
:class="['sub-icon', item.sub_open ? 'active' : '']"
v-if="item.sub_num > 0 || fastAddTask"
:class="['sub-icon', item[openName] ? 'active' : '']"
type="ios-arrow-forward"
@click="getSublist(item)"/>
<div v-if="item.loading === true" class="loading"><Loading /></div>
<EDropdown
v-else
trigger="click"
size="small"
@command="dropTask(item, $event)">
<div>
<div class="drop-icon">
<Icon v-if="item.complete_at" class="completed" type="md-checkmark-circle" />
<Icon v-else type="md-radio-button-off" />
<div v-if="item.loading === true" class="loading"><Loading /></div>
</div>
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
<EDropdownItem v-if="item.complete_at" command="uncomplete">
@ -84,20 +83,25 @@
</Col>
</Row>
<TaskRow
v-if="item.sub_open===true"
:list="item.sub_list"
v-if="item[openName]===true"
:list="item.sub_task"
:parent-id="item.id"
:fast-add-task="fastAddTask"
:color-list="colorList"
:open-key="openKey"
@command="dropTask"/>
</div>
<TaskAddSimple v-if="fastAddTask" :parent-id="parentId" row-mode/>
</div>
</template>
<script>
import TaskPriority from "./TaskPriority";
import TaskAddSimple from "./TaskAddSimple";
export default {
name: "TaskRow",
components: {TaskPriority},
components: {TaskAddSimple, TaskPriority},
props: {
list: {
type: Array,
@ -111,6 +115,18 @@ export default {
return [];
}
},
parentId: {
type: Number,
default: 0
},
fastAddTask: {
type: Boolean,
default: false
},
openKey: {
type: String,
default: 'default'
},
},
data() {
return {
@ -128,6 +144,9 @@ export default {
clearInterval(this.nowInterval)
},
computed: {
openName() {
return 'sub_open_' + this.openKey
},
expiresFormat() {
const {nowTime} = this;
return function (date) {
@ -140,9 +159,6 @@ export default {
return this.formatTime(date)
}
},
},
watch: {
},
methods: {
dropTask(task, command) {
@ -150,8 +166,8 @@ export default {
},
getSublist(task) {
if (task.sub_open === true) {
this.$set(task, 'sub_open', false);
if (task[this.openName] === true) {
this.$set(task, this.openName, false);
return;
}
if (task.loading === true) {
@ -160,8 +176,8 @@ export default {
this.$set(task, 'loading', true);
this.$store.dispatch("getSubTask", task.id).then(({data}) => {
this.$set(task, 'loading', false);
this.$set(task, 'sub_list', data);
this.$set(task, 'sub_open', true);
this.$set(task, 'sub_task', data);
this.$set(task, this.openName, true);
}).catch(({msg}) => {
this.$set(task, 'loading', false);
$A.modalError(msg);

View File

@ -660,10 +660,26 @@ export default {
url: 'project/task/addsub',
data: data,
}).then(result => {
if (data.task_id == state.projectOpenTask.id) {
state.projectOpenTask.sub_task.push(result.data.task);
const {task} = result.data;
if (state.projectDetail.id == task.project_id) {
const column = state.projectDetail.project_column.find(({id}) => id === task.column_id);
if (column) {
const project_task = column.project_task.find(({id}) => id === task.parent_id)
if (project_task) {
let index = project_task.sub_task.findIndex(({id}) => id === task.id)
if (index === -1) {
project_task.sub_task.push(task);
}
}
}
}
dispatch("getTaskOne", data.task_id);
if (data.task_id == state.projectOpenTask.id) {
let index = state.projectOpenTask.sub_task.findIndex(({id}) => id === task.id)
if (index === -1) {
state.projectOpenTask.sub_task.push(task);
}
}
dispatch("getTaskOne", task.parent_id);
resolve(result)
}).catch(result => {
reject(result)

View File

@ -560,12 +560,18 @@
}
&.row-name {
padding-left: 34px;
.drop-icon {
position: relative;
}
.loading {
width: 24px;
height: 14px;
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 16px;
display: flex;
align-items: center;
justify-content: flex-start;
justify-content: center;
.common-loading {
margin: 0;
width: 14px;
@ -686,18 +692,6 @@
}
}
}
&.row-add {
display: flex;
align-items: center;
height: 48px;
cursor: pointer;
> i {
font-size: 24px;
color: #777777;
margin-left: 32px;
margin-right: 4px;
}
}
}
}
.task-rows {
@ -724,6 +718,14 @@
}
}
}
.task-add-row {
background-color: #fcfcfd;
> div {
&.row-add {
padding-left: 56px;
}
}
}
}
}
}

View File

@ -48,3 +48,90 @@
}
}
}
.task-add-row {
background-color: #ffffff;
border-bottom: 1px solid #F4F4F5;
position: relative;
> div {
display: flex;
padding: 8px 12px;
border-right: 1px solid #F4F4F5;
&:last-child {
border-right: 0;
}
&.row-add {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 48px;
padding-left: 34px;
.add-btn {
display: block;
cursor: pointer;
opacity: 0.5;
transition: opacity 0.3s;
.add-icon {
font-size: 16px;
margin-right: 8px;
}
&:hover {
opacity: 1;
}
}
.add-input {
display: none;
align-items: flex-start;
border: 1px solid #dcdee2;
border-radius: 4px;
color: #515a6e;
background-color: #fff;
&:hover {
border-color: #57a3f3;
}
textarea {
border-color: transparent;
resize: none;
&:focus {
box-shadow: none;
}
}
.priority {
margin: 0 4px;
display: flex;
align-items: center;
height: 31px;
> ul {
flex: 1;
display: flex;
align-items: center;
> li {
list-style: none;
margin-right: 4px;
.iconfont {
font-size: 17px;
cursor: pointer;
}
}
}
.ivu-icon {
cursor: pointer;
font-size: 15px;
margin: 0 5px 0 3px;
}
}
}
&.active {
padding-top: 7px;
padding-bottom: 7px;
.add-btn {
display: none;
}
.add-input {
display: flex;
}
}
}
}
}

View File

@ -12,6 +12,7 @@
.calendar-title {
display: flex;
align-items: center;
margin-right: 36px;
> h1 {
color: #333333;
font-size: 28px;
@ -19,7 +20,7 @@
}
}
.calendar-arrow {
margin-left: 36px;
margin-right: 12px;
> button {
color: #888888;
font-size: 12px;
@ -29,7 +30,6 @@
}
}
.calendar-view {
margin-left: 36px;
flex: 1;
display: flex;
justify-content: flex-end;