@fairys/mocker-cli 0.0.1 → 0.0.3
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/README.md +147 -15
- package/bin/fairys-mocker +2 -2
- package/esm/base.js +2 -1
- package/esm/ci.d.ts +4 -2
- package/esm/ci.js +23 -19
- package/esm/controller/mock.router.js +3 -3
- package/esm/controller/proxy.router.js +5 -4
- package/esm/plugins/rsbuild.js +2 -0
- package/esm/router/proxy.js +4 -2
- package/esm/utils/mcok.proxy.js +23 -19
- package/esm/utils/utils.d.ts +12 -2
- package/esm/utils/utils.js +12 -3
- package/package.json +2 -2
- package/public/_fairys_mocker/index.html +1 -1
- package/public/_fairys_mocker/static/js/index.ef2bf9b4.js +1 -0
- package/src/base.ts +5 -3
- package/src/ci.ts +24 -26
- package/src/controller/mock.router.ts +3 -3
- package/src/controller/proxy.router.ts +5 -6
- package/src/plugins/rsbuild.ts +3 -0
- package/src/router/proxy.ts +16 -12
- package/src/utils/mcok.proxy.ts +25 -22
- package/src/utils/utils.ts +22 -2
- package/public/_fairys_mocker/static/js/index.f70ed1dc.js +0 -1
package/README.md
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# mocker-cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[ ] 直接当 mock 服务
|
|
6
|
-
[ ] 生成 mock 数据
|
|
7
|
-
[ ] 服务 + 数据
|
|
3
|
+
功能强大的 Mock 数据生成和代理转发工具
|
|
8
4
|
|
|
9
5
|
## 安装
|
|
10
6
|
|
|
@@ -19,18 +15,154 @@ Usage:
|
|
|
19
15
|
$ fairys-mocker
|
|
20
16
|
|
|
21
17
|
Options:
|
|
22
|
-
--root
|
|
23
|
-
--dir
|
|
24
|
-
--file
|
|
25
|
-
--file2
|
|
26
|
-
--static
|
|
27
|
-
--static-prefix
|
|
18
|
+
--root 设置根目录路径(默认取环境变量中的`FAIRYS_MOCKER_ROOT_DIR`)
|
|
19
|
+
--dir 设置目录名(默认取环境变量中的`FAIRYS_MOCKER_DIR`)
|
|
20
|
+
--file 设置文件名(默认取环境变量中的`FAIRYS_MOCKER_FILE`)
|
|
21
|
+
--file2 设置文件名2(默认取环境变量中的`FAIRYS_MOCKER_PROXY_FILE`)
|
|
22
|
+
--static 设置静态文件目录
|
|
23
|
+
--static-prefix 设置静态文件路径前缀
|
|
24
|
+
--is-mock-file 是否生成mock数据文件,默认生成.
|
|
25
|
+
--is-proxy-file 是否生成proxy数据文件,默认生成.
|
|
26
|
+
--is-connect 是否是connect服务.默认express.
|
|
28
27
|
```
|
|
29
28
|
|
|
30
29
|
**参数说明**
|
|
31
30
|
|
|
32
|
-
`FAIRYS_MOCKER_ROOT_DIR`或`root`:未设置时,取当前执行命令目录
|
|
33
|
-
`FAIRYS_MOCKER_DIR`或者`dir`:未设置时,取当前执行命令目录的`mock`文件夹
|
|
34
|
-
`FAIRYS_MOCKER_FILE`或者`file`:未设置时,取当前执行命令目录的`mock`文件夹下的`index.mock.
|
|
35
|
-
`FAIRYS_MOCKER_PROXY_FILE`或者`file2`:未设置时,取当前执行命令目录的`mock`文件夹下的`proxy.
|
|
31
|
+
- `FAIRYS_MOCKER_ROOT_DIR`或`root`:未设置时,取当前执行命令目录
|
|
32
|
+
- `FAIRYS_MOCKER_DIR`或者`dir`:未设置时,取当前执行命令目录的`mock`文件夹
|
|
33
|
+
- `FAIRYS_MOCKER_FILE`或者`file`:未设置时,取当前执行命令目录的`mock`文件夹下的`index.mock.cache.json`文件
|
|
34
|
+
- `FAIRYS_MOCKER_PROXY_FILE`或者`file2`:未设置时,取当前执行命令目录的`mock`文件夹下的`proxy.cache.json`文件
|
|
35
|
+
|
|
36
|
+
:::tip
|
|
37
|
+
|
|
38
|
+
`file`和`file2`值为移除`.cache.json`的文件名,不是完整的文件名,
|
|
39
|
+
|
|
40
|
+
例如`file=index.mock`, `file2=proxy` 内部会进行转换为 `index.mock.cache.json`、`index.mock.ts`、`proxy.cache.json`、`proxy.ts` 这4个文件名称
|
|
41
|
+
|
|
42
|
+
:::
|
|
43
|
+
|
|
44
|
+
在使用的过程中会生成4个文件
|
|
45
|
+
|
|
46
|
+
1. `index.mock.cache.json`: 生成mock数据的原始配置(页面渲染取值)
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mockList": [
|
|
51
|
+
{
|
|
52
|
+
"url": "/api/test",
|
|
53
|
+
"method": "POST",
|
|
54
|
+
"status": "200",
|
|
55
|
+
"delay": 0,
|
|
56
|
+
"body": {
|
|
57
|
+
"code": 200,
|
|
58
|
+
"data": {
|
|
59
|
+
"id": "@id",
|
|
60
|
+
"name": "@name",
|
|
61
|
+
"email": "@email"
|
|
62
|
+
},
|
|
63
|
+
"message": "success"
|
|
64
|
+
},
|
|
65
|
+
"listCount": 20
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
"rootDir": "...",
|
|
69
|
+
"dir": "mock",
|
|
70
|
+
"fileName": "index.mock",
|
|
71
|
+
"cache": "index.mock.cache.json"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
2. `index.mock.ts`: 生成的mock数据
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// Mock 配置文件
|
|
79
|
+
export interface MockerItem {
|
|
80
|
+
/**该接口允许的 请求方法,默认同时支持 GET 和 POST*/
|
|
81
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
|
82
|
+
/**状态码*/
|
|
83
|
+
status: string;
|
|
84
|
+
//配置响应延迟时间, 如果传入的是一个数组,则代表延迟时间的范围
|
|
85
|
+
delay: number | [number, number];
|
|
86
|
+
/**响应体(可以自定义返回格式)*/
|
|
87
|
+
body: any;
|
|
88
|
+
/**接口地址*/
|
|
89
|
+
url: string;
|
|
90
|
+
/**列表数据条数(仅 list 格式有效)*/
|
|
91
|
+
listCount?: number;
|
|
92
|
+
}
|
|
93
|
+
/**mock配置 列表*/
|
|
94
|
+
export type DefineMockList = MockerItem[];
|
|
95
|
+
export const mockList: DefineMockList = [
|
|
96
|
+
{
|
|
97
|
+
"url": "/api/test",
|
|
98
|
+
"method": "POST",
|
|
99
|
+
"status": "200",
|
|
100
|
+
"delay": 0,
|
|
101
|
+
"body": {
|
|
102
|
+
"code": 200,
|
|
103
|
+
"message": "success",
|
|
104
|
+
"data": {
|
|
105
|
+
"id": "450000200805311843",
|
|
106
|
+
"name": "Sarah Lee",
|
|
107
|
+
"email": "u.azfjyqt@uscf.pe"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"listCount": 20
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
export default mockList;
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
3. `proxy.cache.json`: 生成代理数据原始配置(页面渲染取值)
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"proxyList": [
|
|
122
|
+
{
|
|
123
|
+
"path": "^/docks",
|
|
124
|
+
"target": "http://localhost:9009"
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"rootDir": "...",
|
|
128
|
+
"dir": "mock",
|
|
129
|
+
"fileName": "proxy",
|
|
130
|
+
"cache": "proxy.cache.json"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
4. `proxy.ts`: 生成的代理服务数据
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
// 代理配置文件
|
|
138
|
+
/**
|
|
139
|
+
* 代理配置参数
|
|
140
|
+
*/
|
|
141
|
+
export type ProxyItem = Record<string,{
|
|
142
|
+
/**转发地址*/
|
|
143
|
+
target: string,
|
|
144
|
+
/**路径重写*/
|
|
145
|
+
pathRewrite?: Record<string, string>,
|
|
146
|
+
/**是否开启ws*/
|
|
147
|
+
ws?: boolean
|
|
148
|
+
}>
|
|
149
|
+
|
|
150
|
+
export const proxyConfig: ProxyItem = {
|
|
151
|
+
"^/tsx": {
|
|
152
|
+
"target": "http://localhost:9009"
|
|
153
|
+
},
|
|
154
|
+
"^/wsdse": {
|
|
155
|
+
"target": "http://localhost:8982",
|
|
156
|
+
"pathRewrite": {
|
|
157
|
+
"^/wsdse": ""
|
|
158
|
+
},
|
|
159
|
+
"ws": true
|
|
160
|
+
},
|
|
161
|
+
"^/docks": {
|
|
162
|
+
"target": "http://localhost:9009"
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
export default proxyConfig;
|
|
166
|
+
|
|
167
|
+
```
|
|
36
168
|
|
package/bin/fairys-mocker
CHANGED
|
@@ -12,9 +12,9 @@ if (enableCompileCache) {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
async function main() {
|
|
15
|
-
const {
|
|
15
|
+
const { runCli } = await import('../esm/ci.js');
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
runCli();
|
|
18
18
|
} catch (err) {
|
|
19
19
|
console.error(err);
|
|
20
20
|
}
|
package/esm/base.js
CHANGED
|
@@ -23,7 +23,8 @@ class FairysMockerBase {
|
|
|
23
23
|
staticServer = (dir, prefix = '/', isRegister = true)=>{
|
|
24
24
|
if (!this.app) return;
|
|
25
25
|
if (node_fs.existsSync(dir)) {
|
|
26
|
-
|
|
26
|
+
let _prefix = prefix;
|
|
27
|
+
if (!/^\//.test(prefix)) _prefix = "/" + prefix;
|
|
27
28
|
this.app.use(_prefix, express["static"](dir));
|
|
28
29
|
if (isRegister) this.staticServerList.push(_prefix);
|
|
29
30
|
} else console.log(chalk.red(`${dir} 目录不存在`));
|
package/esm/ci.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { FairysMockerExpress } from "./main.js";
|
|
2
|
+
import { FairysMockerConnect } from "./connect.js";
|
|
3
|
+
export declare const CI: (app: FairysMockerExpress | FairysMockerConnect) => void;
|
|
4
|
+
export declare const runCli: () => void;
|
package/esm/ci.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import yargs_parser from "yargs-parser";
|
|
2
2
|
import { fairysMockerExpress } from "./main.js";
|
|
3
3
|
import { fairysMockerConnect } from "./connect.js";
|
|
4
|
-
import {
|
|
4
|
+
import { utilsGlobalVariable } from "./utils/utils.js";
|
|
5
5
|
function help() {
|
|
6
|
-
console.log('\n Usage: \x1b[34;1fairys-mocker\x1b[0m [--help|h|--root|--dir|--file|--file2|--static|--static-prefix]');
|
|
6
|
+
console.log('\n Usage: \x1b[34;1fairys-mocker\x1b[0m [--help|h|--root|--dir|--file|--file2|--static|--static-prefix|--is-mock-file|--is-proxy-file]');
|
|
7
7
|
console.log('\n Displays help information.');
|
|
8
8
|
console.log('\n Options:\n');
|
|
9
9
|
console.log(' --root ', '设置根目录路径(默认取环境变量中的`FAIRYS_MOCKER_ROOT_DIR`).');
|
|
@@ -12,6 +12,9 @@ function help() {
|
|
|
12
12
|
console.log(' --file2 ', '设置文件名2(默认取环境变量中的`FAIRYS_MOCKER_PROXY_FILE`).');
|
|
13
13
|
console.log(' --static ', '设置静态文件服务目录.');
|
|
14
14
|
console.log(' --static-prefix ', '设置静态文件服务目录访问前缀.');
|
|
15
|
+
console.log(' --is-mock-file ', '是否生成mock数据文件,默认生成.');
|
|
16
|
+
console.log(' --is-proxy-file ', '是否生成proxy数据文件,默认生成.');
|
|
17
|
+
console.log(' --is-connect ', '是否是connect服务.默认express.');
|
|
15
18
|
console.log('\n Example:\n');
|
|
16
19
|
console.log(' $ \x1b[35mfairys-mocker\x1b[0m --dir mock2');
|
|
17
20
|
console.log(' $ \x1b[35mfairys-mocker\x1b[0m --file index.mock');
|
|
@@ -24,26 +27,27 @@ const argv = yargs_parser(process.argv.slice(2), {
|
|
|
24
27
|
'file2',
|
|
25
28
|
'static',
|
|
26
29
|
'static-prefix'
|
|
30
|
+
],
|
|
31
|
+
boolean: [
|
|
32
|
+
'is-mock-file',
|
|
33
|
+
"is-proxy-file",
|
|
34
|
+
'is-connect'
|
|
27
35
|
]
|
|
28
36
|
});
|
|
29
|
-
const
|
|
37
|
+
const CI = (app)=>{
|
|
30
38
|
if (argv.help | argv.h) return void help();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
utilsGlobalVariable.setRootDir(argv.root);
|
|
40
|
+
utilsGlobalVariable.setDir(argv.dir);
|
|
41
|
+
utilsGlobalVariable.setFile(argv.file);
|
|
42
|
+
utilsGlobalVariable.setProxyFile(argv.file2);
|
|
43
|
+
utilsGlobalVariable.setIsCreateMockDataFile(argv['is-mock-file']);
|
|
44
|
+
utilsGlobalVariable.setIsCreateProxyDataFile(argv['is-proxy-file']);
|
|
45
|
+
app.start(()=>{
|
|
46
|
+
if (!argv.static) return;
|
|
47
|
+
app.staticServer(argv.static, argv['static-prefix']);
|
|
37
48
|
});
|
|
38
49
|
};
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
utils.setRootDir(argv.root);
|
|
42
|
-
utils.setDir(argv.dir);
|
|
43
|
-
utils.setFile(argv.file);
|
|
44
|
-
utils.setProxyFile(argv.file2);
|
|
45
|
-
fairysMockerConnect.start(()=>{
|
|
46
|
-
if (argv.static) fairysMockerConnect.staticServer(argv.static, argv['static-prefix']);
|
|
47
|
-
});
|
|
50
|
+
const runCli = ()=>{
|
|
51
|
+
argv['is-connect'] ? CI(fairysMockerConnect) : CI(fairysMockerExpress);
|
|
48
52
|
};
|
|
49
|
-
export {
|
|
53
|
+
export { CI, runCli };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import node_fs from "node:fs";
|
|
2
2
|
import { Controller, Get, Post } from "../utils/decorator.js";
|
|
3
|
-
import {
|
|
3
|
+
import { utilsGlobalVariable } from "../utils/index.js";
|
|
4
4
|
import { MockRouter } from "../router/mock.js";
|
|
5
5
|
import { BaseController } from "./base.js";
|
|
6
6
|
import { createMockFile, getMcokFile } from "../utils/mcok.proxy.js";
|
|
@@ -370,8 +370,8 @@ class MockRouterController extends (_BaseController = BaseController) {
|
|
|
370
370
|
post_mock(req, res) {
|
|
371
371
|
try {
|
|
372
372
|
const { mockList, dir, fileName = 'index.mock', rootDir } = req.body;
|
|
373
|
-
let _rootDir = rootDir ||
|
|
374
|
-
if (rootDir && !node_fs.existsSync(rootDir)) _rootDir =
|
|
373
|
+
let _rootDir = rootDir || utilsGlobalVariable.rootDir;
|
|
374
|
+
if (rootDir && !node_fs.existsSync(rootDir)) _rootDir = utilsGlobalVariable.rootDir;
|
|
375
375
|
const mockData = createMockFile(mockList, _rootDir, dir, fileName);
|
|
376
376
|
if (mockData?.mockConfig) {
|
|
377
377
|
if (this.router?.isEnabled) this.router?.load(mockData.mockConfig);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import node_fs from "node:fs";
|
|
2
2
|
import { Controller, Get, Post } from "../utils/decorator.js";
|
|
3
|
-
import {
|
|
3
|
+
import { utilsGlobalVariable } from "../utils/utils.js";
|
|
4
4
|
import { ProxyRouter } from "../router/proxy.js";
|
|
5
5
|
import { BaseController } from "./base.js";
|
|
6
6
|
import { createProxyFile, getProxyFile } from "../utils/mcok.proxy.js";
|
|
@@ -370,8 +370,8 @@ class ProxyRouterController extends (_BaseController = BaseController) {
|
|
|
370
370
|
post_proxy(req, res) {
|
|
371
371
|
try {
|
|
372
372
|
const { proxyList, dir, fileName = 'proxy', rootDir } = req.body;
|
|
373
|
-
let _rootDir = rootDir ||
|
|
374
|
-
if (rootDir && !node_fs.existsSync(rootDir)) _rootDir =
|
|
373
|
+
let _rootDir = rootDir || utilsGlobalVariable.rootDir;
|
|
374
|
+
if (rootDir && !node_fs.existsSync(rootDir)) _rootDir = utilsGlobalVariable.rootDir;
|
|
375
375
|
const proxyData = createProxyFile(proxyList, _rootDir, dir, fileName);
|
|
376
376
|
if (proxyData?.proxyConfig) {
|
|
377
377
|
if (this.router?.isEnabled) this.router?.load(proxyList);
|
|
@@ -439,9 +439,10 @@ class ProxyRouterController extends (_BaseController = BaseController) {
|
|
|
439
439
|
const proxyData = getProxyFile(rootDir, savePath, saveFileName);
|
|
440
440
|
if (proxyData?.proxyList) {
|
|
441
441
|
this.router?.load(proxyData.proxyList);
|
|
442
|
+
const msg = utilsGlobalVariable.isEnableWebsocket ? '启动代理服务成功' : '非websocket服务代理启动成功';
|
|
442
443
|
res.json({
|
|
443
444
|
code: 200,
|
|
444
|
-
message:
|
|
445
|
+
message: msg,
|
|
445
446
|
data: proxyData.proxyList,
|
|
446
447
|
rootDir: rootDir,
|
|
447
448
|
dir: proxyData.dir,
|
package/esm/plugins/rsbuild.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { fairysMockerBase } from "../base.js";
|
|
2
|
+
import { utilsGlobalVariable } from "../utils/utils.js";
|
|
2
3
|
const fairysMockerRsbuildPlugin = ()=>({
|
|
3
4
|
setup (api) {
|
|
4
5
|
api.onBeforeStartDevServer(({ server })=>{
|
|
5
6
|
fairysMockerBase.initApp(server.middlewares, ()=>{
|
|
6
7
|
fairysMockerBase.logServer(server.port);
|
|
8
|
+
utilsGlobalVariable.isEnableWebsocket = false;
|
|
7
9
|
});
|
|
8
10
|
fairysMockerBase.server = server.httpServer;
|
|
9
11
|
});
|
package/esm/router/proxy.js
CHANGED
|
@@ -3,6 +3,7 @@ import { BaseRouter } from "./base.js";
|
|
|
3
3
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import { fairysMockerBase } from "../base.js";
|
|
6
|
+
import { utilsGlobalVariable } from "../utils/utils.js";
|
|
6
7
|
class ProxyRouter extends BaseRouter {
|
|
7
8
|
router = null;
|
|
8
9
|
wsProxyList = [];
|
|
@@ -30,7 +31,7 @@ class ProxyRouter extends BaseRouter {
|
|
|
30
31
|
}
|
|
31
32
|
console.log(chalk.hex('#AF52DE')(chalk.bold(` 🍇 proxy代理启动:\t${chalk.yellow(protocol)}\t${proxyItem.path} ===> ${_target}\t`)));
|
|
32
33
|
if (!proxyItem.path.startsWith('^')) _path = new RegExp('^' + proxyItem.path);
|
|
33
|
-
if (proxyItem.ws) {
|
|
34
|
+
if (proxyItem.ws) if (utilsGlobalVariable.isEnableWebsocket) {
|
|
34
35
|
const wsProxy = createProxyMiddleware({
|
|
35
36
|
target: proxyItem.target,
|
|
36
37
|
pathRewrite: proxyItem.pathRewrite,
|
|
@@ -40,7 +41,8 @@ class ProxyRouter extends BaseRouter {
|
|
|
40
41
|
_that.wsProxyList.push(wsProxy);
|
|
41
42
|
router.all(_path, wsProxy);
|
|
42
43
|
if (fairysMockerBase.server) fairysMockerBase.server?.on('upgrade', wsProxy.upgrade);
|
|
43
|
-
} else
|
|
44
|
+
} else console.log(chalk.red(`rsbuild/vite等自带websocket服务的环境下无法代理websocket服务:${proxyItem.path}`));
|
|
45
|
+
else router.all(_path, createProxyMiddleware({
|
|
44
46
|
target: proxyItem.target,
|
|
45
47
|
pathRewrite: proxyItem.pathRewrite,
|
|
46
48
|
ws: proxyItem.ws,
|
package/esm/utils/mcok.proxy.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import node_path from "node:path";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { utilsGlobalVariable } from "./utils.js";
|
|
4
4
|
import { createMockData, createProxyData } from "@fairys/create-mock-data";
|
|
5
5
|
const getProxyFile = (rootDir, dir, fileName)=>{
|
|
6
|
-
const _rootDir = rootDir?.trim() ||
|
|
7
|
-
const _dir = dir?.trim() ||
|
|
8
|
-
const _fileName = fileName?.trim() ||
|
|
6
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
7
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
8
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.proxyFile;
|
|
9
9
|
const proxyDir = node_path.join(_rootDir, _dir);
|
|
10
10
|
const cacheFilePath = node_path.join(proxyDir, _fileName + '.cache.json');
|
|
11
11
|
if (node_fs.existsSync(cacheFilePath)) {
|
|
@@ -22,16 +22,17 @@ const getProxyFile = (rootDir, dir, fileName)=>{
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
const createProxyFile = (proxyList, rootDir, dir, fileName)=>{
|
|
25
|
-
const _rootDir = rootDir?.trim() ||
|
|
26
|
-
const _dir = dir?.trim() ||
|
|
27
|
-
const _fileName = fileName?.trim() ||
|
|
25
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
26
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
27
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.proxyFile;
|
|
28
28
|
const proxyDir = node_path.join(_rootDir, _dir);
|
|
29
29
|
if (!node_fs.existsSync(proxyDir)) node_fs.mkdirSync(proxyDir, {
|
|
30
30
|
recursive: true
|
|
31
31
|
});
|
|
32
32
|
const proxyConfig = createProxyData(proxyList);
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
if (utilsGlobalVariable.isCreateProxyDataFile) {
|
|
34
|
+
const proxyFilePath = node_path.join(proxyDir, `${_fileName}.ts`);
|
|
35
|
+
const proxyFileContent = `// 代理配置文件
|
|
35
36
|
// 自动生成于 ${new Date().toISOString()}
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -49,7 +50,8 @@ export type ProxyItem = Record<string,{
|
|
|
49
50
|
export const proxyConfig: ProxyItem = ${JSON.stringify(proxyConfig, null, 2)};
|
|
50
51
|
export default proxyConfig;
|
|
51
52
|
`;
|
|
52
|
-
|
|
53
|
+
node_fs.writeFileSync(proxyFilePath, proxyFileContent);
|
|
54
|
+
}
|
|
53
55
|
const cacheFilePath = node_path.join(proxyDir, _fileName + '.cache.json');
|
|
54
56
|
const cacheFileContent = JSON.stringify({
|
|
55
57
|
proxyList,
|
|
@@ -68,9 +70,9 @@ export default proxyConfig;
|
|
|
68
70
|
};
|
|
69
71
|
};
|
|
70
72
|
const getMcokFile = (rootDir, dir, fileName)=>{
|
|
71
|
-
const _rootDir = rootDir?.trim() ||
|
|
72
|
-
const _dir = dir?.trim() ||
|
|
73
|
-
const _fileName = fileName?.trim() ||
|
|
73
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
74
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
75
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.file;
|
|
74
76
|
const mockDir = node_path.join(_rootDir, _dir);
|
|
75
77
|
const cacheFilePath = node_path.join(mockDir, _fileName + '.cache.json');
|
|
76
78
|
if (node_fs.existsSync(cacheFilePath)) {
|
|
@@ -87,16 +89,17 @@ const getMcokFile = (rootDir, dir, fileName)=>{
|
|
|
87
89
|
}
|
|
88
90
|
};
|
|
89
91
|
const createMockFile = (mockList, rootDir, dir, fileName)=>{
|
|
90
|
-
const _rootDir = rootDir?.trim() ||
|
|
91
|
-
const _dir = dir?.trim() ||
|
|
92
|
-
const _fileName = fileName?.trim() ||
|
|
92
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
93
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
94
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.file;
|
|
93
95
|
const mockDir = node_path.join(_rootDir, _dir);
|
|
94
96
|
if (!node_fs.existsSync(mockDir)) node_fs.mkdirSync(mockDir, {
|
|
95
97
|
recursive: true
|
|
96
98
|
});
|
|
97
99
|
const mockConfig = createMockData(mockList);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
if (utilsGlobalVariable.isCreateMockDataFile) {
|
|
101
|
+
const mockFilePath = node_path.join(mockDir, `${_fileName}.ts`);
|
|
102
|
+
const mockFileContent = `// Mock 配置文件
|
|
100
103
|
// 自动生成于 ${new Date().toISOString()}
|
|
101
104
|
|
|
102
105
|
export interface MockerItem {
|
|
@@ -120,7 +123,8 @@ export type DefineMockList = MockerItem[];
|
|
|
120
123
|
export const mockList: DefineMockList = ${JSON.stringify(mockConfig, null, 2)};
|
|
121
124
|
export default mockList;
|
|
122
125
|
`;
|
|
123
|
-
|
|
126
|
+
node_fs.writeFileSync(mockFilePath, mockFileContent);
|
|
127
|
+
}
|
|
124
128
|
const cacheFilePath = node_path.join(mockDir, _fileName + '.cache.json');
|
|
125
129
|
const cacheFileContent = JSON.stringify({
|
|
126
130
|
mockList,
|
package/esm/utils/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare class
|
|
1
|
+
declare class UtilsGlobalVariable {
|
|
2
2
|
/**根目录*/
|
|
3
3
|
rootDir: string;
|
|
4
4
|
/**目录名*/
|
|
@@ -7,6 +7,12 @@ declare class Utils {
|
|
|
7
7
|
file: string;
|
|
8
8
|
/**代理文件名*/
|
|
9
9
|
proxyFile: string;
|
|
10
|
+
/**是否生成mock数据文件*/
|
|
11
|
+
isCreateMockDataFile: boolean;
|
|
12
|
+
/**是否生成proxy数据文件*/
|
|
13
|
+
isCreateProxyDataFile: boolean;
|
|
14
|
+
/**是否可以启用 websocket 服务(在rsbuild/vite等自带websocket服务的环境下无法使用)*/
|
|
15
|
+
isEnableWebsocket: boolean;
|
|
10
16
|
/**设置根目录*/
|
|
11
17
|
setRootDir: (value?: string) => void;
|
|
12
18
|
/**设置目录名*/
|
|
@@ -15,6 +21,10 @@ declare class Utils {
|
|
|
15
21
|
setFile: (value?: string) => void;
|
|
16
22
|
/**设置代理文件名*/
|
|
17
23
|
setProxyFile: (value?: string) => void;
|
|
24
|
+
/**设置 是否生成mock数据文件*/
|
|
25
|
+
setIsCreateMockDataFile: (fig?: boolean) => void;
|
|
26
|
+
/**设置 是否生成proxy数据文件*/
|
|
27
|
+
setIsCreateProxyDataFile: (fig?: boolean) => void;
|
|
18
28
|
}
|
|
19
|
-
export declare const
|
|
29
|
+
export declare const utilsGlobalVariable: UtilsGlobalVariable;
|
|
20
30
|
export {};
|
package/esm/utils/utils.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import node_fs from "node:fs";
|
|
3
3
|
import node_path from "node:path";
|
|
4
|
-
class
|
|
4
|
+
class UtilsGlobalVariable {
|
|
5
5
|
rootDir = process.cwd();
|
|
6
6
|
dir = 'mock';
|
|
7
7
|
file = 'index.mock';
|
|
8
8
|
proxyFile = 'proxy';
|
|
9
|
+
isCreateMockDataFile = true;
|
|
10
|
+
isCreateProxyDataFile = true;
|
|
11
|
+
isEnableWebsocket = true;
|
|
9
12
|
setRootDir = (value)=>{
|
|
10
13
|
if (value && node_fs.existsSync(value)) this.rootDir = value;
|
|
11
14
|
else {
|
|
@@ -26,6 +29,12 @@ class Utils {
|
|
|
26
29
|
setProxyFile = (value)=>{
|
|
27
30
|
this.proxyFile = value || process.env.FAIRYS_MOCKER_PROXY_FILE || 'proxy';
|
|
28
31
|
};
|
|
32
|
+
setIsCreateMockDataFile = (fig)=>{
|
|
33
|
+
if ("boolean" == typeof fig) this.isCreateMockDataFile = fig;
|
|
34
|
+
};
|
|
35
|
+
setIsCreateProxyDataFile = (fig)=>{
|
|
36
|
+
if ("boolean" == typeof fig) this.isCreateProxyDataFile = fig;
|
|
37
|
+
};
|
|
29
38
|
}
|
|
30
|
-
const
|
|
31
|
-
export {
|
|
39
|
+
const utilsGlobalVariable = new UtilsGlobalVariable();
|
|
40
|
+
export { utilsGlobalVariable };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fairys/mocker-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Fairys Mocker CLI for mock data generation",
|
|
5
5
|
"author": "SunLxy <1011771396@qq.com>",
|
|
6
6
|
"homepage": "https://github.com/autumn-fairy-tales/fairys-mocker",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"fairys-mocker": "bin/fairys-mocker"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@fairys/create-mock-data": "^0.0.
|
|
29
|
+
"@fairys/create-mock-data": "^0.0.3",
|
|
30
30
|
"body-parser": "2.2.2",
|
|
31
31
|
"chalk": "^5.6.2",
|
|
32
32
|
"connect": "^3.7.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><link rel="icon" href="/_fairys_mocker/favicon.png"><title>Fairys Mocker</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/_fairys_mocker/static/js/lib-react.2748fa4b.js"></script><script defer src="/_fairys_mocker/static/js/514.950758f1.js"></script><script defer src="/_fairys_mocker/static/js/index.
|
|
1
|
+
<!DOCTYPE html><html><head><link rel="icon" href="/_fairys_mocker/favicon.png"><title>Fairys Mocker</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script defer src="/_fairys_mocker/static/js/lib-react.2748fa4b.js"></script><script defer src="/_fairys_mocker/static/js/514.950758f1.js"></script><script defer src="/_fairys_mocker/static/js/index.ef2bf9b4.js"></script><link href="/_fairys_mocker/static/css/index.2ba69ff5.css" rel="stylesheet"></head><body><div id="root"></div></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{"use strict";var e,t,r,n,s={711(e,t,r){var n=r(85),s=r(873),o=r(41),a=r(424),i=r.n(a),l=r(346),c=r(990);class d extends l.ProxyInstanceObject{constructor(...e){var t;super(...e),t=this,(0,c._)(this,"open",function(e,r){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3,s=new Date().valueOf().toString();t.store.messageList.push((0,l.ref)({type:e,message:r,id:s}));let o=setTimeout(()=>{t.store.messageList=t.store.messageList.filter(e=>e.id!==s),clearTimeout(o)},n)})}}let x=new d()._ctor({tabKey:"mock",messageList:[],isServer:!0}),{MainProxyProvider:u,useMainProxyStore:m}=(0,l.createCommonMainStore)({proxyInstance:x,namespace:"global"}),b=window.location.origin;function h(e){let{columns:t,dataSource:r,rowKey:s}=e,a=(0,o.useMemo)(()=>(0,n.jsx)("tr",{className:"bg-zinc-100 dark:bg-zinc-800 sticky -top-px z-10",children:t.map((e,t)=>(0,n.jsx)("th",{className:"px-2 py-2 text-left text-xs font-medium text-zinc-700 dark:text-zinc-300 border-b border-zinc-200 dark:border-zinc-700",children:e.title},e.dataIndex||t))}),[t]);return(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsxs)("table",{className:"border-collapse min-w-full border border-zinc-200 dark:border-zinc-700 relative",children:[(0,n.jsx)("thead",{children:a}),(0,n.jsx)("tbody",{children:r.map((e,r)=>{let o="function"==typeof s?s(e):s?e[s]:r;return(0,n.jsx)("tr",{className:"hover:bg-zinc-50 dark:hover:bg-zinc-800",children:t.map(t=>{let s=t.dataIndex?e[t.dataIndex]:e;if(t.isIndex&&(s=r+1),t.render){var a;s=null==(a=t.render)?void 0:a.call(t,e,r)}return(0,n.jsx)("td",{className:`px-2 py-2 border-b border-zinc-200 dark:border-zinc-700 ${t.tdClassName||""}`,children:s},`${o}-${t.dataIndex}`)})},o)})})]})})}var p=r(224);let f=e=>{let{value:t,onChange:r,placeholder:s,className:o}=e;return(0,n.jsx)(p.A,{value:t,language:"json",placeholder:s,onChange:e=>null==r?void 0:r(e.target.value),padding:15,className:o,style:{fontFamily:"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",minHeight:280}})};var g=r(144);function y(){let{state:e,proxyInstance:t}=m(),r=e.isServer,{state:s,dispatch:a,proxyInstance:c}=(0,l.useProxyStore)({rootDir:"",dir:"mock",fileName:"index.mock",mockList:[],response:"",isModalOpen:!1,currentIndex:null,modalBody:"",isEnabledStart:!1},{sync:!0}),d=s.mockList,x=s.response,u=s.isModalOpen,p=s.currentIndex,y=s.modalBody,k=s.rootDir,v=s.dir,j=s.fileName,z=s.isEnabledStart,N=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_is_enabled`).then(e=>e.json());200===e.code&&a({isEnabledStart:e.data})}catch(e){console.error("检查 mock 配置服务是否启用失败:",e)}};(0,o.useEffect)(()=>{N()},[]);let w=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_destroy`).then(e=>e.json());200===e.code?(a({isEnabledStart:!1}),t.open("success","销毁 Mock 数据服务成功")):t.open("error",e.message||"销毁 Mock 数据服务失败")}catch(e){console.error("销毁 mock 数据服务失败:",e)}},C=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_start`).then(e=>e.json());200===e.code?(t.open("success","加载 Mock 数据服务成功"),a({isEnabledStart:!0})):t.open("error",e.message||"加载 Mock 数据服务失败")}catch(e){console.error("加载 mock 数据服务失败:",e)}},S=async e=>{try{let t;if(!0===e)t=await fetch(`${b}/_fairys/_mock`);else{let e=`dir=${decodeURIComponent(v)}&fileName=${decodeURIComponent(j)}&rootDir=${decodeURIComponent(k)}`;t=await fetch(`${b}/_fairys/_mock?${e}`)}let r=await t.json();200===r.code?a({mockList:r.data,dir:r.dir,fileName:r.fileName,rootDir:r.rootDir}):a({mockList:[]})}catch(e){t.store.isServer=!1,console.error("获取缓存数据失败:",e)}};(0,o.useEffect)(()=>{S(!0)},[]);let O=(e,t,r)=>{a({mockList:(c.store.mockList||[]).map((n,s)=>s===e?{...n,[t]:r}:n)})},_=async e=>{e.preventDefault();let s=!0,o="";for(let e=0;e<d.length;e++){let t=d[e];if(!t.url.trim()){s=!1,o=`接口配置 #${e+1} 的 接口地址 不能为空`;break}if(!t.method){s=!1,o=`接口配置 #${e+1} 的 请求方法 不能为空`;break}if(!t.status.trim()){s=!1,o=`接口配置 #${e+1} 的 状态码 不能为空`;break}if(!t.body){s=!1,o=`接口配置 #${e+1} 的 响应体 不能为空`;break}}if(!s)return void t.open("error",o);let l=new Map;for(let e=0;e<d.length;e++){let t=d[e],r=`${t.url.trim()}:${t.method}`;if(l.has(r)){var c;null==(c=l.get(r))||c.push(e+1)}else l.set(r,[e+1])}if(l.size>0){let e=[];for(let[t,r]of l)r.length>1&&e.push((0,n.jsxs)("div",{children:["第 ",r.join(",")," 行数据 接口地址和请求方法 组合重复;"]},t));if(e.length>0)return void t.open("error",e,5e3)}try{if(r){let e=await fetch(`${b}/_fairys/_mock`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mockList:d,dir:v,fileName:j,rootDir:k})}),r=await e.json();d.length>0?a({response:JSON.stringify(r,null,2)}):200===r.code&&t.open("success","保存成功"),a({rootDir:r.rootDir})}else if(d.length>0){let e=d.map(e=>(function(e){let{data:t,...r}={...e.body},n={},s=Object.keys(t),o=e.listCount||20;for(let e=0;e<s.length;e++){let r=s[e],a=t[r];if(/^(\_\|)/.test(r)){let[e,t,s]=r.split("|"),l=`${s||""}`.trim();a&&(n[t]=Array.from({length:l?Number(l):o},()=>i().mock(a)))}else Object.assign(n,i().mock({[r]:a}))}r.data=n;let a=0;if(Array.isArray(e.delay)){let[t,r]=e.delay;a=Math.floor(Math.random()*(r-t+1))+t}else a=e.delay;return{...e,body:r,delay:a}})(e));a({response:JSON.stringify(e,null,2)})}else t.open("success","操作成功")}catch(e){a({response:"Error: "+e.message})}},I=()=>{a({currentIndex:void 0,modalBody:"",isModalOpen:!1}),document.body.style.overflow="auto"};return(0,n.jsxs)("div",{className:"space-y-6 flex-1 flex flex-col box-border overflow-hidden",children:[(0,n.jsxs)("div",{className:"mb-6 text-xs text-zinc-600 dark:text-zinc-300 box-border flex justify-between",children:[(0,n.jsxs)("div",{children:["当前配置总条数: ",d.length]}),r?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:C,className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:[z?"重启":"启动"," mock 数据服务"]}),z?(0,n.jsx)("button",{type:"button",onClick:w,className:"px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"销毁 mock 数据服务"}):(0,n.jsx)(o.Fragment,{})]}):(0,n.jsx)(o.Fragment,{})]}),(0,n.jsxs)("div",{className:"mb-6",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"数据保存到本地"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"根目录"}),(0,n.jsx)("input",{type:"text",value:k,onChange:e=>{a({rootDir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"目录名"}),(0,n.jsx)("input",{type:"text",value:v,onChange:e=>{a({dir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"文件名"}),(0,n.jsx)("input",{type:"text",value:j,onChange:e=>{a({fileName:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsx)("button",{type:"button",onClick:()=>S(!1),className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors whitespace-nowrap text-xs",children:"查询"})]}),(0,n.jsx)("p",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:"默认保存到当前工作目录的 mock 文件夹"})]}),d.length>0?(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsx)(h,{columns:[{title:"#",isIndex:!0,tdClassName:"px-2 py-2 text-xs text-zinc-800 dark:text-zinc-100 border-b border-zinc-200 dark:border-zinc-700"},{title:"接口地址",dataIndex:"url",render:(e,t)=>(0,n.jsx)("input",{type:"text",placeholder:"请输入接口地址",value:e.url,onChange:e=>O(t,"url",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"请求方法",dataIndex:"method",render:(e,t)=>(0,n.jsxs)("select",{value:e.method,onChange:e=>O(t,"method",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",children:[(0,n.jsx)("option",{value:"GET",children:"GET"}),(0,n.jsx)("option",{value:"POST",children:"POST"}),(0,n.jsx)("option",{value:"PUT",children:"PUT"}),(0,n.jsx)("option",{value:"DELETE",children:"DELETE"}),(0,n.jsx)("option",{value:"PATCH",children:"PATCH"}),(0,n.jsx)("option",{value:"HEAD",children:"HEAD"}),(0,n.jsx)("option",{value:"OPTIONS",children:"OPTIONS"})]})},{title:"状态码",dataIndex:"status",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.status,onChange:e=>O(t,"status",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"例如: 200, 400, 500"})},{title:"响应延迟时间(ms)",dataIndex:"delay",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:Array.isArray(e.delay)?`${e.delay[0]},${e.delay[1]}`:e.delay||"",onChange:e=>{let r=e.target.value;if(r.includes(",")){let[e,n]=r.split(",").map(Number);O(t,"delay",[e,n])}else O(t,"delay",parseInt(r)||0)},className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"例如: 1000 或 500,2000"})},{title:"生成数据条数",dataIndex:"listCount",render:(e,t)=>(0,n.jsx)("input",{type:"number",value:e.listCount,onChange:e=>O(t,"listCount",parseInt(e.target.value)||1),min:"1",max:"100",className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"响应体数据",dataIndex:"body",render:e=>(0,n.jsx)("div",{className:"text-zinc-500 dark:text-zinc-400 text-xs w-[400px]",children:JSON.stringify(e.body,null,2)})},{title:"操作",dataIndex:"operation",render:(e,t)=>(0,n.jsxs)("div",{className:"flex space-x-1",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{a({currentIndex:t,modalBody:JSON.stringify(d[t].body,null,2),isModalOpen:!0}),document.body.style.overflow="hidden"},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"编辑响应体数据"}),(0,n.jsx)("button",{type:"button",onClick:()=>{a({mockList:(c.store.mockList||[]).filter((e,r)=>r!==t)})},className:"px-2 py-0.5 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"删除"})]})}],dataSource:d})}):(0,n.jsx)("div",{className:"text-center py-8 text-zinc-500 dark:text-zinc-400",children:'暂无接口配置,请点击"添加接口配置"按钮添加'}),(0,n.jsxs)("div",{className:"flex justify-center",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{a({mockList:[...c.store.mockList||[]].concat([{url:"",method:"POST",status:"200",delay:0,body:{code:200,data:{id:"@id",name:"@name",email:"@email"},message:"success"},listCount:20}])})},className:"px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors mr-4 text-xs",children:"添加接口配置"}),(0,n.jsx)("button",{type:"button",onClick:_,className:"px-4 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存配置"})]}),x&&(0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 flex flex-col w-full max-w-2xl max-h-[80%]",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-2",children:[(0,n.jsx)("h2",{className:"text-sm font-medium text-zinc-800 dark:text-zinc-100",children:"mock 数据"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsx)("button",{type:"button",title:"复制",onClick:()=>{navigator.clipboard.writeText(x),t.open("success","复制成功")},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"复制"}),(0,n.jsx)("button",{type:"button",onClick:()=>a({response:""}),className:"px-2 py-0.5 bg-gray-500 text-white rounded-md hover:bg-gray-600 transition-colors text-xs",children:"关闭"})]})]}),(0,n.jsx)("pre",{className:"flex-1 overflow-auto bg-zinc-100 dark:bg-zinc-800 p-3 rounded-md overflow-x-auto text-xs text-zinc-800 dark:text-zinc-100",children:x})]})}),u&&null!==p&&(null==d?void 0:d[p])&&(0,g.createPortal)((0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50 box-border",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 w-full max-w-2xl box-border",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-3 box-border",children:[(0,n.jsxs)("h2",{className:"text-sm font-medium text-zinc-700 dark:text-zinc-300",children:["编辑响应体数据 - 接口配置 #",p+1]}),(0,n.jsx)("button",{type:"button",onClick:I,className:"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200",children:"\xd7"})]}),(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsx)("div",{children:(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["响应体格式 ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"生成数据条数"}),(0,n.jsx)("input",{type:"number",value:d[p].listCount,onChange:e=>O(p,"listCount",parseInt(e.target.value)||1),min:"1",max:"100",className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["响应体 JSON ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]}),(0,n.jsx)(f,{value:y,onChange:e=>a({modalBody:e}),placeholder:'例如: {"code": 200, "data": {"id": "@id", "name": "@name"}, "message": "success"} 或 {"code": 200, "data": {"rows": [{"id": "@id", "name": "@name"}], "total": "@integer(20, 100)"}, "message": "success"}',className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white min-h-[300px] text-xs"})]})]}),(0,n.jsxs)("div",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:["支持使用 ",(0,n.jsx)("a",{href:"http://mockjs.com/examples.html",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:underline",children:"Mock.js 语法"}),",如 @id, @name, @email 等,",(0,n.jsxs)("div",{className:"text-red-500",children:["数组数据为特殊处理,使用`_|`开头,后面拼接字段:",(0,n.jsx)("b",{children:"_|字段|条数"})," 或者 ",(0,n.jsx)("b",{children:"_|字段"})]})]}),(0,n.jsxs)("div",{className:"flex justify-end space-x-2 mt-3 box-border",children:[(0,n.jsx)("button",{type:"button",onClick:I,className:"px-3 py-1 border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200 rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-600 transition-colors text-xs",children:"取消"}),(0,n.jsx)("button",{type:"button",onClick:()=>{if(null!==p)try{let e=Function("return "+y)();O(p,"body",e),I()}catch(e){t.open("error","JSON 格式错误,请检查输入")}},className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存"})]})]})}),document.body)]})}function k(){let{state:e,proxyInstance:t}=m(),r=e.isServer,{state:s,dispatch:a,proxyInstance:i}=(0,l.useProxyStore)({rootDir:"",dir:"mock",fileName:"proxy",proxyList:[],response:"",isModalOpen:!1,currentIndex:null,modalBody:"",isEnabledStart:!1},{sync:!0}),c=s.proxyList,d=s.response,x=s.isModalOpen,u=s.currentIndex,p=s.modalBody,y=s.rootDir,k=s.dir,v=s.fileName,j=s.isEnabledStart,z=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_is_enabled`).then(e=>e.json());200===e.code&&a({isEnabledStart:e.data})}catch(e){console.error("检查 Proxy 配置服务是否启用失败:",e)}};(0,o.useEffect)(()=>{z()},[]);let N=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_destroy`).then(e=>e.json());200===e.code?(a({isEnabledStart:!1}),t.open("success",e.message||"销毁 Proxy 服务成功")):t.open("error",e.message||"销毁 Proxy 服务失败")}catch(e){console.error("销毁 Proxy 服务失败:",e)}},w=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_start`).then(e=>e.json());200===e.code?(t.open("success",e.message||"加载 Proxy 服务成功"),a({isEnabledStart:!0})):t.open("error",e.message||"加载 Proxy 服务失败")}catch(e){console.error("加载 Proxy 服务失败:",e)}},C=async()=>{try{let e=`dir=${decodeURIComponent(k)}&fileName=${decodeURIComponent(v)}&rootDir=${decodeURIComponent(y)}`,t=await fetch(`${b}/_fairys/_proxy?${e}`),r=await t.json();if(200===r.code){let e=r.data;Array.isArray(r.data)||(e=[]),a({proxyList:e,dir:r.dir,fileName:r.fileName,rootDir:r.rootDir})}else a({proxyList:[]})}catch(e){t.store.isServer=!1,console.error("获取缓存数据失败:",e)}};(0,o.useEffect)(()=>{C()},[]);let S=(e,t,r)=>{a({proxyList:(i.store.proxyList||[]).map((n,s)=>s===e?{...n,[t]:r}:n)})},O=async e=>{e.preventDefault();let s=!0,o="";for(let e=0;e<c.length;e++){let t=c[e];if(!t.path.trim()){s=!1,o=`代理配置 #${e+1} 的 接口地址 不能为空`;break}if(!t.target.trim()){s=!1,o=`代理配置 #${e+1} 的 目标地址 不能为空`;break}}if(!s)return void t.open("error",o);let i=new Map;for(let e=0;e<c.length;e++){let t=c[e],r=`${t.path.trim()}`;if(i.has(r)){var l;null==(l=i.get(r))||l.push(e+1)}else i.set(r,[e+1])}if(i.size>0){let e=[];for(let[t,r]of i)r.length>1&&e.push((0,n.jsxs)("div",{children:["第 ",r.join(",")," 行数据 接口地址重复;"]},t));if(e.length>0)return void t.open("error",e,5e3)}try{if(r){let e=await fetch(`${b}/_fairys/_proxy`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({proxyList:c,dir:k,fileName:v,rootDir:y})}),r=await e.json();c.length>0?a({response:JSON.stringify(r,null,2)}):200===r.code&&t.open("success","保存成功"),a({rootDir:r.rootDir})}else if(c.length>0){let e=c.reduce((e,t)=>{let{path:r,...n}={...t};return{...e,[r]:n}},{});a({response:JSON.stringify(e,null,2)})}else t.open("success","操作成功")}catch(e){a({response:"Error: "+e.message})}},_=()=>{a({currentIndex:void 0,modalBody:"",isModalOpen:!1}),document.body.style.overflow="auto"};return(0,n.jsxs)("div",{className:"space-y-6 flex-1 flex flex-col box-border overflow-hidden",children:[(0,n.jsxs)("div",{className:"mb-6 text-xs text-zinc-600 dark:text-zinc-300 box-border flex justify-between",children:[(0,n.jsxs)("div",{children:["当前配置总条数: ",c.length]}),r?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:w,className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:[j?"重启":"启动"," proxy 服务"]}),j?(0,n.jsx)("button",{type:"button",onClick:N,className:"px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"销毁 proxy 服务"}):(0,n.jsx)(o.Fragment,{})]}):(0,n.jsx)(o.Fragment,{})]}),(0,n.jsxs)("div",{className:"mb-6",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"数据保存到本地"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"根目录"}),(0,n.jsx)("input",{type:"text",value:y,onChange:e=>{a({rootDir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"目录名"}),(0,n.jsx)("input",{type:"text",value:k,onChange:e=>{a({dir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"文件名"}),(0,n.jsx)("input",{type:"text",value:v,onChange:e=>{a({fileName:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsx)("button",{type:"button",onClick:()=>C(),className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors whitespace-nowrap text-xs",children:"查询"})]}),(0,n.jsx)("p",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:"默认保存到当前工作目录的 mock 文件夹"})]}),c.length>0?(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsx)(h,{columns:[{title:"#",tdClassName:"px-2 py-2 text-xs text-zinc-800 dark:text-zinc-100 border-b border-zinc-200 dark:border-zinc-700",isIndex:!0},{title:"接口地址",dataIndex:"path",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.path,placeholder:"请使用 ^ 开头",onChange:e=>S(t,"path",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"目标地址",dataIndex:"target",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.target,onChange:e=>{S(t,"target",e.target.value||"")},className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"目标地址"})},{title:"启用 WebSocket",dataIndex:"enableWebSocket",render:(e,t)=>(0,n.jsx)("input",{type:"checkbox",checked:e.ws||!1,onChange:e=>{S(t,"ws",e.target.checked)},className:"mr-2"})},{title:"路径重写数据",dataIndex:"pathRewrite",render:e=>(0,n.jsx)("div",{className:"text-zinc-500 dark:text-zinc-400 text-xs w-[250px]",children:JSON.stringify(e.pathRewrite,null,2)})},{title:"操作",dataIndex:"operation",render:(e,t)=>(0,n.jsxs)("div",{className:"flex space-x-1",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{a({currentIndex:t,modalBody:JSON.stringify(c[t].pathRewrite,null,2),isModalOpen:!0}),document.body.style.overflow="hidden"},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"编辑路径重写数据"}),(0,n.jsx)("button",{type:"button",onClick:()=>{a({proxyList:(i.store.proxyList||[]).filter((e,r)=>r!==t)})},className:"px-2 py-0.5 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"删除"})]})}],dataSource:c})}):(0,n.jsx)("div",{className:"text-center py-8 text-zinc-500 dark:text-zinc-400",children:'暂无接口配置,请点击"添加接口配置"按钮添加'}),(0,n.jsxs)("div",{className:"flex justify-center",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{a({proxyList:[...i.store.proxyList||[]].concat([{path:"",target:""}])})},className:"px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors mr-4 text-xs",children:"添加接口配置"}),(0,n.jsx)("button",{type:"button",onClick:O,className:"px-4 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存配置"})]}),d&&(0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 flex flex-col w-full max-w-2xl max-h-[80%]",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-2",children:[(0,n.jsx)("h2",{className:"text-sm font-medium text-zinc-800 dark:text-zinc-100",children:"proxy 数据"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsx)("button",{type:"button",title:"复制",onClick:()=>{navigator.clipboard.writeText(d),t.open("success","复制成功")},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"复制"}),(0,n.jsx)("button",{type:"button",onClick:()=>a({response:""}),className:"px-2 py-0.5 bg-gray-500 text-white rounded-md hover:bg-gray-600 transition-colors text-xs",children:"关闭"})]})]}),(0,n.jsx)("pre",{className:"flex-1 overflow-auto bg-zinc-100 dark:bg-zinc-800 p-3 rounded-md overflow-x-auto text-xs text-zinc-800 dark:text-zinc-100",children:d})]})}),x&&null!==u&&(null==c?void 0:c[u])&&(0,g.createPortal)((0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 w-full max-w-2xl",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-3",children:[(0,n.jsxs)("h2",{className:"text-sm font-medium text-zinc-700 dark:text-zinc-300",children:["编辑响应体数据 - 接口配置 #",u+1]}),(0,n.jsx)("button",{type:"button",onClick:_,className:"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200",children:"\xd7"})]}),(0,n.jsx)("div",{className:"space-y-3",children:(0,n.jsxs)("div",{children:[(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["路径重写 JSON ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]}),(0,n.jsx)(f,{value:p,onChange:e=>a({modalBody:e}),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white min-h-[300px] text-xs",placeholder:'例如: { "^/api":"" , "^/api/test":"/api" }'})]})}),(0,n.jsxs)("div",{className:"flex justify-end space-x-2 mt-3 box-border",children:[(0,n.jsx)("button",{type:"button",onClick:_,className:"px-3 py-1 border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200 rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-600 transition-colors text-xs",children:"取消"}),(0,n.jsx)("button",{type:"button",onClick:()=>{if(null!==u)try{let e=Function("return "+p)();S(u,"pathRewrite",e),_()}catch(e){t.open("error","JSON 格式错误,请检查输入")}},className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存"})]})]})}),document.body)]})}let v={success:"text-green-500",info:"text-blue-500",error:"text-red-500",warning:"text-orange-500"},j={info:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"info-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"})})}),success:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"check-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"})})}),error:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{fillRule:"evenodd",viewBox:"64 64 896 896",focusable:"false","data-icon":"close-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"})})}),warning:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"exclamation-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"})})})},z=document.getElementById("root");z&&s.createRoot(z).render((0,n.jsxs)(u,{children:[(0,n.jsx)(function(){let{state:e,dispatch:t}=m(),[r,s]=(0,o.useState)({mock:!0,proxy:!1}),a=e.tabKey,i=e=>{s(t=>({...t,[e]:!0})),t({tabKey:e})};return(0,n.jsx)("div",{className:"h-full bg-zinc-50 dark:bg-black p-4 sm:p-6 box-border overflow-hidden flex flex-col",children:(0,n.jsxs)("div",{className:"flex-1 w-full bg-white dark:bg-zinc-900 rounded-lg shadow-md p-6 box-border flex flex-col overflow-hidden",children:[(0,n.jsxs)("div",{className:"flex border-b border-zinc-200 dark:border-zinc-700 mb-6",children:[(0,n.jsx)("button",{className:`px-4 py-2 text-xs font-medium transition-colors ${"mock"===a?"border-b-2 border-blue-500 text-blue-600 dark:text-blue-400":"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,onClick:()=>i("mock"),children:"Mocker 数据配置"}),(0,n.jsx)("button",{className:`px-4 py-2 text-xs font-medium transition-colors ${"proxy"===a?"border-b-2 border-blue-500 text-blue-600 dark:text-blue-400":"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,onClick:()=>i("proxy"),children:"代理配置"})]}),(0,n.jsxs)("div",{className:"flex-1 relative overflow-hidden",children:[r.mock&&(0,n.jsx)("div",{className:`absolute inset-0 flex flex-col box-border overflow-hidden transition-all duration-300 ease-in-out ${"mock"===a?"opacity-100 translate-x-0":"opacity-0 translate-x-4 pointer-events-none"}`,children:(0,n.jsx)(y,{})}),r.proxy&&(0,n.jsx)("div",{className:`absolute inset-0 flex flex-col box-border overflow-hidden transition-all duration-300 ease-in-out ${"proxy"===a?"opacity-100 translate-x-0":"opacity-0 translate-x-4 pointer-events-none"}`,children:(0,n.jsx)(k,{})})]})]})})},{}),(0,n.jsx)(()=>{let{state:e}=m(),t=e.messageList;return Array.isArray(t)&&t.length?(0,n.jsx)("div",{className:"fixed inset-0 flex flex-col items-center z-90 gap-2 py-2 box-border pointer-events-none",children:t.map(e=>{let t=j[e.type],r=v[e.type];return(0,n.jsxs)("div",{className:"shadow-md py-2 px-4 box-border rounded-lg bg-white text-xs flex items-center gap-2 flex-wrap",children:[t?(0,n.jsx)(t,{className:r}):(0,n.jsx)(n.Fragment,{}),(0,n.jsx)("div",{children:e.message})]},e.id)})}):(0,n.jsx)(n.Fragment,{})},{})]}))}},o={};function a(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return s[e].call(r.exports,r,r.exports,a),r.exports}a.m=s,a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e=[],a.O=(t,r,n,s)=>{if(r){s=s||0;for(var o=e.length;o>0&&e[o-1][2]>s;o--)e[o]=e[o-1];e[o]=[r,n,s];return}for(var i=1/0,o=0;o<e.length;o++){for(var[r,n,s]=e[o],l=!0,c=0;c<r.length;c++)(!1&s||i>=s)&&Object.keys(a.O).every(e=>a.O[e](r[c]))?r.splice(c--,1):(l=!1,s<i&&(i=s));if(l){e.splice(o--,1);var d=n();void 0!==d&&(t=d)}}return t},t={410:0},a.O.j=e=>0===t[e],r=(e,r)=>{var n,s,[o,i,l]=r,c=0;if(o.some(e=>0!==t[e])){for(n in i)a.o(i,n)&&(a.m[n]=i[n]);if(l)var d=l(a)}for(e&&e(r);c<o.length;c++)s=o[c],a.o(t,s)&&t[s]&&t[s][0](),t[s]=0;return a.O(d)},(n=self.webpackChunk_fairys_mocker_ui=self.webpackChunk_fairys_mocker_ui||[]).forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n));var i=a.O(void 0,["783","514"],()=>a(711));i=a.O(i)})();
|
package/src/base.ts
CHANGED
|
@@ -28,7 +28,6 @@ export class FairysMockerBase {
|
|
|
28
28
|
mainApp: express.Express | connect.Server | undefined = undefined;
|
|
29
29
|
/**类*/
|
|
30
30
|
controller: ClassStruct[] = [MockRouterController, ProxyRouterController];
|
|
31
|
-
|
|
32
31
|
/**静态文件服务列表*/
|
|
33
32
|
staticServerList: string[] = [];
|
|
34
33
|
|
|
@@ -38,9 +37,12 @@ export class FairysMockerBase {
|
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
39
|
if (fs.existsSync(dir)) {
|
|
41
|
-
|
|
40
|
+
let _prefix = prefix;
|
|
41
|
+
if (!/^\//.test(prefix)) {
|
|
42
|
+
_prefix = "/" + prefix
|
|
43
|
+
}
|
|
42
44
|
this.app.use(_prefix, express.static(dir));
|
|
43
|
-
// console.log(chalk.green(`静态文件服务:${dir}`))
|
|
45
|
+
// console.log(chalk.green(`静态文件服务:${_prefix}\t${dir}`))
|
|
44
46
|
if (isRegister) {
|
|
45
47
|
this.staticServerList.push(_prefix)
|
|
46
48
|
}
|
package/src/ci.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import parser, { Arguments } from 'yargs-parser'
|
|
2
|
-
import { fairysMockerExpress } from "./main.js"
|
|
3
|
-
import { fairysMockerConnect } from "./connect.js"
|
|
4
|
-
import {
|
|
2
|
+
import { fairysMockerExpress, FairysMockerExpress } from "./main.js"
|
|
3
|
+
import { fairysMockerConnect, FairysMockerConnect } from "./connect.js"
|
|
4
|
+
import { utilsGlobalVariable } from "./utils/utils.js"
|
|
5
5
|
|
|
6
6
|
function help() {
|
|
7
|
-
console.log('\n Usage: \x1b[34;1fairys-mocker\x1b[0m [--help|h|--root|--dir|--file|--file2|--static|--static-prefix]');
|
|
7
|
+
console.log('\n Usage: \x1b[34;1fairys-mocker\x1b[0m [--help|h|--root|--dir|--file|--file2|--static|--static-prefix|--is-mock-file|--is-proxy-file]');
|
|
8
8
|
console.log('\n Displays help information.');
|
|
9
9
|
console.log('\n Options:\n');
|
|
10
10
|
console.log(' --root ', '设置根目录路径(默认取环境变量中的`FAIRYS_MOCKER_ROOT_DIR`).');
|
|
@@ -13,6 +13,9 @@ function help() {
|
|
|
13
13
|
console.log(' --file2 ', '设置文件名2(默认取环境变量中的`FAIRYS_MOCKER_PROXY_FILE`).');
|
|
14
14
|
console.log(' --static ', '设置静态文件服务目录.');
|
|
15
15
|
console.log(' --static-prefix ', '设置静态文件服务目录访问前缀.');
|
|
16
|
+
console.log(' --is-mock-file ', '是否生成mock数据文件,默认生成.');
|
|
17
|
+
console.log(' --is-proxy-file ', '是否生成proxy数据文件,默认生成.');
|
|
18
|
+
console.log(' --is-connect ', '是否是connect服务.默认express.');
|
|
16
19
|
|
|
17
20
|
console.log('\n Example:\n');
|
|
18
21
|
console.log(' $ \x1b[35mfairys-mocker\x1b[0m --dir mock2');
|
|
@@ -21,41 +24,36 @@ function help() {
|
|
|
21
24
|
|
|
22
25
|
const argv: Partial<Arguments> = parser(process.argv.slice(2), {
|
|
23
26
|
string: ["root", 'dir', 'file', 'file2', 'static', 'static-prefix'],
|
|
27
|
+
boolean: ['is-mock-file', "is-proxy-file", 'is-connect']
|
|
24
28
|
})
|
|
25
29
|
|
|
26
|
-
export const
|
|
30
|
+
export const CI = (app: FairysMockerExpress | FairysMockerConnect) => {
|
|
27
31
|
if (argv.help | argv.h) {
|
|
28
32
|
help();
|
|
29
33
|
return;
|
|
30
34
|
} else {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
utilsGlobalVariable.setRootDir(argv.root);
|
|
36
|
+
utilsGlobalVariable.setDir(argv.dir);
|
|
37
|
+
utilsGlobalVariable.setFile(argv.file);
|
|
38
|
+
utilsGlobalVariable.setProxyFile(argv.file2);
|
|
39
|
+
utilsGlobalVariable.setIsCreateMockDataFile(argv['is-mock-file'])
|
|
40
|
+
utilsGlobalVariable.setIsCreateProxyDataFile(argv['is-proxy-file'])
|
|
35
41
|
// 1. 直接当 mock 服务,
|
|
36
42
|
// 2. 生成 mock 数据
|
|
37
43
|
// 3. mock 服务 + 数据
|
|
38
|
-
|
|
39
|
-
if (argv.static) {
|
|
40
|
-
|
|
44
|
+
app.start(() => {
|
|
45
|
+
if (!argv.static) {
|
|
46
|
+
return;
|
|
41
47
|
}
|
|
48
|
+
app.staticServer(argv.static, argv['static-prefix']);
|
|
42
49
|
});
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
export const
|
|
47
|
-
if (argv
|
|
48
|
-
|
|
49
|
-
return;
|
|
53
|
+
export const runCli = () => {
|
|
54
|
+
if (argv['is-connect']) {
|
|
55
|
+
CI(fairysMockerConnect)
|
|
50
56
|
} else {
|
|
51
|
-
|
|
52
|
-
utils.setDir(argv.dir);
|
|
53
|
-
utils.setFile(argv.file);
|
|
54
|
-
utils.setProxyFile(argv.file2);
|
|
55
|
-
fairysMockerConnect.start(() => {
|
|
56
|
-
if (argv.static) {
|
|
57
|
-
fairysMockerConnect.staticServer(argv.static, argv['static-prefix']);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
57
|
+
CI(fairysMockerExpress)
|
|
60
58
|
}
|
|
61
|
-
}
|
|
59
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { Get, Post, Controller } from "../utils/decorator.js"
|
|
4
|
-
import {
|
|
4
|
+
import { utilsGlobalVariable } from "../utils/index.js"
|
|
5
5
|
import { MockRouter } from "../router/mock.js"
|
|
6
6
|
import { BaseController } from "./base.js"
|
|
7
7
|
import { getMcokFile, createMockFile } from '../utils/mcok.proxy.js';
|
|
@@ -23,9 +23,9 @@ export class MockRouterController extends BaseController {
|
|
|
23
23
|
// 定义接口
|
|
24
24
|
try {
|
|
25
25
|
const { mockList, dir, fileName = 'index.mock', rootDir } = req.body;
|
|
26
|
-
let _rootDir = rootDir ||
|
|
26
|
+
let _rootDir = rootDir || utilsGlobalVariable.rootDir;
|
|
27
27
|
if (rootDir && !fs.existsSync(rootDir)) {
|
|
28
|
-
_rootDir =
|
|
28
|
+
_rootDir = utilsGlobalVariable.rootDir;
|
|
29
29
|
}
|
|
30
30
|
const mockData = createMockFile(mockList, _rootDir, dir, fileName)
|
|
31
31
|
if (mockData?.mockConfig) {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import nodePath from "node:path"
|
|
4
|
-
import { createProxyData } from '@fairys/create-mock-data';
|
|
5
3
|
import { Get, Post, Controller } from "../utils/decorator.js"
|
|
6
|
-
import {
|
|
4
|
+
import { utilsGlobalVariable } from "../utils/utils.js"
|
|
7
5
|
import { ProxyRouter } from '../router/proxy.js';
|
|
8
6
|
import { BaseController } from './base.js';
|
|
9
7
|
import { getProxyFile, createProxyFile } from '../utils/mcok.proxy.js';
|
|
@@ -24,9 +22,9 @@ export class ProxyRouterController extends BaseController {
|
|
|
24
22
|
post_proxy(req: express.Request, res: express.Response) {
|
|
25
23
|
try {
|
|
26
24
|
const { proxyList, dir, fileName = 'proxy', rootDir } = req.body;
|
|
27
|
-
let _rootDir = rootDir ||
|
|
25
|
+
let _rootDir = rootDir || utilsGlobalVariable.rootDir;
|
|
28
26
|
if (rootDir && !fs.existsSync(rootDir)) {
|
|
29
|
-
_rootDir =
|
|
27
|
+
_rootDir = utilsGlobalVariable.rootDir;
|
|
30
28
|
}
|
|
31
29
|
const proxyData = createProxyFile(proxyList, _rootDir, dir, fileName)
|
|
32
30
|
if (proxyData?.proxyConfig) {
|
|
@@ -110,9 +108,10 @@ export class ProxyRouterController extends BaseController {
|
|
|
110
108
|
const proxyData = getProxyFile(rootDir, savePath, saveFileName);
|
|
111
109
|
if (proxyData?.proxyList) {
|
|
112
110
|
this.router?.load(proxyData.proxyList);
|
|
111
|
+
const msg = utilsGlobalVariable.isEnableWebsocket ? '启动代理服务成功' : '非websocket服务代理启动成功'
|
|
113
112
|
res.json({
|
|
114
113
|
code: 200,
|
|
115
|
-
message:
|
|
114
|
+
message: msg,
|
|
116
115
|
data: proxyData.proxyList,
|
|
117
116
|
rootDir: rootDir,
|
|
118
117
|
dir: proxyData.dir,
|
package/src/plugins/rsbuild.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { RsbuildPlugin } from '@rsbuild/core';
|
|
2
2
|
import { fairysMockerBase } from '../base.js';
|
|
3
|
+
import { utilsGlobalVariable } from '../utils/utils.js';
|
|
3
4
|
|
|
4
5
|
export const fairysMockerRsbuildPlugin = () => ({
|
|
5
6
|
setup(api) {
|
|
6
7
|
api.onBeforeStartDevServer(({ server }) => {
|
|
7
8
|
fairysMockerBase.initApp(server.middlewares, () => {
|
|
8
9
|
fairysMockerBase.logServer(server.port);
|
|
10
|
+
// rsbuild/vite等自带websocket服务的环境下无法使用websocket服务
|
|
11
|
+
utilsGlobalVariable.isEnableWebsocket = false;
|
|
9
12
|
});
|
|
10
13
|
// @ts-ignore
|
|
11
14
|
fairysMockerBase.server = server.httpServer
|
package/src/router/proxy.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { BaseRouter } from "./base.js"
|
|
|
4
4
|
import { createProxyMiddleware, RequestHandler } from "http-proxy-middleware"
|
|
5
5
|
import chalk from "chalk"
|
|
6
6
|
import { fairysMockerBase } from "../base.js"
|
|
7
|
+
import { utilsGlobalVariable } from "../utils/utils.js"
|
|
7
8
|
|
|
8
9
|
/**代理 路由器实例*/
|
|
9
10
|
export class ProxyRouter extends BaseRouter<ProxyItem> {
|
|
@@ -39,18 +40,21 @@ export class ProxyRouter extends BaseRouter<ProxyItem> {
|
|
|
39
40
|
_path = new RegExp('^' + proxyItem.path)
|
|
40
41
|
}
|
|
41
42
|
if (proxyItem.ws) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
if (utilsGlobalVariable.isEnableWebsocket) {
|
|
44
|
+
const wsProxy = createProxyMiddleware({
|
|
45
|
+
target: proxyItem.target,
|
|
46
|
+
pathRewrite: proxyItem.pathRewrite,
|
|
47
|
+
ws: proxyItem.ws,
|
|
48
|
+
changeOrigin: true,
|
|
49
|
+
})
|
|
50
|
+
_that.wsProxyList.push(wsProxy)
|
|
51
|
+
router.all(_path, wsProxy)
|
|
52
|
+
if (fairysMockerBase.server) {
|
|
53
|
+
// 升级 WebSocket 处理
|
|
54
|
+
fairysMockerBase.server?.on('upgrade', wsProxy.upgrade)
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
console.log(chalk.red(`rsbuild/vite等自带websocket服务的环境下无法代理websocket服务:${proxyItem.path}`))
|
|
54
58
|
}
|
|
55
59
|
} else {
|
|
56
60
|
// 这个不生效问题
|
package/src/utils/mcok.proxy.ts
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
/**保存配置和读取配置*/
|
|
3
3
|
import nodePath from "node:path"
|
|
4
4
|
import fs from 'node:fs';
|
|
5
|
-
import {
|
|
5
|
+
import { utilsGlobalVariable } from "./utils.js";
|
|
6
6
|
import { createProxyData, createMockData, ProxyList, DefineMockList } from "@fairys/create-mock-data";
|
|
7
7
|
|
|
8
8
|
export const getProxyFile = (rootDir?: string, dir?: string, fileName?: string) => {
|
|
9
|
-
const _rootDir = rootDir?.trim() ||
|
|
10
|
-
const _dir = dir?.trim() ||
|
|
11
|
-
const _fileName = fileName?.trim() ||
|
|
9
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
10
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
11
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.proxyFile;
|
|
12
12
|
// 读取 .cache.json 文件
|
|
13
13
|
const proxyDir = nodePath.join(_rootDir, _dir);
|
|
14
14
|
const cacheFilePath = nodePath.join(proxyDir, _fileName + '.cache.json');
|
|
@@ -28,9 +28,9 @@ export const getProxyFile = (rootDir?: string, dir?: string, fileName?: string)
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export const createProxyFile = (proxyList: ProxyList, rootDir?: string, dir?: string, fileName?: string) => {
|
|
31
|
-
const _rootDir = rootDir?.trim() ||
|
|
32
|
-
const _dir = dir?.trim() ||
|
|
33
|
-
const _fileName = fileName?.trim() ||
|
|
31
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
32
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
33
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.proxyFile;
|
|
34
34
|
// 读取 .cache.json 文件
|
|
35
35
|
const proxyDir = nodePath.join(_rootDir, _dir);
|
|
36
36
|
|
|
@@ -38,9 +38,9 @@ export const createProxyFile = (proxyList: ProxyList, rootDir?: string, dir?: st
|
|
|
38
38
|
fs.mkdirSync(proxyDir, { recursive: true });
|
|
39
39
|
}
|
|
40
40
|
const proxyConfig = createProxyData(proxyList)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (utilsGlobalVariable.isCreateProxyDataFile) {
|
|
42
|
+
const proxyFilePath = nodePath.join(proxyDir, `${_fileName}.ts`);
|
|
43
|
+
const proxyFileContent = `// 代理配置文件
|
|
44
44
|
// 自动生成于 ${new Date().toISOString()}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -58,10 +58,11 @@ export type ProxyItem = Record<string,{
|
|
|
58
58
|
export const proxyConfig: ProxyItem = ${JSON.stringify(proxyConfig, null, 2)};
|
|
59
59
|
export default proxyConfig;
|
|
60
60
|
`;
|
|
61
|
-
|
|
61
|
+
fs.writeFileSync(proxyFilePath, proxyFileContent);
|
|
62
|
+
}
|
|
63
|
+
|
|
62
64
|
// 存储原始的 proxyConfig 到 .cache.json 文件
|
|
63
65
|
const cacheFilePath = nodePath.join(proxyDir, _fileName + '.cache.json');
|
|
64
|
-
|
|
65
66
|
const cacheFileContent = JSON.stringify({
|
|
66
67
|
proxyList,
|
|
67
68
|
rootDir: _rootDir,
|
|
@@ -81,9 +82,9 @@ export default proxyConfig;
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
export const getMcokFile = (rootDir?: string, dir?: string, fileName?: string) => {
|
|
84
|
-
const _rootDir = rootDir?.trim() ||
|
|
85
|
-
const _dir = dir?.trim() ||
|
|
86
|
-
const _fileName = fileName?.trim() ||
|
|
85
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
86
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
87
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.file;
|
|
87
88
|
// 读取 .cache.json 文件
|
|
88
89
|
const mockDir = nodePath.join(_rootDir, _dir);
|
|
89
90
|
const cacheFilePath = nodePath.join(mockDir, _fileName + '.cache.json');
|
|
@@ -103,9 +104,9 @@ export const getMcokFile = (rootDir?: string, dir?: string, fileName?: string) =
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
export const createMockFile = (mockList: DefineMockList, rootDir?: string, dir?: string, fileName?: string) => {
|
|
106
|
-
const _rootDir = rootDir?.trim() ||
|
|
107
|
-
const _dir = dir?.trim() ||
|
|
108
|
-
const _fileName = fileName?.trim() ||
|
|
107
|
+
const _rootDir = rootDir?.trim() || utilsGlobalVariable.rootDir;
|
|
108
|
+
const _dir = dir?.trim() || utilsGlobalVariable.dir;
|
|
109
|
+
const _fileName = fileName?.trim() || utilsGlobalVariable.file;
|
|
109
110
|
// 读取 .cache.json 文件
|
|
110
111
|
const mockDir = nodePath.join(_rootDir, _dir);
|
|
111
112
|
|
|
@@ -113,9 +114,9 @@ export const createMockFile = (mockList: DefineMockList, rootDir?: string, dir?:
|
|
|
113
114
|
fs.mkdirSync(mockDir, { recursive: true });
|
|
114
115
|
}
|
|
115
116
|
const mockConfig = createMockData(mockList)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
if (utilsGlobalVariable.isCreateMockDataFile) {
|
|
118
|
+
const mockFilePath = nodePath.join(mockDir, `${_fileName}.ts`);
|
|
119
|
+
const mockFileContent = `// Mock 配置文件
|
|
119
120
|
// 自动生成于 ${new Date().toISOString()}
|
|
120
121
|
|
|
121
122
|
export interface MockerItem {
|
|
@@ -139,7 +140,9 @@ export type DefineMockList = MockerItem[];
|
|
|
139
140
|
export const mockList: DefineMockList = ${JSON.stringify(mockConfig, null, 2)};
|
|
140
141
|
export default mockList;
|
|
141
142
|
`;
|
|
142
|
-
|
|
143
|
+
fs.writeFileSync(mockFilePath, mockFileContent);
|
|
144
|
+
}
|
|
145
|
+
|
|
143
146
|
// 存储原始的 mockConfig 到 .cache.json 文件
|
|
144
147
|
const cacheFilePath = nodePath.join(mockDir, _fileName + '.cache.json');
|
|
145
148
|
|
package/src/utils/utils.ts
CHANGED
|
@@ -3,7 +3,7 @@ import chalk from 'chalk';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from "node:path"
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class UtilsGlobalVariable {
|
|
7
7
|
/**根目录*/
|
|
8
8
|
public rootDir = process.cwd();
|
|
9
9
|
/**目录名*/
|
|
@@ -12,6 +12,12 @@ class Utils {
|
|
|
12
12
|
public file = 'index.mock';
|
|
13
13
|
/**代理文件名*/
|
|
14
14
|
public proxyFile = 'proxy';
|
|
15
|
+
/**是否生成mock数据文件*/
|
|
16
|
+
public isCreateMockDataFile = true;
|
|
17
|
+
/**是否生成proxy数据文件*/
|
|
18
|
+
public isCreateProxyDataFile = true;
|
|
19
|
+
/**是否可以启用 websocket 服务(在rsbuild/vite等自带websocket服务的环境下无法使用)*/
|
|
20
|
+
public isEnableWebsocket: boolean = true;
|
|
15
21
|
|
|
16
22
|
/**设置根目录*/
|
|
17
23
|
setRootDir = (value?: string) => {
|
|
@@ -41,6 +47,20 @@ class Utils {
|
|
|
41
47
|
setProxyFile = (value?: string) => {
|
|
42
48
|
this.proxyFile = value || process.env.FAIRYS_MOCKER_PROXY_FILE || 'proxy';
|
|
43
49
|
}
|
|
50
|
+
|
|
51
|
+
/**设置 是否生成mock数据文件*/
|
|
52
|
+
setIsCreateMockDataFile = (fig?: boolean) => {
|
|
53
|
+
if (typeof fig === "boolean") {
|
|
54
|
+
this.isCreateMockDataFile = fig
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**设置 是否生成proxy数据文件*/
|
|
59
|
+
setIsCreateProxyDataFile = (fig?: boolean) => {
|
|
60
|
+
if (typeof fig === "boolean") {
|
|
61
|
+
this.isCreateProxyDataFile = fig
|
|
62
|
+
}
|
|
63
|
+
}
|
|
44
64
|
}
|
|
45
65
|
|
|
46
|
-
export const
|
|
66
|
+
export const utilsGlobalVariable = new UtilsGlobalVariable()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(()=>{"use strict";var e,t,r,n,s={711(e,t,r){var n=r(85),s=r(873),o=r(41),i=r(424),a=r.n(i),l=r(346),c=r(990);class d extends l.ProxyInstanceObject{constructor(...e){var t;super(...e),t=this,(0,c._)(this,"open",function(e,r){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3e3,s=new Date().valueOf().toString();t.store.messageList.push((0,l.ref)({type:e,message:r,id:s}));let o=setTimeout(()=>{t.store.messageList=t.store.messageList.filter(e=>e.id!==s),clearTimeout(o)},n)})}}let x=new d()._ctor({tabKey:"mock",messageList:[],isServer:!0}),{MainProxyProvider:u,useMainProxyStore:m}=(0,l.createCommonMainStore)({proxyInstance:x,namespace:"global"}),b=window.location.origin;function h(e){let{columns:t,dataSource:r,rowKey:s}=e,i=(0,o.useMemo)(()=>(0,n.jsx)("tr",{className:"bg-zinc-100 dark:bg-zinc-800 sticky -top-px z-10",children:t.map((e,t)=>(0,n.jsx)("th",{className:"px-2 py-2 text-left text-xs font-medium text-zinc-700 dark:text-zinc-300 border-b border-zinc-200 dark:border-zinc-700",children:e.title},e.dataIndex||t))}),[t]);return(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsxs)("table",{className:"border-collapse min-w-full border border-zinc-200 dark:border-zinc-700 relative",children:[(0,n.jsx)("thead",{children:i}),(0,n.jsx)("tbody",{children:r.map((e,r)=>{let o="function"==typeof s?s(e):s?e[s]:r;return(0,n.jsx)("tr",{className:"hover:bg-zinc-50 dark:hover:bg-zinc-800",children:t.map(t=>{let s=t.dataIndex?e[t.dataIndex]:e;if(t.isIndex&&(s=r+1),t.render){var i;s=null==(i=t.render)?void 0:i.call(t,e,r)}return(0,n.jsx)("td",{className:`px-2 py-2 border-b border-zinc-200 dark:border-zinc-700 ${t.tdClassName||""}`,children:s},`${o}-${t.dataIndex}`)})},o)})})]})})}var p=r(224);let f=e=>{let{value:t,onChange:r,placeholder:s,className:o}=e;return(0,n.jsx)(p.A,{value:t,language:"json",placeholder:s,onChange:e=>null==r?void 0:r(e.target.value),padding:15,className:o,style:{fontFamily:"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",minHeight:280}})};var g=r(144);function y(){let{state:e,proxyInstance:t}=m(),r=e.isServer,{state:s,dispatch:i,proxyInstance:c}=(0,l.useProxyStore)({rootDir:"",dir:"mock",fileName:"index.mock",mockList:[],response:"",isModalOpen:!1,currentIndex:null,modalBody:"",isEnabledStart:!1},{sync:!0}),d=s.mockList,x=s.response,u=s.isModalOpen,p=s.currentIndex,y=s.modalBody,k=s.rootDir,v=s.dir,j=s.fileName,z=s.isEnabledStart,N=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_is_enabled`).then(e=>e.json());200===e.code&&i({isEnabledStart:e.data})}catch(e){console.error("检查 mock 配置服务是否启用失败:",e)}};(0,o.useEffect)(()=>{N()},[]);let w=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_destroy`).then(e=>e.json());200===e.code?(i({isEnabledStart:!1}),t.open("success","销毁 Mock 数据服务成功")):t.open("error",e.message||"销毁 Mock 数据服务失败")}catch(e){console.error("销毁 mock 数据服务失败:",e)}},C=async()=>{try{let e=await fetch(`${b}/_fairys/_mock/_start`).then(e=>e.json());200===e.code?(t.open("success","加载 Mock 数据服务成功"),i({isEnabledStart:!0})):t.open("error",e.message||"加载 Mock 数据服务失败")}catch(e){console.error("加载 mock 数据服务失败:",e)}},S=async e=>{try{let t;if(!0===e)t=await fetch(`${b}/_fairys/_mock`);else{let e=`dir=${decodeURIComponent(v)}&fileName=${decodeURIComponent(j)}&rootDir=${decodeURIComponent(k)}`;t=await fetch(`${b}/_fairys/_mock?${e}`)}let r=await t.json();200===r.code?i({mockList:r.data,dir:r.dir,fileName:r.fileName,rootDir:r.rootDir}):i({mockList:[]})}catch(e){t.store.isServer=!1,console.error("获取缓存数据失败:",e)}};(0,o.useEffect)(()=>{S(!0)},[]);let O=(e,t,r)=>{i({mockList:(c.store.mockList||[]).map((n,s)=>s===e?{...n,[t]:r}:n)})},_=async e=>{e.preventDefault();let s=!0,o="";for(let e=0;e<d.length;e++){let t=d[e];if(!t.url.trim()){s=!1,o=`接口配置 #${e+1} 的 接口地址 不能为空`;break}if(!t.method){s=!1,o=`接口配置 #${e+1} 的 请求方法 不能为空`;break}if(!t.status.trim()){s=!1,o=`接口配置 #${e+1} 的 状态码 不能为空`;break}if(!t.body){s=!1,o=`接口配置 #${e+1} 的 响应体 不能为空`;break}}if(!s)return void t.open("error",o);let l=new Map;for(let e=0;e<d.length;e++){let t=d[e],r=`${t.url.trim()}:${t.method}`;if(l.has(r)){var c;null==(c=l.get(r))||c.push(e+1)}else l.set(r,[e+1])}if(l.size>0){let e=[];for(let[t,r]of l)r.length>1&&e.push((0,n.jsxs)("div",{children:["第 ",r.join(",")," 行数据 接口地址和请求方法 组合重复;"]},t));if(e.length>0)return void t.open("error",e,5e3)}try{if(r){let e=await fetch(`${b}/_fairys/_mock`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mockList:d,dir:v,fileName:j,rootDir:k})}),r=await e.json();d.length>0?i({response:JSON.stringify(r,null,2)}):200===r.code&&t.open("success","保存成功"),i({rootDir:r.rootDir})}else if(d.length>0){let e=d.map(e=>(function(e){let{data:t,...r}={...e.body},n={},s=Object.keys(t),o=e.listCount||20;for(let e=0;e<s.length;e++){let r=s[e],i=t[r];if(/^(\_\|)/.test(r)){let[e,t,s]=r.split("|"),l=`${s||""}`.trim();i&&(n[t]=Array.from({length:l?Number(l):o},()=>a().mock(i)))}else Object.assign(n,a().mock({[r]:i}))}r.data=n;let i=0;if(Array.isArray(e.delay)){let[t,r]=e.delay;i=Math.floor(Math.random()*(r-t+1))+t}else i=e.delay;return{...e,body:r,delay:i}})(e));i({response:JSON.stringify(e,null,2)})}else t.open("success","操作成功")}catch(e){i({response:"Error: "+e.message})}},I=()=>{i({currentIndex:void 0,modalBody:"",isModalOpen:!1}),document.body.style.overflow="auto"};return(0,n.jsxs)("div",{className:"space-y-6 flex-1 flex flex-col box-border overflow-hidden",children:[(0,n.jsxs)("div",{className:"mb-6 text-xs text-zinc-600 dark:text-zinc-300 box-border flex justify-between",children:[(0,n.jsxs)("div",{children:["当前配置总条数: ",d.length]}),r?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:C,className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:[z?"重启":"启动"," mock 数据服务"]}),z?(0,n.jsx)("button",{type:"button",onClick:w,className:"px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"销毁 mock 数据服务"}):(0,n.jsx)(o.Fragment,{})]}):(0,n.jsx)(o.Fragment,{})]}),(0,n.jsxs)("div",{className:"mb-6",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"数据保存到本地"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"根目录"}),(0,n.jsx)("input",{type:"text",value:k,onChange:e=>{i({rootDir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"目录名"}),(0,n.jsx)("input",{type:"text",value:v,onChange:e=>{i({dir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"文件名"}),(0,n.jsx)("input",{type:"text",value:j,onChange:e=>{i({fileName:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsx)("button",{type:"button",onClick:()=>S(!1),className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors whitespace-nowrap text-xs",children:"查询"})]}),(0,n.jsx)("p",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:"默认保存到当前工作目录的 mock 文件夹"})]}),d.length>0?(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsx)(h,{columns:[{title:"#",isIndex:!0,tdClassName:"px-2 py-2 text-xs text-zinc-800 dark:text-zinc-100 border-b border-zinc-200 dark:border-zinc-700"},{title:"接口地址",dataIndex:"url",render:(e,t)=>(0,n.jsx)("input",{type:"text",placeholder:"请输入接口地址",value:e.url,onChange:e=>O(t,"url",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"请求方法",dataIndex:"method",render:(e,t)=>(0,n.jsxs)("select",{value:e.method,onChange:e=>O(t,"method",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",children:[(0,n.jsx)("option",{value:"GET",children:"GET"}),(0,n.jsx)("option",{value:"POST",children:"POST"}),(0,n.jsx)("option",{value:"PUT",children:"PUT"}),(0,n.jsx)("option",{value:"DELETE",children:"DELETE"}),(0,n.jsx)("option",{value:"PATCH",children:"PATCH"}),(0,n.jsx)("option",{value:"HEAD",children:"HEAD"}),(0,n.jsx)("option",{value:"OPTIONS",children:"OPTIONS"})]})},{title:"状态码",dataIndex:"status",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.status,onChange:e=>O(t,"status",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"例如: 200, 400, 500"})},{title:"响应延迟时间(ms)",dataIndex:"delay",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:Array.isArray(e.delay)?`${e.delay[0]},${e.delay[1]}`:e.delay||"",onChange:e=>{let r=e.target.value;if(r.includes(",")){let[e,n]=r.split(",").map(Number);O(t,"delay",[e,n])}else O(t,"delay",parseInt(r)||0)},className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"例如: 1000 或 500,2000"})},{title:"生成数据条数",dataIndex:"listCount",render:(e,t)=>(0,n.jsx)("input",{type:"number",value:e.listCount,onChange:e=>O(t,"listCount",parseInt(e.target.value)||1),min:"1",max:"100",className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"响应体数据",dataIndex:"body",render:e=>(0,n.jsx)("div",{className:"text-zinc-500 dark:text-zinc-400 text-xs w-[400px]",children:JSON.stringify(e.body,null,2)})},{title:"操作",dataIndex:"operation",render:(e,t)=>(0,n.jsxs)("div",{className:"flex space-x-1",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{i({currentIndex:t,modalBody:JSON.stringify(d[t].body,null,2),isModalOpen:!0}),document.body.style.overflow="hidden"},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"编辑响应体数据"}),(0,n.jsx)("button",{type:"button",onClick:()=>{i({mockList:(c.store.mockList||[]).filter((e,r)=>r!==t)})},className:"px-2 py-0.5 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"删除"})]})}],dataSource:d})}):(0,n.jsx)("div",{className:"text-center py-8 text-zinc-500 dark:text-zinc-400",children:'暂无接口配置,请点击"添加接口配置"按钮添加'}),(0,n.jsxs)("div",{className:"flex justify-center",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{i({mockList:[...c.store.mockList||[]].concat([{url:"",method:"POST",status:"200",delay:0,body:{code:200,data:{id:"@id",name:"@name",email:"@email"},message:"success"},listCount:20}])})},className:"px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors mr-4 text-xs",children:"添加接口配置"}),(0,n.jsx)("button",{type:"button",onClick:_,className:"px-4 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存配置"})]}),x&&(0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 flex flex-col w-full max-w-2xl max-h-[80%]",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-2",children:[(0,n.jsx)("h2",{className:"text-sm font-medium text-zinc-800 dark:text-zinc-100",children:"mock 数据"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsx)("button",{type:"button",title:"复制",onClick:()=>{navigator.clipboard.writeText(x),t.open("success","复制成功")},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"复制"}),(0,n.jsx)("button",{type:"button",onClick:()=>i({response:""}),className:"px-2 py-0.5 bg-gray-500 text-white rounded-md hover:bg-gray-600 transition-colors text-xs",children:"关闭"})]})]}),(0,n.jsx)("pre",{className:"flex-1 overflow-auto bg-zinc-100 dark:bg-zinc-800 p-3 rounded-md overflow-x-auto text-xs text-zinc-800 dark:text-zinc-100",children:x})]})}),u&&null!==p&&(null==d?void 0:d[p])&&(0,g.createPortal)((0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50 box-border",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 w-full max-w-2xl box-border",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-3 box-border",children:[(0,n.jsxs)("h2",{className:"text-sm font-medium text-zinc-700 dark:text-zinc-300",children:["编辑响应体数据 - 接口配置 #",p+1]}),(0,n.jsx)("button",{type:"button",onClick:I,className:"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200",children:"\xd7"})]}),(0,n.jsxs)("div",{className:"space-y-3",children:[(0,n.jsx)("div",{children:(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["响应体格式 ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]})}),(0,n.jsxs)("div",{children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"生成数据条数"}),(0,n.jsx)("input",{type:"number",value:d[p].listCount,onChange:e=>O(p,"listCount",parseInt(e.target.value)||1),min:"1",max:"100",className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{children:[(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["响应体 JSON ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]}),(0,n.jsx)(f,{value:y,onChange:e=>i({modalBody:e}),placeholder:'例如: {"code": 200, "data": {"id": "@id", "name": "@name"}, "message": "success"} 或 {"code": 200, "data": {"rows": [{"id": "@id", "name": "@name"}], "total": "@integer(20, 100)"}, "message": "success"}',className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white min-h-[300px] text-xs"})]})]}),(0,n.jsxs)("div",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:["支持使用 ",(0,n.jsx)("a",{href:"http://mockjs.com/examples.html",target:"_blank",rel:"noopener noreferrer",className:"text-blue-500 hover:underline",children:"Mock.js 语法"}),",如 @id, @name, @email 等,",(0,n.jsxs)("div",{className:"text-red-500",children:["数组数据为特殊处理,使用`_|`开头,后面拼接字段:",(0,n.jsx)("b",{children:"_|字段|条数"})," 或者 ",(0,n.jsx)("b",{children:"_|字段"})]})]}),(0,n.jsxs)("div",{className:"flex justify-end space-x-2 mt-3 box-border",children:[(0,n.jsx)("button",{type:"button",onClick:I,className:"px-3 py-1 border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200 rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-600 transition-colors text-xs",children:"取消"}),(0,n.jsx)("button",{type:"button",onClick:()=>{if(null!==p)try{let e=Function("return "+y)();O(p,"body",e),I()}catch(e){t.open("error","JSON 格式错误,请检查输入")}},className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存"})]})]})}),document.body)]})}function k(){let{state:e,proxyInstance:t}=m(),r=e.isServer,{state:s,dispatch:i,proxyInstance:a}=(0,l.useProxyStore)({rootDir:"",dir:"mock",fileName:"proxy",proxyList:[],response:"",isModalOpen:!1,currentIndex:null,modalBody:"",isEnabledStart:!1},{sync:!0}),c=s.proxyList,d=s.response,x=s.isModalOpen,u=s.currentIndex,p=s.modalBody,y=s.rootDir,k=s.dir,v=s.fileName,j=s.isEnabledStart,z=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_is_enabled`).then(e=>e.json());200===e.code&&i({isEnabledStart:e.data})}catch(e){console.error("检查 Proxy 配置服务是否启用失败:",e)}};(0,o.useEffect)(()=>{z()},[]);let N=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_destroy`).then(e=>e.json());200===e.code?(i({isEnabledStart:!1}),t.open("success","销毁 Proxy 服务成功")):t.open("error",e.message||"销毁 Proxy 服务失败")}catch(e){console.error("销毁 Proxy 服务失败:",e)}},w=async()=>{try{let e=await fetch(`${b}/_fairys/_proxy/_start`).then(e=>e.json());200===e.code?(t.open("success","加载 Proxy 服务成功"),i({isEnabledStart:!0})):t.open("error",e.message||"加载 Proxy 服务失败")}catch(e){console.error("加载 Proxy 服务失败:",e)}},C=async()=>{try{let e=`dir=${decodeURIComponent(k)}&fileName=${decodeURIComponent(v)}&rootDir=${decodeURIComponent(y)}`,t=await fetch(`${b}/_fairys/_proxy?${e}`),r=await t.json();if(200===r.code){let e=r.data;Array.isArray(r.data)||(e=[]),i({proxyList:e,dir:r.dir,fileName:r.fileName,rootDir:r.rootDir})}else i({proxyList:[]})}catch(e){t.store.isServer=!1,console.error("获取缓存数据失败:",e)}};(0,o.useEffect)(()=>{C()},[]);let S=(e,t,r)=>{i({proxyList:(a.store.proxyList||[]).map((n,s)=>s===e?{...n,[t]:r}:n)})},O=async e=>{e.preventDefault();let s=!0,o="";for(let e=0;e<c.length;e++){let t=c[e];if(!t.path.trim()){s=!1,o=`代理配置 #${e+1} 的 接口地址 不能为空`;break}if(!t.target.trim()){s=!1,o=`代理配置 #${e+1} 的 目标地址 不能为空`;break}}if(!s)return void t.open("error",o);let a=new Map;for(let e=0;e<c.length;e++){let t=c[e],r=`${t.path.trim()}`;if(a.has(r)){var l;null==(l=a.get(r))||l.push(e+1)}else a.set(r,[e+1])}if(a.size>0){let e=[];for(let[t,r]of a)r.length>1&&e.push((0,n.jsxs)("div",{children:["第 ",r.join(",")," 行数据 接口地址重复;"]},t));if(e.length>0)return void t.open("error",e,5e3)}try{if(r){let e=await fetch(`${b}/_fairys/_proxy`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({proxyList:c,dir:k,fileName:v,rootDir:y})}),r=await e.json();c.length>0?i({response:JSON.stringify(r,null,2)}):200===r.code&&t.open("success","保存成功"),i({rootDir:r.rootDir})}else if(c.length>0){let e=c.reduce((e,t)=>{let{path:r,...n}={...t};return{...e,[r]:n}},{});i({response:JSON.stringify(e,null,2)})}else t.open("success","操作成功")}catch(e){i({response:"Error: "+e.message})}},_=()=>{i({currentIndex:void 0,modalBody:"",isModalOpen:!1}),document.body.style.overflow="auto"};return(0,n.jsxs)("div",{className:"space-y-6 flex-1 flex flex-col box-border overflow-hidden",children:[(0,n.jsxs)("div",{className:"mb-6 text-xs text-zinc-600 dark:text-zinc-300 box-border flex justify-between",children:[(0,n.jsxs)("div",{children:["当前配置总条数: ",c.length]}),r?(0,n.jsxs)("div",{className:"flex gap-2",children:[(0,n.jsxs)("button",{type:"button",onClick:w,className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:[j?"重启":"启动"," proxy 服务"]}),j?(0,n.jsx)("button",{type:"button",onClick:N,className:"px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"销毁 proxy 服务"}):(0,n.jsx)(o.Fragment,{})]}):(0,n.jsx)(o.Fragment,{})]}),(0,n.jsxs)("div",{className:"mb-6",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"数据保存到本地"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"根目录"}),(0,n.jsx)("input",{type:"text",value:y,onChange:e=>{i({rootDir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"目录名"}),(0,n.jsx)("input",{type:"text",value:k,onChange:e=>{i({dir:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsxs)("div",{className:"flex-1 flex items-center gap-2",children:[(0,n.jsx)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:"文件名"}),(0,n.jsx)("input",{type:"text",value:v,onChange:e=>{i({fileName:e.target.value})},className:"flex-1 px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})]}),(0,n.jsx)("button",{type:"button",onClick:()=>C(),className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors whitespace-nowrap text-xs",children:"查询"})]}),(0,n.jsx)("p",{className:"text-xs text-zinc-500 dark:text-zinc-400 mt-1",children:"默认保存到当前工作目录的 mock 文件夹"})]}),c.length>0?(0,n.jsx)("div",{className:"flex-1 flex flex-col box-border overflow-auto",children:(0,n.jsx)(h,{columns:[{title:"#",tdClassName:"px-2 py-2 text-xs text-zinc-800 dark:text-zinc-100 border-b border-zinc-200 dark:border-zinc-700",isIndex:!0},{title:"接口地址",dataIndex:"path",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.path,placeholder:"请使用 ^ 开头",onChange:e=>S(t,"path",e.target.value),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs"})},{title:"目标地址",dataIndex:"target",render:(e,t)=>(0,n.jsx)("input",{type:"text",value:e.target,onChange:e=>{S(t,"target",e.target.value||"")},className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white text-xs",placeholder:"目标地址"})},{title:"启用 WebSocket",dataIndex:"enableWebSocket",render:(e,t)=>(0,n.jsx)("input",{type:"checkbox",checked:e.ws||!1,onChange:e=>{S(t,"ws",e.target.checked)},className:"mr-2"})},{title:"路径重写数据",dataIndex:"pathRewrite",render:e=>(0,n.jsx)("div",{className:"text-zinc-500 dark:text-zinc-400 text-xs w-[250px]",children:JSON.stringify(e.pathRewrite,null,2)})},{title:"操作",dataIndex:"operation",render:(e,t)=>(0,n.jsxs)("div",{className:"flex space-x-1",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{i({currentIndex:t,modalBody:JSON.stringify(c[t].pathRewrite,null,2),isModalOpen:!0}),document.body.style.overflow="hidden"},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"编辑路径重写数据"}),(0,n.jsx)("button",{type:"button",onClick:()=>{i({proxyList:(a.store.proxyList||[]).filter((e,r)=>r!==t)})},className:"px-2 py-0.5 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs",children:"删除"})]})}],dataSource:c})}):(0,n.jsx)("div",{className:"text-center py-8 text-zinc-500 dark:text-zinc-400",children:'暂无接口配置,请点击"添加接口配置"按钮添加'}),(0,n.jsxs)("div",{className:"flex justify-center",children:[(0,n.jsx)("button",{type:"button",onClick:()=>{i({proxyList:[...a.store.proxyList||[]].concat([{path:"",target:""}])})},className:"px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors mr-4 text-xs",children:"添加接口配置"}),(0,n.jsx)("button",{type:"button",onClick:O,className:"px-4 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存配置"})]}),d&&(0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 flex flex-col w-full max-w-2xl max-h-[80%]",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-2",children:[(0,n.jsx)("h2",{className:"text-sm font-medium text-zinc-800 dark:text-zinc-100",children:"proxy 数据"}),(0,n.jsxs)("div",{className:"flex gap-4",children:[(0,n.jsx)("button",{type:"button",title:"复制",onClick:()=>{navigator.clipboard.writeText(d),t.open("success","复制成功")},className:"px-2 py-0.5 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"复制"}),(0,n.jsx)("button",{type:"button",onClick:()=>i({response:""}),className:"px-2 py-0.5 bg-gray-500 text-white rounded-md hover:bg-gray-600 transition-colors text-xs",children:"关闭"})]})]}),(0,n.jsx)("pre",{className:"flex-1 overflow-auto bg-zinc-100 dark:bg-zinc-800 p-3 rounded-md overflow-x-auto text-xs text-zinc-800 dark:text-zinc-100",children:d})]})}),x&&null!==u&&(null==c?void 0:c[u])&&(0,g.createPortal)((0,n.jsx)("div",{className:"fixed inset-0 bg-black/30 flex items-center justify-center z-50",children:(0,n.jsxs)("div",{className:"bg-white/90 dark:bg-zinc-900/90 backdrop-blur-sm rounded-lg shadow-xl p-4 w-full max-w-2xl",children:[(0,n.jsxs)("div",{className:"flex justify-between items-center mb-3",children:[(0,n.jsxs)("h2",{className:"text-sm font-medium text-zinc-700 dark:text-zinc-300",children:["编辑响应体数据 - 接口配置 #",u+1]}),(0,n.jsx)("button",{type:"button",onClick:_,className:"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200",children:"\xd7"})]}),(0,n.jsx)("div",{className:"space-y-3",children:(0,n.jsxs)("div",{children:[(0,n.jsxs)("label",{className:"block text-xs font-medium text-zinc-700 dark:text-zinc-300 mb-1",children:["路径重写 JSON ",(0,n.jsx)("span",{className:"text-red-500",children:"*"})]}),(0,n.jsx)(f,{value:p,onChange:e=>i({modalBody:e}),className:"w-full px-2 py-1 border border-zinc-300 dark:border-zinc-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-zinc-800 dark:text-white min-h-[300px] text-xs",placeholder:'例如: { "^/api":"" , "^/api/test":"/api" }'})]})}),(0,n.jsxs)("div",{className:"flex justify-end space-x-2 mt-3 box-border",children:[(0,n.jsx)("button",{type:"button",onClick:_,className:"px-3 py-1 border border-zinc-300 dark:border-zinc-600 bg-white dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200 rounded-md hover:bg-zinc-100 dark:hover:bg-zinc-600 transition-colors text-xs",children:"取消"}),(0,n.jsx)("button",{type:"button",onClick:()=>{if(null!==u)try{let e=Function("return "+p)();S(u,"pathRewrite",e),_()}catch(e){t.open("error","JSON 格式错误,请检查输入")}},className:"px-3 py-1 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors text-xs",children:"保存"})]})]})}),document.body)]})}let v={success:"text-green-500",info:"text-blue-500",error:"text-red-500",warning:"text-orange-500"},j={info:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"info-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"})})}),success:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"check-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"})})}),error:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{fillRule:"evenodd",viewBox:"64 64 896 896",focusable:"false","data-icon":"close-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"})})}),warning:e=>(0,n.jsx)("span",{...e,children:(0,n.jsx)("svg",{viewBox:"64 64 896 896",focusable:"false","data-icon":"exclamation-circle",width:"1em",height:"1em",fill:"currentColor",children:(0,n.jsx)("path",{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"})})})},z=document.getElementById("root");z&&s.createRoot(z).render((0,n.jsxs)(u,{children:[(0,n.jsx)(function(){let{state:e,dispatch:t}=m(),[r,s]=(0,o.useState)({mock:!0,proxy:!1}),i=e.tabKey,a=e=>{s(t=>({...t,[e]:!0})),t({tabKey:e})};return(0,n.jsx)("div",{className:"h-full bg-zinc-50 dark:bg-black p-4 sm:p-6 box-border overflow-hidden flex flex-col",children:(0,n.jsxs)("div",{className:"flex-1 w-full bg-white dark:bg-zinc-900 rounded-lg shadow-md p-6 box-border flex flex-col overflow-hidden",children:[(0,n.jsxs)("div",{className:"flex border-b border-zinc-200 dark:border-zinc-700 mb-6",children:[(0,n.jsx)("button",{className:`px-4 py-2 text-xs font-medium transition-colors ${"mock"===i?"border-b-2 border-blue-500 text-blue-600 dark:text-blue-400":"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,onClick:()=>a("mock"),children:"Mocker 数据配置"}),(0,n.jsx)("button",{className:`px-4 py-2 text-xs font-medium transition-colors ${"proxy"===i?"border-b-2 border-blue-500 text-blue-600 dark:text-blue-400":"text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,onClick:()=>a("proxy"),children:"代理配置"})]}),(0,n.jsxs)("div",{className:"flex-1 relative overflow-hidden",children:[r.mock&&(0,n.jsx)("div",{className:`absolute inset-0 flex flex-col box-border overflow-hidden transition-all duration-300 ease-in-out ${"mock"===i?"opacity-100 translate-x-0":"opacity-0 translate-x-4 pointer-events-none"}`,children:(0,n.jsx)(y,{})}),r.proxy&&(0,n.jsx)("div",{className:`absolute inset-0 flex flex-col box-border overflow-hidden transition-all duration-300 ease-in-out ${"proxy"===i?"opacity-100 translate-x-0":"opacity-0 translate-x-4 pointer-events-none"}`,children:(0,n.jsx)(k,{})})]})]})})},{}),(0,n.jsx)(()=>{let{state:e}=m(),t=e.messageList;return Array.isArray(t)&&t.length?(0,n.jsx)("div",{className:"fixed inset-0 flex flex-col items-center z-90 gap-2 py-2 box-border pointer-events-none",children:t.map(e=>{let t=j[e.type],r=v[e.type];return(0,n.jsxs)("div",{className:"shadow-md py-2 px-4 box-border rounded-lg bg-white text-xs flex items-center gap-2 flex-wrap",children:[t?(0,n.jsx)(t,{className:r}):(0,n.jsx)(n.Fragment,{}),(0,n.jsx)("div",{children:e.message})]},e.id)})}):(0,n.jsx)(n.Fragment,{})},{})]}))}},o={};function i(e){var t=o[e];if(void 0!==t)return t.exports;var r=o[e]={exports:{}};return s[e].call(r.exports,r,r.exports,i),r.exports}i.m=s,i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e=[],i.O=(t,r,n,s)=>{if(r){s=s||0;for(var o=e.length;o>0&&e[o-1][2]>s;o--)e[o]=e[o-1];e[o]=[r,n,s];return}for(var a=1/0,o=0;o<e.length;o++){for(var[r,n,s]=e[o],l=!0,c=0;c<r.length;c++)(!1&s||a>=s)&&Object.keys(i.O).every(e=>i.O[e](r[c]))?r.splice(c--,1):(l=!1,s<a&&(a=s));if(l){e.splice(o--,1);var d=n();void 0!==d&&(t=d)}}return t},t={410:0},i.O.j=e=>0===t[e],r=(e,r)=>{var n,s,[o,a,l]=r,c=0;if(o.some(e=>0!==t[e])){for(n in a)i.o(a,n)&&(i.m[n]=a[n]);if(l)var d=l(i)}for(e&&e(r);c<o.length;c++)s=o[c],i.o(t,s)&&t[s]&&t[s][0](),t[s]=0;return i.O(d)},(n=self.webpackChunk_fairys_mocker_ui=self.webpackChunk_fairys_mocker_ui||[]).forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n));var a=i.O(void 0,["783","514"],()=>i(711));a=i.O(a)})();
|