util.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. import Cookies from 'js-cookie'
  2. // cookie保存的天数
  3. import config from '@/config'
  4. import {forEach, hasOneOf, objEqual, hasAllOf} from '@/libs/tools/tools'
  5. import Vue from 'vue'
  6. const {title, cookieExpires, useI18n} = config
  7. export const TOKEN_KEY = 'token'
  8. export const setToken = (token) => {
  9. Cookies.set(TOKEN_KEY, token, {expires: cookieExpires || 1})
  10. }
  11. export const getToken = () => {
  12. const token = Cookies.get(TOKEN_KEY)
  13. if (token) return token
  14. else return false
  15. }
  16. export const hasChild = (item) => {
  17. return item.children && item.children.length !== 0
  18. }
  19. const showThisMenuEle = (item, access) => {
  20. if (item.meta && item.meta.access && item.meta.access.length) {
  21. if (hasAllOf(item.meta.access, access)) return true
  22. else return false
  23. } else return true
  24. }
  25. /**
  26. * @param {Array} list 通过路由列表得到菜单列表
  27. * @returns {Array}
  28. */
  29. export const getMenuByRouter = (list, access) => {
  30. let res = []
  31. list.forEach(item => {
  32. if (item.objectCode !== 'home') {
  33. let obj = {
  34. icon: (item.meta && item.meta.icon) || '',
  35. name: item.name,
  36. meta: item.meta
  37. }
  38. if (item.children && item.children.length > 0) {
  39. obj.children = item.children.copy();
  40. }
  41. if (!item.meta.hideInMenu) {
  42. res.push(obj);
  43. }
  44. }
  45. // if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
  46. // obj.children = getMenuByRouter(item.children, access)
  47. // }
  48. // if (item.meta && item.meta.href) obj.href = item.meta.href
  49. // if (showThisMenuEle(item, access)) res.push(obj)
  50. })
  51. console.log(res)
  52. return res
  53. }
  54. /**
  55. * @param {Array} routeMetched 当前路由metched
  56. * @returns {Array}
  57. */
  58. export const getBreadCrumbList = (route, homeRoute) => {
  59. let homeItem = {...homeRoute, icon: homeRoute.meta ? homeRoute.meta.icon : null}
  60. let routeMetched = route.matched
  61. if (routeMetched.some(item => item.name === homeRoute.name)) return [homeItem]
  62. let res = routeMetched.filter(item => {
  63. return item.meta === undefined || !item.hideInBread
  64. }).map(item => {
  65. let meta = {...item.meta}
  66. if (meta.title && typeof meta.title === 'function') {
  67. meta.__titleIsFunction__ = true
  68. meta.title = meta.title(route)
  69. }
  70. let obj = {
  71. icon: (item.meta && item.meta.icon) || '',
  72. name: item.name,
  73. meta: meta
  74. }
  75. return obj
  76. })
  77. // 隐藏在菜单的在面包屑中显示
  78. // res = res.filter(item => {
  79. // return !item.meta.hideInMenu
  80. // })
  81. return [{...homeItem, to: homeRoute.path}, ...res]
  82. }
  83. export const getRouteTitleHandled = (route) => {
  84. let router = {...route}
  85. let meta = {...route.meta}
  86. let title = ''
  87. if (meta.title) {
  88. if (typeof meta.title === 'function') {
  89. meta.__titleIsFunction__ = true
  90. title = meta.title(router)
  91. } else title = meta.title
  92. }
  93. router.title = title
  94. router.meta = meta
  95. return router
  96. }
  97. export const showTitle = (item, vm) => {
  98. let {title, __titleIsFunction__} = item.meta
  99. if (!title) return
  100. // TODO 暂时这么修改,正常情况下,是所有的都应该走语言包的
  101. // if (item.meta && (item.meta.hideInMenu || !title)) {
  102. // title = vm.$t(item.name)
  103. // }
  104. if (useI18n) {
  105. if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))
  106. else if (__titleIsFunction__) title = item.meta.title
  107. else title = vm.$t(item.name)
  108. } else title = (item.meta && item.meta.title) || item.name
  109. return title
  110. }
  111. /**
  112. * @description 本地存储和获取标签导航列表
  113. */
  114. export const setTagNavListInLocalstorage = list => {
  115. localStorage.tagNaveList = JSON.stringify(list)
  116. }
  117. /**
  118. * @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
  119. */
  120. export const getTagNavListFromLocalstorage = () => {
  121. const list = localStorage.tagNaveList
  122. return list ? JSON.parse(list) : []
  123. }
  124. /**
  125. * @param {Array} routers 路由列表数组
  126. * @description 用于找到路由列表中name为home的对象
  127. */
  128. export const getHomeRoute = (routers, homeName = 'home') => {
  129. let i = -1
  130. let len = routers.length
  131. let homeRoute = {}
  132. while (++i < len) {
  133. let item = routers[i]
  134. if (item.children && item.children.length) {
  135. let res = getHomeRoute(item.children, homeName)
  136. if (res.name) return res
  137. } else {
  138. if (item.name === homeName) homeRoute = item
  139. }
  140. }
  141. return homeRoute
  142. }
  143. /**
  144. * @param {*} list 现有标签导航列表
  145. * @param {*} newRoute 新添加的路由原信息对象
  146. * @description 如果该newRoute已经存在则不再添加
  147. * @H_X_D 如果当前路由中的参数不相同,则替换为新的参数
  148. */
  149. export const getNewTagList = (list, newRoute) => {
  150. const {name, path, meta, params} = newRoute
  151. let newList = [...list]
  152. let index = newList.findIndex(item => item.name === name)
  153. if (index >= 0) {
  154. if (list[index].params === params) return newList
  155. else list[index].params = params
  156. } else {
  157. newList.push({name, path, meta})
  158. }
  159. return newList
  160. }
  161. /**
  162. * @param {*} access 用户权限数组,如 ['super_admin', 'admin']
  163. * @param {*} route 路由列表
  164. */
  165. const hasAccess = (access, route) => {
  166. if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access)
  167. else return true
  168. }
  169. /**
  170. * 权鉴
  171. * @param {*} name 即将跳转的路由name
  172. * @param {*} access 用户权限数组
  173. * @param {*} routes 路由列表
  174. * @description 用户是否可跳转到该页
  175. */
  176. export const canTurnTo = (name, access, routes) => {
  177. const routePermissionJudge = (list) => {
  178. return list.some(item => {
  179. if (item.name !== name && item.children && item.children.length) {
  180. return routePermissionJudge(item.children)
  181. } else if (item.name === name) {
  182. return hasAccess(access, item)
  183. }
  184. // if(item.name === name){
  185. // return hasAccess(access, item)
  186. // }else if (item.children && item.children.length) {
  187. // return routePermissionJudge(item.children)
  188. // }
  189. })
  190. }
  191. return routePermissionJudge(routes)
  192. }
  193. /**
  194. * @param {String} url
  195. * @description 从URL中解析参数
  196. */
  197. export const getParams = url => {
  198. const keyValueArr = url.split('?')[1].split('&')
  199. let paramObj = {}
  200. keyValueArr.forEach(item => {
  201. const keyValue = item.split('=')
  202. paramObj[keyValue[0]] = keyValue[1]
  203. })
  204. return paramObj
  205. }
  206. /**
  207. * @desc : 跳转到前一个Tab
  208. * @author : 周兴
  209. * @date : 2022/5/23 9:22
  210. */
  211. export const getPreviousRoute = (list, route) => {
  212. let res = {}
  213. const index = list.findIndex(item => routeEqual(item, route))
  214. if (index >= 1) {
  215. res = list[index - 1]
  216. }
  217. return res
  218. }
  219. /**
  220. * @param {Array} list 标签列表
  221. * @param {String} name 当前关闭的标签的name
  222. * @H_x_d 关闭标签后,打开前一页
  223. */
  224. export const getNextRoute = (list, route) => {
  225. let res = {}
  226. // 如果有parentPath,需要跳转到对应的页面
  227. // console.log('res',list,route)
  228. if (route.meta && route.meta.parentPath) {
  229. let newRoute = {}
  230. newRoute.name = route.meta.parentPath;
  231. const index = list.findIndex(item => routeEqual(item, newRoute))
  232. if (index >= 0) {
  233. res = list[index];
  234. return res;
  235. } else {
  236. //跳转到首页
  237. let homePage = {}
  238. homePage.name = 'home'
  239. return homePage
  240. }
  241. }
  242. const index = list.findIndex(item => routeEqual(item, route))
  243. // 如果是最后一个页面,打开前一个
  244. if (index === list.length - 1) {
  245. if (list[list.length - 2]) {
  246. res = list[list.length - 2]
  247. }
  248. } else {
  249. // 如果不是最后一个页面,打开后面一个
  250. if (list[index + 1]) {
  251. res = list[index + 1]
  252. }
  253. }
  254. return res
  255. }
  256. /**
  257. * @param {Number} times 回调函数需要执行的次数
  258. * @param {Function} callback 回调函数
  259. */
  260. export const doCustomTimes = (times, callback) => {
  261. let i = -1
  262. while (++i < times) {
  263. callback(i)
  264. }
  265. }
  266. /**
  267. * @param {Object} file 从上传组件得到的文件对象
  268. * @returns {Promise} resolve参数是解析后的二维数组
  269. * @description 从Csv文件中解析出表格,解析成二维数组
  270. */
  271. export const getArrayFromFile = (file) => {
  272. let nameSplit = file.name.split('.')
  273. let format = nameSplit[nameSplit.length - 1]
  274. return new Promise((resolve, reject) => {
  275. let reader = new FileReader()
  276. reader.readAsText(file) // 以文本格式读取
  277. let arr = []
  278. reader.onload = function (evt) {
  279. let data = evt.target.result // 读到的数据
  280. let pasteData = data.trim()
  281. arr = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => {
  282. return row.split('\t')
  283. }).map(item => {
  284. return item[0].split(',')
  285. })
  286. if (format === 'csv') resolve(arr)
  287. else reject(new Error('[Format Error]:你上传的不是Csv文件'))
  288. }
  289. })
  290. }
  291. /**
  292. * @param {Array} array 表格数据二维数组
  293. * @returns {Object} { columns, tableData }
  294. * @description 从二维数组中获取表头和表格数据,将第一行作为表头,用于在iView的表格中展示数据
  295. */
  296. export const getTableDataFromArray = (array) => {
  297. let columns = []
  298. let tableData = []
  299. if (array.length > 1) {
  300. let titles = array.shift()
  301. columns = titles.map(item => {
  302. return {
  303. title: item,
  304. key: item
  305. }
  306. })
  307. tableData = array.map(item => {
  308. let res = {}
  309. item.forEach((col, i) => {
  310. res[titles[i]] = col
  311. })
  312. return res
  313. })
  314. }
  315. return {
  316. columns,
  317. tableData
  318. }
  319. }
  320. export const findNodeUpper = (ele, tag) => {
  321. if (ele.parentNode) {
  322. if (ele.parentNode.tagName === tag.toUpperCase()) {
  323. return ele.parentNode
  324. } else {
  325. return findNodeUpper(ele.parentNode, tag)
  326. }
  327. }
  328. }
  329. export const findNodeUpperByClasses = (ele, classes) => {
  330. let parentNode = ele.parentNode
  331. if (parentNode) {
  332. let classList = parentNode.classList
  333. if (classList && classes.every(className => classList.contains(className))) {
  334. return parentNode
  335. } else {
  336. return findNodeUpperByClasses(parentNode, classes)
  337. }
  338. }
  339. }
  340. export const findNodeDownward = (ele, tag) => {
  341. const tagName = tag.toUpperCase()
  342. if (ele.childNodes.length) {
  343. let i = -1
  344. let len = ele.childNodes.length
  345. while (++i < len) {
  346. let child = ele.childNodes[i]
  347. if (child.tagName === tagName) return child
  348. else return findNodeDownward(child, tag)
  349. }
  350. }
  351. }
  352. export const showByAccess = (access, canViewAccess) => {
  353. return hasAllOf(canViewAccess, access)
  354. }
  355. /**
  356. * @description 根据name/params/query判断两个路由对象是否相等
  357. * @param {*} route1 路由对象
  358. * @param {*} route2 路由对象
  359. */
  360. export const routeEqual = (route1, route2) => {
  361. // const params1 = route1.params || {}
  362. // const params2 = route2.params || {}
  363. // const query1 = route1.query || {}
  364. // const query2 = route2.query || {}
  365. // return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2)
  366. return route1.name === route2.name // 只判断name(新建编辑不多)
  367. }
  368. /**
  369. * 判断打开的标签列表里是否已存在这个新添加的路由对象
  370. */
  371. export const routeHasExist = (tagNavList, routeItem) => {
  372. let len = tagNavList.length
  373. let res = false
  374. doCustomTimes(len, (index) => {
  375. // if (routeEqual(tagNavList[index], routeItem)) {
  376. // res = true
  377. // }
  378. // 如果名称相同 但是菜单Id不同打开多个
  379. if(tagNavList[index].name === routeItem.name){
  380. if(tagNavList[index].meta && routeItem.meta
  381. && tagNavList[index].meta.menuUuid === routeItem.meta.menuUuid){
  382. res = true;
  383. }
  384. }
  385. })
  386. return res
  387. }
  388. /**
  389. * @desc : 保存本地缓存(Session中)
  390. * @author : 周兴
  391. * @date : 2022/12/21 14:34
  392. */
  393. export const sessionSave = (key, value) => {
  394. sessionStorage.setItem(key, value)
  395. }
  396. /**
  397. * @desc : 保存到本地缓存(Session中)
  398. * @author : 周兴
  399. * @date : 2022/12/21 14:35
  400. */
  401. export const sessionRead = (key) => {
  402. return sessionStorage.getItem(key) || ''
  403. }
  404. /**
  405. * @desc : 保存本地缓存(Local中)
  406. * @author : 周兴
  407. * @date : 2022/12/21 14:34
  408. */
  409. export const localSave = (key, value) => {
  410. //处理语言
  411. if (key === 'local') {
  412. localStorage.setItem(key, value)
  413. localStorage.setItem(key + '_lan', value.replace('-', '_'))
  414. } else {
  415. localStorage.setItem(key, value)
  416. }
  417. }
  418. /**
  419. * @desc : 保存到本地缓存(Local中)
  420. * @author : 周兴
  421. * @date : 2022/12/21 14:35
  422. */
  423. export const localRead = (key) => {
  424. return localStorage.getItem(key) || ''
  425. }
  426. /**
  427. * @desc : 保存到本地缓存(Local中)
  428. * @author : 周兴
  429. * @date : 2022/12/21 14:35
  430. */
  431. export const localRemove = (key) => {
  432. return localStorage.removeItem(key)
  433. }
  434. // scrollTop animation
  435. export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
  436. if (!window.requestAnimationFrame) {
  437. window.requestAnimationFrame = (
  438. window.webkitRequestAnimationFrame ||
  439. window.mozRequestAnimationFrame ||
  440. window.msRequestAnimationFrame ||
  441. function (callback) {
  442. return window.setTimeout(callback, 1000 / 60)
  443. }
  444. )
  445. }
  446. const difference = Math.abs(from - to)
  447. const step = Math.ceil(difference / duration * 50)
  448. const scroll = (start, end, step) => {
  449. if (start === end) {
  450. endCallback && endCallback()
  451. return
  452. }
  453. let d = (start + step > end) ? end : start + step
  454. if (start > end) {
  455. d = (start - step < end) ? end : start - step
  456. }
  457. if (el === window) {
  458. window.scrollTo(d, d)
  459. } else {
  460. el.scrollTop = d
  461. }
  462. window.requestAnimationFrame(() => scroll(d, end, step))
  463. }
  464. scroll(from, to, step)
  465. }
  466. /**
  467. * @description 根据当前跳转的路由设置显示在浏览器标签的title
  468. * @param {Object} routeItem 路由对象
  469. * @param {Object} vm Vue实例
  470. */
  471. export const setTitle = (routeItem, vm) => {
  472. const handledRoute = getRouteTitleHandled(routeItem)
  473. const pageTitle = showTitle(handledRoute, vm)
  474. const NO_AUTH_NAME = ['report_iboss', 'report_day-account', 'report_order-sale', 'report_every-profit', 'report_customer-balance']
  475. if (NO_AUTH_NAME.some(item => {
  476. return item === routeItem.name
  477. })) {
  478. window.document.title = routeItem.meta.title
  479. } else {
  480. const resTitle = pageTitle ? `${title} - ${pageTitle}` : title
  481. window.document.title = resTitle
  482. }
  483. }