kuaifan 5 rokov pred
rodič
commit
c5ec9377c2

+ 369 - 51
app/Http/Controllers/Api/ProjectController.php

@@ -1213,14 +1213,24 @@ class ProjectController extends Controller
     }
 
     /**
-     * 项目任务-归档、取消归档
+     * 项目任务-修改
      *
-     * @apiParam {String} act
-     * - cancel: 取消归档
-     * - else: 加入归档
-     * @apiParam {Number} taskid             任务ID
+     * @apiParam {Number} taskid            任务ID
+     * @apiParam {String} act               修改字段
+     * - title: 标题
+     * - desc: 描述
+     * - level: 优先级
+     * - username: 负责人
+     * - plannedtime: 设置计划时间
+     * - unplannedtime: 取消计划时间
+     * - complete: 标记完成
+     * - unfinished: 标记未完成
+     * - archived: 归档
+     * - unarchived: 取消归档
+     * - delete: 删除任务
+     * @apiParam {String} [content]         修改内容
      */
-    public function task__archived()
+    public function task__edit()
     {
         $user = Users::authE();
         if (Base::isError($user)) {
@@ -1230,77 +1240,351 @@ class ProjectController extends Controller
         }
         //
         $taskid = intval(Request::input('taskid'));
-        $task = Base::DBC2A(DB::table('project_lists')
-            ->join('project_task', 'project_lists.id', '=', 'project_task.projectid')
-            ->select(['project_task.projectid', 'project_task.title', 'project_task.archived'])
+        $task = Base::DBC2A(DB::table('project_task')
             ->where([
-                ['project_lists.delete', '=', 0],
-                ['project_task.delete', '=', 0],
-                ['project_task.id', '=', $taskid],
+                ['delete', '=', 0],
+                ['id', '=', $taskid],
             ])
             ->first());
         if (empty($task)) {
             return Base::retError('任务不存在!');
         }
-        $inRes = Project::inThe($task['projectid'], $user['username']);
-        if (Base::isError($inRes)) {
-            return $inRes;
+        if ($task['projectid'] > 0) {
+            $inRes = Project::inThe($task['projectid'], $user['username']);
+            if (Base::isError($inRes)) {
+                return $inRes;
+            }
+            if (!$inRes['data']['isowner'] && $task['username'] != $user['username']) {
+                return Base::retError('此操作只允许项目管理员或者任务负责人!');
+            }
+        } else {
+            if ($task['username'] != $user['username']) {
+                return Base::retError('此操作只允许任务负责人!');
+            }
         }
         //
-        switch (Request::input('act')) {
-            case 'cancel': {
+        $act = trim(Request::input('act'));
+        $content = trim(Request::input('content'));
+        $message = "";
+        $upArray = [];
+        $logArray = [];
+        switch ($act) {
+            /**
+             * 修改标题
+             */
+            case 'title': {
+                if ($content == $task['title']) {
+                    return Base::retError('标题未做改变!');
+                }
+                $upArray['title'] = $content;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '修改任务标题',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $content,
+                        'old_title' => $task['title'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 修改描述
+             */
+            case 'desc': {
+                if ($content == $task['desc']) {
+                    return Base::retError('描述未做改变!');
+                }
+                $upArray['desc'] = $content;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '修改任务描述',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                        'old_desc' => $task['desc'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 调整任务等级
+             */
+            case 'level': {
+                $content = intval($content);
+                if ($content == $task['level']) {
+                    return Base::retError('优先级未做改变!');
+                }
+                if ($content > 4 || $content < 1) {
+                    return Base::retError('优先级参数错误!');
+                }
+                $upArray['level'] = $content;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '调整任务等级为【P' . $content . '】',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                        'old_level' => $task['level'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 修改任务负责人
+             */
+            case 'username': {
+                if ($content == $task['username']) {
+                    return Base::retError('负责人未做改变!');
+                }
+                if ($task['projectid'] > 0) {
+                    $inRes = Project::inThe($task['projectid'], $content);
+                    if (Base::isError($inRes)) {
+                        return Base::retError($content . '不在成员列表内!');
+                    }
+                }
+                $upArray['username'] = $content;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '修改负责人',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                        'old_username' => $task['username'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 修改计划时间
+             */
+            case 'plannedtime': {
+                list($startdate, $enddate) = explode(",", $content);
+                if (!Base::isDate($startdate) || !Base::isDate($enddate)) {
+                    return Base::retError('计划时间参数错误!');
+                }
+                $startdate = strtotime($startdate);
+                $enddate = strtotime($enddate);
+                if ($startdate == $task['startdate'] && $enddate == $task['enddate']) {
+                    return Base::retError('与原计划时间一致!');
+                }
+                $upArray['startdate'] = $startdate;
+                $upArray['enddate'] = $enddate;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '设置计划时间',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                        'old_startdate' => $task['startdate'],
+                        'old_enddate' => $task['enddate'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 取消计划时间
+             */
+            case 'unplannedtime': {
+                $startdate = 0;
+                $enddate = 0;
+                if ($startdate == $task['startdate'] && $enddate == $task['enddate']) {
+                    return Base::retError('与原计划时间一致!');
+                }
+                $upArray['startdate'] = $startdate;
+                $upArray['enddate'] = $enddate;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '取消计划时间',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                        'old_startdate' => $task['startdate'],
+                        'old_enddate' => $task['enddate'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 标记完成
+             */
+            case 'complete': {
+                if ($task['complete'] == 1) {
+                    return Base::retError('任务已标记完成,请勿重复操作!');
+                }
+                $upArray['complete'] = 1;
+                $upArray['completedate'] = Base::time();
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '标记已完成',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 标记未完成
+             */
+            case 'unfinished': {
+                if ($task['complete'] == 0) {
+                    return Base::retError('任务未完成,无法标记未完成!');
+                }
+                $upArray['complete'] = 0;
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '标记未完成',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 归档
+             */
+            case 'archived': {
+                if ($task['archived'] == 1) {
+                    return Base::retError('任务已经归档,请勿重复操作!');
+                }
+                $upArray['archived'] = 1;
+                $upArray['archiveddate'] = Base::time();
+                $logArray[] = [
+                    'type' => '日志',
+                    'projectid' => $task['projectid'],
+                    'taskid' => $task['id'],
+                    'username' => $user['username'],
+                    'detail' => '任务归档',
+                    'indate' => Base::time(),
+                    'other' => Base::array2string([
+                        'type' => 'task',
+                        'id' => $task['id'],
+                        'title' => $task['title'],
+                    ])
+                ];
+                break;
+            }
+
+            /**
+             * 取消归档
+             */
+            case 'unarchived': {
                 if ($task['archived'] == 0) {
-                    return Base::retError('任务未归档!');
+                    return Base::retError('任务未归档,无法取消归档操作!');
                 }
-                DB::table('project_task')->where('id', $taskid)->update([
-                    'archived' => 1,
-                    'archiveddate' => Base::time()
-                ]);
-                DB::table('project_log')->insert([
+                $upArray['archived'] = 0;
+                $logArray[] = [
                     'type' => '日志',
                     'projectid' => $task['projectid'],
-                    'taskid' => $taskid,
+                    'taskid' => $task['id'],
                     'username' => $user['username'],
                     'detail' => '取消归档',
                     'indate' => Base::time(),
                     'other' => Base::array2string([
                         'type' => 'task',
-                        'id' => $taskid,
+                        'id' => $task['id'],
                         'title' => $task['title'],
                     ])
-                ]);
-                return Base::retSuccess('取消归档成功!');
+                ];
+                break;
             }
-            default: {
-                if ($task['archived'] == 1) {
-                    return Base::retError('任务已归档!');
+
+            /**
+             * 删除任务
+             */
+            case 'delete': {
+                if ($task['delete'] == 1) {
+                    return Base::retError('任务已删除,请勿重复操作!');
                 }
-                DB::table('project_task')->where('id', $taskid)->update([
-                    'archived' => 0,
-                ]);
-                DB::table('project_log')->insert([
+                $upArray['delete'] = 1;
+                $upArray['deletedate'] = Base::time();
+                $logArray[] = [
                     'type' => '日志',
                     'projectid' => $task['projectid'],
-                    'taskid' => $taskid,
+                    'taskid' => $task['id'],
                     'username' => $user['username'],
-                    'detail' => '加入归档',
+                    'detail' => '删除任务',
                     'indate' => Base::time(),
                     'other' => Base::array2string([
                         'type' => 'task',
-                        'id' => $taskid,
+                        'id' => $task['id'],
                         'title' => $task['title'],
                     ])
-                ]);
-                return Base::retSuccess('加入归档成功!');
+                ];
+                $message = "删除成功!";
+                break;
+            }
+
+            default: {
+                return Base::retError('参数错误!');
+                break;
             }
         }
+        //
+        if ($upArray) {
+            DB::table('project_task')->where('id', $taskid)->update($upArray);
+        }
+        if ($logArray) {
+            DB::table('project_log')->insert($logArray);
+        }
+        return Base::retSuccess($message ?: '修改成功!', array_merge($task, $upArray));
     }
 
     /**
      * 项目文件-列表
      *
-     * @apiParam {Number} projectid             项目ID
-     * @apiParam {Number} [taskid]              任务ID
+     * @apiParam {Number} [projectid]           项目ID
+     * @apiParam {Number} [taskid]              任务ID(如果项目ID为空时此参必须赋值且任务必须是自己负责人)
      * @apiParam {String} [name]                文件名称
      * @apiParam {String} [username]            上传者用户名
      * @apiParam {Object} [sorts]               排序方式,格式:{key:'', order:''}
@@ -1319,9 +1603,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 = '`id` DESC';
@@ -1338,8 +1624,23 @@ class ProjectController extends Controller
             }
         }
         //
+        $taskid = intval(Request::input('taskid'));
         $whereArray = [];
-        $whereArray[] = ['projectid', '=', $projectid];
+        if ($projectid > 0) {
+            $whereArray[] = ['projectid', '=', $projectid];
+            if ($taskid > 0) {
+                $whereArray[] = ['taskid', '=', $taskid];
+            }
+        } else {
+            if ($taskid < 0) {
+                return Base::retError('参数错误!');
+            }
+            $count = DB::table('project_task')->where([ 'id' => $taskid, 'username' => $user['username']])->count();
+            if ($count <= 0) {
+                return Base::retError('你不是任务负责人!');
+            }
+            $whereArray[] = ['taskid', '=', $taskid];
+        }
         $whereArray[] = ['delete', '=', 0];
         if (intval(Request::input('taskid')) > 0) {
             $whereArray[] = ['taskid', '=', intval(Request::input('taskid'))];
@@ -1369,8 +1670,8 @@ class ProjectController extends Controller
     /**
      * 项目文件-上传
      *
-     * @apiParam {Number} projectid             项目ID
-     * @apiParam {Number} [taskid]              任务ID
+     * @apiParam {Number} [projectid]           项目ID
+     * @apiParam {Number} [taskid]              任务ID(如果项目ID为空时此参必须赋值且任务必须是自己负责人)
      */
     public function files__upload()
     {
@@ -1383,9 +1684,20 @@ class ProjectController extends Controller
         //
         $projectid = intval(Request::input('projectid'));
         $taskid = intval(Request::input('taskid'));
-        $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;
+            }
+        } else {
+            if ($taskid <= 0) {
+                return Base::retError('参数错误!');
+            }
+            $row = Base::DBC2A(DB::table('project_task')->select(['projectid'])->where([ 'id' => $taskid, 'username' => $user['username']])->first());
+            if (empty($row)) {
+                return Base::retError('你不是任务负责人!');
+            }
+            $projectid = $row['projectid'];
         }
         //
         $data = Base::upload([
@@ -1454,12 +1766,15 @@ class ProjectController extends Controller
                     'name' => $fileData['name'],
                 ])
             ]);
+            if ($taskid > 0) {
+                DB::table('project_task')->where('id', $taskid)->increment('filenum');
+            }
             return Base::retSuccess('success', $array);
         }
     }
 
     /**
-     * 项目文件-上传
+     * 项目文件-下载
      *
      * @apiParam {Number} fileid                文件ID
      */
@@ -1577,6 +1892,9 @@ class ProjectController extends Controller
                 'name' => $fileDetail['name'],
             ])
         ]);
+        if ($fileDetail['taskid'] > 0) {
+            DB::table('project_task')->where('id', $fileDetail['taskid'])->decrement('filenum');
+        }
         //
         return Base::retSuccess('删除成功!');
     }

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

@@ -59,7 +59,7 @@
          * @param lower
          * @returns {boolean}
          */
-        strExists: function (string, find, lower) {
+        strExists: function (string, find, lower = false) {
             string += "";
             find += "";
             if (lower !== true) {
@@ -76,7 +76,7 @@
          * @param lower
          * @returns {boolean}
          */
-        leftExists: function (string, find, lower) {
+        leftExists: function (string, find, lower = false) {
             string += "";
             find += "";
             if (lower !== true) {
@@ -93,7 +93,7 @@
          * @param lower
          * @returns {string}
          */
-        leftDelete: function (string, find, lower) {
+        leftDelete: function (string, find, lower = false) {
             string += "";
             find += "";
             if (this.leftExists(string, find, lower)) {
@@ -109,7 +109,7 @@
          * @param lower
          * @returns {boolean}
          */
-        rightExists: function (string, find, lower) {
+        rightExists: function (string, find, lower = false) {
             string += "";
             find += "";
             if (lower !== true) {
@@ -127,6 +127,7 @@
          * @returns {*}
          */
         getMiddle: function (string, start, end) {
+            string = string.toString();
             if (this.ishave(start) && this.strExists(string, start)) {
                 string = string.substring(string.indexOf(start) + start.length);
             }

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

@@ -82,9 +82,9 @@
                                     loading: true,
                                     onOk: () => {
                                         $A.aAjax({
-                                            url: 'project/task/archived',
+                                            url: 'project/task/edit',
                                             data: {
-                                                act: 'cancel',
+                                                act: 'unarchived',
                                                 taskid: params.row.id,
                                             },
                                             error: () => {

+ 314 - 21
resources/assets/js/main/components/project/task/detail/detail.vue

@@ -3,7 +3,7 @@
         <div class="task-detail-main">
             <div class="detail-left">
                 <div class="detail-title-box detail-icon">
-                    <input v-model="detail.title" type="text" maxlength="60">
+                    <input v-model="detail.title" :disabled="!!loadData.title" type="text" maxlength="60" @blur="handleTask('title')">
                     <div class="time">
                         <span class="z-nick">{{detail.createuser}}</span>
                         创建于:
@@ -12,16 +12,20 @@
                 </div>
                 <div class="detail-desc-box detail-icon">
                     <div class="detail-h2"><strong>描述</strong></div>
-                    <textarea placeholder="添加详细描述..."></textarea>
+                    <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>
+                    </li>
                     <li class="text-username detail-icon">
                         负责人:
                         <em>{{detail.username}}</em>
                     </li>
                     <li class="text-level detail-icon">
                         优先级:
-                        <em :class="`p${detail.level}`">P{{detail.level}}</em>
+                        <em :class="`p${detail.level}`">{{levelFormt(detail.level)}}</em>
                     </li>
                     <li class="text-status detail-icon">
                         任务状态:
@@ -30,9 +34,13 @@
                         <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>
+                    <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-log-box">
-                    <project-task-logs :projectid="detail.projectid" :taskid="detail.taskid" :pagesize="5"></project-task-logs>
+                    <project-task-logs ref="log" :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换行" />
@@ -41,13 +49,59 @@
             </div>
             <div class="detail-right">
                 <div class="cancel"><em @click="visible=false"></em></div>
-                <div class="btn"><i class="ft icon">&#xE6CB;</i>标记已完成</div>
-                <div class="btn"><i class="ft icon">&#xE7AD;</i>优先级</div>
-                <div class="btn"><i class="ft icon">&#xE6FD;</i>负责人</div>
-                <div class="btn"><i class="ft icon">&#xE706;</i>计划时间</div>
-                <div class="btn"><i class="ft icon">&#xE701;</i>附件</div>
-                <div class="btn"><i class="ft icon">&#xE85F;</i>归档</div>
-                <div class="btn remove"><i class="ft icon">&#xE6FB;</i>删除</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>
+                        </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>
+                </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>
         </div>
     </div>
@@ -55,14 +109,65 @@
 
 <script>
     import ProjectTaskLogs from "../logs";
+    import ProjectTaskFiles from "../files";
     export default {
-        components: {ProjectTaskLogs},
+        components: {ProjectTaskFiles, ProjectTaskLogs},
         data() {
             return {
                 visible: false,
                 taskid: 0,
                 detail: {},
+                bakData: {},
+                loadData: {},
                 commentText: '',
+
+                timeValue: [],
+                timeOptions: {
+                    shortcuts: [{
+                        text: '今天',
+                        value() {
+                            return [new Date(), new Date()];
+                        }
+                    }, {
+                        text: '明天',
+                        value() {
+                            let e = new Date();
+                            e.setDate(e.getDate() + 1);
+                            return [new Date(), e];
+                        }
+                    }, {
+                        text: '本周',
+                        value() {
+                            return [$A.getData('今天'), $A.getData('本周结束')];
+                        }
+                    }, {
+                        text: '本月',
+                        value() {
+                            return [$A.getData('今天'), $A.getData('本月结束')];
+                        }
+                    }, {
+                        text: '3天',
+                        value() {
+                            let e = new Date();
+                            e.setDate(e.getDate() + 3);
+                            return [new Date(), e];
+                        }
+                    }, {
+                        text: '5天',
+                        value() {
+                            let e = new Date();
+                            e.setDate(e.getDate() + 5);
+                            return [new Date(), e];
+                        }
+                    }, {
+                        text: '7天',
+                        value() {
+                            let e = new Date();
+                            e.setDate(e.getDate() + 7);
+                            return [new Date(), e];
+                        }
+                    }]
+                },
             }
         },
         beforeCreate() {
@@ -89,18 +194,179 @@
                     this.visible = true;
                 }, 0)
             });
+            this.bakData = $A.cloneData(this.detail);
+        },
+        watch: {
+            taskid() {
+                this.bakData = $A.cloneData(this.detail);
+            }
         },
         methods: {
+            levelFormt(p) {
+                switch (parseInt(p)) {
+                    case 1:
+                        return "重要且紧急 (P1)";
+                    case 2:
+                        return "重要不紧急 (P2)";
+                    case 3:
+                        return "紧急不重要 (P3)";
+                    case 4:
+                        return "不重要不紧急 (P4)";
+                }
+            },
+
             commentKeydown(e) {
                 e = e || event;
                 if (e.keyCode == 13) {
                     if (e.shiftKey) {
-                        console.log("换行");
                         return;
                     }
-                    console.log("发表");
                     e.preventDefault();
                 }
+            },
+
+            handleTask(act, eve) {
+                let ajaxData = {
+                    act: act,
+                    taskid: this.taskid,
+                };
+                let ajaxCallback = () => {};
+                //
+                switch (act) {
+                    case 'title':
+                    case 'desc':
+                        if (this.detail[act] == this.bakData[act]) {
+                            return;
+                        }
+                        if (!this.detail[act]) {
+                            this.$set(this.detail, act, this.bakData[act]);
+                        }
+                        ajaxData.content = this.detail[act];
+                        ajaxCallback = (res) => {
+                            if (res !== 1) {
+                                this.$set(this.detail, act, this.bakData[act]);
+                            }
+                        };
+                        break;
+
+                    case 'fileupload':
+                        this.$refs.upload.uploadHandleClick();
+                        return;
+
+                    case 'filechange':
+                        let filenum = $A.runNum(this.detail.filenum);
+                        switch (eve) {
+                            case 'up':
+                                this.$set(this.detail, 'filenum', filenum + 1);
+                                break;
+                            case 'error':
+                            case 'delete':
+                                this.$set(this.detail, 'filenum', filenum - 1);
+                                break;
+                        }
+                        if (eve == 'add' || eve == 'delete') {
+                            this.$refs.log.getLists(true, true);
+                        }
+                        return;
+
+                    case 'complete':
+                    case 'unfinished':
+                    case 'archived':
+                    case 'unarchived':
+                        break;
+
+                    case 'archived2':
+                        ajaxData.act = 'complete';
+                        ajaxCallback = (res) => {
+                            if (res === 1 && !this.detail.archived) {
+                                this.handleTask('archived');
+                                return false;
+                            }
+                        };
+                        break;
+
+                    case 'level-1':
+                    case 'level-2':
+                    case 'level-3':
+                    case 'level-4':
+                        ajaxData.act = 'level';
+                        ajaxData.content = act.substring(6);
+                        break;
+
+                    case 'username':
+                        if (!eve.username) {
+                            return;
+                        }
+                        ajaxData.content = eve.username;
+                        ajaxCallback = (res) => {
+                            if (res === 1) {
+                                this.visible = false;
+                            }
+                        };
+                        break;
+
+                    case 'opentime':
+                        if (this.detail.startdate > 0 && this.detail.enddate > 0) {
+                            this.timeValue = [$A.formatDate("Y-m-d H:i", this.detail.startdate), $A.formatDate("Y-m-d H:i", this.detail.enddate)]
+                        } else {
+                            this.timeValue = [];
+                        }
+                        return;
+
+                    case 'plannedtime':
+                        this.timeValue = $A.date2string(this.timeValue);
+                        ajaxData.content = this.timeValue[0] + "," + this.timeValue[1];
+                        this.$refs.timeRef.handleClose();
+                        break;
+
+                    case 'unplannedtime':
+                        this.$refs.timeRef.handleClose();
+                        return;
+
+                    case 'deleteb':
+                        this.$Modal.confirm({
+                            title: this.$L('删除提示'),
+                            content: this.$L('您确定要删除此任务吗?'),
+                            onOk: () => {
+                                this.handleTask('delete');
+                            },
+                        });
+                        return;
+
+                    case 'delete':
+                        ajaxCallback = (res) => {
+                            if (res === 1) {
+                                this.visible = false;
+                            }
+                        };
+                        break;
+                }
+                //
+                this.$set(this.loadData, act, true);
+                $A.aAjax({
+                    url: 'project/task/edit',
+                    data: ajaxData,
+                    complete: () => {
+                        this.$set(this.loadData, act, false);
+                    },
+                    error: () => {
+                        ajaxCallback(-1);
+                        alert(this.$L('网络繁忙,请稍后再试!'));
+                    },
+                    success: (res) => {
+                        if (res.ret === 1) {
+                            this.detail = res.data;
+                            this.bakData = $A.cloneData(this.detail);
+                            if (ajaxCallback(1) !== false) {
+                                this.$Message.success(res.msg);
+                                this.$refs.log.getLists(true, true);
+                            }
+                        } else {
+                            ajaxCallback(0);
+                            this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
+                        }
+                    }
+                });
             }
         }
     }
@@ -109,7 +375,7 @@
 <style lang="scss" scoped>
     .project-task-detail-window {
         position: fixed;
-        z-index: 100000;
+        z-index: 99;
         top: 0;
         left: 0;
         height: 100%;
@@ -214,12 +480,11 @@
                         border-radius: 3px;
                         resize: none;
                         margin-top: 10px;
-                    }
-                    textarea:focus {
-                        outline: 0;
-                        background: #fff;
-                        height: 100px;
-                        border-color: #0396f2;
+                        &:focus {
+                            outline: 0;
+                            background: #fff;
+                            border-color: #0396f2;
+                        }
                     }
                 }
                 .detail-text-box {
@@ -236,6 +501,11 @@
                             padding-left: 4px;
                             line-height: 30px;
                         }
+                        &.text-time {
+                            &:before {
+                                content: "\E706";
+                            }
+                        }
                         &.text-username {
                             &:before {
                                 content: "\E903";
@@ -277,6 +547,13 @@
                         }
                     }
                 }
+                .detail-file-box {
+                    &:before {
+                        content: "\E8B9";
+                        font-size: 16px;
+                        padding-left: 2px;
+                    }
+                }
                 .detail-comment-box {
                     &:before {
                         content: "\E753";
@@ -356,9 +633,25 @@
                             color: #ffffff;
                         }
                     }
+                    .p1 {
+                        color: #ed3f14;
+                    }
+                    .p2 {
+                        color: #ff9900;
+                    }
+                    .p3 {
+                        color: #19be6b;
+                    }
+                    .p4 {
+                        color: #666666;
+                    }
                     .icon {
                         margin-right: 4px;
                     }
+                    .checkmark {
+                        margin-left: 8px;
+                        margin-right: -8px;
+                    }
                 }
             }
         }

+ 74 - 33
resources/assets/js/main/components/project/task/files.vue

@@ -3,7 +3,7 @@
         <div class="project-task-file">
 
             <!-- 搜索 -->
-            <Row class="sreachBox">
+            <Row v-if="!simple" class="sreachBox">
                 <div class="item">
                     <div class="item-2">
                         <sreachTitle :val="keys.name">文件名</sreachTitle>
@@ -21,7 +21,7 @@
             </Row>
 
             <!-- 按钮 -->
-            <Row class="butBox" style="float:left;margin-top:-32px;">
+            <Row class="butBox" :style="`float:left;margin-top:-32px;${simple?'display:none':''}`">
                 <Upload
                     name="files"
                     ref="upload"
@@ -39,10 +39,10 @@
             </Row>
 
             <!-- 列表 -->
-            <Table class="tableFill" ref="tableRef" :columns="columns" :data="lists" :loading="loadIng > 0" :no-data-text="noDataText" @on-sort-change="sortChange" stripe></Table>
+            <Table class="tableFill" ref="tableRef" :size="!simple?'default':'small'" :columns="columns" :data="lists" :loading="loadIng > 0" :no-data-text="noDataText" @on-sort-change="sortChange" stripe></Table>
 
             <!-- 分页 -->
-            <Page class="pageBox" :total="listTotal" :current="listPage" :disabled="loadIng > 0" @on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]" placement="top" show-elevator show-sizer show-total transfer></Page>
+            <Page v-if="lastPage > 1 || !simple" :simple="simple" class="pageBox" :total="listTotal" :current="listPage" :disabled="loadIng > 0" @on-change="setPage" @on-page-size-change="setPageSize" :page-size-opts="[10,20,30,50,100]" placement="top" show-elevator show-sizer show-total transfer></Page>
 
         </div>
     </drawer-tabs-container>
@@ -72,10 +72,17 @@
             projectid: {
                 default: 0
             },
+            taskid: {
+                default: 0
+            },
             canload: {
                 type: Boolean,
                 default: true
             },
+            simple: {
+                type: Boolean,
+                default: false
+            },
         },
         data() {
             return {
@@ -91,17 +98,19 @@
                 lists: [],
                 listPage: 1,
                 listTotal: 0,
+                lastPage: 0,
                 noDataText: "数据加载中.....",
 
                 uploadFormat: ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'],
                 actionUrl: $A.aUrl('project/files/upload'),
-                params: {'token': $A.token(), projectid:this.projectid},
+                params: {'token': $A.token(), taskid:this.taskid, projectid:this.projectid},
                 uploadList: [],
             }
         },
 
         created() {
-            this.columns = [{
+            let columns = [];
+            columns.push({
                 "title": "",
                 "width": 60,
                 render: (h, params) => {
@@ -125,7 +134,8 @@
                         },
                     });
                 }
-            }, {
+            });
+            columns.push({
                 "title": "文件名",
                 "key": 'name',
                 "minWidth": 100,
@@ -146,7 +156,8 @@
                     }
                     return h('div', arr);
                 },
-            }, {
+            });
+            columns.push({
                 "title": "大小",
                 "key": 'size',
                 "minWidth": 90,
@@ -156,27 +167,33 @@
                 render: (h, params) => {
                     return h('span', $A.bytesToSize(params.row.size));
                 },
-            }, {
-                "title": "下载次数",
-                "key": 'download',
-                "align": "center",
-                "sortable": true,
-                "width": 100,
-            }, {
-                "title": "上传者",
-                "key": 'username',
-                "minWidth": 90,
-                "maxWidth": 130,
-                "sortable": true,
-            }, {
-                "title": "上传时间",
-                "key": 'indate',
-                "width": 160,
-                "sortable": true,
-                render: (h, params) => {
-                    return h('span', $A.formatDate("Y-m-d H:i:s", params.row.indate));
-                }
-            }, {
+            });
+            if (!this.simple) {
+                columns.push({
+                    "title": "下载次数",
+                    "key": 'download',
+                    "align": "center",
+                    "sortable": true,
+                    "width": 100,
+                });
+                columns.push({
+                    "title": "上传者",
+                    "key": 'username',
+                    "minWidth": 90,
+                    "maxWidth": 130,
+                    "sortable": true,
+                });
+                columns.push({
+                    "title": "上传时间",
+                    "key": 'indate',
+                    "width": 160,
+                    "sortable": true,
+                    render: (h, params) => {
+                        return h('span', $A.formatDate("Y-m-d H:i:s", params.row.indate));
+                    }
+                });
+            }
+            columns.push({
                 "title": " ",
                 "key": 'action',
                 "align": 'right',
@@ -244,7 +261,8 @@
                         })]),
                     ]);
                 }
-            }];
+            });
+            this.columns = columns;
         },
 
         mounted() {
@@ -261,6 +279,11 @@
                     this.getLists(true);
                 }
             },
+            taskid() {
+                if (this.loadYet) {
+                    this.getLists(true);
+                }
+            },
             canload(val) {
                 if (val && !this.loadYet) {
                     this.loadYet = true;
@@ -272,7 +295,8 @@
                     if (typeof file.username === "undefined") {
                         file.username = $A.getUserName();
                         file.indate = Math.round(new Date().getTime()/1000);
-                        this.lists.unshift(file)
+                        this.lists.unshift(file);
+                        this.$emit('change', 'up');
                     }
                 });
             }
@@ -307,10 +331,10 @@
                 if (resetLoad === true) {
                     this.listPage = 1;
                 }
-                if (this.projectid == 0) {
+                if (this.projectid == 0 && this.taskid == 0) {
                     this.lists = [];
                     this.listTotal = 0;
-                    this.noDataText = "没有相关的数据";
+                    this.noDataText = "没有相关的文件";
                     return;
                 }
                 this.loadIng++;
@@ -318,6 +342,7 @@
                 whereData.page = Math.max(this.listPage, 1);
                 whereData.pagesize = Math.max($A.runNum(this.listPageSize), 10);
                 whereData.projectid = this.projectid;
+                whereData.taskid = this.taskid;
                 whereData.sorts = this.sorts;
                 $A.aAjax({
                     url: 'project/files/lists',
@@ -329,9 +354,12 @@
                         if (res.ret === 1) {
                             this.lists = res.data.lists;
                             this.listTotal = res.data.total;
+                            this.lastPage = res.data.lastPage;
+                            this.noDataText = "没有相关的文件";
                         } else {
                             this.lists = [];
                             this.listTotal = 0;
+                            this.lastPage = 0;
                             this.noDataText = res.msg;
                         }
                     }
@@ -427,6 +455,7 @@
                                 setTimeout(() => {
                                     if (res.ret === 1) {
                                         this.$Message.success(res.msg);
+                                        this.$emit('change', 'delete');
                                     } else {
                                         this.$Modal.error({title: this.$L('温馨提示'), content: res.msg });
                                     }
@@ -437,6 +466,10 @@
                 });
             },
 
+            uploadHandleClick() {
+                this.$refs.upload.handleClick();
+            },
+
             handleSuccess (res, file) {
                 //上传完成
                 if (res.ret === 1) {
@@ -445,12 +478,20 @@
                             file[key] = res.data[key];
                         }
                     }
+                    this.$emit('change', 'add');
                 } else {
                     this.$Modal.warning({
                         title: '上传失败',
                         content: '文件 ' + file.name + ' 上传失败,' + res.msg
                     });
                     this.$refs.upload.fileList.pop();
+                    this.lists.some((item, index) => {
+                        if (item.id == res.id) {
+                            this.lists.splice(index, 1);
+                            return true;
+                        }
+                    });
+                    this.$emit('change', 'error');
                 }
                 this.uploadList = this.$refs.upload.fileList;
             },

+ 16 - 4
resources/assets/js/main/components/project/task/logs.vue

@@ -57,13 +57,18 @@
                 }
                 &:last-child {
                     .logs-section {
-                        margin-bottom: -20px;
+                        margin-bottom: -8px;
                     }
                 }
                 .logs-date {
                     color: rgba(0, 0, 0, .36);
                     padding-bottom: 14px;
                 }
+                .logs-section {
+                    .ivu-timeline-item {
+                        padding-bottom: 2px;
+                    }
+                }
                 .logs-dot {
                     width: 18px;
                     height: 18px;
@@ -166,11 +171,13 @@
         },
 
         methods: {
-            getLists(resetLoad) {
+            getLists(resetLoad, noLoading) {
                 if (resetLoad === true) {
                     this.listPage = 1;
                 }
-                this.loadIng++;
+                if (noLoading !== true) {
+                    this.loadIng++;
+                }
                 $A.aAjax({
                     url: 'project/log/lists',
                     data: {
@@ -180,12 +187,17 @@
                         pagesize: this.pagesize,
                     },
                     complete: () => {
-                        this.loadIng--;
+                        if (noLoading !== true) {
+                            this.loadIng--;
+                        }
                     },
                     success: (res) => {
                         if (res.ret === 1) {
                             let timeData,
                                 key;
+                            if (resetLoad === true) {
+                                this.lists = {};
+                            }
                             res.data.lists.forEach((item) => {
                                 timeData = item.timeData;
                                 key = timeData.ymd + " " + timeData.week;