crud-page-react 0.0.6 → 0.1.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/README.md CHANGED
@@ -36,6 +36,8 @@ yarn add crud-page-react
36
36
 
37
37
  ## 快速开始
38
38
 
39
+ ### 基础用法
40
+
39
41
  ```tsx
40
42
  import React from 'react';
41
43
  import { CrudPage } from 'crud-page-react';
@@ -105,6 +107,63 @@ function App() {
105
107
  export default App;
106
108
  ```
107
109
 
110
+ ### 扩展 API 配置
111
+
112
+ v0.0.7+ 版本支持更强大的 API 配置,包括自定义 HTTP 方法、请求头、请求体数据和模板变量:
113
+
114
+ ```tsx
115
+ const advancedSchema: CrudPageSchema = {
116
+ id: 'orders',
117
+ title: '订单管理',
118
+ api: {
119
+ // 简单字符串配置(向后兼容)
120
+ list: '/api/orders',
121
+
122
+ // 扩展对象配置
123
+ create: {
124
+ url: '/api/orders',
125
+ method: 'POST',
126
+ headers: {
127
+ 'X-Request-Source': 'admin-panel'
128
+ },
129
+ data: {
130
+ source: 'web',
131
+ createdBy: '{{currentUser}}',
132
+ timestamp: '{{timestamp}}'
133
+ }
134
+ },
135
+
136
+ update: {
137
+ url: '/api/orders/:id',
138
+ method: 'PUT',
139
+ data: {
140
+ updatedBy: '{{currentUser}}',
141
+ updateTime: '{{timestamp}}'
142
+ }
143
+ },
144
+
145
+ delete: {
146
+ url: '/api/orders/:orderNo',
147
+ method: 'DELETE',
148
+ data: {
149
+ deletedBy: '{{currentUser}}',
150
+ deleteReason: '{{deleteReason}}',
151
+ timestamp: '{{timestamp}}'
152
+ }
153
+ }
154
+ },
155
+ // ... 其他配置
156
+ };
157
+ ```
158
+
159
+ ### 支持的扩展配置
160
+
161
+ - **HTTP 方法**:GET、POST、PUT、PATCH、DELETE
162
+ - **自定义请求头**:添加认证、来源标识等
163
+ - **请求体数据**:固定参数和动态参数
164
+ - **模板变量**:`{{fieldName}}` 格式的动态值替换
165
+ - **URL 占位符**:`:fieldName` 格式的动态 URL 构建
166
+
108
167
  ## 动态 URL 参数
109
168
 
110
169
  支持在 API 配置中使用任意字段作为 URL 参数:
package/dist/index.d.ts CHANGED
@@ -161,12 +161,12 @@ interface CrudPageSchema {
161
161
  id: string;
162
162
  title: string;
163
163
  api: {
164
- list: string;
165
- create?: string;
166
- update?: string;
167
- delete?: string;
168
- detail?: string;
169
- [key: string]: string | ActionApiConfig | undefined;
164
+ list: ActionApiConfig;
165
+ create?: ActionApiConfig;
166
+ update?: ActionApiConfig;
167
+ delete?: ActionApiConfig;
168
+ detail?: ActionApiConfig;
169
+ [key: string]: ActionApiConfig | undefined;
170
170
  };
171
171
  fields: FieldSchema[];
172
172
  actions?: ActionSchema[];
package/dist/index.esm.js CHANGED
@@ -810,13 +810,6 @@ function DynamicForm({ schema, mode, visible, initialValues, onSubmit, onCancel,
810
810
  }
811
811
 
812
812
  const { Title } = Typography;
813
- /** 动态替换 URL 模板中的占位符 */
814
- function buildUrl(template, record) {
815
- return template.replace(/:(\w+)/g, (match, fieldName) => {
816
- const value = record[fieldName];
817
- return value !== undefined ? String(value) : match;
818
- });
819
- }
820
813
  /** 处理模板数据,支持 {{fieldName}} 格式的变量替换 */
821
814
  function processTemplateData(data, record) {
822
815
  const result = {};
@@ -887,14 +880,34 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest }) =>
887
880
  initializeData();
888
881
  return;
889
882
  }
883
+ const listApiConfig = schema.api.list;
890
884
  setLoading(true);
891
885
  try {
886
+ // 构建查询参数
892
887
  const query = new URLSearchParams({ page: String(p), pageSize: String(ps) });
893
888
  Object.entries(params).forEach(([k, v]) => {
894
889
  if (v !== undefined && v !== null && v !== '')
895
890
  query.set(k, String(v));
896
891
  });
897
- const json = await request(`${schema.api.list}?${query}`);
892
+ // 构建请求选项
893
+ const options = {
894
+ method: listApiConfig.method || 'GET',
895
+ headers: Object.assign({ 'Content-Type': 'application/json' }, listApiConfig.headers)
896
+ };
897
+ // 如果是 POST 请求,将查询参数放到请求体中
898
+ let url = listApiConfig.url;
899
+ if (listApiConfig.method === 'POST') {
900
+ const queryParams = {};
901
+ query.forEach((value, key) => {
902
+ queryParams[key] = value;
903
+ });
904
+ const requestData = Object.assign(Object.assign({}, queryParams), listApiConfig.data);
905
+ options.body = JSON.stringify(requestData);
906
+ }
907
+ else {
908
+ url = `${url}?${query}`;
909
+ }
910
+ const json = await request(url, options);
898
911
  const { list, total: tot } = extractListResponse(json);
899
912
  setData(list);
900
913
  setTotal(tot);
@@ -936,8 +949,25 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest }) =>
936
949
  messageApi.error('删除功能未配置');
937
950
  return;
938
951
  }
952
+ const deleteApiConfig = schema.api.delete;
939
953
  try {
940
- await request(buildUrl(schema.api.delete, record), { method: 'DELETE' });
954
+ // 构建 URL,动态替换占位符
955
+ let url = deleteApiConfig.url;
956
+ url = url.replace(/:(\w+)/g, (match, fieldName) => {
957
+ const value = record[fieldName];
958
+ return value !== undefined ? String(value) : match;
959
+ });
960
+ // 构建请求选项
961
+ const options = {
962
+ method: deleteApiConfig.method || 'DELETE',
963
+ headers: Object.assign({ 'Content-Type': 'application/json' }, deleteApiConfig.headers)
964
+ };
965
+ // 处理请求体数据
966
+ if (deleteApiConfig.data && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(deleteApiConfig.method || 'DELETE')) {
967
+ const processedData = processTemplateData(deleteApiConfig.data, record);
968
+ options.body = JSON.stringify(Object.assign(Object.assign({}, processedData), { recordId: record[rowKey], timestamp: new Date().toISOString() }));
969
+ }
970
+ await request(url, options);
941
971
  messageApi.success('删除成功');
942
972
  fetchList();
943
973
  }
@@ -945,7 +975,7 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest }) =>
945
975
  console.error('Delete failed:', error);
946
976
  messageApi.error('删除失败,请稍后重试');
947
977
  }
948
- }, [request, schema.api.delete, fetchList, messageApi]);
978
+ }, [request, schema.api.delete, fetchList, messageApi, rowKey]);
949
979
  // ---------- 操作列点击 ----------
950
980
  const handleAction = useCallback(async (action, record) => {
951
981
  if (action.type === 'view') {
@@ -1043,11 +1073,21 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest }) =>
1043
1073
  messageApi.error('新增功能未配置');
1044
1074
  return;
1045
1075
  }
1076
+ const createApiConfig = schema.api.create;
1046
1077
  try {
1047
- await request(schema.api.create, {
1048
- method: 'POST',
1049
- body: JSON.stringify(values),
1050
- });
1078
+ // 构建请求选项
1079
+ const options = {
1080
+ method: createApiConfig.method || 'POST',
1081
+ headers: Object.assign({ 'Content-Type': 'application/json' }, createApiConfig.headers)
1082
+ };
1083
+ // 处理请求体数据
1084
+ let requestData = Object.assign({}, values);
1085
+ if (createApiConfig.data) {
1086
+ const processedData = processTemplateData(createApiConfig.data, values);
1087
+ requestData = Object.assign(Object.assign(Object.assign({}, requestData), processedData), { timestamp: new Date().toISOString() });
1088
+ }
1089
+ options.body = JSON.stringify(requestData);
1090
+ await request(createApiConfig.url, options);
1051
1091
  messageApi.success('新增成功');
1052
1092
  setModalState({ open: false, mode: 'create' });
1053
1093
  fetchList();
@@ -1062,11 +1102,27 @@ const CrudPage = ({ schema, initialData = [], apiRequest: customApiRequest }) =>
1062
1102
  messageApi.error('编辑功能未配置');
1063
1103
  return;
1064
1104
  }
1105
+ const updateApiConfig = schema.api.update;
1065
1106
  try {
1066
- await request(buildUrl(schema.api.update, values), {
1067
- method: 'PUT',
1068
- body: JSON.stringify(values),
1107
+ // 构建 URL,动态替换占位符
1108
+ let url = updateApiConfig.url;
1109
+ url = url.replace(/:(\w+)/g, (match, fieldName) => {
1110
+ const value = values[fieldName];
1111
+ return value !== undefined ? String(value) : match;
1069
1112
  });
1113
+ // 构建请求选项
1114
+ const options = {
1115
+ method: updateApiConfig.method || 'PUT',
1116
+ headers: Object.assign({ 'Content-Type': 'application/json' }, updateApiConfig.headers)
1117
+ };
1118
+ // 处理请求体数据
1119
+ let requestData = Object.assign({}, values);
1120
+ if (updateApiConfig.data) {
1121
+ const processedData = processTemplateData(updateApiConfig.data, values);
1122
+ requestData = Object.assign(Object.assign(Object.assign({}, requestData), processedData), { timestamp: new Date().toISOString() });
1123
+ }
1124
+ options.body = JSON.stringify(requestData);
1125
+ await request(url, options);
1070
1126
  messageApi.success('编辑成功');
1071
1127
  setModalState({ open: false, mode: 'create' });
1072
1128
  fetchList();