367 lines
10 KiB
JavaScript
367 lines
10 KiB
JavaScript
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) {
|
||
const blob = new Blob([res.data || res])
|
||
const downloadElement = document.createElement('a')
|
||
const href = window.URL.createObjectURL(blob)
|
||
downloadElement.href = href
|
||
downloadElement.download = fileName || new Date().getTime() + '.csv'
|
||
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: '<p>你确定删除吗?</p>',
|
||
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
|
||
}
|
||
}
|
||
|