whistle.mock-plugins 1.3.1 → 1.4.0-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.
- package/VERSION.md +29 -0
- package/app/cgi-bin/interfaces.js +2 -0
- package/app/cgi-bin/settings.js +1 -0
- package/app/cgi-bin/stats.js +22 -12
- package/app/cgi-bin/webdav.js +56 -0
- package/app/public/index.html +1 -1
- package/app/public/js/11.index.js +2 -0
- package/app/public/js/11.index.js.LICENSE.txt +5 -0
- package/app/public/js/704.index.js +2 -0
- package/app/public/js/704.index.js.LICENSE.txt +1 -0
- package/app/public/js/798.index.js +2 -0
- package/app/public/js/798.index.js.LICENSE.txt +53 -0
- package/app/public/js/807.index.js +2 -0
- package/app/public/js/807.index.js.LICENSE.txt +1 -0
- package/app/public/js/968.index.js +2 -0
- package/app/public/js/968.index.js.LICENSE.txt +12 -0
- package/app/public/js/index.js +1 -1
- package/app/public/js/index.js.LICENSE.txt +0 -173
- package/lib/routes/settings.js +1 -0
- package/lib/webdav-sync.js +806 -0
- package/package.json +9 -2
- package/API.md +0 -247
- package/COLUMN_RESIZE_IMPLEMENTATION.md +0 -162
- package/FEATURE_ENHANCEMENT.md +0 -157
- package/TEST_GUIDE.md +0 -156
- package/data/features.json +0 -1
- package/data/interfaces.json +0 -1
- package/index.html +0 -52
- package/initialize.js +0 -32
- package/public/bundle.js +0 -2
- package/public/bundle.js.LICENSE.txt +0 -38
- package/public/index.html +0 -1
- package/public/plugin.mock-plugin.html +0 -14
- package/rules.txt +0 -22
- package/ui/src/App.css +0 -173
- package/ui/src/components/AppLayout.js +0 -407
- package/ui/src/components/FeatureCard.js +0 -58
- package/ui/src/components/KeyboardShortcutsHelp.js +0 -58
- package/ui/src/components/Layout.js +0 -94
- package/ui/src/components/MainNav.js +0 -42
- package/ui/src/components/PageContainer.js +0 -16
- package/ui/src/components/VersionModal.js +0 -99
- package/ui/src/components/interface-management/DataManagementDrawer.js +0 -115
- package/ui/src/components/interface-management/DataManagementModal.js +0 -110
- package/ui/src/components/interface-management/InterfaceTestModal.js +0 -313
- package/ui/src/components/interface-management/PreviewModal.js +0 -48
- package/ui/src/components/interface-management/README.md +0 -184
- package/ui/src/components/interface-management/RealResponseRecorder.js +0 -165
- package/ui/src/components/interface-management/ResponseContentEditor.js +0 -645
- package/ui/src/components/interface-management/constants.js +0 -36
- package/ui/src/components/interface-management/index.js +0 -7
- package/ui/src/components/interface-management/utils.js +0 -103
- package/ui/src/hooks/useKeyboardShortcuts.js +0 -99
- package/ui/src/index.html +0 -14
- package/ui/src/index.js +0 -50
- package/ui/src/pages/InterfaceManagementV2.js +0 -2351
- package/ui/src/pages/MockDataV2.js +0 -1089
- package/ui/src/pages/Settings.js +0 -299
- package/ui/src/pages/Sniffer.js +0 -521
- package/ui/src/pages/Stats.js +0 -288
- package/ui/src/services/del_api.js +0 -192
- package/ui/src/styles/app-layout.css +0 -373
- package/ui/src/styles/cyber-theme.css +0 -1234
- package/ui/src/styles/earth-theme.css +0 -618
- package/ui/src/styles/global.css +0 -224
- package/ui/src/styles/interface-management.css +0 -1321
- package/ui/src/styles/mock-data.css +0 -1185
- package/ui/src/styles/settings.css +0 -252
- package/ui/src/styles/version-modal.css +0 -116
- package/webpack.config.js +0 -54
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Button, Input, message, Space, Tabs, Tag } from 'antd';
|
|
3
|
-
import { DownloadOutlined, ThunderboltOutlined, CopyOutlined } from '@ant-design/icons';
|
|
4
|
-
import axios from 'axios';
|
|
5
|
-
|
|
6
|
-
const { TextArea } = Input;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* JSON 转 Mock.js 模板
|
|
10
|
-
* 简单转换:字符串 -> '@string', 数字 -> '@integer(1,100)', 布尔 -> '@boolean'
|
|
11
|
-
* 保留对象结构
|
|
12
|
-
*/
|
|
13
|
-
const jsonToMockTemplate = (obj, depth = 0) => {
|
|
14
|
-
if (obj === null) return null;
|
|
15
|
-
if (typeof obj === 'string') {
|
|
16
|
-
// 保留特定格式字符串的提示
|
|
17
|
-
if (/^\d{4}-\d{2}-\d{2}/.test(obj)) return '@date';
|
|
18
|
-
if (/^\d{4}-\d{2}-\d{2}T/.test(obj)) return '@datetime';
|
|
19
|
-
if (/^https?:\/\//.test(obj)) return '@url';
|
|
20
|
-
if (/^\w+@\w+\.\w+/.test(obj)) return '@email';
|
|
21
|
-
if (/^1[3-9]\d{9}$/.test(obj)) return '@string("number", 11)';
|
|
22
|
-
return '@csentence(3, 10)';
|
|
23
|
-
}
|
|
24
|
-
if (typeof obj === 'number') {
|
|
25
|
-
if (Number.isInteger(obj)) return '@integer(1, 999)';
|
|
26
|
-
return '@float(1, 100, 2, 2)';
|
|
27
|
-
}
|
|
28
|
-
if (typeof obj === 'boolean') return '@boolean';
|
|
29
|
-
if (Array.isArray(obj)) {
|
|
30
|
-
if (obj.length === 0) return [];
|
|
31
|
-
const template = jsonToMockTemplate(obj[0], depth + 1);
|
|
32
|
-
// 用 |1-5 表示数组长度随机
|
|
33
|
-
return [template];
|
|
34
|
-
}
|
|
35
|
-
if (typeof obj === 'object') {
|
|
36
|
-
const result = {};
|
|
37
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
38
|
-
result[key] = jsonToMockTemplate(value, depth + 1);
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
return obj;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const RealResponseRecorder = ({ urlPattern, onApply }) => {
|
|
46
|
-
const [fetchUrl, setFetchUrl] = useState('');
|
|
47
|
-
const [loading, setLoading] = useState(false);
|
|
48
|
-
const [response, setResponse] = useState(null);
|
|
49
|
-
const [activeTab, setActiveTab] = useState('preview');
|
|
50
|
-
|
|
51
|
-
const handleFetch = async () => {
|
|
52
|
-
const targetUrl = fetchUrl.trim() || urlPattern;
|
|
53
|
-
if (!targetUrl) {
|
|
54
|
-
message.warning('请输入目标 URL');
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
setLoading(true);
|
|
58
|
-
try {
|
|
59
|
-
const res = await axios.post('/cgi-bin/proxy-fetch', {
|
|
60
|
-
url: targetUrl,
|
|
61
|
-
method: 'GET',
|
|
62
|
-
});
|
|
63
|
-
if (res.data.code === 0) {
|
|
64
|
-
setResponse(res.data.data);
|
|
65
|
-
setActiveTab('preview');
|
|
66
|
-
message.success('抓取成功');
|
|
67
|
-
} else {
|
|
68
|
-
throw new Error(res.data.message);
|
|
69
|
-
}
|
|
70
|
-
} catch (err) {
|
|
71
|
-
message.error('抓取失败: ' + (err.response?.data?.message || err.message));
|
|
72
|
-
} finally {
|
|
73
|
-
setLoading(false);
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const handleGenerateMock = () => {
|
|
78
|
-
if (!response?.body) return;
|
|
79
|
-
try {
|
|
80
|
-
const json = JSON.parse(response.body);
|
|
81
|
-
const template = jsonToMockTemplate(json);
|
|
82
|
-
const mockTemplate = JSON.stringify(template, null, 2);
|
|
83
|
-
onApply?.(mockTemplate);
|
|
84
|
-
message.success('Mock 模板已生成');
|
|
85
|
-
} catch (e) {
|
|
86
|
-
message.error('响应不是 JSON,无法生成模板: ' + e.message);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const handleCopy = () => {
|
|
91
|
-
if (response?.body) {
|
|
92
|
-
navigator.clipboard.writeText(response.body);
|
|
93
|
-
message.success('已复制');
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
<div style={{ padding: '16px 0' }}>
|
|
99
|
-
<Space direction="vertical" style={{ width: '100%' }}>
|
|
100
|
-
<Space style={{ width: '100%' }}>
|
|
101
|
-
<Input
|
|
102
|
-
placeholder={urlPattern || '输入真实接口 URL'}
|
|
103
|
-
value={fetchUrl}
|
|
104
|
-
onChange={(e) => setFetchUrl(e.target.value)}
|
|
105
|
-
style={{ width: 400 }}
|
|
106
|
-
onPressEnter={handleFetch}
|
|
107
|
-
/>
|
|
108
|
-
<Button
|
|
109
|
-
type="primary"
|
|
110
|
-
icon={<ThunderboltOutlined />}
|
|
111
|
-
loading={loading}
|
|
112
|
-
onClick={handleFetch}
|
|
113
|
-
>
|
|
114
|
-
抓取真实响应
|
|
115
|
-
</Button>
|
|
116
|
-
</Space>
|
|
117
|
-
|
|
118
|
-
{response && (
|
|
119
|
-
<>
|
|
120
|
-
<Space>
|
|
121
|
-
<Tag color={response.status >= 200 && response.status < 300 ? 'success' : 'error'}>
|
|
122
|
-
{response.status} {response.statusText}
|
|
123
|
-
</Tag>
|
|
124
|
-
<Button size="small" icon={<CopyOutlined />} onClick={handleCopy}>
|
|
125
|
-
复制原文
|
|
126
|
-
</Button>
|
|
127
|
-
<Button size="small" icon={<DownloadOutlined />} onClick={handleGenerateMock} type="primary">
|
|
128
|
-
生成 Mock 模板
|
|
129
|
-
</Button>
|
|
130
|
-
</Space>
|
|
131
|
-
|
|
132
|
-
<Tabs activeKey={activeTab} onChange={setActiveTab}>
|
|
133
|
-
<Tabs.TabPane tab="响应预览" key="preview">
|
|
134
|
-
<TextArea
|
|
135
|
-
value={response.body}
|
|
136
|
-
readOnly
|
|
137
|
-
rows={12}
|
|
138
|
-
style={{ fontFamily: 'monospace', fontSize: 12 }}
|
|
139
|
-
/>
|
|
140
|
-
</Tabs.TabPane>
|
|
141
|
-
<Tabs.TabPane tab="生成的 Mock 模板" key="mock">
|
|
142
|
-
<TextArea
|
|
143
|
-
value={(() => {
|
|
144
|
-
try {
|
|
145
|
-
const json = JSON.parse(response.body);
|
|
146
|
-
const template = jsonToMockTemplate(json);
|
|
147
|
-
return JSON.stringify(template, null, 2);
|
|
148
|
-
} catch (e) {
|
|
149
|
-
return '// 响应不是 JSON,无法生成模板\n' + response.body;
|
|
150
|
-
}
|
|
151
|
-
})()}
|
|
152
|
-
readOnly
|
|
153
|
-
rows={12}
|
|
154
|
-
style={{ fontFamily: 'monospace', fontSize: 12 }}
|
|
155
|
-
/>
|
|
156
|
-
</Tabs.TabPane>
|
|
157
|
-
</Tabs>
|
|
158
|
-
</>
|
|
159
|
-
)}
|
|
160
|
-
</Space>
|
|
161
|
-
</div>
|
|
162
|
-
);
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export default RealResponseRecorder;
|