crud-page-react 0.2.1 → 0.3.0
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/dist/index.esm.js +117 -27
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +117 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -89,8 +89,10 @@ function shouldShowAction(condition, record) {
|
|
|
89
89
|
for (const [fieldPath, allowedValues] of Object.entries(condition)) {
|
|
90
90
|
// 支持点分路径获取嵌套值
|
|
91
91
|
const actualValue = getNestedValue(record, fieldPath);
|
|
92
|
+
// 确保 allowedValues 是数组
|
|
93
|
+
const valuesArray = Array.isArray(allowedValues) ? allowedValues : [allowedValues];
|
|
92
94
|
// 检查值是否在允许的值列表中
|
|
93
|
-
if (!
|
|
95
|
+
if (!valuesArray.includes(actualValue)) {
|
|
94
96
|
return false;
|
|
95
97
|
}
|
|
96
98
|
}
|
|
@@ -293,7 +295,9 @@ function DynamicTable({ schema, data, loading, pagination, onView, onEdit, onDel
|
|
|
293
295
|
return shouldShowAction(action.condition, record);
|
|
294
296
|
});
|
|
295
297
|
const customActions = actions.filter(action => {
|
|
296
|
-
|
|
298
|
+
// 检查是否是自定义操作类型(非基础操作)
|
|
299
|
+
const isBasicAction = action.type === 'view' || action.type === 'edit' || action.type === 'delete';
|
|
300
|
+
if (isBasicAction)
|
|
297
301
|
return false;
|
|
298
302
|
// 检查 condition 条件
|
|
299
303
|
return shouldShowAction(action.condition, record);
|
|
@@ -868,7 +872,22 @@ function DynamicForm({ schema, mode, visible, initialValues, onSubmit, onCancel,
|
|
|
868
872
|
}
|
|
869
873
|
|
|
870
874
|
const { Title } = antd.Typography;
|
|
871
|
-
/**
|
|
875
|
+
/** 动态替换 URL 模板中的占位符,支持 :fieldName 和 {{fieldName}} 两种格式 */
|
|
876
|
+
function buildUrl(template, record) {
|
|
877
|
+
let result = template;
|
|
878
|
+
// 替换 :fieldName 格式
|
|
879
|
+
result = result.replace(/:(\w+)/g, (match, fieldName) => {
|
|
880
|
+
const value = record[fieldName];
|
|
881
|
+
return value !== undefined ? String(value) : match;
|
|
882
|
+
});
|
|
883
|
+
// 替换 {{fieldName}} 格式
|
|
884
|
+
result = result.replace(/\{\{(\w+)\}\}/g, (match, fieldName) => {
|
|
885
|
+
const value = record[fieldName];
|
|
886
|
+
return value !== undefined ? String(value) : match;
|
|
887
|
+
});
|
|
888
|
+
return result;
|
|
889
|
+
}
|
|
890
|
+
/** 处理模板数据,支持 {{fieldName}} 格式的变量替换,支持嵌套对象和数组 */
|
|
872
891
|
function processTemplateData(data, record) {
|
|
873
892
|
const result = {};
|
|
874
893
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -879,6 +898,27 @@ function processTemplateData(data, record) {
|
|
|
879
898
|
return fieldValue !== undefined ? String(fieldValue) : match;
|
|
880
899
|
});
|
|
881
900
|
}
|
|
901
|
+
else if (typeof value === 'object' && value !== null) {
|
|
902
|
+
if (Array.isArray(value)) {
|
|
903
|
+
// 处理数组
|
|
904
|
+
result[key] = value.map(item => {
|
|
905
|
+
if (typeof item === 'object' && item !== null) {
|
|
906
|
+
return processTemplateData(item, record);
|
|
907
|
+
}
|
|
908
|
+
else if (typeof item === 'string' && item.includes('{{') && item.includes('}}')) {
|
|
909
|
+
return item.replace(/\{\{(\w+)\}\}/g, (match, fieldName) => {
|
|
910
|
+
const fieldValue = record[fieldName];
|
|
911
|
+
return fieldValue !== undefined ? String(fieldValue) : match;
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
return item;
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
// 处理嵌套对象
|
|
919
|
+
result[key] = processTemplateData(value, record);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
882
922
|
else {
|
|
883
923
|
result[key] = value;
|
|
884
924
|
}
|
|
@@ -952,17 +992,32 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
952
992
|
method: listApiConfig.method || 'GET',
|
|
953
993
|
headers: Object.assign({ 'Content-Type': 'application/json' }, listApiConfig.headers)
|
|
954
994
|
};
|
|
955
|
-
//
|
|
956
|
-
let url = listApiConfig.url;
|
|
995
|
+
// 构建 URL,支持动态占位符替换
|
|
996
|
+
let url = buildUrl(listApiConfig.url, params);
|
|
957
997
|
if (listApiConfig.method === 'POST') {
|
|
958
998
|
const queryParams = {};
|
|
959
999
|
query.forEach((value, key) => {
|
|
960
1000
|
queryParams[key] = value;
|
|
961
1001
|
});
|
|
962
|
-
|
|
1002
|
+
// 处理模板数据(如果有的话)
|
|
1003
|
+
let processedApiData = {};
|
|
1004
|
+
if (listApiConfig.data) {
|
|
1005
|
+
// 对于list API,通常没有特定的record,使用查询参数作为上下文
|
|
1006
|
+
processedApiData = processTemplateData(listApiConfig.data, queryParams);
|
|
1007
|
+
}
|
|
1008
|
+
const requestData = Object.assign(Object.assign({}, queryParams), processedApiData);
|
|
963
1009
|
options.body = JSON.stringify(requestData);
|
|
964
1010
|
}
|
|
965
1011
|
else {
|
|
1012
|
+
// 对于GET请求,如果有data配置,将其作为查询参数处理
|
|
1013
|
+
if (listApiConfig.data) {
|
|
1014
|
+
const processedApiData = processTemplateData(listApiConfig.data, params);
|
|
1015
|
+
Object.entries(processedApiData).forEach(([key, value]) => {
|
|
1016
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
1017
|
+
query.set(key, String(value));
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
966
1021
|
url = `${url}?${query}`;
|
|
967
1022
|
}
|
|
968
1023
|
const json = await request(url, options);
|
|
@@ -1010,11 +1065,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
1010
1065
|
const deleteApiConfig = schema.api.delete;
|
|
1011
1066
|
try {
|
|
1012
1067
|
// 构建 URL,动态替换占位符
|
|
1013
|
-
let url = deleteApiConfig.url;
|
|
1014
|
-
url = url.replace(/:(\w+)/g, (match, fieldName) => {
|
|
1015
|
-
const value = record[fieldName];
|
|
1016
|
-
return value !== undefined ? String(value) : match;
|
|
1017
|
-
});
|
|
1068
|
+
let url = buildUrl(deleteApiConfig.url, record);
|
|
1018
1069
|
// 构建请求选项
|
|
1019
1070
|
const options = {
|
|
1020
1071
|
method: deleteApiConfig.method || 'DELETE',
|
|
@@ -1036,11 +1087,56 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
1036
1087
|
}, [request, schema.api.delete, fetchList, messageApi, rowKey]);
|
|
1037
1088
|
// ---------- 操作列点击 ----------
|
|
1038
1089
|
const handleAction = react.useCallback(async (action, record) => {
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1090
|
+
var _a, _b;
|
|
1091
|
+
if (action.type === 'view' || action.type === 'edit') {
|
|
1092
|
+
// 如果配置了detail API,先调用获取详细数据
|
|
1093
|
+
if (schema.api.detail) {
|
|
1094
|
+
try {
|
|
1095
|
+
const detailApiConfig = schema.api.detail;
|
|
1096
|
+
// 构建 URL,动态替换占位符
|
|
1097
|
+
let url = buildUrl(detailApiConfig.url, record);
|
|
1098
|
+
// 构建请求选项
|
|
1099
|
+
const options = {
|
|
1100
|
+
method: detailApiConfig.method || 'GET',
|
|
1101
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, detailApiConfig.headers)
|
|
1102
|
+
};
|
|
1103
|
+
// 处理请求体数据(对于GET请求,通常不需要body,但有些API可能需要)
|
|
1104
|
+
if (detailApiConfig.data && ['POST', 'PUT', 'PATCH'].includes(detailApiConfig.method || 'GET')) {
|
|
1105
|
+
const processedData = processTemplateData(detailApiConfig.data, record);
|
|
1106
|
+
options.body = JSON.stringify(processedData);
|
|
1107
|
+
}
|
|
1108
|
+
else if (detailApiConfig.method === 'GET' && detailApiConfig.data) {
|
|
1109
|
+
// 对于GET请求,将data作为查询参数
|
|
1110
|
+
const processedData = processTemplateData(detailApiConfig.data, record);
|
|
1111
|
+
const query = new URLSearchParams();
|
|
1112
|
+
Object.entries(processedData).forEach(([key, value]) => {
|
|
1113
|
+
if (value !== undefined && value !== null) {
|
|
1114
|
+
query.set(key, String(value));
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
url = `${url}?${query}`;
|
|
1118
|
+
}
|
|
1119
|
+
const response = await request(url, options);
|
|
1120
|
+
// 提取详细数据
|
|
1121
|
+
let detailData = record; // 默认使用列表数据
|
|
1122
|
+
if (response && typeof response === 'object') {
|
|
1123
|
+
const responseObj = response;
|
|
1124
|
+
// 尝试从不同的响应结构中提取数据
|
|
1125
|
+
detailData = ((_b = (_a = responseObj.data) !== null && _a !== void 0 ? _a : responseObj.result) !== null && _b !== void 0 ? _b : responseObj);
|
|
1126
|
+
}
|
|
1127
|
+
setModalState({ open: true, mode: action.type, record: detailData });
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
console.error('Failed to fetch detail:', error);
|
|
1131
|
+
messageApi.error('获取详细数据失败,使用列表数据');
|
|
1132
|
+
// 如果获取详细数据失败,仍然使用列表数据
|
|
1133
|
+
setModalState({ open: true, mode: action.type, record });
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
else {
|
|
1137
|
+
// 没有配置detail API,直接使用列表数据
|
|
1138
|
+
setModalState({ open: true, mode: action.type, record });
|
|
1139
|
+
}
|
|
1044
1140
|
}
|
|
1045
1141
|
else if (action.type === 'delete') {
|
|
1046
1142
|
handleDelete(record);
|
|
@@ -1074,11 +1170,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
1074
1170
|
}
|
|
1075
1171
|
try {
|
|
1076
1172
|
// 构建 URL,动态替换占位符
|
|
1077
|
-
let url = apiConfig.url;
|
|
1078
|
-
url = url.replace(/:(\w+)/g, (match, fieldName) => {
|
|
1079
|
-
const value = record[fieldName];
|
|
1080
|
-
return value !== undefined ? String(value) : match;
|
|
1081
|
-
});
|
|
1173
|
+
let url = buildUrl(apiConfig.url, record);
|
|
1082
1174
|
// 构建请求选项
|
|
1083
1175
|
const options = {
|
|
1084
1176
|
method: apiConfig.method || 'GET',
|
|
@@ -1145,7 +1237,9 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
1145
1237
|
requestData = Object.assign(Object.assign(Object.assign({}, requestData), processedData), { timestamp: new Date().toISOString() });
|
|
1146
1238
|
}
|
|
1147
1239
|
options.body = JSON.stringify(requestData);
|
|
1148
|
-
|
|
1240
|
+
// 构建 URL,支持动态占位符替换
|
|
1241
|
+
const url = buildUrl(createApiConfig.url, values);
|
|
1242
|
+
await request(url, options);
|
|
1149
1243
|
messageApi.success('新增成功');
|
|
1150
1244
|
setModalState({ open: false, mode: 'create' });
|
|
1151
1245
|
fetchList();
|
|
@@ -1163,11 +1257,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
|
|
|
1163
1257
|
const updateApiConfig = schema.api.update;
|
|
1164
1258
|
try {
|
|
1165
1259
|
// 构建 URL,动态替换占位符
|
|
1166
|
-
let url = updateApiConfig.url;
|
|
1167
|
-
url = url.replace(/:(\w+)/g, (match, fieldName) => {
|
|
1168
|
-
const value = values[fieldName];
|
|
1169
|
-
return value !== undefined ? String(value) : match;
|
|
1170
|
-
});
|
|
1260
|
+
let url = buildUrl(updateApiConfig.url, values);
|
|
1171
1261
|
// 构建请求选项
|
|
1172
1262
|
const options = {
|
|
1173
1263
|
method: updateApiConfig.method || 'PUT',
|