crud-page-react 0.2.2 → 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.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 (!allowedValues.includes(actualValue)) {
95
+ if (!valuesArray.includes(actualValue)) {
94
96
  return false;
95
97
  }
96
98
  }
@@ -870,7 +872,22 @@ function DynamicForm({ schema, mode, visible, initialValues, onSubmit, onCancel,
870
872
  }
871
873
 
872
874
  const { Title } = antd.Typography;
873
- /** 处理模板数据,支持 {{fieldName}} 格式的变量替换 */
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}} 格式的变量替换,支持嵌套对象和数组 */
874
891
  function processTemplateData(data, record) {
875
892
  const result = {};
876
893
  for (const [key, value] of Object.entries(data)) {
@@ -881,6 +898,27 @@ function processTemplateData(data, record) {
881
898
  return fieldValue !== undefined ? String(fieldValue) : match;
882
899
  });
883
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
+ }
884
922
  else {
885
923
  result[key] = value;
886
924
  }
@@ -954,17 +992,32 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
954
992
  method: listApiConfig.method || 'GET',
955
993
  headers: Object.assign({ 'Content-Type': 'application/json' }, listApiConfig.headers)
956
994
  };
957
- // 如果是 POST 请求,将查询参数放到请求体中
958
- let url = listApiConfig.url;
995
+ // 构建 URL,支持动态占位符替换
996
+ let url = buildUrl(listApiConfig.url, params);
959
997
  if (listApiConfig.method === 'POST') {
960
998
  const queryParams = {};
961
999
  query.forEach((value, key) => {
962
1000
  queryParams[key] = value;
963
1001
  });
964
- const requestData = Object.assign(Object.assign({}, queryParams), listApiConfig.data);
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);
965
1009
  options.body = JSON.stringify(requestData);
966
1010
  }
967
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
+ }
968
1021
  url = `${url}?${query}`;
969
1022
  }
970
1023
  const json = await request(url, options);
@@ -1012,11 +1065,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
1012
1065
  const deleteApiConfig = schema.api.delete;
1013
1066
  try {
1014
1067
  // 构建 URL,动态替换占位符
1015
- let url = deleteApiConfig.url;
1016
- url = url.replace(/:(\w+)/g, (match, fieldName) => {
1017
- const value = record[fieldName];
1018
- return value !== undefined ? String(value) : match;
1019
- });
1068
+ let url = buildUrl(deleteApiConfig.url, record);
1020
1069
  // 构建请求选项
1021
1070
  const options = {
1022
1071
  method: deleteApiConfig.method || 'DELETE',
@@ -1038,11 +1087,56 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
1038
1087
  }, [request, schema.api.delete, fetchList, messageApi, rowKey]);
1039
1088
  // ---------- 操作列点击 ----------
1040
1089
  const handleAction = react.useCallback(async (action, record) => {
1041
- if (action.type === 'view') {
1042
- setModalState({ open: true, mode: 'view', record });
1043
- }
1044
- else if (action.type === 'edit') {
1045
- setModalState({ open: true, mode: 'edit', record });
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
+ }
1046
1140
  }
1047
1141
  else if (action.type === 'delete') {
1048
1142
  handleDelete(record);
@@ -1076,11 +1170,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
1076
1170
  }
1077
1171
  try {
1078
1172
  // 构建 URL,动态替换占位符
1079
- let url = apiConfig.url;
1080
- url = url.replace(/:(\w+)/g, (match, fieldName) => {
1081
- const value = record[fieldName];
1082
- return value !== undefined ? String(value) : match;
1083
- });
1173
+ let url = buildUrl(apiConfig.url, record);
1084
1174
  // 构建请求选项
1085
1175
  const options = {
1086
1176
  method: apiConfig.method || 'GET',
@@ -1147,7 +1237,9 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
1147
1237
  requestData = Object.assign(Object.assign(Object.assign({}, requestData), processedData), { timestamp: new Date().toISOString() });
1148
1238
  }
1149
1239
  options.body = JSON.stringify(requestData);
1150
- await request(createApiConfig.url, options);
1240
+ // 构建 URL,支持动态占位符替换
1241
+ const url = buildUrl(createApiConfig.url, values);
1242
+ await request(url, options);
1151
1243
  messageApi.success('新增成功');
1152
1244
  setModalState({ open: false, mode: 'create' });
1153
1245
  fetchList();
@@ -1165,11 +1257,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest, loca
1165
1257
  const updateApiConfig = schema.api.update;
1166
1258
  try {
1167
1259
  // 构建 URL,动态替换占位符
1168
- let url = updateApiConfig.url;
1169
- url = url.replace(/:(\w+)/g, (match, fieldName) => {
1170
- const value = values[fieldName];
1171
- return value !== undefined ? String(value) : match;
1172
- });
1260
+ let url = buildUrl(updateApiConfig.url, values);
1173
1261
  // 构建请求选项
1174
1262
  const options = {
1175
1263
  method: updateApiConfig.method || 'PUT',