├── .babelrc
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.md
├── assets
└── uploads
│ └── .gitkeep
├── build
└── dev-server.js
├── ca-cert.pem
├── ca-key.pem
├── ca-req.csr
├── docs
├── .nojekyll
├── README.md
├── _coverpage.md
├── _navbar.md
├── _sidebar.md
├── buildmock.md
├── configuration.md
├── images
│ ├── 5.jpg
│ ├── dcloud1.jpg
│ ├── dcloud10.jpg
│ ├── dcloud11.jpg
│ ├── dcloud2.jpg
│ ├── dcloud3.jpg
│ ├── dcloud4.jpg
│ ├── dcloud5.jpg
│ ├── dcloud6.jpg
│ ├── dcloud7.jpg
│ ├── dcloud8.jpg
│ ├── dcloud9.jpg
│ ├── favicon.png
│ └── rbac.jpg
├── index.html
├── notonlymock.md
├── permission.md
├── permissionapi.md
├── quickstart.md
└── template.md
├── gulpfile.js
├── migration
├── book.js
└── index.js
├── nunjucks.tmLanguage
├── package.json
├── publicKey.pub
├── screenshot
├── 1.png
├── 2.jpg
├── 3.jpg
├── 4.jpg
└── 5.jpg
├── src
├── app.js
├── config.js
├── controllers
│ ├── auth.js
│ ├── index.js
│ ├── interface.js
│ ├── menu.js
│ ├── requestlog.js
│ ├── role.js
│ ├── route.js
│ ├── system.js
│ └── user.js
├── db
│ ├── db.json
│ ├── db_backup.json
│ └── request_log_db.json
├── im
│ ├── closeMiddleware.js
│ ├── connectMiddleware.js
│ ├── index.js
│ ├── messageMiddleware.js
│ ├── messageRouteMiddleware.js
│ ├── remoteEmitMiddleware.js
│ ├── roomInfoMiddleware.js
│ └── routes
│ │ ├── index.js
│ │ ├── message.js
│ │ └── room.js
├── lib
│ ├── EasySocket.js
│ ├── compose.js
│ ├── proxy.js
│ └── responseTemplate.js
├── middleware
│ ├── ErrorRoutesCatch.js
│ ├── ParseUserInfo.js
│ ├── PermissionCheck.js
│ ├── Proxy.js
│ └── RequestLog.js
├── models
│ ├── baseModel.js
│ ├── index.js
│ └── requestLogModel.js
├── routes
│ ├── index.js
│ └── main.js
├── services
│ ├── interfaceService.js
│ ├── memuService.js
│ ├── requestLogService.js
│ ├── roleService.js
│ ├── routeService.js
│ ├── systemService.js
│ ├── tokenService.js
│ └── userService.js
└── tool
│ └── Common.js
├── templates
├── config
│ ├── config.js
│ ├── index.js
│ └── model.js
├── generate.js
└── server
│ ├── controller.njk
│ ├── db.njk
│ ├── model.njk
│ ├── quickAdd
│ ├── controller.njk
│ └── route.njk
│ ├── route.njk
│ └── service.njk
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env"
4 | ],
5 | "plugins": [
6 | "@babel/plugin-transform-runtime"
7 | ]
8 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | test/unit/coverage
6 | test/e2e/reports
7 | selenium-debug.log
8 | .idea/
9 | codeGenerate/dist/
10 | yarn.lock
11 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM daocloud.io/node
2 | WORKDIR /app
3 | COPY . /app/
4 | RUN npm install
5 | RUN npm run build
6 | RUN cp -r src/db dist/
7 | CMD ["npm","run","production"]
8 |
9 | EXPOSE 3000
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 若邪
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ## 关于lazy mock
8 | > 一个快速生成后端模拟数据的懒人工具
9 |
10 | ## 是什么
11 |
12 | lazy mock 是一个使用`koa2`构建的,`lowdb`持久化数据到JSON文件的快速生成后端模拟数据的工具。只需要简单的配置就可以实现和json-server一样的功能,但是比json-server更加灵活,后期可配置性更强,完全可以模拟真实后端业务逻辑。
13 |
14 | lazy mock默认包含了`jwt`实现的登录与登出,实现了基于`RBAC`模型的通用权限控制逻辑。
15 |
16 | ## 安装
17 |
18 | ``` bash
19 | $ npm install -g lazy-mock
20 | ```
21 |
22 | ## 使用
23 |
24 | ``` bash
25 | $ lazy-mock init
26 | ```
27 |
28 | 例子:
29 |
30 | ``` bash
31 | $ lazy-mock init d2-admin-pm my-project
32 | ```
33 |
34 | 在 my-project 目录下执行 npm install
35 |
36 | ## 目前支持模板
37 | * [rbac](https://github.com/lazy-mock-templates/rbac) --- 包含 RBAC 权限控制模型
38 | * [d2-admin-pm](https://github.com/lazy-mock-templates/d2-admin-pm) --- 包含 [d2-admin-pm](https://github.com/wjkang/d2-admin-pm) 的 curd 模板
39 |
40 | >支持模板开发及自定义,详细看文档
41 |
42 | ## 特性
43 | - 轻松对接`mock.js`,`faker.js`等假数据生成工具
44 | - 不需要数据库,直接持久化数据到JSON文件
45 | - 相比json-server单JSON文件,支持一个实体一个JSON文件
46 | - 默认包含了`jwt`实现的登录与登出,基于`RBAC`模型的权限控制
47 | - 使用 `async/await` 处理异步问题
48 | - `MVC`代码分层结构
49 | - 内置简单代码生成器
50 |
51 |
52 |
53 | [文档](https://wjkang.github.io/lazy-mock)
54 |
55 | ## Stargazers over time
56 |
57 | [](https://starcharts.herokuapp.com/wjkang/lazy-mock)
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/assets/uploads/.gitkeep:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/build/dev-server.js:
--------------------------------------------------------------------------------
1 | require('@babel/register')
2 | require('@babel/polyfill')
3 | require('../src/app')
4 |
--------------------------------------------------------------------------------
/ca-cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIICDDCCAXUCFGXtwq5k0yQ1BdRHeBAO5ofUXO9IMA0GCSqGSIb3DQEBCwUAMEUx
3 | CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
4 | cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTkwOTE3MTExMTEyWhcNMjkwOTE0MTEx
5 | MTEyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
6 | CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GN
7 | ADCBiQKBgQC9bQDsdARAap/0ZSEpQWpDrepnmO6gRQf86lWdBiISGWgq/bOFdH3A
8 | qq+Pf43xxlZMHGrS2qk3vpw2J19KXYmxP0BZo0CHXTc62VHH3j0HXEwq2M00UAba
9 | vpiCMdPiugnCx4Z7Vr8T+oNSPizjFAaFqJUtWtd4crV1I6wmCSF1cQIDAQABMA0G
10 | CSqGSIb3DQEBCwUAA4GBAGdhWZevVKz3Hvivev7cni5mMHcfnqZjilVhaGxMh4WN
11 | apdYf6Ur1A+We5goKEIGMNpzizrjBaCcposib35fdjTUhKKfYmycYQWmriMhPKKF
12 | Ojgh7QZYAlKidG65qkFmku8ez0KUzMtP03oSN3Se1tedPBuHCfGC4sIoVMn7REcg
13 | -----END CERTIFICATE-----
14 |
--------------------------------------------------------------------------------
/ca-key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXwIBAAKBgQC9bQDsdARAap/0ZSEpQWpDrepnmO6gRQf86lWdBiISGWgq/bOF
3 | dH3Aqq+Pf43xxlZMHGrS2qk3vpw2J19KXYmxP0BZo0CHXTc62VHH3j0HXEwq2M00
4 | UAbavpiCMdPiugnCx4Z7Vr8T+oNSPizjFAaFqJUtWtd4crV1I6wmCSF1cQIDAQAB
5 | AoGBAIqBmZtLeZBgZnUdPRIdcsXp9OurN1CZKS4VamRWh7MUQMaumwWKGCk4pQYY
6 | DoIqtA8S+EkU+YZ5KV+vik2l93cQhRzp37TI9C2/j7STYutMC7ac2qaT+0OzyDEu
7 | tiG5XN+rQzjFiAQfojbvmJauu2txzO8KtFE96ZKDsrig0RrBAkEA56uNLvVaN+2d
8 | xNuWZSNM9TSwu8FN0w5nvdt8g+jQsRkKdye39MhbsvwOTF+Yxi5s5NnTsEev7tUU
9 | XPCi4xaRtwJBANFRtr+zjKlMvYpukFWsaWCO31tEIAVLZ7mk+hpu9Q+zTNPRBdYJ
10 | IYtyoXIEpSAwVr/XNftnX/dhyT4HWVUAkhcCQQCeQZl7Z42OwRpSXPLa+gdbRfgo
11 | +j7Qm3mQv3vKnGLbZ9C3XwGSDMBff0HBOFijoRkwKAEs3Xu4egSkDJoo6MT3AkEA
12 | vIYORGZgX/MgG1gtYxxf5HmJrdeTx3D8wPVX1QruaO+iWHw/92BN+ByMT/bjCjS/
13 | TRV2JzIZ+uL1r4pK6QYUjQJBALxKE67kfWmYwbjaE+0M161dLW4LoOuW3ck+mWhG
14 | fe0o0mxoSScNeoHo8v0yG/PPEEq/sLPOu62PBeUE1PtbrRw=
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/ca-req.csr:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE REQUEST-----
2 | MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
3 | MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
4 | AQUAA4GNADCBiQKBgQC9bQDsdARAap/0ZSEpQWpDrepnmO6gRQf86lWdBiISGWgq
5 | /bOFdH3Aqq+Pf43xxlZMHGrS2qk3vpw2J19KXYmxP0BZo0CHXTc62VHH3j0HXEwq
6 | 2M00UAbavpiCMdPiugnCx4Z7Vr8T+oNSPizjFAaFqJUtWtd4crV1I6wmCSF1cQID
7 | AQABoAAwDQYJKoZIhvcNAQELBQADgYEAfYptIQjk0rd0gzjVNcYCPGx27k3Vx+6y
8 | gKdcuPLA6WIdUX86jUDFDiaGnS/td44cvPUV3+BDPtHNtW5gLF72DmSSQtUF4Txt
9 | lwhjUu3nXQGo4aXF3CUikH2YvnrcgYcmkN8n29jwjqPqkexRMDq+69qzuMVMSDjO
10 | Uv4LtZHh7t4=
11 | -----END CERTIFICATE REQUEST-----
12 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## 关于lazy mock
2 | > 一个快速生成后端模拟数据的懒人工具
3 |
4 | ## 是什么
5 |
6 | lazy mock 是一个使用`koa2`构建的,`lowdb`持久化数据到JSON文件的快速生成后端模拟数据的工具。只需要简单的配置就可以实现和json-server一样的功能,但是比json-server更加灵活,后期可配置性更强,完全可以模拟真实后端业务逻辑。
7 |
8 | lazy mock默认包含了`jwt`实现的登录与登出,实现了基于`RBAC`模型的通用权限控制逻辑。
9 |
10 | 查看[快速开始](quickstart.md)了解详情。
11 |
12 | ## 特性
13 | - 轻松对接`mock.js`,`faker.js`等假数据生成工具
14 | - 不需要数据库,直接持久化数据到JSON文件
15 | - 相比json-server单JSON文件,支持一个实体一个JSON文件
16 | - 默认包含了`jwt`实现的登录与登出,基于`RBAC`模型的权限控制
17 | - 使用 `async/await` 处理异步问题
18 | - `MVC`代码分层结构
19 | - 内置简单代码生成器
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/docs/_coverpage.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # lazy mock
4 |
5 | > 一个快速生成后端模拟数据的懒人工具
6 |
7 | [GitHub](https://github.com/wjkang/lazy-mock)
8 | [Get Started](#关于lazy-mock)
--------------------------------------------------------------------------------
/docs/_navbar.md:
--------------------------------------------------------------------------------
1 | * 使用案例
2 |
3 | * [3YAdmin](https://github.com/wjkang/3YAdmin)
4 | * [vue-quasar-admin](https://github.com/wjkang/vue-quasar-admin)
5 | * [d2-admin-pm](https://github.com/wjkang/d2-admin-pm)
--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
1 | * 入门
2 |
3 | * [快速开始](quickstart.md)
4 | * [构建你自己的mock服务](buildmock.md)
5 |
6 | * 使用权限控制
7 |
8 | * [权限模型](permission.md)
9 | * [权限接口](permissionapi.md)
10 |
11 | * 定制
12 | * [模板定制](template.md)
13 | * [配置](configuration.md)
14 |
15 | * 更多
16 |
17 | * [不仅仅mock](notonlymock.md)
--------------------------------------------------------------------------------
/docs/buildmock.md:
--------------------------------------------------------------------------------
1 | ## 配置实体
2 | 修改 `templates/config/model.js` ,比如
3 | ```js
4 | var shortid = require('shortid')
5 | var Mock = require('mockjs')
6 | var Random = Mock.Random
7 |
8 | //必须包含字段id
9 | export default {
10 | name: "book",
11 | Name: "Book",
12 | properties: [
13 | {
14 | key: "id",
15 | title: "id"
16 | },
17 | {
18 | key: "name",
19 | title: "书名"
20 | },
21 | {
22 | key: "author",
23 | title: "作者"
24 | },
25 | {
26 | key: "press",
27 | title: "出版社"
28 | }
29 | ],
30 | buildMockData: function () {//不需要生成设为false
31 | let data = []
32 | for (let i = 0; i < 100; i++) {
33 | data.push({
34 | id: shortid.generate(),
35 | name: Random.cword(5, 7),
36 | author: Random.cname(),
37 | press: Random.cword(5, 7)
38 | })
39 | }
40 | return data
41 | }
42 | }
43 | ```
44 |
45 | ## 生成代码
46 |
47 | 内部使用`nunjucks`写了个简单的代码生成器,读取配置信息直接生成`CURD`代码
48 | ```
49 | npm run code
50 | ```
51 | !> 如果程序运行过程中执行`npm run code`,程序会自动重启,可直接调用新增的接口
52 |
53 | ## 调用接口
54 |
55 | 接口默认需要授权访问,请求头需要带上token。
56 |
57 | >token 登录成功后取到
58 |
59 | 以`axios`为例(后面请求接口也是使用`axios`)
60 | ```js
61 | import axios from 'axios';
62 |
63 | const request = axios.create({
64 | baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : 'productBaseUrl', // api的base_url
65 | timeout: 20000 // request timeout
66 | })
67 |
68 | request.interceptors.request.use(config => {
69 | config.headers['Authorization'] = 'Bearer ' + 登陆后获取到的token// 让每个请求携带token
70 | return config
71 | }, error => {
72 | Promise.reject(error)
73 | })
74 | ```
75 |
76 | ### Insert
77 |
78 | ```js
79 | request({
80 | url: '/book/save',
81 | method: 'post',
82 | data: {
83 | name: "javascript",
84 | author: "xxoo",
85 | press: "xxoo出版社",
86 | }
87 | }).then(res => {
88 | console.log(res.data)
89 | })
90 | ```
91 | !> 新增不用传入id
92 |
93 | ### Delete
94 |
95 | ```js
96 | request({
97 | url: '/book/del',
98 | method: 'delete',
99 | params: {
100 | id:'dsdsd23e23e'
101 | }
102 | })
103 | ```
104 |
105 | ```js
106 | request({
107 | url: '/book/batchdel',
108 | method: 'delete',
109 | params: {
110 | ids:"['sd23edese343d3','433krker346lkrtr']"
111 | })
112 | ```
113 | !> 注意参数的格式
114 |
115 | ### Update
116 | ```js
117 | request({
118 | url: '/book/save',
119 | method: 'post',
120 | data: {
121 | id: "1",
122 | name: "javascript",
123 | author: "xxoo",
124 | press: "xxoo出版社",
125 | }
126 | }).then(res => {
127 | console.log(res.data)
128 | })
129 | ```
130 | !>更新需要传入id
131 |
132 | ### Query
133 |
134 | ```js
135 | request({
136 | url: '/book/dsdsd23e23e',
137 | method: 'get'
138 | })
139 | ```
140 |
141 | ```js
142 | request({
143 | url: '/book/paged',
144 | method: 'get',
145 | params: {
146 | pageIndex:1,
147 | pageSize:10,
148 | sortBy:'name',
149 | descending:'true',
150 | id:'',
151 | name:'',
152 | author:'',
153 | press:''
154 | })
155 | ```
156 | >所有参数都不是必须
157 |
158 | >默认升序,倒序则将`descending`设为`'true'`
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/docs/configuration.md:
--------------------------------------------------------------------------------
1 | ## 修改应用监听端口
2 | 修改`src/config.js`文件
3 |
4 | ## 生成mock数据
5 | 配置`templates/config/model.js`
6 |
7 | ```js
8 | buildMockData: function () {//不需要生成设为false
9 | let data = []
10 | for (let i = 0; i < 100; i++) {
11 | data.push({
12 | id: shortid.generate(),
13 | name: Random.cword(5, 7),
14 | author: Random.cname(),
15 | press: Random.cword(5, 7)
16 | })
17 | }
18 | return data
19 | }
20 |
21 | ```
22 | 生成代码的时候会执行`buildMockData`,将生成的mock数据填充到对应db.json文件。
23 |
24 | 默认使用[mockjs](https://github.com/nuysoft/Mock),更多规则可查看其[文档](https://github.com/nuysoft/Mock)。也可以自行安装[faker.js](https://github.com/Marak/faker.js)使用
25 |
26 | ## 修改接口名称
27 |
28 | * 修改模板
29 |
30 | 修改`templates/server/route.njk`代码模板,后续生成代码就会以新的模板来生成。
31 |
32 | * 直接修改
33 |
34 | 找到对应的路由文件(`src/routes`下,路由文件名称会以实体名称生成),直接修改即可。
35 |
36 | ## 授权配置
37 |
38 | 默认需要授权访问,请求的时候请求头需要带上 token
39 |
40 | * 完全去掉授权限制
41 |
42 | `src/app.js`找到下行代码
43 | ```js
44 | .use(jwt({ secret: publicKey }).unless({ path: [/^\/public|\/auth\/login|\/assets/] }))
45 | ```
46 | 直接去掉即可。
47 | >完全去掉授权限制 权限控制功能也会失效
48 |
49 | * 部分接口去掉授权显示
50 |
51 | 还是上面那行代码,根据规则修改
52 | ```js
53 | { path: [/^\/public|\/auth\/login|\/assets/] }
54 | ```
55 |
56 | ## 修改数据返回格式
57 |
58 | 修改`src/lib/responseTemplate.js`
59 |
60 | ```js
61 | export let businessError = (ctx,msg) => {
62 | ctx.body = {
63 | statusCode: 500,
64 | msg: msg,
65 | data: null
66 | }
67 | }
68 |
69 | export let success = (ctx,data) => {
70 | ctx.body = {
71 | statusCode: 200,
72 | msg: '',
73 | data: data
74 | }
75 | }
76 | ```
77 |
78 | ## 配置接口访问权限
79 | 使用已经实现的RBAC权限控制,可以实现接口的访问权限控制。
80 |
81 | 假如某个接口只允许特定的角色或具备特定权限的人访问,需要修改对应接口的路由配置,比如
82 | ```js
83 | .get('/function/pagedlist', PermissionCheck({ permission: ["function_view"], role: ["test"] }), controllers.function.getFunctionPagedList)
84 | ```
85 | 使用中间件`PermissionCheck`做权限校验,如果当前用户没有登录,或者不具备function_view权限并且不属于test角色,访问此接口的时候会返回相应的错误信息。
86 |
87 | >permission为功能编码,role为角色编码,如果用户属于admin则不做校验
88 |
89 |
90 | ## 添加业务逻辑
91 |
92 | 如果简单的增删改查不能满足你的要求。你可以自行修改代码,添加你需要的功能。
93 |
94 | 首先需要了解一下整个应用的结构及调用过程。
95 |
96 | * **`src\routes`**
97 |
98 | 生成代码时会在该文件夹下生成相应的路由文件,比如`bookRoute.js`。
99 |
100 | 路由配置里,每个接口被访问的时候,会调用对应controller的方法
101 | ```js
102 | .post('/auth/login', controllers.auth.login)
103 | ```
104 | 比如登陆的时候,调用`auth`控制器的`login`方法
105 |
106 | * **`src\controllers`**
107 |
108 | 生成代码时会在该文件夹下生成相应的控制器文件,比如`book.js`。
109 |
110 | 控制器里会引入相应的实体的服务,也可引入多个实体的服务
111 | ```js
112 | import menuService from '../services/memuService'
113 | import roleService from '../services/roleService'
114 | ```
115 | 调用服务里的方法来完成某些功能需求,比如
116 | ```js
117 | export let getMenuFunctions = async (ctx) => {
118 | let menuId = ctx.query.menuId
119 | let roleId = ctx.query.roleId
120 | let [menuFunctions, roleFunctions] =
121 | await Promise.all([menuService.getMenuFunctions(menuId), roleService.getRoleFunctions(roleId)])
122 | return responseTemplate.success(ctx, {
123 | menuFunctions: menuFunctions,
124 | roleFunctions: roleFunctions
125 | })
126 | }
127 | ```
128 |
129 | * **`src\services`**
130 |
131 | 生成代码时会在该文件夹下生成相应的服务文件,比如`bookService.js`。
132 | 服务里会引入相应的model,也可以引入其它服务
133 | ```js
134 | import model from '../models/baseModel'
135 | import roleService from './roleService'
136 | import functionService from './functionService'
137 | ```
138 |
139 | * **`src\models`**
140 |
141 | 生成代码时会在该文件夹下生成相应的model,比如`bookModel.js`。
142 | model里就是使用`lowdb`读取相应的db.json文件,提供获取`lowdb`实例的方法
143 | ```js
144 | import path from 'path'
145 |
146 | const low = require('lowdb')
147 | const lodashId = require('lodash-id')
148 | const FileAsync = require('lowdb/adapters/FileAsync')
149 | const dbFile = path.join(__dirname, '../db/book_db.json')
150 | const adapter = new FileAsync(dbFile)
151 | let instance = undefined
152 | module.exports = {
153 | init: function (context) {
154 | return new Promise((resolve, reject) => {
155 | if (instance === undefined) {
156 | low(adapter).then(db => {
157 | db._.mixin(lodashId)
158 | instance = db;
159 | resolve(db.get(context))
160 | })
161 | } else {
162 | resolve(instance.get(context))
163 | }
164 | })
165 | },
166 | read: () => {
167 | return new Promise((resolve, reject) => {
168 | if (instance === undefined) {
169 | resolve()
170 | }
171 | else {
172 | instance.read().then(() => {
173 | resolve()
174 | })
175 | }
176 | })
177 | }
178 |
179 | }
180 |
181 | ```
182 |
183 | * **`src\db`**
184 |
185 | 生成代码时会在该文件夹下生成相应的`JSON`文件,比如`book_db.json`。
186 |
187 | json文件的作用就是持久化数据。
188 |
189 | 到此,相信你已经知道如何去修改或添加代码来实现你要的功能。
190 |
191 |
192 |
--------------------------------------------------------------------------------
/docs/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/5.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud1.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud10.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud11.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud2.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud3.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud4.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud5.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud6.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud7.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud8.jpg
--------------------------------------------------------------------------------
/docs/images/dcloud9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/dcloud9.jpg
--------------------------------------------------------------------------------
/docs/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/favicon.png
--------------------------------------------------------------------------------
/docs/images/rbac.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/docs/images/rbac.jpg
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | lazy mock
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/docs/notonlymock.md:
--------------------------------------------------------------------------------
1 | 借助现有的权限管理和持久化数据的功能,`lazy mock`可以作为demo的后端服务支持,甚至可以做为一个博客的后台系统部署到服务器上。
2 |
3 | ## 部署
4 |
5 | 以[daocloud](https://dashboard.daocloud.io)+docker部署为例
6 |
7 | ### 创建项目
8 |
9 | `daocloud`支持多个流行git仓库,也可以使用你自己的git仓库地址
10 |
11 | 
12 |
13 | ### 流程定义
14 |
15 | 编辑那刚才创建的项目,将默认测试任务删除
16 |
17 | 
18 |
19 | ### 构建镜像
20 |
21 | 项目右边才做菜单,选择“手动构建”,然后选择要构建的分支
22 |
23 | 
24 |
25 | 成功后到镜像仓库就可以看到新构建的镜像
26 |
27 | 
28 |
29 | ### 部署应用
30 |
31 | 点击“部署最新版本”
32 |
33 | 
34 |
35 | 填写应用名称,选择镜像版本以及主机(如何配置主机,可以看`daocloud`的文档,那里会更加详细)
36 |
37 | 点击下一步,继续配置
38 |
39 | 
40 |
41 | 然后点部署即可
42 |
43 | 最后还要将项目`src/db`下所有文件拷贝到上面配置的云主机的路径下(`/apps/3YAdmin/db`)
44 |
45 | 以下是我成功部署的两个应用
46 |
47 | 
48 |
49 | ### 持续集成
50 |
51 | 回到流程定义界面,设置“默认构建任务”,设置触发条件
52 |
53 | 
54 |
55 | 点击“发布阶段”的“添加并行任务”
56 |
57 | 
58 |
59 | 选择发布到自有主机,然后选择之前创建的应用
60 |
61 | 
62 |
63 |
64 | 
65 |
66 | 最后点击创建任务。以后每当相应的分支提交了代码,会自动构建镜像,并且以最新镜像部署应用
67 |
68 | >需要手动删除云主机上的旧的镜像,避免占用磁盘空间
69 |
70 |
71 | ## 其它接口
72 |
73 | 以生产环境的方式部署后,用户的访问记录会记录在`request_log_db.json`文件中。
74 |
75 | 查看的接口是
76 | ```js
77 | request({
78 | url: '/requestlog/pagedlist',
79 | method: 'get',
80 | params: {
81 | pageIndex: 1,
82 | pageSize: 10,
83 | sortBy: 'createdDate',
84 | descending: true
85 | }
86 | })
87 | ```
88 |
89 | 如果是将应用作为demo后端服务部署,可能有时候需要将应用的数据重置为最开始部署的样子。对应的接口为
90 | ```js
91 | request({
92 | url: '/resetdb',
93 | method: 'post'
94 | })
95 | ```
96 | 其实就是将`db_backup.json`的内容覆盖到`db.json`里。如果其他的实体的db.json文件也需如此,可按照代码自行添加
97 |
98 |
--------------------------------------------------------------------------------
/docs/permission.md:
--------------------------------------------------------------------------------
1 | # 权限模型
2 |
3 | lazy mock基于RBAC模型实现了权限控制。
4 |
5 | 
--------------------------------------------------------------------------------
/docs/permissionapi.md:
--------------------------------------------------------------------------------
1 | ## 授权
2 |
3 | ### 登录
4 |
5 | #### Request
6 |
7 | ```js
8 | request({
9 | url: '/auth/login',
10 | method: 'post',
11 | data: qs.stringify({
12 | username: 'admin',
13 | password: '123'
14 | })
15 | })
16 | ```
17 | >使用了`qs`的`stringify`,与直接传入js对象的区别是:使用前者,axios会将请求头`content-type`设为`application/x-www-form-urlencoded`,避免浏览器发起`options`请求;后者使用默认的`application/json`。后端`koa`接收的时候,都是通过`ctx.request.body`接收。
18 |
19 | #### Response
20 |
21 | ```js
22 | {
23 | "statusCode": 200,
24 | "msg": "",
25 | "data": {
26 | "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxIiwiaWF0IjoxNTMyMzE2NzIzLCJleHAiOjE1MzI5MjE1MjN9.fCWajolT_ttl_2UGHSw16_lRUNFwxlU6Tl30pt33kaY"
27 | }
28 | }
29 | ```
30 |
31 | #### Error
32 | ```js
33 | {
34 | "statusCode": 500,
35 | "msg": "账号或密码错误!",
36 | "data": null
37 | }
38 | ```
39 |
40 | ### 登出
41 |
42 | #### Request
43 | ```js
44 | request({
45 | url: '/auth/logout',
46 | method: 'post'
47 | })
48 | ```
49 | #### Response
50 | ```js
51 | {
52 | "statusCode": 200,
53 | "msg": "",
54 | "data": null
55 | }
56 | ```
57 |
58 | ## 用户
59 |
60 | ### 获取用户信息
61 |
62 | #### Request
63 | ```js
64 | request({
65 | url: '/user/info',
66 | method: 'get'
67 | })
68 | ```
69 |
70 | #### Response
71 | ```js
72 | {
73 | "statusCode": 200,
74 | "msg": "",
75 | "data": {
76 | "userName": "admin",
77 | "userRole": [
78 | "role_test",
79 | "role_website_admin"
80 | ],
81 | "userPermission": [
82 | "post_edit",
83 | "post_view",
84 | "post_del",
85 | "menu_view",
86 | "role_view",
87 | "role_permission_view",
88 | "role_user_view",
89 | "user_role_view",
90 | "user_view",
91 | "department_view",
92 | "position_view"
93 | ],
94 | "isAdmin": 1,
95 | "avatarUrl": "https://api.adorable.io/avatars/85/abott@adorable.png"
96 | }
97 | }
98 | ```
99 | > 包含用户角色权限信息
100 |
101 | ### 新增或更新用户
102 | #### Request
103 | ```js
104 | request({
105 | url: '/user/save',
106 | method: 'post',
107 | data: {
108 | id: "1",
109 | name: "admin",
110 | email: "123@qq.com",
111 | phone: "18290024784",
112 | trueName: "张三"
113 | }
114 | })
115 | ```
116 | !>不设置id则为新增,否则为更新
117 |
118 | #### Response
119 | ```js
120 | {
121 | "statusCode": 200,
122 | "msg": "",
123 | "data": null
124 | }
125 | ```
126 |
127 | ### 删除用户
128 | #### Request
129 | ```js
130 | request({
131 | url: '/user/del',
132 | method: 'delete',
133 | params: {
134 | id: "1"
135 | }
136 | })
137 | ```
138 | ```js
139 | request({
140 | url: '/user/batchdel',
141 | method: 'delete',
142 | params: {
143 | ids:"['1','2']"
144 | })
145 | ```
146 | #### Response
147 | ```js
148 | {
149 | "statusCode": 200,
150 | "msg": "",
151 | "data": null
152 | }
153 | ```
154 | #### Error
155 | ```js
156 | {
157 | "statusCode": 500,
158 | "msg": "不能删除管理员账号",
159 | "data": null
160 | }
161 | ```
162 | ### 用户列表
163 | #### Request
164 | ```js
165 | request({
166 | url: '/user/pagedlist',
167 | method: 'get',
168 | params: {
169 | pageIndex: 1,
170 | pageSize: 10,
171 | sortBy: 'name',
172 | descending: true,
173 | filter: {
174 | name: 'admin',
175 | email: '',
176 | }
177 | }
178 | })
179 | ```
180 | #### Response
181 | ```js
182 | {
183 | "statusCode": 200,
184 | "msg": "",
185 | "data": {
186 | "totalCount": 1,
187 | "rows": [
188 | {
189 | "id": "1",
190 | "name": "admin",
191 | "password": "123",
192 | "email": "123@qq.com",
193 | "phone": "18290024784",
194 | "trueName": "张三"
195 | }
196 | ]
197 | }
198 | }
199 | ```
200 |
201 | ## 角色
202 | ### 新增或更新角色
203 | #### Request
204 | ```js
205 | request({
206 | url: '/role/save',
207 | method: 'post',
208 | data: {
209 | id: "1",
210 | name: "网站管理员",
211 | code: "role_website_admin",
212 | description: "xxoo"
213 | }
214 | })
215 | ```
216 | !>不设置id则为新增,否则为更新
217 | #### Response
218 | ```js
219 | {
220 | "statusCode": 200,
221 | "msg": "",
222 | "data": null
223 | }
224 | ```
225 |
226 | ### 删除角色
227 | #### Request
228 | ```js
229 | request({
230 | url: '/role/del',
231 | method: 'delete',
232 | params: {
233 | id: "1"
234 | }
235 | })
236 | ```
237 | ```js
238 | request({
239 | url: '/role/batchdel',
240 | method: 'delete',
241 | params: {
242 | ids:"['1','2']"
243 | })
244 | ```
245 | #### Response
246 | ```js
247 | {
248 | "statusCode": 200,
249 | "msg": "",
250 | "data": null
251 | }
252 | ```
253 |
254 | ### 角色列表
255 | #### Request
256 | ```js
257 | request({
258 | url: '/role/pagedlist',
259 | method: 'get',
260 | params: {
261 | pageIndex: 1,
262 | pageSize: 10,
263 | sortBy: 'name',
264 | descending: true,
265 | filter: {
266 | name: '',
267 | code: '',
268 | }
269 | }
270 | })
271 | ```
272 | #### Response
273 | ```js
274 | {
275 | "statusCode": 200,
276 | "msg": "",
277 | "data": {
278 | "totalCount": 2,
279 | "rows": [
280 | {
281 | "name": "测试",
282 | "code": "role_test",
283 | "description": "具备全部数据查看权限,没有相关系统设置的操作权限",
284 | "id": "40af8f42-3b18-410c-9fc2-aba8158e92d7"
285 | },
286 | {
287 | "name": "网站模块管理员",
288 | "code": "role_website_admin",
289 | "description": "网站模块管理员",
290 | "id": "9fc587ff-3543-4f58-93ab-15f64d3d19e5"
291 | }
292 | ]
293 | }
294 | }
295 | ```
296 |
297 | ## 功能
298 | ### 新增或更新功能
299 | #### Request
300 | ```js
301 | request({
302 | url: '/function/save',
303 | method: 'post',
304 | data: {
305 | id: "2817154d-2df0-4875-ac26-5c3dd27061ad",
306 | name: "2-文章编辑",
307 | code: "post_edit",
308 | description: "文章编辑",
309 | moduleId: 3,
310 | module: "文章管理"
311 | }
312 | })
313 | ```
314 | !>不设置id则为新增,否则为更新
315 | >`moduleId`为菜单id,`module`为菜单名称,方便查询
316 |
317 | #### Response
318 | ```js
319 | {
320 | "statusCode": 200,
321 | "msg": "",
322 | "data": null
323 | }
324 | ```
325 |
326 | ### 删除功能
327 | #### Request
328 | ```js
329 | request({
330 | url: '/function/del',
331 | method: 'delete',
332 | params: {
333 | id: "1"
334 | }
335 | })
336 | ```
337 | ```js
338 | request({
339 | url: '/function/batchdel',
340 | method: 'delete',
341 | params: {
342 | ids:"['1','2']"
343 | })
344 | ```
345 | #### Response
346 | ```js
347 | {
348 | "statusCode": 200,
349 | "msg": "",
350 | "data": null
351 | }
352 | ```
353 |
354 | ### 功能列表
355 | #### Request
356 | ```js
357 | request({
358 | url: '/function/pagedlist',
359 | method: 'get',
360 | params: {
361 | pageIndex: 1,
362 | pageSize: 10,
363 | sortBy: 'name',
364 | descending: true,
365 | filter: {
366 | name: '',
367 | code: '',
368 | module: '文章管理'
369 | }
370 | }
371 | })
372 | ```
373 | #### Response
374 | ```js
375 | {
376 | "statusCode": 200,
377 | "msg": "",
378 | "data": {
379 | "totalCount": 3,
380 | "rows": [
381 | {
382 | "name": "1-文章列表",
383 | "moduleId": 3,
384 | "module": "文章管理",
385 | "code": "post_view",
386 | "description": "文章列表",
387 | "id": "17684882-c610-4007-b357-e783631c059f"
388 | },
389 | {
390 | "name": "2-文章编辑",
391 | "code": "post_edit",
392 | "description": "文章编辑",
393 | "moduleId": 3,
394 | "module": "文章管理",
395 | "id": "2817154d-2df0-4875-ac26-5c3dd27061ad"
396 | },
397 | {
398 | "name": "3-文章删除",
399 | "code": "post_del",
400 | "description": "文章删除",
401 | "moduleId": 3,
402 | "module": "文章管理",
403 | "id": "8ab3b7b6-921a-4f8f-9bad-2fd106c870e1"
404 | }
405 | ]
406 | }
407 | }
408 | ```
409 |
410 | ## 角色用户
411 | ### 关联角色用户
412 | #### Request
413 | ```js
414 | request({
415 | url: '/user/editroleuser',
416 | method: 'post',
417 | data: {
418 | roleId: '',
419 | userId: '',
420 | action: 1
421 | }
422 | })
423 | ```
424 | !>`action`为1则添加关联,2则删除关联
425 | #### Reponse
426 | ```js
427 | {
428 | "statusCode": 200,
429 | "msg": "",
430 | "data": null
431 | }
432 | ```
433 |
434 | ## 角色权限
435 |
436 | ### 保存角色权限
437 | #### Request
438 | ```js
439 | request({
440 | url: '/role/savepermission',
441 | method: 'post',
442 | data: {
443 | roleId: '2817154d-2df0-4875-ac26-5c3dd27061ad',
444 | permissions: ['40af8f42-3b18-410c-9fc2-aba8158e92d7']
445 | }
446 | })
447 | ```
448 | >`permissions`为功能id列表,表明当前角色有权限访问这些功能或资源
449 |
450 | #### Response
451 | ```js
452 | {
453 | "statusCode": 200,
454 | "msg": "",
455 | "data": null
456 | }
457 | ```
458 |
459 | ## 菜单
460 | ### 添加或更新菜单
461 | #### Request
462 | ```js
463 | request({
464 | url: '/menu/savemenu',
465 | method: 'post',
466 | data: {
467 | id: 3,
468 | parentId: 2
469 | icon: "settings",
470 | title: "文章管理",
471 | name: "article",
472 | leftMemu: true,
473 | functionCode: "article_view",
474 | sort: 2,
475 | isLock: false
476 | }
477 | })
478 | ```
479 | !>不设置id则为新增,否则为更新。parentId为0则为顶级菜单
480 |
481 | #### Response
482 | ```js
483 | {
484 | "statusCode": 200,
485 | "msg": "",
486 | "data": null
487 | }
488 | ```
489 |
490 | ### 菜单列表
491 | #### Request
492 | ```js
493 | request({
494 | url: '/menu',
495 | method: 'get'
496 | })
497 | ```
498 | #### Response
499 | ```js
500 | {
501 | "statusCode": 200,
502 | "msg": "",
503 | "data": [
504 | {
505 | "id": 4,
506 | "parentId": 0,
507 | "path": "",
508 | "icon": "appstore",
509 | "title": "系统",
510 | "name": "系统",
511 | "leftMemu": true,
512 | "functionCode": "",
513 | "sort": 1,
514 | "children": [
515 | {
516 | "id": 5,
517 | "parentId": 4,
518 | "path": "/system",
519 | "icon": "setting",
520 | "title": "系统设置",
521 | "name": "系统设置",
522 | "leftMemu": true,
523 | "functionCode": "",
524 | "children": [
525 | {
526 | "id": 6,
527 | "parentId": 5,
528 | "path": "menu",
529 | "icon": "chrome",
530 | "title": "菜单管理",
531 | "name": "menu",
532 | "leftMemu": true,
533 | "functionCode": "menu_view",
534 | "children": [
535 |
536 | ]
537 | }
538 | ]
539 | },
540 | {
541 | "id": 7,
542 | "parentId": 4,
543 | "path": "/permission",
544 | "icon": "key",
545 | "title": "权限管理",
546 | "name": "权限管理",
547 | "leftMemu": true,
548 | "functionCode": "",
549 | "children": [
550 | {
551 | "id": 8,
552 | "parentId": 7,
553 | "path": "function",
554 | "icon": "solution",
555 | "title": "功能管理",
556 | "name": "function",
557 | "leftMemu": true,
558 | "functionCode": "function_view",
559 | "children": [
560 |
561 | ]
562 | },
563 | {
564 | "id": 20,
565 | "parentId": 7,
566 | "path": "role",
567 | "icon": "idcard",
568 | "title": "角色管理",
569 | "name": "role",
570 | "leftMemu": true,
571 | "functionCode": "role_view",
572 | "children": [
573 |
574 | ]
575 | },
576 | {
577 | "id": 9,
578 | "parentId": 7,
579 | "path": "rolepermission",
580 | "icon": "calculator",
581 | "title": "角色权限管理",
582 | "name": "rolepermission",
583 | "leftMemu": true,
584 | "functionCode": "role_permission_view",
585 | "children": [
586 |
587 | ]
588 | },
589 | {
590 | "id": 10,
591 | "parentId": 7,
592 | "path": "roleuser",
593 | "icon": "android",
594 | "title": "角色用户管理",
595 | "name": "roleuser",
596 | "leftMemu": true,
597 | "functionCode": "role_user_view",
598 | "children": [
599 |
600 | ]
601 | },
602 | {
603 | "id": 11,
604 | "parentId": 7,
605 | "path": "userrole",
606 | "icon": "dropbox",
607 | "title": "用户角色管理",
608 | "name": "userrole",
609 | "leftMemu": true,
610 | "functionCode": "user_role_view",
611 | "children": [
612 |
613 | ]
614 | }
615 | ]
616 | }
617 | ]
618 | }
619 | ]
620 | }
621 | ```
622 |
623 | ### 获取授权菜单
624 | #### Request
625 | ```js
626 | request({
627 | url: '/menu/getaccessmenu',
628 | method: 'get'
629 | })
630 | ```
631 | #### Response
632 | >如[菜单列表](#菜单列表)接口返回格式
633 |
634 | ### 菜单功能权限
635 | #### Request
636 | ```js
637 | request({
638 | url: '/menu/menufunctions',
639 | method: 'get',
640 | params: {
641 | menuId:0,
642 | roleId:'1'
643 | }
644 | })
645 | ```
646 | #### Response
647 | ```js
648 | {
649 | "statusCode": 200,
650 | "msg": "",
651 | "data": {
652 | "menuFunctions": [
653 | {
654 | "id": 6,
655 | "parentId": 5,
656 | "path": "menu",
657 | "icon": "chrome",
658 | "title": "菜单管理",
659 | "name": "menu",
660 | "leftMemu": true,
661 | "functionCode": "menu_view",
662 | "functions": [
663 | {
664 | "name": "1-菜单列表",
665 | "code": "menu_view",
666 | "description": "查看菜单列表",
667 | "moduleId": 6,
668 | "module": "菜单管理",
669 | "id": "6f3ef7c1-53fb-47b6-8800-0adff147c295"
670 | },
671 | {
672 | "name": "2-菜单编辑",
673 | "code": "menu_edit",
674 | "description": "菜单编辑",
675 | "moduleId": 6,
676 | "module": "菜单管理",
677 | "id": "f8297890-5a35-4704-b901-6b25074beb43"
678 | }
679 | ]
680 | },
681 | ...
682 | ],
683 | "roleFunctions": [
684 | {
685 | "roleId": "40af8f42-3b18-410c-9fc2-aba8158e92d7",
686 | "functionId": "2de3ee27-a382-4bbb-8c8f-fa6f73c99d1d",
687 | "moduleId": 20,
688 | "id": "6b0365da-54d2-49e6-bb28-e129d1bbce1a"
689 | },
690 | ...
691 | ]
692 | }
693 | }
694 | ```
695 | >`menuFunctions`为菜单列表,`menuFunctions.functions`菜单下相应的功能或资源
696 |
697 | >`roleFunctions`为对应角色具备的权限列表
698 |
699 | >此接口用在角色权限编辑
--------------------------------------------------------------------------------
/docs/quickstart.md:
--------------------------------------------------------------------------------
1 | ## 安装
2 |
3 | ``` bash
4 | $ npm install -g lazy-mock
5 | ```
6 |
7 | ## 使用
8 |
9 | ``` bash
10 | $ lazy-mock init rbac lazy-mock-rbac
11 | ```
12 |
13 | ## 安装依赖
14 | 进入 lazy-mock-rbac 文件夹,通过 `npm install` 安装依赖
15 | ```bash
16 | npm install
17 | ```
18 |
19 | ## 启动程序
20 | 通过 `gulp-nodemon` ,程序运行过程,修改受监控的文件时,程序会自动重启。
21 | ```bash
22 | npm run start
23 | ```
24 |
25 | ## 登录
26 | 使用 postman 模拟登陆,拿到 token
27 | 
28 |
29 | >内置账号:admin,密码:123
30 |
31 | >用户,权限管理等信息保存在 `src/db/db.json` 文件中,后面增加实体会生成独立的json文件
--------------------------------------------------------------------------------
/docs/template.md:
--------------------------------------------------------------------------------
1 | ### 目前支持的模板
2 | * [rbac](https://github.com/lazy-mock-templates/rbac) - 包含 RBAC 权限控制模型
3 | * [d2-admin-pm](https://github.com/lazy-mock-templates/d2-admin-pm) - 包含 [d2-admin-pm](https://github.com/wjkang/d2-admin-pm) 的 curd 模板
4 |
5 | ### 开发模板
6 |
7 | 参照 [rbac](https://github.com/lazy-mock-templates/rbac) 模板
8 |
9 | 自定义模板的使用:
10 | ``` bash
11 | $ lazy-mock init username/repo my-project
12 | ```
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | require('@babel/register')
2 | require('@babel/polyfill')
3 | const gulp = require('gulp')
4 | const nodemon = require('gulp-nodemon')
5 | const rename = require('gulp-rename')
6 | const nunjucksRender = require('gulp-nunjucks-render')
7 | const codeGenerate = require('./templates/generate')
8 | const migrate = require('./migration')
9 |
10 | var jsScript = 'node'
11 | if (process.env.npm_config_argv !== undefined && process.env.npm_config_argv.indexOf('debug') > 0) {
12 | jsScript = 'node debug'
13 | }
14 | gulp.task('nodemon', function () {
15 | return nodemon({
16 | script: 'build/dev-server.js',
17 | execMap: {
18 | js: jsScript
19 | },
20 | verbose: true,
21 | ignore: ['build/*.js', 'dist/*.js', 'nodemon.json', '.git', 'node_modules/**/node_modules', 'gulpfile.js', 'src/db', 'codeGenerate'],
22 | env: {
23 | NODE_ENV: 'development'
24 | },
25 | ext: 'js json'
26 | })
27 | })
28 |
29 | const ServerFullPath = require('./package.json').ServerFullPath;
30 | const FrontendFullPath = require('./package.json').FrontendFullPath;
31 | const nunjucksRenderConfig = {
32 | path: 'templates/server',
33 | envOptions: {
34 | tags: {
35 | blockStart: '<%',
36 | blockEnd: '%>',
37 | variableStart: '<$',
38 | variableEnd: '$>',
39 | commentStart: '<#',
40 | commentEnd: '#>'
41 | },
42 | },
43 | ext: '.js',
44 | ServerFullPath,
45 | FrontendFullPath
46 | }
47 |
48 | gulp.task('code', function() {
49 | require('events').EventEmitter.defaultMaxListeners = 0
50 | return codeGenerate.run(gulp, nunjucksRender, rename, nunjucksRenderConfig)
51 | })
52 |
53 | gulp.task('migrate', async function(cb) {
54 | let options = process.argv[4]
55 | if (options) {
56 | options = JSON.parse(options)
57 | }
58 | let modules = []
59 | for (let module of options) {
60 | let s = module.split(':')
61 | modules.push({
62 | entity: s[0],
63 | keys: s[1] ? s[1].split(',') : []
64 | })
65 | }
66 | await migrate(modules, cb)
67 | })
68 |
69 | gulp.task('add', async function(cb) {
70 | let options = process.argv[4].split('|')
71 | if (options.length === 1) {
72 | options[1] = 'new_api'
73 | }
74 | if (options.length === 2) {
75 | options[2] = options[1]
76 | }
77 | await codeGenerate.quickAdd(options, nunjucksRenderConfig)
78 | })
79 |
--------------------------------------------------------------------------------
/migration/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | server: {
3 | api: {
4 | target: '/src/routes/bookRoute.js',
5 | migrate: [
6 | {
7 | from: '/book/proxy',
8 | to: '/book/proxy123'
9 | },
10 | {
11 | from: '/book/paged',
12 | to: '/book/paged'
13 | },
14 | {
15 | from: '/book/:id',
16 | to: '/book/:id'
17 | },
18 | {
19 | from: '/book/del',
20 | to: '/book/del'
21 | },
22 | {
23 | from: '/book/batchdel',
24 | to: '/book/batchdel'
25 | },
26 | {
27 | from: '/book/save',
28 | to: '/book/save'
29 | }
30 | ],
31 | prefix: '',
32 | suffix: ''
33 | },
34 | controller: {
35 | target: '/src/controllers/book.js',
36 | migrate: [
37 | {
38 | from: 'getBook',
39 | to: 'getBook'
40 | },
41 | {
42 | from: 'getBookPagedList',
43 | to: 'getBookPagedList'
44 | },
45 | {
46 | from: 'delBook',
47 | to: 'delBook'
48 | },
49 | {
50 | from: 'delBooks',
51 | to: 'delBooks'
52 | },
53 | {
54 | from: 'saveBook',
55 | to: 'saveBook'
56 | },
57 | {
58 | from: 'bookProxy',
59 | to: 'bookProxy'
60 | }
61 | ],
62 | prefix: 'export let ',
63 | suffix: ' = async'
64 | }
65 | },
66 | frontEnd: {
67 | test: {
68 | target: '/wewew.txt',
69 | migrate: [
70 | {
71 | from: 'df',
72 | to: 'jjjjjjjjjjjj'
73 | }
74 | ],
75 | prefix: '',
76 | suffix: ''
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/migration/index.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 |
3 | let requireDirectory = require('require-directory')
4 | let modules = requireDirectory(module)
5 | const ServerFullPath = require('../package.json').ServerFullPath
6 | const FrontEndFullPath = require('../package.json').FrontendFullPath
7 | module.exports = async function migrate(migrateModules, cb) {
8 | for (let migrateModule of migrateModules) {
9 | let needMigrate = modules[migrateModule.entity]
10 | if (!needMigrate) {
11 | continue
12 | }
13 | // server
14 | if (migrateModule.keys.length > 0) {
15 | for (let key of migrateModule.keys) {
16 | if (key !== 'frontEnd' && key !== 'front') {
17 | await migrateItem(needMigrate.server[key], ServerFullPath)
18 | }
19 | }
20 | } else {
21 | for (let key in needMigrate.server) {
22 | await migrateItem(needMigrate.server[key], ServerFullPath)
23 | }
24 | }
25 | // front
26 | for (let key in needMigrate.frontEnd) {
27 | await migrateItem(needMigrate.frontEnd[key], FrontEndFullPath)
28 | }
29 | }
30 | cb()
31 | }
32 | async function migrateItem(item, rootPath) {
33 | if (!item) {
34 | return
35 | }
36 | const fileFullPath = rootPath + item.target
37 | let content = await fs.readFile(fileFullPath, 'utf-8')
38 | for (let detail of item.migrate) {
39 | let from = item.prefix + detail.from + item.suffix
40 | let to = item.prefix + detail.to + item.suffix
41 | content = content.replace(new RegExp(from, 'ig'), to)
42 | }
43 | await fs.writeFile(fileFullPath, content)
44 | }
45 |
--------------------------------------------------------------------------------
/nunjucks.tmLanguage:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | fileTypes
8 |
9 | nunjucks
10 | nunjs
11 | nj
12 | njk
13 | html
14 | htm
15 | template
16 | tmpl
17 | tpl
18 |
19 |
20 | name
21 | Nunjucks
22 |
23 | patterns
24 |
25 |
26 |
27 | begin
28 | <% comment %>
29 | end
30 | <% endcomment %>
31 | name
32 | comment.block.nunjucks
33 |
34 |
35 |
36 | begin
37 | <#
38 | end
39 | #>
40 | name
41 | comment.line.number-sign.nunjucks
42 |
43 |
44 |
45 | begin
46 | <\$
47 | captures
48 |
49 | 0
50 |
51 | name
52 | entity.tag.tagbraces.nunjucks
53 |
54 |
55 | end
56 | \$>
57 | name
58 | storage.type.variable.nunjucks
59 | patterns
60 |
61 |
62 | include
63 | #template_filter
64 |
65 |
66 |
67 |
68 |
69 | begin
70 | <%-|<%
71 | captures
72 |
73 | 0
74 |
75 | name
76 | entity.tag.tagbraces.nunjucks
77 |
78 |
79 | end
80 | -%>|%>
81 | name
82 | storage.type.templatetag.nunjucks
83 | patterns
84 |
85 |
86 | include
87 | #template_tag
88 |
89 |
90 | include
91 | #template_filter
92 |
93 |
94 |
95 |
96 |
97 | begin
98 | (<)([a-zA-Z0-9:]++)(?=[^>]*></\2>)
99 | beginCaptures
100 |
101 | 1
102 |
103 | name
104 | punctuation.definition.tag.begin.html
105 |
106 | 2
107 |
108 | name
109 | entity.name.tag.html
110 |
111 |
112 | end
113 | (>)(<)(/)(\2)(>)
114 | endCaptures
115 |
116 | 1
117 |
118 | name
119 | punctuation.definition.tag.end.html
120 |
121 | 2
122 |
123 | name
124 | punctuation.definition.tag.begin.html meta.scope.between-tag-pair.html
125 |
126 | 3
127 |
128 | name
129 | punctuation.definition.tag.begin.html
130 |
131 | 4
132 |
133 | name
134 | entity.name.tag.html
135 |
136 | 5
137 |
138 | name
139 | punctuation.definition.tag.end.html
140 |
141 |
142 | name
143 | meta.tag.any.html
144 | patterns
145 |
146 |
147 | include
148 | #tag-stuff
149 |
150 |
151 |
152 |
153 |
154 | begin
155 | (<\?)(xml)
156 | captures
157 |
158 | 1
159 |
160 | name
161 | punctuation.definition.tag.html
162 |
163 | 2
164 |
165 | name
166 | entity.name.tag.xml.html
167 |
168 |
169 | end
170 | (\?>)
171 | name
172 | meta.tag.preprocessor.xml.html
173 | patterns
174 |
175 |
176 | include
177 | #tag-generic-attribute
178 |
179 |
180 | include
181 | #string-double-quoted
182 |
183 |
184 | include
185 | #string-single-quoted
186 |
187 |
188 |
189 |
190 |
191 | begin
192 | <!--
193 | captures
194 |
195 | 0
196 |
197 | name
198 | punctuation.definition.comment.html
199 |
200 |
201 | end
202 | --\s*>
203 | name
204 | comment.block.html
205 | patterns
206 |
207 |
208 | match
209 | --
210 | name
211 | invalid.illegal.bad-comments-or-CDATA.html
212 |
213 |
214 | include
215 | #embedded-code
216 |
217 |
218 |
219 |
220 |
221 | begin
222 | <!
223 | captures
224 |
225 | 0
226 |
227 | name
228 | punctuation.definition.tag.html
229 |
230 |
231 | end
232 | >
233 | name
234 | meta.tag.sgml.html
235 | patterns
236 |
237 |
238 | begin
239 | (?i:DOCTYPE)
240 | captures
241 |
242 | 1
243 |
244 | name
245 | entity.name.tag.doctype.html
246 |
247 |
248 | end
249 | (?=>)
250 | name
251 | meta.tag.sgml.doctype.html
252 | patterns
253 |
254 |
255 | match
256 | "[^">]*"
257 | name
258 | string.quoted.double.doctype.identifiers-and-DTDs.html
259 |
260 |
261 |
262 |
263 | begin
264 | \[CDATA\[
265 | end
266 | ]](?=>)
267 | name
268 | constant.other.inline-data.html
269 |
270 |
271 | match
272 | (\s*)(?!--|>)\S(\s*)
273 | name
274 | invalid.illegal.bad-comments-or-CDATA.html
275 |
276 |
277 |
278 |
279 |
280 | include
281 | #embedded-code
282 |
283 |
284 | begin
285 | (?:^\s+)?(<)((?i:style))\b(?![^>]*/>)
286 | captures
287 |
288 | 1
289 |
290 | name
291 | punctuation.definition.tag.begin.html
292 |
293 | 2
294 |
295 | name
296 | entity.name.tag.style.html
297 |
298 | 3
299 |
300 | name
301 | punctuation.definition.tag.html
302 |
303 |
304 | end
305 | (</)((?i:style))(>)(?:\s*\n)?
306 | name
307 | source.css.embedded.html
308 | patterns
309 |
310 |
311 | include
312 | #tag-stuff
313 |
314 |
315 | begin
316 | (>)
317 | beginCaptures
318 |
319 | 1
320 |
321 | name
322 | punctuation.definition.tag.end.html
323 |
324 |
325 | end
326 | (?=</(?i:style))
327 | patterns
328 |
329 |
330 | begin
331 | <% comment %>
332 | end
333 | <% endcomment %>
334 | name
335 | comment.block.nunjucks
336 |
337 |
338 | begin
339 | <#
340 | end
341 | #>
342 | name
343 | comment.line.number-sign.nunjucks
344 |
345 |
346 | begin
347 | <\$
348 | captures
349 |
350 | 0
351 |
352 | name
353 | entity.tag.tagbraces.nunjucks
354 |
355 |
356 | end
357 | \$>
358 | name
359 | storage.type.variable.nunjucks
360 | patterns
361 |
362 |
363 | include
364 | #template_filter
365 |
366 |
367 |
368 |
369 | begin
370 | <%
371 | captures
372 |
373 | 0
374 |
375 | name
376 | entity.tag.tagbraces.nunjucks
377 |
378 |
379 | end
380 | %>
381 | name
382 | storage.type.templatetag.nunjucks
383 | patterns
384 |
385 |
386 | include
387 | #template_tag
388 |
389 |
390 | include
391 | #template_filter
392 |
393 |
394 |
395 |
396 | include
397 | #embedded-code
398 |
399 |
400 | include
401 | source.css.nunjucks
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 | begin
410 | (?:^\s+)?(<)((?i:script))\b(?![^>]*/>)
411 | beginCaptures
412 |
413 | 1
414 |
415 | name
416 | punctuation.definition.tag.begin.html
417 |
418 | 2
419 |
420 | name
421 | entity.name.tag.script.html
422 |
423 |
424 | end
425 | (?<=</(script|SCRIPT))(>)(?:\s*\n)?
426 | endCaptures
427 |
428 | 2
429 |
430 | name
431 | punctuation.definition.tag.html
432 |
433 |
434 | name
435 | source.js.embedded.html
436 | patterns
437 |
438 |
439 | include
440 | #tag-stuff
441 |
442 |
443 | begin
444 | (?<!</(?:script|SCRIPT))(>)
445 | captures
446 |
447 | 1
448 |
449 | name
450 | punctuation.definition.tag.end.html
451 |
452 | 2
453 |
454 | name
455 | entity.name.tag.script.html
456 |
457 |
458 | end
459 | (</)((?i:script))
460 | patterns
461 |
462 |
463 | begin
464 | <% comment %>
465 | end
466 | <% endcomment %>
467 | name
468 | comment.block.nunjucks
469 |
470 |
471 | begin
472 | <#
473 | end
474 | #>
475 | name
476 | comment.line.number-sign.nunjucks
477 |
478 |
479 | begin
480 | <\$
481 | captures
482 |
483 | 0
484 |
485 | name
486 | entity.tag.tagbraces.nunjucks
487 |
488 |
489 | end
490 | \$>
491 | name
492 | storage.type.variable.nunjucks
493 | patterns
494 |
495 |
496 | include
497 | #template_filter
498 |
499 |
500 |
501 |
502 | begin
503 | <%
504 | captures
505 |
506 | 0
507 |
508 | name
509 | entity.tag.tagbraces.nunjucks
510 |
511 |
512 | end
513 | %>
514 | name
515 | storage.type.templatetag.nunjucks
516 | patterns
517 |
518 |
519 | include
520 | #template_tag
521 |
522 |
523 | include
524 | #template_filter
525 |
526 |
527 |
528 |
529 | captures
530 |
531 | 1
532 |
533 | name
534 | punctuation.definition.comment.js
535 |
536 |
537 | match
538 | (//).*?((?=</script)|$\n?)
539 | name
540 | comment.line.double-slash.js
541 |
542 |
543 | begin
544 | /\*
545 | captures
546 |
547 | 0
548 |
549 | name
550 | punctuation.definition.comment.js
551 |
552 |
553 | end
554 | \*/|(?=</script)
555 | name
556 | comment.block.js
557 |
558 |
559 | include
560 | #php
561 |
562 |
563 | include
564 | source.js
565 |
566 |
567 |
568 |
569 |
570 |
571 | begin
572 | (</?)((?i:body|head|html)\b)
573 | captures
574 |
575 | 1
576 |
577 | name
578 | punctuation.definition.tag.begin.html
579 |
580 | 2
581 |
582 | name
583 | entity.name.tag.structure.any.html
584 |
585 |
586 | end
587 | (>)
588 | endCaptures
589 |
590 | 1
591 |
592 | name
593 | punctuation.definition.tag.end.html
594 |
595 |
596 | name
597 | meta.tag.structure.any.html
598 | patterns
599 |
600 |
601 | include
602 | #tag-stuff
603 |
604 |
605 |
606 |
607 | begin
608 | (</?)((?i:address|blockquote|dd|div|dl|dt|fieldset|form|frame|frameset|h1|h2|h3|h4|h5|h6|iframe|noframes|object|ol|p|ul|applet|center|dir|hr|menu|pre)\b)
609 | beginCaptures
610 |
611 | 1
612 |
613 | name
614 | punctuation.definition.tag.begin.html
615 |
616 | 2
617 |
618 | name
619 | entity.name.tag.block.any.html
620 |
621 |
622 | end
623 | (>)
624 | endCaptures
625 |
626 | 1
627 |
628 | name
629 | punctuation.definition.tag.end.html
630 |
631 |
632 | name
633 | meta.tag.block.any.html
634 | patterns
635 |
636 |
637 | include
638 | #tag-stuff
639 |
640 |
641 |
642 |
643 | begin
644 | (</?)((?i:a|abbr|acronym|area|b|base|basefont|bdo|big|br|button|caption|cite|code|col|colgroup|del|dfn|em|font|head|html|i|img|input|ins|isindex|kbd|label|legend|li|link|map|meta|noscript|optgroup|option|param|q|s|samp|script|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|var)\b)
645 | beginCaptures
646 |
647 | 1
648 |
649 | name
650 | punctuation.definition.tag.begin.html
651 |
652 | 2
653 |
654 | name
655 | entity.name.tag.inline.any.html
656 |
657 |
658 | end
659 | ((?: ?/)?>)
660 | endCaptures
661 |
662 | 1
663 |
664 | name
665 | punctuation.definition.tag.end.html
666 |
667 |
668 | name
669 | meta.tag.inline.any.html
670 | patterns
671 |
672 |
673 | include
674 | #tag-stuff
675 |
676 |
677 |
678 |
679 | begin
680 | (</?)([a-zA-Z0-9:]+)
681 | beginCaptures
682 |
683 | 1
684 |
685 | name
686 | punctuation.definition.tag.begin.html
687 |
688 | 2
689 |
690 | name
691 | entity.name.tag.other.html
692 |
693 |
694 | end
695 | (>)
696 | endCaptures
697 |
698 | 1
699 |
700 | name
701 | punctuation.definition.tag.end.html
702 |
703 |
704 | name
705 | meta.tag.other.html
706 | patterns
707 |
708 |
709 | include
710 | #tag-stuff
711 |
712 |
713 |
714 |
715 | include
716 | #entities
717 |
718 |
719 | match
720 | <>
721 | name
722 | invalid.illegal.incomplete.html
723 |
724 |
725 | match
726 | <
727 | name
728 | invalid.illegal.bad-angle-bracket.html
729 |
730 |
731 | repository
732 |
733 | template_filter
734 |
735 | patterns
736 |
737 |
738 | match
739 | (add|addslashes|capfirst|center|cut|date|default|default_if_none|dictsort|dictsortreversed|divisibleby|escape|escapejs|filesizeformat|first|fix_ampersands|floatformat|force_escape|get_digit|iriencode|join|last|length|length_is|linebreaks|linebreaksbr|linenumbers|ljust|lower|make_list|phone2numeric|pluralize|pprint|random|removetags|rjust|safe|safeseq|slice|slugify|stringformat|striptags|time|timesince|timeutil|title|truncatewords|truncatewords_html|unordered_list|upper|urlencode|urlize|urlizetrunc|wordcount|wordwrap|yesno|apnumber|intcomma|intword|naturalday|ordinal|STATIC_PREFIX)\b
740 | name
741 | keyword.control.filter.nunjucks
742 |
743 |
744 | begin
745 | :"|"
746 | end
747 | "
748 | name
749 | storage.type.attr.nunjucks
750 |
751 |
752 | begin
753 | :\'|\'
754 | end
755 | \'
756 | name
757 | storage.type.attr.nunjucks
758 |
759 |
760 | match
761 | \|
762 | name
763 | string.unquoted.filter-pipe.nunjucks
764 |
765 |
766 | match
767 | [a-zA-Z0-9_.]+
768 | name
769 | string.unquoted.tag-string.nunjucks
770 |
771 |
772 |
773 | template_tag
774 |
775 | patterns
776 |
777 |
778 | match
779 | \b(autoescape|endautoescape|block|endblock|blocktrans|endblocktrans|trans|plural|debug|extends|filter|firstof|for|empty|endfor|if|elif|else|endif|include|ifchanged|endifchanged|ifequal|endifequal|ifnotequal|endifnotequal|load|from|low|regroup|ssi|spaceless|endspaceless|templatetag|widthratio|with|endwith|csrf_token|cycle|url|lorem|thumbnail|endthumbnail|get_static_prefix)\b
780 | name
781 | keyword.control.tag-name.nunjucks
782 |
783 |
784 | match
785 | \b(and|or|not|in|by|as)\b
786 | name
787 | keyword.operator.nunjucks
788 |
789 |
790 |
791 | embedded-code
792 |
793 | patterns
794 |
795 |
796 | include
797 | #ruby
798 |
799 |
800 | include
801 | #php
802 |
803 |
804 | include
805 | #python
806 |
807 |
808 |
809 | entities
810 |
811 | patterns
812 |
813 |
814 | captures
815 |
816 | 1
817 |
818 | name
819 | punctuation.definition.entity.html
820 |
821 | 3
822 |
823 | name
824 | punctuation.definition.entity.html
825 |
826 |
827 | match
828 | (&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)
829 | name
830 | constant.character.entity.html
831 |
832 |
833 | match
834 | &
835 | name
836 | invalid.illegal.bad-ampersand.html
837 |
838 |
839 |
840 | php
841 |
842 | begin
843 | (?=(^\s*)?<\?)
844 | end
845 | (?!(^\s*)?<\?)
846 | patterns
847 |
848 |
849 | include
850 | source.php
851 |
852 |
853 |
854 | python
855 |
856 | begin
857 | (?:^\s*)<\?python(?!.*\?>)
858 | end
859 | \?>(?:\s*$\n)?
860 | name
861 | source.python.embedded.html
862 | patterns
863 |
864 |
865 | include
866 | source.python
867 |
868 |
869 |
870 | ruby
871 |
872 | patterns
873 |
874 |
875 | begin
876 | <%+#
877 | captures
878 |
879 | 0
880 |
881 | name
882 | punctuation.definition.comment.erb
883 |
884 |
885 | end
886 | %>
887 | name
888 | comment.block.erb
889 |
890 |
891 | begin
892 | <%+(?!>)=?
893 | captures
894 |
895 | 0
896 |
897 | name
898 | punctuation.section.embedded.ruby
899 |
900 |
901 | end
902 | -?%>
903 | name
904 | source.ruby.embedded.html
905 | patterns
906 |
907 |
908 | captures
909 |
910 | 1
911 |
912 | name
913 | punctuation.definition.comment.ruby
914 |
915 |
916 | match
917 | (#).*?(?=-?%>)
918 | name
919 | comment.line.number-sign.ruby
920 |
921 |
922 | include
923 | source.ruby
924 |
925 |
926 |
927 |
928 | begin
929 | <\?r(?!>)=?
930 | captures
931 |
932 | 0
933 |
934 | name
935 | punctuation.section.embedded.ruby.nitro
936 |
937 |
938 | end
939 | -?\?>
940 | name
941 | source.ruby.nitro.embedded.html
942 | patterns
943 |
944 |
945 | captures
946 |
947 | 1
948 |
949 | name
950 | punctuation.definition.comment.ruby.nitro
951 |
952 |
953 | match
954 | (#).*?(?=-?\?>)
955 | name
956 | comment.line.number-sign.ruby.nitro
957 |
958 |
959 | include
960 | source.ruby
961 |
962 |
963 |
964 |
965 |
966 |
968 | string-double-quoted
969 |
970 | begin
971 | "
972 | beginCaptures
973 |
974 | 0
975 |
976 | name
977 | punctuation.definition.string.begin.html
978 |
979 |
980 | end
981 | "
982 | endCaptures
983 |
984 | 0
985 |
986 | name
987 | punctuation.definition.string.end.html
988 |
989 |
990 | name
991 | string.quoted.double.html
992 | patterns
993 |
994 |
995 | include
996 | #embedded-code
997 |
998 |
999 | include
1000 | #entities
1001 |
1002 |
1003 |
1004 | string-single-quoted
1005 |
1006 | begin
1007 | '
1008 | beginCaptures
1009 |
1010 | 0
1011 |
1012 | name
1013 | punctuation.definition.string.begin.html
1014 |
1015 |
1016 | end
1017 | '
1018 | endCaptures
1019 |
1020 | 0
1021 |
1022 | name
1023 | punctuation.definition.string.end.html
1024 |
1025 |
1026 | name
1027 | string.quoted.single.html
1028 | patterns
1029 |
1030 |
1031 | include
1032 | #embedded-code
1033 |
1034 |
1035 | include
1036 | #entities
1037 |
1038 |
1039 |
1040 | tag-generic-attribute
1041 |
1042 | match
1043 | \b([a-zA-Z\-:]+)
1044 | name
1045 | entity.other.attribute-name.html
1046 |
1047 | tag-id-attribute
1048 |
1049 | begin
1050 | \b(id)\b\s*(=)
1051 | captures
1052 |
1053 | 1
1054 |
1055 | name
1056 | entity.other.attribute-name.id.html
1057 |
1058 | 2
1059 |
1060 | name
1061 | punctuation.separator.key-value.html
1062 |
1063 |
1064 | end
1065 | (?<='|")
1066 | name
1067 | meta.attribute-with-value.id.html
1068 | patterns
1069 |
1070 |
1071 | begin
1072 | "
1073 | beginCaptures
1074 |
1075 | 0
1076 |
1077 | name
1078 | punctuation.definition.string.begin.html
1079 |
1080 |
1081 | contentName
1082 | meta.toc-list.id.html
1083 | end
1084 | "
1085 | endCaptures
1086 |
1087 | 0
1088 |
1089 | name
1090 | punctuation.definition.string.end.html
1091 |
1092 |
1093 | name
1094 | string.quoted.double.html
1095 | patterns
1096 |
1097 |
1098 | include
1099 | #embedded-code
1100 |
1101 |
1102 | include
1103 | #entities
1104 |
1105 |
1106 |
1107 |
1108 | begin
1109 | '
1110 | beginCaptures
1111 |
1112 | 0
1113 |
1114 | name
1115 | punctuation.definition.string.begin.html
1116 |
1117 |
1118 | contentName
1119 | meta.toc-list.id.html
1120 | end
1121 | '
1122 | endCaptures
1123 |
1124 | 0
1125 |
1126 | name
1127 | punctuation.definition.string.end.html
1128 |
1129 |
1130 | name
1131 | string.quoted.single.html
1132 | patterns
1133 |
1134 |
1135 | include
1136 | #embedded-code
1137 |
1138 |
1139 | include
1140 | #entities
1141 |
1142 |
1143 |
1144 |
1145 |
1146 | tag-stuff
1147 |
1148 | patterns
1149 |
1150 |
1151 | include
1152 | #tag-id-attribute
1153 |
1154 |
1155 | include
1156 | #tag-generic-attribute
1157 |
1158 |
1159 | include
1160 | #string-double-quoted
1161 |
1162 |
1163 | include
1164 | #string-single-quoted
1165 |
1166 |
1167 | include
1168 | #embedded-code
1169 |
1170 |
1171 |
1172 |
1173 | scopeName
1174 | text.html.nunjucks
1175 | uuid
1176 | 0AAEDD0E-56AD-4B71-95C8-2FF271DE5B19
1177 |
1178 |
1179 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lazy-mock",
3 | "version": "1.0.0",
4 | "description": "lazy-mock",
5 | "author": "若邪",
6 | "scripts": {
7 | "start": "gulp nodemon",
8 | "dev": "gulp",
9 | "build": "babel src -d dist",
10 | "code": "gulp code",
11 | "migrate": "gulp migrate --options [\\\"book:api,controller\\\"] ",
12 | "add": "gulp add --options \"book|/book/new|bookNew\" ",
13 | "production": "cross-env NODE_ENV=production node dist/app.js",
14 | "doc": "docsify serve docs"
15 | },
16 | "dependencies": {
17 | "jsonwebtoken": "^8.5.1",
18 | "koa": "^2.8.1",
19 | "koa-body": "^2.5.0",
20 | "koa-compose": "^4.1.0",
21 | "koa-jwt": "^3.6.0",
22 | "koa-router": "^7.4.0",
23 | "koa-static2": "^0.1.8",
24 | "koa2-cors": "^2.0.6",
25 | "lodash": "^4.17.15",
26 | "lodash-id": "^0.14.0",
27 | "lowdb": "^1.0.0",
28 | "matchit": "^1.0.8",
29 | "require-directory": "^2.1.1",
30 | "shortid": "^2.2.13",
31 | "ws": "^6.0.0",
32 | "superagent": "^5.1.0",
33 | "@babel/runtime": "^7.6.0"
34 | },
35 | "devDependencies": {
36 | "@babel/cli": "^7.6.0",
37 | "@babel/core": "^7.6.0",
38 | "@babel/plugin-transform-runtime": "^7.6.0",
39 | "@babel/polyfill": "^7.6.0",
40 | "@babel/preset-env": "^7.6.0",
41 | "@babel/register": "^7.6.0",
42 | "cross-env": "^5.2.1",
43 | "gulp": "^4.0.2",
44 | "gulp-nodemon": "^2.4.2",
45 | "gulp-nunjucks-render": "^2.2.3",
46 | "gulp-rename": "^1.4.0",
47 | "mockjs": "^1.0.1-beta3",
48 | "nunjucks": "^3.2.0",
49 | "fs-extra": "^8.1.0"
50 | },
51 | "engines": {
52 | "node": ">= 7.8.0",
53 | "npm": ">= 4.2.0"
54 | },
55 | "ServerFullPath": "G:/GitHubProject/lazy-mock",
56 | "FrontendFullPath": "G:/GitHubProject/d2-admin-pm"
57 | }
58 |
--------------------------------------------------------------------------------
/publicKey.pub:
--------------------------------------------------------------------------------
1 | wqdjkwl1e21FQlk1j2
2 |
--------------------------------------------------------------------------------
/screenshot/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/screenshot/1.png
--------------------------------------------------------------------------------
/screenshot/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/screenshot/2.jpg
--------------------------------------------------------------------------------
/screenshot/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/screenshot/3.jpg
--------------------------------------------------------------------------------
/screenshot/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/screenshot/4.jpg
--------------------------------------------------------------------------------
/screenshot/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wjkang/lazy-mock/5e69439096f4da08df23efd623ad3e82c3e18526/screenshot/5.jpg
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import Koa2 from 'koa'
2 | import KoaBody from 'koa-body'
3 | import KoaStatic from 'koa-static2'
4 | import cors from 'koa2-cors'
5 | import { System as SystemConfig } from './config'
6 | import path from 'path'
7 | import Routes from './routes/index'
8 | import ErrorRoutesCatch from './middleware/ErrorRoutesCatch'
9 | import ParseUserInfo from './middleware/ParseUserInfo'
10 | import RequestLog from './middleware/RequestLog'
11 | import jwt from 'koa-jwt'
12 | import fs from 'fs'
13 | import im from './im'
14 | import EasySocket from './lib/EasySocket'
15 | import imRoutes from './im/routes'
16 | const https = require('https')
17 |
18 | const app = new Koa2()
19 | const env = process.env.NODE_ENV || 'development' // Current mode
20 |
21 | const publicKey = fs.readFileSync(path.join(__dirname, '../publicKey.pub'))
22 |
23 | app.use(cors())
24 | if (env === 'development') {
25 | // logger
26 | app.use((ctx, next) => {
27 | const start = new Date()
28 | return next().then(() => {
29 | const ms = new Date() - start
30 | console.log(
31 | `${ctx.ip} ${ctx.method} ${decodeURI(ctx.url)} - ${ms}ms`
32 | )
33 | })
34 | })
35 | }
36 | app.use(ErrorRoutesCatch())
37 | .use(KoaStatic('assets', path.resolve(__dirname, '../assets'))) // Static resource
38 | .use(
39 | jwt({ secret: publicKey }).unless({
40 | path: [/^\/public|\/auth\/login|\/resetdb|\/assets/]
41 | })
42 | )
43 | .use(ParseUserInfo())
44 | if (env === 'production') {
45 | app.use(RequestLog())
46 | }
47 | app.use(
48 | KoaBody({
49 | multipart: true,
50 | strict: false,
51 | formidable: {
52 | uploadDir: path.join(__dirname, '../assets/uploads/tmp')
53 | },
54 | jsonLimit: '10mb',
55 | formLimit: '10mb',
56 | textLimit: '10mb'
57 | })
58 | )
59 |
60 | Object.keys(Routes).forEach(function(key) {
61 | app.use(Routes[key].routes()).use(Routes[key].allowedMethods())
62 | })
63 |
64 | // https
65 | // .createServer(options, app.callback())
66 | // .listen(SystemConfig.API_SERVER_PORT, () => {
67 | // console.log(
68 | // 'Now start API server on port ' +
69 | // SystemConfig.API_SERVER_PORT +
70 | // '...'
71 | // )
72 | // })
73 | app.listen(SystemConfig.API_SERVER_PORT)
74 | console.log(
75 | 'Now start API server on port ' + SystemConfig.API_SERVER_PORT + '...'
76 | )
77 |
78 | const imMergeRoutes = {}
79 | Object.keys(imRoutes).forEach(function(key) {
80 | Object.assign(imMergeRoutes, imRoutes[key].default)
81 | })
82 | const easySocket = new EasySocket()
83 | easySocket
84 | .connectionUse(im.connectMiddleware())
85 | .closeUse(im.closeMiddleware())
86 | //.messageUse(im.roomInfoMiddleware())
87 | //.messageUse(im.messageMiddleware()) //与messageRouteMiddleware为两种方案
88 | .messageUse(im.messageRouteMiddleware(imMergeRoutes))
89 | .remoteEmitUse(im.remoteEmitMiddleware())
90 | .listen(SystemConfig.WS_CONFIG)
91 |
92 | easySocket.on('chat message', function(data) {
93 | //触发执行remoteEmit中间件(如果有)
94 | easySocket.emit('chat message', data)
95 | })
96 | easySocket.on('user login', function(data) {
97 | //触发执行remoteEmit中间件(如果有)
98 | easySocket.emit('user login', data)
99 | })
100 |
101 | console.log(
102 | 'Now start WebSocket server on port ' + SystemConfig.WS_CONFIG.port + '...'
103 | )
104 |
105 | export default app
106 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 |
2 | // 系统配置
3 | export let System = {
4 | API_SERVER_PORT: '3000', // API服务器监听的端口号
5 | WS_CONFIG: {
6 | port: 3001,
7 | perMessageDeflate: {
8 | zlibDeflateOptions: { // See zlib defaults.
9 | chunkSize: 1024,
10 | memLevel: 7,
11 | level: 3,
12 | },
13 | zlibInflateOptions: {
14 | chunkSize: 10 * 1024
15 | },
16 | // Other options settable:
17 | clientNoContextTakeover: true, // Defaults to negotiated value.
18 | serverNoContextTakeover: true, // Defaults to negotiated value.
19 | //clientMaxWindowBits: 10, // Defaults to negotiated value.
20 | serverMaxWindowBits: 10, // Defaults to negotiated value.
21 | // Below options specified as default values.
22 | concurrencyLimit: 10, // Limits zlib concurrency for perf.
23 | threshold: 1024, // Size (in bytes) below which messages
24 | // should not be compressed.
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/controllers/auth.js:
--------------------------------------------------------------------------------
1 | import jwt from 'jsonwebtoken'
2 | import fs from 'fs'
3 | import path from 'path'
4 | import * as responseTemplate from '../lib/responseTemplate'
5 | import userService from '../services/userService'
6 | import tokenService from '../services/tokenService'
7 |
8 | const publicKey = fs.readFileSync(path.join(__dirname, '../../publicKey.pub'))
9 |
10 | export let login = async (ctx) => {
11 | let name = ctx.request.body.username
12 | let pwd = ctx.request.body.password
13 | if (!name || !pwd) {
14 | return responseTemplate.businessError(ctx, '请输入账号密码!')
15 | }
16 | let user = await userService.getUserByNameAndPwd(name, pwd)
17 | if (!user) {
18 | return responseTemplate.businessError(ctx, '账号或密码错误!')
19 | }
20 | let token = jwt.sign({
21 | userId: user.id // 你要保存到token的数据
22 | }, publicKey, { expiresIn: '7d' })
23 | //await tokenService.add(token)
24 | return responseTemplate.success(ctx, {
25 | id: user.id,
26 | name: user.trueName,
27 | accessToken: token
28 | })
29 | }
30 | export let logout = async (ctx) => {
31 | let user = ctx.user;
32 | if (!user || !user.token) {
33 | return responseTemplate.success(ctx, null)
34 | }
35 | await tokenService.remove(user.token)
36 | return responseTemplate.success(ctx, null)
37 | }
38 |
--------------------------------------------------------------------------------
/src/controllers/index.js:
--------------------------------------------------------------------------------
1 | let requireDirectory = require('require-directory')
2 | module.exports = requireDirectory(module)
3 |
--------------------------------------------------------------------------------
/src/controllers/interface.js:
--------------------------------------------------------------------------------
1 | import interfaceService from '../services/interfaceService'
2 | import * as responseTemplate from '../lib/responseTemplate'
3 |
4 | export let getInterface = async (ctx) => {
5 | let id = ctx.params.id
6 | console.log(id)
7 | let entity = await interfaceService.getInterface(id)
8 | if (!entity) {
9 | return responseTemplate.businessError(ctx, "接口不存在!")
10 | }
11 | return responseTemplate.success(ctx, entity)
12 | }
13 | export let getInterfacePagedList = async (ctx, next) => {
14 | let pageIndex = ctx.query.pageIndex
15 | let pageSize = ctx.query.pageSize
16 | let sortBy = ctx.query.sortBy
17 | let descending = ctx.query.descending
18 | let filter = {
19 | id: ctx.query.id,
20 | name: ctx.query.name,
21 | path: ctx.query.path,
22 | method: ctx.query.method,
23 | isLocked: ctx.query.isLocked,
24 | description: ctx.query.description,
25 | functionId: ctx.query.functionId
26 | }
27 | let pagedList = await interfaceService.getInterfacePagedList(pageIndex, pageSize, sortBy, descending, filter)
28 | return responseTemplate.success(ctx, pagedList)
29 | }
30 | export let delInterface = async (ctx) => {
31 | let id = ctx.query.id
32 | await interfaceService.delInterface(id)
33 | return responseTemplate.success(ctx, null)
34 | }
35 |
36 | export let delInterfaces = async (ctx) => {
37 | let ids = JSON.parse(ctx.query.ids)
38 | for (let id of ids) {
39 | await interfaceService.delInterface(id)
40 | }
41 | return responseTemplate.success(ctx, null)
42 | }
43 |
44 | export let saveInterface = async (ctx) => {
45 | let entity = ctx.request.body
46 | if (entity.name == "") {
47 | return responseTemplate.businessError(ctx, "名称不能为空!")
48 | }
49 | if (entity.path == "") {
50 | return responseTemplate.businessError(ctx, "接口地址不能为空!")
51 | }
52 | if (entity.method == "") {
53 | return responseTemplate.businessError(ctx, "接口方法不能为空!")
54 | }
55 | let result = await interfaceService.saveInterface(entity)
56 | if (!result.success) {
57 | return responseTemplate.businessError(ctx, result.msg)
58 | }
59 | return responseTemplate.success(ctx, null)
60 | }
61 | export let relateInterface = async (ctx) => {
62 | let functionInterface = ctx.request.body
63 | await interfaceService.relate(functionInterface)
64 | return responseTemplate.success(ctx, null)
65 | }
66 |
--------------------------------------------------------------------------------
/src/controllers/menu.js:
--------------------------------------------------------------------------------
1 | import menuService from '../services/memuService'
2 | import roleService from '../services/roleService'
3 | import * as responseTemplate from '../lib/responseTemplate'
4 |
5 | export let getMenuList = async (ctx) => {
6 | let menuList = await menuService.getMenuList()
7 | return responseTemplate.success(ctx, menuList)
8 | }
9 |
10 | export let getMenu = async (ctx) => {
11 | let id = ctx.params.id
12 | let menu = await menuService.getMenu(id)
13 | if (!menu) {
14 | return responseTemplate.businessError(ctx, "菜单不存在")
15 | }
16 | return responseTemplate.success(ctx, menu)
17 | }
18 | export let saveMenu = async (ctx) => {
19 | let menu = ctx.request.body;
20 | if (menu.title == "") {
21 | return responseTemplate.businessError(ctx, "标题不能为空!")
22 | }
23 | if (!menu.type) {
24 | return responseTemplate.businessError(ctx, "请选择类型!")
25 | }
26 | if (menu.type == 1 && menu.path == "") {
27 | return responseTemplate.businessError(ctx, "路径不能为空!")
28 | }
29 | let result = await menuService.saveMenu(menu)
30 | if (!result.success) {
31 | return responseTemplate.businessError(ctx, result.msg)
32 | }
33 | return responseTemplate.success(ctx, null)
34 | }
35 | export let delMenu = async (ctx) => {
36 | let id = ctx.params.id
37 | let result = await menuService.delMenu(id)
38 | if (!result.success) {
39 | return responseTemplate.businessError(ctx, result.msg)
40 | }
41 | return responseTemplate.success(ctx, null)
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/controllers/requestlog.js:
--------------------------------------------------------------------------------
1 | import requestLogService from '../services/requestLogService'
2 | import * as responseTemplate from '../lib/responseTemplate'
3 |
4 | export let getRequestLogPagedList = async (ctx) => {
5 | let pageIndex = ctx.query.pageIndex
6 | let pageSize = ctx.query.pageSize
7 | let sortBy = ctx.query.sortBy
8 | let descending = ctx.query.descending
9 | let pagedList = await requestLogService.getRequestLogPagedList(pageIndex, pageSize, sortBy, descending)
10 | return responseTemplate.success(ctx, pagedList)
11 | }
--------------------------------------------------------------------------------
/src/controllers/role.js:
--------------------------------------------------------------------------------
1 | import roleService from '../services/roleService'
2 | import menuService from '../services/memuService'
3 | import * as responseTemplate from '../lib/responseTemplate'
4 | export let getRole = async (ctx) => {
5 | let id = ctx.params.id
6 | let role = await roleService.getRole(id)
7 | if (!role) {
8 | return responseTemplate.businessError(ctx, "角色不存在")
9 | }
10 | return responseTemplate.success(ctx, role)
11 | }
12 | export let getRolePagedList = async (ctx) => {
13 | let pageIndex = ctx.query.pageIndex
14 | let pageSize = ctx.query.pageSize
15 | let sortBy = ctx.query.sortBy
16 | let descending = ctx.query.descending
17 | let filter = JSON.parse(ctx.query.filter)
18 | let pagedList = await roleService.getRolePagedList(pageIndex, pageSize, sortBy, descending, filter)
19 | return responseTemplate.success(ctx, pagedList)
20 | }
21 | export let delRole = async (ctx) => {
22 | let id = ctx.query.id
23 | await roleService.delRole(id)
24 | return responseTemplate.success(ctx, null)
25 | }
26 |
27 | export let delRoles = async (ctx) => {
28 | let ids = JSON.parse(ctx.query.ids)
29 | for (let id of ids) {
30 | await roleService.delRole(id)
31 | }
32 | return responseTemplate.success(ctx, null)
33 | }
34 |
35 | export let saveRole = async (ctx) => {
36 | let func = ctx.request.body
37 | if (func.name == "") {
38 | return responseTemplate.businessError(ctx, "名称不能为空!")
39 | }
40 | if (func.code == "") {
41 | return responseTemplate.businessError(ctx, "编码不能为空!")
42 | }
43 | let result = await roleService.saveRole(func)
44 | if (!result.success) {
45 | return responseTemplate.businessError(ctx, result.msg)
46 | }
47 | return responseTemplate.success(ctx, null)
48 | }
49 | export let getRolePermissions = async (ctx) => {
50 | let roleId = ctx.params.roleId;
51 | let rolePermissions = await roleService.getRoleFunctions(roleId);
52 | return responseTemplate.success(ctx, rolePermissions)
53 | }
54 | export let savePermission = async (ctx) => {
55 | let data = ctx.request.body;
56 | await roleService.savePermission(data.roleId, data.permissions)
57 | return responseTemplate.success(ctx, null)
58 | }
--------------------------------------------------------------------------------
/src/controllers/route.js:
--------------------------------------------------------------------------------
1 | import routeService from '../services/routeService'
2 | import * as responseTemplate from '../lib/responseTemplate'
3 |
4 | export let getRoute = async (ctx) => {
5 | let id = ctx.params.id
6 | let route = await routeService.getRoute(id)
7 | if (!route) {
8 | return responseTemplate.businessError(ctx, "route不存在!")
9 | }
10 | return responseTemplate.success(ctx, route)
11 | }
12 | export let getRouteList = async (ctx) => {
13 | let routeList = await routeService.getRouteList()
14 | return responseTemplate.success(ctx, routeList)
15 | }
16 | export let getRoutePagedList = async (ctx, next) => {
17 | let pageIndex = ctx.query.pageIndex
18 | let pageSize = ctx.query.pageSize
19 | let sortBy = ctx.query.sortBy
20 | let descending = ctx.query.descending
21 | let filter = {
22 | id: ctx.query.id,
23 | parentId: ctx.query.parentId,
24 | name: ctx.query.name,
25 | path: ctx.query.path,
26 | title: ctx.query.title,
27 | component: ctx.query.component,
28 | componentPath: ctx.query.componentPath,
29 | cache: ctx.query.cache,
30 | isLock: ctx.query.isLock,
31 | sort: ctx.query.sort,
32 | }
33 | let pagedList = await routeService.getRoutePagedList(pageIndex, pageSize, sortBy, descending, filter)
34 | responseTemplate.success(ctx, pagedList)
35 | return next()
36 | }
37 | export let delRoute = async (ctx) => {
38 | let id = ctx.params.id
39 | await routeService.delRoute(id)
40 | return responseTemplate.success(ctx, null)
41 | }
42 |
43 | export let delRoutes = async (ctx) => {
44 | let ids = JSON.parse(ctx.query.ids)
45 | for (let id of ids) {
46 | await routeService.delRoute(id)
47 | }
48 | return responseTemplate.success(ctx, null)
49 | }
50 |
51 | export let saveRoute = async (ctx) => {
52 | let entity = ctx.request.body
53 | if (!entity.name) {
54 | return responseTemplate.businessError(ctx, "name不能为空!")
55 | }
56 | if (!entity.path) {
57 | return responseTemplate.businessError(ctx, "path不能为空!")
58 | }
59 | if (!entity.title) {
60 | return responseTemplate.businessError(ctx, "标题不能为空!")
61 | }
62 | if (!entity.component && !entity.componentPath) {
63 | return responseTemplate.businessError(ctx, "组件与组件路径不能同时为空!")
64 | }
65 | let result = await routeService.saveRoute(entity)
66 | if (!result.success) {
67 | return responseTemplate.businessError(ctx, result.msg)
68 | }
69 | return responseTemplate.success(ctx, null)
70 | }
71 |
--------------------------------------------------------------------------------
/src/controllers/system.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs')
2 | import path from 'path'
3 | import systemService from '../services/systemService'
4 | import * as responseTemplate from '../lib/responseTemplate'
5 |
6 | export let resetDb = async (ctx) => {
7 | try {
8 | await fs.copyFileSync(path.join(__dirname, '../db/db_backup.json'), path.join(__dirname, '../db/db.json'));
9 | await systemService.resetDb()
10 | return responseTemplate.success(ctx, "初始化成功")
11 | } catch (e) {
12 | console.log(e)
13 | return responseTemplate.businessError(ctx, "初始化失败")
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/controllers/user.js:
--------------------------------------------------------------------------------
1 | import userService from '../services/userService'
2 | import menuService from '../services/memuService'
3 | import routeService from '../services/routeService'
4 | import interfaceService from '../services/interfaceService'
5 | import * as responseTemplate from '../lib/responseTemplate'
6 | let formatAccessMenus = (menus) => {
7 | let f = (item, children) => {
8 | item.children = []
9 | for (let child of children) {
10 | let itemChild = {
11 | title: child.title,
12 | path: child.path,
13 | icon: child.icon
14 | }
15 | if (child.children && child.children.length > 0) {
16 | f(itemChild, child.children)
17 | }
18 | item.children.push(itemChild)
19 | }
20 | }
21 | let list = []
22 | for (let menu of menus) {
23 | let item = {
24 | title: menu.title,
25 | path: menu.path,
26 | icon: menu.icon
27 | }
28 | if (menu.children && menu.children.length > 0) {
29 | f(item, menu.children)
30 | }
31 | list.push(item)
32 | }
33 | return list
34 | }
35 | let formatAccessRoutes = (routes) => {
36 | let f = (item, children) => {
37 | item.children = []
38 | for (let child of children) {
39 | let itemChild = {
40 | name: child.name,
41 | path: child.path,
42 | component: child.component,
43 | componentPath: child.componentPath,
44 | meta: {
45 | title: child.title,
46 | cache: child.cache
47 | }
48 | }
49 | if (child.children && child.children.length > 0) {
50 | f(itemChild, child.children)
51 | }
52 | item.children.push(itemChild)
53 | }
54 | }
55 | let list = []
56 | for (let route of routes) {
57 | let item = {
58 | name: route.name,
59 | path: route.path,
60 | component: route.component,
61 | componentPath: route.componentPath,
62 | meta: {
63 | title: route.title,
64 | cache: route.cache
65 | }
66 | }
67 | if (route.children && route.children.length > 0) {
68 | f(item, route.children)
69 | }
70 | list.push(item)
71 | }
72 | return list
73 | }
74 | export let getUser = async (ctx) => {
75 | let id = ctx.params.id
76 | let user = await userService.getUserById(id)
77 | if (!user) {
78 | return responseTemplate.businessError(ctx, "用户不存在")
79 | }
80 | return responseTemplate.success(ctx, user)
81 | }
82 | export let getUserInfo = async (ctx) => {
83 | let user = ctx.user;
84 | if (!user || !user.userId) {
85 | return responseTemplate.businessError(ctx, '获取用户信息失败!')
86 | }
87 | let [userInfo,
88 | userRole,
89 | permissions,
90 | accessMenus,
91 | accessRoutes,
92 | accessInterfaces,
93 | isAdmin
94 | ] = await Promise.all([
95 | userService.getUserById(user.userId),
96 | userService.getUserRole(user.userId),
97 | userService.getUserPermission(user.userId),
98 | menuService.getAccessMenuList(user.userId),
99 | routeService.getAccessRouteList(user.userId),
100 | interfaceService.getAccessInterfaceList(user.userId),
101 | userService.isAdmin(user.userId)
102 | ])
103 | if (!userInfo) {
104 | return responseTemplate.businessError(ctx, '获取用户信息失败!')
105 | }
106 | return responseTemplate.success(ctx, {
107 | userName: userInfo.name,
108 | userRoles: userRole,
109 | userPermissions: permissions,
110 | accessMenus: formatAccessMenus(accessMenus),
111 | accessRoutes: formatAccessRoutes(accessRoutes),
112 | accessInterfaces: accessInterfaces.map(s => { return { path: s.path, method: s.method } }),
113 | isAdmin: isAdmin ? 1 : 0,
114 | avatarUrl: 'https://api.adorable.io/avatars/85/abott@adorable.png'
115 | })
116 | }
117 |
118 | export let getUserPagedList = async (ctx) => {
119 | let pageIndex = ctx.query.pageIndex
120 | let pageSize = ctx.query.pageSize
121 | let sortBy = ctx.query.sortBy
122 | let descending = ctx.query.descending
123 | let filter = JSON.parse(ctx.query.filter)
124 | let pagedList = await userService.getUserPagedList(pageIndex, pageSize, sortBy, descending, filter)
125 | return responseTemplate.success(ctx, pagedList)
126 | }
127 |
128 | export let delUser = async (ctx) => {
129 | let id = ctx.query.id
130 | console.log(id)
131 | let result = await userService.delUser(id)
132 | if (!result.success) {
133 | return responseTemplate.businessError(ctx, result.msg)
134 | }
135 | return responseTemplate.success(ctx, null)
136 | }
137 |
138 | export let delUsers = async (ctx) => {
139 | let ids = JSON.parse(ctx.query.ids)
140 | for (let id of ids) {
141 | await userService.delUser(id)
142 | }
143 | return responseTemplate.success(ctx, null)
144 | }
145 |
146 | export let saveUser = async (ctx) => {
147 | let func = ctx.request.body
148 | if (func.name == "") {
149 | return responseTemplate.businessError(ctx, "账号不能为空!")
150 | }
151 | let result = await userService.saveUser(func)
152 | if (!result.success) {
153 | return responseTemplate.businessError(ctx, result.msg)
154 | }
155 | return responseTemplate.success(ctx, null)
156 | }
157 |
158 | export let editRoleUser = async (ctx) => {
159 | let roleUser = ctx.request.body
160 | await userService.editRoleUser(roleUser)
161 | return responseTemplate.success(ctx, null)
162 | }
--------------------------------------------------------------------------------
/src/db/db.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": [
3 | {
4 | "id": "1",
5 | "name": "admin",
6 | "password": "123",
7 | "email": "123@qq.com",
8 | "phone": "110",
9 | "trueName": "超级管理员"
10 | },
11 | {
12 | "name": "MenuManager",
13 | "trueName": "菜单管理员",
14 | "password": "123456",
15 | "id": "54a3488f-3c94-489e-bcd0-3f2631991f5e",
16 | "phone": "110",
17 | "email": "12345@qq.com"
18 | },
19 | {
20 | "name": "no",
21 | "trueName": "没有权限的用户",
22 | "password": "123456",
23 | "id": "92e6b921-d820-4ea6-9b57-95b1378c961e",
24 | "phone": "110",
25 | "email": "66666@qq.com"
26 | }
27 | ],
28 | "admin": [
29 | "1"
30 | ],
31 | "menu": [
32 | {
33 | "id": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
34 | "parentId": 0,
35 | "title": "系统",
36 | "path": "/system",
37 | "icon": "cogs",
38 | "sort": "1",
39 | "type": 1
40 | },
41 | {
42 | "id": "52500348-50f0-4327-a898-9e4b9893f1a9",
43 | "parentId": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
44 | "title": "系统设置",
45 | "icon": "cogs",
46 | "sort": "1",
47 | "type": 1
48 | },
49 | {
50 | "id": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
51 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
52 | "title": "菜单管理",
53 | "path": "/system/menu",
54 | "icon": "th-list",
55 | "sort": "1",
56 | "type": 1,
57 | "permission": "p_menu_menu"
58 | },
59 | {
60 | "id": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
61 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
62 | "title": "2-查询菜单",
63 | "sort": "2",
64 | "type": 2,
65 | "permission": "p_menu_view"
66 | },
67 | {
68 | "id": "3423218d-886c-4fb7-944d-42afe4c03076",
69 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
70 | "title": "3-修改菜单",
71 | "sort": "3",
72 | "type": 2,
73 | "permission": "p_menu_edit"
74 | },
75 | {
76 | "id": "c2578794-328c-4f0f-bbba-289ebdace7f1",
77 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
78 | "title": "1-菜单权限",
79 | "type": 2,
80 | "sort": "1",
81 | "permission": "p_menu_menu"
82 | },
83 | {
84 | "id": "6db38bfe-9ad0-4db4-a9be-28082741ef20",
85 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
86 | "path": "/system/route",
87 | "title": "路由管理",
88 | "type": 1,
89 | "permission": "p_route_menu",
90 | "sort": "2",
91 | "icon": "share-alt-square"
92 | },
93 | {
94 | "id": "2b453777-ddb0-4806-8ab0-4ec56167cdb3",
95 | "parentId": "6db38bfe-9ad0-4db4-a9be-28082741ef20",
96 | "title": "1-菜单权限",
97 | "type": 2,
98 | "permission": "p_route_menu"
99 | },
100 | {
101 | "id": "1a74ac59-001c-4914-874e-6dbefe33415c",
102 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
103 | "title": "角色管理",
104 | "path": "/system/role",
105 | "type": 1,
106 | "sort": "3",
107 | "icon": "users",
108 | "permission": "p_role_menu"
109 | },
110 | {
111 | "id": "d0d47bda-ab26-4909-a7f2-74bc2591a357",
112 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
113 | "title": "用户管理",
114 | "path": "/system/user",
115 | "sort": "4",
116 | "type": 1,
117 | "icon": "user",
118 | "permission": "p_user_menu"
119 | },
120 | {
121 | "id": "85bfdc38-fca4-4703-ad22-2cba711fc42a",
122 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
123 | "title": "接口管理",
124 | "path": "/system/interface",
125 | "type": 1,
126 | "sort": "5",
127 | "icon": "paper-plane",
128 | "permission": "p_interface_menu"
129 | },
130 | {
131 | "id": "5e5b0453-cb24-4a8f-89ef-360922cecba5",
132 | "parentId": "1a74ac59-001c-4914-874e-6dbefe33415c",
133 | "title": "1-菜单权限",
134 | "type": 2,
135 | "permission": "p_role_menu"
136 | },
137 | {
138 | "id": "97273b77-bda3-47ad-bd93-3c904fb8fb10",
139 | "parentId": "d0d47bda-ab26-4909-a7f2-74bc2591a357",
140 | "title": "1-菜单权限",
141 | "type": 2,
142 | "permission": "p_user_menu"
143 | },
144 | {
145 | "id": "21352cb0-870b-40f0-acc9-362846fd1506",
146 | "parentId": "85bfdc38-fca4-4703-ad22-2cba711fc42a",
147 | "title": "1-菜单权限",
148 | "type": 2,
149 | "permission": "p_interface_menu"
150 | },
151 | {
152 | "id": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
153 | "parentId": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
154 | "title": "组织架构",
155 | "sort": "2",
156 | "type": 1,
157 | "icon": "pie-chart"
158 | },
159 | {
160 | "id": "dc5667cf-85a8-446e-8e69-354a684a762a",
161 | "parentId": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
162 | "title": "部门管理",
163 | "type": 1,
164 | "isLock": false,
165 | "sort": "1",
166 | "icon": "html5"
167 | },
168 | {
169 | "id": "0fda8037-61df-4a1c-8f9b-18f287d51049",
170 | "parentId": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
171 | "title": "职位管理",
172 | "sort": "2",
173 | "type": 1,
174 | "icon": "opencart"
175 | },
176 | {
177 | "id": "6a0c4206-a78c-4459-bd36-3c8972b7bb53",
178 | "parentId": "dc5667cf-85a8-446e-8e69-354a684a762a",
179 | "title": "1-菜单权限",
180 | "sort": "1",
181 | "type": 2
182 | },
183 | {
184 | "id": "ec47ad63-fb2e-4988-90ec-77fe4e398839",
185 | "parentId": "0fda8037-61df-4a1c-8f9b-18f287d51049",
186 | "title": "1-菜单权限",
187 | "sort": "1",
188 | "type": 2
189 | }
190 | ],
191 | "route": [
192 | {
193 | "id": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
194 | "parentId": 0,
195 | "name": "System",
196 | "title": "系统设置",
197 | "path": "/system",
198 | "permission": "",
199 | "component": "layoutHeaderAside",
200 | "componentPath": "layout/header-aside/layout",
201 | "sort": "1",
202 | "isLock": false,
203 | "cache": true
204 | },
205 | {
206 | "id": "aa4c13f7-f3eb-4d1e-aac2-c2b2f7f8d296",
207 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
208 | "name": "MenuPage",
209 | "title": "菜单管理",
210 | "path": "/system/menu",
211 | "component": "menu",
212 | "componentPath": "pages/sys/menu/index",
213 | "sort": "2",
214 | "cache": true
215 | },
216 | {
217 | "id": "618e2e9c-8afe-4c64-b486-a4b08c752a81",
218 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
219 | "title": "路由管理",
220 | "name": "RoutePage",
221 | "path": "/system/route",
222 | "component": "route",
223 | "componentPath": "pages/sys/route/index",
224 | "sort": "3",
225 | "cache": true
226 | },
227 | {
228 | "id": "67a76a8f-c765-4015-bebd-03edc3170e63",
229 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
230 | "name": "RolePage",
231 | "title": "角色管理",
232 | "path": "/system/role",
233 | "component": "role",
234 | "sort": "3",
235 | "cache": true,
236 | "componentPath": "pages/sys/role/index"
237 | },
238 | {
239 | "id": "58c5bc63-dfdc-413c-9bd6-b827ef06203e",
240 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
241 | "componentPath": "pages/sys/user/index",
242 | "sort": "4",
243 | "cache": true,
244 | "component": "user",
245 | "path": "/system/user",
246 | "title": "用户管理",
247 | "name": "UserPage"
248 | },
249 | {
250 | "id": "d8808450-aa31-4a4a-817d-e49c8eee983b",
251 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
252 | "name": "InterfacePage",
253 | "title": "接口管理",
254 | "path": "/system/interface",
255 | "component": "interface",
256 | "sort": "5"
257 | }
258 | ],
259 | "interface": [
260 | {
261 | "name": "用户登录",
262 | "path": "/auth/login",
263 | "method": "post",
264 | "description": "用户登录",
265 | "id": "4662e940-ebae-4424-8a74-2c67ce408d3e"
266 | },
267 | {
268 | "name": "获取菜单",
269 | "path": "/menu/:id",
270 | "method": "get",
271 | "description": "根据id获取菜单",
272 | "id": "c6567a47-0382-4eb9-852b-3db2c8be9251"
273 | },
274 | {
275 | "name": "获取菜单列表",
276 | "path": "/menu",
277 | "method": "get",
278 | "description": "获取菜单列表",
279 | "id": "23c892ed-76c6-4bdb-9240-4618b3fc4399"
280 | },
281 | {
282 | "name": "提交菜单",
283 | "path": "/menu/save",
284 | "method": "post",
285 | "description": "新增或更新菜单",
286 | "id": "8dba087e-ba42-4220-a036-0de4adc0f585"
287 | },
288 | {
289 | "name": "删除菜单",
290 | "path": "/menu/:id",
291 | "method": "delete",
292 | "description": "根据id删除菜单",
293 | "id": "6be0b030-1d42-4230-aed0-5cc7ca8e53df"
294 | },
295 | {
296 | "name": "获取路由列表",
297 | "path": "/route",
298 | "method": "get",
299 | "description": "获取路由列表",
300 | "id": "f42e8101-af1e-4717-82aa-a9d620b65021"
301 | },
302 | {
303 | "name": "获取路由",
304 | "path": "/route/:id",
305 | "method": "get",
306 | "description": "根据id获取路由",
307 | "id": "53b58c16-b9fb-4ea0-bb65-0bb4cfd96293"
308 | },
309 | {
310 | "name": "提交路由",
311 | "path": "/route/save",
312 | "method": "post",
313 | "description": "新增或更新路由",
314 | "id": "ffef90da-dab5-4177-81ae-1a4d8e70b0c8"
315 | },
316 | {
317 | "name": "删除路由",
318 | "path": "/route/:id",
319 | "method": "delete",
320 | "description": "根本id删除路由",
321 | "id": "cee27c96-c02c-409d-b446-1de2e55e2bf6"
322 | },
323 | {
324 | "name": "获取角色",
325 | "path": "/role/:id",
326 | "method": "get",
327 | "description": "根据id获取角色",
328 | "id": "02ce362f-1f04-4386-99c1-ef7a1bcf71fe"
329 | },
330 | {
331 | "name": "分页获取角色",
332 | "path": "/role/pagedlist",
333 | "method": "get",
334 | "description": "分页的方式获取角色数据,支持排序",
335 | "id": "90a1d0c6-22e5-4743-b39c-9f6e643b75d4"
336 | },
337 | {
338 | "name": "删除角色",
339 | "path": "/role/del",
340 | "method": "delete",
341 | "description": "根据id删除角色",
342 | "id": "873aaf0d-6f67-4c74-8dde-7dba8c524921"
343 | },
344 | {
345 | "name": "批量删除角色",
346 | "path": "/role/batchdel",
347 | "method": "delete",
348 | "description": "批量删除角色",
349 | "id": "0c229c5e-30d7-42c3-841a-73c4ba210a06"
350 | },
351 | {
352 | "name": "提交角色",
353 | "path": "/role/save",
354 | "method": "post",
355 | "description": "新增或更新角色",
356 | "id": "3d0a2d40-89d1-4416-8354-05849276dccd"
357 | },
358 | {
359 | "name": "获取角色功能权限",
360 | "path": "/role/getpermissions/:roleid",
361 | "method": "get",
362 | "description": "获取角色功能权限",
363 | "id": "6eb4cf01-45d1-432c-83ac-d9eb72c0c88e"
364 | },
365 | {
366 | "name": "保存角色功能权限",
367 | "path": "/role/savepermission",
368 | "method": "post",
369 | "description": "保存角色功能权限",
370 | "id": "07ff0d6a-78a6-4cd3-ba76-b4959a0c641a"
371 | },
372 | {
373 | "name": "获取用户",
374 | "path": "/user/:id",
375 | "method": "get",
376 | "description": "获取用户",
377 | "id": "020a75ef-ea43-4435-9a16-cb09fb79dc8b"
378 | },
379 | {
380 | "name": "分页获取用户",
381 | "path": "/user/pagedlist",
382 | "method": "get",
383 | "description": "分页获取用户",
384 | "id": "93c064e8-baf4-4f03-80ef-fa1230911213"
385 | },
386 | {
387 | "name": "提交用户",
388 | "path": "/user/save",
389 | "method": "post",
390 | "description": "新增或更新用户",
391 | "id": "31373f0b-0050-42d4-80b9-48dc3735f213"
392 | },
393 | {
394 | "name": "删除用户",
395 | "path": "/user/del",
396 | "method": "delete",
397 | "description": "删除用户",
398 | "id": "80eb294a-9919-4341-b1c0-ef94462bfa9f"
399 | },
400 | {
401 | "name": "批量删除用户",
402 | "path": "/user/batchdel",
403 | "method": "delete",
404 | "description": "批量删除用户",
405 | "id": "6cf44f79-726c-4655-843a-b05d8ed5ebd5"
406 | },
407 | {
408 | "name": "关联角色用户",
409 | "path": "/user/editroleuser",
410 | "method": "post",
411 | "description": "关联或取消关联",
412 | "id": "61cf07fb-bd28-46f0-88d1-b96d3d7d0556"
413 | },
414 | {
415 | "name": "获取用户权限信息",
416 | "path": "/user/info",
417 | "method": "get",
418 | "description": "获取用户权限信息",
419 | "id": "b49d6801-a037-46f2-bdc9-e175d64e6027"
420 | },
421 | {
422 | "name": "获取接口",
423 | "path": "/interface/:id",
424 | "method": "get",
425 | "description": "根据id获取接口",
426 | "id": "87d9908b-2876-4f50-ad80-7fd4fef34456"
427 | },
428 | {
429 | "name": "分页获取接口",
430 | "path": "/interface/paged",
431 | "method": "get",
432 | "description": "分页获取接口",
433 | "id": "72ce9b95-8b49-42f5-96f9-488f42f84da4"
434 | },
435 | {
436 | "name": "提交接口",
437 | "path": "/interface/save",
438 | "method": "post",
439 | "description": "新增或更新接口",
440 | "id": "dbf8208c-0c93-4f6d-8292-2c4821e2ee29"
441 | },
442 | {
443 | "name": "删除接口",
444 | "path": "/interface/del/:id",
445 | "method": "delete",
446 | "description": "删除接口",
447 | "id": "1a9bcd3d-2b2e-4fb4-8b67-13321d744b40"
448 | },
449 | {
450 | "name": "批量删除接口",
451 | "path": "/interface/batchdel/:ids",
452 | "method": "delete",
453 | "description": "批量删除接口",
454 | "id": "deb494eb-8417-4dcb-a7b9-7e0a3378930c"
455 | },
456 | {
457 | "name": "关联接口",
458 | "path": "/interface/relate",
459 | "method": "post",
460 | "description": "关联或取消关联",
461 | "id": "a77d58dc-69c1-4fb4-ab96-2e613f49d425"
462 | }
463 | ],
464 | "functionInterface": [
465 | {
466 | "functionId": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
467 | "interfaceId": "c6567a47-0382-4eb9-852b-3db2c8be9251"
468 | },
469 | {
470 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
471 | "interfaceId": "8dba087e-ba42-4220-a036-0de4adc0f585"
472 | },
473 | {
474 | "functionId": "c2578794-328c-4f0f-bbba-289ebdace7f1",
475 | "interfaceId": "23c892ed-76c6-4bdb-9240-4618b3fc4399"
476 | },
477 | {
478 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
479 | "interfaceId": "72ce9b95-8b49-42f5-96f9-488f42f84da4"
480 | }
481 | ],
482 | "role": [
483 | {
484 | "name": "菜单管理员",
485 | "code": "R_MENUADMIN",
486 | "description": "菜单管理员",
487 | "id": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
488 | "isAdd": 2
489 | }
490 | ],
491 | "roleUser": [
492 | {
493 | "userId": "54a3488f-3c94-489e-bcd0-3f2631991f5e",
494 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959"
495 | }
496 | ],
497 | "permission": [
498 | {
499 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
500 | "functionId": "c2578794-328c-4f0f-bbba-289ebdace7f1",
501 | "id": "6500ee1f-eaec-4c56-ad60-06b3367d45ba"
502 | },
503 | {
504 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
505 | "functionId": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
506 | "id": "6c9ef830-a5f8-45e2-927b-d096e81052db"
507 | },
508 | {
509 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
510 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
511 | "id": "968204ac-97c3-4f2c-bb3c-3ea1aa89731e"
512 | }
513 | ],
514 | "token": []
515 | }
--------------------------------------------------------------------------------
/src/db/db_backup.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": [
3 | {
4 | "id": "1",
5 | "name": "admin",
6 | "password": "123",
7 | "email": "123@qq.com",
8 | "phone": "110",
9 | "trueName": "超级管理员"
10 | },
11 | {
12 | "name": "MenuManager",
13 | "trueName": "菜单管理员",
14 | "password": "123456",
15 | "id": "54a3488f-3c94-489e-bcd0-3f2631991f5e",
16 | "phone": "110",
17 | "email": "12345@qq.com"
18 | },
19 | {
20 | "name": "no",
21 | "trueName": "没有权限的用户",
22 | "password": "123456",
23 | "id": "92e6b921-d820-4ea6-9b57-95b1378c961e",
24 | "phone": "110",
25 | "email": "66666@qq.com"
26 | }
27 | ],
28 | "admin": [
29 | "1"
30 | ],
31 | "menu": [
32 | {
33 | "id": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
34 | "parentId": 0,
35 | "title": "系统",
36 | "path": "/system",
37 | "icon": "cogs",
38 | "sort": "1",
39 | "type": 1
40 | },
41 | {
42 | "id": "52500348-50f0-4327-a898-9e4b9893f1a9",
43 | "parentId": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
44 | "title": "系统设置",
45 | "icon": "cogs",
46 | "sort": "1",
47 | "type": 1
48 | },
49 | {
50 | "id": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
51 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
52 | "title": "菜单管理",
53 | "path": "/system/menu",
54 | "icon": "th-list",
55 | "sort": "1",
56 | "type": 1,
57 | "permission": "p_menu_menu"
58 | },
59 | {
60 | "id": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
61 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
62 | "title": "2-查询菜单",
63 | "sort": "2",
64 | "type": 2,
65 | "permission": "p_menu_view"
66 | },
67 | {
68 | "id": "3423218d-886c-4fb7-944d-42afe4c03076",
69 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
70 | "title": "3-修改菜单",
71 | "sort": "3",
72 | "type": 2,
73 | "permission": "p_menu_edit"
74 | },
75 | {
76 | "id": "c2578794-328c-4f0f-bbba-289ebdace7f1",
77 | "parentId": "1f3ea5ba-0d67-4710-b75c-52a267296b85",
78 | "title": "1-菜单权限",
79 | "type": 2,
80 | "sort": "1",
81 | "permission": "p_menu_menu"
82 | },
83 | {
84 | "id": "6db38bfe-9ad0-4db4-a9be-28082741ef20",
85 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
86 | "path": "/system/route",
87 | "title": "路由管理",
88 | "type": 1,
89 | "permission": "p_route_menu",
90 | "sort": "2",
91 | "icon": "share-alt-square"
92 | },
93 | {
94 | "id": "2b453777-ddb0-4806-8ab0-4ec56167cdb3",
95 | "parentId": "6db38bfe-9ad0-4db4-a9be-28082741ef20",
96 | "title": "1-菜单权限",
97 | "type": 2,
98 | "permission": "p_route_menu"
99 | },
100 | {
101 | "id": "1a74ac59-001c-4914-874e-6dbefe33415c",
102 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
103 | "title": "角色管理",
104 | "path": "/system/role",
105 | "type": 1,
106 | "sort": "3",
107 | "icon": "users",
108 | "permission": "p_role_menu"
109 | },
110 | {
111 | "id": "d0d47bda-ab26-4909-a7f2-74bc2591a357",
112 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
113 | "title": "用户管理",
114 | "path": "/system/user",
115 | "sort": "4",
116 | "type": 1,
117 | "icon": "user",
118 | "permission": "p_user_menu"
119 | },
120 | {
121 | "id": "85bfdc38-fca4-4703-ad22-2cba711fc42a",
122 | "parentId": "52500348-50f0-4327-a898-9e4b9893f1a9",
123 | "title": "接口管理",
124 | "path": "/system/interface",
125 | "type": 1,
126 | "sort": "5",
127 | "icon": "paper-plane",
128 | "permission": "p_interface_menu"
129 | },
130 | {
131 | "id": "5e5b0453-cb24-4a8f-89ef-360922cecba5",
132 | "parentId": "1a74ac59-001c-4914-874e-6dbefe33415c",
133 | "title": "1-菜单权限",
134 | "type": 2,
135 | "permission": "p_role_menu"
136 | },
137 | {
138 | "id": "97273b77-bda3-47ad-bd93-3c904fb8fb10",
139 | "parentId": "d0d47bda-ab26-4909-a7f2-74bc2591a357",
140 | "title": "1-菜单权限",
141 | "type": 2,
142 | "permission": "p_user_menu"
143 | },
144 | {
145 | "id": "21352cb0-870b-40f0-acc9-362846fd1506",
146 | "parentId": "85bfdc38-fca4-4703-ad22-2cba711fc42a",
147 | "title": "1-菜单权限",
148 | "type": 2,
149 | "permission": "p_interface_menu"
150 | },
151 | {
152 | "id": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
153 | "parentId": "2bf39892-f047-44b1-88d3-ccd7ea5c8c45",
154 | "title": "组织架构",
155 | "sort": "2",
156 | "type": 1,
157 | "icon": "pie-chart"
158 | },
159 | {
160 | "id": "dc5667cf-85a8-446e-8e69-354a684a762a",
161 | "parentId": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
162 | "title": "部门管理",
163 | "type": 1,
164 | "isLock": false,
165 | "sort": "1",
166 | "icon": "html5"
167 | },
168 | {
169 | "id": "0fda8037-61df-4a1c-8f9b-18f287d51049",
170 | "parentId": "18c7a1e3-3c69-4242-afd7-6f54bfdce271",
171 | "title": "职位管理",
172 | "sort": "2",
173 | "type": 1,
174 | "icon": "opencart"
175 | },
176 | {
177 | "id": "6a0c4206-a78c-4459-bd36-3c8972b7bb53",
178 | "parentId": "dc5667cf-85a8-446e-8e69-354a684a762a",
179 | "title": "1-菜单权限",
180 | "sort": "1",
181 | "type": 2
182 | },
183 | {
184 | "id": "ec47ad63-fb2e-4988-90ec-77fe4e398839",
185 | "parentId": "0fda8037-61df-4a1c-8f9b-18f287d51049",
186 | "title": "1-菜单权限",
187 | "sort": "1",
188 | "type": 2
189 | }
190 | ],
191 | "route": [
192 | {
193 | "id": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
194 | "parentId": 0,
195 | "name": "System",
196 | "title": "系统设置",
197 | "path": "/system",
198 | "permission": "",
199 | "component": "layoutHeaderAside",
200 | "componentPath": "layout/header-aside/layout",
201 | "sort": "1",
202 | "isLock": false,
203 | "cache": true
204 | },
205 | {
206 | "id": "aa4c13f7-f3eb-4d1e-aac2-c2b2f7f8d296",
207 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
208 | "name": "MenuPage",
209 | "title": "菜单管理",
210 | "path": "/system/menu",
211 | "component": "menu",
212 | "componentPath": "pages/sys/menu/index",
213 | "sort": "2",
214 | "cache": true
215 | },
216 | {
217 | "id": "618e2e9c-8afe-4c64-b486-a4b08c752a81",
218 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
219 | "title": "路由管理",
220 | "name": "RoutePage",
221 | "path": "/system/route",
222 | "component": "route",
223 | "componentPath": "pages/sys/route/index",
224 | "sort": "3",
225 | "cache": true
226 | },
227 | {
228 | "id": "67a76a8f-c765-4015-bebd-03edc3170e63",
229 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
230 | "name": "RolePage",
231 | "title": "角色管理",
232 | "path": "/system/role",
233 | "component": "role",
234 | "sort": "3",
235 | "cache": true,
236 | "componentPath": "pages/sys/role/index"
237 | },
238 | {
239 | "id": "58c5bc63-dfdc-413c-9bd6-b827ef06203e",
240 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
241 | "componentPath": "pages/sys/user/index",
242 | "sort": "4",
243 | "cache": true,
244 | "component": "user",
245 | "path": "/system/user",
246 | "title": "用户管理",
247 | "name": "UserPage"
248 | },
249 | {
250 | "id": "d8808450-aa31-4a4a-817d-e49c8eee983b",
251 | "parentId": "3af738f0-0792-4f34-aae9-3339d0ab12a7",
252 | "name": "InterfacePage",
253 | "title": "接口管理",
254 | "path": "/system/interface",
255 | "component": "interface",
256 | "sort": "5"
257 | }
258 | ],
259 | "interface": [
260 | {
261 | "name": "用户登录",
262 | "path": "/auth/login",
263 | "method": "post",
264 | "description": "用户登录",
265 | "id": "4662e940-ebae-4424-8a74-2c67ce408d3e"
266 | },
267 | {
268 | "name": "获取菜单",
269 | "path": "/menu/:id",
270 | "method": "get",
271 | "description": "根据id获取菜单",
272 | "id": "c6567a47-0382-4eb9-852b-3db2c8be9251"
273 | },
274 | {
275 | "name": "获取菜单列表",
276 | "path": "/menu",
277 | "method": "get",
278 | "description": "获取菜单列表",
279 | "id": "23c892ed-76c6-4bdb-9240-4618b3fc4399"
280 | },
281 | {
282 | "name": "提交菜单",
283 | "path": "/menu/save",
284 | "method": "post",
285 | "description": "新增或更新菜单",
286 | "id": "8dba087e-ba42-4220-a036-0de4adc0f585"
287 | },
288 | {
289 | "name": "删除菜单",
290 | "path": "/menu/:id",
291 | "method": "delete",
292 | "description": "根据id删除菜单",
293 | "id": "6be0b030-1d42-4230-aed0-5cc7ca8e53df"
294 | },
295 | {
296 | "name": "获取路由列表",
297 | "path": "/route",
298 | "method": "get",
299 | "description": "获取路由列表",
300 | "id": "f42e8101-af1e-4717-82aa-a9d620b65021"
301 | },
302 | {
303 | "name": "获取路由",
304 | "path": "/route/:id",
305 | "method": "get",
306 | "description": "根据id获取路由",
307 | "id": "53b58c16-b9fb-4ea0-bb65-0bb4cfd96293"
308 | },
309 | {
310 | "name": "提交路由",
311 | "path": "/route/save",
312 | "method": "post",
313 | "description": "新增或更新路由",
314 | "id": "ffef90da-dab5-4177-81ae-1a4d8e70b0c8"
315 | },
316 | {
317 | "name": "删除路由",
318 | "path": "/route/:id",
319 | "method": "delete",
320 | "description": "根本id删除路由",
321 | "id": "cee27c96-c02c-409d-b446-1de2e55e2bf6"
322 | },
323 | {
324 | "name": "获取角色",
325 | "path": "/role/:id",
326 | "method": "get",
327 | "description": "根据id获取角色",
328 | "id": "02ce362f-1f04-4386-99c1-ef7a1bcf71fe"
329 | },
330 | {
331 | "name": "分页获取角色",
332 | "path": "/role/pagedlist",
333 | "method": "get",
334 | "description": "分页的方式获取角色数据,支持排序",
335 | "id": "90a1d0c6-22e5-4743-b39c-9f6e643b75d4"
336 | },
337 | {
338 | "name": "删除角色",
339 | "path": "/role/del",
340 | "method": "delete",
341 | "description": "根据id删除角色",
342 | "id": "873aaf0d-6f67-4c74-8dde-7dba8c524921"
343 | },
344 | {
345 | "name": "批量删除角色",
346 | "path": "/role/batchdel",
347 | "method": "delete",
348 | "description": "批量删除角色",
349 | "id": "0c229c5e-30d7-42c3-841a-73c4ba210a06"
350 | },
351 | {
352 | "name": "提交角色",
353 | "path": "/role/save",
354 | "method": "post",
355 | "description": "新增或更新角色",
356 | "id": "3d0a2d40-89d1-4416-8354-05849276dccd"
357 | },
358 | {
359 | "name": "获取角色功能权限",
360 | "path": "/role/getpermissions/:roleid",
361 | "method": "get",
362 | "description": "获取角色功能权限",
363 | "id": "6eb4cf01-45d1-432c-83ac-d9eb72c0c88e"
364 | },
365 | {
366 | "name": "保存角色功能权限",
367 | "path": "/role/savepermission",
368 | "method": "post",
369 | "description": "保存角色功能权限",
370 | "id": "07ff0d6a-78a6-4cd3-ba76-b4959a0c641a"
371 | },
372 | {
373 | "name": "获取用户",
374 | "path": "/user/:id",
375 | "method": "get",
376 | "description": "获取用户",
377 | "id": "020a75ef-ea43-4435-9a16-cb09fb79dc8b"
378 | },
379 | {
380 | "name": "分页获取用户",
381 | "path": "/user/pagedlist",
382 | "method": "get",
383 | "description": "分页获取用户",
384 | "id": "93c064e8-baf4-4f03-80ef-fa1230911213"
385 | },
386 | {
387 | "name": "提交用户",
388 | "path": "/user/save",
389 | "method": "post",
390 | "description": "新增或更新用户",
391 | "id": "31373f0b-0050-42d4-80b9-48dc3735f213"
392 | },
393 | {
394 | "name": "删除用户",
395 | "path": "/user/del",
396 | "method": "delete",
397 | "description": "删除用户",
398 | "id": "80eb294a-9919-4341-b1c0-ef94462bfa9f"
399 | },
400 | {
401 | "name": "批量删除用户",
402 | "path": "/user/batchdel",
403 | "method": "delete",
404 | "description": "批量删除用户",
405 | "id": "6cf44f79-726c-4655-843a-b05d8ed5ebd5"
406 | },
407 | {
408 | "name": "关联角色用户",
409 | "path": "/user/editroleuser",
410 | "method": "post",
411 | "description": "关联或取消关联",
412 | "id": "61cf07fb-bd28-46f0-88d1-b96d3d7d0556"
413 | },
414 | {
415 | "name": "获取用户权限信息",
416 | "path": "/user/info",
417 | "method": "get",
418 | "description": "获取用户权限信息",
419 | "id": "b49d6801-a037-46f2-bdc9-e175d64e6027"
420 | },
421 | {
422 | "name": "获取接口",
423 | "path": "/interface/:id",
424 | "method": "get",
425 | "description": "根据id获取接口",
426 | "id": "87d9908b-2876-4f50-ad80-7fd4fef34456"
427 | },
428 | {
429 | "name": "分页获取接口",
430 | "path": "/interface/paged",
431 | "method": "get",
432 | "description": "分页获取接口",
433 | "id": "72ce9b95-8b49-42f5-96f9-488f42f84da4"
434 | },
435 | {
436 | "name": "提交接口",
437 | "path": "/interface/save",
438 | "method": "post",
439 | "description": "新增或更新接口",
440 | "id": "dbf8208c-0c93-4f6d-8292-2c4821e2ee29"
441 | },
442 | {
443 | "name": "删除接口",
444 | "path": "/interface/del/:id",
445 | "method": "delete",
446 | "description": "删除接口",
447 | "id": "1a9bcd3d-2b2e-4fb4-8b67-13321d744b40"
448 | },
449 | {
450 | "name": "批量删除接口",
451 | "path": "/interface/batchdel/:ids",
452 | "method": "delete",
453 | "description": "批量删除接口",
454 | "id": "deb494eb-8417-4dcb-a7b9-7e0a3378930c"
455 | },
456 | {
457 | "name": "关联接口",
458 | "path": "/interface/relate",
459 | "method": "post",
460 | "description": "关联或取消关联",
461 | "id": "a77d58dc-69c1-4fb4-ab96-2e613f49d425"
462 | }
463 | ],
464 | "functionInterface": [
465 | {
466 | "functionId": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
467 | "interfaceId": "c6567a47-0382-4eb9-852b-3db2c8be9251"
468 | },
469 | {
470 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
471 | "interfaceId": "8dba087e-ba42-4220-a036-0de4adc0f585"
472 | },
473 | {
474 | "functionId": "c2578794-328c-4f0f-bbba-289ebdace7f1",
475 | "interfaceId": "23c892ed-76c6-4bdb-9240-4618b3fc4399"
476 | },
477 | {
478 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
479 | "interfaceId": "72ce9b95-8b49-42f5-96f9-488f42f84da4"
480 | }
481 | ],
482 | "role": [
483 | {
484 | "name": "菜单管理员",
485 | "code": "R_MENUADMIN",
486 | "description": "菜单管理员",
487 | "id": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
488 | "isAdd": 2
489 | }
490 | ],
491 | "roleUser": [
492 | {
493 | "userId": "54a3488f-3c94-489e-bcd0-3f2631991f5e",
494 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959"
495 | }
496 | ],
497 | "permission": [
498 | {
499 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
500 | "functionId": "c2578794-328c-4f0f-bbba-289ebdace7f1",
501 | "id": "6500ee1f-eaec-4c56-ad60-06b3367d45ba"
502 | },
503 | {
504 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
505 | "functionId": "34943e8f-5e57-4038-bd2f-6c13e3c5f168",
506 | "id": "6c9ef830-a5f8-45e2-927b-d096e81052db"
507 | },
508 | {
509 | "roleId": "6db7bf60-1cbc-404b-9894-4dd6f4a02959",
510 | "functionId": "3423218d-886c-4fb7-944d-42afe4c03076",
511 | "id": "968204ac-97c3-4f2c-bb3c-3ea1aa89731e"
512 | }
513 | ],
514 | "token": []
515 | }
--------------------------------------------------------------------------------
/src/db/request_log_db.json:
--------------------------------------------------------------------------------
1 | {
2 | "requestLog": [
3 | ]
4 | }
--------------------------------------------------------------------------------
/src/im/closeMiddleware.js:
--------------------------------------------------------------------------------
1 | export default () => {
2 | return function (context, next) {
3 | let server = context.server;
4 | let client = context.client;
5 | let code = context.code;
6 | let reason = context.message;
7 | server.clients.delete(client.clientId);
8 | if (code === 1003 && (reason === 'invalid clientId' || reason === 'exists clientId')) {
9 | console.log("'invalid clientId' or 'exists clientId' closed")
10 | } else {
11 | console.log(client.clientId + " closed");
12 | if (server.userMap) {
13 | server.userMap.delete(client.shortid);
14 | server.emit("user logout", {
15 | id: client.shortid,
16 | name: client.clientId
17 | });
18 | }
19 | }
20 | next();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/im/connectMiddleware.js:
--------------------------------------------------------------------------------
1 | import url from 'url';
2 | var shortid = require('shortid');
3 |
4 | function makeEvent(event) {
5 | return JSON.stringify({
6 | type: 'event',
7 | event: event.event,
8 | args: event.args
9 | })
10 | }
11 |
12 | export default () => {
13 | return function (context, next) {
14 | let req = context.req;
15 | let client = context.client;
16 | let server = context.server;
17 | let location = url.parse(req.url, true);
18 | let clientId = location.query.token || location.query.user;
19 | if (!clientId) {
20 | client.end(makeEvent({
21 | event: 'loginError',
22 | args: 'invalid token or user'
23 | }))
24 | client.close(1003, "invalid clientId");
25 | }
26 | if (server.clients.has(clientId)) {
27 | client.send(makeEvent({
28 | event: 'loginError',
29 | args: 'user online'
30 | }))
31 | client.close(1003, "exists clientId");
32 | return;
33 | }
34 | let sid = shortid.generate();
35 | let user = {
36 | id: sid,
37 | name: clientId
38 | };
39 | client.clientId = clientId;
40 | client.shortid = sid;
41 | server.clients.set(clientId, client);
42 | if (!server.userMap) {
43 | server.userMap = new Map();
44 | }
45 | if (!server.roomMap) {
46 | server.roomMap = new Map();
47 | }
48 | server.userMap.set(sid, user);
49 | server.emit('user login', {
50 | id: sid,
51 | name: clientId
52 | }, true);
53 | client.send(makeEvent({
54 | event: 'loginSuccess',
55 | args: {
56 | user: user,
57 | userList: [...server.userMap.values()],
58 | roomList: [...server.roomMap.values()]
59 | }
60 | }));
61 | console.log(client.clientId + " Connected");
62 | next();
63 | }
64 | }
--------------------------------------------------------------------------------
/src/im/index.js:
--------------------------------------------------------------------------------
1 | import connectMiddleware from './connectMiddleware';
2 | import closeMiddleware from './closeMiddleware';
3 | import messageMiddleware from './messageMiddleware';
4 | import remoteEmitMiddleware from './remoteEmitMiddleware';
5 | import roomInfoMiddleware from './roomInfoMiddleware';
6 | import messageRouteMiddleware from './messageRouteMiddleware';
7 | export default {
8 | connectMiddleware,
9 | closeMiddleware,
10 | messageMiddleware,
11 | remoteEmitMiddleware,
12 | roomInfoMiddleware,
13 | messageRouteMiddleware
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/src/im/messageMiddleware.js:
--------------------------------------------------------------------------------
1 | export default () => {
2 | return (context, next) => {
3 | if (context.req.type === 'event') {
4 | //context.server.emit(context.req.event, context.req.args, true);
5 | context.server.emit(context.req.event, context.req.args);
6 | }
7 | next();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/im/messageRouteMiddleware.js:
--------------------------------------------------------------------------------
1 | export default (routes) => {
2 | return async (context, next) => {
3 | if (context.req.type === 'event') {
4 | if (routes[context.req.event]) {
5 | await routes[context.req.event](context);
6 | } else {
7 | context.server.emit(context.req.event, context.req.args);
8 | }
9 | }
10 | next();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/im/remoteEmitMiddleware.js:
--------------------------------------------------------------------------------
1 | // emit才会调用此中间件
2 | export default () => {
3 | return (context, next) => {
4 | let server = context.server;
5 | let event = context.event;
6 | let msgType = event.args.type;//broadcast=0,private chat=1,room chat=2, default 0
7 | if (msgType > 0) {
8 | if (msgType == 1) {
9 | let to = event.args.to.user;
10 | let from = event.args.from;
11 | for (let client of server.clients.values()) {
12 | if (to.name == client.clientId || from.name == client.clientId) {
13 | client.send(makeEventMessage(event));
14 | }
15 | }
16 | }
17 | else if (msgType == 2) {
18 | let to = event.args.to.room;
19 | let room = server.roomMap.get(to.id);
20 | for (let client of server.clients.values()) {
21 | if (room.userList.some((user) => user.name == client.clientId)) {
22 | client.send(makeEventMessage(event));
23 | }
24 | }
25 | }
26 | }
27 | else {
28 | for (let client of server.clients.values()) {
29 | client.send(makeEventMessage(event));
30 | }
31 | }
32 | next();
33 | }
34 | }
35 | function makeEventMessage(event) {
36 | return JSON.stringify({
37 | type: 'event',
38 | event: event.event,
39 | args: event.args
40 | })
41 | }
--------------------------------------------------------------------------------
/src/im/roomInfoMiddleware.js:
--------------------------------------------------------------------------------
1 | var shortid = require('shortid');
2 | export default () => {
3 | return (context, next) => {
4 | if (context.req.type === 'event' && context.req.event === 'addRoom') {
5 | if (!context.server.roomMap) {
6 | context.server.roomMap = new Map();
7 | }
8 | let roomId = shortid.generate();
9 | context.req.args.id = roomId;
10 | context.server.roomMap.set(roomId, {
11 | id:roomId,
12 | name: context.req.args.name,
13 | userList: []
14 | });
15 | }
16 | if (context.req.type === 'event' && context.req.event === 'enterRoom') {
17 | let room = context.server.roomMap.get(context.req.args.room.id);
18 | room.userList.push({ ...context.req.args.user });
19 | }
20 |
21 | if (context.req.type === 'event' && context.req.event === 'leaveRoom') {
22 | let room = context.server.roomMap.get(context.req.args.room.id);
23 | room.userList.splice(room.userList.findIndex((user) => user.id == context.req.args.user.id), 1);
24 | }
25 |
26 | next();
27 | }
28 | }
--------------------------------------------------------------------------------
/src/im/routes/index.js:
--------------------------------------------------------------------------------
1 | let requireDirectory = require('require-directory')
2 | module.exports = requireDirectory(module)
--------------------------------------------------------------------------------
/src/im/routes/message.js:
--------------------------------------------------------------------------------
1 | export default {
2 |
3 | }
--------------------------------------------------------------------------------
/src/im/routes/room.js:
--------------------------------------------------------------------------------
1 | var shortid = require('shortid');
2 | export default {
3 | addRoom: function (context) {
4 | if (!context.server.roomMap) {
5 | context.server.roomMap = new Map();
6 | }
7 | let roomId = shortid.generate();
8 | context.req.args.id = roomId;
9 | context.server.roomMap.set(roomId, {
10 | id: roomId,
11 | name: context.req.args.name,
12 | userList: []
13 | });
14 | context.server.emit("addRoom", context.req.args);
15 | console.log("addRoom")
16 | },
17 | enterRoom: function (context) {
18 | let room = context.server.roomMap.get(context.req.args.room.id);
19 | room.userList.push({ ...context.req.args.user });
20 | context.server.emit("enterRoom", context.req.args);
21 | console.log("enterRoom")
22 | },
23 | leaveRoom: function (context) {
24 | let room = context.server.roomMap.get(context.req.args.room.id);
25 | room.userList.splice(room.userList.findIndex((user) => user.id == context.req.args.user.id), 1);
26 | context.server.emit("enterRoom", context.req.args);
27 | console.log("enterRoom")
28 | }
29 | }
--------------------------------------------------------------------------------
/src/lib/EasySocket.js:
--------------------------------------------------------------------------------
1 | import compose from './compose';
2 | const WebSocket = require('ws');
3 | var EventEmitter = require('events').EventEmitter;
4 | export default class EasySocket extends EventEmitter {
5 | constructor() {
6 | super();
7 | this.clients = new Map();
8 | this.connectionMiddleware = [];
9 | this.closeMiddleware = [];
10 | this.messageMiddleware = [];
11 | this.errorMiddleware = [];
12 | this.remoteEmitMiddleware = [];
13 |
14 | this.connectionFn = Promise.resolve();
15 | this.closeFn = Promise.resolve();
16 | this.messageFn = Promise.resolve();
17 | this.errorFn = Promise.resolve();
18 | this.remoteEmitFn = Promise.resolve();
19 | }
20 | connectionUse(fn, runtime) {
21 | this.connectionMiddleware.push(fn);
22 | if (runtime) {
23 | this.connectionFn = compose(this.connectionMiddleware);
24 | }
25 | return this;
26 | }
27 | closeUse(fn, runtime) {
28 | this.closeMiddleware.push(fn);
29 | if (runtime) {
30 | this.closeFn = compose(this.closeMiddleware);
31 | }
32 | return this;
33 | }
34 | messageUse(fn, runtime) {
35 | this.messageMiddleware.push(fn);
36 | if (runtime) {
37 | this.messageFn = compose(this.messageMiddleware);
38 | }
39 | return this;
40 | }
41 | errorUse(fn, runtime) {
42 | this.errorMiddleware.push(fn);
43 | if (runtime) {
44 | this.errorFn = compose(this.errorMiddleware);
45 | }
46 | return this;
47 | }
48 | remoteEmitUse(fn, runtime) {
49 | this.remoteEmitMiddleware.push(fn);
50 | if (runtime) {
51 | this.remoteEmitFn = compose(this.remoteEmitMiddleware);
52 | }
53 | return this;
54 | }
55 | listen(config) {
56 | this.socket = new WebSocket.Server(config);
57 | this.connectionFn = compose(this.connectionMiddleware);
58 | this.messageFn = compose(this.messageMiddleware);
59 | this.closeFn = compose(this.closeMiddleware);
60 | this.errorFn = compose(this.errorMiddleware);
61 | this.remoteEmitFn = compose(this.remoteEmitMiddleware);
62 |
63 | this.socket.on('connection', (client, req) => {
64 | let context = { server: this, client, req };
65 | this.connectionFn(context).catch(error => { console.log(error) });
66 |
67 | client.on('message', (message) => {
68 | let req;
69 | try {
70 | req = JSON.parse(message);
71 | } catch (error) {
72 | req = message;
73 | }
74 | let messageContext = { server: this, client, req }
75 | this.messageFn(messageContext).catch(error => { console.log(error) })
76 | });
77 |
78 | client.on('close', (code, message) => {
79 | let closeContext = { server: this, client, code, message };
80 | this.closeFn(closeContext).catch(error => { console.log(error) })
81 | });
82 |
83 | client.on('error', (error) => {
84 | let errorContext = { server: this, client, error };
85 | this.errorFn(errorContext).catch(error => { console.log(error) })
86 | });
87 | })
88 | }
89 | emit(event, args, isLocal = false) {
90 | let arr = [event, args];
91 | if (isLocal) {
92 | super.emit.apply(this, arr);
93 | return this;
94 | }
95 | let evt = {
96 | event: event,
97 | args: args
98 | }
99 | let remoteEmitContext = { server: this, event: evt };
100 | this.remoteEmitFn(remoteEmitContext).catch(error => { console.log(error) })
101 | return this;
102 | }
103 | }
--------------------------------------------------------------------------------
/src/lib/compose.js:
--------------------------------------------------------------------------------
1 | /**
2 | * copy from https://github.com/koajs/compose
3 | */
4 | export default function compose(middleware) {
5 | if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
6 | for (const fn of middleware) {
7 | if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
8 | }
9 |
10 | /**
11 | * @param {Object} context
12 | * @return {Promise}
13 | * @api public
14 | */
15 |
16 | return function (context, next) {
17 | // last called middleware #
18 | let index = -1
19 | return dispatch(0)
20 | function dispatch(i) {
21 | if (i <= index) return Promise.reject(new Error('next() called multiple times'))
22 | index = i
23 | let fn = middleware[i]
24 | if (i === middleware.length) fn = next
25 | if (!fn) return Promise.resolve()
26 | try {
27 | return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
28 | } catch (err) {
29 | return Promise.reject(err)
30 | }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/lib/proxy.js:
--------------------------------------------------------------------------------
1 | const request = require('superagent')
2 | const url = require('url')
3 |
4 | export default async function(ctx, host, referer = 'http://www.baidu.com') {
5 | let hostObj = url.parse(host)
6 | let result = {}
7 | try {
8 | if (ctx.request.method.toUpperCase() === 'PUT' || ctx.request.method.toUpperCase() === 'POST') {
9 | result = await request(ctx.request.method, host + ctx.request.url)
10 | .set({
11 | ...ctx.request.header,
12 | Referer: referer,
13 | Host: hostObj.hostname
14 | })
15 | .send({ ...ctx.request.body })
16 | } else {
17 | result = await request(ctx.request.method, host + ctx.request.url).set({
18 | ...ctx.request.header,
19 | Referer: referer,
20 | Host: hostObj.hostname
21 | })
22 | }
23 | } catch (ex) {
24 | result.body = ex.response.text
25 | }
26 | return result
27 | }
28 |
--------------------------------------------------------------------------------
/src/lib/responseTemplate.js:
--------------------------------------------------------------------------------
1 | export let businessError = (ctx,msg) => {
2 | ctx.body = {
3 | statusCode: 500,
4 | msg: msg,
5 | data: null
6 | }
7 | }
8 |
9 | export let success = (ctx,data) => {
10 | ctx.body = {
11 | statusCode: 200,
12 | msg: '',
13 | data: data
14 | }
15 | }
--------------------------------------------------------------------------------
/src/middleware/ErrorRoutesCatch.js:
--------------------------------------------------------------------------------
1 | module.exports = function () {
2 | return function (ctx, next) {
3 | return next().catch((err) => {
4 | switch (err.status) {
5 | case 401:
6 | ctx.status = 401
7 | ctx.body = {
8 | status: 401,
9 | result: {
10 | err: 'Authentication Error',
11 | errInfo: 'Protected resource, use Authorization header to get access.'
12 | }
13 | }
14 | break
15 | default:
16 | throw err
17 | }
18 | })
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/middleware/ParseUserInfo.js:
--------------------------------------------------------------------------------
1 | import jwt from 'jsonwebtoken'
2 | import fs from 'fs'
3 | import path from 'path'
4 | const publicKey = fs.readFileSync(path.join(__dirname, '../../publicKey.pub'))
5 |
6 | module.exports = function () {
7 | return function (ctx, next) {
8 | if (ctx.request.header.authorization) {
9 | let token = ctx.header.authorization.split(' ')[1]
10 | if (token&&token!=='undefined') {
11 | let decoded = jwt.verify(token, publicKey)
12 | if (decoded.userId) {
13 | ctx.user = {
14 | token: token,
15 | userId: decoded.userId
16 | }
17 | }
18 | }
19 | }
20 | return next()
21 | }
22 | }
--------------------------------------------------------------------------------
/src/middleware/PermissionCheck.js:
--------------------------------------------------------------------------------
1 | import userService from '../services/userService'
2 | import interfaceService from '../services/interfaceService'
3 | import * as responseTemplate from '../lib/responseTemplate'
4 | import { match, parse } from 'matchit';
5 |
6 | module.exports = (permission = [], role = [], apiCheck = true) => {
7 | return async function (ctx, next) {
8 | if (!ctx.user || !ctx.user.userId) {
9 | return responseTemplate.businessError(ctx, "没有访问权限")
10 | }
11 | if (permission.length == 0 && role.length == 0 && !apiCheck) {
12 | return next()
13 | }
14 | let isAdmin = await userService.isAdmin(ctx.user.userId)
15 | if (isAdmin) {
16 | return next()
17 | }
18 | let roles = await userService.getUserRole(ctx.user.userId)
19 | let r = roles.filter(s => {
20 | return role.indexOf(s) > -1
21 | })
22 | if (r && r.length > 0) {
23 | return next()
24 | }
25 | let userPermisssions = await userService.getUserPermission(ctx.user.userId)
26 | let p = userPermisssions.filter(s => {
27 | return permission.indexOf(s) > -1
28 | })
29 | if (p && p.length > 0) {
30 | return next()
31 | }
32 | let userAccessInterfaces = await interfaceService.getAccessInterfaceList(ctx.user.userId)
33 | userAccessInterfaces = userAccessInterfaces.filter(s => s.method.toUpperCase() === ctx.request.method.toUpperCase()).map(s => parse(s.path))
34 | let matched = match(ctx.request.url.split("?")[0], userAccessInterfaces)
35 | if (matched.length > 0) {
36 | return next()
37 | }
38 | return responseTemplate.businessError(ctx, "没有访问权限")
39 | }
40 | };
--------------------------------------------------------------------------------
/src/middleware/Proxy.js:
--------------------------------------------------------------------------------
1 | const request = require('superagent')
2 | const url = require('url')
3 | module.exports = (host, referer = 'http://www.baidu.com') => {
4 | let hostObj = url.parse(host)
5 | return async function(ctx, next) {
6 | let result = {}
7 | try {
8 | if (ctx.request.method.toUpperCase() === 'PUT' || ctx.request.method.toUpperCase() === 'POST') {
9 | result = await request(ctx.request.method, host + ctx.request.url)
10 | .set({
11 | ...ctx.request.header,
12 | Referer: referer,
13 | Host: hostObj.hostname
14 | })
15 | .send({ ...ctx.request.body })
16 | } else {
17 | result = await request(ctx.request.method, host + ctx.request.url).set({
18 | ...ctx.request.header,
19 | Referer: referer,
20 | Host: hostObj.hostname
21 | })
22 | }
23 | ctx.body = result.type.indexOf('html') > -1 ? result.text : result.body
24 | } catch (ex) {
25 | ctx.status = ex.status
26 | ctx.body = ex.response.text
27 | }
28 | console.log('proxy')
29 | return
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/middleware/RequestLog.js:
--------------------------------------------------------------------------------
1 | import requestLogService from '../services/requestLogService'
2 | module.exports = function () {
3 | return (ctx, next) => {
4 | if (ctx.url.indexOf("/requestlog/pagedlist") > -1) {
5 | return next()
6 | }
7 | const start = new Date()
8 | return next().then(async () => {
9 | const ms = new Date() - start
10 | let userId = ctx.user && ctx.user.userId ? ctx.user.userId : ''
11 | let ip = ctx.ip.split(":").pop()
12 | let log = {
13 | ip: ip,
14 | method: ctx.method,
15 | request: ctx.url.split("?")[0],
16 | time: ms,
17 | createdBy: userId,
18 | createdDate: start.getTime()
19 | }
20 | await requestLogService.addLog(log)
21 | })
22 | }
23 | }
--------------------------------------------------------------------------------
/src/models/baseModel.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | const low = require('lowdb')
4 | const lodashId = require('lodash-id')
5 | const FileAsync = require('lowdb/adapters/FileAsync')
6 | const dbFile = path.join(__dirname, '../db/db.json')
7 | const adapter = new FileAsync(dbFile)
8 | let instance = undefined
9 | module.exports = {
10 | init: function (context) {
11 | return new Promise((resolve, reject) => {
12 | if (instance === undefined) {
13 | low(adapter).then(db => {
14 | db._.mixin(lodashId)
15 | instance = db;
16 | resolve(db.get(context))
17 | })
18 | } else {
19 | resolve(instance.get(context))
20 | }
21 | })
22 | },
23 | read: () => {
24 | return new Promise((resolve, reject) => {
25 | if (instance === undefined) {
26 | resolve()
27 | }
28 | else {
29 | instance.read().then(() => {
30 | resolve()
31 | })
32 | }
33 | })
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/models/index.js:
--------------------------------------------------------------------------------
1 | let requireDirectory = require('require-directory')
2 | module.exports = requireDirectory(module)
3 |
--------------------------------------------------------------------------------
/src/models/requestLogModel.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | const low = require('lowdb')
4 | const lodashId = require('lodash-id')
5 | const FileAsync = require('lowdb/adapters/FileAsync')
6 | const dbFile = path.join(__dirname, '../db/request_log_db.json')
7 | const adapter = new FileAsync(dbFile)
8 | let instance = undefined
9 | module.exports = {
10 | init: function (context) {
11 | return new Promise((resolve, reject) => {
12 | if (instance === undefined) {
13 | low(adapter).then(db => {
14 | db._.mixin(lodashId)
15 | instance = db;
16 | resolve(db.get(context))
17 | })
18 | } else {
19 | resolve(instance.get(context))
20 | }
21 | })
22 | },
23 | read: () => {
24 | return new Promise((resolve, reject) => {
25 | if (instance === undefined) {
26 | resolve()
27 | }
28 | else {
29 | instance.read().then(() => {
30 | resolve()
31 | })
32 | }
33 | })
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/routes/index.js:
--------------------------------------------------------------------------------
1 | let requireDirectory = require('require-directory')
2 | module.exports = requireDirectory(module)
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/routes/main.js:
--------------------------------------------------------------------------------
1 | import KoaRouter from 'koa-router'
2 | import controllers from '../controllers/index.js'
3 | import PermissionCheck from '../middleware/PermissionCheck'
4 |
5 | const router = new KoaRouter()
6 |
7 | router
8 | .get('/public/get', function (ctx, next) {
9 | ctx.body = '允许访问!'
10 | }) // 以/public开头则不用经过权限认证
11 | .post('/auth/login', controllers.auth.login)
12 | .post('/auth/logout', controllers.auth.logout)
13 |
14 | .get('/menu', PermissionCheck(), controllers.menu.getMenuList)
15 | .get('/menu/:id', PermissionCheck(), controllers.menu.getMenu)
16 | .post('/menu/save', PermissionCheck(), controllers.menu.saveMenu)
17 | .del('/menu/:id', PermissionCheck(), controllers.menu.delMenu)
18 |
19 | .get('/route', PermissionCheck(), controllers.route.getRouteList)
20 | .get('/route/paged', PermissionCheck(), controllers.route.getRoutePagedList)
21 | .get('/route/:id', PermissionCheck(), controllers.route.getRoute)
22 | .del('/route/:id', PermissionCheck(), controllers.route.delRoute)
23 | .del('/route/batchdel', PermissionCheck(), controllers.route.delRoutes)
24 | .post('/route/save', PermissionCheck(), controllers.route.saveRoute)
25 |
26 | .get('/role/pagedlist', PermissionCheck(), controllers.role.getRolePagedList)
27 | .get('/role/:id', PermissionCheck(), controllers.role.getRole)
28 | .get('/role/getpermissions/:roleId', PermissionCheck(), controllers.role.getRolePermissions)
29 | .del('/role/del', PermissionCheck(), controllers.role.delRole)
30 | .del('/role/batchdel', PermissionCheck(), controllers.role.delRoles)
31 | .post('/role/save', PermissionCheck(), controllers.role.saveRole)
32 | .post('/role/savepermission', PermissionCheck(), controllers.role.savePermission)
33 |
34 | .get('/user/pagedlist', PermissionCheck(), controllers.user.getUserPagedList)
35 | .get('/user/info', controllers.user.getUserInfo)
36 | .get('/user/:id', PermissionCheck(), controllers.user.getUser)
37 | .del('/user/del', PermissionCheck(), controllers.user.delUser)
38 | .del('/user/batchdel', PermissionCheck(), controllers.user.delUsers)
39 | .post('/user/save', PermissionCheck(), controllers.user.saveUser)
40 | .post('/user/editroleuser', PermissionCheck(), controllers.user.editRoleUser)
41 |
42 | .get('/interface/paged', PermissionCheck(), controllers.interface.getInterfacePagedList)
43 | .get('/interface/:id', PermissionCheck(), controllers.interface.getInterface)
44 | .del('/interface/del', PermissionCheck(), controllers.interface.delInterface)
45 | .del('/interface/batchdel', PermissionCheck(), controllers.interface.delInterfaces)
46 | .post('/interface/save', PermissionCheck(), controllers.interface.saveInterface)
47 | .post('/interface/relate', PermissionCheck(), controllers.interface.relateInterface)
48 |
49 | .get('/requestlog/pagedlist', controllers.requestlog.getRequestLogPagedList)
50 | .post('/resetdb', controllers.system.resetDb)
51 |
52 |
53 | module.exports = router
54 |
--------------------------------------------------------------------------------
/src/services/interfaceService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 | import userService from '../services/userService'
3 | import _ from 'lodash'
4 | const context = 'interface'
5 | const functionInterfaceContext = 'functionInterface'
6 | module.exports = {
7 | getInterface: async (id) => {
8 | let db = await model.init(context)
9 | let entity = db.find({ id: id }).value()
10 | return entity
11 | },
12 | getInterfacePagedList: async (pageIndex, pageSize, sortBy, descending, filter) => {
13 | let db = await model.init(context)
14 | let interfaceList = db.value()
15 | let resultList = JSON.parse(JSON.stringify(interfaceList))
16 | if (filter.id) {
17 | resultList = _.filter(resultList, (o) => {
18 | return o.id.indexOf(filter.id) > -1
19 | });
20 | }
21 | if (filter.name) {
22 | resultList = _.filter(resultList, (o) => {
23 | return o.name.indexOf(filter.name) > -1
24 | });
25 | }
26 | if (filter.path) {
27 | resultList = _.filter(resultList, (o) => {
28 | return o.path.indexOf(filter.path) > -1
29 | });
30 | }
31 | if (filter.method) {
32 | resultList = _.filter(resultList, (o) => {
33 | return o.method.indexOf(filter.method) > -1
34 | });
35 | }
36 | if (filter.isLocked) {
37 | resultList = _.filter(resultList, (o) => {
38 | return o.isLocked.indexOf(filter.isLocked) > -1
39 | });
40 | }
41 | if (filter.description) {
42 | resultList = _.filter(resultList, (o) => {
43 | return o.description.indexOf(filter.description) > -1
44 | });
45 | }
46 | if (filter.functionId) {
47 | let functionInterfaceDb = await model.init(functionInterfaceContext)
48 | let functionInterfaceList = functionInterfaceDb.filter({ functionId: filter.functionId }).value()
49 | let interfaceIdList = functionInterfaceList.map(s => {
50 | return s.interfaceId
51 | })
52 | resultList = _.map(resultList, (item) => {
53 | if (interfaceIdList.indexOf(item.id) > -1) {
54 | item.isAdd = 1
55 | } else {
56 | item.isAdd = 2
57 | }
58 | return item
59 | })
60 | sortBy = "isAdd"
61 | }
62 | let totalCount = resultList.length
63 | if (sortBy) {
64 | resultList = _.sortBy(resultList, [sortBy])
65 | if (descending === 'true') {
66 | resultList = resultList.reverse()
67 | }
68 | }
69 | if (!pageIndex || pageIndex <= 0) {
70 | pageIndex = 1
71 | }
72 | if (pageSize) {
73 | let start = (pageIndex - 1) * pageSize
74 | let end = pageIndex * pageSize
75 | resultList = _.slice(resultList, start, end)
76 | }
77 | return {
78 | totalCount: totalCount,
79 | rows: resultList
80 | }
81 |
82 | },
83 | delInterface: async (id) => {
84 | let db = await model.init(context)
85 | await db.remove({ id: id }).write()
86 | },
87 | saveInterface: async (entity) => {
88 | let db = await model.init(context)
89 | let exist = db.find({ path: entity.path, method: entity.method }).value()
90 | if (exist && exist.id != entity.id) {
91 | return {
92 | success: false,
93 | msg: "路径与方法组合必须唯一"
94 | }
95 | }
96 | if (entity.id) {
97 | await db.find({ id: entity.id })
98 | .assign(entity)
99 | .write()
100 | } else {
101 | await db.insert(entity).write()
102 | }
103 | return {
104 | success: true,
105 | msg: ""
106 | }
107 | },
108 | relate: async (functionInterface) => {
109 | let functionInterfaceDb = await model.init(functionInterfaceContext)
110 | if (functionInterface.action == 1) {
111 | await functionInterfaceDb.push({ functionId: functionInterface.functionId, interfaceId: functionInterface.interfaceId }).write()
112 | } else {
113 | await functionInterfaceDb.remove({ functionId: functionInterface.functionId, interfaceId: functionInterface.interfaceId }).write()
114 | }
115 | },
116 | getAccessInterfaceList: async (userId) => {
117 | let functionInterfaceDb = await model.init(functionInterfaceContext)
118 | let db = await model.init(context)
119 | let userFunctions = await userService.getUserFunctions(userId)
120 | let userFunctionIds = userFunctions.map(s => s.id)
121 | let functionInterfaceList = functionInterfaceDb.value()
122 | let userFunctionInterfaceList = functionInterfaceList.filter(s => {
123 | return userFunctionIds.indexOf(s.functionId) > -1
124 | })
125 | let userInterfaceIdList = userFunctionInterfaceList.map(s => s.interfaceId)
126 | let interfaceIdList = db.value()
127 | let userInterfaceList = interfaceIdList.filter(s => {
128 | return userInterfaceIdList.indexOf(s.id) > -1
129 | })
130 | return userInterfaceList
131 | }
132 | }
--------------------------------------------------------------------------------
/src/services/memuService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 | import userService from './userService'
3 | import _ from 'lodash'
4 | const context = 'menu'
5 | let buildMenu = (parentMenu, menuList) => {
6 | parentMenu.children = []
7 | let children = menuList.filter((item) => {
8 | return item.parentId == parentMenu.id
9 | })
10 | for (let menu of children) {
11 | buildMenu(menu, menuList)
12 | }
13 | parentMenu.children.push(...children)
14 | }
15 | let buildAccessMenu = (parentMenu, menuList, userPermission) => {
16 | parentMenu.children = []
17 | let children = menuList.filter((item) => {
18 | return item.parentId == parentMenu.id && (!item.permission || userPermission.indexOf(item.permission) > -1)
19 | })
20 | //父级没有权限访问,子级也不能访问
21 | for (let menu of children) {
22 | buildAccessMenu(menu, menuList, userPermission)
23 | }
24 | parentMenu.children.push(...children)
25 | }
26 | let checkAccssMenu = (accessMenuList, menuList) => {
27 | for (let item of accessMenuList) {
28 | if (item.children) {
29 | checkAccssMenu(item.children, menuList)
30 | }
31 | }
32 | _.remove(accessMenuList, (item) => {
33 | return item.children.length == 0 && menuList.some(s => {
34 | return s.parentId == item.id
35 | })
36 | });
37 | }
38 | let menuService = {
39 | getMenu: async (id) => {
40 | let db = await model.init(context)
41 | let menu = db.find({ id: id }).value()
42 | if (!menu) {
43 | menu = db.find({ id: parseInt(id) }).value()
44 | }
45 | return menu
46 | },
47 | getMenuList: async () => {
48 | let db = await model.init(context)
49 | let menuList = JSON.parse(JSON.stringify(db.value()))
50 | menuList = _.sortBy(menuList, ["sort"])
51 | let parentMenuList = menuList.filter((item) => {
52 | return item.parentId === 0
53 | })
54 | for (let menu of parentMenuList) {
55 | buildMenu(menu, menuList)
56 | }
57 | return parentMenuList
58 | },
59 | getAccessMenuList: async (userId) => {
60 | let db = await model.init(context)
61 | let menuList = JSON.parse(JSON.stringify(db.filter({ type: 1 }).value()))
62 | menuList = _.sortBy(menuList, ["sort"])
63 | let parentMenuList = menuList.filter((item) => {
64 | return item.parentId == 0 && !item.isLock
65 | })
66 | let isAdmin = await userService.isAdmin(userId)
67 | let userPermission = await userService.getUserPermission(userId)
68 | if (isAdmin) {
69 | for (let menu of parentMenuList) {
70 | buildMenu(menu, menuList)
71 | }
72 | } else {
73 | for (let menu of parentMenuList) {
74 | buildAccessMenu(menu, menuList, userPermission)
75 | }
76 | }
77 | checkAccssMenu(parentMenuList, menuList)
78 | return parentMenuList
79 | },
80 | saveMenu: async (menu) => {
81 | let db = await model.init(context)
82 | if (menu.id) {
83 | await db.find({ id: menu.id })
84 | .assign(menu)
85 | .write()
86 | } else {
87 | await db.insert(menu).write()
88 | }
89 | return {
90 | success: true,
91 | msg: ""
92 | }
93 | },
94 | delMenu: async (menuId) => {
95 | let db = await model.init(context)
96 | let child = db.find({ parentId: menuId }).value()
97 | if (child) {
98 | return {
99 | success: false,
100 | msg: "请先删除子菜单"
101 | }
102 | }
103 | await db.remove({ id: menuId }).write()
104 | return {
105 | success: true,
106 | msg: ""
107 | }
108 | }
109 | }
110 | module.exports = menuService
--------------------------------------------------------------------------------
/src/services/requestLogService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/requestLogModel'
2 | import userService from './userService'
3 | import _ from 'lodash'
4 | const context = 'requestLog'
5 |
6 | let requestLogService = {
7 | addLog: async (log) => {
8 | let db = await model.init(context)
9 | await db.insert(log).write()
10 | },
11 | getRequestLogPagedList: async (pageIndex, pageSize, sortBy, descending) => {
12 | let db = await model.init(context)
13 | let list = db.value()
14 | let resultList = list
15 | let totalCount = resultList.length
16 | if (sortBy) {
17 | resultList = _.sortBy(resultList, [sortBy])
18 | if (descending === 'true') {
19 | resultList = resultList.reverse()
20 | }
21 | }
22 | else {
23 | resultList = _.sortBy(resultList, ["createdDate"])
24 | if (descending === 'true') {
25 | resultList = resultList.reverse()
26 | }
27 | }
28 | let start = (pageIndex - 1) * pageSize
29 | let end = pageIndex * pageSize
30 | resultList = _.slice(resultList, start, end)
31 | let userList = await userService.getUserList()
32 | for (let item of resultList) {
33 | let user = userList.filter(s => {
34 | return s.id == item.createdBy
35 | })
36 | if (user.length > 0) {
37 | item.createdByName = user[0].name
38 | } else {
39 | item.createdByName = item.createdBy
40 | }
41 | }
42 | return {
43 | totalCount: totalCount,
44 | rows: resultList
45 | }
46 |
47 | }
48 | }
49 | module.exports = requestLogService
--------------------------------------------------------------------------------
/src/services/roleService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 | import _ from 'lodash'
3 | const context = 'role'
4 | const permissionContext = "permission"
5 | const roleUserContext = 'roleUser'
6 | module.exports = {
7 | getRole: async (id) => {
8 | let db = await model.init(context)
9 | let role = db.find({ id: id }).value()
10 | return role
11 | },
12 | getRolePagedList: async (pageIndex, pageSize, sortBy, descending, filter) => {
13 | let db = await model.init(context)
14 | let roleList = db.value()
15 | let resultList = roleList
16 | if (filter.code) {
17 | resultList = _.filter(resultList, (o) => {
18 | return o.code.indexOf(filter.code) > -1
19 | });
20 | }
21 | if (filter.name) {
22 | resultList = _.filter(resultList, (o) => {
23 | return o.name.indexOf(filter.name) > -1
24 | });
25 | }
26 | if (filter.userId) {
27 | let roleUserDb = await model.init(roleUserContext)
28 | let roleUserList = roleUserDb.filter({ userId: filter.userId }).value()
29 | roleUserList = roleUserList.map(s => {
30 | return s.roleId
31 | })
32 | resultList = _.map(resultList, (item) => {
33 | if (roleUserList.indexOf(item.id) > -1) {
34 | item.isAdd = 1
35 | } else {
36 | item.isAdd = 2
37 | }
38 | return item
39 | })
40 | sortBy = "isAdd"
41 | }
42 | let totalCount = resultList.length
43 | if (sortBy) {
44 | resultList = _.sortBy(resultList, [sortBy])
45 | if (descending === 'true') {
46 | resultList = resultList.reverse()
47 | }
48 | }
49 | let start = (pageIndex - 1) * pageSize
50 | let end = pageIndex * pageSize
51 | resultList = _.slice(resultList, start, end)
52 |
53 | return {
54 | totalCount: totalCount,
55 | rows: resultList
56 | }
57 |
58 | },
59 | delRole: async (id) => {
60 | let db = await model.init(context)
61 | await db.remove({ id: id }).write()
62 | },
63 | saveRole: async (role) => {
64 | let db = await model.init(context)
65 | let exist = db.find({ code: role.code }).value()
66 | if (exist && exist.id != role.id) {
67 | return {
68 | success: false,
69 | msg: "角色编码已经存在"
70 | }
71 | }
72 | let exist1 = db.find({ name: role.name }).value()
73 | if (exist1 && exist1.id != role.id) {
74 | return {
75 | success: false,
76 | msg: "角色名称已经存在"
77 | }
78 | }
79 | if (role.id) {
80 |
81 | await db.find({ id: role.id })
82 | .assign(role)
83 | .write()
84 | } else {
85 | await db.insert(role).write()
86 | }
87 | return {
88 | success: true,
89 | msg: ""
90 | }
91 | },
92 | getRoleFunctions: async (roleId) => {
93 | let db = await model.init(permissionContext)
94 | let list = db.value()
95 | let roleFunctions = list.filter(s => {
96 | return s.roleId == roleId
97 | })
98 | return roleFunctions
99 | },
100 | getRoleFuntionsByRoleIds: async (roleIds) => {
101 | let db = await model.init(permissionContext)
102 | let list = db.value()
103 | let roleFunctions = list.filter(s => {
104 | return roleIds.indexOf(s.roleId) > -1
105 | })
106 | return roleFunctions
107 | },
108 | savePermission: async (roleId, permissions) => {
109 | let db = await model.init(permissionContext)
110 | await await db.remove({ roleId: roleId }).write()
111 | for (let permission of permissions) {
112 | await db.insert({
113 | roleId: roleId,
114 | functionId: permission,
115 | }).write()
116 | }
117 | },
118 | getRoleListByIdList: async (idList) => {
119 | let db = await model.init(context)
120 | let roleList = db.value()
121 | let result = roleList.filter(s => {
122 | return idList.indexOf(s.id) > -1
123 | })
124 | return result
125 | }
126 | }
--------------------------------------------------------------------------------
/src/services/routeService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 | import userService from './userService'
3 | import _ from 'lodash'
4 | const context = 'route'
5 | let buildChildren = (parent, list) => {
6 | parent.children = []
7 | let children = list.filter((item) => {
8 | return item.parentId == parent.id
9 | })
10 | for (let item of children) {
11 | buildChildren(item, list)
12 | }
13 | parent.children.push(...children)
14 | }
15 | module.exports = {
16 | getRoute: async (id) => {
17 | let db = await model.init(context)
18 | let route = db.find({ id: id }).value()
19 | return route
20 | },
21 | getRouteList: async () => {
22 | let db = await model.init(context)
23 | let list = JSON.parse(JSON.stringify(db.value()))
24 | list = _.sortBy(list, ["sort"])
25 | let parentList = list.filter((item) => {
26 | return !item.parentId
27 | })
28 | for (let item of parentList) {
29 | buildChildren(item, list)
30 | }
31 | return parentList
32 | },
33 | getRoutePagedList: async (pageIndex, pageSize, sortBy, descending, filter) => {
34 | let db = await model.init(context)
35 | let routeList = db.value()
36 | let resultList = routeList
37 |
38 | if (filter.id) {
39 | resultList = _.filter(resultList, (o) => {
40 | return o.id.indexOf(filter.id) > -1
41 | });
42 | }
43 |
44 | if (filter.parentId) {
45 | resultList = _.filter(resultList, (o) => {
46 | return o.parentId.indexOf(filter.parentId) > -1
47 | });
48 | }
49 |
50 | if (filter.name) {
51 | resultList = _.filter(resultList, (o) => {
52 | return o.name.indexOf(filter.name) > -1
53 | });
54 | }
55 |
56 | if (filter.path) {
57 | resultList = _.filter(resultList, (o) => {
58 | return o.path.indexOf(filter.path) > -1
59 | });
60 | }
61 |
62 | if (filter.title) {
63 | resultList = _.filter(resultList, (o) => {
64 | return o.title.indexOf(filter.title) > -1
65 | });
66 | }
67 |
68 | if (filter.component) {
69 | resultList = _.filter(resultList, (o) => {
70 | return o.component.indexOf(filter.component) > -1
71 | });
72 | }
73 |
74 | if (filter.componentPath) {
75 | resultList = _.filter(resultList, (o) => {
76 | return o.componentPath.indexOf(filter.componentPath) > -1
77 | });
78 | }
79 |
80 | if (filter.cache) {
81 | resultList = _.filter(resultList, (o) => {
82 | return o.cache.indexOf(filter.cache) > -1
83 | });
84 | }
85 |
86 | if (filter.isLock) {
87 | resultList = _.filter(resultList, (o) => {
88 | return o.isLock.indexOf(filter.isLock) > -1
89 | });
90 | }
91 |
92 | if (filter.sort) {
93 | resultList = _.filter(resultList, (o) => {
94 | return o.sort.indexOf(filter.sort) > -1
95 | });
96 | }
97 |
98 | let totalCount = resultList.length
99 | if (sortBy) {
100 | resultList = _.sortBy(resultList, [sortBy])
101 | if (descending === 'true') {
102 | resultList = resultList.reverse()
103 | }
104 | }
105 | if (!pageIndex || pageIndex <= 0) {
106 | pageIndex = 1
107 | }
108 | if (pageSize) {
109 | let start = (pageIndex - 1) * pageSize
110 | let end = pageIndex * pageSize
111 | resultList = _.slice(resultList, start, end)
112 | }
113 |
114 | return {
115 | totalCount: totalCount,
116 | rows: resultList
117 | }
118 |
119 | },
120 | delRoute: async (id) => {
121 | let db = await model.init(context)
122 | let child = db.find({ parentId: id }).value()
123 | if (child) {
124 | return {
125 | success: false,
126 | msg: "请先删除子路由"
127 | }
128 | }
129 | await db.remove({ id: id }).write()
130 | return {
131 | success: true,
132 | msg: ""
133 | }
134 | },
135 | saveRoute: async (route) => {
136 | let db = await model.init(context)
137 | let exist = db.find({ name: route.name }).value()
138 | if (exist && exist.id != route.id) {
139 | return {
140 | success: false,
141 | msg: "name已经存在"
142 | }
143 | }
144 | if (route.id) {
145 | await db.find({ id: route.id })
146 | .assign(route)
147 | .write()
148 | } else {
149 | await db.insert(route).write()
150 | }
151 | return {
152 | success: true,
153 | msg: ""
154 | }
155 | },
156 | getAccessRouteList: async (userId) => {
157 | let db = await model.init(context)
158 | let routeList = JSON.parse(JSON.stringify(db.value()))
159 | routeList = _.sortBy(routeList, ["sort"])
160 | let parentRouteList = routeList.filter((item) => {
161 | return item.parentId == 0 && !item.isLock
162 | })
163 | let isAdmin = await userService.isAdmin(userId)
164 | let userPermission = await userService.getUserPermission(userId)
165 | if (isAdmin) {
166 | for (let route of parentRouteList) {
167 | buildRoute(route, routeList)
168 | }
169 | } else {
170 | for (let route of parentRouteList) {
171 | buildAccessRoute(route, routeList, userPermission)
172 | }
173 | }
174 | checkAccssRoute(parentRouteList, routeList)
175 | return parentRouteList
176 | },
177 | }
178 | let buildRoute = (parentRoute, routeList) => {
179 | parentRoute.children = []
180 | let children = routeList.filter((item) => {
181 | return item.parentId == parentRoute.id
182 | })
183 | for (let route of children) {
184 | buildRoute(route, routeList)
185 | }
186 | parentRoute.children.push(...children)
187 | }
188 | let buildAccessRoute = (parentRoute, routeList, userPermission) => {
189 | parentRoute.children = []
190 | let children = routeList.filter((item) => {
191 | return item.parentId == parentRoute.id && (!item.permission || userPermission.indexOf(item.permission) > -1)
192 | })
193 | //父级没有权限访问,子级也不能访问
194 | for (let route of children) {
195 | buildAccessRoute(route, routeList, userPermission)
196 | }
197 | parentRoute.children.push(...children)
198 | }
199 | let checkAccssRoute = (accessRouteList, routeList) => {
200 | for (let item of accessRouteList) {
201 | if (item.children) {
202 | checkAccssRoute(item.children, routeList)
203 | }
204 | }
205 | _.remove(accessRouteList, (item) => {
206 | return item.children.length == 0 && routeList.some(s => {
207 | return s.parentId == item.id
208 | })
209 | });
210 | }
--------------------------------------------------------------------------------
/src/services/systemService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 |
3 | module.exports = {
4 | resetDb:async()=>{
5 | await model.read()
6 | }
7 | }
--------------------------------------------------------------------------------
/src/services/tokenService.js:
--------------------------------------------------------------------------------
1 | import model from '../models/baseModel'
2 | import { exists } from 'fs';
3 | const context = 'token'
4 | module.exports = {
5 | add: async (token) => {
6 | let db = await model.init(context)
7 | await db.push({ value: token }).write()
8 | },
9 | exist: async (token) => {
10 | let db = await model.init(context)
11 | let exist = db.find({ value: token })
12 | .value()
13 | if (exist) {
14 | return true
15 | } else {
16 | return false
17 | }
18 | },
19 | remove: async (token) => {
20 | let db = await model.init(context)
21 | await db.remove({ value: token })
22 | .write()
23 | }
24 | }
--------------------------------------------------------------------------------
/src/services/userService.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash'
2 | import model from '../models/baseModel'
3 | import roleService from './roleService'
4 | const context = 'user'
5 | const adminContext = 'admin'
6 | const roleUserContext = 'roleUser'
7 | const menuContext = 'menu'
8 | module.exports = {
9 | getUserByNameAndPwd: async (name, pwd) => {
10 | let db = await model.init(context)
11 | let user = db.find({ name: name, password: pwd }).value()
12 | return user
13 | },
14 | getUserById: async (id) => {
15 | let db = await model.init(context)
16 | let user = db.find({ id: id }).value()
17 | return user
18 | },
19 | getUserList: async () => {
20 | let db = await model.init(context)
21 | let list = db.value()
22 | return list
23 | },
24 | getUserPagedList: async (pageIndex, pageSize, sortBy, descending, filter) => {
25 | let db = await model.init(context)
26 | let roleList = db.value()
27 | let resultList = JSON.parse(JSON.stringify(roleList))
28 | if (filter.name) {
29 | resultList = _.filter(resultList, (o) => {
30 | return o.name.indexOf(filter.name) > -1 || o.trueName.indexOf(filter.name) > -1
31 | });
32 | }
33 | if (filter.email) {
34 | resultList = _.filter(resultList, (o) => {
35 | return o.email.indexOf(filter.email) > -1
36 | });
37 | }
38 | if (filter.roleId) {
39 | let roleUserDb = await model.init(roleUserContext)
40 | let roleUserList = roleUserDb.filter({ roleId: filter.roleId }).value()
41 | roleUserList = roleUserList.map(s => {
42 | return s.userId
43 | })
44 | resultList = _.map(resultList, (item) => {
45 | if (roleUserList.indexOf(item.id) > -1) {
46 | item.isAdd = 1
47 | } else {
48 | item.isAdd = 2
49 | }
50 | return item
51 | })
52 | sortBy = "isAdd"
53 | }
54 | let totalCount = resultList.length
55 | if (sortBy) {
56 | resultList = _.sortBy(resultList, [sortBy])
57 | if (descending === 'true') {
58 | resultList = resultList.reverse()
59 | }
60 | }
61 | let start = (pageIndex - 1) * pageSize
62 | let end = pageIndex * pageSize
63 | resultList = _.slice(resultList, start, end)
64 |
65 | return {
66 | totalCount: totalCount,
67 | rows: resultList
68 | }
69 |
70 | },
71 | delUser: async (id) => {
72 | let db = await model.init(context)
73 | let adminDb = await model.init(adminContext)
74 | let admin = adminDb.value()
75 | if (admin.indexOf(id) > -1) {
76 | return {
77 | success: false,
78 | msg: "不能删除管理员账号"
79 | }
80 | }
81 | await db.remove({ id: id }).write()
82 | return {
83 | success: true,
84 | msg: ""
85 | }
86 | },
87 | saveUser: async (user) => {
88 | let db = await model.init(context)
89 | let exist = db.find({ name: user.name }).value()
90 | if (exist && exist.id != user.id) {
91 | return {
92 | success: false,
93 | msg: "账号名称已经存在"
94 | }
95 | }
96 | let exist1 = db.find({ email: user.email }).value()
97 | if (exist1 && exist1.id != user.id) {
98 | return {
99 | success: false,
100 | msg: "用户邮箱已经存在"
101 | }
102 | }
103 | if (user.id) {
104 | await db.find({ id: user.id })
105 | .assign(user)
106 | .write()
107 | } else {
108 | user.password = "123456"
109 | await db.insert(user).write()
110 | }
111 | return {
112 | success: true,
113 | msg: ""
114 | }
115 | },
116 | changePassWord: async (user) => {
117 |
118 | },
119 | editRoleUser: async (roleUser) => {
120 | let roleUserDb = await model.init(roleUserContext)
121 | if (roleUser.action == 1) {
122 | await roleUserDb.push({ userId: roleUser.userId, roleId: roleUser.roleId }).write()
123 | } else {
124 | await roleUserDb.remove({ userId: roleUser.userId, roleId: roleUser.roleId }).write()
125 | }
126 | },
127 | getUserRole: async (userId) => {
128 | let roleUserDb = await model.init(roleUserContext)
129 | let roleUserList = roleUserDb.filter({ userId: userId }).value()
130 | let roleIdList = roleUserList.map(s => {
131 | return s.roleId
132 | })
133 | let roleList = await roleService.getRoleListByIdList(roleIdList)
134 | let roleCodeList = roleList.map(s => {
135 | return s.code
136 | })
137 | return roleCodeList
138 | },
139 | getUserPermission: async (userId) => {
140 | let roleUserDb = await model.init(roleUserContext)
141 | let roleUserList = roleUserDb.filter({ userId: userId }).value()
142 | let roleIdList = roleUserList.map(s => {
143 | return s.roleId
144 | })
145 | let roleFunctions = await roleService.getRoleFuntionsByRoleIds(roleIdList)
146 | let functionIds = roleFunctions.map(s => {
147 | return s.functionId
148 | })
149 | let menudb = await model.init(menuContext)
150 | let menuList = menudb.value()
151 | menuList = menuList.filter(s => {
152 | return functionIds.indexOf(s.id) > -1
153 | })
154 | let functionCodeList = menuList.map(s => {
155 | return s.permission
156 | })
157 | functionCodeList = functionCodeList.filter(s => s)
158 | return functionCodeList
159 | },
160 | getUserFunctions: async (userId) => {
161 | let roleUserDb = await model.init(roleUserContext)
162 | let roleUserList = roleUserDb.filter({ userId: userId }).value()
163 | let roleIdList = roleUserList.map(s => {
164 | return s.roleId
165 | })
166 | let roleFunctions = await roleService.getRoleFuntionsByRoleIds(roleIdList)
167 | let functionIds = roleFunctions.map(s => {
168 | return s.functionId
169 | })
170 | let menudb = await model.init(menuContext)
171 | let menuList = menudb.value()
172 | let functionList = menuList.filter(s => {
173 | return functionIds.indexOf(s.id) > -1
174 | })
175 | return functionList;
176 | },
177 | isAdmin: async (userId) => {
178 | let adminDb = await model.init(adminContext)
179 | let admin = adminDb.value()
180 | if (admin.indexOf(userId) > -1) {
181 | return true
182 | }
183 | return false
184 | }
185 | }
--------------------------------------------------------------------------------
/src/tool/Common.js:
--------------------------------------------------------------------------------
1 | import {
2 | SystemConfig
3 | } from '../config'
4 |
5 | // 截取字符串,多余的部分用...代替
6 | export let setString = (str, len) => {
7 | let StrLen = 0
8 | let s = ''
9 | for (let i = 0; i < str.length; i++) {
10 | if (str.charCodeAt(i) > 128) {
11 | StrLen += 2
12 | } else {
13 | StrLen++
14 | }
15 | s += str.charAt(i)
16 | if (StrLen >= len) {
17 | return s + '...'
18 | }
19 | }
20 | return s
21 | }
22 |
23 | // 格式化设置
24 | export let OptionFormat = (GetOptions) => {
25 | let options = '{'
26 | for (let n = 0; n < GetOptions.length; n++) {
27 | options = options + '\'' + GetOptions[n].option_name + '\':\'' + GetOptions[n].option_value + '\''
28 | if (n < GetOptions.length - 1) {
29 | options = options + ','
30 | }
31 | }
32 | return JSON.parse(options + '}')
33 | }
34 |
35 | // 替换SQL字符串中的前缀
36 | export let SqlFormat = (str) => {
37 | if (SystemConfig.mysql_prefix !== 'api_') {
38 | str = str.replace(/api_/g, SystemConfig.mysql_prefix)
39 | }
40 | return str
41 | }
42 |
43 | // 数组去重
44 | export let HovercUnique = (arr) => {
45 | let n = {}
46 | let r = []
47 | for (var i = 0; i < arr.length; i++) {
48 | if (!n[arr[i]]) {
49 | n[arr[i]] = true
50 | r.push(arr[i])
51 | }
52 | }
53 | return r
54 | }
55 |
56 | // 获取json长度
57 | export let getJsonLength = (jsonData) => {
58 | var arr = []
59 | for (var item in jsonData) {
60 | arr.push(jsonData[item])
61 | }
62 | return arr.length
63 | }
64 |
--------------------------------------------------------------------------------
/templates/config/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | //server
3 | RouteRelativePath: '/src/routes/',
4 | ControllerRelativePath: '/src/controllers/',
5 | ServiceRelativePath: '/src/services/',
6 | ModelRelativePath: '/src/models/',
7 | DBRelativePath: '/src/db/'
8 | }
--------------------------------------------------------------------------------
/templates/config/index.js:
--------------------------------------------------------------------------------
1 | import model from './model';
2 | import config from './config';
3 | export default {
4 | model,
5 | config
6 | }
--------------------------------------------------------------------------------
/templates/config/model.js:
--------------------------------------------------------------------------------
1 |
2 | var shortid = require('shortid')
3 | var Mock = require('mockjs')
4 | var Random = Mock.Random
5 |
6 | //必须包含字段id
7 | export default {
8 | name: "book",
9 | Name: "Book",
10 | properties: [
11 | {
12 | key: "id",
13 | title: "id"
14 | },
15 | {
16 | key: "name",
17 | title: "书名"
18 | },
19 | {
20 | key: "author",
21 | title: "作者"
22 | },
23 | {
24 | key: "press",
25 | title: "出版社"
26 | }
27 | ],
28 | buildMockData: function () {//不需要生成设为false
29 | let data = []
30 | for (let i = 0; i < 100; i++) {
31 | data.push({
32 | id: shortid.generate(),
33 | name: Random.cword(5, 7),
34 | author: Random.cname(),
35 | press: Random.cword(5, 7)
36 | })
37 | }
38 | return data
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/templates/generate.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs-extra')
2 | const CodeGenerateConfig = require('./config').default
3 | const Model = CodeGenerateConfig.model
4 |
5 | module.exports = {
6 | run: function(gulp, nunjucksRender, rename, nunjucksRenderConfig) {
7 | nunjucksRenderConfig.data = {
8 | model: CodeGenerateConfig.model,
9 | config: CodeGenerateConfig.config
10 | }
11 | const ServerProjectRootPath = nunjucksRenderConfig.ServerFullPath
12 | //server
13 | const serverTemplatePath = 'templates/server/'
14 | gulp.src(`${serverTemplatePath}controller.njk`)
15 | .pipe(nunjucksRender(nunjucksRenderConfig))
16 | .pipe(rename(Model.name + '.js'))
17 | .pipe(
18 | gulp.dest(
19 | ServerProjectRootPath +
20 | CodeGenerateConfig.config.ControllerRelativePath
21 | )
22 | )
23 |
24 | gulp.src(`${serverTemplatePath}service.njk`)
25 | .pipe(nunjucksRender(nunjucksRenderConfig))
26 | .pipe(rename(Model.name + 'Service.js'))
27 | .pipe(
28 | gulp.dest(
29 | ServerProjectRootPath +
30 | CodeGenerateConfig.config.ServiceRelativePath
31 | )
32 | )
33 |
34 | gulp.src(`${serverTemplatePath}model.njk`)
35 | .pipe(nunjucksRender(nunjucksRenderConfig))
36 | .pipe(rename(Model.name + 'Model.js'))
37 | .pipe(
38 | gulp.dest(
39 | ServerProjectRootPath +
40 | CodeGenerateConfig.config.ModelRelativePath
41 | )
42 | )
43 |
44 | gulp.src(`${serverTemplatePath}db.njk`)
45 | .pipe(nunjucksRender(nunjucksRenderConfig))
46 | .pipe(rename(Model.name + '_db.json'))
47 | .pipe(
48 | gulp.dest(
49 | ServerProjectRootPath +
50 | CodeGenerateConfig.config.DBRelativePath
51 | )
52 | )
53 |
54 | return gulp
55 | .src(`${serverTemplatePath}route.njk`)
56 | .pipe(nunjucksRender(nunjucksRenderConfig))
57 | .pipe(rename(Model.name + 'Route.js'))
58 | .pipe(
59 | gulp.dest(
60 | ServerProjectRootPath +
61 | CodeGenerateConfig.config.RouteRelativePath
62 | )
63 | )
64 | },
65 | quickAdd: async function(options, nunjucksRenderConfig) {
66 | const ServerProjectRootPath = nunjucksRenderConfig.ServerFullPath
67 | const serverTemplatePath = 'templates/server/quickAdd/'
68 | const existFileFullPath =
69 | ServerProjectRootPath +
70 | CodeGenerateConfig.config.ControllerRelativePath +
71 | options[0] +
72 | '.js'
73 | let controllerTemplate = await fs.readFile(
74 | `${ServerProjectRootPath}/${serverTemplatePath}controller.njk`,
75 | 'utf-8'
76 | )
77 | let routeTemplate = await fs.readFile(
78 | `${ServerProjectRootPath}/${serverTemplatePath}route.njk`,
79 | 'utf-8'
80 | )
81 | if (await fs.exists(existFileFullPath)) {
82 | console.log('exist entity')
83 |
84 | await fs.appendFile(
85 | ServerProjectRootPath +
86 | CodeGenerateConfig.config.ControllerRelativePath +
87 | options[0] +
88 | '.js',
89 | controllerTemplate.replace(/<\$ name \$>/g, options[2])
90 | )
91 | let routeContent = await fs.readFile(
92 | ServerProjectRootPath +
93 | CodeGenerateConfig.config.RouteRelativePath +
94 | options[0] +
95 | 'Route.js',
96 | 'utf-8'
97 | )
98 | let routeContentLines = routeContent.split('\n')
99 | routeContentLines.splice(
100 | -2,
101 | 0,
102 | ` .get('${options[1]}', controllers.${options[0]}.${
103 | options[2]
104 | })\r`
105 | )
106 | await fs.writeFile(
107 | ServerProjectRootPath +
108 | CodeGenerateConfig.config.RouteRelativePath +
109 | options[0] +
110 | 'Route.js',
111 | routeContentLines.join('\n')
112 | )
113 | } else {
114 | await fs.writeFile(
115 | ServerProjectRootPath +
116 | CodeGenerateConfig.config.ControllerRelativePath +
117 | options[0] +
118 | '.js',
119 | controllerTemplate.replace(/<\$ name \$>/g, options[2])
120 | )
121 |
122 | await fs.writeFile(
123 | ServerProjectRootPath +
124 | CodeGenerateConfig.config.RouteRelativePath +
125 | options[0] +
126 | 'Route.js',
127 | routeTemplate
128 | .replace(/<\$ api \$>/g, options[1])
129 | .replace(/<\$ entity \$>/g, options[0])
130 | .replace(/<\$ method \$>/g, options[2])
131 | )
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/templates/server/controller.njk:
--------------------------------------------------------------------------------
1 | import <$ model.name $>Service from '../services/<$ model.name $>Service'
2 | import * as responseTemplate from '../lib/responseTemplate'
3 |
4 | export let get<$ model.Name $> = async (ctx) => {
5 | let id = ctx.params.id
6 | let <$ model.name $> = await <$ model.name $>Service.get<$ model.Name $>(id)
7 | if (!<$ model.name $>) {
8 | return responseTemplate.businessError(ctx, "<$ model.name $>不存在!")
9 | }
10 | return responseTemplate.success(ctx, <$ model.name $>)
11 | }
12 | export let get<$ model.Name $>PagedList = async (ctx, next) => {
13 | let pageIndex = ctx.query.pageIndex
14 | let pageSize = ctx.query.pageSize
15 | let sortBy = ctx.query.sortBy
16 | let descending = ctx.query.descending
17 | let filter = {
18 | <% for property in model.properties -%>
19 | <$ property.key $>: ctx.query.<$ property.key -$>,
20 | <% endfor %>
21 | }
22 | let pagedList = await <$ model.name $>Service.get<$ model.Name $>PagedList(pageIndex, pageSize, sortBy, descending, filter)
23 | return responseTemplate.success(ctx, pagedList)
24 | }
25 | export let del<$ model.Name $> = async (ctx) => {
26 | let id = ctx.query.id
27 | await <$ model.name $>Service.del<$ model.Name $>(id)
28 | return responseTemplate.success(ctx, null)
29 | }
30 |
31 | export let del<$ model.Name $>s = async (ctx) => {
32 | let ids = JSON.parse(ctx.query.ids)
33 | for (let id of ids) {
34 | await <$ model.name $>Service.del<$ model.Name $>(id)
35 | }
36 | return responseTemplate.success(ctx, null)
37 | }
38 |
39 | export let save<$ model.Name $> = async (ctx) => {
40 | let entity = ctx.request.body
41 | <% for property in model.properties -%>
42 | <% if property.key!='id' -%>
43 | if (entity.<$ property.key $> == "") {
44 | return responseTemplate.businessError(ctx, "<$ property.title $>不能为空!")
45 | }
46 | <% endif -%>
47 | <% endfor -%>
48 | let result = await <$ model.name $>Service.save<$ model.Name $>(entity)
49 | if (!result.success) {
50 | return responseTemplate.businessError(ctx, result.msg)
51 | }
52 | return responseTemplate.success(ctx, null)
53 | }
54 |
--------------------------------------------------------------------------------
/templates/server/db.njk:
--------------------------------------------------------------------------------
1 | {
2 | "<$ model.name $>":<% if model.buildMockData %><$ model.buildMockData()|dump|safe $><% else %>[]<% endif %>
3 | }
--------------------------------------------------------------------------------
/templates/server/model.njk:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | const low = require('lowdb')
4 | const lodashId = require('lodash-id')
5 | const FileAsync = require('lowdb/adapters/FileAsync')
6 | const dbFile = path.join(__dirname, '../db/<$ model.name $>_db.json')
7 | const adapter = new FileAsync(dbFile)
8 | let instance = undefined
9 | module.exports = {
10 | init: function (context) {
11 | return new Promise((resolve, reject) => {
12 | if (instance === undefined) {
13 | low(adapter).then(db => {
14 | db._.mixin(lodashId)
15 | instance = db;
16 | resolve(db.get(context))
17 | })
18 | } else {
19 | resolve(instance.get(context))
20 | }
21 | })
22 | },
23 | read: () => {
24 | return new Promise((resolve, reject) => {
25 | if (instance === undefined) {
26 | resolve()
27 | }
28 | else {
29 | instance.read().then(() => {
30 | resolve()
31 | })
32 | }
33 | })
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/templates/server/quickAdd/controller.njk:
--------------------------------------------------------------------------------
1 | export let <$ name $> = async ctx => {
2 | ctx.body = {
3 | code: 200,
4 | msg: '',
5 | result: null
6 | }
7 | }
--------------------------------------------------------------------------------
/templates/server/quickAdd/route.njk:
--------------------------------------------------------------------------------
1 | import KoaRouter from 'koa-router'
2 | import controllers from '../controllers/index.js'
3 | import proxy from '../middleware/Proxy'
4 |
5 | const router = new KoaRouter()
6 | router
7 | .get('<$ api $>', controllers.<$ entity $>.<$ method $>)
8 | module.exports = router
--------------------------------------------------------------------------------
/templates/server/route.njk:
--------------------------------------------------------------------------------
1 | import KoaRouter from 'koa-router'
2 | import controllers from '../controllers/index.js'
3 | import PermissionCheck from '../middleware/PermissionCheck'
4 |
5 | const router = new KoaRouter()
6 | router
7 | .get('/<$ model.name $>/paged', controllers.<$model.name $>.get<$ model.Name $>PagedList)
8 | .get('/<$ model.name $>/:id', controllers.<$ model.name $>.get<$ model.Name $>)
9 | .del('/<$ model.name $>/del', controllers.<$ model.name $>.del<$ model.Name $>)
10 | .del('/<$ model.name $>/batchdel', controllers.<$ model.name $>.del<$ model.Name $>s)
11 | .post('/<$ model.name $>/save', controllers.<$ model.name $>.save<$ model.Name $>)
12 |
13 | module.exports = router
--------------------------------------------------------------------------------
/templates/server/service.njk:
--------------------------------------------------------------------------------
1 | import model from '../models/<$ model.name $>Model'
2 | import _ from 'lodash'
3 | const context = '<$ model.name $>'
4 | module.exports = {
5 | get<$ model.Name $>: async (id) => {
6 | let db = await model.init(context)
7 | let <$ model.name $> = db.find({ id: id }).value()
8 | return <$ model.name $>
9 | },
10 | get<$ model.Name $>PagedList: async (pageIndex, pageSize, sortBy, descending, filter) => {
11 | let db = await model.init(context)
12 | let <$ model.name $>List = db.value()
13 | let resultList = <$ model.name $>List
14 | <% for property in model.properties -%>
15 | if (filter.<$ property.key $>) {
16 | resultList = _.filter(resultList, (o) => {
17 | return o.<$ property.key $>.indexOf(filter.<$ property.key $>) > -1
18 | });
19 | }
20 | <% endfor %>
21 | let totalCount = resultList.length
22 | if (sortBy) {
23 | resultList = _.sortBy(resultList, [sortBy])
24 | if (descending === 'true') {
25 | resultList = resultList.reverse()
26 | }
27 | }
28 | if(!pageIndex||pageIndex<=0){
29 | pageIndex=1
30 | }
31 | if(pageSize){
32 | let start = (pageIndex - 1) * pageSize
33 | let end = pageIndex * pageSize
34 | resultList = _.slice(resultList, start, end)
35 | }
36 |
37 | return {
38 | totalCount: totalCount,
39 | rows: resultList
40 | }
41 |
42 | },
43 | del<$ model.Name $>: async (id) => {
44 | let db = await model.init(context)
45 | await db.remove({ id: id }).write()
46 | },
47 | save<$ model.Name $>: async (<$ model.name $>) => {
48 | let db = await model.init(context)
49 | if (<$ model.name $>.id) {
50 | await db.find({ id: <$ model.name $>.id })
51 | .assign(<$ model.name $>)
52 | .write()
53 | } else {
54 | await db.insert(<$ model.name $>).write()
55 | }
56 | return {
57 | success: true,
58 | msg: ""
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------