374 lines
8.4 KiB
Markdown
374 lines
8.4 KiB
Markdown
# DESIGN - 前端 UI 项目架构设计
|
|
|
|
## 🏗️ 整体架构图
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "前端项目 (localhost:3000)"
|
|
A[Vue 3 App] --> B[Vue Router]
|
|
A --> C[Element Plus UI]
|
|
A --> D[Axios HTTP Client]
|
|
|
|
B --> E[Dashboard View]
|
|
B --> F[User Management View]
|
|
B --> G[Product Management View]
|
|
|
|
F --> H[User List Component]
|
|
F --> I[User Form Component]
|
|
|
|
G --> J[Product List Component]
|
|
G --> K[Product Form Component]
|
|
|
|
H --> L[Table Component]
|
|
I --> M[Form Component]
|
|
J --> L
|
|
K --> M
|
|
|
|
D --> N[API Service Layer]
|
|
N --> O[User API]
|
|
N --> P[Product API]
|
|
end
|
|
|
|
subgraph "后端项目 (localhost:8000)"
|
|
Q[FastAPI App]
|
|
R[User Endpoints]
|
|
S[Product Endpoints]
|
|
T[MySQL Database]
|
|
|
|
Q --> R
|
|
Q --> S
|
|
R --> T
|
|
S --> T
|
|
end
|
|
|
|
O -.->|HTTP Requests| R
|
|
P -.->|HTTP Requests| S
|
|
|
|
style A fill:#42b883
|
|
style Q fill:#009688
|
|
style T fill:#336791
|
|
```
|
|
|
|
## 🏛️ 分层设计
|
|
|
|
### 1. 表现层 (Presentation Layer)
|
|
- **Views/Pages**: 页面级组件,对应路由
|
|
- **Components**: 可复用的 UI 组件
|
|
- **Layout**: 布局组件 (侧边栏、头部、内容区域)
|
|
|
|
### 2. 服务层 (Service Layer)
|
|
- **API Services**: HTTP 请求封装
|
|
- **Utils**: 通用工具函数
|
|
- **Constants**: 常量定义
|
|
|
|
### 3. 路由层 (Router Layer)
|
|
- **Route Configuration**: 路由配置
|
|
- **Navigation Guards**: 路由守卫 (如需要)
|
|
|
|
### 4. 状态层 (State Layer)
|
|
- **Local State**: 组件内部状态 (Composition API)
|
|
- **Props/Emit**: 组件间通信
|
|
|
|
## 📦 核心组件设计
|
|
|
|
### 布局组件
|
|
```mermaid
|
|
graph TB
|
|
A[AppLayout] --> B[AppHeader]
|
|
A --> C[AppSidebar]
|
|
A --> D[AppMain]
|
|
|
|
B --> E[Logo]
|
|
B --> F[User Info]
|
|
|
|
C --> G[Navigation Menu]
|
|
G --> H[Dashboard Link]
|
|
G --> I[Users Link]
|
|
G --> J[Products Link]
|
|
|
|
D --> K[Router View]
|
|
```
|
|
|
|
### 页面组件架构
|
|
```mermaid
|
|
graph TB
|
|
subgraph "用户管理页面"
|
|
A[UserManagement] --> B[UserList]
|
|
A --> C[UserDialog]
|
|
B --> D[DataTable]
|
|
B --> E[TableActions]
|
|
C --> F[UserForm]
|
|
C --> G[FormActions]
|
|
end
|
|
|
|
subgraph "产品管理页面"
|
|
H[ProductManagement] --> I[ProductList]
|
|
H --> J[ProductDialog]
|
|
I --> K[DataTable]
|
|
I --> L[TableActions]
|
|
J --> M[ProductForm]
|
|
J --> N[FormActions]
|
|
end
|
|
```
|
|
|
|
## 🔌 接口契约定义
|
|
|
|
### API Service 接口
|
|
```javascript
|
|
// api/user.js
|
|
export const userAPI = {
|
|
// 获取用户列表
|
|
getUsers: () => axios.get('/api/v1/users/'),
|
|
|
|
// 获取单个用户
|
|
getUser: (id) => axios.get(`/api/v1/users/${id}`),
|
|
|
|
// 创建用户
|
|
createUser: (userData) => axios.post('/api/v1/users/', userData),
|
|
|
|
// 更新用户
|
|
updateUser: (id, userData) => axios.put(`/api/v1/users/${id}`, userData),
|
|
|
|
// 删除用户
|
|
deleteUser: (id) => axios.delete(`/api/v1/users/${id}`)
|
|
}
|
|
|
|
// api/product.js
|
|
export const productAPI = {
|
|
// 获取产品列表
|
|
getProducts: () => axios.get('/api/v1/products/'),
|
|
|
|
// 获取单个产品
|
|
getProduct: (id) => axios.get(`/api/v1/products/${id}`),
|
|
|
|
// 创建产品
|
|
createProduct: (productData) => axios.post('/api/v1/products/', productData),
|
|
|
|
// 更新产品
|
|
updateProduct: (id, productData) => axios.put(`/api/v1/products/${id}`, productData),
|
|
|
|
// 删除产品
|
|
deleteProduct: (id) => axios.delete(`/api/v1/products/${id}`)
|
|
}
|
|
```
|
|
|
|
### 组件 Props 接口
|
|
```javascript
|
|
// components/DataTable.vue Props
|
|
interface DataTableProps {
|
|
data: Array<Object> // 表格数据
|
|
columns: Array<Object> // 列配置
|
|
loading: Boolean // 加载状态
|
|
actions: Array<Object> // 操作按钮配置
|
|
}
|
|
|
|
// components/UserForm.vue Props
|
|
interface UserFormProps {
|
|
user: Object | null // 用户数据 (编辑模式)
|
|
mode: 'create' | 'edit' // 表单模式
|
|
loading: Boolean // 提交状态
|
|
}
|
|
|
|
// components/ProductForm.vue Props
|
|
interface ProductFormProps {
|
|
product: Object | null // 产品数据 (编辑模式)
|
|
mode: 'create' | 'edit' // 表单模式
|
|
loading: Boolean // 提交状态
|
|
}
|
|
```
|
|
|
|
## 📊 数据流向图
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant U as User
|
|
participant V as Vue Component
|
|
participant A as API Service
|
|
participant B as Backend API
|
|
participant D as Database
|
|
|
|
U->>V: 用户操作 (点击、提交)
|
|
V->>A: 调用 API 方法
|
|
A->>B: HTTP 请求
|
|
B->>D: 数据库操作
|
|
D-->>B: 返回数据
|
|
B-->>A: HTTP 响应
|
|
A-->>V: 返回结果
|
|
V-->>U: 更新界面
|
|
```
|
|
|
|
## 🚨 异常处理策略
|
|
|
|
### HTTP 错误处理
|
|
```javascript
|
|
// utils/request.js - Axios 拦截器
|
|
axios.interceptors.response.use(
|
|
response => response,
|
|
error => {
|
|
const { status, data } = error.response
|
|
|
|
switch (status) {
|
|
case 400:
|
|
ElMessage.error(data.detail || '请求参数错误')
|
|
break
|
|
case 404:
|
|
ElMessage.error('资源不存在')
|
|
break
|
|
case 409:
|
|
ElMessage.error(data.detail || '数据冲突')
|
|
break
|
|
case 500:
|
|
ElMessage.error('服务器内部错误')
|
|
break
|
|
default:
|
|
ElMessage.error('网络连接异常')
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
```
|
|
|
|
### 表单验证策略
|
|
```javascript
|
|
// 用户表单验证规则
|
|
const userFormRules = {
|
|
username: [
|
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
|
{ min: 3, max: 20, message: '用户名长度为 3-20 个字符', trigger: 'blur' }
|
|
],
|
|
email: [
|
|
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
|
|
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
// 产品表单验证规则
|
|
const productFormRules = {
|
|
name: [
|
|
{ required: true, message: '请输入产品名称', trigger: 'blur' },
|
|
{ min: 2, max: 50, message: '产品名称长度为 2-50 个字符', trigger: 'blur' }
|
|
],
|
|
price: [
|
|
{ required: true, message: '请输入产品价格', trigger: 'blur' },
|
|
{ type: 'number', min: 0, message: '价格必须大于等于 0', trigger: 'blur' }
|
|
],
|
|
stock: [
|
|
{ required: true, message: '请输入库存数量', trigger: 'blur' },
|
|
{ type: 'integer', min: 0, message: '库存必须为非负整数', trigger: 'blur' }
|
|
]
|
|
}
|
|
```
|
|
|
|
## 📱 响应式设计
|
|
|
|
### 断点设计
|
|
```css
|
|
/* 响应式断点 */
|
|
/* 手机端 */
|
|
@media (max-width: 768px) {
|
|
.sidebar { display: none; }
|
|
.main-content { margin-left: 0; }
|
|
}
|
|
|
|
/* 平板端 */
|
|
@media (min-width: 769px) and (max-width: 1024px) {
|
|
.sidebar { width: 200px; }
|
|
.main-content { margin-left: 200px; }
|
|
}
|
|
|
|
/* 桌面端 */
|
|
@media (min-width: 1025px) {
|
|
.sidebar { width: 250px; }
|
|
.main-content { margin-left: 250px; }
|
|
}
|
|
```
|
|
|
|
### 组件响应式
|
|
- 表格组件支持横向滚动
|
|
- 表单组件自适应布局
|
|
- 按钮组合在小屏幕下垂直排列
|
|
|
|
## 🛠️ 开发环境配置
|
|
|
|
### Vite 配置
|
|
```javascript
|
|
// vite.config.js
|
|
export default {
|
|
server: {
|
|
port: 3000,
|
|
proxy: {
|
|
'/api': {
|
|
target: 'http://localhost:8000',
|
|
changeOrigin: true
|
|
}
|
|
}
|
|
},
|
|
build: {
|
|
outDir: 'dist',
|
|
assetsDir: 'assets'
|
|
}
|
|
}
|
|
```
|
|
|
|
### 环境变量
|
|
```bash
|
|
# .env.development
|
|
VITE_API_BASE_URL=http://localhost:8000
|
|
VITE_APP_TITLE=FastAPI Demo - 管理后台
|
|
|
|
# .env.production
|
|
VITE_API_BASE_URL=https://your-api-domain.com
|
|
VITE_APP_TITLE=FastAPI Demo - 管理后台
|
|
```
|
|
|
|
## 🔄 组件生命周期设计
|
|
|
|
### 页面组件生命周期
|
|
```javascript
|
|
// views/UserManagement.vue
|
|
export default {
|
|
setup() {
|
|
const users = ref([])
|
|
const loading = ref(false)
|
|
|
|
// 页面加载时获取数据
|
|
onMounted(async () => {
|
|
await loadUsers()
|
|
})
|
|
|
|
const loadUsers = async () => {
|
|
loading.value = true
|
|
try {
|
|
const response = await userAPI.getUsers()
|
|
users.value = response.data
|
|
} catch (error) {
|
|
console.error('加载用户失败:', error)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
users,
|
|
loading,
|
|
loadUsers
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## 📋 组件复用策略
|
|
|
|
### 通用组件设计
|
|
1. **DataTable**: 通用数据表格组件
|
|
2. **FormDialog**: 通用表单对话框组件
|
|
3. **ConfirmDialog**: 通用确认对话框组件
|
|
4. **LoadingOverlay**: 通用加载覆盖层组件
|
|
5. **EmptyState**: 通用空状态组件
|
|
|
|
### 业务组件设计
|
|
1. **UserForm**: 用户表单组件
|
|
2. **ProductForm**: 产品表单组件
|
|
3. **UserList**: 用户列表组件
|
|
4. **ProductList**: 产品列表组件 |