diff --git a/module/product/control.php b/module/product/control.php index 23e7b7d78d..469fea31f8 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -130,7 +130,6 @@ class product extends control /* Generate data. */ $showModule = !empty($this->config->datatable->productBrowse->showModule) ? $this->config->datatable->productBrowse->showModule : ''; - $productName = ($isProjectStory and empty($productID)) ? $this->lang->product->all : $this->products[$productID]; $productID = $this->app->tab != 'project' ? $this->product->saveVisitState($productID, $this->products) : $productID; $product = $this->productZen->getBrowseProduct($productID); $project = $this->loadModel('project')->getByID($projectID); @@ -143,7 +142,7 @@ class product extends control /* Generate data. */ $moduleID = $this->productZen->getModuleId4Browse($param, $browseType); - $moduleTree = $this->productZen->getModuleTree4BrowseTODO($projectID, $productID, $branch, $param, $storyType, $browseType); + $moduleTree = $this->productZen->getModuleTree4Browse($projectID, $productID, $branch, $param, $storyType, $browseType); $showBranch = $this->productZen->getShowBranch4Browse($projectID, $productID, $storyType, $isProjectStory); $projectProducts = $this->productZen->getProjectProducts4Browse($projectID, $storyType, $isProjectStory); $productPlans = $this->productZen->getProductPlans4Browse($projectProducts, $projectID, $storyType, $isProjectStory); @@ -162,6 +161,7 @@ class product extends control $storyTasks = $this->loadModel('task')->getStoryTaskCounts($storyIdList); $storyBugs = $this->loadModel('bug')->getStoryBugCounts($storyIdList); $storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList); + $productName = ($isProjectStory and empty($productID)) ? $this->lang->product->all : $this->products[$productID]; /* Save session. */ $this->productZen->saveSession4Browse($product, $storyType, $browseType, $isProjectStory); diff --git a/module/product/model.php b/module/product/model.php index 2ca64924fa..51629128a1 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -1331,11 +1331,13 @@ class productModel extends model $products = strtolower($status) == static::ST_BYSEARCH ? $this->getListBySearch($param) : $this->productTao->getList($programID, $status, 0, $line); if(empty($products)) return array(); + $this->loadModel('story'); + /* Get stats data. */ $productIDs = array_keys($products); $products = $this->productTao->getStatsProducts($productIDs,$programID, $orderBy, $pager); - $finishClosedStory = $this->productTao->getFinishClosedStoryTODO(); - $unclosedStory = $this->productTao->getUnClosedStoryTODO(); + $finishClosedStory = $this->story->getFinishClosedTotal(); + $unclosedStory = $this->story->getUnClosedTotal(); $plans = $this->productTao->getPlansTODO($productIDs); $releases = $this->productTao->getReleasesTODO($productIDs); $bugs = $this->productTao->getBugsTODO($productIDs); diff --git a/module/product/tao.php b/module/product/tao.php index 51113ea6dd..e66ecf3cae 100644 --- a/module/product/tao.php +++ b/module/product/tao.php @@ -218,60 +218,6 @@ class productTao extends productModel return $products; } - /* TODO move to story module. */ - protected function getStoriesTODO(array $productIDs): array - { - $stories = $this->dao->select('product, status, count(status) AS count') - ->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('type')->eq('story') - ->andWhere('product')->in($productIDs) - ->groupBy('product, status') - ->fetchGroup('product', 'status'); - - return $stories; - } - - /* TODO move to story module. */ - protected function getRequirementsTODO(array $productIDs): array - { - $requirements = $this->dao->select('product, status, count(status) AS count') - ->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('type')->eq('requirement') - ->andWhere('product')->in($productIDs) - ->groupBy('product, status') - ->fetchGroup('product', 'status'); - - return $requirements; - } - - /* TODO move to story module. */ - protected function getFinishClosedStoryTODO(): array - { - $finishClosedStory = $this->dao->select('product, count(1) as finish')->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('status')->eq('closed') - ->andWhere('type')->eq('story') - ->andWhere('closedReason')->eq('done') - ->groupBy('product') - ->fetchPairs(); - - return $finishClosedStory; - } - - /* TODO move to story module. */ - protected function getUnClosedStoryTODO(): array - { - $unclosedStory = $this->dao->select('product, count(1) as unclosed')->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('type')->eq('story') - ->andWhere('status')->ne('closed') - ->groupBy('product') - ->fetchPairs(); - - return $unclosedStory; - } /* TODO move to productplan module. */ protected function getPlansTODO(array $productIDs): array @@ -386,16 +332,6 @@ class productTao extends productModel return $assignToNull; } - /* TODO move to program module. */ - protected function getProgramsInTODO(array $programIDs): array - { - $programs = $this->dao->select('id,name,PM')->from(TABLE_PROGRAM) - ->where('id')->in($programIDs) - ->fetchAll('id'); - - return $programs; - } - /** * 获取用于统计的产品列表。 * Get products list for statistic. @@ -409,6 +345,8 @@ class productTao extends productModel */ protected function getStatsProducts(array $productIDs, int $programID, string $orderBy, object|null $pager = null): array { + $this->loadModel('program'); + if($orderBy == static::OB_PROGRAM) $products = $this->getPagerProductsWithProgramIn($productIDs, $pager); else $products = $this->getPagerProductsIn($productIDs, $pager, $orderBy); @@ -420,7 +358,7 @@ class productTao extends productModel $programKeys = array(0 => 0); foreach($products as $product) $programKeys[] = $product->program; - $programs = $this->getProgramsInTODO(array_unique($programKeys)); + $programs = $this->program->getBaseDataIn(array_unique($programKeys)); foreach($products as $product) { @@ -442,8 +380,9 @@ class productTao extends productModel */ protected function getStatsStoriesAndRequirements(array $productIDs, string $storyType): array { - $stories = $this->getStoriesTODO($productIDs); - $requirements = $this->getRequirementsTODO($productIDs); + $this->loadModel('story'); + $stories = $this->story->getStoriesCountByProductIDs($productIDs, 'story'); + $requirements = $this->story->getStoriesCountByProductIDs($productIDs); /* Padding the stories to sure all products have records. */ $emptyStory = array_keys($this->lang->story->statusList); @@ -933,13 +872,9 @@ class productTao extends productModel */ protected function getStoryStatusCountByID(int $productID, string $storyType = 'story'): array { - /* TODO move to story module. */ - $stories = $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('type')->eq($storyType) - ->andWhere('product')->eq($productID) - ->groupBy('product, status') - ->fetchAll('status'); + $this->loadModel('story'); + + $stories = $this->story->getStoriesCountByProductID($productID, $storyType); /* Padding the stories to sure all status have records. */ foreach(array_keys($this->lang->story->statusList) as $status) diff --git a/module/product/zen.php b/module/product/zen.php index ab80676c1f..d61d26ccda 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -1131,7 +1131,6 @@ class productZen extends product /** * 获取模块的树形数据结构。 * Get the tree structure of modules. - * TODO return pure HTML string, we need array. * * @param int $projectID * @param int $productID @@ -1142,7 +1141,7 @@ class productZen extends product * @access protected * @return string */ - protected function getModuleTree4BrowseTODO(int $projectID, int $productID, string &$branch, int $param, string $storyType, string $browseType): string + protected function getModuleTree4Browse(int $projectID, int $productID, string &$branch, int $param, string $storyType, string $browseType): string { /* Set moduleTree. */ $createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink'; diff --git a/module/program/tao.php b/module/program/tao.php new file mode 100644 index 0000000000..33ccb20acf --- /dev/null +++ b/module/program/tao.php @@ -0,0 +1,30 @@ + + * @package program + * @link http://www.zentao.net + */ + +class programTao extends programModel +{ + /** + * 通过项目集ID列表批量获取项目集基本数据。 + * Get program base data with program ID array. + * + * @param array $programIDs + * @access protected + * @return array + */ + protected function getBaseDataIn(array $programIDs): array + { + return $this->dao->select('id,name,PM') + ->from(TABLE_PROGRAM) + ->where('id')->in($programIDs) + ->fetchAll('id'); + } +} diff --git a/module/story/tao.php b/module/story/tao.php index 85669da0d7..f8b04dd470 100644 --- a/module/story/tao.php +++ b/module/story/tao.php @@ -213,4 +213,82 @@ class storyTao extends storyModel return $relationGroup; } + + /** + * 批量获取产品所有状态对应的需求总数。 + * Get stories count of each status by product ID. + * + * @param array $productIDs + * @param string $storyType + * @access protected + * @return array + */ + protected function getStoriesCountByProductIDs(array $productIDs, string $storyType = 'requirement'): array + { + return $this->dao->select('product, status, count(status) AS count') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('type')->eq($storyType) + ->andWhere('product')->in($productIDs) + ->groupBy('product, status') + ->fetchGroup('product', 'status'); + } + + /** + * 获取产品所有状态对应的需求总数。 + * Get stories count of each status by product ID. + * + * @param int $productID + * @param string $storyType + * @access protected + * @return array + */ + protected function getStoriesCountByProductID(int $productID, string $storyType = 'requirement'): array + { + return $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('type')->eq($storyType) + ->andWhere('product')->eq($productID) + ->groupBy('product, status') + ->fetchAll('status'); + } + + /** + * 获取所有完成的需求数量。 + * Get the count of closed stories. + * + * @param string $storyType + * @access protected + * @return array + */ + protected function getFinishClosedTotal(string $storyType = 'story'): array + { + return $this->dao->select('product, count(1) AS finish') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('status')->eq('closed') + ->andWhere('type')->eq($storyType) + ->andWhere('closedReason')->eq('done') + ->groupBy('product') + ->fetchPairs(); + } + + /** + * 获取所有未完成的需求数量。 + * Get the count of unclosed stories. + * + * @param string $storyType + * @access protected + * @return array + */ + protected function getUnClosedTotal(string $storyType = 'story'): array + { + return $this->dao->select('product, count(1) AS unclosed') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('type')->eq($storyType) + ->andWhere('status')->ne('closed') + ->groupBy('product') + ->fetchPairs(); + } }