@robot-admin/request-core 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +426 -0
- package/dist/index.cjs +1130 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +644 -0
- package/dist/index.d.ts +644 -0
- package/dist/index.js +1107 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# @robot-admin/request-core
|
|
2
|
+
|
|
3
|
+
> 统一请求核心库:Axios 封装(7 个插件)+ useTableCrud Composable
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@robot-admin/request-core)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
**[English](#english) | [中文文档](#中文文档)**
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 中文文档
|
|
13
|
+
|
|
14
|
+
### ✨ 核心功能
|
|
15
|
+
|
|
16
|
+
#### 1. Axios 封装(7 个内置插件)
|
|
17
|
+
|
|
18
|
+
- **cache**: 请求缓存(内存缓存,支持 TTL)
|
|
19
|
+
- **retry**: 请求重试(指数退避)
|
|
20
|
+
- **dedupe**: 请求去重(基于 AbortController)
|
|
21
|
+
- **cancel**: 自动取消(路由切换时)
|
|
22
|
+
- **request**: 通用请求逻辑(reLogin 管理)
|
|
23
|
+
- **response**: 通用响应逻辑(预留)
|
|
24
|
+
- **reLogin**: 重新登录管理(Promise 队列)
|
|
25
|
+
|
|
26
|
+
#### 2. useTableCrud Composable
|
|
27
|
+
|
|
28
|
+
- 配置驱动的表格 CRUD 解决方案
|
|
29
|
+
- 支持分页、搜索、排序、自定义操作
|
|
30
|
+
- 内置详情查看、编辑、删除等功能
|
|
31
|
+
|
|
32
|
+
### 📦 安装
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @robot-admin/request-core
|
|
36
|
+
# 或
|
|
37
|
+
bun add @robot-admin/request-core
|
|
38
|
+
# 或
|
|
39
|
+
pnpm add @robot-admin/request-core
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 🚀 快速开始
|
|
43
|
+
|
|
44
|
+
#### 1. 初始化 Request Core
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// main.ts
|
|
48
|
+
import { createApp } from "vue";
|
|
49
|
+
import { createRequestCore, onReLoginSuccess } from "@robot-admin/request-core";
|
|
50
|
+
import { useUserStore } from "@/stores/user";
|
|
51
|
+
|
|
52
|
+
const app = createApp(App);
|
|
53
|
+
|
|
54
|
+
const requestCore = createRequestCore({
|
|
55
|
+
request: {
|
|
56
|
+
baseURL: import.meta.env.VITE_API_BASE,
|
|
57
|
+
timeout: 10000,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// 🎯 配置成功状态码(适配不同后端约定)
|
|
61
|
+
// 默认: [200, 0, '200', '0']
|
|
62
|
+
// successCodes: [1, '1', 'success'], // 示例:自定义成功码
|
|
63
|
+
|
|
64
|
+
// 🎯 配置字段别名(适配不同后端响应格式)
|
|
65
|
+
// fieldAliases: {
|
|
66
|
+
// data: ['data', 'result', 'payload'], // 数据层字段
|
|
67
|
+
// list: ['list', 'items', 'records'], // 列表字段
|
|
68
|
+
// total: ['total', 'totalCount', 'count'], // 总数字段
|
|
69
|
+
// },
|
|
70
|
+
|
|
71
|
+
interceptors: {
|
|
72
|
+
// 请求拦截:注入 token
|
|
73
|
+
request: (config) => {
|
|
74
|
+
const token = localStorage.getItem("token");
|
|
75
|
+
if (token) {
|
|
76
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
77
|
+
}
|
|
78
|
+
return config;
|
|
79
|
+
},
|
|
80
|
+
// 响应拦截:处理业务码
|
|
81
|
+
response: (response) => {
|
|
82
|
+
const { code, message } = response.data;
|
|
83
|
+
if (code !== 200) {
|
|
84
|
+
window.$message?.error(message || "请求失败");
|
|
85
|
+
return Promise.reject(new Error(message));
|
|
86
|
+
}
|
|
87
|
+
return response;
|
|
88
|
+
},
|
|
89
|
+
// 响应错误拦截:处理 401
|
|
90
|
+
responseError: async (error) => {
|
|
91
|
+
if (error.response?.status === 401) {
|
|
92
|
+
const userStore = useUserStore();
|
|
93
|
+
await userStore.reLogin();
|
|
94
|
+
onReLoginSuccess(); // 通知所有等待的请求继续
|
|
95
|
+
return Promise.reject(error);
|
|
96
|
+
}
|
|
97
|
+
return Promise.reject(error);
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
app.use(requestCore);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 🎯 高级配置:适配不同的后端接口
|
|
106
|
+
|
|
107
|
+
##### 场景 1:后端返回的成功码不是 `0` 或 `200`
|
|
108
|
+
|
|
109
|
+
如果你的后端 API 返回的成功码是 `1`、`'success'` 或其他值,可以通过 `successCodes` 配置:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const requestCore = createRequestCore({
|
|
113
|
+
request: { baseURL: "/api" },
|
|
114
|
+
|
|
115
|
+
// 配置成功状态码
|
|
116
|
+
successCodes: [1, "1", "success"], // 支持数字和字符串
|
|
117
|
+
|
|
118
|
+
interceptors: {
|
|
119
|
+
response: (response) => {
|
|
120
|
+
const { code, message } = response.data;
|
|
121
|
+
// 自动判断 code 是否在 successCodes 中
|
|
122
|
+
if (![1, "1", "success"].includes(code)) {
|
|
123
|
+
window.$message?.error(message || "请求失败");
|
|
124
|
+
return Promise.reject(new Error(message));
|
|
125
|
+
}
|
|
126
|
+
return response;
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
##### 场景 2:后端返回的字段名不标准
|
|
133
|
+
|
|
134
|
+
如果你的后端 API 返回的字段名不是 `list`、`total`,可以通过 `fieldAliases` 配置:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
// 示例:后端返回格式
|
|
138
|
+
// {
|
|
139
|
+
// code: 0,
|
|
140
|
+
// result: {
|
|
141
|
+
// employees: [...], // 列表字段叫 employees
|
|
142
|
+
// totalRecords: 100 // 总数字段叫 totalRecords
|
|
143
|
+
// }
|
|
144
|
+
// }
|
|
145
|
+
|
|
146
|
+
const requestCore = createRequestCore({
|
|
147
|
+
request: { baseURL: "/api" },
|
|
148
|
+
|
|
149
|
+
// 配置字段别名
|
|
150
|
+
fieldAliases: {
|
|
151
|
+
data: ["result", "data", "payload"], // 数据层字段(按优先级)
|
|
152
|
+
list: ["employees", "items", "list"], // 列表字段(按优先级)
|
|
153
|
+
total: ["totalRecords", "total", "count"], // 总数字段(按优先级)
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
interceptors: { /* ... */ },
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// 现在 useTableCrud 会自动识别这些字段,无需手动配置 extractListData!
|
|
160
|
+
const table = useTableCrud({
|
|
161
|
+
api: { list: "/employees/list" }, // ✅ 自动适配
|
|
162
|
+
columns: [...],
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
##### 场景 3:单个接口特殊格式(临时覆盖)
|
|
167
|
+
|
|
168
|
+
如果只是某个特殊接口格式不同,可以在配置中单独处理:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const table = useTableCrud({
|
|
172
|
+
api: { list: "/special/api" },
|
|
173
|
+
columns: [...],
|
|
174
|
+
|
|
175
|
+
// 针对特殊接口的自定义提取逻辑
|
|
176
|
+
extractListData: (response: any) => {
|
|
177
|
+
return {
|
|
178
|
+
items: response.result?.specialList || [],
|
|
179
|
+
total: response.result?.specialCount || 0,
|
|
180
|
+
};
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### 2. 使用 useTableCrud
|
|
186
|
+
|
|
187
|
+
```vue
|
|
188
|
+
<script setup lang="ts">
|
|
189
|
+
import { useTableCrud } from "@robot-admin/request-core";
|
|
190
|
+
|
|
191
|
+
interface Employee {
|
|
192
|
+
id: number;
|
|
193
|
+
name: string;
|
|
194
|
+
age: number;
|
|
195
|
+
department: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const table = useTableCrud<Employee>({
|
|
199
|
+
api: {
|
|
200
|
+
list: "/api/employees/list",
|
|
201
|
+
get: "/api/employees/:id",
|
|
202
|
+
update: "/api/employees/:id",
|
|
203
|
+
remove: "/api/employees/:id",
|
|
204
|
+
create: "/api/employees",
|
|
205
|
+
},
|
|
206
|
+
columns: [
|
|
207
|
+
{ key: "id", title: "ID", width: 80 },
|
|
208
|
+
{ key: "name", title: "姓名", width: 120 },
|
|
209
|
+
{ key: "age", title: "年龄", width: 80 },
|
|
210
|
+
{ key: "department", title: "部门", width: 150 },
|
|
211
|
+
],
|
|
212
|
+
customActions: [
|
|
213
|
+
{
|
|
214
|
+
key: "export",
|
|
215
|
+
label: "导出",
|
|
216
|
+
icon: "mdi:download",
|
|
217
|
+
handler: (row, ctx) => {
|
|
218
|
+
console.log("导出", row);
|
|
219
|
+
ctx.message.success("导出成功");
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
});
|
|
224
|
+
</script>
|
|
225
|
+
|
|
226
|
+
<template>
|
|
227
|
+
<div>
|
|
228
|
+
<!-- 搜索栏 -->
|
|
229
|
+
<n-space>
|
|
230
|
+
<n-input
|
|
231
|
+
v-model:value="table.searchKeyword.value"
|
|
232
|
+
placeholder="搜索..."
|
|
233
|
+
/>
|
|
234
|
+
<n-button @click="table.search()">搜索</n-button>
|
|
235
|
+
<n-button @click="table.resetSearch()">重置</n-button>
|
|
236
|
+
</n-space>
|
|
237
|
+
|
|
238
|
+
<!-- 表格 -->
|
|
239
|
+
<n-data-table
|
|
240
|
+
ref="table.tableRef.value"
|
|
241
|
+
:data="table.data.value"
|
|
242
|
+
:columns="table.columns.value"
|
|
243
|
+
:loading="table.loading.value"
|
|
244
|
+
:pagination="table.pagination"
|
|
245
|
+
/>
|
|
246
|
+
</div>
|
|
247
|
+
</template>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### 3. 使用插件配置
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import { getData, postData } from "@robot-admin/request-core";
|
|
254
|
+
|
|
255
|
+
// 1. 开启缓存(5 分钟)
|
|
256
|
+
const users = await getData("/api/users", {
|
|
257
|
+
cache: { enabled: true, ttl: 300000 },
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// 2. 开启重试(3 次,指数退避)
|
|
261
|
+
const data = await postData(
|
|
262
|
+
"/api/submit",
|
|
263
|
+
{ name: "张三" },
|
|
264
|
+
{
|
|
265
|
+
retry: { enabled: true, count: 3, exponentialBackoff: true },
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
// 3. 禁用去重
|
|
270
|
+
const data = await getData("/api/timestamp", {
|
|
271
|
+
dedupe: { enabled: false },
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// 4. 白名单(不自动取消)
|
|
275
|
+
const data = await getData("/api/important", {
|
|
276
|
+
cancel: { enabled: false },
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 📖 API 文档
|
|
281
|
+
|
|
282
|
+
#### createRequestCore(config)
|
|
283
|
+
|
|
284
|
+
创建 Request Core 实例。
|
|
285
|
+
|
|
286
|
+
**参数:**
|
|
287
|
+
|
|
288
|
+
- `config.request` - Axios 基础配置(baseURL, timeout, headers 等)
|
|
289
|
+
- `config.successCodes` - 成功状态码配置(默认: `[200, 0, '200', '0']`)
|
|
290
|
+
- `config.fieldAliases` - 字段别名配置(用于适配不同的后端响应格式)
|
|
291
|
+
- `data` - 数据层字段别名(默认: `['data', 'list', 'items', 'records']`)
|
|
292
|
+
- `list` - 列表字段别名(默认: `['list', 'items', 'records', 'rows', 'data']`)
|
|
293
|
+
- `total` - 总数字段别名(默认: `['total', 'totalCount', 'count', 'totalElements']`)
|
|
294
|
+
- `config.interceptors` - 拦截器配置
|
|
295
|
+
- `request` - 请求拦截器
|
|
296
|
+
- `requestError` - 请求错误拦截器
|
|
297
|
+
- `response` - 响应拦截器
|
|
298
|
+
- `responseError` - 响应错误拦截器
|
|
299
|
+
|
|
300
|
+
**返回:**
|
|
301
|
+
|
|
302
|
+
- `install(app)` - Vue 插件安装方法
|
|
303
|
+
- `axiosInstance` - Axios 实例
|
|
304
|
+
|
|
305
|
+
#### useTableCrud\<T\>(config)
|
|
306
|
+
|
|
307
|
+
创建表格 CRUD 实例。
|
|
308
|
+
|
|
309
|
+
**参数:**
|
|
310
|
+
|
|
311
|
+
- `api` - API 端点配置(list, get, create, update, remove)
|
|
312
|
+
- `columns` - 表格列配置
|
|
313
|
+
- `customActions` - 自定义操作按钮
|
|
314
|
+
- `idKey` - ID 字段名(默认 'id')
|
|
315
|
+
- `defaultPageSize` - 默认分页大小(默认 10)
|
|
316
|
+
- `autoLoad` - 是否自动加载(默认 true)
|
|
317
|
+
|
|
318
|
+
**返回对象包含:**
|
|
319
|
+
|
|
320
|
+
- `data` - 表格数据
|
|
321
|
+
- `loading` - 加载状态
|
|
322
|
+
- `total` - 总数
|
|
323
|
+
- `pagination` - 分页配置
|
|
324
|
+
- `search()` - 搜索方法
|
|
325
|
+
- `resetSearch()` - 重置搜索
|
|
326
|
+
- `refresh()` - 刷新数据
|
|
327
|
+
- `viewDetail(row)` - 查看详情
|
|
328
|
+
- `handleEdit(row)` - 编辑
|
|
329
|
+
- `handleDelete(row)` - 删除
|
|
330
|
+
|
|
331
|
+
### 🔌 插件配置
|
|
332
|
+
|
|
333
|
+
所有请求方法(`getData`, `postData`, `putData`, `deleteData`)都支持以下插件配置:
|
|
334
|
+
|
|
335
|
+
| 插件 | 配置项 | 说明 |
|
|
336
|
+
| ---------- | ------------------------------------------------- | ------------------ |
|
|
337
|
+
| **cache** | `enabled`, `ttl`, `forceUpdate` | 请求缓存(仅 GET) |
|
|
338
|
+
| **retry** | `enabled`, `count`, `delay`, `exponentialBackoff` | 请求重试 |
|
|
339
|
+
| **dedupe** | `enabled`, `keyGenerator` | 请求去重 |
|
|
340
|
+
| **cancel** | `enabled`, `whitelist` | 自动取消 |
|
|
341
|
+
|
|
342
|
+
### 📝 类型导出
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
// 核心类型
|
|
346
|
+
export type {
|
|
347
|
+
RequestCoreConfig,
|
|
348
|
+
InterceptorConfig,
|
|
349
|
+
EnhancedAxiosRequestConfig,
|
|
350
|
+
|
|
351
|
+
// CRUD 类型
|
|
352
|
+
UseTableCrudConfig,
|
|
353
|
+
UseTableCrudReturn,
|
|
354
|
+
DataRecord,
|
|
355
|
+
ApiEndpoints,
|
|
356
|
+
TableColumn,
|
|
357
|
+
CustomAction,
|
|
358
|
+
DetailConfig,
|
|
359
|
+
|
|
360
|
+
// 插件类型
|
|
361
|
+
CacheConfig,
|
|
362
|
+
RetryConfig,
|
|
363
|
+
DedupeConfig,
|
|
364
|
+
CancelConfig,
|
|
365
|
+
};
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 🛠️ 开发
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# 安装依赖
|
|
372
|
+
bun install
|
|
373
|
+
|
|
374
|
+
# 开发模式(watch)
|
|
375
|
+
bun run dev
|
|
376
|
+
|
|
377
|
+
# 构建
|
|
378
|
+
bun run build
|
|
379
|
+
|
|
380
|
+
# 类型检查
|
|
381
|
+
bun run type-check
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 📄 License
|
|
385
|
+
|
|
386
|
+
MIT © [ChenYu](mailto:ycyplus@gmail.com)
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## English
|
|
391
|
+
|
|
392
|
+
### ✨ Features
|
|
393
|
+
|
|
394
|
+
#### 1. Axios with 7 Built-in Plugins
|
|
395
|
+
|
|
396
|
+
- **cache**: Request caching (in-memory with TTL support)
|
|
397
|
+
- **retry**: Request retry (exponential backoff)
|
|
398
|
+
- **dedupe**: Request deduplication (AbortController-based)
|
|
399
|
+
- **cancel**: Auto-cancel on route change
|
|
400
|
+
- **request**: Common request logic (reLogin management)
|
|
401
|
+
- **response**: Common response logic (reserved for user config)
|
|
402
|
+
- **reLogin**: Re-login management (Promise queue)
|
|
403
|
+
|
|
404
|
+
#### 2. useTableCrud Composable
|
|
405
|
+
|
|
406
|
+
- Configuration-driven table CRUD solution
|
|
407
|
+
- Supports pagination, search, sort, custom actions
|
|
408
|
+
- Built-in detail view, edit, delete features
|
|
409
|
+
|
|
410
|
+
### 📦 Installation
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
npm install @robot-admin/request-core
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### 🚀 Quick Start
|
|
417
|
+
|
|
418
|
+
See Chinese documentation above for detailed usage examples.
|
|
419
|
+
|
|
420
|
+
### 📝 Type Exports
|
|
421
|
+
|
|
422
|
+
All TypeScript types are fully exported. See the types section in Chinese docs.
|
|
423
|
+
|
|
424
|
+
### 📄 License
|
|
425
|
+
|
|
426
|
+
MIT © [ChenYu](mailto:ycyplus@gmail.com)
|