From 63a8a5d3aba504b7751ae0d11abbea6ae80650f0 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Fri, 21 Jul 2023 10:44:22 +0800 Subject: [PATCH] * Add single product dashboard, and set default blocks in single product dashboard. --- module/block/config.php | 9 + .../css/singleproductstatisticblock.ui.css | 12 + module/block/lang/zh-cn.php | 20 ++ module/block/ui/roadmapblock.html.php | 24 ++ .../block/ui/singlebugstatisticblock.html.php | 24 ++ module/block/ui/singledynamicblock.html.php | 24 ++ .../ui/singlemonthlyprogressblock.html.php | 24 ++ module/block/ui/singleplanblock.html.php | 24 ++ module/block/ui/singlereleaseblock.html.php | 24 ++ module/block/ui/singlestatisticblock.html.php | 295 ++++++++++++++++++ module/block/ui/singlestoryblock.html.php | 24 ++ module/block/zen.php | 110 +++++++ module/index/config.php | 1 - module/product/control.php | 17 +- 14 files changed, 616 insertions(+), 16 deletions(-) create mode 100644 module/block/css/singleproductstatisticblock.ui.css create mode 100644 module/block/ui/roadmapblock.html.php create mode 100644 module/block/ui/singlebugstatisticblock.html.php create mode 100644 module/block/ui/singledynamicblock.html.php create mode 100644 module/block/ui/singlemonthlyprogressblock.html.php create mode 100644 module/block/ui/singleplanblock.html.php create mode 100644 module/block/ui/singlereleaseblock.html.php create mode 100644 module/block/ui/singlestatisticblock.html.php create mode 100644 module/block/ui/singlestoryblock.html.php diff --git a/module/block/config.php b/module/block/config.php index 0cdef575af..afe9ff8e42 100644 --- a/module/block/config.php +++ b/module/block/config.php @@ -368,3 +368,12 @@ $config->block->size['assigntome']['assigntome'] = array('2' => '6', ' $config->block->size['dynamic']['dynamic'] = array('1' => '8'); $config->block->size['zentaodynamic']['zentaodynamic'] = array('1' => '4'); $config->block->size['teamachievement']['teamachievement'] = array('1' => '6'); + +$config->block->size['singleproduct']['singlestatistic'] = array('2' => '5', '1' => '11'); +$config->block->size['singleproduct']['singlebug'] = array('2' => '6', '1' => '6'); +$config->block->size['singleproduct']['roadmap'] = array('2' => '6', '1' => '6'); +$config->block->size['singleproduct']['singlestory'] = array('2' => '6', '1' => '6'); +$config->block->size['singleproduct']['singleplan'] = array('2' => '6', '1' => '6'); +$config->block->size['singleproduct']['singlerelease'] = array('2' => '6', '1' => '6'); +$config->block->size['singleproduct']['singledyncmic'] = array('1' => '13'); +$config->block->size['singleproduct']['singlemonthlyprogress'] = array('2' => '5', '1' => '13'); diff --git a/module/block/css/singleproductstatisticblock.ui.css b/module/block/css/singleproductstatisticblock.ui.css new file mode 100644 index 0000000000..31b2d53f64 --- /dev/null +++ b/module/block/css/singleproductstatisticblock.ui.css @@ -0,0 +1,12 @@ +.singleproductstatistic-block {background: #FCFDFE;} +.singleproductstatistic-block .panel-body {padding: 0;} + +.singleproductstatistic-block .tab-content {width: 100%;} +.singleproductstatistic-block .tab-pane {padding: 0;} +.singleproductstatistic-block .bg-secondary-pale {background: #F3F6FA;} +.singleproductstatistic-block .chart {margin: auto;} +.singleproductstatistic-block .story-num {margin: auto;} + +.singleproductstatistic-block .chart > div {margin: auto;} +.singleproductstatistic-block .pie-chart {position: relative;} +.singleproductstatistic-block .pie-chart .pie-chart-title {position: absolute; top: 50%; left: 50%; margin-top: -25px; margin-left: -45px} diff --git a/module/block/lang/zh-cn.php b/module/block/lang/zh-cn.php index acf553a85a..c7898be52f 100644 --- a/module/block/lang/zh-cn.php +++ b/module/block/lang/zh-cn.php @@ -139,6 +139,7 @@ $lang->block->titleList['projectdynamic'] = '最新动态'; $lang->block->titleList['bug'] = '指派给我的Bug'; $lang->block->titleList['case'] = '指派给我的用例'; $lang->block->titleList['testtask'] = '测试单列表'; +$lang->block->titleList['statistic'] = "{$lang->projectCommon}统计"; $lang->block->default['scrumproject'][] = array('title' => "{$lang->projectCommon}总览", 'module' => 'scrumproject', 'code' => 'scrumoverview', 'width' => '2'); $lang->block->default['scrumproject'][] = array('title' => "{$lang->executionCommon}列表", 'module' => 'scrumproject', 'code' => 'scrumlist', 'width' => '2', 'params' => array('type' => 'undone', 'count' => '20', 'orderBy' => 'id_desc')); @@ -165,6 +166,15 @@ $lang->block->default['product'][] = array('title' => "未关闭{$lang->productC $lang->block->default['product'][] = array('title' => "{$lang->productCommon}发布统计", 'module' => 'product', 'code' => 'releasestatistic', 'width' => '2'); $lang->block->default['product'][] = array('title' => "指派给我的{$lang->SRCommon}", 'module' => 'product', 'code' => 'story', 'width' => '1', 'params' => array('type' => 'assignedTo', 'count' => '20', 'orderBy' => 'id_desc')); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}统计", 'module' => 'singleproduct', 'code' => 'singlestatistic', 'width' => '2', 'params' => array('count' => '20')); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}的Bug数据", 'module' => 'singleproduct', 'code' => 'singlebugstatistic', 'width' => '2', 'params' => array('count' => '20')); +$lang->block->default['singleproduct'][] = array('title' => "产品路线图", 'module' => 'singleproduct', 'code' => 'roadmap', 'width' => '2'); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}的需求列表", 'module' => 'singleproduct', 'code' => 'singlestory', 'width' => '2', 'params' => array('count' => '20')); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}的计划列表", 'module' => 'singleproduct', 'code' => 'singleplan', 'width' => '2', 'params' => array('count' => '20')); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}的发布统计", 'module' => 'singleproduct', 'code' => 'singlerelease', 'width' => '2', 'params' => array('count' => '20')); +$lang->block->default['singleproduct'][] = array('title' => "最新动态", 'module' => 'singleproduct', 'code' => 'singledynamic', 'width' => '1'); +$lang->block->default['singleproduct'][] = array('title' => "{$lang->productCommon}月度推进分析", 'module' => 'singleproduct', 'code' => 'singlemonthlyprogress', 'width' => '1'); + $lang->block->default['qa'][] = array('title' => '测试统计', 'module' => 'qa', 'code' => 'statistic', 'width' => '2', 'params' => array('type' => 'noclosed', 'count' => '20')); $lang->block->default['qa'][] = array('title' => '测试单列表', 'module' => 'qa', 'code' => 'testtask', 'width' => '2', 'params' => array('type' => 'wait', 'count' => '15', 'orderBy' => 'id_desc')); $lang->block->default['qa'][] = array('title' => 'Bug列表', 'module' => 'qa', 'code' => 'bug', 'width' => '1', 'params' => array('type' => 'assignedTo', 'count' => '15', 'orderBy' => 'id_desc')); @@ -278,6 +288,16 @@ if($config->vision == 'rnd') $lang->block->modules['doc']->availableBlocks['prod $lang->block->modules['doc']->availableBlocks['doccollectlist'] = '收藏排行榜'; $lang->block->modules['doc']->availableBlocks['projectdoc'] = $lang->projectCommon . '文档'; +$lang->block->modules['singleproduct'] = new stdclass(); +$lang->block->modules['singleproduct']->availableBlocks['singlestatistic'] = $lang->productCommon . '统计'; +$lang->block->modules['singleproduct']->availableBlocks['singlebugstatistic'] = "{$lang->productCommon}Bug统计"; +$lang->block->modules['singleproduct']->availableBlocks['roadmap'] = "产品路线图"; +$lang->block->modules['singleproduct']->availableBlocks['singlestory'] = "{$lang->SRCommon}列表"; +$lang->block->modules['singleproduct']->availableBlocks['singleplan'] = "计划列表"; +$lang->block->modules['singleproduct']->availableBlocks['singlerelease'] = '发布列表'; +$lang->block->modules['singleproduct']->availableBlocks['singledynamic'] = '最新动态'; +$lang->block->modules['singleproduct']->availableBlocks['singlemonthlyprogress'] = "{$lang->productCommon}月度推进分析"; + $lang->block->orderByList = new stdclass(); $lang->block->orderByList->product = array(); $lang->block->orderByList->product['id_asc'] = 'ID 递增'; diff --git a/module/block/ui/roadmapblock.html.php b/module/block/ui/roadmapblock.html.php new file mode 100644 index 0000000000..924c73c37c --- /dev/null +++ b/module/block/ui/roadmapblock.html.php @@ -0,0 +1,24 @@ + + * @package block + * @link https://www.zentao.net + */ +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); + diff --git a/module/block/ui/singlebugstatisticblock.html.php b/module/block/ui/singlebugstatisticblock.html.php new file mode 100644 index 0000000000..7a8909db64 --- /dev/null +++ b/module/block/ui/singlebugstatisticblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/ui/singledynamicblock.html.php b/module/block/ui/singledynamicblock.html.php new file mode 100644 index 0000000000..eb07e0a769 --- /dev/null +++ b/module/block/ui/singledynamicblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/ui/singlemonthlyprogressblock.html.php b/module/block/ui/singlemonthlyprogressblock.html.php new file mode 100644 index 0000000000..f0842a2dc9 --- /dev/null +++ b/module/block/ui/singlemonthlyprogressblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/ui/singleplanblock.html.php b/module/block/ui/singleplanblock.html.php new file mode 100644 index 0000000000..f3902abcc6 --- /dev/null +++ b/module/block/ui/singleplanblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/ui/singlereleaseblock.html.php b/module/block/ui/singlereleaseblock.html.php new file mode 100644 index 0000000000..539c3659db --- /dev/null +++ b/module/block/ui/singlereleaseblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/ui/singlestatisticblock.html.php b/module/block/ui/singlestatisticblock.html.php new file mode 100644 index 0000000000..f97799b665 --- /dev/null +++ b/module/block/ui/singlestatisticblock.html.php @@ -0,0 +1,295 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; +$app->loadLang('execution'); + +$doneData = array(); +$openedData = array(); +foreach($product->monthFinish as $date => $count) +{ + if($date == date('Y-m')) + { + $product->monthFinish[$lang->datepicker->dpText->TEXT_THIS_MONTH] = $count; + unset($product->monthFinish[$date]); + } + $doneData[] = $count; +} +foreach($product->monthCreated as $date => $count) +{ + if($date == date('Y-m')) + { + $product->monthCreated[$lang->datepicker->dpText->TEXT_THIS_MONTH] = $count; + unset($product->monthCreated[$date]); + } + $openedData[] = $count; +} + +panel +( + setClass('singleproductstatistic-block ' . ($longBlock ? 'block-long' : 'block-sm')), + set::headingClass('border-b'), + set::title($block->title), + div + ( + setClass("flex h-full overflow-hidden " . ($longBlock ? '' : 'col')), + cell + ( + setClass('flex-1'), + $longBlock ? set('width', '70%') : null, + div + ( + setClass('flex h-full ' . ($longBlock ? '' : 'col')), + cell + ( + $longBlock ? set('width', '40%') : null, + setClass($longBlock ? 'p-4' : 'px-4'), + div + ( + setClass('chart pie-chart ' . ($longBlock ? 'py-6' : 'py-1')), + echarts + ( + set::color(array('#2B80FF', '#E3E4E9')), + set::series + ( + array + ( + array + ( + 'type' => 'pie', + 'radius' => array('80%', '90%'), + 'itemStyle' => array('borderRadius' => '40'), + 'label' => array('show' => false), + 'data' => array($product->storyDeliveryRate, 100 - $product->storyDeliveryRate) + ) + ) + ) + )->size('100%', 120), + div + ( + set::class('pie-chart-title text-center'), + div(span(set::class('text-2xl font-bold'), $product->storyDeliveryRate . '%')), + div(span(set::class('text-sm text-gray'), $lang->block->productstatistic->deliveryRate, icon('help', set('data-toggle', 'tooltip'), set('id', 'storyTip'), setClass('text-light')))) + ) + ), + div + ( + setClass('flex h-full story-num w-44'), + cell + ( + setClass('flex-1 text-center'), + div + ( + common::hasPriv('product', 'browse') && $product->totalStories ? a + ( + set('href', helper::createLink('product', 'browse', "productID={$product->id}&branch=all&browseType=allStory¶m=0&storyType=story")), + $product->totalStories + ) : span + ( + $product->totalStories + ) + ), + div + ( + span + ( + setClass('text-sm text-gray'), + $lang->block->productstatistic->effectiveStory + ) + ) + ), + cell + ( + setClass('flex-1 text-center'), + div + ( + common::hasPriv('product', 'browse') && $product->closedStories ? a + ( + set('href', helper::createLink('product', 'browse', "productID={$product->id}&branch=all&browseType=closedstory¶m=0&storyType=story")), + $product->closedStories + ) : span + ( + $product->closedStories + ) + ), + div + ( + span + ( + setClass('text-sm text-gray'), + $lang->block->productstatistic->delivered + ) + ) + ), + cell + ( + setClass('flex-1 text-center'), + div + ( + common::hasPriv('product', 'browse') && $product->unclosedStories ? a + ( + set('href', helper::createLink('product', 'browse', "productID={$product->id}&branch=all&browseType=unclosed¶m=0&storyType=story")), + $product->unclosedStories + ) : span + ( + $product->unclosedStories + ) + ), + div + ( + span + ( + setClass('text-sm text-gray'), + $lang->block->productstatistic->unclosed + ) + ) + ) + ) + ), + cell + ( + $longBlock ? set('width', '60%') : null, + setClass('py-4'), + div + ( + setClass('border-r'), + div + ( + setClass('px-4 pb-2'), + $lang->block->productstatistic->storyStatistics + ), + div + ( + setClass('px-4'), + span + ( + setClass('border-r pr-2 text-sm text-gray'), + html(sprintf($lang->block->productstatistic->monthDone, !empty($monthFinish[$lang->datepicker->dpText->TEXT_THIS_MONTH]) ? $monthFinish[$lang->datepicker->dpText->TEXT_THIS_MONTH] : 0)) + ), + span + ( + setClass('pl-2 text-sm text-gray'), + html(sprintf($lang->block->productstatistic->monthOpened, !empty($monthCreated[$lang->datepicker->dpText->TEXT_THIS_MONTH]) ? $monthCreated[$lang->datepicker->dpText->TEXT_THIS_MONTH] : 0)) + ) + ), + div + ( + setClass('px-4 py-2 chart'), + echarts + ( + set::color(array('#2B80FF', '#17CE97')), + set::grid(array('left' => '10px', 'top' => '30px', 'right' => '0', 'bottom' => '30px', 'containLabel' => true)), + set::legend(array('show' => true, 'right' => '0')), + set::xAxis(array('type' => 'category', 'data' => array_keys($monthFinish), 'splitLine' => array('show' => false), 'axisTick' => array('alignWithLabel' => true, 'interval' => '0'))), + set::yAxis(array('type' => 'value', 'name' => '个', 'splitLine' => array('show' => false), 'axisLine' => array('show' => true, 'color' => '#DDD'))), + set::series + ( + array + ( + array + ( + 'type' => 'line', + 'name' => $lang->block->productstatistic->opened, + 'data' => $openedData + ), + array + ( + 'type' => 'line', + 'name' => $lang->block->productstatistic->done, + 'data' => $doneData + ) + ) + ) + )->size('100%', 170), + ) + ) + ) + ) + ), + ($product->newPlan || $product->newExecution || $product->newRelease) ? cell + ( + set('width', '30%'), + setClass('p-4'), + div + ( + setClass('pb-2'), + span($lang->block->productstatistic->news) + ), + $product->newPlan ? div + ( + setClass('pb-4' . ($longBlock ? '' : 'flex')), + div(span(setClass('text-sm text-gray'), $lang->block->productstatistic->newPlan)), + div + ( + setClass($longBlock ? 'py-1' : 'pl-2'), + common::hasPriv('productplan', 'view') ? a + ( + set('href', helper::createLink('productplan', 'view', "planID={$product->newPlan->id}")), + $product->newPlan->title + ) : span + ( + $product->newPlan->title + ), + span + ( + setClass('label lighter-pale rounded-full ml-2 px-1'), + zget($lang->productplan->statusList, $product->newPlan->status) + ) + ) + ) : null, + $product->newExecution ? div + ( + setClass('pb-4 ' . ($longBlock ? '' : 'flex')), + div(span(setClass('text-sm text-gray'), $lang->block->productstatistic->newExecution)), + div + ( + setClass($longBlock ? 'py-1' : 'pl-2'), + common::hasPriv('execution', 'task') ? a + ( + set('href', helper::createLink('execution', 'task', "executionID={$product->newExecution->id}")), + $product->newExecution->name + ) : span + ( + $product->newExecution->name + ), + span + ( + setClass('label important-pale rounded-full ml-2'), + zget($lang->execution->statusList, $product->newExecution->status) + ) + ) + ) : null, + $product->newRelease ? div + ( + setClass($longBlock ? '' : 'flex'), + div(span(setClass('text-sm text-gray'), $lang->block->productstatistic->newRelease)), + div + ( + setClass($longBlock ? 'py-1' : 'pl-2'), + common::hasPriv('release', 'view') ? a + ( + set('href', helper::createLink('release', 'view', "releaseID={$product->newRelease->id}")), + $product->newRelease->name + ) : span + ( + $product->newRelease->name + ), + span + ( + setClass('label rounded-full ml-2 ' . ($product->newRelease->status == 'normal' ? 'success-pale' : 'lighter-pale')), + zget($lang->release->statusList, $product->newRelease->status) + ) + ) + ) : null + ) : null + ) +); +render(); diff --git a/module/block/ui/singlestoryblock.html.php b/module/block/ui/singlestoryblock.html.php new file mode 100644 index 0000000000..4027a7c077 --- /dev/null +++ b/module/block/ui/singlestoryblock.html.php @@ -0,0 +1,24 @@ + +* @package block +* @link https://www.zentao.net +*/ + +namespace zin; + +panel +( + set('headingClass', 'border-b'), + set::title($block->title), + div + ( + '正在开发中...' + ) +); + +render(); diff --git a/module/block/zen.php b/module/block/zen.php index a29f8e205b..dd5e2a3f3f 100644 --- a/module/block/zen.php +++ b/module/block/zen.php @@ -2431,6 +2431,116 @@ class blockZen extends block $this->view->todayWorkload = 11; } + /** + * 打印单个产品统计区块。 + * Print product statistic block. + * + * @param object $block + * @access protected + * @return bool + */ + protected function printSingleStatisticBlock(object $block): void + { + /* 获取需要统计的产品列表。 */ + /* Obtain a list of product that require statistics. */ + $status = isset($block->params->type) ? $block->params->type : ''; + $count = isset($block->params->count) ? $block->params->count : ''; + $productID = $this->session->product; + + $storyDeliveryRate = $this->loadModel('metric')->getResultByCode('rate_of_delivery_story_in_product', array('product' => $productID)); + $storyDeliveryRate = json_decode(json_encode($storyDeliveryRate), true); + if(!empty($storyDeliveryRate)) $storyDeliveryRate = array_column($storyDeliveryRate, null, 'product'); + + $totalStories = $this->metric->getResultByCode('count_of_valid_story_in_product', array('product' => $productID)); + $totalStories = json_decode(json_encode($totalStories), true); + if(!empty($totalStories)) $totalStories = array_column($totalStories, null, 'product'); + + $closedStories = $this->metric->getResultByCode('count_of_delivered_story_in_product', array('product' => $productID)); + $closedStories = json_decode(json_encode($closedStories), true); + if(!empty($closedStories)) $closedStories = array_column($closedStories, null, 'product'); + + $unclosedStories = $this->metric->getResultByCode('count_of_unclosed_story_in_product', array('product' => $productID)); + $unclosedStories = json_decode(json_encode($unclosedStories), true); + if(!empty($unclosedStories)) $unclosedStories = array_column($unclosedStories, null, 'product'); + + $years = array(); + $months = array(); + for($i = 0; $i <= 5; $i ++) + { + $years[date('Y', strtotime("first day of -{$i} month"))] = date('Y', strtotime("first day of -{$i} month")); + $months[date('m', strtotime("first day of -{$i} month"))] = date('m', strtotime("first day of -{$i} month")); + $groups[date('Y-m', strtotime("first day of -{$i} month"))] = date('Y-m', strtotime("first day of -{$i} month")); + } + $monthFinish = $this->metric->getResultByCode('count_of_monthly_finished_story_in_product', array('product' => $productID, 'year' => join(',', $years), 'month' => join(',', $months))); + $monthCreated = $this->metric->getResultByCode('count_of_monthly_created_story_in_product', array('product' => $productID, 'year' => join(',', $years), 'month' => join(',', $months))); + if(empty($monthFinish)) $monthFinish = array(); + if(empty($monthCreated)) $monthCreated = array(); + + /* 根据产品列表获取预计开始日期距离现在最近且预计开始日期大于当前日期的未开始状态计划。 */ + /* Obtain an unstarted status plan based on the product list, with an expected start date closest to the current date and an expected start date greater than the current date. */ + $newPlan = $this->dao->select('*')->from(TABLE_PRODUCTPLAN) + ->where('deleted')->eq('0') + ->andWhere('product')->eq($productID) + ->andWhere('begin')->ge(date('Y-m-01')) + ->andWhere('status')->eq('wait') + ->orderBy('begin_desc') + ->fetch(); + + /* 根据产品列表获取实际开始日期距离当前最近的进行中状态的执行。 */ + /* Obtain the execution of the current in progress status closest to the actual start date based on the product list. */ + $newExecution = $this->dao->select('execution.*,relation.product')->from(TABLE_EXECUTION)->alias('execution') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('relation')->on('execution.id=relation.project') + ->where('execution.deleted')->eq('0') + ->andWhere('execution.type')->eq('sprint') + ->andWhere('relation.product')->eq($productID) + ->andWhere('execution.status')->eq('doing') + ->orderBy('realBegan_asc') + ->fetch(); + + /* 根据产品列表获取发布日期距离现在最近且发布日期小于当前日期的发布。 */ + /* Retrieve releases with the latest release date from the product list and a release date earlier than the current date. */ + $newRelease = $this->dao->select('*')->from(TABLE_RELEASE) + ->where('deleted')->eq('0') + ->andWhere('product')->eq($productID) + ->andWhere('date')->lt(date('Y-m-01')) + ->orderBy('date_asc') + ->fetch(); + + $product = $this->loadModel('product')->getByID($productID); + + $product->storyDeliveryRate = !empty($storyDeliveryRate) && !empty($storyDeliveryRate[$productID]) ? zget($storyDeliveryRate[$productID], 'value') : 0; + $product->totalStories = !empty($totalStories) && !empty($totalStories[$productID]) ? zget($totalStories[$productID], 'value') : 0; + $product->closedStories = !empty($closedStories) && !empty($closedStories[$productID]) ? zget($closedStories[$productID], 'value') : 0; + $product->unclosedStories = !empty($unclosedStories) && !empty($unclosedStories[$productID]) ? zget($unclosedStories[$productID], 'value') : 0; + $product->newPlan = $newPlan; + $product->newExecution = $newExecution; + $product->newRelease = $newRelease; + + foreach($groups as $group) + { + $product->monthFinish[$group] = 0; + $product->monthCreated[$group] = 0; + if(!empty($monthFinish)) + { + foreach($monthFinish as $story) + { + if($group == "{$story->year}-{$story->month}" && $productID == $story->product) $product->monthFinish[$group] = $story->value; + } + } + if(!empty($monthCreated)) + { + foreach($monthCreated as $story) + { + if($group == "{$story->year}-{$story->month}" && $productID == $story->product) $product->monthCreated[$group] = $story->value; + } + } + } + + $this->view->product = $product; + $this->view->monthFinish = $monthFinish; + $this->view->monthCreated = $monthCreated; + } + /** * 判断是否为内部调用。 * Check request client is chandao or not. diff --git a/module/index/config.php b/module/index/config.php index b4788051cc..0bc9cfa3e4 100644 --- a/module/index/config.php +++ b/module/index/config.php @@ -56,6 +56,5 @@ $config->index->oldPages[] = 'action-trash'; $config->index->oldPages[] = 'dept-browse'; $config->index->oldPages[] = 'story-report'; $config->index->oldPages[] = 'user-dynamic'; -$config->index->oldPages[] = 'product-dashboard'; $config->index->oldPages[] = 'repo-setrules'; $config->index->oldPages[] = 'host-treemap'; diff --git a/module/product/control.php b/module/product/control.php index eebe07637f..0cbd2136f7 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -520,22 +520,9 @@ class product extends control /* Get product. */ $product = $this->product->getStatByID($productID); if(!$product) return print(js::locate('product', 'all')); - $product->desc = $this->loadModel('file')->setImgSize($product->desc); - /* Save env data. */ - $this->productZen->saveBackUriSession4Dashboard(); - $this->product->setMenu($productID); - - /* Assign. */ - $this->view->title = $product->name . $this->lang->colon . $this->lang->product->view; - $this->view->product = $product; - $this->view->actions = $this->loadModel('action')->getList('product', $productID); - $this->view->users = $this->user->getPairs('noletter'); - $this->view->lines = array('') + $this->product->getLinePairs(); - $this->view->dynamics = $this->productZen->getActions4Dashboard($productID); - $this->view->roadmaps = $this->product->getRoadmap($productID, '0', 6); - - $this->display(); + $this->view->title = $product->name . $this->lang->colon . $this->lang->product->view; + echo $this->fetch('block', 'dashboard', 'dashboard=singleproduct'); } /**