json-api-mocker 2.3.0 → 3.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/DESIGN.md +227 -0
- package/README.ch.md +95 -224
- package/README.md +98 -227
- package/dist/cli.js +37 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -2
- package/dist/server.d.ts +17 -14
- package/dist/server.js +290 -100
- package/dist/types.d.ts +26 -21
- package/package.json +21 -11
- package/web/assets/index-C4eZNDku.js +25 -0
- package/web/assets/index-CGhPNH5w.css +1 -0
- package/web/index.html +15 -0
- package/web/monaco-editor-worker-loader.js +8 -0
- package/web/vite.svg +1 -0
package/DESIGN.md
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
# JSON API Mocker 设计思路文档
|
2
|
+
|
3
|
+
## 1. 项目架构设计
|
4
|
+
|
5
|
+
### 1.1 核心模块划分
|
6
|
+
```
|
7
|
+
src/
|
8
|
+
├── types.ts # 类型定义
|
9
|
+
├── server.ts # 服务器核心逻辑
|
10
|
+
├── index.ts # 入口文件
|
11
|
+
└── cli.ts # 命令行工具
|
12
|
+
```
|
13
|
+
|
14
|
+
### 1.2 设计原则
|
15
|
+
- **配置驱动**: 通过 JSON 配置文件定义 API,而不是代码
|
16
|
+
- **约定优于配置**: 提供合理的默认值,减少配置复杂度
|
17
|
+
- **单一职责**: 每个模块只负责一个功能
|
18
|
+
- **开闭原则**: 扩展开放,修改关闭
|
19
|
+
|
20
|
+
## 2. 关键技术决策
|
21
|
+
|
22
|
+
### 2.1 为什么选择 JSON 配置文件
|
23
|
+
- **优点**:
|
24
|
+
- 零代码门槛
|
25
|
+
- 配置直观易读
|
26
|
+
- 方便版本控制
|
27
|
+
- 易于修改和共享
|
28
|
+
- **缺点**:
|
29
|
+
- 灵活性相对较低
|
30
|
+
- 不支持复杂逻辑
|
31
|
+
|
32
|
+
### 2.2 为什么选择文件系统而不是数据库
|
33
|
+
- **优点**:
|
34
|
+
- 无需额外依赖
|
35
|
+
- 配置即数据,直观明了
|
36
|
+
- 方便迁移和备份
|
37
|
+
- **缺点**:
|
38
|
+
- 并发性能较差
|
39
|
+
- 不适合大规模数据
|
40
|
+
|
41
|
+
### 2.3 为什么使用 TypeScript
|
42
|
+
- 类型安全
|
43
|
+
- 更好的开发体验
|
44
|
+
- 自动生成类型声明文件
|
45
|
+
- 便于维护和重构
|
46
|
+
|
47
|
+
## 3. 核心功能实现
|
48
|
+
|
49
|
+
### 3.1 路由系统设计
|
50
|
+
```typescript
|
51
|
+
interface RouteConfig {
|
52
|
+
path: string;
|
53
|
+
methods: {
|
54
|
+
[key: string]: MethodConfig;
|
55
|
+
};
|
56
|
+
}
|
57
|
+
|
58
|
+
// 支持 RESTful API 的标准方法
|
59
|
+
type HttpMethod = 'get' | 'post' | 'put' | 'delete';
|
60
|
+
```
|
61
|
+
|
62
|
+
### 3.2 数据持久化方案
|
63
|
+
```typescript
|
64
|
+
class MockServer {
|
65
|
+
private saveConfig() {
|
66
|
+
// 同步写入确保数据一致性
|
67
|
+
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
|
68
|
+
}
|
69
|
+
}
|
70
|
+
```
|
71
|
+
|
72
|
+
### 3.3 分页实现
|
73
|
+
```typescript
|
74
|
+
interface PaginationConfig {
|
75
|
+
enabled: boolean;
|
76
|
+
pageSize: number;
|
77
|
+
totalCount: number;
|
78
|
+
}
|
79
|
+
|
80
|
+
// 分页处理逻辑
|
81
|
+
const handlePagination = (data: any[], page: number, pageSize: number) => {
|
82
|
+
const start = (page - 1) * pageSize;
|
83
|
+
return data.slice(start, start + pageSize);
|
84
|
+
};
|
85
|
+
```
|
86
|
+
|
87
|
+
## 4. 问题解决方案
|
88
|
+
|
89
|
+
### 4.1 并发写入问题
|
90
|
+
- **问题**: 多个请求同时修改配置文件可能导致数据不一致
|
91
|
+
- **解决方案**:
|
92
|
+
1. 使用同步写入
|
93
|
+
2. 考虑添加文件锁
|
94
|
+
3. 实现写入队列
|
95
|
+
|
96
|
+
### 4.2 动态路由参数
|
97
|
+
- **问题**: 如何支持 `/users/:id` 这样的动态路径
|
98
|
+
- **解决方案**:
|
99
|
+
```typescript
|
100
|
+
// 使用 Express 的路由参数功能
|
101
|
+
app.get(`${baseProxy}${path}/:id`, (req, res) => {
|
102
|
+
const id = req.params.id;
|
103
|
+
// 处理逻辑
|
104
|
+
});
|
105
|
+
```
|
106
|
+
|
107
|
+
### 4.3 类型安全
|
108
|
+
- **问题**: 如何确保运行时类型安全
|
109
|
+
- **解决方案**:
|
110
|
+
```typescript
|
111
|
+
// 请求体验证
|
112
|
+
interface RequestSchema {
|
113
|
+
[key: string]: 'string' | 'number' | 'boolean';
|
114
|
+
}
|
115
|
+
|
116
|
+
const validateRequest = (body: any, schema: RequestSchema) => {
|
117
|
+
// 实现验证逻辑
|
118
|
+
};
|
119
|
+
```
|
120
|
+
|
121
|
+
## 5. 性能优化
|
122
|
+
|
123
|
+
### 5.1 当前实现
|
124
|
+
- 同步文件操作
|
125
|
+
- 内存中保存配置副本
|
126
|
+
- 简单的错误处理
|
127
|
+
|
128
|
+
### 5.2 可能的优化方向
|
129
|
+
1. **缓存优化**
|
130
|
+
```typescript
|
131
|
+
class Cache {
|
132
|
+
private static instance: Cache;
|
133
|
+
private store: Map<string, any>;
|
134
|
+
|
135
|
+
public get(key: string) {
|
136
|
+
return this.store.get(key);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
```
|
140
|
+
|
141
|
+
2. **并发处理**
|
142
|
+
```typescript
|
143
|
+
class WriteQueue {
|
144
|
+
private queue: Array<() => Promise<void>>;
|
145
|
+
|
146
|
+
public async add(task: () => Promise<void>) {
|
147
|
+
this.queue.push(task);
|
148
|
+
await this.process();
|
149
|
+
}
|
150
|
+
}
|
151
|
+
```
|
152
|
+
|
153
|
+
## 6. 扩展性设计
|
154
|
+
|
155
|
+
### 6.1 中间件支持
|
156
|
+
```typescript
|
157
|
+
interface ServerConfig {
|
158
|
+
middleware?: {
|
159
|
+
before?: Function[];
|
160
|
+
after?: Function[];
|
161
|
+
};
|
162
|
+
}
|
163
|
+
```
|
164
|
+
|
165
|
+
### 6.2 自定义响应处理
|
166
|
+
```typescript
|
167
|
+
interface MethodConfig {
|
168
|
+
transform?: (data: any) => any;
|
169
|
+
headers?: Record<string, string>;
|
170
|
+
}
|
171
|
+
```
|
172
|
+
|
173
|
+
## 7. 未来规划
|
174
|
+
|
175
|
+
### 7.1 短期目标
|
176
|
+
- ✅ 添加请求日志 (Completed in v1.2.0)
|
177
|
+
- ✅ 支持文件上传 (Completed in v1.2.5)
|
178
|
+
- ✅ 添加测试用例 (Completed in v1.2.6)
|
179
|
+
|
180
|
+
### 7.2 长期目标
|
181
|
+
- ✅ 提供 Web 界面 (Completed in v2.0.0)
|
182
|
+
- 支持 WebSocket
|
183
|
+
- 支持数据库存储
|
184
|
+
- 支持集群部署
|
185
|
+
|
186
|
+
## 8. 最佳实践
|
187
|
+
|
188
|
+
### 8.1 配置文件组织
|
189
|
+
```json
|
190
|
+
{
|
191
|
+
"server": {
|
192
|
+
"port": 8080,
|
193
|
+
"baseProxy": "/api"
|
194
|
+
},
|
195
|
+
"routes": [
|
196
|
+
{
|
197
|
+
"path": "/users",
|
198
|
+
"methods": {
|
199
|
+
"get": { ... },
|
200
|
+
"post": { ... }
|
201
|
+
}
|
202
|
+
}
|
203
|
+
]
|
204
|
+
}
|
205
|
+
```
|
206
|
+
|
207
|
+
### 8.2 错误处理
|
208
|
+
```typescript
|
209
|
+
class ApiError extends Error {
|
210
|
+
constructor(
|
211
|
+
public status: number,
|
212
|
+
message: string
|
213
|
+
) {
|
214
|
+
super(message);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
const errorHandler = (err: Error, req: Request, res: Response) => {
|
219
|
+
if (err instanceof ApiError) {
|
220
|
+
res.status(err.status).json({ error: err.message });
|
221
|
+
}
|
222
|
+
};
|
223
|
+
```
|
224
|
+
|
225
|
+
## 9. 总结
|
226
|
+
|
227
|
+
本项目的核心是通过配置驱动的方式简化 Mock 服务器的搭建过程。虽然在性能和功能上有一些限制,但对于前端开发中的 Mock 需求来说是一个很好的解决方案。通过合理的模块划分和接口设计,我们既保证了代码的可维护性,也为未来的功能扩展留下了空间。
|
package/README.ch.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# JSON API Mocker
|
2
2
|
|
3
|
-
一个轻量级且灵活的 Mock
|
3
|
+
一个轻量级且灵活的 Mock 服务器,支持 JSON 配置和可视化界面管理。
|
4
4
|
|
5
5
|
<p align="center">
|
6
6
|
<img src="https://img.shields.io/npm/v/json-api-mocker" alt="npm 版本" />
|
@@ -10,33 +10,57 @@
|
|
10
10
|
|
11
11
|
## ✨ 特性
|
12
12
|
|
13
|
-
- 🚀
|
14
|
-
-
|
13
|
+
- 🚀 全新的可视化管理界面
|
14
|
+
- 🚀 支持配置文件和 UI 两种使用方式
|
15
|
+
- 🔄 支持所有常用 HTTP 方法
|
15
16
|
- 📝 自动数据持久化
|
16
17
|
- 🔍 内置分页支持
|
17
18
|
- 🛠 可自定义响应结构
|
18
19
|
- 🎭 集成 Mock.js 实现强大的数据模拟
|
19
|
-
-
|
20
|
+
- 📊 实时请求日志和统计
|
20
21
|
- 💡 TypeScript 支持
|
21
22
|
|
22
23
|
## 📦 安装
|
23
24
|
|
24
25
|
```bash
|
25
|
-
|
26
|
-
|
26
|
+
npm install -g json-api-mocker
|
27
|
+
```
|
28
|
+
|
29
|
+
## 🚀 快速开始
|
30
|
+
|
31
|
+
服务器使用固定端口:
|
32
|
+
- API 服务器:35728
|
33
|
+
- Web 界面:35729
|
34
|
+
- WebSocket:35730
|
35
|
+
|
36
|
+
### 方式一:使用可视化界面(推荐)
|
27
37
|
|
28
|
-
|
29
|
-
|
38
|
+
1. 创建 `data.json` 文件:
|
39
|
+
```json
|
40
|
+
{
|
41
|
+
"server": {
|
42
|
+
"port": 35728,
|
43
|
+
"baseProxy": "/api"
|
44
|
+
},
|
45
|
+
"routes": []
|
46
|
+
}
|
47
|
+
```
|
30
48
|
|
31
|
-
|
32
|
-
|
49
|
+
2. 启动服务器:
|
50
|
+
```bash
|
51
|
+
# 启动服务器并打开浏览器
|
52
|
+
json-api-mocker -o
|
33
53
|
```
|
34
54
|
|
35
|
-
|
55
|
+
启动后,浏览器会自动打开管理界面,你可以:
|
56
|
+
1. 可视化创建和管理 API
|
57
|
+
2. 实时查看请求日志
|
58
|
+
3. 监控 API 调用统计
|
59
|
+
4. 在线调试 Mock 数据
|
36
60
|
|
37
|
-
###
|
61
|
+
### 方式二:使用配置文件(兼容旧版本)
|
38
62
|
|
39
|
-
|
63
|
+
创建 `data.json` 文件:
|
40
64
|
|
41
65
|
```json
|
42
66
|
{
|
@@ -46,40 +70,21 @@ pnpm add json-api-mocker
|
|
46
70
|
},
|
47
71
|
"routes": [
|
48
72
|
{
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"
|
52
|
-
|
53
|
-
"
|
54
|
-
"
|
55
|
-
"
|
56
|
-
|
57
|
-
|
58
|
-
"response": [
|
59
|
-
{
|
60
|
-
"id": 1,
|
61
|
-
"name": "张三",
|
62
|
-
"age": 30,
|
63
|
-
"city": "北京"
|
64
|
-
}
|
65
|
-
]
|
66
|
-
}
|
67
|
-
}
|
68
|
-
},
|
69
|
-
{
|
70
|
-
"path": "/upload/avatar",
|
71
|
-
"methods": {
|
72
|
-
"post": {
|
73
|
-
"type": "object",
|
74
|
-
"mock": {
|
75
|
-
"enabled": true,
|
76
|
-
"template": {
|
77
|
-
"success": true,
|
78
|
-
"message": "上传成功",
|
73
|
+
"id": "user-api",
|
74
|
+
"route": {
|
75
|
+
"path": "/users",
|
76
|
+
"methods": {
|
77
|
+
"get": {
|
78
|
+
"status": 200,
|
79
|
+
"response": {
|
80
|
+
"code": 200,
|
81
|
+
"message": "success",
|
79
82
|
"data": {
|
80
|
-
"
|
81
|
-
|
82
|
-
|
83
|
+
"list|10": [{
|
84
|
+
"id": "@id",
|
85
|
+
"name": "@cname",
|
86
|
+
"email": "@email"
|
87
|
+
}]
|
83
88
|
}
|
84
89
|
}
|
85
90
|
}
|
@@ -90,110 +95,45 @@ pnpm add json-api-mocker
|
|
90
95
|
}
|
91
96
|
```
|
92
97
|
|
93
|
-
|
94
|
-
|
95
|
-
有多种方式可以启动 Mock 服务器:
|
98
|
+
然后启动服务器:
|
96
99
|
|
97
100
|
```bash
|
98
|
-
# 方式一:使用 npx(推荐)
|
99
|
-
npx json-api-mocker
|
100
|
-
|
101
|
-
# 方式二:使用 npx 并指定配置文件
|
102
|
-
npx json-api-mocker ./custom-config.json
|
103
|
-
|
104
|
-
# 方式三:如果全局安装了包
|
105
101
|
json-api-mocker
|
106
|
-
|
107
|
-
# 方式四:如果作为项目依赖安装
|
108
|
-
# 在 package.json 的 scripts 中添加:
|
109
|
-
{
|
110
|
-
"scripts": {
|
111
|
-
"mock": "json-api-mocker"
|
112
|
-
}
|
113
|
-
}
|
114
|
-
# 然后运行:
|
115
|
-
npm run mock
|
116
102
|
```
|
117
103
|
|
118
|
-
|
119
|
-
|
120
|
-
你会看到类似这样的输出:
|
121
|
-
```bash
|
122
|
-
Mock 服务器已启动:
|
123
|
-
- 地址:http://localhost:8080
|
124
|
-
- 基础路径:/api
|
125
|
-
可用的接口:
|
126
|
-
GET http://localhost:8080/api/users
|
127
|
-
POST http://localhost:8080/api/users
|
128
|
-
POST http://localhost:8080/api/upload/avatar
|
129
|
-
```
|
130
|
-
|
131
|
-
## 📖 配置指南
|
132
|
-
|
133
|
-
详细配置请参考 [CONFIG.ch.md](./CONFIG.ch.md)。
|
104
|
+
## 📖 配置说明
|
134
105
|
|
135
106
|
### 服务器配置
|
136
107
|
|
137
|
-
`server` 部分配置基本的服务器设置:
|
138
|
-
|
139
108
|
```json
|
140
109
|
{
|
141
110
|
"server": {
|
142
111
|
"port": 8080, // 服务器端口号
|
143
|
-
"baseProxy": "/api" //
|
112
|
+
"baseProxy": "/api" // API 基础路径
|
144
113
|
}
|
145
114
|
}
|
146
115
|
```
|
147
116
|
|
148
|
-
###
|
117
|
+
### API 配置
|
149
118
|
|
150
|
-
|
119
|
+
每个 API 配置包含:
|
151
120
|
|
152
121
|
```json
|
153
122
|
{
|
154
|
-
"
|
155
|
-
"
|
156
|
-
"
|
157
|
-
|
158
|
-
"
|
159
|
-
"
|
160
|
-
"
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
"post": {
|
166
|
-
"requestSchema": { // 请求体验证模式
|
167
|
-
"name": "string",
|
168
|
-
"age": "number"
|
169
|
-
},
|
170
|
-
"response": {
|
171
|
-
"success": true
|
172
|
-
}
|
173
|
-
}
|
174
|
-
}
|
175
|
-
}
|
176
|
-
```
|
177
|
-
|
178
|
-
### 文件上传支持
|
179
|
-
|
180
|
-
你可以在 `data.json` 中配置文件上传接口:
|
181
|
-
|
182
|
-
```json
|
183
|
-
{
|
184
|
-
"path": "/upload/avatar",
|
185
|
-
"methods": {
|
186
|
-
"post": {
|
187
|
-
"type": "object",
|
188
|
-
"mock": {
|
189
|
-
"enabled": true,
|
190
|
-
"template": {
|
191
|
-
"success": true,
|
192
|
-
"message": "上传成功",
|
123
|
+
"id": "unique-id", // API 唯一标识
|
124
|
+
"route": {
|
125
|
+
"path": "/users", // API 路径(不含基础路径)
|
126
|
+
"methods": { // 支持的 HTTP 方法
|
127
|
+
"get": {
|
128
|
+
"status": 200, // 响应状态码
|
129
|
+
"headers": { // 自定义响应头
|
130
|
+
"Content-Type": "application/json"
|
131
|
+
},
|
132
|
+
"response": { // 响应数据(支持 Mock.js 语法)
|
133
|
+
"code": 200,
|
193
134
|
"data": {
|
194
|
-
"
|
195
|
-
"
|
196
|
-
"size": "@integer(1000, 1000000)"
|
135
|
+
"name": "@name",
|
136
|
+
"age": "@integer(18, 60)"
|
197
137
|
}
|
198
138
|
}
|
199
139
|
}
|
@@ -202,113 +142,44 @@ Mock 服务器已启动:
|
|
202
142
|
}
|
203
143
|
```
|
204
144
|
|
205
|
-
|
206
|
-
|
207
|
-
```bash
|
208
|
-
# 上传单个文件
|
209
|
-
curl -X POST http://localhost:8080/api/upload/avatar \
|
210
|
-
-H "Content-Type: multipart/form-data" \
|
211
|
-
-F "avatar=@/path/to/your/image.jpg"
|
212
|
-
|
213
|
-
# 上传多个文件
|
214
|
-
curl -X POST http://localhost:8080/api/upload/images \
|
215
|
-
-H "Content-Type: multipart/form-data" \
|
216
|
-
-F "images=@/path/to/image1.jpg" \
|
217
|
-
-F "images=@/path/to/image2.jpg"
|
218
|
-
```
|
219
|
-
|
220
|
-
详细配置选项请参考 [CONFIG.ch.md](./CONFIG.ch.md#文件上传配置)。
|
145
|
+
## 🎮 可视化界面功能
|
221
146
|
|
222
|
-
|
147
|
+
### 1. API 管理
|
148
|
+
- 创建、编辑、删除 API
|
149
|
+
- 支持多种 HTTP 方法
|
150
|
+
- 可视化编辑响应数据
|
151
|
+
- Mock.js 语法提示
|
223
152
|
|
224
|
-
###
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
```
|
230
|
-
|
231
|
-
#### 获取单个用户
|
232
|
-
```bash
|
233
|
-
curl http://localhost:8080/api/users/1
|
234
|
-
```
|
153
|
+
### 2. 实时日志
|
154
|
+
- 请求路径和方法
|
155
|
+
- 响应状态和耗时
|
156
|
+
- 请求参数记录
|
157
|
+
- 响应数据查看
|
235
158
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
```
|
159
|
+
### 3. 统计面板
|
160
|
+
- API 总数统计
|
161
|
+
- 请求量监控
|
162
|
+
- 平均响应时间
|
163
|
+
- 成功率统计
|
242
164
|
|
243
|
-
|
244
|
-
```bash
|
245
|
-
curl -X PUT http://localhost:8080/api/users/1 \
|
246
|
-
-H "Content-Type: application/json" \
|
247
|
-
-d '{"name":"李四","age":26,"city":"上海"}'
|
248
|
-
```
|
165
|
+
## 🔧 命令行参数
|
249
166
|
|
250
|
-
#### 删除用户
|
251
167
|
```bash
|
252
|
-
|
253
|
-
```
|
254
|
-
|
255
|
-
### 高级用法
|
168
|
+
json-api-mocker [options]
|
256
169
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
170
|
+
选项:
|
171
|
+
-p, --port <number> 指定服务器端口号(默认:8080)
|
172
|
+
-c, --config <path> 指定配置文件路径(默认:data.json)
|
173
|
+
-o, --open 自动打开管理界面
|
174
|
+
-h, --help 显示帮助信息
|
175
|
+
-v, --version 显示版本号
|
261
176
|
```
|
262
177
|
|
263
|
-
#### 自定义响应头
|
264
|
-
服务器自动添加以下响应头:
|
265
|
-
- `X-Total-Count`:数据总条数(用于分页响应)
|
266
|
-
|
267
|
-
## 🔧 高级配置
|
268
|
-
|
269
|
-
### 动态路由
|
270
|
-
|
271
|
-
你可以在路由中使用 URL 参数:
|
272
|
-
|
273
|
-
```json
|
274
|
-
{
|
275
|
-
"path": "/users/:id/posts",
|
276
|
-
"methods": {
|
277
|
-
"get": {
|
278
|
-
"type": "array",
|
279
|
-
"response": []
|
280
|
-
}
|
281
|
-
}
|
282
|
-
}
|
283
|
-
```
|
284
|
-
|
285
|
-
### 请求验证
|
286
|
-
|
287
|
-
为 POST/PUT 请求添加模式验证:
|
288
|
-
|
289
|
-
```json
|
290
|
-
{
|
291
|
-
"requestSchema": {
|
292
|
-
"name": "string",
|
293
|
-
"age": "number",
|
294
|
-
"email": "string"
|
295
|
-
}
|
296
|
-
}
|
297
|
-
```
|
298
|
-
|
299
|
-
## 🤝 贡献指南
|
300
|
-
|
301
|
-
1. Fork 本仓库
|
302
|
-
2. 创建你的特性分支 (`git checkout -b feature/amazing-feature`)
|
303
|
-
3. 提交你的改动 (`git commit -m '添加一些很棒的特性'`)
|
304
|
-
4. 推送到分支 (`git push origin feature/amazing-feature`)
|
305
|
-
5. 开启一个 Pull Request
|
306
|
-
|
307
178
|
## 📄 许可证
|
308
179
|
|
309
180
|
MIT © [熊海银]
|
310
181
|
|
311
182
|
## 🙏 致谢
|
312
183
|
|
313
|
-
-
|
314
|
-
-
|
184
|
+
- 感谢所有贡献者和用户
|
185
|
+
- 特别感谢 Mock.js 提供数据模拟支持
|