calendar.html.php 19 KB

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