diff --git a/schoolNewsServ/.bin/mysql/sql/initMenuData.sql b/schoolNewsServ/.bin/mysql/sql/initMenuData.sql index ccc13f8..7efb893 100644 --- a/schoolNewsServ/.bin/mysql/sql/initMenuData.sql +++ b/schoolNewsServ/.bin/mysql/sql/initMenuData.sql @@ -60,33 +60,34 @@ INSERT INTO `tb_sys_role_permission` (id, role_id, permission_id, creator, creat -- 插入前端菜单数据 INSERT INTO `tb_sys_menu` (id, menu_id, name, parent_id, url, component, icon, order_num, type, layout, creator, create_time) VALUES +('100', 'menu_home', '首页', NULL, '/home', 'home/HomeView', 'el-icon-house', 1, 1, 'NavigationLayout', '1', now()), -- 资源中心 -('200', 'menu_resource_center', '资源中心', NULL, '/resource-center', 'resource-center/ResourceCenterView', 'el-icon-folder-opened', 2, 1, 'BasicLayout', '1', now()), -('201', 'menu_party_history', '党史学习', 'menu_resource_center', '/resource-center/party-history', 'resource-center/PartyHistoryView', 'el-icon-trophy', 1, 1, 'BasicLayout', '1', now()), -('202', 'menu_leader_speech', '领导讲话', 'menu_resource_center', '/resource-center/leader-speech', 'resource-center/LeaderSpeechView', 'el-icon-microphone', 2, 1, 'BasicLayout', '1', now()), -('203', 'menu_policy_interpretation', '政策解读', 'menu_resource_center', '/resource-center/policy-interpretation', 'resource-center/PolicyInterpretationView', 'el-icon-document', 3, 1, 'BasicLayout', '1', now()), -('204', 'menu_red_classic', '红色经典', 'menu_resource_center', '/resource-center/red-classic', 'resource-center/RedClassicView', 'el-icon-star-on', 4, 1, 'BasicLayout', '1', now()), -('205', 'menu_special_report', '专题报告', 'menu_resource_center', '/resource-center/special-report', 'resource-center/SpecialReportView', 'el-icon-document-copy', 5, 1, 'BasicLayout', '1', now()), -('206', 'menu_world_case', '思政案例', 'menu_resource_center', '/resource-center/world-case', 'resource-center/WorldCaseView', 'el-icon-collection', 6, 1, 'BasicLayout', '1', now()), +('200', 'menu_resource_center', '资源中心', NULL, '/resource-center', 'resource-center/ResourceCenterView', 'el-icon-folder-opened', 2, 1, 'NavigationLayout', '1', now()), +('201', 'menu_party_history', '党史学习', 'menu_resource_center', '/resource-center/party-history', 'resource-center/PartyHistoryView', 'el-icon-trophy', 1, 1, 'NavigationLayout', '1', now()), +('202', 'menu_leader_speech', '领导讲话', 'menu_resource_center', '/resource-center/leader-speech', 'resource-center/LeaderSpeechView', 'el-icon-microphone', 2, 1, 'NavigationLayout', '1', now()), +('203', 'menu_policy_interpretation', '政策解读', 'menu_resource_center', '/resource-center/policy-interpretation', 'resource-center/PolicyInterpretationView', 'el-icon-document', 3, 1, 'NavigationLayout', '1', now()), +('204', 'menu_red_classic', '红色经典', 'menu_resource_center', '/resource-center/red-classic', 'resource-center/RedClassicView', 'el-icon-star-on', 4, 1, 'NavigationLayout', '1', now()), +('205', 'menu_special_report', '专题报告', 'menu_resource_center', '/resource-center/special-report', 'resource-center/SpecialReportView', 'el-icon-document-copy', 5, 1, 'NavigationLayout', '1', now()), +('206', 'menu_world_case', '思政案例', 'menu_resource_center', '/resource-center/world-case', 'resource-center/WorldCaseView', 'el-icon-collection', 6, 1, 'NavigationLayout', '1', now()), -- 学习计划 -('300', 'menu_study_plan', '学习计划', NULL, '/study-plan', 'study-plan/StudyPlanView', 'el-icon-reading', 3, 1, 'BasicLayout', '1', now()), -('301', 'menu_study_tasks', '学习任务', 'menu_study_plan', '/study-plan/tasks', 'study-plan/StudyTasksView', 'el-icon-s-order', 1, 1, 'BasicLayout', '1', now()), -('302', 'menu_course_center', '课程中心', 'menu_study_plan', '/study-plan/course', 'study-plan/CourseCenterView', 'el-icon-video-play', 2, 1, 'BasicLayout', '1', now()), +('300', 'menu_study_plan', '学习计划', NULL, '/study-plan', 'study-plan/StudyPlanView', 'el-icon-reading', 3, 1, 'NavigationLayout', '1', now()), +('301', 'menu_study_tasks', '学习任务', 'menu_study_plan', '/study-plan/tasks', 'study-plan/StudyTasksView', 'el-icon-s-order', 1, 1, 'NavigationLayout', '1', now()), +('302', 'menu_course_center', '课程中心', 'menu_study_plan', '/study-plan/course', 'study-plan/CourseCenterView', 'el-icon-video-play', 2, 1, 'NavigationLayout', '1', now()), -- 个人中心 -('400', 'menu_user_center', '个人中心', NULL, '/user-center', 'user-center/UserCenterView', 'el-icon-user', 4, 1, 'BasicLayout', '1', now()), -('401', 'menu_learning_records', '学习记录', 'menu_user_center', '/user-center/learning-records', 'user-center/LearningRecordsView', 'el-icon-document', 1, 1, 'BasicLayout', '1', now()), -('402', 'menu_my_favorites', '我的收藏', 'menu_user_center', '/user-center/favorites', 'user-center/MyFavoritesView', 'el-icon-star-on', 2, 1, 'BasicLayout', '1', now()), -('403', 'menu_my_achievements', '我的成就', 'menu_user_center', '/user-center/achievements', 'user-center/MyAchievementsView', 'el-icon-trophy', 3, 1, 'BasicLayout', '1', now()), +('400', 'menu_user_center', '个人中心', NULL, '/user-center', 'user-center/UserCenterView', 'el-icon-user', 4, 1, 'NavigationLayout', '1', now()), +('401', 'menu_learning_records', '学习记录', 'menu_user_center', '/user-center/learning-records', 'user-center/LearningRecordsView', 'el-icon-document', 1, 1, 'NavigationLayout', '1', now()), +('402', 'menu_my_favorites', '我的收藏', 'menu_user_center', '/user-center/favorites', 'user-center/MyFavoritesView', 'el-icon-star-on', 2, 1, 'NavigationLayout', '1', now()), +('403', 'menu_my_achievements', '我的成就', 'menu_user_center', '/user-center/achievements', 'user-center/MyAchievementsView', 'el-icon-trophy', 3, 1, 'NavigationLayout', '1', now()), -- 账号中心 -('500', 'menu_profile', '账号中心', NULL, '/profile', 'profile/ProfileView', 'el-icon-user-solid', 5, 1, 'BasicLayout', '1', now()), -('501', 'menu_personal_info', '个人信息', 'menu_profile', '/profile/personal-info', 'profile/PersonalInfoView', 'el-icon-user', 1, 1, 'BasicLayout', '1', now()), -('502', 'menu_account_settings', '账号设置', 'menu_profile', '/profile/account-settings', 'profile/AccountSettingsView', 'el-icon-setting', 2, 1, 'BasicLayout', '1', now()), +('500', 'menu_profile', '账号中心', NULL, '/profile', 'profile/ProfileView', 'el-icon-user-solid', 5, 1, 'NavigationLayout', '1', now()), +('501', 'menu_personal_info', '个人信息', 'menu_profile', '/profile/personal-info', 'profile/PersonalInfoView', 'el-icon-user', 1, 1, 'NavigationLayout', '1', now()), +('502', 'menu_account_settings', '账号设置', 'menu_profile', '/profile/account-settings', 'profile/AccountSettingsView', 'el-icon-setting', 2, 1, 'NavigationLayout', '1', now()), -- 智能体模块 -('600', 'menu_ai_assistant', '智能体模块', NULL, '/ai-assistant', 'ai-assistant/AIAssistantView', 'el-icon-cpu', 6, 1, 'BasicLayout', '1', now()); +('600', 'menu_ai_assistant', '智能体模块', NULL, '/ai-assistant', 'ai-assistant/AIAssistantView', 'el-icon-cpu', 6, 1, 'NavigationLayout', '1', now()); -- 插入后端管理菜单数据 INSERT INTO `tb_sys_menu` (id, menu_id, name, parent_id, url, component, icon, order_num, type, layout, creator, create_time) VALUES diff --git a/schoolNewsWeb/src/components/Breadcrumb.vue b/schoolNewsWeb/src/components/base/Breadcrumb.vue similarity index 100% rename from schoolNewsWeb/src/components/Breadcrumb.vue rename to schoolNewsWeb/src/components/base/Breadcrumb.vue diff --git a/schoolNewsWeb/src/components/base/FloatingSidebar.vue b/schoolNewsWeb/src/components/base/FloatingSidebar.vue new file mode 100644 index 0000000..dc03c42 --- /dev/null +++ b/schoolNewsWeb/src/components/base/FloatingSidebar.vue @@ -0,0 +1,357 @@ + + + + + + diff --git a/schoolNewsWeb/src/components/MenuItem.vue b/schoolNewsWeb/src/components/base/MenuItem.vue similarity index 100% rename from schoolNewsWeb/src/components/MenuItem.vue rename to schoolNewsWeb/src/components/base/MenuItem.vue diff --git a/schoolNewsWeb/src/components/MenuNav.vue b/schoolNewsWeb/src/components/base/MenuNav.vue similarity index 100% rename from schoolNewsWeb/src/components/MenuNav.vue rename to schoolNewsWeb/src/components/base/MenuNav.vue diff --git a/schoolNewsWeb/src/components/TopNavigation.vue b/schoolNewsWeb/src/components/base/TopNavigation.vue similarity index 92% rename from schoolNewsWeb/src/components/TopNavigation.vue rename to schoolNewsWeb/src/components/base/TopNavigation.vue index a359745..8053452 100644 --- a/schoolNewsWeb/src/components/TopNavigation.vue +++ b/schoolNewsWeb/src/components/base/TopNavigation.vue @@ -3,7 +3,7 @@ - + @@ -152,9 +151,11 @@ function handleMouseEnter(menu: SysMenu, event?: MouseEvent) { activeDropdown.value = menu.menuID || null; // 计算下拉菜单位置 - const target = event?.currentTarget as HTMLElement; - if (target && menu.menuID) { - const rect = target.getBoundingClientRect(); + if (event && menu.menuID) { + const target = event.currentTarget as HTMLElement; + const navLink = target.querySelector('.nav-link') as HTMLElement; + const rect = (navLink || target).getBoundingClientRect(); + dropdownPositions.value[menu.menuID] = { left: rect.left, top: rect.bottom, @@ -167,11 +168,15 @@ function handleMouseEnter(menu: SysMenu, event?: MouseEvent) { // 获取下拉菜单位置样式 function getDropdownPosition(menu: SysMenu) { const menuID = menu.menuID; - if (!menuID || !dropdownPositions.value[menuID]) { - return {}; + const pos = menuID && dropdownPositions.value[menuID]; + + if (!pos) { + return { + position: 'fixed' as const, + visibility: 'hidden' as const + }; } - const pos = dropdownPositions.value[menuID]; return { position: 'fixed' as const, left: `${pos.left}px`, @@ -356,15 +361,16 @@ function handleLogout() { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); opacity: 0; visibility: hidden; - transform: translateY(-10px); - transition: all 0.3s; + transform: scaleY(0); + transform-origin: top center; + transition: opacity 0.2s, transform 0.2s, visibility 0.2s; z-index: 10000; pointer-events: none; &.show { opacity: 1; visibility: visible; - transform: translateY(0); + transform: scaleY(1); pointer-events: auto; } } diff --git a/schoolNewsWeb/src/components/UserDropdown.vue b/schoolNewsWeb/src/components/base/UserDropdown.vue similarity index 100% rename from schoolNewsWeb/src/components/UserDropdown.vue rename to schoolNewsWeb/src/components/base/UserDropdown.vue diff --git a/schoolNewsWeb/src/components/base/index.ts b/schoolNewsWeb/src/components/base/index.ts new file mode 100644 index 0000000..d924712 --- /dev/null +++ b/schoolNewsWeb/src/components/base/index.ts @@ -0,0 +1,6 @@ +export { default as Breadcrumb } from './Breadcrumb.vue'; +export { default as FloatingSidebar } from './FloatingSidebar.vue'; +export { default as MenuItem } from './MenuItem.vue'; +export { default as MenuNav } from './MenuNav.vue'; +export { default as TopNavigation } from './TopNavigation.vue'; +export { default as UserDropdown } from './UserDropdown.vue'; \ No newline at end of file diff --git a/schoolNewsWeb/src/components/index.ts b/schoolNewsWeb/src/components/index.ts new file mode 100644 index 0000000..1b2ffa7 --- /dev/null +++ b/schoolNewsWeb/src/components/index.ts @@ -0,0 +1,3 @@ +// 导出 base 基础组件 +export * from './base'; + diff --git a/schoolNewsWeb/src/layouts/BasicLayout.vue b/schoolNewsWeb/src/layouts/BasicLayout.vue index 73f43eb..c97577c 100644 --- a/schoolNewsWeb/src/layouts/BasicLayout.vue +++ b/schoolNewsWeb/src/layouts/BasicLayout.vue @@ -57,12 +57,7 @@ import { useRoute, useRouter } from "vue-router"; import { useStore } from "vuex"; import type { SysMenu } from "@/types"; import { getMenuPath } from "@/utils/route-generator"; -// @ts-ignore - Vue 3.5 defineOptions支持 -import MenuNav from "@/components/MenuNav.vue"; -// @ts-ignore - Vue 3.5 组件导入兼容性 -import Breadcrumb from "@/components/Breadcrumb.vue"; -// @ts-ignore - Vue 3.5 组件导入兼容性 -import UserDropdown from "@/components/UserDropdown.vue"; +import { MenuNav, Breadcrumb, UserDropdown } from "@/components/base"; // 响应式状态 const sidebarCollapsed = ref(false); diff --git a/schoolNewsWeb/src/layouts/NavigationLayout.vue b/schoolNewsWeb/src/layouts/NavigationLayout.vue index 7e74c5c..5418b0b 100644 --- a/schoolNewsWeb/src/layouts/NavigationLayout.vue +++ b/schoolNewsWeb/src/layouts/NavigationLayout.vue @@ -6,9 +6,9 @@
-