app.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. window.rootUrl = window.location.protocol + '//' + window.location.host;
  2. window._AUTH_INFO_ = "AUTH_MANAGER";
  3. window._CONFIG_ = {}; // 后台管理配置.
  4. window._UPLOAD_TOKEN_ = 'GAkucH8'; // 上传通信token
  5. window._UPLOAD_SERVER_CONFIG_ = {}; // 上传服务器配置信息.
  6. window._PLUP_PATH_ = rootUrl + 'app/assets/js/plupload-2.3.7/'; // Plupload 引用资源相对路径.
  7. window._PLUP_SERVER_URI_ = ''; // Plupload服务端URI,有配置以来,预先空字符串.
  8. window._PLUP_FILE_FIELD_NAME_ = 'upload_files'; // 上传文件的表单字段名
  9. window._AES_KEY_ = 'Iz9IhtcyKbYJynAd'; // AES加密的key
  10. layui.extend({
  11. mhttp: "{/}"+ rootUrl +"/app/modules/mhttp", // ajax请求组件
  12. madmin: "{/}"+ rootUrl +"/app/modules/madmin", // admin组件
  13. });
  14. String.prototype.trim = function (char, type) {
  15. if (char) {
  16. if (type == 'left') {
  17. return this.replace(new RegExp('^\\'+char+'+', 'g'), '');
  18. } else if (type == 'right') {
  19. return this.replace(new RegExp('\\'+char+'+$', 'g'), '');
  20. }
  21. return this.replace(new RegExp('^\\'+char+'+|\\'+char+'+$', 'g'), '');
  22. }
  23. return this.replace(/^\s+|\s+$/g, '');
  24. };
  25. String.prototype.rtrim = function (s) {
  26. return this.trim(s, 'right');
  27. };
  28. String.prototype.ltrim = function (s) {
  29. return this.trim(s, 'left');
  30. };
  31. /**
  32. * 获取应用环境.
  33. * @returns
  34. */
  35. function getAppEnv()
  36. {
  37. var appEnv = 'prod';
  38. var hostAndPort = window.location.host;
  39. var devReg = /(127\.0\.0\.1|localhost)/;
  40. var qaReg = /(test)/;
  41. // 设置应用所在环境.
  42. if (devReg.test(hostAndPort)) {
  43. appEnv = 'dev';
  44. } else if (qaReg.test(hostAndPort)) {
  45. appEnv = 'test';
  46. } else {
  47. appEnv = 'prod';
  48. }
  49. return appEnv;
  50. }
  51. /**
  52. * 获取应用配置.
  53. * @returns
  54. */
  55. function getAppConfigPath()
  56. {
  57. var path = 'config/ignore/pear.config.yml';
  58. var url = window.location.protocol + '//' + window.location.host + '/' + path;
  59. return url;
  60. }
  61. /**
  62. * 格式化时长,格式00:00:00
  63. * @param {*} duration
  64. * @returns
  65. */
  66. function formatDuration(duration)
  67. {
  68. duration = parseFloat(duration);
  69. var hour = 60 * 60;
  70. var pHour = duration / hour;
  71. var strHour = '0';
  72. if (pHour > 0) {
  73. strHour = parseInt(pHour).toString()
  74. }
  75. strHour = strHour.padStart(2, '0');
  76. var pMinute = parseInt(duration % hour / 60);
  77. var strMinute = pMinute.toString().padStart(2, '0');
  78. var pSecond = parseInt(duration % hour % 60);
  79. var strSecond = pSecond.toString().padStart(2, '0');
  80. var result = strHour + ":" + strMinute + ":" + strSecond;
  81. return result;
  82. }
  83. function httpRequestPostData(data)
  84. {
  85. return {
  86. "data": data,
  87. "handshake": ""
  88. };
  89. }
  90. function httpRequestPagesParseData(res)
  91. {
  92. return {
  93. "code": res.code,
  94. "msg": res.message,
  95. "data" : res.data.data,
  96. "count": res.data.total ?? 0
  97. };
  98. }
  99. function cbRespnseRedirectLogin(data)
  100. {
  101. localStorage.removeItem(window._AUTH_INFO_);
  102. layer.alert('['+ data.code +']' + data.message + ', 请重新登陆', {
  103. title: '错误信息',
  104. icon: 2,
  105. closeBtn: 1,
  106. shade: 0.5,
  107. shadeClose: false,
  108. end: function () {
  109. parent.location.href = window.rootUrl + '/login.html';
  110. }
  111. });
  112. }
  113. function cbRespnse401(data)
  114. {
  115. // refreshToken();
  116. localStorage.removeItem(window._AUTH_INFO_);
  117. layer.alert('['+ data.code +']' + data.message + ', 请重新登陆', {
  118. title: '错误信息',
  119. icon: 2,
  120. closeBtn: 1,
  121. shade: 0.5,
  122. shadeClose: false,
  123. end: function () {
  124. parent.location.href = window.rootUrl + '/login.html';
  125. }
  126. });
  127. }
  128. function cbRespnseReloadPage(data, message)
  129. {
  130. // localStorage.removeItem(window._AUTH_INFO_);
  131. layer.alert('请求异常,请联系管理员!', {
  132. title: '错误信息',
  133. icon: 2,
  134. closeBtn: 1,
  135. shade: 0.5,
  136. shadeClose: false,
  137. end: function () {
  138. // parent.location.reload();
  139. }
  140. });
  141. }
  142. function getMyDetail()
  143. {
  144. var info = localStorage.getItem(window._AUTH_INFO_);
  145. return JSON.parse(info);
  146. }
  147. function getMyUid()
  148. {
  149. var detail = getMyDetail();
  150. if (detail) {
  151. return detail.manager_uid;
  152. } else {
  153. return '';
  154. }
  155. }
  156. function refreshToken()
  157. {
  158. layui.use(['mhttp', 'popup'], function () {
  159. var mhttp = layui.mhttp;
  160. var popup = layui.popup;
  161. var postData = {
  162. "manager_uid": getMyUid(),
  163. "old_token": mhttp.ajax.getToken()
  164. };
  165. var ret = mhttp.ajax({
  166. url: "/auth/refresh/token",
  167. data : postData,
  168. // 同步.
  169. async: false
  170. });
  171. ret.then((data) => {
  172. if (data.code == 200) {
  173. // 设置token
  174. mhttp.ajax.setToken(data.data.token);
  175. } else {
  176. console.log('刷新token');
  177. // 错误提示.
  178. popup.failure('['+ data.code +']' + data.message);
  179. }
  180. });
  181. });
  182. }
  183. function threadBizCodeNoParams(code, func)
  184. {
  185. // if (code == 401) {
  186. // func.call(null);
  187. // }
  188. }
  189. /**
  190. * 格式化为相对协议.
  191. * @param {*} url
  192. * @returns
  193. */
  194. function slashesUrl(url)
  195. {
  196. var pattern = /^(http|https)\:\/\/(.*?)$/i;
  197. var arr = url.match(pattern);
  198. if (arr) {
  199. return '//' + arr[2];
  200. } else {
  201. return url;
  202. }
  203. }
  204. /**
  205. * 把buffer转b64
  206. * 参考1:https://stackoverflow.com/questions/27375908/crypto-js-read-and-decrypt-file
  207. * 擦靠2:https://gist.github.com/jonleighton/958841
  208. * @param {*} arrayBuffer
  209. * @returns
  210. */
  211. function base64ArrayBuffer(arrayBuffer) {
  212. var base64 = ''
  213. var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  214. var bytes = new Uint8Array(arrayBuffer)
  215. var byteLength = bytes.byteLength
  216. var byteRemainder = byteLength % 3
  217. var mainLength = byteLength - byteRemainder
  218. var a, b, c, d
  219. var chunk
  220. // Main loop deals with bytes in chunks of 3
  221. for (var i = 0; i < mainLength; i = i + 3) {
  222. // Combine the three bytes into a single integer
  223. chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
  224. // Use bitmasks to extract 6-bit segments from the triplet
  225. a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
  226. b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
  227. c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
  228. d = chunk & 63 // 63 = 2^6 - 1
  229. // Convert the raw binary segments to the appropriate ASCII encoding
  230. base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
  231. }
  232. // Deal with the remaining bytes and padding
  233. if (byteRemainder == 1) {
  234. chunk = bytes[mainLength]
  235. a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
  236. // Set the 4 least significant bits to zero
  237. b = (chunk & 3) << 4 // 3 = 2^2 - 1
  238. base64 += encodings[a] + encodings[b] + '=='
  239. } else if (byteRemainder == 2) {
  240. chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
  241. a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
  242. b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
  243. // Set the 2 least significant bits to zero
  244. c = (chunk & 15) << 2 // 15 = 2^4 - 1
  245. base64 += encodings[a] + encodings[b] + encodings[c] + '='
  246. }
  247. return base64
  248. }
  249. /**
  250. * 调试log,只有_DEBUG_全局变量为true才会输出.
  251. */
  252. function debugLog()
  253. {
  254. if (typeof(_DEBUG_) != 'undefined') {
  255. if (_DEBUG_ == true) {
  256. console.log(...arguments)
  257. }
  258. }
  259. }
  260. /**
  261. * 获取自己的上传服务的url。
  262. * @param {*} url
  263. * @returns
  264. */
  265. function getMyUploadUrl(url)
  266. {
  267. return slashesUrl(window._CONFIG_.sysconfig.uploadServerBaseUrl + url);
  268. }
  269. /**
  270. * 获取自己的后台API服务url
  271. * @param {*} url
  272. * @returns
  273. */
  274. function getMyApiUrl(url)
  275. {
  276. return slashesUrl(window._CONFIG_.sysconfig.apiServerBaseUrl + url);
  277. }
  278. /**
  279. * 获取存储服务器组配置信息.
  280. */
  281. function getStorageServersConfig()
  282. {
  283. layui.use(['jquery', 'madmin', 'popup'], function () {
  284. let $ = layui.jquery;
  285. let madmin = layui.madmin;
  286. let popup = layui.popup;
  287. let config = madmin.getConfig();
  288. window._PLUP_SERVER_URI_ = getMyUploadUrl('/uploader.php'); // 依赖 getConfig
  289. $.ajax(
  290. {
  291. type:'GET',
  292. url: getMyUploadUrl('/sg_server_config.php?upload_token='+ window._UPLOAD_TOKEN_),
  293. data: {},
  294. async: false, // 注意,因为初始化,优先这里要同步.
  295. dataType: 'json',
  296. beforeSend : function() {
  297. },
  298. complete: function() {
  299. },
  300. error : function() {
  301. popup.failure('获取上传服务器请求出错');
  302. },
  303. success: function(s) {
  304. if (s.code == 200) {
  305. window._UPLOAD_SERVER_CONFIG_ = s.data;
  306. } else {
  307. popup.failure('['+ data.code +']' + data.message);
  308. }
  309. }
  310. }
  311. );
  312. });
  313. }
  314. /**
  315. * 拼接待解密的完整URL.
  316. * @param {*} url
  317. * @param {*} convertSlashes
  318. * @returns
  319. */
  320. function concatUrl(url, convertSlashes)
  321. {
  322. let baseUrl = '';
  323. if (url.lastIndexOf('|') > -1) {
  324. // 找到分隔符.
  325. let arrData = url.split('|');
  326. let flag = arrData[0];
  327. let relativeUrl = arrData[1];
  328. if (window._UPLOAD_SERVER_CONFIG_.servers.hasOwnProperty(flag)) {
  329. baseUrl = window._UPLOAD_SERVER_CONFIG_.servers[flag]['url'];
  330. var resultUrl = baseUrl + relativeUrl;
  331. if (convertSlashes) {
  332. resultUrl = slashesUrl(resultUrl);
  333. }
  334. return resultUrl;
  335. } else {
  336. return '';
  337. }
  338. } else {
  339. return '';
  340. }
  341. }
  342. /**
  343. * 在属性里获取url.
  344. * @param {*} ele
  345. * @returns
  346. */
  347. function getUrlInAttrs(ele)
  348. {
  349. return layui.use(['jquery'], function () {
  350. let $ = layui.jquery;
  351. let b64 = $(ele).attr('data-b64');
  352. if (b64) {
  353. return $(ele).attr('data-b64');
  354. } else {
  355. return '';
  356. }
  357. });
  358. }
  359. /**
  360. * 解密基于arrayBuffer数据.
  361. * @param {*} buffers
  362. * @returns
  363. */
  364. function aes128ecbDecodeByBuffer(buffers)
  365. {
  366. let encodedData = base64ArrayBuffer(buffers); // 这个地方很重要!
  367. let options = {
  368. iv: '',
  369. mode: CryptoJS.mode.ECB,
  370. padding: CryptoJS.pad.Pkcs7
  371. };
  372. let keyObj = CryptoJS.enc.Utf8.parse(window._AES_KEY_); // 必须是对象key
  373. let decrypted = CryptoJS.AES.decrypt(encodedData, keyObj, options);
  374. return decrypted;
  375. }
  376. /**
  377. * 拼接dataURL.
  378. * @param {*} b64
  379. * @returns
  380. */
  381. function concatImageDataUrl(b64)
  382. {
  383. return "data:image/png;base64," + b64;
  384. }
  385. /**
  386. * 现代浏览器Fetch异步下载并解密图片.
  387. * @param {*} url
  388. * @returns
  389. */
  390. function fetchImageFile(url)
  391. {
  392. return fetch(url, {
  393. method: 'GET'
  394. // headers: {
  395. // Authorization: 'Bearer ' + token,
  396. // 'Accept': 'application/json'
  397. // }
  398. }).then(
  399. // 必须是arrayBuffer
  400. response => {
  401. if (response.ok) {
  402. return response.arrayBuffer();
  403. } else {
  404. return Promise.reject({
  405. status: response.status,
  406. statusText: response.statusText
  407. });
  408. }
  409. }
  410. ).then(respRaw => {
  411. let ext = getFileExt(url);
  412. let strB64 = "";
  413. if (ext == 'ceb') {
  414. // 仅对ceb扩展名,进行解密.
  415. let decrypted = aes128ecbDecodeByBuffer(respRaw);
  416. strB64 = decrypted.toString(CryptoJS.enc.Base64);
  417. } else {
  418. strB64 = base64ArrayBuffer(respRaw);
  419. }
  420. let dataUrl = concatImageDataUrl(strB64);
  421. return dataUrl;
  422. }).catch(error => {
  423. });
  424. }
  425. /**
  426. * 获取文件扩展名,不包括dot.
  427. * @param {*} file
  428. * @returns
  429. */
  430. function getFileExt(file)
  431. {
  432. let ext = file.substring(file.lastIndexOf('.') + 1);
  433. return ext.toLowerCase();
  434. }
  435. /**
  436. * 渲染datahref
  437. * @param {*} ele
  438. * @param {*} dataHref
  439. */
  440. function renderDataHref(ele, dataHref)
  441. {
  442. layui.use(['jquery'], function () {
  443. let $ = layui.jquery;
  444. $(ele).attr('href', dataHref);
  445. });
  446. }
  447. /**
  448. * 渲染data
  449. * @param {*} ele
  450. * @param {*} dataUrl
  451. */
  452. function renderDataUrl(ele, dataUrl)
  453. {
  454. layui.use(['jquery'], function () {
  455. let $ = layui.jquery;
  456. $(ele).attr('src', dataUrl);
  457. });
  458. }
  459. /**
  460. * 单个对象渲染图片(依赖jQuery)
  461. * @param {*} ele
  462. */
  463. function onceRender(ele)
  464. {
  465. layui.use(['jquery'], function () {
  466. let $ = layui.jquery;
  467. let originUrl = '';
  468. let dataCebUrl = $(ele).attr('data-ceb-url');
  469. let srcValue = $(ele).attr('src');
  470. // 优先取data-ceb-url值,因为直接放src属性里的图片,会报404.
  471. if (typeof(dataCebUrl) != 'undefined' && dataCebUrl != '') {
  472. originUrl = dataCebUrl;
  473. } else if (typeof(srcValue) != 'undefined' && srcValue != '') {
  474. originUrl = srcValue;
  475. }
  476. if (originUrl.lastIndexOf('|') > -1) {
  477. let b64Url = originUrl;
  478. let convertSlashes = 1;
  479. // let b64Url = $(ele).attr('data-b64');
  480. let fullUrl = concatUrl(b64Url, convertSlashes);
  481. if (fullUrl != '') {
  482. // 备份一次原始图片地址
  483. $(ele).attr('data-ceb-url', originUrl);
  484. // 合法的才渲染.
  485. let promiseResult = fetchImageFile(fullUrl);
  486. promiseResult.then(dataUrl => {
  487. renderDataUrl(ele, dataUrl);
  488. });
  489. }
  490. }
  491. });
  492. }
  493. /**
  494. * 下载app地址处理
  495. * @param ele
  496. */
  497. function appDownloadRender(ele){
  498. layui.use(['jquery'], function () {
  499. let $ = layui.jquery;
  500. let dataHref = $(ele).attr('href');
  501. if (typeof(dataHref) == 'undefined' || dataHref === '') {
  502. return false;
  503. }
  504. // 拆分
  505. if (dataHref.lastIndexOf('|') > -1) {
  506. let arrData = dataHref.split('|');
  507. let flag = arrData[0];
  508. let relativeUrl = arrData[1];
  509. // 合并
  510. if (window._UPLOAD_SERVER_CONFIG_.servers.hasOwnProperty(flag)) {
  511. let baseUrl = window._UPLOAD_SERVER_CONFIG_.servers[flag]['url'];
  512. var resultUrl = baseUrl + relativeUrl;
  513. $(ele).attr('href',resultUrl);
  514. }
  515. }
  516. });
  517. }
  518. /**
  519. * 页面初始化dom加载完毕后渲染所有img标签.
  520. */
  521. function onloadRender()
  522. {
  523. layui.use(['jquery'], function () {
  524. let $ = layui.jquery;
  525. $(function() {
  526. $('img').each(function (index, ele) {
  527. onceRender(ele);
  528. });
  529. //app下载地址修改
  530. $('.app-download').each(function (index,ele){
  531. appDownloadRender(ele);
  532. });
  533. });
  534. });
  535. }
  536. /**
  537. * 获取同字段名数组的值.
  538. * 因为layui表单获取同字段名数组时,无法正常给数组结构。
  539. * @param {*} fieldName
  540. * @param {*} fieldItems
  541. * @returns
  542. */
  543. function getLayuiArrFieldValue(fieldName, fieldItems)
  544. {
  545. let arrFields = [];
  546. let arrData = [];
  547. if (fieldItems && Object.keys(fieldItems).length > 0) {
  548. for (const keyName in fieldItems) {
  549. if (fieldItems.hasOwnProperty(keyName)) {
  550. var strPattern = '^(' + fieldName +')\\[\\d+\\]$';
  551. var reg = new RegExp(strPattern, 'i')
  552. var result = keyName.match(reg);
  553. if (result) {
  554. arrFields.push(result[0]);
  555. arrData.push(fieldItems[keyName]);
  556. }
  557. }
  558. }
  559. }
  560. return arrData;
  561. }