# Mock 数据规范

## 设计原则

1.  每个列表页对应一个 mock 数据文件，放在 `src/mock/` 目录下
    
2.  使用工厂函数生成数据，默认生成 100 条
    
3.  数据字段要贴合业务实际，不要使用 "test1"、"aaa" 等无意义数据
    
4.  ID 使用递增数字或带业务前缀的编号（如 `SO20260401001`）
    
5.  日期使用合理的时间范围（如近 3 个月内）
    
6.  金额使用合理的数值范围
    
7.  状态字段使用枚举值，并配备对应的中文映射
    

## 数据生成模板

```js
// mock/orderList.js

// 状态枚举
export const ORDER_STATUS = {
  DRAFT: { value: 'draft', label: '草稿', color: 'default' },
  PENDING: { value: 'pending', label: '待审核', color: 'processing' },
  APPROVED: { value: 'approved', label: '已审核', color: 'success' },
  REJECTED: { value: 'rejected', label: '已驳回', color: 'error' },
  COMPLETED: { value: 'completed', label: '已完成', color: 'success' },
  CANCELLED: { value: 'cancelled', label: '已取消', color: 'default' },
};

// 模拟客户名称池
const CUSTOMERS = [
  '华润万家', '沃尔玛', '永辉超市', '大润发', '盒马鲜生',
  '天虹商场', '万达广场', '银泰百货', '苏宁易购', '国美电器',
  '中石化', '中石油', '比亚迪', '格力电器', '美的集团',
];

// 模拟商品名称池
const PRODUCTS = [
  '矿泉水550ml', '纯净水5L', '碳酸饮料330ml', '果汁1L',
  '方便面桶装', '饼干礼盒', '牛奶250ml*12', '酸奶100g*6',
];

// 随机工具函数
const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const randomItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
const randomDate = (startDays, endDays) => {
  const now = new Date();
  const start = new Date(now.getTime() - startDays * 86400000);
  const end = new Date(now.getTime() - endDays * 86400000);
  const d = new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  return d.toISOString().slice(0, 10);
};

// 生成订单号
const genOrderNo = (index) => {
  const date = new Date();
  const prefix = 'SO';
  const dateStr = date.toISOString().slice(0, 10).replace(/-/g, '');
  return `${prefix}${dateStr}${String(index + 1).padStart(3, '0')}`;
};

// 生成数据
export const generateOrderList = (count = 100) => {
  const statusValues = Object.values(ORDER_STATUS);
  return Array.from({ length: count }, (_, i) => ({
    id: i + 1,
    orderNo: genOrderNo(i),
    customerName: randomItem(CUSTOMERS),
    productName: randomItem(PRODUCTS),
    quantity: random(10, 500),
    unitPrice: (random(500, 5000) / 100).toFixed(2),
    totalAmount: 0,  // 下面计算
    status: randomItem(statusValues).value,
    createTime: randomDate(90, 0),
    createBy: randomItem(['张三', '李四', '王五', '赵六']),
    remark: '',
  })).map(item => ({
    ...item,
    totalAmount: (item.quantity * parseFloat(item.unitPrice)).toFixed(2),
  }));
};
```

## 分页逻辑

列表页需要实现前端分页，在页面组件中处理：

```js
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [allData] = useState(() => generateOrderList(100));

// 当前页数据
const currentData = useMemo(() => {
  const start = (currentPage - 1) * pageSize;
  return allData.slice(start, start + pageSize);
}, [allData, currentPage, pageSize]);

// 筛选逻辑
const filteredData = useMemo(() => {
  let data = allData;
  if (filters.status) {
    data = data.filter(item => item.status === filters.status);
  }
  if (filters.keyword) {
    data = data.filter(item =>
      item.orderNo.includes(filters.keyword) ||
      item.customerName.includes(filters.keyword)
    );
  }
  return data;
}, [allData, filters]);
```

## 命名约定

| 业务模块 | 文件名 | 导出函数 |
| --- | --- | --- |
| 销售订单 | `orderList.js` | `generateOrderList` |
| 客户管理 | `customerList.js` | `generateCustomerList` |
| 采购单 | `purchaseList.js` | `generatePurchaseList` |
| 供应商 | `supplierList.js` | `generateSupplierList` |
| 库存  | `inventoryList.js` | `generateInventoryList` |
| 入库单 | `inboundList.js` | `generateInboundList` |
| 出库单 | `outboundList.js` | `generateOutboundList` |

<br>