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;
}