Files
admin_core/src/utils/uiTool.js
张成 970edeb759 1
2025-10-28 16:11:23 +08:00

370 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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: '<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
}
}