grid-extend.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. (function (w, $) {
  2. let Dcat = w.Dcat;
  3. /**
  4. * 树状表格
  5. *
  6. * @param opts
  7. * @constructor
  8. */
  9. function Tree(opts) {
  10. this.options = $.extend({
  11. button: null,
  12. table: null,
  13. url: '',
  14. perPage: '',
  15. showNextPage: '',
  16. pageQueryName: '',
  17. parentIdQueryName: '',
  18. tierQueryName: '',
  19. showIcon: 'fa-angle-right',
  20. hideIcon: 'fa-angle-down',
  21. loadMoreIcon: '<i class="feather icon-more-horizontal"></i>',
  22. }, opts);
  23. this.key = this.tier = this.row = this.data = this._req = null;
  24. this._init();
  25. }
  26. Tree.prototype = {
  27. _init: function () {
  28. this._bindClick();
  29. },
  30. _bindClick: function () {
  31. var _this = this,
  32. opts = _this.options;
  33. $(opts.button).off('click').click(function () {
  34. if (_this._req) {
  35. return;
  36. }
  37. var $this = $(this),
  38. _i = $("i", this),
  39. shown = _i.hasClass(opts.showIcon);
  40. _this.key = $this.data('key');
  41. _this.tier = $this.data('tier');
  42. _this.row = $this.closest('tr');
  43. if ($this.data('inserted') == '0') {
  44. _this.request(1);
  45. $this.data('inserted', 1);
  46. }
  47. _i.toggleClass(opts.showIcon + ' ' + opts.hideIcon);
  48. var children = [];
  49. getChildren(_this.row.nextAll(), _this.row).forEach(function (v) {
  50. if (getTier(v) !== (_this.tier + 1)) {
  51. return;
  52. }
  53. children.push(v);
  54. shown ? $(v).show() : $(v).hide();
  55. });
  56. children.forEach(function (v) {
  57. if (shown) {
  58. return
  59. }
  60. var icon = $(v).find('a[data-tier=' + getTier(v) + '] i');
  61. if (icon.hasClass(opts.hideIcon)) {
  62. icon.parent().click();
  63. }
  64. })
  65. })
  66. },
  67. request: function (page, after) {
  68. var _this = this,
  69. row = _this.row,
  70. key = _this.key,
  71. tier = _this.tier,
  72. tableSelector = _this.options.table;
  73. if (_this._req) {
  74. return;
  75. }
  76. _this._req = 1;
  77. Dcat.loading();
  78. var data = {};
  79. data[_this.options.parentIdQueryName] = key;
  80. data[_this.options.tierQueryName] = tier + 1;
  81. data[_this.options.pageQueryName.replace(':key', key)] = page;
  82. $.ajax({
  83. url: _this.options.url,
  84. type: 'GET',
  85. data: data,
  86. headers: {'X-PJAX': true},
  87. success: function (resp) {
  88. after && after();
  89. Dcat.loading(false);
  90. _this._req = 0;
  91. // 获取最后一行
  92. var children = getChildren(row.nextAll(), row);
  93. row = children.length ? $(children.pop()) : row;
  94. var _body = $('<div>'+resp+'</div>'),
  95. _tbody = _body.find(tableSelector + ' tbody'),
  96. lastPage = _body.find('last-page').text(),
  97. nextPage = _body.find('next-page').text();
  98. // 标记子节点行
  99. _tbody.find('tr').each(function (_, v) {
  100. $(v).attr('data-tier', tier + 1)
  101. });
  102. if (
  103. _this.options.showNextPage
  104. && _tbody.find('tr').length == _this.options.perPage
  105. && lastPage >= page
  106. ) {
  107. // 加载更多
  108. let loadMore = $(
  109. `<tr data-tier="${tier + 1}" data-page="${nextPage}">
  110. <td colspan="${row.find('td').length}" align="center" style="cursor: pointer">
  111. <a href="#" style="font-size: 1.5rem">${_this.options.loadMoreIcon}</a>
  112. </td>
  113. </tr>`
  114. );
  115. row.after(loadMore);
  116. // 加载更多
  117. loadMore.click(function () {
  118. var _t = $(this);
  119. _this.request(_t.data('page'), function () {
  120. _t.remove();
  121. });
  122. });
  123. }
  124. // 附加子节点
  125. row.after(_tbody.html());
  126. // 附加子节点js脚本以及触发子节点js脚本执行
  127. _body.find('script').each(function (_, v) {
  128. row.after(v);
  129. });
  130. // 主动触发ready事件,执行子节点附带的js脚本
  131. Dcat.triggerReady();
  132. },
  133. error:function(a, b, c){
  134. after && after();
  135. Dcat.loading(false);
  136. _this._req = 0;
  137. if (a.status != 404) {
  138. Dcat.handleAjaxError(a, b, c);
  139. }
  140. }
  141. });
  142. }
  143. };
  144. /**
  145. * 可排序功能
  146. *
  147. * @param opts
  148. * @constructor
  149. */
  150. function Orderable(opts) {
  151. this.options = $.extend({
  152. button: null,
  153. url: '',
  154. }, opts);
  155. this.direction = this.key = this.tier = this.row = this._req = null;
  156. this.init();
  157. }
  158. Orderable.prototype = {
  159. init: function () {
  160. var _this = this;
  161. $(_this.options.button).off('click').click(function () {
  162. if (_this._req) {
  163. return;
  164. }
  165. _this._req = 1;
  166. Dcat.loading();
  167. var $this = $(this);
  168. _this.key = $this.data('id');
  169. _this.direction = $this.data('direction');
  170. _this.row = $this.closest('tr');
  171. _this.tier = getTier(_this.row);
  172. _this.request();
  173. })
  174. },
  175. request: function () {
  176. var _this = this,
  177. key = _this.key,
  178. row = _this.row,
  179. tier = _this.tier,
  180. direction = _this.direction,
  181. prevAll = row.prevAll(),
  182. nextAll = row.nextAll(),
  183. prev = row.prevAll('tr').first(),
  184. next = row.nextAll('tr').first();
  185. $.put({
  186. url: _this.options.url.replace(':key', key),
  187. data: {_orderable: direction},
  188. success: function(data){
  189. Dcat.loading(false);
  190. _this._req = 0;
  191. if (! data.status) {
  192. return data.message && Dcat.warning(data.message);
  193. }
  194. Dcat.success(data.message);
  195. if (direction) {
  196. var prevRow = sibling(prevAll, tier);
  197. if (swapable(prevRow, tier) && prev.length && getTier(prev) >= tier) {
  198. prevRow.before(row);
  199. // 把所有子节点上移
  200. getChildren(nextAll, row).forEach(function (v) {
  201. prevRow.before(v)
  202. });
  203. }
  204. } else {
  205. var nextRow = sibling(nextAll, tier),
  206. nextRowChildren = nextRow ? getChildren(nextRow.nextAll(), nextRow) : [];
  207. if (swapable(nextRow, tier) && next.length && getTier(next) >= tier) {
  208. nextAll = row.nextAll();
  209. if (nextRowChildren.length) {
  210. nextRow = $(nextRowChildren.pop())
  211. }
  212. // 把所有子节点下移
  213. var all = [];
  214. getChildren(nextAll, row).forEach(function (v) {
  215. all.unshift(v)
  216. });
  217. all.forEach(function(v) {
  218. nextRow.after(v)
  219. });
  220. nextRow.after(row);
  221. }
  222. }
  223. },
  224. error: function (a, b, c) {
  225. _this._req = 0;
  226. Dcat.loading(false);
  227. Dcat.handleAjaxError(a, b, c)
  228. }
  229. });
  230. },
  231. };
  232. /**
  233. * 异步加载表格
  234. *
  235. * @param options
  236. * @constructor
  237. */
  238. function AsyncTable(options) {
  239. options = $.extend({
  240. container: '.table-card',
  241. }, options)
  242. function load(url, box) {
  243. var $this = $(this);
  244. box = box || $this;
  245. url = $this.data('url') || url;
  246. if (! url) {
  247. return;
  248. }
  249. // 缓存当前请求地址
  250. box.attr('data-current', url);
  251. box.loading({background: 'transparent!important'});
  252. Dcat.helpers.asyncRender(url, function (html) {
  253. box.loading(false);
  254. box.html(html);
  255. bind(box);
  256. box.trigger('table:loaded');
  257. });
  258. }
  259. function bind(box) {
  260. function loadLink() {
  261. load($(this).attr('href'), box);
  262. return false;
  263. }
  264. box.find('.pagination .page-link').on('click', loadLink);
  265. box.find('.grid-column-header a').on('click', loadLink);
  266. box.find('form').on('submit', function () {
  267. load($(this).attr('action')+'&'+$(this).serialize(), box);
  268. return false;
  269. });
  270. box.find('.filter-box .reset').on('click', loadLink);
  271. box.find('.grid-selector a').on('click', loadLink);
  272. Dcat.ready(function () {
  273. setTimeout(function () {
  274. box.find('.grid-refresh').off('click').on('click', function () {
  275. load(box.data('current'), box);
  276. return false;
  277. })
  278. }, 10)
  279. })
  280. }
  281. $(options.container).on('table:load', load);
  282. }
  283. function isTr(v) {
  284. return $(v).prop('tagName').toLocaleLowerCase() === 'tr'
  285. }
  286. function getTier(v) {
  287. return parseInt($(v).data('tier') || 0);
  288. }
  289. function isChildren(parent, child) {
  290. return getTier(child) > getTier(parent);
  291. }
  292. function getChildren(all, parent) {
  293. var arr = [], isBreak = false, firstTr;
  294. all.each(function (_, v) {
  295. // 过滤非tr标签
  296. if (! isTr(v) || isBreak) return;
  297. firstTr || (firstTr = $(v));
  298. // 非连续的子节点
  299. if (firstTr && ! isChildren(parent, firstTr)) {
  300. return;
  301. }
  302. if (isChildren(parent, v)) {
  303. arr.push(v)
  304. } else {
  305. isBreak = true;
  306. }
  307. });
  308. return arr;
  309. }
  310. function swapable(_o, tier) {
  311. if (
  312. _o
  313. && _o.length
  314. && tier === getTier(_o)
  315. ) {
  316. return true
  317. }
  318. }
  319. function sibling(all, tier) {
  320. var next;
  321. all.each(function (_, v) {
  322. if (getTier(v) === tier && ! next && isTr(v)) {
  323. next = $(v);
  324. }
  325. });
  326. return next;
  327. }
  328. Dcat.grid.Tree = function (opts) {
  329. return new Tree(opts);
  330. };
  331. Dcat.grid.Orderable = function (opts) {
  332. return new Orderable(opts);
  333. };
  334. Dcat.grid.AsyncTable =function (opts) {
  335. return new AsyncTable(opts)
  336. }
  337. })(window, jQuery);