From a2ca64d909d990e1997fb2e547149ee7bd94a3a7 Mon Sep 17 00:00:00 2001 From: molong Date: Wed, 11 Feb 2026 09:39:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=90=8E=E5=A4=A9=E8=A7=84?= =?UTF-8?q?=E5=88=99=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clinerules/admin-rule.md | 691 +++++++++++++++++++++++++++++++++++--- 1 file changed, 651 insertions(+), 40 deletions(-) diff --git a/.clinerules/admin-rule.md b/.clinerules/admin-rule.md index 7769030..0e6dcd3 100644 --- a/.clinerules/admin-rule.md +++ b/.clinerules/admin-rule.md @@ -59,6 +59,18 @@ resources/admin/ │ │ └── index.vue # 主布局 │ ├── pages/ # 页面组件 │ │ ├── auth/ # 认证页面 +│ │ │ ├── users/ # 用户管理 +│ │ │ │ ├── index.vue # 主页面 +│ │ │ │ └── components/ # 页面私有组件 +│ │ │ │ ├── SaveDialog.vue # 新增/编辑弹窗 +│ │ │ │ ├── RoleDialog.vue # 角色设置弹窗 +│ │ │ │ └── DetailDialog.vue # 详情弹窗 +│ │ │ ├── roles/ # 角色管理 +│ │ │ │ ├── index.vue +│ │ │ │ └── components/ +│ │ │ │ ├── SaveDialog.vue +│ │ │ │ └── PermissionDialog.vue +│ │ │ └── ... │ │ ├── home/ # 首页 │ │ ├── login/ # 登录页 │ │ ├── system/ # 系统管理 @@ -84,13 +96,446 @@ resources/admin/ └── README.md # 项目说明 ``` -### 2. 组件开发规范 +### 2. 页面组件开发规范 + +#### 页面组件目录结构 + +每个页面模块应遵循以下目录结构: + +``` +pages/ +└── {module}/ # 模块目录(如 auth, system 等) + └── {resource}/ # 资源目录(如 users, roles 等) + ├── index.vue # 主页面(列表页) + └── components/ # 页面私有组件目录 + ├── SaveDialog.vue # 新增/编辑弹窗(字段较少时使用) + ├── SaveDrawer.vue # 新增/编辑抽屉(字段较多时使用) + ├── DetailDialog.vue # 详情弹窗 + ├── RoleDialog.vue # 角色设置弹窗 + ├── SearchDrawer.vue # 高级搜索抽屉 + └── ... # 其他页面专用组件 +``` + +**目录结构说明**: +- `index.vue`: 页面的主入口组件,通常是列表展示页面 +- `components/`: 存放该页面专用的私有组件 + - 弹窗/抽屉组件:根据表单字段数量选择使用弹窗或抽屉 + - 字段较少(3-5个):使用 `*Dialog.vue` 弹窗组件 + - 字段较多(5个以上):使用 `*Drawer.vue` 抽屉组件 + - `SaveDialog.vue` / `SaveDrawer.vue`: 用于新增和编辑数据的表单组件 + - `DetailDialog.vue`: 用于查看数据详情的弹窗 + - `SearchDrawer.vue`: 用于高级搜索条件的抽屉组件 + - 其他与该页面紧密关联的组件 + +**组件命名规范**: +- 页面私有组件使用 PascalCase 命名 +- 建议以功能命名: + - 表单类:`SaveDialog.vue`, `SaveDrawer.vue`, `EditDialog.vue` 等 + - 功能类:`RoleDialog.vue`, `PermissionDialog.vue` 等 + - 搜索类:`SearchDrawer.vue` +- 避免 `Dialog.vue` 或 `Drawer.vue` 这样过于通用的命名 + +#### 页面布局规范 + +**基本布局要求**: + +1. **使用 Flex 布局**: 页面容器必须使用 Flex 布局,确保占满全部内容区域 +2. **表格高度自适应**: 表格使用封装的 `scTable` 组件,高度占满剩余内容空间 + +**标准页面布局模板**: + +```vue + + + +``` + +**布局样式说明**: +- 页面根元素使用 `display: flex` 和 `flex-direction: column` 实现垂直布局 +- `height: 100%` 确保页面占满父容器高度 +- `padding: 0` 去除内边距(由布局组件控制外边距) +- `table-content` 使用 `flex: 1` 占据剩余空间 +- `overflow: hidden` 防止出现滚动条(表格内部自己处理滚动) + +**侧边栏布局示例** (如用户管理页面): + +```vue + + + +``` + +#### 列表搜索区域规范 + +**搜索区域设计原则**: + +1. **精简显示**: 搜索条件不全部显示,只显示最常用的 1-2 项 +2. **优先使用表格筛选**: 对于状态等枚举类型的筛选,优先使用 Ant Design Vue Table 的自定义过滤器功能 +3. **高级搜索抽屉**: 其他复杂搜索条件使用抽屉弹出(需要在页面 components 目录下创建 SearchDrawer.vue 组件) +4. **保持界面整洁**: 避免搜索区域占用过多空间 + +**实现方式**: + +**方式一: 使用表格自定义筛选(推荐)** + +```vue + + + +``` + +**方式二: 使用高级搜索抽屉(复杂搜索条件)** + +```vue + + + +``` + +**SearchDrawer.vue 组件示例**: + +```vue + + + +``` + +**搜索条件选择建议**: + +常用搜索条件(显示在工具栏): +- 主要关键字搜索(如用户名、角色名称) +- 无需筛选的简单字段 + +表格筛选(推荐用于): +- 状态、类型等枚举值字段 +- 不需要组合条件的单一筛选 + +高级搜索抽屉(用于): +- 次要字段(如邮箱、手机号) +- 日期范围筛选 +- 多条件组合筛选 +- 复杂的搜索逻辑 + +**scTable 组件筛选器优化说明**: + +scTable 组件已支持 Ant Design Vue Table 的筛选功能,使用方式: + +1. 在 `columns` 配置中添加 `filters` 属性 +2. 通过 `@filterChange` 事件处理筛选变化 +3. 将筛选条件合并到搜索表单中提交 + +```javascript +// 在 useTable Hook 中处理筛选变化 +const handleFilterChange = (pagination, filters) => { + // 将筛选条件添加到搜索表单 + if (filters.status) { + searchForm.status = filters.status[0] // filterMultiple: false 时取第一个值 + } + handleSearch() +} +``` + +### 3. 组件开发规范 #### 组件命名 - **单文件组件**: 使用 PascalCase 命名,如 `UserList.vue` - **公共组件**: 以 `sc` 开头,如 `scTable.vue` -- **页面组件**: 使用语义化命名,如 `UserManagement.vue` +- **页面私有组件**: 使用语义化命名,如 `SaveDialog.vue`, `RoleDialog.vue` #### 组件结构 @@ -121,7 +566,7 @@ onMounted(() => {}) ``` -### 3. API 接口开发规范 +### 4. API 接口开发规范 #### API 文件组织 @@ -189,7 +634,7 @@ const getMenu = async () => { } ``` -### 4. 路由开发规范 +### 5. 路由开发规范 #### 路由类型 @@ -243,7 +688,23 @@ export default [ **后端菜单数据格式**: -菜单权限节点需要遵循以下规范: +菜单权限节点数据结构如下: + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | number | 权限ID | +| title | string | 权限标题(用于菜单显示) | +| name | string | 权限编码(唯一标识) | +| type | string | 权限类型:menu(菜单)、api(接口)、button(按钮)、url(链接) | +| parent_id | number | 父级ID,顶级菜单为 0 | +| path | string | 路由路径(如 `/system/users`) | +| component | string | 前端组件路径(如 `system/users/index`) | +| meta | object | 元数据(包含 icon、hidden、keepAlive 等) | +| sort | number | 排序 | +| status | number | 状态:1启用 0禁用 | +| children | array | 子权限列表(树形结构) | + +**菜单节点规范**: 1. **顶级菜单**(parent_id=0)不需要 component 值 - 顶级菜单作为分组容器,不需要指定组件路径 @@ -260,47 +721,77 @@ export default [ - 前端会将菜单数据转换为路由,所有页面路由都会挂载到 Layout 布局下 - 不需要在前端维护嵌套的路由结构 +**数据示例**: + ```javascript // 示例:顶级菜单(无 component) { - name: '系统管理', - code: 'system', + id: 1, + title: '系统管理', + name: 'system', type: 'menu', parent_id: 0, - route: '/system', + path: '/system', component: null, // 顶级菜单不需要 component meta: { icon: 'Setting', - hidden: false + hidden: false, + hiddenBreadcrumb: false, + keepAlive: false }, - sort: 1 + sort: 1, + status: 1, + children: [] } // 示例:最后一级菜单(有 component) { - name: '用户管理', - code: 'system.users', + id: 2, + title: '用户管理', + name: 'system.users', type: 'menu', parent_id: 0, - route: '/system/users', + path: '/system/users', component: 'system/users/index', // 最后一级菜单需要 component meta: { icon: 'User', - hidden: false + hidden: false, + hiddenBreadcrumb: false, + keepAlive: true }, - sort: 1 + sort: 1, + status: 1, + children: [] } // 示例:按钮权限(无 component) { - name: '查看用户', - code: 'system.users.view', + id: 3, + title: '查看用户', + name: 'system.users.view', type: 'button', - parent_id: 0, - route: 'admin.users.index', + parent_id: 2, + path: null, component: null, // 非菜单类型不需要 component meta: null, - sort: 1 + sort: 1, + status: 1, + children: [] +} + +// 示例:API 权限 +{ + id: 4, + title: '获取用户列表', + name: 'system.users.list', + type: 'api', + parent_id: 0, + path: 'admin.users.index', + component: null, + meta: null, + sort: 1, + status: 1, + children: [] } ``` @@ -313,12 +804,12 @@ export default [ function transformMenusToRoutes(menus) { return menus.map(menu => { const route = { - path: menu.route, - name: menu.name || menu.code, + path: menu.path, + name: menu.name, meta: { - title: menu.name, + title: menu.title, icon: menu.meta?.icon, - hidden: menu.meta?.hidden, + hidden: menu.meta?.hidden || false, keepAlive: menu.meta?.keepAlive || false } } @@ -346,9 +837,12 @@ function loadComponent(componentPath) { **菜单拉平处理说明**: 由于前端将所有页面菜单拉平挂载在 Layout 下,因此: -- 后端菜单的 parent_id 主要用于构建菜单树的层级关系(侧边栏显示) +- 后端菜单的 `parent_id` 主要用于构建菜单树的层级关系(侧边栏显示) - 路由层面不需要维护嵌套结构,所有页面路由都在同一层级 -- component 值只需要在最后一级菜单(叶子节点)中设置 +- `component` 值只需要在最后一级菜单(叶子节点)中设置 +- 路由 `path` 使用后端返回的 `path` 字段 +- 路由 `name` 使用后端返回的 `name` 字段(权限编码) +- 路由 `meta.title` 使用后端返回的 `title` 字段(权限标题) #### 路由守卫 @@ -387,7 +881,7 @@ router.beforeEach(async (to, from, next) => { }) ``` -### 5. 状态管理规范 +### 6. 状态管理规范 #### Pinia Store 定义 @@ -547,7 +1041,7 @@ const userStore = useUserStore() ``` -### 6. 表格开发规范 +### 7. 表格开发规范 #### 使用 useTable Hook @@ -594,7 +1088,7 @@ const searchParams = ref({ ``` -### 7. 表单开发规范 +### 8. 表单开发规范 #### scForm 组件使用 @@ -650,7 +1144,7 @@ const handleSubmit = async () => { ``` -### 8. 图标使用规范 +### 9. 图标使用规范 #### Ant Design Vue Icons @@ -680,7 +1174,7 @@ const handleSubmit = async () => { - `info-circle`: 信息 - `warning`: 警告 -### 9. 国际化 (i18n) 规范 +### 10. 国际化 (i18n) 规范 #### 使用 i18n @@ -711,7 +1205,7 @@ export default { } ``` -### 10. 文件上传规范 +### 11. 文件上传规范 #### scUpload 组件使用 @@ -732,7 +1226,7 @@ const imageUrl = ref('') ``` -### 11. 富文本编辑器规范 +### 12. 富文本编辑器规范 #### scEditor 组件使用 @@ -757,12 +1251,129 @@ const toolbarConfig = [ ``` -### 12. 样式规范 +### 13. 样式规范 #### 全局样式 在 `src/style.css` 中定义全局样式。 +#### 页面公共样式 + +页面布局的公共样式已提取到全局样式文件中,各页面可直接使用: + +**在 `src/assets/style/pages.scss` 中定义的公共类:** + +```scss +// 标准页面布局(垂直布局) +.pages-base-layout { + display: flex; + flex-direction: column; + height: 100%; + padding: 0; + + .tool-bar { + padding: 12px 16px; + background: #fff; + border-bottom: 1px solid #f0f0f0; + + .left-panel { + display: flex; + align-items: center; + flex: 1; + } + + .right-panel { + display: flex; + gap: 8px; + } + } + + .table-content { + flex: 1; + overflow: hidden; + padding: 16px; + background: #f5f5f5; + } +} + +// 侧边栏布局(左右分栏) +.pages-sidebar-layout { + display: flex; + flex-direction: row; + height: 100%; + padding: 0; + + .left-box { + width: 260px; + border-right: 1px solid #f0f0f0; + display: flex; + flex-direction: column; + background: #fff; + + .header { + padding: 12px 16px; + border-bottom: 1px solid #f0f0f0; + background: #fafafa; + } + + .body { + flex: 1; + overflow-y: auto; + padding: 16px; + } + } + + .right-box { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + + .tool-bar { + padding: 12px 16px; + background: #fff; + border-bottom: 1px solid #f0f0f0; + + .left-panel { + display: flex; + align-items: center; + flex: 1; + } + + .right-panel { + display: flex; + gap: 8px; + } + } + + .table-content { + flex: 1; + overflow: hidden; + padding: 16px; + background: #f5f5f5; + } + } +} +``` + +**使用示例:** + +```vue + + + + + +``` + #### 组件样式 使用 `scoped` 避免样式污染: @@ -784,7 +1395,7 @@ const toolbarConfig = [ - 使用 BEM 命名法 - 类名使用 kebab-case -### 13. 工具函数使用 +### 14. 工具函数使用 #### request.js (HTTP 请求) @@ -816,7 +1427,7 @@ formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss') deepClone(originalObject) ``` -### 14. 开发流程 +### 15. 开发流程 #### 登录流程 @@ -875,7 +1486,7 @@ const handleLogin = async () => { 3. 添加必要的 Props 和 Emits 4. 编写组件文档 -### 15. 常用命令 +### 16. 常用命令 ```bash # 安装依赖 @@ -897,7 +1508,7 @@ npm run format npm run lint ``` -### 16. 注意事项 +### 17. 注意事项 1. **禁止重复引入图标**: Ant Design Vue 图标已全局引入,直接使用即可 2. **使用组合式 API**: 新代码统一使用 `