From b559be298dbf4cb4d07c0faaceaa301675399aa9 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Fri, 5 May 2023 15:47:36 +0800 Subject: [PATCH] * adjust code for getProjectStatsByProduct method in productModel. --- module/product/control.php | 4 +- module/product/model.php | 62 +++---------------- module/product/zen.php | 20 +++--- module/program/model.php | 122 ++++++++++++++++++------------------- 4 files changed, 83 insertions(+), 125 deletions(-) diff --git a/module/product/control.php b/module/product/control.php index 524b2b87d5..2b0a0ba872 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -383,7 +383,7 @@ class product extends control if(!empty($_POST)) { $data = form::data($this->config->product->form->create); - $product = $this->productZen->prepareCreateExtras($data); + $product = $this->productZen->prepareCreateExtras($data, $this->post->acl, $this->post->uid); $productID = $this->product->create($product, $this->post->uid, zget($_POST, 'lineName', '')); if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -414,7 +414,7 @@ class product extends control if(!empty($_POST)) { $data = form::data($this->config->product->form->edit); - $product = $this->productZen->prepareEditExtras($data); + $product = $this->productZen->prepareEditExtras($data, $this->post->acl, $this->post->uid); $changes = $this->product->update($productID, $product, $this->post->uid); if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError())); diff --git a/module/product/model.php b/module/product/model.php index d48c7c96c5..f8a7958f8e 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -1214,7 +1214,7 @@ class productModel extends model * @param string $orderBy * @param object $pager * @access public - * @return array + * @return int[] */ public function getProjectStatsByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', object|null $pager = null): array { @@ -1223,8 +1223,6 @@ class productModel extends model $projectKeys = array_keys($projects); $stats = array(); - $hours = array(); - $emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0); /* Get all tasks and compute totalEstimate, totalConsumed, totalLeft, progress according to them. */ $tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason') @@ -1233,59 +1231,17 @@ class productModel extends model ->andWhere('parent')->lt(1) ->andWhere('deleted')->eq(0) ->fetchGroup('project', 'id'); - - /* Compute totalEstimate, totalConsumed, totalLeft. */ - foreach($tasks as $projectID => $projectTasks) - { - $hour = (object)$emptyHour; - foreach($projectTasks as $task) - { - if($task->status != 'cancel') - { - $hour->totalEstimate += $task->estimate; - $hour->totalConsumed += $task->consumed; - } - if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left; - } - $hours[$projectID] = $hour; - } - - /* Compute totalReal and progress. */ - $progressList = $this->loadModel('project')->getWaterfallProgress(array_keys($hours)); - foreach($hours as $projectID => $hour) - { - $hour->totalEstimate = round($hour->totalEstimate, 1) ; - $hour->totalConsumed = round($hour->totalConsumed, 1); - $hour->totalLeft = round($hour->totalLeft, 1); - $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; - $hour->progress = $projects[$projectID]->model == 'waterfall' ? $progressList[$projectID] : ($hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 2) * 100 : 0); - } + $hours = $this->loadModel('program')->computeProjectHours($tasks); /* Get the number of project teams. */ - $teams = $this->dao->select('root,count(*) as teams')->from(TABLE_TEAM) - ->where('root')->in($projectKeys) - ->andWhere('type')->eq('project') - ->groupBy('root') - ->fetchAll('root'); + $teams = $this->dao->select('t1.root,t1.account')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account=t2.account') + ->where('t1.root')->in($projectKeys) + ->andWhere('t1.type')->eq('project') + ->andWhere('t2.deleted')->eq(0) + ->fetchGroup('root', 'account'); - /* Process projects. */ - foreach($projects as $key => $project) - { - if($project->end == '0000-00-00') $project->end = ''; - - /* Judge whether the project is delayed. */ - if($project->status != 'done' and $project->status != 'closed' and $project->status != 'suspended') - { - $delay = helper::diffDate(helper::today(), $project->end); - if($delay > 0) $project->delay = $delay; - } - - /* Process the hours. */ - $project->hours = isset($hours[$project->id]) ? $hours[$project->id] : (object)$emptyHour; - - $project->teamCount = isset($teams[$project->id]) ? $teams[$project->id]->teams : 0; - $stats[] = $project; - } + $stats = $this->program->appendStatToProjects($projects, 'hours,teamCount', array('hours' => $hours, 'teams' => $teams)); return $stats; } diff --git a/module/product/zen.php b/module/product/zen.php index 70a270f87d..415cd0fde5 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -407,38 +407,42 @@ class productZen extends product * 追加创建信息,处理白名单、项目集字段,还有富文本内容处理。 * Prepare data for create. * - * @param form $data + * @param form $data + * @param string $acl + * @param string $uid * @access protected * @return object */ - protected function prepareCreateExtras(form $data): object + protected function prepareCreateExtras(form $data, string $acl, string $uid = ''): object { $product = $data->setDefault('createdBy', $this->app->user->account) ->setDefault('createdDate', helper::now()) ->setDefault('createdVersion', $this->config->version) ->setIF($this->config->systemMode == 'light', 'program', (int)zget($this->config->global, 'defaultProgram', 0)) - ->setIF($data->rawdata->acl == 'open', 'whitelist', '') + ->setIF($acl == 'open', 'whitelist', '') ->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags) ->get(); - return $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $data->rawdata->uid); + return $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $uid); } /** * 处理白名单和富文本内容。 * Prepare data for edit. * - * @param form $data + * @param form $data + * @param string $acl + * @param string $uid * @access protected * @return object */ - protected function prepareEditExtras(form $data): object + protected function prepareEditExtras(form $data, string $acl, string $uid = ''): object { - $product = fixer::input('post')->setIF($data->rawdata->acl == 'open', 'whitelist', '') + $product = fixer::input('post')->setIF($acl == 'open', 'whitelist', '') ->stripTags($this->config->product->editor->edit['id'], $this->config->allowedTags) ->get(); - return $this->loadModel('file')->processImgURL($product, $this->config->product->editor->edit['id'], zget($data->rawdata, 'uid', '')); + return $this->loadModel('file')->processImgURL($product, $this->config->product->editor->edit['id'], $uid); } /** diff --git a/module/program/model.php b/module/program/model.php index b3da73ba3e..0be3f59eee 100644 --- a/module/program/model.php +++ b/module/program/model.php @@ -344,7 +344,7 @@ class programModel extends model ->andWhere('deleted')->eq(0) ->fetchGroup('execution', 'id'); - $hours = $this->computeProgress($tasks); + $hours = $this->computeProjectHours($tasks); $projectHours = $this->getProgressList(); /* Group data by product. */ @@ -517,22 +517,25 @@ class programModel extends model } /** - * Compute progress for project or execution. + * 根据按照项目分组的任务,统计各个项目的工时和进度 + * Compute hours and progress for project or execution. * * @param array $tasks * @access public - * @return void + * @return array */ - public function computeProgress($tasks) + public function computeProjectHours(array $tasks): array { $hours = array(); foreach($tasks as $projectID => $projectTasks) { + /* Init hour. */ $hour = new stdclass(); $hour->totalConsumed = 0; $hour->totalEstimate = 0; $hour->totalLeft = 0; + /* Compute totalEstimate, totalConsumed, totalLeft to them. */ foreach($projectTasks as $task) { $hour->totalConsumed += $task->consumed; @@ -542,18 +545,64 @@ class programModel extends model $hours[$projectID] = $hour; } - foreach($hours as $hour) + /* 计算进度。四舍五入totalEstimate, totalConsumed, totalLeft. */ + $progressList = $this->loadModel('project')->getWaterfallProgress(array_keys($hours)); + foreach($hours as $projectID => $hour) { $hour->totalEstimate = round($hour->totalEstimate, 1) ; $hour->totalConsumed = round($hour->totalConsumed, 1); $hour->totalLeft = round($hour->totalLeft, 1); $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; - $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 2) * 100 : 0; + $hour->progress = zget($progressList, $projectID, ($hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 2) * 100 : 0)) ; } return $hours; } + /** + * 将工时、团队人数、剩余任务数、团队成员等统计信息,追加到对应的项目中。 + * Append statistics fields to projects. + * + * @param array $projects + * @param string $appendFields hours,teamCount,leftTasks,teamMembers + * @param array $data array keys are hours, teams and leftTasks. + * @access public + * @return array + */ + public function appendStatToProjects(array $projects, string $appendFields = '', array $data = array()): array + { + $appendFields = explode(',', $appendFields); + $emptyHour = json_decode(json_encode(array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0))); + /* Process projects. */ + $stats = array(); + foreach($projects as $projectID => $project) + { + if(helper::isZeroDate($project->end)) $project->end = ''; + + /* Judge whether the project is delayed. */ + if($project->status != 'done' and $project->status != 'closed' and $project->status != 'suspended') + { + $delay = empty($project->end) ? 0 : helper::diffDate(helper::today(), $project->end); + if($delay > 0) $project->delay = $delay; + } + + /* Merge the hours. */ + if(in_array('hours', $appendFields)) + { + $project->hours = $emptyHour; + if(isset($data['hours'])) $project->hours = zget($data['hours'], $project->id, $emptyHour); + } + + /* Merge the team and left tasks. */ + if(in_array('teamCount', $appendFields)) $project->teamCount = isset($data['teams'][$project->id]) ? count($data['teams'][$project->id]) : 0; + if(in_array('teamMembers', $appendFields)) $project->teamMembers = isset($data['teams'][$project->id]) ? array_keys($data['teams'][$project->id]) : array(); + if(in_array('leftTasks', $appendFields)) $project->leftTasks = isset($data['leftTasks'][$project->id]) ? $data['leftTasks'][$project->id]->tasks : '—'; + + $stats[$projectID] = $project; + } + return $stats; + } + /** * Get project list data. * @@ -1418,15 +1467,10 @@ class programModel extends model /* Init vars. */ $projects = $this->getProjectList($programID, $browseType, $queryID, $orderBy, $pager, $programTitle, $involved, $queryAll); - if(empty($projects)) return array(); $projectKeys = array_keys($projects); - $stats = array(); - $hours = array(); - $emptyHour = array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0); $leftTasks = array(); - $teamMembers = array(); $executions = $this->dao->select('id')->from(TABLE_EXECUTION) ->where('deleted')->eq(0) @@ -1438,37 +1482,11 @@ class programModel extends model $tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason, execution') ->from(TABLE_TASK) ->where('project')->in($projectKeys) + ->andWhere('execution')->in(array_keys($executions)) ->andWhere('parent')->lt(1) ->andWhere('deleted')->eq(0) ->fetchGroup('project', 'id'); - - /* Compute totalEstimate, totalConsumed, totalLeft. */ - foreach($tasks as $projectID => $projectTasks) - { - $hour = (object)$emptyHour; - foreach($projectTasks as $task) - { - if(isset($executions[$task->execution])) - { - $hour->totalConsumed += $task->consumed; - $hour->totalEstimate += $task->estimate; - - if(strpos('cancel,closed', $task->status) === false) $hour->totalLeft += $task->left; - } - } - $hours[$projectID] = $hour; - } - - /* Compute totalReal and progress. */ - $progressList = $this->loadModel('project')->getWaterfallProgress(array_keys($hours)); - foreach($hours as $projectID => $hour) - { - $hour->totalEstimate = round($hour->totalEstimate, 1) ; - $hour->totalConsumed = round($hour->totalConsumed, 1); - $hour->totalLeft = round($hour->totalLeft, 1); - $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; - $hour->progress = $projects[$projectID]->model == 'waterfall' ? $progressList[$projectID] : ($hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 2) * 100 : 0); - } + $hours = $this->computeProjectHours($tasks); /* Get the number of left tasks. */ if($this->cookie->projectType and $this->cookie->projectType == 'bycard') @@ -1489,30 +1507,10 @@ class programModel extends model ->andWhere('t2.deleted')->eq(0) ->fetchGroup('root', 'account'); - /* Process projects. */ - foreach($projects as $key => $project) - { - if($project->end == '0000-00-00') $project->end = ''; + $stats = $this->appendStatToProjects($projects, 'hours,teamCount,teamMembers,leftTasks', array('hours' => $hours, 'teams' => $teamMembers, 'leftTasks' => $leftTasks)); + /* Convert predefined HTML entities to characters. */ + foreach($stats as $project) $project->name = htmlspecialchars_decode($project->name, ENT_QUOTES); - /* Judge whether the project is delayed. */ - if($project->status != 'done' and $project->status != 'closed' and $project->status != 'suspended') - { - $delay = helper::diffDate(helper::today(), $project->end); - if($delay > 0) $project->delay = $delay; - } - - /* Process the hours. */ - $project->hours = isset($hours[$project->id]) ? $hours[$project->id] : (object)$emptyHour; - - $project->teamCount = isset($teamMembers[$project->id]) ? count($teamMembers[$project->id]) : 0; - $project->leftTasks = isset($leftTasks[$project->id]) ? $leftTasks[$project->id]->tasks : '—'; - $project->teamMembers = isset($teamMembers[$project->id]) ? array_keys($teamMembers[$project->id]) : array(); - - /* Convert predefined HTML entities to characters. */ - $project->name = htmlspecialchars_decode($project->name, ENT_QUOTES); - - $stats[$key] = $project; - } return $stats; }