update.ui.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. window.saveData = function(event)
  2. {
  3. const myTable = zui.DTable.query();
  4. const applicableState = myTable.$.getApplicableState();
  5. const url = $(event.target).data('url');
  6. const form = new FormData();
  7. form.append('type', 'update');
  8. $.each(applicableState, function(index)
  9. {
  10. form.append('checkedList[' + index + ']', applicableState[index] ? 'yes' : 'no');
  11. });
  12. $.ajaxSubmit({url, data: form});
  13. };
  14. zui.DTable.definePlugin(
  15. {
  16. name: 'process-trimming',
  17. plugins: ['nested'],
  18. defaultOptions:
  19. {
  20. noTrimName: 'noTrim', // 禁止裁剪属性名
  21. applicableName: 'applicable', // 裁剪结果状态属性名,true 适用, false 不适用,null 空(未裁剪)
  22. nested: true,
  23. showTrimmingToggles: true,
  24. },
  25. state: function() {return {applicableState: {}, savedApplicableState: {}, isSavingApplicableState: false, showTrimmingToggles: this.options.showTrimmingToggles};},
  26. colTypes:
  27. {
  28. trimCheckbox: function(colSetting)
  29. {
  30. return {
  31. width: 40,
  32. hidden: !this.isShowTrimmingToggles(),
  33. align: 'center',
  34. onRenderCell: function(result, info)
  35. {
  36. const rowData = info.row.data;
  37. if(rowData[this.options.noTrimName]) return result;
  38. const applicable = this.isRowApplicable(info.row.id);
  39. if(applicable === true) result[0] = {html: '<div class="dtable-applicable-toggle w-3 h-3 rounded canvas state ring ring-darker hover:ring-primary text-success hover:text-primary center"><i class="icon icon-check"></i></div>'};
  40. else if(applicable === false) result[0] = {html: '<div class="dtable-applicable-toggle w-3 h-3 rounded canvas state ring ring-darker hover:ring-primary text-danger hover:text-primary center"><i class="icon icon-close"></i></div>'};
  41. else result[0] = {html: '<div class="dtable-applicable-toggle w-3 h-3 rounded canvas state ring ring-darker hover:ring-primary hover:text-primary center"></div>'};
  42. return result;
  43. }
  44. };
  45. },
  46. applicableState:
  47. {
  48. onRenderCell: function(result, info)
  49. {
  50. const rowData = info.row.data;
  51. const applicable = this.isRowApplicable(info.row.id);
  52. const mapValue = info.col.setting.map ? info.col.setting.map[applicable] : undefined;
  53. if(mapValue !== undefined) result[0] = mapValue;
  54. return result;
  55. }
  56. }
  57. },
  58. footer:
  59. {
  60. trimmingActions: function(_, layout)
  61. {
  62. const showTrimmingToggles = this.isShowTrimmingToggles();
  63. const saveURL = this.options.saveURL;
  64. const backURL = this.options.backURL;
  65. const savingClass = this.state.isSavingApplicableState ? ' disabled' : '';
  66. const jsx = zui.jsx || zui.html;
  67. return [
  68. jsx`<button type="button" class="btn primary size-sm mr-4${savingClass}" data-url="${saveURL}" data-on='click' data-call='saveData' data-params='event'>${zui.i18n.getLang('save')}</button>`,
  69. jsx`<a type="button" class="btn size-sm mr-4${savingClass}" href="${backURL}">${zui.i18n.getLang('cancel')}</a>`,
  70. this.options.trimingActionsTip,
  71. ]
  72. }
  73. },
  74. methods:
  75. {
  76. /* 检查指定行是否可以进行裁剪,true 适用(未裁剪),false 不适用(已裁剪),null 空(待定) */
  77. isRowApplicable: function(rowID)
  78. {
  79. const {applicableState, savedApplicableState} = this.state;
  80. const modifiedApplicableState = applicableState[rowID];
  81. if(modifiedApplicableState !== undefined) return modifiedApplicableState;
  82. const saveApplicableState = savedApplicableState[rowID];
  83. if(saveApplicableState !== undefined) return saveApplicableState;
  84. const row = this.getRowInfo(rowID);
  85. if(row.data[this.options.noTrimName]) return null;
  86. return row ? row.data[this.options.applicableName] : null;
  87. },
  88. /* 获取当前的裁剪状态,includeAll 参数为 true 时会返回所有行,否则只返回用户变更过的行 */
  89. getApplicableState: function(includeAll)
  90. {
  91. const originState = {};
  92. this.layout.allRows.forEach((row) =>
  93. {
  94. if(row.data[this.options.noTrimName]) return;
  95. originState[row.id] = row.data[this.options.applicableName];
  96. });
  97. const {applicableState, savedApplicableState} = this.state;
  98. if(includeAll) return Object.assign({}, originState, savedApplicableState, applicableState);
  99. const state = {};
  100. Object.keys(applicableState).forEach((rowID) =>
  101. {
  102. let newValue = applicableState[rowID];
  103. if(newValue === originState[rowID] || newValue === savedApplicableState[rowID]) return;
  104. state[rowID] = newValue;
  105. });
  106. return state;
  107. },
  108. /* 切换行的裁剪适用状态,true 适用(未裁剪),false 不适用(已裁剪),null 空(待定) */
  109. toggleRowApplicable: function(rowID, toggle)
  110. {
  111. const row = this.getRowInfo(rowID);
  112. const noTrimName = this.options.noTrimName;
  113. if(row.data[noTrimName]) return;
  114. const allState = this.getApplicableState(true);
  115. const oldApplicable = allState[rowID];
  116. if(toggle !== undefined && toggle === oldApplicable) return;
  117. if(toggle === undefined) toggle = !oldApplicable;
  118. const currentState = this.state.applicableState;
  119. const newState = Object.assign({}, currentState, {[rowID]: toggle});
  120. const nestedMap = this.data.nestedMap;
  121. const nestedInfo = nestedMap.get(rowID); // {children: ['121', '123', '125'], parent: 'P-a'}
  122. const relatedRows = new Set();
  123. // 子级设置为不适用
  124. let children = nestedInfo.children;
  125. while(children && children.length)
  126. {
  127. const newChildren = [];
  128. children.forEach((childID) =>
  129. {
  130. if(relatedRows.has(childID)) return;
  131. relatedRows.add(childID);
  132. const childInfo = nestedMap.get(childID);
  133. if(childInfo.children) newChildren.push(...childInfo.children);
  134. });
  135. children = newChildren;
  136. }
  137. if(toggle === true) // 父级和子级都需要设置为适用
  138. {
  139. let parentID = nestedInfo.parent;
  140. while(parentID !== undefined)
  141. {
  142. relatedRows.add(parentID);
  143. const parentInfo = nestedMap.get(parentID);
  144. parentID = parentInfo.parent;
  145. }
  146. }
  147. relatedRows.forEach(id =>
  148. {
  149. const theRow = this.getRowInfo(id);
  150. if(theRow.data[noTrimName]) return;
  151. newState[id] = toggle;
  152. });
  153. this.setState({applicableState: newState});
  154. },
  155. /* 切换行的裁剪操作按钮,如果不指定 show 参数则自动切换和隐藏 */
  156. showTrimmingToggles: function(show)
  157. {
  158. if(show === undefined) show = !this.state.showTrimmingToggles;
  159. this.update({dirtyType: 'layout', state: {showTrimmingToggles: show}});
  160. },
  161. /* 检查是否显示裁剪操作按钮 */
  162. isShowTrimmingToggles: function()
  163. {
  164. let showTrimmingToggles = this.state.showTrimmingToggles;
  165. if(showTrimmingToggles === undefined) showTrimmingToggles = this.options.showTrimmingToggles;
  166. return showTrimmingToggles;
  167. },
  168. /* 保存裁剪状态 */
  169. saveApplicableState: async function()
  170. {
  171. const onSaveApplicableState = this.options.onSaveApplicableState;
  172. const newState = {isSavingApplicableState: false};
  173. if(onSaveApplicableState)
  174. {
  175. this.setState({isSavingApplicableState: true});
  176. const changedState = this.getApplicableState();
  177. if(!Object.keys(changedState).length)
  178. {
  179. newState.showTrimmingToggles = false;
  180. this.update({dirtyType: 'layout', state: newState});
  181. return false;
  182. }
  183. const result = await onSaveApplicableState(changedState);
  184. if(result === false)
  185. {
  186. this.setState(newState);
  187. return false;
  188. }
  189. if(result === true)
  190. {
  191. const {applicableState, savedApplicableState} = this.state;
  192. newState.applicableState = {};
  193. newState.savedApplicableState = $.extend({}, savedApplicableState, applicableState);
  194. }
  195. }
  196. newState.showTrimmingToggles = false;
  197. this.update({dirtyType: 'layout', state: newState});
  198. }
  199. },
  200. onAddCol: function(col)
  201. {
  202. if(col.type === 'trimCheckbox' && !this.state.showTrimmingToggles) col.hidden = true;
  203. },
  204. onCellClick: function(event, info)
  205. {
  206. if($(event.target).closest('.dtable-applicable-toggle').length) this.toggleRowApplicable(info.rowID);
  207. }
  208. });