admin.js 51 KB

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