- 在 CLAUDE.md 中新增自定义弹框组件使用规范 - 明确禁止使用原生 n-modal,强制使用 NovaDialog - 提供完整的使用指南和代码示例 - 详细说明组件属性、事件、方法和插槽 - 列出已完成集成的页面作为参考 - 修复文档中 Vue 模板语法引起的 ESLint 错误 - 确保后续开发严格遵循统一的弹框使用规范
19 KiB
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):在完成开发任务时,如果发现任何已无用(过时)的代码、文件或注释,应主动提出清理建议。
项目概述
Nova Admin 是一个基于 Vue3、Vite5、TypeScript 和 Naive UI 的简洁后台管理模板,实现了完整的认证、权限管理、路由管理等功能。
常用命令
开发环境
# 启动开发服务器 (端口 9980)
pnpm dev
# 不同环境启动
pnpm dev:test # 测试环境
pnpm dev:prod # 生产环境
构建项目
# 生产环境构建
pnpm build
# 不同环境构建
pnpm build:dev # 开发环境
pnpm build:test # 测试环境
代码检查
# 运行 ESLint 检查和类型检查
pnpm lint
# 自动修复代码问题
pnpm lint:fix
# 检查 ESLint 配置
pnpm lint:check
其他工具
# 预览构建结果 (端口 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. 消息提示
// ❌ 严禁使用Element Plus原生消息
// ✅ 必须使用项目封装的消息函数
import { coiMsgError, coiMsgSuccess } from '@/utils/coi.ts'
ElMessage.success('操作成功')
this.$message.error('操作失败')
coiMsgSuccess('操作成功')
coiMsgError('操作失败')
2. 类型定义
// ❌ 严禁使用any类型
const response: any = await getList()
// ✅ 必须使用完整的类型定义
const response: Result<ResponseVo[]> = await getList()
3. 数据访问
// ❌ 错误的数据访问
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
// 正确示例
import { coiMsgBox, coiMsgError, coiMsgSuccess } from '@/utils/coi'
// 成功提示
coiMsgSuccess('操作成功')
// 错误提示
coiMsgError('操作失败')
// 确认对话框
coiMsgBox('确定要删除吗?', '删除确认').then(() => {
// 确认操作
}).catch(() => {
// 取消操作
})
开发注意事项
添加新页面
- 在
src/views/创建页面组件 - 在
src/router/routes.static.ts添加路由配置 - 配置权限要求(roles字段)
添加新API
- 在
src/service/api/定义接口 - 使用项目封装的alova实例
- 遵循统一的响应处理格式
📁 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模块创建规则
- 模块化原则: 每个业务功能模块必须创建独立的目录和文件
- 统一导出: 每个模块目录必须有
index.ts文件导出所有API - 直接导入: 必须从具体的模块路径导入API,禁止聚合导出
- 明确导入: 导入路径必须明确指向具体的功能模块
示例:正确的API组织和导入方式
// 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模块对应,按功能模块组织,禁止在页面组件中重复定义类型
类型文件组织原则
- 就近原则: 类型定义与使用它们的API函数在同一模块
- 单一职责: 每个types.ts文件只包含一个业务模块的类型
- 统一导出: API模块的index.ts必须重新导出types.ts中的类型
- 禁止重复: 页面组件不得重复定义已有类型
正确的类型组织示例
// 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<UserVo[]>([])
const searchForm = ref<UserSearchForm>({})
类型命名规范
- 请求参数类型:
实体名QueryBo,实体名CreateBo,实体名UpdateBo - 响应数据类型:
实体名Vo - 分页结果类型:
Page实体名Vo - 表单类型:
实体名SearchForm,实体名Form
状态管理
- 新增状态优先考虑使用现有store
- 需要持久化的状态使用pinia-plugin-persist
- 计算属性优先使用computed缓存
组件开发
- 优先使用Naive UI组件
- 自定义组件放在
src/components/下 - 使用TypeScript定义组件Props和Emits
🔥 自定义弹框组件规范(强制要求)
在开发任何新页面或功能时,如果需要使用弹框/模态框,必须使用项目封装的 NovaDialog 组件,严禁使用 Naive UI 原生的 n-modal 组件。
NovaDialog 组件位置
- 组件文件:
src/components/common/NovaDialog.vue - 这是项目专门封装的统一弹框组件
使用方式
1. 导入组件
import NovaDialog from '@/components/common/NovaDialog.vue'
2. 创建弹框引用
// 为每个弹框创建独立的引用
const userDialogRef = ref()
const editDialogRef = ref()
const deleteDialogRef = ref()
3. 模板中使用
<template>
<!-- 用户表单弹框示例 -->
<NovaDialog
ref="userDialogRef"
:title="modalTitle"
:width="800"
height="auto"
confirm-text="确定"
cancel-text="取消"
@nova-confirm="handleSubmit"
@nova-cancel="handleCancel"
>
<template #content>
<div class="px-3 py-2">
<!-- 弹框内容 -->
<n-form ref="formRef" :model="formData">
<!-- 表单内容 -->
</n-form>
</div>
</template>
</NovaDialog>
<!-- 仅查看类弹框示例(无确认按钮) -->
<NovaDialog
ref="viewDialogRef"
title="查看详情"
:width="600"
height="auto"
cancel-text="关闭"
:show-confirm="false"
@nova-cancel="handleClose"
>
<template #content>
<div class="p-3">
<!-- 查看内容 -->
</div>
</template>
</NovaDialog>
</template>
4. 控制弹框显示/隐藏
// 显示弹框
function handleAdd() {
modalTitle.value = '新增用户'
// 初始化表单数据
formData.value = { /* ... */ }
userDialogRef.value?.novaOpen()
}
// 隐藏弹框
function handleCancel() {
userDialogRef.value?.novaClose()
}
// 提交成功后关闭弹框
async function handleSubmit() {
try {
await submitForm()
coiMsgSuccess('操作成功')
userDialogRef.value?.novaClose()
} catch (error) {
coiMsgError('操作失败')
}
}
NovaDialog 核心属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | string | '' | 弹框标题 |
| width | number | 500 | 弹框宽度(px) |
| height | string | 'auto' | 弹框高度 |
| confirm-text | string | '确定' | 确认按钮文字 |
| cancel-text | string | '取消' | 取消按钮文字 |
| show-confirm | boolean | true | 是否显示确认按钮 |
| show-cancel | boolean | true | 是否显示取消按钮 |
NovaDialog 核心事件
| 事件 | 说明 |
|---|---|
| @nova-confirm | 点击确认按钮时触发 |
| @nova-cancel | 点击取消按钮时触发 |
NovaDialog 核心方法
| 方法 | 说明 |
|---|---|
| novaOpen() | 显示弹框 |
| novaClose() | 隐藏弹框 |
插槽支持
| 插槽 | 说明 |
|---|---|
| #header | 自定义弹框头部内容 |
| #content | 弹框主体内容(必需) |
已完成的集成示例
- ✅ 角色管理页面:
src/views/system/role/index.vue - ✅ 用户管理页面:
src/views/system/user/index.vue
严格禁止行为
- ❌ 使用
n-modal组件创建新弹框 - ❌ 使用
v-model:show控制弹框显示/隐藏 - ❌ 忽略 NovaDialog 组件直接使用原生弹框
为什么必须使用 NovaDialog?
- 统一用户体验:确保所有弹框具有一致的视觉风格和交互行为
- 维护便利性:统一的组件便于后续样式调整和功能增强
- 团队协作:统一的组件API减少开发人员的学习成本
- 质量保证:封装的组件经过充分测试,避免重复开发和潜在bug
📝 Vue3组件文件结构规范(强制要求)
所有Vue3组件必须严格按照以下顺序组织代码块
组件代码块排布顺序
<script setup lang="ts">
// 脚本内容
</script>
<template>
<!-- 模板内容 -->
</template>
<style scoped>
/* 样式内容 */
</style>
强制要求
- ✅ 必须按照
template→script→style的顺序排布 - ✅ 使用
<script setup lang="ts">语法 - ✅ 样式块使用
scoped属性确保样式隔离 - ✅ 每个代码块之间保持一个空行间隔
严格禁止行为
- ❌ 任何其他顺序的代码块排布
- ❌ 使用
<script>而非<script setup> - ❌ 省略
lang="ts"属性 - ❌ 在全局组件中省略
scoped属性
文档资源
项目包含完整的文档系统:
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+