whistle.mock-plugins 1.1.2 → 1.1.3-beta.2

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.
@@ -1,342 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Card, Table, Button, Space, Select, Tabs, Form, Input, Modal, Divider, message } from 'antd';
3
- import { PlusOutlined, EditOutlined, DeleteOutlined, SaveOutlined, ExclamationCircleOutlined, CopyOutlined, PlayCircleOutlined } from '@ant-design/icons';
4
- import { FeatureAPI, InterfaceAPI } from '../services/api';
5
-
6
- const { Option } = Select;
7
- const { TabPane } = Tabs;
8
- const { confirm } = Modal;
9
- const { TextArea } = Input;
10
-
11
- const InterfacePage = () => {
12
- const [features, setFeatures] = useState([]);
13
- const [interfaces, setInterfaces] = useState([]);
14
- const [loading, setLoading] = useState(false);
15
- const [selectedFeature, setSelectedFeature] = useState(null);
16
- const [modalVisible, setModalVisible] = useState(false);
17
- const [currentInterface, setCurrentInterface] = useState(null);
18
- const [form] = Form.useForm();
19
-
20
- useEffect(() => {
21
- fetchFeatures();
22
- }, []);
23
-
24
- useEffect(() => {
25
- if (selectedFeature) {
26
- fetchInterfaces(selectedFeature);
27
- }
28
- }, [selectedFeature]);
29
-
30
- const fetchFeatures = async () => {
31
- setLoading(true);
32
- try {
33
- const data = await FeatureAPI.getAllFeatures();
34
- setFeatures(data);
35
- if (data.length > 0 && !selectedFeature) {
36
- setSelectedFeature(data[0].id);
37
- }
38
- } catch (error) {
39
- console.error("获取功能列表失败:", error);
40
- } finally {
41
- setLoading(false);
42
- }
43
- };
44
-
45
- const fetchInterfaces = async (featureId) => {
46
- setLoading(true);
47
- try {
48
- const data = await FeatureAPI.getFeatureInterfaces(featureId);
49
- setInterfaces(data);
50
- } catch (error) {
51
- console.error("获取接口列表失败:", error);
52
- } finally {
53
- setLoading(false);
54
- }
55
- };
56
-
57
- const handleFeatureChange = (value) => {
58
- setSelectedFeature(value);
59
- };
60
-
61
- const handleAdd = () => {
62
- form.resetFields();
63
- form.setFieldsValue({
64
- featureId: selectedFeature,
65
- method: 'GET',
66
- status: 200,
67
- delay: 0,
68
- headers: '{\n "Content-Type": "application/json"\n}',
69
- responseBody: '{\n "code": 0,\n "message": "success",\n "data": {}\n}'
70
- });
71
- setCurrentInterface(null);
72
- setModalVisible(true);
73
- };
74
-
75
- const handleEdit = (record) => {
76
- form.setFieldsValue({
77
- ...record,
78
- headers: typeof record.headers === 'object'
79
- ? JSON.stringify(record.headers, null, 2)
80
- : record.headers || '{}',
81
- responseBody: typeof record.responseBody === 'object'
82
- ? JSON.stringify(record.responseBody, null, 2)
83
- : record.responseBody || '{}'
84
- });
85
- setCurrentInterface(record);
86
- setModalVisible(true);
87
- };
88
-
89
- const handleDelete = (record) => {
90
- confirm({
91
- title: '确认删除',
92
- icon: <ExclamationCircleOutlined />,
93
- content: `确定要删除接口 "${record.path}" 吗?`,
94
- okText: '确认',
95
- cancelText: '取消',
96
- onOk: async () => {
97
- try {
98
- await InterfaceAPI.deleteInterface(record.id);
99
- fetchInterfaces(selectedFeature);
100
- } catch (error) {
101
- console.error("删除接口失败:", error);
102
- }
103
- },
104
- });
105
- };
106
-
107
- const handleCancel = () => {
108
- setModalVisible(false);
109
- };
110
-
111
- const handleOk = async () => {
112
- try {
113
- const values = await form.validateFields();
114
-
115
- try {
116
- // 尝试解析 JSON
117
- if (values.headers) {
118
- values.headers = JSON.parse(values.headers);
119
- }
120
- if (values.responseBody) {
121
- values.responseBody = JSON.parse(values.responseBody);
122
- }
123
- } catch (e) {
124
- message.error('JSON 格式错误,请检查');
125
- return;
126
- }
127
-
128
- if (currentInterface) {
129
- await InterfaceAPI.updateInterface(currentInterface.id, values);
130
- } else {
131
- await InterfaceAPI.createInterface(values);
132
- }
133
-
134
- setModalVisible(false);
135
- fetchInterfaces(selectedFeature);
136
- } catch (error) {
137
- console.error("保存接口失败:", error);
138
- }
139
- };
140
-
141
- const handleTest = async (record) => {
142
- try {
143
- const result = await InterfaceAPI.testInterface(record.id);
144
- Modal.info({
145
- title: '测试结果',
146
- width: 800,
147
- content: (
148
- <div>
149
- <pre style={{ maxHeight: '500px', overflow: 'auto' }}>
150
- {JSON.stringify(result, null, 2)}
151
- </pre>
152
- </div>
153
- ),
154
- okText: '关闭'
155
- });
156
- } catch (error) {
157
- console.error("测试失败:", error);
158
- message.error('测试失败: ' + error.message);
159
- }
160
- };
161
-
162
- const columns = [
163
- {
164
- title: 'URL 路径',
165
- dataIndex: 'path',
166
- key: 'path',
167
- ellipsis: true,
168
- },
169
- {
170
- title: '请求方法',
171
- dataIndex: 'method',
172
- key: 'method',
173
- width: 100,
174
- },
175
- {
176
- title: '状态码',
177
- dataIndex: 'status',
178
- key: 'status',
179
- width: 100,
180
- },
181
- {
182
- title: '延迟(ms)',
183
- dataIndex: 'delay',
184
- key: 'delay',
185
- width: 100,
186
- },
187
- {
188
- title: '描述',
189
- dataIndex: 'description',
190
- key: 'description',
191
- ellipsis: true,
192
- },
193
- {
194
- title: '操作',
195
- key: 'action',
196
- width: 240,
197
- render: (_, record) => (
198
- <Space size="small">
199
- <Button type="text" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
200
- 编辑
201
- </Button>
202
- <Button type="text" icon={<PlayCircleOutlined />} onClick={() => handleTest(record)}>
203
- 测试
204
- </Button>
205
- <Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record)}>
206
- 删除
207
- </Button>
208
- </Space>
209
- ),
210
- },
211
- ];
212
-
213
- return (
214
- <div className="interface-page">
215
- <Card
216
- title="接口管理"
217
- extra={
218
- <Space>
219
- <span>功能:</span>
220
- <Select
221
- style={{ width: 200 }}
222
- value={selectedFeature}
223
- onChange={handleFeatureChange}
224
- loading={loading}
225
- >
226
- {features.map(feature => (
227
- <Option key={feature.id} value={feature.id}>{feature.name}</Option>
228
- ))}
229
- </Select>
230
- <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
231
- 添加接口
232
- </Button>
233
- </Space>
234
- }
235
- >
236
- <Table
237
- columns={columns}
238
- dataSource={interfaces}
239
- rowKey="id"
240
- loading={loading}
241
- />
242
- </Card>
243
-
244
- <Modal
245
- title={currentInterface ? "编辑接口" : "添加接口"}
246
- open={modalVisible}
247
- onOk={handleOk}
248
- onCancel={handleCancel}
249
- width={800}
250
- okText="保存"
251
- cancelText="取消"
252
- >
253
- <Form
254
- form={form}
255
- layout="vertical"
256
- >
257
- <Form.Item
258
- name="featureId"
259
- label="所属功能"
260
- rules={[{ required: true, message: '请选择所属功能!' }]}
261
- >
262
- <Select>
263
- {features.map(feature => (
264
- <Option key={feature.id} value={feature.id}>{feature.name}</Option>
265
- ))}
266
- </Select>
267
- </Form.Item>
268
-
269
- <Form.Item
270
- name="path"
271
- label="URL 路径"
272
- rules={[{ required: true, message: '请输入 URL 路径!' }]}
273
- >
274
- <Input placeholder="/api/your-path" />
275
- </Form.Item>
276
-
277
- <div style={{ display: 'flex', gap: '16px' }}>
278
- <Form.Item
279
- name="method"
280
- label="请求方法"
281
- rules={[{ required: true, message: '请选择请求方法!' }]}
282
- style={{ flex: 1 }}
283
- >
284
- <Select>
285
- <Option value="GET">GET</Option>
286
- <Option value="POST">POST</Option>
287
- <Option value="PUT">PUT</Option>
288
- <Option value="DELETE">DELETE</Option>
289
- <Option value="PATCH">PATCH</Option>
290
- </Select>
291
- </Form.Item>
292
-
293
- <Form.Item
294
- name="status"
295
- label="状态码"
296
- rules={[{ required: true, message: '请输入状态码!' }]}
297
- style={{ flex: 1 }}
298
- >
299
- <Input type="number" placeholder="200" />
300
- </Form.Item>
301
-
302
- <Form.Item
303
- name="delay"
304
- label="延迟(ms)"
305
- rules={[{ required: true, message: '请输入延迟时间!' }]}
306
- style={{ flex: 1 }}
307
- >
308
- <Input type="number" placeholder="0" />
309
- </Form.Item>
310
- </div>
311
-
312
- <Form.Item
313
- name="description"
314
- label="描述"
315
- >
316
- <Input placeholder="接口描述" />
317
- </Form.Item>
318
-
319
- <Tabs defaultActiveKey="1">
320
- <TabPane tab="响应体" key="1">
321
- <Form.Item
322
- name="responseBody"
323
- rules={[{ required: true, message: '请输入响应体!' }]}
324
- >
325
- <TextArea rows={10} placeholder="响应JSON数据" />
326
- </Form.Item>
327
- </TabPane>
328
- <TabPane tab="响应头" key="2">
329
- <Form.Item
330
- name="headers"
331
- >
332
- <TextArea rows={10} placeholder="响应头JSON数据" />
333
- </Form.Item>
334
- </TabPane>
335
- </Tabs>
336
- </Form>
337
- </Modal>
338
- </div>
339
- );
340
- };
341
-
342
- export default InterfacePage;
@@ -1,165 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { Card, Form, Input, Button, Switch, message, Divider, Typography, Space, Select } from 'antd';
3
- import { SaveOutlined, ReloadOutlined } from '@ant-design/icons';
4
-
5
- const { Title, Paragraph, Text } = Typography;
6
- const { Option } = Select;
7
-
8
- // 模拟设置 API
9
- const SettingsAPI = {
10
- getSettings: () => Promise.resolve({
11
- mockFolder: './mocks',
12
- enableAutoSave: true,
13
- responseDelay: 200,
14
- logLevel: 'info',
15
- }),
16
- saveSettings: (settings) => Promise.resolve(settings)
17
- };
18
-
19
- const SettingsPage = () => {
20
- const [form] = Form.useForm();
21
- const [loading, setLoading] = useState(false);
22
-
23
- useEffect(() => {
24
- fetchSettings();
25
- }, []);
26
-
27
- const fetchSettings = async () => {
28
- setLoading(true);
29
- try {
30
- const settings = await SettingsAPI.getSettings();
31
- form.setFieldsValue(settings);
32
- } catch (error) {
33
- console.error("获取设置失败:", error);
34
- message.error('获取设置失败');
35
- } finally {
36
- setLoading(false);
37
- }
38
- };
39
-
40
- const handleSave = async () => {
41
- try {
42
- const values = await form.validateFields();
43
- setLoading(true);
44
- await SettingsAPI.saveSettings(values);
45
- message.success('设置保存成功');
46
- } catch (error) {
47
- console.error("保存设置失败:", error);
48
- message.error('保存设置失败');
49
- } finally {
50
- setLoading(false);
51
- }
52
- };
53
-
54
- const handleReset = () => {
55
- form.resetFields();
56
- fetchSettings();
57
- };
58
-
59
- return (
60
- <div className="settings-page">
61
- <Card title="全局设置">
62
- <Form
63
- form={form}
64
- layout="vertical"
65
- initialValues={{
66
- mockFolder: './mocks',
67
- enableAutoSave: true,
68
- responseDelay: 200,
69
- logLevel: 'info',
70
- }}
71
- >
72
- <Title level={4}>基本设置</Title>
73
- <Form.Item
74
- name="mockFolder"
75
- label="Mock 数据文件夹路径"
76
- rules={[{ required: true, message: '请输入 Mock 数据文件夹路径!' }]}
77
- >
78
- <Input placeholder="./mocks" />
79
- </Form.Item>
80
-
81
- <Form.Item
82
- name="enableAutoSave"
83
- label="启用自动保存"
84
- valuePropName="checked"
85
- >
86
- <Switch />
87
- </Form.Item>
88
-
89
- <Form.Item
90
- name="responseDelay"
91
- label="默认响应延迟(ms)"
92
- rules={[{ required: true, message: '请输入默认响应延迟!' }]}
93
- >
94
- <Input type="number" placeholder="200" />
95
- </Form.Item>
96
-
97
- <Form.Item
98
- name="logLevel"
99
- label="日志级别"
100
- rules={[{ required: true, message: '请选择日志级别!' }]}
101
- >
102
- <Select placeholder="请选择日志级别">
103
- <Option value="debug">Debug</Option>
104
- <Option value="info">Info</Option>
105
- <Option value="warn">Warning</Option>
106
- <Option value="error">Error</Option>
107
- </Select>
108
- </Form.Item>
109
-
110
- <Divider />
111
-
112
- <Title level={4}>使用说明</Title>
113
- <Paragraph>
114
- Whistle Mock 插件用于快速创建 API 模拟数据,支持以下功能:
115
- </Paragraph>
116
-
117
- <Paragraph>
118
- <ul>
119
- <li>
120
- <Text strong>接口管理</Text> - 创建和管理模拟接口,支持 GET、POST 等多种请求方法
121
- </li>
122
- <li>
123
- <Text strong>文件管理</Text> - 编辑 JSON 文件作为模拟数据源
124
- </li>
125
- <li>
126
- <Text strong>Mock 模板语法</Text> - 支持使用 Mock.js 模板语法生成随机数据
127
- </li>
128
- <li>
129
- <Text strong>路径匹配规则</Text> - 支持通配符和正则表达式匹配请求路径
130
- </li>
131
- </ul>
132
- </Paragraph>
133
-
134
- <Paragraph>
135
- 要启用 Whistle Mock 插件,请在 Whistle 界面添加以下规则:
136
- <pre>
137
- example.com mock://
138
- </pre>
139
- </Paragraph>
140
-
141
- <Divider />
142
-
143
- <Space>
144
- <Button
145
- type="primary"
146
- icon={<SaveOutlined />}
147
- onClick={handleSave}
148
- loading={loading}
149
- >
150
- 保存设置
151
- </Button>
152
- <Button
153
- icon={<ReloadOutlined />}
154
- onClick={handleReset}
155
- >
156
- 重置
157
- </Button>
158
- </Space>
159
- </Form>
160
- </Card>
161
- </div>
162
- );
163
- };
164
-
165
- export default SettingsPage;