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 +59 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.esm.js +73 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +73 -17
- package/dist/index.js.map +1 -1
- package/dist/types/schema.d.ts +6 -6
- package/package.json +1 -1
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:
|
|
165
|
-
create?:
|
|
166
|
-
update?:
|
|
167
|
-
delete?:
|
|
168
|
-
detail?:
|
|
169
|
-
[key: string]:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
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
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
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();
|