whistle.mock-plugins 1.2.2-beta.2 → 1.2.2-beta.22
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.
- package/VERSION.md +50 -1
- package/app/cgi-bin/settings.js +37 -0
- package/app/public/js/index.js +1 -1
- package/lib/models.js +9 -0
- package/lib/routes/interfaces.js +6 -3
- package/lib/routes/settings.js +51 -0
- package/lib/ruleManager.js +105 -41
- package/lib/server.js +4 -0
- package/package.json +1 -1
- package/ui/src/components/interface-management/DataManagementDrawer.js +115 -0
- package/ui/src/components/interface-management/ResponseContentEditor.js +146 -36
- package/ui/src/components/interface-management/index.js +1 -0
- package/ui/src/pages/InterfaceManagementV2.js +448 -145
- package/ui/src/pages/MockDataV2.js +1 -1
- package/ui/src/pages/Settings.js +143 -6
- package/ui/src/styles/interface-management.css +3 -12
- package/ui/src/styles/settings.css +29 -0
package/ui/src/pages/Settings.js
CHANGED
|
@@ -1,11 +1,73 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import AppLayout from '../components/AppLayout';
|
|
3
|
-
import { Card, Typography,
|
|
3
|
+
import { Card, Typography, Switch, Space, Divider } from 'antd';
|
|
4
|
+
import axios from 'axios';
|
|
4
5
|
import '../styles/settings.css';
|
|
5
6
|
|
|
6
7
|
const { Title, Text, Paragraph } = Typography;
|
|
7
8
|
|
|
9
|
+
const syncSettingsToBackend = (patch) => {
|
|
10
|
+
axios.put('/cgi-bin/settings', patch).catch(() => {});
|
|
11
|
+
};
|
|
12
|
+
|
|
8
13
|
const Settings = () => {
|
|
14
|
+
const [displayMode, setDisplayMode] = useState('modal');
|
|
15
|
+
const [interfaceFormDisplayMode, setInterfaceFormDisplayMode] = useState('modal');
|
|
16
|
+
const [interfaceParamMatcherEnabled, setInterfaceParamMatcherEnabled] = useState(true);
|
|
17
|
+
const [responseParamMatcherEnabled, setResponseParamMatcherEnabled] = useState(true);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const savedMode = localStorage.getItem('dataManagementDisplayMode');
|
|
21
|
+
if (savedMode) setDisplayMode(savedMode);
|
|
22
|
+
|
|
23
|
+
const savedInterfaceFormMode = localStorage.getItem('interfaceFormDisplayMode');
|
|
24
|
+
if (savedInterfaceFormMode) setInterfaceFormDisplayMode(savedInterfaceFormMode);
|
|
25
|
+
|
|
26
|
+
// 优先从后端读取入参匹配开关,保持前后端一致
|
|
27
|
+
axios.get('/cgi-bin/settings').then(({ data }) => {
|
|
28
|
+
const ipm = data.interfaceParamMatcherEnabled !== false;
|
|
29
|
+
const rpm = data.responseParamMatcherEnabled !== false;
|
|
30
|
+
setInterfaceParamMatcherEnabled(ipm);
|
|
31
|
+
setResponseParamMatcherEnabled(rpm);
|
|
32
|
+
localStorage.setItem('interfaceParamMatcherEnabled', String(ipm));
|
|
33
|
+
localStorage.setItem('responseParamMatcherEnabled', String(rpm));
|
|
34
|
+
window.dispatchEvent(new Event('storage'));
|
|
35
|
+
}).catch(() => {
|
|
36
|
+
const savedInterfaceParamMatcher = localStorage.getItem('interfaceParamMatcherEnabled');
|
|
37
|
+
if (savedInterfaceParamMatcher !== null) setInterfaceParamMatcherEnabled(savedInterfaceParamMatcher !== 'false');
|
|
38
|
+
const savedResponseParamMatcher = localStorage.getItem('responseParamMatcherEnabled');
|
|
39
|
+
if (savedResponseParamMatcher !== null) setResponseParamMatcherEnabled(savedResponseParamMatcher !== 'false');
|
|
40
|
+
});
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
const handleDisplayModeChange = (checked) => {
|
|
44
|
+
const newMode = checked ? 'drawer' : 'modal';
|
|
45
|
+
setDisplayMode(newMode);
|
|
46
|
+
localStorage.setItem('dataManagementDisplayMode', newMode);
|
|
47
|
+
window.dispatchEvent(new Event('storage'));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleInterfaceFormDisplayModeChange = (checked) => {
|
|
51
|
+
const newMode = checked ? 'drawer' : 'modal';
|
|
52
|
+
setInterfaceFormDisplayMode(newMode);
|
|
53
|
+
localStorage.setItem('interfaceFormDisplayMode', newMode);
|
|
54
|
+
window.dispatchEvent(new Event('storage'));
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleInterfaceParamMatcherChange = (checked) => {
|
|
58
|
+
setInterfaceParamMatcherEnabled(checked);
|
|
59
|
+
localStorage.setItem('interfaceParamMatcherEnabled', String(checked));
|
|
60
|
+
syncSettingsToBackend({ interfaceParamMatcherEnabled: checked });
|
|
61
|
+
window.dispatchEvent(new Event('storage'));
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const handleResponseParamMatcherChange = (checked) => {
|
|
65
|
+
setResponseParamMatcherEnabled(checked);
|
|
66
|
+
localStorage.setItem('responseParamMatcherEnabled', String(checked));
|
|
67
|
+
syncSettingsToBackend({ responseParamMatcherEnabled: checked });
|
|
68
|
+
window.dispatchEvent(new Event('storage'));
|
|
69
|
+
};
|
|
70
|
+
|
|
9
71
|
return (
|
|
10
72
|
<AppLayout>
|
|
11
73
|
<div className="page-container">
|
|
@@ -19,10 +81,85 @@ const Settings = () => {
|
|
|
19
81
|
</div>
|
|
20
82
|
|
|
21
83
|
<Card title="界面设置" className="settings-card">
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
84
|
+
<div className="settings-item">
|
|
85
|
+
<div className="settings-item-header">
|
|
86
|
+
<div>
|
|
87
|
+
<div className="settings-item-title">数据管理交互</div>
|
|
88
|
+
<div className="settings-item-description">
|
|
89
|
+
选择数据管理的显示方式
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<Space>
|
|
93
|
+
<Text type="secondary">
|
|
94
|
+
{displayMode === 'drawer' ? '抽屉模式' : '弹窗模式'}
|
|
95
|
+
</Text>
|
|
96
|
+
<Switch
|
|
97
|
+
checked={displayMode === 'drawer'}
|
|
98
|
+
onChange={handleDisplayModeChange}
|
|
99
|
+
/>
|
|
100
|
+
</Space>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div className="settings-item">
|
|
105
|
+
<div className="settings-item-header">
|
|
106
|
+
<div>
|
|
107
|
+
<div className="settings-item-title">接口表单交互</div>
|
|
108
|
+
<div className="settings-item-description">
|
|
109
|
+
选择添加/编辑接口的显示方式
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
<Space>
|
|
113
|
+
<Text type="secondary">
|
|
114
|
+
{interfaceFormDisplayMode === 'drawer' ? '抽屉模式' : '弹窗模式'}
|
|
115
|
+
</Text>
|
|
116
|
+
<Switch
|
|
117
|
+
checked={interfaceFormDisplayMode === 'drawer'}
|
|
118
|
+
onChange={handleInterfaceFormDisplayModeChange}
|
|
119
|
+
/>
|
|
120
|
+
</Space>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div className="settings-item">
|
|
125
|
+
<div className="settings-item-header">
|
|
126
|
+
<div>
|
|
127
|
+
<div className="settings-item-title">接口入参匹配</div>
|
|
128
|
+
<div className="settings-item-description">
|
|
129
|
+
是否在接口编辑表单中显示「接口匹配条件」配置区域
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<Space>
|
|
133
|
+
<Text type="secondary">
|
|
134
|
+
{interfaceParamMatcherEnabled ? '已开启' : '已关闭'}
|
|
135
|
+
</Text>
|
|
136
|
+
<Switch
|
|
137
|
+
checked={interfaceParamMatcherEnabled}
|
|
138
|
+
onChange={handleInterfaceParamMatcherChange}
|
|
139
|
+
/>
|
|
140
|
+
</Space>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div className="settings-item">
|
|
145
|
+
<div className="settings-item-header">
|
|
146
|
+
<div>
|
|
147
|
+
<div className="settings-item-title">响应入参匹配</div>
|
|
148
|
+
<div className="settings-item-description">
|
|
149
|
+
是否在响应内容编辑器中显示「入参匹配规则」配置区域
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<Space>
|
|
153
|
+
<Text type="secondary">
|
|
154
|
+
{responseParamMatcherEnabled ? '已开启' : '已关闭'}
|
|
155
|
+
</Text>
|
|
156
|
+
<Switch
|
|
157
|
+
checked={responseParamMatcherEnabled}
|
|
158
|
+
onChange={handleResponseParamMatcherChange}
|
|
159
|
+
/>
|
|
160
|
+
</Space>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
26
163
|
</Card>
|
|
27
164
|
</div>
|
|
28
165
|
</AppLayout>
|
|
@@ -294,20 +294,11 @@
|
|
|
294
294
|
.interface-table td {
|
|
295
295
|
padding: 12px 16px !important;
|
|
296
296
|
white-space: nowrap;
|
|
297
|
-
overflow:
|
|
298
|
-
text-overflow: ellipsis;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/* 确保表格容器不裁剪下拉菜单 */
|
|
302
|
-
.interface-list-container {
|
|
303
|
-
overflow: visible !important;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
.interface-list-container .ant-table-container {
|
|
307
|
-
overflow: visible !important;
|
|
297
|
+
overflow: hidden;
|
|
308
298
|
}
|
|
309
299
|
|
|
310
|
-
|
|
300
|
+
/* 当前响应列需要 overflow: visible 以显示完整的下拉菜单 */
|
|
301
|
+
.interface-table td.current-response-cell {
|
|
311
302
|
overflow: visible !important;
|
|
312
303
|
}
|
|
313
304
|
|
|
@@ -33,6 +33,35 @@
|
|
|
33
33
|
font-weight: 500;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/* 设置项样式 */
|
|
37
|
+
.settings-item {
|
|
38
|
+
padding: 16px 0;
|
|
39
|
+
border-bottom: 1px solid #f0f0f0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.settings-item:last-child {
|
|
43
|
+
border-bottom: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.settings-item-header {
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
align-items: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.settings-item-title {
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
font-weight: 500;
|
|
55
|
+
color: #262626;
|
|
56
|
+
margin-bottom: 4px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.settings-item-description {
|
|
60
|
+
font-size: 12px;
|
|
61
|
+
color: #8c8c8c;
|
|
62
|
+
line-height: 1.5;
|
|
63
|
+
}
|
|
64
|
+
|
|
36
65
|
.settings-section {
|
|
37
66
|
margin-bottom: 32px;
|
|
38
67
|
}
|