You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1154 lines
49 KiB

  1. /*
  2. * 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架(http://www.learun.cn)
  3. * Copyright (c) 2013-2018 上海力软信息技术有限公司
  4. * 创建人:力软-前端开发组
  5. * 日 期:2018.11.22
  6. * 描 述:甘特图
  7. */
  8. (function ($, learun) {
  9. "use strict";
  10. //+---------------------------------------------------
  11. //| 日期计算
  12. //+---------------------------------------------------
  13. Date.prototype.DateAdd = function (strInterval, Number) {
  14. var dtTmp = this;
  15. switch (strInterval) {
  16. case 's': return new Date(Date.parse(dtTmp) + (1000 * Number));// 秒
  17. case 'n': return new Date(Date.parse(dtTmp) + (60000 * Number));// 分
  18. case 'h': return new Date(Date.parse(dtTmp) + (3600000 * Number));// 小时
  19. case 'd': return new Date(Date.parse(dtTmp) + (86400000 * Number));// 天
  20. case 'w': return new Date(Date.parse(dtTmp) + ((86400000 * 7) * Number));// 星期
  21. case 'q': return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + Number * 3, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds());// 季度
  22. case 'm': return new Date(dtTmp.getFullYear(), (dtTmp.getMonth()) + Number, dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds());// 月
  23. case 'y': return new Date((dtTmp.getFullYear() + Number), dtTmp.getMonth(), dtTmp.getDate(), dtTmp.getHours(), dtTmp.getMinutes(), dtTmp.getSeconds());// 年
  24. }
  25. }
  26. //+---------------------------------------------------
  27. //| 比较日期差 dtEnd 格式为日期型或者 有效日期格式字符串
  28. //+---------------------------------------------------
  29. Date.prototype.DateDiff = function (strInterval, dtEnd) {
  30. var dtStart = this;
  31. if (typeof dtEnd == 'string')//如果是字符串转换为日期型
  32. {
  33. dtEnd = learun.parseDate(dtEnd);
  34. }
  35. switch (strInterval) {
  36. case 's': return parseInt((dtEnd - dtStart) / 1000);
  37. case 'n': return parseInt((dtEnd - dtStart) / 60000);
  38. case 'h': return parseInt((dtEnd - dtStart) / 3600000);
  39. case 'd': return parseInt((dtEnd - dtStart) / 86400000);
  40. case 'w': return parseInt((dtEnd - dtStart) / (86400000 * 7));
  41. case 'm': return (dtEnd.getMonth() + 1) + ((dtEnd.getFullYear() - dtStart.getFullYear()) * 12) - (dtStart.getMonth() + 1);
  42. case 'y': return dtEnd.getFullYear() - dtStart.getFullYear();
  43. }
  44. }
  45. //+---------------------------------------------------
  46. //| 取得当前日期所在月的最大天数
  47. //+---------------------------------------------------
  48. Date.prototype.MaxDayOfDate = function () {
  49. var myDate = this;
  50. var date1 = learun.parseDate(learun.formatDate(myDate, 'yyyy-MM-01 00:00:00'));
  51. var date2 = date1.DateAdd('m', 1);
  52. var result = date1.DateDiff('d', date2);
  53. return result;
  54. }
  55. //---------------------------------------------------
  56. // 判断闰年
  57. //---------------------------------------------------
  58. Date.prototype.isLeapYear = function () {
  59. return (0 == this.getYear() % 4 && ((this.getYear() % 100 != 0) || (this.getYear() % 400 == 0)));
  60. }
  61. var _gantt = {
  62. init: function ($self, op) {
  63. $self.addClass('lr-gantt');
  64. var $title = $('<div class="lr-gantt-title">\
  65. <div class="lr-gantt-title-text" >时间维度:</div>\
  66. <div class="btn-group btn-group-sm" >\
  67. </div>\
  68. </div>');
  69. $.each(op.timebtns, function (_index, _item) {
  70. switch (_item) {
  71. case 'month':
  72. $title.find('.btn-group-sm').append('<a class="btn btn-default month" data-value="month" >月</a>');
  73. break;
  74. case 'week':
  75. $title.find('.btn-group-sm').append('<a class="btn btn-default week" data-value="week" >周</a>');
  76. break;
  77. case 'day':
  78. $title.find('.btn-group-sm').append('<a class="btn btn-default day" data-value="day" >天</a>');
  79. break;
  80. case 'hour':
  81. $title.find('.btn-group-sm').append('<a class="btn btn-default hour" data-value="hour" >时</a>');
  82. break;
  83. }
  84. });
  85. var $footer = $('<div class="lr-gantt-footer" ></div>');
  86. var $body = $('<div class="lr-gantt-body lr-gantt-body-pr" ></div>').css({ 'padding-left': op.leftWidh });
  87. var $left = $('<div class="lr-gantt-left" ><div class="lr-gantt-left-content" ></div></div>').css({ width: op.leftWidh }); // 左侧显示区域
  88. var $right = $('<div class="lr-gantt-right" >\
  89. <div class="lr-gantt-rightheader" >\
  90. </div>\
  91. <div class="lr-gantt-rightbody" ></div>\
  92. </div>'); // 右侧显示区域
  93. $left.append('<div class="lr-gantt-move" ></div>'); // 左右移动滑块
  94. $right.append('<div class="lr-gantt-nodata-img" ><img src="' + op.imgUrl + '"></div>');
  95. $body.append('<div class="lr-gantt-showtext" >\
  96. <div class="lr-gantt-showtext-title-remove"><i title="关闭" class="fa fa-close"></i></div>\
  97. <div class="lr-gantt-showtext-content" ></div>\
  98. </div>');
  99. op._row = 0;
  100. _gantt.initTitle($title, op);
  101. _gantt.initFooter($footer, $self, op);
  102. _gantt.initLeft($left, $self, op);
  103. _gantt.initRight($right, $self, op);
  104. _gantt.initMove($self);
  105. _gantt.initShow($body);
  106. $body.append($left);
  107. $body.append($right);
  108. $self.append($title);
  109. $self.append($body);
  110. $self.append($footer);
  111. // 绘制数据
  112. _gantt.renderData($self, op);
  113. // 加载后台数据
  114. // _gantt.loadData($self, op);
  115. $title = null;
  116. $body = null;
  117. $footer = null;
  118. $left = null;
  119. $right = null;
  120. $self = null;
  121. },
  122. initShow: function ($body) {
  123. $body.find('.lr-gantt-showtext-content').lrscroll();
  124. $body.find('.lr-gantt-showtext-title-remove').on('click', function () {
  125. var $this = $(this);
  126. $this.parent().removeClass('active');
  127. $this.parents('.lr-gantt').removeClass('lr-gantt-showtext-active');
  128. $this.parent().find('.lr-scroll-box').html('');
  129. $this = null;
  130. });
  131. },
  132. initMove: function ($self) {
  133. $self.on('mousedown', function (e) {
  134. e = e || window.event;
  135. var et = e.target || e.srcElement;
  136. var $et = $(et);
  137. var $this = $(this);
  138. var dfop = $this[0].dfop;
  139. if ($et.hasClass('lr-gantt-move')) {
  140. dfop._ismove = true;
  141. dfop._pageX = e.pageX;
  142. }
  143. });
  144. $self.mousemove(function (e) {
  145. var $this = $(this);
  146. var dfop = $this[0].dfop;
  147. if (dfop._ismove) {
  148. var $block = $this.find('.lr-gantt-left');
  149. $block.css('width', dfop.leftWidh + (e.pageX - dfop._pageX));
  150. $this.find('.lr-gantt-body').css('padding-left', dfop.leftWidh + (e.pageX - dfop._pageX));
  151. }
  152. });
  153. $self.on('click', function (e) {
  154. var $this = $(this);
  155. var dfop = $this[0].dfop;
  156. if (dfop._ismove) {
  157. dfop.leftWidh += (e.pageX - dfop._pageX);
  158. dfop._ismove = false;
  159. }
  160. });
  161. },
  162. initTitle: function ($title, op) {
  163. $title.find('.' + op.type).addClass('active');
  164. $title.find('a').on('click', function () {
  165. var $this = $(this);
  166. if (!$this.hasClass('active')) {
  167. $this.parent().find('.active').removeClass('active');
  168. var $self = $this.parents('.lr-gantt');
  169. var _op = $self[0].dfop;
  170. _op.type = $this.attr('data-value');
  171. setTimeout(function () {
  172. _gantt.renderRightHeader($self.find('.lr-gantt-rightheader'), op);
  173. _gantt.renderRightData($self, op);
  174. $self = null;
  175. });
  176. $this.addClass('active');
  177. }
  178. $this = null;
  179. });
  180. },
  181. initFooter: function ($footer, $self, op) {
  182. if (op.isPage) {
  183. var $pagebar = $('<div class="lr-gantt-page-bar" id="lr_gantt_page_bar_' + op.id + '"><div class="lr-gantt-page-bar-info" >无显示数据</div>\
  184. <div class="paginations" id="lr_gantt_page_bar_nums_' + op.id + '" style="display:none;" >\
  185. <ul class="pagination pagination-sm"><li><a href="javascript:void(0);" class="pagebtn">首页</a></li></ul>\
  186. <ul class="pagination pagination-sm"><li><a href="javascript:void(0);" class="pagebtn">上一页</a></li></ul>\
  187. <ul class="pagination pagination-sm" id="lr_gantt_page_bar_num_' + op.id + '" ></ul>\
  188. <ul class="pagination pagination-sm"><li><a href="javascript:void(0);" class="pagebtn">下一页</a></li></ul>\
  189. <ul class="pagination pagination-sm"><li><a href="javascript:void(0);" class="pagebtn">尾页</a></li></ul>\
  190. <ul class="pagination"><li><span></span></li></ul>\
  191. <ul class="pagination"><li><input type="text" class="form-control"></li></ul>\
  192. <ul class="pagination pagination-sm"><li><a href="javascript:void(0);" class="pagebtn">跳转</a></li></ul>\
  193. </div></div>');
  194. $footer.append($pagebar);
  195. $pagebar.find('#lr_gantt_page_bar_num_' + op.id).on('click', _gantt.turnPage);
  196. $pagebar.find('#lr_gantt_page_bar_nums_' + op.id + ' .pagebtn').on('click', { op: op }, _gantt.turnPage2);
  197. $pagebar = null;
  198. }
  199. else {
  200. $self.addClass('lr-gantt-nopage');
  201. }
  202. $footer = null;
  203. },
  204. initLeft: function ($left, $self, op) {
  205. $left.find('.lr-gantt-left-content').lrscroll(function (x, y) {
  206. if (!$self.is(":hidden")) {
  207. $self.find('.lr-gantt-rightbody').lrscrollSet('moveY', y);
  208. }
  209. });
  210. },
  211. initRight: function ($right, $self, op) {
  212. $right.find('.lr-gantt-rightbody').lrscroll(function (x, y) {
  213. if (!$self.is(":hidden")) {
  214. $self.find('.lr-gantt-rightheader').css('left', -x);
  215. $self.find('.lr-gantt-left-content').lrscrollSet('moveY', y);
  216. }
  217. });
  218. },
  219. renderRightHeader: function ($header, op) {
  220. $header.hide();
  221. $header.html('');
  222. op._time = DateUtils.getBoundaryDatesFromData(op.data, op.cellNum, op.type);
  223. // 绘制头部
  224. var $month = $('<div class="lr-gantt-rightheader-months" ></div>');
  225. var $day = $('<div class="lr-gantt-rightheader-days" ></div>');
  226. var len = 0;
  227. var last = op._time.min;
  228. var y = '';
  229. var w = 0;
  230. var $y = null;
  231. op._num = 0;
  232. switch (op.type) {
  233. case 'month':
  234. len = op._time.min.DateDiff('m', op._time.max) + 1;
  235. w = 0;
  236. for (var i = 0; i < len; i++) {
  237. var _y = last.getFullYear();
  238. if (y != _y) {
  239. y = _y;
  240. if ($y != null) {
  241. $y.css({ 'width': w * 28 });
  242. }
  243. $y = $('<div class="lr-gantt-rightheader-month" >' + y + '</div>');
  244. $month.append($y);
  245. w = 0;
  246. }
  247. $day.append('<div class="lr-gantt-rightheader-day" >' + (last.getMonth()+1) + '</div>');
  248. last = last.DateAdd('m', 1);
  249. w++;
  250. op._num++;
  251. }
  252. $y.css({ 'width': w * 28 });
  253. break;
  254. case 'week':
  255. len = op._time.min.DateDiff('w', op._time.max) +1;
  256. w = 0;
  257. var start = null;
  258. for (var i = 0; i < len; i++) {
  259. var _y = op.monthNames[last.getMonth()] + '/' + last.getFullYear();
  260. if (y != _y) {
  261. y = _y;
  262. if ($y != null) {
  263. if (op._time.min.DateDiff('m', start) > 0) {
  264. $y.css({ 'width': start.MaxDayOfDate() * 4 });
  265. }
  266. else {
  267. $y.css({ 'width': (start.MaxDayOfDate() - start.getDate() + 1) * 4 });
  268. }
  269. }
  270. start = last;
  271. $y = $('<div class="lr-gantt-rightheader-month" >' + y + '</div>');
  272. $month.append($y);
  273. w = 0;
  274. }
  275. $day.append('<div class="lr-gantt-rightheader-day" >' + DateUtils.getWeekNumber(last) + '</div>');
  276. last = last.DateAdd('w', 1);
  277. w++;
  278. op._num++;
  279. }
  280. $y.css({ 'width': (last.DateAdd('w', -1).getDate() + 6) * 4 });
  281. break;
  282. case 'day':
  283. len = op._time.min.DateDiff('d', op._time.max) + 1;
  284. w = 0;
  285. for (var i = 0; i < len; i++) {
  286. var _y = op.monthNames[last.getMonth()] + '/' + last.getFullYear();
  287. if (y != _y) {
  288. y = _y;
  289. if ($y != null) {
  290. $y.css({ 'width': w * 28 });
  291. }
  292. $y = $('<div class="lr-gantt-rightheader-month" >' + y + '</div>');
  293. $month.append($y);
  294. w = 0;
  295. }
  296. $day.append('<div class="lr-gantt-rightheader-day ' + (DateUtils.isWeekend(last)?'lr-gantt-weekend':'') + ' " >' + last.getDate() + '</div>');
  297. last = last.DateAdd('d', 1);
  298. w++;
  299. op._num++;
  300. }
  301. $y.css({ 'width': w * 28 });
  302. break;
  303. case 'hour':
  304. len = op._time.min.DateDiff('h', op._time.max) + 1;
  305. w = 0;
  306. for (var i = 0; i < len; i++) {
  307. var _y = last.getDate() + '/' + op.monthNames[last.getMonth()] + '/' + last.getFullYear();
  308. if (y != _y) {
  309. y = _y;
  310. if ($y != null) {
  311. $y.css({ 'width': w * 28 });
  312. }
  313. $y = $('<div class="lr-gantt-rightheader-month" >' + y + '</div>');
  314. $month.append($y);
  315. w = 0;
  316. }
  317. $day.append('<div class="lr-gantt-rightheader-day " >' + last.getHours() + '</div>');
  318. last = last.DateAdd('h', 1);
  319. w++;
  320. op._num++;
  321. }
  322. $y.css({ 'width': w * 28 });
  323. break;
  324. }
  325. op._width = op._num * 28;
  326. $header.css("width", op._width + "px");
  327. $header.append($month);
  328. $header.append($day);
  329. $header.show();
  330. $header = null;
  331. $month = null;
  332. $day = null;
  333. },
  334. renderRightGird: function ($content, op) {
  335. $content.hide();
  336. $content.css({ 'width': op._width });
  337. $content.html('');
  338. var $row = $('<div class="lr-gantt-grid-row"></div>');
  339. for (var j = 0; j < op._num; j++) {
  340. var $cell = $('<div class="lr-gantt-grid-row-cell" ></div>', { "class": "ganttview-grid-row-cell" });
  341. $row.append($cell);
  342. $cell = null;
  343. }
  344. for (var j = 0; j < op._row; j++) {
  345. $content.append($row.clone());
  346. }
  347. $content.show();
  348. if (op._row == 0) {
  349. $content.parents('.lr-gantt-right').find('.lr-gantt-nodata-img').show();
  350. }
  351. else {
  352. $content.parents('.lr-gantt-right').find('.lr-gantt-nodata-img').hide();
  353. }
  354. $row = null;
  355. $content = null;
  356. },
  357. // 加载数据
  358. loadData: function ($self, op) {
  359. var _param = op.param || {};
  360. if (op.isPage) {
  361. learun.loading(true, '正在获取数据');
  362. op.pageparam = op.pageparam || {
  363. rows: op.rows, // 每页行数
  364. page: 1, // 当前页
  365. sidx: '', // 排序列
  366. sord: '', // 排序类型
  367. records: 0, // 总记录数
  368. total: 0 // 总页数
  369. };
  370. op.pageparam.rows = op.rows;
  371. op.pageparam.sidx = op.sidx;
  372. op.pageparam.sord = op.sord;
  373. op.pageparam.page = op.pageparam.page || 1;
  374. op.pageparam.records = 0;
  375. op.pageparam.total = 0;
  376. op.param = op.param || {};
  377. delete op.param['pagination'];
  378. var _paramString = JSON.stringify(op.param);
  379. if (op.paramString != _paramString) {
  380. op.paramString = _paramString;
  381. op.pageparam.page = 1;
  382. }
  383. op.param['pagination'] = JSON.stringify(op.pageparam);
  384. learun.httpAsync('GET', op.url, op.param, function (data) {
  385. learun.loading(false);
  386. if (data) {
  387. op.data = data.rows;
  388. op.pageparam.page = data.page;
  389. op.pageparam.records = data.records;
  390. op.pageparam.total = data.total;
  391. }
  392. else {
  393. op.data = [];
  394. op.pageparam.page = 1;
  395. op.pageparam.records = 0;
  396. op.pageparam.total = 0;
  397. }
  398. _gantt.renderData($self, op);
  399. var $pagebar = $self.find('#lr_gantt_page_bar_' + op.id);
  400. var $pagebarBtn = $pagebar.find('#lr_gantt_page_bar_num_' + op.id);
  401. var $pagebarBtns = $pagebar.find('#lr_gantt_page_bar_nums_' + op.id);
  402. var pagebarLabel = '';
  403. var btnlist = "";
  404. if (op.data.length == 0) {
  405. pagebarLabel = '无显示数据';
  406. }
  407. else {
  408. var pageparam = op.pageparam;
  409. var beginnum = (pageparam.page - 1) * pageparam.rows + 1;
  410. var endnum = beginnum + op.data.length - 1;
  411. pagebarLabel = '显示第 ' + beginnum + ' - ' + endnum + ' 条记录 <span>|</span> 检索到 ' + pageparam.records + ' 条记录';
  412. if (pageparam.total > 1) {
  413. var bpage = pageparam.page - 6;
  414. bpage = bpage < 0 ? 0 : bpage;
  415. var epage = bpage + 10;
  416. if (epage > pageparam.total) {
  417. epage = pageparam.total;
  418. }
  419. if ((epage - bpage) < 10) {
  420. bpage = epage - 10;
  421. }
  422. bpage = bpage < 0 ? 0 : bpage;
  423. for (var i = bpage; i < epage; i++) {
  424. btnlist += '<li><a href="javascript:void(0);" class=" pagebtn ' + ((i + 1) == pageparam.page ? 'active' : '') + '" >' + (i + 1) + '</a></li>';
  425. }
  426. $pagebarBtns.find('span').text('共' + pageparam.total + '页,到');
  427. $pagebarBtns.show();
  428. }
  429. else {
  430. $pagebarBtns.hide();
  431. }
  432. }
  433. $pagebarBtn.html(btnlist);
  434. $pagebar.find('.lr-gantt-page-bar-info').html(pagebarLabel);
  435. op.onRenderComplete && op.onRenderComplete(op.data);
  436. });
  437. }
  438. else {
  439. if (op.url) {
  440. learun.loading(true, '正在获取数据');
  441. learun.httpAsync('GET', op.url, _param, function (data) {
  442. learun.loading(false);
  443. op.data = data || [];
  444. _gantt.renderData($self, op);
  445. op.onRenderComplete && op.onRenderComplete(op.data);
  446. });
  447. }
  448. }
  449. },
  450. turnPage: function (e) {
  451. e = e || window.event;
  452. var $this = $(this);
  453. var $self = $('#' + $this.attr('id').replace('lr_gantt_page_bar_num_', ''));
  454. var op = $self[0].dfop;
  455. var et = e.target || e.srcElement;
  456. var $et = $(et);
  457. if ($et.hasClass('pagebtn')) {
  458. var page = parseInt($et.text());
  459. if (page != op.pageparam.page) {
  460. $this.find('.active').removeClass('active');
  461. $et.addClass('active');
  462. op.pageparam.page = page;
  463. _gantt.loadData($self, op);
  464. }
  465. }
  466. },
  467. turnPage2: function (e) {
  468. var $this = $(this);
  469. var op = e.data.op;
  470. var name = $this.text();
  471. var $pagenum = $('#lr_gantt_page_bar_num_' + op.id);
  472. var page = parseInt($pagenum.find('.active').text());
  473. var falg = false;
  474. switch (name) {
  475. case '首页':
  476. if (page != 1) {
  477. op.pageparam.page = 1;
  478. falg = true;
  479. }
  480. break;
  481. case '上一页':
  482. if (page > 1) {
  483. op.pageparam.page = page - 1;
  484. falg = true;
  485. }
  486. break;
  487. case '下一页':
  488. if (page < op.pageparam.total) {
  489. op.pageparam.page = page + 1;
  490. falg = true;
  491. }
  492. break;
  493. case '尾页':
  494. if (page != op.pageparam.total) {
  495. op.pageparam.page = op.pageparam.total;
  496. falg = true;
  497. }
  498. break;
  499. case '跳转':
  500. var text = $this.parents('#lr_gantt_page_bar_nums_' + op.id).find('input').val();
  501. if (!!text) {
  502. var p = parseInt(text);
  503. if (String(p) != 'NaN') {
  504. if (p < 1) {
  505. p = 1;
  506. }
  507. if (p > op.pageparam.total) {
  508. p = op.pageparam.total;
  509. }
  510. op.pageparam.page = p;
  511. falg = true;
  512. }
  513. }
  514. break;
  515. }
  516. if (falg) {
  517. _gantt.loadData($('#' + op.id), op);
  518. }
  519. },
  520. // 渲染数据
  521. renderData: function ($self, op) {
  522. _gantt.hideinfo($self);
  523. _gantt.renderRightHeader($self.find('.lr-gantt-rightheader'), op);
  524. // 绘制左侧列表数据
  525. _gantt.renderLeftData($self, op);
  526. // 绘制右侧数据
  527. _gantt.renderRightData($self, op);
  528. },
  529. // 左侧
  530. renderLeftData: function ($self, op) {
  531. var $treeRoot = $('<ul class="lr-gantt-tree-root" ></ul>');
  532. var _len = op.data.length;
  533. op._timeDatas = {};
  534. op._row = 0;
  535. for (var i = 0; i < _len; i++) {
  536. var $node = _gantt.renderNode(op.data[i], 0, i, op, true);
  537. $treeRoot.append($node);
  538. }
  539. $self.find('.lr-gantt-left .lr-scroll-box').html($treeRoot);
  540. },
  541. renderNode: function (node, deep, path, dfop, isShow) {
  542. if (isShow) {
  543. dfop._timeDatas[path + ''] = node;
  544. dfop._row++;
  545. }
  546. node._deep = deep;
  547. node._path = path;
  548. // 渲染成单个节点
  549. var nid = node.id.replace(/[^\w]/gi, "_");
  550. var title = node.title || node.text;
  551. var $node = $('<li class="lr-gantt-tree-node"></li>');
  552. var $nodeDiv = $('<div id="' + dfop.id + '_' + nid + '" tpath="' + path + '" title="' + title + '" dataId="' + dfop.id + '" class="lr-gantt-tree-node-el" ></div>');
  553. if (node.hasChildren) {
  554. var c = (node.isexpand || dfop.isAllExpand) ? 'lr-gantt-tree-node-expanded' : 'lr-gantt-tree-node-collapsed';
  555. $nodeDiv.addClass(c);
  556. }
  557. else {
  558. $nodeDiv.addClass('lr-gantt-tree-node-leaf');
  559. }
  560. // span indent
  561. var $span = $('<span class="lr-gantt-tree-node-indent"></span>');
  562. if (deep == 1) {
  563. $span.append('<img class="lr-gantt-tree-icon" src="' + dfop.cbiconpath + 's.gif"/>');
  564. }
  565. else if (deep > 1) {
  566. $span.append('<img class="lr-gantt-tree-icon" src="' + dfop.cbiconpath + 's.gif"/>');
  567. for (var j = 1; j < deep; j++) {
  568. $span.append('<img class="lr-gantt-tree-icon" src="' + dfop.cbiconpath + 's.gif"/>');
  569. }
  570. }
  571. $nodeDiv.append($span);
  572. // img
  573. var $img = $('<img class="lr-gantt-tree-ec-icon" src="' + dfop.cbiconpath + 's.gif"/>');
  574. $nodeDiv.append($img);
  575. // a
  576. var ahtml = '<a class="lr-gantt-tree-node-anchor" href="javascript:void(0);">';
  577. ahtml += '<span data-value="' + node.id + '" class="lr-gantt-tree-node-text" >' + node.text + '</span>';
  578. ahtml += '</a>';
  579. $nodeDiv.append(ahtml);
  580. // 节点事件绑定
  581. $nodeDiv.on('click', _gantt.nodeClick);
  582. if (!node.complete) {
  583. $nodeDiv.append('<div class="lr-gantt-tree-loading"><img class="lr-gantt-tree-ec-icon" src="' + dfop.cbiconpath + 'loading.gif"/></div>');
  584. }
  585. $node.append($nodeDiv);
  586. if (node.hasChildren) {
  587. var $treeChildren = $('<ul class="lr-gantt-tree-node-ct" >');
  588. if (!node.isexpand && !dfop.isAllExpand) {
  589. $treeChildren.css('display', 'none');
  590. }
  591. if (node.children) {
  592. var l = node.children.length;
  593. for (var k = 0; k < l; k++) {
  594. node.children[k].parent = node;
  595. var $childNode = _gantt.renderNode(node.children[k], deep + 1, path + "." + k, dfop);
  596. $treeChildren.append($childNode);
  597. }
  598. $node.append($treeChildren);
  599. }
  600. }
  601. node.render = true;
  602. return $node;
  603. },
  604. renderNodeAsync: function ($this, node, dfop) {
  605. var $treeChildren = $('<ul class="lr-gantt-tree-node-ct" >');
  606. if (!node.isexpand && !dfop.isAllExpand) {
  607. $treeChildren.css('display', 'none');
  608. }
  609. if (node.children) {
  610. var l = node.children.length;
  611. for (var k = 0; k < l; k++) {
  612. node.children[k].parent = node;
  613. var $childNode = _gantt.renderNode(node.children[k], node._deep + 1, node._path + "." + k, dfop);
  614. $treeChildren.append($childNode);
  615. }
  616. $this.parent().append($treeChildren);
  617. }
  618. return $treeChildren;
  619. },
  620. getItem: function (path, dfop) {
  621. var ap = path.split(".");
  622. var t = dfop.data;
  623. for (var i = 0; i < ap.length; i++) {
  624. if (i == 0) {
  625. t = t[ap[i]];
  626. }
  627. else {
  628. t = t.children[ap[i]];
  629. }
  630. }
  631. return t;
  632. },
  633. nodeClick: function (e) {
  634. e = e || window.event;
  635. var et = e.target || e.srcElement;
  636. var $this = $(this);
  637. var $parent = $('#' + $this.attr('dataId'));
  638. var dfop = $parent[0].dfop;
  639. var path = $this.attr('tpath');
  640. var node = _gantt.getItem(path, dfop);
  641. if (et.tagName == 'IMG') {
  642. var $et = $(et);
  643. var $ul = $this.next('.lr-gantt-tree-node-ct');
  644. if ($et.hasClass("lr-gantt-tree-ec-icon")) {
  645. if ($this.hasClass('lr-gantt-tree-node-expanded')) {
  646. $ul.slideUp(200, function () {
  647. $this.removeClass('lr-gantt-tree-node-expanded');
  648. $this.addClass('lr-gantt-tree-node-collapsed');
  649. _gantt.removeTimeDatas(node.children, dfop);
  650. // 重新刷新下右侧的数据
  651. _gantt.renderRightData($parent, dfop);
  652. });
  653. }
  654. else if ($this.hasClass('lr-gantt-tree-node-collapsed')) {
  655. // 展开
  656. if (!node.complete) {
  657. if (!node._loading) {
  658. node._loading = true;// 表示正在加载数据
  659. $this.find('.lr-gantt-tree-loading').show();
  660. var param = dfop.childParam || {};
  661. param.parentId = node.id;
  662. var url = dfop.childUrl || dfop.url;
  663. learun.httpAsync('GET', url, param, function (data) {
  664. if (data) {
  665. node.children = data;
  666. $ul = _gantt.renderNodeAsync($this, node, dfop);
  667. $ul.slideDown(200, function () {
  668. $this.removeClass('lr-gantt-tree-node-collapsed');
  669. $this.addClass('lr-gantt-tree-node-expanded');
  670. // 检测下当前节点下哪些节点显示了
  671. _gantt.addTimeDatas(node.children, dfop);
  672. // 重新刷新下右侧的数据
  673. _gantt.renderRightData($parent, dfop);
  674. });
  675. node.complete = true;
  676. $this.find('.lr-gantt-tree-loading').hide();
  677. }
  678. node._loading = false;
  679. });
  680. }
  681. }
  682. else {
  683. $ul.slideDown(200, function () {
  684. $this.removeClass('lr-gantt-tree-node-collapsed');
  685. $this.addClass('lr-gantt-tree-node-expanded');
  686. // 检测下当前节点下哪些节点显示了
  687. _gantt.addTimeDatas(node.children, dfop);
  688. // 重新刷新下右侧的数据
  689. _gantt.renderRightData($parent, dfop);
  690. });
  691. }
  692. }
  693. }
  694. }
  695. else {
  696. dfop.currentItem = node;
  697. $parent.find('.lr-gantt-tree-selected').removeClass('lr-gantt-tree-selected');
  698. $this.addClass('lr-gantt-tree-selected');
  699. dfop.click && dfop.click(node, $this);
  700. }
  701. return false;
  702. },
  703. addTimeDatas: function (data, op) {
  704. $.each(data, function (_index, _item) {
  705. var nid = _item.id.replace(/[^\w]/gi, "_");
  706. var id = op.id + '_' + nid;
  707. var $node = $('#' + id);
  708. if (!$node.is(":hidden")) {
  709. var path = $node.attr('tpath');
  710. op._timeDatas[path] = _item;
  711. op._row++;
  712. if (_item.hasChildren && _item.children && _item.children.length) {
  713. _gantt.addTimeDatas(_item.children, op);
  714. }
  715. }
  716. });
  717. },
  718. removeTimeDatas: function (data, op) {
  719. $.each(data, function (_index, _item) {
  720. var nid = _item.id.replace(/[^\w]/gi, "_");
  721. var id = op.id + '_' + nid;
  722. var $node = $('#' + id);
  723. if ($node.is(":hidden")) {
  724. var path = $node.attr('tpath');
  725. if (op._timeDatas) {
  726. delete op._timeDatas[path];
  727. op._row--;
  728. }
  729. if (_item.hasChildren && _item.children && _item.children.length) {
  730. _gantt.addTimeDatas(_item.children, op);
  731. }
  732. }
  733. });
  734. },
  735. // 右侧
  736. renderRightData: function ($self, op) {
  737. _gantt.renderRightGird($self.find('.lr-gantt-rightbody .lr-scroll-box'), op);
  738. var $blocks = $('<div class="lr-gantt-blocks" ></div>');
  739. // 对 op._timeDatas 进行排序
  740. var _dataTemp = [];
  741. $.each(op._timeDatas, function (_index, _item) {
  742. if (_index.indexOf('.') == -1) {
  743. _dataTemp.push(_item);
  744. // 获取他的子节点
  745. _gantt.addRightChildTimeDatas(op._timeDatas, _dataTemp, _index);
  746. }
  747. });
  748. $.each(_dataTemp, function (_index, _item) {
  749. var $blockContainer = $('<div class="lr-gantt-block-container" ></div>');
  750. $.each(_item.timeList || [], function (_i, _t) {
  751. var res = DateUtils.getDateBlock(_t.beginTime, _t.endTime, op);
  752. if (res.width > 0) {
  753. var $block = $('<div class="lr-gantt-block" ><div class="lr-gantt-block-text" ></div></div>').css({ width: res.width, left: res.left, 'background-color': _t.color || '#3286ed' });
  754. if (_t.text) {
  755. $block.find('.lr-gantt-block-text').text(_t.text);
  756. }
  757. if (_t.overtime) {
  758. $block.append('<div class="lr-gantt-block-icon" title="超时" ><i class="fa fa-arrow-circle-down" ></i></div>');
  759. }
  760. $block[0].ganttData = {
  761. item: _item,
  762. mytime:_t
  763. };
  764. // 点击
  765. $block.on('click', { op: op }, function (e) {
  766. e = e || window.event;
  767. var _op = e.data.op;
  768. var ganttData = $(this)[0].ganttData;
  769. _op.timeClick && _op.timeClick(ganttData, $('#' + _op.id));
  770. });
  771. // 双击
  772. $block.on('dblclick', { op: op }, function (e) {
  773. e = e || window.event;
  774. var _op = e.data.op;
  775. var ganttData = $(this)[0].ganttData;
  776. _op.timeDoubleClick && _op.timeDoubleClick(ganttData, $('#' + _op.id));
  777. });
  778. // 移入、移出
  779. $block.hover(function () {
  780. var ganttData = $(this)[0].ganttData;
  781. op.timeHover && op.timeHover(ganttData, true, $('#' + op.id));
  782. }, function () {
  783. var ganttData = $(this)[0].ganttData;
  784. op.timeHover && op.timeHover(ganttData, false, $('#' + op.id));
  785. });
  786. $blockContainer.append($block);
  787. }
  788. });
  789. $blocks.append($blockContainer);
  790. });
  791. $self.find('.lr-gantt-rightbody .lr-scroll-box').append($blocks);
  792. },
  793. addRightChildTimeDatas: function (data, _dataTemp, path) {
  794. var num =0;
  795. while(true){
  796. var _path = path + '.' + num;
  797. if (data[_path]) {
  798. _dataTemp.push(data[_path]);
  799. _gantt.addRightChildTimeDatas(data, _dataTemp, _path);
  800. num++;
  801. }
  802. else {
  803. break;
  804. }
  805. }
  806. },
  807. // 方法
  808. showInfo: function ($self, info) {// 显示右侧信息板信息
  809. var $content = $self.find('.lr-gantt-showtext-content .lr-scroll-box');
  810. $content.html(info);
  811. var $showText = $self.find('.lr-gantt-showtext');
  812. if (!$showText.hasClass('active')) {
  813. $showText.addClass('active');
  814. $self.addClass('lr-gantt-showtext-active');
  815. }
  816. },
  817. hideinfo: function ($self) {// 隐藏右侧信息板信息
  818. var $content = $self.find('.lr-gantt-showtext-content .lr-scroll-box');
  819. var $showText = $self.find('.lr-gantt-showtext');
  820. if ($showText.hasClass('active')) {
  821. $showText.removeClass('active');
  822. $self.removeClass('lr-gantt-showtext-active');
  823. $content.html('');
  824. }
  825. }
  826. };
  827. var DateUtils = {
  828. getDateBlock: function (start, end, op) {// 根据开始结束时间获取宽度和起始位置
  829. start = DateUtils.parseDate(start, 'h');
  830. end = DateUtils.parseDate(end, 'h');
  831. var wnum = 0;
  832. var dnum = 0;
  833. var res = {
  834. left: 0,
  835. width: 0
  836. };
  837. switch (op.type) {
  838. case 'day':
  839. wnum = start.DateDiff('d', end) + 1;
  840. dnum = op._time.min.DateDiff('d', start);
  841. break;
  842. case 'week':
  843. dnum = op._time.min.DateDiff('w', start);
  844. var eweek = op._time.min.DateDiff('w', end);
  845. wnum = eweek - dnum + 1;
  846. break;
  847. case 'month':
  848. dnum = op._time.min.DateDiff('m', start);
  849. var emonth = op._time.min.DateDiff('m', end);
  850. wnum = emonth - dnum + 1;
  851. break;
  852. case 'hour':
  853. dnum = op._time.min.DateDiff('h', start);
  854. var ehour = op._time.min.DateDiff('h', end);
  855. wnum = ehour - dnum + 1;
  856. break;
  857. }
  858. res.left = dnum * 28 + 2;
  859. res.width = wnum * 28 - 4;
  860. return res;
  861. },
  862. isLeapYear:function(year) {
  863. return (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
  864. },
  865. getMonthDays:function(year, month) {
  866. return [31, (DateUtils.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
  867. },
  868. getWeekNumber: function (targetDay) {
  869. var year = targetDay.getFullYear();
  870. var month = targetDay.getMonth();
  871. var days = targetDay.getDate();
  872. //那一天是那一年中的第多少天
  873. for (var i = 0; i < month; i++) {
  874. days += DateUtils.getMonthDays(year, i);
  875. }
  876. //那一年第一天是星期几
  877. var yearFirstDay = (new Date(year, 0, 1)).getDay();
  878. //计算是第几周
  879. days += yearFirstDay;
  880. var week = Math.ceil(days / 7);
  881. var _num = 7 - targetDay.getDay();
  882. if (targetDay.DateAdd('d', _num).getFullYear() != year) {
  883. return 1;
  884. }
  885. return week;
  886. },
  887. isWeekend: function (date) {
  888. return date.getDay() % 6 == 0;
  889. },
  890. getBoundaryDatesFromData: function (data, num, type) {
  891. var time = {
  892. min: DateUtils.parseDate(new Date(), 'h'),
  893. max: DateUtils.parseDate(new Date(), 'h')
  894. };
  895. DateUtils.getMinMax(data, time, true);
  896. switch (type) {
  897. case 'month':
  898. time.min = DateUtils.parseDate(time.min, 'm');
  899. time.max = DateUtils.parseDate(time.max, 'm').DateAdd('m',1);
  900. if (time.min.DateDiff('m', time.max) < num) {
  901. time.max = time.min.DateAdd('m', num);
  902. }
  903. if (time.min.getMonth() == 11) {
  904. time.min = time.min.DateAdd('m', -1);
  905. }
  906. if (time.max.getMonth() == 0) {
  907. time.max = time.max.DateAdd('m', 1);
  908. }
  909. break;
  910. case 'week':
  911. time.min = DateUtils.parseDate(time.min, 'w');
  912. time.max = DateUtils.parseDate(time.max, 'w').DateAdd('w', 1);
  913. if (time.min.DateDiff('w', time.max) < num) {
  914. time.max = time.min.DateAdd('w', num);
  915. }
  916. if (time.min.MaxDayOfDate() - time.min.getDate() + 1 < 21) {
  917. var _wnum = time.min.getDate() - time.min.getDate() % 7;
  918. time.min = time.min.DateAdd('d',-_wnum);
  919. }
  920. if (time.max.getDate() < 21) {
  921. var _wnum = parseInt((time.max.MaxDayOfDate() - time.max.getDate()) / 7);
  922. time.max = time.max.DateAdd('w', _wnum);
  923. }
  924. break;
  925. case 'day':
  926. if (time.min.DateDiff('d', time.max) < num) {
  927. time.max = time.min.DateAdd('d', num);
  928. }
  929. // 获取当前月最大天数
  930. var minMonths = time.min.MaxDayOfDate();
  931. var minCurrentDay = time.min.getDate();
  932. var maxCurrentDay = time.max.getDate();
  933. if (minMonths - minCurrentDay < 2) {
  934. time.min = time.min.DateAdd('d', -(2 + minCurrentDay - minMonths));
  935. }
  936. if (maxCurrentDay < 3) {
  937. time.max = time.max.DateAdd('d', (3 - maxCurrentDay));
  938. }
  939. break;
  940. case 'hour':
  941. if (time.min.DateDiff('h', time.max) < num) {
  942. time.max = time.min.DateAdd('h', num);
  943. }
  944. break;
  945. }
  946. return time;
  947. },
  948. getMinMax:function(data, time, isFirst) {
  949. $.each(data || [], function (_index, _item) {
  950. $.each(_item.timeList, function (_jindex, _jitem) {
  951. var start = DateUtils.parseDate(_jitem.beginTime, 'h');
  952. var end = DateUtils.parseDate(_jitem.endTime, 'h');
  953. if (isFirst) {
  954. time.min = start;
  955. time.max = end;
  956. isFirst = false;
  957. }
  958. if (time.min.DateDiff('h', start) < 0) { time.min = start; }
  959. if (time.max.DateDiff('h', end) > 0) { time.max = end; }
  960. });
  961. if (data.children && data.children.length > 0) {
  962. DateUtils.getMinMax(data.children, time, false);
  963. }
  964. });
  965. },
  966. parseDate: function (day, strInterval) {
  967. switch (strInterval) {
  968. case 'd':
  969. return learun.parseDate(learun.formatDate(day, 'yyyy-MM-dd 00:00:00'));
  970. break;
  971. case 'w':// 获取当前周的第一天
  972. var d = learun.parseDate(learun.formatDate(day, 'yyyy-MM-dd 00:00:00'));
  973. var w = d.getDay();
  974. return d.DateAdd('d', (1 -w));
  975. break;
  976. case 'm':
  977. return learun.parseDate(learun.formatDate(day, 'yyyy-MM-01 00:00:00'));
  978. break;
  979. case 'h':
  980. return learun.parseDate(learun.formatDate(day, 'yyyy-MM-dd hh:00:00'));
  981. break;
  982. default:
  983. return learun.parseDate(learun.formatDate(day, 'yyyy-MM-dd 00:00:00'));
  984. break;
  985. }
  986. }
  987. };
  988. $.fn.lrGantt = function (op) {
  989. //id, // id 对应字段
  990. //text, // 显示文本对应字段
  991. //isexpand:false, // 是否展开
  992. //complete:true, // 是否加载完数据
  993. //timeList // 显示时间字段数组
  994. // ----
  995. //-beginTime, // 开始时间对应字段
  996. //-endTime, // 结束时间对应字段
  997. //-color, // 颜色对应字段
  998. //-overtime, // 超时对饮字段
  999. //children
  1000. var dfop = {
  1001. url: false, // 接口地址
  1002. childUrl: false, // 加载子节点参数
  1003. data: [], // 加载数据
  1004. param: false, // 访问接口参数
  1005. childParam: false, // 访问子节点接口参数
  1006. leftWidh: 200,
  1007. type: 'day', // month,week,day,hour
  1008. timebtns: ['month', 'week', 'day', 'hour'],
  1009. monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一", "十二"],
  1010. isAllExpand:false,
  1011. isPage: false,
  1012. rows: 50,
  1013. imgUrl:top.$.rootUrl + '/Content/images/jfgrid/nodata.jpg',
  1014. cbiconpath: top.$.rootUrl + '/Content/images/learuntree/',
  1015. cellNum: 100,
  1016. click: false, // 单击事件 item
  1017. timeClick: false, // 时间段点击事件 item 和 时间段信息
  1018. timeDoubleClick: false, // 时间段双击事件 item 和 时间段信息
  1019. timeHover: false, // 时间段hover事件 移入事件/移出事件 item 和 时间段信息 flag 标志 true 移入 false 移出
  1020. onRenderComplete:false // 动态加载后台数据完成后执行
  1021. };
  1022. $.extend(dfop, op || {});
  1023. var $self = $(this);
  1024. $self[0].dfop = dfop;
  1025. dfop.id = $self.attr('id');
  1026. _gantt.init($self, dfop);
  1027. return $self;
  1028. }
  1029. $.fn.lrGanttSet = function (name, data) {
  1030. var $this = $(this);
  1031. var op = $this[0].dfop;
  1032. switch (name) {
  1033. case 'showinfo': // 显示信息框
  1034. _gantt.showInfo($this, data);
  1035. break;
  1036. case 'hideinfo': // 关闭信息框
  1037. _gantt.hideinfo($this);
  1038. break;
  1039. case 'refreshdata': // 刷新数据
  1040. op.data = data || [];
  1041. _gantt.renderData($this, op);
  1042. break;
  1043. case 'reload':
  1044. if (data) {
  1045. op.param = data;
  1046. }
  1047. _gantt.loadData($this, op);
  1048. break;
  1049. }
  1050. };
  1051. })(window.jQuery, top.learun);