418 lines
8.4 KiB
Markdown
418 lines
8.4 KiB
Markdown
# 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)
|