Files
admin-vben/docs/开发文档.md

563 lines
11 KiB
Markdown
Raw Normal View History

# 开发文档
## 开发环境搭建
### 环境要求
- **Node.js**: 18.0.0 或更高版本
- **pnpm**: 8.0.0 或更高版本
- **Git**: 2.0.0 或更高版本
### 安装步骤
1. **安装 Node.js**
```bash
# 下载并安装 Node.js 18+
# 验证安装
node --version
npm --version
```
2. **安装 pnpm**
```bash
# 使用 npm 安装 pnpm
npm install -g pnpm
# 验证安装
pnpm --version
```
3. **克隆项目**
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
cd vue-vben-admin
```
4. **安装依赖**
```bash
# 安装项目依赖
pnpm install
```
5. **启动开发服务器**
```bash
# 启动 Ant Design 版本
pnpm dev:antd
# 启动 Element Plus 版本
pnpm dev:ele
# 启动 Naive UI 版本
pnpm dev:naive
```
## 项目结构说明
### 目录结构详解
```
yudao-ui-admin-vben/
├── apps/ # 应用目录
│ ├── web-antd/ # Ant Design 版本
│ │ ├── src/ # 源代码
│ │ │ ├── api/ # API 接口
│ │ │ ├── components/ # 组件
│ │ │ ├── layouts/ # 布局
│ │ │ ├── router/ # 路由
│ │ │ ├── store/ # 状态管理
│ │ │ ├── utils/ # 工具函数
│ │ │ └── views/ # 页面视图
│ │ └── package.json # 应用配置
│ ├── web-ele/ # Element Plus 版本
│ ├── web-naive/ # Naive UI 版本
│ └── backend-mock/ # 后端模拟服务
├── packages/ # 共享包目录
│ ├── @core/ # 核心功能
│ ├── constants/ # 常量定义
│ ├── effects/ # 副作用管理
│ ├── icons/ # 图标库
│ ├── locales/ # 国际化
│ ├── stores/ # 状态管理
│ ├── styles/ # 样式文件
│ ├── types/ # 类型定义
│ └── utils/ # 工具函数
└── internal/ # 内部配置
├── lint-configs/ # 代码规范
├── tailwind-config/ # Tailwind 配置
├── tsconfig/ # TypeScript 配置
└── vite-config/ # Vite 配置
```
### 核心包说明
#### @core 包
- 基础组件封装
- 工具函数集合
- 类型定义扩展
#### stores 包
- 全局状态管理
- 用户信息存储
- 应用配置管理
#### utils 包
- 数据处理工具
- 日期时间工具
- 表单验证工具
## 开发规范
### 代码规范
#### 1. 命名规范
- **文件命名**: 使用 kebab-case (例如: user-info.vue)
- **组件命名**: 使用 PascalCase (例如: UserInfo)
- **变量命名**: 使用 camelCase (例如: userName)
- **常量命名**: 使用 UPPER_SNAKE_CASE (例如: API_BASE_URL)
#### 2. 组件规范
```typescript
// 组件结构示例
<script setup lang="ts">
// 导入
import { ref, computed } from 'vue'
import { useUserStore } from '@/stores/user'
// 类型定义
interface Props {
userId: number
userName: string
}
// Props 定义
const props = defineProps<Props>()
// 状态管理
const userStore = useUserStore()
const loading = ref(false)
// 计算属性
const fullName = computed(() => `${props.userName} (${props.userId})`)
// 方法
const handleSubmit = async () => {
loading.value = true
try {
await userStore.updateUser(props.userId, { name: props.userName })
} finally {
loading.value = false
}
}
</script>
<template>
<div class="user-info">
<h3>{{ fullName }}</h3>
<button :disabled="loading" @click="handleSubmit">
{{ loading ? '保存中...' : '保存' }}
</button>
</div>
</template>
<style scoped>
.user-info {
padding: 16px;
}
</style>
```
#### 3. API 调用规范
```typescript
// api/user.ts
import { request } from '@/utils/request'
export interface User {
id: number
name: string
email: string
}
export const userApi = {
// 获取用户列表
getUsers: (params: { page: number; size: number }) => {
return request.get<{ list: User[]; total: number }>('/api/users', { params })
},
// 创建用户
createUser: (data: Omit<User, 'id'>) => {
return request.post<User>('/api/users', data)
},
// 更新用户
updateUser: (id: number, data: Partial<User>) => {
return request.put<User>(`/api/users/${id}`, data)
},
// 删除用户
deleteUser: (id: number) => {
return request.delete(`/api/users/${id}`)
}
}
```
### 样式规范
#### 1. CSS 类命名
- 使用 BEM 命名规范
- 避免使用全局样式
- 优先使用 Tailwind CSS
```css
/* BEM 示例 */
.user-list {}
.user-list__item {}
.user-list__item--active {}
.user-list__item__avatar {}
```
#### 2. Tailwind CSS 使用
```vue
<template>
<div class="p-4 bg-white rounded-lg shadow-sm">
<h3 class="text-lg font-semibold text-gray-900 mb-4">用户信息</h3>
<div class="space-y-3">
<div class="flex items-center space-x-3">
<span class="text-sm text-gray-500 w-20">姓名:</span>
<span class="text-sm text-gray-900">{{ user.name }}</span>
</div>
</div>
</div>
</template>
```
## 功能开发指南
### 1. 新增页面
#### 步骤 1: 创建页面组件
```bash
# 在 apps/web-antd/src/views/ 下创建页面目录
mkdir -p apps/web-antd/src/views/user-management
```
#### 步骤 2: 创建页面组件
```vue
<!-- apps/web-antd/src/views/user-management/index.vue -->
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { userApi } from '@/api/user'
interface User {
id: number
name: string
email: string
}
const users = ref<User[]>([])
const loading = ref(false)
const loadUsers = async () => {
loading.value = true
try {
const response = await userApi.getUsers({ page: 1, size: 10 })
users.value = response.data.list
} finally {
loading.value = false
}
}
onMounted(() => {
loadUsers()
})
</script>
<template>
<div class="user-management">
<h1>用户管理</h1>
<div v-if="loading">加载中...</div>
<div v-else>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<style scoped>
.user-management {
padding: 20px;
}
</style>
```
#### 步骤 3: 配置路由
```typescript
// apps/web-antd/src/router/routes.ts
import type { RouteRecordRaw } from 'vue-router'
export const routes: RouteRecordRaw[] = [
// ... 其他路由
{
path: '/user-management',
name: 'UserManagement',
component: () => import('@/views/user-management/index.vue'),
meta: {
title: '用户管理',
requiresAuth: true
}
}
]
```
### 2. 新增组件
#### 创建可复用组件
```vue
<!-- apps/web-antd/src/components/UserAvatar.vue -->
<script setup lang="ts">
interface Props {
user: {
name: string
avatar?: string
}
size?: 'small' | 'medium' | 'large'
}
const props = withDefaults(defineProps<Props>(), {
size: 'medium'
})
const sizeMap = {
small: 'w-8 h-8',
medium: 'w-12 h-12',
large: 'w-16 h-16'
}
</script>
<template>
<div class="user-avatar flex items-center space-x-3">
<img
v-if="user.avatar"
:src="user.avatar"
:alt="user.name"
:class="['rounded-full', sizeMap[size]]"
/>
<div
v-else
:class="['bg-gray-200 rounded-full flex items-center justify-center', sizeMap[size]]"
>
<span class="text-gray-600 font-medium">{{ user.name.charAt(0) }}</span>
</div>
<span class="text-gray-900 font-medium">{{ user.name }}</span>
</div>
</template>
<style scoped>
.user-avatar {
display: inline-flex;
align-items: center;
}
</style>
```
## 开发计划
### 第一阶段:基础功能开发 (1-2周)
#### 任务清单
- [x] 项目环境搭建
- [x] 基础架构配置
- [x] 用户登录功能
- [x] 权限管理系统
- [x] 基础布局组件
#### 技术要点
- Vue3 Composition API 使用
- TypeScript 类型定义
- Pinia 状态管理
- Vue Router 路由配置
### 第二阶段:业务功能开发 (2-3周)
#### 任务清单
- [x] 用户管理模块
- [x] 角色管理模块
- [x] 菜单管理模块
- [x] 系统设置模块
- [x] 数据表格组件
#### 技术要点
- 表单验证处理
- 表格数据展示
- 分页查询优化
- 文件上传下载
### 第三阶段:优化完善 (1周)
#### 任务清单
- [x] 性能优化
- [x] 代码重构
- [x] 测试用例编写
- [x] 文档完善
#### 技术要点
- 代码分割优化
- 懒加载实现
- 单元测试覆盖
- 文档自动生成
## 常见问题解决
### 1. 依赖安装问题
**问题**: pnpm install 失败
**解决方案**:
```bash
# 清理缓存
pnpm store prune
# 重新安装
pnpm install --force
```
### 2. 类型检查错误
**问题**: TypeScript 类型错误
**解决方案**:
```bash
# 检查类型错误
pnpm type-check
# 自动修复
pnpm lint:fix
```
### 3. 构建失败
**问题**: 生产构建失败
**解决方案**:
```bash
# 清理构建缓存
pnpm clean
# 重新构建
pnpm build
```
## 测试指南
### 单元测试
```typescript
// __tests__/user.spec.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import UserInfo from '@/components/UserInfo.vue'
describe('UserInfo', () => {
it('renders user name correctly', () => {
const wrapper = mount(UserInfo, {
props: {
user: {
name: '张三',
email: 'zhangsan@example.com'
}
}
})
expect(wrapper.text()).toContain('张三')
})
})
```
### E2E 测试
```typescript
// __tests__/e2e/user.spec.ts
import { test, expect } from '@playwright/test'
test('user login flow', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="username"]', 'admin')
await page.fill('[data-testid="password"]', '123456')
await page.click('[data-testid="login-btn"]')
await expect(page).toHaveURL('/dashboard')
})
```
## 部署指南
### 开发环境部署
```bash
# 启动开发服务器
pnpm dev:antd
# 访问地址
http://localhost:3000
```
### 生产环境部署
```bash
# 构建生产版本
pnpm build:antd
# 部署到服务器
# 将 dist 目录上传到 Web 服务器
```
## 性能优化
### 构建优化
- 代码分割
- 树摇优化
- 压缩资源
- 缓存策略
### 运行时优化
- 虚拟滚动
- 图片懒加载
- 组件懒加载
- 防抖节流
## 安全指南
### 前端安全
- XSS 防护
- CSRF 防护
- 输入验证
- 权限控制
### 代码安全
- 敏感信息加密
- API 密钥保护
- 代码混淆
- 安全审计
## 维护指南
### 日常维护
- 定期更新依赖
- 监控系统性能
- 备份重要数据
- 安全漏洞修复
### 版本管理
- 使用 Git 版本控制
- 遵循语义化版本
- 定期发布版本
- 维护更新日志