productview.html.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <?php
  2. /**
  3. * The UI file of program module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author chen.tao <chentao@easycorp.ltd>
  8. * @package program
  9. * @link https://www.zentao.net
  10. */
  11. namespace zin;
  12. $hasProduct = false;
  13. /* Closure creating program buttons. */
  14. $fnGenerateCreateProgramBtns = function() use ($lang, $browseType)
  15. {
  16. $items = array();
  17. hasPriv('program', 'create') && $items[] = array('text' => $lang->program->create, 'icon' => 'plus', 'url' => createLink('program', 'create'));
  18. hasPriv('product', 'create') && $items[] = array('text' => $lang->program->createProduct, 'icon' => 'plus', 'url' => createLink('product', 'create'), 'data-app' => 'product', 'class' => 'product-create-btn');
  19. hasPriv('product', 'manageLine') && $items[] = array('text' => $lang->program->manageLine, 'icon' => 'edit', 'data-url' => createLink('product', 'manageLine', $browseType), 'data-toggle' => 'modal', 'data-id' => 'manageLineModal');
  20. if(empty($items)) return null;
  21. return count($items) > 1 ? btnGroup
  22. (
  23. btn
  24. (
  25. setClass('btn primary'),
  26. set(reset($items))
  27. ),
  28. dropdown
  29. (
  30. btn(setClass('btn primary dropdown-toggle'), setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))),
  31. set::placement('bottom-end'),
  32. set::items($items)
  33. )
  34. ) : btn
  35. (
  36. setClass('btn primary'),
  37. set(reset($items))
  38. );
  39. };
  40. /* Closure for generating program row data. */
  41. $fnGenerateProgramRowData = function($programID, $program) use ($config, $users)
  42. {
  43. if(!isset($program['programName']) || strpos(',ALM,PLM,', ",{$config->systemMode},") === false) return null;
  44. /* ALM mode with more data. */
  45. $totalStories = $program['totalStories'];
  46. $pmName = '';
  47. if(!empty($program['programPM']))
  48. {
  49. $programPM = $program['programPM'];
  50. $userName = zget($users, $programPM);
  51. $pmName = $userName;
  52. }
  53. $item = new stdClass();
  54. $item->type = 'program';
  55. $item->id = 'program-' . $programID;
  56. $item->parent = 0;
  57. $item->isParent = true;
  58. $item->name = $program['programName'];
  59. $item->PM = $pmName;
  60. $item->createdDate = '';
  61. $item->createdBy = '';
  62. $item->totalUnclosedStories = $totalStories - $program['closedStories'];
  63. $item->totalStories = $totalStories;
  64. $item->closedStoryRate = empty($item->totalUnclosedStories + $program['finishedStories']) ? 0 : round($program['finishedStories'] / ($item->totalUnclosedStories + $program['finishedStories']), 3) * 100;
  65. $item->totalPlans = $program['plans'];
  66. $item->totalProjects = 0;
  67. $item->totalExecutions = 0;
  68. $item->testCaseCoverage = $program['coverage'] ?? 0;
  69. $item->totalActivatedBugs = 0;
  70. $item->totalBugs = 0;
  71. $item->fixedRate = empty($program['unresolvedBugs'] + $program['fixedBugs']) ? 0 : round($program['fixedBugs'] / ($program['unresolvedBugs'] + $program['fixedBugs']), 3) * 100;
  72. $item->totalReleases = $program['releases'];
  73. $item->latestReleaseDate = '';
  74. $item->latestRelease = '';
  75. return $item;
  76. };
  77. /* Closure for generating product line row data. */
  78. $fnGenerateLineRowData = function($programID, $lineID, $line) use ($config, &$linesCount)
  79. {
  80. if(!isset($line['lineName']) || !isset($line['products']) || !is_array($line['products']) || ($config->systemMode != 'ALM' && $config->systemMode != 'PLM')) return null;
  81. /* ALM mode with Product Line. */
  82. $linesCount++;
  83. $item = new stdClass();
  84. $item->type = 'productLine';
  85. $item->id = 'productLine-' . $lineID;
  86. $item->parent = 'program-' . $programID;
  87. $item->isParent = true;
  88. $item->name = $line['lineName'];
  89. $item->PM = '';
  90. $item->createdDate = '';
  91. $item->createdBy = '';
  92. $item->totalUnclosedStories = zget($line, 'totalStories', 0) - zget($line, 'closedStories', 0);
  93. $item->finishClosedStories = zget($line, 'finishClosedStories', 0);
  94. $item->totalStories = zget($line, 'totalStories', 0);
  95. $item->closedStoryRate = empty($item->totalUnclosedStories + $item->finishClosedStories) ? 0 : round($item->finishClosedStories / ($item->totalUnclosedStories + $item->finishClosedStories), 3) * 100;
  96. $item->totalPlans = zget($line, 'plans', 0);
  97. $item->totalProjects = 0;
  98. $item->totalExecutions = 0;
  99. $item->testCaseCoverage = zget($line, 'coverage', 0);
  100. $item->totalActivatedBugs = zget($line, 'unresolvedBugs', 0);
  101. $item->totalFixedBugs = zget($line, 'fixedBugs', 0);
  102. $item->totalBugs = 0;
  103. $item->fixedRate = empty($item->totalFixedBugs + $item->totalActivatedBugs) ? 0 : round($item->totalFixedBugs / ($item->totalActivatedBugs + $item->totalFixedBugs), 3) * 100;
  104. $item->totalReleases = zget($line, 'releases', 0);
  105. $item->latestReleaseDate = '';
  106. $item->latestRelease = '';
  107. return $item;
  108. };
  109. /* Closure for generating product row data. */
  110. $fnGenerateProductRowData = function($lineID, $product) use ($users)
  111. {
  112. $item = new stdClass();
  113. $item->type = 'product';
  114. $item->id = $product->id;
  115. $item->parent = $product->line ? "productLine-$lineID" : ($product->program ? "program-$product->program" : 0);
  116. $item->name = $product->name;
  117. $item->PO = !empty($product->PO) ? zget($users, $product->PO) : '';
  118. $item->createdDate = $product->createdDate;
  119. $item->createdBy = $product->createdBy;
  120. $item->totalUnclosedStories = $product->totalStories - $product->closedStories;
  121. $item->totalStories = $product->totalStories;
  122. $item->closedStoryRate = empty($item->totalUnclosedStories + $product->finishedStories) ? 0 : round($product->finishedStories / ($item->totalUnclosedStories + $product->finishedStories), 3) * 100;
  123. $item->totalPlans = $product->plans;
  124. $item->totalProjects = $product->projects;
  125. $item->totalExecutions = $product->executions;
  126. $item->testCaseCoverage = $product->coverage;
  127. $item->totalActivatedBugs = $product->unresolvedBugs;
  128. $item->totalBugs = $product->totalBugs;
  129. $item->fixedRate = empty($item->totalActivatedBugs + $product->fixedBugs) ? 0 : round($product->fixedBugs / ($item->totalActivatedBugs + $product->fixedBugs), 3) * 100;
  130. $item->totalReleases = $product->releases;
  131. $item->latestReleaseDate = $product->latestReleaseDate;
  132. $item->latestRelease = $product->latestRelease;
  133. return $item;
  134. };
  135. $linesCount = 0;
  136. $data = array();
  137. foreach($productStructure as $programID => $program)
  138. {
  139. if(isset($programLines[$programID]))
  140. {
  141. foreach($programLines[$programID] as $lineID => $lineName)
  142. {
  143. if(isset($program[$lineID])) continue;
  144. $program[$lineID] = array();
  145. $program[$lineID]['products'] = array();
  146. $program[$lineID]['lineName'] = $lineName;
  147. }
  148. }
  149. $totalExecutions = 0;
  150. $totalBugs = 0;
  151. $totalActiveBugs = 0;
  152. $totalProjects = 0;
  153. foreach($program as $lineID => $line)
  154. {
  155. $totalProductExecutions = 0;
  156. $totalProductBugs = 0;
  157. $totalProductActiveBugs = 0;
  158. $totalProductProjects = 0;
  159. if(isset($line['products']) && is_array($line['products']))
  160. {
  161. /* Generate product row data. */
  162. foreach($line['products'] as $productID => $product)
  163. {
  164. $productRow = $fnGenerateProductRowData($lineID, $product);
  165. $totalProductExecutions += $productRow->totalExecutions;
  166. $totalProductBugs += $productRow->totalBugs;
  167. $totalProductActiveBugs += $productRow->totalActivatedBugs;
  168. $totalProductProjects += $productRow->totalProjects;
  169. $data[] = $productRow;
  170. /* Set flag variable. */
  171. $hasProduct = true;
  172. }
  173. }
  174. /* Generate product line row data. */
  175. $lineRow = $fnGenerateLineRowData($programID, $lineID, $line);
  176. if(!empty($lineRow))
  177. {
  178. $lineRow->totalExecutions = $totalProductExecutions;
  179. $lineRow->totalBugs = $totalProductBugs;
  180. $lineRow->totalActivatedBugs = $totalProductActiveBugs;
  181. $lineRow->totalProjects = $totalProductProjects;
  182. $data[] = $lineRow;
  183. }
  184. $totalExecutions += $totalProductExecutions;
  185. $totalBugs += $totalProductBugs;
  186. $totalActiveBugs += $totalProductActiveBugs;
  187. $totalProjects += $totalProductProjects;
  188. }
  189. /* Generate program row data. */
  190. $programRow = $fnGenerateProgramRowData($programID, $program);
  191. if(!empty($programRow))
  192. {
  193. $programRow->totalExecutions = $totalExecutions;
  194. $programRow->totalBugs = $totalBugs;
  195. $programRow->totalActivatedBugs = $totalActiveBugs;
  196. $programRow->totalProjects = $totalProjects;
  197. $data[] = $programRow;
  198. }
  199. }
  200. $canBatchEdit = (common::hasPriv('product', 'batchEdit') && $hasProduct === true);
  201. /* Generate cols for the data table. */
  202. $fnGenerateCols = function() use ($canBatchEdit)
  203. {
  204. $cols = $this->loadModel('datatable') ->getSetting('program');
  205. foreach($cols as $colName => &$setting)
  206. {
  207. if($colName == 'name')
  208. {
  209. $setting['checkbox'] = $canBatchEdit;
  210. break;
  211. }
  212. }
  213. return $cols;
  214. };
  215. $pageSummary = sprintf($lang->product->lineSummary, $linesCount, count($productStats));
  216. jsVar('checkedSummary', $lang->program->checkedProducts);
  217. /* ZIN: layout. */
  218. featureBar
  219. (
  220. set::current($browseType),
  221. set::linkParams("status={key}&orderBy=$orderBy&param={$param}"),
  222. li(searchToggle(set::open($browseType == 'bySearch'), set::module('program')))
  223. );
  224. toolbar($fnGenerateCreateProgramBtns());
  225. $canSort = common::hasPriv('program', 'updateOrder') && strpos(',program_asc,order_asc,', ",$orderBy,") !== false;
  226. dtable
  227. (
  228. setID('productviews'),
  229. set::cols($fnGenerateCols()),
  230. set::data($data),
  231. set::userMap($users),
  232. set::customCols(true),
  233. set::checkable($canBatchEdit),
  234. set::nested(true),
  235. set::className('shadow rounded'),
  236. set::footPager(usePager()),
  237. set::canRowCheckable(jsRaw("function(rowID){return this.getRowInfo(rowID).data.type == 'product';}")),
  238. set::onRenderCell(jsRaw('window.renderCellProductView')),
  239. set::orderBy($orderBy),
  240. set::plugins(array('sortable')),
  241. set::sortable($canSort),
  242. set::onSortEnd($canSort ? jsRaw('window.onSortEnd') : null),
  243. set::canSortTo($canSort ? jsRaw('window.canSortTo') : null),
  244. set::sortLink(createLink('program', 'productview', "browseType={$browseType}&orderBy={name}_{sortType}&param={$param}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")),
  245. set::footToolbar(array
  246. (
  247. 'type' => 'btn-group',
  248. 'items' => array(
  249. $canBatchEdit ? array
  250. (
  251. 'text' => $lang->edit,
  252. 'className' => 'secondary batch-btn',
  253. 'data-page' => 'batch',
  254. 'data-formaction' => $this->createLink('product', 'batchEdit')
  255. ) : null
  256. )
  257. )),
  258. set::checkInfo(jsRaw("function(checkedIDList){ return window.footerSummary(checkedIDList, '{$pageSummary}');}")),
  259. set::emptyTip($lang->program->noProgram),
  260. set::createTip($lang->program->create),
  261. set::createLink(hasPriv('program', 'create') ? createLink('program', 'create') : null)
  262. );
  263. render();