# 通用CRUD筛选规范

## 概述

本规范定义了通用CRUD模块的增强筛选功能，支持多种查询模式和灵活的筛选条件。

## 新增功能

### 1. 筛选参数支持
- **参数名**: `filters`
- **类型**: JSON字符串
- **位置**: 查询参数
- **可选**: 是

### 2. 支持的筛选操作

| 操作类型 | 语法格式 | 示例 | 说明 |
|----------|----------|------|------|
| 精确匹配 | `"字段名": 值` | `{"status": 1}` | 等于指定值 |
| 模糊匹配 | `"字段名": "%值%"` | `{"name": "%张%"}` | LIKE查询，包含指定值 |
| 大于 | `"字段名": {"gt": 值}` | `{"age": {"gt": 18}}` | 大于指定值 |
| 大于等于 | `"字段名": {"gte": 值}` | `{"age": {"gte": 18}}` | 大于等于指定值 |
| 小于 | `"字段名": {"lt": 值}` | `{"score": {"lt": 60}}` | 小于指定值 |
| 小于等于 | `"字段名": {"lte": 值}` | `{"score": {"lte": 60}}` | 小于等于指定值 |
| 范围查询 | `"字段名": {"between": [最小值, 最大值]}` | `{"createdAt": {"between": ["2024-01-01", "2024-12-31"]}}` | 在指定范围内 |
| IN查询 | `"字段名": [值1, 值2, ...]` | `{"status": [1, 2, 3]}` | 值在指定数组中 |
| NULL匹配 | `"字段名": null` | `{"deletedAt": null}` | 字段为NULL |

### 3. 组合查询
支持多个条件同时筛选，所有条件为AND关系：

```json
{
  "status": 1,
  "name": "%张%",
  "createdAt": {"gte": "2024-01-01"}
}
```

## API使用规范

### 请求格式
```http
GET /api/v1/entities?filters={"status":1,"name":"%张%","createdAt":{"gte":"2024-01-01"}}
```

### 响应格式
```json
{
  "data": [...],
  "pagination": {
    "total": 100,
    "current": 1,
    "pageSize": 10
  }
}
```

### 错误处理
- 格式错误：返回400状态码，message为"筛选条件格式错误"
- 字段不存在：安全忽略，不影响查询
- 类型不匹配：安全处理，返回空结果

## 前端集成规范

### React Hook示例
```typescript
const useEntityList = () => {
  const [data, setData] = useState([]);
  
  const fetchData = async (filters = {}) => {
    const response = await client.$get({
      query: {
        page: 1,
        pageSize: 10,
        filters: JSON.stringify(filters)
      }
    });
    // 处理响应...
  };
  
  return { data, fetchData };
};
```

### ProTable集成
```typescript
const columns = [
  {
    title: '状态',
    dataIndex: 'status',
    valueType: 'select',
    valueEnum: { 0: '禁用', 1: '启用' },
  },
  {
    title: '创建时间',
    dataIndex: 'createdAt',
    valueType: 'dateRange',
  },
];

const handleRequest = async (params) => {
  const filters = {};
  
  if (params.status !== undefined) filters.status = params.status;
  if (params.createdAt?.length === 2) {
    filters.createdAt = { between: params.createdAt };
  }
  
  return client.$get({
    query: {
      page: params.current,
      pageSize: params.pageSize,
      keyword: params.keyword,
      filters: JSON.stringify(filters)
    }
  });
};
```

## 后端实现规范

### GenericCrudService使用
```typescript
// 直接使用（无需修改）
const service = new GenericCrudService(dataSource, UserEntity);
const [data, total] = await service.getList(
  page, pageSize, keyword, searchFields, where, relations, order, filters
);

// 自定义实现
export class UserService extends GenericCrudService<User> {
  async getList(
    page: number = 1,
    pageSize: number = 10,
    keyword?: string,
    searchFields?: string[],
    where?: Partial<User>,
    relations: string[] = [],
    order: any = {},
    filters?: any
  ) {
    // 添加业务特定的筛选
    const customFilters = {
      ...filters,
      isDeleted: 0
    };
    
    return super.getList(page, pageSize, keyword, searchFields, where, relations, order, customFilters);
  }
}
```

## 最佳实践

### 1. 性能优化
- 为常用筛选字段添加数据库索引
- 避免对大字段进行模糊查询
- 合理使用分页参数

### 2. 安全考虑
- 避免传递敏感字段到filters
- 验证用户权限相关的筛选条件
- 限制查询结果集大小

### 3. 类型安全
```typescript
// 推荐：定义筛选类型
interface UserFilters {
  status?: number;
  name?: string;
  age?: { gte?: number; lte?: number };
  createdAt?: { between?: [string, string] };
}

// 使用时
const filters: UserFilters = { status: 1 };
```

### 4. 错误处理
```typescript
try {
  const filters = JSON.parse(query.filters);
  // 验证filters结构...
} catch (error) {
  return { code: 400, message: '筛选条件格式错误' };
}
```

## 常见问题

### Q: 如何忽略大小写的模糊匹配？
A: 使用标准SQL LIKE语法，数据库层面处理大小写

### Q: 是否支持OR条件？
A: 当前版本仅支持AND关系，OR条件需要自定义实现

### Q: 如何处理空字符串？
A: 空字符串会被自动忽略，不会加入筛选条件

### Q: 是否支持嵌套对象筛选？
A: 支持，使用点表示法：`{"related.field": "value"}`

## 版本兼容
- 完全向后兼容，不影响现有API调用
- 新增参数为可选，不传递时保持原有行为
- 错误时返回标准化错误响应