@robot-admin/request-core 0.2.0 → 0.4.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +248 -357
  4. package/SECURITY.md +14 -0
  5. package/dist/axios.cjs +134 -809
  6. package/dist/axios.cjs.map +1 -1
  7. package/dist/axios.d.cts +55 -220
  8. package/dist/axios.d.ts +55 -220
  9. package/dist/axios.js +2 -790
  10. package/dist/axios.js.map +1 -1
  11. package/dist/chunk-2JXH7SIL.js +711 -0
  12. package/dist/chunk-2JXH7SIL.js.map +1 -0
  13. package/dist/chunk-56QOEWUS.js +8 -0
  14. package/dist/chunk-56QOEWUS.js.map +1 -0
  15. package/dist/chunk-DUP3Y4DN.js +320 -0
  16. package/dist/chunk-DUP3Y4DN.js.map +1 -0
  17. package/dist/chunk-JGFRUAZT.cjs +1007 -0
  18. package/dist/chunk-JGFRUAZT.cjs.map +1 -0
  19. package/dist/chunk-KHI6XQRN.cjs +717 -0
  20. package/dist/chunk-KHI6XQRN.cjs.map +1 -0
  21. package/dist/chunk-OAZ5BUBU.js +969 -0
  22. package/dist/chunk-OAZ5BUBU.js.map +1 -0
  23. package/dist/chunk-QSDNDTOZ.js +28 -0
  24. package/dist/chunk-QSDNDTOZ.js.map +1 -0
  25. package/dist/chunk-UHXBAFY6.cjs +323 -0
  26. package/dist/chunk-UHXBAFY6.cjs.map +1 -0
  27. package/dist/chunk-WUZ43MLM.cjs +30 -0
  28. package/dist/chunk-WUZ43MLM.cjs.map +1 -0
  29. package/dist/chunk-WXHQXPS4.cjs +10 -0
  30. package/dist/chunk-WXHQXPS4.cjs.map +1 -0
  31. package/dist/crud.cjs +12 -484
  32. package/dist/crud.cjs.map +1 -1
  33. package/dist/crud.d.cts +8 -269
  34. package/dist/crud.d.ts +8 -269
  35. package/dist/crud.js +4 -487
  36. package/dist/crud.js.map +1 -1
  37. package/dist/index.cjs +136 -1302
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +7 -165
  40. package/dist/index.d.ts +7 -165
  41. package/dist/index.js +5 -1283
  42. package/dist/index.js.map +1 -1
  43. package/dist/naive.cjs +14 -0
  44. package/dist/naive.cjs.map +1 -0
  45. package/dist/naive.d.cts +9 -0
  46. package/dist/naive.d.ts +9 -0
  47. package/dist/naive.js +5 -0
  48. package/dist/naive.js.map +1 -0
  49. package/dist/types-BRDRqYFs.d.cts +197 -0
  50. package/dist/types-BVJhlSuh.d.cts +310 -0
  51. package/dist/types-BVJhlSuh.d.ts +310 -0
  52. package/dist/types-CUyibJZX.d.ts +197 -0
  53. package/dist/vue.cjs +93 -0
  54. package/dist/vue.cjs.map +1 -0
  55. package/dist/vue.d.cts +38 -0
  56. package/dist/vue.d.ts +38 -0
  57. package/dist/vue.js +71 -0
  58. package/dist/vue.js.map +1 -0
  59. package/package.json +60 -16
@@ -0,0 +1,711 @@
1
+ import { normalizeRequestError, getData, postData, putData, RequestError, isCanceledError, deleteData, getGlobalConfig } from './chunk-OAZ5BUBU.js';
2
+ import { provide, inject, getCurrentInstance, shallowRef, ref, reactive, computed, getCurrentScope, onScopeDispose, onMounted } from 'vue';
3
+
4
+ var REQUEST_CLIENT_KEY = /* @__PURE__ */ Symbol.for(
5
+ "@robot-admin/request-core/vue-client/v1"
6
+ );
7
+ function createRequestPlugin(client) {
8
+ return {
9
+ install(app) {
10
+ app.provide(REQUEST_CLIENT_KEY, client);
11
+ }
12
+ };
13
+ }
14
+ function provideRequestClient(client) {
15
+ provide(REQUEST_CLIENT_KEY, client);
16
+ return client;
17
+ }
18
+ function useRequestClient(optional = false) {
19
+ const client = inject(REQUEST_CLIENT_KEY, void 0);
20
+ if (!client && !optional) {
21
+ throw new Error(
22
+ "Request client was not provided. Install createRequestPlugin(client) or pass client explicitly."
23
+ );
24
+ }
25
+ return client;
26
+ }
27
+
28
+ // src/composables/useTableCrud/constants.ts
29
+ var DEFAULT_CONFIG = {
30
+ /** 默认 ID 字段名 */
31
+ idKey: "id",
32
+ /** 默认分页大小 */
33
+ pageSize: 10,
34
+ /** 默认启用分页 */
35
+ paginationEnabled: true,
36
+ /** 默认当前页 */
37
+ currentPage: 1
38
+ };
39
+ var DATA_FIELD_ALIASES = ["data", "list", "items", "records"];
40
+ var LIST_FIELD_ALIASES = [
41
+ "list",
42
+ "items",
43
+ "records",
44
+ "rows",
45
+ "data"
46
+ ];
47
+ var TOTAL_FIELD_ALIASES = [
48
+ "total",
49
+ "totalCount",
50
+ "count",
51
+ "totalElements"
52
+ ];
53
+ var SUCCESS_CODES = [200, 0, "200", "0"];
54
+ var DEFAULT_MESSAGES = {
55
+ createSuccess: "\u65B0\u589E\u6210\u529F",
56
+ updateSuccess: "\u66F4\u65B0\u6210\u529F",
57
+ deleteSuccess: "\u5220\u9664\u6210\u529F",
58
+ saveError: "\u4FDD\u5B58\u5931\u8D25",
59
+ deleteError: "\u5220\u9664\u5931\u8D25",
60
+ loadError: "\u6570\u636E\u52A0\u8F7D\u5931\u8D25",
61
+ detailError: "\u8BE6\u60C5\u83B7\u53D6\u5931\u8D25",
62
+ noDeleteApi: "\u672A\u914D\u7F6E\u5220\u9664\u63A5\u53E3"
63
+ };
64
+
65
+ // src/composables/useTableCrud/utils.ts
66
+ function getRuntimeFieldAliases() {
67
+ const config = getGlobalConfig();
68
+ return {
69
+ data: config.fieldAliases.data || DATA_FIELD_ALIASES,
70
+ list: config.fieldAliases.list || LIST_FIELD_ALIASES,
71
+ total: config.fieldAliases.total || TOTAL_FIELD_ALIASES
72
+ };
73
+ }
74
+ function getRuntimeSuccessCodes() {
75
+ const config = getGlobalConfig();
76
+ return config.successCodes || SUCCESS_CODES;
77
+ }
78
+ var FieldFinder = {
79
+ /**
80
+ * 查找第一个存在的字段值
81
+ */
82
+ findFirst(obj, aliases, defaultValue) {
83
+ if (!obj || typeof obj !== "object") return defaultValue;
84
+ const record = obj;
85
+ for (const key of aliases) {
86
+ if (key in record && record[key] !== void 0) {
87
+ return record[key];
88
+ }
89
+ }
90
+ return defaultValue;
91
+ },
92
+ /**
93
+ * 查找第一个存在的数字字段
94
+ */
95
+ findNumber(obj, aliases, defaultValue = 0) {
96
+ const value = this.findFirst(obj, aliases, defaultValue);
97
+ const numberValue = Number(value);
98
+ return Number.isFinite(numberValue) ? numberValue : defaultValue;
99
+ }
100
+ };
101
+ var ResponseNormalizer = {
102
+ /**
103
+ * 判断响应是否成功
104
+ */
105
+ isSuccess(res) {
106
+ if (!res || typeof res !== "object") return false;
107
+ const record = res;
108
+ if (typeof record.success === "boolean") return record.success;
109
+ if (!("code" in record)) return true;
110
+ const successCodes = getRuntimeSuccessCodes();
111
+ return successCodes.includes(record.code) || successCodes.some((code) => String(code) === String(record.code));
112
+ },
113
+ /**
114
+ * 标准化响应数据(提取 data 层)
115
+ */
116
+ normalize(res) {
117
+ if (!res || typeof res !== "object") {
118
+ return { data: res, success: true, raw: res };
119
+ }
120
+ const aliases = getRuntimeFieldAliases();
121
+ const record = res;
122
+ const hasDataLayer = aliases.data.some((key) => key in record);
123
+ if (!hasDataLayer) {
124
+ return { data: res, success: ResponseNormalizer.isSuccess(res), raw: res };
125
+ }
126
+ return {
127
+ data: FieldFinder.findFirst(record, aliases.data, res),
128
+ success: ResponseNormalizer.isSuccess(res),
129
+ raw: res
130
+ };
131
+ }
132
+ };
133
+ var UrlUtils = {
134
+ /**
135
+ * 构建 URL(处理路径参数)
136
+ */
137
+ buildUrl(endpoint, id) {
138
+ if (id !== void 0 && endpoint.includes(":id")) {
139
+ return endpoint.replace(":id", encodeURIComponent(String(id)));
140
+ }
141
+ return endpoint;
142
+ }
143
+ };
144
+ var DataExtractor = {
145
+ /**
146
+ * 从响应中提取列表数据(支持多种格式)
147
+ *
148
+ * 支持的响应结构:
149
+ * 1. { code: 0, data: { list: [...], total: 10 } } // 嵌套结构(最常见)
150
+ * 2. { data: { items: [...], total: 10 } } // 嵌套结构
151
+ * 3. { list: [...], total: 10 } // 扁平结构
152
+ * 4. { items: [...], totalCount: 10 } // 不同字段名
153
+ * 5. { data: [...] } // 直接数组
154
+ * 6. [...] // 纯数组
155
+ */
156
+ extractList(response) {
157
+ const normalized = ResponseNormalizer.normalize(response);
158
+ const dataLayer = normalized.data;
159
+ const aliases = getRuntimeFieldAliases();
160
+ if (Array.isArray(dataLayer)) {
161
+ const rootTotal2 = FieldFinder.findNumber(
162
+ response && typeof response === "object" ? response : null,
163
+ aliases.total,
164
+ dataLayer.length
165
+ );
166
+ return { items: dataLayer, total: rootTotal2 };
167
+ }
168
+ if (!dataLayer || typeof dataLayer !== "object") {
169
+ return { items: [], total: 0 };
170
+ }
171
+ const list = FieldFinder.findFirst(dataLayer, aliases.list, []);
172
+ const rootTotal = FieldFinder.findNumber(
173
+ response && typeof response === "object" ? response : null,
174
+ aliases.total,
175
+ Array.isArray(list) ? list.length : 0
176
+ );
177
+ const total = FieldFinder.findNumber(dataLayer, aliases.total, rootTotal);
178
+ return {
179
+ items: Array.isArray(list) ? list : [],
180
+ total
181
+ };
182
+ },
183
+ /**
184
+ * 从响应中提取详情数据
185
+ */
186
+ extractDetail(response) {
187
+ const normalized = ResponseNormalizer.normalize(response);
188
+ return normalized.data;
189
+ }
190
+ };
191
+ var RowUtils = {
192
+ /**
193
+ * 从数组中查找行索引
194
+ */
195
+ findIndex(items, idKey, id) {
196
+ return items.findIndex((item) => item[idKey] === id);
197
+ },
198
+ /**
199
+ * 从数组中移除行
200
+ */
201
+ remove(items, idKey, id) {
202
+ const index = this.findIndex(items, idKey, id);
203
+ if (index !== -1) {
204
+ items.splice(index, 1);
205
+ return true;
206
+ }
207
+ return false;
208
+ },
209
+ /**
210
+ * 生成默认 ID
211
+ */
212
+ generateId() {
213
+ return Date.now() + Math.floor(Math.random() * 1e3);
214
+ }
215
+ };
216
+
217
+ // src/composables/useTableCrud/useTableCrud.ts
218
+ var noopMessage = {
219
+ success: () => void 0,
220
+ error: () => void 0,
221
+ warning: () => void 0,
222
+ info: () => void 0
223
+ };
224
+ var noopDialog = {
225
+ warning: () => void 0,
226
+ error: () => void 0,
227
+ success: () => void 0,
228
+ info: () => void 0
229
+ };
230
+ function cloneValue(value) {
231
+ if (typeof structuredClone === "function") {
232
+ try {
233
+ return structuredClone(value);
234
+ } catch {
235
+ }
236
+ }
237
+ return Array.isArray(value) ? [...value] : value && typeof value === "object" ? { ...value } : value;
238
+ }
239
+ function recordValue(row, key) {
240
+ return row[key];
241
+ }
242
+ function asQueryResult(value) {
243
+ if (!value || typeof value !== "object") return null;
244
+ const candidate = value;
245
+ return Array.isArray(candidate.items) && Number.isFinite(candidate.total) ? { items: candidate.items, total: Number(candidate.total) } : null;
246
+ }
247
+ function useTableCrud(config) {
248
+ const {
249
+ api,
250
+ query,
251
+ mutations = {},
252
+ columns = [],
253
+ customActions = [],
254
+ detail: detailConfig,
255
+ idKey = DEFAULT_CONFIG.idKey,
256
+ defaultPageSize = DEFAULT_CONFIG.pageSize,
257
+ defaultPaginationEnabled = DEFAULT_CONFIG.paginationEnabled,
258
+ initialFilters = {},
259
+ initialSort = null,
260
+ createNewRow,
261
+ autoLoad = true,
262
+ extractListData,
263
+ refreshAfterMutation = true,
264
+ batchConcurrency = 4,
265
+ detailTitle
266
+ } = config;
267
+ if (!query && !api?.list) {
268
+ throw new Error("useTableCrud requires either query or api.list.");
269
+ }
270
+ if (!Number.isInteger(batchConcurrency) || batchConcurrency < 1) {
271
+ throw new RangeError("batchConcurrency must be an integer greater than 0.");
272
+ }
273
+ const injectedClient = getCurrentInstance() ? useRequestClient(true) : void 0;
274
+ const client = config.client ?? injectedClient;
275
+ const message = config.ui?.message ?? noopMessage;
276
+ const dialog = config.ui?.dialog ?? noopDialog;
277
+ const notify = (type, text) => {
278
+ try {
279
+ void Promise.resolve(message[type](text)).catch(() => void 0);
280
+ } catch {
281
+ }
282
+ };
283
+ const data = shallowRef([]);
284
+ const total = ref(0);
285
+ const tableRef = ref();
286
+ const paginationEnabled = ref(defaultPaginationEnabled);
287
+ const filters = ref(cloneValue(initialFilters));
288
+ const sort = ref(cloneValue(initialSort));
289
+ const error = shallowRef(null);
290
+ const lastUpdated = ref(null);
291
+ const page = reactive({
292
+ current: DEFAULT_CONFIG.currentPage,
293
+ size: defaultPageSize
294
+ });
295
+ const counts = reactive({
296
+ refresh: 0,
297
+ detail: 0,
298
+ create: 0,
299
+ update: 0,
300
+ remove: 0
301
+ });
302
+ const controllers = /* @__PURE__ */ new Set();
303
+ let refreshController = null;
304
+ let refreshSequence = 0;
305
+ let disposed = false;
306
+ const loading = computed(() => Object.values(counts).some((count) => count > 0));
307
+ const isInitialLoading = computed(
308
+ () => counts.refresh > 0 && lastUpdated.value === null
309
+ );
310
+ const isRefreshing = computed(
311
+ () => counts.refresh > 0 && lastUpdated.value !== null
312
+ );
313
+ const creating = computed(() => counts.create > 0);
314
+ const updating = computed(() => counts.update > 0);
315
+ const removing = computed(() => counts.remove > 0);
316
+ const startOperation = (operation) => {
317
+ counts[operation] += 1;
318
+ const controller = new AbortController();
319
+ controllers.add(controller);
320
+ return controller;
321
+ };
322
+ const finishOperation = (operation, controller) => {
323
+ counts[operation] = Math.max(0, counts[operation] - 1);
324
+ controllers.delete(controller);
325
+ };
326
+ const reportError = async (cause, operation, fallbackMessage) => {
327
+ const normalized = normalizeRequestError(cause);
328
+ if (!isCanceledError(normalized)) {
329
+ error.value = normalized;
330
+ notify("error", fallbackMessage);
331
+ try {
332
+ await config.onError?.(normalized, operation);
333
+ } catch {
334
+ }
335
+ }
336
+ return normalized;
337
+ };
338
+ const detailVisible = ref(false);
339
+ const detailData = ref(null);
340
+ const detailTitleState = ref("");
341
+ const detail = {
342
+ visible: detailVisible,
343
+ data: detailData,
344
+ title: detailTitleState,
345
+ show: (row) => {
346
+ detailData.value = row;
347
+ detailTitleState.value = detailTitle?.(row) ?? `\u8BE6\u60C5 - ${String(
348
+ row.name ?? recordValue(row, idKey) ?? ""
349
+ )}`;
350
+ detailVisible.value = true;
351
+ },
352
+ close: () => {
353
+ detailVisible.value = false;
354
+ detailData.value = null;
355
+ detailTitleState.value = "";
356
+ }
357
+ };
358
+ const requestList = async (signal) => {
359
+ if (query) {
360
+ return query({
361
+ page: page.current,
362
+ pageSize: page.size,
363
+ paginationEnabled: paginationEnabled.value,
364
+ filters: filters.value,
365
+ sort: sort.value,
366
+ signal
367
+ });
368
+ }
369
+ const paginationParams = paginationEnabled.value ? { page: page.current, pageSize: page.size } : {};
370
+ const params = {
371
+ ...paginationParams,
372
+ ...filters.value,
373
+ ...sort.value ? { sort: sort.value } : {}
374
+ };
375
+ return client ? client.get(api.list, { params, signal, concurrency: "takeLatest" }) : getData(api.list, { params, signal, dedupe: true });
376
+ };
377
+ const refresh = async () => {
378
+ if (disposed) return;
379
+ refreshController?.abort();
380
+ const sequence = ++refreshSequence;
381
+ const controller = startOperation("refresh");
382
+ refreshController = controller;
383
+ error.value = null;
384
+ try {
385
+ const response = await requestList(controller.signal);
386
+ if (sequence !== refreshSequence || controller.signal.aborted) return;
387
+ const extracted = extractListData?.(response) ?? asQueryResult(response) ?? DataExtractor.extractList(response);
388
+ data.value = [...extracted.items];
389
+ total.value = extracted.total;
390
+ lastUpdated.value = Date.now();
391
+ } catch (cause) {
392
+ if (!controller.signal.aborted) {
393
+ await reportError(cause, "refresh", DEFAULT_MESSAGES.loadError);
394
+ }
395
+ } finally {
396
+ if (refreshController === controller) refreshController = null;
397
+ finishOperation("refresh", controller);
398
+ }
399
+ };
400
+ const maybeRefresh = async () => {
401
+ if (refreshAfterMutation) await refresh();
402
+ };
403
+ const getDetail = async (row) => {
404
+ if (!mutations.get && !api?.get) {
405
+ detail.show(row);
406
+ return row;
407
+ }
408
+ const controller = startOperation("detail");
409
+ try {
410
+ let result;
411
+ if (mutations.get) {
412
+ result = await mutations.get(row, { signal: controller.signal });
413
+ } else {
414
+ const url = UrlUtils.buildUrl(api.get, recordValue(row, idKey));
415
+ const response = client ? await client.get(url, { signal: controller.signal }) : await getData(url, { signal: controller.signal });
416
+ result = DataExtractor.extractDetail(response);
417
+ }
418
+ if (result) detail.show(result);
419
+ return result;
420
+ } catch (cause) {
421
+ if (!controller.signal.aborted) {
422
+ await reportError(cause, "detail", DEFAULT_MESSAGES.detailError);
423
+ }
424
+ return null;
425
+ } finally {
426
+ finishOperation("detail", controller);
427
+ }
428
+ };
429
+ const create = async (row) => {
430
+ if (!mutations.create && !api?.create) {
431
+ notify("warning", "\u672A\u914D\u7F6E\u65B0\u589E\u64CD\u4F5C");
432
+ return;
433
+ }
434
+ const controller = startOperation("create");
435
+ try {
436
+ if (mutations.create) {
437
+ await mutations.create(row, { signal: controller.signal });
438
+ } else if (client) {
439
+ await client.post(api.create, row, { signal: controller.signal });
440
+ } else {
441
+ await postData(api.create, row, { signal: controller.signal });
442
+ }
443
+ notify("success", DEFAULT_MESSAGES.createSuccess);
444
+ await maybeRefresh();
445
+ } catch (cause) {
446
+ throw await reportError(cause, "create", "\u65B0\u589E\u5931\u8D25");
447
+ } finally {
448
+ finishOperation("create", controller);
449
+ }
450
+ };
451
+ const save = async (row) => {
452
+ if (!mutations.update && !api?.update) {
453
+ notify("warning", "\u672A\u914D\u7F6E\u66F4\u65B0\u64CD\u4F5C");
454
+ return;
455
+ }
456
+ const controller = startOperation("update");
457
+ try {
458
+ if (mutations.update) {
459
+ await mutations.update(row, { signal: controller.signal });
460
+ } else {
461
+ const url = UrlUtils.buildUrl(api.update, recordValue(row, idKey));
462
+ if (client) await client.put(url, row, { signal: controller.signal });
463
+ else await putData(url, row, { signal: controller.signal });
464
+ }
465
+ notify("success", DEFAULT_MESSAGES.updateSuccess);
466
+ await maybeRefresh();
467
+ } catch (cause) {
468
+ throw await reportError(cause, "update", DEFAULT_MESSAGES.saveError);
469
+ } finally {
470
+ finishOperation("update", controller);
471
+ }
472
+ };
473
+ const removeOne = async (row, signal) => {
474
+ if (mutations.remove) {
475
+ await mutations.remove(row, { signal });
476
+ return;
477
+ }
478
+ if (!api?.remove) throw new Error("Delete operation is not configured.");
479
+ const url = UrlUtils.buildUrl(api.remove, recordValue(row, idKey));
480
+ if (client) await client.delete(url, { signal });
481
+ else await deleteData(url, { signal });
482
+ };
483
+ const removeRowsLocally = (rows) => {
484
+ let removed = 0;
485
+ for (const row of rows) {
486
+ if (RowUtils.remove(data.value, idKey, recordValue(row, idKey))) {
487
+ removed += 1;
488
+ }
489
+ }
490
+ if (removed > 0) {
491
+ data.value = [...data.value];
492
+ total.value = Math.max(0, total.value - removed);
493
+ }
494
+ };
495
+ const remove = async (row) => {
496
+ if (!mutations.remove && !api?.remove) {
497
+ notify("warning", DEFAULT_MESSAGES.noDeleteApi);
498
+ return;
499
+ }
500
+ const controller = startOperation("remove");
501
+ try {
502
+ await removeOne(row, controller.signal);
503
+ notify("success", DEFAULT_MESSAGES.deleteSuccess);
504
+ if (refreshAfterMutation) await refresh();
505
+ else removeRowsLocally([row]);
506
+ } catch (cause) {
507
+ throw await reportError(cause, "remove", DEFAULT_MESSAGES.deleteError);
508
+ } finally {
509
+ finishOperation("remove", controller);
510
+ }
511
+ };
512
+ const batchRemove = async (rows) => {
513
+ if (rows.length === 0) {
514
+ notify("warning", "\u8BF7\u9009\u62E9\u8981\u5220\u9664\u7684\u6570\u636E");
515
+ return;
516
+ }
517
+ if (!mutations.batchRemove && !mutations.remove && !api?.batchRemove && !api?.remove) {
518
+ notify("warning", DEFAULT_MESSAGES.noDeleteApi);
519
+ return;
520
+ }
521
+ const controller = startOperation("remove");
522
+ try {
523
+ if (mutations.batchRemove) {
524
+ await mutations.batchRemove(rows, { signal: controller.signal });
525
+ } else if (api?.batchRemove) {
526
+ const ids = rows.map((row) => recordValue(row, idKey));
527
+ if (client) {
528
+ await client.post(api.batchRemove, { ids }, { signal: controller.signal });
529
+ } else {
530
+ await postData(api.batchRemove, { ids }, { signal: controller.signal });
531
+ }
532
+ } else {
533
+ let cursor = 0;
534
+ const failures = [];
535
+ const worker = async () => {
536
+ while (cursor < rows.length && !controller.signal.aborted) {
537
+ const current = rows[cursor++];
538
+ try {
539
+ await removeOne(current, controller.signal);
540
+ } catch (cause) {
541
+ failures.push(cause);
542
+ }
543
+ }
544
+ };
545
+ await Promise.all(
546
+ Array.from({ length: Math.min(batchConcurrency, rows.length) }, worker)
547
+ );
548
+ if (controller.signal.aborted) {
549
+ throw Object.assign(new Error("canceled"), {
550
+ name: "AbortError",
551
+ code: "ERR_CANCELED"
552
+ });
553
+ }
554
+ if (failures.length > 0) {
555
+ throw new RequestError({
556
+ kind: "business",
557
+ message: `${failures.length} delete operation(s) failed.`,
558
+ data: failures
559
+ });
560
+ }
561
+ }
562
+ notify("success", `\u6210\u529F\u5220\u9664 ${rows.length} \u6761\u6570\u636E`);
563
+ if (refreshAfterMutation) await refresh();
564
+ else removeRowsLocally(rows);
565
+ } catch (cause) {
566
+ throw await reportError(cause, "remove", "\u6279\u91CF\u5220\u9664\u5931\u8D25");
567
+ } finally {
568
+ finishOperation("remove", controller);
569
+ }
570
+ };
571
+ const search = async (next) => {
572
+ if (next) Object.assign(filters.value, next);
573
+ page.current = DEFAULT_CONFIG.currentPage;
574
+ await refresh();
575
+ };
576
+ const resetSearch = async () => {
577
+ filters.value = cloneValue(initialFilters);
578
+ page.current = DEFAULT_CONFIG.currentPage;
579
+ await refresh();
580
+ };
581
+ const setSort = async (next) => {
582
+ sort.value = cloneValue(next);
583
+ page.current = DEFAULT_CONFIG.currentPage;
584
+ await refresh();
585
+ };
586
+ const handlePaginationChange = (pageNumber, pageSize) => {
587
+ page.current = pageNumber;
588
+ page.size = pageSize;
589
+ void refresh();
590
+ };
591
+ const handleRowDelete = (row) => {
592
+ removeRowsLocally([row]);
593
+ };
594
+ const createActionContext = (index) => ({
595
+ data: data.value,
596
+ index,
597
+ page,
598
+ paginationEnabled: paginationEnabled.value,
599
+ message,
600
+ dialog,
601
+ refresh
602
+ });
603
+ const actions = computed(() => {
604
+ const result = {};
605
+ if (mutations.update || api?.update) {
606
+ result.edit = async (row) => {
607
+ try {
608
+ await save(row);
609
+ return { data: row, error: null };
610
+ } catch (cause) {
611
+ return { data: null, error: normalizeRequestError(cause) };
612
+ }
613
+ };
614
+ }
615
+ if (mutations.remove || api?.remove) {
616
+ result.delete = async (row) => {
617
+ try {
618
+ await remove(row);
619
+ return { data: { success: true }, error: null };
620
+ } catch (cause) {
621
+ return { data: null, error: normalizeRequestError(cause) };
622
+ }
623
+ };
624
+ }
625
+ if (mutations.get || api?.get) {
626
+ result.detail = async (row) => {
627
+ const value = await getDetail(row);
628
+ return { data: value, error: error.value };
629
+ };
630
+ }
631
+ if (customActions.length > 0) {
632
+ result.custom = customActions.map((action) => ({
633
+ key: action.key,
634
+ label: action.label,
635
+ icon: action.icon,
636
+ type: action.type ?? "default",
637
+ onClick: (row, index) => action.handler(row, createActionContext(index))
638
+ }));
639
+ }
640
+ return result;
641
+ });
642
+ const pagination = computed(
643
+ () => paginationEnabled.value ? {
644
+ enabled: true,
645
+ page: page.current,
646
+ pageSize: page.size,
647
+ itemCount: total.value
648
+ } : false
649
+ );
650
+ const createDraft = () => createNewRow?.() ?? {};
651
+ const cancel = () => {
652
+ refreshSequence += 1;
653
+ refreshController?.abort();
654
+ refreshController = null;
655
+ for (const controller of controllers) controller.abort();
656
+ };
657
+ const dispose = () => {
658
+ if (disposed) return;
659
+ disposed = true;
660
+ cancel();
661
+ };
662
+ if (getCurrentScope()) onScopeDispose(dispose);
663
+ if (autoLoad === "mounted" && getCurrentInstance()) {
664
+ onMounted(() => void refresh());
665
+ } else if (autoLoad === "mounted") {
666
+ void refresh();
667
+ } else if (autoLoad) void refresh();
668
+ return {
669
+ data,
670
+ rows: data,
671
+ loading,
672
+ isInitialLoading,
673
+ isRefreshing,
674
+ creating,
675
+ updating,
676
+ removing,
677
+ total,
678
+ error,
679
+ lastUpdated,
680
+ columns: computed(() => columns),
681
+ actions,
682
+ tableRef,
683
+ page,
684
+ filters,
685
+ sort,
686
+ paginationEnabled,
687
+ pagination,
688
+ refresh,
689
+ reload: refresh,
690
+ search,
691
+ resetSearch,
692
+ setSort,
693
+ create,
694
+ save,
695
+ remove,
696
+ batchRemove,
697
+ getDetail,
698
+ createDraft,
699
+ cancel,
700
+ dispose,
701
+ handleCancel: refresh,
702
+ handlePaginationChange,
703
+ handleRowDelete,
704
+ detail,
705
+ detailConfig
706
+ };
707
+ }
708
+
709
+ export { REQUEST_CLIENT_KEY, createRequestPlugin, provideRequestClient, useRequestClient, useTableCrud };
710
+ //# sourceMappingURL=chunk-2JXH7SIL.js.map
711
+ //# sourceMappingURL=chunk-2JXH7SIL.js.map