excel-csv-handler 1.1.0 → 1.1.1
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/package.json +1 -1
- package/src/excel-csv-handler.d.ts +56 -0
- package/src/index.js +143 -0
package/package.json
CHANGED
|
@@ -59,4 +59,60 @@ export default class ExcelCsvHandler {
|
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
61
|
static getAbsolutePath(importMetaUrl: string, relativePath: string): string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 自动分页请求并汇总所有数据
|
|
65
|
+
* @param requestFn - 请求函数,接收一个参数对象,如 { pageNum: 1, pageSize: 50 }
|
|
66
|
+
* @param config - 配置对象
|
|
67
|
+
* @returns 完整的列表数据
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* // 基本用法(使用默认的 pageNum 和 pageSize)
|
|
72
|
+
* const data = await ExcelCsvHandler.getPagination(fetchFn, {
|
|
73
|
+
* listPath: 'data.list',
|
|
74
|
+
* totalPath: 'data.total',
|
|
75
|
+
* pageSize: 50
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* // 自定义页码字段名
|
|
79
|
+
* const data = await ExcelCsvHandler.getPagination(fetchFn, {
|
|
80
|
+
* listPath: 'result.items',
|
|
81
|
+
* totalPath: 'result.count',
|
|
82
|
+
* pageSize: 100,
|
|
83
|
+
* pageNumKey: 'page', // 使用 page 而不是 pageNum
|
|
84
|
+
* pageSizeKey: 'size' // 使用 size 而不是 pageSize
|
|
85
|
+
* });
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
static getPagination<T = any>(
|
|
89
|
+
requestFn: (params: Record<string, any>) => Promise<any>,
|
|
90
|
+
config: PaginationConfig
|
|
91
|
+
): Promise<T[]>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 分页请求配置对象
|
|
96
|
+
*/
|
|
97
|
+
export interface PaginationConfig {
|
|
98
|
+
/**
|
|
99
|
+
* 列表数据的属性路径,如 'data.pageData.list'
|
|
100
|
+
*/
|
|
101
|
+
listPath: string;
|
|
102
|
+
/**
|
|
103
|
+
* 总数量的属性路径,如 'data.pageData.count'
|
|
104
|
+
*/
|
|
105
|
+
totalPath: string;
|
|
106
|
+
/**
|
|
107
|
+
* 每页大小
|
|
108
|
+
*/
|
|
109
|
+
pageSize: number;
|
|
110
|
+
/**
|
|
111
|
+
* 请求参数中页码的字段名,默认 'pageNum'
|
|
112
|
+
*/
|
|
113
|
+
pageNumKey?: string;
|
|
114
|
+
/**
|
|
115
|
+
* 请求参数中每页大小的字段名,默认 'pageSize'
|
|
116
|
+
*/
|
|
117
|
+
pageSizeKey?: string;
|
|
62
118
|
}
|
package/src/index.js
CHANGED
|
@@ -277,6 +277,149 @@ ExcelCsvHandler.getAbsolutePath = function (importMetaUrl, relativePath) {
|
|
|
277
277
|
return path.join(__dirname, cleanPath);
|
|
278
278
|
};
|
|
279
279
|
|
|
280
|
+
/**
|
|
281
|
+
* 自动分页请求并汇总所有数据
|
|
282
|
+
* @param {Function} requestFn - 请求函数,接收一个参数对象,如 { pageNum: 1, pageSize: 50 }
|
|
283
|
+
* @param {Object} config - 配置对象
|
|
284
|
+
* @param {string} config.listPath - 列表数据的属性路径,如 'data.pageData.list'
|
|
285
|
+
* @param {string} config.totalPath - 总数量的属性路径,如 'data.pageData.count'
|
|
286
|
+
* @param {number} config.pageSize - 每页大小
|
|
287
|
+
* @param {string} [config.pageNumKey='pageNum'] - 请求参数中页码的字段名,默认 'pageNum'
|
|
288
|
+
* @param {string} [config.pageSizeKey='pageSize'] - 请求参数中每页大小的字段名,默认 'pageSize'
|
|
289
|
+
* @returns {Promise<Array>} 完整的列表数据
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* // 基本用法(使用默认的 pageNum 和 pageSize)
|
|
293
|
+
* const data = await ExcelCsvHandler.getPagination(fetchFn, {
|
|
294
|
+
* listPath: 'data.list',
|
|
295
|
+
* totalPath: 'data.total',
|
|
296
|
+
* pageSize: 50
|
|
297
|
+
* });
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* // 自定义页码字段名
|
|
301
|
+
* const data = await ExcelCsvHandler.getPagination(fetchFn, {
|
|
302
|
+
* listPath: 'result.items',
|
|
303
|
+
* totalPath: 'result.count',
|
|
304
|
+
* pageSize: 100,
|
|
305
|
+
* pageNumKey: 'page', // 使用 page 而不是 pageNum
|
|
306
|
+
* pageSizeKey: 'size' // 使用 size 而不是 pageSize
|
|
307
|
+
* });
|
|
308
|
+
*/
|
|
309
|
+
ExcelCsvHandler.getPagination = async function (requestFn, config) {
|
|
310
|
+
// 参数校验
|
|
311
|
+
if (typeof requestFn !== 'function') {
|
|
312
|
+
throw new Error('请求函数必须是一个函数');
|
|
313
|
+
}
|
|
314
|
+
if (!config || typeof config !== 'object') {
|
|
315
|
+
throw new Error('配置参数必须是一个对象');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const {
|
|
319
|
+
listPath,
|
|
320
|
+
totalPath,
|
|
321
|
+
pageSize,
|
|
322
|
+
pageNumKey = 'pageNum',
|
|
323
|
+
pageSizeKey = 'pageSize'
|
|
324
|
+
} = config;
|
|
325
|
+
|
|
326
|
+
if (!listPath || typeof listPath !== 'string') {
|
|
327
|
+
throw new Error('列表路径(listPath)必须是一个字符串');
|
|
328
|
+
}
|
|
329
|
+
if (!totalPath || typeof totalPath !== 'string') {
|
|
330
|
+
throw new Error('总数量路径(totalPath)必须是一个字符串');
|
|
331
|
+
}
|
|
332
|
+
if (!pageSize || pageSize <= 0) {
|
|
333
|
+
throw new Error('每页大小(pageSize)必须大于0');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 根据路径获取对象属性值
|
|
338
|
+
* @param {Object} obj - 源对象
|
|
339
|
+
* @param {string} path - 属性路径,如 'data.pageData.list'
|
|
340
|
+
*/
|
|
341
|
+
function getValueByPath(obj, path) {
|
|
342
|
+
return path.split('.').reduce((current, key) => current?.[key], obj);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
// 第一次请求,获取总数量和第一页数据
|
|
347
|
+
console.log(`开始分页请求,每页 ${pageSize} 条...`);
|
|
348
|
+
console.log(`使用参数名: ${pageNumKey}(页码), ${pageSizeKey}(每页大小)`);
|
|
349
|
+
|
|
350
|
+
const firstPageParams = {
|
|
351
|
+
[pageNumKey]: 1,
|
|
352
|
+
[pageSizeKey]: pageSize
|
|
353
|
+
};
|
|
354
|
+
const firstResponse = await requestFn(firstPageParams);
|
|
355
|
+
|
|
356
|
+
// 获取第一页数据和总数量
|
|
357
|
+
const firstPageList = getValueByPath(firstResponse, listPath);
|
|
358
|
+
const total = getValueByPath(firstResponse, totalPath);
|
|
359
|
+
|
|
360
|
+
if (!Array.isArray(firstPageList)) {
|
|
361
|
+
throw new Error(`无法从响应中获取列表数据,路径: ${listPath}`);
|
|
362
|
+
}
|
|
363
|
+
if (typeof total !== 'number') {
|
|
364
|
+
throw new Error(`无法从响应中获取总数量,路径: ${totalPath}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
console.log(`总计 ${total} 条数据`);
|
|
368
|
+
|
|
369
|
+
// 如果总数量为 0 或第一页已经包含所有数据,直接返回
|
|
370
|
+
if (total === 0) {
|
|
371
|
+
console.log('没有数据');
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
if (total <= pageSize) {
|
|
375
|
+
console.log('所有数据已在第一页');
|
|
376
|
+
return firstPageList;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 计算总页数
|
|
380
|
+
const totalPages = Math.ceil(total / pageSize);
|
|
381
|
+
console.log(`需要请求 ${totalPages} 页`);
|
|
382
|
+
|
|
383
|
+
// 初始化结果数组,先放入第一页数据
|
|
384
|
+
const allData = [...firstPageList];
|
|
385
|
+
|
|
386
|
+
// 请求剩余的页面
|
|
387
|
+
const requests = [];
|
|
388
|
+
for (let page = 2; page <= totalPages; page++) {
|
|
389
|
+
const pageParams = {
|
|
390
|
+
[pageNumKey]: page,
|
|
391
|
+
[pageSizeKey]: pageSize
|
|
392
|
+
};
|
|
393
|
+
requests.push(
|
|
394
|
+
requestFn(pageParams).then(response => {
|
|
395
|
+
const pageList = getValueByPath(response, listPath);
|
|
396
|
+
if (!Array.isArray(pageList)) {
|
|
397
|
+
console.warn(`第 ${page} 页数据格式错误`);
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
console.log(`第 ${page}/${totalPages} 页请求完成,获取 ${pageList.length} 条数据`);
|
|
401
|
+
return pageList;
|
|
402
|
+
})
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 并发请求所有剩余页面
|
|
407
|
+
const remainingPages = await Promise.all(requests);
|
|
408
|
+
|
|
409
|
+
// 合并所有数据
|
|
410
|
+
remainingPages.forEach(pageData => {
|
|
411
|
+
allData.push(...pageData);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
console.log(`分页请求完成,共获取 ${allData.length} 条数据`);
|
|
415
|
+
return allData;
|
|
416
|
+
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.error('分页请求失败:', error.message);
|
|
419
|
+
throw error;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
280
423
|
export default ExcelCsvHandler;
|
|
281
424
|
|
|
282
425
|
// 示例用法(取消注释可测试)
|