zentaolist.ui.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. function getType()
  2. {
  3. return $('#zentaolist').data('type');
  4. }
  5. function getSettings(useFormData = false)
  6. {
  7. const settings = $('#zentaolist').data('settings');
  8. const idList = $('#zentaolist').data('idlist');
  9. settings.idList = idList;
  10. if(!useFormData) return settings;
  11. const formData = new FormData();
  12. for(const key in settings)
  13. {
  14. const value = settings[key];
  15. if(Array.isArray(value))
  16. {
  17. value.forEach((item, index) => (formData.append(`${key}[]`, item)));
  18. }
  19. else
  20. {
  21. formData.append(key, value);
  22. }
  23. }
  24. return formData;
  25. }
  26. function getValue(name)
  27. {
  28. return $('#zentaolist [name=' + name + ']').val();
  29. }
  30. function updatePicker(name, items)
  31. {
  32. const $picker = $('#zentaolist [name=' + name + ']').zui('picker');
  33. $picker.render({items});
  34. $picker.$.setValue(null);
  35. }
  36. function checkForm(form, formData)
  37. {
  38. let isValid = true;
  39. $(form).find('.error-tip').addClass('hidden');
  40. $(form).find('.form-group').removeClass('has-error');
  41. // 遍历 FormData 中的所有键值对
  42. for (let [name, value] of formData.entries()) {
  43. const inputElement = form.querySelector(`[name="${name}"]`);
  44. const formGroup = $(inputElement).closest('.form-group');
  45. // 检查是否是必填项
  46. if (inputElement && formGroup.hasClass('required') && !value?.length) {
  47. isValid = false;
  48. formGroup.find('.error-tip').removeClass('hidden');
  49. formGroup.addClass('has-error');
  50. }
  51. }
  52. return isValid;
  53. }
  54. window.backToSet = function()
  55. {
  56. const settings = $('#previewForm').data('settings');
  57. const blockID = $('#previewForm').data('blockid');
  58. parent.zui.Modal.open({
  59. size: 'lg',
  60. url: settings.replace('{blockID}', blockID)
  61. });
  62. }
  63. window.toggleCheckRows = function()
  64. {
  65. const idList = $('#zentaolist').data('idlist');
  66. if(!idList?.length) return;
  67. const dtable = zui.DTable.query($('#previewTable'));
  68. dtable.$.toggleCheckRows(idList.split(','), true);
  69. }
  70. function loadWithForm(formData, view = 'setting', action = 'load')
  71. {
  72. const sessionUrl = $.createLink('doc', 'buildZentaoList', 'type=' + getType());
  73. const loadUrl = $.createLink('doc', 'zentaolist', 'type=' + getType() + '&view=' + view);
  74. $.post(sessionUrl, formData, function(data)
  75. {
  76. data = JSON.parse(data);
  77. if(data.result == 'success') action === 'load' ? loadPage(loadUrl) : loadCurrentPage('#customSearchContent');
  78. });
  79. }
  80. function preview()
  81. {
  82. const form = $('#zentaolist form');
  83. const formData = new FormData(form[0]);
  84. if(!checkForm(form[0], formData)) return;
  85. formData.append('action', 'preview');
  86. loadWithForm(formData);
  87. }
  88. function insert()
  89. {
  90. const dtable = zui.DTable.query($('#previewTable'));
  91. const checkedList = dtable.$.getChecks();
  92. const tip = $('#insert').data('tip');
  93. if(checkedList.length == 0)
  94. {
  95. zui.Modal.alert(tip);
  96. return;
  97. }
  98. const form = $('#zentaolist form');
  99. const formData = new FormData(form[0]);
  100. formData.append('action', 'insert');
  101. formData.append('idList', checkedList.join(','));
  102. loadWithForm(formData, 'list');
  103. }
  104. window.cancel = function()
  105. {
  106. zui.Editor.iframe.delete();
  107. }
  108. function changeCondition()
  109. {
  110. const condition = getValue('condition');
  111. if(condition == 'customSearch')
  112. {
  113. $('#customSearchContent').removeClass('hidden');
  114. }
  115. else
  116. {
  117. $('#customSearchContent').addClass('hidden');
  118. }
  119. }
  120. window.updateCustomSearchItem = function($this, action)
  121. {
  122. const index = $this.data('index');
  123. const form = $('#zentaolist form');
  124. const formData = new FormData(form[0]);
  125. formData.append('conditionAction', action);
  126. formData.append('conditionIndex', index);
  127. loadWithForm(formData, 'setting', 'post');
  128. }
  129. window.updateCustomSearch = function()
  130. {
  131. const form = $('#zentaolist form');
  132. const formData = new FormData(form[0]);
  133. loadWithForm(formData, 'setting', 'post');
  134. }
  135. function changeProduct()
  136. {
  137. const product = getValue('product');
  138. const type = getType();
  139. if(type === 'planStory' || type == 'planBug')
  140. {
  141. const link = $.createLink('productplan', 'ajaxGetProductplans', 'product=' + product);
  142. $.get(link, function(resp)
  143. {
  144. resp = JSON.parse(resp);
  145. updatePicker('plan', resp);
  146. });
  147. }
  148. if(type === 'productCase')
  149. {
  150. const condition = getValue('condition');
  151. if(condition == 'customSearch') updateCustomSearch();
  152. }
  153. }
  154. window.renderCell = function(result, info)
  155. {
  156. if(['productStory', 'ER', 'UR', 'planStory', 'projectStory'].indexOf(blockType) !== -1)
  157. {
  158. if(info.col.name == 'title' && result)
  159. {
  160. const story = info.row.data;
  161. let html = '';
  162. if(blockType == 'planStory' || blockType == 'projectStory')
  163. {
  164. let gradeLabel = gradeGroup[story.type][story.grade];
  165. if(gradeLabel) html += "<span class='label gray-pale rounded-xl clip'>" + gradeLabel + "</span> ";
  166. }
  167. else
  168. {
  169. let gradeLabel = '';
  170. let showGrade = false;
  171. const gradeMap = gradeGroup[story.type] || {};
  172. if(story.type != storyType) showGrade = true;
  173. if((story.type == 'epic' || story.type == 'requirement') && Object.keys(gradeMap).length >= 2) showGrade = true;
  174. if(story.type == 'story' && Object.keys(gradeMap).length >= 3) showGrade = true;
  175. if(story.grade > 1) showGrade = true;
  176. if(showGrade) gradeLabel = gradeMap[story.grade];
  177. if(gradeLabel) html += "<span class='label gray-pale rounded-xl clip'>" + gradeLabel + "</span> ";
  178. if(story.color) result[0].props.style = 'color: ' + story.color;
  179. }
  180. if(html) result.unshift({html});
  181. }
  182. }
  183. if(blockType == 'productRelease')
  184. {
  185. if(info.col.name == 'build')
  186. {
  187. result = [];
  188. if(!info.row.data.build.name) return result;
  189. result.push({html: info.row.data.build.name});
  190. }
  191. if(info.col.name == 'project')
  192. {
  193. result = [];
  194. if(!info.row.data.projectName) return result;
  195. result.push({html: `<span title='${info.row.data.projectName}'>${info.row.data.projectName}</span>`});
  196. }
  197. }
  198. if(blockType == 'projectRelease')
  199. {
  200. if(info.col.name == 'name')
  201. {
  202. if(info.row.data.marker == 1)
  203. {
  204. result[result.length] = {html: "<icon class='icon icon-flag text-danger' title='" + markerTitle + "'></icon>"};
  205. }
  206. }
  207. if(info.col.name == 'build')
  208. {
  209. if(!info.row.data.buildInfos) info.row.data.buildInfos = info.row.data.builds;
  210. let result = [];
  211. for(key in info.row.data.buildInfos) result.push({html: info.row.data.buildInfos[key].name})
  212. return result;
  213. }
  214. }
  215. if(blockType == 'productCase')
  216. {
  217. if(result)
  218. {
  219. if(info.col.name == 'caseID' && info.row.data.isScene) result.shift(); // 移除场景ID
  220. if(info.col.name == 'title')
  221. {
  222. const data = info.row.data;
  223. if(data.color) result[0].props.style = 'color: ' + data.color;
  224. if(data.isScene) // 场景
  225. {
  226. result.shift(); // 移除带链接的场景名称
  227. result.push({html: data.title}); // 添加不带链接的场景名称
  228. result.unshift({html: '<span class="label gray-300-outline text-gray rounded-full nowrap">' + scene + '</span>'}); // 添加场景标签
  229. }
  230. else // 用例
  231. {
  232. if(data.auto == 'auto') result.unshift({html: '<span class="label gray-pale rounded-full nowrap">' + automated + '</span>'}); // 添加自动化标签
  233. if(info.row.data.fromCaseID > 0) result.push({html: `[<i class='icon icon-share'></i> #${info.row.data.fromCaseID}]`}); // 添加来源用例
  234. }
  235. }
  236. if(info.col.name == 'pri' && info.row.data.isScene) result.shift(); // 移除场景优先级
  237. if(info.col.name == 'status' && info.row.data.status == 'casechanged') result[0] = {html: '<span style="color:#ff6f42">' + caseChanged + '</span>'};
  238. }
  239. if(info.row.data.lastEditedDate == '0000-00-00 00:00:00') info.row.data.lastEditedDate = '';
  240. if(info.row.data.reviewedDate == '0000-00-00') info.row.data.reviewedDate = '';
  241. }
  242. if(blockType == 'task')
  243. {
  244. if(result)
  245. {
  246. if(info.col.name == 'name' && !info.row.data.canView)
  247. {
  248. result.shift();
  249. result.push({html: info.row.data.name});
  250. }
  251. }
  252. }
  253. return result;
  254. };
  255. window.getCellSpan = function(cell)
  256. {
  257. if(['id', 'branchName', 'name', 'branch', 'status', 'date', 'desc', 'releasedDate', 'actions', 'system'].includes(cell.col.name) && cell.row.data.rowspan)
  258. {
  259. return {rowSpan: cell.row.data.rowspan};
  260. }
  261. }