whistle.mock-plugins 1.2.0-beta.10 → 1.2.0-beta.12

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.
@@ -156,5 +156,3 @@
156
156
  /**![setting](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIGZpbGw9IiNjYWNhY2EiIHZpZXdCb3g9IjY0IDY0IDg5NiA4OTYiIGZvY3VzYWJsZT0iZmFsc2UiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTkyNC44IDYyNS43bC02NS41LTU2YzMuMS0xOSA0LjctMzguNCA0LjctNTcuOHMtMS42LTM4LjgtNC43LTU3LjhsNjUuNS01NmEzMi4wMyAzMi4wMyAwIDAwOS4zLTM1LjJsLS45LTIuNmE0NDMuNzQgNDQzLjc0IDAgMDAtNzkuNy0xMzcuOWwtMS44LTIuMWEzMi4xMiAzMi4xMiAwIDAwLTM1LjEtOS41bC04MS4zIDI4LjljLTMwLTI0LjYtNjMuNS00NC05OS43LTU3LjZsLTE1LjctODVhMzIuMDUgMzIuMDUgMCAwMC0yNS44LTI1LjdsLTIuNy0uNWMtNTIuMS05LjQtMTA2LjktOS40LTE1OSAwbC0yLjcuNWEzMi4wNSAzMi4wNSAwIDAwLTI1LjggMjUuN2wtMTUuOCA4NS40YTM1MS44NiAzNTEuODYgMCAwMC05OSA1Ny40bC04MS45LTI5LjFhMzIgMzIgMCAwMC0zNS4xIDkuNWwtMS44IDIuMWE0NDYuMDIgNDQ2LjAyIDAgMDAtNzkuNyAxMzcuOWwtLjkgMi42Yy00LjUgMTIuNS0uOCAyNi41IDkuMyAzNS4ybDY2LjMgNTYuNmMtMy4xIDE4LjgtNC42IDM4LTQuNiA1Ny4xIDAgMTkuMiAxLjUgMzguNCA0LjYgNTcuMUw5OSA2MjUuNWEzMi4wMyAzMi4wMyAwIDAwLTkuMyAzNS4ybC45IDIuNmMxOC4xIDUwLjQgNDQuOSA5Ni45IDc5LjcgMTM3LjlsMS44IDIuMWEzMi4xMiAzMi4xMiAwIDAwMzUuMSA5LjVsODEuOS0yOS4xYzI5LjggMjQuNSA2My4xIDQzLjkgOTkgNTcuNGwxNS44IDg1LjRhMzIuMDUgMzIuMDUgMCAwMDI1LjggMjUuN2wyLjcuNWE0NDkuNCA0NDkuNCAwIDAwMTU5IDBsMi43LS41YTMyLjA1IDMyLjA1IDAgMDAyNS44LTI1LjdsMTUuNy04NWEzNTAgMzUwIDAgMDA5OS43LTU3LjZsODEuMyAyOC45YTMyIDMyIDAgMDAzNS4xLTkuNWwxLjgtMi4xYzM0LjgtNDEuMSA2MS42LTg3LjUgNzkuNy0xMzcuOWwuOS0yLjZjNC41LTEyLjMuOC0yNi4zLTkuMy0zNXpNNzg4LjMgNDY1LjljMi41IDE1LjEgMy44IDMwLjYgMy44IDQ2LjFzLTEuMyAzMS0zLjggNDYuMWwtNi42IDQwLjEgNzQuNyA2My45YTM3MC4wMyAzNzAuMDMgMCAwMS00Mi42IDczLjZMNzIxIDcwMi44bC0zMS40IDI1LjhjLTIzLjkgMTkuNi01MC41IDM1LTc5LjMgNDUuOGwtMzguMSAxNC4zLTE3LjkgOTdhMzc3LjUgMzc3LjUgMCAwMS04NSAwbC0xNy45LTk3LjItMzcuOC0xNC41Yy0yOC41LTEwLjgtNTUtMjYuMi03OC43LTQ1LjdsLTMxLjQtMjUuOS05My40IDMzLjJjLTE3LTIyLjktMzEuMi00Ny42LTQyLjYtNzMuNmw3NS41LTY0LjUtNi41LTQwYy0yLjQtMTQuOS0zLjctMzAuMy0zLjctNDUuNSAwLTE1LjMgMS4yLTMwLjYgMy43LTQ1LjVsNi41LTQwLTc1LjUtNjQuNWMxMS4zLTI2LjEgMjUuNi01MC43IDQyLjYtNzMuNmw5My40IDMzLjIgMzEuNC0yNS45YzIzLjctMTkuNSA1MC4yLTM0LjkgNzguNy00NS43bDM3LjktMTQuMyAxNy45LTk3LjJjMjguMS0zLjIgNTYuOC0zLjIgODUgMGwxNy45IDk3IDM4LjEgMTQuM2MyOC43IDEwLjggNTUuNCAyNi4yIDc5LjMgNDUuOGwzMS40IDI1LjggOTIuOC0zMi45YzE3IDIyLjkgMzEuMiA0Ny42IDQyLjYgNzMuNkw3ODEuOCA0MjZsNi41IDM5Ljl6TTUxMiAzMjZjLTk3LjIgMC0xNzYgNzguOC0xNzYgMTc2czc4LjggMTc2IDE3NiAxNzYgMTc2LTc4LjggMTc2LTE3Ni03OC44LTE3Ni0xNzYtMTc2em03OS4yIDI1NS4yQTExMS42IDExMS42IDAgMDE1MTIgNjE0Yy0yOS45IDAtNTgtMTEuNy03OS4yLTMyLjhBMTExLjYgMTExLjYgMCAwMTQwMCA1MDJjMC0yOS45IDExLjctNTggMzIuOC03OS4yQzQ1NCA0MDEuNiA0ODIuMSAzOTAgNTEyIDM5MGMyOS45IDAgNTggMTEuNiA3OS4yIDMyLjhBMTExLjYgMTExLjYgMCAwMTYyNCA1MDJjMCAyOS45LTExLjcgNTgtMzIuOCA3OS4yeiIgLz48L3N2Zz4=) */
157
157
 
158
158
  /**![sort-ascending](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIGZpbGw9IiNjYWNhY2EiIHZpZXdCb3g9IjY0IDY0IDg5NiA4OTYiIGZvY3VzYWJsZT0iZmFsc2UiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTgzOS42IDQzMy44TDc0OSAxNTAuNWE5LjI0IDkuMjQgMCAwMC04LjktNi41aC03Ny40Yy00LjEgMC03LjYgMi42LTguOSA2LjVsLTkxLjMgMjgzLjNjLS4zLjktLjUgMS45LS41IDIuOSAwIDUuMSA0LjIgOS4zIDkuMyA5LjNoNTYuNGM0LjIgMCA3LjgtMi44IDktNi44bDE3LjUtNjEuNmg4OWwxNy4zIDYxLjVjMS4xIDQgNC44IDYuOCA5IDYuOGg2MS4yYzEgMCAxLjktLjEgMi44LS40IDIuNC0uOCA0LjMtMi40IDUuNS00LjYgMS4xLTIuMiAxLjMtNC43LjYtNy4xek02NjMuMyAzMjUuNWwzMi44LTExNi45aDYuM2wzMi4xIDExNi45aC03MS4yem0xNDMuNSA0OTIuOUg2NzcuMnYtLjRsMTMyLjYtMTg4LjljMS4xLTEuNiAxLjctMy40IDEuNy01LjR2LTM2LjRjMC01LjEtNC4yLTkuMy05LjMtOS4zaC0yMDRjLTUuMSAwLTkuMyA0LjItOS4zIDkuM3Y0M2MwIDUuMSA0LjIgOS4zIDkuMyA5LjNoMTIyLjZ2LjRMNTg3LjcgODI4LjlhOS4zNSA5LjM1IDAgMDAtMS43IDUuNHYzNi40YzAgNS4xIDQuMiA5LjMgOS4zIDkuM2gyMTEuNGM1LjEgMCA5LjMtNC4yIDkuMy05LjN2LTQzYTkuMiA5LjIgMCAwMC05LjItOS4zek00MTYgNzAyaC03NlYxNzJjMC00LjQtMy42LTgtOC04aC01NmMtNC40IDAtOCAzLjYtOCA4djUzMGgtNzZjLTYuNyAwLTEwLjUgNy44LTYuMyAxM2wxMTIgMTQxLjlhOCA4IDAgMDAxMi42IDBsMTEyLTE0MS45YzQuMS01LjIuNC0xMy02LjMtMTN6IiAvPjwvc3ZnPg==) */
159
-
160
- /**![unordered-list](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIGZpbGw9IiNjYWNhY2EiIHZpZXdCb3g9IjY0IDY0IDg5NiA4OTYiIGZvY3VzYWJsZT0iZmFsc2UiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTkxMiAxOTJIMzI4Yy00LjQgMC04IDMuNi04IDh2NTZjMCA0LjQgMy42IDggOCA4aDU4NGM0LjQgMCA4LTMuNiA4LTh2LTU2YzAtNC40LTMuNi04LTgtOHptMCAyODRIMzI4Yy00LjQgMC04IDMuNi04IDh2NTZjMCA0LjQgMy42IDggOCA4aDU4NGM0LjQgMCA4LTMuNiA4LTh2LTU2YzAtNC40LTMuNi04LTgtOHptMCAyODRIMzI4Yy00LjQgMC04IDMuNi04IDh2NTZjMCA0LjQgMy42IDggOCA4aDU4NGM0LjQgMCA4LTMuNiA4LTh2LTU2YzAtNC40LTMuNi04LTgtOHpNMTA0IDIyOGE1NiA1NiAwIDEwMTEyIDAgNTYgNTYgMCAxMC0xMTIgMHptMCAyODRhNTYgNTYgMCAxMDExMiAwIDU2IDU2IDAgMTAtMTEyIDB6bTAgMjg0YTU2IDU2IDAgMTAxMTIgMCA1NiA1NiAwIDEwLTExMiAweiIgLz48L3N2Zz4=) */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whistle.mock-plugins",
3
- "version": "1.2.0-beta.10",
3
+ "version": "1.2.0-beta.12",
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, Input as AntInput, Radio, Drawer, Divider
7
+ Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer
8
8
  } from 'antd';
9
9
  import {
10
10
  PlusOutlined, EditOutlined, DeleteOutlined,
@@ -64,7 +64,6 @@ const InterfaceManagement = () => {
64
64
  const [groups, setGroups] = useState([]);
65
65
  const [selectedGroup, setSelectedGroup] = useState(null);
66
66
  const [groupActionLoading, setGroupActionLoading] = useState(false);
67
- const [newGroupName, setNewGroupName] = useState('');
68
67
 
69
68
  // 模态框状态
70
69
  const [modalVisible, setModalVisible] = useState(false);
@@ -217,17 +216,6 @@ const InterfaceManagement = () => {
217
216
  setSelectedGroup(null);
218
217
  }
219
218
  };
220
-
221
- // 添加新分组
222
- const addNewGroup = () => {
223
- if (newGroupName.trim() && !groups.includes(newGroupName.trim())) {
224
- const updatedGroups = [...groups, newGroupName.trim()].sort();
225
- setGroups(updatedGroups);
226
- setNewGroupName('');
227
- return newGroupName.trim();
228
- }
229
- return null;
230
- };
231
219
 
232
220
  // 根据分组和搜索关键词筛选接口
233
221
  const getFilteredInterfaces = () => {
@@ -1310,55 +1298,27 @@ const InterfaceManagement = () => {
1310
1298
  tooltip="为接口设置分组,便于管理和批量操作"
1311
1299
  >
1312
1300
  <Select
1313
- placeholder="选择或输入新分组名称"
1301
+ placeholder="选择或创建分组"
1314
1302
  showSearch
1315
1303
  allowClear
1316
1304
  style={{ width: '100%' }}
1317
- dropdownMatchSelectWidth={false}
1318
- filterOption={(input, option) =>
1319
- option?.children?.toLowerCase()?.indexOf(input.toLowerCase()) >= 0
1320
- }
1305
+ mode="tags"
1306
+ maxTagCount="responsive"
1307
+ maxTagTextLength={10}
1308
+ onChange={(value) => {
1309
+ // 如果值是数组(tags模式),只取第一个元素
1310
+ if (Array.isArray(value) && value.length > 0) {
1311
+ // 如果第一个元素是空字符串,则设置为undefined
1312
+ const groupValue = value[0] === '' ? undefined : value[0];
1313
+ form.setFieldsValue({ group: groupValue });
1314
+ }
1315
+ }}
1321
1316
  onInputKeyDown={(e) => {
1322
1317
  // 防止回车键提交表单
1323
1318
  if (e.key === 'Enter') {
1324
1319
  e.stopPropagation();
1325
1320
  }
1326
1321
  }}
1327
- dropdownRender={(menu) => (
1328
- <div>
1329
- {menu}
1330
- <Divider style={{ margin: '4px 0' }} />
1331
- <div style={{ display: 'flex', flexWrap: 'nowrap', padding: 8 }}>
1332
- <Input
1333
- style={{ flex: 'auto' }}
1334
- value={newGroupName}
1335
- onChange={(e) => setNewGroupName(e.target.value)}
1336
- placeholder="输入新分组名称"
1337
- onPressEnter={(e) => {
1338
- e.stopPropagation();
1339
- const groupName = addNewGroup();
1340
- if (groupName) {
1341
- form.setFieldsValue({ group: groupName });
1342
- }
1343
- }}
1344
- />
1345
- <Button
1346
- type="text"
1347
- icon={<PlusOutlined />}
1348
- style={{ flex: 'none', padding: '4px 8px', cursor: 'pointer' }}
1349
- onClick={(e) => {
1350
- e.stopPropagation();
1351
- const groupName = addNewGroup();
1352
- if (groupName) {
1353
- form.setFieldsValue({ group: groupName });
1354
- }
1355
- }}
1356
- >
1357
- 添加
1358
- </Button>
1359
- </div>
1360
- </div>
1361
- )}
1362
1322
  >
1363
1323
  {Array.from(new Set(interfaces.map(item => item.group).filter(Boolean))).map(group => (
1364
1324
  <Option key={group} value={group}>{group}</Option>
@@ -10,7 +10,7 @@ import AppLayout from '../components/AppLayout';
10
10
  import {
11
11
  Table, Button, Modal, Form, Input, Select, message, Switch,
12
12
  Popconfirm, Alert, Space, Card, Badge, Tooltip, Row, Col,
13
- Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer, Dropdown, Menu, Collapse, Divider
13
+ Popover, Checkbox, Tag, Input as AntInput, Radio, Drawer, Dropdown, Menu, Collapse
14
14
  } from 'antd';
15
15
  import {
16
16
  PlusOutlined, EditOutlined, DeleteOutlined,
@@ -70,7 +70,6 @@ const InterfaceManagement = () => {
70
70
  const [groups, setGroups] = useState([]);
71
71
  const [selectedGroup, setSelectedGroup] = useState(null);
72
72
  const [groupActionLoading, setGroupActionLoading] = useState(false);
73
- const [newGroupName, setNewGroupName] = useState('');
74
73
 
75
74
  // 模态框状态
76
75
  const [modalVisible, setModalVisible] = useState(false);
@@ -223,17 +222,6 @@ const InterfaceManagement = () => {
223
222
  setSelectedGroup(null);
224
223
  }
225
224
  };
226
-
227
- // 添加新分组
228
- const addNewGroup = () => {
229
- if (newGroupName.trim() && !groups.includes(newGroupName.trim())) {
230
- const updatedGroups = [...groups, newGroupName.trim()].sort();
231
- setGroups(updatedGroups);
232
- setNewGroupName('');
233
- return newGroupName.trim();
234
- }
235
- return null;
236
- };
237
225
 
238
226
  // 根据分组和搜索关键词筛选接口
239
227
  const getFilteredInterfaces = () => {
@@ -1332,8 +1320,8 @@ const InterfaceManagement = () => {
1332
1320
  <Collapse
1333
1321
  defaultActiveKey={
1334
1322
  editingInterface && editingInterface.proxyType === 'response'
1335
- ? ['3']
1336
- : ['1', '2', '3']
1323
+ ? ['3'] // mock代理场景:只展开第3步(高级配置)
1324
+ : ['1', '2', '3'] // 其他场景:展开所有步骤
1337
1325
  }
1338
1326
  style={{ marginBottom: '16px' }}
1339
1327
  ghost
@@ -1365,55 +1353,27 @@ const InterfaceManagement = () => {
1365
1353
  tooltip="为接口设置分组,便于管理和批量操作"
1366
1354
  >
1367
1355
  <Select
1368
- placeholder="选择或输入新分组名称"
1356
+ placeholder="选择或创建分组"
1369
1357
  showSearch
1370
1358
  allowClear
1371
1359
  style={{ width: '100%' }}
1372
- dropdownMatchSelectWidth={false}
1373
- filterOption={(input, option) =>
1374
- option?.children?.toLowerCase()?.indexOf(input.toLowerCase()) >= 0
1375
- }
1360
+ mode="tags"
1361
+ maxTagCount="responsive"
1362
+ maxTagTextLength={10}
1363
+ onChange={(value) => {
1364
+ // 如果值是数组(tags模式),只取第一个元素
1365
+ if (Array.isArray(value) && value.length > 0) {
1366
+ // 如果第一个元素是空字符串,则设置为undefined
1367
+ const groupValue = value[0] === '' ? undefined : value[0];
1368
+ form.setFieldsValue({ group: groupValue });
1369
+ }
1370
+ }}
1376
1371
  onInputKeyDown={(e) => {
1377
1372
  // 防止回车键提交表单
1378
1373
  if (e.key === 'Enter') {
1379
1374
  e.stopPropagation();
1380
1375
  }
1381
1376
  }}
1382
- dropdownRender={(menu) => (
1383
- <div>
1384
- {menu}
1385
- <Divider style={{ margin: '4px 0' }} />
1386
- <div style={{ display: 'flex', flexWrap: 'nowrap', padding: 8 }}>
1387
- <Input
1388
- style={{ flex: 'auto' }}
1389
- value={newGroupName}
1390
- onChange={(e) => setNewGroupName(e.target.value)}
1391
- placeholder="输入新分组名称"
1392
- onPressEnter={(e) => {
1393
- e.stopPropagation();
1394
- const groupName = addNewGroup();
1395
- if (groupName) {
1396
- form.setFieldsValue({ group: groupName });
1397
- }
1398
- }}
1399
- />
1400
- <Button
1401
- type="text"
1402
- icon={<PlusOutlined />}
1403
- style={{ flex: 'none', padding: '4px 8px', cursor: 'pointer' }}
1404
- onClick={(e) => {
1405
- e.stopPropagation();
1406
- const groupName = addNewGroup();
1407
- if (groupName) {
1408
- form.setFieldsValue({ group: groupName });
1409
- }
1410
- }}
1411
- >
1412
- 添加
1413
- </Button>
1414
- </div>
1415
- </div>
1416
- )}
1417
1377
  >
1418
1378
  {Array.from(new Set(interfaces.map(item => item.group).filter(Boolean))).map(group => (
1419
1379
  <Option key={group} value={group}>{group}</Option>
@@ -6,8 +6,8 @@
6
6
  import React, { useState, useEffect } from 'react';
7
7
  import { useHistory } from 'react-router-dom';
8
8
  import AppLayout from '../components/AppLayout';
9
- import { Card, Row, Col, Button, Modal, Form, Input, message, Switch, Empty, Spin, Typography, Tooltip, Badge, Select, Pagination, Tag, List } from 'antd';
10
- import { PlusOutlined, EditOutlined, DeleteOutlined, ApiOutlined, ExportOutlined, InfoCircleOutlined, CalendarOutlined, SortAscendingOutlined, AppstoreOutlined, UnorderedListOutlined } from '@ant-design/icons';
9
+ import { Card, Row, Col, Button, Modal, Form, Input, message, Switch, Empty, Spin, Typography, Tooltip, Badge, Select, Pagination } from 'antd';
10
+ import { PlusOutlined, EditOutlined, DeleteOutlined, ApiOutlined, ExportOutlined, InfoCircleOutlined, CalendarOutlined, SortAscendingOutlined } from '@ant-design/icons';
11
11
  import '../styles/mock-data.css';
12
12
  import axios from 'axios';
13
13
 
@@ -34,12 +34,6 @@ const MockData = () => {
34
34
  const [loading, setLoading] = useState(true);
35
35
  const [form] = Form.useForm();
36
36
 
37
- // 视图模式配置(卡片/列表)
38
- const [viewMode, setViewMode] = useState(() => {
39
- const savedViewMode = localStorage.getItem('feature-view-mode');
40
- return savedViewMode === 'list' ? 'list' : 'card'; // 默认为卡片视图
41
- });
42
-
43
37
  // 排序和分页配置(支持缓存)
44
38
  const [listConfig, setListConfig] = useState(() => {
45
39
  const cached = localStorage.getItem('feature-list-config');
@@ -57,13 +51,6 @@ const MockData = () => {
57
51
  setListConfig(newConfig);
58
52
  localStorage.setItem('feature-list-config', JSON.stringify(newConfig));
59
53
  };
60
-
61
- // 切换视图模式(卡片/列表)
62
- const toggleViewMode = () => {
63
- const newMode = viewMode === 'card' ? 'list' : 'card';
64
- setViewMode(newMode);
65
- localStorage.setItem('feature-view-mode', newMode);
66
- };
67
54
 
68
55
  // 加载功能列表
69
56
  useEffect(() => {
@@ -426,98 +413,6 @@ const MockData = () => {
426
413
  return sortedFeatures.slice(startIndex, endIndex);
427
414
  };
428
415
 
429
- // 渲染功能模块列表项
430
- const renderFeatureListItem = (feature) => {
431
- const formattedDate = feature.createdAt
432
- ? new Date(feature.createdAt).toLocaleDateString()
433
- : '未知日期';
434
-
435
- return (
436
- <div
437
- key={feature.id}
438
- className={`feature-list-item ${!feature.active ? 'inactive-feature' : ''}`}
439
- onClick={() => viewInterfaces(feature)}
440
- >
441
- <div className="feature-list-content">
442
- <div className="feature-list-main">
443
- <div className="feature-list-name">
444
- <h3>{feature.name}</h3>
445
- {!feature.active && <Tag color="red">已禁用</Tag>}
446
- {feature.active && <Tag color="green">已启用</Tag>}
447
- </div>
448
- <div className="feature-list-description">
449
- {feature.description || '无描述'}
450
- </div>
451
- </div>
452
-
453
- <div className="feature-list-meta">
454
- <div className="feature-list-stats">
455
- <span><InfoCircleOutlined /> {feature.interfaceCount || 0} 个接口</span>
456
- <span><CalendarOutlined /> {formattedDate}</span>
457
- </div>
458
- </div>
459
- </div>
460
-
461
- <div className="feature-list-actions">
462
- <Switch
463
- checked={feature.active}
464
- onChange={(checked, e) => {
465
- e.stopPropagation();
466
- handleToggleActive(feature.id, feature.active);
467
- }}
468
- onClick={(e) => e.stopPropagation()}
469
- size="small"
470
- />
471
- <Tooltip title="管理接口">
472
- <Button
473
- icon={<ApiOutlined />}
474
- size="small"
475
- type="text"
476
- onClick={(e) => {
477
- e.stopPropagation();
478
- viewInterfaces(feature);
479
- }}
480
- />
481
- </Tooltip>
482
- <Tooltip title="编辑功能">
483
- <Button
484
- icon={<EditOutlined />}
485
- size="small"
486
- type="text"
487
- onClick={(e) => {
488
- e.stopPropagation();
489
- openModal(feature);
490
- }}
491
- />
492
- </Tooltip>
493
- <Tooltip title="删除功能">
494
- <Button
495
- icon={<DeleteOutlined />}
496
- size="small"
497
- type="text"
498
- danger
499
- onClick={(e) => {
500
- e.stopPropagation();
501
- deleteFeature(feature.id);
502
- }}
503
- />
504
- </Tooltip>
505
- <Tooltip title="导出配置">
506
- <Button
507
- icon={<ExportOutlined />}
508
- size="small"
509
- type="text"
510
- onClick={(e) => {
511
- e.stopPropagation();
512
- exportFeatureConfig(feature);
513
- }}
514
- />
515
- </Tooltip>
516
- </div>
517
- </div>
518
- );
519
- };
520
-
521
416
  // 渲染功能模块卡片
522
417
  const renderFeatureCard = (feature) => {
523
418
  const formattedDate = feature.createdAt
@@ -722,7 +617,7 @@ const MockData = () => {
722
617
  </Col>
723
618
 
724
619
  {/* 分页控制区域 */}
725
- <Col xs={24} sm={12} md={5} lg={6}>
620
+ <Col xs={24} sm={24} md={8} lg={9}>
726
621
  <div className="pagination-controls">
727
622
  <div className="control-group">
728
623
  <span className="control-label">每页显示</span>
@@ -743,22 +638,6 @@ const MockData = () => {
743
638
  </div>
744
639
  </div>
745
640
  </Col>
746
-
747
- {/* 视图切换按钮区域 */}
748
- <Col xs={24} sm={12} md={3} lg={3}>
749
- <div className="view-toggle-controls">
750
- <Tooltip title={viewMode === 'card' ? '切换到列表视图' : '切换到卡片视图'}>
751
- <Button
752
- type="default"
753
- icon={viewMode === 'card' ? <UnorderedListOutlined /> : <AppstoreOutlined />}
754
- onClick={toggleViewMode}
755
- className="view-toggle-button"
756
- >
757
- {viewMode === 'card' ? '列表视图' : '卡片视图'}
758
- </Button>
759
- </Tooltip>
760
- </div>
761
- </Col>
762
641
  </Row>
763
642
  </Card>
764
643
  )}
@@ -771,16 +650,9 @@ const MockData = () => {
771
650
  </div>
772
651
  ) : mockFeatures.length > 0 ? (
773
652
  <>
774
- {/* 根据视图模式渲染不同的视图 */}
775
- {viewMode === 'card' ? (
776
- <Row gutter={[20, 20]} className="feature-grid">
777
- {getPaginatedFeatures().map(feature => renderFeatureCard(feature))}
778
- </Row>
779
- ) : (
780
- <div className="feature-list-view">
781
- {getPaginatedFeatures().map(feature => renderFeatureListItem(feature))}
782
- </div>
783
- )}
653
+ <Row gutter={[20, 20]} className="feature-grid">
654
+ {getPaginatedFeatures().map(feature => renderFeatureCard(feature))}
655
+ </Row>
784
656
 
785
657
  {/* 分页组件 */}
786
658
  {mockFeatures.length > listConfig.pageSize && (
@@ -121,118 +121,6 @@
121
121
  min-height: 300px;
122
122
  }
123
123
 
124
- /* 视图切换按钮样式 */
125
- .view-toggle-controls {
126
- display: flex;
127
- justify-content: flex-end;
128
- align-items: center;
129
- height: 100%;
130
- }
131
-
132
- .view-toggle-button {
133
- border-radius: 4px;
134
- border: 1px solid #e8e8e8;
135
- background: #fafafa;
136
- transition: all 0.3s;
137
- }
138
-
139
- .view-toggle-button:hover {
140
- border-color: #1890ff;
141
- color: #1890ff;
142
- }
143
-
144
- /* 列表视图样式 */
145
- .feature-list-view {
146
- display: flex;
147
- flex-direction: column;
148
- gap: 16px;
149
- min-height: 300px;
150
- }
151
-
152
- .feature-list-item {
153
- display: flex;
154
- justify-content: space-between;
155
- align-items: center;
156
- padding: 16px 20px;
157
- border-radius: 8px;
158
- border: 1px solid #f0f0f0;
159
- background: #ffffff;
160
- transition: all 0.3s;
161
- cursor: pointer;
162
- position: relative;
163
- }
164
-
165
- .feature-list-item:hover {
166
- border-color: #d9d9d9;
167
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
168
- transform: translateY(-2px);
169
- }
170
-
171
- .feature-list-item.inactive-feature {
172
- opacity: 0.7;
173
- background-color: #fafafa;
174
- }
175
-
176
- .feature-list-content {
177
- flex: 1;
178
- display: flex;
179
- flex-direction: column;
180
- gap: 8px;
181
- overflow: hidden;
182
- }
183
-
184
- .feature-list-main {
185
- display: flex;
186
- flex-direction: column;
187
- gap: 4px;
188
- }
189
-
190
- .feature-list-name {
191
- display: flex;
192
- align-items: center;
193
- gap: 12px;
194
- }
195
-
196
- .feature-list-name h3 {
197
- margin: 0;
198
- font-size: 16px;
199
- font-weight: 600;
200
- color: #1890ff;
201
- }
202
-
203
- .feature-list-description {
204
- color: #666;
205
- font-size: 14px;
206
- max-width: 80%;
207
- overflow: hidden;
208
- white-space: nowrap;
209
- text-overflow: ellipsis;
210
- }
211
-
212
- .feature-list-meta {
213
- display: flex;
214
- justify-content: space-between;
215
- }
216
-
217
- .feature-list-stats {
218
- display: flex;
219
- gap: 16px;
220
- color: #8c8c8c;
221
- font-size: 13px;
222
- }
223
-
224
- .feature-list-stats span {
225
- display: flex;
226
- align-items: center;
227
- gap: 4px;
228
- }
229
-
230
- .feature-list-actions {
231
- display: flex;
232
- align-items: center;
233
- gap: 8px;
234
- }
235
-
236
124
  .feature-card {
237
125
  position: relative;
238
126
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
@@ -1151,33 +1039,6 @@ input:checked + .slider:before {
1151
1039
  height: auto;
1152
1040
  }
1153
1041
 
1154
- .feature-list-item {
1155
- flex-direction: column;
1156
- align-items: flex-start;
1157
- gap: 16px;
1158
- padding: 16px;
1159
- }
1160
-
1161
- .feature-list-content {
1162
- width: 100%;
1163
- }
1164
-
1165
- .feature-list-description {
1166
- max-width: 100%;
1167
- }
1168
-
1169
- .feature-list-actions {
1170
- width: 100%;
1171
- justify-content: flex-end;
1172
- border-top: 1px solid #f0f0f0;
1173
- padding-top: 12px;
1174
- }
1175
-
1176
- .view-toggle-controls {
1177
- justify-content: flex-start;
1178
- margin-top: 12px;
1179
- }
1180
-
1181
1042
  .form-actions {
1182
1043
  flex-direction: column;
1183
1044
  }