import http from './http' // 组件映射表(将后端返回的路径映射到实际组件) const componentMap = {} export default class uiTool { /** * 设置组件映射表 * @param {Object} map - 组件映射对象 */ static setComponentMap(map) { Object.assign(componentMap, map) } /** * 根据路径获取组件 * @param {String} componentPath - 组件路径(如 "system/sys_user.vue") * @returns {Component} 组件或 null */ static getComponent(componentPath) { if (!componentPath) return null // 标准化路径(移除 .vue 后缀) const normalizedPath = componentPath.replace(/\.vue$/, '') // 从映射表中查找 return componentMap[normalizedPath] || componentMap[componentPath] } /** * 文件下载工具 * @param {Object|Blob} res - 响应数据或Blob对象 * @param {String} fileName - 文件名(可选,默认为时间戳.csv) */ static downloadFile(res, fileName) { // 开头和结尾去掉 中间不去掉 let tempFileName = fileName || `${new Date().getTime()}.csv` const blob = new Blob([res.data || res]) const downloadElement = document.createElement('a') const href = window.URL.createObjectURL(blob) downloadElement.href = href downloadElement.download = tempFileName document.body.appendChild(downloadElement) downloadElement.click() document.body.removeChild(downloadElement) window.URL.revokeObjectURL(href) } static setRem() { let whdef = 100 / 1920 let bodyWidth = document.body.clientWidth if (bodyWidth < 1360) { bodyWidth = 1360 } let rem = bodyWidth * whdef document.documentElement.style.fontSize = rem + 'px' console.log('自适应html字体大小', parseInt(rem)) console.log('自适应缩放比列', (rem / 100).toFixed(3)) window.$whdef = rem } static getImgSrc(src) { if (src) { return http.baseUrl() + src } else { return '/assets/img/noImg.png' } } static getBtn(h, options) { let rets = [] if (!options) { options = [options] } options.forEach(item => { rets.push( h( 'Button', { props: { type: 'text', ghost: true, loading: item.loading }, style: { margin: '2px', color: '#2d8cf0' }, on: { click: () => { item.click && item.click() } } }, item.title ) ) }) return h('div', { style: { margin: '5px' } }, rets) } static getDropdown(h, items) { let btns = [] if (items && items.length > 0) { items.forEach(item => { btns.push( h( 'DropdownItem', { on: { click: () => { item.click && item.click() } } }, item.title ) ) }) } return h('Dropdown', {}, [ h('a', {}, ['更多', h('Icon', { props: { type: 'ios-arrow-down' } })]), h('DropdownMenu', { slot: 'list' }, btns) ]) } static delConfirm(callback) { const Modal = (window.framework && window.framework.ViewUI && window.framework.ViewUI.Modal) || window.$Modal if (Modal) { Modal.confirm({ title: '温馨提示', content: '
你确定删除吗?
', onOk: () => { callback && callback() } }) } } static showConfirm({ title = '温馨提示', content = '内容' }, callback) { const Modal = (window.framework && window.framework.ViewUI && window.framework.ViewUI.Modal) || window.$Modal if (Modal) { Modal.confirm({ title, content, onOk: () => { callback && callback() } }) } } static subTree(curTree, tree, callback) { if (curTree && curTree.length > 0) { curTree.forEach(p => { let childrenTree = tree.filter(p2 => p.id === p2.parent_id) if (childrenTree) { let subTree = uiTool.subTree(childrenTree, tree, callback) p.children = subTree || [] } }) if (callback) { return curTree.map(p => { return callback(p) }) } return curTree } return [] } static transformTree(tree, callback) { let rootTree = tree.filter(p => p.parent_id === 0) let curTrees = uiTool.subTree(rootTree, tree, callback) return curTrees } static menuToRoute(menus, ParentView, Page404) { if (menus && menus.length > 0) { menus.forEach(item => { if (item.type === '菜单') { item.component = ParentView } else if (item.type === '页面' || item.type === '功能') { try { let componentPath = item.component // 从组件映射表中获取组件 let component = uiTool.getComponent(componentPath) if (component) { // 找到了对应的组件 item.component = component } else { // 未找到组件,使用占位组件并记录路径 console.warn(`组件未找到: ${componentPath},使用占位组件`) item.component = { render: h => h('div', { style: { padding: '20px' } }, [ h('Alert', { props: { type: 'warning' } }, [ h('p', `页面组件未加载: ${componentPath}`), h('p', '请在项目中创建此组件或在组件映射表中注册') ]) ]) } item.componentPath = componentPath } } catch (e) { console.error('组件加载失败:', e) item.component = Page404 } } else { item.component = ParentView } item.meta = { icon: item.icon, isMenu: item.is_show_menu, type: item.type, title: item.name } if (item.children && item.children.length > 0) { item.children = uiTool.menuToRoute(item.children, ParentView, Page404) } }) return menus } return [] } static getRoutes(Main, ParentView, Page404, HomePage) { // 如果没有传入 HomePage,使用默认的欢迎页面 const defaultHomePage = { render: h => h('div', { style: { padding: '20px', display: 'flex', justifyContent: 'center', alignItems: 'center', height: 'calc(100vh - 200px)' } }, [ h('div', { style: { textAlign: 'center' } }, [ h('h1', { style: { fontSize: '30px', color: '#2d8cf0', marginBottom: '20px' } }, '欢迎使用管理系统'), h('p', { style: { fontSize: '16px', color: '#666' } }, '请从左侧菜单选择功能模块') ]) ]) } let mainRoute = { path: '/', name: '主视图', redirect: '/home', component: Main, meta: { title: '首页', notCache: true }, children: [ { path: '/home', name: '首页', component: HomePage || defaultHomePage, meta: { title: '首页', notCache: true } } ] } // 从 localStorage 读取权限菜单 if ( localStorage.authorityMenus && localStorage.authorityMenus !== 'undefined' ) { let authorityMenus = JSON.parse(localStorage.authorityMenus) || [] if (authorityMenus && authorityMenus.length > 0) { let menus = uiTool.transformTree(authorityMenus) let curRoutes = uiTool.menuToRoute(menus, ParentView, Page404) // 递归检查所有层级中是否有首页路由 const hasHomeInRoutes = (routes) => { if (!routes || !Array.isArray(routes)) return false for (let route of routes) { // 检查当前路由的 path if (route.path === '/home' || route.path === 'home') { return true } // 递归检查子路由 if (route.children && route.children.length > 0) { if (hasHomeInRoutes(route.children)) { return true } } } return false } const homeRoute = mainRoute.children.find(r => r.path === '/home') const hasHome = hasHomeInRoutes(curRoutes) if (hasHome) { // 如果权限路由中有 home,使用权限路由的 home(不添加默认首页) mainRoute.children = curRoutes mainRoute.redirect = '/home' } else { // 如果权限路由中没有 home,保留默认 home 并添加其他路由 mainRoute.children = [homeRoute, ...curRoutes] mainRoute.redirect = '/home' } // 动态设置 redirect 到第一个有效的路由 // 优先查找首页路由,如果没有则使用第一个菜单项 const findFirstRoute = (routes) => { if (!routes || routes.length === 0) return null for (let route of routes) { // 优先查找 /home 路由 if (route.path === '/home' || route.path === 'home') { return route.path.startsWith('/') ? route.path : '/' + route.path } } // 如果没有 home,使用第一个页面路由 for (let route of routes) { if (route.type !== '菜单' && route.path) { return route.path.startsWith('/') ? route.path : '/' + route.path } // 如果是菜单,递归查找子路由 if (route.children && route.children.length > 0) { const childRoute = findFirstRoute(route.children) if (childRoute) return childRoute } } return null } const firstRoutePath = findFirstRoute(mainRoute.children) if (firstRoutePath) { mainRoute.redirect = firstRoutePath console.log('主路由 redirect 设置为:', firstRoutePath) } } } return mainRoute } }