diff --git a/resources/assets/js/pages/manage/components/ProjectList.vue b/resources/assets/js/pages/manage/components/ProjectList.vue index 0b860038..31177f06 100644 --- a/resources/assets/js/pages/manage/components/ProjectList.vue +++ b/resources/assets/js/pages/manage/components/ProjectList.vue @@ -116,8 +116,7 @@ {{$L('删除')}} - {{$L('颜色')}} - +
{{$L(c.name)}}
@@ -154,42 +153,7 @@
{{item.name}}
-
- - - - -
- {{$L('标记未完成')}} -
-
- -
- {{$L('完成')}} -
-
- -
- {{$L('归档')}} -
-
- -
- {{$L('删除')}} -
-
- {{$L('背景色')}} - -
- {{$L(c.name)}} -
-
-
-
+
@@ -286,7 +250,7 @@ - +
@@ -301,7 +265,7 @@ - +
@@ -316,7 +280,7 @@ - +
@@ -331,7 +295,7 @@ {{projectData.task_num > 0 && projectParameter('showCompleted') ? $L('完成时间') : ''}} - +
@@ -475,10 +439,12 @@ import TaskArchived from "./TaskArchived"; import ProjectLog from "./ProjectLog"; import DrawerOverlay from "../../../components/DrawerOverlay"; import ProjectWorkflow from "./ProjectWorkflow"; +import TaskMenu from "./TaskMenu"; export default { name: "ProjectList", components: { + TaskMenu, ProjectWorkflow, DrawerOverlay, ProjectLog, TaskArchived, TaskRow, Draggable, TaskAddSimple, UserInput, TaskAdd, TaskPriority}, @@ -489,9 +455,6 @@ export default { columnLoad: {}, columnTopShow: {}, - taskLoad: {}, - - tempShowTasks: [], sortField: 'end_at', sortType: 'desc', @@ -639,13 +602,13 @@ export default { }, myList() { - const {projectId, cacheTasks, searchText, tempShowTasks, sortField, sortType} = this; + const {projectId, cacheTasks, searchText, sortField, sortType} = this; const array = cacheTasks.filter((task) => { if (task.project_id != projectId) { return false; } if (!this.projectParameter('completedTask')) { - if (task.complete_at && !tempShowTasks.find(({id}) => id == task.id)) { + if (task.complete_at) { return false; } } @@ -672,13 +635,13 @@ export default { }, helpList() { - const {projectId, cacheTasks, searchText, tempShowTasks, userId, sortField, sortType} = this; + const {projectId, cacheTasks, searchText, userId, sortField, sortType} = this; const array = cacheTasks.filter((task) => { if (task.project_id != projectId || task.parent_id > 0) { return false; } if (!this.projectParameter('completedTask')) { - if (task.complete_at && !tempShowTasks.find(({id}) => id == task.id)) { + if (task.complete_at) { return false; } } @@ -767,9 +730,6 @@ export default { projectData() { this.sortData = this.getSort(); }, - '$route'() { - this.tempShowTasks = []; - }, searchShow(val) { if (val) { this.$nextTick(() => { @@ -965,112 +925,6 @@ export default { }); }, - dropTask(task, command) { - if ($A.isJson(command)) { - if (command.name) { - // 修改背景色 - this.updateTask(task, { - color: command.color - }) - } - return; - } - if ($A.leftExists(command, 'column::')) { - // 修改列表 - this.updateTask(task, { - column_id: $A.leftDelete(command, 'column::') - }) - return; - } - if ($A.leftExists(command, 'priority::')) { - // 修改优先级 - let data = this.taskPriority[parseInt($A.leftDelete(command, 'priority::'))]; - if (data) { - this.updateTask(task, { - p_level: data.priority, - p_name: data.name, - p_color: data.color, - }) - } - return; - } - switch (command) { - case 'complete': - if (task.complete_at) return; - this.updateTask(task, { - complete_at: $A.formatDate("Y-m-d H:i:s") - }).then(() => { - this.tempShowTasks.push(task) - }) - break; - - case 'uncomplete': - if (!task.complete_at) return; - this.updateTask(task, { - complete_at: false - }).then(() => { - this.tempShowTasks = this.tempShowTasks.filter(({id}) => id != task.id) - }) - break; - - case 'archived': - case 'remove': - this.archivedOrRemoveTask(task, command); - break; - } - }, - - updateTask(task, updata) { - return new Promise((resolve, reject) => { - if (this.taskLoad[task.id] === true) { - reject() - return; - } - this.$set(this.taskLoad, task.id, true); - // - Object.keys(updata).forEach(key => this.$set(task, key, updata[key])); - // - this.$store.dispatch("taskUpdate", Object.assign(updata, { - task_id: task.id, - })).then(() => { - this.$set(this.taskLoad, task.id, false); - resolve() - }).catch(({msg}) => { - $A.modalError(msg); - this.$set(this.taskLoad, task.id, false); - this.$store.dispatch("getTaskOne", task.id); - reject() - }); - }); - }, - - archivedOrRemoveTask(task, type) { - let typeDispatch = type == 'remove' ? 'removeTask' : 'archivedTask'; - let typeName = type == 'remove' ? '删除' : '归档'; - let typeTask = task.parent_id > 0 ? '子任务' : '任务'; - $A.modalConfirm({ - title: typeName + typeTask, - content: '你确定要' + typeName + typeTask + '【' + task.name + '】吗?', - loading: true, - onOk: () => { - if (this.taskLoad[task.id] === true) { - this.$Modal.remove(); - return; - } - this.$set(this.taskLoad, task.id, true); - this.$store.dispatch(typeDispatch, task.id).then(({msg}) => { - $A.messageSuccess(msg); - this.$Modal.remove(); - this.$set(this.taskLoad, task.id, false); - }).catch(({msg}) => { - $A.modalError(msg, 301); - this.$Modal.remove(); - this.$set(this.taskLoad, task.id, false); - }); - } - }); - }, - onSort(field) { this.sortField = field; this.sortType = this.sortType == 'desc' ? 'asc' : 'desc'; @@ -1311,7 +1165,6 @@ export default { toggleCompleted() { this.$store.dispatch('toggleProjectParameter', 'completedTask'); - this.tempShowTasks = []; }, expiresFormat(date) { diff --git a/resources/assets/js/pages/manage/components/TaskArchived.vue b/resources/assets/js/pages/manage/components/TaskArchived.vue index 8ba24db5..66c554d3 100644 --- a/resources/assets/js/pages/manage/components/TaskArchived.vue +++ b/resources/assets/js/pages/manage/components/TaskArchived.vue @@ -97,6 +97,13 @@ export default { title: this.$L('完成时间'), key: 'complete_at', width: 168, + render: (h, {row}) => { + return h('div', { + style: { + color: row.complete_at ? '' : '#f00' + } + }, row.complete_at || this.$L('未完成')); + } }, { title: this.$L('归档时间'), diff --git a/resources/assets/js/pages/manage/components/TaskDetail.vue b/resources/assets/js/pages/manage/components/TaskDetail.vue index d0739d45..f65db90f 100644 --- a/resources/assets/js/pages/manage/components/TaskDetail.vue +++ b/resources/assets/js/pages/manage/components/TaskDetail.vue @@ -2,40 +2,7 @@
  • -
    - -
    - - -
    - - -
    - {{$L('标记未完成')}} -
    -
    - -
    - {{$L('完成')}} -
    -
    - -
    - {{$L('时间')}} -
    -
    - -
    - {{$L('删除')}} -
    -
    -
    -
    +
    -
    - {{taskDetail.end_at && taskDetail.end_at != mainEndAt ? expiresFormat(taskDetail.end_at) : ' '}} +
    + {{expiresFormat(taskDetail.end_at)}}
    +
    - - +
    @@ -428,10 +370,11 @@ import TaskUpload from "./TaskUpload"; import DialogWrapper from "./DialogWrapper"; import ProjectLog from "./ProjectLog"; import {Store} from "le5le-store"; +import TaskMenu from "./TaskMenu"; export default { name: "TaskDetail", - components: {ProjectLog, DialogWrapper, TaskUpload, UserInput, TaskPriority, TEditor}, + components: {TaskMenu, ProjectLog, DialogWrapper, TaskUpload, UserInput, TaskPriority, TEditor}, props: { taskId: { type: Number, @@ -794,34 +737,8 @@ export default { } }, - dropTask(command) { - switch (command) { - case 'complete': - this.updateData('complete') - break; - case 'uncomplete': - this.updateData('uncomplete') - break; - case 'times': - this.openTime() - break; - case 'archived': - case 'remove': - this.archivedOrRemoveTask(command); - break; - } - }, - updateData(action, params) { switch (action) { - case 'complete': - this.$set(this.taskDetail, 'complete_at', $A.formatDate()); - action = 'complete_at'; - break; - case 'uncomplete': - this.$set(this.taskDetail, 'complete_at', false); - action = 'complete_at'; - break; case 'priority': this.$set(this.taskDetail, 'p_level', params.priority) this.$set(this.taskDetail, 'p_name', params.name) diff --git a/resources/assets/js/pages/manage/components/TaskMenu.vue b/resources/assets/js/pages/manage/components/TaskMenu.vue new file mode 100644 index 00000000..3d9b981a --- /dev/null +++ b/resources/assets/js/pages/manage/components/TaskMenu.vue @@ -0,0 +1,184 @@ + + + diff --git a/resources/assets/js/pages/manage/components/TaskRow.vue b/resources/assets/js/pages/manage/components/TaskRow.vue index fcc4a43b..f6cca7a0 100644 --- a/resources/assets/js/pages/manage/components/TaskRow.vue +++ b/resources/assets/js/pages/manage/components/TaskRow.vue @@ -9,47 +9,7 @@ :class="['sub-icon', taskOpen[item.id] ? 'active' : '']" type="ios-arrow-forward" @click="getSublist(item)"/> - -
    - - -
    -
    - - -
    - {{$L('标记未完成')}} -
    -
    - -
    - {{$L('完成')}} -
    -
    - -
    - {{$L('归档')}} -
    -
    - -
    - {{$L('删除')}} -
    -
    - -
    -
    +
    {{$L('子任务')}} +{{item.sub_my.length}} @@ -145,10 +105,11 @@ import TaskPriority from "./TaskPriority"; import TaskAddSimple from "./TaskAddSimple"; import {mapState} from "vuex"; import {Store} from "le5le-store"; +import TaskMenu from "./TaskMenu"; export default { name: "TaskRow", - components: {TaskAddSimple, TaskPriority}, + components: {TaskMenu, TaskAddSimple, TaskPriority}, props: { list: { type: Array, @@ -211,8 +172,31 @@ export default { return column ? column.name : ''; }, + dropTask(task, command) { - this.$emit("command", task, command) + const el = this.$refs[`taskMenu_${task.id}`]; + if (!el) { + return; + } + // + if ($A.leftExists(command, 'column::')) { + // 修改列表 + el[0].updateTask({ + column_id: $A.leftDelete(command, 'column::') + }) + return; + } + if ($A.leftExists(command, 'priority::')) { + // 修改优先级 + let data = this.taskPriority[parseInt($A.leftDelete(command, 'priority::'))]; + if (data) { + el[0].updateTask({ + p_level: data.priority, + p_name: data.name, + p_color: data.color, + }) + } + } }, onPriority(data) { diff --git a/resources/assets/js/pages/manage/dashboard.vue b/resources/assets/js/pages/manage/dashboard.vue index fe91974e..b95641c3 100644 --- a/resources/assets/js/pages/manage/dashboard.vue +++ b/resources/assets/js/pages/manage/dashboard.vue @@ -40,45 +40,11 @@ v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"> - -
    + +
    - - -
    - {{$L('标记未完成')}} -
    -
    - -
    - {{$L('完成')}} -
    -
    - -
    - {{$L('归档')}} -
    -
    - -
    - {{$L('删除')}} -
    -
    - -
    - +
    {{$L('子任务')}} +{{item.sub_my.length}} @@ -107,9 +73,10 @@ import {mapGetters, mapState} from "vuex"; import AppDown from "../../components/AppDown"; import {Store} from "le5le-store"; +import TaskMenu from "./components/TaskMenu"; export default { - components: {AppDown}, + components: {TaskMenu, AppDown}, data() { return { nowTime: $A.Time(), @@ -117,10 +84,6 @@ export default { loadIng: 0, dashboard: 'today', - - taskLoad: {}, - - tempShowTasks: [], } }, @@ -156,7 +119,7 @@ export default { }, list() { - const {dashboard, tempShowTasks} = this; + const {dashboard} = this; let data = []; switch (dashboard) { case 'today': @@ -166,112 +129,17 @@ export default { data = this.transforTasks(this.dashboardTask.overdue); break } - if (tempShowTasks.length > 0) { - data.push(...tempShowTasks); - } return data.sort((a, b) => { return $A.Date(a.end_at) - $A.Date(b.end_at); }); }, }, - watch: { - '$route'() { - this.tempShowTasks = []; - }, - dashboard() { - this.tempShowTasks = []; - } - }, - methods: { - dropTask(task, command) { - switch (command) { - case 'complete': - if (task.complete_at) return; - this.updateTask(task, { - complete_at: $A.formatDate("Y-m-d H:i:s") - }).then(() => { - this.tempShowTasks.push(task) - }) - break; - case 'uncomplete': - if (!task.complete_at) return; - this.updateTask(task, { - complete_at: false - }).then(() => { - this.tempShowTasks = this.tempShowTasks.filter(({id}) => id != task.id) - }) - break; - case 'archived': - case 'remove': - this.archivedOrRemoveTask(task, command); - break; - default: - if (command.name) { - this.updateTask(task, { - color: command.color - }) - } - break; - } - }, - openTask(task) { this.$store.dispatch("openTask", task) }, - updateTask(task, updata) { - return new Promise((resolve, reject) => { - if (this.taskLoad[task.id] === true) { - reject() - return; - } - this.$set(this.taskLoad, task.id, true); - // - Object.keys(updata).forEach(key => this.$set(task, key, updata[key])); - // - this.$store.dispatch("taskUpdate", Object.assign(updata, { - task_id: task.id, - })).then(() => { - this.$set(this.taskLoad, task.id, false); - resolve() - }).catch(({msg}) => { - $A.modalError(msg); - this.$set(this.taskLoad, task.id, false); - this.$store.dispatch("getTaskOne", task.id); - reject(); - }); - }) - }, - - archivedOrRemoveTask(task, type) { - let typeDispatch = type == 'remove' ? 'removeTask' : 'archivedTask'; - let typeName = type == 'remove' ? '删除' : '归档'; - let typeTask = task.parent_id > 0 ? '子任务' : '任务'; - $A.modalConfirm({ - title: typeName + typeTask, - content: '你确定要' + typeName + typeTask + '【' + task.name + '】吗?', - loading: true, - onOk: () => { - if (this.taskLoad[task.id] === true) { - this.$Modal.remove(); - return; - } - this.$set(this.taskLoad, task.id, true); - this.$store.dispatch(typeDispatch, task.id).then(({msg}) => { - $A.messageSuccess(msg); - this.$Modal.remove(); - this.$set(this.taskLoad, task.id, false); - }).catch(({msg}) => { - $A.modalError(msg, 301); - this.$Modal.remove(); - this.$set(this.taskLoad, task.id, false); - }); - } - }); - }, - expiresFormat(date) { return $A.countDownFormat(date, this.nowTime) }, diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 29aeff4e..afdecbdb 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -1135,6 +1135,7 @@ export default { reject({msg: 'Parameter error'}); return; } + dispatch("taskLoadAdd", task_id) dispatch("call", { url: 'project/task/remove', data: { @@ -1142,10 +1143,12 @@ export default { }, }).then(result => { dispatch("forgetTask", task_id) + dispatch("taskLoadSub", task_id) resolve(result) }).catch(e => { console.error(e); dispatch("getTaskOne", task_id); + dispatch("taskLoadSub", task_id) reject(e) }); }); @@ -1164,6 +1167,7 @@ export default { reject({msg: 'Parameter error'}); return; } + dispatch("taskLoadAdd", task_id) dispatch("call", { url: 'project/task/archived', data: { @@ -1171,10 +1175,12 @@ export default { }, }).then(result => { dispatch("forgetTask", task_id) + dispatch("taskLoadSub", task_id) resolve(result) }).catch(e => { console.error(e); - dispatch("getTaskOne", task_id); + dispatch("getTaskOne", task_id) + dispatch("taskLoadSub", task_id) reject(e) }); }); @@ -1365,28 +1371,67 @@ export default { * 更新任务 * @param state * @param dispatch - * @param data + * @param data {task_id, ?} * @returns {Promise} */ taskUpdate({state, dispatch}, data) { return new Promise(function (resolve, reject) { const post = $A.cloneJSON($A.date2string(data)); // + dispatch("taskLoadAdd", post.task_id) dispatch("call", { url: 'project/task/update', data: post, method: 'post', }).then(result => { + dispatch("taskLoadSub", post.task_id) dispatch("saveTask", result.data) resolve(result) }).catch(e => { console.error(e); + dispatch("taskLoadSub", post.task_id) dispatch("getTaskOne", post.task_id); reject(e) }); }); }, + /** + * 任务增加等待 + * @param state + * @param task_id + */ + taskLoadAdd({state}, task_id) { + setTimeout(() => { + const load = state.taskLoading.find(({id}) => id == task_id) + if (!load) { + state.taskLoading.push({ + id: task_id, + num: 1 + }) + } else { + load.num++; + } + }, 300) + }, + + /** + * 任务减少等待 + * @param state + * @param task_id + */ + taskLoadSub({state}, task_id) { + const load = state.taskLoading.find(({id}) => id == task_id) + if (!load) { + state.taskLoading.push({ + id: task_id, + num: -1 + }) + } else { + load.num--; + } + }, + /** * 获取任务优先级预设数据 * @param state diff --git a/resources/assets/js/store/state.js b/resources/assets/js/store/state.js index 31c5a572..fdd82c7f 100644 --- a/resources/assets/js/store/state.js +++ b/resources/assets/js/store/state.js @@ -67,6 +67,7 @@ state.taskId = 0; state.taskContents = []; state.taskFiles = []; state.taskLogs = []; +state.taskLoading = []; // 任务优先级 state.taskPriority = []; diff --git a/resources/assets/sass/pages/components/_.scss b/resources/assets/sass/pages/components/_.scss index 2217113b..e848824d 100755 --- a/resources/assets/sass/pages/components/_.scss +++ b/resources/assets/sass/pages/components/_.scss @@ -10,5 +10,6 @@ @import "task-add-simple"; @import "task-archived"; @import "task-detail"; +@import "task-menu"; @import "task-priority"; @import "team-management"; diff --git a/resources/assets/sass/pages/components/project-list.scss b/resources/assets/sass/pages/components/project-list.scss index 36d2add9..d463b93f 100644 --- a/resources/assets/sass/pages/components/project-list.scss +++ b/resources/assets/sass/pages/components/project-list.scss @@ -380,10 +380,11 @@ } .ivu-icon { font-size: 22px; - color: #777777; - cursor: pointer; - &:hover { - color: #555555; + &.uncomplete { + color: #777777; + &:hover { + color: #555555; + } } } } @@ -651,31 +652,12 @@ align-items: flex-start; padding: 12px 12px 12px 34px; line-height: 24px; - .drop-icon { - position: relative; - } .loading { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 16px; - display: flex; - align-items: center; - justify-content: center; - .common-loading { - margin: 0; - width: 14px; - height: 14px; - } + height: 24px; } .ivu-icon { cursor: pointer; font-size: 16px; - color: #cccccc; - &.completed { - color: $primary-color; - } &.sub-icon { font-size: 16px; width: 16px; @@ -689,6 +671,9 @@ transform: rotate(90deg); } } + &.uncomplete { + color: #cccccc; + } } .item-title { flex: 1; diff --git a/resources/assets/sass/pages/components/task-detail.scss b/resources/assets/sass/pages/components/task-detail.scss index ea691001..2a7b4092 100644 --- a/resources/assets/sass/pages/components/task-detail.scss +++ b/resources/assets/sass/pages/components/task-detail.scss @@ -26,11 +26,23 @@ background-color: #f4f5f5; } .icon { - width: 18px; - font-size: 18px; - cursor: pointer; - &.completed { - color: $primary-color; + .task-menu-icon { + display: flex; + align-items: center; + .ivu-icon { + font-size: 18px; + } + .loading { + width: 18px; + height: 18px; + .common-loading { + width: 16px; + height: 16px; + } + } + .uncomplete { + color: #888888; + } } } .nav { @@ -78,8 +90,12 @@ } .menu { margin-left: 12px; - font-size: 22px; - cursor: pointer; + display: flex; + align-items: center; + .ivu-icon { + font-size: 22px; + color: #606266; + } } } } @@ -243,37 +259,22 @@ &:last-child { margin-bottom: -6px; } + &:hover { + .subtask-time { + .clock { + transform: translateX(0); + opacity: 0.8; + } + } + } .subtask-icon { width: 16px; height: 26px; line-height: 26px; margin-right: 6px; + display: flex; + align-items: center; cursor: pointer; - .loading { - width: 16px; - height: 16px; - margin: 0; - padding: 2px; - } - .ivu-icon { - font-size: 16px; - color: #cccccc; - &.completed { - color: $primary-color; - } - } - &.sub-icon { - font-size: 16px; - width: 16px; - height: 16px; - margin-left: -20px; - margin-right: 4px; - color: #cfcfcf; - transition: transform 0.2s; - &.active { - transform: rotate(90deg); - } - } } .subtask-name { flex: 1; @@ -309,6 +310,13 @@ color: #ff9900; } } + .clock { + margin: 3px 2px; + font-size: 20px; + transition: all 0.2s; + transform: translateX(50%); + opacity: 0; + } } .subtask-avatar { height: 20px; diff --git a/resources/assets/sass/pages/components/task-menu.scss b/resources/assets/sass/pages/components/task-menu.scss new file mode 100644 index 00000000..75c2b5ae --- /dev/null +++ b/resources/assets/sass/pages/components/task-menu.scss @@ -0,0 +1,50 @@ +.task-menu-icon { + position: relative; + + .loading { + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; + + .common-loading { + margin: 0; + width: 14px; + height: 14px; + } + } + + .ivu-icon { + cursor: pointer; + font-size: 16px; + color: #cccccc; + + &.completed { + color: $primary-color; + } + } +} + +.task-menu-more-dropdown { + > li { + .item { + display: flex; + align-items: center; + + > i { + width: 18px; + height: 18px; + line-height: 18px; + font-size: 18px; + margin-right: 8px; + padding: 0; + color: #bbbbbb; + + &.ivu-icon { + font-size: 16px; + } + } + } + } +}