calendar.html.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. /**
  3. * The view file of my module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2012 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license business(商业软件)
  7. * @author Yangyang Shi <shiyangyang@cnezsoft.com>
  8. * @package calendar
  9. * @version $Id$
  10. * @link http://www.zentao.net
  11. */
  12. ?>
  13. <?php include $app->getModuleRoot() . 'common/view/header.html.php';?>
  14. <?php include '../../../common/ext/view/calendar.html.php';?>
  15. <?php js::set('moreLang', $this->lang->side->more);?>
  16. <?php js::set('originObject', 'taskTotal');?>
  17. <?php js::set('moduleList', $config->todo->moduleList);?>
  18. <?php $isEn = $app->getClientLang() == 'en';?>
  19. <div id="mainMenu" class="clearfix">
  20. <div class="btn-toolbar pull-left">
  21. <?php echo html::a('#', $lang->todo->todoCalendar, '', "class='btn btn-link'");?>
  22. </div>
  23. <div class="btn-toolbar pull-right">
  24. <?php if(common::hasPriv('my', 'todo')):?>
  25. <div class="btn-group panel-actions">
  26. <?php echo html::a(helper::createLink('todo', 'calendar'), "<i class='icon-cards-view'></i> &nbsp;", '', "class='btn btn-icon text-primary' title='{$lang->todo->calendar}' id='switchButton'");?>
  27. <?php echo html::a(helper::createLink('my', 'todo', "type=all"), "<i class='icon-list'></i> &nbsp;", '', "class='btn btn-icon' title='{$lang->todo->list}' id='switchButton'");?>
  28. </div>
  29. <?php endif;?>
  30. <?php if(common::hasPriv('todo', 'export')) echo html::a('javascript:exportCalendar("' . helper::createLink('todo', 'export', "userID={$this->app->user->id}&orderBy=id_desc&date=_date_") . '")', "<i class='icon-export muted'> </i> " . $lang->todo->export, '', "class='btn btn-link'");?>
  31. <?php if(common::hasPriv('todo', 'create') or common::hasPriv('todo', 'batchCreate')):?>
  32. <div class='btn-group dropdown'>
  33. <?php common::printLink('todo', common::hasPriv('todo', 'create') ? 'create' : 'batchCreate', '', "<i class='icon icon-plus'></i> " . (common::hasPriv('todo', 'create') ? $lang->todo->create : $lang->todo->batchCreate), '', "id='create' class='btn btn-primary iframe' data-width='80%' data-app='my'", '', true);?>
  34. <?php if(common::hasPriv('todo', 'create') and common::hasPriv('todo', 'batchCreate')):?>
  35. <button type='button' class='btn btn-primary dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
  36. <ul class='dropdown-menu pull-right'>
  37. <li><?php echo html::a($this->createLink('todo', 'create', '', '', true), $lang->todo->create, '', "class='iframe' data-width='80%'");?></li>
  38. <li><?php echo html::a($this->createLink('todo', 'batchCreate', '', '', true), $lang->todo->batchCreate, '', "class='iframe' data-width='80%'");?></li>
  39. </ul>
  40. <?php endif;?>
  41. </div>
  42. <?php endif;?>
  43. </div>
  44. </div>
  45. <div class="main-row">
  46. <div class="main-col">
  47. <div class="cell">
  48. <div id="todoCalendar" class="calendar">
  49. <header class="calender-header table-row">
  50. <div class="btn-toolbar col-4 table-col text-middle">
  51. <button type="button" class="btn btn-info btn-mini btn-today"><?php echo $lang->today;?></button>
  52. <button type="button" class="btn btn-info btn-icon btn-mini btn-prev"><i class="icon-chevron-left"></i></button>
  53. <span id='date' class="calendar-caption"></span>
  54. <button type="button" class="btn btn-info btn-icon btn-mini btn-next"><i class="icon-chevron-right"></i></button>
  55. </div>
  56. </header>
  57. </div>
  58. </div>
  59. </div>
  60. <div class="side-col" id="sidebar">
  61. <div class="sidebar-toggle" style='left: 5px;'><i class="icon icon-angle-right"></i></div>
  62. <div class="cell">
  63. <ul class="nav nav-secondary nav-justified">
  64. <li class="active"><a href="#tab_task" data-toggle='tab' class="object-calendar"><?php echo $lang->side->task?><span class="label label-light label-badge label-todo" id="<?php echo 'taskTotal';?>" data-object="<?php echo 'task';?>"><?php echo count($todoList['task']);?></span></a></li>
  65. <?php $index = 1;?>
  66. <?php $objects = array('task');?>
  67. <?php $noEmptyObjects = array();?>
  68. <?php $showNum = $isEn ? 2 : 3;?>
  69. <?php foreach($todoList as $type => $todoSides):?>
  70. <?php if($type == 'task') continue;?>
  71. <?php if(!empty($todoSides) && $index < $showNum):?>
  72. <li><a href="#tab_<?php echo $type;?>" data-toggle='tab' class="object-calendar"><?php echo $lang->side->$type?><span class="label label-light label-badge label-todo hidden" id="<?php echo $type . 'Total';?>" data-object="<?php echo $type;?>"><?php echo count($todoList[$type]);?></span></a></li>
  73. <?php $objects[] = $type;?>
  74. <?php endif;?>
  75. <?php
  76. if(!empty($todoSides))
  77. {
  78. $noEmptyObjects[$type] = count($todoSides);
  79. $index++;
  80. }
  81. ?>
  82. <?php endforeach;?>
  83. <?php if(count($noEmptyObjects) == $showNum):?>
  84. <?php $objectTypes = array_keys($noEmptyObjects);?>
  85. <?php $lastObjectType = end($objectTypes);?>
  86. <li><a href="#tab_<?php echo $lastObjectType;?>" data-toggle='tab' class="object-calendar"><?php echo $lang->side->$lastObjectType?><span class="label label-light label-badge label-todo hidden" id="<?php echo $lastObjectType . 'Total';?>" data-object="<?php echo $lastObjectType;?>"><?php echo count($todoList[$lastObjectType]);?></span></a></li>
  87. <?php elseif($index >= $showNum + 1):?>
  88. <li id="tabMore">
  89. <a href="#tab_more" class="dropdown-toggle" data-toggle="dropdown" id="more"><?php echo $lang->side->more?><span class="caret"></span></a>
  90. <ul class="dropdown-menu pull-right" id="tabList">
  91. <?php foreach($todoList as $type => $todoSides):?>
  92. <?php if(in_array($type, $objects) || empty($todoSides)) continue;?>
  93. <li><a href="#tab_<?php echo $type;?>" data-toggle='tab' class="more-calendar" id="<?php echo $type . 'Total';?>" data-object="<?php echo $type;?>"><?php echo $lang->side->$type?></a></li>
  94. <?php endforeach;?>
  95. </ul>
  96. </li>
  97. <?php endif;?>
  98. </ul>
  99. <div class='tab-content' id="todoLists">
  100. <?php if(!empty($todoList)):?>
  101. <?php foreach($todoList as $type => $todoSides):?>
  102. <div class='tab-pane fade <?php if($type == 'task') echo 'active in';?>' id='tab_<?php echo $type;?>'>
  103. <?php if(!empty($todoSides)):?>
  104. <ul class='todo-list'>
  105. <?php $i = 1;?>
  106. <?php foreach($todoSides as $id => $todo):?>
  107. <?php $projectID = isset($todoProjects[$type][$id]) ? $todoProjects[$type][$id] : 0;?>
  108. <?php if($type == 'task') $type = $this->config->vision == 'or' ? 'researchtask' : $type;?>
  109. <?php $method = $type == 'feedback' ? 'adminView' : 'view';?>
  110. <li data-index='<?php echo $i++;?>'>
  111. <?php $class = common::hasPriv('todo', 'create') ? 'todo-item' : 'todoList'?>
  112. <?php echo html::a($this->createLink($type, $method, "id=$id", 'html', true), $todo, '', "class='iframe $class' data-id='{$id}' data-type='{$type}' data-title='{$todo}' title='{$todo}' data-width='90%'");?>
  113. </li>
  114. <?php endforeach;?>
  115. </ul>
  116. <?php endif;?>
  117. </div>
  118. <?php endforeach;?>
  119. <?php endif;?>
  120. </div>
  121. </div>
  122. </div>
  123. </div>
  124. <script>
  125. config.ajaxGetTodosUrl = '<?php echo $this->createLink('todo', 'ajaxGetTodos', "userID={$this->app->user->id}&year={year}");?>';
  126. config.ajaxChangeDaysUrl = '<?php echo $this->createLink('todo', 'ajaxChangeDays', 'id={id}&date={date}');?>';
  127. config.ajaxFinishUrl = '<?php echo $this->createLink('todo', 'finish', 'id={id}');?>';
  128. config.ajaxActivateUrl = '<?php echo $this->createLink('todo', 'activate', 'id={id}');?>';
  129. config.todoCreateUrl = '<?php echo $this->createLink('todo', 'create', '', 'json');?>';
  130. config.todoViewUrl = '<?php echo $this->createLink('todo', 'view', 'id={id}', '', true);?>';
  131. config.batchAddUrl = '<?php echo $this->createLink('todo', 'batchCreate', 'date={date}', '', true);?>';
  132. config.userAccount = '<?php echo $this->app->user->account;?>';
  133. config.textNetworkError = '<?php echo $lang->textNetworkError;?>';
  134. config.textHasMoreItems = '<?php echo $lang->textHasMoreItems;?>';
  135. </script>
  136. <script>
  137. var todoModalTrigger = new $.zui.ModalTrigger(
  138. {
  139. width: '70%',
  140. type: 'iframe',
  141. rememberPos: 'todoViewModal',
  142. waittime: 5000
  143. });
  144. var batchAddModalTrigger = new $.zui.ModalTrigger(
  145. {
  146. width: '80%',
  147. type: 'iframe',
  148. waittime: 5000
  149. });
  150. var displayDate = 0;
  151. var calendar = false;
  152. $(function()
  153. {
  154. var expandedDays = {};
  155. var minExpandCount = 6;
  156. var $calendar = $('#todoCalendar');
  157. var toggleLoading = function(loading)
  158. {
  159. $calendar.toggleClass('loading', !!loading);
  160. };
  161. calendar = $calendar.calendar(
  162. {
  163. hideEmptyWeekends: true,
  164. data:
  165. {
  166. events: [],
  167. calendars:
  168. {
  169. defaultCal: {color: '#fff'}
  170. }
  171. },
  172. beforeDisplay: function(display, doDisplay) {
  173. var date = display.date;
  174. var thisDisplayDate = date.getFullYear();
  175. if(displayDate === thisDisplayDate)
  176. {
  177. return doDisplay();
  178. }
  179. else
  180. {
  181. displayDate = thisDisplayDate;
  182. }
  183. var calendar = this;
  184. toggleLoading(true);
  185. $.ajax(
  186. {
  187. url: config.ajaxGetTodosUrl.replace('{year}', date.getFullYear()),
  188. dataType: 'json',
  189. success: function(data)
  190. {
  191. $.each(data, function(index, todo)
  192. {
  193. todo.finish = todo.status === 'done' || todo.status === 'closed';
  194. todo.allDay = !todo.end;
  195. });
  196. calendar.resetData({events: data});
  197. doDisplay();
  198. },
  199. error: function()
  200. {
  201. $.zui.messager.danger(config.textNetworkError);
  202. },
  203. complete: function() {toggleLoading(false);}
  204. });
  205. return false;
  206. },
  207. eventCreator: function(event, $cell, calendar)
  208. {
  209. var pri = event.pri != '' ? '(' + event.pri + ')' : '';
  210. var $event = $('<div title="' + pri + event.title + '" data-id="' + (event.id || '') + '" class="event">' + (event.finish ? '<i class="icon todo-check icon-check-circle"></i>' : '<i class="icon todo-check icon-check-circle-empty"></i>') + '<span class="title">' + pri + event.title + '</span>' + (event.allDay ? '' : '<span class="time">' + event.start.format('hh:mm') + '</span>') + '</div>');
  211. $event.toggleClass('has-time', !event.allDay)
  212. .toggleClass('expired', !event.finish && !$cell.hasClass('future'));
  213. return $event;
  214. },
  215. dayFormater: function($cell, date, dayEvents, calendar)
  216. {
  217. if(dayEvents && dayEvents.maxPos >= minExpandCount)
  218. {
  219. var hideManyEvents = !expandedDays[date.toDateString()];
  220. $cell.toggleClass('hide-many-events', hideManyEvents);
  221. if(hideManyEvents)
  222. {
  223. var $cellContent = $cell.find('.day > .content');
  224. var $showMore = $cellContent.find('.show-more-events');
  225. if(!$showMore.length)
  226. {
  227. $showMore = $('<div class="show-more-events" />').appendTo($cellContent);
  228. }
  229. else
  230. {
  231. $showMore.show();
  232. }
  233. $showMore.text(config.textHasMoreItems.format(dayEvents.maxPos - minExpandCount + 1));
  234. }
  235. }
  236. else
  237. {
  238. $cell.removeClass('hide-many-events');
  239. }
  240. if($cell.is('.future')) $cell.addClass('with-plus-sign');
  241. },
  242. beforeChange: function(change)
  243. {
  244. toggleLoading(true);
  245. $.ajax(
  246. {
  247. url: config.ajaxChangeDaysUrl.replace('{id}', change.event.id).replace('{date}', change.to.getTime()),
  248. error: function()
  249. {
  250. $.zui.messager.danger(config.textNetworkError);
  251. calendar.display();
  252. },
  253. complete: function() {toggleLoading(false);}
  254. });
  255. displayDate = 0;
  256. this.display();
  257. },
  258. eventSorter: function(a, b)
  259. {
  260. var result = (a.finish ? 1 : 0) - (b.finish ? 1 : 0);
  261. if(result === 0) result = (a.allDay ? (-1) : 0) - (b.allDay ? (-1) : 0);
  262. if(result === 0) result = a.start - b.start;
  263. if(result === 0) return a.id - b.id;
  264. return result;
  265. }
  266. }).data('zui.calendar');
  267. $calendar.on('click', '.show-more-events', function(e)
  268. {
  269. var $cell = $(this).hide().closest('.cell-day');
  270. $cell.removeClass('hide-many-events');
  271. expandedDays[$cell.find('.day').attr('data-date')] = true;
  272. e.stopPropagation();
  273. }).on('click', '.event', function(e)
  274. {
  275. var event = $(this).data('event');
  276. todoModalTrigger.show({url: config.todoViewUrl.replace('{id}', event.id)});
  277. e.stopPropagation();
  278. }).on('click', '.day', function(e)
  279. {
  280. var $day = $(this);
  281. if($day.parent().hasClass('future')) batchAddModalTrigger.show({url: config.batchAddUrl.replace('{date}', $day.data('date').format('yyyyMMdd')), showHeader:false});
  282. e.stopPropagation();
  283. }).on('click', '.todo-check', function(e)
  284. {
  285. // 当点击日历待办勾选框时
  286. var $event = $(this).closest('.event');
  287. var event = $event.data('event');
  288. toggleLoading(true);
  289. var actionUrl = event.finish ? config.ajaxActivateUrl : config.ajaxFinishUrl;
  290. $.ajax({
  291. url: actionUrl.replace('{id}', event.id),
  292. success: function(data)
  293. {
  294. event.finish = !event.finish;
  295. data = jQuery.parseJSON(data);
  296. if(actionUrl == config.ajaxFinishUrl && $.isPlainObject(data['load']))
  297. {
  298. if(confirm(data['load']['confirm']) == true) window.$.apps.openApp(data['load']['confirmed']['url'], data['load']['confirmed']['app']);
  299. }
  300. calendar.display();
  301. },
  302. error: function()
  303. {
  304. $.zui.messager.danger(config.textNetworkError);
  305. calendar.display();
  306. },
  307. complete: function() {toggleLoading(false);}
  308. });
  309. displayDate = 0;
  310. e.preventDefault();
  311. e.stopPropagation();
  312. });
  313. $('#todoLists').droppable(
  314. {
  315. selector: '.todo-item',
  316. target: function()
  317. {
  318. return $calendar.find('.cell-day');
  319. },
  320. before: function()
  321. {
  322. $calendar.addClass('event-dragging');
  323. },
  324. always: function()
  325. {
  326. $calendar.removeClass('event-dragging');
  327. },
  328. drop: function(e)
  329. {
  330. var $item = $(e.element);
  331. var $day = $(e.target).children('.day');
  332. var date = $day.data('date');
  333. var item = $item.data();
  334. var $li = $item.parent();
  335. var finish = $li.hasClass('active');
  336. var todoEvent = {
  337. id: item.id,
  338. title: item.title,
  339. start: date,
  340. end: null,
  341. finish: finish,
  342. status: finish ? 'done' : 'wait',
  343. allDay: true
  344. };
  345. if(item.type === 'todo')
  346. {
  347. $.ajax(
  348. {
  349. url: config.ajaxChangeDaysUrl.replace('{id}', item.id).replace('{date}', date.getTime()),
  350. error: function()
  351. {
  352. $.zui.messager.danger(config.textNetworkError);
  353. calendar.display();
  354. },
  355. success: function() {
  356. calendar.addEvents([todoEvent]);
  357. $li.remove();
  358. },
  359. complete: function() {toggleLoading(false);}
  360. });
  361. }
  362. else if(moduleList.indexOf(item.type) !== -1)
  363. {
  364. $.ajax(
  365. {
  366. type: 'POST',
  367. dataType: 'json',
  368. url: config.todoCreateUrl,
  369. data: {
  370. date: date.format('yyyy-MM-dd'),
  371. type: item.type,
  372. objectID: item.id,
  373. name: item.title,
  374. begin: '',
  375. end: '',
  376. pri: 3,
  377. status: 'wait',
  378. },
  379. error: function()
  380. {
  381. $.zui.messager.danger(config.textNetworkError);
  382. calendar.display();
  383. },
  384. success: function() {
  385. calendar.addEvents([todoEvent]);
  386. $li.remove();
  387. /* After adding the to-do, refresh the number. */
  388. var objectClass = $('#' + item.type + 'Total').attr('class');
  389. if(objectClass == 'more-calendar')
  390. {
  391. $('#' + item.type + 'Total').click();
  392. }
  393. else
  394. {
  395. var todoTotal = $('#tab_' + item.type).find('ul').children('li').length;
  396. $('#' + item.type + 'Total').text(todoTotal);
  397. }
  398. },
  399. complete: function() {toggleLoading(false);}
  400. });
  401. }
  402. displayDate = 0;
  403. }
  404. })
  405. $('#batchCreate').click(function(e)
  406. {
  407. batchAddModalTrigger.show({url: $(this).attr('href'), showHeader:false});
  408. return false;
  409. })
  410. $('.pull-left .btn-link').click(function()
  411. {
  412. $(this).css('background', 'unset');
  413. })
  414. addPager('#tab_task');
  415. addPager('#tab_story');
  416. addPager('#tab_bug');
  417. addPager('#tab_issue');
  418. addPager('#tab_risk');
  419. addPager('#tab_opportunity');
  420. addPager('#tab_review');
  421. addPager('#tab_testtask');
  422. });
  423. /*
  424. $.extend({'closeModal':function(callback, location)
  425. {
  426. batchAddModalTrigger.close();
  427. if(callback && $.isFunction(callback)) callback();
  428. }});
  429. */
  430. function addPager(selecter)
  431. {
  432. var preNum = 15;
  433. var tab = $(selecter);
  434. var count = tab.find('li').length;
  435. var page = Math.ceil(count / preNum);
  436. if(page > 1)
  437. {
  438. for(i = page; i > 0; i--)
  439. {
  440. tab.append("<span class='page-num btn' data-id='" + i + "'>" + i + '</span>')
  441. }
  442. $(selecter + ' span.page-num').click(function()
  443. {
  444. var tab = $(this).parent();
  445. var page = $(this).data('id');
  446. tab.find('.page-num').removeClass('active');
  447. $(this).addClass('active');
  448. page = parseInt(page) * preNum;
  449. tab.find('li').hide();
  450. for(i = page; i > page - preNum; i--)
  451. {
  452. var item = tab.find('[data-index=' + i + ']');
  453. if(item.prop('data-remove') != '1') item.show();
  454. }
  455. });
  456. $(selecter + ' span.page-num[data-id=1]').click();
  457. }
  458. }
  459. /**
  460. * Get the to-do list under the object.
  461. *
  462. * @access public
  463. * @return void
  464. */
  465. $(".object-calendar").click(function()
  466. {
  467. $('#' + originObject).addClass('hidden');
  468. if(originObject != objectId)
  469. {
  470. var objectId = $(this).find('span').attr('id');
  471. $('#' + objectId).removeClass('hidden');
  472. originObject = objectId;
  473. }
  474. var object = $(this).find('span').attr('data-object');
  475. var todoTotal = $('#tab_' + object).find('ul').children('li').length;
  476. $(this).find('span').text(todoTotal);
  477. var moreLink = '<a href="#tab_more" class="dropdown-toggle" data-toggle="dropdown" id="more">' + moreLang + '<span class="caret"></span></a>';
  478. $("#more").replaceWith(moreLink);
  479. });
  480. /**
  481. * Choose to do objects from more menu.
  482. *
  483. * @access public
  484. * @return void
  485. */
  486. $(".more-calendar").click(function()
  487. {
  488. $("#tabList").children('li').removeAttr('class');
  489. setTimeout("selectMore()", 150);
  490. $('#' + originObject).addClass('hidden');
  491. });
  492. function selectMore(){$("#tabMore").attr("class" , 'active')}
  493. </script>
  494. <?php include $app->getModuleRoot() . 'common/view/footer.html.php';?>