model.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. <?php
  2. /**
  3. * The model file of weekly module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL (http://zpl.pub/page/zplv11.html)
  7. * @author Xiying Guan <guanxiying@xirangit.com>
  8. * @package weekly
  9. * @version $Id$
  10. * @link https://www.zentao.net
  11. */
  12. class weeklyModel extends model
  13. {
  14. /**
  15. * GetPageNav
  16. *
  17. * @param int $project
  18. * @param int $date
  19. * @access public
  20. * @return string
  21. */
  22. public function getPageNav($project, $date)
  23. {
  24. $date = date('Ymd', strtotime($this->getThisMonday($date)));
  25. $today = helper::today();
  26. $thisSunday = date('Ymd', strtotime($this->getThisSunday($today)));
  27. switch($project->status)
  28. {
  29. case 'wait':
  30. $begin = helper::now();
  31. $end = $begin;
  32. break;
  33. case 'doing':
  34. $begin = !helper::isZeroDate($project->realBegan) ? $project->realBegan : $date;
  35. $end = $thisSunday;
  36. break;
  37. case 'suspended':
  38. $begin = !helper::isZeroDate($project->realBegan) ? $project->realBegan : $project->suspendedDate;
  39. $end = $project->suspendedDate;
  40. break;
  41. case 'closed':
  42. $begin = !helper::isZeroDate($project->realBegan) ? $project->realBegan : $project->realEnd;
  43. $end = $project->realEnd;
  44. break;
  45. }
  46. $weeks = $this->getWeekPairs($begin, $end);
  47. $current = zget($weeks, $date, current($weeks));
  48. $selectHtml = "<div class='btn-group angle-btn'>";
  49. $selectHtml .= html::a('###', $this->lang->weekly->common . $this->lang->hyphen . $project->name, '', "class='btn'");
  50. $selectHtml .= '</div>';
  51. $selectHtml .= "<div class='btn-group angle-btn'>";
  52. $selectHtml .= "<div class='btn-group'>";
  53. $selectHtml .= "<a data-toggle='dropdown' class='btn' title=$current>" . $current . " <span class='caret'></span></a>";
  54. $selectHtml .= "<ul class='dropdown-menu'>";
  55. foreach($weeks as $day => $title)
  56. {
  57. $selectHtml .= '<li>' . html::a(helper::createLink('weekly', 'index', "project={$project->id}&date=$day"), $title) . '</li>';
  58. }
  59. $selectHtml .='</ul></div></div>';
  60. return $selectHtml;
  61. }
  62. /**
  63. * GetWeekPairs
  64. *
  65. * @param int $begin
  66. * @access public
  67. * @return array
  68. */
  69. public function getWeekPairs($begin, $end = '')
  70. {
  71. $sn = $end != '' ? $this->getWeekSN($begin, $end) : $this->getWeekSN($begin, date('Y-m-d'));
  72. $weeks = array();
  73. for($i = 0; $i < $sn; $i++)
  74. {
  75. $monday = $this->getThisMonday($begin);
  76. $sunday = $this->getThisSunday($begin);
  77. $begin = date('Y-m-d', strtotime("$begin +7 days"));
  78. $key = date('Ymd', strtotime($monday));
  79. $weeks[$key] = sprintf($this->lang->weekly->weekDesc, $i + 1, $monday, $sunday);
  80. }
  81. krsort($weeks);
  82. return $weeks;
  83. }
  84. /**
  85. * GetFromDB
  86. *
  87. * @param int $project
  88. * @param int $date
  89. * @access public
  90. * @return object
  91. */
  92. public function getFromDB($project, $date)
  93. {
  94. $monday = $this->getThisMonday($date);
  95. return $this->dao->select('*')
  96. ->from(TABLE_WEEKLYREPORT)
  97. ->where('weekStart')->eq($monday)
  98. ->andWhere('project')->eq($project)
  99. ->fetch();
  100. }
  101. /**
  102. * Save data.
  103. *
  104. * @param int $project
  105. * @param int $date
  106. * @access public
  107. * @return void
  108. */
  109. public function save($project, $date)
  110. {
  111. $weekStart = $this->getThisMonday($date);
  112. $report = new stdclass();
  113. $PVEV = $this->getPVEV($project, $date, $mode = 'new');
  114. $report->pv = $PVEV['PV'];
  115. $report->ev = $PVEV['EV'];
  116. $report->ac = $this->getAC($project, $date, $mode = 'new');
  117. $report->sv = $this->getSV($report->ev, $report->pv);
  118. $report->cv = $this->getCV($report->ev, $report->ac);
  119. $report->project = $project;
  120. $report->weekStart = $weekStart;
  121. $report->staff = $this->getStaff($project);
  122. $report->workload = json_encode($this->getWorkloadByType($project, $date));
  123. $this->dao->replace(TABLE_WEEKLYREPORT)->data($report)->exec();
  124. }
  125. /**
  126. * GetWeekSN
  127. *
  128. * @param int $begin
  129. * @param int $date
  130. * @access public
  131. * @return int
  132. */
  133. public function getWeekSN($begin, $date)
  134. {
  135. return ceil((strtotime($date) - strtotime($begin)) / 7 / 86400);
  136. }
  137. /**
  138. * Get monday for a date.
  139. *
  140. * @param int $date
  141. * @access public
  142. * @return date
  143. */
  144. public function getThisMonday($date)
  145. {
  146. $timestamp = strtotime($date);
  147. $day = date('w', $timestamp);
  148. if($day == 0) $day = 7;
  149. return date('Y-m-d', $timestamp - (($day - 1) * 24 * 3600));
  150. }
  151. /**
  152. * GetThisSunday
  153. *
  154. * @param int $date
  155. * @access public
  156. * @return date
  157. */
  158. public function getThisSunday($date)
  159. {
  160. $monday = $this->getThisMonday($date);
  161. return date('Y-m-d', strtotime($monday) + (6 * 24 * 3600));
  162. }
  163. /**
  164. * GetLastDay
  165. *
  166. * @param int $date
  167. * @access public
  168. * @return string
  169. */
  170. public function getLastDay($date)
  171. {
  172. $this->loadModel('project');
  173. $weekend = zget($this->config->project, 'weekend', 2);
  174. $monday = $this->getThisMonday($date);
  175. $sunday = $this->getThisSunday($date);
  176. $workdays = $this->loadModel('holiday')->getActualWorkingDays($monday, $sunday);
  177. return end($workdays);
  178. }
  179. /**
  180. * GetStaff
  181. *
  182. * @param int $project
  183. * @param string $date
  184. * @access public
  185. * @return array
  186. */
  187. public function getStaff($project, $date = '')
  188. {
  189. if(!$date) $date = date('Y-m-d');
  190. $monday = $this->getThisMonday($date);
  191. $sunday = $this->getThisSunday($date);
  192. $executions = $this->loadModel('execution')->getList($project, 'all', 'all', 0, 0, 0);
  193. $executionIdList = array_keys($executions);
  194. return $this->dao->select('count(distinct account) as count')
  195. ->from(TABLE_EFFORT)
  196. ->where('objectType')->eq('task')
  197. ->andWhere('execution')->in($executionIdList)
  198. ->andWhere('date')->ge($monday)
  199. ->andWhere('date')->le($sunday)
  200. ->andWhere('deleted')->eq(0)
  201. ->fetch('count');
  202. }
  203. /**
  204. * GetFinished
  205. *
  206. * @param int $project
  207. * @param string $date
  208. * @param int $pager
  209. * @access public
  210. * @return void
  211. */
  212. public function getFinished($project, $date = '', $pager = null)
  213. {
  214. if(!$date) $date = date('Y-m-d');
  215. $monday = $this->getThisMonday($date);
  216. $sunday = $this->getThisSunday($date);
  217. $executions = $this->loadModel('execution')->getList($project, 'all', $status = 'all', $limit = 0, $productID = 0, $branch = 0);
  218. $executionIdList = array_keys($executions);
  219. $tasks = $this->dao->select('*')
  220. ->from(TABLE_TASK)
  221. ->where('execution')->in($executionIdList)
  222. ->andWhere("(status = 'done' or closedReason = 'done')")
  223. ->andWhere('finishedDate')->ge($monday)
  224. ->andWhere('finishedDate')->le($sunday)
  225. ->andWhere('deleted')->eq(0)
  226. ->fetchAll();
  227. return $this->loadModel('task')->processTasks($tasks);
  228. }
  229. /**
  230. * GetPostponed
  231. *
  232. * @param int $project
  233. * @param string $date
  234. * @access public
  235. * @return void
  236. */
  237. public function getPostponed($project, $date = '')
  238. {
  239. if(!$date) $date = date('Y-m-d');
  240. $monday = $this->getThisMonday($date);
  241. $sunday = $this->getThisSunday($date);
  242. $nextMonday = date('Y-m-d', strtotime($sunday) + 24 * 3600);
  243. $executions = $this->loadModel('execution')->getList($project, 'all', $status = 'all', $limit = 0, $productID = 0, $branch = 0);
  244. $executionIdList = array_keys($executions);
  245. $unFinished = $this->dao->select('*')
  246. ->from(TABLE_TASK)
  247. ->where('execution')->in($executionIdList)
  248. ->andWhere('status')->in('wait,doing,pause')
  249. ->andWhere('deadline')->ge($monday)
  250. ->andWhere('deadline')->le($sunday)
  251. ->andWhere('deleted')->eq(0)
  252. ->fetchAll('id');
  253. $postponed = $this->dao->select('*')
  254. ->from(TABLE_TASK)
  255. ->where('execution')->in($executionIdList)
  256. ->andWhere('finishedDate')->gt($nextMonday)
  257. ->andWhere('deadline')->ge($monday)
  258. ->andWhere('deadline')->lt($nextMonday)
  259. ->andWhere('deleted')->eq(0)
  260. ->fetchAll('id');
  261. $tasks = array_merge($unFinished, $postponed);
  262. return $this->loadModel('task')->processTasks($tasks);
  263. }
  264. /**
  265. * GetTasksOfNextWeek
  266. *
  267. * @param int $project
  268. * @param string $date
  269. * @access public
  270. * @return void
  271. */
  272. public function getTasksOfNextWeek($project, $date = '')
  273. {
  274. if(!$date) $date = date('Y-m-d');
  275. $sunday = $this->getThisSunday($date);
  276. $timestamp = strtotime($sunday);
  277. $nextMonday = date('Y-m-d', $timestamp + 24 * 3600);
  278. $sencondMondy = date('Y-m-d', $timestamp + (8 * 24 * 3600));
  279. $executions = $this->loadModel('execution')->getList($project, 'all', $status = 'all', $limit = 0, $productID = 0, $branch = 0);
  280. $executionIdList = array_keys($executions);
  281. $tasks = $this->dao->select('*')
  282. ->from(TABLE_TASK)
  283. ->where('execution')->in($executionIdList)
  284. ->andWhere("((deadline >= '$nextMonday' and deadline < '$sencondMondy') or (estStarted >= '$nextMonday' and estStarted < '$sencondMondy') or (estStarted < '$nextMonday' and deadline > '$sencondMondy'))")
  285. ->andWhere('deleted')->eq(0)
  286. ->fetchAll('id');
  287. return $this->loadModel('task')->processTasks($tasks);
  288. }
  289. /**
  290. * GetWorkloadByType
  291. *
  292. * @param int $project
  293. * @param string $date
  294. * @access public
  295. * @return object
  296. */
  297. public function getWorkloadByType($project, $date = '')
  298. {
  299. if(!$date) $date = date('Y-m-d');
  300. $sunday = $this->getThisSunday($date);
  301. $timestamp = strtotime($sunday);
  302. $nextMonday = date('Y-m-d', $timestamp + 24 * 3600);
  303. $sencondMondy = date('Y-m-d', $timestamp + (8 * 24 * 3600));
  304. $executions = $this->loadModel('execution')->getList($project, 'all', $status = 'all', $limit = 0, $productID = 0, $branch = 0);
  305. $executionIdList = array_keys($executions);
  306. return $this->dao->select('type, sum(cast(estimate as decimal(10,2))) as workload')
  307. ->from(TABLE_TASK)
  308. ->where('execution')->in($executionIdList)
  309. ->andWhere('deleted')->eq(0)
  310. ->andWhere('isParent')->eq('0')
  311. ->groupBy('type')
  312. ->fetchPairs();
  313. }
  314. /**
  315. * GetPlanedTaskByWeek
  316. *
  317. * @param int $project
  318. * @param string $date
  319. * @access public
  320. * @return array
  321. */
  322. public function getPlanedTaskByWeek($project, $date = '')
  323. {
  324. if(!$date) $date = date('Y-m-d');
  325. $monday = $this->getThisMonday($date);
  326. $nextMonday = date('Y-m-d', strtotime($monday) + (7 * 24 * 3600));
  327. $executions = $this->loadModel('execution')->getList($project);
  328. $executionIdList = array_keys($executions);
  329. return $this->dao->select('*')
  330. ->from(TABLE_TASK)
  331. ->where('execution')->in($executionIdList)
  332. ->andWhere('deadline')->ge($monday)
  333. ->andWhere('deleted')->eq(0)
  334. ->fetchAll('id');
  335. }
  336. /**
  337. * Get PV and EV
  338. *
  339. * @param int $project
  340. * @param string $date
  341. * @param string $mode
  342. * @access public
  343. * @return array
  344. */
  345. public function getPVEV($projectID, $date = '', $mode = 'old')
  346. {
  347. $report = $this->getFromDB($projectID, $date);
  348. if(!empty($report) && $mode == 'old') return array('PV' => $report->pv, 'EV' => $report->ev);
  349. if(!$date) $date = date('Y-m-d');
  350. $lastDay = $this->getLastDay($date);
  351. $monday = $this->getThisMonday($date);
  352. if(empty($lastDay)) $lastDay = $monday;
  353. $executions = $this->dao->select('id,begin,end,realBegan,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($projectID)->fetchAll('id');
  354. $stmt = $this->dao->select('*')->from(TABLE_TASK)
  355. ->where('execution')->in(array_keys($executions))
  356. ->andWhere("isParent")->eq(0)
  357. ->andWhere("deleted")->eq(0)
  358. ->andWhere("status")->ne('cancel')
  359. ->query();
  360. $PV = 0;
  361. $EV = 0;
  362. $this->loadModel('holiday');
  363. while($task = $stmt->fetch())
  364. {
  365. if(empty($task->execution)) continue;
  366. $execution = $executions[$task->execution];
  367. if(helper::isZeroDate($task->estStarted)) $task->estStarted = $execution->begin;
  368. if(helper::isZeroDate($task->deadline)) $task->deadline = $execution->end;
  369. if($task->deadline <= $lastDay)
  370. {
  371. $PV += $task->estimate;
  372. }
  373. elseif($task->estStarted <= $lastDay)
  374. {
  375. $fullDays = $this->holiday->getActualWorkingDays($task->estStarted, $task->deadline);
  376. $weekActualDays = $this->holiday->getActualWorkingDays($task->estStarted, $lastDay);
  377. if(!empty($fullDays) and !empty($weekActualDays)) $PV += round(count($weekActualDays) / count($fullDays) * $task->estimate, 2);
  378. }
  379. if($task->status == 'done' or $task->closedReason == 'done')
  380. {
  381. $EV += $task->estimate;
  382. }
  383. else
  384. {
  385. $task->progress = 0;
  386. if(($task->consumed + $task->left) > 0) $task->progress = round($task->consumed / ($task->consumed + $task->left) * 100, 2);
  387. $EV += round($task->estimate * $task->progress / 100, 2);
  388. }
  389. }
  390. return array('PV' => sprintf("%.2f", $PV), 'EV' => sprintf("%.2f", $EV));
  391. }
  392. /**
  393. * Get AC data.
  394. *
  395. * @param int $project
  396. * @param string $date
  397. * @param string $mode
  398. * @access public
  399. * @return int
  400. */
  401. public function getAC($project, $date = '', $mode = 'old')
  402. {
  403. $report = $this->getFromDB($project, $date);
  404. if(!empty($report) && $mode == 'old') return $report->ac;
  405. if(!$date) $date = date('Y-m-d');
  406. $lastDay = $this->getLastDay($date);
  407. if(empty($lastDay)) $lastDay = $this->getThisMonday($date);
  408. $AC = $this->dao->select('sum(consumed) as consumed')
  409. ->from(TABLE_EFFORT)
  410. ->where('project')->eq($project)
  411. ->andWhere('date')->le($lastDay)
  412. ->andWhere('deleted')->eq(0)
  413. ->fetch('consumed');
  414. if(is_null($AC)) $AC = 0;
  415. return sprintf("%.2f", $AC);
  416. }
  417. /**
  418. * Get left.
  419. *
  420. * @param int $projectID
  421. * @param string $date
  422. * @access public
  423. * @return float
  424. */
  425. public function getLeft($projectID, $date = '')
  426. {
  427. if(!$date) $date = date('Y-m-d');
  428. $lastDay = $this->getLastDay($date);
  429. $monday = $this->getThisMonday($date);
  430. if(empty($lastDay)) $lastDay = $monday;
  431. $executions = $this->dao->select('id,begin,end,realBegan,realEnd,status')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('vision')->eq($this->config->vision)->andWhere('project')->eq($projectID)->fetchAll('id');
  432. $stmt = $this->dao->select('*')->from(TABLE_TASK)
  433. ->where('execution')->in(array_keys($executions))
  434. ->andWhere('isParent')->eq('0')
  435. ->andWhere("deleted")->eq(0)
  436. ->andWhere("status")->ne('cancel')
  437. ->query();
  438. $left = 0;
  439. while($task = $stmt->fetch())
  440. {
  441. $execution = $executions[$task->execution];
  442. if(helper::isZeroDate($task->estStarted)) $task->estStarted = $execution->begin;
  443. if(helper::isZeroDate($task->deadline)) $task->deadline = $execution->end;
  444. if($task->deadline <= $lastDay or ($task->estStarted <= $lastDay and $task->deadline > $lastDay)) $left += $task->left;
  445. }
  446. return sprintf("%.2f", $left);
  447. }
  448. /**
  449. * Get SV data.
  450. *
  451. * @param int $ev
  452. * @param int $pv
  453. * @access public
  454. * @return int
  455. */
  456. public function getSV($ev, $pv)
  457. {
  458. if($pv == 0) return 0;
  459. $sv = -1 * (1- ($ev / $pv));
  460. return sprintf("%.2f", $sv * 100);
  461. }
  462. /**
  463. * GetCV
  464. *
  465. * @param int $ev
  466. * @param int $ac
  467. * @access public
  468. * @return int
  469. */
  470. public function getCV($ev, $ac)
  471. {
  472. if($ac == 0) return 0;
  473. $cv = -1 * (1 - ($ev / $ac));
  474. return sprintf("%.2f", $cv * 100);
  475. }
  476. /**
  477. * GetTips
  478. *
  479. * @param string $type
  480. * @param int $data
  481. * @access public
  482. * @return string
  483. */
  484. public function getTips($type = 'progress', $data = 0)
  485. {
  486. $this->app->loadConfig('custom');
  487. if($type == 'progress') $tipsConfig = isset($this->config->custom->SV->progressTip) ? $this->config->custom->SV->progressTip : '';
  488. if($type == 'cost') $tipsConfig = isset($this->config->custom->CV->costTip) ? $this->config->custom->CV->costTip : '';
  489. if(empty($tipsConfig)) return '';
  490. $tipsConfig = json_decode($tipsConfig);
  491. $data = (float)$data;
  492. foreach($tipsConfig as $tipConfig)
  493. {
  494. if((float)$tipConfig->min <= $data and (float)$tipConfig->max >= $data) return $tipConfig->tip;
  495. }
  496. return '';
  497. }
  498. /**
  499. * Get report data.
  500. *
  501. * @param int $projectID
  502. * @param string $date
  503. * @param bool $loadMaster
  504. * @access public
  505. * @return stdclass
  506. */
  507. public function getReportData($projectID = 0, $date = '', $loadMaster = false)
  508. {
  509. $data = new stdclass();
  510. $PVEV = $this->getPVEV($projectID, $date);
  511. $data->pv = (float)$PVEV['PV'];
  512. $data->ev = (float)$PVEV['EV'];
  513. $data->ac = (float)$this->getAC($projectID, $date);
  514. $data->sv = $this->getSV($data->ev, $data->pv);
  515. $data->cv = $this->getCV($data->ev, $data->ac);
  516. $data->project = $this->loadModel('project')->getByID($projectID);
  517. $data->weekSN = $this->getWeekSN($data->project->begin, $date);
  518. $data->monday = $this->getThisMonday($date);
  519. $data->lastDay = $this->getThisSunday($date);
  520. $data->staff = $this->getStaff($projectID, $date);
  521. $data->finished = $this->getFinished($projectID, $date);
  522. $data->postponed = $this->getPostponed($projectID, $date);
  523. $data->nextWeek = $this->getTasksOfNextWeek($projectID, $date);
  524. $data->workload = $this->getWorkloadByType($projectID, $date);
  525. $data->progress = $this->getTips('progress', $data->sv) . '<br/>' . $this->getTips('cost', $data->cv);
  526. if($loadMaster)
  527. {
  528. $data->users = $this->loadModel('user')->getPairs('noletter');
  529. $data->master = zget($data->users, $data->project->PM, '');
  530. }
  531. return $data;
  532. }
  533. /**
  534. * 添加内置项目周报模板。
  535. * Add builtin project weekly report template.
  536. *
  537. * @access public
  538. * @return bool
  539. */
  540. public function addBuiltinWeeklyTemplate()
  541. {
  542. /* Set scope data. */
  543. $scopeID = $this->addBuiltinScope();
  544. if(!$scopeID) return false;
  545. /* Set category data. */
  546. $categoryID = $this->addBuiltinCategory($scopeID);
  547. /* Set docblock data. */
  548. $blockIdList = array();
  549. $docBlock = new stdclass();
  550. foreach($this->config->weekly->charts as $chartKey => $chartContent)
  551. {
  552. $docBlock->type = $chartKey;
  553. $docBlock->content = json_encode($chartContent);
  554. $this->dao->insert(TABLE_DOCBLOCK)->data($docBlock)->exec();
  555. $blockIdList[$chartKey] = $this->dao->lastInsertId();
  556. }
  557. /* Set template data. */
  558. $this->addBuiltinTemplate($scopeID, $categoryID, $blockIdList);
  559. return !dao::isError();
  560. }
  561. /**
  562. * 添加内置报告模板范围。
  563. * Add builtin report template scope.
  564. *
  565. * @access public
  566. * @return int|bool
  567. */
  568. public function addBuiltinScope()
  569. {
  570. $scope = $this->dao->select('id')->from(TABLE_DOCLIB)->where('type')->eq('reportTemplate')->andWhere('main')->eq(1)->andWhere('vision')->eq($this->config->vision)->fetch();
  571. if($scope) return $scope->id;
  572. $this->loadModel('setting');
  573. /* Set scope data. */
  574. $scope = new stdClass();
  575. $scope->type = 'reportTemplate';
  576. $scope->main = '1';
  577. $scope->vision = $this->config->vision;
  578. $scope->addedBy = 'system';
  579. $scope->addedDate = helper::now();
  580. foreach($this->lang->weekly->builtInScopes as $vision => $scopeList)
  581. {
  582. $scopeMaps = array();
  583. $scope->vision = $vision;
  584. foreach($scopeList as $scopeKey => $scopeName)
  585. {
  586. if(empty($scopeName)) continue;
  587. $scope->name = $scopeName;
  588. $this->dao->insert(TABLE_DOCLIB)->data($scope)->exec();
  589. $scopeMaps[$scopeKey] = $this->dao->lastInsertID();
  590. }
  591. if(!empty($scopeMaps)) $this->setting->setItem("system.reporttemplate.builtInScopeMaps@{$vision}", json_encode($scopeMaps));
  592. }
  593. return array_pop($scopeMaps);
  594. }
  595. /**
  596. * 添加内置报告模板分类。
  597. * Add builtin report template category.
  598. *
  599. * @param int $scopeID
  600. * @access public
  601. * @return int
  602. */
  603. public function addBuiltinCategory($scopeID)
  604. {
  605. /* Set category data. */
  606. $category = new stdClass();
  607. $category->root = $scopeID;
  608. $category->name = $this->lang->projectCommon;
  609. $category->grade = 1;
  610. $category->type = 'reportTemplate';
  611. $this->dao->insert(TABLE_MODULE)->data($category)->exec();
  612. $categoryID = $this->dao->lastInsertID();
  613. $this->dao->update(TABLE_MODULE)->set('`path`')->eq(",{$categoryID},")->where('id')->eq($categoryID)->exec();
  614. return $categoryID;
  615. }
  616. /**
  617. * 添加内置报告模板。
  618. * Add builtin report template.
  619. *
  620. * @param int $libID
  621. * @param int $moduleID
  622. * @param array $blockIdList
  623. * @access public
  624. * @return bool
  625. */
  626. public function addBuiltinTemplate($libID, $moduleID, $blockIdList)
  627. {
  628. $now = helper::now();
  629. $cycleConfig = array('turnon' => 'on', 'frequency' => 'week', 'acl' => 'open', 'readGroups' => '', 'readUsers' => '', 'groups' => '', 'users' => '');
  630. $objects = $this->dao->select('id')->from(TABLE_WORKFLOWGROUP)->where('type')->eq('project')->andWhere('projectModel')->in('waterfall,waterfallplus,ipd')->andWhere('status')->eq('normal')->andWhere('vision')->eq($this->config->vision)->andWhere('objectID')->eq(0)->andWhere('deleted')->eq(0)->fetchPairs('id');
  631. $template = new stdclass();
  632. $template->lib = $libID;
  633. $template->module = $moduleID;
  634. $template->title = $this->lang->weekly->projectTemplate;
  635. $template->type = 'text';
  636. $template->status = 'normal';
  637. $template->acl = 'open';
  638. $template->builtIn = 1;
  639. $template->templateType = 'reportTemplate';
  640. $template->templateDesc = $this->lang->weekly->builtinDesc;
  641. $template->cycle = 'week';
  642. $template->cycleConfig = json_encode($cycleConfig);
  643. $template->objects = ',' . implode(',', $objects) . ',';
  644. $template->addedBy = 'system';
  645. $template->addedDate = $now;
  646. $this->dao->insert(TABLE_DOC)->data($template)->exec();
  647. $templateID = $this->dao->lastInsertID();
  648. $this->dao->update(TABLE_DOC)->set('`path`')->eq(",{$templateID},")->set('`order`')->eq($templateID)->where('id')->eq($templateID)->exec();
  649. $this->dao->update(TABLE_DOCBLOCK)->set('doc')->eq($templateID)->where('id')->in(array_values($blockIdList))->exec();
  650. $templateContent = new stdclass();
  651. $templateContent->doc = $templateID;
  652. $templateContent->title = $template->title;
  653. $templateContent->type = 'doc';
  654. $templateContent->version = 1;
  655. $templateContent->rawContent = $this->getBuildinRawContent($blockIdList);
  656. $templateContent->addedBy = 'system';
  657. $templateContent->addedDate = $now;
  658. $this->dao->insert(TABLE_DOCCONTENT)->data($templateContent)->exec();
  659. $this->loadModel('action')->create('reportTemplate', $templateID, 'Created', '', '', 'system');
  660. return !dao::isError();
  661. }
  662. /**
  663. * 获取内置项目周报模板内容。
  664. * Get builtin project weekly report template content.
  665. *
  666. * @param array $blockIdList
  667. * @access public
  668. * @return string
  669. */
  670. public function getBuildinRawContent($blockIdList)
  671. {
  672. global $oldRequestType;
  673. if(!empty($oldRequestType) && $oldRequestType == 'PATH_INFO') $this->config->requestType = 'PATH_INFO';
  674. $blockCodes = array();
  675. foreach($blockIdList as $blockKey => $blockID) $blockCodes[] = '{' . $blockKey . '}';
  676. $rawContent = json_decode($this->lang->weekly->builtinRawContent);
  677. foreach($rawContent as $content)
  678. {
  679. if(isset($content->id)) $content->id = uniqid();
  680. if(isset($content->createDate)) $content->createDate = time();
  681. if(empty($content->children)) continue;
  682. foreach($content->children as $childList)
  683. {
  684. if(isset($childList->id)) $childList->id = uniqid();
  685. if(empty($childList->children)) continue;
  686. foreach($childList->children as $child)
  687. {
  688. if(isset($child->id)) $child->id = uniqid();
  689. if(!empty($child->props->text->delta))
  690. {
  691. foreach($child->props->text->delta as $delta)
  692. {
  693. if(isset($delta->attributes->holder->id)) $delta->attributes->holder->id = uniqid();
  694. if(isset($delta->attributes->holder->name) && isset($blockIdList[$delta->attributes->holder->name])) $delta->attributes->holder->name = "{$delta->attributes->holder->name}_{$blockIdList[$delta->attributes->holder->name]}";
  695. if(isset($delta->attributes->holder->data->blockID) && isset($blockIdList[$delta->attributes->holder->data->type])) $delta->attributes->holder->data->blockID = $blockIdList[$delta->attributes->holder->data->type];
  696. }
  697. }
  698. if(!empty($child->props->content))
  699. {
  700. if(!empty($child->props->content->fetcher[0]))
  701. {
  702. $fetcher = $child->props->content->fetcher[0];
  703. $fetcher->params = str_replace($blockCodes, array_values($blockIdList), $fetcher->params);
  704. $fetcherLink = helper::createLink($fetcher->module, $fetcher->method, $fetcher->params);
  705. $fetcherLink = str_replace(array('install.php', 'upgrade.php'), 'index.php', $fetcherLink);
  706. $child->props->content->fetcher = "{$fetcherLink}";
  707. }
  708. if(isset($child->props->content->exportUrl)) $child->props->content->exportUrl = str_replace($blockCodes, array_values($blockIdList), $child->props->content->exportUrl);
  709. }
  710. }
  711. }
  712. }
  713. if(!empty($oldRequestType) && $oldRequestType == 'PATH_INFO') $this->config->requestType = 'GET';
  714. return json_encode($rawContent);
  715. }
  716. }