侧边栏修正
This commit is contained in:
@@ -227,7 +227,7 @@ INSERT INTO sys.tb_sys_view (
|
|||||||
-- 平台管理后台内部视图(AdminSidebarLayout布局,在platform服务内)
|
-- 平台管理后台内部视图(AdminSidebarLayout布局,在platform服务内)
|
||||||
('VIEW-P201', 'view_platform_admin_overview', '数据概览', NULL, '/admin/overview', 'admin/overview/OverviewView.vue', 'DataLine', 1,
|
('VIEW-P201', 'view_platform_admin_overview', '数据概览', NULL, '/admin/overview', 'admin/overview/OverviewView.vue', 'DataLine', 1,
|
||||||
'route', NULL, 'platform', 'AdminSidebarLayout', 210, '平台数据概览', 'system', now(), false),
|
'route', NULL, 'platform', 'AdminSidebarLayout', 210, '平台数据概览', 'system', now(), false),
|
||||||
('VIEW-P202', 'view_platform_admin_user', '用户管理', NULL, '/admin/user', 'admin/user/UserView.vue', 'User', 1,
|
('VIEW-P202', 'view_platform_admin_user', '用户管理', NULL, '/admin/userManagement', 'admin/userManagement/UserManagementView.vue', 'User', 1,
|
||||||
'route', NULL, 'platform', 'AdminSidebarLayout', 220, '平台用户管理', 'system', now(), false),
|
'route', NULL, 'platform', 'AdminSidebarLayout', 220, '平台用户管理', 'system', now(), false),
|
||||||
('VIEW-P203', 'view_platform_admin_knowledge', '知识库', NULL, '/admin/knowledge', 'admin/knowledge/KnowledgeView.vue', 'Document', 1,
|
('VIEW-P203', 'view_platform_admin_knowledge', '知识库', NULL, '/admin/knowledge', 'admin/knowledge/KnowledgeView.vue', 'Document', 1,
|
||||||
'route', NULL, 'platform', 'AdminSidebarLayout', 230, '平台知识库管理', 'system', now(), false),
|
'route', NULL, 'platform', 'AdminSidebarLayout', 230, '平台知识库管理', 'system', now(), false),
|
||||||
|
|||||||
@@ -108,14 +108,7 @@ import {
|
|||||||
Loading
|
Loading
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MenuItem } from 'shared/types'
|
||||||
interface MenuItem {
|
|
||||||
key: string
|
|
||||||
label: string
|
|
||||||
icon: string
|
|
||||||
url?: string
|
|
||||||
type: 'route' | 'iframe'
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -227,7 +220,7 @@ const handleMenuClick = (item: MenuItem) => {
|
|||||||
// 所有菜单都通过路由跳转
|
// 所有菜单都通过路由跳转
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
router.push(item.url)
|
router.push(item.url)
|
||||||
if (item.type === 'iframe') {
|
if (item.viewType === 'iframe') {
|
||||||
iframeLoading.value = true
|
iframeLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,15 +95,28 @@ declare module 'shared/types' {
|
|||||||
parentId?: string
|
parentId?: string
|
||||||
url?: string
|
url?: string
|
||||||
component?: string
|
component?: string
|
||||||
service?: string
|
|
||||||
iframeUrl?: string
|
iframeUrl?: string
|
||||||
icon?: string
|
icon?: string
|
||||||
type?: number
|
type?: number
|
||||||
|
viewType?: string
|
||||||
|
service?: string
|
||||||
layout?: string
|
layout?: string
|
||||||
orderNum?: number
|
orderNum?: number
|
||||||
description?: string
|
description?: string
|
||||||
children?: TbSysViewDTO[]
|
children?: TbSysViewDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 菜单项类型(扩展 TbSysViewDTO)
|
||||||
|
export interface MenuItem extends TbSysViewDTO {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
expanded?: boolean
|
||||||
|
children?: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单工具函数
|
||||||
|
export function toMenuItem(view: TbSysViewDTO, expanded?: boolean): MenuItem
|
||||||
|
export function toMenuItems(views: TbSysViewDTO[], defaultExpanded?: boolean): MenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'shared/utils/route' {
|
declare module 'shared/utils/route' {
|
||||||
|
|||||||
@@ -96,14 +96,7 @@ import {
|
|||||||
Back
|
Back
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MenuItem } from 'shared/types'
|
||||||
interface MenuItem {
|
|
||||||
key: string
|
|
||||||
label: string
|
|
||||||
icon: string
|
|
||||||
url?: string
|
|
||||||
type: 'route' | 'iframe'
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|||||||
@@ -108,14 +108,7 @@ import {
|
|||||||
Loading
|
Loading
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MenuItem } from 'shared/types'
|
||||||
interface MenuItem {
|
|
||||||
key: string
|
|
||||||
label: string
|
|
||||||
icon: string
|
|
||||||
url?: string
|
|
||||||
type: 'route' | 'iframe'
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -228,7 +221,7 @@ const handleMenuClick = (item: MenuItem) => {
|
|||||||
// 所有菜单都通过路由跳转
|
// 所有菜单都通过路由跳转
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
router.push(item.url)
|
router.push(item.url)
|
||||||
if (item.type === 'iframe') {
|
if (item.viewType === 'iframe') {
|
||||||
iframeLoading.value = true
|
iframeLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
import type { TbSysViewDTO } from 'shared/types'
|
import type { TbSysViewDTO } from 'shared/types'
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
import router from './index'
|
import router from './index'
|
||||||
import { SidebarLayout, BlankLayout, AdminIframeSidebarLayout } from '@/layouts'
|
import { SidebarLayout, BlankLayout, AdminIframeSidebarLayout, AdminSidebarLayout } from '@/layouts'
|
||||||
|
|
||||||
// Platform 布局组件映射
|
// Platform 布局组件映射
|
||||||
const platformLayoutMap: Record<string, () => Promise<any>> = {
|
const platformLayoutMap: Record<string, () => Promise<any>> = {
|
||||||
@@ -26,7 +26,8 @@ const platformLayoutMap: Record<string, () => Promise<any>> = {
|
|||||||
'BlankLayout': () => Promise.resolve({ default: BlankLayout }),
|
'BlankLayout': () => Promise.resolve({ default: BlankLayout }),
|
||||||
'NavigationLayout': () => Promise.resolve({ default: SidebarLayout }),
|
'NavigationLayout': () => Promise.resolve({ default: SidebarLayout }),
|
||||||
'BasicLayout': () => Promise.resolve({ default: SidebarLayout }),
|
'BasicLayout': () => Promise.resolve({ default: SidebarLayout }),
|
||||||
'AdminIframeSidebarLayout': () => Promise.resolve({ default: AdminIframeSidebarLayout })
|
'AdminIframeSidebarLayout': () => Promise.resolve({ default: AdminIframeSidebarLayout }),
|
||||||
|
'AdminSidebarLayout': () => Promise.resolve({ default: AdminSidebarLayout })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 视图组件加载器
|
// 视图组件加载器
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory('/platform/'),
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -95,15 +95,28 @@ declare module 'shared/types' {
|
|||||||
parentId?: string
|
parentId?: string
|
||||||
url?: string
|
url?: string
|
||||||
component?: string
|
component?: string
|
||||||
service?: string
|
|
||||||
iframeUrl?: string
|
iframeUrl?: string
|
||||||
icon?: string
|
icon?: string
|
||||||
type?: number
|
type?: number
|
||||||
|
viewType?: string
|
||||||
|
service?: string
|
||||||
layout?: string
|
layout?: string
|
||||||
orderNum?: number
|
orderNum?: number
|
||||||
description?: string
|
description?: string
|
||||||
children?: TbSysViewDTO[]
|
children?: TbSysViewDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 菜单项类型(扩展 TbSysViewDTO)
|
||||||
|
export interface MenuItem extends TbSysViewDTO {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
expanded?: boolean
|
||||||
|
children?: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单工具函数
|
||||||
|
export function toMenuItem(view: TbSysViewDTO, expanded?: boolean): MenuItem
|
||||||
|
export function toMenuItems(views: TbSysViewDTO[], defaultExpanded?: boolean): MenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'shared/utils/route' {
|
declare module 'shared/utils/route' {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ const __filename = fileURLToPath(import.meta.url)
|
|||||||
const __dirname = dirname(__filename)
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Platform 是根路径应用
|
// Platform 应用的基础路径
|
||||||
base: '/',
|
base: '/platform/',
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
vue({
|
vue({
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<aside class="sidebar" :class="{ collapsed: collapsed }">
|
<aside class="sidebar" :class="{ collapsed: collapsed }">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<img src="/logo.jpg" alt="Logo" class="logo-img" />
|
<img :src="logoUrl" alt="Logo" class="logo-img" />
|
||||||
<span v-if="!collapsed" class="logo-text">城市生命线</span>
|
<span v-if="!collapsed" class="logo-text">城市生命线</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse-btn" @click="toggleSidebar">
|
<div class="collapse-btn" @click="toggleSidebar">
|
||||||
@@ -104,21 +104,12 @@ import {
|
|||||||
ArrowRight
|
ArrowRight
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MenuItem } from '@/types/menu'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
service?: string // 服务名称:platform, bidding, workcase
|
service?: string // 服务名称:platform, bidding, workcase
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MenuItem {
|
|
||||||
key: string
|
|
||||||
label: string
|
|
||||||
icon: string
|
|
||||||
url?: string
|
|
||||||
type: 'route' | 'iframe'
|
|
||||||
children?: MenuItem[] // 子菜单
|
|
||||||
expanded?: boolean // 是否展开
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
service: undefined // 不设默认值,从路由自动检测
|
service: undefined // 不设默认值,从路由自动检测
|
||||||
})
|
})
|
||||||
@@ -185,6 +176,18 @@ const currentService = computed(() => {
|
|||||||
return 'workcase'
|
return 'workcase'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 动态 Logo URL
|
||||||
|
const logoUrl = computed(() => {
|
||||||
|
const service = currentService.value
|
||||||
|
// 根据不同服务返回对应的 logo 路径
|
||||||
|
const serviceLogos: Record<string, string> = {
|
||||||
|
'platform': '/platform/logo.jpg',
|
||||||
|
'workcase': '/workcase/logo.jpg',
|
||||||
|
'bidding': '/bidding/logo.jpg'
|
||||||
|
}
|
||||||
|
return serviceLogos[service] || '/logo.jpg' // 默认回退到根路径
|
||||||
|
})
|
||||||
|
|
||||||
// 状态管理
|
// 状态管理
|
||||||
const collapsed = ref(false)
|
const collapsed = ref(false)
|
||||||
const activeMenu = ref('home')
|
const activeMenu = ref('home')
|
||||||
@@ -310,12 +313,12 @@ const toggleMenu = (item: MenuItem) => {
|
|||||||
|
|
||||||
// 处理菜单点击
|
// 处理菜单点击
|
||||||
const handleMenuClick = (item: MenuItem) => {
|
const handleMenuClick = (item: MenuItem) => {
|
||||||
activeMenu.value = item.key
|
activeMenu.value = item.key || ''
|
||||||
|
|
||||||
// 所有菜单都通过路由跳转
|
// 所有菜单都通过路由跳转
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
router.push(item.url)
|
router.push(item.url)
|
||||||
if (item.type === 'iframe') {
|
if (item.viewType === 'iframe') {
|
||||||
iframeLoading.value = true
|
iframeLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export * from "./page"
|
|||||||
export * from "./base"
|
export * from "./base"
|
||||||
export * from "./sys"
|
export * from "./sys"
|
||||||
export * from "./enums"
|
export * from "./enums"
|
||||||
|
export * from "./menu"
|
||||||
|
|
||||||
// 服务 types
|
// 服务 types
|
||||||
export * from "./auth"
|
export * from "./auth"
|
||||||
|
|||||||
42
urbanLifelineWeb/packages/shared/src/types/menu/index.ts
Normal file
42
urbanLifelineWeb/packages/shared/src/types/menu/index.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* 菜单相关类型定义
|
||||||
|
* 基于 TbSysViewDTO 扩展
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { TbSysViewDTO } from '../sys/permission'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单项类型
|
||||||
|
* 扩展 TbSysViewDTO,添加运行时状态
|
||||||
|
*/
|
||||||
|
export interface MenuItem extends TbSysViewDTO {
|
||||||
|
/** 唯一标识(用于菜单选中状态),覆盖为必需 */
|
||||||
|
key: string
|
||||||
|
/** 显示标签,覆盖为必需 */
|
||||||
|
label: string
|
||||||
|
/** 是否展开(运行时状态,仅用于有子菜单的项) */
|
||||||
|
expanded?: boolean
|
||||||
|
/** 子菜单(覆盖类型为 MenuItem[]) */
|
||||||
|
children?: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 TbSysViewDTO 转换为 MenuItem
|
||||||
|
*/
|
||||||
|
export function toMenuItem(view: TbSysViewDTO, expanded = false): MenuItem {
|
||||||
|
return {
|
||||||
|
...view,
|
||||||
|
key: view.viewId || view.name || '',
|
||||||
|
label: view.name || '',
|
||||||
|
expanded,
|
||||||
|
// 递归转换子菜单
|
||||||
|
children: view.children?.map(child => toMenuItem(child, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 TbSysViewDTO 数组转换为 MenuItem 数组
|
||||||
|
*/
|
||||||
|
export function toMenuItems(views: TbSysViewDTO[], defaultExpanded = false): MenuItem[] {
|
||||||
|
return views.map(view => toMenuItem(view, defaultExpanded))
|
||||||
|
}
|
||||||
@@ -83,14 +83,7 @@ import {
|
|||||||
Loading
|
Loading
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import type { MenuItem } from 'shared/types'
|
||||||
interface MenuItem {
|
|
||||||
key: string
|
|
||||||
label: string
|
|
||||||
icon: string
|
|
||||||
url?: string
|
|
||||||
type: 'route' | 'iframe'
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -202,7 +195,7 @@ const handleMenuClick = (item: MenuItem) => {
|
|||||||
// 所有菜单都通过路由跳转
|
// 所有菜单都通过路由跳转
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
router.push(item.url)
|
router.push(item.url)
|
||||||
if (item.type === 'iframe') {
|
if (item.viewType === 'iframe') {
|
||||||
iframeLoading.value = true
|
iframeLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,12 +93,25 @@ declare module 'shared/types' {
|
|||||||
iframeUrl?: string
|
iframeUrl?: string
|
||||||
icon?: string
|
icon?: string
|
||||||
type?: number
|
type?: number
|
||||||
|
viewType?: string
|
||||||
service?: string
|
service?: string
|
||||||
layout?: string
|
layout?: string
|
||||||
orderNum?: number
|
orderNum?: number
|
||||||
description?: string
|
description?: string
|
||||||
children?: TbSysViewDTO[]
|
children?: TbSysViewDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 菜单项类型(扩展 TbSysViewDTO)
|
||||||
|
export interface MenuItem extends TbSysViewDTO {
|
||||||
|
key: string
|
||||||
|
label: string
|
||||||
|
expanded?: boolean
|
||||||
|
children?: MenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单工具函数
|
||||||
|
export function toMenuItem(view: TbSysViewDTO, expanded?: boolean): MenuItem
|
||||||
|
export function toMenuItems(views: TbSysViewDTO[], defaultExpanded?: boolean): MenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'shared/utils/route' {
|
declare module 'shared/utils/route' {
|
||||||
|
|||||||
Reference in New Issue
Block a user