perf: 添加任务窗口
This commit is contained in:
parent
7171d1d6b2
commit
e65c80962d
@ -32,6 +32,9 @@ class ProjectController extends AbstractController
|
||||
* - all:全部
|
||||
* - no:未归档(默认)
|
||||
* - yes:已归档
|
||||
* @apiParam {String} [andcolumn] 同时取项目列表
|
||||
* - no:不取(默认)
|
||||
* - yes:取列表
|
||||
* @apiParam {Object} [keys] 搜索条件
|
||||
* - keys.name 项目名称
|
||||
*
|
||||
@ -44,6 +47,7 @@ class ProjectController extends AbstractController
|
||||
//
|
||||
$all = Request::input('all');
|
||||
$archived = Request::input('archived', 'no');
|
||||
$andcolumn = Request::input('andcolumn', 'no');
|
||||
//
|
||||
if ($all) {
|
||||
$user->identity('admin');
|
||||
@ -52,6 +56,10 @@ class ProjectController extends AbstractController
|
||||
$builder = Project::select(Project::projectSelect)->authData();
|
||||
}
|
||||
//
|
||||
if ($andcolumn == 'yes') {
|
||||
$builder->with(['projectColumn']);
|
||||
}
|
||||
//
|
||||
if ($archived == 'yes') {
|
||||
$builder->whereNotNull('projects.archived_at');
|
||||
} elseif ($archived == 'no') {
|
||||
|
@ -58,7 +58,7 @@
|
||||
"stylus-loader": "^6.2.0",
|
||||
"tinymce": "^5.10.2",
|
||||
"tui-calendar-hi": "^1.15.1-1",
|
||||
"view-design-hi": "^4.7.0-3",
|
||||
"view-design-hi": "^4.7.0-5",
|
||||
"vue": "^2.6.14",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-emoji-picker": "^1.0.3",
|
||||
|
@ -126,12 +126,11 @@
|
||||
<!--添加任务-->
|
||||
<Modal
|
||||
v-model="addTaskShow"
|
||||
:title="$L('添加任务')"
|
||||
:mask-closable="false"
|
||||
:styles="{
|
||||
width: '90%',
|
||||
maxWidth: '640px'
|
||||
}"
|
||||
:mask-closable="false"
|
||||
footer-hide>
|
||||
<TaskAdd ref="addTask" v-model="addTaskShow"/>
|
||||
</Modal>
|
||||
@ -256,9 +255,6 @@ export default {
|
||||
'column_id': data,
|
||||
});
|
||||
this.addTaskShow = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.addTask.$refs.input.focus();
|
||||
})
|
||||
});
|
||||
//
|
||||
document.addEventListener('keydown', this.shortcutEvent);
|
||||
|
@ -815,7 +815,7 @@ export default {
|
||||
this.$store.dispatch("saveColumn", data);
|
||||
}).catch(({msg}) => {
|
||||
this.$set(this.columnLoad, column.id, false);
|
||||
this.$store.dispatch("getColumns", {project_id: this.projectId})
|
||||
this.$store.dispatch("getColumns", this.projectId)
|
||||
$A.modalError(msg);
|
||||
});
|
||||
},
|
||||
|
@ -1,5 +1,16 @@
|
||||
<template>
|
||||
<div class="task-add">
|
||||
<div class="head" :class="{empty:addData.cascader.length == 0,visible:cascaderShow}">
|
||||
<Cascader
|
||||
v-model="addData.cascader"
|
||||
:data="cascaderData"
|
||||
:clearable="false"
|
||||
:placeholder="$L('请选择项目')"
|
||||
:load-data="cascaderLoadData"
|
||||
@on-input-change="cascaderInputChange"
|
||||
@on-visible-change="cascaderShow=!cascaderShow"
|
||||
filterable/>
|
||||
</div>
|
||||
<div class="task-add-form">
|
||||
<div class="title">
|
||||
<Input
|
||||
@ -39,22 +50,6 @@
|
||||
</div>
|
||||
|
||||
<Form v-if="advanced" class="task-add-advanced" label-width="auto" @submit.native.prevent>
|
||||
<FormItem :label="$L('任务列表')">
|
||||
<Select
|
||||
v-model="addData.column_id"
|
||||
:placeholder="$L('选择任务列表')"
|
||||
:multipleMax="1"
|
||||
multiple
|
||||
filterable
|
||||
transfer
|
||||
allowCreate
|
||||
transfer-class-name="task-add-advanced-transfer"
|
||||
@on-create="columnCreate">
|
||||
<div slot="drop-prepend" class="task-drop-prepend">{{$L('最多只能选择1项')}}</div>
|
||||
<Option v-for="(item, key) in columnList" :value="item.id" :key="key">{{ item.name }}</Option>
|
||||
<Option v-for="(item, key) in columnAdd" :value="item.id" :key="'_' + key">{{ item.name }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('计划时间')">
|
||||
<DatePicker
|
||||
v-model="addData.times"
|
||||
@ -70,7 +65,7 @@
|
||||
v-model="addData.owner"
|
||||
:multiple-max="10"
|
||||
:placeholder="$L('选择任务负责人')"
|
||||
:project-id="projectId"/>
|
||||
:project-id="addData.project_id"/>
|
||||
</FormItem>
|
||||
<div class="subtasks">
|
||||
<div v-if="addData.subtasks.length > 0" class="sublist">
|
||||
@ -102,7 +97,7 @@
|
||||
v-model="item.owner"
|
||||
:multiple-max="1"
|
||||
:placeholder="$L('选择负责人')"
|
||||
:project-id="projectId"/>
|
||||
:project-id="addData.project_id"/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
@ -118,13 +113,13 @@
|
||||
<div class="ivu-modal-footer">
|
||||
<Button type="default" @click="close">{{$L('取消')}}</Button>
|
||||
<ButtonGroup class="page-manage-add-task-button-group">
|
||||
<Button type="primary" :loading="loadIng > 0" @click="onAdd">{{$L('添加')}}</Button>
|
||||
<Button type="primary" :loading="loadIng > 0" @click="onAdd">{{$L('添加任务')}}</Button>
|
||||
<Dropdown @on-click="onAdd(true)">
|
||||
<Button type="primary" :loading="loadIng > 0">
|
||||
<Icon type="ios-arrow-down"></Icon>
|
||||
</Button>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem>{{$L('添加并继续')}}</DropdownItem>
|
||||
<DropdownItem>{{$L('提交继续添加')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</ButtonGroup>
|
||||
@ -149,9 +144,11 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
addData: {
|
||||
cascader: [],
|
||||
name: "",
|
||||
content: "",
|
||||
owner: 0,
|
||||
project_id: 0,
|
||||
column_id: 0,
|
||||
times: [],
|
||||
subtasks: [],
|
||||
@ -160,9 +157,14 @@ export default {
|
||||
p_color: '',
|
||||
},
|
||||
|
||||
cascaderShow: false,
|
||||
cascaderData: [],
|
||||
cascaderValue: '',
|
||||
cascaderLoading: 0,
|
||||
cascaderAlready: [],
|
||||
|
||||
advanced: false,
|
||||
subName: '',
|
||||
columnAdd: [],
|
||||
|
||||
taskPlugins: [
|
||||
'advlist autolink lists link image charmap print preview hr anchor pagebreak',
|
||||
@ -195,14 +197,29 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
//
|
||||
|
||||
},
|
||||
computed: {
|
||||
...mapState(['userId', 'projectId', 'columns', 'taskPriority']),
|
||||
|
||||
columnList() {
|
||||
return this.columns.filter(({project_id}) => project_id == this.projectId)
|
||||
...mapState(['userId', 'projects', 'projectId', 'columns', 'taskPriority']),
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (val) {
|
||||
this.initCascaderData();
|
||||
this.initProjectData();
|
||||
this.$nextTick(this.$refs.input.focus)
|
||||
}
|
||||
},
|
||||
'addData.column_id' () {
|
||||
const {project_id, column_id} = this.addData;
|
||||
this.$nextTick(() => {
|
||||
if (project_id && column_id) {
|
||||
this.$set(this.addData, 'cascader', [project_id, column_id]);
|
||||
} else {
|
||||
this.$set(this.addData, 'cascader', []);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initLanguage() {
|
||||
@ -256,17 +273,55 @@ export default {
|
||||
}]
|
||||
};
|
||||
},
|
||||
close() {
|
||||
this.$emit("input", !this.value)
|
||||
},
|
||||
columnCreate(val) {
|
||||
if (!this.columnAdd.find(({id}) => id == val)) {
|
||||
this.columnAdd.push({
|
||||
id: val,
|
||||
name: val
|
||||
|
||||
initCascaderData() {
|
||||
this.cascaderData = this.projects.map(project => {
|
||||
const children = this.columns.filter(({project_id}) => project_id == project.id).map(column => {
|
||||
return {
|
||||
value: column.id,
|
||||
label: column.name
|
||||
}
|
||||
});
|
||||
let data = {
|
||||
value: project.id,
|
||||
label: project.name,
|
||||
children,
|
||||
};
|
||||
if (children.length == 0) {
|
||||
data.loading = false;
|
||||
}
|
||||
return data
|
||||
});
|
||||
},
|
||||
|
||||
initProjectData() {
|
||||
let column_id = this.addData.column_id;
|
||||
if (column_id) {
|
||||
let column = this.columns.find(({id}) => id == column_id);
|
||||
if (column) {
|
||||
this.addData.project_id = column.project_id;
|
||||
this.addData.column_id = column.id;
|
||||
}
|
||||
} else {
|
||||
let project = this.projects.find(({id}) => id == this.projectId) || this.projects.find(({id}) => id > 0);
|
||||
if (project) {
|
||||
let column = this.columns.find(({project_id}) => project_id == project.id);
|
||||
if (column) {
|
||||
this.addData.project_id = column.project_id;
|
||||
this.addData.column_id = column.id;
|
||||
} else {
|
||||
this.$store.dispatch("getColumns", project.id).then((data) => {
|
||||
column = data.find(({id}) => id > 0);
|
||||
if (column) {
|
||||
this.addData.project_id = column.project_id;
|
||||
this.addData.column_id = column.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
taskTimeChange(times) {
|
||||
let tempc = $A.date2string(times, "Y-m-d H:i");
|
||||
if (tempc[0] && tempc[1]) {
|
||||
@ -275,6 +330,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onKeydown(e) {
|
||||
if (e.keyCode === 13) {
|
||||
if (e.shiftKey) {
|
||||
@ -284,6 +340,7 @@ export default {
|
||||
this.onAdd();
|
||||
}
|
||||
},
|
||||
|
||||
addSubTask() {
|
||||
if (this.subName.trim() !== '') {
|
||||
this.addData.subtasks.push({
|
||||
@ -294,6 +351,7 @@ export default {
|
||||
this.subName = '';
|
||||
}
|
||||
},
|
||||
|
||||
choosePriority(item) {
|
||||
let start = new Date();
|
||||
let end = new Date(new Date().setDate(start.getDate() + $A.runNum(item.days)));
|
||||
@ -302,6 +360,7 @@ export default {
|
||||
this.$set(this.addData, 'p_name', item.name)
|
||||
this.$set(this.addData, 'p_color', item.color)
|
||||
},
|
||||
|
||||
defaultPriority() {
|
||||
if (this.taskPriority.length === 0) {
|
||||
return;
|
||||
@ -311,18 +370,59 @@ export default {
|
||||
}
|
||||
this.choosePriority(this.taskPriority[0]);
|
||||
},
|
||||
|
||||
cascaderLoadData(item, callback) {
|
||||
item.loading = true;
|
||||
this.$store.dispatch("getColumns", item.value).then((data) => {
|
||||
item.children = data.map(column => {
|
||||
return {
|
||||
value: column.id,
|
||||
label: column.name
|
||||
}
|
||||
});
|
||||
item.loading = false;
|
||||
callback();
|
||||
}).catch(() => {
|
||||
item.loading = false;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
cascaderInputChange(key) {
|
||||
this.cascaderValue = key || "";
|
||||
//
|
||||
if (this.cascaderAlready[this.cascaderValue] === true) {
|
||||
return;
|
||||
}
|
||||
this.cascaderAlready[this.cascaderValue] = true;
|
||||
//
|
||||
setTimeout(() => {
|
||||
this.cascaderLoading++;
|
||||
}, 1000)
|
||||
this.$store.dispatch("getProjects", {
|
||||
keys: {
|
||||
name: this.cascaderValue,
|
||||
},
|
||||
andcolumn: 'yes'
|
||||
}).then(() => {
|
||||
this.cascaderLoading--;
|
||||
this.initCascaderData();
|
||||
}).catch(() => {
|
||||
this.cascaderLoading--;
|
||||
});
|
||||
},
|
||||
|
||||
setData(data) {
|
||||
this.addData = Object.assign({}, this.addData, data);
|
||||
},
|
||||
|
||||
onAdd(again) {
|
||||
if (!this.addData.name) {
|
||||
$A.messageError("任务描述不能为空");
|
||||
return;
|
||||
}
|
||||
this.loadIng++;
|
||||
this.$store.dispatch("taskAdd", Object.assign(this.addData, {
|
||||
project_id: this.projectId
|
||||
})).then(({msg}) => {
|
||||
this.$store.dispatch("taskAdd", this.addData).then(({msg}) => {
|
||||
this.loadIng--;
|
||||
$A.messageSuccess(msg);
|
||||
if (again === true) {
|
||||
@ -334,6 +434,7 @@ export default {
|
||||
this.$refs.input.focus();
|
||||
} else {
|
||||
this.addData = {
|
||||
cascader: [],
|
||||
name: "",
|
||||
content: "",
|
||||
owner: 0,
|
||||
@ -350,7 +451,11 @@ export default {
|
||||
this.loadIng--;
|
||||
$A.modalError(msg);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$emit("input", !this.value)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
86
resources/assets/js/store/actions.js
vendored
86
resources/assets/js/store/actions.js
vendored
@ -516,6 +516,10 @@ export default {
|
||||
dispatch("saveProject", project)
|
||||
});
|
||||
} else if (state.method.isJson(data)) {
|
||||
if (typeof data.project_column !== "undefined") {
|
||||
dispatch("saveColumn", data.project_column)
|
||||
delete data.project_column;
|
||||
}
|
||||
let index = state.projects.findIndex(({id}) => id == data.id);
|
||||
if (index > -1) {
|
||||
state.projects.splice(index, 1, Object.assign(state.projects[index], data));
|
||||
@ -571,10 +575,10 @@ export default {
|
||||
dispatch("call", {
|
||||
url: 'project/lists',
|
||||
data: data || {}
|
||||
}).then(result => {
|
||||
state.projectTotal = result.data.total_all;
|
||||
dispatch("saveProject", result.data.data);
|
||||
resolve(result)
|
||||
}).then(({data}) => {
|
||||
state.projectTotal = data.total_all;
|
||||
dispatch("saveProject", data.data);
|
||||
resolve(data)
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
reject(e)
|
||||
@ -747,45 +751,51 @@ export default {
|
||||
* @param state
|
||||
* @param dispatch
|
||||
* @param project_id
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
getColumns({state, dispatch}, project_id) {
|
||||
if (state.userId === 0) {
|
||||
state.columns = [];
|
||||
return;
|
||||
}
|
||||
if (state.cacheColumns.length > 0) {
|
||||
state.columns = state.cacheColumns;
|
||||
}
|
||||
state.projectLoad++;
|
||||
dispatch("call", {
|
||||
url: 'project/column/lists',
|
||||
data: {
|
||||
project_id
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (state.userId === 0) {
|
||||
state.columns = [];
|
||||
reject({msg: 'Parameter error'})
|
||||
return;
|
||||
}
|
||||
}).then(result => {
|
||||
state.projectLoad--;
|
||||
const ids = result.data.data.map(({id}) => id)
|
||||
if (ids.length > 0) {
|
||||
state.columns = state.columns.filter((item) => item.project_id != project_id || ids.includes(item.id));
|
||||
if (state.cacheColumns.length > 0) {
|
||||
state.columns = state.cacheColumns;
|
||||
}
|
||||
dispatch("saveColumn", result.data.data);
|
||||
// 判断只有1列的时候默认版面为表格模式
|
||||
if (state.columns.filter(item => item.project_id == project_id).length === 1) {
|
||||
const cache = state.cacheTablePanel.find(item => item.project_id == project_id) || {};
|
||||
if (typeof cache.cardInit === "undefined" || cache.cardInit === false) {
|
||||
dispatch("toggleTablePanel", {
|
||||
project_id,
|
||||
key: {
|
||||
card: false,
|
||||
cardInit: true,
|
||||
}
|
||||
});
|
||||
state.projectLoad++;
|
||||
dispatch("call", {
|
||||
url: 'project/column/lists',
|
||||
data: {
|
||||
project_id
|
||||
}
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
state.projectLoad--;
|
||||
});
|
||||
}).then(({data}) => {
|
||||
state.projectLoad--;
|
||||
const ids = data.data.map(({id}) => id)
|
||||
if (ids.length > 0) {
|
||||
state.columns = state.columns.filter((item) => item.project_id != project_id || ids.includes(item.id));
|
||||
}
|
||||
dispatch("saveColumn", data.data);
|
||||
// 判断只有1列的时候默认版面为表格模式
|
||||
if (state.columns.filter(item => item.project_id == project_id).length === 1) {
|
||||
const cache = state.cacheTablePanel.find(item => item.project_id == project_id) || {};
|
||||
if (typeof cache.cardInit === "undefined" || cache.cardInit === false) {
|
||||
dispatch("toggleTablePanel", {
|
||||
project_id,
|
||||
key: {
|
||||
card: false,
|
||||
cardInit: true,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(data.data)
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
state.projectLoad--;
|
||||
reject(e);
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,57 @@
|
||||
.task-add {
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
.ivu-cascader {
|
||||
.ivu-cascader-label {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:after {
|
||||
transition: all 0.2s;
|
||||
padding: 6px;
|
||||
font-family: Ionicons, serif;
|
||||
content: "\f116";
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.ivu-cascader-arrow {
|
||||
display: none;
|
||||
}
|
||||
.ivu-input {
|
||||
padding: 4px 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
font-size: 15px;
|
||||
}
|
||||
.ivu-cascader-not-found-tip {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
&.empty {
|
||||
.ivu-cascader {
|
||||
.ivu-cascader-label {
|
||||
&:after {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.visible {
|
||||
.ivu-cascader {
|
||||
.ivu-cascader-label {
|
||||
&:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.task-add-form,
|
||||
.task-add-advanced {
|
||||
.title {
|
||||
@ -95,14 +148,3 @@
|
||||
padding: 26px 0 22px !important;
|
||||
}
|
||||
}
|
||||
.task-add-advanced-transfer {
|
||||
.task-drop-prepend {
|
||||
text-align: center;
|
||||
color: #c5c8ce;
|
||||
line-height: 20px;
|
||||
padding-bottom: 5px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user