task.ui.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. $(document).off('click','.batch-btn').on('click', '.batch-btn', function()
  2. {
  3. const dtable = zui.DTable.query($(this).target);
  4. const checkedList = dtable.$.getChecks();
  5. if(!checkedList.length) return;
  6. const url = $(this).data('url');
  7. const form = new FormData();
  8. checkedList.forEach((id) => form.append('taskIdList[]', id));
  9. if($(this).hasClass('ajax-btn'))
  10. {
  11. $.ajaxSubmit({url, data: form});
  12. }
  13. else if($(this).hasClass('ajax-cancel-btn'))
  14. {
  15. $.ajaxSubmit({url, data: form}).then();
  16. }
  17. else
  18. {
  19. postAndLoadPage(url, form);
  20. }
  21. }).off('click', '#actionBar .export').on('click', '#actionBar .export', function()
  22. {
  23. const dtable = zui.DTable.query($('#table-execution-task'));
  24. if(!$('#table-execution-task').length) return;
  25. const checkedList = dtable.$.getChecks();
  26. if(!checkedList.length) return;
  27. $.cookie.set('checkedItem', checkedList, {expires:config.cookieLife, path:config.webRoot});
  28. });
  29. /**
  30. * 计算表格任务信息的统计。
  31. * Set task summary for table footer.
  32. *
  33. * @param element element
  34. * @param array checkedIDList
  35. * @access public
  36. * @return object
  37. */
  38. window.setStatistics = function(element, checkedIDList)
  39. {
  40. if(typeof element == 'undefined') return;
  41. let totalLeft = 0;
  42. let totalEstimate = 0;
  43. let totalConsumed = 0;
  44. let waitCount = 0;
  45. let doingCount = 0;
  46. let totalCount = 0;
  47. const rows = element.layout.allRows;
  48. rows.forEach((row) => {
  49. if(checkedIDList.length == 0 || checkedIDList.includes(row.id))
  50. {
  51. const task = row.data;
  52. totalCount ++;
  53. if(task.rawStatus == 'wait')
  54. {
  55. waitCount ++;
  56. }
  57. else if(task.rawStatus == 'doing')
  58. {
  59. doingCount ++;
  60. }
  61. if(task.isParent > 0) return true;
  62. if(task.isParent == 0)
  63. {
  64. totalEstimate += Number(task.estimate);
  65. totalConsumed += Number(task.consumed);
  66. }
  67. if(task.rawStatus != 'cancel' && task.rawStatus != 'closed' && task.isParent == 0) totalLeft += Number(task.left);
  68. }
  69. })
  70. let summary = checkedIDList.length > 0 ? checkedSummary : pageSummary;
  71. summary = summary.replace('%total%', totalCount)
  72. .replace('%wait%', waitCount)
  73. .replace('%doing%', doingCount)
  74. .replace('%estimate%', totalEstimate.toFixed(1))
  75. .replace('%consumed%', totalConsumed.toFixed(1))
  76. .replace('%left%', totalLeft.toFixed(1));
  77. $('.dtable-check-info').attr('title', summary.replace(/<[^>]+>/g,""));
  78. return {html: summary};
  79. }
  80. /**
  81. * 对部分列进行重定义。
  82. * Redefine the partial column.
  83. *
  84. * @param array result
  85. * @param array info
  86. * @access public
  87. * @return string|array
  88. */
  89. window.renderCell = function(result, info)
  90. {
  91. const isFromDoc = this.props.isFromDoc;
  92. if(isFromDoc) return result;
  93. const task = info.row.data;
  94. if(info.col.name == 'name' && result)
  95. {
  96. let html = '';
  97. if(typeof result[0] == 'object') result[0].props.className = 'overflow-hidden';
  98. const module = this.options.modules[info.row.data.module];
  99. if(module) html += '<span class="label gray-pale rounded-full mr-1 whitespace-nowrap">' + module + '</span>'; // 添加模块标签
  100. if(task.mode)
  101. {
  102. html += "<span class='label gray-pale rounded p-0 size-sm whitespace-nowrap'>" + multipleAB + "</span>";
  103. }
  104. if(task.isParent > 0)
  105. {
  106. html += "<span class='label gray-pale rounded p-0 size-sm whitespace-nowrap'>" + parentAB + "</span>";
  107. }
  108. else if(task.parent > 0)
  109. {
  110. html += "<span class='label gray-pale rounded p-0 size-sm whitespace-nowrap'>" + childrenAB + "</span>";
  111. }
  112. if(task.color) result[0].props.style = 'color: ' + task.color;
  113. if(html) result.unshift({html});
  114. if(typeof task.delay != 'undefined' && task.delay > 0)
  115. {
  116. result[result.length] = { html: '<span class="label danger-pale ml-1 flex-none nowrap">' + delayWarning.replace('%s', task.delay) + '</span>', className: 'flex items-end', style: { flexDirection: "column" } };
  117. }
  118. if(task.fromBug > 0 && !isFromDoc)
  119. {
  120. const bugLink = $.createLink('bug', 'view', `id=${task.fromBug}`);
  121. const bugTitle = `<a class="bug" href='${bugLink}'>[BUG#${task.fromBug}]</a>`;
  122. result.push({html: bugTitle});
  123. }
  124. }
  125. if(info.col.name == 'status' && result)
  126. {
  127. result[0] = {html: `<span class='status-${info.row.data.rawStatus}'>` + info.row.data.status + "</span>"};
  128. }
  129. if(info.col.name == 'deadline' && result[0])
  130. {
  131. if(['done', 'cancel', 'closed'].includes(task.rawStatus)) return result;
  132. const today = zui.formatDate(zui.createDate(), 'yyyy-MM-dd');
  133. const yesterday = zui.formatDate(convertStringToDate(today) - 24 * 60 * 60 * 1000, 'yyyy-MM-dd');
  134. if(result[0] == today)
  135. {
  136. result[0] = {html: '<span class="label warning-pale rounded-full size-sm">' + todayLabel + '</span>'};
  137. }
  138. else if(result[0] == yesterday)
  139. {
  140. result[0] = {html: '<span class="label danger-pale rounded-full size-sm">' + yesterdayLabel + '</span>'};
  141. }
  142. else if(result[0] < yesterday)
  143. {
  144. result[0] = {html: '<span class="label danger-pale rounded-full size-sm">' + result[0] + '</span>'};
  145. }
  146. }
  147. if(info.col.name == 'assignedTo' && result)
  148. {
  149. if(task.mode == 'multi' && !task.assignedTo && !['done','closed','cancel'].includes(task.rawStatus))
  150. {
  151. if(canAssignTo) result[0]['props']['children'][1]['props']['children'] = teamLang;
  152. if(!canAssignTo) result[0] = teamLang;
  153. }
  154. if(typeof task.canAssignTo != 'undefined' && !task.canAssignTo && typeof result[0] == 'object')
  155. {
  156. let taskAssignTo = typeof this.props.userMap[task.assignedTo] != 'undefined' ? this.props.userMap[task.assignedTo] : task.assignedTo;
  157. result[0] = {html: `<span class='text-left ml-7'>` + taskAssignTo + "</span>", className: 'flex'};
  158. }
  159. }
  160. if(['estimate', 'consumed','left'].includes(info.col.name) && result) result[0] = {html: result[0] + ' h'};
  161. if(info.col.name == 'design')
  162. {
  163. result[0] = {html: task.designName};
  164. result[1].attrs['title'] = task.designName;
  165. }
  166. return result;
  167. }
  168. $(document).off('click', '.switchButton').on('click', '.switchButton', function()
  169. {
  170. var taskViewType = $(this).attr('data-type');
  171. $.cookie.set('taskViewType', taskViewType, {expires:config.cookieLife, path:config.webRoot});
  172. loadCurrentPage();
  173. });
  174. window.firstRendered = false;
  175. window.toggleCheckRows = function(idList)
  176. {
  177. if(!idList?.length || firstRendered) return;
  178. firstRendered = true;
  179. const dtable = zui.DTable.query($('#tasks'));
  180. dtable.$.toggleCheckRows(idList.split(','), true);
  181. }