view.html.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <?php
  2. /**
  3. * The activate view file of task module of ZenTaoPMS.
  4. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Shujie Tian<tianshujie@easycorp.ltd>
  7. * @package task
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. include($this->app->getModuleRoot() . 'ai/ui/promptmenu.html.php');
  12. $releaseModule = $app->rawModule == 'projectrelease' ? 'projectrelease' : 'release';
  13. $isInModal = isInModal();
  14. jsVar('initLink', $link);
  15. jsVar('type', $type);
  16. jsVar('loadFileUrl', createLink($releaseModule, 'view', "releaseID={$release->id}&type=releaseInfo"));
  17. $canBeChanged = common::canBeChanged($releaseModule, $release);
  18. $actions = $this->loadModel('common')->buildOperateMenu($release, $releaseModule);
  19. foreach($actions as $actionType => $typeActions)
  20. {
  21. foreach($typeActions as $key => $action)
  22. {
  23. $actions[$actionType][$key]['className'] = isset($action['className']) ? $action['className'] . ' ghost' : 'ghost';
  24. $actions[$actionType][$key]['iconClass'] = isset($action['iconClass']) ? $action['iconClass'] . ' text-primary' : 'text-primary';
  25. $actions[$actionType][$key]['url'] = str_replace('{id}', (string)$release->id, $action['url']);
  26. if($actionType == 'suffixActions')
  27. {
  28. if($action['icon'] == 'edit')
  29. {
  30. $actions['suffixActions'][$key]['text'] = $lang->edit;
  31. $actions['suffixActions'][$key]['data-app'] = $app->tab;
  32. }
  33. if($action['icon'] == 'trash') $actions['suffixActions'][$key]['text'] = $lang->delete;
  34. }
  35. }
  36. }
  37. detailHeader
  38. (
  39. to::prefix
  40. (
  41. $isInModal ? null : backBtn
  42. (
  43. set::icon('back'),
  44. set::type('secondary'),
  45. set::url($releaseModule, 'browse', $releaseModule == 'projectrelease' ? "projectID={$this->session->project}" : "productID={$release->product}"),
  46. $lang->goback
  47. ),
  48. entityLabel(set(array('entityID' => $release->id, 'level' => 2, 'text' => zget($appList, $release->system) . $release->name))),
  49. $release->deleted ? span(setClass('label danger'), $lang->release->deleted) : null
  50. ),
  51. !$isInModal && (!empty($actions['mainActions']) || !empty($actions['suffixActions'])) ? to::suffix
  52. (
  53. btnGroup(set::items($actions['mainActions'])),
  54. !empty($actions['mainActions']) && !empty($actions['suffixActions']) ? div(setClass('divider')): null,
  55. btnGroup(set::items($actions['suffixActions']))
  56. ) : null
  57. );
  58. jsVar('releaseID', $release->id);
  59. jsVar('showGrade', $showGrade);
  60. jsVar('grades', $grades);
  61. if(!empty($release->releases) || $release->deleted || ($app->tab == 'project' && !common::canModify('project', $project)))
  62. {
  63. $config->release->dtable->story->fieldList['id']['type'] = 'ID';
  64. $config->release->dtable->bug->fieldList['id']['type'] = 'ID';
  65. $config->release->dtable->leftBug->fieldList['id']['type'] = 'ID';
  66. unset($config->release->dtable->story->fieldList['actions']);
  67. unset($config->release->dtable->bug->fieldList['actions']);
  68. unset($config->release->dtable->leftBug->fieldList['actions']);
  69. }
  70. if(!common::hasPriv($releaseModule, 'unlinkStory')) unset($config->release->dtable->story->fieldList['actions']['list']['unlinkStory']);
  71. if(!common::hasPriv($releaseModule, 'unlinkBug')) unset($config->release->dtable->bug->fieldList['actions']['list']['unlinkBug']);
  72. /* Table data and setting for finished stories tab. */
  73. jsVar('storyCases', $storyCases);
  74. jsVar('confirmunlinkstory', $lang->release->confirmUnlinkStory);
  75. jsVar('checkedSummary', $lang->product->checkedSRSummary);
  76. jsVar('unlinkstoryurl', helper::createLink($releaseModule, 'unlinkStory', "releaseID={$release->id}&storyID=%s"));
  77. $storyTableData = initTableData($stories, $config->release->dtable->story->fieldList, $this->release);
  78. $canBatchUnlinkStory = !$isInModal && $canBeChanged && common::hasPriv($releaseModule, 'batchUnlinkStory');
  79. $canBatchCloseStory = !$isInModal && $canBeChanged && common::hasPriv('story', 'batchClose');
  80. $storyFootToolbar = array();
  81. if($canBatchUnlinkStory) $storyFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'story', 'data-url' => createLink($releaseModule, 'batchUnlinkStory', "release={$release->id}"));
  82. if($canBatchCloseStory) $storyFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn load-btn', 'text' => $lang->story->batchClose, 'data-type' => 'story', 'data-url' => createLink('story', 'batchClose', "productID={$release->product}"));
  83. /* Table data and setting for resolved bugs tab. */
  84. jsVar('confirmunlinkbug', $lang->release->confirmUnlinkBug);
  85. jsVar('unlinkbugurl', helper::createLink($releaseModule, 'unlinkBug', "releaseID={$release->id}&bugID=%s"));
  86. $config->release->dtable->bug->fieldList['resolvedBuild']['map'] = $builds;
  87. $bugTableData = initTableData($bugs, $config->release->dtable->bug->fieldList, $this->release);
  88. $bugTableData = array_map(function($bug)
  89. {
  90. if(helper::isZeroDate($bug->resolvedDate)) $bug->resolvedDate = '';
  91. return $bug;
  92. }, $bugTableData);
  93. $canBatchUnlinkBug = !$isInModal && $canBeChanged && common::hasPriv($releaseModule, 'batchUnlinkBug');
  94. $canBatchCloseBug = !$isInModal && $canBeChanged && common::hasPriv('bug', 'batchClose');
  95. $bugFootToolbar = array();
  96. if($canBatchUnlinkBug) $bugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'bug', 'data-url' => createLink($releaseModule, 'batchUnlinkBug', "release={$release->id}"));
  97. if($canBatchCloseBug) $bugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn bug-batch-close', 'text' => $lang->bug->batchClose, 'data-type' => 'bug', 'data-url' => createLink('bug', 'batchClose', "release={$release->id}&viewType=release"));
  98. /* Table data and setting for left bugs tab. */
  99. jsVar('confirmunlinkleftbug', $lang->release->confirmUnlinkBug);
  100. jsVar('unlinkleftbugurl', helper::createLink($releaseModule, 'unlinkBug', "releaseID={$release->id}&bugID=%s&type=leftBug"));
  101. $releaseBuild = array();
  102. foreach($release->builds as $build) $releaseBuild[] = $build->name;
  103. $leftBugTableData = initTableData($leftBugs, $config->release->dtable->leftBug->fieldList, $this->release);
  104. $leftBugTableData = array_map(function($bug)
  105. {
  106. if(helper::isZeroDate($bug->resolvedDate)) $bug->resolvedDate = '';
  107. return $bug;
  108. }, $leftBugTableData);
  109. if(commonModel::hasPriv($releaseModule, 'unlinkBug'))
  110. {
  111. foreach($leftBugTableData as $leftBug)
  112. {
  113. $openedBuilds = '';
  114. foreach(explode(',', $leftBug->openedBuild) as $openedBuild)
  115. {
  116. $openedBuilds .= zget($builds, $openedBuild) . ',';
  117. }
  118. $leftBug->openedBuild = trim($openedBuilds, ',');
  119. if(!empty($leftBug->actions)) continue;
  120. $leftBug->actions[] = array('name' => 'unlinkLeftBug', 'disabled' => false);
  121. }
  122. }
  123. $leftBugFootToolbar = array();
  124. if($canBatchUnlinkBug) $leftBugFootToolbar['items'][] = array('className' => 'btn primary size-sm batch-btn', 'text' => $lang->release->batchUnlink, 'data-type' => 'bug', 'data-url' => createLink($releaseModule, 'batchUnlinkBug', "release={$release->id}&type=leftBug"));
  125. /* Process release info data. */
  126. $releaseBuild = array();
  127. foreach($release->builds as $build) $releaseBuild[] = $build->name;
  128. $releaseBranch = array();
  129. if($product->type != 'normal')
  130. {
  131. foreach($release->branches as $branchID) $releaseBranch[] = zget($branches, $branchID, '');
  132. }
  133. $releaseSystem = array();
  134. foreach($linkedReleases as $linkedRelease) $releaseSystem[] = zget($appList, $linkedRelease->system) . $linkedRelease->name;
  135. $releaseIncluded = array();
  136. foreach($includedApps as $includedApp)
  137. {
  138. $releaseIncluded[] = html::a
  139. (
  140. inLink('view', "releaseID={$includedApp->id}"),
  141. zget($appList, $includedApp->system) . $includedApp->name,
  142. '_blank'
  143. );
  144. }
  145. /* Right menus, export and link. */
  146. $exportBtn = null;
  147. if(!$isInModal && common::hasPriv($releaseModule, 'export') && ($summary || count($bugs) || count($leftBugs)))
  148. {
  149. $exportBtn = btn(set(array(
  150. 'text' => $lang->release->export,
  151. 'icon' => 'export',
  152. 'url' => createLink($releaseModule, 'export', "releaseID={$release->id}"),
  153. 'class' => 'ghost',
  154. 'data-size' => 'sm',
  155. 'data-toggle' => 'modal'
  156. )));
  157. }
  158. $decodeParam = helper::safe64Decode($param);
  159. $linkStoryBtn = $linkBugBtn = $linkLeftBtn = null;
  160. jsVar('linkParams', $decodeParam);
  161. jsVar('releaseModule', $releaseModule);
  162. if(!$release->deleted && $canBeChanged && empty($release->releases))
  163. {
  164. if(!$isInModal && common::hasPriv($releaseModule, 'linkStory'))
  165. {
  166. $linkStoryBtn = btn
  167. (
  168. set::text($lang->release->linkStory),
  169. set::icon('link'),
  170. set::type('primary'),
  171. set::className('linkStory-btn'),
  172. bind::click('window.showLink', array('params' => array('story')))
  173. );
  174. }
  175. if(!$isInModal && common::hasPriv($releaseModule, 'linkBug'))
  176. {
  177. $linkBugBtn = btn
  178. (
  179. set::text($lang->release->linkBug),
  180. set::icon('bug'),
  181. set::type('primary'),
  182. set::className('linkBug-btn'),
  183. bind::click('window.showLink', array('params' => array('bug')))
  184. );
  185. $linkLeftBtn = btn
  186. (
  187. set::text($lang->release->linkBug),
  188. set::icon('bug'),
  189. set::type('primary'),
  190. set::className('leftBug-btn'),
  191. bind::click('window.showLink', array('params' => array('leftBug')))
  192. );
  193. }
  194. }
  195. detailBody
  196. (
  197. set::hasExtraMain(false),
  198. on::click('.batch-btn > a, .batch-btn')->call('handleClickBatchBtn', jsRaw('$this')),
  199. setClass('release-view-body'),
  200. sectionList(
  201. tabs
  202. (
  203. set::className('w-full'),
  204. set::id('releaseTabs'),
  205. set::headerClass('border-b'),
  206. /* Linked story table. */
  207. tabPane
  208. (
  209. to::prefix(icon('lightbulb')),
  210. set::key('finishedStory'),
  211. set::title($lang->release->stories),
  212. set::active($type == 'story'),
  213. div
  214. (
  215. setClass('tab-actions'),
  216. $exportBtn,
  217. $linkStoryBtn
  218. ),
  219. dtable(setID('finishedStoryDTable'), set::style(array('min-width' => '100%')), set::cols(array_values($config->release->dtable->story->fieldList)), set::data($storyTableData), set::userMap($users), set::checkable(empty($release->releases) && ($canBatchUnlinkStory || $canBatchCloseStory)), set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=story&link={$link}&param={$param}&orderBy={name}_{sortType}")), set::orderBy($orderBy), set::onRenderCell(jsRaw('window.renderStoryCell')), set::extraHeight('+144'), set::footToolbar($storyFootToolbar), set::footPager(usePager('storyPager', '', array('recPerPage' => $storyPager->recPerPage, 'recTotal' => $storyPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=story&link={$link}&param={$param}&orderBy={$orderBy}&recTotal={$storyPager->recTotal}&recPerPage={recPerPage}&page={page}")))), set::checkInfo(jsRaw("function(checkedIDList){return window.setStoryStatistics(this, checkedIDList, '{$summary}');}")))
  220. ),
  221. /* Resolved bug table. */
  222. tabPane
  223. (
  224. to::prefix(icon('bug')),
  225. set::key('resolvedBug'),
  226. set::title($lang->release->bugs),
  227. set::active($type == 'bug'),
  228. div
  229. (
  230. setClass('tab-actions'),
  231. $exportBtn,
  232. $linkBugBtn
  233. ),
  234. dtable
  235. (
  236. setID('resolvedBugDTable'),
  237. set::style(array('min-width' => '100%')),
  238. set::userMap($users),
  239. set::cols(array_values($config->release->dtable->bug->fieldList)),
  240. set::data($bugTableData),
  241. set::checkable(empty($release->releases) && ($canBatchUnlinkBug || $canBatchCloseBug)),
  242. set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=bug&link={$link}&param={$param}&orderBy={name}_{sortType}")),
  243. set::orderBy($orderBy),
  244. set::extraHeight('+144'),
  245. set::footToolbar($bugFootToolbar),
  246. set::footPager(usePager('bugPager', '', array('recPerPage' => $bugPager->recPerPage, 'recTotal' => $bugPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=bug&link={$link}&param={$param}&orderBy={$orderBy}&recTotal={$bugPager->recTotal}&recPerPage={recPerPage}&page={page}"))))
  247. )
  248. ),
  249. /* Left bug table. */
  250. tabPane
  251. (
  252. to::prefix(icon('bug')),
  253. set::key('leftBug'),
  254. set::title($lang->release->generatedBugs),
  255. set::active($type == 'leftBug'),
  256. div
  257. (
  258. setClass('tab-actions'),
  259. $exportBtn,
  260. $linkLeftBtn
  261. ),
  262. dtable
  263. (
  264. setID('leftBugDTable'),
  265. set::style(array('min-width' => '100%')),
  266. set::userMap($users),
  267. set::cols(array_values($config->release->dtable->leftBug->fieldList)),
  268. set::data($leftBugTableData),
  269. set::checkable(empty($release->releases) && ($canBatchUnlinkBug || $canBatchCloseBug)),
  270. set::sortLink(createLink($releaseModule, 'view', "releaseID={$release->id}&type=leftBug&link={$link}&param={$param}&orderBy={name}_{sortType}")),
  271. set::orderBy($orderBy),
  272. set::extraHeight('+144'),
  273. set::footToolbar($leftBugFootToolbar),
  274. set::footPager(usePager('leftBugPager', '', array('recPerPage' => $leftBugPager->recPerPage, 'recTotal' => $leftBugPager->recTotal, 'linkCreator' => createLink($releaseModule, 'view', "releaseID={$release->id}&type=leftBug&link={$link}&param={$param}&orderBy={$orderBy}&recTotal={$leftBugPager->recTotal}&recPerPage={recPerPage}&page={page}"))))
  275. )
  276. ),
  277. /* Basic info block. */
  278. tabPane
  279. (
  280. to::prefix(icon('flag')),
  281. set::key('releaseInfo'),
  282. set::title($lang->release->basicInfo),
  283. set::active($type == 'releaseInfo'),
  284. div
  285. (
  286. setClass('tab-actions'),
  287. $exportBtn
  288. ),
  289. div(
  290. section(
  291. set::title($lang->release->basicInfo),
  292. tableData
  293. (
  294. item
  295. (
  296. set::name($lang->release->product),
  297. $release->productName
  298. ),
  299. !empty($releaseBranch) ? item
  300. (
  301. set::name($lang->release->branch),
  302. implode($lang->comma, $releaseBranch)
  303. ) : null,
  304. item
  305. (
  306. set::name($lang->release->system),
  307. zget($appList, $release->system)
  308. ),
  309. item
  310. (
  311. set::name($lang->release->name),
  312. $release->name
  313. ),
  314. empty($releaseBuild) ? null : item
  315. (
  316. set::name($lang->release->includedBuild),
  317. implode($lang->comma, $releaseBuild)
  318. ),
  319. empty($releaseSystem) ? null : item
  320. (
  321. set::name($lang->release->includedSystem),
  322. implode($lang->comma, $releaseSystem)
  323. ),
  324. item
  325. (
  326. set::name($lang->release->status),
  327. $this->processStatus('release', $release)
  328. ),
  329. item
  330. (
  331. set::name($lang->release->date),
  332. $release->date
  333. ),
  334. item
  335. (
  336. set::name($lang->release->releasedDate),
  337. $release->releasedDate
  338. ),
  339. empty($releaseIncluded) ? null : item
  340. (
  341. set::name($lang->release->includedApp),
  342. html(implode($lang->comma, $releaseIncluded))
  343. ),
  344. item
  345. (
  346. set::name($lang->release->desc),
  347. html($release->desc)
  348. )
  349. )
  350. ),
  351. html($this->printExtendFields($release, 'html', 'position=all', false)),
  352. fileList(set::files($release->files), set::showEdit(true), set::showDelete(true)),
  353. h::hr(set::className('mt-6')),
  354. history(set::objectID($release->id), set::objectType('release'))
  355. )
  356. )
  357. )
  358. )
  359. );
  360. render();