---
alwaysApply: true
---
## useTableRequest 使用规则

### 🌐 全局配置

在应用入口处设置全局默认配置：

```typescript
import { setTableRequestGlobalConfig } from 'xn-fe-tools'

setTableRequestGlobalConfig({
  immediate: true,
  debounceDelay: 500,
  pagination: {
    defaultPageSize: 20,
    pageKey: 'pageNum',
    pageSizeKey: 'size',
  },
  dataField: 'data',         // 响应数据中的数据字段
  totalField: 'total',       // 响应数据中的总数字段
  currentPageField: 'page',  // 响应数据中的当前页码字段
})
```

### 🎯 核心原则
- **类型安全**：确保输入参数和返回结果具有明确的类型定义
- **响应式参数**：使用 `computed` 或 `ref` 包装动态参数
- **数据转换**：使用 `transformResult` 统一处理后端返回的数据格式
- **错误处理**：合理使用 `onError` 回调处理异常情况

### 📝 使用规范

#### 1. 基础用法
```typescript
import { computed, ref } from 'vue'
import { useTableRequest } from 'xn-fe-tools'

// 定义请求函数
const fetchUserList = (params: UserListParams) => api.get('/users', { params })

// 搜索参数
const search = ref('')
const status = ref<number>()

// 使用 Hook
const { data, loading, pagination, run, onPageChange, onSizeChange } = useTableRequest(
  fetchUserList,
  {
    params: computed(() => ({ 
      keyword: search.value,
      status: status.value 
    })),
    immediate: true,
    transformResult: (res) => ({
      list: res.data.records,
      total: res.data.total,
    }),
  }
)
```

#### 2. 参数说明

| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|-------|------|------|--------|------|
| `requestFn` | `(params) => Promise` | 是 | - | 请求函数 |
| `options.params` | `MaybeRefOrGetter<P>` | 否 | `{}` | 请求参数（响应式） |
| `options.immediate` | `boolean` | 否 | `true` | 是否立即执行 |
| `options.debounceDelay` | `number` | 否 | `0` | 防抖延迟（毫秒），默认不防抖 |
| `options.pagination` | `PaginationConfig` | 否 | 见下方 | 分页配置 |
| `options.dataField` | `string` | 否 | `''` | 数据列表字段名，支持点号分隔的嵌套路径 |
| `options.totalField` | `string` | 否 | `''` | 总数字段名，支持点号分隔的嵌套路径 |
| `options.currentPageField` | `string` | 否 | `''` | 当前页码字段名，支持点号分隔的嵌套路径 |
| `options.transformParams` | `Function` | 否 | - | 请求前参数转换 |
| `options.transformResult` | `Function` | 否 | - | 请求后数据转换 |
| `options.onSuccess` | `Function` | 否 | - | 成功回调 |
| `options.onError` | `Function` | 否 | - | 失败回调 |

**分页配置 PaginationConfig：**
| 参数名 | 类型 | 默认值 | 说明 |
|-------|------|--------|------|
| `defaultPage` | `number` | `1` | 默认页码 |
| `defaultPageSize` | `number` | `10` | 默认每页数量 |
| `pageKey` | `string` | `'page'` | 页码字段名 |
| `pageSizeKey` | `string` | `'pageSize'` | 每页数量字段名 |

#### 3. 返回值说明

| 属性名 | 类型 | 说明 |
|-------|------|------|
| `data` | `Ref<T[]>` | 列表数据 |
| `loading` | `Ref<boolean>` | 加载状态 |
| `error` | `Ref<Error \| null>` | 错误信息 |
| `pagination` | `ComputedRef<PaginationState>` | 分页信息（page, pageSize, total） |
| `run` | `() => Promise<void>` | 手动触发请求 |
| `onPageChange` | `(page: number) => Promise<void>` | 切换页码 |
| `onSizeChange` | `(size: number) => Promise<void>` | 改变每页数量 |

### ✅ 推荐用法

```typescript
// ✅ 使用 computed 包装动态参数
const { data } = useTableRequest(fetchData, {
  params: computed(() => ({ keyword: search.value })),
  transformResult: (res) => ({ list: res.data, total: res.total }),
})

// ✅ 自定义分页参数名（适配不同后端）
const { data } = useTableRequest(fetchData, {
  pagination: {
    pageKey: 'pageNum',
    pageSizeKey: 'size',
  },
})

// ✅ 使用 transformParams 完全控制请求参数
const { data } = useTableRequest(fetchData, {
  params: computed(() => ({ keyword: search.value })),
  transformParams: (params, pagination) => ({
    search: params.keyword,
    current: pagination.page,
    limit: pagination.pageSize,
  }),
})

// ✅ 手动触发请求
const { run } = useTableRequest(fetchData, {
  immediate: false,
  debounceDelay: 0,
})
```

### ❌ 错误用法

```typescript
// ❌ 直接使用非响应式对象作为 params（参数变化不会触发请求）
const { data } = useTableRequest(fetchData, {
  params: { keyword: search.value }, // 不会响应 search 变化
})

// ❌ transformResult 返回格式错误
const { data } = useTableRequest(fetchData, {
  transformResult: (res) => res.data, // 必须返回 { list, total } 格式
})

// ❌ 在条件语句中调用
if (condition) {
  const { data } = useTableRequest(fetchData) // 违反 Composition API 规则
}
```

### 🚨 注意事项

1. **参数变化自动重置页码**：当 `params` 变化时会自动重置到第一页
2. **防抖仅对参数监听生效**：`run`、`onPageChange`、`onSizeChange` 立即执行
3. **竞态控制**：自动处理请求竞态，只有最后一次请求的结果会被使用
4. **必须在 setup 顶层调用**：遵循 Vue Composition API 规范
5. **transformResult 必须返回固定格式**：`{ list: T[], total: number }`

### 🧪 测试建议

- 测试 `immediate: true/false` 的行为差异
- 测试参数变化时的防抖和页码重置
- 测试分页操作（翻页、改变每页数量）
- 测试请求成功和失败的状态变化
- 测试 `transformParams` 和 `transformResult` 的转换逻辑

### 🔗 相关链接

- [使用文档](/hooks/useTableRequest)
- [toAwaitFetch](/hooks/toAwaitFetch) - 底层请求工具

### 📋 模版代码

#### Ant Design Vue 适配模版

Ant Design Vue 的 Table 组件需要特定的分页对象格式，建议使用 `computed` 进行转换：

```vue
<script setup>
import { computed } from 'vue'
import { useTableRequest } from 'xn-fe-tools'

const {
  data,
  loading,
  pagination,
  onPageChange,
  onSizeChange
} = useTableRequest(fetchData, {
  // ...
})

// 核心转换逻辑
const antdPagination = computed(() => ({
  current: pagination.value.page,
  pageSize: pagination.value.pageSize,
  total: pagination.value.total,
  showSizeChanger: true,
  onChange: onPageChange,
  onShowSizeChange: (_: number, size: number) => onSizeChange(size)
}))

const handleTableChange = (pag) => {
  onPageChange(pag.current)
  if (pag.pageSize !== pagination.value.pageSize) {
    onSizeChange(pag.pageSize)
  }
}
</script>

<template>
  <a-table
    :dataSource="data"
    :loading="loading"
    :pagination="antdPagination"
    @change="handleTableChange"
  />
</template>
```
