whistle.mock-plugins 1.1.3-beta.2 → 1.1.3-dev.4
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.
|
@@ -25,51 +25,45 @@ const { TextArea } = Input;
|
|
|
25
25
|
// 刷新缓存工具函数
|
|
26
26
|
const flushCache = async () => {
|
|
27
27
|
try {
|
|
28
|
-
await fetch('/cgi-bin/
|
|
28
|
+
await fetch('/cgi-bin/flush-cache', { method: 'POST' });
|
|
29
|
+
console.log('缓存刷新成功');
|
|
29
30
|
} catch (error) {
|
|
30
|
-
console.error('
|
|
31
|
-
throw error;
|
|
31
|
+
console.error('缓存刷新失败:', error);
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
|
|
36
35
|
const MockData = () => {
|
|
37
36
|
const history = useHistory();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const [
|
|
41
|
-
const [formData, setFormData] = useState({
|
|
42
|
-
name: '',
|
|
43
|
-
description: '',
|
|
44
|
-
active: true
|
|
45
|
-
});
|
|
46
|
-
const [loading, setLoading] = useState(true);
|
|
37
|
+
|
|
38
|
+
// 功能模块状态
|
|
39
|
+
const [features, setFeatures] = useState([]);
|
|
47
40
|
const [form] = Form.useForm();
|
|
41
|
+
const [loading, setLoading] = useState(false);
|
|
42
|
+
const [modalVisible, setModalVisible] = useState(false);
|
|
43
|
+
const [editingFeature, setEditingFeature] = useState(null);
|
|
48
44
|
|
|
49
|
-
//
|
|
50
|
-
const [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
sortOrder: 'ascend', // ascend, descend
|
|
55
|
-
pageSize: 12,
|
|
56
|
-
current: 1
|
|
57
|
-
};
|
|
58
|
-
});
|
|
45
|
+
// 搜索和筛选状态
|
|
46
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
47
|
+
const [filteredFeatures, setFilteredFeatures] = useState([]);
|
|
48
|
+
const [statusFilter, setStatusFilter] = useState('all'); // all, active, inactive
|
|
49
|
+
const [sortBy, setSortBy] = useState('name'); // name, createTime, updateTime
|
|
59
50
|
|
|
60
|
-
//
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
// 分页状态
|
|
52
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
53
|
+
const [pageSize, setPageSize] = useState(12);
|
|
54
|
+
|
|
55
|
+
// 导入/导出状态
|
|
56
|
+
const [exportLoading, setExportLoading] = useState(false);
|
|
57
|
+
const [importLoading, setImportLoading] = useState(false);
|
|
66
58
|
|
|
67
|
-
// 加载功能列表
|
|
68
59
|
useEffect(() => {
|
|
69
60
|
fetchFeatures();
|
|
70
61
|
}, []);
|
|
71
62
|
|
|
72
|
-
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
filterAndSortFeatures();
|
|
65
|
+
}, [features, searchTerm, statusFilter, sortBy]);
|
|
66
|
+
|
|
73
67
|
const fetchFeatures = async () => {
|
|
74
68
|
try {
|
|
75
69
|
setLoading(true);
|
|
@@ -77,114 +71,78 @@ const MockData = () => {
|
|
|
77
71
|
const result = await response.json();
|
|
78
72
|
|
|
79
73
|
if (result.code === 0) {
|
|
80
|
-
|
|
74
|
+
setFeatures(result.data || []);
|
|
81
75
|
} else {
|
|
82
|
-
|
|
83
|
-
message.error('获取功能模块失败: ' + result.message);
|
|
76
|
+
throw new Error(result.message || '获取功能模块失败');
|
|
84
77
|
}
|
|
85
78
|
} catch (error) {
|
|
86
|
-
console.error('
|
|
87
|
-
message.error('
|
|
79
|
+
console.error('获取功能模块失败:', error);
|
|
80
|
+
message.error('获取功能模块失败: ' + error.message);
|
|
81
|
+
setFeatures([]);
|
|
88
82
|
} finally {
|
|
89
83
|
setLoading(false);
|
|
90
84
|
}
|
|
91
85
|
};
|
|
92
86
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
if (feature) {
|
|
96
|
-
setFormData({
|
|
97
|
-
name: feature.name,
|
|
98
|
-
description: feature.description || '',
|
|
99
|
-
active: feature.active !== false
|
|
100
|
-
});
|
|
101
|
-
form.setFieldsValue({
|
|
102
|
-
name: feature.name,
|
|
103
|
-
description: feature.description || '',
|
|
104
|
-
active: feature.active !== false
|
|
105
|
-
});
|
|
106
|
-
} else {
|
|
107
|
-
setFormData({
|
|
108
|
-
name: '',
|
|
109
|
-
description: '',
|
|
110
|
-
active: true
|
|
111
|
-
});
|
|
112
|
-
form.resetFields();
|
|
113
|
-
}
|
|
114
|
-
setShowModal(true);
|
|
115
|
-
};
|
|
87
|
+
const filterAndSortFeatures = () => {
|
|
88
|
+
let filtered = [...features];
|
|
116
89
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
description
|
|
123
|
-
|
|
124
|
-
|
|
90
|
+
// 搜索筛选
|
|
91
|
+
if (searchTerm) {
|
|
92
|
+
const term = searchTerm.toLowerCase();
|
|
93
|
+
filtered = filtered.filter(feature =>
|
|
94
|
+
feature.name.toLowerCase().includes(term) ||
|
|
95
|
+
(feature.description && feature.description.toLowerCase().includes(term))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
125
98
|
|
|
126
|
-
|
|
99
|
+
// 状态筛选
|
|
100
|
+
if (statusFilter === 'active') {
|
|
101
|
+
filtered = filtered.filter(feature => feature.active !== false);
|
|
102
|
+
} else if (statusFilter === 'inactive') {
|
|
103
|
+
filtered = filtered.filter(feature => feature.active === false);
|
|
104
|
+
}
|
|
127
105
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
console.log('更新响应:', result);
|
|
140
|
-
|
|
141
|
-
if (result.code === 0) {
|
|
142
|
-
message.success('功能模块更新成功');
|
|
143
|
-
setShowModal(false);
|
|
144
|
-
fetchFeatures();
|
|
145
|
-
|
|
146
|
-
// 刷新缓存
|
|
147
|
-
await flushCache();
|
|
148
|
-
} else {
|
|
149
|
-
message.error('功能模块更新失败: ' + (result.message || '未知错误'));
|
|
150
|
-
}
|
|
151
|
-
} else {
|
|
152
|
-
// 创建新功能模块
|
|
153
|
-
const response = await fetch('/cgi-bin/features', {
|
|
154
|
-
method: 'POST',
|
|
155
|
-
headers: {
|
|
156
|
-
'Content-Type': 'application/json',
|
|
157
|
-
},
|
|
158
|
-
body: JSON.stringify(submitData),
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const result = await response.json();
|
|
162
|
-
console.log('创建响应:', result);
|
|
163
|
-
|
|
164
|
-
if (result.code === 0) {
|
|
165
|
-
message.success('功能模块创建成功');
|
|
166
|
-
setShowModal(false);
|
|
167
|
-
fetchFeatures();
|
|
168
|
-
|
|
169
|
-
// 刷新缓存
|
|
170
|
-
await flushCache();
|
|
171
|
-
} else {
|
|
172
|
-
message.error('功能模块创建失败: ' + (result.message || '未知错误'));
|
|
173
|
-
}
|
|
106
|
+
// 排序
|
|
107
|
+
filtered.sort((a, b) => {
|
|
108
|
+
switch (sortBy) {
|
|
109
|
+
case 'name':
|
|
110
|
+
return a.name.localeCompare(b.name);
|
|
111
|
+
case 'createTime':
|
|
112
|
+
return new Date(b.createTime || 0) - new Date(a.createTime || 0);
|
|
113
|
+
case 'updateTime':
|
|
114
|
+
return new Date(b.updateTime || 0) - new Date(a.updateTime || 0);
|
|
115
|
+
default:
|
|
116
|
+
return 0;
|
|
174
117
|
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
setFilteredFeatures(filtered);
|
|
121
|
+
setCurrentPage(1); // 重置到第一页
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const handleAddFeature = () => {
|
|
125
|
+
form.resetFields();
|
|
126
|
+
setEditingFeature(null);
|
|
127
|
+
setModalVisible(true);
|
|
179
128
|
};
|
|
180
129
|
|
|
181
|
-
const
|
|
130
|
+
const handleEditFeature = (feature) => {
|
|
131
|
+
form.setFieldsValue({
|
|
132
|
+
name: feature.name,
|
|
133
|
+
description: feature.description
|
|
134
|
+
});
|
|
135
|
+
setEditingFeature(feature);
|
|
136
|
+
setModalVisible(true);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const handleDeleteFeature = async (id) => {
|
|
182
140
|
try {
|
|
183
141
|
const response = await fetch(`/cgi-bin/features?id=${id}`, {
|
|
184
|
-
method: 'DELETE'
|
|
142
|
+
method: 'DELETE'
|
|
185
143
|
});
|
|
186
|
-
|
|
187
144
|
const result = await response.json();
|
|
145
|
+
|
|
188
146
|
if (result.code === 0) {
|
|
189
147
|
message.success('功能模块删除成功');
|
|
190
148
|
fetchFeatures();
|
|
@@ -192,27 +150,29 @@ const MockData = () => {
|
|
|
192
150
|
// 刷新缓存
|
|
193
151
|
await flushCache();
|
|
194
152
|
} else {
|
|
195
|
-
|
|
153
|
+
throw new Error(result.message || '删除失败');
|
|
196
154
|
}
|
|
197
155
|
} catch (error) {
|
|
198
|
-
console.error('
|
|
199
|
-
message.error('
|
|
156
|
+
console.error('删除功能模块失败:', error);
|
|
157
|
+
message.error('删除功能模块失败: ' + error.message);
|
|
200
158
|
}
|
|
201
159
|
};
|
|
202
160
|
|
|
203
161
|
const handleToggleActive = async (id, currentActive) => {
|
|
204
162
|
try {
|
|
205
|
-
const response = await fetch(`/cgi-bin/features
|
|
206
|
-
method: '
|
|
163
|
+
const response = await fetch(`/cgi-bin/features`, {
|
|
164
|
+
method: 'PATCH',
|
|
207
165
|
headers: {
|
|
208
|
-
'Content-Type': 'application/json'
|
|
166
|
+
'Content-Type': 'application/json'
|
|
209
167
|
},
|
|
210
168
|
body: JSON.stringify({
|
|
169
|
+
id,
|
|
211
170
|
active: !currentActive
|
|
212
|
-
})
|
|
171
|
+
})
|
|
213
172
|
});
|
|
214
173
|
|
|
215
174
|
const result = await response.json();
|
|
175
|
+
|
|
216
176
|
if (result.code === 0) {
|
|
217
177
|
message.success(`功能模块${!currentActive ? '启用' : '禁用'}成功`);
|
|
218
178
|
fetchFeatures();
|
|
@@ -220,236 +180,194 @@ const MockData = () => {
|
|
|
220
180
|
// 刷新缓存
|
|
221
181
|
await flushCache();
|
|
222
182
|
} else {
|
|
223
|
-
|
|
183
|
+
throw new Error(result.message || '操作失败');
|
|
224
184
|
}
|
|
225
185
|
} catch (error) {
|
|
226
|
-
console.error(
|
|
227
|
-
message.error(
|
|
186
|
+
console.error('切换功能模块状态失败:', error);
|
|
187
|
+
message.error('操作失败: ' + error.message);
|
|
228
188
|
}
|
|
229
189
|
};
|
|
230
190
|
|
|
231
|
-
const
|
|
232
|
-
history.push(`/interface/${featureId}`);
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// 导出功能配置
|
|
236
|
-
const exportFeatureConfig = async () => {
|
|
191
|
+
const handleSubmit = async () => {
|
|
237
192
|
try {
|
|
238
|
-
const
|
|
193
|
+
const values = await form.validateFields();
|
|
194
|
+
|
|
195
|
+
const requestData = {
|
|
196
|
+
name: values.name,
|
|
197
|
+
description: values.description || '',
|
|
198
|
+
active: true
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const url = editingFeature
|
|
202
|
+
? `/cgi-bin/features?id=${editingFeature.id}`
|
|
203
|
+
: '/cgi-bin/features';
|
|
204
|
+
|
|
205
|
+
const method = editingFeature ? 'PUT' : 'POST';
|
|
206
|
+
|
|
207
|
+
const response = await fetch(url, {
|
|
208
|
+
method,
|
|
209
|
+
headers: {
|
|
210
|
+
'Content-Type': 'application/json'
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify(requestData)
|
|
213
|
+
});
|
|
214
|
+
|
|
239
215
|
const result = await response.json();
|
|
240
216
|
|
|
241
217
|
if (result.code === 0) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const url = URL.createObjectURL(dataBlob);
|
|
246
|
-
const link = document.createElement('a');
|
|
247
|
-
link.href = url;
|
|
248
|
-
link.download = `whistle-mock-features-${new Date().getTime()}.json`;
|
|
249
|
-
document.body.appendChild(link);
|
|
250
|
-
link.click();
|
|
251
|
-
document.body.removeChild(link);
|
|
252
|
-
URL.revokeObjectURL(url);
|
|
218
|
+
message.success(editingFeature ? '功能模块更新成功' : '功能模块创建成功');
|
|
219
|
+
setModalVisible(false);
|
|
220
|
+
fetchFeatures();
|
|
253
221
|
|
|
254
|
-
|
|
222
|
+
// 刷新缓存
|
|
223
|
+
await flushCache();
|
|
255
224
|
} else {
|
|
256
|
-
|
|
225
|
+
throw new Error(result.message || '操作失败');
|
|
226
|
+
}
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error('提交失败:', error);
|
|
229
|
+
message.error('操作失败: ' + error.message);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const handleCancel = () => {
|
|
234
|
+
setModalVisible(false);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const handleNavigateToInterfaces = (featureId) => {
|
|
238
|
+
history.push(`/interface-management/${featureId}`);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// 导出功能
|
|
242
|
+
const handleExport = async () => {
|
|
243
|
+
try {
|
|
244
|
+
setExportLoading(true);
|
|
245
|
+
const response = await fetch('/cgi-bin/features/export');
|
|
246
|
+
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
throw new Error('导出失败');
|
|
257
249
|
}
|
|
250
|
+
|
|
251
|
+
const blob = await response.blob();
|
|
252
|
+
const url = window.URL.createObjectURL(blob);
|
|
253
|
+
const a = document.createElement('a');
|
|
254
|
+
a.href = url;
|
|
255
|
+
a.download = `features-${new Date().toISOString().split('T')[0]}.json`;
|
|
256
|
+
document.body.appendChild(a);
|
|
257
|
+
a.click();
|
|
258
|
+
window.URL.revokeObjectURL(url);
|
|
259
|
+
document.body.removeChild(a);
|
|
260
|
+
|
|
261
|
+
message.success('导出成功');
|
|
258
262
|
} catch (error) {
|
|
259
263
|
console.error('导出失败:', error);
|
|
260
264
|
message.error('导出失败: ' + error.message);
|
|
265
|
+
} finally {
|
|
266
|
+
setExportLoading(false);
|
|
261
267
|
}
|
|
262
268
|
};
|
|
263
269
|
|
|
264
|
-
//
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (!file) return;
|
|
272
|
-
|
|
270
|
+
// 导入功能
|
|
271
|
+
const handleImport = (event) => {
|
|
272
|
+
const file = event.target.files[0];
|
|
273
|
+
if (!file) return;
|
|
274
|
+
|
|
275
|
+
const reader = new FileReader();
|
|
276
|
+
reader.onload = async (e) => {
|
|
273
277
|
try {
|
|
274
|
-
|
|
275
|
-
const data = JSON.parse(
|
|
278
|
+
setImportLoading(true);
|
|
279
|
+
const data = JSON.parse(e.target.result);
|
|
276
280
|
|
|
277
|
-
const response = await fetch('/cgi-bin/import
|
|
281
|
+
const response = await fetch('/cgi-bin/features/import', {
|
|
278
282
|
method: 'POST',
|
|
279
283
|
headers: {
|
|
280
|
-
'Content-Type': 'application/json'
|
|
284
|
+
'Content-Type': 'application/json'
|
|
281
285
|
},
|
|
282
|
-
body: JSON.stringify(data)
|
|
286
|
+
body: JSON.stringify(data)
|
|
283
287
|
});
|
|
284
|
-
|
|
288
|
+
|
|
285
289
|
const result = await response.json();
|
|
290
|
+
|
|
286
291
|
if (result.code === 0) {
|
|
287
|
-
message.success('
|
|
292
|
+
message.success('导入成功');
|
|
288
293
|
fetchFeatures();
|
|
289
|
-
|
|
290
|
-
// 刷新缓存
|
|
291
|
-
await flushCache();
|
|
292
294
|
} else {
|
|
293
|
-
|
|
295
|
+
throw new Error(result.message || '导入失败');
|
|
294
296
|
}
|
|
295
297
|
} catch (error) {
|
|
296
298
|
console.error('导入失败:', error);
|
|
297
299
|
message.error('导入失败: ' + error.message);
|
|
300
|
+
} finally {
|
|
301
|
+
setImportLoading(false);
|
|
302
|
+
// 清除文件选择
|
|
303
|
+
event.target.value = '';
|
|
298
304
|
}
|
|
299
305
|
};
|
|
300
|
-
input.click();
|
|
301
|
-
};
|
|
302
306
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const [filterStatus, setFilterStatus] = useState('all'); // all, active, inactive
|
|
306
|
-
|
|
307
|
-
// 筛选和排序数据
|
|
308
|
-
const getFilteredAndSortedData = () => {
|
|
309
|
-
let filtered = [...mockFeatures];
|
|
310
|
-
|
|
311
|
-
// 文本搜索
|
|
312
|
-
if (searchText) {
|
|
313
|
-
const searchLower = searchText.toLowerCase();
|
|
314
|
-
filtered = filtered.filter(item =>
|
|
315
|
-
item.name.toLowerCase().includes(searchLower) ||
|
|
316
|
-
(item.description && item.description.toLowerCase().includes(searchLower))
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// 状态筛选
|
|
321
|
-
if (filterStatus === 'active') {
|
|
322
|
-
filtered = filtered.filter(item => item.active !== false);
|
|
323
|
-
} else if (filterStatus === 'inactive') {
|
|
324
|
-
filtered = filtered.filter(item => item.active === false);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// 排序
|
|
328
|
-
filtered.sort((a, b) => {
|
|
329
|
-
let aValue, bValue;
|
|
330
|
-
|
|
331
|
-
switch (listConfig.sortBy) {
|
|
332
|
-
case 'name':
|
|
333
|
-
aValue = a.name || '';
|
|
334
|
-
bValue = b.name || '';
|
|
335
|
-
break;
|
|
336
|
-
case 'createdAt':
|
|
337
|
-
aValue = new Date(a.createdAt || 0);
|
|
338
|
-
bValue = new Date(b.createdAt || 0);
|
|
339
|
-
break;
|
|
340
|
-
case 'interfaceCount':
|
|
341
|
-
aValue = a.interfaceCount || 0;
|
|
342
|
-
bValue = b.interfaceCount || 0;
|
|
343
|
-
break;
|
|
344
|
-
case 'active':
|
|
345
|
-
aValue = a.active === false ? 0 : 1;
|
|
346
|
-
bValue = b.active === false ? 0 : 1;
|
|
347
|
-
break;
|
|
348
|
-
default:
|
|
349
|
-
aValue = a.name || '';
|
|
350
|
-
bValue = b.name || '';
|
|
351
|
-
}
|
|
307
|
+
reader.readAsText(file);
|
|
308
|
+
};
|
|
352
309
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
});
|
|
310
|
+
// 清空搜索
|
|
311
|
+
const handleClearSearch = () => {
|
|
312
|
+
setSearchTerm('');
|
|
313
|
+
};
|
|
359
314
|
|
|
360
|
-
|
|
315
|
+
// 刷新数据
|
|
316
|
+
const handleRefresh = () => {
|
|
317
|
+
fetchFeatures();
|
|
318
|
+
message.success('数据已刷新');
|
|
361
319
|
};
|
|
362
320
|
|
|
363
|
-
|
|
321
|
+
// 获取分页数据
|
|
322
|
+
const getPaginatedFeatures = () => {
|
|
323
|
+
const startIndex = (currentPage - 1) * pageSize;
|
|
324
|
+
const endIndex = startIndex + pageSize;
|
|
325
|
+
return filteredFeatures.slice(startIndex, endIndex);
|
|
326
|
+
};
|
|
364
327
|
|
|
365
|
-
//
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
328
|
+
// 筛选菜单
|
|
329
|
+
const filterMenu = (
|
|
330
|
+
<Menu
|
|
331
|
+
selectedKeys={[statusFilter]}
|
|
332
|
+
onClick={({ key }) => setStatusFilter(key)}
|
|
333
|
+
>
|
|
334
|
+
<Menu.Item key="all">全部状态</Menu.Item>
|
|
335
|
+
<Menu.Item key="active">启用</Menu.Item>
|
|
336
|
+
<Menu.Item key="inactive">禁用</Menu.Item>
|
|
337
|
+
</Menu>
|
|
338
|
+
);
|
|
369
339
|
|
|
370
340
|
// 排序菜单
|
|
371
341
|
const sortMenu = (
|
|
372
|
-
<Menu
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
<Menu.Item key="name
|
|
377
|
-
<Menu.Item key="
|
|
378
|
-
<Menu.Item key="
|
|
379
|
-
<Menu.Item key="createdAt-ascend">创建时间 (旧-新)</Menu.Item>
|
|
380
|
-
<Menu.Item key="interfaceCount-descend">接口数量 (多-少)</Menu.Item>
|
|
381
|
-
<Menu.Item key="interfaceCount-ascend">接口数量 (少-多)</Menu.Item>
|
|
382
|
-
<Menu.Item key="active-descend">状态 (启用优先)</Menu.Item>
|
|
383
|
-
<Menu.Item key="active-ascend">状态 (禁用优先)</Menu.Item>
|
|
342
|
+
<Menu
|
|
343
|
+
selectedKeys={[sortBy]}
|
|
344
|
+
onClick={({ key }) => setSortBy(key)}
|
|
345
|
+
>
|
|
346
|
+
<Menu.Item key="name">按名称排序</Menu.Item>
|
|
347
|
+
<Menu.Item key="createTime">按创建时间排序</Menu.Item>
|
|
348
|
+
<Menu.Item key="updateTime">按更新时间排序</Menu.Item>
|
|
384
349
|
</Menu>
|
|
385
350
|
);
|
|
386
351
|
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
<EditOutlined key="edit" onClick={() => openModal(feature)} />
|
|
402
|
-
</Tooltip>,
|
|
403
|
-
<Tooltip title="管理接口">
|
|
404
|
-
<SettingOutlined key="setting" onClick={() => gotoInterfaceManagement(feature.id)} />
|
|
405
|
-
</Tooltip>,
|
|
406
|
-
<Popconfirm
|
|
407
|
-
title="确定删除此功能模块吗?"
|
|
408
|
-
description="删除后相关的所有接口配置也会被删除,且无法恢复。"
|
|
409
|
-
onConfirm={() => handleDelete(feature.id)}
|
|
410
|
-
okText="确定"
|
|
411
|
-
cancelText="取消"
|
|
412
|
-
>
|
|
413
|
-
<Tooltip title="删除功能">
|
|
414
|
-
<DeleteOutlined key="delete" style={{ color: '#ff4d4f' }} />
|
|
415
|
-
</Tooltip>
|
|
416
|
-
</Popconfirm>,
|
|
417
|
-
]}
|
|
418
|
-
>
|
|
419
|
-
<div className="feature-card-header">
|
|
420
|
-
<div className="feature-name">
|
|
421
|
-
{feature.name}
|
|
422
|
-
</div>
|
|
423
|
-
<Switch
|
|
424
|
-
checked={isActive}
|
|
425
|
-
onChange={() => handleToggleActive(feature.id, isActive)}
|
|
426
|
-
size="small"
|
|
427
|
-
/>
|
|
428
|
-
</div>
|
|
429
|
-
<div className="feature-description">
|
|
430
|
-
{feature.description || '暂无描述'}
|
|
431
|
-
</div>
|
|
432
|
-
<div className="feature-stats">
|
|
433
|
-
<div className="stat-item">
|
|
434
|
-
<span className="stat-label">接口数量:</span>
|
|
435
|
-
<span className="stat-value">{feature.interfaceCount || 0}</span>
|
|
436
|
-
</div>
|
|
437
|
-
<div className="stat-item">
|
|
438
|
-
<span className="stat-label">创建时间:</span>
|
|
439
|
-
<span className="stat-value">
|
|
440
|
-
{feature.createdAt ? new Date(feature.createdAt).toLocaleDateString() : '未知'}
|
|
441
|
-
</span>
|
|
442
|
-
</div>
|
|
443
|
-
</div>
|
|
444
|
-
</Card>
|
|
445
|
-
</Badge.Ribbon>
|
|
446
|
-
</Col>
|
|
447
|
-
);
|
|
352
|
+
const getStatusText = (filter) => {
|
|
353
|
+
switch (filter) {
|
|
354
|
+
case 'active': return '启用';
|
|
355
|
+
case 'inactive': return '禁用';
|
|
356
|
+
default: return '全部状态';
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const getSortText = (sort) => {
|
|
361
|
+
switch (sort) {
|
|
362
|
+
case 'createTime': return '创建时间';
|
|
363
|
+
case 'updateTime': return '更新时间';
|
|
364
|
+
default: return '名称';
|
|
365
|
+
}
|
|
448
366
|
};
|
|
449
367
|
|
|
450
368
|
return (
|
|
451
369
|
<AppLayout>
|
|
452
|
-
<div className="
|
|
370
|
+
<div className="mock-data-container">
|
|
453
371
|
{/* V2版本标识 */}
|
|
454
372
|
<div style={{
|
|
455
373
|
position: 'absolute',
|
|
@@ -465,233 +383,302 @@ const MockData = () => {
|
|
|
465
383
|
重构后版本 V2
|
|
466
384
|
</div>
|
|
467
385
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
<div className="
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
</div>
|
|
475
|
-
<div className="page-actions">
|
|
476
|
-
<Button
|
|
477
|
-
type="primary"
|
|
478
|
-
icon={<PlusOutlined />}
|
|
479
|
-
onClick={() => openModal()}
|
|
480
|
-
>
|
|
481
|
-
新建功能
|
|
482
|
-
</Button>
|
|
483
|
-
<Button
|
|
484
|
-
type="primary"
|
|
485
|
-
icon={<ExportOutlined />}
|
|
486
|
-
onClick={importFeatureConfig}
|
|
487
|
-
style={{ backgroundColor: '#52c41a', borderColor: '#52c41a' }}
|
|
488
|
-
>
|
|
489
|
-
导入功能
|
|
490
|
-
</Button>
|
|
491
|
-
</div>
|
|
492
|
-
</div>
|
|
493
|
-
|
|
494
|
-
{/* 排序和分页控制栏 */}
|
|
495
|
-
{mockFeatures.length > 0 && !loading && (
|
|
496
|
-
<Card className="filter-controls" bordered={false}>
|
|
497
|
-
<div className="control-row">
|
|
498
|
-
<div className="search-controls">
|
|
386
|
+
{/* 头部操作栏 */}
|
|
387
|
+
<Card className="header-card" bordered={false}>
|
|
388
|
+
<div className="header-content">
|
|
389
|
+
<div className="header-left">
|
|
390
|
+
<h2 className="page-title">功能模块管理</h2>
|
|
391
|
+
<div className="search-container">
|
|
499
392
|
<Input
|
|
500
|
-
placeholder="
|
|
393
|
+
placeholder="搜索功能模块名称或描述"
|
|
394
|
+
value={searchTerm}
|
|
395
|
+
onChange={(e) => setSearchTerm(e.target.value)}
|
|
396
|
+
style={{ width: 300 }}
|
|
501
397
|
prefix={<SearchOutlined />}
|
|
502
|
-
value={searchText}
|
|
503
|
-
onChange={(e) => setSearchText(e.target.value)}
|
|
504
|
-
style={{ width: 240 }}
|
|
505
398
|
allowClear
|
|
399
|
+
onClear={handleClearSearch}
|
|
506
400
|
/>
|
|
507
|
-
<Select
|
|
508
|
-
value={filterStatus}
|
|
509
|
-
onChange={setFilterStatus}
|
|
510
|
-
style={{ width: 120 }}
|
|
511
|
-
>
|
|
512
|
-
<Option value="all">全部状态</Option>
|
|
513
|
-
<Option value="active">已启用</Option>
|
|
514
|
-
<Option value="inactive">已禁用</Option>
|
|
515
|
-
</Select>
|
|
516
401
|
</div>
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
排序
|
|
523
|
-
</Button>
|
|
524
|
-
</Dropdown>
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
<div className="header-right">
|
|
405
|
+
<Space size="middle">
|
|
406
|
+
<Tooltip title="刷新数据">
|
|
525
407
|
<Button
|
|
526
|
-
icon={<
|
|
527
|
-
onClick={
|
|
528
|
-
|
|
529
|
-
|
|
408
|
+
icon={<ReloadOutlined />}
|
|
409
|
+
onClick={handleRefresh}
|
|
410
|
+
loading={loading}
|
|
411
|
+
/>
|
|
412
|
+
</Tooltip>
|
|
413
|
+
|
|
414
|
+
<Dropdown overlay={filterMenu} trigger={['click']}>
|
|
415
|
+
<Button icon={<FilterOutlined />}>
|
|
416
|
+
{getStatusText(statusFilter)}
|
|
417
|
+
</Button>
|
|
418
|
+
</Dropdown>
|
|
419
|
+
|
|
420
|
+
<Dropdown overlay={sortMenu} trigger={['click']}>
|
|
421
|
+
<Button icon={<SortAscendingOutlined />}>
|
|
422
|
+
按{getSortText(sortBy)}
|
|
530
423
|
</Button>
|
|
424
|
+
</Dropdown>
|
|
425
|
+
|
|
426
|
+
<Button
|
|
427
|
+
icon={<ExportOutlined />}
|
|
428
|
+
onClick={handleExport}
|
|
429
|
+
loading={exportLoading}
|
|
430
|
+
>
|
|
431
|
+
导出
|
|
432
|
+
</Button>
|
|
433
|
+
|
|
434
|
+
<div style={{ position: 'relative' }}>
|
|
435
|
+
<input
|
|
436
|
+
type="file"
|
|
437
|
+
accept=".json"
|
|
438
|
+
onChange={handleImport}
|
|
439
|
+
style={{ display: 'none' }}
|
|
440
|
+
id="import-input"
|
|
441
|
+
/>
|
|
531
442
|
<Button
|
|
532
|
-
icon={<
|
|
533
|
-
|
|
534
|
-
|
|
443
|
+
icon={<ImportOutlined />}
|
|
444
|
+
loading={importLoading}
|
|
445
|
+
onClick={() => document.getElementById('import-input').click()}
|
|
535
446
|
>
|
|
536
|
-
|
|
447
|
+
导入
|
|
537
448
|
</Button>
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
</Button>
|
|
548
|
-
)}
|
|
549
|
-
</Space>
|
|
550
|
-
</div>
|
|
551
|
-
</div>
|
|
552
|
-
|
|
553
|
-
<div className="result-info">
|
|
554
|
-
<Space>
|
|
555
|
-
<span>
|
|
556
|
-
共 {mockFeatures.length} 个功能模块
|
|
557
|
-
{filteredData.length !== mockFeatures.length && (
|
|
558
|
-
<span>,筛选后 {filteredData.length} 个</span>
|
|
559
|
-
)}
|
|
560
|
-
</span>
|
|
561
|
-
<Badge
|
|
562
|
-
count={mockFeatures.filter(f => f.active !== false).length}
|
|
563
|
-
style={{ backgroundColor: '#52c41a' }}
|
|
564
|
-
title="启用的功能数量"
|
|
565
|
-
/>
|
|
566
|
-
<Badge
|
|
567
|
-
count={mockFeatures.filter(f => f.active === false).length}
|
|
568
|
-
style={{ backgroundColor: '#ff4d4f' }}
|
|
569
|
-
title="禁用的功能数量"
|
|
570
|
-
/>
|
|
449
|
+
</div>
|
|
450
|
+
|
|
451
|
+
<Button
|
|
452
|
+
type="primary"
|
|
453
|
+
icon={<PlusOutlined />}
|
|
454
|
+
onClick={handleAddFeature}
|
|
455
|
+
>
|
|
456
|
+
添加功能模块
|
|
457
|
+
</Button>
|
|
571
458
|
</Space>
|
|
572
459
|
</div>
|
|
573
|
-
</
|
|
574
|
-
|
|
460
|
+
</div>
|
|
461
|
+
</Card>
|
|
462
|
+
|
|
463
|
+
{/* 统计信息卡片 */}
|
|
464
|
+
<Card className="stats-card" bordered={false}>
|
|
465
|
+
<Row gutter={[24, 24]}>
|
|
466
|
+
<Col xs={24} sm={8} md={6}>
|
|
467
|
+
<div className="stat-item">
|
|
468
|
+
<div className="stat-number">{features.length}</div>
|
|
469
|
+
<div className="stat-label">总功能模块</div>
|
|
470
|
+
</div>
|
|
471
|
+
</Col>
|
|
472
|
+
<Col xs={24} sm={8} md={6}>
|
|
473
|
+
<div className="stat-item">
|
|
474
|
+
<div className="stat-number text-success">
|
|
475
|
+
{features.filter(f => f.active !== false).length}
|
|
476
|
+
</div>
|
|
477
|
+
<div className="stat-label">启用模块</div>
|
|
478
|
+
</div>
|
|
479
|
+
</Col>
|
|
480
|
+
<Col xs={24} sm={8} md={6}>
|
|
481
|
+
<div className="stat-item">
|
|
482
|
+
<div className="stat-number text-warning">
|
|
483
|
+
{features.filter(f => f.active === false).length}
|
|
484
|
+
</div>
|
|
485
|
+
<div className="stat-label">禁用模块</div>
|
|
486
|
+
</div>
|
|
487
|
+
</Col>
|
|
488
|
+
<Col xs={24} sm={8} md={6}>
|
|
489
|
+
<div className="stat-item">
|
|
490
|
+
<div className="stat-number text-info">{filteredFeatures.length}</div>
|
|
491
|
+
<div className="stat-label">筛选结果</div>
|
|
492
|
+
</div>
|
|
493
|
+
</Col>
|
|
494
|
+
</Row>
|
|
495
|
+
</Card>
|
|
575
496
|
|
|
576
497
|
{/* 功能模块列表 */}
|
|
577
|
-
<
|
|
498
|
+
<Card className="list-card" bordered={false} title="功能模块列表">
|
|
578
499
|
{loading ? (
|
|
579
500
|
<div className="loading-container">
|
|
580
501
|
<Row gutter={[16, 16]}>
|
|
581
|
-
{[
|
|
582
|
-
<Col xs={24} sm={12} md={8} lg={6} key={
|
|
583
|
-
<Card loading
|
|
502
|
+
{[...Array(6)].map((_, index) => (
|
|
503
|
+
<Col xs={24} sm={12} md={8} lg={6} key={index}>
|
|
504
|
+
<Card loading />
|
|
584
505
|
</Col>
|
|
585
506
|
))}
|
|
586
507
|
</Row>
|
|
587
508
|
</div>
|
|
588
|
-
) :
|
|
589
|
-
<
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
509
|
+
) : getPaginatedFeatures().length === 0 ? (
|
|
510
|
+
<div className="empty-state">
|
|
511
|
+
<div className="empty-icon">📦</div>
|
|
512
|
+
<div className="empty-text">
|
|
513
|
+
{searchTerm || statusFilter !== 'all' ? '没有找到匹配的功能模块' : '暂无功能模块'}
|
|
514
|
+
</div>
|
|
515
|
+
<div className="empty-description">
|
|
516
|
+
{searchTerm || statusFilter !== 'all' ? '尝试调整搜索条件或筛选器' : '点击上方按钮创建你的第一个功能模块'}
|
|
517
|
+
</div>
|
|
518
|
+
{!searchTerm && statusFilter === 'all' && (
|
|
519
|
+
<Button
|
|
520
|
+
type="primary"
|
|
521
|
+
icon={<PlusOutlined />}
|
|
522
|
+
onClick={handleAddFeature}
|
|
523
|
+
style={{ marginTop: 16 }}
|
|
524
|
+
>
|
|
525
|
+
创建功能模块
|
|
526
|
+
</Button>
|
|
527
|
+
)}
|
|
528
|
+
</div>
|
|
604
529
|
) : (
|
|
605
530
|
<>
|
|
606
|
-
<Row gutter={[16, 16]}
|
|
607
|
-
{
|
|
531
|
+
<Row gutter={[16, 16]}>
|
|
532
|
+
{getPaginatedFeatures().map(feature => (
|
|
533
|
+
<Col xs={24} sm={12} md={8} lg={6} key={feature.id}>
|
|
534
|
+
<Card
|
|
535
|
+
className={`feature-card ${feature.active === false ? 'inactive' : ''}`}
|
|
536
|
+
hoverable
|
|
537
|
+
actions={[
|
|
538
|
+
<Tooltip title="编辑">
|
|
539
|
+
<EditOutlined
|
|
540
|
+
key="edit"
|
|
541
|
+
onClick={() => handleEditFeature(feature)}
|
|
542
|
+
/>
|
|
543
|
+
</Tooltip>,
|
|
544
|
+
<Tooltip title="接口管理">
|
|
545
|
+
<SettingOutlined
|
|
546
|
+
key="setting"
|
|
547
|
+
onClick={() => handleNavigateToInterfaces(feature.id)}
|
|
548
|
+
/>
|
|
549
|
+
</Tooltip>,
|
|
550
|
+
<Popconfirm
|
|
551
|
+
title="确定要删除这个功能模块吗?"
|
|
552
|
+
description="删除后将无法恢复,请谨慎操作。"
|
|
553
|
+
onConfirm={() => handleDeleteFeature(feature.id)}
|
|
554
|
+
okText="确定"
|
|
555
|
+
cancelText="取消"
|
|
556
|
+
>
|
|
557
|
+
<Tooltip title="删除">
|
|
558
|
+
<DeleteOutlined key="delete" className="text-danger" />
|
|
559
|
+
</Tooltip>
|
|
560
|
+
</Popconfirm>
|
|
561
|
+
]}
|
|
562
|
+
>
|
|
563
|
+
<div className="feature-card-header">
|
|
564
|
+
<div className="feature-card-title">
|
|
565
|
+
<span className="feature-name">{feature.name}</span>
|
|
566
|
+
<Switch
|
|
567
|
+
checked={feature.active !== false}
|
|
568
|
+
onChange={() => handleToggleActive(feature.id, feature.active !== false)}
|
|
569
|
+
size="small"
|
|
570
|
+
className="feature-switch"
|
|
571
|
+
/>
|
|
572
|
+
</div>
|
|
573
|
+
<Badge
|
|
574
|
+
status={feature.active === false ? 'error' : 'success'}
|
|
575
|
+
text={feature.active === false ? '已禁用' : '已启用'}
|
|
576
|
+
className="feature-status"
|
|
577
|
+
/>
|
|
578
|
+
</div>
|
|
579
|
+
|
|
580
|
+
<div className="feature-card-content">
|
|
581
|
+
{feature.description ? (
|
|
582
|
+
<p className="feature-description">
|
|
583
|
+
{feature.description}
|
|
584
|
+
</p>
|
|
585
|
+
) : (
|
|
586
|
+
<p className="feature-description empty">
|
|
587
|
+
暂无描述
|
|
588
|
+
</p>
|
|
589
|
+
)}
|
|
590
|
+
|
|
591
|
+
<div className="feature-meta">
|
|
592
|
+
{feature.createTime && (
|
|
593
|
+
<div className="meta-item">
|
|
594
|
+
<span className="meta-label">创建:</span>
|
|
595
|
+
<span className="meta-value">
|
|
596
|
+
{new Date(feature.createTime).toLocaleDateString()}
|
|
597
|
+
</span>
|
|
598
|
+
</div>
|
|
599
|
+
)}
|
|
600
|
+
{feature.updateTime && feature.updateTime !== feature.createTime && (
|
|
601
|
+
<div className="meta-item">
|
|
602
|
+
<span className="meta-label">更新:</span>
|
|
603
|
+
<span className="meta-value">
|
|
604
|
+
{new Date(feature.updateTime).toLocaleDateString()}
|
|
605
|
+
</span>
|
|
606
|
+
</div>
|
|
607
|
+
)}
|
|
608
|
+
</div>
|
|
609
|
+
</div>
|
|
610
|
+
</Card>
|
|
611
|
+
</Col>
|
|
612
|
+
))}
|
|
608
613
|
</Row>
|
|
609
614
|
|
|
610
|
-
{/*
|
|
611
|
-
{
|
|
615
|
+
{/* 分页 */}
|
|
616
|
+
{filteredFeatures.length > pageSize && (
|
|
612
617
|
<div className="pagination-container">
|
|
613
618
|
<Pagination
|
|
614
|
-
current={
|
|
615
|
-
pageSize={
|
|
616
|
-
total={
|
|
619
|
+
current={currentPage}
|
|
620
|
+
pageSize={pageSize}
|
|
621
|
+
total={filteredFeatures.length}
|
|
617
622
|
showSizeChanger
|
|
618
623
|
showQuickJumper
|
|
619
624
|
showTotal={(total, range) =>
|
|
620
|
-
|
|
625
|
+
`共 ${total} 个功能模块,显示第 ${range[0]}-${range[1]} 个`
|
|
621
626
|
}
|
|
622
|
-
pageSizeOptions={['8', '12', '
|
|
623
|
-
onChange={(
|
|
624
|
-
|
|
627
|
+
pageSizeOptions={['8', '12', '24', '48']}
|
|
628
|
+
onChange={(page, size) => {
|
|
629
|
+
setCurrentPage(page);
|
|
630
|
+
setPageSize(size);
|
|
625
631
|
}}
|
|
626
632
|
/>
|
|
627
633
|
</div>
|
|
628
634
|
)}
|
|
629
635
|
</>
|
|
630
636
|
)}
|
|
631
|
-
</
|
|
637
|
+
</Card>
|
|
632
638
|
|
|
633
|
-
{/*
|
|
639
|
+
{/* 添加/编辑功能模块模态框 */}
|
|
634
640
|
<Modal
|
|
635
|
-
title={
|
|
636
|
-
open={
|
|
637
|
-
|
|
638
|
-
|
|
641
|
+
title={editingFeature ? '编辑功能模块' : '添加功能模块'}
|
|
642
|
+
open={modalVisible}
|
|
643
|
+
onOk={handleSubmit}
|
|
644
|
+
onCancel={handleCancel}
|
|
645
|
+
okText={editingFeature ? '保存' : '创建'}
|
|
646
|
+
cancelText="取消"
|
|
639
647
|
destroyOnClose
|
|
640
648
|
>
|
|
641
649
|
<Form
|
|
642
650
|
form={form}
|
|
643
651
|
layout="vertical"
|
|
644
|
-
onFinish={handleSubmit}
|
|
645
652
|
initialValues={{
|
|
646
653
|
name: '',
|
|
647
|
-
description: ''
|
|
648
|
-
active: true
|
|
654
|
+
description: ''
|
|
649
655
|
}}
|
|
650
656
|
>
|
|
651
657
|
<Form.Item
|
|
652
658
|
name="name"
|
|
653
|
-
label="
|
|
659
|
+
label="功能模块名称"
|
|
654
660
|
rules={[
|
|
655
|
-
{ required: true, message: '
|
|
656
|
-
{ max: 50, message: '
|
|
661
|
+
{ required: true, message: '请输入功能模块名称' },
|
|
662
|
+
{ max: 50, message: '名称长度不能超过50个字符' }
|
|
657
663
|
]}
|
|
658
664
|
>
|
|
659
|
-
<Input placeholder="
|
|
665
|
+
<Input placeholder="请输入功能模块名称" />
|
|
660
666
|
</Form.Item>
|
|
661
667
|
|
|
662
668
|
<Form.Item
|
|
663
669
|
name="description"
|
|
664
|
-
label="
|
|
670
|
+
label="描述"
|
|
665
671
|
rules={[
|
|
666
|
-
{ max: 200, message: '
|
|
672
|
+
{ max: 200, message: '描述长度不能超过200个字符' }
|
|
667
673
|
]}
|
|
668
674
|
>
|
|
669
|
-
<TextArea
|
|
670
|
-
placeholder="
|
|
675
|
+
<TextArea
|
|
676
|
+
placeholder="请输入功能模块描述(可选)"
|
|
671
677
|
rows={3}
|
|
672
678
|
showCount
|
|
673
679
|
maxLength={200}
|
|
674
680
|
/>
|
|
675
681
|
</Form.Item>
|
|
676
|
-
|
|
677
|
-
<Form.Item
|
|
678
|
-
name="active"
|
|
679
|
-
label="启用状态"
|
|
680
|
-
valuePropName="checked"
|
|
681
|
-
>
|
|
682
|
-
<Switch checkedChildren="启用" unCheckedChildren="禁用" />
|
|
683
|
-
</Form.Item>
|
|
684
|
-
|
|
685
|
-
<Form.Item className="form-actions">
|
|
686
|
-
<Space>
|
|
687
|
-
<Button onClick={() => setShowModal(false)}>
|
|
688
|
-
取消
|
|
689
|
-
</Button>
|
|
690
|
-
<Button type="primary" htmlType="submit">
|
|
691
|
-
{currentFeature ? '保存' : '创建'}
|
|
692
|
-
</Button>
|
|
693
|
-
</Space>
|
|
694
|
-
</Form.Item>
|
|
695
682
|
</Form>
|
|
696
683
|
</Modal>
|
|
697
684
|
</div>
|