admin.js 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. // +----------------------------------------------------------------------
  2. // | ThinkAdmin
  3. // +----------------------------------------------------------------------
  4. // | 版权所有 2014~2022 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
  5. // +----------------------------------------------------------------------
  6. // | 官方网站: https://thinkadmin.top
  7. // +----------------------------------------------------------------------
  8. // | 开源协议 ( https://mit-license.org )
  9. // | 免费声明 ( https://thinkadmin.top/disclaimer )
  10. // +----------------------------------------------------------------------
  11. // | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
  12. // | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
  13. // +----------------------------------------------------------------------
  14. /*! 数组兼容处理 */
  15. if (typeof Array.prototype.some !== 'function') {
  16. Array.prototype.some = function (callable) {
  17. for (var i in this) if (callable(this[i], i, this) === true) {
  18. return true;
  19. }
  20. return false;
  21. };
  22. }
  23. if (typeof Array.prototype.every !== 'function') {
  24. Array.prototype.every = function (callable) {
  25. for (var i in this) if (callable(this[i], i, this) === false) {
  26. return false;
  27. }
  28. return true;
  29. };
  30. }
  31. if (typeof Array.prototype.forEach !== 'function') {
  32. Array.prototype.forEach = function (callable, context) {
  33. typeof context === "undefined" ? context = window : null;
  34. for (var i in this) callable.call(context, this[i], i, this)
  35. };
  36. }
  37. /*! 应用根路径,静态插件库路径,动态插件库路径 */
  38. var srcs = document.scripts[document.scripts.length - 1].src.split('/');
  39. window.appRoot = srcs.slice(0, -2).join('/') + '/';
  40. window.baseRoot = srcs.slice(0, -1).join('/') + '/';
  41. window.tapiRoot = window.tapiRoot || window.appRoot + "admin";
  42. /*! 挂载 layui & jquery 对象 */
  43. layui.config({base: baseRoot + 'plugs/layui_exts/'});
  44. window.form = layui.form, window.layer = layui.layer;
  45. window.laytpl = layui.laytpl, window.laydate = layui.laydate;
  46. window.jQuery = window.$ = window.jQuery || window.$ || layui.$;
  47. /*! 配置 require 参数 */
  48. require.config({
  49. baseUrl: baseRoot, waitSeconds: 60, map: {'*': {css: baseRoot + 'plugs/require/css.js'}}, paths: {
  50. 'vue': ['plugs/vue/vue.min'],
  51. 'md5': ['plugs/jquery/md5.min'],
  52. 'json': ['plugs/jquery/json.min'],
  53. 'xlsx': ['plugs/jquery/xlsx.min'],
  54. 'excel': ['plugs/jquery/excel.xlsx'],
  55. 'base64': ['plugs/jquery/base64.min'],
  56. 'upload': [tapiRoot + '/api.upload/index?'],
  57. 'notify': ['plugs/notify/notify.min'],
  58. 'angular': ['plugs/angular/angular.min'],
  59. 'cropper': ['plugs/cropper/cropper.min'],
  60. 'echarts': ['plugs/echarts/echarts.min'],
  61. 'ckeditor4': ['plugs/ckeditor4/ckeditor'],
  62. 'ckeditor5': ['plugs/ckeditor5/ckeditor'],
  63. 'websocket': ['plugs/socket/websocket'],
  64. 'pcasunzips': ['plugs/jquery/pcasunzips'],
  65. 'sortablejs': ['plugs/sortable/sortable.min'],
  66. 'vue.sortable': ['plugs/sortable/vue.draggable.min'],
  67. 'jquery.ztree': ['plugs/ztree/ztree.all.min'],
  68. 'jquery.masonry': ['plugs/jquery/masonry.min'],
  69. 'jquery.cropper': ['plugs/cropper/cropper.min'],
  70. 'jquery.autocompleter': ['plugs/jquery/autocompleter.min'],
  71. }, shim: {
  72. 'excel': {deps: [baseRoot + 'plugs/layui_exts/excel.js']},
  73. 'notify': {deps: ['css!' + baseRoot + 'plugs/notify/light.css']},
  74. 'cropper': {deps: ['css!' + baseRoot + 'plugs/cropper/cropper.min.css']},
  75. 'websocket': {deps: [baseRoot + 'plugs/socket/swfobject.min.js']},
  76. 'ckeditor5': {deps: ['jquery', 'upload', 'css!' + baseRoot + 'plugs/ckeditor5/ckeditor.css']},
  77. 'vue.sortable': {deps: ['vue', 'sortablejs']},
  78. 'jquery.ztree': {deps: ['jquery', 'css!' + baseRoot + 'plugs/ztree/zTreeStyle/zTreeStyle.css']},
  79. 'jquery.autocompleter': {deps: ['jquery', 'css!' + baseRoot + 'plugs/jquery/autocompleter.css']},
  80. }
  81. });
  82. /*! 注册 jquery 组件 */
  83. define('jquery', [], function () {
  84. return layui.$;
  85. });
  86. /*! 注册 ckeditor 组件 */
  87. define('ckeditor', (function (type) {
  88. if (/^ckeditor[45]$/.test(type)) return [type];
  89. return [Object.fromEntries ? 'ckeditor5' : 'ckeditor4'];
  90. })(window.taEditor || 'ckeditor4'), function (ckeditor) {
  91. return ckeditor;
  92. });
  93. $(function () {
  94. window.$body = $('body');
  95. /*! 注册单次事件 */
  96. function onEvent(event, select, callable) {
  97. return $body.off(event, select).on(event, select, callable);
  98. }
  99. /*! 注册确认回调 */
  100. function onConfirm(confirm, callable) {
  101. confirm ? $.msg.confirm(confirm, callable) : callable();
  102. }
  103. /*! 获取加载回调 */
  104. onConfirm.getLoadcallable = function (tabldId, callable) {
  105. typeof callable === 'function' && callable();
  106. return tabldId ? function (ret, time) {
  107. if (ret.code < 1) return true;
  108. time === 'false' ? $.layTable.reload(tabldId) : $.msg.success(ret.info, time, function () {
  109. $.layTable.reload(tabldId);
  110. });
  111. return false;
  112. } : false;
  113. }
  114. /*! 读取 data-rule 绑定 table 值 */
  115. function applyRuleValue(elem, data) {
  116. // 新 tableId 规则兼容处理
  117. if (elem.dataset.tableId && elem.dataset.rule) {
  118. var idx1, idx2, temp, regx, field, rule = {};
  119. var json = layui.table.checkStatus(elem.dataset.tableId).data;
  120. layui.each(elem.dataset.rule.split(';'), function (idx, item, attr) {
  121. (attr = item.split('#', 2)), rule[attr[0]] = attr[1];
  122. });
  123. for (idx1 in rule) {
  124. temp = [], regx = new RegExp(/^{(.*?)}$/);
  125. if (regx.test(rule[idx1]) && (field = rule[idx1].replace(regx, '$1'))) {
  126. for (idx2 in json) if (json[idx2][field]) temp.push(json[idx2][field]);
  127. if (temp.length < 1) return $.msg.tips('请选择需要更改的数据!'), false;
  128. data[idx1] = temp.join(',');
  129. } else {
  130. data[idx1] = rule[idx1];
  131. }
  132. }
  133. return data;
  134. } else {
  135. var value = elem.dataset.value || (function (rule, array) {
  136. $(elem.dataset.target || 'input[type=checkbox].list-check-box').map(function () {
  137. this.checked && array.push(this.value);
  138. });
  139. return array.length > 0 ? rule.replace('{key}', array.join(',')) : '';
  140. })(elem.dataset.rule || '', []) || '';
  141. if (value.length < 1) return $.msg.tips('请选择需要更改的数据!'), false;
  142. return value.split(';').forEach(function (item) {
  143. data[item.split('#')[0]] = item.split('#')[1];
  144. }), data;
  145. }
  146. }
  147. /*! 消息组件实例 */
  148. $.msg = new function () {
  149. var that = this;
  150. this.idx = [], this.mdx = [];
  151. this.shade = [0.02, '#000000'];
  152. /*! 关闭消息框 */
  153. this.close = function (idx) {
  154. if (idx !== null) return layer.close(idx);
  155. for (var i in this.idx) that.close(this.idx[i]);
  156. this.idx = [];
  157. };
  158. /*! 弹出警告框 */
  159. this.alert = function (msg, call) {
  160. var idx = layer.alert(msg, {end: call, scrollbar: false});
  161. return that.idx.push(idx), idx;
  162. };
  163. /*! 显示成功类型的消息 */
  164. this.success = function (msg, time, call) {
  165. var idx = layer.msg(msg, {icon: 1, shade: this.shade, scrollbar: false, end: call, time: (time || 2) * 1000, shadeClose: true});
  166. return that.idx.push(idx), idx;
  167. };
  168. /*! 显示失败类型的消息 */
  169. this.error = function (msg, time, call) {
  170. var idx = layer.msg(msg, {icon: 2, shade: this.shade, scrollbar: false, time: (time || 3) * 1000, end: call, shadeClose: true});
  171. return that.idx.push(idx), idx;
  172. };
  173. /*! 状态消息提示 */
  174. this.tips = function (msg, time, call) {
  175. var idx = layer.msg(msg, {time: (time || 3) * 1000, shade: this.shade, end: call, shadeClose: true});
  176. return that.idx.push(idx), idx;
  177. };
  178. /*! 显示加载提示 */
  179. this.loading = function (msg, call) {
  180. var idx = msg ? layer.msg(msg, {icon: 16, scrollbar: false, shade: this.shade, time: 0, end: call}) : layer.load(2, {time: 0, scrollbar: false, shade: this.shade, end: call});
  181. return that.idx.push(idx), idx;
  182. };
  183. /*! 页面加载层 */
  184. this.page = new function () {
  185. this.$body = $('body>.think-page-loader');
  186. this.$main = $('.think-page-body+.think-page-loader');
  187. this.stat = function () {
  188. return this.$body.is(':visible');
  189. }, this.done = function () {
  190. that.page.$body.fadeOut();
  191. }, this.show = function () {
  192. this.stat() || this.$main.removeClass('layui-hide').show();
  193. }, this.hide = function () {
  194. if (this.time) clearTimeout(this.time);
  195. this.time = setTimeout(function () {
  196. (that.page.time = 0) || that.page.$main.fadeOut();
  197. }, 200);
  198. };
  199. };
  200. /*! 确认对话框 */
  201. this.confirm = function (msg, ok, no) {
  202. return layer.confirm(msg, {title: '操作确认', btn: ['确认', '取消']}, function (idx) {
  203. (typeof ok === 'function' && ok.call(this, idx)), that.close(idx);
  204. }, function (idx) {
  205. (typeof no === 'function' && no.call(this, idx)), that.close(idx);
  206. });
  207. };
  208. /*! 自动处理JSON数据 */
  209. this.auto = function (ret, time) {
  210. var url = ret.url || (typeof ret.data === 'string' ? ret.data : '');
  211. var msg = ret.msg || (typeof ret.info === 'string' ? ret.info : '');
  212. if (parseInt(ret.code) === 1 && time === 'false') {
  213. return url ? location.href = url : $.form.reload();
  214. } else return (parseInt(ret.code) === 1) ? this.success(msg, time, function () {
  215. url ? location.href = url : $.form.reload();
  216. that.close($.msg.mdx.length > 0 ? $.msg.mdx.pop() : null);
  217. }) : this.error(msg, 3, function () {
  218. url ? location.href = url : '';
  219. });
  220. };
  221. };
  222. /*! 表单自动化组件 */
  223. $.form = new function () {
  224. var that = this;
  225. /*! 内容区选择器 */
  226. this.selecter = '.layui-layout-admin>.layui-body>.think-page-body';
  227. /*! 刷新当前页面 */
  228. this.reload = function (force) {
  229. if (force) return top.location.reload();
  230. if (self !== top) return location.reload();
  231. return $.menu.href(location.hash);
  232. };
  233. /*! 内容区域动态加载后初始化 */
  234. this.reInit = function ($dom) {
  235. layui.form.render(), layui.element.render(), $(window).trigger('scroll');
  236. $.vali.listen($dom = $dom || $(this.selecter)), $body.trigger('reInit', $dom);
  237. return $dom.find('[required]').map(function () {
  238. this.$parent = $(this).parent();
  239. if (this.$parent.is('label')) this.$parent.addClass('label-required-prev'); else this.$parent.prevAll('label.layui-form-label').addClass('label-required-next');
  240. }), $dom.find('[data-lazy-src]:not([data-lazy-loaded])').map(function () {
  241. if (this.dataset.lazyLoaded === 'true') return; else this.dataset.lazyLoaded = 'true';
  242. if (this.nodeName === 'IMG') this.src = this.dataset.lazySrc; else this.style.backgroundImage = 'url(' + this.dataset.lazySrc + ')';
  243. }), $dom.find('input[data-date-range]').map(function () {
  244. this.setAttribute('autocomplete', 'off'), laydate.render({
  245. type: this.dataset.dateRange || 'date', range: true, elem: this, done: function (value) {
  246. $(this.elem).val(value).trigger('change');
  247. }
  248. });
  249. }), $dom.find('input[data-date-input]').map(function () {
  250. this.setAttribute('autocomplete', 'off'), laydate.render({
  251. type: this.dataset.dateInput || 'date', range: false, elem: this, done: function (value) {
  252. $(this.elem).val(value).trigger('change');
  253. }
  254. });
  255. }), $dom;
  256. };
  257. /*! 在内容区显示视图 */
  258. this.show = function (html) {
  259. that.reInit($(this.selecter).html(html));
  260. };
  261. /*! 异步加载的数据 */
  262. this.load = function (url, data, method, callable, loading, tips, time, headers) {
  263. // 如果主页面 loader 显示中,绝对不显示 loading 图标
  264. loading = $('.layui-page-loader').is(':visible') ? false : loading;
  265. var loadidx = loading !== false ? $.msg.loading(tips) : 0;
  266. if (typeof data === 'object' && typeof data['_token_'] === 'string') {
  267. headers = headers || {}, headers['User-Form-Token'] = data['_token_'], delete data['_token_'];
  268. }
  269. $.ajax({
  270. data: data || {}, type: method || 'GET', url: $.menu.parseUri(url), beforeSend: function (xhr, i) {
  271. if (typeof Pace === 'object' && loading !== false) Pace.restart();
  272. if (typeof headers === 'object') for (i in headers) xhr.setRequestHeader(i, headers[i]);
  273. }, error: function (XMLHttpRequest, $dialog, layIdx, iframe) {
  274. if (parseInt(XMLHttpRequest.status) !== 200 && XMLHttpRequest.responseText.indexOf('Call Stack') > -1) try {
  275. layIdx = layer.open({title: XMLHttpRequest.status + ' - ' + XMLHttpRequest.statusText, type: 2, move: false, content: 'javascript:;'});
  276. layer.full(layIdx), $dialog = $('#layui-layer' + layIdx), iframe = $dialog.find('iframe').get(0);
  277. (iframe.contentDocument || iframe.contentWindow.document).write(XMLHttpRequest.responseText);
  278. $dialog.find('.layui-layer-setwin').css({right: '35px', top: '28px'}).find('a').css({marginLeft: 0});
  279. $dialog.find('.layui-layer-title').css({color: 'red', height: '70px', lineHeight: '70px', fontSize: '22px', textAlign: 'center', fontWeight: 700});
  280. } catch (e) {
  281. layer.close(layIdx);
  282. }
  283. layer.closeAll('loading');
  284. if (parseInt(XMLHttpRequest.status) !== 200) {
  285. $.msg.tips('E' + XMLHttpRequest.status + ' - 服务器繁忙,请稍候再试!');
  286. } else {
  287. this.success(XMLHttpRequest.responseText);
  288. }
  289. }, success: function (ret) {
  290. time = time || ret.wait || undefined;
  291. if (typeof callable === 'function' && callable.call(that, ret, time) === false) return false;
  292. return typeof ret === 'object' ? $.msg.auto(ret, time) : that.show(ret);
  293. }, complete: function () {
  294. $.msg.page.done();
  295. $.msg.close(loadidx);
  296. }
  297. });
  298. };
  299. /*! 以 HASH 打开新网页 */
  300. this.href = function (url, elem) {
  301. this.isMenu = elem && elem.dataset.menuNode;
  302. if (this.isMenu) layui.sessionData('pages', null);
  303. if (url !== '#') return location.hash = $.menu.parseUri(url, elem);
  304. if (this.isMenu) return $('[data-menu-node^="' + elem.dataset.menuNode + '-"]:first').trigger('click');
  305. };
  306. /*! 加载 HTML 到 BODY 位置 */
  307. this.open = function (url, data, call, load, tips) {
  308. this.load(url, data, 'get', function (ret) {
  309. return (typeof ret === 'object' ? $.msg.auto(ret) : that.show(ret)), false;
  310. }, load, tips);
  311. };
  312. /*! 打开 IFRAME 窗口 */
  313. this.iframe = function (url, name, area, offset, destroy, success, isfull) {
  314. this.idx = layer.open({title: name || '窗口', type: 2, area: area || ['800px', '580px'], end: destroy || null, offset: offset, fixed: true, maxmin: false, content: url, success: success});
  315. return isfull && layer.full(this.idx), this.idx;
  316. };
  317. /*! 加载 HTML 到弹出层 */
  318. this.modal = function (url, data, name, call, load, tips, area, offset, isfull) {
  319. this.load(url, data, 'GET', function (res) {
  320. if (typeof res === 'object') return $.msg.auto(res), false;
  321. return $.msg.mdx.push(this.idx = layer.open({
  322. type: 1, btn: false, area: area || "800px", resize: false, content: res, title: name || '', offset: offset || 'auto', success: function ($dom, idx) {
  323. typeof call === 'function' && call.call(that, $dom);
  324. $.form.reInit($dom.off('click', '[data-close]').on('click', '[data-close]', function () {
  325. onConfirm(this.dataset.confirm, function () {
  326. layer.close(idx);
  327. });
  328. }));
  329. }
  330. })), isfull && layer.full(this.idx), false;
  331. }, load, tips);
  332. };
  333. };
  334. /*! 后台菜单辅助插件 */
  335. $.menu = new function () {
  336. var that = this;
  337. /*! 计算 URL 地址中有效的 URI */
  338. this.getUri = function (uri) {
  339. uri = uri || location.href;
  340. uri = uri.indexOf(location.host) > -1 ? uri.split(location.host)[1] : uri;
  341. return (uri.indexOf('#') > -1 ? uri.split('#')[1] : uri).split('?')[0];
  342. };
  343. /*! 通过 URI 查询最佳菜单 NODE */
  344. this.queryNode = function (uri, node) {
  345. if (!/^m-/.test(node = node || location.href.replace(/.*spm=([\d\-m]+).*/ig, '$1'))) {
  346. var $menu = $('[data-menu-node][data-open*="' + uri.replace(/\.html$/ig, '') + '"]');
  347. return $menu.size() ? $menu.get(0).dataset.menuNode : '';
  348. }
  349. return node;
  350. };
  351. /*! 完整 URL 转 URI 地址 */
  352. this.parseUri = function (uri, elem, vars, temp, attrs) {
  353. vars = {}, attrs = [], elem = elem || document.createElement('a');
  354. if (uri.indexOf('?') > -1) uri.split('?')[1].split('&').forEach(function (item) {
  355. if (item.indexOf('=') > -1 && (temp = item.split('=')) && typeof temp[0] === 'string' && temp[0].length > 0) {
  356. vars[temp[0]] = encodeURIComponent(decodeURIComponent(temp[1].replace(/%2B/ig, '%20')));
  357. }
  358. });
  359. uri = this.getUri(uri);
  360. if (typeof vars.spm !== 'string') vars.spm = elem.dataset.menuNode || this.queryNode(uri) || '';
  361. if (typeof vars.spm !== 'string' || vars.spm.length < 1) delete vars.spm;
  362. for (var i in vars) attrs.push(i + '=' + vars[i]);
  363. return uri + (attrs.length > 0 ? '?' + attrs.join('&') : '');
  364. };
  365. /*! 后台菜单动作初始化 */
  366. this.listen = function () {
  367. var layout = $('.layui-layout-admin'), mclass = 'layui-layout-left-mini';
  368. /*! 菜单切及MiniTips处理 */
  369. onEvent('click', '[data-target-menu-type]', function () {
  370. layui.data('AdminMenuType', {key: 'mini', value: layout.toggleClass(mclass).hasClass(mclass)});
  371. }).on('click', '[data-submenu-layout]>a', function () {
  372. setTimeout("$.menu.sync(1)", 100);
  373. }).on('mouseenter', '[data-target-tips]', function (evt) {
  374. if (!layout.hasClass(mclass) || !this.dataset.targetTips) return;
  375. evt.idx = layer.tips(this.dataset.targetTips, this, {time: 0});
  376. $(this).mouseleave(function () {
  377. layer.close(evt.idx);
  378. });
  379. });
  380. /*! 监听窗口大小及HASH切换 */
  381. $(window).on('resize', function () {
  382. (layui.data('AdminMenuType')['mini'] || $body.width() < 1000) ? layout.addClass(mclass) : layout.removeClass(mclass);
  383. }).trigger('resize').on('hashchange', function () {
  384. if (/^#(https?:)?(\/\/|\\\\)/.test(location.hash)) return $.msg.tips('禁止访问外部链接!');
  385. if (location.hash.length < 1) return $body.find('[data-menu-node]:first').trigger('click'); else return that.href(location.hash);
  386. }).trigger('hashchange');
  387. };
  388. /*! 同步二级菜单展示状态 */
  389. this.sync = function (mode) {
  390. $('[data-submenu-layout]').map(function () {
  391. var node = this.dataset.submenuLayout;
  392. if (mode === 1) layui.data('AdminMenuState', {key: node, value: $(this).hasClass('layui-nav-itemed') ? 2 : 1}); else if (mode === 2) (layui.data('AdminMenuState')[node] || 2) === 2 && $(this).addClass('layui-nav-itemed');
  393. });
  394. };
  395. /*! 页面 LOCATION-HASH 跳转 */
  396. this.href = function (hash, node) {
  397. if ((hash || '').length < 1) return $('[data-menu-node]:first').trigger('click');
  398. // $.msg.page.show(),$.form.load(hash, {}, 'get', $.msg.page.hide, true),that.sync(2);
  399. $.form.load(hash, {}, 'get', false, !$.msg.page.stat()), that.sync(2);
  400. /*! 菜单选择切换 */
  401. if (/^m-/.test(node = node || that.queryNode(that.getUri()))) {
  402. var arr = node.split('-'), tmp = arr.shift(), $all = $('a[data-menu-node]').parent('.layui-this');
  403. while (arr.length > 0) {
  404. tmp = tmp + '-' + arr.shift();
  405. $all = $all.not($('a[data-menu-node="' + tmp + '"]').parent().addClass('layui-this'));
  406. }
  407. $all.removeClass('layui-this');
  408. /*! 菜单模式切换 */
  409. if (node.split('-').length > 2) {
  410. var _tmp = node.split('-'), _node = _tmp.shift() + '-' + _tmp.shift();
  411. $('[data-menu-layout]').not($('[data-menu-layout="' + _node + '"]').removeClass('layui-hide')).addClass('layui-hide');
  412. $('[data-menu-node="' + node + '"]').parent().parent().parent().addClass('layui-nav-itemed');
  413. $('.layui-layout-admin').removeClass('layui-layout-left-hide');
  414. } else {
  415. $('.layui-layout-admin').addClass('layui-layout-left-hide');
  416. }
  417. setTimeout("$.menu.sync(1);", 100);
  418. }
  419. };
  420. };
  421. /*! 表单验证组件 */
  422. $.vali = function (form, callable) {
  423. return $(form).data('validate') || new Validate();
  424. function Validate() {
  425. var that = this;
  426. /* 绑定表单元素 */
  427. this.form = $(form);
  428. /* 绑定元素事件, 筛选表单元素 */
  429. this.evts = 'blur change';
  430. this.tags = 'input,select,textarea';
  431. /* 预设检测规则 */
  432. this.patterns = {
  433. phone: '^1[3-9][0-9]{9}$', email: '^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$'
  434. };
  435. /*! 检测属性是否有定义 */
  436. this.hasProp = function (ele, prop) {
  437. var attrProp = ele.getAttribute(prop);
  438. return typeof attrProp !== 'undefined' && attrProp !== null && attrProp !== false;
  439. }, this.isRegex = function (ele) {
  440. var real = $.trim($(ele).val());
  441. var regexp = ele.getAttribute('pattern');
  442. regexp = this.patterns[regexp] || regexp;
  443. if (real === "" || !regexp) return true;
  444. return new RegExp(regexp, 'i').test(real);
  445. }, this.checkAllInput = function () {
  446. var status = true;
  447. return that.form.find(this.tags).each(function () {
  448. if (that.checkInput(this) === false) return $(this).focus(), status = false;
  449. }), status;
  450. }, this.checkInput = function (input) {
  451. if (this.hasProp(input, 'data-auto-none')) return true;
  452. var type = (input.getAttribute('type') || '').replace(/\W+/, "").toLowerCase();
  453. var ingores = ['file', 'reset', 'image', 'radio', 'checkbox', 'submit', 'hidden'];
  454. if (ingores.length > 0) for (var i in ingores) if (type === ingores[i]) return true;
  455. if (this.hasProp(input, 'required') && $.trim($(input).val()) === '') return this.remind(input);
  456. return this.isRegex(input) ? (this.hideError(input), true) : this.remind(input);
  457. }, this.remind = function (input) {
  458. if (!$(input).is(':visible')) return true;
  459. return this.showError(input, input.getAttribute('title') || input.getAttribute('placeholder') || '输入错误'), false;
  460. }, this.showError = function (ele, tip) {
  461. $(ele).addClass('validate-error');
  462. this.insertError(ele).addClass('layui-anim-fadein').css({width: 'auto'}).html(tip);
  463. }, this.hideError = function (ele) {
  464. $(ele).removeClass('validate-error');
  465. this.insertError(ele).removeClass('layui-anim-fadein').css({width: '30px'}).html('');
  466. }, this.insertError = function (ele) {
  467. if ($(ele).data('input-info')) return $(ele).data('input-info');
  468. var $html = $('<span class="absolute block layui-anim text-center font-s12 notselect" style="color:#A44;z-index:2"></span>');
  469. var $next = $(ele).nextAll('.input-right-icon'), right = ($next ? $next.width() + parseFloat($next.css('right') || '0') : 0) + 10;
  470. var style = {top: $(ele).position().top + 'px', right: right + 'px', lineHeight: ele.nodeName === 'TEXTAREA' ? '32px' : $(ele).css('height')};
  471. return $(ele).data('input-info', $html.css(style).insertAfter(ele)), $html;
  472. };
  473. /*! 表单元素验证 */
  474. this.form.attr({onsubmit: 'return false', novalidate: 'novalidate', autocomplete: 'off'});
  475. this.form.off(this.evts, this.tags).on(this.evts, this.tags, function () {
  476. that.checkInput(this);
  477. }).data('validate', this).bind("submit", function (evt) {
  478. evt.button = that.form.find('button[type=submit],button:not([type=button])');
  479. /* 检查所有表单元素是否通过H5的规则验证 */
  480. if (that.checkAllInput() && typeof callable === 'function') {
  481. if (typeof CKEDITOR === 'object' && typeof CKEDITOR.instances === 'object') {
  482. for (var i in CKEDITOR.instances) CKEDITOR.instances[i].updateElement();
  483. }
  484. /* 触发表单提交后,锁定三秒不能再次提交表单 */
  485. if (that.form.attr('submit-locked')) return false;
  486. that.form.attr('submit-locked', 1), evt.button.addClass('submit-button-loading');
  487. callable.call(this, that.form.formToJson(), []), setTimeout(function () {
  488. that.form.removeAttr('submit-locked'), evt.button.removeClass('submit-button-loading');
  489. }, 3000);
  490. }
  491. return evt.preventDefault(), false;
  492. }).find('[data-form-loaded]').map(function () {
  493. $(this).html(this.dataset.formLoaded || this.innerHTML);
  494. $(this).removeAttr('data-form-loaded').removeClass('layui-disabled');
  495. });
  496. }
  497. };
  498. /*! 自动监听表单 */
  499. $.vali.listen = function ($dom, $els) {
  500. $els = $($dom || $body).find('form[data-auto]');
  501. $dom && $($dom).filter('form[data-auto]') && $els.add($dom);
  502. $els.size() > 0 && $els.map(function (idx, form) {
  503. $(this).vali(function (data) {
  504. var emap = form.dataset, type = form.method || 'POST', href = form.action || location.href;
  505. var tips = emap.tips || undefined, time = emap.time || undefined, taid = emap.tableId || false;
  506. var call = window[emap.callable || '_default_callable'] || (taid ? function (ret) {
  507. if (typeof ret === 'object' && ret.code > 0 && $('#' + taid).size() > 0) {
  508. return $.msg.success(ret.info, 3, function () {
  509. (typeof ret.data === 'string' && ret.data) ? location.href = ret.data : $.layTable.reload(taid);
  510. $.msg.close($.msg.mdx.length > 0 ? $.msg.mdx.pop() : null);
  511. }) && false;
  512. }
  513. } : undefined);
  514. onConfirm(emap.confirm, function () {
  515. $.form.load(href, data, type, call, true, tips, time);
  516. });
  517. });
  518. });
  519. };
  520. /*! 注册对象到JqFn */
  521. $.fn.vali = function (callable) {
  522. return this.each(function () {
  523. $.vali(this, callable);
  524. });
  525. };
  526. /*! 表单转JSON */
  527. $.fn.formToJson = function () {
  528. var self = this, data = {}, push = {};
  529. var rules = {key: /[a-zA-Z0-9_]+|(?=\[])/g, push: /^$/, fixed: /^\d+$/, named: /^[a-zA-Z0-9_]+$/};
  530. this.build = function (base, key, value) {
  531. return (base[key] = value), base;
  532. }, this.pushCounter = function (name) {
  533. if (push[name] === undefined) push[name] = 0;
  534. return push[name]++;
  535. }, $.each($(this).serializeArray(), function () {
  536. var key, keys = this.name.match(rules.key), merge = this.value, name = this.name;
  537. while ((key = keys.pop()) !== undefined) {
  538. name = name.replace(new RegExp("\\[" + key + "\\]$"), '');
  539. if (key.match(rules.push)) merge = self.build([], self.pushCounter(name), merge); else if (key.match(rules.fixed)) merge = self.build([], key, merge); else if (key.match(rules.named)) merge = self.build({}, key, merge);
  540. }
  541. data = $.extend(true, data, merge);
  542. });
  543. return data;
  544. };
  545. /*! 全局文件上传插件 */
  546. $.fn.uploadFile = function (callable, initialize) {
  547. return this.each(function () {
  548. if ($(this).data('inited')) return false;
  549. var that = $(this), mult = '|one|btn|'.indexOf(that.data('file') || 'one') > -1 ? 0 : 1;
  550. that.data('inited', true).data('multiple', mult), require(['upload'], function (apply) {
  551. apply(that, callable), (typeof initialize === 'function' && setTimeout(initialize, 100));
  552. });
  553. });
  554. };
  555. /*! 上传单张图片 */
  556. $.fn.uploadOneImage = function () {
  557. return this.each(function () {
  558. if ($(this).data('inited')) return true; else $(this).data('inited', true);
  559. var $in = $(this), $bt = $('<a data-file class="uploadimage transition"><span class="layui-icon">&#x1006;</span><span class="layui-icon">&#xe615;</span></a>').data('input', this);
  560. $bt.attr('data-size', $in.data('size') || 0).attr('data-type', $in.data('type') || 'png,jpg,gif,jpeg').find('span').on('click', function (event) {
  561. event.stopPropagation();
  562. if ($(this).index() === 0) $bt.attr('style', ''), $in.val(''); else $in.val() && $.previewImage(encodeURI($in.val()));
  563. }), $in.on('change', function () {
  564. if (this.value) $bt.css('backgroundImage', 'url(' + encodeURI(this.value) + ')');
  565. }).after($bt).trigger('change');
  566. });
  567. };
  568. /*! 上传多张图片 */
  569. $.fn.uploadMultipleImage = function () {
  570. return this.each(function () {
  571. if ($(this).data('inited')) return true; else $(this).data('inited', true);
  572. var $in = $(this), $bt = $('<a data-file="mul" class="uploadimage"></a>'), imgs = this.value ? this.value.split('|') : []
  573. $in.after($bt.attr('data-size', $in.data('size') || 0).attr('data-type', $in.data('type') || 'gif,png,jpg,jpeg').uploadFile(function (src) {
  574. imgs.push(src), $in.val(imgs.join('|')), showImageContainer([src]);
  575. })), (imgs.length > 0 && showImageContainer(imgs));
  576. function showImageContainer(srcs) {
  577. $(srcs).each(function (idx, src, $image) {
  578. $image = $('<div class="uploadimage uploadimagemtl transition"><div><a class="layui-icon">&#xe603;</a><a class="layui-icon">&#x1006;</a><a class="layui-icon">&#xe602;</a></div></div>');
  579. $image.attr('data-tips-image', encodeURI(src)).css('backgroundImage', 'url(' + encodeURI(src) + ')').on('click', 'a', function (event, index, prevs, $item) {
  580. event.stopPropagation(), $item = $(this).parent().parent(), index = $(this).index();
  581. if (index === 2 && $item.index() !== $bt.prevAll('div.uploadimage').length) $item.next().after($item); else if (index === 0 && $item.index() > 1) $item.prev().before($item); else if (index === 1) $item.remove();
  582. imgs = [], $bt.prevAll('.uploadimage').map(function () {
  583. imgs.push($(this).attr('data-tips-image'));
  584. });
  585. imgs.reverse(), $in.val(imgs.join('|'));
  586. }), $bt.before($image);
  587. });
  588. }
  589. });
  590. };
  591. /*! 上传单个视频 */
  592. $.fn.uploadOneVideo = function () {
  593. return this.each(function () {
  594. if ($(this).data('inited')) return true; else $(this).data('inited', true);
  595. var $in = $(this), $bt = $('<a data-file class="uploadimage uploadvideo transition"><span class="layui-icon">&#x1006;</span><span class="layui-icon">&#xe615;</span></a>').data('input', this);
  596. $bt.attr('data-size', $in.data('size') || 0).attr('data-type', $in.data('type') || 'mp4').find('span').on('click', function (event) {
  597. event.stopPropagation();
  598. if ($(this).index() === 0) $bt.attr('style', ''), $in.val(''); else $in.val() && $.previewImage(encodeURI($in.val()));
  599. }), $in.on('change', function () {
  600. if (this.value) $bt.html('<video width="76" height="76" controls><source src="' + encodeURI(this.value) + '" type="video/mp4"></video>');
  601. }).after($bt).trigger('change');
  602. });
  603. };
  604. /*! 标签输入插件 */
  605. $.fn.initTagInput = function () {
  606. return this.each(function () {
  607. var $this = $(this), tags = this.value ? this.value.split(',') : [];
  608. var $text = $('<textarea class="layui-input layui-input-inline layui-tag-input"></textarea>');
  609. var $tags = $('<div class="layui-tags"></div>').append($text);
  610. $this.parent().append($tags), $text.off('keydown blur'), (tags.length > 0 && showTags(tags));
  611. $text.on('blur keydown', function (event, value) {
  612. if (event.keyCode === 13 || event.type === 'blur') {
  613. event.preventDefault(), (value = $text.val().replace(/^\s*|\s*$/g, ''));
  614. if (tags.indexOf($(this).val()) > -1) return layer.msg('该标签已经存在!');
  615. if (value.length > 0) tags.push(value), $this.val(tags.join(',')), showTags([value]), this.focus(), $text.val('');
  616. }
  617. });
  618. function showTags(tagsArr) {
  619. $(tagsArr).each(function (idx, text, elem) {
  620. elem = $('<div class="layui-tag"></div>').html(text + '<i class="layui-icon">&#x1006;</i>');
  621. elem.on('click', 'i', function (tagText, tagIdx) {
  622. tagText = $(this).parent().text(), tagIdx = tags.indexOf(tagText);
  623. tags.splice(tagIdx, 1), $(this).parent().remove(), $this.val(tags.join(','));
  624. }), $tags.append(elem, $text);
  625. });
  626. }
  627. });
  628. };
  629. /*! 文本框插入内容 */
  630. $.fn.insertAtCursor = function (value) {
  631. return this.each(function () {
  632. this.focus();
  633. if (document.selection) {
  634. var selection = document.selection.createRange();
  635. (selection.text = value), selection.select(), selection.unselect();
  636. } else if (this.selectionStart || this.selectionStart === 0) {
  637. var spos = this.selectionStart, apos = this.selectionEnd || spos;
  638. this.value = this.value.substring(0, spos) + value + this.value.substring(apos);
  639. this.selectionEnd = this.selectionStart = spos + value.length;
  640. } else {
  641. this.value += value;
  642. }
  643. this.focus();
  644. });
  645. };
  646. /*! 组件 layui.table 封装 */
  647. $.fn.layTable = function (params) {
  648. return this.each(function () {
  649. $.layTable.create(this, params);
  650. });
  651. };
  652. $.layTable = new function () {
  653. this.render = function (tabldId) {
  654. return this.reload(tabldId, true);
  655. }, this.reload = function (tabldId, force) {
  656. return typeof tabldId === 'string' ? $('#' + tabldId).trigger(force ? 'render' : 'reload') : $.form.reload();
  657. }, this.create = function (table, params) {
  658. // 动态初始化表格
  659. table.id = table.id || 't' + Math.random().toString().replace('.', '');
  660. var $table = $(table).attr('lay-filter', table.dataset.id = table.getAttribute('lay-filter') || table.id);
  661. // 插件初始化参数
  662. var option = params || {}, data = option.where || {}, sort = option.initSort || option.sort || {};
  663. option.id = table.id, option.elem = table, option.url = params.url || table.dataset.url || location.href;
  664. option.limit = params.limit || 20, option.loading = params.loading !== false, option.autoSort = params.autoSort === true;
  665. option.page = params.page !== false ? (params.page || true) : false, option.cols = params.cols || [[]], option.success = params.done || '';
  666. // 初始化不显示头部
  667. var cls = ['.layui-table-header', '.layui-table-fixed', '.layui-table-body', '.layui-table-page'];
  668. option.css = (option.css || '') + cls.join('{opacity:0}') + '{opacity:0}';
  669. // 默认动态设置页数, 动态设置最大高度
  670. if (option.page === true) option.page = {curr: layui.sessionData('pages')[option.id] || 1};
  671. if (option.height === 'full') if ($table.parents('.iframe-pagination').size()) {
  672. $table.parents('.iframe-pagination').addClass('not-footer');
  673. option.height = $(window).height() - $table.removeClass('layui-hide').offset().top - 20;
  674. } else {
  675. option.height = $(window).height() - $table.removeClass('layui-hide').offset().top - 35;
  676. }
  677. // 动态计算最大页数
  678. option.done = function () {
  679. typeof option.success === 'function' && option.success.call(this);
  680. layui.sessionData('pages', {key: table.id, value: this.page.curr || 1});
  681. $.form.reInit($table.next()).find('[data-load],[data-queue],[data-action],[data-iframe]').not('[data-table-id]').attr('data-table-id', table.id);
  682. (option.loading = this.loading = true) && $table.data('next', this).next().find(cls.join(',')).animate({opacity: 1});
  683. }, option.parseData = function (res) {
  684. if (typeof params.filter === 'function') {
  685. res.data = params.filter(res.data, res);
  686. }
  687. if (!this.page || !this.page.curr) return res;
  688. var curp = this.page.curr, maxp = Math.ceil(res.count / option.limit);
  689. if (curp > maxp && maxp > 1) $table.trigger('reload', {page: {curr: maxp}});
  690. return res;
  691. };
  692. // 关联搜索表单
  693. var sform, search = params.search || table.dataset.targetSearch;
  694. if (search) (sform = $body.find(search)).map(function () {
  695. $(this).attr('data-table-id', table.id);
  696. });
  697. // 关联绑定选择项
  698. var checked = params.checked || table.dataset.targetChecked;
  699. if (checked) $body.find(checked).map(function () {
  700. $(this).attr('data-table-id', table.id);
  701. });
  702. // 实例并绑定事件
  703. $table.data('this', layui.table.render(bindData(option)));
  704. $table.bind('reload render reloadData', function (evt, opts) {
  705. data = $.extend({}, data, (opts = opts || {}).where || {});
  706. opts = bindData($.extend({}, opts, {loading: true}));
  707. if (evt.type.indexOf('reload') > -1) {
  708. var $next = $table.data('next');
  709. if ($next && $next.page && $next.page.jump) {
  710. $next.sort = $next.initSort = opts.initSort, $next.where = data;
  711. if (opts.page && opts.page.curr) $next.page.curr = opts.page.curr || 1;
  712. $next.page.jump({curr: $next.page.curr, limit: option.limit});
  713. } else {
  714. layui.table.reloadData(table.id, opts);
  715. }
  716. } else {
  717. layui.table.reload(table.id, opts);
  718. }
  719. }).bind('row sort tool edit radio toolbar checkbox rowDouble', function (evt, call) {
  720. layui.table.on(evt.type + '(' + table.dataset.id + ')', call)
  721. }).bind('setFullHeight', function () {
  722. $table.trigger('render', {height: $(window).height() - $table.next().offset().top - 35})
  723. }).trigger('sort', function (rets) {
  724. (sort = rets), $table.trigger('reload')
  725. });
  726. return $table;
  727. // 生成初始化参数
  728. function bindData(options) {
  729. data['output'] = 'layui.table';
  730. if (sort.field && sort.type) {
  731. data['_order_'] = sort.type, data['_field_'] = sort.field;
  732. options.initSort = {type: sort.type.split(',')[0].split(' ')[0], field: sort.field.split(',')[0].split(' ')[0]};
  733. if (sform) $(sform).find('[data-form-export]').attr('data-sort-field', sort.field).attr('data-sort-type', sort.type);
  734. }
  735. if (options.page === false) options.limit = '';
  736. return (options['where'] = data), options;
  737. }
  738. };
  739. };
  740. /*! 弹出图片层 */
  741. $.previewImage = function (src, area) {
  742. var img = new Image(), defer = $.Deferred(), loaded = $.msg.loading();
  743. img.style.background = '#FFF', img.referrerPolicy = 'no-referrer';
  744. img.style.height = 'auto', img.style.width = area || '100%', img.style.display = 'none';
  745. return document.body.appendChild(img), img.onerror = function () {
  746. $.msg.close(loaded), defer.reject();
  747. }, img.src = src, img.onload = function () {
  748. layer.open({
  749. type: 1, title: false, shadeClose: true, content: $(img), success: function ($elem, idx) {
  750. $.msg.close(loaded), defer.notify($elem, idx);
  751. }, area: area || '480px', skin: 'layui-layer-nobg', closeBtn: 1, end: function () {
  752. document.body.removeChild(img), defer.resolve()
  753. }
  754. });
  755. }, defer.promise();
  756. };
  757. /*! 以手机模式显示内容 */
  758. $.previewPhonePage = function (href, title) {
  759. var template = '<div class="mobile-preview"><div class="mobile-header">{{d.title}}</div><div class="mobile-body"><iframe src="{{d.url}}"></iframe></div></div>';
  760. layer.style(layer.open({type: true, resize: false, scrollbar: false, area: ['320px', '600px'], title: false, closeBtn: true, shadeClose: false, skin: 'layui-layer-nobg', content: laytpl(template).render({title: title || '公众号', url: href})}), {boxShadow: 'none'});
  761. };
  762. /*! 显示任务进度消息 */
  763. $.loadQueue = function (code, doScript, element) {
  764. var doAjax = true, doReload = false;
  765. layer.open({
  766. type: 1, title: false, area: ['560px', '315px'], anim: 2, shadeClose: false, end: function () {
  767. doAjax = false;
  768. if (doReload && doScript) {
  769. $.layTable.reload(((element || {}).dataset || {}).tableId || true);
  770. }
  771. }, content: '' + '<div class="padding-30 padding-bottom-0" data-queue-load="' + code + '">' + ' <div class="layui-elip notselect nowrap" data-message-title></div>' + ' <div class="margin-top-15 layui-progress layui-progress-big" lay-showPercent="yes"><div class="layui-progress-bar transition" lay-percent="0.00%"></div></div>' + ' <div class="margin-top-15"><code class="layui-textarea layui-bg-black border-0" disabled style="resize:none;overflow:hidden;height:190px"></code></div>' + '</div>', success: function ($elem) {
  772. new function () {
  773. var that = this;
  774. this.$box = $elem.find('[data-queue-load=' + code + ']');
  775. if (doAjax === false || this.$box.length < 1) return false;
  776. this.$coder = this.$box.find('code'), this.$name = this.$box.find('[data-message-title]');
  777. this.$percent = this.$box.find('.layui-progress div'), this.SetCache = function (code, index, value) {
  778. var ckey = code + '_' + index, ctype = 'admin-queue-script';
  779. return value !== undefined ? layui.data(ctype, {key: ckey, value: value}) : layui.data(ctype)[ckey] || 0;
  780. }, this.SetState = function (status, message) {
  781. if (message.indexOf('javascript:') === -1) if (status === 1) {
  782. that.$name.html('<b class="color-text">' + message + '</b>').addClass('text-center');
  783. that.$percent.addClass('layui-bg-blue').removeClass('layui-bg-green layui-bg-red');
  784. } else if (status === 2) {
  785. if (message.indexOf('>>>') > -1) {
  786. that.$name.html('<b class="color-blue">' + message + '</b>').addClass('text-center');
  787. } else {
  788. that.$name.html('<b class="color-blue">正在处理:</b>' + message).removeClass('text-center');
  789. }
  790. that.$percent.addClass('layui-bg-blue').removeClass('layui-bg-green layui-bg-red');
  791. } else if (status === 3) {
  792. doReload = true;
  793. that.$name.html('<b class="color-green">' + message + '</b>').addClass('text-center');
  794. that.$percent.addClass('layui-bg-green').removeClass('layui-bg-blue layui-bg-red');
  795. } else if (status === 4) {
  796. that.$name.html('<b class="color-red">' + message + '</b>').addClass('text-center');
  797. that.$percent.addClass('layui-bg-red').removeClass('layui-bg-blue layui-bg-green');
  798. }
  799. }, (this.LoadProgress = function () {
  800. if (doAjax === false || that.$box.length < 1) return false;
  801. $.form.load(tapiRoot + '/api.queue/progress', {code: code}, 'post', function (ret) {
  802. if (ret.code) {
  803. var lines = [];
  804. for (var idx in ret.data.history) {
  805. var line = ret.data.history[idx], percent = '[ ' + line.progress + '% ] ';
  806. if (line.message.indexOf('javascript:') === -1) lines.push(line.message.indexOf('>>>') > -1 ? line.message : percent + line.message); else if (!that.SetCache(code, idx) && doScript !== false) that.SetCache(code, idx, 1), location.href = line.message;
  807. }
  808. if (ret.data.status > 0) {
  809. that.SetState(parseInt(ret.data.status), ret.data.message);
  810. that.$percent.attr('lay-percent', (parseFloat(ret.data.progress || '0.00').toFixed(2)) + '%'), layui.element.render();
  811. that.$coder.html('<p class="layui-elip">' + lines.join('</p><p class="layui-elip">') + '</p>').animate({scrollTop: that.$coder[0].scrollHeight + 'px'}, 200);
  812. return parseInt(ret.data.status) === 3 || parseInt(ret.data.status) === 4 || setTimeout(that.LoadProgress, Math.floor(Math.random() * 200)), false;
  813. } else return setTimeout(that.LoadProgress, Math.floor(Math.random() * 500) + 200), false;
  814. }
  815. }, false);
  816. })();
  817. };
  818. }
  819. });
  820. };
  821. /*! 注册 data-search 表单搜索行为 */
  822. onEvent('submit', 'form.form-search', function () {
  823. if (this.dataset.tableId) return $('table#' + this.dataset.tableId).trigger('reload', {
  824. page: {curr: 1}, where: $(this).formToJson()
  825. });
  826. var url = $(this).attr('action').replace(/&?page=\d+/g, '');
  827. if ((this.method || 'get').toLowerCase() === 'get') {
  828. var split = url.indexOf('?') > -1 ? '&' : '?', stype = location.href.indexOf('spm=') > -1 ? '#' : '';
  829. return location.href = stype + $.menu.parseUri(url + split + $(this).serialize().replace(/\+/g, ' '));
  830. }
  831. return $.form.load(url, this, 'post');
  832. });
  833. /*! 注册 data-file 事件行为 */
  834. onEvent('click', '[data-file]', function () {
  835. if ($(this).data('inited') !== true) (function (that) {
  836. that.uploadFile(undefined, function () {
  837. that.trigger('upload.start');
  838. });
  839. })($(this));
  840. });
  841. /*! 注册 data-load 事件行为 */
  842. onEvent('click', '[data-load]', function () {
  843. var emap = this.dataset, data = {};
  844. if (emap.rule && (applyRuleValue(this, data)) === false) return false; else onConfirm(emap.confirm, function () {
  845. $.form.load(emap.load, data, 'get', onConfirm.getLoadcallable(emap.tableId), true, emap.tips, emap.time);
  846. });
  847. });
  848. /*! 注册 data-reload 事件行为 */
  849. onEvent('click', '[data-reload]', function () {
  850. $.layTable.reload(this.dataset.tableId || true);
  851. });
  852. /*! 注册 data-dbclick 事件行为 */
  853. onEvent('dblclick', '[data-dbclick]', function () {
  854. $(this).find(this.dataset.dbclick || '[data-dbclick]').trigger('click');
  855. });
  856. /*! 注册 data-check 事件行为 */
  857. onEvent('click', '[data-check-target]', function () {
  858. var target = this;
  859. $(this.dataset.checkTarget).map(function () {
  860. (this.checked = !!target.checked), $(this).trigger('change');
  861. });
  862. });
  863. /*! 表单元素失去焦点时数字 */
  864. onEvent('blur', '[data-blur-number]', function () {
  865. var emap = this.dataset, min = emap.valueMin, max = emap.valueMax;
  866. var value = parseFloat(this.value) || 0, fiexd = parseInt(emap.blurNumber || 0);
  867. if (typeof min !== 'undefined' && value < min) value = min;
  868. if (typeof max !== 'undefined' && value > max) value = max;
  869. this.value = parseFloat(value).toFixed(fiexd);
  870. });
  871. /*! 表单元素失焦时提交 */
  872. onEvent('blur', '[data-action-blur],[data-blur-action]', function () {
  873. var that = $(this), emap = this.dataset, data = {'_token_': emap.token || emap.csrf || '--'};
  874. var attrs = (emap.value || '').replace('{value}', that.val()).split(';');
  875. for (var i in attrs) data[attrs[i].split('#')[0]] = attrs[i].split('#')[1];
  876. onConfirm(emap.confirm, function () {
  877. $.form.load(emap.actionBlur || emap.blurAction, data, emap.method || 'post', function (ret) {
  878. return that.css('border', (ret && ret.code) ? '1px solid #e6e6e6' : '1px solid red') && false;
  879. }, emap.loading !== 'false', emap.loading, emap.time);
  880. });
  881. });
  882. /*! 注册 data-href 事件行为 */
  883. onEvent('click', '[data-href]', function () {
  884. if (this.dataset.href && this.dataset.href.indexOf('#') !== 0) {
  885. location.href = this.dataset.href;
  886. }
  887. });
  888. /*! 注册 data-open 事件行为 */
  889. onEvent('click', '[data-open]', function () {
  890. if (this.dataset.open.match(/^https?:/)) {
  891. location.href = this.dataset.open;
  892. } else {
  893. $.form.href(this.dataset.open, this);
  894. }
  895. });
  896. /*! 注册 data-action 事件行为 */
  897. onEvent('click', '[data-action]', function () {
  898. var emap = this.dataset, data = {'_token_': emap.token || emap.csrf || '--'};
  899. var load = emap.loading !== 'false', tips = typeof load === 'string' ? load : undefined;
  900. if ((applyRuleValue(this, data)) === false) return false; else onConfirm(emap.confirm, function () {
  901. $.form.load(emap.action, data, emap.method || 'post', onConfirm.getLoadcallable(emap.tableId), load, tips, emap.time)
  902. });
  903. });
  904. /*! 注册 data-modal 事件行为 */
  905. onEvent('click', '[data-modal]', function () {
  906. var un = undefined, emap = this.dataset, data = {open_type: 'modal'};
  907. if (emap.rule && (applyRuleValue(this, data)) === false) return false;
  908. return $.form.modal(emap.modal, data, emap.title || this.innerText || '编辑', un, un, un, emap.area || emap.width || '800px', emap.offset || 'auto', emap.full !== un);
  909. });
  910. /*! 注册 data-iframe 事件行为 */
  911. onEvent('click', '[data-iframe]', function () {
  912. var emap = this.dataset, data = {open_type: 'iframe'};
  913. if (emap.rule && (applyRuleValue(this, data)) === false) return false;
  914. var name = emap.title || this.innerText || 'IFRAME 窗口';
  915. var area = emap.area || [emap.width || '800px', emap.height || '580px'];
  916. var frame = emap.iframe + (emap.iframe.indexOf('?') > -1 ? '&' : '?') + $.param(data);
  917. $(this).attr('data-index', $.form.iframe(frame, name, area, emap.offset || 'auto', function () {
  918. typeof emap.refresh !== 'undefined' && $.layTable.reload(emap.tableId || true);
  919. }, undefined, emap.full !== undefined));
  920. });
  921. /*! 注册 data-icon 事件行为 */
  922. onEvent('click', '[data-icon]', function () {
  923. var location = tapiRoot + '/api.plugs/icon', field = this.dataset.icon || this.dataset.field || 'icon';
  924. $.form.iframe(location + (location.indexOf('?') > -1 ? '&' : '?') + 'field=' + field, '图标选择', ['900px', '700px']);
  925. });
  926. /*! 注册 data-copy 事件行为 */
  927. onEvent('click', '[data-copy]', function () {
  928. var copy = this.dataset.copy || this.innerText;
  929. if (window.clipboardData) {
  930. window.clipboardData.setData('text', copy);
  931. $.msg.tips('已复制到剪贴板!');
  932. } else {
  933. var $input = $('<textarea readonly></textarea>');
  934. $input.css({position: 'fixed', top: '-500px'}).appendTo($body).val(copy).select();
  935. $.msg.tips(document.execCommand('Copy') ? '已复制到剪贴板!' : '请使用鼠标操作复制!') && $input.remove();
  936. }
  937. });
  938. /*! 异步任务状态监听与展示 */
  939. onEvent('click', '[data-queue]', function () {
  940. var that = this, emap = this.dataset;
  941. onConfirm(emap.confirm || false, function () {
  942. $.form.load(emap.queue, {}, 'post', function (ret) {
  943. if (typeof ret.data === 'string' && ret.data.indexOf('Q') === 0) {
  944. return $.loadQueue(ret.data, true, that), false;
  945. }
  946. });
  947. });
  948. });
  949. /*! 注册 data-tips-text 事件行为 */
  950. onEvent('mouseenter', '[data-tips-text]', function () {
  951. var opts = {tips: [$(this).attr('data-tips-type') || 3, '#78BA32'], time: 0};
  952. var layidx = layer.tips($(this).attr('data-tips-text') || this.innerText, this, opts);
  953. $(this).off('mouseleave').on('mouseleave', function () {
  954. setTimeout("layer.close('" + layidx + "')", 100);
  955. });
  956. });
  957. /*! 注册 data-tips-hover 事件行为 */
  958. onEvent('mouseenter', '[data-tips-image][data-tips-hover]', function () {
  959. var img = new Image(), ele = $(this);
  960. if ((img.src = this.dataset.tipsImage || this.dataset.lazySrc || this.src)) {
  961. img.layopt = {time: 0, skin: 'layui-layer-image', anim: 5, isOutAnim: false, scrollbar: false};
  962. img.referrerPolicy = 'no-referrer', img.style.maxWidth = '260px', img.style.maxHeight = '260px';
  963. ele.data('layidx', layer.tips(img.outerHTML, this, img.layopt)).off('mouseleave').on('mouseleave', function () {
  964. layer.close(ele.data('layidx'));
  965. });
  966. }
  967. });
  968. /*! 注册 data-tips-image 事件行为 */
  969. onEvent('click', '[data-tips-image]', function (event) {
  970. (event.items = [], event.$imgs = $(this).parent().find('[data-tips-image]')).map(function () {
  971. event.items.push({src: this.dataset.tipsImage || this.dataset.lazySrc || this.src});
  972. }) && layer.photos({
  973. anim: 5, closeBtn: 1, photos: {start: event.$imgs.index(this), data: event.items}, tab: function (pic, $ele) {
  974. $ele.find('img').attr('referrer-policy', 'no-referrer');
  975. $ele.find('.layui-layer-close').css({top: '20px', right: '20px', position: 'fixed'});
  976. }
  977. });
  978. });
  979. /*! 注册 data-phone-view 事件行为 */
  980. onEvent('click', '[data-phone-view]', function () {
  981. $.previewPhonePage(this.dataset.phoneView || this.href);
  982. });
  983. /*! 表单编辑返回操作 */
  984. onEvent('click', '[data-history-back]', function () {
  985. $.msg.confirm(this.dataset.historyBack || '确定要返回吗?', function () {
  986. history.back();
  987. })
  988. });
  989. /*! 图片加载异常处理 */
  990. document.addEventListener('error', function (event) {
  991. if (event.target.nodeName !== 'IMG') return;
  992. event.target.src = baseRoot + 'theme/img/404_icon.png';
  993. }, true);
  994. /*! 系统菜单表单页面初始化 */
  995. $.menu.listen(), $.form.reInit($body);
  996. });