whistle.mock-plugins 1.2.0-beta.4 → 1.2.0-beta.6

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,3 +156,5 @@
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.4",
3
+ "version": "1.2.0-beta.6",
4
4
  "description": "Whistle 插件,用于快速创建 API 模拟数据",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -94,7 +94,6 @@ const AppLayout = ({ children }) => {
94
94
  <div className="header-left">
95
95
  <div className="logo-container">
96
96
  <div className="logo-icon-group">
97
- <ApiOutlined className="logo-icon logo-icon-primary" />
98
97
  <ExperimentOutlined className="logo-icon logo-icon-secondary" />
99
98
  </div>
100
99
  <div className="logo-text">MockMaster</div>
@@ -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 } from 'antd';
10
- import { PlusOutlined, EditOutlined, DeleteOutlined, ApiOutlined, ExportOutlined, InfoCircleOutlined, CalendarOutlined, SortAscendingOutlined } from '@ant-design/icons';
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';
11
11
  import '../styles/mock-data.css';
12
12
  import axios from 'axios';
13
13
 
@@ -34,6 +34,12 @@ 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
+
37
43
  // 排序和分页配置(支持缓存)
38
44
  const [listConfig, setListConfig] = useState(() => {
39
45
  const cached = localStorage.getItem('feature-list-config');
@@ -51,6 +57,13 @@ const MockData = () => {
51
57
  setListConfig(newConfig);
52
58
  localStorage.setItem('feature-list-config', JSON.stringify(newConfig));
53
59
  };
60
+
61
+ // 切换视图模式(卡片/列表)
62
+ const toggleViewMode = () => {
63
+ const newMode = viewMode === 'card' ? 'list' : 'card';
64
+ setViewMode(newMode);
65
+ localStorage.setItem('feature-view-mode', newMode);
66
+ };
54
67
 
55
68
  // 加载功能列表
56
69
  useEffect(() => {
@@ -413,6 +426,98 @@ const MockData = () => {
413
426
  return sortedFeatures.slice(startIndex, endIndex);
414
427
  };
415
428
 
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
+
416
521
  // 渲染功能模块卡片
417
522
  const renderFeatureCard = (feature) => {
418
523
  const formattedDate = feature.createdAt
@@ -617,7 +722,7 @@ const MockData = () => {
617
722
  </Col>
618
723
 
619
724
  {/* 分页控制区域 */}
620
- <Col xs={24} sm={24} md={8} lg={9}>
725
+ <Col xs={24} sm={12} md={5} lg={6}>
621
726
  <div className="pagination-controls">
622
727
  <div className="control-group">
623
728
  <span className="control-label">每页显示</span>
@@ -638,6 +743,22 @@ const MockData = () => {
638
743
  </div>
639
744
  </div>
640
745
  </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>
641
762
  </Row>
642
763
  </Card>
643
764
  )}
@@ -650,9 +771,16 @@ const MockData = () => {
650
771
  </div>
651
772
  ) : mockFeatures.length > 0 ? (
652
773
  <>
653
- <Row gutter={[20, 20]} className="feature-grid">
654
- {getPaginatedFeatures().map(feature => renderFeatureCard(feature))}
655
- </Row>
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
+ )}
656
784
 
657
785
  {/* 分页组件 */}
658
786
  {mockFeatures.length > listConfig.pageSize && (
@@ -240,11 +240,11 @@ body {
240
240
  position: relative;
241
241
  z-index: 2;
242
242
  font-size: 22px;
243
+ display: none;
243
244
  }
244
245
 
245
246
  .logo-icon-secondary {
246
247
  position: absolute;
247
- top: 0;
248
248
  right: -6px;
249
249
  font-size: 16px;
250
250
  color: #52c41a;
@@ -121,6 +121,118 @@
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
+
124
236
  .feature-card {
125
237
  position: relative;
126
238
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
@@ -1039,6 +1151,33 @@ input:checked + .slider:before {
1039
1151
  height: auto;
1040
1152
  }
1041
1153
 
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
+
1042
1181
  .form-actions {
1043
1182
  flex-direction: column;
1044
1183
  }