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