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.
- package/API.md +247 -0
- package/README.md +91 -0
- package/app/cgi-bin/features.js +285 -0
- package/app/cgi-bin/index.js +31 -0
- package/app/cgi-bin/interfaces.js +409 -0
- package/app/cgi-bin/logs.js +151 -0
- package/app/cgi-bin/test-interface.js +152 -0
- package/app/public/index.html +1 -0
- package/app/public/js/index.js +2 -0
- package/app/public/js/index.js.LICENSE.txt +150 -0
- package/app/util/index.js +24 -0
- package/index.html +52 -0
- package/initialize.js +32 -0
- package/lib/dataManager.js +500 -0
- package/lib/index.js +3 -0
- package/lib/models.js +64 -0
- package/lib/routes/features.js +213 -0
- package/lib/routes/interfaces.js +304 -0
- package/lib/routes/proxy.js +239 -0
- package/lib/ruleManager.js +551 -0
- package/lib/rules-server.js +267 -0
- package/lib/server.js +805 -0
- package/lib/storage.js +16 -0
- package/lib/ui-server.js +68 -0
- package/package.json +51 -0
- package/public/bundle.js +2 -0
- package/public/bundle.js.LICENSE.txt +38 -0
- package/public/index.html +1 -0
- package/public/plugin.mock-plugin.html +14 -0
- package/rules.txt +22 -0
- package/test/rulesServer.test.js +120 -0
- package/ui/src/App.css +173 -0
- package/ui/src/App.js +24 -0
- package/ui/src/components/AppLayout.js +149 -0
- package/ui/src/components/FeatureCard.js +53 -0
- package/ui/src/components/Layout.js +94 -0
- package/ui/src/components/MainNav.js +42 -0
- package/ui/src/components/PageContainer.js +16 -0
- package/ui/src/index.html +11 -0
- package/ui/src/index.js +43 -0
- package/ui/src/pages/FileProxy.js +235 -0
- package/ui/src/pages/FilesPage.js +292 -0
- package/ui/src/pages/Home.js +128 -0
- package/ui/src/pages/HomePage.js +195 -0
- package/ui/src/pages/InterfaceManagement.js +829 -0
- package/ui/src/pages/InterfacePage.js +342 -0
- package/ui/src/pages/MockData.js +472 -0
- package/ui/src/pages/Settings.js +192 -0
- package/ui/src/pages/SettingsPage.js +165 -0
- package/ui/src/pages/UrlRedirect.js +225 -0
- package/ui/src/pages/Welcome.js +155 -0
- package/ui/src/services/api.js +186 -0
- package/ui/src/styles/app-layout.css +337 -0
- package/ui/src/styles/feature-card.css +172 -0
- package/ui/src/styles/file-proxy.css +301 -0
- package/ui/src/styles/global.css +224 -0
- package/ui/src/styles/home.css +123 -0
- package/ui/src/styles/index.css +419 -0
- package/ui/src/styles/interface-management.css +694 -0
- package/ui/src/styles/layout.css +159 -0
- package/ui/src/styles/logs-page.css +427 -0
- package/ui/src/styles/main-nav.css +52 -0
- package/ui/src/styles/mock-data.css +850 -0
- package/ui/src/styles/page-container.css +11 -0
- package/ui/src/styles/settings.css +208 -0
- package/ui/src/styles/url-redirect.css +279 -0
- package/ui/src/styles/welcome.css +282 -0
- package/webpack.config.js +49 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import Layout from '../components/Layout';
|
|
3
|
+
import FeatureCard from '../components/FeatureCard';
|
|
4
|
+
import '../styles/home.css';
|
|
5
|
+
|
|
6
|
+
const Home = () => {
|
|
7
|
+
const [viewMode, setViewMode] = useState('cards'); // 'cards' or 'list'
|
|
8
|
+
const [sortOption, setSortOption] = useState('name'); // 'name', 'status', 'date'
|
|
9
|
+
|
|
10
|
+
const [features, setFeatures] = useState([
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
name: '用户数据',
|
|
14
|
+
description: '模拟用户信息相关接口',
|
|
15
|
+
active: true,
|
|
16
|
+
interfaceCount: 3,
|
|
17
|
+
createdAt: '2023-09-15'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 2,
|
|
21
|
+
name: '订单信息',
|
|
22
|
+
description: '模拟订单相关接口',
|
|
23
|
+
active: false,
|
|
24
|
+
interfaceCount: 2,
|
|
25
|
+
createdAt: '2023-08-20'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 3,
|
|
29
|
+
name: '商品列表',
|
|
30
|
+
description: '模拟商品数据接口',
|
|
31
|
+
active: true,
|
|
32
|
+
interfaceCount: 5,
|
|
33
|
+
createdAt: '2023-10-01'
|
|
34
|
+
}
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
// 根据排序选项排序功能
|
|
38
|
+
const sortedFeatures = [...features].sort((a, b) => {
|
|
39
|
+
if (sortOption === 'name') {
|
|
40
|
+
return a.name.localeCompare(b.name);
|
|
41
|
+
} else if (sortOption === 'status') {
|
|
42
|
+
return (b.active ? 1 : 0) - (a.active ? 1 : 0);
|
|
43
|
+
} else if (sortOption === 'date') {
|
|
44
|
+
return new Date(b.createdAt) - new Date(a.createdAt);
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Layout>
|
|
51
|
+
<div className="content-header">
|
|
52
|
+
<div className="content-title">功能列表</div>
|
|
53
|
+
<div className="view-controls">
|
|
54
|
+
<span>视图:</span>
|
|
55
|
+
<div className="view-toggle">
|
|
56
|
+
<button
|
|
57
|
+
className={viewMode === 'cards' ? 'active' : ''}
|
|
58
|
+
onClick={() => setViewMode('cards')}
|
|
59
|
+
>
|
|
60
|
+
卡片
|
|
61
|
+
</button>
|
|
62
|
+
<button
|
|
63
|
+
className={viewMode === 'list' ? 'active' : ''}
|
|
64
|
+
onClick={() => setViewMode('list')}
|
|
65
|
+
>
|
|
66
|
+
列表
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="sort-control">
|
|
70
|
+
<span>排序:</span>
|
|
71
|
+
<select
|
|
72
|
+
value={sortOption}
|
|
73
|
+
onChange={(e) => setSortOption(e.target.value)}
|
|
74
|
+
>
|
|
75
|
+
<option value="name">名称</option>
|
|
76
|
+
<option value="status">状态</option>
|
|
77
|
+
<option value="date">创建日期</option>
|
|
78
|
+
</select>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{viewMode === 'cards' ? (
|
|
84
|
+
<div className="feature-cards">
|
|
85
|
+
{sortedFeatures.map(feature => (
|
|
86
|
+
<FeatureCard key={feature.id} feature={feature} />
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<div className="feature-list-view">
|
|
91
|
+
<table>
|
|
92
|
+
<thead>
|
|
93
|
+
<tr>
|
|
94
|
+
<th>名称</th>
|
|
95
|
+
<th>描述</th>
|
|
96
|
+
<th>状态</th>
|
|
97
|
+
<th>接口数量</th>
|
|
98
|
+
<th>创建日期</th>
|
|
99
|
+
<th>操作</th>
|
|
100
|
+
</tr>
|
|
101
|
+
</thead>
|
|
102
|
+
<tbody>
|
|
103
|
+
{sortedFeatures.map(feature => (
|
|
104
|
+
<tr key={feature.id}>
|
|
105
|
+
<td>{feature.name}</td>
|
|
106
|
+
<td>{feature.description}</td>
|
|
107
|
+
<td>
|
|
108
|
+
<span className={`status-badge ${feature.active ? 'active' : 'inactive'}`}>
|
|
109
|
+
{feature.active ? '已启用' : '未启用'}
|
|
110
|
+
</span>
|
|
111
|
+
</td>
|
|
112
|
+
<td>{feature.interfaceCount}</td>
|
|
113
|
+
<td>{feature.createdAt}</td>
|
|
114
|
+
<td>
|
|
115
|
+
<button className="action-btn edit">编辑</button>
|
|
116
|
+
<button className="action-btn">管理接口</button>
|
|
117
|
+
</td>
|
|
118
|
+
</tr>
|
|
119
|
+
))}
|
|
120
|
+
</tbody>
|
|
121
|
+
</table>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
</Layout>
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export default Home;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Card, Table, Button, Space, Typography, Statistic, Row, Col, Modal, Form, Input } from 'antd';
|
|
3
|
+
import { PlusOutlined, EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
|
4
|
+
import { FeatureAPI } from '../services/api';
|
|
5
|
+
|
|
6
|
+
const { Title, Paragraph } = Typography;
|
|
7
|
+
const { confirm } = Modal;
|
|
8
|
+
|
|
9
|
+
const HomePage = () => {
|
|
10
|
+
const [features, setFeatures] = useState([]);
|
|
11
|
+
const [loading, setLoading] = useState(false);
|
|
12
|
+
const [modalVisible, setModalVisible] = useState(false);
|
|
13
|
+
const [form] = Form.useForm();
|
|
14
|
+
const [editFeatureId, setEditFeatureId] = useState(null);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
fetchFeatures();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
const fetchFeatures = async () => {
|
|
21
|
+
setLoading(true);
|
|
22
|
+
try {
|
|
23
|
+
const data = await FeatureAPI.getAllFeatures();
|
|
24
|
+
setFeatures(data);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("获取功能列表失败:", error);
|
|
27
|
+
// 在实际项目中应添加错误提示
|
|
28
|
+
} finally {
|
|
29
|
+
setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handleAdd = () => {
|
|
34
|
+
form.resetFields();
|
|
35
|
+
setEditFeatureId(null);
|
|
36
|
+
setModalVisible(true);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleEdit = (record) => {
|
|
40
|
+
form.setFieldsValue({
|
|
41
|
+
name: record.name,
|
|
42
|
+
description: record.description,
|
|
43
|
+
});
|
|
44
|
+
setEditFeatureId(record.id);
|
|
45
|
+
setModalVisible(true);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleDelete = (record) => {
|
|
49
|
+
confirm({
|
|
50
|
+
title: '确认删除',
|
|
51
|
+
icon: <ExclamationCircleOutlined />,
|
|
52
|
+
content: `确定要删除功能 "${record.name}" 吗?`,
|
|
53
|
+
okText: '确认',
|
|
54
|
+
cancelText: '取消',
|
|
55
|
+
onOk: async () => {
|
|
56
|
+
try {
|
|
57
|
+
await FeatureAPI.deleteFeature(record.id);
|
|
58
|
+
fetchFeatures();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("删除功能失败:", error);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const handleCancel = () => {
|
|
67
|
+
setModalVisible(false);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const handleOk = async () => {
|
|
71
|
+
try {
|
|
72
|
+
const values = await form.validateFields();
|
|
73
|
+
if (editFeatureId) {
|
|
74
|
+
await FeatureAPI.updateFeature(editFeatureId, values);
|
|
75
|
+
} else {
|
|
76
|
+
await FeatureAPI.createFeature(values);
|
|
77
|
+
}
|
|
78
|
+
setModalVisible(false);
|
|
79
|
+
fetchFeatures();
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error("保存功能失败:", error);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const columns = [
|
|
86
|
+
{
|
|
87
|
+
title: '名称',
|
|
88
|
+
dataIndex: 'name',
|
|
89
|
+
key: 'name',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
title: '描述',
|
|
93
|
+
dataIndex: 'description',
|
|
94
|
+
key: 'description',
|
|
95
|
+
ellipsis: true,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
title: '接口数量',
|
|
99
|
+
dataIndex: 'interfaceCount',
|
|
100
|
+
key: 'interfaceCount',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
title: '创建时间',
|
|
104
|
+
dataIndex: 'createdAt',
|
|
105
|
+
key: 'createdAt',
|
|
106
|
+
render: (text) => text ? new Date(text).toLocaleString() : '-',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
title: '操作',
|
|
110
|
+
key: 'action',
|
|
111
|
+
render: (_, record) => (
|
|
112
|
+
<Space size="middle">
|
|
113
|
+
<Button type="text" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
|
|
114
|
+
编辑
|
|
115
|
+
</Button>
|
|
116
|
+
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record)}>
|
|
117
|
+
删除
|
|
118
|
+
</Button>
|
|
119
|
+
</Space>
|
|
120
|
+
),
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div className="home-page">
|
|
126
|
+
<Row gutter={16} style={{ marginBottom: '24px' }}>
|
|
127
|
+
<Col span={8}>
|
|
128
|
+
<Card>
|
|
129
|
+
<Statistic title="功能总数" value={features.length} />
|
|
130
|
+
</Card>
|
|
131
|
+
</Col>
|
|
132
|
+
<Col span={8}>
|
|
133
|
+
<Card>
|
|
134
|
+
<Statistic
|
|
135
|
+
title="接口总数"
|
|
136
|
+
value={features.reduce((sum, feature) => sum + (feature.interfaceCount || 0), 0)}
|
|
137
|
+
/>
|
|
138
|
+
</Card>
|
|
139
|
+
</Col>
|
|
140
|
+
<Col span={8}>
|
|
141
|
+
<Card>
|
|
142
|
+
<Statistic title="今日请求次数" value={0} />
|
|
143
|
+
</Card>
|
|
144
|
+
</Col>
|
|
145
|
+
</Row>
|
|
146
|
+
|
|
147
|
+
<Card
|
|
148
|
+
title="功能列表"
|
|
149
|
+
extra={
|
|
150
|
+
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
|
|
151
|
+
添加功能
|
|
152
|
+
</Button>
|
|
153
|
+
}
|
|
154
|
+
>
|
|
155
|
+
<Table
|
|
156
|
+
columns={columns}
|
|
157
|
+
dataSource={features}
|
|
158
|
+
rowKey="id"
|
|
159
|
+
loading={loading}
|
|
160
|
+
/>
|
|
161
|
+
</Card>
|
|
162
|
+
|
|
163
|
+
<Modal
|
|
164
|
+
title={editFeatureId ? "编辑功能" : "添加功能"}
|
|
165
|
+
open={modalVisible}
|
|
166
|
+
onOk={handleOk}
|
|
167
|
+
onCancel={handleCancel}
|
|
168
|
+
okText="保存"
|
|
169
|
+
cancelText="取消"
|
|
170
|
+
>
|
|
171
|
+
<Form
|
|
172
|
+
form={form}
|
|
173
|
+
layout="vertical"
|
|
174
|
+
initialValues={{ name: '', description: '' }}
|
|
175
|
+
>
|
|
176
|
+
<Form.Item
|
|
177
|
+
name="name"
|
|
178
|
+
label="功能名称"
|
|
179
|
+
rules={[{ required: true, message: '请输入功能名称!' }]}
|
|
180
|
+
>
|
|
181
|
+
<Input placeholder="请输入功能名称" />
|
|
182
|
+
</Form.Item>
|
|
183
|
+
<Form.Item
|
|
184
|
+
name="description"
|
|
185
|
+
label="功能描述"
|
|
186
|
+
>
|
|
187
|
+
<Input.TextArea placeholder="请输入功能描述" rows={4} />
|
|
188
|
+
</Form.Item>
|
|
189
|
+
</Form>
|
|
190
|
+
</Modal>
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export default HomePage;
|