# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ### 第一部分:核心编程原则 (Guiding Principles) 这是我们合作的顶层思想,指导所有具体的行为。 可读性优先 (Readability First):始终牢记“代码是写给人看的,只是恰好机器可以执行”。清晰度高于一切。 DRY (Don't Repeat Yourself):绝不复制代码片段。通过抽象(如函数、类、模块)来封装和复用通用逻辑。 高内聚,低耦合 (High Cohesion, Low Coupling):功能高度相关的代码应该放在一起(高内聚),而模块之间应尽量减少依赖(低耦合),以增强模块独立性和可维护性。 ### 第二部分:具体执行指令 (Actionable Instructions) 这是 Claude 在日常工作中需要严格遵守的具体操作指南。 沟通与语言规范 默认语言:请默认使用简体中文进行所有交流、解释和思考过程的陈述。 代码与术语:所有代码实体(变量名、函数名、类名等)及技术术语(如库名、框架名、设计模式等)必须保持英文原文。 注释规范:代码注释应使用中文。 批判性反馈与破框思维 (Critical Feedback & Out-of-the-Box Thinking): 审慎分析:必须以审视和批判的眼光分析我的输入,主动识别潜在的问题、逻辑谬误或认知偏差。 坦率直言:需要明确、直接地指出我思考中的盲点,并提供显著超越我当前思考框架的建议,以挑战我的预设。 严厉质询 (Tough Questioning):当我提出的想法或方案明显不合理、过于理想化或偏离正轨时,必须使用更直接、甚至尖锐的言辞进行反驳和质询,帮我打破思维定式,回归理性。 开发与调试策略 (Development & Debugging Strategy) 坚韧不拔的解决问题 (Tenacious Problem-Solving):当面对编译错误、逻辑不通或多次尝试失败时,绝不允许通过简化或伪造实现来“绕过”问题。 逐个击破 (Incremental Debugging):必须坚持对错误和问题进行逐一分析、定位和修复。 ### 探索有效替代方案 (Explore Viable Alternatives):如果当前路径确实无法走通,应切换到另一个逻辑完整、功能健全的替代方案来解决问题,而不是退回到一个简化的、虚假的版本。 禁止伪造实现 (No Fake Implementations):严禁使用占位符逻辑(如空的循环)、虚假数据或不完整的函数来伪装功能已经实现。所有交付的代码都必须是意图明确且具备真实逻辑的。 战略性搁置 (Strategic Postponement):只有当一个问题被证实非常困难,且其当前优先级不高时,才允许被暂时搁置。搁置时,必须以 TODO 形式在代码中或任务列表中明确标记,并清晰说明遇到的问题。在核心任务完成后,必须回过头来重新审视并解决这些被搁置的问题。 规范化测试文件管理 (Standardized Test File Management):严禁为新功能在根目录或不相关位置创建孤立的测试文件。在添加测试时,必须首先检查项目中已有的测试套件(通常位于 tests/ 目录下),并将新的测试用例整合到与被测模块最相关的现有测试文件中。只有当确实没有合适的宿主文件时,才允许在 tests/ 目录下创建符合项目命名规范的新测试文件。 项目与代码维护 (Project & Code Maintenance) 统一文档维护 (Unified Documentation Maintenance):严禁为每个独立任务(如重构、功能实现)创建新的总结文档(例如 CODE_REFACTORING_SUMMARY.md)。在任务完成后,必须优先检查项目中已有的相关文档(如 README.md、既有的设计文档等),并将新的总结、变更或补充内容直接整合到现有文档中,维护其完整性和时效性。 及时清理 (Timely Cleanup):在完成开发任务时,如果发现任何已无用(过时)的代码、文件或注释,应主动提出清理建议。 ## 项目概述 Coi Admin 是一个基于 Vue3、Vite5、TypeScript 和 Naive UI 的简洁后台管理模板,实现了完整的认证、权限管理、路由管理等功能。 ## 常用命令 ### 开发环境 ```bash # 启动开发服务器 (端口 9980) pnpm dev # 不同环境启动 pnpm dev:test # 测试环境 pnpm dev:prod # 生产环境 ``` ### 构建项目 ```bash # 生产环境构建 pnpm build # 不同环境构建 pnpm build:dev # 开发环境 pnpm build:test # 测试环境 ``` ### 代码检查 ```bash # 运行 ESLint 检查和类型检查 pnpm lint # 自动修复代码问题 pnpm lint:fix # 检查 ESLint 配置 pnpm lint:check ``` ### 其他工具 ```bash # 预览构建结果 (端口 9981) pnpm preview # 查看打包体积分析 pnpm sizecheck ``` ## 项目架构 ### 核心技术栈 - **Vue 3.5.16** + **Composition API** - **Vite 6.3.5** 构建工具 - **TypeScript 5.8.3** 类型安全 - **Naive UI 2.41.1** 组件库 - **Pinia 3.0.3** 状态管理 - **Vue Router 4.5.1** 路由管理 - **UnoCSS 66.2.0** 原子化CSS - **Alova 3.3.2** HTTP客户端 ### 目录结构要点 ``` src/ ├── store/ # Pinia状态管理 │ ├── auth.ts # 认证状态(登录、用户信息) │ ├── router/ # 路由状态和菜单管理 │ ├── tab.ts # 标签页状态 │ └── app/ # 应用全局状态 ├── router/ # 路由配置 │ ├── index.ts # 路由实例 │ ├── guard.ts # 路由守卫 │ ├── routes.inner.ts # 内置路由(登录、错误页等) │ └── routes.static.ts # 静态路由配置 ├── views/ # 页面组件 ├── layouts/ # 布局组件 ├── components/ # 通用组件 ├── service/ # API服务层 │ ├── api/ # 接口定义 │ └── http/ # HTTP配置 ├── hooks/ # 组合式函数 ├── utils/ # 工具函数 ├── typings/ # 类型定义 └── constants/ # 常量定义 ``` ## 核心系统架构 ### 1. 认证系统 - 基于JWT Token的认证机制 - 支持双Token(AccessToken + RefreshToken) - 自动Token刷新和过期处理 - 本地存储管理(localStorage) **关键文件**: - `src/store/auth.ts` - 认证状态管理 - `src/views/login/` - 登录页面组件 - `src/service/api/login.ts` - 登录API接口 ### 2. 权限系统 - 基于角色的访问控制(RBAC) - 多层权限验证:路由级、组件级、API级 - 权限指令 `v-permission` 和组合函数 `usePermission` - 支持super角色绕过所有权限检查 **关键文件**: - `src/hooks/usePermission.ts` - 权限验证组合函数 - `src/directives/permission.ts` - 权限指令 ### 3. 路由系统 - 支持静态路由和动态路由 - 路由守卫实现权限验证 - 自动菜单生成和路由缓存 - 多种布局模式支持 **关键文件**: - `src/router/guard.ts` - 路由守卫逻辑 - `src/store/router/` - 路由状态管理 - `src/store/router/helper.ts` - 路由处理工具函数 ### 4. 状态管理 - 使用Pinia进行状态管理 - 支持状态持久化 - 模块化状态设计 **状态模块**: - `authStore` - 用户认证状态 - `routeStore` - 路由和菜单状态 - `tabStore` - 标签页状态 - `appStore` - 应用全局状态 ## 重要配置文件 ### 环境配置 - 支持多环境配置:dev、test、prod - 环境变量通过 `.env.*` 文件管理 - 服务配置通过 `service.config.ts` 统一管理 ### 路由配置 - 通过 `VITE_ROUTE_LOAD_MODE` 控制路由加载模式 - 静态路由配置在 `src/router/routes.static.ts` - 动态路由通过API从后端获取 ### 权限配置 - 角色类型:super、admin、user、editor - 权限验证支持单角色和多角色 - 默认无权限要求时直接通过 ## 📝 命名规范(强制要求) **1. 接口函数命名** - 查询列表:`getList`, `get列表名List` - 新增:`add项名`, `create项名` - 修改:`update项名`, `edit项名` - 删除:`delete项名`, `remove项名` - 详情:`get项名ById`, `get项名Detail` **2. 类型定义命名** - 请求参数:`项名Bo` (Business Object) - 响应数据:`项名Vo` (View Object) - 查询参数:`项名QueryBo` - 分页结果:`Page项名Vo` **3. 枚举命名** - 全大写,下划线分隔:`USER_LIST`, `ADD_USER`, `UPDATE_USER` ## ⚠️ 严格禁止事项 **1. 消息提示** ```typescript // ❌ 严禁使用Element Plus原生消息 // ✅ 必须使用项目封装的消息函数 import { coiMsgError, coiMsgSuccess } from '@/utils/coi.ts' ElMessage.success('操作成功') this.$message.error('操作失败') coiMsgSuccess('操作成功') coiMsgError('操作失败') ``` **2. 类型定义** ```typescript // ❌ 严禁使用any类型 const response: any = await getList() // ✅ 必须使用完整的类型定义 const response: Result = await getList() ``` **3. 数据访问** ```typescript // ❌ 错误的数据访问 const data = response // ✅ 正确的数据访问 const data = response.data ``` ### 消息提示规范 **强制使用 coi.ts 封装的消息提示方法**,严禁直接使用 Element Plus 的消息提示: - **消息提示**:使用 `coiMsg`、`coiMsgSuccess`、`coiMsgError`、`coiMsgWarning`、`coiMsgInfo` - **通知提示**:使用 `coiNotice`、`coiNoticeSuccess`、`coiNoticeError`、`coiNoticeWarning`、`coiNoticeInfo` - **确认对话框**:使用 `coiMsgBox`、`coiMsgBoxHtml`、`coiMsgBoxAlert` - **输入对话框**:使用 `coiMsgBoxPrompt` ```typescript // 正确示例 import { coiMsgBox, coiMsgError, coiMsgSuccess } from '@/utils/coi' // 成功提示 coiMsgSuccess('操作成功') // 错误提示 coiMsgError('操作失败') // 确认对话框 coiMsgBox('确定要删除吗?', '删除确认').then(() => { // 确认操作 }).catch(() => { // 取消操作 }) ``` ## 📝 图标使用规范(强制要求) **项目中的图标使用规范,所有按钮和操作界面必须严格遵守** ### 核心原则 1. **所有按钮必须配备图标** - 提升用户体验和界面美观度 2. **图标必须语义化** - 图标含义要与按钮功能高度匹配 3. **统一的图标库** - 统一使用 `icon-park-outline` 图标库 ### 图标添加方式 **✅ 正确方式:直接在模板中使用图标组件** ```vue ``` **❌ 错误方式:字符串传递或复杂处理** ```vue ``` ### 常用图标语义映射 | 操作类型 | 推荐图标 | 示例场景 | |---------|---------|---------| | 新增/添加 | `icon-park-outline:plus` | 新增用户、添加数据 | | 编辑/修改 | `icon-park-outline:edit` | 编辑信息、修改配置 | | 删除 | `icon-park-outline:delete` | 删除记录、移除项目 | | 搜索 | `icon-park-outline:search` | 搜索按钮、查询操作 | | 刷新/重置 | `icon-park-outline:refresh` | 重置表单、刷新数据 | | 保存 | `icon-park-outline:check` | 保存设置、确认操作 | | 取消 | `icon-park-outline:close` | 取消操作、关闭弹框 | | 导出 | `icon-park-outline:download` | 导出数据、下载文件 | | 导入 | `icon-park-outline:upload` | 导入数据、上传文件 | | 设置 | `icon-park-outline:setting` | 系统设置、配置管理 | | 查看 | `icon-park-outline:preview-open` | 查看详情、预览内容 | | 复制 | `icon-park-outline:copy` | 复制内容、克隆数据 | ### 图标使用要求 **1. 必须添加图标的场景** - ✅ 所有操作按钮(新增、编辑、删除、保存等) - ✅ 搜索和重置按钮 - ✅ 导入导出按钮 - ✅ 空状态组件的操作按钮 - ✅ 表单提交和取消按钮 **2. 按钮样式规范** - ✅ 表格列表页面的操作按钮:使用标准方形按钮,不使用圆角(`round`)属性 - ✅ 按钮格式:图标 + 文字的组合形式 - ✅ 参考用户管理页面的按钮样式标准 **3. 图标尺寸规范** - 默认按钮:无需指定尺寸 - 大按钮:可根据需要调整 - 小按钮:保持图标清晰可见 **4. 图标样式要求** ```html ``` ### 严格禁止行为 - ❌ 按钮不添加图标 - ❌ 使用字符串方式传递图标 - ❌ 在JavaScript中动态处理图标组件 - ❌ 使用其他图标库(除非特殊需求) - ❌ 图标与功能语义不匹配 - ❌ 在表格列表页面使用圆角按钮(`round` 属性) ### 示例:完整的页面按钮实现 ```vue ``` **遵循此规范可确保项目界面的一致性和专业性!** ### 🚀 render函数中图标渲染规范(强制要求) **在DataTable等组件的render函数中使用图标时,必须遵循以下规范** #### 问题背景 在render函数中,不能使用模板语法 ``,必须使用正确的组件引用方式。 #### 正确的render函数图标使用方式 **✅ 步骤1:导入具体的图标组件** ```typescript // 从 ~icons 路径导入具体图标组件 import IconParkOutlineEdit from '~icons/icon-park-outline/edit' import IconParkOutlineDelete from '~icons/icon-park-outline/delete' import IconParkOutlineRefresh from '~icons/icon-park-outline/refresh' import IconParkOutlineSetting from '~icons/icon-park-outline/setting' ``` **✅ 步骤2:在render函数中使用组件引用** ```typescript // 表格列定义中的正确用法 const columns: DataTableColumns = [ { title: '操作', key: 'actions', render: (row) => { const buttons = [] // 编辑按钮 - 正确方式 buttons.push(h(NButton, { type: 'primary', size: 'small', onClick: () => handleEdit(row), }, { icon: () => h(NIcon, { size: 14 }, { default: () => h(IconParkOutlineEdit) }), default: () => '编辑', })) // 删除按钮 - 正确方式 buttons.push(h(NButton, { type: 'error', size: 'small', onClick: () => handleDelete(row), }, { icon: () => h(NIcon, { size: 14 }, { default: () => h(IconParkOutlineDelete) }), default: () => '删除', })) return h('div', { class: 'flex gap-2' }, buttons) } } ] ``` **❌ 错误方式:使用字符串引用** ```typescript // 这种方式在render函数中无效 icon: () => h(NIcon, {}, { default: () => h('icon-park-outline:edit') }) // 这种方式也无效 icon: () => h(NIcon, {}, { default: () => h('IconParkOutlineEdit') }) ``` #### 常用图标的正确导入方式 ```typescript // 操作类图标 import IconParkOutlineEdit from '~icons/icon-park-outline/edit' // 编辑 import IconParkOutlineDelete from '~icons/icon-park-outline/delete' // 删除 import IconParkOutlineRefresh from '~icons/icon-park-outline/refresh' // 刷新/重置 import IconParkOutlineSetting from '~icons/icon-park-outline/setting' // 设置/分配 // 功能类图标 import IconParkOutlinePlus from '~icons/icon-park-outline/plus' // 新增 import IconParkOutlineSearch from '~icons/icon-park-outline/search' // 搜索 import IconParkOutlineDownload from '~icons/icon-park-outline/download' // 下载/导出 import IconParkOutlineUpload from '~icons/icon-park-outline/upload' // 上传/导入 import IconParkOutlinePreviewOpen from '~icons/icon-park-outline/preview-open' // 查看 ``` #### 完整示例:表格操作列实现 ```typescript import { h } from 'vue' import { NButton, NIcon, NPopconfirm } from 'naive-ui' import IconParkOutlineEdit from '~icons/icon-park-outline/edit' import IconParkOutlineDelete from '~icons/icon-park-outline/delete' import IconParkOutlineSetting from '~icons/icon-park-outline/setting' const columns: DataTableColumns = [ { title: '操作', key: 'actions', width: 280, align: 'center', fixed: 'right', render: (row) => { const buttons = [] // 编辑按钮 if (hasPermission('edit')) { buttons.push(h(NButton, { type: 'primary', size: 'small', onClick: () => handleEdit(row), }, { icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h(IconParkOutlineEdit) }), default: () => '编辑', })) } // 删除按钮(带确认) if (hasPermission('delete')) { buttons.push(h(NPopconfirm, { onPositiveClick: () => handleDelete(row.id), negativeText: '取消', positiveText: '确定', }, { default: () => '确定删除此项吗?', trigger: () => h(NButton, { type: 'error', size: 'small', }, { icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h(IconParkOutlineDelete) }), default: () => '删除', }), })) } // 设置按钮 if (hasPermission('setting')) { buttons.push(h(NButton, { type: 'warning', size: 'small', onClick: () => handleSetting(row), }, { icon: () => h(NIcon, { size: 14, style: 'transform: translateY(-1px)' }, { default: () => h(IconParkOutlineSetting) }), default: () => '设置', })) } return h('div', { class: 'flex items-center justify-center gap-2' }, buttons) }, }, ] ``` #### 核心要点总结 1. **导入方式**:使用 `~icons/icon-park-outline/图标名` 导入具体组件 2. **组件引用**:在render函数中使用 `h(IconComponent)` 而非字符串 3. **命名规范**:图标组件名采用 `IconParkOutline + 图标名(首字母大写)` 格式 4. **样式调整**:可通过 `style` 属性微调图标位置和样式 5. **尺寸设置**:通过 `NIcon` 的 `size` 属性控制图标大小 **遵循此规范确保render函数中的图标能正确显示!** ## 开发注意事项 ### 添加新页面 1. 在 `src/views/` 创建页面组件 2. 在 `src/router/routes.static.ts` 添加路由配置 3. 配置权限要求(roles字段) ### 添加新API 1. 在 `src/service/api/` 定义接口 2. 使用项目封装的alova实例 3. 遵循统一的响应处理格式 ## 📁 API文件组织规范(强制要求) **API文件必须按功能模块组织,严格按模块导入,严禁聚合导出或混合不同业务模块的API** ### 文件结构规范 ``` src/service/api/ ├── auth/ # 认证相关API │ └── index.ts # 登录、注册、验证码等认证API ├── system/ # 系统管理模块 │ ├── user/index.ts # 用户管理API │ ├── role/index.ts # 角色管理API │ ├── menu/index.ts # 菜单管理API │ └── ... └── ... ``` ### API模块创建规则 1. **模块化原则**: 每个业务功能模块必须创建独立的目录和文件 2. **统一导出**: 每个模块目录必须有 `index.ts` 文件导出所有API 3. **直接导入**: 必须从具体的模块路径导入API,禁止聚合导出 4. **明确导入**: 导入路径必须明确指向具体的功能模块 ### 示例:正确的API组织和导入方式 ```typescript // src/service/api/auth/index.ts // 页面中的正确导入方式 import { fetchCaptchaPng, fetchLogin, fetchLogout } from '@/service/api/auth' import { addUser, getUserList, updateUser } from '@/service/api/system/user' import { assignUserRole, getRoleList } from '@/service/api/system/role' import { fetchUserRoutes } from '@/service/api/system/menu' export function fetchLogin(data: LoginRequest) { /* ... */ } export function fetchLogout() { /* ... */ } export function fetchCaptchaPng() { /* ... */ } // src/service/api/system/user/index.ts export interface UserQueryBo { /* ... */ } export interface UserVo { /* ... */ } export function getUserList(params: UserQueryBo) { /* ... */ } export function addUser(data: UserVo) { /* ... */ } ``` ### 强制要求 - ✅ 每个API模块独立维护和导入 - ✅ 导入路径指向具体功能模块 - ✅ 按功能拆分API到不同模块目录 - ✅ 类型定义与API函数放在同一模块目录下 ### 严格禁止行为 - ❌ 创建 `system.ts` 等聚合导出文件 - ❌ 在单一文件中混合多个业务模块的API - ❌ 从聚合文件导入API (如 `from '@/service/api/system'`) - ❌ 创建功能不明确的API文件 - ❌ 在页面组件中重复定义类型,应从API模块导入 ## 📝 类型定义组织规范(强制要求) **类型定义必须与API模块对应,按功能模块组织,禁止在页面组件中重复定义类型** ### 类型文件组织原则 1. **就近原则**: 类型定义与使用它们的API函数在同一模块 2. **单一职责**: 每个types.ts文件只包含一个业务模块的类型 3. **统一导出**: API模块的index.ts必须重新导出types.ts中的类型 4. **禁止重复**: 页面组件不得重复定义已有类型 ### 正确的类型组织示例 ```typescript // src/service/api/system/user/types.ts // src/service/api/system/user/index.ts import type { UserQueryBo, UserSearchForm, UserVo } from './types' // 页面组件中的正确使用方式 import { getUserList } from '@/service/api/system/user' import type { UserSearchForm, UserVo } from '@/service/api/system/user' export interface UserVo { userId: number loginName: string userName: string // ...其他字段 } export interface UserQueryBo { pageNo?: number pageSize?: number loginName?: string // ...其他查询条件 } export interface UserSearchForm { loginName?: string userName?: string timeRange?: [number, number] | null // ...其他搜索字段 } // 重新导出类型供外部使用 export type { UserQueryBo, UserSearchForm, UserVo } from './types' // API函数定义 export function getUserList(params: UserQueryBo) { /* ... */ } // 使用统一类型,不重复定义 const tableData = ref([]) const searchForm = ref({}) ``` ### 类型命名规范 - **请求参数类型**: `实体名QueryBo`, `实体名CreateBo`, `实体名UpdateBo` - **响应数据类型**: `实体名Vo` - **分页结果类型**: `Page实体名Vo` - **表单类型**: `实体名SearchForm`, `实体名Form` ### 状态管理 1. 新增状态优先考虑使用现有store 2. 需要持久化的状态使用pinia-plugin-persist 3. 计算属性优先使用computed缓存 ### 组件开发 1. 优先使用Naive UI组件 2. 自定义组件放在 `src/components/` 下 3. 使用TypeScript定义组件Props和Emits ## 🔥 自定义弹框组件规范(强制要求) **在开发任何新页面或功能时,如果需要使用弹框/模态框,必须使用项目封装的 CoiDialog 组件,严禁使用 Naive UI 原生的 n-modal 组件。** ### CoiDialog 组件位置 - 组件文件:`src/components/common/CoiDialog.vue` - 这是项目专门封装的统一弹框组件 ### 使用方式 #### 1. 导入组件 ```typescript import CoiDialog from '@/components/common/CoiDialog.vue' ``` #### 2. 创建弹框引用 ```typescript // 为每个弹框创建独立的引用 const userDialogRef = ref() const editDialogRef = ref() const deleteDialogRef = ref() ``` #### 3. 模板中使用 ```html ``` #### 4. 控制弹框显示/隐藏 ```typescript // 显示弹框 function handleAdd() { modalTitle.value = '新增用户' // 初始化表单数据 formData.value = { /* ... */ } userDialogRef.value?.coiOpen() } // 隐藏弹框 function handleCancel() { userDialogRef.value?.coiClose() } // 提交成功后关闭弹框 async function handleSubmit() { try { await submitForm() coiMsgSuccess('操作成功') userDialogRef.value?.coiClose() } catch (error) { coiMsgError('操作失败') } } ``` ### CoiDialog 核心属性 | 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | title | string | '提示' | 弹框标题 | | width | number | 500 | 弹框宽度(px) | | height | string | 'auto' | 弹框高度 | | confirm-text | string | '确定' | 确认按钮文字 | | cancel-text | string | '取消' | 取消按钮文字 | | show-confirm | boolean | true | 是否显示确认按钮 | | show-cancel | boolean | true | 是否显示取消按钮 | | close-on-esc | boolean | true | ESC键关闭弹框 | | mask-closable | boolean | false | 点击遮罩层关闭 | ### CoiDialog 核心事件 | 事件 | 说明 | |------|------| | @coi-confirm | 点击确认按钮时触发 | | @coi-cancel | 点击取消按钮时触发 | ### CoiDialog 核心方法 | 方法 | 说明 | |------|------| | coiOpen() | 显示弹框 | | coiClose() | 隐藏弹框 | ### 插槽支持 | 插槽 | 说明 | |------|------| | #header | 自定义弹框头部内容 | | #content | 弹框主体内容(必需) | ### 已完成的集成示例 - ✅ 角色管理页面:`src/views/system/role/index.vue` - ✅ 用户管理页面:`src/views/system/user/index.vue` ### 严格禁止行为 - ❌ 使用 `n-modal` 组件创建新弹框 - ❌ 使用 `v-model:show` 控制弹框显示/隐藏 - ❌ 忽略 CoiDialog 组件直接使用原生弹框 ### 为什么必须使用 CoiDialog? 1. **统一用户体验**:确保所有弹框具有一致的视觉风格和交互行为 2. **维护便利性**:统一的组件便于后续样式调整和功能增强 3. **团队协作**:统一的组件API减少开发人员的学习成本 4. **质量保证**:封装的组件经过充分测试,避免重复开发和潜在bug ## 📝 Vue3组件文件结构规范(强制要求) **所有Vue3组件必须严格按照以下顺序组织代码块** ### 组件代码块排布顺序 ``` ``` ### 强制要求 - ✅ 必须按照 `template` → `script` → `style` 的顺序排布 - ✅ 使用 ` ``` **遵循此规范确保页面具有统一的视觉效果和良好的主题适配性!** ## 🏷️ 标签组件主题色统一规范(强制要求) **所有新增的标签组件都必须严格遵循动态主题色统一原则,确保与用户选择的系统主题色保持一致** ### 标签组件实现原则 1. **强制使用 Naive UI 标准组件**: - ✅ 必须使用 `NTag` 组件,严禁自定义标签样式 - ✅ 利用 Naive UI 的主题系统自动适配主题色 - ✅ 确保标签在所有主题切换时都能正确显示 2. **正确的标签类型选择**: - ✅ 主要标签使用 `type: 'primary'`(跟随系统主题色) - ✅ 状态标签使用 `type: 'success' | 'warning' | 'error'` - ✅ 信息标签使用 `type: 'info'` - ❌ 严禁使用 `type: 'default'`(显示为白色背景,不符合主题) ### 正确的标签实现方式 **✅ 推荐实现(render函数中)**: ```typescript // 文件后缀标签 - 使用主题色 render: (row) => { return h(NTag, { type: 'primary', // 跟随系统主题色 size: 'small' }, { default: () => row.fileSuffix?.toUpperCase() }) } // 状态标签 - 使用语义化颜色 render: (row) => { const statusMap = { active: { type: 'success', text: '启用' }, inactive: { type: 'error', text: '禁用' }, pending: { type: 'warning', text: '待审核' } } const config = statusMap[row.status] return h(NTag, { type: config.type, size: 'small' }, { default: () => config.text }) } ``` **✅ 推荐实现(模板中)**: ```vue ``` ### 技术实现原理 **Naive UI 主题系统工作机制**: 1. `n-config-provider` 注入全局主题配置(`theme-overrides`) 2. 主题配置来自 `appStore.theme.common.primaryColor` 3. 用户选择主题色时,`setPrimaryColor()` 更新所有相关颜色变体 4. 所有 `type: 'primary'` 的标签自动继承新的主题色 5. 实现真正的动态主题色统一 ### 严格禁止的做法 - ❌ 自定义标签样式:`class="custom-tag-style"` - ❌ 固定颜色值:`style="background-color: #18A058"` - ❌ 使用默认类型:`type: 'default'` - ❌ CSS变量覆盖:`style="--n-color: var(--primary-color)"` - ❌ 字符串返回:`return row.status`(应该返回标签组件) ### 验证标准 在添加新标签时,必须通过以下检查: - [ ] 标签在不同主题色下都能正确显示 - [ ] 标签颜色与系统主题色保持一致 - [ ] 标签在主题切换时能实时更新 - [ ] 代码使用 Naive UI 标准组件和类型 ### 参考实现 项目中的标准实现参考: - ✅ 角色管理页面:角色编码标签 `h(NTag, { type: 'primary', size: 'small' })` - ✅ 文件管理页面:文件后缀标签 `h(NTag, { type: 'primary', size: 'small' })` - ✅ 用户管理页面:用户状态标签 `h(NTag, { type: 'success/error', size: 'small' })` **遵循此规范确保所有标签组件都能与用户的主题色选择保持完美统一!** 🎨 ## 📝 表单验证规范(强制要求) **所有包含表单提交的页面都必须实现统一的表单验证和错误处理机制** ### 表单验证处理原则 1. **分离验证逻辑**:将表单验证和API调用分开处理 2. **统一错误提示**:使用项目封装的消息提示函数 3. **用户友好提示**:验证失败时给予明确的指导信息 4. **一致性体验**:所有表单页面使用相同的验证处理模式 ### 必须实现的验证流程 **✅ 正确的表单提交函数实现** ```typescript // 提交表单 async function handleSubmit() { if (!formRef.value) return try { // 先进行表单验证 await formRef.value.validate() } catch { // 表单验证失败,提示用户检查填写内容 coiMsgWarning('验证失败,请检查填写内容') return } // 表单验证通过,执行API调用 try { const submitData = { ...formData.value } const { isSuccess } = isEdit.value ? await updateData(submitData) : await addData(submitData) if (isSuccess) { coiMsgSuccess(isEdit.value ? '修改成功' : '新增成功') dialogRef.value?.coiClose() await refreshData() } else { coiMsgError(isEdit.value ? '修改失败,请稍后重试' : '新增失败,请稍后重试') } } catch (error) { if (error instanceof Error) { coiMsgError(error.message || (isEdit.value ? '修改失败,请检查网络连接' : '新增失败,请检查网络连接')) } else { coiMsgError(isEdit.value ? '修改失败,请检查网络连接' : '新增失败,请检查网络连接') } } } ``` ### 必要的导入依赖 ```typescript import { coiMsgError, coiMsgSuccess, coiMsgWarning } from '@/utils/coi' ``` ### 适用场景 - ✅ 新增/编辑表单页面 - ✅ 用户注册/登录表单 - ✅ 设置/配置表单 - ✅ 搜索表单(如需验证) - ✅ 任何包含用户输入和提交的表单 ### 验证消息规范 - **验证失败**: `coiMsgWarning('验证失败,请检查填写内容')` - **操作成功**: `coiMsgSuccess('操作成功')` 或具体操作说明 - **操作失败**: `coiMsgError('操作失败,请检查网络连接')` 或具体错误信息 ### 已实现的参考示例 - ✅ 角色管理页面:`src/views/system/role/index.vue:1121-1153` - ✅ 菜单管理页面:`src/views/system/menu/index.vue:1360-1407` ### 严格禁止行为 - ❌ 直接提交表单不进行验证 - ❌ 验证失败时不给出提示信息 - ❌ 使用原生alert()或console.log()进行错误提示 - ❌ 验证逻辑与API调用耦合在同一个try-catch中 - ❌ 忽略表单验证的catch块 ### 实现检查清单 开发表单页面时,必须确保: - [ ] 已导入 `coiMsgWarning` 函数 - [ ] 表单验证和API调用分离处理 - [ ] 验证失败时显示 `coiMsgWarning` 提示 - [ ] API调用成功时显示 `coiMsgSuccess` 提示 - [ ] API调用失败时显示 `coiMsgError` 提示 - [ ] 错误信息根据操作类型(新增/修改)进行区分 **遵循此规范确保所有表单页面具有一致的用户体验和错误处理机制!** ## 🎯 按钮样式统一规范(强制要求) **所有新创建的表格列表页面必须严格遵循标准按钮样式规范,确保界面的一致性和专业性** ### 按钮样式核心要求 1. **标准方形按钮**: - ✅ 所有表格列表页面的操作按钮必须使用标准方形样式 - ✅ 严禁使用圆角按钮(`round` 属性) - ✅ 参考用户管理页面的按钮样式标准 2. **图标 + 文字组合**: - ✅ 按钮必须采用图标 + 文字的组合形式 - ✅ 图标位于文字左侧,提升用户体验 - ✅ 使用语义化的图标选择 ### 正确的按钮实现示例 ```vue ``` ### 错误示例(严格禁止) ```vue ``` ### 参考标准页面 - ✅ 用户管理页面:`src/views/system/user/index.vue` - ✅ 角色管理页面:`src/views/system/role/index.vue` - ✅ 菜单管理页面:`src/views/system/menu/index.vue` ### 强制要求检查清单 开发新的表格列表页面时,必须确保: - [ ] 所有操作按钮都使用标准方形样式(不使用 `round` 属性) - [ ] 所有按钮都采用图标 + 文字的组合形式 - [ ] 按钮样式与现有页面保持一致 - [ ] 图标选择符合语义化要求 - [ ] 按钮类型和颜色符合项目主题规范 ### 严格禁止行为 - ❌ 使用圆角按钮(`round` 属性) - ❌ 按钮只有图标没有文字 - ❌ 按钮只有文字没有图标 - ❌ 使用与项目标准不一致的按钮样式 - ❌ 忽略参考页面的样式标准 **遵循此规范确保所有表格列表页面具有统一的按钮样式和用户体验!** ## 📝 表单布局紧凑设计规范(强制要求) **所有新创建的表单页面和弹框表单都必须严格遵循紧凑布局设计规范,确保界面的一致性和空间利用率** ### 表单紧凑设计核心原则 1. **统一紧凑样式类**: - ✅ 所有表单必须使用 `class="compact-form"` 样式类 - ✅ 确保在所有弹框和表单页面中保持一致的视觉密度 - ✅ 参考菜单管理、用户管理、角色管理页面的标准样式 2. **标准化间距设置**: - ✅ 表单项间距:`class="mb-2"`(8px 底部间距) - ✅ 网格列间距:`:x-gap="10"`(10px 列间距) - ✅ 标签宽度:`label-width="90px"`(90px 标签宽度) - ✅ 容器内边距:`class="px-3 py-2"`(标准内边距) 3. **弹框尺寸标准**: - ✅ 表单弹框宽度:`:width="800"`(800px 统一宽度) - ✅ 弹框高度:`height="auto"`(自适应高度) ### 正确的表单布局实现 **✅ 标准CoiDialog弹框表单结构**: ```vue ``` ### 必需的紧凑表单CSS样式 **✅ 每个包含表单的页面都必须包含以下CSS样式**: ```css /* 紧凑表单样式 */ .compact-form :deep(.n-form-item) { margin-bottom: 8px !important; } .compact-form :deep(.n-form-item .n-form-item-feedback-wrapper) { min-height: 0 !important; padding-top: 2px !important; } .compact-form :deep(.n-form-item .n-form-item-label) { padding-bottom: 2px !important; } .compact-form :deep(.n-input), .compact-form :deep(.n-input-number), .compact-form :deep(.n-select), .compact-form :deep(.n-cascader), .compact-form :deep(.n-radio-group) { font-size: 14px !important; } .compact-form :deep(.n-input .n-input__input-el), .compact-form :deep(.n-input-number .n-input__input-el) { padding: 2px 1px !important; min-height: 32px !important; } .compact-form :deep(.n-select .n-base-selection) { min-height: 32px !important; padding: 2px 1px !important; } .compact-form :deep(.n-select .n-base-selection .n-base-selection-label) { padding: 0 6px !important; min-height: 30px !important; line-height: 30px !important; } .compact-form :deep(.n-cascader .n-cascader-trigger) { min-height: 32px !important; padding: 2px 1px !important; } ``` ### 表单布局配置标准 | 配置项 | 标准值 | 说明 | |--------|--------|------| | 弹框宽度 | `:width="800"` | 统一800px宽度 | | 弹框高度 | `height="auto"` | 自适应内容高度 | | 表单样式类 | `class="compact-form"` | 紧凑表单样式类 | | 标签宽度 | `label-width="90px"` | 统一90px标签宽度 | | 标签位置 | `label-placement="left"` | 标签左对齐 | | 必填标记 | `require-mark-placement="right-hanging"` | 必填标记右悬挂 | | 网格列数 | `:cols="2"` | 双列布局 | | 列间距 | `:x-gap="10"` | 10px列间距 | | 表单项间距 | `class="mb-2"` | 8px底部间距 | | 容器内边距 | `class="px-3 py-2"` | 标准内边距 | ### 已实现的标准参考页面 - ✅ 菜单管理页面:`src/views/system/menu/index.vue` - ✅ 用户管理页面:`src/views/system/user/index.vue` - ✅ 角色管理页面:`src/views/system/role/index.vue` ### 强制要求检查清单 开发新的表单页面时,必须确保: - [ ] 使用 `class="compact-form"` 样式类 - [ ] 所有表单项都有 `class="mb-2"` 间距类 - [ ] 网格布局使用 `:x-gap="10"` 列间距 - [ ] 弹框宽度设置为 `:width="800"` - [ ] 标签宽度设置为 `label-width="90px"` - [ ] 包含完整的紧凑表单CSS样式 - [ ] 容器使用 `class="px-3 py-2"` 内边距 ### 严格禁止行为 - ❌ 使用默认表单样式(不添加 `compact-form` 类) - ❌ 表单项间距过大或不一致 - ❌ 弹框宽度不统一(非800px) - ❌ 标签宽度不一致(非90px) - ❌ 缺少必需的紧凑表单CSS样式 - ❌ 使用过大的列间距(超过10px) - ❌ 忽略参考页面的布局标准 ### 紧凑表单设计优势 1. **视觉一致性**:所有表单页面具有统一的外观和感觉 2. **空间利用率**:紧凑的布局提高了屏幕空间的利用效率 3. **用户体验**:减少了视觉噪音,提升了表单填写的效率 4. **响应式友好**:在不同屏幕尺寸下都有良好的显示效果 5. **维护便利性**:统一的样式类和配置便于后续维护和扩展 ### 示例:完整的表单页面实现 ```vue ``` **遵循此规范确保所有表单页面具有统一的紧凑布局和优秀的用户体验!** ## 文档资源 项目包含完整的文档系统: - `doc/auth-system.md` - 认证系统文档 - `doc/permission-system.md` - 权限系统文档 - `doc/router-system.md` - 路由系统文档 - `doc/architecture.md` - 整体架构文档 ## API接口 项目使用ApiFox进行接口Mock,在线文档:https://nova-admin.apifox.cn ## 开发环境要求 - Node.js 21.x - pnpm 10.x - 现代浏览器支持ES6+