whistle.mockbubu 1.0.0-dev.1
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/.editorconfig +18 -0
- package/.gitignore +63 -0
- package/README.md +80 -0
- package/index.js +19 -0
- package/lib/const.js +28 -0
- package/lib/resRulesServer.js +9 -0
- package/lib/server.js +107 -0
- package/lib/uiServer/index.js +35 -0
- package/lib/uiServer/router/index.js +171 -0
- package/lib/uiServer/router/version-router.js +127 -0
- package/lib/uiServer/util.js +99 -0
- package/lib/utils.js +287 -0
- package/package.json +44 -0
- package/public/fonts/element-icons.f1a45d74.ttf +0 -0
- package/public/fonts/element-icons.ff18efd1.woff +0 -0
- package/public/img/jsoneditor-icons.94cc3007.svg +749 -0
- package/public/index.html +12 -0
- package/public/js/app.js +3537 -0
- package/public/js/app.js.map +1 -0
- package/public/js/chunk-vendors.js +39851 -0
- package/public/js/chunk-vendors.js.map +1 -0
- package/rules.txt +2 -0
- package/step1.png +0 -0
- package/step2.png +0 -0
package/.editorconfig
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# http://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
end_of_line = lf
|
|
7
|
+
indent_size = 2
|
|
8
|
+
indent_style = space
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
max_line_length = 80
|
|
11
|
+
trim_trailing_whitespace = true
|
|
12
|
+
|
|
13
|
+
[*.md]
|
|
14
|
+
max_line_length = 0
|
|
15
|
+
trim_trailing_whitespace = false
|
|
16
|
+
|
|
17
|
+
[COMMIT_EDITMSG]
|
|
18
|
+
max_line_length = 0
|
package/.gitignore
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
|
|
8
|
+
# Runtime data
|
|
9
|
+
pids
|
|
10
|
+
*.pid
|
|
11
|
+
*.seed
|
|
12
|
+
*.pid.lock
|
|
13
|
+
|
|
14
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
15
|
+
lib-cov
|
|
16
|
+
|
|
17
|
+
# Coverage directory used by tools like istanbul
|
|
18
|
+
coverage
|
|
19
|
+
|
|
20
|
+
# nyc test coverage
|
|
21
|
+
.nyc_output
|
|
22
|
+
|
|
23
|
+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
24
|
+
.grunt
|
|
25
|
+
|
|
26
|
+
# Bower dependency directory (https://bower.io/)
|
|
27
|
+
bower_components
|
|
28
|
+
|
|
29
|
+
# node-waf configuration
|
|
30
|
+
.lock-wscript
|
|
31
|
+
|
|
32
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
33
|
+
build/Release
|
|
34
|
+
|
|
35
|
+
# Dependency directories
|
|
36
|
+
node_modules/
|
|
37
|
+
jspm_packages/
|
|
38
|
+
|
|
39
|
+
# TypeScript v1 declaration files
|
|
40
|
+
typings/
|
|
41
|
+
|
|
42
|
+
# Optional npm cache directory
|
|
43
|
+
.npm
|
|
44
|
+
|
|
45
|
+
# Optional eslint cache
|
|
46
|
+
.eslintcache
|
|
47
|
+
|
|
48
|
+
# Optional REPL history
|
|
49
|
+
.node_repl_history
|
|
50
|
+
|
|
51
|
+
# Output of 'npm pack'
|
|
52
|
+
*.tgz
|
|
53
|
+
|
|
54
|
+
# Yarn Integrity file
|
|
55
|
+
.yarn-integrity
|
|
56
|
+
|
|
57
|
+
# dotenv environment variables file
|
|
58
|
+
.env
|
|
59
|
+
|
|
60
|
+
# next.js build output
|
|
61
|
+
.next
|
|
62
|
+
/.history
|
|
63
|
+
/dist
|
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# whistle.mockbubu
|
|
2
|
+
|
|
3
|
+
whistle.mockbubu 是[whistle](https://github.com/avwo/whistle)的一个扩展脚本插件,包括以下功能
|
|
4
|
+
|
|
5
|
+
- 实时生成捕获接口的 mock 文件
|
|
6
|
+
- 管理 mock 文件
|
|
7
|
+
|
|
8
|
+
# 安装
|
|
9
|
+
|
|
10
|
+
$ w2 install whistle.mockbubu
|
|
11
|
+
|
|
12
|
+
# 用法
|
|
13
|
+
|
|
14
|
+
### 配置 [whistle 规则](https://avwo.github.io/whistle/rules/)
|
|
15
|
+
|
|
16
|
+
> mode 有三种选项 pathname | href | pattern,默认是 pathname
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
pattern mockbubu://[mode]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 生成 mock 文件
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
#### pathname 模式:使用接口的 origin + pathname 作为文件名
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
pattern mockbubu:// 或者 pattern mockbubu://pathname
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
#### href 模式:使用接口的 路径 作为文件名
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
pattern mockbubu://href
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
#### pattern 模式:使用 pattern 作为文件名
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
pattern mockbubu://pattern
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### 开始 mock
|
|
52
|
+
|
|
53
|
+
第一步:开启文件的 mock 开关,系统生成一条规则:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
文件名 resBody:{文件内容}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
第二步:在 Response 面板管理文件内容
|
|
60
|
+
|
|
61
|
+
手动添加文件
|
|
62
|
+
|
|
63
|
+
- 如果需要提前生成 mock 文件,可手动添加(通常不需要手动添加,通过实时捕获接口即可生成 mock 文件)
|
|
64
|
+
|
|
65
|
+
编辑文件
|
|
66
|
+
|
|
67
|
+
- 支持文件编辑
|
|
68
|
+
|
|
69
|
+
多版本
|
|
70
|
+
|
|
71
|
+
- 支持新增不同版本的文件内容
|
|
72
|
+
- 其中 source 版本是默认生成的,是原始接口响应数据,支持修改
|
|
73
|
+
|
|
74
|
+
切换 mock 文件
|
|
75
|
+
|
|
76
|
+
- mock 返回内容使用当前选中的版本
|
|
77
|
+
|
|
78
|
+

|
|
79
|
+
|
|
80
|
+

|
package/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
exports.uiServer = require('./lib/uiServer')
|
|
2
|
+
// exports.rulesServer = require('./lib/rulesServer')
|
|
3
|
+
// exports.tunnelRulesServer = require('./lib/tunnelRulesServer');
|
|
4
|
+
exports.resRulesServer = require('./lib/resRulesServer')
|
|
5
|
+
// exports.statsServer = require('./lib/statsServer')
|
|
6
|
+
// exports.resStatsServer = require('./lib/resStatsServer')
|
|
7
|
+
exports.server = require('./lib/server')
|
|
8
|
+
// exports.reqRead = require('./lib/reqRead')
|
|
9
|
+
// exports.reqWrite = require('./lib/reqWrite');
|
|
10
|
+
// exports.resRead = require('./lib/resRead')
|
|
11
|
+
// exports.resWrite = require('./lib/resWrite')
|
|
12
|
+
// exports.wsReqRead = require('./lib/wsReqRead');
|
|
13
|
+
// exports.wsReqWrite = require('./lib/wsReqWrite');
|
|
14
|
+
// exports.wsResRead = require('./lib/wsResRead');
|
|
15
|
+
// exports.wsResWrite = require('./lib/wsResWrite');
|
|
16
|
+
// exports.tunnelReqRead = require('./lib/tunnelReqRead');
|
|
17
|
+
// exports.tunnelReqWrite = require('./lib/tunnelReqWrite');
|
|
18
|
+
// exports.tunnelResRead = require('./lib/tunnelResRead');
|
|
19
|
+
// exports.tunnelResWrite = require('./lib/tunnelResWrite');
|
package/lib/const.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
exports.RuleValueMap = {
|
|
2
|
+
href: 'href',
|
|
3
|
+
pathname: 'pathname',
|
|
4
|
+
pattern: 'pattern',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
exports.RangeMap = {
|
|
8
|
+
MOCKING: 'mocking',
|
|
9
|
+
NOT_MOCKING: 'not-mocking',
|
|
10
|
+
LOCKED: 'locked',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
exports.RangeFilterMap = {
|
|
14
|
+
'mocking': { key: 'mock', value: true, method: 'equal' },
|
|
15
|
+
'not-mocking': { key: 'mock', value: false, method: 'equal' },
|
|
16
|
+
'locked': { key: 'locked', value: true, method: 'equal' },
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.RuleFilterMap = {
|
|
20
|
+
'href': { key: 'ruleValue', value: 'href', method: 'equal' },
|
|
21
|
+
'pathname': { key: 'ruleValue', value: 'pathname', method: 'equal' },
|
|
22
|
+
'pattern': { key: 'ruleValue', value: 'pattern', method: 'equal' },
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.LockedFilterMap = {
|
|
26
|
+
'locked': { key: 'locked', value: true, method: 'equal' },
|
|
27
|
+
'unlocked': { key: 'locked', value: false, method: 'equal' },
|
|
28
|
+
}
|
package/lib/server.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getProperty,
|
|
3
|
+
setProperty,
|
|
4
|
+
getFilename,
|
|
5
|
+
getRule,
|
|
6
|
+
isJsonReq,
|
|
7
|
+
setApiListUpdated,
|
|
8
|
+
getVersionContent,
|
|
9
|
+
handleBuffer2String,
|
|
10
|
+
withTryCatch,
|
|
11
|
+
} = require('./utils')
|
|
12
|
+
const qs = require('qs')
|
|
13
|
+
|
|
14
|
+
module.exports = (server, { storage }) => {
|
|
15
|
+
server.on('request', (req, res) => {
|
|
16
|
+
const { originalReq, method } = req
|
|
17
|
+
const { headers, ruleValue, url, pattern } = originalReq
|
|
18
|
+
const filename = getFilename(originalReq)
|
|
19
|
+
const rule = getRule(originalReq)
|
|
20
|
+
|
|
21
|
+
// 非json请求直接透传
|
|
22
|
+
if (!isJsonReq(headers)) return req.passThrough()
|
|
23
|
+
|
|
24
|
+
// 获取请求信息
|
|
25
|
+
let str = ''
|
|
26
|
+
req.on('data', (chunk) => {
|
|
27
|
+
str += chunk
|
|
28
|
+
})
|
|
29
|
+
req.on('end', () => {
|
|
30
|
+
setProperty(storage, filename, { payload: str })
|
|
31
|
+
})
|
|
32
|
+
setProperty(storage, filename, {
|
|
33
|
+
query: qs.parse(new URL(url).searchParams.toString()),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const { mock, mockVersion } = getProperty(storage, filename) || {}
|
|
38
|
+
const sessionCache = storage.readFile(filename)
|
|
39
|
+
|
|
40
|
+
if (mock) {
|
|
41
|
+
if (sessionCache) {
|
|
42
|
+
const resCache = JSON.parse(sessionCache)?.res
|
|
43
|
+
const { statusCode, statusMessage, headers } = resCache
|
|
44
|
+
|
|
45
|
+
headers['from-res-cache'] = 'true'
|
|
46
|
+
delete headers['content-encoding']
|
|
47
|
+
delete headers['content-length']
|
|
48
|
+
res.writeHead(statusCode, statusMessage, headers)
|
|
49
|
+
if (mockVersion) {
|
|
50
|
+
const mockVersionContent = getVersionContent({ storage, filename, versionName: mockVersion })
|
|
51
|
+
res.end(JSON.stringify(mockVersionContent))
|
|
52
|
+
} else {
|
|
53
|
+
res.end(resCache.body)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
// 已有缓存则直接透传
|
|
58
|
+
if (sessionCache) return req.passThrough()
|
|
59
|
+
|
|
60
|
+
// 命中插件规则,没有勾选mock的缓存最新的接口数据
|
|
61
|
+
const client = req.request((svrRes) => {
|
|
62
|
+
const encoding = svrRes.headers['content-encoding']
|
|
63
|
+
let body
|
|
64
|
+
|
|
65
|
+
svrRes.on('data', (data) => {
|
|
66
|
+
body = body ? Buffer.concat([body, data]) : data
|
|
67
|
+
})
|
|
68
|
+
svrRes.on('end', withTryCatch(async () => {
|
|
69
|
+
if (!body) return
|
|
70
|
+
|
|
71
|
+
const content = await handleBuffer2String({ body, encoding })
|
|
72
|
+
// 获取完整的抓包数据,要等待响应完成
|
|
73
|
+
req.getSession(async (session) => {
|
|
74
|
+
// 如果设置了 enable://hide 会获取到空数据
|
|
75
|
+
if (!session) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
setProperty(storage, filename, {
|
|
79
|
+
method,
|
|
80
|
+
rule,
|
|
81
|
+
status: session.res.statusCode,
|
|
82
|
+
pattern,
|
|
83
|
+
ruleValue: ruleValue || 'pathname',
|
|
84
|
+
url,
|
|
85
|
+
mock: false,
|
|
86
|
+
locked: false,
|
|
87
|
+
date: Date.now(),
|
|
88
|
+
mockTime: null,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const tempSession = JSON.parse(JSON.stringify(session))
|
|
92
|
+
tempSession.res.body = content
|
|
93
|
+
storage.writeFile(filename, JSON.stringify(tempSession))
|
|
94
|
+
|
|
95
|
+
setApiListUpdated(storage, true)
|
|
96
|
+
})
|
|
97
|
+
}))
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
req.pipe(client)
|
|
101
|
+
req.passThrough()
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
req.passThrough()
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const Koa = require('koa')
|
|
2
|
+
const bodyParser = require('koa-bodyparser')
|
|
3
|
+
const onerror = require('koa-onerror')
|
|
4
|
+
const serve = require('koa-static')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const router = require('koa-router')()
|
|
7
|
+
const setupRouter = require('./router')
|
|
8
|
+
const cors = require('koa2-cors')
|
|
9
|
+
const MAX_AGE = 1000 * 60 * 5
|
|
10
|
+
|
|
11
|
+
module.exports = (server, options) => {
|
|
12
|
+
const app = new Koa()
|
|
13
|
+
|
|
14
|
+
app.proxy = true
|
|
15
|
+
app.silent = true
|
|
16
|
+
onerror(app)
|
|
17
|
+
setupRouter(router, options)
|
|
18
|
+
app.use(
|
|
19
|
+
cors({
|
|
20
|
+
origin: '*',
|
|
21
|
+
maxAge: 10,
|
|
22
|
+
credentials: true,
|
|
23
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
24
|
+
}),
|
|
25
|
+
)
|
|
26
|
+
app.use(bodyParser({
|
|
27
|
+
jsonLimit: '10mb',
|
|
28
|
+
formLimit: '10mb',
|
|
29
|
+
textLimit: '10mb',
|
|
30
|
+
}))
|
|
31
|
+
app.use(router.routes())
|
|
32
|
+
app.use(router.allowedMethods())
|
|
33
|
+
app.use(serve(path.join(__dirname, '../../public'), { maxage: MAX_AGE }))
|
|
34
|
+
server.on('request', app.callback())
|
|
35
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const {
|
|
2
|
+
updateFile,
|
|
3
|
+
removeFile,
|
|
4
|
+
writeFile,
|
|
5
|
+
readFile,
|
|
6
|
+
setProperty,
|
|
7
|
+
getProperty,
|
|
8
|
+
getApiListUpdated,
|
|
9
|
+
setApiListUpdated,
|
|
10
|
+
} = require('../../utils')
|
|
11
|
+
const {
|
|
12
|
+
createErrorResponse,
|
|
13
|
+
createSuccessResponse,
|
|
14
|
+
handleFilterList,
|
|
15
|
+
getFullDataList,
|
|
16
|
+
} = require('../util')
|
|
17
|
+
const versionRouter = require('./version-router')
|
|
18
|
+
|
|
19
|
+
module.exports = (router) => {
|
|
20
|
+
// 文件版本路由
|
|
21
|
+
versionRouter(router)
|
|
22
|
+
|
|
23
|
+
// 获取列表数据接口
|
|
24
|
+
router.post('/cgi-bin/mockbubu/api-list', async (ctx) => {
|
|
25
|
+
try {
|
|
26
|
+
const { localStorage } = ctx.req
|
|
27
|
+
|
|
28
|
+
const filteredList = handleFilterList(
|
|
29
|
+
getFullDataList(localStorage),
|
|
30
|
+
ctx.request.body,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
setApiListUpdated(localStorage, false)
|
|
34
|
+
ctx.body = createSuccessResponse(filteredList || [])
|
|
35
|
+
} catch (error) {
|
|
36
|
+
ctx.body = createErrorResponse(error.message)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// 检测接口是否更新
|
|
41
|
+
router.get('/cgi-bin/mockbubu/check-api-list', (ctx) => {
|
|
42
|
+
try {
|
|
43
|
+
const { localStorage } = ctx.req
|
|
44
|
+
const updated = getApiListUpdated(localStorage)
|
|
45
|
+
ctx.body = createSuccessResponse(updated)
|
|
46
|
+
} catch (error) {
|
|
47
|
+
ctx.body = createErrorResponse(error.message)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// 更新文件详情接口
|
|
52
|
+
router.post('/cgi-bin/mockbubu/update-api-data', (ctx) => {
|
|
53
|
+
try {
|
|
54
|
+
const { localStorage } = ctx.req
|
|
55
|
+
const { name, data } = ctx.request.body
|
|
56
|
+
|
|
57
|
+
updateFile(localStorage, name, data)
|
|
58
|
+
const file = readFile(localStorage, name)
|
|
59
|
+
const props = getProperty(localStorage, name) || {}
|
|
60
|
+
|
|
61
|
+
ctx.body = createSuccessResponse({
|
|
62
|
+
...props,
|
|
63
|
+
name,
|
|
64
|
+
data: file,
|
|
65
|
+
})
|
|
66
|
+
} catch (error) {
|
|
67
|
+
ctx.body = createErrorResponse(error.message)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// 获取文件详情接口
|
|
72
|
+
router.post('/cgi-bin/mockbubu/get-api-data', (ctx) => {
|
|
73
|
+
try {
|
|
74
|
+
const { localStorage } = ctx.req
|
|
75
|
+
const { name } = ctx.request.body
|
|
76
|
+
|
|
77
|
+
const file = readFile(localStorage, name)
|
|
78
|
+
const props = getProperty(localStorage, name) || {}
|
|
79
|
+
|
|
80
|
+
ctx.body = createSuccessResponse({
|
|
81
|
+
...props,
|
|
82
|
+
name,
|
|
83
|
+
data: file,
|
|
84
|
+
})
|
|
85
|
+
} catch (error) {
|
|
86
|
+
ctx.body = createErrorResponse(error.message)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// 新增mock接口
|
|
91
|
+
router.post('/cgi-bin/mockbubu/create-api-data', (ctx) => {
|
|
92
|
+
try {
|
|
93
|
+
const { localStorage } = ctx.req
|
|
94
|
+
const { name, content, ruleValue } = ctx.request.body
|
|
95
|
+
|
|
96
|
+
writeFile({
|
|
97
|
+
storage: localStorage,
|
|
98
|
+
filename: name,
|
|
99
|
+
body: content,
|
|
100
|
+
properties: { ruleValue, mock: true },
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
ctx.body = createSuccessResponse(null, '创建成功')
|
|
104
|
+
} catch (error) {
|
|
105
|
+
ctx.body = createErrorResponse(error.message)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// 修改接口mock开关
|
|
110
|
+
router.post('/cgi-bin/mockbubu/update-api-mock', (ctx) => {
|
|
111
|
+
try {
|
|
112
|
+
const { localStorage } = ctx.req
|
|
113
|
+
const { name, mock } = ctx.request.body
|
|
114
|
+
|
|
115
|
+
setProperty(localStorage, name, { mock })
|
|
116
|
+
ctx.body = createSuccessResponse(null, '更新成功')
|
|
117
|
+
} catch (error) {
|
|
118
|
+
ctx.body = createErrorResponse(error.message)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
// 修改接口lock开关
|
|
123
|
+
router.post('/cgi-bin/mockbubu/update-api-lock', (ctx) => {
|
|
124
|
+
try {
|
|
125
|
+
const { localStorage } = ctx.req
|
|
126
|
+
const { name, locked } = ctx.request.body
|
|
127
|
+
|
|
128
|
+
setProperty(localStorage, name, { locked })
|
|
129
|
+
ctx.body = createSuccessResponse(null, '更新成功')
|
|
130
|
+
} catch (error) {
|
|
131
|
+
ctx.body = createErrorResponse(error.message)
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// 删除接口数据
|
|
136
|
+
router.post('/cgi-bin/mockbubu/delete-api', (ctx) => {
|
|
137
|
+
try {
|
|
138
|
+
const { localStorage } = ctx.req
|
|
139
|
+
const { name } = ctx.request.body
|
|
140
|
+
|
|
141
|
+
removeFile(localStorage, name)
|
|
142
|
+
ctx.body = createSuccessResponse(null, '删除成功')
|
|
143
|
+
} catch (error) {
|
|
144
|
+
ctx.body = createErrorResponse(error.message)
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// 批量删除接口
|
|
149
|
+
router.post('/cgi-bin/mockbubu/batch-delete-api', (ctx) => {
|
|
150
|
+
try {
|
|
151
|
+
const { localStorage } = ctx.req
|
|
152
|
+
|
|
153
|
+
const filteredList = handleFilterList(getFullDataList(localStorage), {
|
|
154
|
+
...ctx.request.body,
|
|
155
|
+
locked: 'unlocked', // 锁定的文件不可批量删除
|
|
156
|
+
})
|
|
157
|
+
// 批量删除
|
|
158
|
+
filteredList.forEach((item) => {
|
|
159
|
+
try {
|
|
160
|
+
removeFile(localStorage, item.name)
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error(`删除文件 ${item.name} 失败:`, error.message)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
ctx.body = createSuccessResponse(null, '删除成功')
|
|
167
|
+
} catch (error) {
|
|
168
|
+
ctx.body = createErrorResponse(error.message)
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const {
|
|
2
|
+
addNewVersion,
|
|
3
|
+
updateVersionContent,
|
|
4
|
+
deleteVersion,
|
|
5
|
+
updateVersionName,
|
|
6
|
+
getVersions,
|
|
7
|
+
setProperty,
|
|
8
|
+
getPropertyAttr,
|
|
9
|
+
removePropertyAttr,
|
|
10
|
+
} = require('../../utils')
|
|
11
|
+
const { createErrorResponse, createSuccessResponse } = require('../util')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module.exports = (router) => {
|
|
15
|
+
// 新增版本
|
|
16
|
+
router.post('/cgi-bin/mockbubu/add-new-version', (ctx) => {
|
|
17
|
+
try {
|
|
18
|
+
const { localStorage } = ctx.req
|
|
19
|
+
const { versionName, content = {}, name } = ctx.request.body || {}
|
|
20
|
+
|
|
21
|
+
addNewVersion({
|
|
22
|
+
storage: localStorage,
|
|
23
|
+
filename: name,
|
|
24
|
+
versionName,
|
|
25
|
+
content,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
ctx.body = createSuccessResponse({
|
|
29
|
+
filename: versionName,
|
|
30
|
+
content,
|
|
31
|
+
}, '版本创建成功')
|
|
32
|
+
} catch (error) {
|
|
33
|
+
ctx.body = createErrorResponse(error.message)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// 删除版本
|
|
38
|
+
router.post('/cgi-bin/mockbubu/delete-version', (ctx) => {
|
|
39
|
+
try {
|
|
40
|
+
const { localStorage } = ctx.req
|
|
41
|
+
const { versionName, name } = ctx.request.body || {}
|
|
42
|
+
|
|
43
|
+
const mockVersion = getPropertyAttr(localStorage, name, 'mockVersion')
|
|
44
|
+
|
|
45
|
+
// 如果删除的是当前mock版本,则清除mock版本设置
|
|
46
|
+
if (versionName === mockVersion) {
|
|
47
|
+
removePropertyAttr(localStorage, name, 'mockVersion')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
deleteVersion({
|
|
51
|
+
storage: localStorage,
|
|
52
|
+
filename: name,
|
|
53
|
+
versionName,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
ctx.body = createSuccessResponse(null, '版本删除成功')
|
|
57
|
+
} catch (error) {
|
|
58
|
+
ctx.body = createErrorResponse(error.message)
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// 更新版本内容
|
|
63
|
+
router.post('/cgi-bin/mockbubu/update-version-content', (ctx) => {
|
|
64
|
+
try {
|
|
65
|
+
const { localStorage } = ctx.req
|
|
66
|
+
const { versionName, content, name } = ctx.request.body || {}
|
|
67
|
+
|
|
68
|
+
updateVersionContent({
|
|
69
|
+
storage: localStorage,
|
|
70
|
+
filename: name,
|
|
71
|
+
versionName,
|
|
72
|
+
content,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
ctx.body = createSuccessResponse(null, '版本内容更新成功')
|
|
76
|
+
} catch (error) {
|
|
77
|
+
ctx.body = createErrorResponse(error.message)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// 更新版本名称
|
|
82
|
+
router.post('/cgi-bin/mockbubu/update-version-name', (ctx) => {
|
|
83
|
+
try {
|
|
84
|
+
const { localStorage } = ctx.req
|
|
85
|
+
const { versionName, name, newVersion } = ctx.request.body || {}
|
|
86
|
+
|
|
87
|
+
updateVersionName({
|
|
88
|
+
storage: localStorage,
|
|
89
|
+
filename: name,
|
|
90
|
+
versionName,
|
|
91
|
+
newVersion,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
ctx.body = createSuccessResponse(null, '版本名称更新成功')
|
|
95
|
+
} catch (error) {
|
|
96
|
+
ctx.body = createErrorResponse(error.message)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// 获取版本列表
|
|
101
|
+
router.post('/cgi-bin/mockbubu/get-versions', (ctx) => {
|
|
102
|
+
try {
|
|
103
|
+
const { localStorage } = ctx.req
|
|
104
|
+
const { name } = ctx.request.body || {}
|
|
105
|
+
|
|
106
|
+
const list = getVersions({ storage: localStorage, filename: name }) || []
|
|
107
|
+
|
|
108
|
+
ctx.body = createSuccessResponse(list, '获取版本列表成功')
|
|
109
|
+
} catch (error) {
|
|
110
|
+
ctx.body = createErrorResponse(error.message)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// 设置mock的版本
|
|
115
|
+
router.post('/cgi-bin/mockbubu/set-mock-version', (ctx) => {
|
|
116
|
+
try {
|
|
117
|
+
const { localStorage } = ctx.req
|
|
118
|
+
const { name, versionName } = ctx.request.body || {}
|
|
119
|
+
|
|
120
|
+
setProperty(localStorage, name, { mockVersion: versionName })
|
|
121
|
+
|
|
122
|
+
ctx.body = createSuccessResponse(null, 'Mock版本设置成功')
|
|
123
|
+
} catch (error) {
|
|
124
|
+
ctx.body = createErrorResponse(error.message)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|