diff --git a/lib/zin/wg/roadmap/v1.php b/lib/zin/wg/roadmap/v1.php index fa2ae4fd07..e3569d3576 100644 --- a/lib/zin/wg/roadmap/v1.php +++ b/lib/zin/wg/roadmap/v1.php @@ -81,10 +81,17 @@ class roadMap extends wg } global $lang; + if(!isset($lang->execution->iterationInfo)) + { + global $app; + $app->loadLang('execution'); + } + $iterationInfo = $lang->execution->iterationInfo; + return div ( setClass('release-path flex gap-6 items-end'), - $this->releaseHead($year, sprintf($lang->execution->iterationInfo, (string)$count)), + $this->releaseHead($year, sprintf($iterationInfo, (string)$count)), div ( setClass('grow'), diff --git a/module/product/model.php b/module/product/model.php index 79ba53ab6a..b103496349 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -1806,4 +1806,46 @@ class productModel extends model 'url' => helper::createLink($module, $method, $params, '', $onlyBody) ); } + + /** + * Build roadmap for UI. + * + * @param array $roadmaps + * @param int $branchKey + * @access public + * @return array + */ + public function buildRoadmapForUI(array $roadmaps, int $branchKey = 0): array + { + unset($roadmaps['total']); + + $data = array(); + foreach($roadmaps as $year => $yearRoadmaps) + { + if(!isset($yearRoadmaps[$branchKey])) continue; + + foreach($yearRoadmaps[$branchKey] as $roadmapData) + { + $yearNodes = array(); + foreach($roadmapData as $roadmap) + { + $isPlan = (isset($roadmap->begin) && isset($roadmap->end)); + $moduleName = $isPlan ? 'productplan' : 'release'; + $node = array(); + $node['href'] = common::hasPriv($moduleName, 'view') ? helper::createLink($moduleName, 'view', "id={$roadmap->id}") : '###'; + $node['version'] = $isPlan ? $roadmap->title : $roadmap->name; + $node['date'] = $isPlan ? $roadmap->begin . '~' . $roadmap->end : $roadmap->date; + if(!empty($roadmap->marker)) $node['marker'] = true; + $yearNodes[] = $node; + } + + $count = count($yearNodes); + $cols = 5; + $lines = array(); + for($i = 0; $i * $cols < $count; $i ++) $lines[] = array_slice($yearNodes, $i * $cols, $cols); + $data[$year] = array_reverse($lines); + } + } + return $data; + } } diff --git a/module/product/ui/roadmap.html.php b/module/product/ui/roadmap.html.php new file mode 100644 index 0000000000..3bf0f447f7 --- /dev/null +++ b/module/product/ui/roadmap.html.php @@ -0,0 +1,63 @@ + +* @package product +* @link https://www.zentao.net +*/ + +namespace zin; + +$productModel = $this->product; + +$fnPrintSingleRoadmap = function($branchKey = 0) use ($roadmaps, $product, $productModel) +{ + $data = $productModel->buildRoadmapForUI($roadmaps, $branchKey); + $hasRoadmaps = !empty($data) ; + + if(!$hasRoadmaps) + { + return div + ( + setClass('table-empty-tip'), + span(setClass('text-gray'), $lang->release->noRelease), + common::canModify('product', $product) && common::hasPriv('release', 'create') ? btn(setClass('secondary'), set::url(createLink('release', 'create', "productID=$product->id&branch=$branchKey")), icon(setClass('pr-1'), 'plus'), $lang->release->create) : null, + ); + } + else + { + return roadMap(set::releases($data)); + } +}; + +$fnPrintBranchRoadmap = function() use ($branches, $roadmaps, $product, $productModel, $fnPrintSingleRoadmap) +{ + $tabPaneItems = array(); + foreach($branches as $branchKey => $branchName) + { + $tabPaneItems[] = tabPane + ( + set::key("roadmap_{$branchKey}"), + set::title($branchName), + set::active($branchKey == 0), + $fnPrintSingleRoadmap($branchKey), + ); + } + return tabs($tabPaneItems); +}; + +panel +( + set::title($lang->product->iteration), + set::titleClass("text-lg"), + set::headingClass('justify-start'), + to::heading + ( + span(setClass('label rounded-full'), sprintf($lang->product->iterationInfo, $roadmaps['total'])), + ), + $product->type == 'normal' ? $fnPrintSingleRoadmap() : $fnPrintBranchRoadmap(), +);