control.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. <?php
  2. /**
  3. * The control file of program module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chunsheng Wang <chunsheng@cnezsoft.com>
  8. * @package program
  9. * @link https://www.zentao.net
  10. */
  11. class program extends control
  12. {
  13. /**
  14. * Construct
  15. *
  16. * @param string $moduleName
  17. * @param string $methodName
  18. * @access public
  19. * @return void
  20. */
  21. public function __construct($moduleName = '', $methodName = '')
  22. {
  23. parent::__construct($moduleName, $methodName);
  24. $this->loadModel('project');
  25. }
  26. /**
  27. * Program list.
  28. *
  29. * @param string $status
  30. * @param string $orderBy
  31. * @access public
  32. * @return void
  33. * @param int $recTotal
  34. * @param int $recPerPage
  35. * @param int $pageID
  36. * @param int $param
  37. */
  38. public function browse($status = 'unclosed', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 100, $pageID = 1, $param = 0)
  39. {
  40. $uri = $this->app->getURI(true);
  41. $this->session->set('programList', $uri, 'program');
  42. $this->session->set('projectList', $uri, 'program');
  43. $this->session->set('createProjectLocate', $uri, 'program');
  44. $this->app->loadClass('pager', $static = true);
  45. $pager = new pager($recTotal, $recPerPage, $pageID);
  46. $programs = $this->programZen->getProgramsByType($status, $orderBy, (int)$param, $pager);
  47. $PMList = $this->programZen->getPMListByPrograms($programs);
  48. /* Build the search form. */
  49. $actionURL = $this->createLink('program', 'browse', "status=bySearch&orderBy={$orderBy}&recTotal={$recTotal}&recPerPage={$recPerPage}&pageID={$pageID}&param=myQueryID");
  50. $this->config->program->search['actionURL'] = $actionURL;
  51. $this->loadModel('search')->setSearchParams($this->config->program->search);
  52. $this->view->title = $this->lang->program->browse;
  53. $this->view->programs = $programs;
  54. $this->view->status = $status;
  55. $this->view->orderBy = $orderBy;
  56. $this->view->pager = $pager;
  57. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  58. $this->view->usersAvatar = $this->user->getAvatarPairs('');
  59. $this->view->PMList = $PMList;
  60. $this->view->param = $param;
  61. $this->display();
  62. }
  63. /**
  64. * 项目集看板。
  65. * Program kanban list.
  66. *
  67. * @param string $browseType
  68. * @access public
  69. * @return void
  70. */
  71. public function kanban($browseType = 'my')
  72. {
  73. $this->view->title = $this->lang->program->kanban->common;
  74. $this->view->kanbanList = $this->programZen->getKanbanList($browseType);
  75. $this->view->browseType = $browseType;
  76. $this->display();
  77. }
  78. /**
  79. * 项目集下产品列表。
  80. * Program products list.
  81. *
  82. * @param int $programID
  83. * @param string $browseType
  84. * @param string $orderBy
  85. * @param int $recTotal
  86. * @param int $recPerPage
  87. * @param int $pageID
  88. * @access public
  89. * @return void
  90. */
  91. public function product($programID = 0, $browseType = 'noclosed', $orderBy = 'order_asc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
  92. {
  93. $programPairs = $this->program->getPairs();
  94. if($programID && !isset($programPairs[$programID]))
  95. {
  96. if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'fail', 'message' => '404 Not found'));
  97. return $this->send(array('result' => 'success', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->createLink('program', 'browse'))));
  98. }
  99. $programID = $this->program->checkAccess($programID, $programPairs);
  100. helper::setcookie("lastProgram", (string)$programID);
  101. common::setMenuVars('program', $programID);
  102. /* Get the top programID. */
  103. if($programID)
  104. {
  105. $program = $this->program->getByID($programID);
  106. $path = explode(',', $program->path);
  107. $path = array_filter($path);
  108. $programID = (int)current($path);
  109. $this->view->program = $program;
  110. }
  111. /* Load pager. */
  112. $this->app->loadClass('pager', true);
  113. $pager = new pager($recTotal, $recPerPage, $pageID);
  114. $products = $this->loadModel('product')->getList($programID, $browseType);
  115. $this->view->products = $this->product->getStats(array_keys($products), $orderBy, $pager, 'story', $programID);
  116. $this->view->title = $this->lang->program->product;
  117. $this->view->programID = $programID;
  118. $this->view->browseType = $browseType;
  119. $this->view->orderBy = $orderBy;
  120. $this->view->pager = $pager;
  121. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  122. $this->view->userIdPairs = $this->user->getPairs('noletter|showid');
  123. $this->view->usersAvatar = $this->user->getAvatarPairs('');
  124. $this->display();
  125. }
  126. /**
  127. * Create a program.
  128. *
  129. * @param int $parentProgramID
  130. * @param int $charterID
  131. * @param string $extra
  132. * @access public
  133. * @return void
  134. */
  135. public function create($parentProgramID = 0, $charterID = 0, $extra = '')
  136. {
  137. $parentProgram = $this->program->getByID($parentProgramID);
  138. if($_POST)
  139. {
  140. $program = $this->programZen->buildProgramForCreate();
  141. $programID = $this->program->create($program);
  142. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  143. $this->loadModel('action')->create('program', $programID, 'opened');
  144. $locateLink = $this->session->programList ? $this->session->programList : $this->createLink('program', 'browse');
  145. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $programID, 'load' => $locateLink));
  146. }
  147. $originExtra = $extra;
  148. $extra = str_replace(array(',', ' '), array('&', ''), $extra);
  149. parse_str($extra, $output);
  150. $this->view->title = isset($parentProgram->id) ? $this->lang->program->children : $this->lang->program->create;
  151. $this->view->gobackLink = (isset($output['from']) && $output['from'] == 'global') ? $this->createLink('program', 'browse') : '';
  152. $this->view->pmUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst');
  153. $this->view->poUsers = $this->user->getPairs('noclosed|nodeleted|pofirst');
  154. $this->view->users = $this->user->getPairs('noclosed|nodeleted');
  155. $this->view->parentProgram = $parentProgram;
  156. $this->view->parents = $this->program->getParentPairs();
  157. $this->view->programList = $this->program->getList();
  158. $this->view->budgetUnitList = $this->project->getBudgetUnitList();
  159. $this->view->budgetLeft = empty($parentProgram) ? 0 : $this->program->getBudgetLeft($parentProgram);
  160. $this->view->loadUrl = $this->createLink('program', 'create', "parentProgramID={parent}&charterID=0" . (empty($originExtra) ? '' : "&extra=$originExtra"));
  161. $this->display();
  162. }
  163. /**
  164. * 编辑项目集。
  165. * Edit the program.
  166. *
  167. * @param int $programID
  168. * @param int $parentProgramID
  169. * @access public
  170. * @return void
  171. */
  172. public function edit($programID = 0, $parentProgramID = 0)
  173. {
  174. if($_POST)
  175. {
  176. $program = $this->programZen->buildProgramForEdit($programID);
  177. $changes = $this->program->update($programID, $program);
  178. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  179. if($changes)
  180. {
  181. $actionID = $this->loadModel('action')->create('program', $programID, 'edited');
  182. $this->action->logHistory($actionID, $changes);
  183. }
  184. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->session->programList ? $this->session->programList : inLink('browse')));
  185. }
  186. $program = $this->program->getByID($programID);
  187. if($parentProgramID) $program->parent = $parentProgramID;
  188. $parentProgram = $program->parent ? $this->program->getByID($program->parent) : new stdclass();
  189. $parents = $this->program->getParentPairs();
  190. $parents = $this->programZen->removeSubjectToCurrent($parents, $programID);
  191. $disableParent = false;
  192. if(!isset($parents[$program->parent]))
  193. {
  194. $disableParent = true;
  195. if(!empty($program->parent)) $parents = array($parentProgram->id => $parentProgram->name);
  196. }
  197. $this->view->title = $this->lang->program->edit;
  198. $this->view->pmUsers = $this->loadModel('user')->getPairs('noclosed|nodeleted|pmfirst', $program->PM);
  199. $this->view->program = $program;
  200. $this->view->parents = $parents;
  201. $this->view->disableParent = $disableParent;
  202. $this->view->budgetUnitList = $this->loadModel('project')->getBudgetUnitList();
  203. $this->view->parentProgram = $parentProgram;
  204. $this->view->loadUrl = $this->createLink('program', 'edit', "programID=$programID&parentProgramID={parent}");
  205. $this->display();
  206. }
  207. /**
  208. * 关闭一个项目集。
  209. * Close a program.
  210. *
  211. * @param int $programID
  212. * @access public
  213. * @return void
  214. */
  215. public function close($programID)
  216. {
  217. $this->loadModel('action');
  218. $program = $this->program->getByID($programID);
  219. if(!empty($_POST))
  220. {
  221. /* Only when all subprograms and subprojects are closed can the program be closed. */
  222. $hasUnfinished = $this->program->hasUnfinishedChildren($program);
  223. if($hasUnfinished) return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.alert('{$this->lang->program->closeErrorMessage}');"));
  224. $programData = form::data(null, $programID)
  225. ->add('closedBy', $this->app->user->account)
  226. ->add('lastEditedBy', $this->app->user->account)
  227. ->get();
  228. $changes = $this->program->close($programData, $program);
  229. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  230. if($this->post->comment != '' || !empty($changes))
  231. {
  232. $actionID = $this->action->create('program', $programID, 'Closed', $this->post->comment);
  233. $this->action->logHistory($actionID, $changes);
  234. }
  235. $this->executeHooks($programID);
  236. return $this->sendSuccess(array('closeModal' => true, 'load' => true));
  237. }
  238. $this->view->title = $this->lang->program->close;
  239. $this->view->program = $program;
  240. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  241. $this->view->actions = $this->action->getList('program', $programID);
  242. $this->display();
  243. }
  244. /**
  245. * 启动项目集。
  246. * Start a program.
  247. *
  248. * @param int $programID
  249. * @access public
  250. * @return void
  251. */
  252. public function start($programID)
  253. {
  254. $this->loadModel('action');
  255. $program = $this->project->getByID($programID);
  256. if(!empty($_POST))
  257. {
  258. $postData = form::data($this->config->program->form->start, $programID);
  259. $postData = $this->programZen->prepareStartExtras($postData);
  260. $changes = $this->project->start($programID, $postData);
  261. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  262. if($this->post->comment != '' or !empty($changes))
  263. {
  264. $actionID = $this->action->create('program', $programID, 'Started', $this->post->comment);
  265. $this->action->logHistory($actionID, $changes);
  266. }
  267. $this->loadModel('common')->syncPPEStatus($programID);
  268. $this->executeHooks($programID);
  269. return $this->sendSuccess(array('closeModal' => true, 'load' => true));
  270. }
  271. $this->view->title = $this->lang->program->start;
  272. $this->view->project = $program;
  273. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  274. $this->view->actions = $this->action->getList('program', $programID);
  275. $this->display('project', 'start');
  276. }
  277. /**
  278. * 激活一个项目集。
  279. * Activate a program.
  280. *
  281. * @param int $programID
  282. * @access public
  283. * @return void
  284. */
  285. public function activate($programID = 0)
  286. {
  287. $this->loadModel('action');
  288. $program = $this->program->getByID($programID);
  289. if(!empty($_POST))
  290. {
  291. $programData = form::data(null, $programID)->add('lastEditedBy', $this->app->user->account)->get();
  292. $changes = $this->program->activate($programData, $program);
  293. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  294. if($this->post->comment != '' || !empty($changes))
  295. {
  296. $actionID = $this->action->create('program', $programID, 'Activated', $this->post->comment);
  297. $this->action->logHistory($actionID, $changes);
  298. }
  299. return $this->sendSuccess(array('closeModal' => true, 'load' => true));
  300. }
  301. $newBegin = date('Y-m-d');
  302. $dateDiff = helper::diffDate($newBegin, $program->begin);
  303. $newEnd = date('Y-m-d', strtotime($program->end) + $dateDiff * 24 * 3600);
  304. $this->view->title = $this->lang->program->activate;
  305. $this->view->program = $program;
  306. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  307. $this->view->actions = $this->action->getList('program', $programID);
  308. $this->view->newBegin = $newBegin;
  309. $this->view->newEnd = $newEnd;
  310. $this->display();
  311. }
  312. /**
  313. * 挂起项目集。
  314. * Suspend a program.
  315. *
  316. * @param int $programID
  317. * @access public
  318. * @return void
  319. */
  320. public function suspend($programID)
  321. {
  322. $this->loadModel('action');
  323. $this->extendRequireFields($programID);
  324. if(!empty($_POST))
  325. {
  326. $postData = fixer::input('post')
  327. ->add('id', $programID)
  328. ->setDefault('status', 'suspended')
  329. ->setDefault('lastEditedBy', $this->app->user->account)
  330. ->setDefault('lastEditedDate', helper::now())
  331. ->setDefault('suspendedDate', helper::today())
  332. ->stripTags($this->config->program->editor->suspend['id'], $this->config->allowedTags)
  333. ->get();
  334. $isSucceed = $this->program->suspend($programID, $postData);
  335. if(!$isSucceed) return $this->sendError(dao::getError(), true);
  336. $this->executeHooks($programID);
  337. return $this->sendSuccess(array('closeModal' => true, 'load' => true));
  338. }
  339. $this->view->title = $this->lang->program->suspend;
  340. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  341. $this->view->actions = $this->action->getList('program', $programID);
  342. $this->view->program = $this->program->getByID($programID);
  343. $this->display();
  344. }
  345. /**
  346. * 删除一个项目集。
  347. * Delete a program.
  348. *
  349. * @param int $programID
  350. * @param string $confirm
  351. * @access public
  352. * @return void
  353. */
  354. public function delete($programID, $confirm = 'no')
  355. {
  356. /* The program can NOT be deleted if it has a child program. */
  357. $childrenPairs = $this->program->getChildrenPairsByID($programID);
  358. if(count($childrenPairs))
  359. {
  360. if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => 'Can not delete the program has children.'));
  361. return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.alert({icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x', message: '{$this->lang->program->hasChildren}'})"));
  362. }
  363. /* The program can NOT be deleted if it has a product. */
  364. $productPairs = $this->program->getProductPairsByID($programID);
  365. if(count($productPairs)) return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.alert({icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x', message: '{$this->lang->program->hasProduct}'})"));
  366. /* Mark the program is deleted and record the action log. */
  367. $program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($programID)->andWhere('deleted')->eq('0')->fetch();
  368. if($confirm == 'no')
  369. {
  370. return $this->send(array('result' => 'fail', 'callback' => "zui.Modal.confirm({icon: 'icon-exclamation-sign', iconClass: 'warning-pale rounded-full icon-2x', message: '" . sprintf($this->lang->program->confirmDelete, $program->name) . "'}).then((res) => {if(res) $.ajaxSubmit({url: '" . $this->createLink('program', 'delete', "programID={$programID}&confirm=yes") . "'});});"));
  371. }
  372. else
  373. {
  374. if($program)
  375. {
  376. $this->dao->update(TABLE_PROGRAM)->set('deleted')->eq('1')->where('id')->eq($programID)->exec();
  377. $this->loadModel('action')->create('program', $programID, 'deleted', '', actionModel::CAN_UNDELETED);
  378. }
  379. return $this->send(array('result' => 'success', 'load' => true));
  380. }
  381. }
  382. /**
  383. * 获取项目集下的项目。
  384. * Program project list.
  385. *
  386. * @param int $programID
  387. * @param string $browseType
  388. * @param string $orderBy
  389. * @param int $recTotal
  390. * @param int $recPerPage
  391. * @param int $pageID
  392. * @access public
  393. * @return void
  394. */
  395. public function project($programID = 0, $browseType = 'doing', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
  396. {
  397. $programID = $this->program->checkAccess($programID, $this->program->getPairs());
  398. helper::setcookie("lastProgram", (string)$programID);
  399. common::setMenuVars('program', $programID);
  400. /* Set back link. */
  401. $uri = $this->app->getURI(true);
  402. $this->app->session->set('programProject', $uri, 'program');
  403. $this->app->session->set('projectList', $uri, 'program');
  404. $this->app->session->set('createProjectLocate', $uri, 'program');
  405. /* Load pager. */
  406. $this->app->loadClass('pager', $static = true);
  407. $pager = new pager($recTotal, $recPerPage, $pageID);
  408. $programTitle = $this->loadModel('setting')->getItem('owner=' . $this->app->user->account . '&module=program&key=programTitle');
  409. $order = explode('_', $orderBy);
  410. $sortField = zget($this->config->program->sortFields, $order[0], 'id') . '_' . $order[1];
  411. $projectStats = $this->program->getProjectStats($programID, $browseType, 0, $sortField, $programTitle, false, $pager);
  412. $this->view->title = $this->lang->program->project;
  413. $this->view->projectStats = $projectStats;
  414. $this->view->pager = $pager;
  415. $this->view->programID = $programID;
  416. $this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted');
  417. $this->view->PMList = $this->user->getListByAccounts(helper::arrayColumn($projectStats, 'PM'), 'account');
  418. $this->view->browseType = $browseType;
  419. $this->view->orderBy = $orderBy;
  420. $this->display();
  421. }
  422. /**
  423. * 项目集下的干系人列表。
  424. * Program stakeholder list.
  425. *
  426. * @param int $programID
  427. * @param string $orderBy
  428. * @param int $recTotal
  429. * @param int $recPerPage
  430. * @param int $pageID
  431. * @access public
  432. * @return void
  433. */
  434. public function stakeholder($programID = 0, $orderBy = 't1.id_desc', $recTotal = 0, $recPerPage = 15, $pageID = 1)
  435. {
  436. $this->app->loadLang('stakeholder');
  437. common::setMenuVars('program', $programID);
  438. $this->app->loadClass('pager', true);
  439. $pager = new pager($recTotal, $recPerPage, $pageID);
  440. $sort = $orderBy;
  441. if(strpos($sort, 'name_') !== false) $sort = str_replace('name_', 'realname_', $sort);
  442. $this->view->title = $this->lang->program->stakeholder;
  443. $this->view->pager = $pager;
  444. $this->view->stakeholders = $this->program->getStakeholders($programID, $sort, $pager);
  445. $this->view->programID = $programID;
  446. $this->view->program = $this->program->getByID($programID);
  447. $this->view->users = $this->loadModel('user')->getPairs('noletter|pofirst|nodeleted');
  448. $this->view->orderBy = $orderBy;
  449. $this->display();
  450. }
  451. /**
  452. * 创建项目集干系人。
  453. * Create program stakeholder.
  454. *
  455. * @param int $programID
  456. * @access public
  457. * @return void
  458. */
  459. public function createStakeholder($programID = 0)
  460. {
  461. return print($this->fetch('stakeholder', 'create', "objectID=$programID"));
  462. }
  463. /**
  464. * 解除干系人跟项目集的关联关系。
  465. * Unlink stakeholder from the program.
  466. *
  467. * @param int $programID
  468. * @param int $stakeholderID
  469. * @access public
  470. * @return void
  471. */
  472. public function unlinkStakeholder($programID, $stakeholderID)
  473. {
  474. $this->program->batchUnlinkStakeholders($programID, array($stakeholderID));
  475. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  476. return $this->send(array('result' => 'success', 'load' => true));
  477. }
  478. /**
  479. * 批量移除项目集下的关系人。
  480. * Batch unlink program stakeholders.
  481. *
  482. * @param int $programID
  483. * @access public
  484. * @return void
  485. */
  486. public function batchUnlinkStakeholders($programID = 0)
  487. {
  488. if(!$this->post->stakeholderIdList) return $this->send(array('load' => true));
  489. $this->program->batchUnlinkStakeholders($programID, $this->post->stakeholderIdList);
  490. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  491. return $this->sendSuccess(array('load' => true));
  492. }
  493. /**
  494. * 导出项目集。
  495. * Export program.
  496. *
  497. * @param string $status
  498. * @param string $orderBy
  499. * @access public
  500. * @return void
  501. */
  502. public function export($status, $orderBy)
  503. {
  504. if($_POST)
  505. {
  506. /* Create field lists. */
  507. $fields = $this->post->exportFields ? $this->post->exportFields : explode(',', $this->config->program->list->exportFields);
  508. foreach($fields as $key => $fieldName)
  509. {
  510. $fieldName = trim($fieldName);
  511. $fields[$fieldName] = zget($this->lang->program, $fieldName);
  512. unset($fields[$key]);
  513. }
  514. /* Get and process program list. */
  515. $users = $this->loadModel('user')->getPairs('noletter');
  516. $programs = $this->program->getList($status, $orderBy);
  517. $products = $this->program->getProductByProgram(array_keys($programs));
  518. foreach($programs as $programID => $program)
  519. {
  520. $program->PM = zget($users, $program->PM);
  521. $program->status = $this->processStatus('project', $program);
  522. $program->model = zget($this->lang->project->modelList, $program->model);
  523. $program->product = empty($products[$programID]) ? '' : implode(",", helper::arrayColumn($products[$programID], 'name'));
  524. $program->budget = $program->budget . zget($this->lang->project->unitList, $program->budgetUnit);
  525. if($this->post->exportType == 'selected')
  526. {
  527. $checkedItem = $this->post->checkedItem;
  528. if(strpos(",$checkedItem,", ",{$program->id},") === false) unset($programs[$programID]);
  529. }
  530. }
  531. if($this->config->edition != 'open') list($fields, $projectStats) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $projectStats);
  532. $this->post->set('fields', $fields);
  533. $this->post->set('rows', $programs);
  534. $this->post->set('kind', 'program');
  535. $this->fetch('file', 'export2' . $this->post->fileType);
  536. }
  537. $this->display();
  538. }
  539. /**
  540. * 获取项目集下1.5级导航数据。
  541. * Get sub navigation data of program.
  542. *
  543. * @param int $programID
  544. * @param string $module
  545. * @param string $method
  546. * @access public
  547. * @return void
  548. */
  549. public function ajaxGetDropMenu($programID, $module, $method)
  550. {
  551. $programs = $this->program->getList('all', 'order_asc');
  552. foreach($programs as $programID => $program)
  553. {
  554. if($program->type != 'program') unset($programs[$programID]);
  555. if($module == 'program' && $method == 'product' && $program->parent != 0) unset($programs[$programID]);
  556. }
  557. $this->view->programTree = $this->programZen->buildTree($programs);
  558. $this->view->link = $this->programZen->getLink($module, $method, '{id}', '', 'program');
  559. $this->display();
  560. }
  561. /**
  562. * 更新项目集排序。
  563. * Update program order.
  564. *
  565. * @access public
  566. * @return string
  567. */
  568. public function updateOrder()
  569. {
  570. $programIdList = json_decode($this->post->programIdList, true);
  571. if(!$programIdList) return $this->send(array('result' => 'success'));
  572. asort($programIdList);
  573. $programIdList = array_flip($programIdList);
  574. $oldOrders = $this->dao->select('id,`order`')->from(TABLE_PROJECT)->where('id')->in($programIdList)->orderBy('`order`')->fetchPairs('id', 'order');
  575. if(count($programIdList) != count($oldOrders)) return $this->send(array('result' => 'success'));
  576. $newOrders = array_combine($programIdList, $oldOrders);
  577. foreach($newOrders as $programID => $order)
  578. {
  579. if($order != $oldOrders[$programID]) $this->dao->update(TABLE_PROJECT)->set('`order`')->eq($order)->where('id')->eq($programID)->exec();
  580. }
  581. return $this->send(array('result' => 'success', 'load' => true));
  582. }
  583. /*
  584. * 移除项目集白名单成员。
  585. * Removing users from the white list.
  586. *
  587. * @param int $aclID
  588. * @access public
  589. * @return void
  590. */
  591. /**
  592. * @param int $aclID
  593. */
  594. public function unbindWhitelist($aclID)
  595. {
  596. echo $this->fetch('personnel', 'unbindWhitelist', "id={$aclID}&confirm=yes");
  597. }
  598. /**
  599. * 查看项目集详情。
  600. * View program detail.
  601. *
  602. * @param int $programID
  603. * @access public
  604. * @return void
  605. */
  606. public function view($programID)
  607. {
  608. $program = $this->program->getByID($programID);
  609. if(!$program) return $this->sendError($this->lang->notFound, true);
  610. if(common::hasPriv('program', 'product')) $this->locate(inlink('product', "programID=$programID"));
  611. if(common::hasPriv('program', 'project')) $this->locate(inlink('project', "programID=$programID"));
  612. }
  613. /**
  614. * 设置显示非当前项目集的项目信息。
  615. * Set to display project information other than the current project set.
  616. *
  617. * @access public
  618. * @return void
  619. */
  620. public function ajaxSetShowSetting()
  621. {
  622. if($this->post->showAllProjects !== false) $this->loadModel('setting')->updateItem("{$this->app->user->account}.program.showAllProjects", $this->post->showAllProjects);
  623. }
  624. /**
  625. * 以产品视角查看项目集。
  626. * Show program list in product view.
  627. * copied from all() function of product module.
  628. *
  629. * @param string $browseType
  630. * @param string $orderBy
  631. * @param int $param
  632. * @param int $recTotal
  633. * @param int $recPerPage
  634. * @param int $pageID
  635. * @access public
  636. * @return void
  637. */
  638. public function productView($browseType = 'unclosed', $orderBy = 'program_asc', $param = 0, $recTotal = 0, $recPerPage = 100, $pageID = 1)
  639. {
  640. /* Load module and set session. */
  641. $this->loadModel('product');
  642. $this->loadModel('user');
  643. $this->session->set('productList', $this->app->getURI(true), 'program');
  644. $this->app->loadClass('pager', true);
  645. $pager = new pager($recTotal, $recPerPage, $pageID);
  646. /* Process product structure. */
  647. if($this->config->systemMode == 'light' and $orderBy == 'program_asc') $orderBy = 'order_asc';
  648. $products = $this->product->getList();
  649. if(strtolower($browseType) == 'bysearch')
  650. {
  651. $programs = $this->program->getListBySearch('id', (int)$param);
  652. array_map(function($product) use($programs, &$products){ if(!isset($programs[$product->program])) unset($products[$product->id]);}, $products);
  653. }
  654. $products = $this->programZen->getProductsByBrowseType($browseType, $products); /* Filter the program by browse type. */
  655. $productStats = $this->product->getStats(array_keys($products), $orderBy, $pager); /* The product stats list with program data and product data. */
  656. $productStructure = $this->product->statisticProgram($productStats);
  657. $productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll();
  658. $programLines = array();
  659. foreach($productLines as $productLine)
  660. {
  661. if(!isset($programLines[$productLine->root])) $programLines[$productLine->root] = array();
  662. $programLines[$productLine->root][$productLine->id] = $productLine->name;
  663. }
  664. $actionURL = $this->createLink('program', 'productview', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID");
  665. $this->config->program->search['actionURL'] = $actionURL;
  666. $this->loadModel('search')->setSearchParams($this->config->program->search);
  667. $this->view->title = $this->lang->product->common;
  668. $this->view->productStats = $productStats;
  669. $this->view->productStructure = $productStructure;
  670. $this->view->productLines = $productLines;
  671. $this->view->programLines = $programLines;
  672. $this->view->users = $this->user->getPairs('noletter');
  673. $this->view->orderBy = $orderBy;
  674. $this->view->browseType = $browseType;
  675. $this->view->pager = $pager;
  676. $this->view->checkedEditProduct = !empty((int)$this->cookie->checkedEditProduct);
  677. $this->view->param = $param;
  678. $this->render();
  679. }
  680. /**
  681. * 刷新项目集统计数据。
  682. * Refresh program stats.
  683. *
  684. * @access public
  685. * @return void
  686. */
  687. public function refreshStats()
  688. {
  689. $this->program->refreshStats();
  690. if(dao::isError())
  691. {
  692. echo json_encode(dao::getError());
  693. return true;
  694. }
  695. echo 'success';
  696. }
  697. }