kuaifan 5 éve
szülő
commit
ab1beb82ef

+ 180 - 4
app/Http/Controllers/Api/ProjectController.php

@@ -99,7 +99,7 @@ class ProjectController extends Controller
             return $inRes;
         }
         //子分类
-        $label = Base::DBC2A(DB::table('project_label')->where('projectid', $projectid)->orderBy('inorder')->orderByDesc('id')->get());
+        $label = Base::DBC2A(DB::table('project_label')->where('projectid', $projectid)->orderBy('inorder')->orderBy('id')->get());
         //任务
         $task = Base::DBC2A(DB::table('project_task')->where([ 'projectid' => $projectid, 'delete' => 0, 'complete' => 0 ])->orderBy('level')->orderBy('id')->get());
         //任务归类
@@ -599,6 +599,174 @@ class ProjectController extends Controller
     }
 
     /**
+     * 项目子分类-添加分类
+     *
+     * @apiParam {Number} projectid             项目ID
+     * @apiParam {String} title                 分类名称
+     */
+    public function label__add()
+    {
+        $user = Users::authE();
+        if (Base::isError($user)) {
+            return $user;
+        } else {
+            $user = $user['data'];
+        }
+        //
+        $projectid = trim(Request::input('projectid'));
+        $inRes = Project::inThe($projectid, $user['username']);
+        if (Base::isError($inRes)) {
+            return $inRes;
+        }
+        //
+        $title = trim(Request::input('title'));
+        if (empty($title)) {
+            return Base::retError('列表名称不能为空!');
+        } elseif (mb_strlen($title) > 32) {
+            return Base::retError('列表名称最多只能设置32个字!');
+        }
+        //
+        $count = DB::table('project_label')->where('projectid', $projectid)->where('title', $title)->count();
+        if ($count > 0) {
+            return Base::retError('列表名称已存在!');
+        }
+        //
+        $id = DB::table('project_label')->insertGetId([
+            'projectid' => $projectid,
+            'title' => $title,
+            'inorder' => intval(DB::table('project_label')->where('projectid', $projectid)->orderByDesc('inorder')->value('inorder')) + 1,
+        ]);
+        if (empty($id)) {
+            return Base::retError('系统繁忙,请稍后再试!');
+        }
+        DB::table('project_log')->insert([
+            'type' => '日志',
+            'projectid' => $projectid,
+            'username' => $user['username'],
+            'detail' => '添加流程列表【' . $title . '】',
+            'indate' => Base::time()
+        ]);
+        //
+        $row = Base::DBC2A(DB::table('project_label')->where('id', $id)->first());
+        $row['taskLists'] = [];
+        return Base::retSuccess('添加成功', $row);
+    }
+
+    /**
+     * 项目子分类-重命名分类
+     *
+     * @apiParam {Number} projectid             项目ID
+     * @apiParam {Number} labelid               分类ID
+     * @apiParam {String} title                 新分类名称
+     */
+    public function label__rename()
+    {
+        $user = Users::authE();
+        if (Base::isError($user)) {
+            return $user;
+        } else {
+            $user = $user['data'];
+        }
+        //
+        $projectid = trim(Request::input('projectid'));
+        $inRes = Project::inThe($projectid, $user['username']);
+        if (Base::isError($inRes)) {
+            return $inRes;
+        }
+        //
+        $title = trim(Request::input('title'));
+        if (empty($title)) {
+            return Base::retError('列表名称不能为空!');
+        } elseif (mb_strlen($title) > 32) {
+            return Base::retError('列表名称最多只能设置32个字!');
+        }
+        //
+        $labelid = intval(Request::input('labelid'));
+        $count = DB::table('project_label')->where('id', '!=', $labelid)->where('projectid', $projectid)->where('title', $title)->count();
+        if ($count > 0) {
+            return Base::retError('列表名称已存在!');
+        }
+        //
+        $labelDetail = Base::DBC2A(DB::table('project_label')->where('id', $labelid)->where('projectid', $projectid)->first());
+        if (empty($labelDetail)) {
+            return Base::retError('列表不存在或已被删除!');
+        }
+        //
+        if (DB::table('project_label')->where('id', $labelDetail['id'])->update([ 'title' => $title ])) {
+            DB::table('project_log')->insert([
+                'type' => '日志',
+                'projectid' => $projectid,
+                'username' => $user['username'],
+                'detail' => '流程列表【' . $labelDetail['title'] . '】重命名【' . $title . '】',
+                'indate' => Base::time()
+            ]);
+        }
+        //
+        return Base::retSuccess('修改成功');
+    }
+
+    /**
+     * 项目子分类-删除分类
+     *
+     * @apiParam {Number} projectid             项目ID
+     * @apiParam {Number} labelid               分类ID
+     *
+     * @throws \Throwable
+     */
+    public function label__delete()
+    {
+        $user = Users::authE();
+        if (Base::isError($user)) {
+            return $user;
+        } else {
+            $user = $user['data'];
+        }
+        //
+        $projectid = trim(Request::input('projectid'));
+        $inRes = Project::inThe($projectid, $user['username']);
+        if (Base::isError($inRes)) {
+            return $inRes;
+        }
+        //
+        $labelid = intval(Request::input('labelid'));
+        $labelDetail = Base::DBC2A(DB::table('project_label')->where('id', $labelid)->where('projectid', $projectid)->first());
+        if (empty($labelDetail)) {
+            return Base::retError('列表不存在或已被删除!');
+        }
+        //
+        return DB::transaction(function () use ($user, $projectid, $labelDetail) {
+            $taskLists = Base::DBC2A(DB::table('project_task')->where('labelid', $labelDetail['id'])->get());
+            $logArray = [];
+            foreach ($taskLists AS $task) {
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $projectid,
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '删除列表任务【' . $task['title'] . '】',
+                    'indate' => Base::time()
+                ];
+            }
+            $logArray[] = [
+                'type' => '日志',
+                'projectid' => $projectid,
+                'taskid' => 0,
+                'username' => $user['username'],
+                'detail' => '删除流程列表【' . $labelDetail['title'] . '】',
+                'indate' => Base::time()
+            ];
+            DB::table('project_task')->where('labelid', $labelDetail['id'])->update([
+                'delete' => 1,
+                'deletedate' => Base::time()
+            ]);
+            DB::table('project_label')->where('id', $labelDetail['id'])->delete();
+            DB::table('project_log')->insert($logArray);
+            //
+            return Base::retSuccess('删除成功');
+        });
+    }
+
+    /**
      * 项目任务-列表
      *
      * @apiParam {Number} projectid             项目ID
@@ -613,6 +781,7 @@ class ProjectController extends Controller
      * - 已超期
      * - 已完成
      * @apiParam {Number} [statistics]          是否获取统计数据(1:获取)
+     * @apiParam {Number} [levelsort]           是否按紧急排序(1:是)
      * @apiParam {Number} [page]                当前页,默认:1
      * @apiParam {Number} [pagesize]            每页显示数量,默认:20,最大:100
      */
@@ -635,6 +804,7 @@ class ProjectController extends Controller
         $whereArray = [];
         $whereArray[] = ['project_lists.id', '=', $projectid];
         $whereArray[] = ['project_lists.delete', '=', 0];
+        $whereArray[] = ['project_task.delete', '=', 0];
         if (intval(Request::input('labelid')) > 0) {
             $whereArray[] = ['project_task.labelid', '=', intval(Request::input('labelid'))];
         }
@@ -663,6 +833,9 @@ class ProjectController extends Controller
                 $whereArray[] = ['project_task.complete', '=', 1];
                 break;
         }
+        if (intval(Request::input('levelsort')) == 1) {
+            $orderBy = '`level` ASC,' . $orderBy;
+        }
         //
         $lists = DB::table('project_lists')
             ->join('project_task', 'project_lists.id', '=', 'project_task.projectid')
@@ -671,9 +844,9 @@ class ProjectController extends Controller
             ->orderByRaw($orderBy)->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
         $lists = Base::getPageList($lists);
         if (intval(Request::input('statistics')) == 1) {
-            $lists['statistics_unfinished'] = $type === '未完成' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('complete', 0)->count();
-            $lists['statistics_overdue'] = $type === '已超期' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('complete', 0)->whereBetween('enddate', [1, Base::time()])->count();
-            $lists['statistics_complete'] = $type === '已完成' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('complete', 1)->count();
+            $lists['statistics_unfinished'] = $type === '未完成' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('delete', 0)->where('complete', 0)->count();
+            $lists['statistics_overdue'] = $type === '已超期' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('delete', 0)->where('complete', 0)->whereBetween('enddate', [1, Base::time()])->count();
+            $lists['statistics_complete'] = $type === '已完成' ? $lists['total'] : DB::table('project_task')->where('projectid', $projectid)->where('delete', 0)->where('complete', 1)->count();
         }
         if ($lists['total'] == 0) {
             return Base::retError('未找到任何相关的任务', $lists);
@@ -738,6 +911,8 @@ class ProjectController extends Controller
         $title = trim(Request::input('title'));
         if (empty($title)) {
             return Base::retError('任务标题不能为空!');
+        } elseif (mb_strlen($title) > 255) {
+            return Base::retError('任务标题最多只能设置255个字!');
         }
         //
         $inArray = [
@@ -793,6 +968,7 @@ class ProjectController extends Controller
             ->select(['project_task.projectid', 'project_task.title', 'project_task.archived'])
             ->where([
                 ['project_lists.delete', '=', 0],
+                ['project_task.delete', '=', 0],
                 ['project_task.id', '=', $taskid],
             ])
             ->first());

+ 1 - 1
resources/assets/js/main/components/project/complete.vue

@@ -89,10 +89,10 @@
                                             },
                                             success: (res) => {
                                                 this.$Modal.remove();
+                                                this.getLists();
                                                 setTimeout(() => {
                                                     if (res.ret === 1) {
                                                         this.$Message.success(res.msg);
-                                                        this.getLists();
                                                     }else{
                                                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                                     }

+ 2 - 2
resources/assets/js/main/components/project/users.vue

@@ -124,10 +124,10 @@
                                             },
                                             success: (res) => {
                                                 this.$Modal.remove();
+                                                this.getLists();
                                                 setTimeout(() => {
                                                     if (res.ret === 1) {
                                                         this.$Message.success(res.msg);
-                                                        this.getLists();
                                                     }else{
                                                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                                     }
@@ -253,10 +253,10 @@
                                 },
                                 success: (res) => {
                                     this.$Modal.remove();
+                                    this.getLists();
                                     setTimeout(() => {
                                         if (res.ret === 1) {
                                             this.$Message.success(res.msg);
-                                            this.getLists();
                                         } else {
                                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
                                         }

+ 3 - 3
resources/assets/js/main/mixins/project.js

@@ -18,10 +18,10 @@ export default {
                         },
                         success: (res) => {
                             this.$Modal.remove();
+                            typeof successCallback === "function" && successCallback();
                             setTimeout(() => {
                                 if (res.ret === 1) {
                                     this.$Message.success(res.msg);
-                                    typeof successCallback === "function" && successCallback();
                                 }else{
                                     this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                 }
@@ -45,10 +45,10 @@ export default {
                 },
                 success: (res) => {
                     this.$Modal.remove();
+                    typeof successCallback === "function" && successCallback();
                     setTimeout(() => {
                         if (res.ret === 1) {
                             this.$Message.success(res.msg);
-                            typeof successCallback === "function" && successCallback();
                         }else{
                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                         }
@@ -71,10 +71,10 @@ export default {
                         },
                         success: (res) => {
                             this.$Modal.remove();
+                            typeof successCallback === "function" && successCallback();
                             setTimeout(() => {
                                 if (res.ret === 1) {
                                     this.$Message.success(res.msg);
-                                    typeof successCallback === "function" && successCallback();
                                 }else{
                                     this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                 }

+ 194 - 5
resources/assets/js/main/pages/project-panel.vue

@@ -28,12 +28,15 @@
                 <div v-for="label in projectLabel" :key="label.id" class="label-item label-draggable">
                     <div class="label-body">
                         <div class="title-box">
+                            <div v-if="label.loadIng === true" class="title-loading">
+                                <w-loading></w-loading>
+                            </div>
                             <h2>{{label.title}}</h2>
-                            <Dropdown trigger="click" transfer>
+                            <Dropdown trigger="click" @on-click="handleLabel($event, label)" transfer>
                                 <Icon type="ios-more"/>
                                 <DropdownMenu slot="list">
-                                    <DropdownItem>重命名</DropdownItem>
-                                    <DropdownItem>删除</DropdownItem>
+                                    <Dropdown-item name="rename">{{$L('重命名')}}</Dropdown-item>
+                                    <Dropdown-item name="delete">{{$L('删除')}}</Dropdown-item>
                                 </DropdownMenu>
                             </Dropdown>
                         </div>
@@ -53,7 +56,7 @@
                         </draggable>
                     </div>
                 </div>
-                <div v-if="loadDetailed" slot="footer" class="label-item label-create">
+                <div v-if="loadDetailed" slot="footer" class="label-item label-create" @click="addLabel">
                     <div class="label-body">
                         <div class="trigger-box ft hover"><i class="ft icon">&#xE8C8;</i>添加一个新列表</div>
                     </div>
@@ -119,6 +122,11 @@
                 padding-right: 15px;
                 &.label-create {
                     cursor: pointer;
+                    &:hover {
+                        .trigger-box {
+                            transform: translate(0, -50%) scale(1.1);
+                        }
+                    }
                 }
                 .label-body {
                     width: 300px;
@@ -139,6 +147,11 @@
                         align-items: center;
                         width: 100%;
                         height: 42px;
+                        .title-loading {
+                            width: 16px;
+                            height: 16px;
+                            margin-right: 6px;
+                        }
                         h2 {
                             flex: 1;
                             font-size: 16px;
@@ -237,7 +250,8 @@
                         width: 100%;
                         position: absolute;
                         top: 50%;
-                        transform: translate(0, -50%);
+                        transform: translate(0, -50%) scale(1);
+                        transition: all 0.2s;
                     }
                 }
             }
@@ -304,14 +318,189 @@
                     }
                 });
             },
+            handleLabel(event, labelDetail) {
+                switch (event) {
+                    case 'rename': {
+                        this.renameLabel(labelDetail);
+                        break;
+                    }
+                    case 'delete': {
+                        this.deleteLabel(labelDetail);
+                        break;
+                    }
+                }
+            },
+
+            renameLabel(item) {
+                this.renameValue = "";
+                this.$Modal.confirm({
+                    render: (h) => {
+                        return h('div', [
+                            h('div', {
+                                style: {
+                                    fontSize: '16px',
+                                    fontWeight: '500',
+                                    marginBottom: '20px',
+                                }
+                            }, '重命名列表'),
+                            h('Input', {
+                                props: {
+                                    value: this.renameValue,
+                                    autofocus: true,
+                                    placeholder: '请输入新的列表名称'
+                                },
+                                on: {
+                                    input: (val) => {
+                                        this.renameValue = val;
+                                    }
+                                }
+                            })
+                        ])
+                    },
+                    loading: true,
+                    onOk: () => {
+                        if (this.renameValue) {
+                            this.$set(item, 'loadIng', true);
+                            let title = this.renameValue;
+                            $A.aAjax({
+                                url: 'project/label/rename',
+                                data: {
+                                    projectid: this.projectid,
+                                    labelid: item.id,
+                                    title: title,
+                                },
+                                complete: () => {
+                                    this.$set(item, 'loadIng', false);
+                                },
+                                error: () => {
+                                    this.$Modal.remove();
+                                    this.$Message.error(this.$L('网络繁忙,请稍后再试!'));
+                                },
+                                success: (res) => {
+                                    this.$Modal.remove();
+                                    this.$set(item, 'title', title);
+                                    setTimeout(() => {
+                                        if (res.ret === 1) {
+                                            this.$Message.success(res.msg);
+                                        } else {
+                                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
+                                        }
+                                    }, 350);
+                                }
+                            });
+                        } else {
+                            this.$Modal.remove();
+                        }
+                    },
+                });
+            },
+
+            deleteLabel(item) {
+                let redTip = item.taskLists.length > 0 ? '<div style="color:red;font-weight:500">注:将同时删除列表下所有任务</div>' : '';
+                this.$Modal.confirm({
+                    title: '删除列表',
+                    content: '<div>你确定要删除此列表吗?</div>' + redTip,
+                    loading: true,
+                    onOk: () => {
+                        $A.aAjax({
+                            url: 'project/label/delete',
+                            data: {
+                                projectid: this.projectid,
+                                labelid: item.id,
+                            },
+                            error: () => {
+                                this.$Modal.remove();
+                                this.$Message.error(this.$L('网络繁忙,请稍后再试!'));
+                            },
+                            success: (res) => {
+                                this.$Modal.remove();
+                                this.projectLabel.some((label, index) => {
+                                    if (label.id == item.id) {
+                                        this.projectLabel.splice(index, 1);
+                                        return true;
+                                    }
+                                });
+                                setTimeout(() => {
+                                    if (res.ret === 1) {
+                                        this.$Message.success(res.msg);
+                                    } else {
+                                        this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
+                                    }
+                                }, 350);
+                            }
+                        });
+                    }
+                });
+            },
+
+            addLabel() {
+                this.labelValue = "";
+                this.$Modal.confirm({
+                    render: (h) => {
+                        return h('div', [
+                            h('div', {
+                                style: {
+                                    fontSize: '16px',
+                                    fontWeight: '500',
+                                    marginBottom: '20px',
+                                }
+                            }, '添加列表'),
+                            h('Input', {
+                                props: {
+                                    value: this.labelValue,
+                                    autofocus: true,
+                                    placeholder: '请输入列表名称'
+                                },
+                                on: {
+                                    input: (val) => {
+                                        this.labelValue = val;
+                                    }
+                                }
+                            })
+                        ])
+                    },
+                    loading: true,
+                    onOk: () => {
+                        if (this.labelValue) {
+                            $A.aAjax({
+                                url: 'project/label/add',
+                                data: {
+                                    projectid: this.projectid,
+                                    title: this.labelValue
+                                },
+                                error: () => {
+                                    this.$Modal.remove();
+                                    this.$Message.error(this.$L('网络繁忙,请稍后再试!'));
+                                },
+                                success: (res) => {
+                                    this.$Modal.remove();
+                                    this.projectLabel.push(res.data);
+                                    setTimeout(() => {
+                                        if (res.ret === 1) {
+                                            this.$Message.success(res.msg);
+                                        } else {
+                                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
+                                        }
+                                    }, 350);
+                                }
+                            });
+                        } else {
+                            this.$Modal.remove();
+                        }
+                    },
+                });
+            },
             addTaskSuccess(label) {
+                this.$set(label, 'loadIng', true);
                 $A.aAjax({
                     url: 'project/task/lists',
                     data: {
                         projectid: this.projectid,
                         labelid: label.id,
+                        levelsort: 1
                     },
                     complete: () => {
+                        this.$set(label, 'loadIng', false);
                     },
                     error: () => {
                         window.location.reload();

+ 14 - 5
resources/assets/js/main/pages/project.vue

@@ -23,16 +23,17 @@
             <!-- 列表 -->
             <ul class="project-list">
                 <li v-for="(item, index) in lists">
-                    <div class="project-item" @click="handleProject('open', item)">
+                    <div class="project-item">
                         <div class="project-head">
                             <div v-if="item.loadIng === true" class="project-loading">
                                 <w-loading></w-loading>
                             </div>
-                            <div class="project-title">{{item.title}}</div>
+                            <div class="project-title" @click="handleProject('open', item)">{{item.title}}</div>
                             <div class="project-setting">
                                 <Dropdown class="right-info" trigger="click" @on-click="handleProject($event, item)" transfer>
                                     <Icon class="project-setting-icon" type="md-settings" size="16"/>
                                     <Dropdown-menu slot="list">
+                                        <Dropdown-item name="open">{{$L('打开')}}</Dropdown-item>
                                         <Dropdown-item name="favor">{{$L('收藏')}}</Dropdown-item>
                                         <Dropdown-item v-if="item.isowner" name="rename">{{$L('重命名')}}</Dropdown-item>
                                         <Dropdown-item v-if="item.isowner" name="transfer">{{$L('移交项目')}}</Dropdown-item>
@@ -42,7 +43,7 @@
                                 </Dropdown>
                             </div>
                         </div>
-                        <div class="project-num">
+                        <div class="project-num" @click="handleProject('open', item)">
                             <div class="project-complete"><em>{{item.complete}}</em>已完成数</div>
                             <div class="project-num-line"></div>
                             <div class="project-unfinished"><em>{{item.unfinished}}</em>未完成数</div>
@@ -176,11 +177,17 @@
                             text-overflow:ellipsis;
                             white-space:nowrap;
                             color: #333333;
+                            cursor: pointer;
                         }
                         .project-setting{
+                            width: 30px;
+                            text-align: right;
                             .project-setting-icon {
                                 cursor: pointer;
                                 color: #333333;
+                                &:hover {
+                                    color: #0396f2;
+                                }
                             }
                         }
                     }
@@ -190,6 +197,7 @@
                         display: flex;
                         flex-direction: row;
                         align-items: center;
+                        cursor: pointer;
                         .project-complete,
                         .project-unfinished {
                             flex: 1;
@@ -219,6 +227,7 @@
                         align-items: center;
                         border-top: 1px solid #efefef;
                         padding: 6px 0;
+                        cursor: default;
                         .project-iconbtn {
                             flex: 1;
                             text-align: center;
@@ -531,10 +540,10 @@
                                 },
                                 success: (res) => {
                                     this.$Modal.remove();
+                                    this.$set(item, 'title', title);
                                     setTimeout(() => {
                                         if (res.ret === 1) {
                                             this.$Message.success(res.msg);
-                                            this.$set(item, 'title', title);
                                         } else {
                                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
                                         }
@@ -593,10 +602,10 @@
                                 },
                                 success: (res) => {
                                     this.$Modal.remove();
+                                    this.getLists();
                                     setTimeout(() => {
                                         if (res.ret === 1) {
                                             this.$Message.success(res.msg);
-                                            this.getLists();
                                         } else {
                                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
                                         }

+ 1 - 1
resources/assets/js/main/pages/team.vue

@@ -201,10 +201,10 @@
                                                 },
                                                 success: (res) => {
                                                     this.$Modal.remove();
+                                                    this.getLists();
                                                     setTimeout(() => {
                                                         if (res.ret === 1) {
                                                             this.$Message.success(res.msg);
-                                                            this.getLists();
                                                         }else{
                                                             this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                                         }