sa.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. // =========================== sa对象封装一系列工具方法 ===========================
  2. var sa = {
  3. version: '2.4.3',
  4. update_time: '2020-10-2',
  5. info: '新增双击layer标题处全屏'
  6. };
  7. // =========================== 当前环境配置 =======================================
  8. (function(){
  9. // 公司开发环境
  10. var cfg_dev = {
  11. api_url: 'http://192.168.88.34:8080', // 所有ajax请求接口父地址
  12. web_url: 'http://www.baidu.com' // 此项目前台地址 (此配置项非必须)
  13. }
  14. // 服务器测试环境
  15. var cfg_test = {
  16. api_url: 'http://www.baidu.com',
  17. web_url: 'http://www.baidu.com'
  18. }
  19. // 正式生产环境
  20. var cfg_prod = {
  21. api_url: 'http://www.baidu.com',
  22. web_url: 'http://www.baidu.com'
  23. }
  24. sa.cfg = cfg_dev; // 最终环境 , 上线前请选择正确的环境
  25. })();
  26. // =========================== ajax的封装 =======================================
  27. (function(){
  28. /** 对ajax的再封装, 这个ajax假设你的接口会返回以下格式的内容
  29. {
  30. "code": 200,
  31. "msg": "ok",
  32. "data": []
  33. }
  34. 如果返回的不是这个格式, 你可能需要改动一下源码, 要么改动服务端适应此ajax, 要么改动这个ajax适应你的服务端
  35. * @param {Object} url 请求地址
  36. * @param {Object} data 请求参数
  37. * @param {Object} success200 当返回的code码==200时的回调函数
  38. * @param {Object} 其它配置,可配置项有:
  39. {
  40. msg: '', // 默认的提示文字 填null为不提示
  41. type: 'get', // 设定请求类型 默认post
  42. baseUrl: '', // ajax请求拼接的父路径 默认取 sa.cfg.api_url
  43. sleep: 0, // ajax模拟的延时毫秒数, 默认0
  44. success500: fn, // code码等于500时的回调函数 (一般代表服务器错误)
  45. success403: fn, // code码等于403时的回调函数 (一般代表无权限)
  46. success401: fn, // code码等于401时的回调函数 (一般代表未登录)
  47. errorfn: fn, // ajax发生错误时的回调函数 (一般是ajax请求本身发生了错误)
  48. complete: fn, // ajax无论成功还是失败都会执行的回调函数
  49. }
  50. */
  51. sa.ajax = function(url, data, success200, cfg){
  52. // 如果是简写模式(省略了data参数)
  53. if(typeof data === 'function'){
  54. cfg = success200;
  55. success200 = data;
  56. data = {};
  57. }
  58. // 默认配置
  59. var defaultCfg = {
  60. msg: '努力加载中...', // 提示语
  61. baseUrl: (url.indexOf('http') === 0 ? '' : sa.cfg.api_url),// 父url,拼接在url前面
  62. sleep: 0, // 休眠n毫秒处理回调函数
  63. type: 'post', // 默认请求类型
  64. success200: success200, // code=200, 代表成功
  65. success500: function(res){ // code=500, 代表失败
  66. return layer.alert('失败:' + res.msg);
  67. },
  68. success403: function(res){ // code=403, 代表权限不足
  69. return layer.alert("权限不足," + res.msg, {icon: 5});
  70. },
  71. success401: function(res){ // code=401, 代表未登录
  72. return layer.confirm("您当前暂未登录,是否立即登录?", {}, function(){
  73. layer.closeAll();
  74. return sa.$page.openLogin(cfg.login_url);
  75. });
  76. },
  77. errorfn: function(xhr, type, errorThrown){ // ajax发生异常时的默认处理函数
  78. if(xhr.status == 0){
  79. return layer.alert('无法连接到服务器,请检查网络');
  80. }
  81. return layer.alert("异常:" + JSON.stringify(xhr));
  82. },
  83. complete: function(xhr, ts) { // 成功失败都会执行
  84. }
  85. }
  86. // 将调用者的配置和默认配置合并
  87. cfg = sa.extendJson(cfg, defaultCfg);
  88. // 打印请求地址和参数, 以便调试
  89. console.log("请求地址:" + cfg.baseUrl + url);
  90. console.log("请求参数:" + JSON.stringify(data));
  91. // 开始显示loading图标
  92. if(cfg.msg != null){
  93. sa.loading(cfg.msg);
  94. }
  95. // 开始请求ajax
  96. return $.ajax({
  97. url: cfg.baseUrl + url,
  98. type: cfg.type,
  99. data: data,
  100. dataType: 'json',
  101. // xhrFields: {
  102. // withCredentials: true // 携带跨域cookie
  103. // },
  104. // crossDomain: true,
  105. beforeSend: function(xhr) {
  106. xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
  107. // 追加token
  108. if(localStorage.tokenName) {
  109. xhr.setRequestHeader(localStorage.tokenName, localStorage.tokenValue);
  110. }
  111. },
  112. success: function(res){
  113. console.log('返回数据:', res);
  114. setTimeout(function() {
  115. sa.hideLoading();
  116. // 如果相应的处理函数存在
  117. if(cfg['success' + res.code] != undefined) {
  118. return cfg['success' + res.code](res);
  119. }
  120. layer.alert('未知状态码:' + JSON.stringify(res));
  121. }, cfg.sleep);
  122. },
  123. error: function(xhr, type, errorThrown){
  124. setTimeout(function() {
  125. sa.hideLoading();
  126. return cfg.errorfn(xhr, type, errorThrown);
  127. }, cfg.sleep);
  128. },
  129. complete: cfg.complete
  130. });
  131. };
  132. // 模拟一个ajax
  133. // 请注意: 本模板中所有ajax请求调用的均为此模拟函数
  134. sa.ajax2 = function(url, data, success200, cfg){
  135. // 如果是简写模式(省略了data参数)
  136. if(typeof data === 'function'){
  137. cfg = success200;
  138. success200 = data;
  139. data = {};
  140. }
  141. // 几个默认配置
  142. cfg = cfg || {};
  143. cfg.baseUrl = (url.indexOf('http') === 0 ? '' : sa.cfg.api_url); // 父url,拼接在url前面
  144. // 设定一个默认的提示文字
  145. if(cfg.msg == undefined || cfg.msg == null || cfg.msg == '') {
  146. cfg.msg = '正在努力加载...';
  147. }
  148. // 默认延时函数
  149. if(cfg.sleep == undefined || cfg.sleep == null || cfg.sleep == '' || cfg.sleep == 0) {
  150. cfg.sleep = 600;
  151. }
  152. // 默认的模拟数据
  153. cfg.res = cfg.res || {
  154. code: 200,
  155. msg: 'ok',
  156. data: []
  157. }
  158. // 开始loding
  159. sa.loading(cfg.msg);
  160. // 打印请求地址和参数, 以便调试
  161. console.log("======= 模拟ajax =======");
  162. console.log("请求地址:" + cfg.baseUrl + url);
  163. console.log("请求参数:" + JSON.stringify(data));
  164. // 模拟ajax的延时
  165. setTimeout(function() {
  166. sa.hideLoading(); // 隐藏掉转圈圈
  167. console.log('返回数据:', cfg.res);
  168. success200(cfg.res);
  169. }, cfg.sleep)
  170. };
  171. })();
  172. // =========================== 封装弹窗相关函数 =======================================
  173. (function() {
  174. var me = sa;
  175. if(window.layer) {
  176. layer.ready(function(){});
  177. }
  178. // tips提示文字
  179. me.msg = function(msg, cfg) {
  180. msg = msg || '操作成功';
  181. layer.msg(msg, cfg);
  182. };
  183. // 操作成功的提示
  184. me.ok = function(msg) {
  185. msg = msg || '操作成功';
  186. layer.msg(msg, {anim: 0, icon: 1 });
  187. }
  188. me.ok2 = function(msg) {
  189. msg = msg || '操作成功';
  190. layer.msg(msg, {anim: 0, icon: 6 });
  191. }
  192. // 操作失败的提示
  193. me.error = function(msg) {
  194. msg = msg || '操作失败';
  195. layer.msg(msg, {anim: 6, icon: 2 });
  196. }
  197. me.error2 = function(msg) {
  198. msg = msg || '操作失败';
  199. layer.msg(msg, {anim: 6, icon: 5 });
  200. }
  201. // alert弹窗 [text=提示文字, okFn=点击确定之后的回调函数]
  202. me.alert = function(text, okFn) {
  203. // 开始弹窗
  204. layer.alert(text, function(index) {
  205. layer.close(index);
  206. if(okFn) {
  207. okFn();
  208. }
  209. });
  210. };
  211. // 询问框 [text=提示文字, okFn=点击确定之后的回调函数]
  212. me.confirm = function(text, okFn) {
  213. layer.confirm(text, {}, function(index) {
  214. layer.close(index);
  215. if(okFn) {
  216. okFn();
  217. }
  218. }.bind(this));
  219. };
  220. // 输入框 [title=提示文字, okFn=点击确定后的回调函数, formType=输入框类型(0=文本,1=密码,2=多行文本域) 可省略, value=默认值 可省略 ]
  221. me.prompt = function(title, okFn, formType, value) {
  222. layer.prompt({
  223. title: title,
  224. formType: formType,
  225. value: value
  226. }, function(pass, index){
  227. layer.close(index);
  228. if(okFn) {
  229. okFn(pass);
  230. }
  231. });
  232. }
  233. // 打开loading
  234. me.loading = function(msg) {
  235. layer.closeAll(); // 开始前先把所有弹窗关了
  236. return layer.msg(msg, {icon: 16, shade: 0.3, time: 1000 * 20, skin: 'ajax-layer-load' });
  237. };
  238. // 隐藏loading
  239. me.hideLoading = function() {
  240. layer.closeAll();
  241. };
  242. // ============== 一些常用弹窗 =====================
  243. // 大窗显示一个图片
  244. // 参数: src=地址、w=宽度(默认80%)、h=高度(默认80%)
  245. me.showImage = function(src, w, h) {
  246. w = w || '80%';
  247. h = h || '80%';
  248. var content = '<div style="height: 100%; overflow: hidden !important;">' +
  249. '<img src="' + src + ' " style="width: 100%; height: 100%;" />' +
  250. '</div>';
  251. layer.open({
  252. type: 1,
  253. title: false,
  254. shadeClose: true,
  255. closeBtn: 0,
  256. area: [w, h], //宽高
  257. content: content
  258. });
  259. }
  260. // 预览一组图片
  261. // srcList=图片路径数组(可以是json样,也可以是逗号切割式), index=打开立即显示哪张(可填下标, 也可填写src路径)
  262. me.showImageList = function(srcList, index) {
  263. // 如果填的是个string
  264. srcList = srcList || [];
  265. if(typeof srcList === 'string') {
  266. try{
  267. srcList = JSON.parse(srcList);
  268. }catch(e){
  269. try{
  270. srcList = srcList.split(','); // 尝试字符串切割
  271. }catch(e){
  272. srcList = [];
  273. }
  274. }
  275. }
  276. // 如果填的是路径
  277. index = index || 0;
  278. if(typeof index === 'string') {
  279. index = srcList.indexOf(index);
  280. index = (index == -1 ? 0 : index);
  281. }
  282. // 开始展示
  283. var arr_list = [];
  284. srcList.forEach(function(item) {
  285. arr_list.push({
  286. alt: '左右键切换',
  287. pid: 1,
  288. src: item,
  289. thumb: item
  290. })
  291. })
  292. layer.photos({
  293. photos: {
  294. title: '',
  295. id: new Date().getTime(),
  296. start: index,
  297. data: arr_list
  298. }
  299. ,anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数)
  300. });
  301. }
  302. // 显示一个iframe
  303. // 参数: 标题,地址,宽,高 , 点击遮罩是否关闭, 默认false
  304. me.showIframe = function(title, url, w, h, shadeClose) {
  305. // 参数修正
  306. w = w || '95%';
  307. h = h || '95%';
  308. shadeClose = (shadeClose === undefined ? false : shadeClose);
  309. // 弹出面板
  310. var index = layer.open({
  311. type: 2,
  312. title: title, // 标题
  313. shadeClose: shadeClose, // 是否点击遮罩关闭
  314. maxmin: true, // 显示最大化按钮
  315. shade: 0.8, // 遮罩透明度
  316. scrollbar: false, // 屏蔽掉外层的滚动条
  317. moveOut: true, // 是否可拖动到外面
  318. area: [w, h], // 大小
  319. content: url, // 传值
  320. // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
  321. resizing: function(layero) {
  322. solveLayerBug(index);
  323. }
  324. });
  325. // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
  326. $('#layui-layer' + index + ' .layui-layer-max').click(function() {
  327. setTimeout(function() {
  328. solveLayerBug(index);
  329. }, 200)
  330. })
  331. }
  332. me.showView = me.showIframe;
  333. // 显示一个iframe, 底部按钮方式
  334. // 参数: 标题,地址,点击确定按钮执行的代码(在子窗口执行),宽,高
  335. me.showIframe2 = function(title, url, evalStr, w, h) {
  336. // 参数修正
  337. w = w || '95%';
  338. h = h || '95%';
  339. // 弹出面板
  340. var index = layer.open({
  341. type: 2,
  342. title: title, // 标题
  343. closeBtn: (title ? 1 : 0), // 是否显示关闭按钮
  344. btn: ['确定', '取消'],
  345. shadeClose: false, // 是否点击遮罩关闭
  346. maxmin: true, // 显示最大化按钮
  347. shade: 0.8, // 遮罩透明度
  348. scrollbar: false, // 屏蔽掉外层的滚动条
  349. moveOut: true, // 是否可拖动到外面
  350. area: [w, h], // 大小
  351. content: url, // 传值
  352. // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
  353. resizing: function(layero) {
  354. },
  355. yes: function(index, layero) {
  356. var iframe = document.getElementById('layui-layer-iframe' + index);
  357. var iframeWindow = iframe.contentWindow;
  358. iframeWindow.eval(evalStr);
  359. }
  360. });
  361. }
  362. // 当前iframe关闭自身 (在iframe中调用)
  363. me.closeCurrIframe = function() {
  364. try{
  365. var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
  366. parent.layer.close(index); //再执行关闭
  367. }catch(e){
  368. //TODO handle the exception
  369. }
  370. }
  371. me.closeCurrView = me.closeCurrIframe;
  372. //执行一个函数, 解决layer拉伸或者最大化的时候,iframe高度不能自适应的问题
  373. function solveLayerBug(index) {
  374. var selected = '#layui-layer' + index;
  375. var height = $(selected).height();
  376. var title_height = $(selected).find('.layui-layer-title').height();
  377. $(selected).find('iframe').css('height', (height - title_height) + 'px');
  378. }
  379. // 监听回车事件,达到回车关闭弹窗的效果
  380. if(window.$) {
  381. $(document).on('keydown', function() {
  382. if(event.keyCode === 13 && $(".layui-layer-btn0").length == 1 && !window.is_not_watch_enter && $(this).find('.layui-layer-input').length == 0){
  383. $(".layui-layer-btn0").click();
  384. return false;
  385. }
  386. });
  387. }
  388. })();
  389. // =========================== 常用util函数封装 =======================================
  390. (function () {
  391. // 超级对象
  392. var me = sa;
  393. // =========================== 常用util函数封装 =======================================
  394. if(true) {
  395. // 从url中查询到指定参数值
  396. me.p = function(name, defaultValue){
  397. var query = window.location.search.substring(1);
  398. var vars = query.split("&");
  399. for (var i=0;i<vars.length;i++) {
  400. var pair = vars[i].split("=");
  401. if(pair[0] == name){return pair[1];}
  402. }
  403. return(defaultValue == undefined ? null : defaultValue);
  404. }
  405. me.q = function(name, defaultValue){
  406. var query = window.location.search.substring(1);
  407. var vars = query.split("&");
  408. for (var i=0;i<vars.length;i++) {
  409. var pair = vars[i].split("=");
  410. if(pair[0] == name){return pair[1];}
  411. }
  412. return(defaultValue == undefined ? null : defaultValue);
  413. }
  414. // 判断一个变量是否为null
  415. // 返回true或false,如果return_obj有值,则在true的情况下返回return_obj
  416. me.isNull = function(obj, return_obj){
  417. var flag = [null, undefined, '', 'null', 'undefined'].indexOf(obj) != -1;
  418. if(return_obj === undefined){
  419. return flag;
  420. } else {
  421. if(flag){
  422. return return_obj;
  423. } else {
  424. return obj;
  425. }
  426. }
  427. }
  428. // 将时间戳转化为指定时间
  429. // way:方式(1=年月日,2=年月日时分秒)默认1, 也可以指定格式:yyyy-MM-dd HH:mm:ss
  430. me.forDate = function(inputTime, way) {
  431. if(me.isNull(inputTime) == true){
  432. return "";
  433. }
  434. var date = new Date(inputTime);
  435. var y = date.getFullYear();
  436. var m = date.getMonth() + 1;
  437. m = m < 10 ? ('0' + m) : m;
  438. var d = date.getDate();
  439. d = d < 10 ? ('0' + d) : d;
  440. var h = date.getHours();
  441. h = h < 10 ? ('0' + h) : h;
  442. var minute = date.getMinutes();
  443. var second = date.getSeconds();
  444. minute = minute < 10 ? ('0' + minute) : minute;
  445. second = second < 10 ? ('0' + second) : second;
  446. var ms = date.getMilliseconds();
  447. way = way || 1;
  448. // way == 1 年月日
  449. if(way === 1) {
  450. return y + '-' + m + '-' + d;
  451. }
  452. // way == 1 年月日时分秒
  453. if(way === 2){
  454. return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
  455. }
  456. // way == 具体格式 标准格式: yyyy-MM-dd HH:mm:ss
  457. if(typeof way == 'string') {
  458. return way.replace("yyyy", y).replace("MM", m).replace("dd", d).replace("HH", h).replace("mm", minute).replace("ss", second).replace("ms", ms);
  459. }
  460. return y + '-' + m + '-' + d;
  461. };
  462. // 时间日期
  463. me.forDatetime = function(inputTime) {
  464. return me.forDate(inputTime, 2);
  465. }
  466. // 将时间转化为 个性化 如:3小时前,
  467. // d1 之于 d2 ,d2不填则默认取当前时间
  468. me.forDate2 = function(d, d2){
  469. var hou = "前";
  470. if(d == null || d == '') {
  471. return '';
  472. }
  473. if(d2 == null || d2 == '') {
  474. d2 = new Date();
  475. }
  476. d2 = new Date(d2).getTime();
  477. var timestamp = new Date(d).getTime() - 1000;
  478. var mistiming = Math.round((d2 - timestamp) / 1000);
  479. if(mistiming < 0) {
  480. mistiming = 0 - mistiming;
  481. hou = '后'
  482. }
  483. var arrr = ['年', '月', '周', '天', '小时', '分钟', '秒'];
  484. var arrn = [31536000, 2592000, 604800, 86400, 3600, 60, 1];
  485. for (var i = 0; i < arrn.length; i++) {
  486. var inm = Math.floor(mistiming / arrn[i]);
  487. if (inm != 0) {
  488. return inm + arrr[i] + hou;
  489. }
  490. }
  491. }
  492. // 综合以上两种方式,进行格式化
  493. // 小于24小时的走forDate2,否则forDat
  494. me.forDate3 = function(d, way) {
  495. if(d == null || d == '' ) {
  496. return '';
  497. }
  498. var cha = new Date().getTime() - new Date(d).getTime();
  499. cha = (cha > 0 ? cha : 0 - cha);
  500. if(cha < (86400 * 1000)) {
  501. return me.forDate2(d);
  502. }
  503. return me.forDate(d, way);
  504. }
  505. // 返回时间差, 此格式数组:[x, x, x, 天, 时, 分, 秒]
  506. me.getSJC = function (small_time, big_time) {
  507. var date1 = new Date(small_time); //开始时间
  508. var date2 = new Date(big_time); //结束时间
  509. var date3 = date2.getTime() - date1.getTime(); //时间差秒
  510. //计算出相差天数
  511. var days = Math.floor(date3 / (24 * 3600 * 1000));
  512. //计算出小时数
  513. var leave1 = date3 % (24 * 3600 * 1000); //计算天数后剩余的毫秒数
  514. var hours = Math.floor(leave1 / (3600 * 1000));
  515. //计算相差分钟数
  516. var leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数
  517. var minutes = Math.floor(leave2 / (60 * 1000));
  518. //计算相差秒数
  519. var leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数
  520. var seconds = Math.round(leave3 / 1000);
  521. // 返回数组
  522. return [0, 0, 0, days, hours, minutes, seconds];
  523. }
  524. // 将日期,加上指定天数
  525. me.dateAdd = function(d, n) {
  526. var s = new Date(d).getTime();
  527. s += 86400000 * n;
  528. return new Date(s);
  529. }
  530. // 转化json,出错返回默认值
  531. me.JSONParse = function(obj, default_obj){
  532. try{
  533. return JSON.parse(obj) || default_obj;
  534. }catch(e){
  535. return default_obj || {};
  536. }
  537. }
  538. // 截取指定长度字符,默认50
  539. me.maxLength = function (str, length) {
  540. length = length || 50;
  541. if(!str){
  542. return "";
  543. }
  544. return (str.length > length) ? str.substr(0, length) + ' ...' : str;
  545. },
  546. // 过滤掉标签
  547. me.text = function(str){
  548. if(!str){
  549. return "";
  550. }
  551. return str.replace(/<[^>]+>/g,"");
  552. }
  553. // 为指定集合的每一项元素添加上is_update属性
  554. me.listAU = function(list){
  555. list.forEach(function(ts){
  556. ts.is_update = false;
  557. })
  558. return list;
  559. }
  560. // 获得一段文字中所有图片的路径
  561. me.getSrcList = function(str){
  562. try{
  563. var imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片(g表示匹配所有结果i表示区分大小写)
  564. var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; //匹配src属性
  565. var arr = str.match(imgReg); // 图片数组
  566. var srcList = [];
  567. for (var i = 0; i < arr.length; i++) {
  568. var src = arr[i].match(srcReg);
  569. srcList.push(src[1]);
  570. }
  571. return srcList;
  572. } catch (e){
  573. return [];
  574. }
  575. }
  576. // 无精度损失的乘法
  577. me.accMul = function(arg1, arg2) {
  578. var m = 0,
  579. s1 = arg1.toString(),
  580. s2 = arg2.toString(),
  581. t;
  582. t = s1.split(".");
  583. // 判断有没有小数位,避免出错
  584. if (t[1]) {
  585. m += t[1].length
  586. }
  587. t = s2.split(".");
  588. if (t[1]) {
  589. m += t[1].length
  590. }
  591. return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
  592. }
  593. // 正则验证是否为手机号
  594. me.isPhone = function(str) {
  595. str = str + '';
  596. if((/^1[34578]\d{9}$/.test(str))){
  597. return true;
  598. }
  599. return false;
  600. }
  601. // 产生随机字符串
  602. me.randomString = function(len) {
  603.   len = len || 32;
  604.   var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
  605.   var maxPos = $chars.length;
  606.   var str = '';
  607.   for (i = 0; i < len; i++) {
  608.     str += $chars.charAt(Math.floor(Math.random() * maxPos));
  609.   }
  610.   return str;
  611. }
  612. // 刷新页面
  613. me.f5 = function() {
  614. location.reload();
  615. }
  616. // 动态加载js
  617. me.loadJS = function(src, onload) {
  618. var script = document.createElement("script");
  619. script.setAttribute("type", "text/javascript");
  620. script.src = src;
  621. script.onload = onload;
  622. document.body.appendChild(script);
  623. }
  624. // 产生随机数字
  625. me.randomNum = function(min, max) {
  626. return parseInt(Math.random() * (max - min + 1) + min, 10);
  627. }
  628. // 打开页面
  629. me.open = function(url) {
  630. window.open(url);
  631. }
  632. // == if 结束
  633. }
  634. // =========================== 数组操作 =======================================
  635. if (true) {
  636. // 从数组里获取数据,根据指定数据
  637. me.getArrayField = function(arr, prop){
  638. var propArr = [];
  639. for (var i = 0; i < arr.length; i++) {
  640. propArr.push(arr[i][prop]);
  641. }
  642. return propArr;
  643. }
  644. // 从数组里获取数据,根据指定数据
  645. me.arrayGet = function(arr, prop, value){
  646. for (var i = 0; i < arr.length; i++) {
  647. if(arr[i][prop] == value){
  648. return arr[i];
  649. }
  650. }
  651. return null;
  652. }
  653. // 从数组删除指定记录
  654. me.arrayDelete = function(arr, item){
  655. if(item instanceof Array) {
  656. for (let i = 0; i < item.length; i++) {
  657. let ite = item[i];
  658. let index = arr.indexOf(ite);
  659. if (index > -1) {
  660. arr.splice(index, 1);
  661. }
  662. }
  663. } else {
  664. var index = arr.indexOf(item);
  665. if (index > -1) {
  666. arr.splice(index, 1);
  667. }
  668. }
  669. }
  670. // 从数组删除指定id的记录
  671. me.arrayDeleteById = function(arr, id){
  672. var item = me.arrayGet(arr, 'id', id);
  673. me.arrayDelete(arr, item);
  674. }
  675. // 将数组B添加到数组A的开头
  676. me.unshiftArray = function(arrA, arrB){
  677. if(arrB){
  678. arrB.reverse().forEach(function(ts){
  679. arrA.unshift(ts);
  680. })
  681. }
  682. return arrA;
  683. }
  684. // 将数组B添加到数组A的末尾
  685. me.pushArray = function(arrA, arrB){
  686. if(arrB){
  687. arrB.forEach(function(ts){
  688. arrA.push(ts);
  689. })
  690. }
  691. return arrA;
  692. }
  693. // == if 结束
  694. }
  695. // =========================== 浏览器相关 =======================================
  696. if (true) {
  697. // set cookie 值
  698. me.setCookie = function setCookie(cname, cvalue, exdays) {
  699. exdays = exdays || 30;
  700. var d = new Date();
  701. d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
  702. var expires = "expires=" + d.toGMTString();
  703. document.cookie = cname + "=" + escape(cvalue) + "; " + expires + "; path=/";
  704. }
  705. // get cookie 值
  706. me.getCookie = function(objName){
  707. var arrStr = document.cookie.split("; ");
  708. for (var i = 0; i < arrStr.length; i++) {
  709. var temp = arrStr[i].split("=");
  710. if (temp[0] == objName){
  711. return unescape(temp[1])
  712. };
  713. }
  714. return "";
  715. }
  716. // 复制指定文本
  717. me.copyText = function(str){
  718. var oInput = document.createElement('input');
  719. oInput.value = str;
  720. document.body.appendChild(oInput);
  721. oInput.select(); // 选择对象
  722. document.execCommand("Copy"); // 执行浏览器复制命令
  723. oInput.className = 'oInput';
  724. oInput.style.display='none';
  725. }
  726. // jquery序列化表单增强版: 排除空值
  727. me.serializeNotNull = function(selected){
  728. var serStr = $(selected).serialize();
  729. return serStr.split("&").filter(function(str){return !str.endsWith("=")}).join("&");
  730. }
  731. // 将cookie序列化为k=v形式
  732. me.strCookie = function(){
  733. return document.cookie.replace(/; /g,"&");
  734. }
  735. // 回到顶部
  736. me.goTop = function() {
  737. function smoothscroll(){
  738. var currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
  739. if (currentScroll > 0) {
  740. window.requestAnimationFrame(smoothscroll);
  741. window.scrollTo (0,currentScroll - (currentScroll/5));
  742. }
  743. };
  744. smoothscroll();
  745. }
  746. // == if 结束
  747. }
  748. // =========================== javascript对象操作 =======================================
  749. if (true) {
  750. // 去除json对象中的空值
  751. me.removeNull = function(obj){
  752. var newObj = {};
  753. if(obj != undefined && obj != null) {
  754. for(var key in obj) {
  755. if(obj[key] === undefined || obj[key] === null || obj[key] === '') {
  756. //
  757. } else {
  758. newObj[key] = obj[key];
  759. }
  760. }
  761. }
  762. return newObj;
  763. }
  764. // JSON 浅拷贝, 返回拷贝后的obj
  765. me.copyJSON = function(obj){
  766. if(obj === null || obj === undefined) {
  767. return obj;
  768. };
  769. var new_obj = {};
  770. for(var key in obj) {
  771. new_obj[key] = obj [key];
  772. }
  773. return new_obj;
  774. }
  775. // json合并, 将 defaulet配置项 转移到 user配置项里 并返回 user配置项
  776. me.extendJson = function(userOption, defaultOption) {
  777. if(!userOption) {
  778. return defaultOption;
  779. };
  780. for(var key in defaultOption) {
  781. if(userOption[key] === undefined) {
  782. userOption[key] = defaultOption[key];
  783. } else if(userOption[key] == null){
  784. } else if(typeof userOption[key] == "object") {
  785. me.extendJson(userOption[key], defaultOption[key]); //深度匹配
  786. }
  787. }
  788. return userOption;
  789. }
  790. // == if 结束
  791. }
  792. // =========================== 本地集合存储 =======================================
  793. if (true) {
  794. // 获取指定key的list
  795. me.keyListGet = function(key){
  796. try{
  797. var str = localStorage.getItem('LIST_' + key);
  798. if(str == undefined || str == null || str =='' || str == 'undefined' || typeof(JSON.parse(str)) == 'string'){
  799. //alert('key' + str);
  800. str = '[]';
  801. }
  802. return JSON.parse(str);
  803. }catch(e){
  804. return [];
  805. }
  806. },
  807. me.keyListSet = function(key, list){
  808. localStorage.setItem('LIST_' + key, JSON.stringify(list));
  809. },
  810. me.keyListHas = function(key, item){
  811. var arr2 = me.keyListGet(key);
  812. return arr2.indexOf(item) != -1;
  813. },
  814. me.keyListAdd = function(key, item){
  815. var arr = me.keyListGet(key);
  816. arr.push(item);
  817. me.keyListSet(key,arr);
  818. },
  819. me.keyListRemove = function(key, item){
  820. var arr = me.keyListGet(key);
  821. var index = arr.indexOf(item);
  822. if (index > -1) {
  823. arr.splice(index, 1);
  824. }
  825. me.keyListSet(key,arr);
  826. }
  827. // == if 结束
  828. }
  829. // =========================== 对sa-admin的优化 =======================================
  830. if (true) {
  831. // 封装element-ui的导出表格
  832. // 参数:选择器(默认.data-count),fileName=导出的文件名称
  833. me.exportExcel = function(select, fileName) {
  834. // 声明函数
  835. let exportExcel_fn = function(select, fileName) {
  836. // 赋默认值
  837. select = select || '.data-table';
  838. fileName = fileName || 'table.xlsx';
  839. // 开始导出
  840. let wb = XLSX.utils.table_to_book(document.querySelector(select)); // 这里就是表格
  841. let sheet = wb.Sheets.Sheet1; // 单元表
  842. try{
  843. // 强改宽度
  844. sheet['!cols'] = sheet['!cols'] || [];
  845. let thList = document.querySelector(select).querySelectorAll('.el-table__header-wrapper tr th');
  846. for (var i = 0; i < thList.length; i++) {
  847. // 如果是多选框
  848. if(thList[i].querySelector('.el-checkbox')) {
  849. sheet['!cols'].push({ wch: 5 }); // 强改宽度
  850. continue;
  851. }
  852. sheet['!cols'].push({ wch: 15 }); // 强改宽度
  853. }
  854. // 强改高度
  855. sheet['!rows'] = sheet['!rows'] || [];
  856. let trList = document.querySelector(select).querySelectorAll('.el-table__body-wrapper tbody tr');
  857. for (var i = 0; i < trList.length + 1; i++) {
  858. sheet['!rows'].push({ hpx: 20 }); // 强改高度
  859. }
  860. } catch(e) {
  861. console.err(e);
  862. }
  863. // 开始制作并输出
  864. let wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' });
  865. // 点击
  866. let blob = new Blob([wbout], { type: 'application/octet-stream'});
  867. const a= document.createElement("a")
  868. a.href = URL.createObjectURL(blob)
  869. a.download = fileName // 这里填保存成的文件名
  870. a.click()
  871. URL.revokeObjectURL(a.href)
  872. a.remove();
  873. sa.hideLoading();
  874. }
  875. sa.loading('正在导出...');
  876. // 判断是否首次加载
  877. if(window.XLSX) {
  878. return exportExcel_fn(select, fileName);
  879. } else {
  880. me.loadJS('https://unpkg.com/xlsx@0.16.6/dist/xlsx.core.min.js', function() {
  881. return exportExcel_fn(select, fileName);
  882. });
  883. }
  884. }
  885. // 刷新表格高度, 请务必在所有表格高度发生变化的地方调用此方法
  886. me.f5TableHeight = function() {
  887. Vue.nextTick(function() {
  888. if($('.el-table.data-table .el-table__body-wrapper table').length == 0) {
  889. return;
  890. }
  891. var _f5Height = function() {
  892. var height = $('.el-table .el-table__body-wrapper table').height();
  893. height = height == 0 ? 60 : height;
  894. // 判断是否有滚动条
  895. var tw = $('.el-table .el-table__body-wrapper').get(0);
  896. if(tw.scrollWidth > tw.clientWidth) {
  897. height = height + 16;
  898. }
  899. if($('.el-table .el-table__body-wrapper table td').width() == 0) {
  900. return;
  901. }
  902. // 设置高度
  903. $('.el-table .el-table__body-wrapper').css('min-height', height);
  904. $('.el-table .el-table__body-wrapper').css('max-height', height);
  905. };
  906. setTimeout(_f5Height, 0)
  907. setTimeout(_f5Height, 200)
  908. })
  909. }
  910. // 在表格查询的页面,监听input回车事件,提交查询
  911. me.onInputEnter = function(app) {
  912. Vue.nextTick(function() {
  913. app = app || window.app;
  914. // document.querySelectorAll('.el-form input').forEach(function(item) {
  915. // item.onkeydown = function(e) {
  916. // var theEvent = e || window.event;
  917. // var code = theEvent.keyCode || theEvent.which || theEvent.charCode;
  918. // if (code == 13) {
  919. // app.p.pageNo = 1;
  920. // app.f5();
  921. // }
  922. // }
  923. // })
  924. document.querySelectorAll('.el-form').forEach(function(item) {
  925. item.onkeydown = function(e) {
  926. var theEvent = e || window.event;
  927. var code = theEvent.keyCode || theEvent.which || theEvent.charCode;
  928. if (code == 13) {
  929. var target = e.target||e.srcElement;
  930. if(target.tagName.toLowerCase()=="input") {
  931. app.p.pageNo = 1;
  932. app.f5();
  933. }
  934. }
  935. }
  936. })
  937. })
  938. }
  939. // 如果value为true,则抛出异常
  940. me.check = function(value, errorMsg) {
  941. if(value === true) {
  942. throw {type: 'sa-error', msg: errorMsg};
  943. }
  944. }
  945. // 如果value为null,则抛出异常
  946. me.checkNull = function(value, errorMsg) {
  947. if(me.isNull(value)) {
  948. throw {type: 'sa-error', msg: errorMsg};
  949. }
  950. }
  951. // 监听窗口变动
  952. if(!window.onresize) {
  953. window.onresize = function() {
  954. try{
  955. me.f5TableHeight();
  956. }catch(e){
  957. // console.log(e);
  958. }
  959. }
  960. }
  961. // 双击layer标题处全屏
  962. if(window.$) {
  963. $(document).on('mousedown', '.layui-layer-title', function(e) {
  964. // console.log('单击中');
  965. if(window.layer_title_last_click_time) {
  966. var cz = new Date().getTime() - window.layer_title_last_click_time;
  967. if(cz < 250) {
  968. console.log('双击');
  969. $(this).parent().find('.layui-layer-max').click();
  970. }
  971. }
  972. window.layer_title_last_click_time = new Date().getTime();
  973. })
  974. }
  975. // == if 结束
  976. }
  977. })();
  978. // =========================== $sys 有关当前系统的方法 一般不能复制到别的项目中用 =======================================
  979. (function(){
  980. // 超级对象
  981. var me = {};
  982. sa.$sys = me;
  983. // ======================= 登录相关 ============================
  984. // 写入当前已登陆用户信息
  985. me.setCurrUser = function(currUser){
  986. localStorage.setItem('currUser', JSON.stringify(currUser));
  987. }
  988. // 获得当前已登陆用户信息
  989. me.getCurrUser = function(){
  990. var user = localStorage.getItem("currUser");
  991. if(user == undefined || user == null || user == 'null' || user == '' || user == '{}' || user.length < 10){
  992. user = {
  993. id: '0',
  994. username: '未登录'
  995. }
  996. }else{
  997. user = JSON.parse(user);
  998. }
  999. return user;
  1000. }
  1001. // 如果未登录,则强制跳转到登录
  1002. me.checkLogin = function(not_login_url){
  1003. console.log(me.getCurrUser());
  1004. if(me.getCurrUser().id == 0) {
  1005. location.href= not_login_url || '../../login.html';
  1006. throw '未登录,请先登录';
  1007. }
  1008. }
  1009. // 同上, 只不过是以弹窗的形式显示未登录
  1010. me.checkLoginTs = function(not_login_url){
  1011. if(me.getCurrUser().id == 0) {
  1012. sa.$page.openLogin(not_login_url || '../../login.html');
  1013. throw '未登录,请先登录';
  1014. }
  1015. }
  1016. // ========================= 权限验证 =========================
  1017. // 定义key
  1018. var pcode_key = 'permission_code';
  1019. // 写入当前会话的权限码集合
  1020. sa.setAuth = function(codeList) {
  1021. sa.keyListSet(pcode_key, codeList);
  1022. }
  1023. // 清除当前会话的权限码集合
  1024. sa.clearAuth = function() {
  1025. sa.keyListSet(pcode_key, []);
  1026. }
  1027. // 检查当前会话是否拥有一个权限码, 返回true和false
  1028. sa.isAuth = function(pcode) {
  1029. return sa.keyListHas(pcode_key, pcode);
  1030. }
  1031. // 检查当前会话是否拥有一个权限码, 如果没有, 则跳转到无权限页面
  1032. // 注意: 非二级目录页面请注意调整路径问题
  1033. sa.checkAuth = function(pcode, not_pcode_url) {
  1034. var is_have = sa.keyListHas(pcode_key, pcode);
  1035. if(is_have == false) {
  1036. location.href= not_pcode_url || '../../sa-view/error-page/403.html';
  1037. throw '暂无权限: ' + pcode;
  1038. }
  1039. }
  1040. // 同上, 只不过是以弹窗的形式显示出来无权限来
  1041. sa.checkAuthTs = function(pcode, not_pcode_url) {
  1042. var is_have = sa.keyListHas(pcode_key, pcode);
  1043. if(is_have == false) {
  1044. var url = not_pcode_url || '../../sa-view/error-page/403.html';
  1045. layer.open({
  1046. type: 2,
  1047. title: false, // 标题
  1048. shadeClose: true, // 是否点击遮罩关闭
  1049. shade: 0.8, // 遮罩透明度
  1050. scrollbar: false, // 屏蔽掉外层的滚动条
  1051. closeBtn: false,
  1052. area: ['700px', '600px'], // 大小
  1053. content: url // 传值
  1054. });
  1055. throw '暂无权限: ' + pcode;
  1056. }
  1057. }
  1058. // ======================= 配置相关 ============================
  1059. // 写入配置信息
  1060. me.setAppCfg = function(cfg) {
  1061. if(typeof cfg != 'string') {
  1062. cfg = JSON.stringify(cfg);
  1063. }
  1064. localStorage.setItem('app_cfg', cfg);
  1065. }
  1066. // 获取配置信息
  1067. me.getAppCfg = function() {
  1068. var app_cfg = sa.JSONParse(localStorage.getItem('app_cfg'), {}) || {};
  1069. return app_cfg;
  1070. }
  1071. })();
  1072. // =========================== $page 跳页面相关 避免一次变动,到处乱改 =======================================
  1073. (function(){
  1074. // 超级对象
  1075. var me={};
  1076. sa.$page = me;
  1077. // 打开登录页面
  1078. me.openLogin = function(login_url) {
  1079. layer.open({
  1080. type: 2,
  1081. // title: '登录',
  1082. title: false,
  1083. closeBtn: false,
  1084. shadeClose: true,
  1085. shade: 0.8,
  1086. // area: ['90%', '100%'],
  1087. area: ['70%', '80%'],
  1088. // area: ['450px', '360px'],
  1089. resize: false,
  1090. content: login_url || '../../login.html'
  1091. });
  1092. }
  1093. // 打开admin信息界面
  1094. me.openAdminInfo = function(id, username) {
  1095. var title = username + ' - 账号详情';
  1096. if(username === undefined) {
  1097. title = '账号详情';
  1098. }
  1099. sa.showIframe(title, '../sp-admin/admin-info.html?id=' + id, '700px', '600px');
  1100. }
  1101. })();
  1102. // 如果是sa_admin环境
  1103. window.sa_admin = window.sa_admin || parent.sa_admin || top.sa_admin;
  1104. window.saAdmin = window.sa_admin;
  1105. // 如果当前是Vue环境, 则挂在到 Vue 示例
  1106. if(window.Vue) {
  1107. // 全局的 sa 对象
  1108. Vue.prototype.sa = window.sa;
  1109. Vue.prototype.sa_admin = window.sa_admin;
  1110. Vue.prototype.saAdmin = window.saAdmin;
  1111. // 表单校验异常捕获
  1112. Vue.config.errorHandler = function(err, vm) {
  1113. if(err.type == 'sa-error') {
  1114. return sa.error(err.msg);
  1115. }
  1116. throw err;
  1117. }
  1118. // Element-UI 全局组件样式
  1119. Vue.prototype.$ELEMENT = { size: 'mini', zIndex: 3000 };
  1120. // 加载全局组件 (注意路径问题)
  1121. // if(window.httpVueLoader && window.loadComponent !== false) {
  1122. // Vue.component("sa-item", httpVueLoader('../../sa-frame/com/sa-item.vue'));
  1123. // Vue.component("sa-td", httpVueLoader('../../sa-frame/com/sa-td.vue'));
  1124. // }
  1125. }
  1126. // 对外开放, 在模块化时解开此注释
  1127. // export default sa;