侧边栏修正

This commit is contained in:
2025-12-13 16:46:04 +08:00
parent b57a002de8
commit a9b2c729e3
14 changed files with 114 additions and 56 deletions

View File

@@ -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),

View File

@@ -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
} }
} }

View File

@@ -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' {

View File

@@ -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()

View File

@@ -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
} }
} }

View File

@@ -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 })
} }
// 视图组件加载器 // 视图组件加载器

View File

@@ -16,7 +16,7 @@ const routes: RouteRecordRaw[] = [
] ]
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory('/platform/'),
routes routes
}) })

View File

@@ -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' {

View File

@@ -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({

View File

@@ -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
} }
} }

View File

@@ -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"

View 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))
}

View File

@@ -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
} }
} }

View File

@@ -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' {