view.html.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. /**
  3. * The view view file of roadmap module of ZenTaoPMS.
  4. * @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  5. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  6. * @author Qiyu Xie <xieqiyu@easycorp.ltd>
  7. * @package roadmap
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. jsVar('gradeGroup', $gradeGroup);
  12. jsVar('roadmapID', $roadmap->id);
  13. jsVar('orderBy', $orderBy);
  14. jsVar('storyPageID', $storyPager->pageID);
  15. jsVar('storyRecPerPage', $storyPager->recPerPage);
  16. jsVar('storyRecTotal', $storyPager->recTotal);
  17. jsVar('summary', $summary);
  18. jsVar('checkedSummary', $lang->roadmap->checkedSummary);
  19. jsVar('link', $link);
  20. /* 初始化需求列表列。*/
  21. $storyCols = array();
  22. foreach($config->roadmap->defaultFields['story'] as $field)
  23. {
  24. if($field == 'branch' && $product->type == 'normal') continue;
  25. $storyCols[$field] = zget($config->story->dtable->fieldList, $field, array());
  26. if($field == 'id' && common::hasPriv('execution', 'storySort'))
  27. {
  28. $storyCols['sort']['title'] = $lang->roadmap->updateOrder;
  29. $storyCols['sort']['fixed'] = 'left';
  30. $storyCols['sort']['align'] = 'center';
  31. $storyCols['sort']['group'] = 1;
  32. $storyCols['sort']['width'] = 60;
  33. }
  34. }
  35. $storyCols['title']['link'] = $this->createLink('story', 'storyView', "storyID={id}");
  36. $storyCols['title']['title'] = $lang->roadmap->storyName;
  37. $storyCols['assignedTo']['type'] = 'user';
  38. $storyCols['module']['type'] = 'text';
  39. $storyCols['module']['map'] = $modulePairs;
  40. $storyCols['module']['sortType'] = true;
  41. $storyCols['actions']['list'] = $config->roadmap->actionList;
  42. $storyCols['actions']['menu'] = array('unlinkUR');
  43. $storyCols['actions']['minWidth'] = 60;
  44. if(isset($storyCols['branch'])) $storyCols['branch']['map'] = $branchOption;
  45. if($config->vision != 'or') unset($storyCols['actions']);
  46. /* 初始化需求数据。*/
  47. $roadmapStories = initTableData($roadmapStories, $storyCols, $this->roadmap);
  48. foreach($roadmapStories as $story)
  49. {
  50. $story->estimate = $story->estimate . $config->hourUnit;
  51. if($config->vision == 'or')
  52. {
  53. foreach($story->actions as $key => $action)
  54. {
  55. if($action['name'] == 'unlinkUR' && !in_array($story->stage, array('wait', 'inroadmap', 'incharter'))) $story->actions[$key]['disabled'] = true;
  56. }
  57. }
  58. }
  59. /* 需求列表批量操作。*/
  60. $canBatchClose = common::hasPriv('requirement', 'batchClose');
  61. $canBatchEdit = common::hasPriv('requirement', 'batchEdit');
  62. $canBatchChangeBranch = common::hasPriv('requirement', 'batchChangeBranch');
  63. $canBatchChangeModule = common::hasPriv('requirement', 'batchChangeModule');
  64. $canBatchChangeRoadmap = common::hasPriv('requirement', 'batchChangeRoadmap');
  65. $canBatchAssignTo = common::hasPriv('requirement', 'batchAssignTo');
  66. $canBatchAction = $config->vision == 'or' && $canBeChanged && ($canBatchClose || $canBatchEdit || $canBatchChangeBranch || $canBatchChangeModule || $canBatchChangeRoadmap || $canBatchAssignTo);
  67. $branchItems = $moduleItems = $assignItems = $roadmapItems = array();
  68. foreach($branchTagOption as $branchID => $branchName) $branchItems[] = array('text' => $branchName, 'class' => 'batch-btn', 'data-type' => 'story', 'data-url' => $this->createLink('requirement', 'batchChangeBranch', "branchID=$branchID"));
  69. foreach($modules as $moduleID => $moduleName) $moduleItems[] = array('text' => $moduleName, 'class' => 'batch-btn', 'data-type' => 'story', 'data-url' => $this->createLink('requirement', 'batchChangeModule', "moduleID=$moduleID"));
  70. foreach($users as $account => $realname)
  71. {
  72. if(empty($account) || $account == 'closed') continue;
  73. $assignItems[] = array('text' => $realname, 'class' => 'batch-btn', 'data-type' => 'story', 'data-url' => $this->createLink('requirement', 'batchAssignTo', "productID=$roadmap->product"), 'data-account' => $account);
  74. }
  75. foreach($roadmaps as $roadmapID => $roadmapName)
  76. {
  77. if($roadmapID == $roadmap->id) continue;
  78. $roadmapItems[] = array('text' => $roadmapName, 'class' => 'batch-btn', 'disabled' => !in_array($roadmap->status, array('wait', 'reject')), 'data-type' => 'story', 'data-url' => $this->createLink('requirement', 'batchChangeRoadmap', "roadmapID=$roadmapID"), 'data-disabled' => !in_array($roadmap->status, array('wait', 'reject')));
  79. }
  80. $navStoryActionItems = array();
  81. if($canBatchClose) $navStoryActionItems[] = array('text' => $lang->close, 'class' => 'batch-btn', 'data-type' => 'story', 'data-page' => 'batch', 'data-url' => helper::createLink('requirement', 'batchClose', "productID={$roadmap->product}&executionID=0&storyType=requirement"));
  82. if($canBatchEdit) $navStoryActionItems[] = array('text' => $lang->edit, 'class' => 'batch-btn', 'data-type' => 'story', 'data-page' => 'batch', 'data-url' => helper::createLink('requirement', 'batchEdit', "productID=$roadmap->product&projectID=$projectID&branch=$branch&storyType=requirement"));
  83. if($canBatchChangeRoadmap) $navStoryActionItems[] = array('class' => 'not-hide-menu', 'disabled' => !in_array($roadmap->status, array('wait', 'reject')), 'text' => $lang->roadmap->common, 'items' => $roadmapItems);
  84. if($canBatchChangeBranch && $product->type != 'normal') $navStoryActionItems[] = array('class' => 'not-hide-menu', 'text' => $lang->product->branchName[$product->type], 'items' => $branchItems);
  85. if($canBatchChangeModule) $navStoryActionItems[] = array('class' => 'not-hide-menu', 'text' => $lang->story->moduleAB, 'items' => $moduleItems);
  86. if($canBatchAssignTo) $navStoryActionItems[] = array('class' => 'not-hide-menu', 'text' => $lang->story->assignedTo, 'items' => $assignItems);
  87. $storyFootToolbar = array();
  88. if($canBatchAction)
  89. {
  90. $storyFootToolbar = array('items' => array
  91. (
  92. array('type' => 'btn-group', 'items' => array
  93. (
  94. array('text' => $lang->roadmap->unlinkURAB, 'className' => 'batch-btn size-sm', 'btnType' => 'secondary', 'data-type' => 'story', 'data-url' => helper::createLink('roadmap', 'batchUnlinkUR', "roadmapID=$roadmap->id")),
  95. array('caret' => 'up', 'className' => 'size-sm', 'btnType' => 'secondary', 'data-toggle' => 'dropdown', 'data-placement' => 'top-start', 'items' => $navStoryActionItems)
  96. ))
  97. ));
  98. }
  99. $actions = $this->loadModel('common')->buildOperateMenu($roadmap);
  100. foreach($actions as $actionType => $typeActions)
  101. {
  102. foreach($typeActions as $key => $action)
  103. {
  104. $actions[$actionType][$key]['url'] = str_replace(array('{roadmapID}'), array((string)$roadmap->id), $action['url']);
  105. $actions[$actionType][$key]['className'] = isset($action['className']) ? $action['className'] . ' ghost' : 'ghost';
  106. $actions[$actionType][$key]['iconClass'] = isset($action['iconClass']) ? $action['iconClass'] . ' text-primary' : 'text-primary';
  107. }
  108. }
  109. detailHeader
  110. (
  111. to::prefix
  112. (
  113. backBtn(set::icon('back'), set::type('secondary'), set::url(inlink('browse', "productID=$roadmap->product")), $lang->goback),
  114. entityLabel(set(array('entityID' => $roadmap->id, 'level' => 1, 'text' => $roadmap->name))),
  115. span(setClass('label circle primary'), ($roadmap->begin == $config->roadmap->future || $roadmap->end == $config->roadmap->future) ? $lang->roadmap->future : $roadmap->begin . '~' . $roadmap->end),
  116. $roadmap->deleted ? span(setClass('label danger'), $lang->product->deleted) : null
  117. ),
  118. !$roadmap->deleted && $actions && $config->vision == 'or' ? to::suffix
  119. (
  120. btnGroup(set::items($actions['mainActions'])),
  121. !empty($actions['mainActions']) && !empty($actions['suffixActions']) ? div(setClass('divider mx-2')): null,
  122. btnGroup(set::items($actions['suffixActions']))
  123. ) : null
  124. );
  125. detailBody
  126. (
  127. set::hasExtraMain(false),
  128. sectionList
  129. (
  130. tabs
  131. (
  132. setClass('w-full relative'),
  133. tabPane
  134. (
  135. to::prefix(icon($lang->icons['story'], setClass('text-secondary'))),
  136. set::key('stories'),
  137. set::title($lang->roadmap->linkedURS),
  138. set::active($type == 'story'),
  139. toolbar
  140. (
  141. setClass('tab-actions absolute right-0 gap-2'),
  142. setStyle('top', '-8px'),
  143. common::hasPriv('roadmap', 'linkUR') && $config->vision == 'or' ? btn
  144. (
  145. set::type('primary'),
  146. set::icon('link'),
  147. set::text($lang->roadmap->linkUR),
  148. bind::click("window.showLink()")
  149. ) : null
  150. ),
  151. dtable
  152. (
  153. setID('storyDTable'),
  154. set::plugins(array('sortable')),
  155. set::sortHandler('.move-roadmap'),
  156. set::onSortEnd(jsRaw('window.onSortEnd')),
  157. set::style(array('min-width' => '100%')),
  158. set::userMap($users),
  159. set::bordered(true),
  160. set::cols($storyCols),
  161. set::data(array_values($roadmapStories)),
  162. set::noNestedCheck(),
  163. set::checkable($canBatchAction),
  164. set::onRenderCell(jsRaw('window.renderStoryCell')),
  165. set::footToolbar($storyFootToolbar),
  166. set::sortLink(createLink('roadmap', 'view', "roadmapID={$roadmap->id}&type=story&orderBy={name}_{sortType}&link=false&param={$param}&recTotal={$storyPager->recTotal}&recPerPage={$storyPager->recPerPage}&page={$storyPager->pageID}")),
  167. set::orderBy($orderBy),
  168. set::extraHeight('+144'),
  169. set::checkInfo(jsRaw("function(checkedIDList){return window.setStatistics(this, checkedIDList, '{$summary}');}")),
  170. set::footPager
  171. (
  172. usePager('storyPager', '', array(
  173. 'recPerPage' => $storyPager->recPerPage,
  174. 'recTotal' => $storyPager->recTotal,
  175. 'linkCreator' => helper::createLink('roadmap', 'view', "roadmapID={$roadmap->id}&type=story&orderBy={$orderBy}&link=false&param={$param}&recTotal={$storyPager->recTotal}&recPerPage={recPerPage}&pageID={page}")
  176. ))
  177. )
  178. )
  179. ),
  180. tabPane
  181. (
  182. to::prefix(icon('flag', setClass('text-special'))),
  183. set::key('roadmapInfo'),
  184. set::title($lang->roadmap->view),
  185. set::active($type == 'roadmapInfo'),
  186. tableData
  187. (
  188. set::title($lang->roadmap->basicInfo),
  189. item(set::name($lang->roadmap->name), $roadmap->name),
  190. $product->type != 'normal' ? item(set::name($lang->product->branch), $branchOption[$roadmap->branch]) : null,
  191. item(set::name($lang->roadmap->begin), $roadmap->begin == $config->roadmap->future ? $lang->roadmap->future : $roadmap->begin),
  192. item(set::name($lang->roadmap->end), $roadmap->end == $config->roadmap->future ? $lang->roadmap->future : $roadmap->end),
  193. item(set::name($lang->roadmap->status), $lang->roadmap->statusList[$roadmap->status]),
  194. item(set::name($lang->roadmap->desc), empty($roadmap->desc) ? $lang->noData : html(($roadmap->desc)))
  195. ),
  196. h::hr(setClass('mt-4')),
  197. history(set::objectID($roadmap->id), set::commentBtn(false))
  198. )
  199. )
  200. )
  201. );