crgs/src/mocks/MOCK_DATA_CONSISTENCY.md

249 lines
7.0 KiB
Markdown
Raw Normal View History

2026-04-30 14:30:20 +08:00
# Mock 数据一致性说明
## 概述
本文档说明 Mock 数据与后端 API 响应结构的一致性处理方式,确保 Mock 数据能够准确模拟真实后端行为。
## 数据结构一致性
### 1. 标准响应格式
所有 Mock 接口统一使用以下响应格式:
```javascript
{
code: 0, // 响应码0成功-1失败
msg: 'success', // 响应消息
data: {...} // 响应数据
}
```
### 2. 分页响应格式
分页接口使用以下格式:
```javascript
{
code: 0,
msg: 'success',
data: {
records: [...], // 当前页数据列表
total: 100, // 总记录数
size: 10, // 每页大小
current: 1, // 当前页码
pages: 10 // 总页数
}
}
```
## 数据一致性处理工具
### 分页处理
`paginatedResponse()` 函数提供完整的分页处理能力:
```javascript
import { paginatedResponse } from '@/mocks/utils/handler-utils'
// 支持的参数
{
current: 1, // 当前页码(必需)
size: 10, // 每页大小(必需)
orderField: 'createTime', // 排序字段
orderingRule: 'desc', // 排序规则asc/desc
orderFields: ['field1', 'field2'], // 多字段排序
orderSorts: ['asc', 'desc'], // 多字段排序规则
custom: { // 自定义筛选条件
status: 1
},
likeParamMap: { // 模糊查询条件
name: '关键词'
},
inParamMap: { // IN 查询条件
status: [1, 2, 3]
}
}
```
### 排序处理
`sortData()` 函数支持:
- **单字段排序**`{ field: 'name', order: 'asc' }`
- **多字段排序**`{ fields: ['name', 'age'], orders: ['asc', 'desc'] }`
- **嵌套字段排序**`field: 'user.address.city'`
- **类型处理**:自动识别数字、日期、字符串类型进行排序
### 筛选处理
`filterData()` 函数支持:
- **精确匹配**`{ status: 1 }`
- **模糊查询**`{ likeParamMap: { name: '关键词' } }`
- **IN 查询**`{ inParamMap: { status: [1, 2] } }`
- **自定义筛选**`{ customParamMap: { customFn: (item) => item.value > 100 } }`
## 数据类型映射
### 企业数据结构
```javascript
{
companyId: 'com_xxx', // 企业ID
pripid: 'prip_xxx', // 原系统ID
uniscid: '91440100...', // 统一社会信用代码
entname: '企业名称', // 市场主体名称
regstate: '1', // 企业状态码
regstateCn: '存续', // 企业状态(中文)
industryphy: 'C', // 行业门类码
industryphyCn: '制造业', // 行业门类(中文)
riskLevel: '1', // 风险等级码
riskLevelCn: '低风险', // 风险等级(中文)
riskScore: 75, // 风险评分
estdate: '2020-01-01', // 成立时间
createTime: '...', // 创建时间
updateTime: '...' // 更新时间
}
```
### 用户数据结构
```javascript
{
userId: 'user_xxx', // 用户ID
username: 'admin', // 用户名
realName: '张三', // 真实姓名
account: 'admin', // 账号
department: 'xxx', // 部门
roleId: 'role_xxx', // 角色ID
roleName: '管理员', // 角色名称
status: 1, // 状态
createTime: '...', // 创建时间
lastLoginTime: '...' // 最后登录时间
}
```
## 加载延迟模拟
所有 Mock 接口都使用随机延迟200-800ms来模拟真实网络请求
```javascript
import { mockDelay, handlePaginatedRequest } from '@/mocks/utils/handler-utils'
// 方式1使用 mockDelay
await mockDelay()
// 方式2使用 handlePaginatedRequest自动延迟
const response = await handlePaginatedRequest(data, request)
```
## 错误场景模拟
### 1. 业务错误响应
```javascript
import { errorResponse } from '@/mocks/utils/handler-utils'
return res(
ctx.status(200),
ctx.json(errorResponse('参数错误', -1))
)
```
### 2. HTTP 状态码
```javascript
return res(
ctx.status(401), // 未授权
ctx.json({ code: 401, msg: '未登录或登录已过期' })
)
```
### 3. 模拟特定错误
```javascript
// 登录失败
if (username !== 'admin' || password !== '123456') {
return res(
ctx.status(200),
ctx.json(errorResponse('用户名或密码错误'))
)
}
```
## Mock 数据验证检查清单
在开发 Mock 数据时,确保以下项目:
- [ ] **响应格式**:使用 `successResponse()``errorResponse()` 统一格式
- [ ] **分页结构**:使用 `paginatedResponse()` 包含 records/total/size/current/pages
- [ ] **字段命名**:字段名与后端 API 文档保持一致(驼峰命名)
- [ ] **数据类型**:数字字段使用 `Number`,日期使用 ISO 字符串格式
- [ ] **枚举值**:状态码、类型码等与后端定义一致
- [ ] **关联关系**:外键 ID 格式正确,如 `companyId`、`userId`
- [ ] **分页支持**:支持排序、筛选、模糊查询等后端功能
- [ ] **延迟模拟**:使用 `mockDelay()``handlePaginatedRequest()` 模拟网络延迟
- [ ] **错误处理**:提供合理的错误响应场景
## Mock 数据维护建议
1. **数据量控制**:每个模块生成 20-100 条 Mock 数据
2. **数据真实性**:使用 `@faker-js/faker` 生成接近真实的测试数据
3. **字段完整性**:确保 Mock 数据包含后端返回的所有字段
4. **边界测试**:提供空数据、单页数据、多页数据等边界情况
5. **定期更新**:后端 API 变更时同步更新 Mock 数据结构
## 使用示例
### 完整的分页请求处理
```javascript
export const examplePaginatedHandler = rest.post(
getBasePath('/example/list'),
async (req, res, ctx) => {
const body = await getRequestBody(req)
const response = await handlePaginatedRequest(mockData, body)
return res(
ctx.status(200),
ctx.json(successResponse(response))
)
}
)
```
### 带筛选的处理
```javascript
export const exampleFilterHandler = rest.post(
getBasePath('/example/list'),
async (req, res, ctx) => {
const body = await getRequestBody(req)
// 自定义筛选逻辑
const result = filterData(mockData, body, {
likeParamMap: { name: body.keyword },
inParamMap: { status: [1, 2] }
})
return res(
ctx.status(200),
ctx.json(successResponse(result))
)
}
)
```
## 工具函数速查表
| 函数 | 说明 | 参数 |
|------|------|------|
| `successResponse(data, msg)` | 成功响应 | data, msg |
| `errorResponse(msg, code)` | 错误响应 | msg, code |
| `paginate(data, size, current)` | 简单分页 | data, size, current |
| `paginatedResponse(data, request)` | 完整分页(排序+筛选) | data, request |
| `sortData(data, options)` | 排序 | data, { field, order, fields, orders } |
| `filterData(data, filters, options)` | 筛选 | data, filters, { customParamMap, likeParamMap, inParamMap } |
| `handlePaginatedRequest(data, request)` | 处理分页请求(带延迟) | data, request |
| `mockDelay()` | 模拟延迟 | 无 |
| `getNestedValue(obj, path)` | 获取嵌套属性 | obj, 'path.to.field' |