@@ -456,7 +457,7 @@ $(function() ?> gantt.serverList("userList", ); - gantt.config.readonly = false; + gantt.config.readonly = canGanttEdit ? true : false; gantt.config.details_on_dblclick = false; gantt.config.order_branch = 'marker'; gantt.config.details_on_dblclick = false; From 0ab5b2956d100425d8703efb50770790b04c77a6 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 4 Aug 2022 09:07:37 +0800 Subject: [PATCH 11/29] * Finish task #62892. --- db/update17.4.sql | 3 +- module/programplan/control.php | 18 +++---- module/programplan/model.php | 2 +- module/programplan/view/gantt.html.php | 28 +++++------ module/task/model.php | 70 ++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/db/update17.4.sql b/db/update17.4.sql index 658ea1b080..36b545f067 100644 --- a/db/update17.4.sql +++ b/db/update17.4.sql @@ -1 +1,2 @@ -ALTER TABLE `zt_task` add `order` mediumint(8) NOT NULL AFTER `activatedDate`; +ALTER TABLE `zt_task` ADD `order` mediumint(8) NOT NULL DEFAULT '0' AFTER `activatedDate`; +ALTER TABLE `zt_task` ADD INDEX `order` (`order`); diff --git a/module/programplan/control.php b/module/programplan/control.php index bb2530c811..f175bb02fd 100644 --- a/module/programplan/control.php +++ b/module/programplan/control.php @@ -266,21 +266,19 @@ class programplan extends control /** * Save task drag action. * + * @param int $productID + * + * @access public * @access public * @return void */ - public function ajaxSaveGanttMove() + public function ajaxSaveGanttMove($productID = 0) { - if($_POST) + if(!empty($_POST)) { - $data = fixer::input('post')->get(); - $IdList = explode('-', $data->id); - $executionID = $IdList[0]; - $taskID = $IdList[1]; - - return 1231231; + $this->loadModel('task')->saveTaskMove($productID); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + return $this->send(array('result' => 'success')); } - - return $this->send(); } } diff --git a/module/programplan/model.php b/module/programplan/model.php index b01efa8209..d877c4bf9b 100755 --- a/module/programplan/model.php +++ b/module/programplan/model.php @@ -218,7 +218,7 @@ class programplanModel extends model if(empty($selectCustom)) $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); - $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->fetchAll('id'); + $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->orderBy('execution_asc, order_asc, id_desc')->fetchAll('id'); $taskTeams = $this->dao->select('root,account')->from(TABLE_TEAM)->where('type')->eq('task')->andWhere('root')->in(array_keys($tasks))->fetchGroup('root', 'account'); $users = $this->loadModel('user')->getPairs('noletter'); diff --git a/module/programplan/view/gantt.html.php b/module/programplan/view/gantt.html.php index 831a520152..bb5efa388d 100644 --- a/module/programplan/view/gantt.html.php +++ b/module/programplan/view/gantt.html.php @@ -459,10 +459,8 @@ $(function() gantt.config.readonly = false; gantt.config.details_on_dblclick = false; gantt.config.order_branch = 'marker'; - gantt.config.details_on_dblclick = false; - gantt.config.drag_progress = true; + gantt.config.drag_progress = false; gantt.config.drag_links = false; - gantt.config.drag_resize = false; gantt.config.smart_rendering = true; gantt.config.smart_scales = true; gantt.config.static_background = true; @@ -621,18 +619,20 @@ $(function() var link = createLink('programplan', 'ajaxSaveGanttMove'); //prevent moving to another position. - if(task.parent != parent || id.indexOf('-') == -1) return false; - - $.ajax({ + if(task.parent != parent || id.indexOf('-') == -1) + { + return false; + } + else + { + $.ajax({ url: link, - dataType: "json", - data: {id: id, type: task.type, order: tindex}, - type: "post", - success: function(result) - { - var target = result; - } - }); + dataType: "json", + data: {id: id, type: task.type, index: tindex}, + type: "post", + success: function(result){} + }); + } return true; }); diff --git a/module/task/model.php b/module/task/model.php index cdba5ab456..c44660fdf9 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -3977,4 +3977,74 @@ class taskModel extends model return true; } + + /** + * Save task order. + * + * @param int $productID + * @access public + * @return void + */ + public function saveTaskMove($productID = 0) + { + $data = fixer::input('post')->get(); + $targetTaskID = explode('-', $data->dropTarget)[1]; + $IdList = explode('-', $data->id); + $executionID = $IdList[0]; + $taskID = $IdList[1]; + $index = (int)$data->index; + + $oldTask = $this->loadModel('task')->getByID($taskID); + $targetTask = $this->loadModel('task')->getByID($targetTaskID); + $execution = $this->loadModel('execution')->getByID($executionID); + $tasks = $this->dao->select('id')->from(TABLE_TASK) + ->where('execution')->eq($executionID) + ->andWhere('deleted')->eq(0) + ->beginIF($oldTask->parent <= 0)->andWhere('parent')->le(0) + ->beginIF($oldTask->parent > 0)->andWhere('parent')->eq($oldTask->parent) + ->fetchPairs('id'); + $taskOrderSum = $this->dao->select('SUM(`order`) as sum')->from(TABLE_TASK) + ->where('deleted')->eq(0) + ->andWhere('execution')->eq($executionID) + ->beginIF($oldTask->parent <= 0)->andWhere('parent')->le(0) + ->beginIF($oldTask->parent > 0)->andWhere('parent')->eq($oldTask->parent) + ->fetch('sum'); + + if(!$taskOrderSum) + { + $order = 1; + foreach($tasks as $task) + { + $this->dao->update(TABLE_TASK)->set('`order`')->eq($order)->where('id')->eq($task)->exec(); + $order ++; + } + } + else + { + $order = ++ $index; + $oldOrder = (int)$oldTask->order; + if($order > $oldOrder) + { + $this->dao->update(TABLE_TASK)->set('`order`')->eq('`order`-1') + ->where('execution')->eq($executionID) + ->andWhere('`order`')->le($order) + ->andWhere('`order`')->gt($oldOrder) + ->beginIF($oldTask->parent <= 0)->andWhere('parent')->le(0) + ->beginIF($oldTask->parent > 0)->andWhere('parent')->eq($oldTask->parent) + ->exec(); + } + else if($order < $oldOrder) + { + $this->dao->update(TABLE_TASK)->set('`order`=`order`+1') + ->where('execution')->eq($executionID) + ->andWhere('`order`')->lt($oldOrder) + ->andWhere('`order`')->ge($order) + ->beginIF($oldTask->parent <= 0)->andWhere('parent')->le(0) + ->beginIF($oldTask->parent > 0)->andWhere('parent')->eq($oldTask->parent) + ->exec(); + } + + $this->dao->update(TABLE_TASK)->set('`order`')->eq($order)->where('id')->eq($taskID)->exec(); + } + } } From dfeafd9dbd38b5d6d9aea813ff19def27ddea589 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 4 Aug 2022 09:21:05 +0800 Subject: [PATCH 12/29] * Add key for zt_task. --- db/zentao.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/db/zentao.sql b/db/zentao.sql index 5cd07c3b2c..eab2fde60b 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -1537,6 +1537,7 @@ CREATE TABLE IF NOT EXISTS `zt_task` ( KEY `story` (`story`), KEY `parent` (`parent`), KEY `assignedTo` (`assignedTo`) + KEY `order` (`order`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_taskestimate`; CREATE TABLE IF NOT EXISTS `zt_taskestimate` ( From 397c6d55b429cb8c666224507b7cca6e79254773 Mon Sep 17 00:00:00 2001 From: mayue Date: Thu, 4 Aug 2022 09:38:01 +0800 Subject: [PATCH 13/29] * Optimize code. --- module/programplan/view/gantt.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/programplan/view/gantt.html.php b/module/programplan/view/gantt.html.php index a50396eb6f..d3089e6ff8 100644 --- a/module/programplan/view/gantt.html.php +++ b/module/programplan/view/gantt.html.php @@ -457,7 +457,7 @@ $(function() ?> gantt.serverList("userList", ); - gantt.config.readonly = canGanttEdit ? true : false; + gantt.config.readonly = canGanttEdit ? false : true; gantt.config.details_on_dblclick = false; gantt.config.order_branch = 'marker'; gantt.config.drag_progress = false; From 8ce6a83819c8721607f1cc669dfc2f000bb9ea4d Mon Sep 17 00:00:00 2001 From: lanzongjun Date: Thu, 4 Aug 2022 09:56:03 +0800 Subject: [PATCH 14/29] * fix bug --- module/programplan/control.php | 23 ++- module/programplan/lang/zh-cn.php | 4 + module/programplan/model.php | 188 ++++++++++++++++++++++++ module/programplan/view/browse.html.php | 2 +- module/programplan/view/gantt.html.php | 19 ++- 5 files changed, 224 insertions(+), 12 deletions(-) diff --git a/module/programplan/control.php b/module/programplan/control.php index bb2530c811..2828763e31 100644 --- a/module/programplan/control.php +++ b/module/programplan/control.php @@ -86,6 +86,18 @@ class programplan extends control $plans = $this->programplan->getDataForGantt($projectID, $this->productID, $baselineID, $selectCustom, false); } + if($type == 'assignedTo') + { + $owner = $this->app->user->account; + $module = 'programplan'; + $section = 'browse'; + $object = 'stageCustom'; + $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); + if(strpos($selectCustom, 'date') !== false) $dateDetails = 0; + + $plans = $this->programplan->getDataForGanttGroupByAssignedTo($projectID, $this->productID, $baselineID, $selectCustom, false); + } + if($type == 'lists') { $sort = common::appendOrder($orderBy); @@ -103,6 +115,7 @@ class programplan extends control $this->view->selectCustom = $selectCustom; $this->view->dateDetails = $dateDetails; $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->ganttType = $type; $this->display(); } @@ -248,14 +261,8 @@ class programplan extends control { if(!empty($_POST)) { - if($_POST['type'] == 'task') - { - $objectID = explode('-', $_POST['id'])[1]; - } - else - { - $objectID = $_POST['id']; - } + if(!isset($_POST['id']) or empty($_POST['id'])) return $this->send(array('result' => 'fail', 'message' => '')); + $objectID = $_POST['id']; $this->loadModel('task')->saveTaskDrag($objectID, $_POST['type']); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); diff --git a/module/programplan/lang/zh-cn.php b/module/programplan/lang/zh-cn.php index ff6a2b751f..fb9d36953d 100644 --- a/module/programplan/lang/zh-cn.php +++ b/module/programplan/lang/zh-cn.php @@ -86,3 +86,7 @@ $lang->programplan->error->parentWorkload = '子阶段的工作量之和不能 $lang->programplan->error->parentDuration = '子阶段计划开始、计划完成不能超过父阶段'; $lang->programplan->error->sameName = '阶段名称不能相同!'; $lang->programplan->error->taskDrag = '%s的任务不可以拖动'; + + +$lang->programplan->ganttBrowseType['gantt'] = '按阶段分组'; +$lang->programplan->ganttBrowseType['assignedTo'] = '按指派给分组'; diff --git a/module/programplan/model.php b/module/programplan/model.php index b01efa8209..c4a84618c4 100755 --- a/module/programplan/model.php +++ b/module/programplan/model.php @@ -144,6 +144,7 @@ class programplanModel extends model * @param int $baselineID * @param string $selectCustom * @param bool $returnJson + * @param string $type * @access public * @return string */ @@ -329,6 +330,193 @@ class programplanModel extends model } $datas['data'] = isset($datas['data']) ? array_values($datas['data']) : array(); +// a($datas['data']);exit; + return $returnJson ? json_encode($datas) : $datas; + } + + public function getDataForGanttGroupByAssignedTo($executionID, $productID, $baselineID = 0, $selectCustom = '', $returnJson = true) + { + $plans = $this->getStage($executionID, $productID); + + $datas = array(); + $planIdList = array(); + $isMilestone = " "; + $stageIndex = array(); + + foreach($plans as $plan) + { + $planIdList[$plan->id] = $plan->id; + } + + $taskSign = "[ T ] "; + $taskPri = "%s "; + + /* Judge whether to display tasks under the stage. */ + $owner = $this->app->user->account; + $module = 'programplan'; + $section = 'browse'; + $object = 'stageCustom'; + if(empty($selectCustom)) $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); + + $tasksGroup = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIdList)->fetchGroup('assignedTo','id'); + $users = $this->loadModel('user')->getPairs('noletter'); + + foreach($tasksGroup as $group => $tasks) + { + foreach($tasks as $id => $task) + { + if($task->mode == 'multi') + { + $team = $this->dao->select('t1.*,t2.realname')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') + ->where('t1.root')->eq($id)->andWhere('t1.type')->eq('task')->orderBy('t1.order')->fetchAll('account'); + foreach($team as $account => $member) + { + if($account == $group) continue; + if(!isset($taskGroups[$account])) $taskGroups[$account] = array(); + + $taskGroups[$account][$id] = clone $task; + $taskGroups[$account][$id]->id = $id . '_' . $account; + $taskGroups[$account][$id]->realID = $id; + $taskGroups[$account][$id]->assignedTo = $account; + $taskGroups[$account][$id]->realname = $member->realname; + } + } + } + } + + $groupID = 0; + foreach($tasksGroup as $group => $tasks) + { + $groupID --; + $groupName = $group; + $groupName = zget($users, $group); + $dataGroup = new stdclass(); + $dataGroup->id = $groupID; + $dataGroup->type = 'group'; + $dataGroup->text = $groupName; + $dataGroup->percent = ''; + $dataGroup->attribute = ''; + $dataGroup->milestone = ''; + $dataGroup->owner_id = $group; + $dataGroup->status = ''; + $dataGroup->begin = ''; + $dataGroup->deadline = ''; + $dataGroup->realBegan = ''; + $dataGroup->realEnd = ''; + $dataGroup->parent = 0; + $dataGroup->open = true; + $dataGroup->progress = ''; + $dataGroup->start_date = ''; + $dataGroup->endDate = ''; + $dataGroup->duration = 0; + + $groupKey = $groupID . $group; + $datas['data'][$groupKey] = $dataGroup; + + foreach($tasks as $taskID => $task) + { + // if($task->parent > 0 and $task->assignedTo) + // { + // $a = $task->parent; + // a($tasksGroup[$task->assignedTo]); + // a($task->parent);exit; + // } + $execution = zget($plans, $task->execution, array()); + + $priIcon = sprintf($taskPri, $task->pri, $task->pri, $task->pri); + + $estStart = helper::isZeroDate($task->estStarted) ? '' : $task->estStarted; + $estEnd = helper::isZeroDate($task->deadline) ? '' : $task->deadline; + $realBegan = helper::isZeroDate($task->realStarted) ? '' : $task->realStarted; + $realEnd = (in_array($task->status, array('done', 'closed')) and !helper::isZeroDate($task->finishedDate)) ? $task->finishedDate : ''; + + $start = $realBegan ? $realBegan : $estStart; + $end = $realEnd ? $realEnd : $estEnd; + if(empty($start) and $execution) $start = $execution->begin; + if(empty($end) and $execution) $end = $execution->end; + if($start > $end) $end = $start; + + $data = new stdclass(); + $data->id = $task->id; + $data->type = 'task'; + $data->text = $taskSign . $priIcon . $task->name; + $data->percent = ''; + $data->status = $this->processStatus('task', $task); + $data->owner_id = $task->assignedTo; + $data->attribute = ''; + $data->milestone = ''; + $data->begin = $start; + $data->deadline = $end; + $data->realBegan = $realBegan; + $data->realEnd = $realEnd; + $data->pri = $task->pri; + $data->parent = ($task->parent > 0 and $task->assignedTo != '') ? $task->parent : $groupID; + $data->open = true; + $progress = $task->consumed ? round($task->consumed / ($task->left + $task->consumed), 3) : 0; + $data->progress = $progress; + $data->taskProgress = ($progress * 100) . '%'; + $data->start_date = $start; + $data->endDate = $end; + $data->duration = 0; + + /* If multi task then show the teams. */ + // if($task->mode == 'multi' and !empty($taskTeams[$task->id])) + // { + // $teams = array_keys($taskTeams[$task->id]); + // $assigneds = array(); + // foreach($teams as $assignedTo) $assigneds[] = zget($users, $assignedTo); + // $data->owner_id = join(',', $assigneds); + // } + + if($data->endDate > $data->start_date) $data->duration = helper::diffDate($data->endDate, $data->start_date) + 1; + if($data->start_date) $data->start_date = date('d-m-Y', strtotime($data->start_date)); + if($data->start_date == '' or $data->endDate == '') $data->duration = 0; + + if(strpos($selectCustom, 'task') !== false) $datas['data'][$data->id] = $data; + + foreach($stageIndex as $index => $stage) + { + if($stage['planID'] == $task->execution) + { + $stageIndex[$index]['progress']['totalConsumed'] += $task->consumed; + $stageIndex[$index]['progress']['totalReal'] += ($task->left + $task->consumed); + + $parent = $stage['parent']; + if(isset($stageIndex[$parent])) + { + $stageIndex[$parent]['progress']['totalConsumed'] += $task->consumed; + $stageIndex[$parent]['progress']['totalReal'] += ($task->left + $task->consumed); + } + } + } + } + } + + /* Calculate the progress of the phase. */ + foreach($stageIndex as $index => $stage) + { + $progress = empty($stage['progress']['totalConsumed']) ? 0 : round($stage['progress']['totalConsumed'] / $stage['progress']['totalReal'], 3); + $datas['data'][$index]->progress = $progress; + + $progress = ($progress * 100) . '%'; + $datas['data'][$index]->taskProgress = $progress; + } + + $datas['links'] = array(); + if($this->config->edition != 'open') + { + $relations = $this->dao->select('*')->from(TABLE_RELATIONOFTASKS)->where('execution')->in($planIdList)->orderBy('task,pretask')->fetchAll(); + foreach($relations as $relation) + { + $link['source'] = $relation->execution . '-' . $relation->pretask; + $link['target'] = $relation->execution . '-' . $relation->task; + $link['type'] = $this->config->execution->gantt->linkType[$relation->condition][$relation->action]; + $datas['links'][] = $link; + } + } + + $datas['data'] = isset($datas['data']) ? array_values($datas['data']) : array(); return $returnJson ? json_encode($datas) : $datas; } diff --git a/module/programplan/view/browse.html.php b/module/programplan/view/browse.html.php index 5a299d37f0..a257219961 100644 --- a/module/programplan/view/browse.html.php +++ b/module/programplan/view/browse.html.php @@ -24,7 +24,7 @@

- +