admin.js 49 KB

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