@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.
- package/CHANGELOG.md +109 -0
- package/LICENSE +21 -0
- package/README.md +248 -357
- package/SECURITY.md +14 -0
- package/dist/axios.cjs +134 -809
- package/dist/axios.cjs.map +1 -1
- package/dist/axios.d.cts +55 -220
- package/dist/axios.d.ts +55 -220
- package/dist/axios.js +2 -790
- package/dist/axios.js.map +1 -1
- package/dist/chunk-2JXH7SIL.js +711 -0
- package/dist/chunk-2JXH7SIL.js.map +1 -0
- package/dist/chunk-56QOEWUS.js +8 -0
- package/dist/chunk-56QOEWUS.js.map +1 -0
- package/dist/chunk-DUP3Y4DN.js +320 -0
- package/dist/chunk-DUP3Y4DN.js.map +1 -0
- package/dist/chunk-JGFRUAZT.cjs +1007 -0
- package/dist/chunk-JGFRUAZT.cjs.map +1 -0
- package/dist/chunk-KHI6XQRN.cjs +717 -0
- package/dist/chunk-KHI6XQRN.cjs.map +1 -0
- package/dist/chunk-OAZ5BUBU.js +969 -0
- package/dist/chunk-OAZ5BUBU.js.map +1 -0
- package/dist/chunk-QSDNDTOZ.js +28 -0
- package/dist/chunk-QSDNDTOZ.js.map +1 -0
- package/dist/chunk-UHXBAFY6.cjs +323 -0
- package/dist/chunk-UHXBAFY6.cjs.map +1 -0
- package/dist/chunk-WUZ43MLM.cjs +30 -0
- package/dist/chunk-WUZ43MLM.cjs.map +1 -0
- package/dist/chunk-WXHQXPS4.cjs +10 -0
- package/dist/chunk-WXHQXPS4.cjs.map +1 -0
- package/dist/crud.cjs +12 -484
- package/dist/crud.cjs.map +1 -1
- package/dist/crud.d.cts +8 -269
- package/dist/crud.d.ts +8 -269
- package/dist/crud.js +4 -487
- package/dist/crud.js.map +1 -1
- package/dist/index.cjs +136 -1302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -165
- package/dist/index.d.ts +7 -165
- package/dist/index.js +5 -1283
- package/dist/index.js.map +1 -1
- package/dist/naive.cjs +14 -0
- package/dist/naive.cjs.map +1 -0
- package/dist/naive.d.cts +9 -0
- package/dist/naive.d.ts +9 -0
- package/dist/naive.js +5 -0
- package/dist/naive.js.map +1 -0
- package/dist/types-BRDRqYFs.d.cts +197 -0
- package/dist/types-BVJhlSuh.d.cts +310 -0
- package/dist/types-BVJhlSuh.d.ts +310 -0
- package/dist/types-CUyibJZX.d.ts +197 -0
- package/dist/vue.cjs +93 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +38 -0
- package/dist/vue.d.ts +38 -0
- package/dist/vue.js +71 -0
- package/dist/vue.js.map +1 -0
- package/package.json +60 -16
package/dist/crud.js
CHANGED
|
@@ -1,489 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function getGlobalAxiosInstance() {
|
|
6
|
-
{
|
|
7
|
-
throw new Error(
|
|
8
|
-
"Axios instance not initialized. Please call createRequestCore() or setGlobalAxiosInstance() first."
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
new Proxy({}, {
|
|
13
|
-
get(_target, prop) {
|
|
14
|
-
return getGlobalAxiosInstance()[prop];
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
async function getData(url, config) {
|
|
18
|
-
const response = await getGlobalAxiosInstance().get(url, config);
|
|
19
|
-
return response.data;
|
|
20
|
-
}
|
|
21
|
-
async function postData(url, data, config) {
|
|
22
|
-
const response = await getGlobalAxiosInstance().post(url, data, config);
|
|
23
|
-
return response.data;
|
|
24
|
-
}
|
|
25
|
-
async function putData(url, data, config) {
|
|
26
|
-
const response = await getGlobalAxiosInstance().put(url, data, config);
|
|
27
|
-
return response.data;
|
|
28
|
-
}
|
|
29
|
-
async function deleteData(url, config) {
|
|
30
|
-
const response = await getGlobalAxiosInstance().delete(url, config);
|
|
31
|
-
return response.data;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// src/composables/useTableCrud/constants.ts
|
|
35
|
-
var DEFAULT_CONFIG = {
|
|
36
|
-
/** 默认 ID 字段名 */
|
|
37
|
-
idKey: "id",
|
|
38
|
-
/** 默认分页大小 */
|
|
39
|
-
pageSize: 10,
|
|
40
|
-
/** 默认启用分页 */
|
|
41
|
-
paginationEnabled: true,
|
|
42
|
-
/** 默认当前页 */
|
|
43
|
-
currentPage: 1
|
|
44
|
-
};
|
|
45
|
-
var DATA_FIELD_ALIASES = ["data", "list", "items", "records"];
|
|
46
|
-
var LIST_FIELD_ALIASES = [
|
|
47
|
-
"list",
|
|
48
|
-
"items",
|
|
49
|
-
"records",
|
|
50
|
-
"rows",
|
|
51
|
-
"data"
|
|
52
|
-
];
|
|
53
|
-
var TOTAL_FIELD_ALIASES = [
|
|
54
|
-
"total",
|
|
55
|
-
"totalCount",
|
|
56
|
-
"count",
|
|
57
|
-
"totalElements"
|
|
58
|
-
];
|
|
59
|
-
var SUCCESS_CODES = [200, 0, "200", "0"];
|
|
60
|
-
var DEFAULT_MESSAGES = {
|
|
61
|
-
createSuccess: "\u65B0\u589E\u6210\u529F",
|
|
62
|
-
updateSuccess: "\u66F4\u65B0\u6210\u529F",
|
|
63
|
-
deleteSuccess: "\u5220\u9664\u6210\u529F",
|
|
64
|
-
saveError: "\u4FDD\u5B58\u5931\u8D25",
|
|
65
|
-
deleteError: "\u5220\u9664\u5931\u8D25",
|
|
66
|
-
loadError: "\u6570\u636E\u52A0\u8F7D\u5931\u8D25",
|
|
67
|
-
detailError: "\u8BE6\u60C5\u83B7\u53D6\u5931\u8D25",
|
|
68
|
-
noDeleteApi: "\u672A\u914D\u7F6E\u5220\u9664\u63A5\u53E3"
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// src/core.ts
|
|
72
|
-
var globalConfig = {
|
|
73
|
-
successCodes: [200, 0, "200", "0"],
|
|
74
|
-
fieldAliases: {
|
|
75
|
-
data: ["data", "list", "items", "records"],
|
|
76
|
-
list: ["list", "items", "records", "rows", "data"],
|
|
77
|
-
total: ["total", "totalCount", "count", "totalElements"]
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
function getGlobalConfig() {
|
|
81
|
-
return globalConfig;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// src/composables/useTableCrud/utils.ts
|
|
85
|
-
function getRuntimeFieldAliases() {
|
|
86
|
-
const config = getGlobalConfig();
|
|
87
|
-
return {
|
|
88
|
-
data: config.fieldAliases.data || DATA_FIELD_ALIASES,
|
|
89
|
-
list: config.fieldAliases.list || LIST_FIELD_ALIASES,
|
|
90
|
-
total: config.fieldAliases.total || TOTAL_FIELD_ALIASES
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function getRuntimeSuccessCodes() {
|
|
94
|
-
const config = getGlobalConfig();
|
|
95
|
-
return config.successCodes || SUCCESS_CODES;
|
|
96
|
-
}
|
|
97
|
-
var FieldFinder = {
|
|
98
|
-
/**
|
|
99
|
-
* 查找第一个存在的字段值
|
|
100
|
-
*/
|
|
101
|
-
findFirst(obj, aliases, defaultValue) {
|
|
102
|
-
if (!obj || typeof obj !== "object") return defaultValue;
|
|
103
|
-
for (const key of aliases) {
|
|
104
|
-
if (key in obj && obj[key] !== void 0) {
|
|
105
|
-
return obj[key];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return defaultValue;
|
|
109
|
-
},
|
|
110
|
-
/**
|
|
111
|
-
* 查找第一个存在的数字字段
|
|
112
|
-
*/
|
|
113
|
-
findNumber(obj, aliases, defaultValue = 0) {
|
|
114
|
-
const value = this.findFirst(obj, aliases, defaultValue);
|
|
115
|
-
return Number(value) || defaultValue;
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
var ResponseNormalizer = {
|
|
119
|
-
/**
|
|
120
|
-
* 判断响应是否成功
|
|
121
|
-
*/
|
|
122
|
-
isSuccess(res) {
|
|
123
|
-
if (typeof res.success === "boolean") return res.success;
|
|
124
|
-
const successCodes = getRuntimeSuccessCodes();
|
|
125
|
-
return successCodes.includes(res.code) || successCodes.includes(String(res.code));
|
|
126
|
-
},
|
|
127
|
-
/**
|
|
128
|
-
* 标准化响应数据(提取 data 层)
|
|
129
|
-
*/
|
|
130
|
-
normalize(res) {
|
|
131
|
-
if (!res || typeof res !== "object" || !("data" in res)) {
|
|
132
|
-
return { data: res, success: true, raw: res };
|
|
133
|
-
}
|
|
134
|
-
const aliases = getRuntimeFieldAliases();
|
|
135
|
-
return {
|
|
136
|
-
data: FieldFinder.findFirst(res, aliases.data, res),
|
|
137
|
-
success: ResponseNormalizer.isSuccess(res),
|
|
138
|
-
raw: res
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
var UrlUtils = {
|
|
143
|
-
/**
|
|
144
|
-
* 构建 URL(处理路径参数)
|
|
145
|
-
*/
|
|
146
|
-
buildUrl(endpoint, id) {
|
|
147
|
-
if (id !== void 0 && endpoint.includes(":id")) {
|
|
148
|
-
return endpoint.replace(":id", String(id));
|
|
149
|
-
}
|
|
150
|
-
return endpoint;
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
var DataExtractor = {
|
|
154
|
-
/**
|
|
155
|
-
* 从响应中提取列表数据(支持多种格式)
|
|
156
|
-
*
|
|
157
|
-
* 支持的响应结构:
|
|
158
|
-
* 1. { code: 0, data: { list: [...], total: 10 } } // 嵌套结构(最常见)
|
|
159
|
-
* 2. { data: { items: [...], total: 10 } } // 嵌套结构
|
|
160
|
-
* 3. { list: [...], total: 10 } // 扁平结构
|
|
161
|
-
* 4. { items: [...], totalCount: 10 } // 不同字段名
|
|
162
|
-
* 5. { data: [...] } // 直接数组
|
|
163
|
-
* 6. [...] // 纯数组
|
|
164
|
-
*/
|
|
165
|
-
extractList(response) {
|
|
166
|
-
const normalized = ResponseNormalizer.normalize(response);
|
|
167
|
-
const dataLayer = normalized.data ?? response;
|
|
168
|
-
const aliases = getRuntimeFieldAliases();
|
|
169
|
-
const list = FieldFinder.findFirst(dataLayer, aliases.list, []);
|
|
170
|
-
const total = FieldFinder.findNumber(dataLayer, aliases.total, 0);
|
|
171
|
-
return {
|
|
172
|
-
items: Array.isArray(list) ? list : [],
|
|
173
|
-
total
|
|
174
|
-
};
|
|
175
|
-
},
|
|
176
|
-
/**
|
|
177
|
-
* 从响应中提取详情数据
|
|
178
|
-
*/
|
|
179
|
-
extractDetail(response) {
|
|
180
|
-
const normalized = ResponseNormalizer.normalize(response);
|
|
181
|
-
return normalized.data;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
var RowUtils = {
|
|
185
|
-
/**
|
|
186
|
-
* 从数组中查找行索引
|
|
187
|
-
*/
|
|
188
|
-
findIndex(items, idKey, id) {
|
|
189
|
-
return items.findIndex((item) => item[idKey] === id);
|
|
190
|
-
},
|
|
191
|
-
/**
|
|
192
|
-
* 从数组中移除行
|
|
193
|
-
*/
|
|
194
|
-
remove(items, idKey, id) {
|
|
195
|
-
const index = this.findIndex(items, idKey, id);
|
|
196
|
-
if (index !== -1) {
|
|
197
|
-
items.splice(index, 1);
|
|
198
|
-
return true;
|
|
199
|
-
}
|
|
200
|
-
return false;
|
|
201
|
-
},
|
|
202
|
-
/**
|
|
203
|
-
* 生成默认 ID
|
|
204
|
-
*/
|
|
205
|
-
generateId() {
|
|
206
|
-
return Date.now() + Math.floor(Math.random() * 1e3);
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
// src/composables/useTableCrud/useTableCrud.ts
|
|
211
|
-
function useTableCrud(config) {
|
|
212
|
-
const {
|
|
213
|
-
api,
|
|
214
|
-
columns,
|
|
215
|
-
customActions = [],
|
|
216
|
-
detail: detailConfig,
|
|
217
|
-
idKey = DEFAULT_CONFIG.idKey,
|
|
218
|
-
defaultPageSize = DEFAULT_CONFIG.pageSize,
|
|
219
|
-
defaultPaginationEnabled = DEFAULT_CONFIG.paginationEnabled,
|
|
220
|
-
autoLoad = true,
|
|
221
|
-
extractListData
|
|
222
|
-
} = config;
|
|
223
|
-
const message = useMessage();
|
|
224
|
-
const dialog = useDialog();
|
|
225
|
-
const data = shallowRef([]);
|
|
226
|
-
const total = ref(0);
|
|
227
|
-
const loading = ref(false);
|
|
228
|
-
const tableRef = ref();
|
|
229
|
-
const paginationEnabled = ref(defaultPaginationEnabled);
|
|
230
|
-
const page = reactive({
|
|
231
|
-
current: DEFAULT_CONFIG.currentPage,
|
|
232
|
-
size: defaultPageSize
|
|
233
|
-
});
|
|
234
|
-
const detailVisible = ref(false);
|
|
235
|
-
const detailData = ref(null);
|
|
236
|
-
const detailTitle = ref("");
|
|
237
|
-
const detail = {
|
|
238
|
-
visible: detailVisible,
|
|
239
|
-
data: detailData,
|
|
240
|
-
title: detailTitle,
|
|
241
|
-
show: (row) => {
|
|
242
|
-
detailData.value = row;
|
|
243
|
-
detailTitle.value = `\u8BE6\u60C5 - ${row.name || row[idKey]}`;
|
|
244
|
-
detailVisible.value = true;
|
|
245
|
-
},
|
|
246
|
-
close: () => {
|
|
247
|
-
detailVisible.value = false;
|
|
248
|
-
detailData.value = null;
|
|
249
|
-
detailTitle.value = "";
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
const refresh = async () => {
|
|
253
|
-
if (!api.list) return;
|
|
254
|
-
loading.value = true;
|
|
255
|
-
try {
|
|
256
|
-
const queryParams = paginationEnabled.value ? { page: page.current, pageSize: page.size } : {};
|
|
257
|
-
const response = await getData(api.list, { params: queryParams });
|
|
258
|
-
const extracted = extractListData ? extractListData(response) : DataExtractor.extractList(response);
|
|
259
|
-
data.value = extracted.items;
|
|
260
|
-
total.value = extracted.total;
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error("[useTableCrud] \u6570\u636E\u52A0\u8F7D\u5931\u8D25:", error);
|
|
263
|
-
message.error(DEFAULT_MESSAGES.loadError);
|
|
264
|
-
} finally {
|
|
265
|
-
loading.value = false;
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
const getDetail = async (row) => {
|
|
269
|
-
if (!api.get) {
|
|
270
|
-
detail.show(row);
|
|
271
|
-
return row;
|
|
272
|
-
}
|
|
273
|
-
loading.value = true;
|
|
274
|
-
try {
|
|
275
|
-
const url = UrlUtils.buildUrl(api.get, row[idKey]);
|
|
276
|
-
const response = await getData(url, {});
|
|
277
|
-
const detailData2 = DataExtractor.extractDetail(response);
|
|
278
|
-
if (detailData2) {
|
|
279
|
-
detail.show(detailData2);
|
|
280
|
-
return detailData2;
|
|
281
|
-
}
|
|
282
|
-
return null;
|
|
283
|
-
} catch (error) {
|
|
284
|
-
console.error("[useTableCrud] \u8BE6\u60C5\u83B7\u53D6\u5931\u8D25:", error);
|
|
285
|
-
message.error(DEFAULT_MESSAGES.detailError);
|
|
286
|
-
return null;
|
|
287
|
-
} finally {
|
|
288
|
-
loading.value = false;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
const create = async (row) => {
|
|
292
|
-
if (!api.create) {
|
|
293
|
-
message.warning("\u672A\u914D\u7F6E\u65B0\u589E\u63A5\u53E3");
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
loading.value = true;
|
|
297
|
-
try {
|
|
298
|
-
await postData(api.create, row);
|
|
299
|
-
message.success(DEFAULT_MESSAGES.createSuccess);
|
|
300
|
-
await refresh();
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.error("[useTableCrud] \u65B0\u589E\u5931\u8D25:", error);
|
|
303
|
-
message.error("\u65B0\u589E\u5931\u8D25");
|
|
304
|
-
throw error;
|
|
305
|
-
} finally {
|
|
306
|
-
loading.value = false;
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
const save = async (row) => {
|
|
310
|
-
if (!api.update) {
|
|
311
|
-
message.warning("\u672A\u914D\u7F6E\u66F4\u65B0\u63A5\u53E3");
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
loading.value = true;
|
|
315
|
-
try {
|
|
316
|
-
const url = UrlUtils.buildUrl(api.update, row[idKey]);
|
|
317
|
-
await putData(url, row);
|
|
318
|
-
message.success(DEFAULT_MESSAGES.updateSuccess);
|
|
319
|
-
await refresh();
|
|
320
|
-
} catch (error) {
|
|
321
|
-
console.error("[useTableCrud] \u66F4\u65B0\u5931\u8D25:", error);
|
|
322
|
-
message.error(DEFAULT_MESSAGES.saveError);
|
|
323
|
-
throw error;
|
|
324
|
-
} finally {
|
|
325
|
-
loading.value = false;
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
const remove = async (row) => {
|
|
329
|
-
if (!api.remove) {
|
|
330
|
-
message.warning(DEFAULT_MESSAGES.noDeleteApi);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
loading.value = true;
|
|
334
|
-
try {
|
|
335
|
-
const url = UrlUtils.buildUrl(api.remove, row[idKey]);
|
|
336
|
-
await deleteData(url);
|
|
337
|
-
message.success(DEFAULT_MESSAGES.deleteSuccess);
|
|
338
|
-
RowUtils.remove(data.value, idKey, row[idKey]);
|
|
339
|
-
await refresh();
|
|
340
|
-
} catch (error) {
|
|
341
|
-
console.error("[useTableCrud] \u5220\u9664\u5931\u8D25:", error);
|
|
342
|
-
message.error(DEFAULT_MESSAGES.deleteError);
|
|
343
|
-
throw error;
|
|
344
|
-
} finally {
|
|
345
|
-
loading.value = false;
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
const batchRemove = async (rows) => {
|
|
349
|
-
if (!rows || rows.length === 0) {
|
|
350
|
-
message.warning("\u8BF7\u9009\u62E9\u8981\u5220\u9664\u7684\u6570\u636E");
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (!api.remove && !api.batchRemove) {
|
|
354
|
-
message.warning(DEFAULT_MESSAGES.noDeleteApi);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
loading.value = true;
|
|
358
|
-
try {
|
|
359
|
-
if (api.batchRemove) {
|
|
360
|
-
const ids = rows.map((row) => row[idKey]);
|
|
361
|
-
await postData(api.batchRemove, { ids });
|
|
362
|
-
} else {
|
|
363
|
-
await Promise.all(
|
|
364
|
-
rows.map((row) => {
|
|
365
|
-
const url = UrlUtils.buildUrl(api.remove, row[idKey]);
|
|
366
|
-
return deleteData(url);
|
|
367
|
-
})
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
message.success(`\u6210\u529F\u5220\u9664 ${rows.length} \u6761\u6570\u636E`);
|
|
371
|
-
await refresh();
|
|
372
|
-
} catch (error) {
|
|
373
|
-
console.error("[useTableCrud] \u6279\u91CF\u5220\u9664\u5931\u8D25:", error);
|
|
374
|
-
message.error("\u6279\u91CF\u5220\u9664\u5931\u8D25");
|
|
375
|
-
throw error;
|
|
376
|
-
} finally {
|
|
377
|
-
loading.value = false;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
const handleCancel = async () => {
|
|
381
|
-
await refresh();
|
|
382
|
-
};
|
|
383
|
-
const handlePaginationChange = (pageNum, pageSize) => {
|
|
384
|
-
page.current = pageNum;
|
|
385
|
-
page.size = pageSize;
|
|
386
|
-
refresh();
|
|
387
|
-
};
|
|
388
|
-
const handleRowDelete = (deletedRow) => {
|
|
389
|
-
RowUtils.remove(data.value, idKey, deletedRow[idKey]);
|
|
390
|
-
};
|
|
391
|
-
const pagination = computed(() => {
|
|
392
|
-
if (!paginationEnabled.value) return false;
|
|
393
|
-
return {
|
|
394
|
-
enabled: true,
|
|
395
|
-
page: page.current,
|
|
396
|
-
pageSize: page.size
|
|
397
|
-
};
|
|
398
|
-
});
|
|
399
|
-
const createActionContext = (index) => ({
|
|
400
|
-
data: data.value,
|
|
401
|
-
index,
|
|
402
|
-
page,
|
|
403
|
-
paginationEnabled: paginationEnabled.value,
|
|
404
|
-
message,
|
|
405
|
-
dialog,
|
|
406
|
-
refresh
|
|
407
|
-
});
|
|
408
|
-
const actions = computed(() => {
|
|
409
|
-
const result = {};
|
|
410
|
-
if (api.update) {
|
|
411
|
-
result.edit = async (row) => {
|
|
412
|
-
try {
|
|
413
|
-
await save(row);
|
|
414
|
-
return { data: row, error: null };
|
|
415
|
-
} catch (error) {
|
|
416
|
-
return { data: null, error };
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
if (api.remove) {
|
|
421
|
-
result.delete = async (row) => {
|
|
422
|
-
try {
|
|
423
|
-
await remove(row);
|
|
424
|
-
return { data: { success: true }, error: null };
|
|
425
|
-
} catch (error) {
|
|
426
|
-
return { data: null, error };
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
if (api.get) {
|
|
431
|
-
result.detail = async (row) => {
|
|
432
|
-
try {
|
|
433
|
-
const detailData2 = await getDetail(row);
|
|
434
|
-
return { data: detailData2, error: null };
|
|
435
|
-
} catch (error) {
|
|
436
|
-
return { data: null, error };
|
|
437
|
-
}
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
if (customActions.length > 0) {
|
|
441
|
-
result.custom = customActions.map((action) => ({
|
|
442
|
-
key: action.key,
|
|
443
|
-
label: action.label,
|
|
444
|
-
icon: action.icon,
|
|
445
|
-
type: action.type || "default",
|
|
446
|
-
onClick: (row, index) => {
|
|
447
|
-
const context = createActionContext(index);
|
|
448
|
-
return action.handler(row, context);
|
|
449
|
-
}
|
|
450
|
-
}));
|
|
451
|
-
}
|
|
452
|
-
return result;
|
|
453
|
-
});
|
|
454
|
-
if (autoLoad) {
|
|
455
|
-
refresh();
|
|
456
|
-
}
|
|
457
|
-
return {
|
|
458
|
-
// 数据状态
|
|
459
|
-
data,
|
|
460
|
-
loading,
|
|
461
|
-
total,
|
|
462
|
-
// 表格配置
|
|
463
|
-
columns: computed(() => columns),
|
|
464
|
-
actions,
|
|
465
|
-
tableRef,
|
|
466
|
-
// 分页
|
|
467
|
-
page,
|
|
468
|
-
paginationEnabled,
|
|
469
|
-
pagination,
|
|
470
|
-
// 核心方法
|
|
471
|
-
refresh,
|
|
472
|
-
create,
|
|
473
|
-
save,
|
|
474
|
-
remove,
|
|
475
|
-
batchRemove,
|
|
476
|
-
getDetail,
|
|
477
|
-
// 事件处理
|
|
478
|
-
handleCancel,
|
|
479
|
-
handlePaginationChange,
|
|
480
|
-
handleRowDelete,
|
|
481
|
-
// 详情弹窗
|
|
482
|
-
detail,
|
|
483
|
-
detailConfig
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
export { useTableCrud };
|
|
1
|
+
export { useTableCrud } from './chunk-56QOEWUS.js';
|
|
2
|
+
export { useNaiveTableCrud } from './chunk-QSDNDTOZ.js';
|
|
3
|
+
import './chunk-2JXH7SIL.js';
|
|
4
|
+
import './chunk-OAZ5BUBU.js';
|
|
488
5
|
//# sourceMappingURL=crud.js.map
|
|
489
6
|
//# sourceMappingURL=crud.js.map
|
package/dist/crud.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/axios/service.ts","../src/composables/useTableCrud/constants.ts","../src/core.ts","../src/composables/useTableCrud/utils.ts","../src/composables/useTableCrud/useTableCrud.ts"],"names":["detailData"],"mappings":"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","file":"crud.js","sourcesContent":["import type { AxiosInstance } from \"axios\";\nimport type { EnhancedAxiosRequestConfig } from \"./types\";\n\nlet globalService: AxiosInstance | null = null;\n\nexport function setGlobalAxiosInstance(instance: AxiosInstance): void {\n globalService = instance;\n}\n\nexport function getGlobalAxiosInstance(): AxiosInstance {\n if (!globalService) {\n throw new Error(\n \"Axios instance not initialized. Please call createRequestCore() or setGlobalAxiosInstance() first.\",\n );\n }\n return globalService;\n}\n\nconst service = new Proxy({} as AxiosInstance, {\n get(_target, prop) {\n return getGlobalAxiosInstance()[prop as keyof AxiosInstance];\n },\n});\n\nexport default service;\n\nexport async function getData<T = any>(\n url: string,\n config?: EnhancedAxiosRequestConfig,\n): Promise<T> {\n const response = await getGlobalAxiosInstance().get(url, config);\n return response.data;\n}\n\nexport async function postData<T = any>(\n url: string,\n data?: any,\n config?: EnhancedAxiosRequestConfig,\n): Promise<T> {\n const response = await getGlobalAxiosInstance().post(url, data, config);\n return response.data;\n}\n\nexport async function putData<T = any>(\n url: string,\n data?: any,\n config?: EnhancedAxiosRequestConfig,\n): Promise<T> {\n const response = await getGlobalAxiosInstance().put(url, data, config);\n return response.data;\n}\n\nexport async function deleteData<T = any>(\n url: string,\n config?: EnhancedAxiosRequestConfig,\n): Promise<T> {\n const response = await getGlobalAxiosInstance().delete(url, config);\n return response.data;\n}\n","/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-07 10:00:00\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-02-07 10:00:00\n * @FilePath: \\robot-admin-request-core\\src\\composables\\useTableCrud\\constants.ts\n * @Description: useTableCrud 常量定义\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\n/**\n * 默认配置\n */\nexport const DEFAULT_CONFIG = {\n /** 默认 ID 字段名 */\n idKey: \"id\",\n /** 默认分页大小 */\n pageSize: 10,\n /** 默认启用分页 */\n paginationEnabled: true,\n /** 默认当前页 */\n currentPage: 1,\n} as const;\n\n/**\n * 响应字段别名配置(支持多种后端响应格式)\n */\n\n/** 数据字段别名(按优先级排序) - 用于从响应中提取数据层 */\nexport const DATA_FIELD_ALIASES = [\"data\", \"list\", \"items\", \"records\"] as const;\n\n/** 列表字段别名(按优先级排序) - 用于从数据层提取列表数组 */\nexport const LIST_FIELD_ALIASES = [\n \"list\",\n \"items\",\n \"records\",\n \"rows\",\n \"data\",\n] as const;\n\n/** 总数字段别名(按优先级排序) - 用于提取数据总数 */\nexport const TOTAL_FIELD_ALIASES = [\n \"total\",\n \"totalCount\",\n \"count\",\n \"totalElements\",\n] as const;\n\n/** 成功状态码(支持数字和字符串) */\nexport const SUCCESS_CODES = [200, 0, \"200\", \"0\"] as const;\n\n/**\n * 默认消息文本\n */\nexport const DEFAULT_MESSAGES = {\n createSuccess: \"新增成功\",\n updateSuccess: \"更新成功\",\n deleteSuccess: \"删除成功\",\n saveError: \"保存失败\",\n deleteError: \"删除失败\",\n loadError: \"数据加载失败\",\n detailError: \"详情获取失败\",\n noDeleteApi: \"未配置删除接口\",\n} as const;\n","/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-07 10:00:00\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-02-07 10:00:00\n * @FilePath: \\robot-admin-request-core\\src\\core.ts\n * @Description: Request Core - 核心配置和初始化 API\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\nimport type { App } from \"vue\";\nimport type {\n AxiosRequestConfig,\n AxiosResponse,\n InternalAxiosRequestConfig,\n} from \"axios\";\nimport { createAxiosInstance } from \"./axios/request\";\nimport { setGlobalAxiosInstance } from \"./axios/service\";\n\n/**\n * 全局配置存储\n */\nlet globalConfig: Required<\n Pick<RequestCoreConfig, \"successCodes\" | \"fieldAliases\">\n> = {\n successCodes: [200, 0, \"200\", \"0\"],\n fieldAliases: {\n data: [\"data\", \"list\", \"items\", \"records\"],\n list: [\"list\", \"items\", \"records\", \"rows\", \"data\"],\n total: [\"total\", \"totalCount\", \"count\", \"totalElements\"],\n },\n};\n\n/**\n * 获取全局配置\n */\nexport function getGlobalConfig() {\n return globalConfig;\n}\n\n/**\n * 拦截器配置\n *\n * @description\n * 用于配置 axios 请求和响应拦截器,处理 token 注入、业务码判断等业务逻辑\n */\nexport interface InterceptorConfig {\n /**\n * 请求拦截器\n * @description 在请求发送前执行,常用于注入 token、修改请求头等\n */\n request?: (\n config: InternalAxiosRequestConfig,\n ) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;\n\n /**\n * 请求错误拦截器\n * @description 请求配置阶段发生错误时执行\n */\n requestError?: (error: any) => any;\n\n /**\n * 响应拦截器\n * @description 响应到达后执行,常用于统一处理业务码、数据格式等\n */\n response?: (\n response: AxiosResponse,\n ) => AxiosResponse | Promise<AxiosResponse>;\n\n /**\n * 响应错误拦截器\n * @description 响应阶段发生错误时执行,常用于处理 401、403、500 等错误\n */\n responseError?: (error: any) => any;\n}\n\n/**\n * 字段别名配置\n *\n * @description\n * 用于自定义 API 响应的字段映射,适配不同的后端响应格式\n */\nexport interface FieldAliases {\n /**\n * 数据层字段别名(用于提取响应中的 data 层)\n * @default ['data', 'list', 'items', 'records']\n * @example ['result', 'payload']\n */\n data?: string[];\n\n /**\n * 列表字段别名(用于提取数据层中的列表数组)\n * @default ['list', 'items', 'records', 'rows', 'data']\n * @example ['employees', 'users', 'products']\n */\n list?: string[];\n\n /**\n * 总数字段别名(用于提取数据总数)\n * @default ['total', 'totalCount', 'count', 'totalElements']\n * @example ['totalRecords', 'totalItems']\n */\n total?: string[];\n}\n\n/**\n * Request Core 配置\n *\n * @description\n * 用于初始化 Request Core 实例,配置 axios 和拦截器\n */\nexport interface RequestCoreConfig {\n /**\n * Axios 基础配置\n * @description 包括 baseURL、timeout、headers 等,参考 axios 官方文档\n */\n request?: AxiosRequestConfig;\n\n /**\n * 拦截器配置\n * @description 用于处理 token 注入、业务码判断、错误提示等业务逻辑\n */\n interceptors?: InterceptorConfig;\n\n /**\n * 成功状态码配置\n * @description 用于判断 API 响应的业务状态码是否成功\n * @default [200, 0, '200', '0']\n * @example [1, '1', 'success']\n */\n successCodes?: Array<number | string>;\n\n /**\n * 字段别名配置\n * @description 用于自定义 API 响应的字段映射,适配不同的后端响应格式\n */\n fieldAliases?: FieldAliases;\n}\n\n/**\n * 创建 Request Core 实例\n *\n * @description\n * 初始化 axios 实例并注册 6 个内置插件;reLogin 通过显式共享 Promise 协调\n * 返回 Vue 插件对象和 axios 实例\n *\n * @param config Request Core 配置\n * @returns Vue 插件对象(包含 install 方法)和 axios 实例\n *\n * @example\n * ```ts\n * // main.ts\n * import {\n * createRequestCore,\n * getReLoginPromise,\n * waitForReLogin,\n * onReLoginSuccess,\n * onReLoginCancel,\n * } from '@robot-admin/request-core'\n * import { useUserStore } from '@/stores/user'\n *\n * const requestCore = createRequestCore({\n * request: {\n * baseURL: import.meta.env.VITE_API_BASE,\n * timeout: 10000,\n * },\n * interceptors: {\n * // 请求拦截:注入 token\n * request: (config) => {\n * const token = localStorage.getItem('token')\n * if (token) {\n * config.headers.Authorization = `Bearer ${token}`\n * }\n * return config\n * },\n * // 响应拦截:处理业务码\n * response: (response) => {\n * const { code, message } = response.data\n * if (code !== 200) {\n * window.$message?.error(message || '请求失败')\n * return Promise.reject(new Error(message))\n * }\n * return response\n * },\n * // 响应错误拦截:处理 401\n * responseError: async (error) => {\n * if (error.response?.status === 401) {\n * const shouldStartLogin = !getReLoginPromise()\n * const waiting = waitForReLogin()\n * const userStore = useUserStore()\n * if (shouldStartLogin) {\n * userStore.reLogin().then(onReLoginSuccess, onReLoginCancel)\n * }\n * await waiting\n * return requestCore.axiosInstance.request(error.config)\n * }\n * return Promise.reject(error)\n * }\n * }\n * })\n *\n * app.use(requestCore)\n * ```\n */\nexport function createRequestCore(config: RequestCoreConfig = {}) {\n const {\n request = {},\n interceptors = {},\n successCodes,\n fieldAliases,\n } = config;\n\n // 合并全局配置\n if (successCodes) {\n globalConfig.successCodes = successCodes;\n }\n if (fieldAliases) {\n globalConfig.fieldAliases = {\n data: fieldAliases.data || globalConfig.fieldAliases.data,\n list: fieldAliases.list || globalConfig.fieldAliases.list,\n total: fieldAliases.total || globalConfig.fieldAliases.total,\n };\n }\n\n // 创建 axios 实例\n const axiosInstance = createAxiosInstance(request);\n\n // 设置为全局实例\n setGlobalAxiosInstance(axiosInstance);\n\n // 注册拦截器\n if (interceptors.request) {\n axiosInstance.interceptors.request.use(\n interceptors.request,\n interceptors.requestError,\n );\n }\n\n if (interceptors.response) {\n axiosInstance.interceptors.response.use(\n interceptors.response,\n interceptors.responseError,\n );\n }\n\n return {\n install(app: App) {\n // 可以挂载到 app.config.globalProperties\n app.config.globalProperties.$axios = axiosInstance;\n },\n axiosInstance,\n };\n}\n","/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-07 10:00:00\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-02-07 10:00:00\n * @FilePath: \\robot-admin-request-core\\src\\composables\\useTableCrud\\utils.ts\n * @Description: useTableCrud 工具函数\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\nimport type { DataRecord } from \"./types\";\nimport {\n DATA_FIELD_ALIASES,\n LIST_FIELD_ALIASES,\n TOTAL_FIELD_ALIASES,\n SUCCESS_CODES,\n} from \"./constants\";\nimport { getGlobalConfig } from \"../../core\";\n\n/**\n * 获取运行时字段别名(优先使用全局配置)\n */\nfunction getRuntimeFieldAliases() {\n const config = getGlobalConfig();\n return {\n data: config.fieldAliases.data || DATA_FIELD_ALIASES,\n list: config.fieldAliases.list || LIST_FIELD_ALIASES,\n total: config.fieldAliases.total || TOTAL_FIELD_ALIASES,\n };\n}\n\n/**\n * 获取运行时成功状态码(优先使用全局配置)\n */\nfunction getRuntimeSuccessCodes() {\n const config = getGlobalConfig();\n return config.successCodes || SUCCESS_CODES;\n}\n\n/**\n * 字段查找器(支持多种字段别名)\n */\nexport const FieldFinder = {\n /**\n * 查找第一个存在的字段值\n */\n findFirst<T>(\n obj: Record<string, any> | null | undefined,\n aliases: readonly string[],\n defaultValue: T,\n ): T {\n if (!obj || typeof obj !== \"object\") return defaultValue;\n\n for (const key of aliases) {\n if (key in obj && obj[key] !== undefined) {\n return obj[key] as T;\n }\n }\n return defaultValue;\n },\n\n /**\n * 查找第一个存在的数字字段\n */\n findNumber(\n obj: Record<string, any> | null | undefined,\n aliases: readonly string[],\n defaultValue = 0,\n ): number {\n const value = this.findFirst(obj, aliases, defaultValue);\n return Number(value) || defaultValue;\n },\n};\n\n/**\n * 响应标准化工具\n */\nexport const ResponseNormalizer = {\n /**\n * 判断响应是否成功\n */\n isSuccess(res: any): boolean {\n if (typeof res.success === \"boolean\") return res.success;\n // 使用运行时配置的成功状态码\n const successCodes = getRuntimeSuccessCodes();\n return (\n successCodes.includes(res.code) ||\n successCodes.includes(String(res.code) as any)\n );\n },\n\n /**\n * 标准化响应数据(提取 data 层)\n */\n normalize<T = any>(res: any): { data: T; success: boolean; raw: any } {\n // 如果响应没有标准结构,直接返回\n if (!res || typeof res !== \"object\" || !(\"data\" in res)) {\n return { data: res as T, success: true, raw: res };\n }\n\n const aliases = getRuntimeFieldAliases();\n return {\n data: FieldFinder.findFirst(res, aliases.data, res),\n success: ResponseNormalizer.isSuccess(res),\n raw: res,\n };\n },\n};\n\n/**\n * URL 工具\n */\nexport const UrlUtils = {\n /**\n * 构建 URL(处理路径参数)\n */\n buildUrl(endpoint: string, id?: string | number): string {\n if (id !== undefined && endpoint.includes(\":id\")) {\n return endpoint.replace(\":id\", String(id));\n }\n return endpoint;\n },\n};\n\n/**\n * 数据提取工具(增强版,支持多种响应格式)\n */\nexport const DataExtractor = {\n /**\n * 从响应中提取列表数据(支持多种格式)\n *\n * 支持的响应结构:\n * 1. { code: 0, data: { list: [...], total: 10 } } // 嵌套结构(最常见)\n * 2. { data: { items: [...], total: 10 } } // 嵌套结构\n * 3. { list: [...], total: 10 } // 扁平结构\n * 4. { items: [...], totalCount: 10 } // 不同字段名\n * 5. { data: [...] } // 直接数组\n * 6. [...] // 纯数组\n */\n extractList<T = any>(response: any): { items: T[]; total: number } {\n // 第一步:标准化响应,提取 data 层\n const normalized = ResponseNormalizer.normalize(response);\n const dataLayer = normalized.data ?? response;\n\n // 第二步:从 data 层提取列表数组(使用运行时配置)\n const aliases = getRuntimeFieldAliases();\n const list = FieldFinder.findFirst<any[]>(dataLayer, aliases.list, []);\n\n // 第三步:提取总数(使用运行时配置)\n const total = FieldFinder.findNumber(dataLayer, aliases.total, 0);\n\n return {\n items: Array.isArray(list) ? list : [],\n total,\n };\n },\n\n /**\n * 从响应中提取详情数据\n */\n extractDetail<T = any>(response: any): T | null {\n // 标准化响应\n const normalized = ResponseNormalizer.normalize(response);\n return normalized.data as T | null;\n },\n};\n\n/**\n * 行操作工具\n */\nexport const RowUtils = {\n /**\n * 从数组中查找行索引\n */\n findIndex<T extends DataRecord>(items: T[], idKey: keyof T, id: any): number {\n return items.findIndex((item) => item[idKey] === id);\n },\n\n /**\n * 从数组中移除行\n */\n remove<T extends DataRecord>(items: T[], idKey: keyof T, id: any): boolean {\n const index = this.findIndex(items, idKey, id);\n if (index !== -1) {\n items.splice(index, 1);\n return true;\n }\n return false;\n },\n\n /**\n * 生成默认 ID\n */\n generateId(): number {\n return Date.now() + Math.floor(Math.random() * 1000);\n },\n};\n","/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-02-07 10:00:00\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-02-07 10:00:00\n * @FilePath: \\robot-admin-request-core\\src\\composables\\useTableCrud\\useTableCrud.ts\n * @Description: useTableCrud 核心逻辑 - CRUD + 分页 + 表单管理\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\nimport { ref, reactive, computed, shallowRef } from \"vue\";\nimport { useMessage, useDialog } from \"naive-ui\";\nimport { getData, postData, putData, deleteData } from \"../../axios/service\";\nimport type {\n DataRecord,\n UseTableCrudConfig,\n UseTableCrudReturn,\n ActionContext,\n DetailModal,\n} from \"./types\";\nimport { DEFAULT_CONFIG, DEFAULT_MESSAGES } from \"./constants\";\nimport { UrlUtils, DataExtractor, RowUtils } from \"./utils\";\n\n/**\n * 表格 CRUD 组合式 API\n *\n * @description\n * 配置驱动的表格 CRUD 解决方案,极简使用,功能完整\n * 完全替代 usePageCrud,专注于表格场景\n *\n * @template T 数据行类型\n * @param config 配置对象\n * @returns 表格 CRUD 实例\n *\n * @example\n * ```ts\n * const table = useTableCrud<Employee>({\n * api: {\n * list: '/employees/list',\n * get: '/employees/:id',\n * update: '/employees/:id',\n * remove: '/employees/:id',\n * create: '/employees'\n * },\n * columns: [...],\n * customActions: [\n * {\n * key: 'copy',\n * label: '复制',\n * icon: 'mdi:content-copy',\n * handler: (row, ctx) => {\n * const newRow = { ...row, id: Date.now() }\n * ctx.data.unshift(newRow)\n * ctx.message.success('复制成功')\n * }\n * }\n * ]\n * })\n *\n * // 组件中使用\n * <c-table\n * v-model:data=\"table.data.value\"\n * :columns=\"table.columns.value\"\n * :actions=\"table.actions.value\"\n * @save=\"table.save\"\n * />\n * ```\n */\nexport function useTableCrud<T extends DataRecord>(\n config: UseTableCrudConfig<T>,\n): UseTableCrudReturn<T> {\n // ==================== 配置解析 ====================\n const {\n api,\n columns,\n customActions = [],\n detail: detailConfig,\n idKey = DEFAULT_CONFIG.idKey as keyof T,\n defaultPageSize = DEFAULT_CONFIG.pageSize,\n defaultPaginationEnabled = DEFAULT_CONFIG.paginationEnabled,\n autoLoad = true,\n extractListData,\n } = config;\n\n // ==================== 全局实例 ====================\n const message = useMessage();\n const dialog = useDialog();\n\n // ==================== 响应式状态 ====================\n const data = shallowRef<T[]>([]);\n const total = ref(0);\n const loading = ref(false);\n const tableRef = ref();\n const paginationEnabled = ref(defaultPaginationEnabled);\n\n // 分页状态\n const page: { current: number; size: number } = reactive({\n current: DEFAULT_CONFIG.currentPage,\n size: defaultPageSize,\n });\n\n // ==================== 详情弹窗 ====================\n const detailVisible = ref(false);\n const detailData = ref<T | null>(null);\n const detailTitle = ref(\"\");\n\n const detail: DetailModal<T> = {\n visible: detailVisible,\n data: detailData as any,\n title: detailTitle,\n show: (row: T) => {\n detailData.value = row;\n detailTitle.value = `详情 - ${(row as any).name || row[idKey]}`;\n detailVisible.value = true;\n },\n close: () => {\n detailVisible.value = false;\n detailData.value = null;\n detailTitle.value = \"\";\n },\n };\n\n // ==================== 核心方法 ====================\n\n /**\n * 刷新数据\n */\n const refresh = async (): Promise<void> => {\n if (!api.list) return;\n\n loading.value = true;\n try {\n const queryParams = paginationEnabled.value\n ? { page: page.current, pageSize: page.size }\n : {};\n\n const response = await getData(api.list, { params: queryParams });\n\n const extracted = extractListData\n ? extractListData(response)\n : DataExtractor.extractList<T>(response);\n\n data.value = extracted.items;\n total.value = extracted.total;\n } catch (error) {\n console.error(\"[useTableCrud] 数据加载失败:\", error);\n message.error(DEFAULT_MESSAGES.loadError);\n } finally {\n loading.value = false;\n }\n };\n\n /**\n * 获取详情\n */\n const getDetail = async (row: T): Promise<T | null> => {\n if (!api.get) {\n // 如果没有详情接口,直接显示当前数据\n detail.show(row);\n return row;\n }\n\n loading.value = true;\n try {\n const url = UrlUtils.buildUrl(api.get, row[idKey] as any);\n const response = await getData(url, {});\n const detailData = DataExtractor.extractDetail<T>(response);\n\n if (detailData) {\n detail.show(detailData);\n return detailData;\n }\n\n return null;\n } catch (error) {\n console.error(\"[useTableCrud] 详情获取失败:\", error);\n message.error(DEFAULT_MESSAGES.detailError);\n return null;\n } finally {\n loading.value = false;\n }\n };\n\n /**\n * 新增数据\n */\n const create = async (row: T): Promise<void> => {\n if (!api.create) {\n message.warning(\"未配置新增接口\");\n return;\n }\n\n loading.value = true;\n try {\n await postData(api.create, row);\n message.success(DEFAULT_MESSAGES.createSuccess);\n await refresh();\n } catch (error) {\n console.error(\"[useTableCrud] 新增失败:\", error);\n message.error(\"新增失败\");\n throw error;\n } finally {\n loading.value = false;\n }\n };\n\n /**\n * 更新数据\n */\n const save = async (row: T): Promise<void> => {\n if (!api.update) {\n message.warning(\"未配置更新接口\");\n return;\n }\n\n loading.value = true;\n try {\n const url = UrlUtils.buildUrl(api.update, row[idKey] as any);\n await putData(url, row);\n message.success(DEFAULT_MESSAGES.updateSuccess);\n await refresh();\n } catch (error) {\n console.error(\"[useTableCrud] 更新失败:\", error);\n message.error(DEFAULT_MESSAGES.saveError);\n throw error;\n } finally {\n loading.value = false;\n }\n };\n\n /**\n * 删除数据\n */\n const remove = async (row: T): Promise<void> => {\n if (!api.remove) {\n message.warning(DEFAULT_MESSAGES.noDeleteApi);\n return;\n }\n\n loading.value = true;\n try {\n const url = UrlUtils.buildUrl(api.remove, row[idKey] as any);\n await deleteData(url);\n message.success(DEFAULT_MESSAGES.deleteSuccess);\n\n // 从本地数据中移除\n RowUtils.remove(data.value, idKey, row[idKey]);\n\n await refresh();\n } catch (error) {\n console.error(\"[useTableCrud] 删除失败:\", error);\n message.error(DEFAULT_MESSAGES.deleteError);\n throw error;\n } finally {\n loading.value = false;\n }\n };\n\n /**\n * 批量删除数据\n */\n const batchRemove = async (rows: T[]): Promise<void> => {\n if (!rows || rows.length === 0) {\n message.warning(\"请选择要删除的数据\");\n return;\n }\n\n if (!api.remove && !api.batchRemove) {\n message.warning(DEFAULT_MESSAGES.noDeleteApi);\n return;\n }\n\n loading.value = true;\n try {\n if (api.batchRemove) {\n // 使用批量删除接口\n const ids = rows.map((row) => row[idKey]);\n await postData(api.batchRemove, { ids });\n } else {\n // 使用单个删除接口循环删除\n await Promise.all(\n rows.map((row) => {\n const url = UrlUtils.buildUrl(api.remove!, row[idKey] as any);\n return deleteData(url);\n }),\n );\n }\n\n message.success(`成功删除 ${rows.length} 条数据`);\n await refresh();\n } catch (error) {\n console.error(\"[useTableCrud] 批量删除失败:\", error);\n message.error(\"批量删除失败\");\n throw error;\n } finally {\n loading.value = false;\n }\n };\n\n // ==================== 事件处理 ====================\n\n /**\n * 处理取消编辑\n */\n const handleCancel = async (): Promise<void> => {\n // 取消编辑,刷新数据恢复原始状态\n await refresh();\n };\n\n /**\n * 处理分页变化\n */\n const handlePaginationChange = (pageNum: number, pageSize: number): void => {\n page.current = pageNum;\n page.size = pageSize;\n refresh();\n };\n\n /**\n * 处理行删除(UI层)\n */\n const handleRowDelete = (deletedRow: T): void => {\n RowUtils.remove(data.value, idKey, deletedRow[idKey]);\n };\n\n // ==================== 计算属性 ====================\n\n /**\n * 分页配置\n */\n const pagination = computed(() => {\n if (!paginationEnabled.value) return false;\n return {\n enabled: true,\n page: page.current,\n pageSize: page.size,\n };\n });\n\n /**\n * 操作上下文(用于自定义操作)\n */\n const createActionContext = (index: number): ActionContext<T> => ({\n data: data.value,\n index,\n page,\n paginationEnabled: paginationEnabled.value,\n message,\n dialog,\n refresh,\n });\n\n /**\n * 表格操作配置\n */\n const actions = computed(() => {\n const result: any = {};\n\n // 编辑操作\n if (api.update) {\n result.edit = async (row: T) => {\n try {\n await save(row);\n return { data: row, error: null };\n } catch (error) {\n return { data: null, error };\n }\n };\n }\n\n // 删除操作\n if (api.remove) {\n result.delete = async (row: T) => {\n try {\n await remove(row);\n return { data: { success: true }, error: null };\n } catch (error) {\n return { data: null, error };\n }\n };\n }\n\n // 详情操作\n if (api.get) {\n result.detail = async (row: T) => {\n try {\n const detailData = await getDetail(row);\n return { data: detailData, error: null };\n } catch (error) {\n return { data: null, error };\n }\n };\n }\n\n // 自定义操作\n if (customActions.length > 0) {\n result.custom = customActions.map((action) => ({\n key: action.key,\n label: action.label,\n icon: action.icon,\n type: action.type || \"default\",\n onClick: (row: T, index: number) => {\n const context = createActionContext(index);\n return action.handler(row, context);\n },\n }));\n }\n\n return result;\n });\n\n // ==================== 返回 ====================\n\n // 自动加载数据\n if (autoLoad) {\n refresh();\n }\n\n return {\n // 数据状态\n data,\n loading,\n total,\n\n // 表格配置\n columns: computed(() => columns),\n actions,\n tableRef,\n\n // 分页\n page,\n paginationEnabled,\n pagination,\n\n // 核心方法\n refresh,\n create,\n save,\n remove,\n batchRemove,\n getDetail,\n\n // 事件处理\n handleCancel,\n handlePaginationChange,\n handleRowDelete,\n\n // 详情弹窗\n detail,\n detailConfig,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"crud.js"}
|