grid-extend.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. this._bindClick()
  161. },
  162. _bindClick: function () {
  163. var _this = this;
  164. $(_this.options.button).off('click').click(function () {
  165. if (_this._req) {
  166. return;
  167. }
  168. _this._req = 1;
  169. Dcat.loading();
  170. var $this = $(this);
  171. _this.key = $this.data('id');
  172. _this.direction = $this.data('direction');
  173. _this.row = $this.closest('tr');
  174. _this.tier = getTier(_this.row);
  175. _this._request();
  176. })
  177. },
  178. _request: function () {
  179. var _this = this,
  180. key = _this.key,
  181. row = _this.row,
  182. tier = _this.tier,
  183. direction = _this.direction,
  184. prevAll = row.prevAll(),
  185. nextAll = row.nextAll(),
  186. prev = row.prevAll('tr').first(),
  187. next = row.nextAll('tr').first();
  188. $.ajax({
  189. type: 'POST',
  190. url: _this.options.url.replace(':key', key),
  191. data: {_method:'PUT', _orderable:direction},
  192. success: function(data){
  193. Dcat.loading(false);
  194. _this._req = 0;
  195. if (! data.status) {
  196. return data.message && Dcat.warning(data.message);
  197. }
  198. Dcat.success(data.message);
  199. if (direction) {
  200. var prevRow = sibling(prevAll, tier);
  201. if (swapable(prevRow, tier) && prev.length && getTier(prev) >= tier) {
  202. prevRow.before(row);
  203. // 把所有子节点上移
  204. getChildren(nextAll, row).forEach(function (v) {
  205. prevRow.before(v)
  206. });
  207. }
  208. } else {
  209. var nextRow = sibling(nextAll, tier),
  210. nextRowChildren = nextRow ? getChildren(nextRow.nextAll(), nextRow) : [];
  211. if (swapable(nextRow, tier) && next.length && getTier(next) >= tier) {
  212. nextAll = row.nextAll();
  213. if (nextRowChildren.length) {
  214. nextRow = $(nextRowChildren.pop())
  215. }
  216. // 把所有子节点下移
  217. var all = [];
  218. getChildren(nextAll, row).forEach(function (v) {
  219. all.unshift(v)
  220. });
  221. all.forEach(function(v) {
  222. nextRow.after(v)
  223. });
  224. nextRow.after(row);
  225. }
  226. }
  227. },
  228. error: function (a, b, c) {
  229. _this._req = 0;
  230. Dcat.loading(false);
  231. Dcat.handleAjaxError(a, b, c)
  232. }
  233. });
  234. },
  235. };
  236. /**
  237. * 异步加载表格
  238. *
  239. * @param options
  240. * @constructor
  241. */
  242. function AsyncTable(options) {
  243. options = $.extend({
  244. container: '.table-card',
  245. }, options)
  246. function load(url, box) {
  247. var $this = $(this);
  248. box = box || $this;
  249. url = $this.data('url') || url;
  250. if (! url) {
  251. return;
  252. }
  253. // 缓存当前请求地址
  254. box.attr('data-current', url);
  255. box.loading({background: 'transparent!important'});
  256. Dcat.helpers.asyncRender(url, function (html) {
  257. box.loading(false);
  258. box.html(html);
  259. bind(box);
  260. box.trigger('table:loaded');
  261. });
  262. }
  263. function bind(box) {
  264. function loadLink() {
  265. load($(this).attr('href'), box);
  266. return false;
  267. }
  268. box.find('.pagination .page-link').on('click', loadLink);
  269. box.find('.grid-column-header a').on('click', loadLink);
  270. box.find('form').on('submit', function () {
  271. load($(this).attr('action')+'&'+$(this).serialize(), box);
  272. return false;
  273. });
  274. box.find('.filter-box .reset').on('click', loadLink);
  275. Dcat.ready(function () {
  276. setTimeout(function () {
  277. box.find('.grid-refresh').off('click').on('click', function () {
  278. load(box.data('current'), box);
  279. return false;
  280. })
  281. }, 10)
  282. })
  283. }
  284. $(options.container).on('table:load', load);
  285. }
  286. function isTr(v) {
  287. return $(v).prop('tagName').toLocaleLowerCase() === 'tr'
  288. }
  289. function getTier(v) {
  290. return parseInt($(v).data('tier') || 0);
  291. }
  292. function isChildren(parent, child) {
  293. return getTier(child) > getTier(parent);
  294. }
  295. function getChildren(all, parent) {
  296. var arr = [], isBreak = false, firstTr;
  297. all.each(function (_, v) {
  298. // 过滤非tr标签
  299. if (! isTr(v) || isBreak) return;
  300. firstTr || (firstTr = $(v));
  301. // 非连续的子节点
  302. if (firstTr && ! isChildren(parent, firstTr)) {
  303. return;
  304. }
  305. if (isChildren(parent, v)) {
  306. arr.push(v)
  307. } else {
  308. isBreak = true;
  309. }
  310. });
  311. return arr;
  312. }
  313. function swapable(_o, tier) {
  314. if (
  315. _o
  316. && _o.length
  317. && tier === getTier(_o)
  318. ) {
  319. return true
  320. }
  321. }
  322. function sibling(all, tier) {
  323. var next;
  324. all.each(function (_, v) {
  325. if (getTier(v) === tier && ! next && isTr(v)) {
  326. next = $(v);
  327. }
  328. });
  329. return next;
  330. }
  331. Dcat.grid.Tree = function (opts) {
  332. return new Tree(opts);
  333. };
  334. Dcat.grid.Orderable = function (opts) {
  335. return new Orderable(opts);
  336. };
  337. Dcat.grid.AsyncTable =function (opts) {
  338. return new AsyncTable(opts)
  339. }
  340. })(window, jQuery);