util.js 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783
  1. import { MessageBox, Message } from 'yuwp-ui';
  2. import { sessionStore, extend } from '@yufp/xy-utils';
  3. import frameConfig from '@/config/frame';
  4. import { auditlogdata } from '@xdjf/oca-web/api/monitor';
  5. import { getAccessToken, getContrs } from '@/utils/oauth';
  6. import router from '@/router';
  7. import XLSX from 'xlsx';
  8. import { ADMIN_ROLECODES, MENU_STOREOG_KEY, USER_STORE_KEY } from '@/config/constant/app.data.common';
  9. import backend from '@/config/constant/app.data.service.js';
  10. /**
  11. * 显示信息
  12. * @param {string} msg 待显示的信息
  13. * @param {String} type 显示信息类型 error|warning|info|success
  14. * @param {Integer} duration 显示信息长度,单位秒,默认5秒
  15. */
  16. export function showMessage(msg, type = 'error', duration = 5) {
  17. msg &&
  18. Message({
  19. message: msg,
  20. type,
  21. duration: duration * 1000,
  22. });
  23. }
  24. /**
  25. * 显示信息
  26. * @param {string} msg 待显示的信息
  27. * @param {String} type 显示信息类型 error|waring|info|success
  28. */
  29. export function showMessageAlert(msg, type = 'error') {
  30. msg &&
  31. MessageBox({
  32. message: msg,
  33. type,
  34. });
  35. }
  36. // 判断浏览器类型
  37. export function getBrowserType() {
  38. const { userAgent } = navigator; // 取得浏览器的userAgent字符串
  39. if (userAgent.indexOf('OPR') > -1) {
  40. return 'Opera';
  41. } // 判断是否Opera浏览器 OPR/43.0.2442.991
  42. if (userAgent.indexOf('Firefox') > -1) {
  43. return 'FF';
  44. } // 判断是否Firefox浏览器 Firefox/51.0
  45. if (userAgent.indexOf('Trident') > -1) {
  46. return 'IE';
  47. } // 判断是否IE浏览器 Trident/7.0; rv:11.0
  48. if (userAgent.indexOf('Edge') > -1) {
  49. return 'Edge';
  50. } // 判断是否Edge浏览器 Edge/14.14393
  51. if (userAgent.indexOf('Chrome') > -1) {
  52. return 'Chrome';
  53. } // Chrome/56.0.2924.87
  54. if (userAgent.indexOf('Safari') > -1) {
  55. return 'Safari';
  56. } // 判断是否Safari浏览器 AppleWebKit/534.57.2 Version/5.1.7 Safari/534.57.2
  57. }
  58. /** *
  59. * 上午下午中午
  60. */
  61. export function getTimeOfDay() {
  62. const now = new Date();
  63. const hour = now.getHours();
  64. if (hour < 12) {
  65. return '早上';
  66. }
  67. if (hour >= 12 && hour < 18) {
  68. return '下午';
  69. }
  70. return '晚上';
  71. }
  72. /**
  73. * 获取默认皮肤对象
  74. */
  75. export function getDefaultTheme() {
  76. const themes = frameConfig.baseFrameOptions.themesList.filter((item) => {
  77. const themekey = window.XYWEB_SYS_CONFIG.theme || frameConfig.theme;
  78. return item.id === themekey;
  79. });
  80. return themes.length > 0 ? themes[0] : null;
  81. }
  82. /**
  83. * 获取默认布局对象
  84. */
  85. export function getDefaultMenuModel() {
  86. const model = frameConfig.baseFrameOptions.modelList.filter((item) => {
  87. return item.id === frameConfig.menumodel;
  88. });
  89. return model.length > 0 ? model[0] : null;
  90. }
  91. /**
  92. * 获取当前选中系统名称
  93. */
  94. export function getSystemName() {
  95. const systemName = sessionStore.get('currentApp');
  96. if (systemName) {
  97. return systemName.applicationName;
  98. }
  99. if (frameConfig.baseFrameOptions.appOptions.length > 1) {
  100. return frameConfig.baseFrameOptions.appOptions[0].applicationName;
  101. }
  102. return '';
  103. }
  104. /**
  105. * 获取全路径
  106. */
  107. export function getUrl(param) {
  108. let paramUrl = param.url || param.name;
  109. if (!paramUrl) {
  110. throw new Error('Yufp.service.request: 未设置请求URL');
  111. }
  112. const reg = /^(http|https):\/\//;
  113. // url请求未附带http(s)://前缀,则按yufp.settings.url及ssl添加前缀
  114. if (!reg.test(paramUrl)) {
  115. let protocol;
  116. let prefixUrl = import.meta.env.VUE_APP_DOWNLOAD_PATH || '';
  117. // yufp.settings.url 非空,即非默认同源模式,计算服务端URL源路径
  118. if (prefixUrl) {
  119. if (reg.test(prefixUrl)) {
  120. protocol = '';
  121. } else {
  122. protocol = 'http://';
  123. }
  124. prefixUrl = protocol + prefixUrl;
  125. }
  126. paramUrl = `/${paramUrl}`.replace(/^\/\//, '/'); // 添加前缀
  127. paramUrl = (import.meta.env.VUE_APP_BASE_API || '') + paramUrl; // 添加basePath
  128. paramUrl = prefixUrl + paramUrl; // 组合origin
  129. }
  130. return paramUrl;
  131. }
  132. /**
  133. * 为url添加token信息
  134. * @param url
  135. * @returns {string}
  136. */
  137. export function addTokenInfo(url) {
  138. const token = 'accessToken=';
  139. let _url = '';
  140. if (url === null || url === '') {
  141. return _url;
  142. }
  143. if (!url.indexOf(token) > -1) {
  144. _url = url + (url.indexOf('?') > -1 ? '&' : '?') + token + getAccessToken();
  145. }
  146. return _url;
  147. }
  148. /**
  149. * @description 从文件服务器上获取文件路径
  150. * @param {String} fileId 文件ID
  151. * @returns {String} 文件全路径,文件ID为空时,返回空字符串
  152. */
  153. export function getFileUrl(fileId) {
  154. return (fileId && addTokenInfo(`${backend.fileService}/api/file/provider/download?fileId=${fileId}`)) || '';
  155. }
  156. /**
  157. * @description 获取文件上传路径
  158. * @returns {String} 文件全路径,文件ID为空时,返回空字符串
  159. */
  160. export function getUploadFileUrl() {
  161. return addTokenInfo(`${backend.fileService}/api/file/provider/uploadfile`);
  162. }
  163. /**
  164. * 下载文件
  165. */
  166. export function download(path) {
  167. if (path) {
  168. if (path.indexOf('http') <= -1) {
  169. // 当不包含http时拼接gateway地址
  170. path = getUrl({
  171. url: path,
  172. });
  173. }
  174. } else {
  175. showMessage('必须设置请求url!', 'warning');
  176. }
  177. // url添加token
  178. path = addTokenInfo(path);
  179. // 模拟a标签进行下载
  180. const a = document.createElement('a');
  181. a.href = path;
  182. console.log('href', path);
  183. if (window.fireEvent) {
  184. window.open(a.href);
  185. } else {
  186. a.click();
  187. }
  188. }
  189. /**
  190. * @param {HTMLElement} element
  191. * @param {string} className
  192. */
  193. export function toggleClass(element, className, oid) {
  194. if (!element || !className) {
  195. return;
  196. }
  197. let classString = element.className;
  198. // 替换2个以上的空格为一个空格 解决\s+正则替换出现样式无空格问题
  199. classString = classString.replace(/\s{1,}/g, ' ').replace(oid, '');
  200. const nameIndex = classString.indexOf(className);
  201. if (nameIndex === -1) {
  202. classString += ` ${className}`;
  203. } else {
  204. // 旧id存在时,才做替换,解决空样式替换出现的主题色消失问题
  205. oid && (classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length));
  206. }
  207. element.className = classString;
  208. }
  209. /**
  210. * 切换皮肤
  211. * @param {String} theme 选中皮肤
  212. */
  213. export function changeTheme(theme) {
  214. const colors = theme.colorList;
  215. // 改变全局变量来换肤
  216. document.getElementsByTagName('body')[0].style.setProperty('--main-color', colors[0]);
  217. document.getElementsByTagName('body')[0].style.setProperty('--second-color', colors[1]);
  218. document.getElementsByTagName('body')[0].style.setProperty('--third-color', colors[2]);
  219. document.getElementsByTagName('body')[0].style.setProperty('--fourth-color', colors[3]);
  220. document.getElementsByTagName('body')[0].style.setProperty('--fifth-color', colors[4]);
  221. }
  222. /**
  223. * 更新界面是否紧凑模式
  224. * @param {Boolean} isCompact 是否紧凑模式
  225. */
  226. export function changeSizeModel(isCompact) {
  227. // const target = document.getElementsByTagName('link');
  228. const dom = document.querySelector('.yu-frame-body'); // dom结构
  229. const newClas = isCompact ? 'compact' : 'normal'; // 新样式
  230. const oldClas = !isCompact ? 'compact' : 'normal'; // 旧样式
  231. // 切换样式
  232. toggleClass(dom, newClas, oldClas);
  233. }
  234. /**
  235. * 格式化时间
  236. */
  237. export function parseTime(time, cFormat) {
  238. if (arguments.length === 0) {
  239. return null;
  240. }
  241. const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
  242. let date;
  243. if (typeof time === 'object') {
  244. date = time;
  245. } else {
  246. // modify by luyq1 解决时间传参问题
  247. if (typeof time === 'number' && !isNaN(time) && `${time}`.length === 10) {
  248. time = parseInt(time) * 1000;
  249. }
  250. if (typeof time === 'string') {
  251. time = time.replace(/-/g, '/');
  252. }
  253. // 解决new Date 创建时间 默认是8点的问题
  254. date = new Date(time);
  255. }
  256. const formatObj = {
  257. y: date.getFullYear(),
  258. m: date.getMonth() + 1,
  259. d: date.getDate(),
  260. h: date.getHours(),
  261. i: date.getMinutes(),
  262. s: date.getSeconds(),
  263. a: date.getDay(),
  264. };
  265. const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, function (result, key) {
  266. let value = formatObj[key];
  267. if (key === 'a') {
  268. return ['一', '二', '三', '四', '五', '六', '日'][value - 1];
  269. }
  270. if (result.length > 0 && value < 10) {
  271. value = `0${value}`;
  272. }
  273. return value || 0;
  274. });
  275. return timeStr;
  276. }
  277. /**
  278. * 将时间转成字符串
  279. */
  280. export function formatTime(time) {
  281. return `${time.hours < 10 ? `0${time.hours}` : time.hours}:${time.minutes < 10 ? `0${time.minutes}` : time.minutes}`;
  282. }
  283. /**
  284. * 判断两个时间段是否相差 多少天
  285. * @param {new Date(‘2023-01-13 10:14:30’)} time1 日期类型
  286. * @param {new Date(‘2023-01-13 10:14:30’)} time2 日期类型
  287. * @param {Number} m 天数
  288. */
  289. export function completeDate(time1, time2, m) {
  290. let totalDays;
  291. let diffDate;
  292. // eslint-disable-next-line camelcase
  293. const myDate_1 = Date.parse(time1);
  294. // eslint-disable-next-line camelcase
  295. const myDate_2 = Date.parse(time2);
  296. // eslint-disable-next-line camelcase
  297. diffDate = Math.abs(myDate_1 - myDate_2);
  298. totalDays = diffDate / (1000 * 3600 * 24);
  299. return totalDays <= m;
  300. // var diffyear = time2.getFullYear() - time1.getFullYear() ;
  301. // var diffmonth = diffyear * 12 + time2.getMonth() - time1.getMonth() ;
  302. // if(diffmonth < 0) {
  303. // return false ;
  304. // }
  305. // var diffDay = time2.getDate() - time1.getDate() ;
  306. // if(diffmonth < m || (diffmonth == m && diffDay <= 0)) {
  307. // if(diffmonth == m && diffDay == 0) {
  308. // var timeA = time1.getHours() * 3600 + 60 * time1.getMinutes() + time1.getSeconds();
  309. // var timeB = time2.getHours() * 3600 + 60 * time2.getMinutes() + time2.getSeconds();
  310. // if(timeB - timeA > 0) {
  311. // return false;
  312. // }
  313. // }
  314. // return true ;
  315. // }
  316. // return false ;
  317. }
  318. /**
  319. * 获取基础路径配置信息
  320. */
  321. export function getBaseUrl() {
  322. const devEnv = import.meta.env.NODE_ENV === 'development'; // 开发环境
  323. const baseApi = import.meta.env.VUE_APP_BASE_API; // 应用服务前缀URL
  324. const proxyPrefix = import.meta.env.VUE_APP_PROXY_PREFIX || ''; // 代理API前缀
  325. const match = /^(https?:\/\/)([0-9a-z.]+)(:[0-9]+)?([/0-9a-z.-]+)?/i; // 匹配URL(协议+域名+端口)
  326. const matchResult = match.exec(baseApi);
  327. return devEnv && matchResult ? proxyPrefix + (matchResult[4] || '') : baseApi;
  328. }
  329. /**
  330. * 获取公钥字符串
  331. */
  332. export function getRSAPublicKey() {
  333. return 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrDUHc85ADQVxXRP4M90nqttWoZctV6JJVVdPjIle5vd9G2/4kgIhNc78Jd+ENxg+n4Gj9UMwNhJmb2jnMaW3zyGB+qi/ZrMO5dEUhW8salirzRgGg/4Arz4ObPmCWlZsws3Ij/3IEsFD3vMdIZD2j8b33DAbj47PjcCcMbtHYuQIDAQAB';
  334. }
  335. /**
  336. * @created by zhangkun6
  337. * @updated by 2018/01/14
  338. * @description 数字金额格式化(千分位)
  339. */
  340. export function moneyFormatter(money, num) {
  341. /*
  342. * 参数说明:
  343. * money:要格式化的数字
  344. * num:保留几位小数
  345. * */
  346. num = num > 0 && num <= 20 ? num : 2;
  347. money = `${parseFloat(`${money}`.replace(/[^\d.-]/g, '')).toFixed(num)}`;
  348. const l = money.split('.')[0].split('').reverse();
  349. const r = money.split('.')[1];
  350. let t = '';
  351. for (let i = 0; i < l.length; i++) {
  352. t += l[i] + ((i + 1) % 3 === 0 && i + 1 !== l.length ? ',' : '');
  353. }
  354. return `${t.split('').reverse().join('')}.${r}`;
  355. }
  356. /**
  357. * @created by zhangkun6
  358. * @updated by 2018/05/03
  359. * @description 数值百分比显示
  360. */
  361. export function toPercent(money, num) {
  362. /*
  363. * 参数说明:
  364. * money:要格式化的数字
  365. * num:保留几位小数
  366. */
  367. // num = num > 0 && num <= 20 ? num : 2;
  368. money = `${parseFloat(`${money}`)}%`;
  369. return money;
  370. }
  371. /**
  372. * @created by zhangkun6
  373. * @updated by 2018/01/14
  374. * @description 数字金额转汉字金额
  375. */
  376. export function moneyToUpper(money) {
  377. /*
  378. * 参数说明:
  379. * money:要转化的数字
  380. */
  381. // 汉字的数字
  382. const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  383. // 基本单位
  384. const cnIntRadice = ['', '拾', '佰', '仟'];
  385. // 对应整数部分扩展单位
  386. const cnIntUnits = ['', '万', '亿', '兆'];
  387. // 对应小数部分单位
  388. const cnDecUnits = ['角', '分', '毫', '厘'];
  389. // 整数金额时后面跟的字符
  390. const cnInteger = '整';
  391. // 整型完以后的单位
  392. const cnIntLast = '元';
  393. // 最大处理的数字
  394. const maxNum = 999999999999999.9999;
  395. // 金额整数部分
  396. let integerNum;
  397. // 金额小数部分
  398. let decimalNum;
  399. // 输出的中文金额字符串
  400. let chineseStr = '';
  401. // 分离金额后用的数组,预定义
  402. let parts;
  403. if (money === '') {
  404. return '';
  405. }
  406. money = parseFloat(money);
  407. if (money >= maxNum) {
  408. // 超出最大处理数字
  409. return '';
  410. }
  411. if (money === 0) {
  412. chineseStr = cnNums[0] + cnIntLast + cnInteger;
  413. return chineseStr;
  414. }
  415. // 转换为字符串
  416. money = money.toString();
  417. if (money.indexOf('.') === -1) {
  418. integerNum = money;
  419. decimalNum = '';
  420. } else {
  421. parts = money.split('.');
  422. integerNum = parts[0];
  423. decimalNum = parts[1].substr(0, 4);
  424. }
  425. // 获取整型部分转换
  426. if (parseInt(integerNum, 10) > 0) {
  427. let zeroCount = 0;
  428. const IntLen = integerNum.length;
  429. for (let i = 0; i < IntLen; i++) {
  430. const n = integerNum.substr(i, 1);
  431. const p = IntLen - i - 1;
  432. const q = p / 4;
  433. const m = p % 4;
  434. if (n === '0') {
  435. zeroCount++;
  436. } else {
  437. if (zeroCount > 0) {
  438. chineseStr += cnNums[0];
  439. }
  440. // 归零
  441. zeroCount = 0;
  442. chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
  443. }
  444. if (m === 0 && zeroCount < 4) {
  445. chineseStr += cnIntUnits[q];
  446. }
  447. }
  448. chineseStr += cnIntLast;
  449. }
  450. // 小数部分
  451. if (decimalNum !== '') {
  452. const decLen = decimalNum.length;
  453. for (let i = 0; i < decLen; i++) {
  454. const n = decimalNum.substr(i, 1);
  455. if (n !== '0') {
  456. chineseStr += cnNums[Number(n)] + cnDecUnits[i];
  457. }
  458. }
  459. }
  460. if (chineseStr === '') {
  461. chineseStr += cnNums[0] + cnIntLast + cnInteger;
  462. } else if (decimalNum === '') {
  463. chineseStr += cnInteger;
  464. }
  465. return chineseStr;
  466. }
  467. /**
  468. * @created by zhangkun6
  469. * @updated by 2018/01/19
  470. * @description 汉字金额转数字金额
  471. */
  472. export function upperToMoney(upper) {
  473. /*
  474. * 参数说明:
  475. * upper:要转化的汉字
  476. */
  477. // 金额数值
  478. const num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  479. // 汉字的数字
  480. const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  481. // 对应单位的乘积
  482. const upperMap = [10, 100, 1000];
  483. // 基本单位
  484. const cnIntRadice = ['拾', '佰', '仟'];
  485. // 对应整数部分扩展单位
  486. // var cnIntUnits = ['万', '亿', '兆'];
  487. // 对应小数部分单位乘积
  488. const cnDecMap = [0.1, 0.01];
  489. // 对应小数部分单位
  490. const cnDecUnits = ['角', '分'];
  491. // 金额单位亿之前的数值数组
  492. let maxArray = [];
  493. // 金额单位亿和万之间的数值数组
  494. let middleArray = [];
  495. // 金额单位万和元之间的数值数组
  496. let minArray = [];
  497. const part = upper.split('元');
  498. // 金额整数部分
  499. const integerNum = part[0];
  500. // 金额小数部分
  501. const decimalNum = part[1].split('');
  502. if (integerNum.indexOf('亿') !== -1) {
  503. maxArray = integerNum.split('亿')[0].split('');
  504. if (integerNum.indexOf('万') !== -1) {
  505. middleArray = integerNum.split('亿')[1].split('万')[0].split('');
  506. minArray = integerNum.split('亿')[1].split('万')[1].split('');
  507. } else {
  508. minArray = integerNum.split('亿')[1].split('');
  509. }
  510. } else if (integerNum.indexOf('万') !== -1) {
  511. middleArray = integerNum.split('万')[0].split('');
  512. minArray = integerNum.split('万')[1].split('');
  513. } else {
  514. minArray = integerNum.split('');
  515. }
  516. const getNum = function (upArray, cnNums, cnRadice, numArray, map) {
  517. const { length } = upArray;
  518. let num = 0;
  519. let sum = 0;
  520. for (let i = 0; i < length; i++) {
  521. const index = cnNums.indexOf(upArray[i]);
  522. const _index = cnRadice.indexOf(upArray[i]);
  523. if (index !== -1) {
  524. num += numArray[index];
  525. if (i === length - 1) {
  526. sum += num;
  527. }
  528. }
  529. if (_index !== -1) {
  530. num *= map[_index];
  531. sum += num;
  532. num = 0;
  533. }
  534. }
  535. return sum;
  536. };
  537. const maxSum = getNum(maxArray, cnNums, cnIntRadice, num, upperMap);
  538. const middleSun = getNum(middleArray, cnNums, cnIntRadice, num, upperMap);
  539. const minSun = getNum(minArray, cnNums, cnIntRadice, num, upperMap);
  540. const cesSum = getNum(decimalNum, cnNums, cnDecUnits, num, cnDecMap);
  541. // 输出的数字金额字符串
  542. return maxSum * 100000000 + middleSun * 10000 + minSun + cesSum;
  543. }
  544. /**
  545. * 从路径中解析查询参数
  546. * @param {String} url 路径
  547. */
  548. export function resolveQueryParameters(url) {
  549. if (url) {
  550. const i = url.indexOf('?');
  551. if (i > -1) {
  552. const query = url.substr(i + 1);
  553. const vars = query.split('&');
  554. const queryParams = {};
  555. for (let i = 0; i < vars.length; i++) {
  556. const pair = vars[i].split('=');
  557. queryParams[pair[0]] = pair[1];
  558. }
  559. return queryParams;
  560. }
  561. }
  562. return null;
  563. }
  564. /**
  565. * @description 判断传入的节点是不是选中节点的子节点
  566. * @param value 当前输入信息
  567. * @param nodeData 当前节点属性信息
  568. * @param label 当前节点名称
  569. */
  570. export function checkBelongToChooseNode(value, node, label) {
  571. const { level } = node;
  572. // 如果传入的节点本身就是一级节点就不用校验了
  573. if (level === 1) {
  574. return false;
  575. }
  576. // 先取当前节点的父节点
  577. let parentData = node.parent;
  578. // 遍历当前节点的父节点
  579. let index = 0;
  580. while (index < level - 1) {
  581. // 如果匹配到直接返回
  582. if (parentData.data[label] && parentData.data[label].indexOf(value) !== -1) {
  583. return true;
  584. }
  585. // 否则的话再往上一层做匹配
  586. parentData = parentData.parent;
  587. index++;
  588. }
  589. // 没匹配到返回false
  590. return false;
  591. }
  592. /* 监控 */
  593. if (frameConfig.monitorAble) {
  594. require('./yufp.monitor');
  595. }
  596. /**
  597. * @description 上传按钮日志
  598. */
  599. export function logInfo(data) {
  600. auditlogdata(data);
  601. }
  602. // 控制点公共方法
  603. export function checkCtrl(ctrlCode, menuId, isView) {
  604. const ctrls = getContrs();
  605. const route = router.history.current;
  606. // 低码预览页面,路由的参数在route.params.routeId中
  607. menuId = menuId || route.meta.routeId || route.params.routeId;
  608. if (!ctrlCode || !ctrls || !menuId) {
  609. return false;
  610. }
  611. const ctrlItem = ctrls.filter((item) => {
  612. return item.funcId === menuId && item.contrCode === ctrlCode;
  613. });
  614. if (ctrls && menuId && !ctrlItem.length) {
  615. return true;
  616. }
  617. return false;
  618. }
  619. /**
  620. * @description 上传页面访问rizhi
  621. * @to 路由信息
  622. */
  623. export function menuLog(to) {
  624. if (!to.meta) {
  625. return;
  626. }
  627. const zhCn = {
  628. menu: '菜单',
  629. path: '路径:',
  630. accessMenu: '访问菜单:',
  631. };
  632. const lang = zhCn;
  633. const log = {
  634. logCtg: '2',
  635. oprObj: lang.menu,
  636. oprCtnt: `${lang.accessMenu}${to.meta.title},${lang.path}${to.meta.routeUrl}`,
  637. funcModlName: to.meta.title,
  638. };
  639. logInfo(log);
  640. }
  641. /**
  642. * 倒计时,
  643. * 通过当前系统时间为维度进行动态计算时间差,
  644. * @param {*} options
  645. * options: {
  646. * time: Number
  647. * change: Function 倒计时刷新函数
  648. * finish: Function 结束倒计时函数
  649. * }
  650. */
  651. export function countDown(options) {
  652. const endTime = options.time * 1000 + Date.now();
  653. let rafId;
  654. let isCounting = true;
  655. const getCurrentRemain = () => Math.max(endTime - Date.now(), 0);
  656. const isSameSecond = (time1, time2) => {
  657. return Math.floor(time1 / 1000) === Math.floor(time2 / 1000);
  658. };
  659. let currentTime = endTime;
  660. const setRemain = (value) => {
  661. currentTime = value;
  662. typeof options.change === 'function' && options.change(parseInt(currentTime / 1000));
  663. if (value === 0) {
  664. cancelAnimationFrame(rafId);
  665. isCounting = false;
  666. typeof options.finish === 'function' && options.finish();
  667. }
  668. };
  669. const macroTick = () => {
  670. rafId = requestAnimationFrame(() => {
  671. // in case of call reset immediately after finish
  672. if (isCounting) {
  673. const remainRemain = getCurrentRemain();
  674. if (!isSameSecond(remainRemain, currentTime) || remainRemain === 0) {
  675. setRemain(remainRemain);
  676. }
  677. if (currentTime >= 0) {
  678. macroTick();
  679. }
  680. }
  681. });
  682. };
  683. macroTick();
  684. return {
  685. stop: () => {
  686. cancelAnimationFrame(rafId);
  687. isCounting = false;
  688. },
  689. };
  690. }
  691. /** 补齐方法,防止校验报错 */
  692. /**
  693. * 将数组转化为树
  694. * @param {*} data 数组数据
  695. * @param {*} options 映射关系,默认{ id: 'id', pid: 'pid', root: '-1 }
  696. * @returns
  697. */
  698. export function array2tree(data, options) {
  699. const _options = {
  700. id: 'id',
  701. pid: 'pid',
  702. root: '-1',
  703. };
  704. extend(_options, options || {});
  705. const idField = _options.id;
  706. const pidField = _options.pid;
  707. let root;
  708. let children = [];
  709. if (typeof _options.root === 'object') {
  710. root = _options.root;
  711. } else {
  712. const tempObj = {};
  713. tempObj[idField] = _options.root;
  714. root = tempObj;
  715. }
  716. const rId = `${root[idField]}`;
  717. for (let i = 0, len = data.length; i < len; i++) {
  718. const d = data[i];
  719. if (rId === `${d[idField]}`) {
  720. root = d;
  721. } else if (rId === `${d[pidField]}`) {
  722. children.push(d);
  723. }
  724. }
  725. root.id = root[idField];
  726. children = root.children ? root.children.concat(children) : children;
  727. root.children = children;
  728. for (let i = 0, len = root.children.length; i < len; i++) {
  729. _options.root = root.children[i];
  730. root.children[i] = array2tree(data, _options);
  731. }
  732. return root;
  733. }
  734. /**
  735. * 将大写并且带有下划线的XX_YY设置成小驼峰
  736. */
  737. export function toCamelCase(str) {
  738. return str
  739. .toLowerCase() // 将字符串转换为小写
  740. .replace(
  741. /_./g,
  742. (
  743. match, // 用正则表达式匹配下划线及其后的字符
  744. ) => match.charAt(1).toUpperCase(), // 将下划线后的字符转为大写
  745. );
  746. }
  747. /**
  748. * 通过 a 标签 download 属性结合 blob 构造函数下载
  749. * @param {*} res
  750. * @param {*} filename
  751. * @param {*} fileType
  752. */
  753. export function fileDownloadBlob(res, filename, fileType) {
  754. // 添加文件类型
  755. let blobTypeParams = {};
  756. if (fileType === 'xls') {
  757. blobTypeParams = {
  758. type: 'application/vnd.ms-excel',
  759. };
  760. } else if (fileType === 'pdf') {
  761. blobTypeParams = {
  762. type: 'application/pdf',
  763. };
  764. } else if (fileType === 'xlsx') {
  765. blobTypeParams = {
  766. type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  767. };
  768. } else if (fileType === 'zip') {
  769. blobTypeParams = {
  770. type: 'application/zip',
  771. };
  772. }
  773. const nFileType = fileType ? '.' + fileType : '';
  774. let nFileName = filename + nFileType;
  775. const blobData = new Blob([res.data], blobTypeParams);
  776. // 有可能下载失败,比如返回{code: 0},但设置了responseType: 'blob',axios会把data强制转为blob,导致下载undefined
  777. // 解决:将已转为blob类型的data转回json格式,判断是否下载成功
  778. const reader = new window.FileReader();
  779. let parseObj = null;
  780. reader.readAsText(res.data, 'utf-8');
  781. reader.onload = function () {
  782. try {
  783. parseObj = JSON.parse(reader.result);
  784. showMessage(parseObj.message || '下载失败');
  785. } catch (error) {
  786. // filename不存在时取请求头中的文件名称
  787. if (!nFileName) {
  788. let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*');
  789. let contentDisposition = decodeURI(res.headers['content-disposition']);
  790. nFileName = patt.exec(contentDisposition)[1];
  791. }
  792. if (window.navigator.msSaveBlob) {
  793. window.navigator.msSaveBlob(blobData, nFileName);
  794. } else {
  795. const url = window.URL.createObjectURL(blobData);
  796. const link = document.createElement('a');
  797. link.style.display = 'none';
  798. link.href = url;
  799. link.setAttribute('download', nFileName);
  800. document.body.appendChild(link);
  801. link.click();
  802. }
  803. }
  804. };
  805. }
  806. // 对象判空
  807. export function isNullOrUndefined(param) {
  808. if (param === null || param === '' || param === undefined || param.length === 0 || typeof param === 'undefined') {
  809. return true;
  810. }
  811. return false;
  812. }
  813. // 参数为空则默认某值,否则返回该参数
  814. export function isNullOrUndefinedSetDef(param, defValue) {
  815. if (isNullOrUndefined(param)) {
  816. return defValue;
  817. }
  818. return param;
  819. }
  820. /**
  821. * js导出excel
  822. * 方法参数为一个Object, 包含以下属性:
  823. * ref: xtable对应的vue对象ref
  824. * importType: selected: 选中行的数据;page: 当前页面展示的所有表格数据;service:根据传递的参数从服务端获取要导出的数据
  825. * method: 从服务端获取要导出的数据时的请求method
  826. * url: 从服务端获取要导出的数据时的请求url
  827. * param: 从服务端获取要导出的数据时的请求参数
  828. * fileName: 导出文件名
  829. * importHidCloum: true/false 是否导出隐藏列,默认导出
  830. * stringifyNum: true/false 是否转换数字单元格内容为文本,以防止大数字显示为科学计数,默认为false
  831. * FAQ: 对于多表头的列,
  832. * 只有最底层的子节点可以配置prop属性,
  833. * 非最底层的不可以配置prop属性,
  834. * 整个表格的prop不可以重复,
  835. * 当表格使用了插槽的时候,会导致表格列的数据结构发生变化,现有方法不能满足使用插槽的表格导出
  836. * @author lvzl
  837. * @returns {*}
  838. */
  839. export function exportExcelByTable(options) {
  840. // const {log} = console;
  841. options.importHidCloum = options.importHidCloum || true;
  842. let tableRef = options.ref;
  843. let colums = tableRef.tableColumns;
  844. let tableColumns = colums.concat([]);
  845. if (!options.importHidCloum) {
  846. removeHidCloums(tableColumns);
  847. }
  848. // 移除隐藏列
  849. function removeHidCloums(arr) {
  850. if (!arr || !Array.isArray(arr)) {
  851. return new Error('参数类型必须是数组');
  852. }
  853. for (let i = 0; i < arr.length; i++) {
  854. let element = arr[i];
  855. if (element.hideColumn) {
  856. arr.splice(i, 1);
  857. }
  858. if (element.children && Array.isArray(element.children) && element.children.length > 0) {
  859. removeHidCloums(element.children);
  860. }
  861. }
  862. }
  863. /** 输出计算的结果 */
  864. // log('初始状态的tableColumns', JSON.stringify(tableColumns));
  865. let collectionHtml = tableRef.$el.getElementsByClassName('el-table__header-wrapper')[0].getElementsByTagName('tr');
  866. /** ----------------------------------> 1.获取表头行列数,给表头每个单元格设置行列合并数rowspan/colspan <------------------------------------------ */
  867. // 获取表头行数和列数(包含多级表头)
  868. function getRowAndCol(list) {
  869. if (!list || !Array.isArray(list)) {
  870. return new Error('参数类型必须是数组');
  871. }
  872. let haveSubCellList = []; // 存储每个多级表头整体的行列数信息
  873. for (let i = 0; i < list.length; i++) {
  874. if (list[i].children) {
  875. haveSubCellList.push(getMaxFloor(list[i].children));
  876. }
  877. }
  878. // 含有多个多级表头时获取最大的行数
  879. let maxRow;
  880. if (haveSubCellList.length > 0) {
  881. maxRow = Math.max.apply(null, haveSubCellList) + 1;
  882. } else {
  883. maxRow = 1;
  884. }
  885. return { rowCount: maxRow, colCount: maxColCount(list) };
  886. }
  887. // 计算colCount
  888. function maxColCount(column) {
  889. if (!column || !Array.isArray(column)) {
  890. return new Error('参数类型必须是数组');
  891. }
  892. let colCount = 0; // colCount: 横向最底层单元格列数
  893. for (let i = 0; i < column.length; i++) {
  894. let element = column[i];
  895. if (element.children && Array.isArray(element.children) && element.children.length > 0) {
  896. let childrenColCount = maxColCount(element.children);
  897. colCount += childrenColCount; // 横向叠加计算总列数
  898. } else {
  899. colCount++;
  900. }
  901. }
  902. return colCount;
  903. }
  904. // 计算多表头的rowCount
  905. function getMaxFloor(treeData) {
  906. // let floor = 0;
  907. // let v = this;
  908. let max = 0;
  909. function each(data, floor) {
  910. data.forEach(function (e) {
  911. e.floor = floor;
  912. if (floor > max) {
  913. max = floor;
  914. }
  915. if (e.children && Array.isArray(e.children) && e.children.length > 0) {
  916. each(e.children, floor + 1);
  917. }
  918. });
  919. }
  920. each(treeData, 1);
  921. return max;
  922. }
  923. // 获取整个完整表头的行列数
  924. let cellData = getRowAndCol(tableColumns);
  925. /** 输出计算的结果 */
  926. // log('整个表头的行列数:', JSON.stringify(cellData));
  927. // 给表头每个单元格设置行列合并数量信息rowspan行 colspan列
  928. let maxcolspan = function (list) {
  929. if (list && Array.isArray(list) == true) {
  930. for (let i = 0; i < list.length; i++) {
  931. let element = list[i];
  932. let children = element.children;
  933. let childrenColCount;
  934. if (children) {
  935. childrenColCount = maxColCount(children); // 获取当前单元格的子单元格行列数
  936. }
  937. if (children && Array.isArray(children) && children.length > 0) {
  938. // 存在子节点
  939. element.rowspan = 0;
  940. element.colspan = childrenColCount - 1;
  941. getChildColspan(children);
  942. } else {
  943. // 不存在子节点
  944. element.colspan = 0;
  945. element.rowspan = cellData.rowCount - 1;
  946. }
  947. }
  948. }
  949. };
  950. function getChildColspan(list) {
  951. let listRowCount = getMaxFloor(list); // 获取当前list的占用单元格的行数和列数
  952. let rowIndex = cellData.rowCount - listRowCount;
  953. if (list && Array.isArray(list) == true) {
  954. for (let i = 0; i < list.length; i++) {
  955. let element = list[i];
  956. let children = element.children;
  957. let childrenColCount;
  958. if (children) {
  959. childrenColCount = maxColCount(children); // 获取当前单元格的子单元格行列数
  960. }
  961. if (children && Array.isArray(children) && children.length > 0) {
  962. // 存在子节点
  963. element.colspan = childrenColCount - 1;
  964. element.rowspan = 0;
  965. getChildColspan(children);
  966. } else {
  967. // 不存在子节点
  968. element.rowspan = listRowCount - rowIndex <= 0 ? 0 : listRowCount - rowIndex;
  969. element.colspan = 0;
  970. }
  971. }
  972. }
  973. }
  974. maxcolspan(tableColumns);
  975. /** 输出计算的结果 */
  976. // let arr = [];
  977. // for (let i = 0; i < tableColumns.length; i++) {
  978. // arr.push({label: tableColumns[i].label, colspan: tableColumns[i].colspan, rowspan: tableColumns[i].rowspan});
  979. // }
  980. // log('每个单元格的colspan&rowspan:', JSON.stringify(arr));
  981. /** ----------------------------------> 2.获取所有表头字段名label <------------------------------------------ */
  982. // 存储所有表头字段名
  983. let headLabel = []; // 所有表头的label,prop,没有prop就取''.
  984. let havePropArr = []; // 所有表头字段的prop
  985. let haveOptions = []; // 所有含有options的prop
  986. function getHeadLabel(list) {
  987. if (!list || !Array.isArray(list)) {
  988. return new Error('参数类型必须是数组');
  989. }
  990. for (let i = 0; i < list.length; i++) {
  991. if (list[i].label) {
  992. headLabel.push({ label: list[i].label, prop: list[i].prop || '' });
  993. if (list[i].prop) {
  994. havePropArr.push({ prop: list[i].prop });
  995. if (list[i].options) {
  996. haveOptions.push({ prop: list[i].prop, options: list[i].options });
  997. }
  998. }
  999. if (list[i].children && Array.isArray(list[i].children)) {
  1000. getHeadLabel(list[i].children); // 递归子表头数据
  1001. }
  1002. }
  1003. }
  1004. }
  1005. getHeadLabel(tableColumns);
  1006. /** 输出计算的结果 */
  1007. // log('所有label:', JSON.stringify(headLabel));
  1008. // log('所有有prop属性的label:', JSON.stringify(havePropArr));
  1009. /** ----------------------------------> 3.设置表头每个表头单元格的行列起始信息 <------------------------------------------ */
  1010. let mergeCellDataList = []; // 存放表头每个单元格的行列起始信息
  1011. function genCellPlace() {
  1012. return {
  1013. // 定义单元格的起止行列
  1014. s: {
  1015. // s为开始
  1016. c: 0, // 开始列
  1017. r: 0, // 开始行
  1018. },
  1019. e: {
  1020. // e结束
  1021. c: 0, // 结束列
  1022. r: 0, // 结束行
  1023. },
  1024. };
  1025. }
  1026. /**
  1027. * 设置表头每个表头单元格的行列起始信息
  1028. * @param {Array} list 表头列组成的数据
  1029. * @param {Number} subLength 当前表头有几个子表头(不含子表头的子表头的标志)
  1030. */
  1031. function getMerges(list) {
  1032. if (!list || !Array.isArray(list)) {
  1033. return new Error('参数类型必须是数组');
  1034. }
  1035. let lastEc = 0;
  1036. for (let i = 0; i < list.length; i++) {
  1037. let element = list[i];
  1038. let cellPlace = genCellPlace();
  1039. let children = element.children;
  1040. if (children && Array.isArray(children) && children.length > 0) {
  1041. // 存在子节点
  1042. if (i == 0) {
  1043. // 第一列就是多表头的处理
  1044. cellPlace.s.c = lastEc > i ? lastEc : i;
  1045. } else {
  1046. cellPlace.s.c = lastEc + 1;
  1047. }
  1048. cellPlace.s.r = element.rowspan;
  1049. cellPlace.e.c = cellPlace.s.c + element.colspan;
  1050. cellPlace.e.r = element.rowspan;
  1051. lastEc = cellPlace.e.c;
  1052. mergeCellDataList.push(cellPlace);
  1053. getChildMerges(children, cellPlace.s.c);
  1054. } else {
  1055. // 没有子节点的一级表头
  1056. lastEc = lastEc > i ? lastEc : i;
  1057. cellPlace.s.c = getCellPlaceSC(element.prop);
  1058. cellPlace.s.r = element.colspan;
  1059. cellPlace.e.c = cellPlace.s.c;
  1060. cellPlace.e.r = element.rowspan;
  1061. lastEc = cellPlace.e.c;
  1062. mergeCellDataList.push(cellPlace);
  1063. }
  1064. }
  1065. }
  1066. function getChildMerges(list, lastColIndex) {
  1067. let listRowCount = getMaxFloor(list); // 获取当前list的占用单元格的行数和列数
  1068. let rowIndex = cellData.rowCount - listRowCount;
  1069. let lastEc = lastColIndex;
  1070. for (let i = 0; i < list.length; i++) {
  1071. let element = list[i];
  1072. let cellPlace = genCellPlace();
  1073. let children = element.children;
  1074. if (children && Array.isArray(children) && children.length > 0) {
  1075. // 存在子节点
  1076. if (i < 1) {
  1077. cellPlace.s.c = lastEc > lastColIndex ? lastEc + 1 : lastEc;
  1078. } else {
  1079. cellPlace.s.c = lastEc + 1;
  1080. }
  1081. cellPlace.s.r = rowIndex;
  1082. cellPlace.e.c = cellPlace.s.c + element.colspan;
  1083. cellPlace.e.r = rowIndex;
  1084. lastEc = cellPlace.e.c;
  1085. mergeCellDataList.push(cellPlace);
  1086. getChildMerges(children, cellPlace.s.c);
  1087. } else {
  1088. if (element.prop) {
  1089. cellPlace.s.c = getCellPlaceSC(element.prop);
  1090. } else {
  1091. cellPlace.s.c = lastEc > lastColIndex ? lastEc + 1 : lastEc;
  1092. }
  1093. cellPlace.s.r = rowIndex;
  1094. cellPlace.e.c = cellPlace.s.c;
  1095. cellPlace.e.r = rowIndex + element.rowspan;
  1096. lastEc = cellPlace.e.c;
  1097. mergeCellDataList.push(cellPlace);
  1098. }
  1099. }
  1100. }
  1101. function getCellPlaceSC(prop) {
  1102. if (prop) {
  1103. let index = 0;
  1104. for (let i = 0; i < havePropArr.length; i++) {
  1105. let element = havePropArr[i];
  1106. if (element.prop === prop) {
  1107. index = i;
  1108. break;
  1109. }
  1110. }
  1111. } else {
  1112. return 0;
  1113. }
  1114. return index;
  1115. }
  1116. getMerges(tableColumns);
  1117. // log('每个表头单元格的行列起始信息:', JSON.stringify(mergeCellDataList));
  1118. /** ----------------------------------> 4.表头单元格对应到excel中的位置排列(包括列数超出26处理),比如A1 B1...AA1 AB1 AC1 <------------------------------------- */
  1119. let l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  1120. let letter = l.split('');
  1121. // 表头数量超过26个
  1122. if (cellData.colCount > l.length) {
  1123. for (let len = cellData.colCount - l.length, ln = parseInt(len / l.length), k = 0; k <= ln; k++) {
  1124. for (let i = 0; i < Math.min(len, l.length); ) {
  1125. letter.push(letter[k] + '' + letter[i++]);
  1126. }
  1127. }
  1128. }
  1129. /** ----------------------------------> 5.设置所有表头单元格对应excel的单元格位置信息 <------------------------------------- */
  1130. // 表头单元格对应excel的位置 ,比如 A1 B1 C1 ...
  1131. let headSheel = [];
  1132. /**
  1133. * 设置所有表头单元格对应excel的单元格位置信息
  1134. * @param {Array} list 表头每个单元格的行列起始信息组成的数据
  1135. */
  1136. function getHeadcellPosition(list) {
  1137. if (!list || !Array.isArray(list)) {
  1138. return new Error('参数类型必须是数组');
  1139. }
  1140. for (let i = 0; i < list.length; i++) {
  1141. let obj = list[i];
  1142. headSheel.push(letter[obj.s.c] + (obj.s.r + 1)); // 根据单元格的起始行和起始列来对应excel的位置
  1143. }
  1144. }
  1145. getHeadcellPosition(mergeCellDataList);
  1146. // log('表头单元格对应excel的位置:', JSON.stringify(headSheel));
  1147. /** ----------------------------------> 6.获取要导出的数据 <------------------------------------- */
  1148. let data = [];
  1149. let tableData = [];
  1150. // 导出方式
  1151. if (options.importType == 'page') {
  1152. // updated by taoting1 on 20200211
  1153. // 解决导出无法取得表格数据的情况
  1154. tableData = tableRef.tabledata;
  1155. } else if (options.importType == 'selected') {
  1156. tableData = tableRef.selections;
  1157. } else if (options.importType == 'service') {
  1158. request({
  1159. url: options.url,
  1160. async: false,
  1161. data: options.param,
  1162. method: options.method ? options.method : 'GET',
  1163. }).then((code, message, response) => {
  1164. // 处理请求成功的情况
  1165. if (options.jsonData) {
  1166. let tmp = options.jsonData.split('.');
  1167. let obj = response;
  1168. for (let z = 0; z < tmp.length; z++) {
  1169. if (!obj) {
  1170. break;
  1171. }
  1172. obj = obj[tmp[z]];
  1173. }
  1174. tableData = obj;
  1175. } else {
  1176. tableData = response.data;
  1177. }
  1178. });
  1179. }
  1180. /** ----------------------------------> 7.列字段中对数据字典的翻译 <------------------------------------- */
  1181. /**
  1182. * 获取实际对应数据的列字段名称
  1183. * @param {String} name 某一列的label属性对应的中文名
  1184. * @return {String} 某一列的label属性对应的prop英文字段
  1185. */
  1186. // 存放表头最底层实际对应数据的列字段prop 比如['id','title','username'...]
  1187. let headList_ = [];
  1188. // 循环获取表头最底层实际对应数据的列字段prop存储于headList数组
  1189. for (let j = 0; j < havePropArr.length; j++) {
  1190. let key = havePropArr[j].prop;
  1191. headList_[headList_.length] = key;
  1192. }
  1193. /**
  1194. * 获取列的数据字典
  1195. * @param {String} column 某一列的label属性对应的中文名
  1196. * @param {Array} tableColumns 表头列数组
  1197. * @return {String} 数据字典dataCode
  1198. */
  1199. let getColumnsDataCode = function (column, tableColumns) {
  1200. let code;
  1201. for (let i = 0; i < tableColumns.length; i++) {
  1202. if (tableColumns[i].children && tableColumns[i].children instanceof Array == true) {
  1203. code = getColumnsDataCode(column, tableColumns[i].children);
  1204. if (code != undefined && code != null) {
  1205. break;
  1206. }
  1207. } else {
  1208. if (column == tableColumns[i].prop) {
  1209. code = tableColumns[i].dataCode || '';
  1210. break;
  1211. }
  1212. }
  1213. }
  1214. return code;
  1215. };
  1216. // 翻译数据字典字段
  1217. for (let i = 0; i < tableData.length; i++) {
  1218. let o = {};
  1219. let rowData = tableData[i];
  1220. for (let j = 0; j < headList_.length; j++) {
  1221. let k = headList_[j];
  1222. let code = getColumnsDataCode(k, tableColumns);
  1223. if (code) {
  1224. let val = lookup.convertKey(code, rowData[k]);
  1225. o['' + k + ''] = val; // 如果配置了字典项则为翻译后的值
  1226. } else {
  1227. o['' + k + ''] = rowData[k]; // 没配置字典项为原始值
  1228. }
  1229. }
  1230. for (let index = 0; index < haveOptions.length; index++) {
  1231. let element = haveOptions[index];
  1232. let value = getValByKey(rowData[element.prop], element.options);
  1233. o[element.prop] = value;
  1234. }
  1235. data.push(o);
  1236. }
  1237. function getValByKey(key, options) {
  1238. if (!key) {
  1239. return;
  1240. }
  1241. if (!options || !Array.isArray(options)) {
  1242. return key;
  1243. }
  1244. let val;
  1245. for (let i = 0; i < options.length; i++) {
  1246. let element = options[i];
  1247. if (element.key === key) {
  1248. val = element.value;
  1249. break;
  1250. }
  1251. }
  1252. return val;
  1253. }
  1254. // TODO 有待了解插入空对象原因,但是如果删掉会导致导出数据的前两条丢失
  1255. for (let i = 1; i < collectionHtml.length; i++) {
  1256. data.unshift({});
  1257. }
  1258. /** ----------------------------------> 8.导出相关数据构造 <------------------------------------- */
  1259. let saveAs = function (obj, fileName) {
  1260. // 当然可以自定义简单的下载文件实现方式
  1261. let tmpa = document.createElement('a');
  1262. tmpa.download = fileName || '下载';
  1263. tmpa.href = URL.createObjectURL(obj); // 绑定a标签
  1264. tmpa.click(); // 模拟点击实现下载
  1265. setTimeout(function () {
  1266. // 延时释放
  1267. URL.revokeObjectURL(obj); // 用URL.revokeObjectURL()来释放这个object URL
  1268. }, 100);
  1269. };
  1270. // 字符串转字符流
  1271. let s2ab = function (s) {
  1272. if (typeof ArrayBuffer !== 'undefined') {
  1273. let buf = new ArrayBuffer(s.length);
  1274. let view = new Uint8Array(buf);
  1275. for (let i = 0; i < s.length; ++i) {
  1276. view[i] = s.charCodeAt(i) & 0xff;
  1277. }
  1278. return buf;
  1279. } else {
  1280. let buf = new Array(s.length);
  1281. for (let i = 0; i < s.length; ++i) {
  1282. buf[i] = s.charCodeAt(i) & 0xff;
  1283. }
  1284. return buf;
  1285. }
  1286. };
  1287. let wb = { SheetNames: ['Sheet1'], Sheets: {}, Props: {} };
  1288. data = XLSX.utils.json_to_sheet(data);
  1289. for (let i = 0; i < headSheel.length; i++) {
  1290. data[headSheel[i]] = { t: 's', v: headLabel[i].label };
  1291. }
  1292. // 如果单元格是数字,将数字转换成字符串,防止导出后成为科学计数显示格式
  1293. if (options.stringifyNum) {
  1294. Object.keys(data).forEach((item) => {
  1295. const cell = data[item];
  1296. if (cell.t === 'n') {
  1297. cell.t = 's';
  1298. cell.v = cell.v.toString();
  1299. }
  1300. });
  1301. }
  1302. data['!merges'] = mergeCellDataList;
  1303. wb.Sheets['Sheet1'] = data;
  1304. let wopts = { bookType: 'xlsx', bookSST: true, type: 'binary' }; // 这里的数据是用来定义导出的格式类型
  1305. let blob = new window.Blob([s2ab(XLSX.write(wb, wopts))], { type: 'application/octet-stream' });
  1306. let filename = options.fileName + '.' + (wopts.bookType == 'biff2' ? 'xls' : wopts.bookType);
  1307. let browser = getBrowserType();
  1308. if (browser == 'IE') {
  1309. window.navigator.msSaveBlob(blob, filename);
  1310. } else {
  1311. saveAs(blob, filename);
  1312. }
  1313. // 导出后置空
  1314. tableRef = colums = tableColumns = collectionHtml = getColumnsDataCode = saveAs = s2ab = options = null;
  1315. }
  1316. /**
  1317. * @description 获取机构名称
  1318. */
  1319. export function getOrgName() {}
  1320. /**
  1321. * @description 获取用户名称
  1322. */
  1323. export function getUserName() {}
  1324. /**
  1325. * @description 根据菜单 funcUrl 获取菜单数据
  1326. * @param funcUrl 菜单funcUrl
  1327. */
  1328. export function getMenuNode(funcUrl) {
  1329. const menuList = storage.get(MENU_STOREOG_KEY) || [];
  1330. return menuList.find((item) => {
  1331. return `/${item.funcUrl}` === funcUrl;
  1332. });
  1333. }
  1334. /**
  1335. * @description 判断当前用户是否管理员,从缓存中获取当前用户所有角色,然后与固定值判断是否项匹配
  1336. */
  1337. export function isAdmin() {
  1338. const userInfo = sessionStore.get(USER_STORE_KEY) || {}; // 获取用户缓存信息
  1339. const { additionals = {}, userCode = '' } = userInfo;
  1340. const { authOrgRoles = [] } = additionals;
  1341. if (ADMIN_ROLECODES.includes(userCode)) {
  1342. return true;
  1343. }
  1344. if (authOrgRoles.length > 0) {
  1345. for (let i = 0, l = authOrgRoles.length; i < l; i++) {
  1346. if (ADMIN_ROLECODES.includes(authOrgRoles[i].roleCode)) {
  1347. return true;
  1348. }
  1349. }
  1350. }
  1351. return false;
  1352. }
  1353. /**
  1354. * 取消刷新动画帧函数
  1355. * @param {*} id
  1356. */
  1357. export function cancelAnimationFrame(id) {
  1358. const cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
  1359. cancelAnimationFrame.call(window, id);
  1360. }
  1361. let prev = Date.now();
  1362. /**
  1363. * 延迟器,优先使用系统自带API,根据不同系统刷新动画帧
  1364. */
  1365. export function requestAnimationFrame(fn) {
  1366. const requestAnimationFrame =
  1367. window.requestAnimationFrame ||
  1368. function (fn) {
  1369. const curr = Date.now();
  1370. const ms = Math.max(0, 16 - (curr - prev));
  1371. const id = setTimeout(fn, ms);
  1372. prev = curr + ms;
  1373. return id;
  1374. };
  1375. return requestAnimationFrame.call(window, fn);
  1376. }
  1377. /**
  1378. * 对手机号码进行脱敏处理
  1379. * @param {*} mobileNo 手机号码
  1380. */
  1381. export function mobileNoHide(mobileNo) {
  1382. if (mobileNo != null && typeof mobileNo !== 'string') {
  1383. mobileNo = mobileNo.toString();
  1384. }
  1385. if (!mobileNo) {
  1386. return '';
  1387. } else {
  1388. let temp;
  1389. let hideNumber = mobileNo.substring(3, mobileNo.length - 4);
  1390. let star = '';
  1391. for (let i = 0; i < hideNumber.length; i++) {
  1392. star += '*';
  1393. }
  1394. if (mobileNo.length === 11) {
  1395. temp = mobileNo.replace(hideNumber, star);
  1396. } else {
  1397. temp = mobileNo;
  1398. }
  1399. }
  1400. return temp;
  1401. }
  1402. /**
  1403. * @description 判断文件是否图片
  1404. * @param {String} param 文件后缀
  1405. * @returns 判断结果
  1406. */
  1407. export function isPicture(ext = '') {
  1408. return ['bmp', 'gif', 'svg', 'jpeg', 'png', 'jpg'].indexOf(ext.split('.').reverse()[0]) > -1;
  1409. }
  1410. /**
  1411. * @description 判断文件是否视频
  1412. * @param {String} str 文件类型
  1413. * @returns 判断结果
  1414. */
  1415. export function isVideo(ext = '') {
  1416. return ['mp4', 'avi', 'rmvb', 'mov', '3gp', 'flv'].indexOf(ext.split('.').reverse()[0]) > -1;
  1417. }
  1418. /**
  1419. * 检查字符串是否包含中文
  1420. * @param {*} value 检查值
  1421. * @returns {Boolean}
  1422. */
  1423. export function strIsChn(value) {
  1424. const reg = /[\u4E00-\u9FA5]/;
  1425. return reg.test(value);
  1426. }
  1427. /**
  1428. * 判断文字是否超过dom宽度 el:DOM元素
  1429. */
  1430. export function textRange(el) {
  1431. const textContent = el;
  1432. const targetW = textContent.getBoundingClientRect().width;
  1433. const range = document.createRange();
  1434. range.setStart(textContent, 0);
  1435. range.setEnd(textContent, textContent.childNodes.length);
  1436. const rangeWidth = range.getBoundingClientRect().width;
  1437. return rangeWidth > targetW;
  1438. }
  1439. /**
  1440. * 根据key值将引入的数组进行去重
  1441. * @param {*} key
  1442. * @param {*} selArr 要引入的数据
  1443. * @param {*} oriArr 原数据
  1444. */
  1445. export function arrayUnrepeat(key, selArr, oriArr) {
  1446. let arr = [];
  1447. const keyArr = oriArr.map((item) => item[key]);
  1448. for (let i = 0; i < selArr.length; i++) {
  1449. if (keyArr.indexOf(selArr[i][key]) === -1) {
  1450. arr.push(selArr[i]);
  1451. }
  1452. }
  1453. return arr;
  1454. }
  1455. /**
  1456. * 根据key值将引入的数组进行去重
  1457. * @param {*} orgLevel 要判断的机构级别
  1458. * 总行及下属部门: 1 分行及下属部门: 2 二级分行及下属部门:3 支行: 4 二级支行:5
  1459. */
  1460. export function getLevelByOrgLevel(orgLevel) {
  1461. let level = '';
  1462. if (orgLevel === '1') {
  1463. level = '1'; // 总行
  1464. } else if (orgLevel === '2' || orgLevel === '3') {
  1465. level = '2'; // 分行
  1466. } else if (orgLevel === '4' || orgLevel === '5') {
  1467. level = '3'; // 支行
  1468. }
  1469. return level;
  1470. }
  1471. /**
  1472. * 数值向下取整
  1473. * @param {*} num
  1474. * @param {*} n
  1475. * @returns
  1476. */
  1477. export function numFloor(num, n) {
  1478. if (num.toString().indexOf('.') > 0) {
  1479. if (n) {
  1480. let reg = eval('/^\\d+(?:\\.\\d{0,' + n + '})?/');
  1481. num = Number(num.toString().match(reg)).toFixed(n); // 小数向下取小数n位
  1482. } else {
  1483. num = Number(num.toString().split('.')[0]); // 整数
  1484. }
  1485. }
  1486. return num;
  1487. }
  1488. /**
  1489. * 开始日期和结束日期比较
  1490. * date 选择日期
  1491. * compaDate 需要比较日期
  1492. * message 错误提示信息
  1493. * compMsg 比较日期提示信息
  1494. * type 比较类型
  1495. */
  1496. export function compaStrtToEndDate(date, message, compaDate, compMsg, type) {
  1497. let exdate = '';
  1498. let precompaDate = '';
  1499. if (typeof date == 'object') {
  1500. exdate = date.getTime();
  1501. } else {
  1502. exdate = new Date(date).getTime();
  1503. }
  1504. if (typeof compaDate == 'object') {
  1505. precompaDate = compaDate.getTime();
  1506. } else {
  1507. precompaDate = new Date(compaDate).getTime();
  1508. }
  1509. if (
  1510. (type == 'strt' && exdate <= precompaDate) ||
  1511. (type == 'end' && exdate >= precompaDate) ||
  1512. ((!compaDate || compaDate == '') && type == 'strt')
  1513. ) {
  1514. return true;
  1515. } else {
  1516. let tipsMsg = type == 'strt' ? '应该小于' : '应该大于';
  1517. showMessage(message + tipsMsg + compMsg, 'error');
  1518. return false;
  1519. }
  1520. }
  1521. /**
  1522. * 日期两者之间计算相差天数
  1523. * strtDate 选择日期
  1524. * endDate 需要比较日期
  1525. */
  1526. export function diffDays(strtDate, endDate) {
  1527. if (strtDate && endDate) {
  1528. let diff = new Date(endDate) - new Date(strtDate);
  1529. if (!diff) {
  1530. return '';
  1531. } else {
  1532. let days = Math.round(diff / 1000 / 3600 / 24) + 1;
  1533. return days;
  1534. }
  1535. } else {
  1536. return '';
  1537. }
  1538. }
  1539. /**
  1540. * 日期两者之间计算相差小时数
  1541. * strtDate 选择日期
  1542. * endDate 需要比较日期
  1543. */
  1544. export function diffHours(strtDate, endDate) {
  1545. if (strtDate && endDate) {
  1546. let diff = new Date(endDate) - new Date(strtDate);
  1547. if (!diff && diff != '0') {
  1548. return '0';
  1549. } else {
  1550. let days = Math.round(diff / 1000 / 3600);
  1551. return days;
  1552. }
  1553. } else {
  1554. return '';
  1555. }
  1556. }
  1557. /**
  1558. * 精准加法计算
  1559. * @param {*} arg1
  1560. * @param {*} arg2
  1561. * @returns
  1562. */
  1563. export function accAdd(arg1, arg2) {
  1564. let r1, r2, m;
  1565. try {
  1566. r1 = arg1.toString().split('.')[1].length;
  1567. } catch (e) {
  1568. r1 = 0;
  1569. }
  1570. try {
  1571. r2 = arg2.toString().split('.')[1].length;
  1572. } catch (e) {
  1573. r2 = 0;
  1574. }
  1575. m = Math.pow(10, Math.max(r1, r2));
  1576. return (accMul(arg1, m) + accMul(arg2, m)) / m;
  1577. }
  1578. /**
  1579. * 精准乘法法计算
  1580. * @param {*} arg1
  1581. * @param {*} arg2
  1582. * @returns
  1583. */
  1584. export function accMul(arg1, arg2) {
  1585. let m = 0,
  1586. s1 = arg1.toString(),
  1587. s2 = arg2.toString();
  1588. try {
  1589. m += s1.split('.')[1].length;
  1590. } catch (e) {}
  1591. try {
  1592. m += s2.split('.')[1].length;
  1593. } catch (e) {}
  1594. return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m);
  1595. }
  1596. /**
  1597. * 精准减法法计算
  1598. * @param {*} arg1
  1599. * @param {*} arg2
  1600. * @returns
  1601. */
  1602. export function accSub(arg1, arg2) {
  1603. let r1, r2, m, n;
  1604. try {
  1605. r1 = arg1.toString().split('.')[1].length;
  1606. } catch (e) {
  1607. r1 = 0;
  1608. }
  1609. try {
  1610. r2 = arg2.toString().split('.')[1].length;
  1611. } catch (e) {
  1612. r2 = 0;
  1613. }
  1614. m = Math.pow(10, Math.max(r1, r2));
  1615. // last modify by deeka
  1616. // 动态控制精度长度
  1617. n = r1 >= r2 ? r1 : r2;
  1618. return ((arg1 * m - arg2 * m) / m).toFixed(n);
  1619. }
  1620. /**
  1621. * 精准除法计算
  1622. * @param {*} arg1
  1623. * @param {*} arg2
  1624. * @returns
  1625. */
  1626. export function accDiv(arg1, arg2) {
  1627. let t1 = 0,
  1628. t2 = 0,
  1629. r1,
  1630. r2;
  1631. try {
  1632. t1 = arg1.toString().split('.')[1].length;
  1633. } catch (e) {}
  1634. try {
  1635. t2 = arg2.toString().split('.')[1].length;
  1636. } catch (e) {}
  1637. // with(Math) {
  1638. r1 = Number(arg1.toString().replace('.', ''));
  1639. r2 = Number(arg2.toString().replace('.', ''));
  1640. return (r1 / r2) * Math.pow(10, t2 - t1);
  1641. // }
  1642. }
  1643. // 跳转客户外部数据
  1644. export function toCustOutData(row) {
  1645. if (row.cstTyp === '1' && row.source != 1) {
  1646. // 对公
  1647. // TODO 跳转天探系统
  1648. showMessage('TODO 跳转天探系统', 'info');
  1649. } else if (row.cstTyp === '2' || (row.cstTyp === '1' && row.source == 1)) {
  1650. // 零售
  1651. let pathName = '/custOutData_' + new Date().getTime();
  1652. router.addRoute('dsamp-web/npam/dailyManage/custView/outData/index.vue', '客户外部数据信息', {}, pathName);
  1653. router.push({
  1654. path: pathName,
  1655. query: { cstId: row.cstId, custName: row.custName, cstTyp: row.cstTyp, relaCertCode: row.relaCertCode },
  1656. });
  1657. } else {
  1658. showMessage('该客户非对公、零售客户', 'warning');
  1659. }
  1660. }
  1661. // 跳转借据详情
  1662. export function toIouDetailFn(query) {
  1663. let path = 'dsamp-web/common/npam/iouInfo/index.vue';
  1664. let title = '借据信息';
  1665. let pathName = '/laonIouInfo_' + new Date().getTime();
  1666. router.addRoute(path, title, {}, pathName);
  1667. router.push({
  1668. path: pathName,
  1669. query: query,
  1670. needBackHistory: true,
  1671. });
  1672. }
  1673. /**
  1674. * 债权引入确定时校验
  1675. * 1. 线下贷款:只能引入同一个产品类别的借据。对公1 零售2
  1676. * 2. 线上贷款:只能引入同一个产品名称的借据 公司线上3 零售线上6
  1677. * 3. 线上贷款与线下贷款不能同时发起。
  1678. * @param {*} arr 待引入选中的数组
  1679. * @param {*} oriTableData 已经引入的列表数据(第一页或全部)
  1680. * @returns
  1681. */
  1682. export function validImportSameIou(arr, oriTableData) {
  1683. // 获取已选择的借据
  1684. let newArr = yufp.extend([], arr);
  1685. let selectedIou = oriTableData.length > 0 ? oriTableData[0] : null;
  1686. if (selectedIou) newArr.push(selectedIou);
  1687. let bsinPlatArr = []; // 业务板块
  1688. let prdTypArr = []; // 产品类别
  1689. let bsinTypeArr = []; // 产品名称
  1690. for (let i = 0; i < newArr.length; i++) {
  1691. if (bsinPlatArr.indexOf(newArr[i].bizSct) === -1) bsinPlatArr.push(newArr[i].bizSct);
  1692. if (prdTypArr.indexOf(newArr[i].prdTyp) === -1) prdTypArr.push(newArr[i].prdTyp);
  1693. if (bsinTypeArr.indexOf(newArr[i].bsinType) === -1) bsinTypeArr.push(newArr[i].bsinType);
  1694. }
  1695. let onlyInline = bsinPlatArr.indexOf('3') > -1 || bsinPlatArr.indexOf('6') > -1; // 线上贷款:公司线上3 零售线上6
  1696. let onlyOffline = bsinPlatArr.indexOf('1') > -1 || bsinPlatArr.indexOf('2') > -1; // 线下贷款:对公1 零售2
  1697. // 同时存在线上线下
  1698. if (onlyInline && onlyOffline) {
  1699. showMessage('线上贷款与线下贷款不能同时发起', 'warning');
  1700. return false;
  1701. }
  1702. // 仅线上
  1703. if (onlyInline && !onlyOffline && prdTypArr.length > 1) {
  1704. showMessage('线上贷款:只能引入同一个产品类别的借据', 'warning');
  1705. return false;
  1706. }
  1707. // 仅线下
  1708. if (!onlyInline && onlyOffline && bsinTypeArr.length > 1) {
  1709. showMessage('线下贷款:只能引入同一个产品名称的借据', 'warning');
  1710. return false;
  1711. }
  1712. return true;
  1713. }
  1714. // 跳转信用卡详情
  1715. export function toCardDetailFn(query) {
  1716. let path = 'dsamp-web/common/npam/cardInfo/index.vue';
  1717. let title = '信用卡信息';
  1718. let pathName = '/laonIouInfo_' + new Date().getTime();
  1719. router.addRoute(path, title, {}, pathName);
  1720. router.push({
  1721. path: pathName,
  1722. query: query,
  1723. });
  1724. }
  1725. /**
  1726. * @description 渲染水印方法
  1727. */
  1728. export function renderWatermark() {
  1729. if (frameConfig.watermark) {
  1730. !window.watermark && import('@/utils/yufp.watermark');
  1731. window.watermark && window.watermark.init();
  1732. }
  1733. }
  1734. /**
  1735. * @description 清除水印方法
  1736. */
  1737. export function clearWatermark() {
  1738. if (frameConfig.watermark) {
  1739. window.watermark && window.watermark.clearWatermark();
  1740. }
  1741. }
  1742. // 调用水印渲染
  1743. renderWatermark();