whistle.mock-plugins 1.1.1-dev.14 → 1.1.1-dev.8

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.
@@ -23,7 +23,6 @@ const processInterfaceData = (data) => {
23
23
  console.log('=== 开始处理接口数据 ===');
24
24
  console.log('原始数据:', JSON.stringify({
25
25
  name: result.name,
26
- group: result.group, // 添加分组信息的日志
27
26
  hasResponses: !!result.responses,
28
27
  responsesType: typeof result.responses,
29
28
  responsesLength: result.responses ? result.responses.length : 0,
@@ -109,7 +108,6 @@ const processInterfaceData = (data) => {
109
108
  console.log('=== 处理后的最终接口数据 ===');
110
109
  console.log('最终数据:', JSON.stringify({
111
110
  name: result.name,
112
- group: result.group, // 添加分组信息的日志
113
111
  responsesLength: result.responses.length,
114
112
  responses: result.responses,
115
113
  activeResponseId: result.activeResponseId,
@@ -518,175 +516,6 @@ const initRouter = () => {
518
516
  }
519
517
  });
520
518
 
521
- // 批量更新接口状态
522
- router.patch('/interfaces', (req, res) => {
523
- try {
524
- const { active } = req.query;
525
- const { featureId, group } = req.body;
526
-
527
- if (active === undefined) {
528
- return res.status(400).json({
529
- code: 1,
530
- message: '状态参数为必填项'
531
- });
532
- }
533
-
534
- if (!featureId) {
535
- return res.status(400).json({
536
- code: 1,
537
- message: '功能ID为必填项'
538
- });
539
- }
540
-
541
- // 检查功能是否存在
542
- const featuresFile = path.join(DATA_DIR, 'features.json');
543
- if (!fs.existsSync(featuresFile)) {
544
- return res.status(404).json({
545
- code: 1,
546
- message: '功能不存在'
547
- });
548
- }
549
-
550
- const features = fs.readJsonSync(featuresFile);
551
- const feature = features.find(f => f.id === featureId);
552
- if (!feature) {
553
- return res.status(404).json({
554
- code: 1,
555
- message: '功能不存在'
556
- });
557
- }
558
-
559
- // 读取接口列表
560
- const interfacesFile = path.join(DATA_DIR, `interfaces-${featureId}.json`);
561
- if (!fs.existsSync(interfacesFile)) {
562
- return res.status(404).json({
563
- code: 1,
564
- message: '接口列表不存在'
565
- });
566
- }
567
-
568
- const interfaces = fs.readJsonSync(interfacesFile);
569
-
570
- // 根据分组筛选要更新的接口
571
- let updatedCount = 0;
572
- const updatedInterfaces = interfaces.map(item => {
573
- // 如果指定了分组,只更新该分组下的接口
574
- if (group && item.group !== group) {
575
- return item;
576
- }
577
-
578
- // 更新接口状态
579
- if (item.active !== (active === 'true')) {
580
- updatedCount++;
581
- return {
582
- ...item,
583
- active: active === 'true',
584
- updatedAt: new Date().toISOString()
585
- };
586
- }
587
-
588
- return item;
589
- });
590
-
591
- // 保存更新后的接口列表
592
- fs.writeJsonSync(interfacesFile, updatedInterfaces, { spaces: 2 });
593
-
594
- res.json({
595
- code: 0,
596
- message: `成功${active === 'true' ? '启用' : '禁用'} ${updatedCount} 个接口`,
597
- data: { updatedCount }
598
- });
599
- } catch (err) {
600
- console.error('批量更新接口状态失败:', err);
601
- res.status(500).json({
602
- code: 1,
603
- message: '批量更新接口状态失败: ' + err.message
604
- });
605
- }
606
- });
607
-
608
- // 部分更新接口
609
- router.patch('/interfaces/:id', (req, res) => {
610
- try {
611
- const { id } = req.params;
612
- const updateData = req.body;
613
-
614
- if (!id) {
615
- return res.status(400).json({
616
- code: 1,
617
- message: '接口ID为必填项'
618
- });
619
- }
620
-
621
- // 检查功能是否存在
622
- const featuresFile = path.join(DATA_DIR, 'features.json');
623
- if (!fs.existsSync(featuresFile)) {
624
- return res.status(404).json({
625
- code: 1,
626
- message: '功能不存在'
627
- });
628
- }
629
-
630
- const features = fs.readJsonSync(featuresFile);
631
-
632
- // 在所有功能模块中查找接口
633
- let foundInterface = null;
634
- let foundFeature = null;
635
- let foundInterfaceIndex = -1;
636
- let interfacesFile = '';
637
-
638
- for (const feature of features) {
639
- const featureInterfacesFile = path.join(DATA_DIR, `interfaces-${feature.id}.json`);
640
- if (fs.existsSync(featureInterfacesFile)) {
641
- const interfaces = fs.readJsonSync(featureInterfacesFile);
642
- const index = interfaces.findIndex(item => item.id === id);
643
-
644
- if (index !== -1) {
645
- foundInterface = interfaces[index];
646
- foundFeature = feature;
647
- foundInterfaceIndex = index;
648
- interfacesFile = featureInterfacesFile;
649
- break;
650
- }
651
- }
652
- }
653
-
654
- if (!foundInterface) {
655
- return res.status(404).json({
656
- code: 1,
657
- message: '接口不存在'
658
- });
659
- }
660
-
661
- // 读取接口所在文件的所有接口
662
- const interfaces = fs.readJsonSync(interfacesFile);
663
-
664
- // 更新接口
665
- const updatedInterface = {
666
- ...foundInterface,
667
- ...updateData,
668
- updatedAt: new Date().toISOString()
669
- };
670
-
671
- interfaces[foundInterfaceIndex] = updatedInterface;
672
-
673
- // 保存更新后的接口列表
674
- fs.writeJsonSync(interfacesFile, interfaces, { spaces: 2 });
675
-
676
- res.json({
677
- code: 0,
678
- message: '接口更新成功',
679
- data: updatedInterface
680
- });
681
- } catch (err) {
682
- console.error('更新接口失败:', err);
683
- res.status(500).json({
684
- code: 1,
685
- message: '更新接口失败: ' + err.message
686
- });
687
- }
688
- });
689
-
690
519
  return router;
691
520
  };
692
521
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whistle.mock-plugins",
3
- "version": "1.1.1-dev.14",
3
+ "version": "1.1.1-dev.8",
4
4
  "description": "Whistle 插件,用于快速创建 API 模拟数据",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -4,7 +4,7 @@ import AppLayout from '../components/AppLayout';
4
4
  import {
5
5
  Table, Button, Modal, Form, Input, Select, message, Switch,
6
6
  Popconfirm, Alert, Space, Card, Badge, Tooltip, Row, Col,
7
- Popover, Checkbox, Tag
7
+ Popover, Checkbox
8
8
  } from 'antd';
9
9
  import {
10
10
  PlusOutlined, EditOutlined, DeleteOutlined,
@@ -32,7 +32,6 @@ const { Option } = Select;
32
32
  const COLUMN_CONFIG = [
33
33
  { key: 'active', title: '状态', required: true },
34
34
  { key: 'name', title: '名称', required: true },
35
- { key: 'group', title: '分组', required: false },
36
35
  { key: 'urlPattern', title: 'URL匹配规则', required: false },
37
36
  { key: 'proxyType', title: '处理方式', required: false },
38
37
  { key: 'currentResponse', title: '当前响应', required: false },
@@ -58,11 +57,6 @@ const InterfaceManagement = () => {
58
57
  const [interfacesLoading, setInterfacesLoading] = useState(false);
59
58
  const [selectedFeatureId, setSelectedFeatureId] = useState(null);
60
59
 
61
- // 分组状态
62
- const [groups, setGroups] = useState([]);
63
- const [selectedGroup, setSelectedGroup] = useState(null);
64
- const [groupActionLoading, setGroupActionLoading] = useState(false);
65
-
66
60
  // 模态框状态
67
61
  const [modalVisible, setModalVisible] = useState(false);
68
62
  const [previewVisible, setPreviewVisible] = useState(false);
@@ -172,10 +166,6 @@ const InterfaceManagement = () => {
172
166
 
173
167
  setInterfaces(processedInterfaces);
174
168
  console.log('处理后的接口列表:', processedInterfaces);
175
- console.log('接口分组信息:', processedInterfaces.map(item => ({ id: item.id, name: item.name, group: item.group })));
176
-
177
- // 提取并更新分组列表
178
- updateGroups(processedInterfaces);
179
169
  } else {
180
170
  console.warn('接口数据格式不正确:', response.data);
181
171
  setInterfaces([]);
@@ -189,41 +179,6 @@ const InterfaceManagement = () => {
189
179
  setInterfacesLoading(false);
190
180
  }
191
181
  };
192
-
193
- // 提取并更新分组列表
194
- const updateGroups = (interfaces) => {
195
- // 从接口列表中提取所有分组
196
- const groupSet = new Set();
197
- interfaces.forEach(item => {
198
- if (item.group) {
199
- groupSet.add(item.group);
200
- }
201
- });
202
-
203
- // 转换为数组并排序
204
- const groupArray = Array.from(groupSet).sort();
205
- setGroups(groupArray);
206
-
207
- // 如果当前选中的分组不在列表中,重置选中的分组
208
- if (selectedGroup && !groupArray.includes(selectedGroup)) {
209
- setSelectedGroup(null);
210
- }
211
- };
212
-
213
- // 根据分组筛选接口
214
- const getFilteredInterfaces = () => {
215
- // 首先按功能模块筛选
216
- const featureFiltered = interfaces.filter(item =>
217
- !selectedFeatureId || item.featureId === selectedFeatureId
218
- );
219
-
220
- // 然后按分组筛选
221
- if (selectedGroup) {
222
- return featureFiltered.filter(item => item.group === selectedGroup);
223
- }
224
-
225
- return featureFiltered;
226
- };
227
182
 
228
183
  const handleAddInterface = () => {
229
184
  if (!selectedFeatureId) {
@@ -251,8 +206,7 @@ const InterfaceManagement = () => {
251
206
  activeResponseId: defaultResponseId,
252
207
  httpMethod: 'ALL',
253
208
  headerItems: [], // 初始化为空数组
254
- paramMatchers: [], // 初始化为空数组
255
- group: undefined // 确保分组字段为undefined,而不是空字符串
209
+ paramMatchers: [] // 初始化为空数组
256
210
  });
257
211
 
258
212
  setCurrentResponseId(defaultResponseId);
@@ -299,16 +253,9 @@ const InterfaceManagement = () => {
299
253
  }));
300
254
  }
301
255
 
302
- // 处理分组值,确保它是字符串而不是数组
303
- let groupValue = record.group;
304
- if (Array.isArray(groupValue)) {
305
- groupValue = groupValue.length > 0 ? groupValue[0] : undefined;
306
- }
307
-
308
256
  // 设置表单值
309
257
  form.setFieldsValue({
310
258
  name: record.name,
311
- group: groupValue || undefined, // 使用undefined而不是空字符串
312
259
  pattern: record.urlPattern,
313
260
  proxyType: record.proxyType || 'response',
314
261
  statusCode: (record.httpStatus || record.statusCode || 200).toString(),
@@ -322,8 +269,6 @@ const InterfaceManagement = () => {
322
269
  responseDelay: record.responseDelay ? record.responseDelay.toString() : '0'
323
270
  });
324
271
 
325
- console.log('编辑接口时设置的分组值:', groupValue);
326
-
327
272
  setCurrentResponseId(activeResponseId);
328
273
  setEditingInterface(record);
329
274
  setModalVisible(true);
@@ -349,15 +294,12 @@ const InterfaceManagement = () => {
349
294
 
350
295
  const handleToggleActive = async (id, currentActive) => {
351
296
  try {
352
- const response = await axios.patch(`/cgi-bin/interfaces/${id}`, {
297
+ const response = await axios.patch(`/cgi-bin/interfaces?id=${id}`, {
353
298
  active: !currentActive
354
299
  });
355
300
  if (response.data && response.data.code === 0) {
356
301
  message.success(`接口${!currentActive ? '启用' : '禁用'}成功`);
357
302
  fetchInterfaces();
358
-
359
- // 刷新规则缓存
360
- refreshCacheAfterUpdate();
361
303
  } else {
362
304
  throw new Error(response.data?.message || `接口${!currentActive ? '启用' : '禁用'}失败`);
363
305
  }
@@ -383,16 +325,9 @@ const InterfaceManagement = () => {
383
325
  });
384
326
  }
385
327
 
386
- // 处理分组值,确保它是字符串而不是数组
387
- let groupValue = values.group;
388
- if (Array.isArray(groupValue)) {
389
- groupValue = groupValue.length > 0 ? groupValue[0] : '';
390
- }
391
-
392
328
  // 构建接口数据
393
329
  const interfaceData = {
394
330
  name: values.name,
395
- group: groupValue || '', // 确保group不为undefined
396
331
  urlPattern: values.pattern,
397
332
  proxyType: values.proxyType,
398
333
  featureId: selectedFeatureId,
@@ -405,8 +340,6 @@ const InterfaceManagement = () => {
405
340
  active: true
406
341
  };
407
342
 
408
- console.log('提交的分组值:', groupValue);
409
-
410
343
  // 根据代理类型添加不同字段
411
344
  if (values.proxyType === 'redirect' || values.proxyType === 'url_redirect') {
412
345
  interfaceData.targetUrl = values.targetUrl;
@@ -441,8 +374,6 @@ const InterfaceManagement = () => {
441
374
  const response = await axios.post('/cgi-bin/interfaces', interfaceData);
442
375
  if (response.data && response.data.code === 0) {
443
376
  message.success('接口创建成功');
444
- console.log('接口创建成功,返回数据:', response.data);
445
- console.log('返回的接口数据中的分组信息:', response.data.data?.group);
446
377
  setModalVisible(false);
447
378
  fetchInterfaces();
448
379
 
@@ -529,7 +460,9 @@ const InterfaceManagement = () => {
529
460
  }
530
461
  };
531
462
 
532
- const filteredInterfaces = getFilteredInterfaces();
463
+ const filteredInterfaces = interfaces.filter(item =>
464
+ !selectedFeatureId || item.featureId === selectedFeatureId
465
+ );
533
466
 
534
467
  // 处理表格变化(排序、分页)
535
468
  const handleTableChange = (pagination, filters, sorter) => {
@@ -594,27 +527,6 @@ const InterfaceManagement = () => {
594
527
  sorter: (a, b) => a.name.localeCompare(b.name),
595
528
  render: (text) => <span className="interface-name">{text}</span>,
596
529
  },
597
- {
598
- title: '分组',
599
- dataIndex: 'group',
600
- key: 'group',
601
- width: 120,
602
- sorter: (a, b) => {
603
- const groupA = a.group || '';
604
- const groupB = b.group || '';
605
- return groupA.localeCompare(groupB);
606
- },
607
- render: (group) => {
608
- if (!group) {
609
- return <span style={{ color: '#999', fontStyle: 'italic' }}>未分组</span>;
610
- }
611
- return (
612
- <Tag color="blue" style={{ cursor: 'pointer' }} onClick={() => setSelectedGroup(group)}>
613
- {group}
614
- </Tag>
615
- );
616
- },
617
- },
618
530
  {
619
531
  title: 'URL匹配规则',
620
532
  dataIndex: 'urlPattern',
@@ -863,28 +775,6 @@ const InterfaceManagement = () => {
863
775
  const visibleColumns = tableConfig.visibleColumns || COLUMN_CONFIG.map(col => col.key);
864
776
  const columns = allColumns.filter(col => visibleColumns.includes(col.key));
865
777
 
866
- // 分组筛选和操作区域
867
- const handleBatchToggleActive = async (active) => {
868
- try {
869
- setGroupActionLoading(true);
870
- const response = await axios.patch(`/cgi-bin/interfaces?active=${active}`, {
871
- featureId: selectedFeatureId,
872
- group: selectedGroup
873
- });
874
- if (response.data && response.data.code === 0) {
875
- message.success(`分组 "${selectedGroup}" 中的接口已成功${active ? '启用' : '禁用'}`);
876
- fetchInterfaces();
877
- } else {
878
- throw new Error(response.data?.message || '批量操作失败');
879
- }
880
- } catch (error) {
881
- console.error('批量操作失败:', error);
882
- message.error(error.response?.data?.message || error.message || '批量操作失败');
883
- } finally {
884
- setGroupActionLoading(false);
885
- }
886
- };
887
-
888
778
  return (
889
779
  <AppLayout>
890
780
  <div className="interface-management-container">
@@ -938,77 +828,6 @@ const InterfaceManagement = () => {
938
828
  />
939
829
  )}
940
830
 
941
- {/* 分组筛选和操作区域 */}
942
- <div style={{
943
- display: 'flex',
944
- justifyContent: 'space-between',
945
- alignItems: 'center',
946
- marginBottom: 16,
947
- padding: '12px 16px',
948
- backgroundColor: '#f5f5f5',
949
- borderRadius: '4px'
950
- }}>
951
- <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
952
- <span>分组筛选:</span>
953
- <Select
954
- value={selectedGroup}
955
- onChange={value => setSelectedGroup(value)}
956
- style={{ width: 200 }}
957
- placeholder="选择分组"
958
- allowClear
959
- showSearch
960
- loading={interfacesLoading}
961
- >
962
- {groups.map(group => (
963
- <Option key={group} value={group}>{group}</Option>
964
- ))}
965
- </Select>
966
- {selectedGroup && (
967
- <Button
968
- type="link"
969
- onClick={() => setSelectedGroup(null)}
970
- size="small"
971
- >
972
- 清除筛选
973
- </Button>
974
- )}
975
- </div>
976
-
977
- {selectedGroup && (
978
- <div style={{ display: 'flex', gap: '8px' }}>
979
- <Popconfirm
980
- title={`确定要启用分组 "${selectedGroup}" 中的所有接口吗?`}
981
- onConfirm={() => handleBatchToggleActive(true)}
982
- okText="确定"
983
- cancelText="取消"
984
- >
985
- <Button
986
- type="primary"
987
- size="small"
988
- loading={groupActionLoading}
989
- >
990
- 批量启用
991
- </Button>
992
- </Popconfirm>
993
-
994
- <Popconfirm
995
- title={`确定要禁用分组 "${selectedGroup}" 中的所有接口吗?`}
996
- onConfirm={() => handleBatchToggleActive(false)}
997
- okText="确定"
998
- cancelText="取消"
999
- >
1000
- <Button
1001
- danger
1002
- size="small"
1003
- loading={groupActionLoading}
1004
- >
1005
- 批量禁用
1006
- </Button>
1007
- </Popconfirm>
1008
- </div>
1009
- )}
1010
- </div>
1011
-
1012
831
  {/* 接口列表状态栏 */}
1013
832
  {filteredInterfaces.length > 0 && !interfacesLoading && (
1014
833
  <div style={{
@@ -1024,11 +843,6 @@ const InterfaceManagement = () => {
1024
843
  }}>
1025
844
  <span>
1026
845
  当前功能模块:<strong>{selectedFeature?.name}</strong>
1027
- {selectedGroup && (
1028
- <span style={{ marginLeft: 8 }}>
1029
- | 分组:<Tag color="blue">{selectedGroup}</Tag>
1030
- </span>
1031
- )}
1032
846
  </span>
1033
847
  <span>
1034
848
  共 {filteredInterfaces.length} 个接口,每页显示 {tableConfig.pageSize} 个
@@ -1143,7 +957,6 @@ const InterfaceManagement = () => {
1143
957
  layout="vertical"
1144
958
  initialValues={{
1145
959
  name: '',
1146
- group: '',
1147
960
  pattern: '',
1148
961
  proxyType: 'response',
1149
962
  statusCode: '200',
@@ -1156,7 +969,7 @@ const InterfaceManagement = () => {
1156
969
  responseDelay: '0'
1157
970
  }}
1158
971
  >
1159
- {/* 基础信息表单项 */}
972
+ {/* 基础信息表单项保持原样 */}
1160
973
  <div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
1161
974
  <div style={{ flex: 1 }}>
1162
975
  <Form.Item
@@ -1167,44 +980,6 @@ const InterfaceManagement = () => {
1167
980
  <Input placeholder="请输入接口名称" />
1168
981
  </Form.Item>
1169
982
  </div>
1170
- <div style={{ flex: 1 }}>
1171
- <Form.Item
1172
- name="group"
1173
- label="分组"
1174
- tooltip="为接口设置分组,便于管理和批量操作"
1175
- >
1176
- <Select
1177
- placeholder="选择或创建分组"
1178
- showSearch
1179
- allowClear
1180
- style={{ width: '100%' }}
1181
- mode="tags"
1182
- maxTagCount="responsive"
1183
- maxTagTextLength={10}
1184
- onChange={(value) => {
1185
- // 如果值是数组(tags模式),只取第一个元素
1186
- if (Array.isArray(value) && value.length > 0) {
1187
- // 如果第一个元素是空字符串,则设置为undefined
1188
- const groupValue = value[0] === '' ? undefined : value[0];
1189
- form.setFieldsValue({ group: groupValue });
1190
- }
1191
- }}
1192
- onInputKeyDown={(e) => {
1193
- // 防止回车键提交表单
1194
- if (e.key === 'Enter') {
1195
- e.stopPropagation();
1196
- }
1197
- }}
1198
- >
1199
- {Array.from(new Set(interfaces.map(item => item.group).filter(Boolean))).map(group => (
1200
- <Option key={group} value={group}>{group}</Option>
1201
- ))}
1202
- </Select>
1203
- </Form.Item>
1204
- </div>
1205
- </div>
1206
-
1207
- <div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
1208
983
  <div style={{ flex: 1 }}>
1209
984
  <Form.Item
1210
985
  name="pattern"
@@ -1284,6 +1059,9 @@ const InterfaceManagement = () => {
1284
1059
  />
1285
1060
  </Form.Item>
1286
1061
  </div>
1062
+ </div>
1063
+
1064
+ <div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
1287
1065
  <div style={{ flex: 1 }}>
1288
1066
  <Form.Item
1289
1067
  name="proxyType"
@@ -1311,7 +1089,7 @@ const InterfaceManagement = () => {
1311
1089
  const patternInput = document.querySelector('input[placeholder="根据选择的处理方式输入相应格式的URL"]');
1312
1090
  if (patternInput) {
1313
1091
  if (value === 'response') {
1314
- patternInput.placeholder = "例如:/api/users,/api/users/*,/api\\/users\\/\\d+/";
1092
+ patternInput.placeholder = "例如:/api/users,/api/users/*,/api\/users\/\d+/";
1315
1093
  } else if (value === 'redirect') {
1316
1094
  patternInput.placeholder = "例如:https://example.com/api";
1317
1095
  } else if (value === 'url_redirect') {
@@ -1325,9 +1103,6 @@ const InterfaceManagement = () => {
1325
1103
  </Select>
1326
1104
  </Form.Item>
1327
1105
  </div>
1328
- </div>
1329
-
1330
- <div style={{ display: 'flex', flexDirection: 'row', gap: '16px' }}>
1331
1106
  <div style={{ flex: 1 }}>
1332
1107
  <Form.Item
1333
1108
  name="httpMethod"
@@ -1341,9 +1116,6 @@ const InterfaceManagement = () => {
1341
1116
  </Select>
1342
1117
  </Form.Item>
1343
1118
  </div>
1344
- <div style={{ flex: 1 }}>
1345
- {/* 这里可以留空或添加其他字段 */}
1346
- </div>
1347
1119
  </div>
1348
1120
 
1349
1121
  {/* 根据proxyType显示不同的表单项 */}