# Design Document
## Overview
本设计文档描述将 supermart-mini 微信小程序迁移到 React Native/Expo iOS 应用的技术方案。迁移遵循以下原则:
1. 保持与小程序一致的视觉样式和交互体验
2. 复用小程序的 CDN 图片资源(通过 Images 常量配置)
3. 对接相同的后端 API 接口
4. 使用 React Native 的 ImageBackground 组件实现背景图效果
## Architecture
```mermaid
graph TB
subgraph "React Native App"
subgraph "Pages (app/)"
Tabs["Tab Pages
(tabs)"]
Login["Login Page"]
Address["Address Pages"]
Orders["Order Pages"]
Product["Product Pages"]
end
subgraph "Components"
Home["Home Components"]
ProductComp["Product Components"]
Common["Common Components"]
end
subgraph "Services"
UserService["user.ts"]
MallService["mall.ts"]
AwardService["award.ts"]
AddressService["address.ts"]
BaseService["base.ts"]
end
subgraph "Constants"
Images["images.ts"]
Theme["theme.ts"]
end
subgraph "Contexts"
AuthContext["AuthContext"]
end
end
subgraph "Backend API"
API["REST API Server"]
end
Tabs --> Services
Login --> UserService
Address --> AddressService
Orders --> MallService
Product --> MallService
Services --> API
Pages --> Images
Pages --> Components
```
## Components and Interfaces
### 1. 页面组件结构
#### Login Page (`app/login.tsx`)
```typescript
interface LoginScreenProps {}
// 状态
- phone: string // 手机号
- verifyCode: string // 验证码
- agreeFlag: boolean // 协议同意状态
- loading: boolean // 登录加载状态
- countdown: number // 验证码倒计时
// 方法
- handleGetVerifyCode() // 获取验证码
- handleLogin() // 登录
- goBack() // 返回
```
#### Mine Page (`app/(tabs)/mine.tsx`)
```typescript
interface MineScreenProps {}
interface IndexData {
couponCount?: number;
inventoryCount?: number;
magicBalance?: number;
treasureBoxCount?: number;
}
// 状态
- userInfo: UserInfo | null
- indexData: IndexData | null
// 方法
- loadData() // 加载用户数据
- handleLogin() // 跳转登录
- handleCopy(text) // 复制文本
- handleMenuPress(route) // 菜单点击
- showNumber(key) // 格式化数字显示
```
#### Address List Page (`app/address/index.tsx`)
```typescript
interface Address {
id: string;
contactName: string;
contactNo: string;
province: string;
city: string;
district: string;
address: string;
defaultFlag: number;
}
// 方法
- loadData() // 加载地址列表
- selectAddress(item) // 选择地址
- setDefault(item) // 设为默认
- handleDelete(item) // 删除地址
- editAddress(item) // 编辑地址
- addNewAddress() // 新增地址
```
#### Orders Page (`app/orders/index.tsx`)
```typescript
interface OrderItem {
tradeNo: string;
status: number;
statusText: string;
goodsName: string;
goodsCover: string;
quantity: number;
paymentAmount: number;
createTime: string;
}
// Tab 配置
const tabs = [
{ label: '全部', value: undefined },
{ label: '待付款', value: 1 },
{ label: '待发货', value: 2 },
{ label: '待收货', value: 3 },
{ label: '已完成', value: 4 },
];
```
### 2. 服务层接口
#### Address Service (`services/address.ts`)
```typescript
// API 端点
const apis = {
LIST: '/api/addressBook',
ADD: '/api/addressBook/add',
DELETE: '/api/addressBook/delete/{id}',
DEFAULT: '/api/addressBook/getDefault',
UPDATE: '/api/addressBook/update',
GET_AREA: '/api/area',
};
// 方法
export const getAddressList: () => Promise
export const getDefaultAddress: () => Promise
export const addAddress: (params) => Promise
export const updateAddress: (params) => Promise
export const deleteAddress: (id) => Promise
export const getArea: (pid) => Promise
```
#### Award Service (`services/award.ts`)
```typescript
// 新增方法
export const getMagicIndex: () => Promise
export const getPoolList: (params) => Promise
export const getPoolDetail: (poolId) => Promise
export const getIPList: () => Promise
```
## Data Models
### User Info
```typescript
interface UserInfo {
id: string;
nickname: string;
avatar: string;
phone?: string;
realName?: string;
idNum?: string;
balance?: number;
}
```
### Address
```typescript
interface Address {
id: string;
contactName: string;
contactNo: string;
location?: string;
province: string;
city: string;
district: string;
address: string;
defaultFlag: number; // 0: 非默认, 1: 默认
}
```
### Order
```typescript
interface OrderItem {
tradeNo: string;
status: number;
statusText: string;
goodsName: string;
goodsCover: string;
quantity: number;
paymentAmount: number;
createTime: string;
}
interface OrderDetail extends OrderItem {
address?: {
contactName: string;
contactNo: string;
province: string;
city: string;
district: string;
address: string;
};
expressInfo?: ExpressInfo[];
}
```
### Pool (奖池)
```typescript
interface PoolItem {
id: string;
name: string;
cover: string;
price: number;
mode: string;
}
interface PoolDetail extends PoolItem {
description?: string;
prizes?: PrizeItem[];
boxCount?: number;
}
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
Property 1: Login API call with correct parameters
*For any* valid phone number and verify code combination, when the login function is called, it SHALL send a request with loginWay, mobile, and verifycode parameters to the login API endpoint.
**Validates: Requirements 1.3**
Property 2: Navigation after login success
*For any* successful login response, the system SHALL navigate back if needInfo is false, or navigate to user-info page if needInfo is true.
**Validates: Requirements 1.4**
Property 3: User profile data display
*For any* user info object with avatar, nickname, id, and phone fields, the mine page SHALL render all these fields in the appropriate UI elements.
**Validates: Requirements 2.2**
Property 4: Statistics data display
*For any* index data object, the mine page SHALL display couponCount, inventoryCount, magicBalance, and treasureBoxCount values.
**Validates: Requirements 2.3**
Property 5: Function entry navigation
*For any* function entry tap with a valid route, the system SHALL trigger navigation to that route.
**Validates: Requirements 2.4, 2.5**
Property 6: Address list rendering
*For any* list of addresses, the address list page SHALL render each address with contactName, contactNo, and full address (province + city + district + address).
**Validates: Requirements 3.2**
Property 7: Address save API call
*For any* valid address form submission, the system SHALL call the add or update API and navigate back on success.
**Validates: Requirements 3.5**
Property 8: Order item rendering
*For any* order item, the orders page SHALL display tradeNo, statusText, goodsCover, goodsName, paymentAmount, quantity, and createTime.
**Validates: Requirements 4.2**
Property 9: Order navigation
*For any* order item tap, the system SHALL navigate to the order detail page with the correct tradeNo.
**Validates: Requirements 4.3**
Property 10: Order action handling
*For any* order with status 1 (待付款), the pay action SHALL be available; for status 3 (待收货), the confirm receipt action SHALL be available.
**Validates: Requirements 4.4**
Property 11: Welfare room navigation
*For any* room entry tap with type 0, 1, or 2, the system SHALL navigate to the corresponding welfare page (room, catchDoll, or wish).
**Validates: Requirements 6.3**
Property 12: Image constants consistency
*For any* image key used in the app, the Images constant SHALL provide a valid CDN URL matching the ossurl configuration.
**Validates: Requirements 8.1, 8.2**
Property 13: API service function mapping
*For any* service function call, the request SHALL be sent to the correct API endpoint matching the mini-program service configuration.
**Validates: Requirements 9.1**
Property 14: API error handling
*For any* failed API call, the system SHALL catch the error and not crash, optionally displaying an error message.
**Validates: Requirements 9.2**
Property 15: Authentication token inclusion
*For any* authenticated API request, the HTTP headers SHALL include the authorization token.
**Validates: Requirements 9.3**
## Error Handling
### API 错误处理
```typescript
// HTTP 请求封装中的错误处理
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code === '401') {
// Token 过期,跳转登录
router.push('/login');
return { success: false, code: '401' };
}
return data;
} catch (error) {
console.error('API Error:', error);
return { success: false, error };
}
```
### 页面错误处理
- 加载失败时显示重试按钮
- 网络错误时显示提示信息
- 表单验证失败时显示具体错误
## Testing Strategy
### 单元测试
- 使用 Jest 进行单元测试
- 测试服务层函数的参数处理和返回值
- 测试工具函数(如数字格式化)
### 属性测试
- 使用 fast-check 进行属性测试
- 每个属性测试运行至少 100 次迭代
- 测试标注格式:`**Feature: miniapp-to-rn-migration, Property {number}: {property_text}**`
### 测试覆盖范围
1. 服务层 API 调用测试
2. 页面组件渲染测试
3. 导航逻辑测试
4. 表单验证测试
5. 错误处理测试