diff --git a/module/execution/control.php b/module/execution/control.php index 841142d36b..b9a4427e6a 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -3319,6 +3319,32 @@ class execution extends control die(html::select("group", $groups, $group, 'class="form-control chosen" data-max_drop_width="215"')); } + /** + * Ajax update kanban. + * + * @param int $executionID + * @param string $enterTime + * @param string $browseType + * @param string $groupBy + * @access public + * @return void + */ + public function ajaxUpdateKanban($executionID = 0, $enterTime = '', $browseType = '', $groupBy = '') + { + $enterTime = date('Y-m-d H:i:s', $enterTime); + $lastEditedTime = $this->dao->select("max(lastEditedTime) as lastEditedTime")->from(TABLE_KANBANLANE)->where('execution')->eq($executionID)->fetch('lastEditedTime'); + + if($lastEditedTime > $enterTime) + { + $kanbanGroup = $this->loadModel('kanban')->getExecutionKanban($executionID, $browseType, $groupBy); + die(json_encode($kanbanGroup)); + } + else + { + die(''); + } + } + /** * AJAX: Update the execution name. * diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index e43e4e874e..8ce3c9e1f3 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -466,8 +466,64 @@ function findDropColumns($element, $root) */ function changeCardColType(card, fromColType, toColType, kanbanID) { - /* TODO: Post data to server on change card type 将变更卡片类型操作提交到服务器 */ - console.log('TODO: Post data to server on change card type 将变更卡片类型操作提交到服务器', {card, fromColType, toColType, kanbanID}); + if(typeof card == 'undefined') return false; + var objectID = card.id; + var showIframe = false; + + if(kanbanID == 'task') + { + if(toColType == 'developed') + { + if((fromColType == 'developing' || fromColType == 'wait') && priv.canFinishTask) + { + var link = createLink('task', 'finish', 'taskID=' + objectID, '', true); + showIframe = true; + } + } + else if(toColType == 'pause') + { + if(fromColType == 'developing' && priv.canPauseTask) + { + var link = createLink('task', 'pause', 'taskID=' + objectID, '', true); + showIframe = true; + } + } + else if(toColType == 'developing') + { + if((fromColType == 'pause' || fromColType == 'cancel' || fromColType == 'closed' || fromColType == 'developed') && priv.canActivateTask) + { + var link = createLink('task', 'activate', 'taskID=' + objectID, '', true); + showIframe = true; + } + if(fromColType == 'wait' && priv.canStartTask) + { + var link = createLink('task', 'start', 'taskID=' + objectID, '', true); + showIframe = true; + } + } + else if(toColType == 'canceled') + { + if((fromColType == 'developing' || fromColType == 'wait' || fromColType == 'pause') && priv.canCancelTask) + { + var link = createLink('task', 'cancel', 'taskID=' + objectID, '', true); + showIframe = true; + } + } + else if(toColType == 'closed') + { + if((fromColType == 'developed' || fromColType == 'canceled') && priv.canCloseTask) + { + var link = createLink('task', 'close', 'taskID=' + objectID, '', true); + showIframe = true; + } + } + } + + if(showIframe) + { + var modalTrigger = new $.zui.ModalTrigger({type: 'iframe', width: '80%', url: link}); + modalTrigger.show(); + } /* // TODO: The server must return a updated kanban data 服务器返回更新后的看板数据 @@ -771,6 +827,34 @@ $(function() $('#type_chosen .chosen-single span').prepend(''); $('#group_chosen .chosen-single span').prepend(kanbanLang.laneGroup + ': '); + + /* Ajax update kanban. */ + setInterval(function() + { + $.get(createLink('execution', 'ajaxUpdateKanban', "executionID=" + executionID + "&entertime=" + entertime + "&browseType=" + browseType + "&groupBy=" + groupBy), function(data) + { + if(data) + { + kanbanGroup = $.parseJSON(data); + if(groupBy == 'default') + { + var kanbanLane = ''; + for(var i in kanbanList) + { + if(kanbanList[i] == 'story') kanbanLane = kanbanGroup.story; + if(kanbanList[i] == 'bug') kanbanLane = kanbanGroup.bug; + if(kanbanList[i] == 'task') kanbanLane = kanbanGroup.task; + + if(browseType == kanbanList[i] || browseType == 'all') updateKanban(kanbanList[i], kanbanLane); + } + } + else + { + updateKanban(browseType, kanbanGroup[groupBy]); + } + } + }); + }, 10000); }); $('#type').change(function() diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index 48213f32ed..534de79bca 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -137,7 +137,13 @@ js::set('priv', 'canLinkStoryByPlane' => $canLinkStoryByPlane, 'canAssignTask' => common::hasPriv('task', 'assignto'), 'canAssignStory' => common::hasPriv('story', 'assignto'), - 'canAssignBug' => common::hasPriv('bug', 'assignto') + 'canAssignBug' => common::hasPriv('bug', 'assignto'), + 'canFinishTask' => common::hasPriv('task', 'finish'), + 'canPauseTask' => common::hasPriv('task', 'pause'), + 'canCancelTask' => common::hasPriv('task', 'cancel'), + 'canCloseTask' => common::hasPriv('task', 'close'), + 'canActivateTask' => common::hasPriv('task', 'activate'), + 'canStartTask' => common::hasPriv('task', 'start') ) ); ?> @@ -152,4 +158,5 @@ js::set('priv', task->deadlineAB);?> task->noAssigned);?> + diff --git a/module/kanban/model.php b/module/kanban/model.php index b02817e3c4..b9df8bd351 100644 --- a/module/kanban/model.php +++ b/module/kanban/model.php @@ -337,6 +337,24 @@ class kanbanModel extends model } } + /** + * Update kanban lane. + * + * @param int $executionID + * @param string $laneType + * @access public + * @return void + */ + public function updateLane($executionID, $laneType) + { + $lanes = $this->dao->select('*')->from(TABLE_KANBANLANE) + ->where('execution')->eq($executionID) + ->andWhere('type')->eq($laneType) + ->fetchAll('id'); + + foreach($lanes as $lane) $this->updateCards($lane); + } + /** * Update column cards. * @@ -448,6 +466,8 @@ class kanbanModel extends model { $this->dao->update(TABLE_KANBANCOLUMN)->set('cards')->eq($cards)->where('lane')->eq($lane->id)->andWhere('type')->eq($colType)->exec(); } + + $this->dao->update(TABLE_KANBANLANE)->set('lastEditedTime')->eq(helper::now())->where('id')->eq($lane->id)->exec(); } /** diff --git a/module/story/model.php b/module/story/model.php index a3cbcd947d..57768e318c 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -280,6 +280,7 @@ class storyModel extends model { $this->linkStory($executionID, $this->post->product, $storyID); if($this->config->systemMode == 'new' and $executionID != $this->session->project) $this->linkStory($this->session->project, $this->post->product, $storyID); + $this->loadModel('kanban')->updateLane($executionID, 'story'); } if(is_array($this->post->URS)) @@ -1816,6 +1817,8 @@ class storyModel extends model $tasks[] = $taskID; $this->action->create('task', $taskID, 'Opened', ''); } + + $this->loadModel('kanban')->updateLane($executionID, 'task'); return $tasks; } diff --git a/module/task/model.php b/module/task/model.php index 3ce29cb28d..597708c727 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -138,6 +138,8 @@ class taskModel extends model $this->dao->insert(TABLE_TASKSPEC)->data($taskSpec)->autoCheck()->exec(); if(dao::isError()) return false; + $this->loadModel('kanban')->updateLane($executionID, 'task'); + if($this->post->story) $this->loadModel('story')->setStage($this->post->story); if($this->post->selectTestStory) { @@ -408,7 +410,12 @@ class taskModel extends model $mails[$i]->actionID = $actionID; } - if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchCreate'); + if(!dao::isError()) + { + $this->loadModel('score')->create('ajax', 'batchCreate'); + $this->loadModel('kanban')->updateLane($executionID, 'task'); + } + if($parentID > 0 && !empty($taskID)) { $oldParentTask = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq((int)$parentID)->fetch(); @@ -1008,6 +1015,7 @@ class taskModel extends model if($this->post->story != false) $this->loadModel('story')->setStage($this->post->story); if($task->status == 'done') $this->loadModel('score')->create('task', 'finish', $taskID); if($task->status == 'closed') $this->loadModel('score')->create('task', 'close', $taskID); + if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($task->execution, 'task'); $this->loadModel('action'); $changed = $task->parent != $oldTask->parent; @@ -1286,6 +1294,7 @@ class taskModel extends model if($task->status == 'done') $this->loadModel('score')->create('task', 'finish', $taskID); if($task->status == 'closed') $this->loadModel('score')->create('task', 'close', $taskID); + if($task->status != $oldTask->status) $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); $allChanges[$taskID] = common::createChanges($oldTask, $task); } else @@ -1461,6 +1470,7 @@ class taskModel extends model $this->computeBeginAndEnd($oldTask->parent); } if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); if(!dao::isError()) return common::createChanges($oldTask, $task); } @@ -1719,7 +1729,11 @@ class taskModel extends model if($oldTask->parent > 0) $this->updateParentStatus($taskID); if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if($task->status == 'done' && !dao::isError()) $this->loadModel('score')->create('task', 'finish', $taskID); + if($task->status == 'done' && !dao::isError()) + { + $this->loadModel('score')->create('task', 'finish', $taskID); + $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); + } if(!dao::isError()) return common::createChanges($oldTask, $task); } @@ -1778,6 +1792,8 @@ class taskModel extends model if($oldTask->parent > 0) $this->updateParentStatus($taskID); if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); $this->loadModel('score')->create('task', 'close', $taskID); + $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); + return common::createChanges($oldTask, $task); } } @@ -1816,6 +1832,7 @@ class taskModel extends model $this->dao->update(TABLE_TASK)->set('assignedTo=openedBy')->where('parent')->eq((int)$taskID)->exec(); } if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); if(!dao::isError()) return common::createChanges($oldTask, $task); } @@ -1881,6 +1898,7 @@ class taskModel extends model $this->computeWorkingHours($taskID); } if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + $this->loadModel('kanban')->updateLane($oldTask->execution, 'task'); if(!dao::isError()) return common::createChanges($oldTask, $task); }