From 36197537eb4049fdb18281de5d1b888fa347ad83 Mon Sep 17 00:00:00 2001 From: tianshujie Date: Mon, 21 Aug 2023 14:52:39 +0800 Subject: [PATCH] * Refactor export method. --- module/task/control.php | 251 +++------------------------------------- module/task/model.php | 110 +++++++++++++++++- module/task/zen.php | 205 +++++++++++++++++++++++++++++++- 3 files changed, 326 insertions(+), 240 deletions(-) diff --git a/module/task/control.php b/module/task/control.php index fcb3442c22..55cfb8c5e3 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -1044,258 +1044,35 @@ class task extends control } /** - * get data to export + * 导出任务数据。 + * get data to export. * - * @param int $executionID + * @param int $executionID * @param string $orderBy + * @param string $type * @access public * @return void */ public function export(int $executionID, string $orderBy, string $type) { - $execution = $this->execution->getById($executionID); + /* Get execution info and export fields. */ + $execution = $this->execution->getByID($executionID); $allExportFields = $this->config->task->exportFields; if($execution->lifetime == 'ops' or in_array($execution->attribute, array('request', 'review'))) $allExportFields = str_replace(' story,', '', $allExportFields); if($_POST) { $this->loadModel('file'); - $taskLang = $this->lang->task; /* Create field lists. */ - $sort = common::appendOrder($orderBy); - $fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $allExportFields); - - /* Compatible with the new UI widget. */ - if($this->post->exportFields && str_contains($fields[0], ',')) - { - $fields = explode(',', $fields[0]); - } - - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($taskLang->$fieldName) ? $taskLang->$fieldName : $fieldName; - unset($fields[$key]); - } + $fields = $this->taskZen->getExportFields($allExportFields); /* Get tasks. */ - $tasks = array(); - if($this->session->taskOnlyCondition) - { - $tasks = $this->dao->select('*')->from(TABLE_TASK)->alias('t1')->where($this->session->taskQueryCondition) - ->beginIF($this->post->exportType == 'selected')->andWhere('t1.id')->in($this->cookie->checkedItem)->fi() - ->orderBy($sort)->fetchAll('id'); + $tasks = $this->task->getExportTasks($orderBy); + if($type == 'group') $tasks = $this->taskZen->processExportGroup($tasks, $orderBy); - foreach($tasks as $key => $task) - { - /* Compute task progress. */ - if($task->consumed == 0 and $task->left == 0) - { - $task->progress = 0; - } - elseif($task->consumed != 0 and $task->left == 0) - { - $task->progress = 100; - } - else - { - $task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100; - } - $task->progress .= '%'; - } - } - elseif($this->session->taskQueryCondition) - { - $stmt = $this->dbh->query($this->session->taskQueryCondition . ($this->post->exportType == 'selected' ? " AND t1.id IN({$this->cookie->checkedItem})" : '') . " ORDER BY " . strtr($orderBy, '_', ' ')); - while($row = $stmt->fetch()) $tasks[$row->id] = $row; - } - - /* Get users and executions. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $executions = $this->execution->getPairs($execution->project, 'all', 'all|nocode'); - - /* Get related objects id lists. */ - $relatedStoryIdList = array(); - foreach($tasks as $task) - { - $relatedStoryIdList[$task->story] = $task->story; - $relatedBugIdList[$task->fromBug] = $task->fromBug; - } - - /* Get team for multiple task. */ - $taskTeam = $this->dao->select('*')->from(TABLE_TASKTEAM)->where('task')->in(array_keys($tasks))->fetchGroup('task'); - - /* Process multiple task info. */ - if(!empty($taskTeam)) - { - foreach($taskTeam as $taskID => $team) - { - $tasks[$taskID]->team = $team; - $tasks[$taskID]->estimate = ''; - $tasks[$taskID]->left = ''; - $tasks[$taskID]->consumed = ''; - - foreach($team as $userInfo) - { - $tasks[$taskID]->estimate .= zget($users, $userInfo->account) . ':' . $userInfo->estimate . "\n"; - $tasks[$taskID]->left .= zget($users, $userInfo->account) . ':' . $userInfo->left . "\n"; - $tasks[$taskID]->consumed .= zget($users, $userInfo->account) . ':' . $userInfo->consumed . "\n"; - } - } - } - - /* Get related objects title or names. */ - $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('task')->andWhere('objectID')->in(array_keys($tasks))->andWhere('extra')->ne('editor')->fetchGroup('objectID'); - $relatedModules = $this->loadModel('tree')->getAllModulePairs('task'); - - if($tasks) - { - $children = array(); - foreach($tasks as $task) - { - if($task->parent > 0 and isset($tasks[$task->parent])) - { - $children[$task->parent][$task->id] = $task; - unset($tasks[$task->id]); - } - } - if(!empty($children)) - { - $position = 0; - foreach($tasks as $task) - { - $position ++; - if(isset($children[$task->id])) - { - array_splice($tasks, $position, 0, $children[$task->id]); - $position += count($children[$task->id]); - } - } - } - } - - if($type == 'group') - { - $stories = $this->loadModel('story')->getExecutionStories($executionID); - $groupTasks = array(); - foreach($tasks as $task) - { - $task->storyTitle = isset($stories[$task->story]) ? $stories[$task->story]->title : ''; - - if(!isset($task->team)) - { - $groupTasks[$task->$orderBy][] = $task; - continue; - } - - if($orderBy == 'finishedBy') $task->consumed = $task->estimate = $task->left = 0; - foreach($task->team as $team) - { - if($orderBy == 'finishedBy' and $team->left != 0) - { - $task->estimate += $team->estimate; - $task->consumed += $team->consumed; - $task->left += $team->left; - continue; - } - - $cloneTask = clone $task; - $cloneTask->estimate = $team->estimate; - $cloneTask->consumed = $team->consumed; - $cloneTask->left = $team->left; - if($team->left == 0) $cloneTask->status = 'done'; - - if($orderBy == 'assignedTo') - { - $cloneTask->assignedToRealName = zget($users, $team->account); - $cloneTask->assignedTo = $team->account; - } - if($orderBy == 'finishedBy')$cloneTask->finishedBy = $team->account; - $groupTasks[$team->account][] = $cloneTask; - } - if(!empty($task->left) and $orderBy == 'finishedBy') $groupTasks[$task->finishedBy][] = $task; - } - - $tasks = array(); - foreach($groupTasks as $groupTask) - { - foreach($groupTask as $task)$tasks[] = $task; - } - } - - $bugs = $this->loadModel('bug')->getByIdList($relatedBugIdList); - foreach($tasks as $task) - { - if($this->post->fileType == 'csv') - { - $task->desc = htmlspecialchars_decode($task->desc); - $task->desc = str_replace("
", "\n", $task->desc); - $task->desc = str_replace('"', '""', $task->desc); - $task->desc = str_replace(' ', ' ', $task->desc); - } - - /* fill some field with useful value. */ - $task->story = isset($relatedStories[$task->story]) ? $relatedStories[$task->story] . "(#$task->story)" : ''; - - $task->fromBug = empty($task->fromBug) ? '' : "#$task->fromBug " . $bugs[$task->fromBug]->title; - - if(isset($executions[$task->execution])) $task->execution = $executions[$task->execution] . "(#$task->execution)"; - if(isset($taskLang->typeList[$task->type])) $task->type = $taskLang->typeList[$task->type]; - if(isset($taskLang->priList[$task->pri])) $task->pri = $taskLang->priList[$task->pri]; - if(isset($taskLang->statusList[$task->status])) $task->status = $this->processStatus('task', $task); - if(isset($taskLang->reasonList[$task->closedReason])) $task->closedReason = $taskLang->reasonList[$task->closedReason]; - if(isset($relatedModules[$task->module])) $task->module = $relatedModules[$task->module] . "(#$task->module)"; - if(isset($taskLang->modeList[$task->mode])) $task->mode = $taskLang->modeList[$task->mode]; - - if(isset($users[$task->openedBy])) $task->openedBy = $users[$task->openedBy]; - if(isset($users[$task->assignedTo])) $task->assignedTo = $users[$task->assignedTo]; - if(isset($users[$task->finishedBy])) $task->finishedBy = $users[$task->finishedBy]; - if(isset($users[$task->canceledBy])) $task->canceledBy = $users[$task->canceledBy]; - if(isset($users[$task->closedBy])) $task->closedBy = $users[$task->closedBy]; - if(isset($users[$task->lastEditedBy])) $task->lastEditedBy = $users[$task->lastEditedBy]; - - /* Convert username to real name. */ - if(!empty($task->mailto)) - { - $mailtoList = explode(',', $task->mailto); - - $task->mailto = ''; - foreach($mailtoList as $mailto) - { - if(!empty($mailto)) $task->mailto .= ',' . zget($users, $mailto); - } - } - - if($task->parent > 0 && strpos($task->name, htmlentities('>')) !== 0) $task->name = '>' . $task->name; - if(!empty($task->team)) - { - $task->name = '[' . $taskLang->multipleAB . '] ' . $task->name; - unset($task->team); - } - - $task->openedDate = helper::isZeroDate($task->openedDate) ? '' : substr($task->openedDate, 0, 10); - $task->assignedDate = helper::isZeroDate($task->assignedDate) ? '' : substr($task->assignedDate, 0, 10); - $task->finishedDate = helper::isZeroDate($task->finishedDate) ? '' : substr($task->finishedDate, 0, 10); - $task->canceledDate = helper::isZeroDate($task->canceledDate) ? '' : substr($task->canceledDate, 0, 10); - $task->closedDate = helper::isZeroDate($task->closedDate) ? '' : substr($task->closedDate, 0, 10); - $task->lastEditedDate = helper::isZeroDate($task->lastEditedDate) ? '' : substr($task->lastEditedDate, 0, 10); - $task->estimate = $task->estimate . $this->lang->execution->workHourUnit; - $task->consumed = $task->consumed . $this->lang->execution->workHourUnit; - $task->left = $task->left . $this->lang->execution->workHourUnit; - - /* Set related files. */ - $task->files = ''; - if(isset($relatedFiles[$task->id])) - { - foreach($relatedFiles[$task->id] as $file) - { - $fileURL = common::getSysURL() . $this->createLink('file', 'download', "fileID={$file->id}"); - $task->files .= html::a($fileURL, $file->title, '_blank') . '
'; - } - } - } + /* Process export data. */ + $tasks = $this->taskZen->processExportData($tasks, $execution->project); if($this->config->edition != 'open') list($fields, $tasks) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $tasks); $this->post->set('fields', $fields); @@ -1304,9 +1081,6 @@ class task extends control $this->fetch('file', 'export2' . $this->post->fileType, $_POST); } - $this->app->loadLang('execution'); - $fileName = $this->lang->task->common; - $executionName = $this->dao->findById($executionID)->from(TABLE_PROJECT)->fetch('name'); if(isset($this->lang->execution->featureBar['task'][$type])) { $browseType = $this->lang->execution->featureBar['task'][$type]; @@ -1316,12 +1090,13 @@ class task extends control $browseType = isset($this->lang->execution->statusSelects[$type]) ? $this->lang->execution->statusSelects[$type] : ''; } - $this->view->fileName = $executionName . $this->lang->dash . $browseType . $fileName; + $this->view->fileName = $execution->name . $this->lang->dash . $browseType . $this->lang->task->common; $this->view->allExportFields = $allExportFields; $this->view->customExport = true; $this->view->orderBy = $orderBy; $this->view->type = $type; $this->view->executionID = $executionID; + $this->display(); } diff --git a/module/task/model.php b/module/task/model.php index 869c5c8a4a..ec815bf4f0 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -648,7 +648,7 @@ class taskModel extends model elseif($effortID) { $efforts = $this->getTaskEfforts($taskID, '', $effortID); - $prevTeam = $currentTeam = current($teams); + $prevTeam = current($teams); foreach($efforts as $effort) { $currentTeam = reset($teams); @@ -1694,6 +1694,52 @@ class taskModel extends model return $effort; } + /** + * 获取导出的任务数据。 + * Get export task information. + * + * @param string $orderBy + * @access public + * @return object[] + */ + public function getExportTasks(string $orderBy): array + { + $sort = common::appendOrder($orderBy); + $tasks = array(); + if($this->session->taskOnlyCondition) + { + $tasks = $this->dao->select('*')->from(TABLE_TASK)->alias('t1')->where($this->session->taskQueryCondition) + ->beginIF($this->post->exportType == 'selected')->andWhere('t1.id')->in($this->cookie->checkedItem)->fi() + ->orderBy($sort) + ->fetchAll('id'); + + foreach($tasks as $key => $task) + { + /* Compute task progress. */ + if($task->consumed == 0 and $task->left == 0) + { + $task->progress = 0; + } + elseif($task->consumed != 0 and $task->left == 0) + { + $task->progress = 100; + } + else + { + $task->progress = round($task->consumed / ($task->consumed + $task->left), 2) * 100; + } + $task->progress .= '%'; + } + } + elseif($this->session->taskQueryCondition) + { + $stmt = $this->dbh->query($this->session->taskQueryCondition . ($this->post->exportType == 'selected' ? " AND t1.id IN({$this->cookie->checkedItem})" : '') . " ORDER BY " . strtr($orderBy, '_', ' ')); + while($row = $stmt->fetch()) $tasks[$row->id] = $row; + } + + return $this->processExportTasks($tasks); + } + /** * 检查当前登录用户是否可以操作日志。 * Check if the current user can operate effort. @@ -2043,6 +2089,68 @@ class taskModel extends model return $task; } + /** + * 处理导出的任务信息。 + * Process export task information. + * + * @param array $tasks + * @access protected + * @return object[] + */ + protected function processExportTasks(array $tasks): array + { + /* Process multiple task info. */ + $taskTeam = $this->dao->select('*')->from(TABLE_TASKTEAM)->where('task')->in(array_keys($tasks))->fetchGroup('task'); + $users = $this->loadModel('user')->getPairs('noletter'); + if(!empty($taskTeam)) + { + foreach($taskTeam as $taskID => $team) + { + $tasks[$taskID]->team = $team; + $tasks[$taskID]->estimate = ''; + $tasks[$taskID]->left = ''; + $tasks[$taskID]->consumed = ''; + + foreach($team as $userInfo) + { + $tasks[$taskID]->estimate .= zget($users, $userInfo->account) . ':' . $userInfo->estimate . "\n"; + $tasks[$taskID]->left .= zget($users, $userInfo->account) . ':' . $userInfo->left . "\n"; + $tasks[$taskID]->consumed .= zget($users, $userInfo->account) . ':' . $userInfo->consumed . "\n"; + } + } + } + + /* Process parent-child task task info. */ + if($tasks) + { + $children = array(); + foreach($tasks as $task) + { + if($task->parent > 0 and isset($tasks[$task->parent])) + { + $children[$task->parent][$task->id] = $task; + unset($tasks[$task->id]); + } + } + if(!empty($children)) + { + $position = 0; + foreach($tasks as $task) + { + $position ++; + if(isset($children[$task->id])) + { + array_splice($tasks, $position, 0, $children[$task->id]); + $position += count($children[$task->id]); + } + } + } + } + + return $tasks; + } + + /** * When task is finish, check whether need update status of bug. * diff --git a/module/task/zen.php b/module/task/zen.php index ddd0d1740a..d4879ad748 100644 --- a/module/task/zen.php +++ b/module/task/zen.php @@ -766,7 +766,6 @@ class taskZen extends task protected function buildEffortForFinish(object $oldTask, object $task): object { /* Record consumed and left. */ - $consumed = $task->consumed; if(empty($oldTask->team)) { $consumed = $task->consumed - $oldTask->consumed; @@ -1073,6 +1072,54 @@ class taskZen extends task return !dao::isError(); } + /** + * 格式化导出任务的字段。 + * Format export task. + * + * @param object $task + * @param array $executions + * @param array $users + * @access protected + * @return object + */ + protected function formatExportTask(object $task, array $executions, array $users): object + { + $taskLang = $this->lang->task; + if($this->post->fileType == 'csv') + { + $task->desc = htmlspecialchars_decode((string)$task->desc); + $task->desc = str_replace("
", "\n", $task->desc); + $task->desc = str_replace('"', '""', $task->desc); + $task->desc = str_replace(' ', ' ', $task->desc); + } + + if(isset($executions[$task->execution])) $task->execution = $executions[$task->execution] . "(#$task->execution)"; + if(isset($taskLang->typeList[$task->type])) $task->type = $taskLang->typeList[$task->type]; + if(isset($taskLang->priList[$task->pri])) $task->pri = $taskLang->priList[$task->pri]; + if(isset($taskLang->statusList[$task->status])) $task->status = $this->processStatus('task', $task); + if(isset($taskLang->reasonList[$task->closedReason])) $task->closedReason = $taskLang->reasonList[$task->closedReason]; + if(isset($taskLang->modeList[$task->mode])) $task->mode = $taskLang->modeList[$task->mode]; + + if(isset($users[$task->openedBy])) $task->openedBy = $users[$task->openedBy]; + if(isset($users[$task->assignedTo])) $task->assignedTo = $users[$task->assignedTo]; + if(isset($users[$task->finishedBy])) $task->finishedBy = $users[$task->finishedBy]; + if(isset($users[$task->canceledBy])) $task->canceledBy = $users[$task->canceledBy]; + if(isset($users[$task->closedBy])) $task->closedBy = $users[$task->closedBy]; + if(isset($users[$task->lastEditedBy])) $task->lastEditedBy = $users[$task->lastEditedBy]; + + $task->openedDate = helper::isZeroDate($task->openedDate) ? '' : substr($task->openedDate, 0, 10); + $task->assignedDate = helper::isZeroDate($task->assignedDate) ? '' : substr($task->assignedDate, 0, 10); + $task->finishedDate = helper::isZeroDate($task->finishedDate) ? '' : substr($task->finishedDate, 0, 10); + $task->canceledDate = helper::isZeroDate($task->canceledDate) ? '' : substr($task->canceledDate, 0, 10); + $task->closedDate = helper::isZeroDate($task->closedDate) ? '' : substr($task->closedDate, 0, 10); + $task->lastEditedDate = helper::isZeroDate($task->lastEditedDate) ? '' : substr($task->lastEditedDate, 0, 10); + $task->estimate = $task->estimate . $this->lang->execution->workHourUnit; + $task->consumed = $task->consumed . $this->lang->execution->workHourUnit; + $task->left = $task->left . $this->lang->execution->workHourUnit; + + return $task; + } + /** * 为表单获取自定义字段。 * Get task's custom fields for form. @@ -1104,6 +1151,30 @@ class taskZen extends task return array($customFields, $checkedFields); } + /** + * 获取导出的字段。 + * Get export fields. + * + * @param string $allExportFields + * @access protected + * @return void + */ + protected function getExportFields(string $allExportFields): array + { + $fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $allExportFields); + + /* Compatible with the new UI widget. */ + if($this->post->exportFields && str_contains($fields[0], ',')) $fields = explode(',', $fields[0]); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($this->lang->task->$fieldName) ? $this->lang->task->$fieldName : $fieldName; + unset($fields[$key]); + } + + return $fields; + } + /** * 任务的数据更新之后,获取对应看板的数据。 * Get R&D kanban's or task kanban's data after task's data is updated. @@ -1213,6 +1284,138 @@ class taskZen extends task ->get(); } + /** + * 处理导出的任务数据。 + * Process export data. + * + * @param array $tasks + * @param int $projectID + * @access protected + * @return object[] + */ + protected function processExportData(array $tasks, int $projectID): array + { + /* Get users and executions. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $executions = $this->loadModel('execution')->fetchPairs($projectID, 'all', true, true); + + /* Get related objects id lists. */ + $relatedStoryIdList = array(); + foreach($tasks as $task) + { + $relatedStoryIdList[$task->story] = $task->story; + $relatedBugIdList[$task->fromBug] = $task->fromBug; + } + + /* Get related objects title or names. */ + $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('task')->andWhere('objectID')->in(array_keys($tasks))->andWhere('extra')->ne('editor')->fetchGroup('objectID'); + $relatedModules = $this->loadModel('tree')->getAllModulePairs('task'); + + $bugs = $this->loadModel('bug')->getByIdList($relatedBugIdList); + foreach($tasks as $task) + { + $task->story = isset($relatedStories[$task->story]) ? $relatedStories[$task->story] . "(#$task->story)" : ''; + $task->fromBug = empty($task->fromBug) ? '' : "#$task->fromBug " . $bugs[$task->fromBug]->title; + + if(isset($relatedModules[$task->module])) $task->module = $relatedModules[$task->module] . "(#$task->module)"; + + /* Convert username to real name. */ + if(!empty($task->mailto)) + { + $mailtoList = explode(',', $task->mailto); + + $task->mailto = ''; + foreach($mailtoList as $mailto) + { + if(!empty($mailto)) $task->mailto .= ',' . zget($users, $mailto); + } + } + + if($task->parent > 0 && strpos($task->name, htmlentities('>')) !== 0) $task->name = '>' . $task->name; + if(!empty($task->team)) + { + $task->name = '[' . $this->lang->task->multipleAB . '] ' . $task->name; + unset($task->team); + } + + $task = $this->formatExportTask($task, $executions, $users); + + /* Set related files. */ + $task->files = ''; + if(isset($relatedFiles[$task->id])) + { + foreach($relatedFiles[$task->id] as $file) + { + $fileURL = common::getSysURL() . $this->createLink('file', 'download', "fileID={$file->id}"); + $task->files .= html::a($fileURL, $file->title, '_blank') . '
'; + } + } + } + + return $tasks; + } + + /** + * 处理导出任务分组信息。 + * Process export task group information. + * + * @param array $tasks + * @param string $orderBy + * @access protected + * @return object[] + */ + protected function processExportGroup(array $tasks, string $orderBy): array + { + $stories = $this->loadModel('story')->getExecutionStories($executionID); + $groupTasks = array(); + foreach($tasks as $task) + { + $task->storyTitle = isset($stories[$task->story]) ? $stories[$task->story]->title : ''; + + if(!isset($task->team)) + { + $groupTasks[$task->$orderBy][] = $task; + continue; + } + + if($orderBy == 'finishedBy') $task->consumed = $task->estimate = $task->left = 0; + foreach($task->team as $team) + { + if($orderBy == 'finishedBy' and $team->left != 0) + { + $task->estimate += $team->estimate; + $task->consumed += $team->consumed; + $task->left += $team->left; + continue; + } + + $cloneTask = clone $task; + $cloneTask->estimate = $team->estimate; + $cloneTask->consumed = $team->consumed; + $cloneTask->left = $team->left; + if($team->left == 0) $cloneTask->status = 'done'; + + if($orderBy == 'assignedTo') + { + $cloneTask->assignedToRealName = zget($users, $team->account); + $cloneTask->assignedTo = $team->account; + } + if($orderBy == 'finishedBy')$cloneTask->finishedBy = $team->account; + $groupTasks[$team->account][] = $cloneTask; + } + if(!empty($task->left) and $orderBy == 'finishedBy') $groupTasks[$task->finishedBy][] = $task; + } + + $tasks = array(); + foreach($groupTasks as $groupTask) + { + foreach($groupTask as $task) $tasks[] = $task; + } + + return $tasks; + } + /** * 通过任务状态处理任务的人员、日期字段。 * Process the person and date fields of a task by status.