kuaifan 5 年之前
父节点
当前提交
58cf4a1f38

+ 65 - 6
app/Http/Controllers/Api/ProjectController.php

@@ -965,6 +965,7 @@ class ProjectController extends Controller
      * @apiParam {Number} [projectid]           项目ID
      * @apiParam {String} [username]            负责人用户名(如果项目ID为空时此参数无效只获取自己的任务)
      * @apiParam {Number} [labelid]             项目子分类ID
+     * @apiParam {Number} [taskid]              任务ID (赋值返回详细数据,不返回列表数据)
      * @apiParam {Number} [level]               任务等级(1~4)
      * @apiParam {String} [archived]            任务是否归档
      * - 未归档 (默认)
@@ -1025,6 +1026,7 @@ class ProjectController extends Controller
             }
         }
         //
+        $taskid = intval(Request::input('taskid'));
         $whereRaw = null;
         $whereFunc = null;
         $whereArray = [];
@@ -1038,6 +1040,9 @@ class ProjectController extends Controller
         } else {
             $whereArray[] = ['project_task.username', '=', $user['username']];
         }
+        if ($taskid > 0) {
+            $whereArray[] = ['project_task.id', '=', intval(Request::input('taskid'))];
+        }
         if (intval(Request::input('labelid')) > 0) {
             $whereArray[] = ['project_task.labelid', '=', intval(Request::input('labelid'))];
         }
@@ -1094,7 +1099,7 @@ class ProjectController extends Controller
             ->where($whereArray)
             ->orderByRaw($orderBy)
             ->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
-        $lists = Base::getPageList($lists);
+        $lists = Base::getPageList($lists, $taskid > 0 ? false : true);
         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();
             $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();
@@ -1107,7 +1112,11 @@ class ProjectController extends Controller
             $info['overdue'] = Project::taskIsOverdue($info);
             $lists['lists'][$key] = array_merge($info, Users::username2basic($info['username']));
         }
-        return Base::retSuccess('success', $lists);
+        if ($taskid > 0) {
+            return Base::retSuccess('success', $lists['lists'][0]);
+        } else {
+            return Base::retSuccess('success', $lists);
+        }
     }
 
     /**
@@ -1182,7 +1191,6 @@ class ProjectController extends Controller
             'indate' => Base::time(),
             'startdate' => Base::time(),
             'subtask' => Base::array2string([]),
-            'files' => Base::array2string([]),
             'follower' => Base::array2string([]),
         ];
         return DB::transaction(function () use ($inArray) {
@@ -1216,7 +1224,7 @@ class ProjectController extends Controller
      * 项目任务-修改
      *
      * @apiParam {Number} taskid            任务ID
-     * @apiParam {String} act               修改字段
+     * @apiParam {String} act               修改字段|操作类型
      * - title: 标题
      * - desc: 描述
      * - level: 优先级
@@ -1228,7 +1236,8 @@ class ProjectController extends Controller
      * - archived: 归档
      * - unarchived: 取消归档
      * - delete: 删除任务
-     * @apiParam {String} [content]         修改内容
+     * - comment: 评论
+     * @apiParam {String} [content]         内容数据
      */
     public function task__edit()
     {
@@ -1565,6 +1574,30 @@ class ProjectController extends Controller
                 break;
             }
 
+            /**
+             * 评论任务
+             */
+            case 'comment': {
+                if (mb_strlen($content) < 2) {
+                    return Base::retError('评论内容至少2个字!');
+                }
+                $logArray[] = [
+                    'type' => '评论',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => $content,
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                    ])
+                ];
+                $message = "评论成功!";
+                break;
+            }
+
             default: {
                 return Base::retError('参数错误!');
                 break;
@@ -1577,7 +1610,11 @@ class ProjectController extends Controller
         if ($logArray) {
             DB::table('project_log')->insert($logArray);
         }
-        return Base::retSuccess($message ?: '修改成功!', array_merge($task, $upArray));
+        //
+        $task = array_merge($task, $upArray);
+        $task['overdue'] = Project::taskIsOverdue($task);
+        $task = array_merge($task, Users::username2basic($task['username']));
+        return Base::retSuccess($message ?: '修改成功!', $task);
     }
 
     /**
@@ -1904,6 +1941,10 @@ class ProjectController extends Controller
      *
      * @apiParam {Number} [projectid]           项目ID
      * @apiParam {Number} [taskid]              任务ID(如果项目ID为空时此参必须赋值且任务必须是自己负责人)
+     * @apiParam {String} [type]                类型
+     * - 全部: 日志+评论(默认)
+     * - 日志
+     * - 评论
      * @apiParam {String} [username]            用户名
      * @apiParam {Number} [page]                当前页,默认:1
      * @apiParam {Number} [pagesize]            每页显示数量,默认:20,最大:100
@@ -1927,6 +1968,7 @@ class ProjectController extends Controller
         //
         $taskid = intval(Request::input('taskid'));
         $whereArray = [];
+        $whereFunc = null;
         if ($projectid > 0) {
             $whereArray[] = ['projectid', '=', $projectid];
             if ($taskid > 0) {
@@ -1945,9 +1987,26 @@ class ProjectController extends Controller
         if (trim(Request::input('username'))) {
             $whereArray[] = ['username', '=', trim(Request::input('username'))];
         }
+        switch (trim(Request::input('type'))) {
+            case '日志': {
+                $whereArray[] = ['type', '=', '日志'];
+                break;
+            }
+            case '评论': {
+                $whereArray[] = ['type', '=', '评论'];
+                break;
+            }
+            default: {
+                $whereFunc = function ($query) {
+                    $query->whereIn('type', ['日志', '评论']);
+                };
+                break;
+            }
+        }
         //
         $lists = DB::table('project_log')
             ->where($whereArray)
+            ->where($whereFunc)
             ->orderByDesc('indate')->paginate(Min(Max(Base::nullShow(Request::input('pagesize'), 10), 1), 100));
         $lists = Base::getPageList($lists);
         if ($lists['total'] == 0) {

+ 5 - 1
resources/assets/js/common.js

@@ -1430,9 +1430,10 @@
         /**
          * 获取一些指定时间
          * @param str
+         * @param retInt
          * @returns {*|string}
          */
-        getData(str) {
+        getData(str, retInt = false) {
             let now = new Date();                   //当前日期
             let nowDayOfWeek = now.getDay();        //今天本周的第几天
             let nowDay = now.getDate();             //当前日
@@ -1520,6 +1521,9 @@
                     time = new Date(nowYear, quarterEndMonth, getMonthDays(quarterEndMonth));
                     break;
             }
+            if (retInt === true) {
+                return time;
+            }
             return $A.formatDate("Y-m-d", parseInt(time / 1000))
         },
 

+ 158 - 97
resources/assets/js/main/components/project/task/detail/detail.vue

@@ -11,13 +11,14 @@
                     </div>
                 </div>
                 <div class="detail-desc-box detail-icon">
-                    <div class="detail-h2"><strong>描述</strong></div>
+                    <div class="detail-h2"><strong class="active">描述</strong></div>
                     <textarea v-model="detail.desc" placeholder="添加详细描述..." @blur="handleTask('desc')"></textarea>
                 </div>
                 <ul class="detail-text-box">
                     <li v-if="detail.startdate > 0 && detail.enddate > 0" class="text-time detail-icon">
                         计划时间:
                         <em>{{$A.formatDate("Y-m-d H:i", detail.startdate)}} 至 {{$A.formatDate("Y-m-d H:i", detail.enddate)}}</em>
+                        <em v-if="detail.overdue" class="overdue">[已超期]</em>
                     </li>
                     <li class="text-username detail-icon">
                         负责人:
@@ -29,79 +30,70 @@
                     </li>
                     <li class="text-status detail-icon">
                         任务状态:
-                        <em v-if="detail.overdue" class="overdue">已超期</em>
-                        <em v-else-if="detail.complete" class="complete">已完成</em>
+                        <em v-if="detail.complete" class="complete">已完成</em>
                         <em v-else class="unfinished">未完成</em>
                     </li>
                 </ul>
                 <div :style="`${detail.filenum>0?'':'display:none'}`">
-                    <div class="detail-h2 detail-file-box detail-icon"><strong>附件</strong></div>
+                    <div class="detail-h2 detail-file-box detail-icon"><strong class="active">附件</strong></div>
                     <project-task-files ref="upload" :taskid="taskid" :simple="true" @change="handleTask('filechange', $event)"></project-task-files>
                 </div>
-                <div class="detail-h2 detail-comment-box detail-icon"><strong>评论</strong><em></em><strong>操作记录</strong></div>
+                <div class="detail-h2 detail-comment-box detail-icon"><strong class="link" :class="{active:logType=='评论'}" @click="logType='评论'">评论</strong><em></em><strong class="link" :class="{active:logType=='日志'}" @click="logType='日志'">操作记录</strong></div>
                 <div class="detail-log-box">
-                    <project-task-logs ref="log" :projectid="detail.projectid" :taskid="taskid" :pagesize="5"></project-task-logs>
+                    <project-task-logs ref="log" :logtype="logType" :projectid="detail.projectid" :taskid="taskid" :pagesize="5"></project-task-logs>
                 </div>
                 <div class="detail-footer-box">
                     <Input class="comment-input" v-model="commentText" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 3 }" :maxlength="255" @on-keydown="commentKeydown" placeholder="输入评论,Enter发表评论,Shift+Enter换行" />
-                    <Button type="primary">评 论</Button>
+                    <Button :loading="!!loadData.comment" :disabled="!commentText" type="primary" @click="handleTask('comment')">评 论</Button>
                 </div>
             </div>
             <div class="detail-right">
                 <div class="cancel"><em @click="visible=false"></em></div>
-                <div class="btn">
-                    <Dropdown trigger="click" @on-click="handleTask">
-                        <i class="ft icon">&#xE6CB;</i>标记{{detail.complete?'未完成':'已完成'}}
-                        <DropdownMenu slot="list">
-                            <DropdownItem name="complete">标记已完成<Icon v-if="detail.complete && !detail.archived" type="md-checkmark" class="checkmark"/></DropdownItem>
-                            <DropdownItem name="unfinished">标记未完成<Icon v-if="!detail.complete" type="md-checkmark" class="checkmark"/></DropdownItem>
-                            <DropdownItem name="archived2">完成并归档<Icon v-if="detail.complete && detail.archived" type="md-checkmark" class="checkmark"/></DropdownItem>
-                        </DropdownMenu>
-                    </Dropdown>
-                </div>
-                <div class="btn">
-                    <Dropdown trigger="click" @on-click="handleTask">
-                        <i class="ft icon">&#xE7AD;</i>优先级
-                        <DropdownMenu slot="list">
-                            <DropdownItem v-for="level in [1,2,3,4]" :key="level" :name="`level-${level}`" :class="`p${level}`">{{levelFormt(level)}}<Icon v-if="detail.level==level" type="md-checkmark" class="checkmark"/></DropdownItem>
-                        </DropdownMenu>
-                    </Dropdown>
-                </div>
-                <div class="btn">
-                    <Poptip placement="bottom" transfer>
-                        <i class="ft icon">&#xE6FD;</i>负责人
-                        <div slot="content">
-                            <div style="width:240px">
-                                选择负责人
-                                <UseridInput :projectid="detail.projectid" @change="handleTask('username', $event)" placeholder="输入关键词搜索" style="margin:5px 0 3px"></UseridInput>
-                            </div>
+                <Dropdown trigger="click" class="block" @on-click="handleTask">
+                    <Button :loading="!!loadData.unfinished || !!loadData.complete" icon="md-checkmark-circle-outline" class="btn">标记{{detail.complete?'未完成':'已完成'}}</Button>
+                    <DropdownMenu slot="list">
+                        <DropdownItem name="unfinished">标记未完成<Icon v-if="!detail.complete" type="md-checkmark" class="checkmark"/></DropdownItem>
+                        <DropdownItem name="complete">标记已完成<Icon v-if="detail.complete" type="md-checkmark" class="checkmark"/></DropdownItem>
+                        <DropdownItem name="archived2">完成并归档<Icon v-if="detail.complete && detail.archived" type="md-checkmark" class="checkmark"/></DropdownItem>
+                    </DropdownMenu>
+                </Dropdown>
+                <Dropdown trigger="click" class="block" @on-click="handleTask">
+                    <Button :loading="!!loadData.level" icon="md-funnel" class="btn">优先级</Button>
+                    <DropdownMenu slot="list">
+                        <DropdownItem v-for="level in [1,2,3,4]" :key="level" :name="`level-${level}`" :class="`p${level}`">{{levelFormt(level)}}<Icon v-if="detail.level==level" type="md-checkmark" class="checkmark"/></DropdownItem>
+                    </DropdownMenu>
+                </Dropdown>
+                <Poptip placement="bottom" class="block" transfer>
+                    <Button :loading="!!loadData.username" icon="md-person" class="btn">负责人</Button>
+                    <div slot="content">
+                        <div style="width:240px">
+                            选择负责人
+                            <UseridInput :projectid="detail.projectid" @change="handleTask('username', $event)" placeholder="输入关键词搜索" style="margin:5px 0 3px"></UseridInput>
                         </div>
-                    </Poptip>
-                </div>
-                <div class="btn">
-                    <Poptip ref="timeRef" placement="bottom" @on-popper-show="handleTask('opentime')" transfer>
-                        <i class="ft icon">&#xE706;</i>计划时间
-                        <div slot="content">
-                            <div style="width:280px">
-                                选择日期范围
-                                <Date-picker
-                                    v-model="timeValue"
-                                    :options="timeOptions"
-                                    :placeholder="$L('日期范围')"
-                                    format="yyyy-MM-dd HH:mm"
-                                    type="datetimerange"
-                                    placement="bottom"
-                                    @on-ok="handleTask('plannedtime')"
-                                    @on-clear="handleTask('unplannedtime')"
-                                    style="display:block;margin:5px 0 3px"></Date-picker>
-                            </div>
+                    </div>
+                </Poptip>
+                <Poptip ref="timeRef" placement="bottom" class="block" @on-popper-show="handleTask('opentime')" transfer>
+                    <Button :loading="!!loadData.plannedtime || !!loadData.unplannedtime" icon="md-calendar" class="btn">计划时间</Button>
+                    <div slot="content">
+                        <div style="width:280px">
+                            选择日期范围
+                            <Date-picker
+                                v-model="timeValue"
+                                :options="timeOptions"
+                                :placeholder="$L('日期范围')"
+                                format="yyyy-MM-dd HH:mm"
+                                type="datetimerange"
+                                placement="bottom"
+                                @on-ok="handleTask('plannedtime')"
+                                @on-clear="handleTask('unplannedtime')"
+                                style="display:block;margin:5px 0 3px"></Date-picker>
                         </div>
-                    </Poptip>
-                </div>
-                <div class="btn" @click="handleTask('fileupload')"><i class="ft icon">&#xE701;</i>添加附件</div>
-                <div v-if="!detail.archived" class="btn" @click="handleTask('archived')"><i class="ft icon">&#xE85F;</i>归档</div>
-                <div v-else class="btn" @click="handleTask('unarchived')"><i class="ft icon">&#xE85F;</i>取消归档</div>
-                <div class="btn remove" @click="handleTask('deleteb')"><i class="ft icon">&#xE6FB;</i>删除</div>
+                    </div>
+                </Poptip>
+                <Button icon="md-attach" class="btn" @click="handleTask('fileupload')">添加附件</Button>
+                <Button v-if="!detail.archived" :loading="!!loadData.archived" icon="md-filing" class="btn" @click="handleTask('archived')">归档</Button>
+                <Button v-else :loading="!!loadData.unarchived" icon="md-filing" class="btn" @click="handleTask('unarchived')">取消归档</Button>
+                <Button :loading="!!loadData.delete" icon="md-trash" class="btn" type="error" ghost @click="handleTask('deleteb')">删除</Button>
             </div>
         </div>
     </div>
@@ -114,12 +106,17 @@
         components: {ProjectTaskFiles, ProjectTaskLogs},
         data() {
             return {
-                visible: false,
                 taskid: 0,
                 detail: {},
+                callback: null,
+
+                visible: false,
+
                 bakData: {},
                 loadData: {},
+
                 commentText: '',
+                logType: '评论',
 
                 timeValue: [],
                 timeOptions: {
@@ -138,12 +135,12 @@
                     }, {
                         text: '本周',
                         value() {
-                            return [$A.getData('今天'), $A.getData('本周结束')];
+                            return [$A.getData('今天', true), $A.getData('本周结束', true)];
                         }
                     }, {
                         text: '本月',
                         value() {
-                            return [$A.getData('今天'), $A.getData('本月结束')];
+                            return [$A.getData('今天', true), $A.getData('本月结束', true)];
                         }
                     }, {
                         text: '3天',
@@ -195,10 +192,12 @@
                 }, 0)
             });
             this.bakData = $A.cloneData(this.detail);
+            this.getTaskDetail();
         },
         watch: {
             taskid() {
                 this.bakData = $A.cloneData(this.detail);
+                this.getTaskDetail();
             }
         },
         methods: {
@@ -222,10 +221,43 @@
                         return;
                     }
                     e.preventDefault();
+                    this.handleTask('comment');
                 }
             },
 
+            getTaskDetail() {
+                $A.aAjax({
+                    url: 'project/task/lists',
+                    data: {
+                        taskid: this.taskid
+                    },
+                    error: () => {
+                        alert(this.$L('网络繁忙,请稍后再试!'));
+                        this.visible = false;
+                    },
+                    success: (res) => {
+                        if (res.ret === 1) {
+                            this.detail = res.data;
+                            this.bakData = $A.cloneData(this.detail);
+                        } else {
+                            this.$Modal.error({
+                                title: this.$L('温馨提示'),
+                                content: res.msg,
+                                onOk: () => {
+                                    this.visible = false;
+                                }
+                            });
+                        }
+                    }
+                });
+            },
+
             handleTask(act, eve) {
+                if (!!this.loadData[act]) {
+                    this.$Message.info(this.$L('请稍候...'));
+                    return;
+                }
+                //
                 let ajaxData = {
                     act: act,
                     taskid: this.taskid,
@@ -240,6 +272,7 @@
                         }
                         if (!this.detail[act]) {
                             this.$set(this.detail, act, this.bakData[act]);
+                            return;
                         }
                         ajaxData.content = this.detail[act];
                         ajaxCallback = (res) => {
@@ -265,7 +298,7 @@
                                 break;
                         }
                         if (eve == 'add' || eve == 'delete') {
-                            this.$refs.log.getLists(true, true);
+                            this.logType == '日志' && this.$refs.log.getLists(true, true);
                         }
                         return;
 
@@ -300,7 +333,13 @@
                         ajaxData.content = eve.username;
                         ajaxCallback = (res) => {
                             if (res === 1) {
-                                this.visible = false;
+                                this.$Modal.info({
+                                    title: '温馨提示',
+                                    content: '任务负责人已改变,点击确定关闭窗口。',
+                                    onOk: () => {
+                                        this.visible = false;
+                                    }
+                                });
                             }
                         };
                         break;
@@ -321,7 +360,7 @@
 
                     case 'unplannedtime':
                         this.$refs.timeRef.handleClose();
-                        return;
+                        break;
 
                     case 'deleteb':
                         this.$Modal.confirm({
@@ -336,18 +375,41 @@
                     case 'delete':
                         ajaxCallback = (res) => {
                             if (res === 1) {
-                                this.visible = false;
+                                this.$Modal.info({
+                                    title: '温馨提示',
+                                    content: '任务已删除,点击确定关闭窗口。',
+                                    onOk: () => {
+                                        this.visible = false;
+                                    }
+                                });
                             }
                         };
                         break;
+
+                    case 'comment':
+                        if (!this.commentText) {
+                            return;
+                        }
+                        ajaxData.content = this.commentText;
+                        ajaxCallback = (res) => {
+                            if (res === 1) {
+                                this.commentText = "";
+                                this.logType == '评论' && this.$refs.log.getLists(true, true);
+                            }
+                        };
+                        break;
+
+                    default: {
+                        return;
+                    }
                 }
                 //
-                this.$set(this.loadData, act, true);
+                this.$set(this.loadData, ajaxData.act, true);
                 $A.aAjax({
                     url: 'project/task/edit',
                     data: ajaxData,
                     complete: () => {
-                        this.$set(this.loadData, act, false);
+                        this.$set(this.loadData, ajaxData.act, false);
                     },
                     error: () => {
                         ajaxCallback(-1);
@@ -358,8 +420,11 @@
                             this.detail = res.data;
                             this.bakData = $A.cloneData(this.detail);
                             if (ajaxCallback(1) !== false) {
+                                this.logType == '日志' && this.$refs.log.getLists(true, true);
                                 this.$Message.success(res.msg);
-                                this.$refs.log.getLists(true, true);
+                            }
+                            if (typeof this.callback === "function") {
+                                this.callback(ajaxData.act, res.data, ajaxData);
                             }
                         } else {
                             ajaxCallback(0);
@@ -396,9 +461,9 @@
         .task-detail-main {
             display: flex;
             flex-direction: row;
-            width: 96%;
+            width: 92%;
             max-width: 800px;
-            max-height: 96%;
+            max-height: 92%;
             background: #ffffff;
             overflow: hidden;
             border-radius: 4px;
@@ -415,8 +480,19 @@
                     display: flex;
                     align-items: center;
                     line-height: 26px;
+                    strong {
+                        font-size: 14px;
+                        font-weight: normal;
+                        &.link {
+                            cursor: pointer;
+                        }
+                        &.active {
+                            font-size: 16px;
+                            font-weight: bold;
+                        }
+                    }
                     em {
-                        margin: 0 11px;
+                        margin: 0 9px;
                         width: 1px;
                         height: 10px;
                         background: #cccccc;
@@ -492,14 +568,14 @@
                     li {
                         color: #606266;
                         font-size: 14px;
-                        line-height: 30px;
+                        line-height: 32px;
                         word-break: break-all;
                         &:before {
                             font-weight: normal;
                             color: #606266;
                             font-size: 14px;
                             padding-left: 4px;
-                            line-height: 30px;
+                            line-height: 32px;
                         }
                         &.text-time {
                             &:before {
@@ -611,28 +687,8 @@
                         }
                     }
                 }
-                .btn {
-                    background: rgba(9, 30, 66, 0.04);
-                    border: 1px solid #E8EAEE;
-                    border-radius: 4px;
-                    padding: 4px 8px;
-                    margin-top: 6px;
-                    color: #172b4d;
-                    cursor: pointer;
+                .block {
                     display: block;
-                    &:hover {
-                        border-color: #409EFF;
-                        background: #409EFF;
-                        color: #fff;
-                    }
-                    &.remove {
-                        color: rgba(248, 14, 21, 0.5);
-                        &:hover {
-                            border-color: #ffa5a3;
-                            background: #ffa5a3;
-                            color: #ffffff;
-                        }
-                    }
                     .p1 {
                         color: #ed3f14;
                     }
@@ -645,14 +701,19 @@
                     .p4 {
                         color: #666666;
                     }
-                    .icon {
-                        margin-right: 4px;
-                    }
                     .checkmark {
                         margin-left: 8px;
                         margin-right: -8px;
                     }
                 }
+                .btn {
+                    display: block;
+                    width: 118px;
+                    text-align: left;
+                    margin-top: 8px;
+                    padding-left: 10px;
+                    padding-right: 10px;
+                }
             }
         }
     }

+ 7 - 1
resources/assets/js/main/components/project/task/detail/index.js

@@ -1,7 +1,7 @@
 import Vue from 'vue';
 import component from './detail.vue'
 
-const detailElement = (taskid, detail = {}) => {
+const detailElement = (taskid, detail = {}, callback = null) => {
     let cloneData = (myObj) => {
         if (typeof (myObj) !== 'object') return myObj;
         if (myObj === null) return myObj;
@@ -17,6 +17,11 @@ const detailElement = (taskid, detail = {}) => {
     return new Promise(() => {
         let custom = Vue.extend(component);
 
+        if (typeof detail === "function") {
+            callback = detail;
+            detail = {};
+        }
+
         if (typeof taskid === 'object' && taskid !== null) {
             detail = cloneData(taskid);
             taskid = parseInt(taskid.id);
@@ -36,6 +41,7 @@ const detailElement = (taskid, detail = {}) => {
         let data = {
             taskid: taskid,
             detail: detail,
+            callback: callback,
         };
 
         let instance = new custom({

+ 37 - 5
resources/assets/js/main/components/project/task/logs.vue

@@ -2,11 +2,11 @@
     <drawer-tabs-container>
         <div class="project-task-logs">
             <ul class="logs-activity" :class="`${taskid>0?'istaskid':''}`">
-                <li v-for="(items, key) in lists">
-                    <div class="logs-date">{{key}}</div>
+                <li v-for="items in lists">
+                    <div class="logs-date">{{items | logDate}}</div>
                     <div class="logs-section">
                         <Timeline>
-                            <TimelineItem v-for="(item, index) in items" :key="index">
+                            <TimelineItem v-for="(item, index) in items.lists" :key="index">
                                 <div slot="dot" class="logs-dot">
                                     <img :src="item.userimg"/>
                                 </div>
@@ -22,6 +22,7 @@
                 </li>
                 <li v-if="loadIng > 0" class="logs-loading"><w-loading></w-loading></li>
                 <li v-else-if="hasMorePages" class="logs-more" @click="getMore">加载更多</li>
+                <li v-else-if="totalNum == 0" class="logs-none" @click="getLists(true)">没有相关{{logtype.indexOf(['日志', '评论'])===-1?logtype:'数据'}}</li>
             </ul>
         </div>
     </drawer-tabs-container>
@@ -52,6 +53,11 @@
                         color: #048be0;
                     }
                 }
+                &.logs-none {
+                    cursor: pointer;
+                    color: #666666;
+                    line-height: 26px;
+                }
                 &:first-child {
                     padding-top: 0;
                 }
@@ -123,6 +129,9 @@
             pagesize: {
                 default: 100
             },
+            logtype: {
+                default: '全部'
+            },
             canload: {
                 type: Boolean,
                 default: true
@@ -137,6 +146,7 @@
                 lists: {},
                 listPage: 1,
                 hasMorePages: false,
+                totalNum: -1,
             }
         },
 
@@ -151,14 +161,29 @@
             }
         },
 
+        filters: {
+            logDate(items) {
+                let md = $A.formatDate("m-d");
+                return md == items.ymd ? (items.ymd + ' 今天') : items.key;
+            }
+        },
+
         watch: {
             projectid() {
                 if (this.loadYet) {
+                    this.lists = {};
                     this.getLists(true);
                 }
             },
             taskid() {
                 if (this.loadYet) {
+                    this.lists = {};
+                    this.getLists(true);
+                }
+            },
+            logtype() {
+                if (this.loadYet) {
+                    this.lists = {};
                     this.getLists(true);
                 }
             },
@@ -183,6 +208,7 @@
                     data: {
                         projectid: this.projectid,
                         taskid: this.taskid,
+                        type: this.logtype,
                         page: Math.max(this.listPage, 1),
                         pagesize: this.pagesize,
                     },
@@ -202,14 +228,20 @@
                                 timeData = item.timeData;
                                 key = timeData.ymd + " " + timeData.week;
                                 if (typeof this.lists[key] !== "object") {
-                                    this.$set(this.lists, key, []);
+                                    this.$set(this.lists, key, {
+                                        key: key,
+                                        ymd: timeData.ymd,
+                                        lists: [],
+                                    });
                                 }
-                                this.lists[key].push(item);
+                                this.lists[key].lists.push(item);
                             });
                             this.hasMorePages = res.data.hasMorePages;
+                            this.totalNum = res.data.total;
                         } else {
                             this.lists = {};
                             this.hasMorePages = false;
+                            this.totalNum = 0;
                         }
                     }
                 });

+ 26 - 2
resources/assets/js/main/pages/todo.vue

@@ -50,7 +50,7 @@
                                     :disabled="taskSortDisabled"
                                     @sort="taskSortUpdate"
                                     @remove="taskSortUpdate">
-                                    <div v-for="task in taskDatas[index].lists" class="content-li task-draggable" :key="task.id" :class="{complete:task.complete}" @click="taskDetail(task)">
+                                    <div v-for="task in taskDatas[index].lists" class="content-li task-draggable" :key="task.id" :class="{complete:task.complete}" @click="openTaskModal(task)">
                                         <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>
@@ -380,7 +380,7 @@
                         level: index,
                         sorts: {key:'userorder', order:'desc'},
                         page: currentPage,
-                        pagesize: 10,
+                        pagesize: 20,
                     },
                     complete: () => {
                         this.taskSortDisabled = false;
@@ -528,6 +528,30 @@
                     }
                 });
             },
+
+            openTaskModal(task) {
+                this.taskDetail(task, (act, detail) => {
+                    for (let key in detail) {
+                        if (detail.hasOwnProperty(key)) {
+                            this.$set(task, key, detail[key])
+                        }
+                    }
+                    switch (act) {
+                        case "title": // 标题
+                        case "desc": // 描述
+                        case "level": // 优先级
+                        case "username": // 负责人
+                        case "plannedtime": // 设置计划时间
+                        case "unplannedtime": // 取消计划时间
+                        case "complete": // 标记完成
+                        case "unfinished": // 标记未完成
+                        case "archived": // 归档
+                        case "unarchived": // 取消归档
+                        case "delete": // 删除任务
+                        case "comment": // 评论
+                    }
+                })
+            }
         },
     }
 </script>