browsebylist.html.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. /**
  3. * The browses view file of productplan 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 productplan
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. jsVar('childrenAB', $lang->productplan->childrenAB);
  12. jsVar('expiredLang', $lang->productplan->expired);
  13. jsVar('nextStep', $lang->productplan->nextStep);
  14. jsVar('enterProjectList', $lang->productplan->enterProjectList);
  15. jsVar('plans', $plans);
  16. $isFromDoc = $from === 'doc';
  17. $isFromAI = $from === 'ai';
  18. if($isFromDoc || $isFromAI)
  19. {
  20. $this->app->loadLang('doc');
  21. $products = $this->loadModel('product')->getPairs('', 0, '', 'all');
  22. $productChangeLink = createLink($app->rawModule, $app->rawMethod, "productID={productID}&branch={$branch}&browseType={$browseType}&queryID={$queryID}&orderBy={$orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from={$from}&blockID={$blockID}");
  23. $insertListLink = createLink($app->rawModule, $app->rawMethod, "productID={$productID}&branch={$branch}&browseType={$browseType}&queryID={$queryID}&orderBy={$orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from={$from}&blockID={blockID}");
  24. formPanel
  25. (
  26. setID('zentaolist'),
  27. setClass('mb-4-important'),
  28. set::title(sprintf($this->lang->doc->insertTitle, $this->lang->doc->zentaoList['productPlan'])),
  29. set::actions(array()),
  30. set::showExtra(false),
  31. to::titleSuffix
  32. (
  33. span
  34. (
  35. setClass('text-muted text-sm text-gray-600 font-light'),
  36. span(setClass('text-warning mr-1'), icon('help')),
  37. $lang->doc->previewTip
  38. )
  39. ),
  40. formRow
  41. (
  42. formGroup
  43. (
  44. set::width('1/2'),
  45. set::name('product'),
  46. set::label($lang->doc->product),
  47. set::control(array('required' => false)),
  48. set::items($products),
  49. set::value($productID),
  50. set::required(),
  51. span
  52. (
  53. setClass('error-tip text-danger hidden'),
  54. $lang->doc->emptyError
  55. ),
  56. on::change('[name="product"]')->do("loadModal('$productChangeLink'.replace('{productID}', $(this).val()))")
  57. )
  58. )
  59. );
  60. }
  61. /* zin: Define the set::module('productplan') feature bar on main menu. */
  62. featureBar
  63. (
  64. set::current($browseType),
  65. set::module('productplan'),
  66. set::method('browse'),
  67. set::linkParams("productID={$productID}&branch={$branch}&browseType={key}&queryID={$queryID}&orderBy={$orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from={$from}&blockID={$blockID}"),
  68. set::isModal($isFromDoc || $isFromAI),
  69. li(searchToggle
  70. (
  71. set::simple($isFromDoc || $isFromAI),
  72. set::module('productplan'),
  73. set::open($browseType == 'bySearch'),
  74. ($isFromDoc || $isFromAI) ? set::target('#docSearchForm') : null,
  75. ($isFromDoc || $isFromAI) ? set::onSearch(jsRaw('function(){$(this.element).closest(".modal").find("#featureBar .nav-item>.active").removeClass("active").find(".label").hide()}')) : null
  76. ))
  77. );
  78. if($isFromDoc || $isFromAI)
  79. {
  80. div(setID('docSearchForm'));
  81. }
  82. $canCreatePlan = common::canModify('product', $product) && common::hasPriv($app->rawModule, 'create');
  83. toolbar
  84. (
  85. setClass(array('hidden' => $isFromDoc || $isFromAI)),
  86. btnGroup(btn(setClass($viewType == 'list' ? 'text-primary font-bold shadow-inner bg-canvas' : ''), set::icon('format-list-bulleted'), setData('type', 'list'), setClass('switchButton'), setData('app', $app->tab)), btn(setClass($viewType == 'kanban' ? 'text-primary font-bold shadow-inner bg-canvas' : ''), set::icon('kanban'), setData('type', 'kanban'), setClass('switchButton'), setData('app', $app->tab))),
  87. $canCreatePlan ? item(set(array('icon' => 'plus', 'class' => 'primary plan-create-btn', 'text' => $lang->productplan->create, 'url' => createLink($app->rawModule, 'create', "productID={$productID}&branch={$branch}")))) : null
  88. );
  89. $cols = $this->loadModel('datatable')->getSetting('productplan');
  90. $cols['title']['data-app'] = $app->tab;
  91. if($app->rawModule == 'projectplan') $cols['actions']['list']['createExecution']['url']['params'] = "projectID={$projectID}&executionID=0&copyExecutionID=0&planID={id}";
  92. if($isFromDoc || $isFromAI)
  93. {
  94. if(isset($cols['actions'])) unset($cols['actions']);
  95. foreach($cols as $key => $col)
  96. {
  97. $cols[$key]['sortType'] = false;
  98. if(isset($col['link'])) unset($cols[$key]['link']);
  99. if($key == 'title') $cols[$key]['link'] = array('url' => createLink('productplan', 'view', 'planID={id}'), 'data-toggle' => 'modal', 'data-size' => 'lg');
  100. }
  101. }
  102. $tableData = initTableData($plans, $cols, $this->productplan);
  103. foreach($tableData as $plan)
  104. {
  105. $otherActions = array();
  106. foreach($plan->actions as $i => $action)
  107. {
  108. if(is_string($action) && strpos($action, 'other:') !== false)
  109. {
  110. $otherActions = explode(',', str_replace('other:', '', $action));
  111. break;
  112. }
  113. }
  114. $otherActions = array_filter(array_map(function($action) use($plan)
  115. {
  116. if($plan->status == 'doing' && (strpos($action, 'close') !== false || strpos($action, 'activate') !== false)) return $action;
  117. if($plan->status == 'done' && strpos($action, 'activate') !== false) return $action;
  118. if($plan->status == 'closed' && strpos($action, 'close') !== false) return $action;
  119. if($plan->status == 'wait') return $action;
  120. return null;
  121. }, $otherActions));
  122. if($otherActions) $plan->actions[$i] = 'other:' . implode(',', $otherActions);
  123. }
  124. $canBatchEdit = common::hasPriv('productplan', 'batchEdit');
  125. $canBatchChangeStatus = common::hasPriv('productplan', 'batchChangeStatus');
  126. $canBatchAction = $canBatchEdit || $canBatchChangeStatus;
  127. $footToolbar = array();
  128. if($canBatchAction && !$isFromDoc && !$isFromAI)
  129. {
  130. if($canBatchEdit)
  131. {
  132. $footToolbar['items'][] = array(
  133. 'text' => $lang->edit,
  134. 'className' => 'btn batch-btn size-sm secondary',
  135. 'data-url' => $this->createLink('productplan', 'batchEdit', "productID={$productID}&branch={$branch}")
  136. );
  137. }
  138. if($canBatchChangeStatus)
  139. {
  140. $footToolbar['items'][] = array(
  141. 'text' => $lang->close,
  142. 'className' => 'btn batch-btn size-sm secondary',
  143. 'data-url' => $this->createLink('productplan', 'batchChangeStatus', "status=closed&productID={$productID}")
  144. );
  145. }
  146. if($canBatchChangeStatus)
  147. {
  148. $items = array();
  149. foreach($lang->productplan->statusList as $statusKey => $statusText)
  150. {
  151. if($statusKey == 'closed') continue;
  152. $items[$statusKey] = array
  153. (
  154. 'text' => $statusText,
  155. 'class' => 'batch-btn ajax-btn not-open-url',
  156. 'data-url' => createLink('productplan', 'batchChangeStatus', "status={$statusKey}&productID={$productID}")
  157. );
  158. }
  159. menu
  160. (
  161. setID('navStatus'),
  162. setClass('dropdown-menu'),
  163. set::items(array_values($items))
  164. );
  165. $footToolbar['items'][] = array(
  166. 'text' => $lang->statusAB,
  167. 'btnType' => 'secondary',
  168. 'caret' => 'up',
  169. 'url' => '#navStatus',
  170. 'data-toggle' => 'dropdown',
  171. 'data-placement' => 'top-start'
  172. );
  173. }
  174. }
  175. if($isFromDoc) $footToolbar = array(array('text' => $lang->doc->insertText, 'data-on' => 'click', 'data-call' => "insertListToDoc('#productPlans', 'productPlan', $blockID, '$insertListLink')"));
  176. if($isFromAI) $footToolbar = array(array('text' => $lang->doc->insertText, 'data-on' => 'click', 'data-call' => "insertListToAI('#productPlans', 'plan')"));
  177. $sortLink = createLink('productplan', 'browse', "productID={$productID}&branch={$branch}&browseType={$browseType}&queryID={$queryID}&orderBy={name}_{sortType}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}");
  178. $createPlanLink = $canCreatePlan ? createLink($app->rawModule, 'create', "productID={$productID}&branch={$branch}") : '';
  179. dtable
  180. (
  181. setID('productPlans'),
  182. set::cols($cols),
  183. set::data($tableData),
  184. set::orderBy($orderBy),
  185. set::onRenderCell(jsRaw('window.renderCell')),
  186. set::footToolbar($footToolbar),
  187. set::emptyTip($lang->productplan->noPlan),
  188. set::footPager(usePager(array('linkCreator' => createLink($app->rawModule, 'browse', "productID={$productID}&branch={$branch}&browseType={$browseType}&queryID={$queryID}&orderBy={$orderBy}&recTotal={$pager->recTotal}&recPerPage={recPerPage}&pageID={page}&from=$from&blockID=$blockID")))),
  189. !$isFromDoc ? null : set::afterRender(jsCallback()->call('toggleCheckRows', $idList)),
  190. (!$isFromDoc && !$isFromAI) ? null : set::onCheckChange(jsRaw('window.checkedChange')),
  191. (!$isFromDoc && !$isFromAI) ? null : set::height(400),
  192. (!$isFromDoc && !$isFromAI) ? null : set::noNestedCheck(),
  193. ($isFromDoc || $isFromAI) ? null : set::customCols(true),
  194. ($isFromDoc || $isFromAI) ? null : set::sortLink($sortLink),
  195. ($isFromDoc || $isFromAI) ? null : set::checkInfo(jsRaw("function(checkedIDList){return window.setStatistics(this, checkedIDList, '{$summary}');}")),
  196. ($isFromDoc || $isFromAI) ? null : set::createTip($lang->productplan->create),
  197. ($isFromDoc || $isFromAI) ? null : set::createLink($createPlanLink)
  198. );
  199. modal
  200. (
  201. setID('createExecutionModal'),
  202. set::modalProps(array('title' => $lang->productplan->selectProjects)),
  203. form
  204. (
  205. setID('createExecutionForm'),
  206. setClass('py-4'),
  207. set::actions
  208. (
  209. array(
  210. array
  211. (
  212. 'class' => 'createExecutionBtn',
  213. 'text' => !empty($projects) ? $lang->productplan->nextStep : $lang->productplan->enterProjectList,
  214. 'id' => !empty($projects) ? 'createExecutionButton' : '',
  215. 'type' => 'primary',
  216. 'url' => !empty($projects) ? '###' : createLink('product', 'project', "status=all&productID={$productID}&branch={$branch}")
  217. ),
  218. array
  219. (
  220. 'text' => $lang->cancel,
  221. 'data-dismiss' => 'modal'
  222. )
  223. )
  224. ),
  225. formGroup
  226. (
  227. set::label($lang->productplan->project),
  228. picker
  229. (
  230. set::name('project'),
  231. set::items($projects),
  232. set::required(true),
  233. set::disabled(empty($projects))
  234. )
  235. ),
  236. formRow
  237. (
  238. !empty($projects) ? setClass('hidden') : null,
  239. setClass('projectTips'),
  240. formGroup
  241. (
  242. set::label(''),
  243. span
  244. (
  245. setClass('text-danger'),
  246. $lang->productplan->noLinkedProject
  247. ),
  248. formHidden('planID', '')
  249. )
  250. )
  251. )
  252. );