browse.html.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. /**
  3. * The browse view file of testcase 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 Yuting Wang <wangyuting@easycorp.ltd>
  7. * @package testcase
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. $isFromDoc = $from === 'doc';
  12. $isFromAI = $from === 'ai';
  13. if($isFromDoc || $isFromAI) $this->app->loadLang('doc');
  14. include 'header.html.php';
  15. jsVar('confirmBatchDeleteSceneCase', $lang->testcase->confirmBatchDeleteSceneCase);
  16. jsVar('caseChanged', $lang->testcase->changed);
  17. jsVar('isFromDoc', $isFromDoc);
  18. jsVar('isFromAI', $isFromAI);
  19. $topSceneCount = count(array_filter(array_map(function($case){return $case->isScene && $case->grade == 1;}, $cases)));
  20. $canBatchRun = $canModify && hasPriv('testtask', 'batchRun');
  21. $canBatchEdit = $canModify && hasPriv('testcase', 'batchEdit') && $productID;
  22. $canBatchReview = $canModify && hasPriv('testcase', 'batchReview') && ($config->testcase->needReview || !empty($config->testcase->forceReview));
  23. $canBatchDelete = $canModify && hasPriv('testcase', 'batchDelete');
  24. $canBatchChangeType = $canModify && hasPriv('testcase', 'batchChangeType');
  25. $canBatchConfirmStoryChange = $canModify && hasPriv('testcase', 'batchConfirmStoryChange');
  26. $canBatchChangeBranch = $canModify && hasPriv('testcase', 'batchChangeBranch') && isset($product->type) && $product->type != 'normal';
  27. $canBatchChangeModule = $canModify && hasPriv('testcase', 'batchChangeModule') && !empty($productID) && ((isset($product->type) && $product->type == 'normal') || $branch !== 'all');
  28. $canBatchChangeScene = $canModify && hasPriv('testcase', 'batchChangeScene');
  29. $canImportToLib = $canModify && hasPriv('testcase', 'importToLib') && helper::hasFeature('caselib');
  30. $canGroupBatch = ($canBatchRun || $canBatchEdit || $canBatchReview || $canBatchDelete || $canBatchChangeType || $canBatchConfirmStoryChange);
  31. $canBatchAction = ($canGroupBatch || $canBatchChangeBranch || $canBatchChangeModule || $canBatchChangeScene || $canImportToLib);
  32. jsVar('canImportToLib', $canImportToLib);
  33. $productCount = count(array_unique(array_map(function($case){return $case->product;}, $cases)));
  34. $caseProductID = $productCount > 1 ? 0 : $productID;
  35. $navActions = array();
  36. if($canBatchReview || $canBatchDelete || $canBatchChangeType || $canBatchConfirmStoryChange)
  37. {
  38. if($canBatchReview)
  39. {
  40. $reviewItems = array();
  41. foreach($lang->testcase->reviewResultList as $key => $result)
  42. {
  43. if($key == '') continue;
  44. $reviewItems[] = array('text' => $result, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => $this->createLink('testcase', 'batchReview', "result=$key"));
  45. }
  46. $navActions[] = array('text' => $lang->testcase->review, 'class' => 'not-hide-menu', 'items' => $reviewItems);
  47. }
  48. if($canBatchDelete) $navActions[] = array('text' => $lang->delete, 'innerClass' => 'batch-btn ajax-btn not-open-url batch-delete-btn', 'data-url' => helper::createLink('testcase', 'batchDelete', "productID=$productID"));
  49. if($canBatchChangeType)
  50. {
  51. $typeItems = array();
  52. foreach($lang->testcase->typeList as $key => $type)
  53. {
  54. if(!$key || $key == 'unit') continue;
  55. $typeItems[] = array('text' => $type, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => helper::createLink('testcase', 'batchChangeType', "type={$key}"));
  56. }
  57. $navActions[] = array('text' => $lang->testcase->type, 'class' => 'not-hide-menu', 'items' => $typeItems);
  58. }
  59. if($canBatchConfirmStoryChange) $navActions[] = array('text' => $lang->testcase->confirmStoryChange, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => helper::createLink('testcase', 'batchConfirmStoryChange', "productID=$productID"));
  60. }
  61. if($canBatchChangeModule)
  62. {
  63. $moduleItems = array();
  64. foreach($modules as $changeModuleID => $module) $moduleItems[] = array('text' => $module, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => helper::createLink('testcase', 'batchChangeModule', "moduleID={$changeModuleID}"));
  65. }
  66. if($canBatchChangeBranch)
  67. {
  68. $branchItems = array();
  69. foreach($branchTagOption as $branchTagID => $branchName) $branchItems[] = array('text' => $branchName, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => helper::createLink('testcase', 'batchChangeBranch', "branchID=$branchTagID"));
  70. }
  71. if($canBatchChangeScene)
  72. {
  73. $sceneItems = array();
  74. foreach($iscenes as $sceneID => $scene) $sceneItems[] = array('text' => $scene, 'innerClass' => 'batch-btn ajax-btn not-open-url', 'data-url' => helper::createLink('testcase', 'batchChangeScene', "sceneId=$sceneID"));
  75. }
  76. $footToolbar = $canBatchAction ? array('items' => array
  77. (
  78. $canGroupBatch ? array('type' => 'btn-group', 'items' => array
  79. (
  80. $canBatchRun ? array('text' => $lang->testtask->runCase, 'className' => 'batch-btn secondary not-open-url', 'data-url' => helper::createLink('testtask', 'batchRun', "productID=$productID&orderBy=$orderBy&from=testcase")) : null,
  81. $canBatchEdit ? array('text' => $lang->edit, 'className' => 'batch-btn secondary not-open-url', 'data-url' => helper::createLink('testcase', 'batchEdit', "productID=$caseProductID&branch=$branch")) : null,
  82. !empty($navActions) ? array('caret' => 'up', 'className' => 'secondary', 'items' => $navActions, 'data-placement' => 'top-start') : null,
  83. )) : null,
  84. $canBatchChangeBranch ? array('caret' => 'up', 'text' => $lang->product->branchName[$product->type], 'type' => 'dropdown', 'items' => $branchItems, 'data-placement' => 'top-start') : null,
  85. $canBatchChangeModule ? array('caret' => 'up', 'text' => $lang->testcase->moduleAB, 'type' => 'dropdown', 'items' => $moduleItems, 'data-placement' => 'top-start', 'data-menu' => array('searchBox' => true)) : null,
  86. $canBatchChangeScene ? array('caret' => 'up', 'text' => $lang->testcase->scene, 'type' => 'dropdown', 'items' => $sceneItems, 'data-placement' => 'top-start') : null,
  87. $canImportToLib ? array('text' => $lang->testcase->importToLib, 'data-toggle' => 'modal', 'data-target' => '#importToLib', 'data-size' => 'sm') : null,
  88. ), 'btnProps' => array('size' => 'sm', 'btnType' => 'secondary')) : null;
  89. $footToolbar['items'] = $canBatchAction ? array_values(array_filter($footToolbar['items'])) : array();
  90. if($isFromDoc)
  91. {
  92. $insertListLink = createLink($app->rawModule, $app->rawMethod, "productID=$product->id&branch=$branch&browseType=$browseType&param=$param&caseType=$caseType&orderBy=$orderBy&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&projectID=$projectID&from=$from&blockID={blockID}");
  93. $footToolbar = array(array('text' => $lang->doc->insertText, 'data-on' => 'click', 'data-call' => "insertListToDoc('#testcases', 'productCase', $blockID, '$insertListLink')"));
  94. }
  95. if($isFromAI) $footToolbar = array(array('text' => $lang->doc->insertText, 'data-on' => 'click', 'data-call' => "insertListToAI('#testcases', 'case')"));
  96. $cols = $this->loadModel('datatable')->getSetting('testcase');
  97. if(!empty($cols['actions']['list']))
  98. {
  99. $executionID = ($app->tab == 'project' || $app->tab == 'execution') ? $this->session->{$app->tab} : '0';
  100. foreach($cols['actions']['list'] as $method => $methodParams)
  101. {
  102. if(!isset($methodParams['url'])) continue;
  103. $cols['actions']['list'][$method]['url'] = str_replace(array('%executionID%', '{runID}'), array((string)$executionID, '0'), $methodParams['url']);
  104. }
  105. }
  106. if(isset($cols['title'])) $cols['title']['nestedToggle'] = $topSceneCount > 0;
  107. if(isset($cols['branch'])) $cols['branch']['map'] = $branchTagOption;
  108. if(isset($cols['story'])) $cols['story']['map'] = $stories;
  109. if(isset($cols['scene'])) $cols['scene']['map'] = $iscenes;
  110. if(isset($cols['status'])) $cols['status']['statusMap']['changed'] = $lang->story->changed;
  111. foreach($cases as $case)
  112. {
  113. $case->lastRunDate = formatTime($case->lastRunDate);
  114. if($case->fromCaseVersion > 0 && $case->fromCaseVersion > $case->version) $case->status = 'casechanged';
  115. $actionType = $case->isScene ? 'scene' : 'testcase';
  116. $cols['actions']['menu'] = $config->$actionType->menu;
  117. if($actionType == 'testcase' && !$this->config->testcase->needReview && empty($config->testcase->forceReview)) unset($cols['actions']['menu'][1][0]);
  118. if($actionType == 'scene') $case->bugs = $case->results = $case->stepNumber = $case->version = '';
  119. if(!empty($case->needconfirm)) $case->status = 'changed';
  120. if(isset($case->script)) unset($case->script);
  121. $stages = array();
  122. $reviewedByList = array();
  123. foreach(explode(',', $case->stage) as $stage) $stages[] = zget($lang->testcase->stageList, $stage, '');
  124. foreach(explode(',', $case->reviewedBy) as $reviewedBy) $reviewedByList[] = zget($users, $reviewedBy, '');
  125. $case->stage = implode(',', array_filter($stages));
  126. $case->reviewedBy = implode(',', array_filter($reviewedByList));
  127. $case->browseType = $browseType;
  128. initTableData(array($case), $cols, $this->testcase);
  129. if(!$canModify) unset($case->actions);
  130. }
  131. if($isFromDoc || $isFromAI)
  132. {
  133. if(isset($cols['actions'])) unset($cols['actions']);
  134. foreach($cols as $key => $col)
  135. {
  136. $cols[$key]['sortType'] = false;
  137. if(isset($col['link'])) unset($cols[$key]['link']);
  138. if($key == 'pri') $cols[$key]['priList'] = $lang->testcase->priList;
  139. if($key == 'title') $cols[$key]['link'] = array('url' => createLink('testcase', 'view', "caseID={caseID}&version={version}"), 'data-toggle' => 'modal', 'data-size' => 'lg');
  140. }
  141. }
  142. $linkParams = '';
  143. foreach($app->rawParams as $key => $value) $linkParams = $key != 'orderBy' ? "{$linkParams}&{$key}={$value}" : "{$linkParams}&orderBy={name}_{sortType}";
  144. $caseCreateLink = $canCreateCase ? $createCaseLink : '';
  145. div(
  146. on::click('[data-col="actions"] .ztf-case', 'window.checkZtf'),
  147. dtable
  148. (
  149. set::id('testcases'),
  150. set::plugins(array('sortable')),
  151. set::sortable(strpos($orderBy, 'sort_asc') !== false),
  152. set::onSortEnd(strpos($orderBy, 'sort_asc') !== false ? jsRaw('window.onSortEnd') : null),
  153. set::canSortTo(strpos($orderBy, 'sort_asc') !== false ? jsRaw('window.canSortTo') : null),
  154. ($isFromDoc || $isFromAI) ? set::afterRender(jsCallback()->call('toggleCheckRows', $idList)) : null,
  155. ($isFromDoc || $isFromAI) ? set::onCheckChange(jsRaw('window.checkedChange')) : null,
  156. ($isFromDoc || $isFromAI) ? set::height(400) : null,
  157. ($isFromDoc || $isFromAI) ? null : set::customCols(true),
  158. ($isFromDoc || $isFromAI) ? null : set::sortLink(createLink($app->rawModule, $app->rawMethod, $linkParams)),
  159. ($isFromDoc || $isFromAI) ? null : set::createTip($lang->testcase->create),
  160. ($isFromDoc || $isFromAI) ? null : set::createLink($caseCreateLink),
  161. set::userMap($users),
  162. set::cols($cols),
  163. set::nested(true),
  164. set::data(array_values($cases)),
  165. set::onRenderCell(jsRaw('window.onRenderCell')),
  166. set::checkable($canBatchAction),
  167. set::checkInfo(jsRaw('function(checks){return window.setStatistics(this, checks);}')),
  168. set::orderBy($orderBy),
  169. set::nested(true),
  170. set::footToolbar($footToolbar),
  171. set::footPager(usePager()),
  172. set::emptyTip($lang->testcase->noCase),
  173. set::customData(array('modules' => $modulePairs))
  174. )
  175. );
  176. modal
  177. (
  178. on::click('button[type="submit"]', "getCheckedCaseIdList('testcases')"),
  179. setID('importToLib'),
  180. set::modalProps(array('title' => $lang->testcase->importToLib)),
  181. formPanel
  182. (
  183. set::url(createLink('testcase', 'importToLib')),
  184. set::actions(array('submit')),
  185. set::submitBtnText($lang->testcase->import),
  186. formRow
  187. (
  188. formGroup
  189. (
  190. set::label($lang->testcase->selectLibAB),
  191. set::name('lib'),
  192. set::items($libraries),
  193. set::value(''),
  194. set::required(true)
  195. )
  196. ),
  197. formRow
  198. (
  199. setClass('hidden'),
  200. formGroup
  201. (
  202. set::name('caseIdList'),
  203. set::value('')
  204. )
  205. )
  206. )
  207. );
  208. modal
  209. (
  210. setID('dragModal'),
  211. set::title($lang->testcase->dragModalTitle),
  212. set::size('sm'),
  213. divider(),
  214. div(setClass('my-4'), $lang->testcase->dragModalDesc),
  215. div($lang->testcase->dragModalOrder),
  216. div($lang->testcase->dragModalScene),
  217. div(setClass('my-4'), $lang->testcase->dragModalAction),
  218. divider(),
  219. div
  220. (
  221. setClass('mt-4 pull-right'),
  222. btn(setClass('primary mr-2'), $lang->testcase->dragModalChangeScene, set('data-on', 'click'), set('data-call', 'clickChangeScenen')),
  223. btn(setClass('primary mr-2'), $lang->testcase->dragModalChangeOrder, set('data-on', 'click'), set('data-call', 'clickChangeOrder')),
  224. btn($lang->close, set('data-dismiss', 'modal'))
  225. )
  226. );
  227. render();