kuaifan 5 years ago
parent
commit
488a9c2b63

+ 57 - 41
app/Http/Controllers/Api/ProjectController.php

@@ -874,9 +874,11 @@ class ProjectController extends Controller
     /**
      * 项目任务-列表
      *
-     * @apiParam {Number} projectid             项目ID
+     * @apiParam {Number} [projectid]           项目ID
+     * @apiParam {String} [username]            负责人用户名(如果项目ID为空时此参数无效只获取自己的任务)
      * @apiParam {Number} [labelid]             项目子分类ID
-     * @apiParam {String} [archived]            是否归档
+     * @apiParam {Number} [level]               任务等级(1~4)
+     * @apiParam {String} [archived]            任务是否归档
      * - 未归档 (默认)
      * - 已归档
      * - 全部
@@ -885,11 +887,11 @@ class ProjectController extends Controller
      * - 未完成
      * - 已超期
      * - 已完成
-     * @apiParam {String} [username]            负责人用户名
      * @apiParam {Number} [statistics]          是否获取统计数据(1:获取)
      * @apiParam {Object} [sorts]               排序方式,格式:{key:'', order:''}("archived=已归档"时无效)
      * - key: title|labelid|enddate|username|level|indate|type
      * - order: asc|desc
+     * @apiParam {Number} [idlater]             获取数据ID之后的数据
      * @apiParam {Number} [page]                当前页,默认:1
      * @apiParam {Number} [pagesize]            每页显示数量,默认:20,最大:100
      */
@@ -903,9 +905,11 @@ class ProjectController extends Controller
         }
         //
         $projectid = intval(Request::input('projectid'));
-        $inRes = Project::inThe($projectid, $user['username']);
-        if (Base::isError($inRes)) {
-            return $inRes;
+        if ($projectid > 0) {
+            $inRes = Project::inThe($projectid, $user['username']);
+            if (Base::isError($inRes)) {
+                return $inRes;
+            }
         }
         //
         $orderBy = '`inorder` DESC,`id` DESC';
@@ -930,17 +934,24 @@ class ProjectController extends Controller
         }
         //
         $whereArray = [];
-        $whereArray[] = ['project_lists.id', '=', $projectid];
-        $whereArray[] = ['project_lists.delete', '=', 0];
         $whereArray[] = ['project_task.delete', '=', 0];
+        if ($projectid > 0) {
+            $whereArray[] = ['project_lists.id', '=', $projectid];
+            $whereArray[] = ['project_lists.delete', '=', 0];
+            if (trim(Request::input('username'))) {
+                $whereArray[] = ['project_task.username', '=', trim(Request::input('username'))];
+            }
+        } else {
+            $whereArray[] = ['project_task.username', '=', $user['username']];
+        }
         if (intval(Request::input('labelid')) > 0) {
             $whereArray[] = ['project_task.labelid', '=', intval(Request::input('labelid'))];
         }
         if (intval(Request::input('level')) > 0) {
             $whereArray[] = ['project_task.level', '=', intval(Request::input('level'))];
         }
-        if (trim(Request::input('username'))) {
-            $whereArray[] = ['project_task.username', '=', trim(Request::input('username'))];
+        if (intval(Request::input('idlater')) > 0) {
+            $whereArray[] = ['project_task.id', '<', intval(Request::input('idlater'))];
         }
         $archived = trim(Request::input('archived'));
         if (empty($archived)) $archived = "未归档";
@@ -968,11 +979,14 @@ class ProjectController extends Controller
                 break;
         }
         //
-        $lists = DB::table('project_lists')
-            ->join('project_task', 'project_lists.id', '=', 'project_task.projectid')
-            ->select(['project_task.*'])
+        $builder = DB::table('project_task');
+        if ($projectid > 0) {
+            $builder = $builder->join('project_lists', 'project_lists.id', '=', 'project_task.projectid');
+        }
+        $lists = $builder->select(['project_task.*'])
             ->where($whereArray)
-            ->orderByRaw($orderBy)->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
+            ->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('delete', 0)->where('complete', 0)->count();
@@ -992,13 +1006,11 @@ class ProjectController extends Controller
     /**
      * 项目任务-添加任务
      *
-     * @apiParam {Number} projectid             项目ID
-     * @apiParam {Number} labelid               项目子分类ID
      * @apiParam {String} title                 任务标题
      * @apiParam {Number} [level]               任务紧急级别(1~4,默认:2)
-     * @apiParam {String} [username]            任务负责人用户名
-     * - 0: 未归档
-     * - 1: 已归档
+     * @apiParam {String} [username]            任务负责人用户名(如果项目ID为空时此参数无效复制人为自己)
+     * @apiParam {Number} [projectid]           项目ID
+     * @apiParam {Number} [labelid]             项目子分类ID
      *
      * @throws \Throwable
      */
@@ -1012,31 +1024,35 @@ class ProjectController extends Controller
         }
         //
         $projectid = intval(Request::input('projectid'));
-        $projectDetail = Base::DBC2A(DB::table('project_lists')->where('id', $projectid)->where('delete', 0)->first());
-        if (empty($projectDetail)) {
-            return Base::retError('项目不存在或已被删除!');
-        }
-        //
         $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('项目子分类不存在或已被删除!');
-        }
-        //
-        $inRes = Project::inThe($projectid, $user['username']);
-        if (Base::isError($inRes)) {
-            return $inRes;
-        }
-        //
-        $username = trim(Request::input('username'));
-        if (empty($username)) {
-            $username = $user['username'];
-        }
-        if ($username != $user['username']) {
-            $inRes = Project::inThe($projectid, $username);
+        if ($projectid > 0) {
+            $projectDetail = Base::DBC2A(DB::table('project_lists')->where('id', $projectid)->where('delete', 0)->first());
+            if (empty($projectDetail)) {
+                return Base::retError('项目不存在或已被删除!');
+            }
+            //
+            $labelDetail = Base::DBC2A(DB::table('project_label')->where('id', $labelid)->where('projectid', $projectid)->first());
+            if (empty($labelDetail)) {
+                return Base::retError('项目子分类不存在或已被删除!');
+            }
+            //
+            $inRes = Project::inThe($projectid, $user['username']);
             if (Base::isError($inRes)) {
-                return Base::retError('负责人不在项目成员内!');
+                return $inRes;
             }
+            //
+            $username = trim(Request::input('username'));
+            if (empty($username)) {
+                $username = $user['username'];
+            }
+            if ($username != $user['username']) {
+                $inRes = Project::inThe($projectid, $username);
+                if (Base::isError($inRes)) {
+                    return Base::retError('负责人不在项目成员内!');
+                }
+            }
+        } else {
+            $username = $user['username'];
         }
         //
         $title = trim(Request::input('title'));

+ 16 - 0
resources/assets/js/common.js

@@ -87,6 +87,22 @@
         },
 
         /**
+         * 删除左边字符串
+         * @param string
+         * @param find
+         * @param lower
+         * @returns {string}
+         */
+        leftDelete: function (string, find, lower) {
+            string += "";
+            find += "";
+            if (this.leftExists(string, find, lower)) {
+                string = string.substring(find.length)
+            }
+            return string ? string : '';
+        },
+
+        /**
          * 字符串是否右边包含
          * @param string
          * @param find

+ 3 - 1
resources/assets/js/main/components/WContent.vue

@@ -12,7 +12,9 @@
         right: 0;
         bottom: 0;
         overflow: auto;
-        background: url("../../../statics/images/bg1.jpg") no-repeat center;
+        background-repeat: no-repeat;
+        background-position: center;
+        background-image: url("../../../statics/images/bg1.jpg");
         background-size: cover;
 
         .w-container {

+ 280 - 52
resources/assets/js/main/pages/todo.vue

@@ -22,54 +22,35 @@
 
         <w-content>
             <div class="todo-main">
-                <ul>
-                    <li>
+                <ul v-for="subs in [['1', '2'], ['3', '4']]">
+                    <li v-for="index in subs">
                         <div class="todo-card">
-                            <div class="todo-card-head p1">
+                            <div class="todo-card-head" :class="['p' + index]">
                                 <i class="ft icon flag">&#xE753;</i>
-                                <div class="todo-card-title">{{$L('重要且紧急')}}</div>
-                                <i class="ft icon close">&#xE740;</i>
+                                <div class="todo-card-title">{{$L(pTitle(index))}}</div>
+                                <label class="todo-input-box" :class="{active: !!taskDatas[index].focus}" @click="()=>{$set(taskDatas[index],'focus',true)}">
+                                    <div class="todo-input-ibox" @click.stop="">
+                                        <Input v-model="taskDatas[index].title" class="todo-input-enter" :placeholder="$L('在这里输入事项,回车即可保存')" @on-enter="addTask(index)"></Input>
+                                        <div class="todo-input-close" @click="()=>{$set(taskDatas[index],'focus',false)}"><i class="ft icon">&#xE710;</i></div>
+                                    </div>
+                                    <div class="todo-input-pbox">
+                                        <div class="todo-input-placeholder">{{$L('点击可快速添加需要处理的事项')}}</div>
+                                        <div class="todo-input-close"><i class="ft icon">&#xE740;</i></div>
+                                    </div>
+                                </label>
                             </div>
                             <div class="todo-card-content">
-                                <div class="empty">{{$L('恭喜你!已完成了所有待办')}}</div>
-                            </div>
-                        </div>
-                    </li>
-                    <li>
-                        <div class="todo-card">
-                            <div class="todo-card-head p2">
-                                <i class="ft icon flag">&#xE753;</i>
-                                <div class="todo-card-title">{{$L('重要不紧急')}}</div>
-                                <i class="ft icon close">&#xE740;</i>
-                            </div>
-                            <div class="todo-card-content">
-                                <div class="empty">{{$L('恭喜你!已完成了所有待办')}}</div>
-                            </div>
-                        </div>
-                    </li>
-                </ul>
-                <ul>
-                    <li>
-                        <div class="todo-card">
-                            <div class="todo-card-head p3">
-                                <i class="ft icon flag">&#xE753;</i>
-                                <div class="todo-card-title">{{$L('紧急不重要')}}</div>
-                                <i class="ft icon close">&#xE740;</i>
-                            </div>
-                            <div class="todo-card-content">
-                                <div class="empty">{{$L('恭喜你!已完成了所有待办')}}</div>
-                            </div>
-                        </div>
-                    </li>
-                    <li>
-                        <div class="todo-card">
-                            <div class="todo-card-head p4">
-                                <i class="ft icon flag">&#xE753;</i>
-                                <div class="todo-card-title">{{$L('不重要不紧急')}}</div>
-                                <i class="ft icon close">&#xE740;</i>
-                            </div>
-                            <div class="todo-card-content">
-                                <div class="empty">{{$L('恭喜你!已完成了所有待办')}}</div>
+                                <ul v-if="taskDatas[index].lists.length > 0">
+                                    <li v-for="task in taskDatas[index].lists" :key="task.id" :class="{complete:task.complete}">
+                                        <Icon v-if="task.complete" class="task-check" type="md-checkbox-outline" />
+                                        <Icon v-else class="task-check" type="md-square-outline" />
+                                        <div v-if="task.overdue" class="task-overdue">[超期]</div>
+                                        <div class="task-title">{{task.title}}</div>
+                                    </li>
+                                    <li v-if="taskDatas[index].hasMorePages === true" class="more" @click="getTask(index, true)">加载更多</li>
+                                </ul>
+                                <div v-else-if="taskDatas[index].loadIng == 0" class="content-empty">{{$L('恭喜你!已完成了所有待办')}}</div>
+                                <div v-if="taskDatas[index].loadIng > 0" class="content-loading"><w-loading></w-loading></div>
                             </div>
                         </div>
                     </li>
@@ -80,6 +61,14 @@
     </div>
 </template>
 
+<style lang="scss">
+    .todo-input-enter {
+        .ivu-input {
+            border: 0;
+            background-color: rgba(255, 255, 255, 0.9);
+        }
+    }
+</style>
 <style lang="scss" scoped>
     .todo {
         .todo-main {
@@ -113,7 +102,8 @@
                         .todo-card-head {
                             display: flex;
                             align-items: center;
-                            padding: 8px 10px;
+                            padding: 0 10px;
+                            height: 38px;
                             border-radius: 4px 4px 0 0;
                             color: #ffffff;
                             .ft.icon {
@@ -123,15 +113,62 @@
                                 font-weight: bold;
                                 font-size: 14px;
                                 margin-right: 5px;
-                            }
-                            .close {
-                                font-size: 18px;
-                                font-weight: normal;
+                                min-width: 16px;
                             }
                             .todo-card-title {
-                                flex: 1;
                                 font-weight: bold;
                             }
+                            .todo-input-box {
+                                flex: 1;
+                                display: flex;
+                                flex-direction: row;
+                                align-items: center;
+                                justify-content: flex-end;
+                                height: 100%;
+                                cursor: pointer;
+                                &:hover {
+                                    .todo-input-placeholder {
+                                        opacity: 1;
+                                    }
+                                }
+                                &.active {
+                                    .todo-input-pbox {
+                                        display: none;
+                                    }
+                                    .todo-input-ibox {
+                                        display: flex;
+                                    }
+                                }
+                                .todo-input-placeholder {
+                                    color: rgba(255, 255, 255, 0.6);
+                                    padding-right: 6px;
+                                    transition: all 0.2s;
+                                    opacity: 0;
+                                }
+                                .todo-input-pbox,
+                                .todo-input-ibox {
+                                    flex: 1;
+                                    display: flex;
+                                    flex-direction: row;
+                                    align-items: center;
+                                    justify-content: flex-end;
+                                    padding-left: 14px;
+                                    height: 100%;
+                                }
+                                .todo-input-ibox {
+                                    display: none;
+                                }
+                                .todo-input-close {
+                                    height: 100%;
+                                    display: flex;
+                                    align-items: center;
+                                    padding-left: 8px;
+                                    i {
+                                        font-size: 18px;
+                                        font-weight: normal;
+                                    }
+                                }
+                            }
                             &.p1 {
                                 background: rgba(248, 14, 21, 0.6);
                             }
@@ -149,7 +186,57 @@
                             flex: 1;
                             background-color: #f5f6f7;
                             border-radius: 0 0 4px 4px;
-                            .empty {
+                            overflow: auto;
+                            transform: translateZ(0);
+                            ul {
+                                display: flex;
+                                flex-direction: column;
+                                li {
+                                    display: flex;
+                                    flex-direction: row;
+                                    align-items: flex-start;
+                                    width: 100%;
+                                    padding: 8px;
+                                    color: #444444;
+                                    border-bottom: dotted 1px rgba(153, 153, 153, 0.25);
+                                    position: relative;
+                                    cursor: pointer;
+                                    &.complete {
+                                        color: #999999;
+                                        .task-title {
+                                            text-decoration: line-through;
+                                        }
+                                    }
+                                    &.more {
+                                        color: #666;
+                                        justify-content: center;
+                                    }
+                                    .task-check {
+                                        font-size: 16px;
+                                        padding-right: 6px;
+                                        padding-top: 2px;
+                                    }
+                                    .task-overdue {
+                                        color: #ff0000;
+                                        padding-right: 2px;
+                                    }
+                                    .task-title {
+                                        flex: 1;
+                                        word-break: break-all;
+                                        &:hover {
+                                            color: #000000;
+                                        }
+                                    }
+                                }
+                            }
+                            .content-loading {
+                                width: 100%;
+                                height: 22px;
+                                text-align: center;
+                                margin-top: 8px;
+                                margin-bottom: 8px;
+                            }
+                            .content-empty {
                                 margin: 20px auto;
                                 text-align: center;
                                 color: #666;
@@ -159,22 +246,56 @@
                 }
             }
         }
+        @media (max-width: 780px) {
+            .todo-main {
+                height: auto;
+                ul {
+                    flex-direction: column;
+                    li {
+                        width: 100%;
+                        .todo-card {
+                            position: static;
+                            top: 0;
+                            right: 0;
+                            left: 0;
+                            bottom: 0;
+                            margin: 10px;
+                            display: flex;
+                            flex-direction: column;
+                            min-height: 320px;
+                            max-height: 520px;
+                        }
+                    }
+                }
+            }
+        }
     }
 </style>
 <script>
     import WHeader from "../components/WHeader";
     import WContent from "../components/WContent";
+    import WLoading from "../components/WLoading";
     export default {
-        components: {WContent, WHeader},
+        components: {WContent, WHeader, WLoading},
         data () {
             return {
                 userInfo: {},
+
+                taskDatas: {
+                    "1": {lists: [], hasMorePages: false},
+                    "2": {lists: [], hasMorePages: false},
+                    "3": {lists: [], hasMorePages: false},
+                    "4": {lists: [], hasMorePages: false},
+                },
             }
         },
         mounted() {
             this.userInfo = $A.getUserInfo((res) => {
                 this.userInfo = res;
             });
+            for (let i = 1; i <= 4; i++) {
+                this.getTask(i.toString());
+            }
         },
         computed: {
 
@@ -183,7 +304,114 @@
 
         },
         methods: {
+            pTitle(p) {
+                switch (p) {
+                    case "1":
+                        return "重要且紧急";
+                    case "2":
+                        return "重要不紧急";
+                    case "3":
+                        return "紧急不重要";
+                    case "4":
+                        return "不重要不紧急";
+                }
+            },
+
+            getTask(index, isNext) {
+                let taskData = this.taskDatas[index];
+                let idlater = 0;
+                if (isNext === true) {
+                    if (taskData.hasMorePages !== true) {
+                        return;
+                    }
+                    idlater = taskData.lists[taskData.lists.length - 1].id
+                }
+                this.$set(taskData, 'hasMorePages', false);
+                this.$set(taskData, 'loadIng', $A.runNum(taskData.loadIng) + 1);
+                $A.aAjax({
+                    url: 'project/task/lists',
+                    data: {
+                        level: index,
+                        idlater: idlater,
+                        page: 1,
+                        pagesize: 10,
+                    },
+                    complete: () => {
+                        this.$set(taskData, 'loadIng', $A.runNum(taskData.loadIng) - 1);
+                    },
+                    success: (res) => {
+                        if (res.ret === 1) {
+                            let inLists;
+                            res.data.lists.forEach((data) => {
+                                inLists = false;
+                                taskData.lists.some((item, i) => {
+                                    if (item.id == data.id) {
+                                        taskData.lists.splice(i, 1, data);
+                                        return inLists = true;
+                                    }
+                                });
+                                if (!inLists) {
+                                    taskData.lists.push(data);
+                                }
+                            });
+                            this.$set(taskData, 'hasMorePages', res.data.hasMorePages);
+                        } else {
+                            this.$set(taskData, 'lists', []);
+                            this.$set(taskData, 'hasMorePages', false);
+                        }
+                    }
+                });
+            },
 
+            addTask(index) {
+                let taskData = this.taskDatas[index];
+                let title = $A.trim(taskData.title);
+                if ($A.count(title) == 0) {
+                    return;
+                }
+                this.$set(taskData, 'focus', false);
+                this.$set(taskData, 'title', '');
+                //
+                let tempId = $A.randomString(16);
+                taskData.lists.unshift({
+                    id: tempId,
+                    title: title,
+                    loadIng: true,
+                });
+                $A.aAjax({
+                    url: 'project/task/add',
+                    data: {
+                        title: title,
+                        level: index,
+                    },
+                    error: () => {
+                        taskData.lists.some((item, i) => {
+                            if (item.id == tempId) {
+                                taskData.lists.splice(i, 1);
+                                return true;
+                            }
+                        });
+                        alert(this.$L('网络繁忙,请稍后再试!'));
+                    },
+                    success: (res) => {
+                        if (res.ret === 1) {
+                            this.$Message.success(res.msg);
+                        } else {
+                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
+                        }
+                        taskData.lists.some((item, i) => {
+                            if (item.id == tempId) {
+                                if (res.ret === 1) {
+                                    taskData.lists.splice(i, 1, res.data);
+                                } else {
+                                    taskData.lists.splice(i, 1);
+                                }
+                                return true;
+                            }
+                        });
+                    }
+                });
+            }
         },
     }
 </script>