grid-extend.js 13 KB

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