whistle.mock-plugins 1.0.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.
Files changed (68) hide show
  1. package/API.md +247 -0
  2. package/README.md +91 -0
  3. package/app/cgi-bin/features.js +285 -0
  4. package/app/cgi-bin/index.js +31 -0
  5. package/app/cgi-bin/interfaces.js +409 -0
  6. package/app/cgi-bin/logs.js +151 -0
  7. package/app/cgi-bin/test-interface.js +152 -0
  8. package/app/public/index.html +1 -0
  9. package/app/public/js/index.js +2 -0
  10. package/app/public/js/index.js.LICENSE.txt +150 -0
  11. package/app/util/index.js +24 -0
  12. package/index.html +52 -0
  13. package/initialize.js +32 -0
  14. package/lib/dataManager.js +500 -0
  15. package/lib/index.js +3 -0
  16. package/lib/models.js +64 -0
  17. package/lib/routes/features.js +213 -0
  18. package/lib/routes/interfaces.js +304 -0
  19. package/lib/routes/proxy.js +239 -0
  20. package/lib/ruleManager.js +551 -0
  21. package/lib/rules-server.js +267 -0
  22. package/lib/server.js +805 -0
  23. package/lib/storage.js +16 -0
  24. package/lib/ui-server.js +68 -0
  25. package/package.json +51 -0
  26. package/public/bundle.js +2 -0
  27. package/public/bundle.js.LICENSE.txt +38 -0
  28. package/public/index.html +1 -0
  29. package/public/plugin.mock-plugin.html +14 -0
  30. package/rules.txt +22 -0
  31. package/test/rulesServer.test.js +120 -0
  32. package/ui/src/App.css +173 -0
  33. package/ui/src/App.js +24 -0
  34. package/ui/src/components/AppLayout.js +149 -0
  35. package/ui/src/components/FeatureCard.js +53 -0
  36. package/ui/src/components/Layout.js +94 -0
  37. package/ui/src/components/MainNav.js +42 -0
  38. package/ui/src/components/PageContainer.js +16 -0
  39. package/ui/src/index.html +11 -0
  40. package/ui/src/index.js +43 -0
  41. package/ui/src/pages/FileProxy.js +235 -0
  42. package/ui/src/pages/FilesPage.js +292 -0
  43. package/ui/src/pages/Home.js +128 -0
  44. package/ui/src/pages/HomePage.js +195 -0
  45. package/ui/src/pages/InterfaceManagement.js +829 -0
  46. package/ui/src/pages/InterfacePage.js +342 -0
  47. package/ui/src/pages/MockData.js +472 -0
  48. package/ui/src/pages/Settings.js +192 -0
  49. package/ui/src/pages/SettingsPage.js +165 -0
  50. package/ui/src/pages/UrlRedirect.js +225 -0
  51. package/ui/src/pages/Welcome.js +155 -0
  52. package/ui/src/services/api.js +186 -0
  53. package/ui/src/styles/app-layout.css +337 -0
  54. package/ui/src/styles/feature-card.css +172 -0
  55. package/ui/src/styles/file-proxy.css +301 -0
  56. package/ui/src/styles/global.css +224 -0
  57. package/ui/src/styles/home.css +123 -0
  58. package/ui/src/styles/index.css +419 -0
  59. package/ui/src/styles/interface-management.css +694 -0
  60. package/ui/src/styles/layout.css +159 -0
  61. package/ui/src/styles/logs-page.css +427 -0
  62. package/ui/src/styles/main-nav.css +52 -0
  63. package/ui/src/styles/mock-data.css +850 -0
  64. package/ui/src/styles/page-container.css +11 -0
  65. package/ui/src/styles/settings.css +208 -0
  66. package/ui/src/styles/url-redirect.css +279 -0
  67. package/ui/src/styles/welcome.css +282 -0
  68. package/webpack.config.js +49 -0
@@ -0,0 +1,850 @@
1
+ .mock-data-container {
2
+ padding: 24px;
3
+ background: #fff;
4
+ border-radius: 8px;
5
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
6
+ }
7
+
8
+ .header {
9
+ display: flex;
10
+ justify-content: space-between;
11
+ align-items: center;
12
+ margin-bottom: 24px;
13
+ padding-bottom: 16px;
14
+ border-bottom: 1px solid #f0f0f0;
15
+ }
16
+
17
+ .feature-card {
18
+ position: relative;
19
+ transition: all 0.3s;
20
+ height: 100%;
21
+ display: flex;
22
+ flex-direction: column;
23
+ border-radius: 8px;
24
+ overflow: hidden;
25
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
26
+ }
27
+
28
+ .feature-card:hover {
29
+ transform: translateY(-5px);
30
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
31
+ }
32
+
33
+ .feature-card-content {
34
+ padding: 16px;
35
+ height: 140px;
36
+ display: flex;
37
+ flex-direction: column;
38
+ }
39
+
40
+ .feature-name {
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: space-between;
44
+ margin-bottom: 10px;
45
+ }
46
+
47
+ .feature-name h4 {
48
+ margin: 0;
49
+ font-size: 18px;
50
+ color: #1890ff;
51
+ font-weight: 600;
52
+ flex: 1;
53
+ overflow: hidden;
54
+ text-overflow: ellipsis;
55
+ white-space: nowrap;
56
+ }
57
+
58
+ .status-tag {
59
+ font-size: 12px;
60
+ padding: 2px 8px;
61
+ border-radius: 10px;
62
+ display: inline-flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ font-weight: 500;
66
+ }
67
+
68
+ .status-tag.inactive {
69
+ background-color: #fff1f0;
70
+ color: #f5222d;
71
+ border: 1px solid #ffa39e;
72
+ }
73
+
74
+ .status-tag.active {
75
+ background-color: #f6ffed;
76
+ color: #52c41a;
77
+ border: 1px solid #b7eb8f;
78
+ }
79
+
80
+ .feature-description {
81
+ color: #666;
82
+ font-size: 14px;
83
+ margin-bottom: 16px;
84
+ flex: 1;
85
+ overflow: hidden;
86
+ display: -webkit-box;
87
+ -webkit-box-orient: vertical;
88
+ -webkit-line-clamp: 2;
89
+ }
90
+
91
+ .feature-stat {
92
+ margin-top: auto;
93
+ color: #8c8c8c;
94
+ font-size: 13px;
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
+ }
99
+
100
+ .feature-date {
101
+ color: #999;
102
+ font-size: 12px;
103
+ }
104
+
105
+ .inactive-feature {
106
+ opacity: 0.75;
107
+ background-color: #fafafa;
108
+ }
109
+
110
+ .inactive-feature .ant-card-meta-title {
111
+ color: #999;
112
+ }
113
+
114
+ .empty-data {
115
+ text-align: center;
116
+ padding: 48px 0;
117
+ background-color: #f9f9f9;
118
+ border-radius: 8px;
119
+ margin: 24px 0;
120
+ }
121
+
122
+ .loading {
123
+ text-align: center;
124
+ padding: 48px 0;
125
+ }
126
+
127
+ .mock-data-header {
128
+ display: flex;
129
+ justify-content: space-between;
130
+ align-items: center;
131
+ margin-bottom: 20px;
132
+ }
133
+
134
+ .mock-data-header h2 {
135
+ font-size: 18px;
136
+ margin: 0;
137
+ color: #1890ff;
138
+ }
139
+
140
+ .add-mock-btn {
141
+ background-color: #1890ff;
142
+ color: white;
143
+ border: none;
144
+ border-radius: 4px;
145
+ padding: 8px 16px;
146
+ cursor: pointer;
147
+ transition: background-color 0.3s;
148
+ }
149
+
150
+ .add-mock-btn:hover {
151
+ background-color: #40a9ff;
152
+ }
153
+
154
+ .mock-editor {
155
+ background-color: #f9f9f9;
156
+ border-radius: 8px;
157
+ padding: 20px;
158
+ margin-bottom: 20px;
159
+ }
160
+
161
+ .mock-form {
162
+ display: flex;
163
+ flex-direction: column;
164
+ gap: 15px;
165
+ }
166
+
167
+ .form-row {
168
+ display: flex;
169
+ gap: 15px;
170
+ }
171
+
172
+ .method-select {
173
+ width: 120px;
174
+ }
175
+
176
+ .path-input {
177
+ flex: 1;
178
+ }
179
+
180
+ .form-group {
181
+ display: flex;
182
+ flex-direction: column;
183
+ gap: 5px;
184
+ }
185
+
186
+ .form-group label {
187
+ font-weight: 500;
188
+ color: #333;
189
+ }
190
+
191
+ .form-group input,
192
+ .form-group select,
193
+ .form-group textarea {
194
+ padding: 8px 12px;
195
+ border: 1px solid #d9d9d9;
196
+ border-radius: 4px;
197
+ font-size: 14px;
198
+ transition: border-color 0.3s;
199
+ font-family: inherit;
200
+ }
201
+
202
+ .form-group textarea {
203
+ font-family: monospace;
204
+ resize: vertical;
205
+ min-height: 150px;
206
+ }
207
+
208
+ .form-group input:focus,
209
+ .form-group select:focus,
210
+ .form-group textarea:focus {
211
+ border-color: #40a9ff;
212
+ outline: none;
213
+ box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
214
+ }
215
+
216
+ .form-actions {
217
+ display: flex;
218
+ justify-content: flex-end;
219
+ gap: 10px;
220
+ margin-top: 10px;
221
+ }
222
+
223
+ .cancel-btn {
224
+ padding: 8px 16px;
225
+ background-color: #f5f5f5;
226
+ border: 1px solid #d9d9d9;
227
+ border-radius: 4px;
228
+ cursor: pointer;
229
+ transition: all 0.3s;
230
+ }
231
+
232
+ .cancel-btn:hover {
233
+ background-color: #e6e6e6;
234
+ }
235
+
236
+ .save-btn {
237
+ padding: 8px 16px;
238
+ background-color: #1890ff;
239
+ color: white;
240
+ border: none;
241
+ border-radius: 4px;
242
+ cursor: pointer;
243
+ transition: background-color 0.3s;
244
+ }
245
+
246
+ .save-btn:hover {
247
+ background-color: #40a9ff;
248
+ }
249
+
250
+ .mock-table {
251
+ width: 100%;
252
+ border-collapse: collapse;
253
+ }
254
+
255
+ .mock-table th,
256
+ .mock-table td {
257
+ padding: 12px 15px;
258
+ text-align: left;
259
+ border-bottom: 1px solid #eee;
260
+ }
261
+
262
+ .mock-table th {
263
+ font-weight: 500;
264
+ color: #666;
265
+ background-color: #f9f9f9;
266
+ }
267
+
268
+ .mock-table tr.inactive {
269
+ color: #999;
270
+ background-color: #f9f9f9;
271
+ }
272
+
273
+ .mock-table tr:hover {
274
+ background-color: #f5f5f5;
275
+ }
276
+
277
+ .toggle-switch {
278
+ position: relative;
279
+ display: inline-block;
280
+ width: 40px;
281
+ height: 20px;
282
+ }
283
+
284
+ .toggle-switch input {
285
+ opacity: 0;
286
+ width: 0;
287
+ height: 0;
288
+ }
289
+
290
+ .toggle-slider {
291
+ position: absolute;
292
+ cursor: pointer;
293
+ top: 0;
294
+ left: 0;
295
+ right: 0;
296
+ bottom: 0;
297
+ background-color: #ccc;
298
+ transition: .4s;
299
+ border-radius: 34px;
300
+ }
301
+
302
+ .toggle-slider:before {
303
+ position: absolute;
304
+ content: "";
305
+ height: 16px;
306
+ width: 16px;
307
+ left: 2px;
308
+ bottom: 2px;
309
+ background-color: white;
310
+ transition: .4s;
311
+ border-radius: 50%;
312
+ }
313
+
314
+ input:checked + .toggle-slider {
315
+ background-color: #1890ff;
316
+ }
317
+
318
+ input:checked + .toggle-slider:before {
319
+ transform: translateX(20px);
320
+ }
321
+
322
+ .edit-btn,
323
+ .delete-btn {
324
+ padding: 5px 10px;
325
+ border: none;
326
+ border-radius: 4px;
327
+ cursor: pointer;
328
+ font-size: 13px;
329
+ margin-right: 5px;
330
+ }
331
+
332
+ .edit-btn {
333
+ background-color: #f0f7ff;
334
+ color: #1890ff;
335
+ }
336
+
337
+ .delete-btn {
338
+ background-color: #fff0f0;
339
+ color: #ff4d4f;
340
+ }
341
+
342
+ .edit-btn:hover {
343
+ background-color: #e6f7ff;
344
+ }
345
+
346
+ .delete-btn:hover {
347
+ background-color: #ffd4d4;
348
+ }
349
+
350
+ .empty-list {
351
+ text-align: center;
352
+ padding: 30px;
353
+ color: #999;
354
+ font-style: italic;
355
+ background-color: #f9f9f9;
356
+ border-radius: 4px;
357
+ }
358
+
359
+ .page-header {
360
+ display: flex;
361
+ justify-content: space-between;
362
+ align-items: center;
363
+ margin-bottom: 24px;
364
+ padding-bottom: 16px;
365
+ border-bottom: 1px solid #f0f0f0;
366
+ }
367
+
368
+ .page-header h1 {
369
+ font-size: 24px;
370
+ font-weight: 600;
371
+ color: #1890ff;
372
+ margin: 0;
373
+ }
374
+
375
+ .header-actions {
376
+ display: flex;
377
+ gap: 12px;
378
+ }
379
+
380
+ .add-button, .import-button {
381
+ height: 36px;
382
+ padding: 0 16px;
383
+ border-radius: 4px;
384
+ cursor: pointer;
385
+ font-size: 14px;
386
+ display: flex;
387
+ align-items: center;
388
+ justify-content: center;
389
+ border: none;
390
+ font-weight: 500;
391
+ transition: all 0.3s;
392
+ }
393
+
394
+ .add-button {
395
+ background-color: #1890ff;
396
+ color: white;
397
+ }
398
+
399
+ .add-button:hover {
400
+ background-color: #40a9ff;
401
+ box-shadow: 0 4px 12px rgba(24, 144, 255, 0.2);
402
+ }
403
+
404
+ .import-button {
405
+ background-color: #52c41a;
406
+ color: white;
407
+ }
408
+
409
+ .import-button:hover {
410
+ background-color: #73d13d;
411
+ box-shadow: 0 4px 12px rgba(82, 196, 26, 0.2);
412
+ }
413
+
414
+ .feature-list-container {
415
+ background-color: white;
416
+ border-radius: 4px;
417
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
418
+ overflow: hidden;
419
+ }
420
+
421
+ .feature-table {
422
+ width: 100%;
423
+ border-collapse: collapse;
424
+ }
425
+
426
+ .feature-table th,
427
+ .feature-table td {
428
+ padding: 12px 16px;
429
+ text-align: left;
430
+ border-bottom: 1px solid #f0f0f0;
431
+ }
432
+
433
+ .feature-table th {
434
+ background-color: #fafafa;
435
+ color: #8c8c8c;
436
+ font-weight: 500;
437
+ font-size: 14px;
438
+ }
439
+
440
+ .feature-table tr:hover {
441
+ background-color: #fafafa;
442
+ }
443
+
444
+ .feature-table tr.inactive {
445
+ color: #a6a6a6;
446
+ background-color: #f9f9f9;
447
+ }
448
+
449
+ .action-buttons {
450
+ display: flex;
451
+ gap: 8px;
452
+ }
453
+
454
+ .edit-button,
455
+ .delete-button,
456
+ .interface-button,
457
+ .export-button {
458
+ border: none;
459
+ border-radius: 4px;
460
+ padding: 4px 8px;
461
+ cursor: pointer;
462
+ font-size: 12px;
463
+ }
464
+
465
+ .interface-button {
466
+ background-color: #e6f7ff;
467
+ color: #1890ff;
468
+ }
469
+
470
+ .interface-button:hover {
471
+ background-color: #bae7ff;
472
+ }
473
+
474
+ .export-button {
475
+ background-color: #f6ffed;
476
+ color: #52c41a;
477
+ }
478
+
479
+ .export-button:hover {
480
+ background-color: #d9f7be;
481
+ }
482
+
483
+ .edit-button {
484
+ background-color: #f0f5ff;
485
+ color: #597ef7;
486
+ }
487
+
488
+ .edit-button:hover {
489
+ background-color: #d6e4ff;
490
+ }
491
+
492
+ .delete-button {
493
+ background-color: #fff1f0;
494
+ color: #f5222d;
495
+ }
496
+
497
+ .delete-button:hover {
498
+ background-color: #ffccc7;
499
+ }
500
+
501
+ /* 切换开关样式 */
502
+ .switch {
503
+ position: relative;
504
+ display: inline-block;
505
+ width: 36px;
506
+ height: 20px;
507
+ }
508
+
509
+ .switch input {
510
+ opacity: 0;
511
+ width: 0;
512
+ height: 0;
513
+ }
514
+
515
+ .slider {
516
+ position: absolute;
517
+ cursor: pointer;
518
+ top: 0;
519
+ left: 0;
520
+ right: 0;
521
+ bottom: 0;
522
+ background-color: #ccc;
523
+ transition: .4s;
524
+ border-radius: 20px;
525
+ }
526
+
527
+ .slider:before {
528
+ position: absolute;
529
+ content: "";
530
+ height: 16px;
531
+ width: 16px;
532
+ left: 2px;
533
+ bottom: 2px;
534
+ background-color: white;
535
+ transition: .4s;
536
+ border-radius: 50%;
537
+ }
538
+
539
+ input:checked + .slider {
540
+ background-color: #1890ff;
541
+ }
542
+
543
+ input:checked + .slider:before {
544
+ transform: translateX(16px);
545
+ }
546
+
547
+ /* 空数据样式 */
548
+ .empty-data {
549
+ display: flex;
550
+ flex-direction: column;
551
+ align-items: center;
552
+ justify-content: center;
553
+ padding: 60px 0;
554
+ color: #8c8c8c;
555
+ }
556
+
557
+ .empty-icon {
558
+ font-size: 48px;
559
+ margin-bottom: 16px;
560
+ color: #d9d9d9;
561
+ }
562
+
563
+ .empty-text {
564
+ font-size: 16px;
565
+ margin-bottom: 24px;
566
+ color: #8c8c8c;
567
+ }
568
+
569
+ .empty-actions {
570
+ display: flex;
571
+ gap: 16px;
572
+ }
573
+
574
+ .create-button, .import-button-large {
575
+ height: 36px;
576
+ padding: 0 20px;
577
+ border-radius: 4px;
578
+ cursor: pointer;
579
+ font-size: 14px;
580
+ border: none;
581
+ display: flex;
582
+ align-items: center;
583
+ justify-content: center;
584
+ }
585
+
586
+ .create-button {
587
+ background-color: #1890ff;
588
+ color: white;
589
+ }
590
+
591
+ .create-button:hover {
592
+ background-color: #40a9ff;
593
+ }
594
+
595
+ .import-button-large {
596
+ background-color: #52c41a;
597
+ color: white;
598
+ }
599
+
600
+ .import-button-large:hover {
601
+ background-color: #73d13d;
602
+ }
603
+
604
+ /* 模态框样式 */
605
+ .modal-overlay {
606
+ position: fixed;
607
+ top: 0;
608
+ left: 0;
609
+ right: 0;
610
+ bottom: 0;
611
+ background-color: rgba(0, 0, 0, 0.5);
612
+ display: flex;
613
+ align-items: center;
614
+ justify-content: center;
615
+ z-index: 1000;
616
+ animation: fadeIn 0.3s;
617
+ }
618
+
619
+ .modal {
620
+ background-color: white;
621
+ border-radius: 8px;
622
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
623
+ width: 500px;
624
+ max-width: 90%;
625
+ max-height: 90vh;
626
+ overflow-y: auto;
627
+ animation: slideIn 0.3s;
628
+ }
629
+
630
+ @keyframes fadeIn {
631
+ from {
632
+ opacity: 0;
633
+ }
634
+ to {
635
+ opacity: 1;
636
+ }
637
+ }
638
+
639
+ @keyframes slideIn {
640
+ from {
641
+ transform: translateY(-20px);
642
+ opacity: 0;
643
+ }
644
+ to {
645
+ transform: translateY(0);
646
+ opacity: 1;
647
+ }
648
+ }
649
+
650
+ .modal-header {
651
+ display: flex;
652
+ justify-content: space-between;
653
+ align-items: center;
654
+ padding: 16px 24px;
655
+ border-bottom: 1px solid #f0f0f0;
656
+ }
657
+
658
+ .modal-header h2 {
659
+ margin: 0;
660
+ font-size: 18px;
661
+ font-weight: 600;
662
+ color: #1890ff;
663
+ }
664
+
665
+ .close-button {
666
+ background: none;
667
+ border: none;
668
+ font-size: 20px;
669
+ color: #999;
670
+ cursor: pointer;
671
+ width: 32px;
672
+ height: 32px;
673
+ display: flex;
674
+ align-items: center;
675
+ justify-content: center;
676
+ border-radius: 50%;
677
+ transition: all 0.3s;
678
+ }
679
+
680
+ .close-button:hover {
681
+ background-color: #f5f5f5;
682
+ color: #555;
683
+ }
684
+
685
+ .feature-form {
686
+ padding: 24px;
687
+ }
688
+
689
+ .form-group {
690
+ margin-bottom: 20px;
691
+ }
692
+
693
+ .form-group label {
694
+ display: block;
695
+ margin-bottom: 8px;
696
+ font-weight: 500;
697
+ color: #333;
698
+ }
699
+
700
+ .checkbox-label {
701
+ display: flex;
702
+ align-items: center;
703
+ gap: 8px;
704
+ font-weight: 500;
705
+ color: #333;
706
+ cursor: pointer;
707
+ }
708
+
709
+ .form-group input[type="text"] {
710
+ width: 100%;
711
+ height: 40px;
712
+ padding: 0 12px;
713
+ border: 1px solid #d9d9d9;
714
+ border-radius: 4px;
715
+ font-size: 14px;
716
+ transition: all 0.3s;
717
+ }
718
+
719
+ .form-group input[type="text"]:focus {
720
+ border-color: #40a9ff;
721
+ box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
722
+ outline: none;
723
+ }
724
+
725
+ .form-group input[type="checkbox"] {
726
+ width: 16px;
727
+ height: 16px;
728
+ margin: 0;
729
+ }
730
+
731
+ .form-actions {
732
+ display: flex;
733
+ justify-content: flex-end;
734
+ gap: 12px;
735
+ margin-top: 24px;
736
+ }
737
+
738
+ .cancel-button {
739
+ height: 40px;
740
+ padding: 0 16px;
741
+ background-color: white;
742
+ border: 1px solid #d9d9d9;
743
+ border-radius: 4px;
744
+ cursor: pointer;
745
+ font-size: 14px;
746
+ transition: all 0.3s;
747
+ }
748
+
749
+ .cancel-button:hover {
750
+ background-color: #f5f5f5;
751
+ }
752
+
753
+ .submit-button {
754
+ height: 40px;
755
+ padding: 0 24px;
756
+ background-color: #1890ff;
757
+ color: white;
758
+ border: none;
759
+ border-radius: 4px;
760
+ cursor: pointer;
761
+ font-size: 14px;
762
+ transition: all 0.3s;
763
+ }
764
+
765
+ .submit-button:hover {
766
+ background-color: #40a9ff;
767
+ }
768
+
769
+ /* 加载中样式 */
770
+ .loading {
771
+ display: flex;
772
+ flex-direction: column;
773
+ align-items: center;
774
+ justify-content: center;
775
+ height: 300px;
776
+ color: #8c8c8c;
777
+ font-size: 16px;
778
+ }
779
+
780
+ .loading-spinner {
781
+ border: 4px solid #f3f3f3;
782
+ border-top: 4px solid #1890ff;
783
+ border-radius: 50%;
784
+ width: 40px;
785
+ height: 40px;
786
+ animation: spin 2s linear infinite;
787
+ margin-bottom: 16px;
788
+ }
789
+
790
+ @keyframes spin {
791
+ 0% { transform: rotate(0deg); }
792
+ 100% { transform: rotate(360deg); }
793
+ }
794
+
795
+ /* 响应式调整 */
796
+ @media (max-width: 768px) {
797
+ .mock-data-container {
798
+ padding: 16px;
799
+ }
800
+
801
+ .page-header {
802
+ flex-direction: column;
803
+ align-items: flex-start;
804
+ }
805
+
806
+ .header-actions {
807
+ margin-top: 16px;
808
+ width: 100%;
809
+ }
810
+
811
+ .add-button, .import-button {
812
+ flex: 1;
813
+ }
814
+
815
+ .feature-card-content {
816
+ height: auto;
817
+ }
818
+
819
+ .form-actions {
820
+ flex-direction: column;
821
+ }
822
+
823
+ .cancel-button, .submit-button {
824
+ width: 100%;
825
+ }
826
+ }
827
+
828
+ /* 修复功能模块状态标记(ribbon)与按钮的重叠问题 */
829
+ .ant-ribbon.ant-ribbon-placement-end {
830
+ top: 5px; /* 向下调整 ribbon 位置 */
831
+ right: 0px;
832
+ z-index: 5;
833
+ }
834
+
835
+ /* 确保功能卡片右上角有足够空间容纳 ribbon */
836
+ .ant-card-extra {
837
+ margin-right: 70px; /* 为 ribbon 提供足够空间 */
838
+ }
839
+
840
+ /* 当屏幕宽度较小时调整 ribbon 位置 */
841
+ @media (max-width: 576px) {
842
+ .ant-ribbon.ant-ribbon-placement-end {
843
+ top: 3px;
844
+ z-index: 5;
845
+ }
846
+
847
+ .ant-card-extra {
848
+ margin-right: 60px;
849
+ }
850
+ }