diff --git a/module/program/config.php b/module/program/config.php index a9759c3b1c..f330bc631c 100644 --- a/module/program/config.php +++ b/module/program/config.php @@ -165,7 +165,7 @@ $config->program->productView->dtable->fieldList['closedReqRate']['minWidth'] = $config->program->productView->dtable->fieldList['closedReqRate']['type'] = 'circleProgress'; $config->program->productView->dtable->fieldList['closedReqRate']['sortType'] = true; -$config->program->productView->dtable->fieldList['planCount']['name'] = 'planCount'; +$config->program->productView->dtable->fieldList['planCount']['name'] = 'plans'; $config->program->productView->dtable->fieldList['planCount']['title'] = $lang->productplan->shortCommon; $config->program->productView->dtable->fieldList['planCount']['width'] = 60; $config->program->productView->dtable->fieldList['planCount']['type'] = 'format'; @@ -183,7 +183,7 @@ $config->program->productView->dtable->fieldList['testCaseCoverRate']['minWidth' $config->program->productView->dtable->fieldList['testCaseCoverRate']['type'] = 'circleProgress'; $config->program->productView->dtable->fieldList['testCaseCoverRate']['sortType'] = true; -$config->program->productView->dtable->fieldList['bugActivedCount']['name'] = 'bugActivedCount'; +$config->program->productView->dtable->fieldList['bugActivedCount']['name'] = 'unResolvedBugs'; $config->program->productView->dtable->fieldList['bugActivedCount']['title'] = $lang->program->bugActivedCount; $config->program->productView->dtable->fieldList['bugActivedCount']['minWidth'] = 60; $config->program->productView->dtable->fieldList['bugActivedCount']['type'] = 'format'; @@ -223,11 +223,11 @@ $config->program->projectView->dtable->fieldList['status']['type'] = 'statu $config->program->projectView->dtable->fieldList['status']['sortType'] = true; $config->program->projectView->dtable->fieldList['status']['statusMap'] = $lang->program->statusList; -$config->program->projectView->dtable->fieldList['PMName']['name'] = 'PMName'; -$config->program->projectView->dtable->fieldList['PMName']['title'] = $lang->program->PM; -$config->program->projectView->dtable->fieldList['PMName']['minWidth'] = 80; -$config->program->projectView->dtable->fieldList['PMName']['type'] = 'avatarBtn'; -$config->program->projectView->dtable->fieldList['PMName']['sortType'] = true; +$config->program->projectView->dtable->fieldList['PM']['name'] = 'PM'; +$config->program->projectView->dtable->fieldList['PM']['title'] = $lang->program->PM; +$config->program->projectView->dtable->fieldList['PM']['minWidth'] = 80; +$config->program->projectView->dtable->fieldList['PM']['type'] = 'avatarBtn'; +$config->program->projectView->dtable->fieldList['PM']['sortType'] = true; $config->program->projectView->dtable->fieldList['budget']['name'] = 'budget'; $config->program->projectView->dtable->fieldList['budget']['title'] = $lang->program->budget; diff --git a/module/program/control.php b/module/program/control.php index e1e22dbcc8..8a1ac2c81b 100644 --- a/module/program/control.php +++ b/module/program/control.php @@ -781,7 +781,7 @@ class program extends control } /** - * Product View list. + * Project View list. * copied from browse() * * @param string $status @@ -801,7 +801,7 @@ class program extends control $this->session->set('projectList', $this->app->getURI(true), 'program'); $this->session->set('createProjectLocate', $this->app->getURI(true), 'program'); - $this->app->loadClass('pager', $static = true); + $this->app->loadClass('pager', true); $pager = new pager($recTotal, $recPerPage, $pageID); $programType = $this->cookie->programType ? $this->cookie->programType : 'bylist'; @@ -873,8 +873,9 @@ class program extends control /** * Product View list. + * copied from all() function of product module. * - * @param string $status + * @param string $browseType * @param string $orderBy * @param int $recTotal * @param int $recPerPage @@ -883,60 +884,54 @@ class program extends control * @access public * @return void */ - public function productView($status = 'unclosed', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 10, $pageID = 1, $param = 0) + public function productView($browseType = 'unclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) { - if(common::hasPriv('program', 'create')) $this->lang->pageActions = html::a($this->createLink('program', 'create'), " " . $this->lang->program->create, '', "class='btn btn-primary create-program-btn'"); + /* Load module and set session. */ + $this->loadModel('product'); + $this->loadModel('user'); + $this->session->set('productView', $this->app->getURI(true), 'program'); - $this->session->set('programList', $this->app->getURI(true), 'program'); - $this->session->set('projectList', $this->app->getURI(true), 'program'); - $this->session->set('createProjectLocate', $this->app->getURI(true), 'program'); + $queryID = ($browseType == 'bySearch') ? (int)$param : 0; + + if($this->app->viewType == 'mhtml') + { + $productID = $this->product->saveState(0, $this->products); + $this->product->setMenu($productID); + } $this->app->loadClass('pager', true); $pager = new pager($recTotal, $recPerPage, $pageID); - $programType = $this->cookie->programType ? $this->cookie->programType : 'bylist'; + /* Process product structure. */ + if($this->config->systemMode == 'light' and $orderBy == 'program_asc') $orderBy = 'order_asc'; + $productStats = $this->product->getStats($orderBy, $pager, $browseType, '', 'story', '', $queryID); + $productStructure = $this->product->statisticProgram($productStats); + $productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll(); + $programLines = array(); - if(strtolower($status) == 'bysearch') + foreach($productLines as $productLine) { - $queryID = (int)$param; - $programs = $this->program->getListBySearch($orderBy, $queryID); - } - else - { - /* Get top programs and projects. */ - $topObjects = $this->program->getList($status == 'unclosed' ? 'doing,suspended,wait' : $status, $orderBy, $pager, 'top'); - if(!$topObjects) $topObjects = array(0); - $programs = $this->program->getList($status == 'closed' ? 'closed' : 'all', $orderBy, NULL, 'child', array_keys($topObjects)); - - /* Get summary. */ - $topCount = $indCount = 0; - foreach($programs as $program) - { - if($program->type == 'program' and $program->parent == 0) $topCount ++; - if($program->type == 'project' and $program->parent == 0) $indCount ++; - } - $summary = sprintf($this->lang->program->summary, $topCount, $indCount); + if(!isset($programLines[$productLine->root])) $programLines[$productLine->root] = array(); + $programLines[$productLine->root][$productLine->id] = $productLine->name; } - /* Get PM id list. */ - $accounts = array(); - $hasProject = false; - foreach($programs as $program) - { - if(!empty($program->PM) and !in_array($program->PM, $accounts)) $accounts[] = $program->PM; - if($hasProject === false and $program->type != 'program') $hasProject = true; - } - $PMList = $this->loadModel('user')->getListByAccounts($accounts, 'account'); + $actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID"); + $this->product->buildProductSearchForm($param, $actionURL); - $this->view->programs = $programs; - $this->view->status = $status; - $this->view->programType = $programType; - $this->view->hasProject = true; - $this->view->orderBy = $orderBy; - $this->view->recTotal = 322; - $this->view->summary = isset($summary) ? $summary : ''; - $this->view->pager = $pager; - $this->view->PMList = $PMList; + $this->view->title = $this->lang->product->common; + $this->view->position[] = $this->lang->product->common; + $this->view->recTotal = $pager->recTotal; + $this->view->productStats = $productStats; + $this->view->productStructure = $productStructure; + $this->view->productLines = $productLines; + $this->view->programLines = $programLines; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->userIdPairs = $this->user->getPairs('noletter|showid'); + $this->view->usersAvatar = $this->user->getAvatarPairs(''); + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->pager = $pager; + $this->view->showBatchEdit = $this->cookie->showProductBatchEdit; $this->render(); } diff --git a/module/program/ui/productview.html.php b/module/program/ui/productview.html.php index 1dec926080..2ff8b57c46 100644 --- a/module/program/ui/productview.html.php +++ b/module/program/ui/productview.html.php @@ -3,124 +3,153 @@ namespace zin; $cols = array_values($config->program->productView->dtable->fieldList); -$data = array(); +$totalStories = 0; +$hasProduct = false; +$linesCount = 0; +$data = array(); +foreach($productStructure as $programID => $program) +{ + /* TODO attach program lines */ + if(isset($programLines[$programID])) + { + foreach($programLines[$programID] as $lineID => $lineName) + { + if(!isset($program[$lineID])) + { + $program[$lineID] = array(); + $program[$lineID]['product'] = ''; + $program[$lineID]['lineName'] = $lineName; + } + } + } -$i = 100; -$item = new stdClass(); + /* ALM mode with more data. */ + if(isset($program['programName']) and $config->systemMode == 'ALM') + { + $item = new stdClass(); -$item->id = "$i"; -$item->name = 'parent'; -$item->type = 'program'; -$item->asParent = true; -$item->PM = '管理员'; -$item->feedback = 200; -$item->unclosedReqCount = 100; -$item->closedReqRate = intval(800 / $i); -$item->planCount = $i; -$item->executionCount = $i; -$item->testCaseCoverRate = intval(800 / $i); -$item->bugActivedCount = $i; -$item->fixedRate = intval(800 / $i); -$item->releaseCount = $i; -$item->releaseCountBefore= 102; + $item->programPM = ''; + if(!empty($program['programPM'])) + { + $programPM = $program['programPM']; + $userName = zget($users, $programPM); -$data[] = $item; + $userID = isset($userIdPairs[$programPM]) ? $userIdPairs[$programPM] : ''; -$i = 101; -$item = new stdClass(); + $item->programPM = $userName; + $item->PM = $userName; + $item->PMAccount = $userName; + $item->PMAvatar = $usersAvatar[$programPM]; + } -$item->id = "$i"; -$item->name = 'ProductLine'; -$item->type = 'productLine'; -$item->asParent = true; -$item->parent = "100"; -$item->PM = '管理员'; -$item->feedback = 200; -$item->unclosedReqCount = 100; -$item->closedReqRate = intval(800 / $i); -$item->planCount = $i; -$item->executionCount = $i; -$item->testCaseCoverRate = intval(800 / $i); -$item->bugActivedCount = $i; -$item->fixedRate = intval(800 / $i); -$item->releaseCount = $i; -$item->releaseCountBefore= 102; + $totalStories = $program['finishClosedStories'] + $program['unclosedStories']; -$data[] = $item; + $item->name = $program['programName']; + $item->id = 'program-' . $programID; + $item->type = 'program'; + $item->level = 1; + $item->asParent = true; + $item->feedback = rand(0, 100); + $item->programName = $program['programName']; + $item->draftStories = $program['draftStories']; + $item->activeStories = $program['activeStories']; + $item->changingStories = $program['changingStories']; + $item->reviewingStories = $program['reviewingStories']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round($program['finishClosedStories'] / $totalStories, 3) * 100); + $item->unResolvedBugs = $program['unResolvedBugs']; + $item->fixedRate = (($program['unResolvedBugs'] + $program['fixedBugs']) == 0 ? 0 : round($program['fixedBugs'] / ($program['unResolvedBugs'] + $program['fixedBugs']), 3) * 100); + $item->plans = $program['plans']; + $item->releaseCount = $program['releases']; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverRate = rand(0, 100); + /* TODO attach extend fields. */ -$i = 102; -$item = new stdClass(); + $data[] = $item; + } -$item->id = "$i"; -$item->name = 'Product'; -$item->type = 'product'; -$item->asParent = false; -$item->parent = "101"; -$item->PM = '管理员'; -$item->feedback = 200; -$item->unclosedReqCount = 100; -$item->closedReqRate = intval(800 / $i); -$item->planCount = $i; -$item->executionCount = $i; -$item->testCaseCoverRate = intval(800 / $i); -$item->bugActivedCount = $i; -$item->fixedRate = intval(800 / $i); -$item->releaseCount = $i; -$item->releaseCountBefore= 102; + foreach($program as $lineID => $line) + { + /* ALM mode with Product Line. */ + if(isset($line['lineName']) and isset($line['products']) and is_array($line['products']) and $config->systemMode == 'ALM') + { + $totalStories = (isset($line['finishClosedStories']) ? $line['finishClosedStories'] : 0) + (isset($line['unclosedStories']) ? $line['unclosedStories'] : 0); + $linesCount++; -$data[] = $item; + $item = new stdClass(); + $item->name = $line['lineName']; + $item->id = 'productLine-' . $lineID; + $item->type = 'productLine'; + $item->asParent = true; + $item->feedback = rand(0, 100); + $item->parent = 'program-' . $programID; + $item->programName = $line['lineName']; + $item->draftStories = $line['draftStories']; + $item->activeStories = $line['activeStories']; + $item->changingStories = $line['changingStories']; + $item->reviewingStories = $line['reviewingStories']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round((isset($line['finishClosedStories']) ? $line['finishClosedStories'] : 0) / $totalStories, 3) * 100); + $item->unResolvedBugs = $line['unResolvedBugs']; + $item->fixedRate = ((isset($line['fixedBugs']) and ($line['unResolvedBugs'] + $line['fixedBugs'] != 0)) ? round($line['fixedBugs'] / ($line['unResolvedBugs'] + $line['fixedBugs']), 3) * 100 : 0); + $item->plans = $line['plans']; + $item->releaseCount = isset($line['releases']) ? $line['releases'] : 0; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverRate = rand(0, 100); + /* TODO attach extend fields. */ -$i = 103; -$item = new stdClass(); + $data[] = $item; + } -$item->id = "$i"; -$item->name = 'IndProduct'; -$item->type = 'product'; -$item->asParent = false; -$item->parent = "0"; -$item->PM = '管理员'; -$item->feedback = 200; -$item->unclosedReqCount = 100; -$item->closedReqRate = intval(800 / $i); -$item->planCount = $i; -$item->executionCount = $i; -$item->testCaseCoverRate = intval(800 / $i); -$item->bugActivedCount = $i; -$item->fixedRate = intval(800 / $i); -$item->releaseCount = $i; -$item->releaseCountBefore= 102; + /* Products of Product Line. */ + if(isset($line['products']) and is_array($line['products'])) + { + foreach($line['products'] as $productID => $product) + { + $hasProduct = true; -$data[] = $item; + $item = new stdClass(); -$i = 104; -$item = new stdClass(); + if(!empty($product->PO)) + { + $item->PM = zget($users, $product->PO); + $item->PMAvatar = $usersAvatar[$product->PO]; + $item->PMAccount = $product->PO; + } + $totalStories = $product->stories['finishClosed'] + $product->stories['unclosed']; -$item->id = "$i"; -$item->name = 'SubProduct'; -$item->type = 'product'; -$item->asParent = false; -$item->parent = "100"; -$item->PM = '管理员'; -$item->feedback = 200; -$item->unclosedReqCount = 100; -$item->closedReqRate = intval(800 / $i); -$item->planCount = $i; -$item->executionCount = $i; -$item->testCaseCoverRate = intval(800 / $i); -$item->bugActivedCount = $i; -$item->fixedRate = intval(800 / $i); -$item->releaseCount = $i; -$item->releaseCountBefore= 102; + $item->name = $product->name; /* TODO replace with */ + $item->id = $product->id; + $item->type = 'product'; + $item->programName = $product->name; /* TODO replace with */ + $item->feedback = rand(0, 100); + $item->draftStories = $product->stories['draft']; + $item->activeStories = $product->stories['active']; + $item->changingStories = $product->stories['changing']; + $item->reviewingStories = $product->stories['reviewing']; + $item->closedReqRate = ($totalStories == 0 ? 0 : round($product->stories['finishClosed'] / $totalStories, 3) * 100); + $item->unResolvedBugs = $product->unResolved; + $item->fixedRate = (($product->unResolved + $product->fixedBugs) == 0 ? 0 : round($product->fixedBugs / ($product->unResolved + $product->fixedBugs), 3) * 100); + $item->plans = $product->plans; + $item->parent = $product->line ? "productLine-$lineID" : ($product->program ? "program-$product->program" : ''); + $item->releaseCount = $product->releases; + $item->releaseCountOld = rand(0, 10); + $item->testCaseCoverRate = rand(0, 100); + /* TODO attach extend fields. */ -$data[] = $item; + $data[] = $item; + } + } + } +} -set::title('产品视角'); +$summary = sprintf($lang->product->lineSummary, $linesCount, count($productStats)); + +set::title($lang->program->productView); featureBar ( - set::current($status), + set::current($browseType), set::linkParams("status={key}&orderBy=$orderBy"), - (hasPriv('project', 'batchEdit') && $programType != 'bygrid' && $hasProject === true) ? item + (hasPriv('product', 'batchEdit') && $hasProduct === true) ? item ( set::type('checkbox'), set::text($lang->project->edit), @@ -158,29 +187,23 @@ toolbar ))), ); -js -( - 'window.footerGenerator = function()', - '{', - 'const count = this.layout.allRows.filter((x) => x.data.type === "product").length;', - "const statistic = '{$summary}'.replace('%s', ' ' + count + ' ');", - 'return [{children: statistic, className: "text-dark"}, "flex", "pager"];', - '}' -); - -/* Render release count. */ js ( << 0) result[0] = {html: row.data.releaseCount + ' +' + changed + ''}; - if(changed < 0) result[0] = {html: row.data.releaseCount + ' ' + changed + ''}; + if(changed === 0) result[0] = 0; + if(changed > 0) result[0] = {html: row.data.releaseCount + ' +' + changed + ''}; + if(changed < 0) result[0] = {html: row.data.releaseCount + ' ' + changed + ''}; return result; } diff --git a/module/program/ui/projectview.html.php b/module/program/ui/projectview.html.php index 61c191e130..22bdca5d08 100644 --- a/module/program/ui/projectview.html.php +++ b/module/program/ui/projectview.html.php @@ -19,8 +19,8 @@ foreach($programs as $program) if(!empty($program->PM)) { $userName = zget($users, $program->PM); - $program->PMNameAvatar = $usersAvatar[$program->PM]; - $program->PMName = $userName; + $program->PMAvatar = $usersAvatar[$program->PM]; + $program->PM = $userName; } /* Calculate budget.*/ @@ -28,10 +28,7 @@ foreach($programs as $program) $program->budget = $program->budget != 0 ? zget($lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $lang->project->future; /* Progress. */ - if(isset($progressList[$program->id])) - { - $program->progress = round($progressList[$program->id]); - } + if(isset($progressList[$program->id])) $program->progress = round($progressList[$program->id]); $program->invested = 0; @@ -42,18 +39,11 @@ foreach($programs as $program) { if(is_object($action)) $action->name = $program->type . '_' . $action->name; else $action = $program->type . '_' . $action; - if(isset($action->items)) - { - foreach($action->items as $idx => $item) - { - $action->items[$idx]->name = $program->type . '_' . $item->name; - } - } + + if(isset($action->items)) foreach($action->items as $idx => $item) $action->items[$idx]->name = $program->type . '_' . $item->name; $program->actions[] = $action; - } - $data[] = $program; }