rwadurian/frontend/mobile-upgrade/docs/DEVELOPMENT.md

418 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mobile Upgrade Admin - 开发指南
## 环境要求
| 工具 | 版本 | 说明 |
|------|------|------|
| Node.js | >= 18.x | 运行环境 |
| npm | >= 9.x | 包管理器 |
| Git | >= 2.x | 版本控制 |
## 快速开始
### 1. 克隆项目
```bash
git clone https://git.gdzx.xyz/hailin/rwadurian.git
cd rwadurian/frontend/mobile-upgrade
```
### 2. 安装依赖
```bash
npm install
```
### 3. 配置环境变量
```bash
# 复制环境变量模板
cp .env.local.example .env.local
# 编辑配置
# NEXT_PUBLIC_API_URL=http://localhost:3000
```
### 4. 启动开发服务器
```bash
npm run dev
```
访问 http://localhost:3000 查看应用。
## 项目脚本
```bash
# 开发模式
npm run dev
# 生产构建
npm run build
# 启动生产服务
npm run start
# 代码检查
npm run lint
# 类型检查
npm run type-check
```
## 开发规范
### 目录结构规范
```
src/
├── domain/ # 领域层:纯 TypeScript无框架依赖
├── infrastructure/ # 基础设施层:外部服务交互
├── application/ # 应用层:业务逻辑和状态管理
├── presentation/ # 表示层React 组件
└── app/ # Next.js 页面路由
```
### 命名规范
| 类型 | 规范 | 示例 |
|------|------|------|
| 文件名 | kebab-case | `version-card.tsx` |
| 组件名 | PascalCase | `VersionCard` |
| 函数名 | camelCase | `fetchVersions` |
| 常量 | UPPER_SNAKE_CASE | `API_BASE_URL` |
| 类型/接口 | PascalCase | `AppVersion` |
### 代码风格
项目使用 ESLint + Prettier 进行代码规范检查。
```json
// .eslintrc.json
{
"extends": ["next/core-web-vitals"]
}
```
## 开发流程
### 1. 新增功能开发流程
```
1. 在 Domain 层定义实体和接口
2. 在 Infrastructure 层实现 API 调用
3. 在 Application 层添加状态管理逻辑
4. 在 Presentation 层创建 UI 组件
5. 编写测试用例
6. 提交代码
```
### 2. 示例:添加新的 API 功能
#### Step 1: Domain 层 - 定义类型
```typescript
// src/domain/entities/version.ts
export interface BatchDeleteInput {
ids: string[]
}
```
#### Step 2: Domain 层 - 定义接口
```typescript
// src/domain/repositories/version-repository.ts
export interface IVersionRepository {
// ... 现有方法
batchDelete(input: BatchDeleteInput): Promise<void>
}
```
#### Step 3: Infrastructure 层 - 实现接口
```typescript
// src/infrastructure/repositories/version-repository-impl.ts
export class VersionRepositoryImpl implements IVersionRepository {
// ... 现有方法
async batchDelete(input: BatchDeleteInput): Promise<void> {
await this.client.post('/api/v1/versions/batch-delete', input)
}
}
```
#### Step 4: Application 层 - 添加状态管理
```typescript
// src/application/stores/version-store.ts
interface VersionState {
// ... 现有状态
batchDeleteVersions: (ids: string[]) => Promise<void>
}
export const useVersionStore = create<VersionState>((set, get) => ({
// ... 现有实现
batchDeleteVersions: async (ids: string[]) => {
set({ isLoading: true, error: null })
try {
await versionRepository.batchDelete({ ids })
const { versions } = get()
set({
versions: versions.filter((v) => !ids.includes(v.id)),
isLoading: false,
})
} catch (err) {
set({
error: err instanceof Error ? err.message : 'Failed to delete',
isLoading: false,
})
throw err
}
},
}))
```
#### Step 5: Application 层 - 添加 Hook
```typescript
// src/application/hooks/use-versions.ts
export function useVersionActions() {
const { batchDeleteVersions, ... } = useVersionStore()
return {
batchDelete: batchDeleteVersions,
// ... 其他方法
}
}
```
#### Step 6: Presentation 层 - 使用
```typescript
// src/presentation/components/batch-actions.tsx
export function BatchActions({ selectedIds }: { selectedIds: string[] }) {
const { batchDelete } = useVersionActions()
const handleBatchDelete = async () => {
try {
await batchDelete(selectedIds)
toast.success('批量删除成功')
} catch (err) {
toast.error('批量删除失败')
}
}
return (
<button onClick={handleBatchDelete}>
批量删除 ({selectedIds.length})
</button>
)
}
```
## 状态管理
### Zustand Store 设计
```typescript
// 状态结构
interface VersionState {
// 数据状态
versions: AppVersion[]
selectedVersion: AppVersion | null
// UI 状态
isLoading: boolean
error: string | null
// 筛选状态
filter: {
platform?: Platform
includeDisabled: boolean
}
// Actions
fetchVersions: () => Promise<void>
setFilter: (filter: Partial<VersionState['filter']>) => void
clearError: () => void
}
```
### 使用 Hooks
```typescript
// 在组件中使用
function VersionList() {
const { versions, isLoading, error, refetch, setFilter } = useVersions()
const { deleteVersion, toggleVersion } = useVersionActions()
// 筛选
const handleFilterChange = (platform: Platform | 'all') => {
setFilter({ platform: platform === 'all' ? undefined : platform })
}
// 删除
const handleDelete = async (id: string) => {
await deleteVersion(id)
refetch()
}
return (/* JSX */)
}
```
## 组件开发
### 组件结构规范
```typescript
'use client'
import { useState, useEffect } from 'react'
import { useVersions } from '@/application'
import { AppVersion } from '@/domain'
// Props 接口定义
interface VersionCardProps {
version: AppVersion
onEdit: () => void
onDelete: () => void
}
// 组件实现
export function VersionCard({ version, onEdit, onDelete }: VersionCardProps) {
// Hooks
const [isExpanded, setIsExpanded] = useState(false)
// 事件处理
const handleToggle = () => {
setIsExpanded(!isExpanded)
}
// 渲染
return (
<div className="card">
{/* 组件内容 */}
</div>
)
}
```
### 样式规范
使用 Tailwind CSS 原子类:
```tsx
// 推荐
<button className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
提交
</button>
// 复用样式定义在 globals.css
<button className="btn btn-primary">提交</button>
```
全局样式定义:
```css
/* src/app/globals.css */
@layer components {
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-colors;
}
.btn-primary {
@apply bg-blue-600 text-white hover:bg-blue-700;
}
.card {
@apply bg-white rounded-lg shadow-sm border p-6;
}
.input {
@apply w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500;
}
}
```
## 调试技巧
### 1. React DevTools
安装浏览器扩展查看组件树和状态。
### 2. Zustand DevTools
```typescript
import { devtools } from 'zustand/middleware'
export const useVersionStore = create<VersionState>()(
devtools(
(set, get) => ({
// store 实现
}),
{ name: 'version-store' }
)
)
```
### 3. API 请求调试
```typescript
// 在 api-client.ts 添加请求日志
apiClient.interceptors.request.use((config) => {
console.log('API Request:', config.method?.toUpperCase(), config.url)
return config
})
apiClient.interceptors.response.use(
(response) => {
console.log('API Response:', response.status, response.config.url)
return response
},
(error) => {
console.error('API Error:', error.response?.status, error.config.url)
return Promise.reject(error)
}
)
```
## 常见问题
### 1. 类型错误
确保导入路径使用别名:
```typescript
// 正确
import { AppVersion } from '@/domain'
// 错误
import { AppVersion } from '../../../domain/entities/version'
```
### 2. 环境变量不生效
Next.js 要求客户端环境变量以 `NEXT_PUBLIC_` 开头:
```bash
# 正确 - 客户端可访问
NEXT_PUBLIC_API_URL=http://localhost:3000
# 错误 - 仅服务端可访问
API_URL=http://localhost:3000
```
### 3. 热更新不工作
```bash
# 删除 .next 缓存目录
rm -rf .next
npm run dev
```
## 相关文档
- [架构文档](./ARCHITECTURE.md)
- [API 文档](./API.md)
- [测试指南](./TESTING.md)
- [部署指南](./DEPLOYMENT.md)