@codertqy/elpis 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -0
- package/.eslintrc +55 -0
- package/README.md +218 -0
- package/app/controller/base.js +40 -0
- package/app/controller/project.js +81 -0
- package/app/controller/view.js +22 -0
- package/app/extend/logger.js +43 -0
- package/app/middleware/api-params-verify.js +73 -0
- package/app/middleware/api-sign-verify.js +49 -0
- package/app/middleware/error-handler.js +31 -0
- package/app/middleware/project-handler.js +26 -0
- package/app/middleware.js +44 -0
- package/app/pages/assets/custom.css +14 -0
- package/app/pages/boot.js +56 -0
- package/app/pages/common/curl.js +84 -0
- package/app/pages/common/index.css +3 -0
- package/app/pages/common/utils.js +1 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +126 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +45 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +35 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +120 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +87 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +100 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +122 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +161 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +95 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +135 -0
- package/app/pages/dashboard/dashboard.vue +86 -0
- package/app/pages/dashboard/entry.dashboard.js +48 -0
- package/app/pages/store/index.js +3 -0
- package/app/pages/store/menu.js +68 -0
- package/app/pages/store/project.js +12 -0
- package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
- package/app/pages/widgets/header-container/asserts/logo.png +0 -0
- package/app/pages/widgets/header-container/header-container.vue +107 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +138 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +140 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +122 -0
- package/app/pages/widgets/schema-form/form-item-config.js +20 -0
- package/app/pages/widgets/schema-form/schema-form.vue +135 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +51 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +63 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +41 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +126 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +22 -0
- package/app/pages/widgets/schema-table/schema-table.vue +259 -0
- package/app/pages/widgets/sider-container/sider-container.vue +27 -0
- package/app/public/output/entry.page1.tpl +40 -0
- package/app/public/output/entry.page2.tpl +11 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +22 -0
- package/app/router/view.js +17 -0
- package/app/router-schema/project.js +34 -0
- package/app/service/base.js +15 -0
- package/app/service/project.js +59 -0
- package/app/view/entry.tpl +25 -0
- package/app/webpack/config/webpack.base.js +280 -0
- package/app/webpack/config/webpack.dev.js +57 -0
- package/app/webpack/config/webpack.prod.js +127 -0
- package/app/webpack/dev.js +63 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +22 -0
- package/config/config.beta.js +1 -0
- package/config/config.default.js +3 -0
- package/config/config.prod.js +1 -0
- package/elpis-core/env.js +27 -0
- package/elpis-core/index.js +98 -0
- package/elpis-core/loader/config.js +58 -0
- package/elpis-core/loader/controller.js +93 -0
- package/elpis-core/loader/extend.js +63 -0
- package/elpis-core/loader/middleware.js +84 -0
- package/elpis-core/loader/router-schema.js +56 -0
- package/elpis-core/loader/router.js +50 -0
- package/elpis-core/loader/service.js +85 -0
- package/index.js +38 -0
- package/model/index.js +129 -0
- package/package.json +92 -0
- package/test/controller/project.test.js +214 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const Koa = require("koa");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { sep } = path; // 兼容不同操作系统上的斜杠
|
|
4
|
+
|
|
5
|
+
const env = require("./env");
|
|
6
|
+
|
|
7
|
+
const middlewareLoader = require("./loader/middleware");
|
|
8
|
+
const routerSchemaLoader = require("./loader/router-schema");
|
|
9
|
+
const routerLoader = require("./loader/router");
|
|
10
|
+
const controllerLoader = require("./loader/controller");
|
|
11
|
+
const configLoader = require("./loader/config");
|
|
12
|
+
const extendLoader = require("./loader/extend");
|
|
13
|
+
const serviceLoader = require("./loader/service");
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
/**
|
|
17
|
+
* 启动项目
|
|
18
|
+
* @param {} options 项目配置
|
|
19
|
+
* options = {
|
|
20
|
+
* name // 项目名称
|
|
21
|
+
* homePath // 项目首页
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
start(options = {}) {
|
|
25
|
+
const app = new Koa();
|
|
26
|
+
// 将配置挂载到app实例上
|
|
27
|
+
app.options = options;
|
|
28
|
+
|
|
29
|
+
// 基础路径
|
|
30
|
+
app.baseDir = process.cwd();
|
|
31
|
+
|
|
32
|
+
// 业务路径
|
|
33
|
+
app.businessPath = path.resolve(app.baseDir, `.${sep}app`);
|
|
34
|
+
|
|
35
|
+
// 初始化环境配置
|
|
36
|
+
app.env = env();
|
|
37
|
+
console.log(`----[start] env: ${app.env.get()} ----`);
|
|
38
|
+
|
|
39
|
+
// 加载middleware中间件
|
|
40
|
+
middlewareLoader(app);
|
|
41
|
+
console.log(`----[start] middleware done ----`);
|
|
42
|
+
|
|
43
|
+
// 加载routerSchema路由配置
|
|
44
|
+
routerSchemaLoader(app);
|
|
45
|
+
console.log(`----[start] router-schema done ----`);
|
|
46
|
+
|
|
47
|
+
// 加载controller控制器
|
|
48
|
+
controllerLoader(app);
|
|
49
|
+
console.log(`----[start] controller done ----`);
|
|
50
|
+
|
|
51
|
+
// 加载service服务
|
|
52
|
+
serviceLoader(app);
|
|
53
|
+
console.log(`----[start] service done ----`);
|
|
54
|
+
|
|
55
|
+
// 加载config配置
|
|
56
|
+
configLoader(app);
|
|
57
|
+
console.log(`----[start] config done ----`);
|
|
58
|
+
|
|
59
|
+
// 加载extend扩展
|
|
60
|
+
extendLoader(app);
|
|
61
|
+
console.log(`----[start] extend done ----`);
|
|
62
|
+
|
|
63
|
+
// 注册 elpis全局中间件
|
|
64
|
+
const elpisMiddlewarePath = path.resolve(
|
|
65
|
+
__dirname,
|
|
66
|
+
`..${sep}app${sep}middleware.js`,
|
|
67
|
+
);
|
|
68
|
+
const elpisMiddleware = require(elpisMiddlewarePath);
|
|
69
|
+
elpisMiddleware(app);
|
|
70
|
+
console.log(`----[start] load gloabl elpis middelware done ----`);
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
// 注册 业务全局中间件 也就是通过app/middleware.js文件进行注册
|
|
74
|
+
try {
|
|
75
|
+
require(`${app.businessPath}${sep}middleware.js`)(app);
|
|
76
|
+
console.log(`----[start] load gloabl business middelware done ----`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.log("[exception] there is no gloabl business middleware file");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 加载router路由 要经过前面所有的
|
|
82
|
+
routerLoader(app);
|
|
83
|
+
console.log(`----[start] router done ----`);
|
|
84
|
+
|
|
85
|
+
// 启动服务
|
|
86
|
+
try {
|
|
87
|
+
const port = process.env.PORT || 8080;
|
|
88
|
+
const host = process.env.IP || "0.0.0.0";
|
|
89
|
+
app.listen(port, host);
|
|
90
|
+
console.log(`Server runing on port: ${port}`);
|
|
91
|
+
} catch (e) {
|
|
92
|
+
console.log(e);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 暴露出去交给测试使用
|
|
96
|
+
return app;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
/**
|
|
4
|
+
* config loader
|
|
5
|
+
* @param {object} app Koa实例
|
|
6
|
+
*
|
|
7
|
+
* 配置加载器 区分 本地/测试/生产 ,通过env环境读取不同文件配置 env.config
|
|
8
|
+
* 通过 env.config 覆盖 default.config 加载到 app.config 中
|
|
9
|
+
*
|
|
10
|
+
* 目录下对应的 config 配置
|
|
11
|
+
* 默认配置 config/config.default.js
|
|
12
|
+
* 本地配置 config/config.local.js
|
|
13
|
+
* 测试配置 config/config.beta.js
|
|
14
|
+
* 生产配置 config/config.prod.js
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
// elpis config 目录及相关文件
|
|
20
|
+
const elpisConfigPath = path.resolve(
|
|
21
|
+
__dirname,
|
|
22
|
+
`..${sep}..${sep}config`,
|
|
23
|
+
);
|
|
24
|
+
let defaultConfig = require(
|
|
25
|
+
path.resolve(elpisConfigPath, `.${sep}config.default.js`),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// 业务 config 目录及相关文件
|
|
29
|
+
const busnissConfigPath = path.resolve(process.cwd(), `.${sep}config`);
|
|
30
|
+
try {
|
|
31
|
+
defaultConfig = {
|
|
32
|
+
...defaultConfig,
|
|
33
|
+
...require(path.resolve(busnissConfigPath, `.${sep}config.default.js`)),
|
|
34
|
+
};
|
|
35
|
+
} catch (e) {
|
|
36
|
+
console.log("[exception] there is not config.default file");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 3. 获取 env.config
|
|
40
|
+
let envConfig = {};
|
|
41
|
+
try {
|
|
42
|
+
if (app.env.isLocal()) {
|
|
43
|
+
//本地环境
|
|
44
|
+
envConfig = require(path.resolve(busnissConfigPath, `.${sep}config.local.js`));
|
|
45
|
+
} else if (app.env.isBeta()) {
|
|
46
|
+
//测试环境
|
|
47
|
+
envConfig = require(path.resolve(busnissConfigPath, `.${sep}config.beta.js`));
|
|
48
|
+
} else if (app.env.isProd()) {
|
|
49
|
+
//生产环境
|
|
50
|
+
envConfig = require(path.resolve(busnissConfigPath, `.${sep}config.prod.js`));
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.log("[exception] there is not config.env file or logical errors");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 4. 覆盖并加载 config 配置
|
|
57
|
+
app.config = Object.assign({}, defaultConfig, envConfig);
|
|
58
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
/**
|
|
5
|
+
* controller loader
|
|
6
|
+
* @param {object} app Koa实例
|
|
7
|
+
*
|
|
8
|
+
* 加载所有controller , 可通过'app.controller.${目录}.${文件}' 访问
|
|
9
|
+
* 例子
|
|
10
|
+
* app/controller
|
|
11
|
+
* |
|
|
12
|
+
* |-- custom-module
|
|
13
|
+
* |
|
|
14
|
+
* |-- custom-controller.js
|
|
15
|
+
* ====> app.controller.customModule.customController
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
const controller = {};
|
|
20
|
+
|
|
21
|
+
// 读取 elpis/app/controller/**/**.js所有文件
|
|
22
|
+
const elpisControllerPath = path.resolve(
|
|
23
|
+
__dirname,
|
|
24
|
+
`..${sep}..${sep}app${sep}controller`,
|
|
25
|
+
);
|
|
26
|
+
// 遍历所有js文件
|
|
27
|
+
const elpisFileList = glob.sync(
|
|
28
|
+
path.resolve(elpisControllerPath, `.${sep}**${sep}**.js`),
|
|
29
|
+
);
|
|
30
|
+
elpisFileList.forEach((file) => {
|
|
31
|
+
handleFile(file);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 读取 业务/app/controller/**/**.js所有文件
|
|
35
|
+
const businessControllerPath = path.resolve(
|
|
36
|
+
app.businessPath,
|
|
37
|
+
`.${sep}controller`,
|
|
38
|
+
);
|
|
39
|
+
// 遍历所有js文件
|
|
40
|
+
const businessFileList = glob.sync(
|
|
41
|
+
path.resolve(businessControllerPath, `.${sep}**${sep}**.js`),
|
|
42
|
+
);
|
|
43
|
+
businessFileList.forEach((file) => {
|
|
44
|
+
handleFile(file);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
function handleFile(file) {
|
|
48
|
+
// 提取文件名称
|
|
49
|
+
let name = path.resolve(file);
|
|
50
|
+
|
|
51
|
+
// 截取路径 app/controller/custom-module/custom-controller.js =》custom-module/custom-controller
|
|
52
|
+
name = name.substring(
|
|
53
|
+
name.lastIndexOf(`controller${sep}`) + `controller${sep}`.length,
|
|
54
|
+
name.lastIndexOf("."),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// 把 - 统一改为驼峰式
|
|
58
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.substring(1).toUpperCase());
|
|
59
|
+
|
|
60
|
+
// 根据文件夹构建嵌套对象
|
|
61
|
+
let tempController = controller;
|
|
62
|
+
|
|
63
|
+
// 分割/ 过滤空字符串
|
|
64
|
+
const names = name.split(sep).filter(Boolean);
|
|
65
|
+
for (let i = 0, len = names.length; i < len; i++) {
|
|
66
|
+
const key = names[i];
|
|
67
|
+
// 最后一层,挂载中间件函数
|
|
68
|
+
if (i === len - 1) {
|
|
69
|
+
/**
|
|
70
|
+
* 因为在koa里面middleware是一个可执行方法,可以直接执行
|
|
71
|
+
* controller是一个类,需要构造对象执行
|
|
72
|
+
*
|
|
73
|
+
* require(file)表示加载执行指定路径下的文件。app是当做参数传递给该文件函数
|
|
74
|
+
*/
|
|
75
|
+
const ControllerModule = require(file)(app);
|
|
76
|
+
tempController[key] = new ControllerModule();
|
|
77
|
+
} else {
|
|
78
|
+
// 不是最后一层,创建嵌套对象 假设 key为user tempController={user:{}} 也就是则tempController=.user
|
|
79
|
+
if (!tempController[key]) {
|
|
80
|
+
tempController[key] = {};
|
|
81
|
+
}
|
|
82
|
+
// tempcontroller就变为tempcontroller.user ={}
|
|
83
|
+
tempController = tempController[key];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 第二层:key为app 则tempController={ user: { app: { } } } 也就是tempController=.user.app
|
|
87
|
+
*/
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 遍历所有文件目录,把内容加载到 app.controller 下
|
|
91
|
+
|
|
92
|
+
app.controller = controller;
|
|
93
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
/**
|
|
5
|
+
* extend loader
|
|
6
|
+
* @param {object} app Koa实例
|
|
7
|
+
*
|
|
8
|
+
* 加载所有extend , 可通过'app.extend.${文件}' 访问 没有多级路径
|
|
9
|
+
* 例子:
|
|
10
|
+
* app/extend
|
|
11
|
+
* |
|
|
12
|
+
* |-- custom-extend.js
|
|
13
|
+
* ====> app.extend.customExtend
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
module.exports = (app) => {
|
|
17
|
+
// 1.读取 eplis/app/extend/**.js所有文件
|
|
18
|
+
const elpisExtendPath = path.resolve(
|
|
19
|
+
__dirname,
|
|
20
|
+
`..${sep}..${sep}app${sep}extend`,
|
|
21
|
+
);
|
|
22
|
+
// 2.遍历所有js文件
|
|
23
|
+
const elpisFileList = glob.sync(
|
|
24
|
+
path.resolve(elpisExtendPath, `.${sep}**${sep}**.js`),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
elpisFileList.forEach((file) => {
|
|
28
|
+
handleFile(file);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// 1.读取 业务/app/extend/**.js所有文件
|
|
32
|
+
const businessExtendPath = path.resolve(app.businessPath, `.${sep}extend`);
|
|
33
|
+
// 2.遍历所有js文件
|
|
34
|
+
const businessFileList = glob.sync(
|
|
35
|
+
path.resolve(businessExtendPath, `.${sep}**${sep}**.js`),
|
|
36
|
+
);
|
|
37
|
+
businessFileList.forEach((file) => {
|
|
38
|
+
handleFile(file);
|
|
39
|
+
});
|
|
40
|
+
function handleFile(file) {
|
|
41
|
+
// 3.1提取文件名称
|
|
42
|
+
let name = path.resolve(file);
|
|
43
|
+
|
|
44
|
+
// 3.2截取路径 app/extend/custom-extend.js =》custom-extend
|
|
45
|
+
name = name.substring(
|
|
46
|
+
name.lastIndexOf(`extend${sep}`) + `extend${sep}`.length,
|
|
47
|
+
name.lastIndexOf("."),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// 3.3 把 - 统一改为驼峰式
|
|
51
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.substring(1).toUpperCase());
|
|
52
|
+
|
|
53
|
+
// 3.4 过滤 app 已经存在的key
|
|
54
|
+
for (const key in app) {
|
|
55
|
+
if (key === name) {
|
|
56
|
+
console.log(`[extend load error] name:${name} is already in app`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 挂载extend 到 app 上
|
|
61
|
+
app[name] = require(file)(app);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
/**
|
|
5
|
+
* middleware loader
|
|
6
|
+
* @param {object} app Koa实例
|
|
7
|
+
*
|
|
8
|
+
* 加载所有middleware , 可通过'app.middleware.${目录}.${文件}' 访问
|
|
9
|
+
* 例子
|
|
10
|
+
* app/middleware
|
|
11
|
+
* |
|
|
12
|
+
* |-- custom-module
|
|
13
|
+
* |
|
|
14
|
+
* |-- custom-middleware.js
|
|
15
|
+
* ====> app.middleware.customModule.customMiddleware
|
|
16
|
+
*/
|
|
17
|
+
module.exports = (app) => {
|
|
18
|
+
const middlewares = {};
|
|
19
|
+
// 1. 读取 elpis/app/middleware/**/**.js所有文件
|
|
20
|
+
const elpisMiddlewarePath = path.resolve(
|
|
21
|
+
__dirname,
|
|
22
|
+
`..${sep}..${sep}app${sep}middleware`,
|
|
23
|
+
);
|
|
24
|
+
// 2. 遍历所有js文件
|
|
25
|
+
const elpisFileList = glob.sync(
|
|
26
|
+
path.resolve(elpisMiddlewarePath, `.${sep}**${sep}**.js`),
|
|
27
|
+
);
|
|
28
|
+
elpisFileList.forEach((file) => {
|
|
29
|
+
handleFile(file);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 读取 业务根目录/app/middleware/**/**.js所有文件
|
|
33
|
+
const businessMiddlewarePath = path.resolve(
|
|
34
|
+
app.businessPath,
|
|
35
|
+
`.${sep}middleware`,
|
|
36
|
+
);
|
|
37
|
+
const businessFileList = glob.sync(
|
|
38
|
+
path.resolve(businessMiddlewarePath, `.${sep}**${sep}**.js`),
|
|
39
|
+
);
|
|
40
|
+
businessFileList.forEach((file) => {
|
|
41
|
+
handleFile(file);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 3. 遍历所有文件目录,把内容加载到 app.middlewares 下
|
|
45
|
+
function handleFile(file) {
|
|
46
|
+
// 3.1提取文件名称
|
|
47
|
+
let name = path.resolve(file);
|
|
48
|
+
|
|
49
|
+
// 3.2截取路径 app/middleware/custom-module/custom-middleware.js =》custom-module/custom-middleware
|
|
50
|
+
name = name.substring(
|
|
51
|
+
name.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length,
|
|
52
|
+
name.lastIndexOf("."),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// 3.3把 - 统一改为驼峰式
|
|
56
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.substring(1).toUpperCase());
|
|
57
|
+
|
|
58
|
+
// 3.4根据文件夹构建嵌套对象
|
|
59
|
+
let tempMiddleware = middlewares;
|
|
60
|
+
|
|
61
|
+
// 3.5 分割/ 过滤空字符串 [customMoudle, customController]
|
|
62
|
+
const names = name.split(sep).filter(Boolean);
|
|
63
|
+
for (let i = 0, len = names.length; i < len; i++) {
|
|
64
|
+
const key = names[i];
|
|
65
|
+
// 最后一层,挂载中间件函数
|
|
66
|
+
if (i === len - 1) {
|
|
67
|
+
tempMiddleware[key] = require(file)(app);
|
|
68
|
+
} else {
|
|
69
|
+
// 不是最后一层,创建嵌套对象 假设 key为user 则tempMiddleware={user:{}} 也就是则tempMiddleware.user
|
|
70
|
+
if (!tempMiddleware[key]) {
|
|
71
|
+
tempMiddleware[key] = {};
|
|
72
|
+
}
|
|
73
|
+
// tempMiddleware就变为tempMiddleware.user ={}
|
|
74
|
+
tempMiddleware = tempMiddleware[key];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 第二层:key为app 则tempMiddleware={ user: { app: { } } } 也就是tempMiddleware.user.app
|
|
78
|
+
* 依次循环
|
|
79
|
+
*/
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// 4. 挂载 不能使用middleware因为koa内置已经有middleware
|
|
83
|
+
app.middlewares = middlewares;
|
|
84
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
/**
|
|
5
|
+
* router-schema loader
|
|
6
|
+
* @param {object} app Koa实例
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* 通过 'json-schema & ajv' 对API规则进行约束,配合api-params-verify中间件使用
|
|
10
|
+
* --- json-schema 是定义接口,接受什么参数、参数哪些是必传的,参数类型是什么,参数范围是什么
|
|
11
|
+
* --- ajv 是校验json-schema
|
|
12
|
+
*
|
|
13
|
+
* app/router-schema/**.js
|
|
14
|
+
*
|
|
15
|
+
* 输出:
|
|
16
|
+
* app.routerScheam = {
|
|
17
|
+
* `${api1}}`: ${jsonSchema},
|
|
18
|
+
* `${api2}}`: ${jsonSchema},
|
|
19
|
+
* `${api3}}`: ${jsonSchema},
|
|
20
|
+
* `${api4}}`: ${jsonSchema}
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
module.exports = (app) => {
|
|
24
|
+
let routerSchema = {};
|
|
25
|
+
// 读取 elpis/app/router-schema/**/**.js所有文件
|
|
26
|
+
const elpisRouterSchemaPath = path.resolve(
|
|
27
|
+
__dirname,
|
|
28
|
+
`..${sep}..${sep}app${sep}router-schema`,
|
|
29
|
+
);
|
|
30
|
+
const elpisFileList = glob.sync(
|
|
31
|
+
path.resolve(elpisRouterSchemaPath, `.${sep}**${sep}**.js`),
|
|
32
|
+
);
|
|
33
|
+
elpisFileList.forEach((file) => {
|
|
34
|
+
handleFile(file);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 读取 业务/app/router-schema/**/**.js所有文件
|
|
38
|
+
const businessRouterSchemaPath = path.resolve(
|
|
39
|
+
app.businessPath,
|
|
40
|
+
`.${sep}router-schema`,
|
|
41
|
+
);
|
|
42
|
+
const businessFileList = glob.sync(
|
|
43
|
+
path.resolve(businessRouterSchemaPath, `.${sep}**${sep}**.js`),
|
|
44
|
+
);
|
|
45
|
+
businessFileList.forEach((file) => {
|
|
46
|
+
handleFile(file);
|
|
47
|
+
});
|
|
48
|
+
// 注册所有 routerSchema,使得可以 'app.routerSchema’ 这样访问
|
|
49
|
+
|
|
50
|
+
function handleFile(file) {
|
|
51
|
+
// 因为每个接口路径不一样,所以通过扩展运算符的形式,将router-schema下的文件中的数据进行合并
|
|
52
|
+
routerSchema = { ...routerSchema, ...require(path.resolve(file)) };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
app.routerSchema = routerSchema;
|
|
56
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const KoaRouter = require("koa-router");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const glob = require("glob");
|
|
4
|
+
const { sep } = path;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* router loader
|
|
8
|
+
* @param {*} app Koa实例
|
|
9
|
+
* 解析所有 app/router/ 下所有 js 文件,加载到 KoaRouter 下
|
|
10
|
+
*/
|
|
11
|
+
module.exports = (app) => {
|
|
12
|
+
const router = new KoaRouter();
|
|
13
|
+
|
|
14
|
+
// 找到 elpis 路由文件路径
|
|
15
|
+
const elpisRouterPath = path.resolve(
|
|
16
|
+
__dirname,
|
|
17
|
+
`..${sep}..${sep}app${sep}router`,
|
|
18
|
+
);
|
|
19
|
+
// 注册所有 elpis 路由
|
|
20
|
+
const elpisFileList = glob.sync(
|
|
21
|
+
path.resolve(elpisRouterPath, `.${sep}**${sep}**.js`),
|
|
22
|
+
);
|
|
23
|
+
elpisFileList.forEach((file) => {
|
|
24
|
+
require(path.resolve(file))(app, router);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 找到业务路由文件路径
|
|
28
|
+
const businessRouterPath = path.resolve(app.businessPath, `.${sep}router`);
|
|
29
|
+
|
|
30
|
+
// 注册所有业务路由
|
|
31
|
+
const businessFileList = glob.sync(
|
|
32
|
+
path.resolve(businessRouterPath, `.${sep}**${sep}**.js`),
|
|
33
|
+
);
|
|
34
|
+
businessFileList.forEach((file) => {
|
|
35
|
+
require(path.resolve(file))(app, router);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// 4. 路由兜底
|
|
40
|
+
router.get("*", async (ctx, next) => {
|
|
41
|
+
console.log("默认传递重定向的路由地址", app?.options?.homePage);
|
|
42
|
+
|
|
43
|
+
ctx.status = 302; // 临时重定向
|
|
44
|
+
ctx.redirect(`${app?.options?.homePage ?? "/"}`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 5. 路由注册到 app 上
|
|
48
|
+
app.use(router.routes());
|
|
49
|
+
app.use(router.allowedMethods());
|
|
50
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const glob = require("glob");
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
/**
|
|
5
|
+
* service loader
|
|
6
|
+
* @param {object} app Koa实例
|
|
7
|
+
*
|
|
8
|
+
* 加载所有service , 可通过'app.service.${目录}.${文件}' 访问
|
|
9
|
+
* 例子
|
|
10
|
+
* app/service
|
|
11
|
+
* |
|
|
12
|
+
* |-- custom-module
|
|
13
|
+
* |
|
|
14
|
+
* |-- custom-service.js
|
|
15
|
+
* ====> app.service.customModule.customService
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
const service = {};
|
|
20
|
+
|
|
21
|
+
// 读取 app/service/**/**.js所有文件
|
|
22
|
+
const elpisServicePath = path.resolve(
|
|
23
|
+
__dirname,
|
|
24
|
+
`..${sep}..${sep}app${sep}service`,
|
|
25
|
+
);
|
|
26
|
+
// 遍历所有js文件
|
|
27
|
+
const elpisFileList = glob.sync(
|
|
28
|
+
path.resolve(elpisServicePath, `.${sep}**${sep}**.js`),
|
|
29
|
+
);
|
|
30
|
+
// 遍历所有文件目录,把内容加载到 app.service 下
|
|
31
|
+
elpisFileList.forEach((file) => {
|
|
32
|
+
handleFile(file);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 读取 app/service/**/**.js所有文件
|
|
36
|
+
const businessServicePath = path.resolve(app.businessPath, `.${sep}service`);
|
|
37
|
+
// 遍历所有js文件
|
|
38
|
+
const businessFileList = glob.sync(
|
|
39
|
+
path.resolve(businessServicePath, `.${sep}**${sep}**.js`),
|
|
40
|
+
);
|
|
41
|
+
// 遍历所有文件目录,把内容加载到 app.service 下
|
|
42
|
+
businessFileList.forEach((file) => {
|
|
43
|
+
handleFile(file);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
function handleFile(file) {
|
|
47
|
+
// 提取文件名称
|
|
48
|
+
let name = path.resolve(file);
|
|
49
|
+
|
|
50
|
+
// 截取路径 app/service/custom-module/custom-service.js =》custom-module/custom-service
|
|
51
|
+
name = name.substring(
|
|
52
|
+
name.lastIndexOf(`service${sep}`) + `service${sep}`.length,
|
|
53
|
+
name.lastIndexOf("."),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// 把 - 统一改为驼峰式
|
|
57
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.substring(1).toUpperCase());
|
|
58
|
+
|
|
59
|
+
// 根据文件夹构建嵌套对象
|
|
60
|
+
let tempService = service;
|
|
61
|
+
|
|
62
|
+
// 分割/ 过滤空字符串
|
|
63
|
+
const names = name.split(sep).filter(Boolean);
|
|
64
|
+
for (let i = 0, len = names.length; i < len; i++) {
|
|
65
|
+
const key = names[i];
|
|
66
|
+
// 最后一层,挂载中间件函数
|
|
67
|
+
if (i === len - 1) {
|
|
68
|
+
/**
|
|
69
|
+
* service返回的是一个构造对象(), 文件名作为键名,值为构造对象实例
|
|
70
|
+
*/
|
|
71
|
+
const ServiceModule = require(file)(app);
|
|
72
|
+
// 存入的类型就是键值对,键为文件名,值为构造对象 例如:project: ProjectService{}
|
|
73
|
+
tempService[key] = new ServiceModule();
|
|
74
|
+
} else {
|
|
75
|
+
// 不是最后一层,创建嵌套对象 假设 key为user tempService={user:{}} 也就是则tempService=.user
|
|
76
|
+
if (!tempService[key]) {
|
|
77
|
+
tempService[key] = {};
|
|
78
|
+
}
|
|
79
|
+
tempService = tempService[key];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
app.service = service;
|
|
85
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// 引入模块
|
|
2
|
+
const ElpisCore = require("./elpis-core");
|
|
3
|
+
|
|
4
|
+
// 引入前端工程化构建方法
|
|
5
|
+
const FEBuildDev = require("./app/webpack/dev.js");
|
|
6
|
+
const FEBuildProd = require("./app/webpack/prod.js");
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
/**
|
|
10
|
+
* 服务端基础
|
|
11
|
+
*/
|
|
12
|
+
Controller: {
|
|
13
|
+
Base: require("./app/controller/base.js"),
|
|
14
|
+
},
|
|
15
|
+
Service: {
|
|
16
|
+
Base: require("./app/service/base.js"),
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* 编译构建前端工程
|
|
20
|
+
* @param {} env 环境变量 local/prod
|
|
21
|
+
*/
|
|
22
|
+
frontendBuild(env) {
|
|
23
|
+
if (env === "local") {
|
|
24
|
+
FEBuildDev();
|
|
25
|
+
} else if (env === "prod") {
|
|
26
|
+
FEBuildProd();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* 启动 elpis
|
|
31
|
+
* @param {Object} options 项目配置,透传到 elpis-core
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
serverStart(options = {}) {
|
|
35
|
+
const app = ElpisCore.start(options);
|
|
36
|
+
return app;
|
|
37
|
+
},
|
|
38
|
+
};
|