diff --git a/.kiro/steering/common.md b/.kiro/steering/common.md index 06ad486..96f69f3 100644 --- a/.kiro/steering/common.md +++ b/.kiro/steering/common.md @@ -4,38 +4,55 @@ inclusion: always # 项目开发规范 -## 语言规范 -- 所有回复和对话使用中文(简体中文) -- 文档、注释和说明使用中文 -- 代码注释使用中文,保持简洁明了 +## 语言和交流规范 +- 所有回复、对话、文档和代码注释使用中文(简体中文) +- 保持技术术语的准确性和一致性 -## 代码规范 +## 代码更改约定 +- 修复问题后,对需不需要进行修复文档的新增进行询问,如果选择不新增,在对话框中修复情况进行说明即可 -### Java 后端规范 -- 遵循 Spring Boot 最佳实践 -- 使用 MyBatis Plus 进行数据库操作 -- 统一异常处理和返回结果格式 -- 接口文档使用 Swagger 注解 -- 实体类使用 Lombok 简化代码 -- 服务层方法需要事务注解 +## 后端开发规范 (Spring Boot + MyBatis Plus) -### Vue 前端规范 -- 使用 TypeScript 进行类型安全开发 -- 组件命名使用 PascalCase -- 使用 Pinia 进行状态管理 -- API 调用统一封装在 api 目录 -- 路由配置支持权限控制 +### 项目结构 +- Controller层:处理HTTP请求,参数验证 +- Service层:业务逻辑处理,必须添加 `@Transactional` 注解 +- Mapper层:数据访问层,使用MyBatis Plus +- Entity层:数据实体,使用Lombok注解简化代码 +- DTO层:数据传输对象,用于API请求响应 -## 架构模式 -- 前后端分离架构 -- RESTful API 设计 -- JWT 身份认证 -- RBAC 权限控制模型 -- 统一的错误处理和日志记录 +### 代码约定 +- 统一返回格式:使用 `Result` 包装所有API响应 +- 异常处理:使用 `@ControllerAdvice` 全局异常处理 +- API文档:所有接口必须添加Swagger注解 +- 数据库表名:统一使用 `sys_` 前缀 +- API路径:统一使用 `/api` 前缀 -## 开发约定 -- 数据库表名使用 sys_ 前缀 -- API 接口统一使用 /api 前缀 -- 分页查询统一返回格式 -- 密码加密使用 BCrypt -- 时间格式统一使用 ISO 8601 \ No newline at end of file +## 前端开发规范 (Vue 3 + TypeScript) + +### 项目结构 +- 组件命名:使用PascalCase(如 `UserManagement.vue`) +- 状态管理:使用Pinia,store文件放在 `src/stores/` +- API调用:统一封装在 `src/api/` 目录 +- 类型定义:放在 `src/types/` 目录 + +### 开发约定 +- 所有组件必须使用TypeScript +- 路由配置支持基于角色的权限控制 +- 使用组合式API(Composition API) + +## 架构和安全规范 + +### 认证授权 +- JWT Token认证机制 +- RBAC(基于角色的访问控制)权限模型 +- 密码使用BCrypt加密存储 + +### API设计 +- 遵循RESTful设计原则 +- 分页查询统一返回 `PageResult` 格式 +- 时间格式统一使用ISO 8601标准 + +### 数据库设计 +- 主键统一使用Long类型的id +- 创建时间和更新时间字段必须包含 +- 逻辑删除使用deleted字段标识 \ No newline at end of file diff --git a/admin-backend/src/main/java/com/admin/config/SecurityConfig.java b/admin-backend/src/main/java/com/admin/config/SecurityConfig.java index 94b369e..c3c6d90 100644 --- a/admin-backend/src/main/java/com/admin/config/SecurityConfig.java +++ b/admin-backend/src/main/java/com/admin/config/SecurityConfig.java @@ -86,7 +86,7 @@ public class SecurityConfig { .antMatchers("/favicon.ico").permitAll() // 其他请求需要认证 .anyRequest().authenticated()) - + // 允许iframe嵌入 .headers(headers -> headers .frameOptions(frame -> frame.disable()) diff --git a/admin-frontend/src/layout/LayoutView.vue b/admin-frontend/src/layout/LayoutView.vue index 91b0ebd..39ac7a6 100644 --- a/admin-frontend/src/layout/LayoutView.vue +++ b/admin-frontend/src/layout/LayoutView.vue @@ -69,12 +69,15 @@ @click="toggleSidebar" > + + + @@ -146,7 +149,7 @@ import { useTabsStore } from '@/stores/tabs' import { useUserStore } from '@/stores/user' import { ArrowDown, - Expand, + ArrowLeft, Fold, House, Loading, @@ -158,7 +161,7 @@ import { } from '@element-plus/icons-vue' import { ElMessage, ElMessageBox } from 'element-plus' import { storeToRefs } from 'pinia' -import { computed, onMounted, ref, watch } from 'vue' +import { computed, nextTick, onMounted, ref, watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() @@ -176,7 +179,6 @@ const cachedViews = computed(() => { }) // 侧边栏状态 -const isCollapse = ref(false) const isHidden = ref(false) const sidebarWidthValue = ref(200) // 实际宽度值 const isResizing = ref(false) @@ -208,16 +210,19 @@ const breadcrumbs = computed(() => { // 切换侧边栏 const toggleSidebar = () => { - if (!isHidden.value && !autoCollapse.value) { - // 展开 → 折叠 - sidebarWidthValue.value = MIN_WIDTH - } else if (!isHidden.value && autoCollapse.value) { - // 折叠 → 隐藏 + if (isHidden.value) { + // 隐藏状态 → 展开状态(显示菜单图标时点击展开) + isHidden.value = false + // 使用 nextTick 确保 DOM 更新后再设置宽度,避免动画冲突 + nextTick(() => { + sidebarWidthValue.value = 200 + }) + } else if (autoCollapse.value) { + // 折叠状态 → 隐藏状态(显示折叠图标时点击隐藏) isHidden.value = true } else { - // 隐藏 → 展开 - isHidden.value = false - sidebarWidthValue.value = 200 + // 展开状态 → 折叠状态(显示展开图标时点击折叠) + sidebarWidthValue.value = MIN_WIDTH } } @@ -404,6 +409,24 @@ watch( overflow-y: auto; } +/* 优化菜单展开动画 - 减少Element Plus默认的过渡时间 */ +.sidebar-menu .el-menu-item, +.sidebar-menu .el-sub-menu { + transition: all 0.15s ease !important; /* 缩短过渡时间 */ +} + +.sidebar-menu .el-menu-item .el-menu-item__title, +.sidebar-menu .el-sub-menu__title { + transition: all 0.15s ease !important; /* 缩短文本显示时间 */ +} + +/* 当菜单从折叠状态展开时,立即显示文本 */ +.sidebar-menu:not(.el-menu--collapse) .el-menu-item span, +.sidebar-menu:not(.el-menu--collapse) .el-sub-menu__title span { + opacity: 1 !important; + transition: opacity 0.1s ease !important; +} + .header { background-color: white; border-bottom: 1px solid #e4e7ed; diff --git a/admin-frontend/tsconfig.app.json b/admin-frontend/tsconfig.app.json index 913b8f2..e264566 100644 --- a/admin-frontend/tsconfig.app.json +++ b/admin-frontend/tsconfig.app.json @@ -1,12 +1,20 @@ { "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], - "exclude": ["src/**/__tests__/*"], + "include": [ + "env.d.ts", + "src/**/*", + "src/**/*.vue" + ], + "exclude": [ + "src/**/__tests__/*" + ], "compilerOptions": { + "incremental": true, "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } } -} +} \ No newline at end of file diff --git a/admin-frontend/tsconfig.node.json b/admin-frontend/tsconfig.node.json index a83dfc9..31af1a6 100644 --- a/admin-frontend/tsconfig.node.json +++ b/admin-frontend/tsconfig.node.json @@ -9,11 +9,13 @@ "eslint.config.*" ], "compilerOptions": { + "incremental": true, "noEmit": true, "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "module": "ESNext", "moduleResolution": "Bundler", - "types": ["node"] + "types": [ + "node" + ] } -} +} \ No newline at end of file diff --git a/docs/侧边菜单隐藏功能/菜单交互修复报告.md b/docs/侧边菜单隐藏功能/菜单交互修复报告.md new file mode 100644 index 0000000..34869a1 --- /dev/null +++ b/docs/侧边菜单隐藏功能/菜单交互修复报告.md @@ -0,0 +1,134 @@ +# 侧边菜单交互按钮修复报告 + +## 问题描述 + +前端菜单栏的展开隐藏交互按钮存在反直觉的问题: +- 当按钮显示展开图标时,用户期望点击后会展开菜单 +- 但实际上点击后菜单会折叠,与用户预期相反 + +## 问题分析 + +### 原始逻辑问题 +1. **图标显示逻辑**: + - 隐藏时显示 `Menu` 图标 ✓ + - 折叠时显示 `Expand` 图标 ❌(应该显示折叠相关图标) + - 展开时显示 `Fold` 图标 ❌(应该显示展开相关图标) + +2. **交互逻辑**: + - 展开 → 折叠 ✓ + - 折叠 → 隐藏 ✓ + - 隐藏 → 展开 ✓ + +### 根本原因 +图标显示的含义与实际操作不匹配,导致用户困惑。 + +## 解决方案 + +### 修复后的图标逻辑 +```typescript +// 图标显示逻辑:显示当前可执行的操作 + + + +``` + +### 修复后的交互逻辑 +```typescript +const toggleSidebar = () => { + if (isHidden.value) { + // 隐藏状态 → 展开状态(显示菜单图标时点击展开) + isHidden.value = false + sidebarWidthValue.value = 200 + } else if (autoCollapse.value) { + // 折叠状态 → 隐藏状态(显示折叠图标时点击隐藏) + isHidden.value = true + } else { + // 展开状态 → 折叠状态(显示展开图标时点击折叠) + sidebarWidthValue.value = MIN_WIDTH + } +} +``` + +## 修复内容 + +### 文件修改 +- **文件**:`admin-frontend/src/layout/LayoutView.vue` +- **修改内容**: + 1. 调整图标显示逻辑,让图标表示当前可执行的操作 + 2. 重新排列交互逻辑的判断顺序,提高代码可读性 + 3. 添加详细注释说明每种状态的图标和操作 + 4. **图标优化**:将展开状态的拉伸图标改为折叠图标,折叠状态使用左箭头图标 + 5. **动画优化**:解决菜单展开时文本延迟显示的问题 + - 缩短 Element Plus 菜单的过渡动画时间 + - 优化文本显示的时机 + - 使用 nextTick 避免 DOM 更新冲突 + +### 交互流程 +1. **隐藏状态**:显示菜单图标 → 点击展开菜单 +2. **展开状态**:显示折叠图标 → 点击折叠为图标模式 +3. **折叠状态**:显示左箭头图标 → 点击完全隐藏 + +## 测试建议 + +1. **功能测试**: + - 验证三种状态间的切换是否正常 + - 确认图标显示与实际操作一致 + +2. **用户体验测试**: + - 确认图标的直观性 + - 验证交互的流畅性 + +## 图标选择说明 + +### 图标语义 +- **Menu 图标**:表示菜单,用于隐藏状态,暗示可以展开菜单 +- **Fold 图标**:表示折叠/收起,用于展开状态,暗示可以收起菜单 +- **ArrowLeft 图标**:表示向左隐藏,用于折叠状态,暗示可以完全隐藏 + +### 为什么不用 Expand 图标 +原来的 `Expand` 图标在展开状态下显示会让用户困惑,因为: +1. 视觉上像拉伸符号,不够直观 +2. 用户看到展开图标会期望点击后进一步展开,而不是收起 +3. `Fold` 图标更清楚地表达"收起"的含义 + +## 动画优化说明 + +### 问题分析 +菜单展开时文本延迟显示的原因: +1. Element Plus 的 `el-menu` 组件有内置的折叠/展开动画 +2. 默认的过渡时间较长(约 0.3s) +3. 文本显示需要等待宽度动画完成 + +### 解决方案 +1. **缩短过渡时间**:将菜单项的过渡时间从默认的 0.3s 缩短到 0.15s +2. **优化文本显示**:确保文本在菜单展开时立即显示 +3. **DOM 更新优化**:使用 `nextTick` 避免状态变化时的冲突 + +### CSS 优化 +```css +/* 缩短Element Plus默认的过渡时间 */ +.sidebar-menu .el-menu-item, +.sidebar-menu .el-sub-menu { + transition: all 0.15s ease !important; +} + +/* 立即显示文本 */ +.sidebar-menu:not(.el-menu--collapse) .el-menu-item span, +.sidebar-menu:not(.el-menu--collapse) .el-sub-menu__title span { + opacity: 1 !important; + transition: opacity 0.1s ease !important; +} +``` + +## 总结 + +通过调整图标显示逻辑、选择更合适的图标,以及优化菜单展开动画,现在侧边栏的交互体验更加流畅和直观: +1. 按钮图标准确反映点击后的操作结果 +2. 菜单展开时文本立即显示,无延迟 +3. 整体交互更符合用户预期 \ No newline at end of file