browse.ui.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. $(document).off('click', '[data-formaction]').on('click', '[data-formaction]', function()
  2. {
  3. const $this = $(this);
  4. if($this.attr('class').indexOf('disabled') !== -1) return;
  5. const dtable = zui.DTable.query($('#stories'));
  6. const checkedList = dtable.$.getChecks();
  7. if(!checkedList.length) return;
  8. const postData = new FormData();
  9. checkedList.forEach((id) => postData.append('storyIdList[]', id));
  10. if($this.data('account')) postData.append('assignedTo', $this.data('account'));
  11. if($this.data('page') == 'batch')
  12. {
  13. postAndLoadPage($this.data('formaction'), postData);
  14. }
  15. else
  16. {
  17. $.ajaxSubmit({"url": $this.data('formaction'), "data": postData});
  18. }
  19. });
  20. $(document).off('click', '.batchImportToLibBtn').on('click', '.batchImportToLibBtn', function()
  21. {
  22. const dtable = zui.DTable.query($('#stories'));
  23. const checkedList = dtable.$.getChecks();
  24. if(!checkedList.length) return;
  25. $("[name='storyIdList'").val(checkedList.join(','));
  26. });
  27. $(document).off('click', '.batchChangeParentBtn').on('click', '.batchChangeParentBtn', function(e)
  28. {
  29. const dtable = zui.DTable.query($('#stories'));
  30. const checkedList = dtable.$.getChecks();
  31. $.cookie.set('checkedItem', checkedList.join(','), {expires:config.cookieLife, path:config.webRoot});
  32. });
  33. $(document).off('click', '.switchButton').on('click', '.switchButton', function()
  34. {
  35. var storyViewType = $(this).attr('data-type');
  36. $.cookie.set('storyViewType', storyViewType, {expires:config.cookieLife, path:config.webRoot});
  37. loadCurrentPage();
  38. });
  39. $(document).off('click','#linkStoryByPlan button[type="submit"]').on('click', '#linkStoryByPlan button[type="submit"]', function()
  40. {
  41. var planID = $('[name=plan]').val();
  42. if(planID)
  43. {
  44. $.ajaxSubmit({url: $.createLink('execution', 'importPlanStories', 'projectID=' + projectID + '&planID=' + planID)});
  45. }
  46. return false;
  47. });
  48. $(document).off('click', '.batchUnlinkStory').on('click', '.batchUnlinkStory', function(e)
  49. {
  50. const dtable = zui.DTable.query($('#stories'));
  51. const checkedList = dtable.$.getChecks();
  52. if(!checkedList.length) return;
  53. /* 处理选中的子需求的ID,截取-后的子需求ID。*/
  54. /* Process selected child story ID. */
  55. for(i in checkedList)
  56. {
  57. const storyID = checkedList[i];
  58. if(storyID.includes('-')) checkedList[i] = storyID.slice(storyID.indexOf('-') + 1);
  59. }
  60. let batchUnlinkStoryURL = $.createLink('projectstory', 'batchUnlinkStory', 'projectID=' + projectID + '&stories=' + encodeURIComponent(checkedList.join(',')));
  61. $.get(batchUnlinkStoryURL, function(data)
  62. {
  63. try
  64. {
  65. data = JSON.parse(data);
  66. if(typeof data.result != 'undefined') return loadCurrentPage();
  67. }
  68. catch(error){}
  69. zui.Modal.open({id: 'batchUnlinkStoryBox'});
  70. $('#batchUnlinkStoryBox').html(data);
  71. $('#batchUnlinkStoryBox').off('mousedown', '.confirmBtn').on('mousedown', '.confirmBtn', function()
  72. {
  73. loadCurrentPage();
  74. });
  75. });
  76. });
  77. window.renderCell = function(result, info)
  78. {
  79. if(info.col.name == 'title' && result)
  80. {
  81. const story = info.row.data;
  82. let html = '';
  83. if(story.parentName != undefined && story.parent > 0 && $.cookie.get('tab') == 'project' && projectHasProduct && vision != 'lite') html += story.parentName + ' / ';
  84. if(typeof modulePairs[story.rawModule] != 'undefined') html += "<span class='label gray-pale rounded-xl clip'>" + modulePairs[story.rawModule] + "</span> ";
  85. let gradeLabel = '';
  86. let showGrade = false;
  87. const gradeMap = gradeGroup[story.type] || {};
  88. if(story.type != storyType) showGrade = true;
  89. if((story.type == 'epic' || story.type == 'requirement') && Object.keys(gradeMap).length >= 2) showGrade = true;
  90. if(story.type == 'story' && Object.keys(gradeMap).length >= 3) showGrade = true;
  91. if(story.grade > 1) showGrade = true;
  92. if(tab != 'product') showGrade = true;
  93. if(showGrade) gradeLabel = gradeMap[story.grade];
  94. if(gradeLabel) html += "<span class='label gray-pale rounded-xl clip'>" + gradeLabel + "</span> ";
  95. if(story.color)
  96. {
  97. if(result[0].props !== undefined)
  98. {
  99. result[0].props.style = 'color: ' + story.color;
  100. }
  101. else
  102. {
  103. result[2]['style']['color'] = story.color;
  104. }
  105. }
  106. if(result[0].props && ((story.type == 'story' && !storyViewPriv) || (story.type == 'requirement' && !requirementViewPriv) || (story.type == 'epic' && !epicViewPriv))) result[0] = result[0].props.children;
  107. if(html) result.unshift({html});
  108. }
  109. if(info.col.name == 'status' && result)
  110. {
  111. result[0] = {html: `<span class='status-${info.row.data.rawStatus}'>` + info.row.data.status + "</span>"};
  112. }
  113. if(info.col.name == 'assignedTo')
  114. {
  115. if(info.row.data.rawStatus == 'closed' && result[0]['props'])
  116. {
  117. delete result[0]['props']['data-toggle'];
  118. delete result[0]['props']['href'];
  119. result[0]['props']['className'] += ' disabled';
  120. }
  121. else
  122. {
  123. let assignToClass = info.row.data.assignedTo == userAccount ? 'is-me' : '';
  124. if(!info.row.data.assignedTo) assignToClass = 'is-unassigned';
  125. if(storyAssignedToPriv && requirementAssignedToPriv && info.row.data.type == 'requirement')
  126. {
  127. result[0]['props']['href'] = $.createLink('requirement', 'assignTo', 'storyID=' + info.row.data.id);
  128. }
  129. else if(!storyAssignedToPriv && requirementAssignedToPriv && info.row.data.type == 'requirement')
  130. {
  131. result[0] = {html : '<a href=' + $.createLink('requirement', 'assignTo', 'storyID=' + info.row.data.id) + ' data-toggle="modal" class="dtable-assign-btn ' + assignToClass + '"><i class="icon icon-hand-right"></i><span>' + result[0] + '</span></a>'};
  132. }
  133. if(storyAssignedToPriv && epicAssignedToPriv && info.row.data.type == 'epic')
  134. {
  135. result[0]['props']['href'] = $.createLink('epic', 'assignTo', 'storyID=' + info.row.data.id);
  136. }
  137. else if(!storyAssignedToPriv && epicAssignedToPriv && info.row.data.type == 'epic')
  138. {
  139. result[0] = {html : '<a href=' + $.createLink('epic', 'assignTo', 'storyID=' + info.row.data.id) + ' data-toggle="modal" class="dtable-assign-btn ' + assignToClass + '"><i class="icon icon-hand-right"></i><span>' + result[0] + '</span></a>'};
  140. }
  141. if((!requirementAssignedToPriv && info.row.data.type == 'requirement') || (!epicAssignedToPriv && info.row.data.type == 'epic'))
  142. {
  143. delete result[0]['props']['data-toggle'];
  144. delete result[0]['props']['href'];
  145. result[0]['props']['className'] += ' disabled';
  146. }
  147. }
  148. }
  149. if(info.col.name == 'childItem')
  150. {
  151. result[1]['attrs']['title'] = info.row.data?.childItemTitle;
  152. }
  153. if(info.col.name == 'taskCount' && !info.row.data.taskCount)
  154. {
  155. if(result[0]['type']) result[0]['type'] = 'text';
  156. if(result[0]['props'])
  157. {
  158. delete result[0]['props']['data-toggle'];
  159. delete result[0]['props']['href'];
  160. }
  161. }
  162. if(info.col.name == 'bugCount' && !info.row.data.bugCount)
  163. {
  164. if(result[0]['type']) result[0]['type'] = 'text';
  165. if(result[0]['props'])
  166. {
  167. delete result[0]['props']['data-toggle'];
  168. delete result[0]['props']['href'];
  169. }
  170. }
  171. if(info.col.name == 'caseCount' && !info.row.data.caseCount)
  172. {
  173. if(result[0]['type']) result[0]['type'] = 'text';
  174. if(result[0]['props'])
  175. {
  176. delete result[0]['props']['data-toggle'];
  177. delete result[0]['props']['href'];
  178. }
  179. }
  180. return result;
  181. };
  182. window.setStatistics = function(element, checkedIdList, pageSummary)
  183. {
  184. if(checkedIdList == undefined || checkedIdList.length == 0) return {html: pageSummary};
  185. let total = 0;
  186. let estimate = 0;
  187. let rate = '0%';
  188. let hasCase = 0;
  189. let rateCount = checkedIdList.length;
  190. const rows = element.layout.allRows;
  191. rows.forEach((row) => {
  192. if(checkedIdList.includes(row.id))
  193. {
  194. const story = row.data;
  195. if(story.type != storyType && tab == 'product') return;
  196. if(story?.needSummaryEstimate) estimate += parseFloat(story.estimate);
  197. if(story.caseCount > 0)
  198. {
  199. hasCase += 1;
  200. }
  201. else if(typeof story.isParent != 'undefined' && story.isParent == '1')
  202. {
  203. rateCount -= 1;
  204. }
  205. total += 1;
  206. }
  207. })
  208. if(rateCount) rate = Math.round(hasCase / rateCount * 10000) / 100 + '' + '%';
  209. return {html: checkedSummary.replace('%total%', total).replace('%estimate%', estimate.toFixed(2)).replace('%rate%', rate)};
  210. };
  211. window.setShowGrades = function()
  212. {
  213. const showGrades = $('[name^=showGrades]').zui('picker').$.state.value;
  214. if(oldShowGrades == showGrades) return;
  215. const module = tab == 'product' || from == 'doc' || from == 'ai' ? storyType : tab;
  216. const link = $.createLink('product', 'ajaxSetShowGrades', 'module=' + module + '&showGrades=' + showGrades);
  217. $.get(link, function()
  218. {
  219. if(from == 'doc' || from == 'ai')
  220. {
  221. const currentLink = $.createLink('product', 'browse', `productID=${productID}&branch=${branch}&browseType=${browseType}&param=${param}&storyType=${storyType}&orderBy=${orderBy}&recTotal=${recTotal}&recPerPage=${recPerPage}&pageID=${pageID}&projectID=${projectID}&from=${from}&blockID=${blockID}`);
  222. loadModal(currentLink);
  223. }
  224. else
  225. {
  226. loadCurrentPage();
  227. }
  228. });
  229. }
  230. window.importToLib = function()
  231. {
  232. const dtable = zui.DTable.query($('#stories'));
  233. const checkedList = dtable.$.getChecks();
  234. if(!checkedList.length) return;
  235. let storyIdList = '';
  236. checkedList.forEach((id) => storyIdList += id + ',');
  237. $('#storyIdList').val(storyIdList);
  238. }
  239. window.firstRendered = false;
  240. window.toggleCheckRows = function(idList)
  241. {
  242. if(!idList?.length || firstRendered) return;
  243. firstRendered = true;
  244. const dtable = zui.DTable.query($('#stories'));
  245. dtable.$.toggleCheckRows(idList.split(','), true);
  246. }