8.4 KiB
8.4 KiB
Mobile Upgrade Admin - 开发指南
环境要求
| 工具 | 版本 | 说明 |
|---|---|---|
| Node.js | >= 18.x | 运行环境 |
| npm | >= 9.x | 包管理器 |
| Git | >= 2.x | 版本控制 |
快速开始
1. 克隆项目
git clone https://git.gdzx.xyz/hailin/rwadurian.git
cd rwadurian/frontend/mobile-upgrade
2. 安装依赖
npm install
3. 配置环境变量
# 复制环境变量模板
cp .env.local.example .env.local
# 编辑配置
# NEXT_PUBLIC_API_URL=http://localhost:3000
4. 启动开发服务器
npm run dev
访问 http://localhost:3000 查看应用。
项目脚本
# 开发模式
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 进行代码规范检查。
// .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 层 - 定义类型
// src/domain/entities/version.ts
export interface BatchDeleteInput {
ids: string[]
}
Step 2: Domain 层 - 定义接口
// src/domain/repositories/version-repository.ts
export interface IVersionRepository {
// ... 现有方法
batchDelete(input: BatchDeleteInput): Promise<void>
}
Step 3: Infrastructure 层 - 实现接口
// 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 层 - 添加状态管理
// 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
// src/application/hooks/use-versions.ts
export function useVersionActions() {
const { batchDeleteVersions, ... } = useVersionStore()
return {
batchDelete: batchDeleteVersions,
// ... 其他方法
}
}
Step 6: Presentation 层 - 使用
// 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 设计
// 状态结构
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
// 在组件中使用
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 */)
}
组件开发
组件结构规范
'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 原子类:
// 推荐
<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>
全局样式定义:
/* 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
import { devtools } from 'zustand/middleware'
export const useVersionStore = create<VersionState>()(
devtools(
(set, get) => ({
// store 实现
}),
{ name: 'version-store' }
)
)
3. API 请求调试
// 在 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. 类型错误
确保导入路径使用别名:
// 正确
import { AppVersion } from '@/domain'
// 错误
import { AppVersion } from '../../../domain/entities/version'
2. 环境变量不生效
Next.js 要求客户端环境变量以 NEXT_PUBLIC_ 开头:
# 正确 - 客户端可访问
NEXT_PUBLIC_API_URL=http://localhost:3000
# 错误 - 仅服务端可访问
API_URL=http://localhost:3000
3. 热更新不工作
# 删除 .next 缓存目录
rm -rf .next
npm run dev