@wanglindoc/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.
Files changed (88) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +52 -0
  3. package/.idea/codeStyles/Project.xml +14 -0
  4. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  5. package/.idea/elpis.iml +12 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/prettier.xml +7 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/README.md +232 -0
  11. package/app/controller/base.js +42 -0
  12. package/app/controller/project.js +76 -0
  13. package/app/controller/view.js +19 -0
  14. package/app/extend/logger.js +42 -0
  15. package/app/middleware/api-params-verify.js +81 -0
  16. package/app/middleware/api-sign-verify.js +45 -0
  17. package/app/middleware/error-handler.js +41 -0
  18. package/app/middleware/project-handler.js +30 -0
  19. package/app/middleware.js +42 -0
  20. package/app/pages/assets/custom.css +14 -0
  21. package/app/pages/boot.js +51 -0
  22. package/app/pages/common/curl.js +91 -0
  23. package/app/pages/common/utils.js +7 -0
  24. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +18 -0
  25. package/app/pages/dashboard/complex-view/header-view/header-view.vue +154 -0
  26. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +46 -0
  27. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
  28. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +127 -0
  29. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
  30. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
  31. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +104 -0
  32. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +129 -0
  33. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +137 -0
  34. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
  35. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu.vue +21 -0
  36. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +141 -0
  37. package/app/pages/dashboard/dashboard.vue +96 -0
  38. package/app/pages/dashboard/entry.dashboard.js +53 -0
  39. package/app/pages/dashboard/todo/todo.vue +6 -0
  40. package/app/pages/store/index.js +5 -0
  41. package/app/pages/store/menu.js +73 -0
  42. package/app/pages/store/project.js +15 -0
  43. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  44. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  45. package/app/pages/widgets/header-container/header-container.vue +106 -0
  46. package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
  47. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +135 -0
  48. package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
  49. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  50. package/app/pages/widgets/schema-form/schema-form.vue +145 -0
  51. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +52 -0
  52. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  53. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +42 -0
  54. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
  55. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +129 -0
  56. package/app/pages/widgets/schema-search-bar/search-item-config.js +24 -0
  57. package/app/pages/widgets/schema-table/schema-table.vue +212 -0
  58. package/app/pages/widgets/sider-container/sider-container.vue +26 -0
  59. package/app/public/output/entry.page1.tpl +55 -0
  60. package/app/public/output/entry.page2.tpl +11 -0
  61. package/app/public/static/favicon.ico +0 -0
  62. package/app/public/static/normalize.css +267 -0
  63. package/app/router/project.js +14 -0
  64. package/app/router/view.js +9 -0
  65. package/app/router-schema/project.js +32 -0
  66. package/app/service/base.js +15 -0
  67. package/app/service/project.js +48 -0
  68. package/app/view/entry.tpl +22 -0
  69. package/app/webpack/build-dev.js +64 -0
  70. package/app/webpack/build-prod.js +29 -0
  71. package/app/webpack/config/webpack.base.js +352 -0
  72. package/app/webpack/config/webpack.dev.js +59 -0
  73. package/app/webpack/config/webpack.prod.js +145 -0
  74. package/app/webpack/libs/blank.js +1 -0
  75. package/config/config.default.js +4 -0
  76. package/elpis-core/env.js +20 -0
  77. package/elpis-core/index.js +106 -0
  78. package/elpis-core/loader/config.js +62 -0
  79. package/elpis-core/loader/controller.js +79 -0
  80. package/elpis-core/loader/extend.js +67 -0
  81. package/elpis-core/loader/middleware.js +77 -0
  82. package/elpis-core/loader/router-schema.js +57 -0
  83. package/elpis-core/loader/router.js +57 -0
  84. package/elpis-core/loader/service.js +76 -0
  85. package/index.js +39 -0
  86. package/model/index.js +128 -0
  87. package/package.json +90 -0
  88. package/test/controller/project.test.js +243 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * config loader 配置加载器
3
+ * @param {*} app Koa 实例
4
+ *
5
+ * 配置区分 开发/测试/生产 通过 env 环境读取不同文件配置 env.config
6
+ * 通过env.config 覆盖 default.config 加载到 app.config 中
7
+ *
8
+ * 目录下对应的 config 配置
9
+ * 默认配置 config/config.default.js
10
+ * 本地配置 config/config.local.js
11
+ * 测试配置 config/config.beta.js
12
+ * 生产配置 config/config.prod.js
13
+ */
14
+ const path = require("node:path");
15
+ const { sep } = path;
16
+
17
+ module.exports = (app) => {
18
+ // elpis config 目录及相关文件
19
+ const elpisConfigPath = path.resolve(__dirname, `..${sep}..${sep}config`);
20
+ let defaultConfig = require(
21
+ path.resolve(elpisConfigPath, `.${sep}config.default.js`),
22
+ );
23
+
24
+ // 获取业务 config 目录及相关配置
25
+ const businessConfigPath = path.resolve(process.cwd(), `.${sep}config`);
26
+ try {
27
+ defaultConfig = {
28
+ ...defaultConfig,
29
+ ...require(path.resolve(businessConfigPath, `.${sep}config.default.js`)),
30
+ };
31
+ } catch (error) {
32
+ console.log("[exception] there is no default.config file");
33
+ }
34
+
35
+ // 获取env.config
36
+ let envConfig = {};
37
+
38
+ try {
39
+ if (app.env.isLocal()) {
40
+ // 本地环境
41
+ envConfig = require(
42
+ path.resolve(businessConfigPath, `.${sep}config.local.js`),
43
+ );
44
+ } else if (app.env.isBeta()) {
45
+ // 测试环境
46
+ envConfig = require(
47
+ path.resolve(businessConfigPath, `.${sep}config.beta.js`),
48
+ );
49
+ } else if (app.env.isProduction()) {
50
+ // 生产环境
51
+ envConfig = require(
52
+ path.resolve(businessConfigPath, `.${sep}config.prod.js`),
53
+ );
54
+ }
55
+ } catch (error) {
56
+ console.log(error, "error");
57
+ console.log("[exception] there is no env.config file");
58
+ }
59
+
60
+ // 覆盖并加载 config 配置
61
+ app.config = Object.assign({}, defaultConfig, envConfig);
62
+ };
@@ -0,0 +1,79 @@
1
+ const glob = require("glob");
2
+ const path = require("path");
3
+ const { sep } = path;
4
+
5
+ /**
6
+ * controller loader
7
+ * @param {*} app koa实例
8
+ * @description 加载所有 controller,可通过 'app.controllers.${目录}.${文件}' 访问
9
+ * @example app/controller
10
+ * |
11
+ * | -- custom-module
12
+ * |
13
+ * | -- custom-controller.js
14
+ * => app.controller.customModule.costomController
15
+ *
16
+ */
17
+ module.exports = (app) => {
18
+ const controllers = {};
19
+
20
+ // 读取 elpis/app/controller/**/**.js 下的所有文件
21
+ const elpisControllerPath = path.resolve(
22
+ __dirname,
23
+ `..${sep}..${sep}app${sep}controller`,
24
+ );
25
+ const elpisFileList = glob.sync(
26
+ path.resolve(elpisControllerPath, `.${sep}**${sep}**.js`),
27
+ );
28
+ // 遍历所有文件目录,把内容加载到 app.controllers 中
29
+ elpisFileList.forEach((file) => {
30
+ handleFile(file);
31
+ });
32
+
33
+ // 读取业务 app/controller/**/**.js 下的所有文件
34
+ const businessControllerPath = path.resolve(
35
+ app.businessPath,
36
+ `.${sep}controller`,
37
+ );
38
+ const businessFileList = glob.sync(
39
+ path.resolve(businessControllerPath, `.${sep}**${sep}**.js`),
40
+ );
41
+ // 遍历所有文件目录,把内容加载到 app.controllers 中
42
+ businessFileList.forEach((file) => {
43
+ handleFile(file);
44
+ });
45
+
46
+ function handleFile(file) {
47
+ // 提取文件名称
48
+ let fileName = path.resolve(file);
49
+
50
+ // 截取路径 app/controller/custom-module/custom-controller.js => custom-module/custom-controller
51
+ fileName = fileName.substring(
52
+ fileName.lastIndexOf(`controller${sep}`) + `controller${sep}`.length,
53
+ fileName.lastIndexOf("."),
54
+ );
55
+
56
+ // 把 '-' 统一改为驼峰式,custom-module/costom-controller => customModule/costomController
57
+ fileName = fileName.replace(/[_-][a-z]/gi, (s) =>
58
+ s.substring(1).toUpperCase(),
59
+ ); // s:-a或者_a
60
+
61
+ let tempController = controllers; // {}
62
+ const splitFileNames = fileName.split(`${sep}`); // ["customModule(目录)","costomController(文件)"]
63
+ for (let i = 0, len = splitFileNames.length; i < len; ++i) {
64
+ if (i === len - 1) {
65
+ // controller 是一些 class类
66
+ const ControllerMoule = require(path.resolve(file))(app);
67
+ tempController[splitFileNames[i]] = new ControllerMoule(); // 3、tempController = { b: file }、controllers = { a: { b: file }}
68
+ } else {
69
+ if (!tempController[splitFileNames[i]]) {
70
+ tempController[splitFileNames[i]] = {}; // 1、tempController: { a:{} }、controllers = { a:{} }
71
+ }
72
+ tempController = tempController[splitFileNames[i]]; // 2、tempController = a:{}、controllers = { a:{} }
73
+ }
74
+ }
75
+ }
76
+
77
+ // 将 middlewares 对象挂载到内存中的 app 对象上
78
+ app.controllers = controllers;
79
+ };
@@ -0,0 +1,67 @@
1
+ const glob = require("glob");
2
+ const path = require("path");
3
+ const { sep } = path;
4
+
5
+ /**
6
+ * extend loader
7
+ * @param {*} app koa实例
8
+ * @description 加载所有 extend,可通过 'app.extend.${文件}' 访问
9
+ * @example app/extend
10
+ * |
11
+ * | -- custom-extend.js
12
+ * => app.extend.costomExtend 访问
13
+ * extend 是 app 的拓展,只允许有一级目录
14
+ *
15
+ */
16
+
17
+ module.exports = (app) => {
18
+ // 读取 elpis/app/extend/**.js 下的所有文件
19
+ const elpisExtendPath = path.resolve(
20
+ __dirname,
21
+ `..${sep}..${sep}app${sep}extend`,
22
+ );
23
+ const elpisFileList = glob.sync(
24
+ path.resolve(elpisExtendPath, `.${sep}**.js`),
25
+ );
26
+ // 遍历所有文件目录,把内容加载到 app 上
27
+ elpisFileList.forEach((file) => {
28
+ handleFile(file);
29
+ });
30
+
31
+ // 读取业务 app/extend/**.js 下的所有文件
32
+ const businessExtendPath = path.resolve(app.businessPath, `.${sep}extend`);
33
+ const businessFileList = glob.sync(
34
+ path.resolve(businessExtendPath, `.${sep}**.js`),
35
+ );
36
+ // 遍历所有文件目录,把内容加载到 app 上
37
+ businessFileList.forEach((file) => {
38
+ handleFile(file);
39
+ });
40
+
41
+ function handleFile(file) {
42
+ // 提取文件名称
43
+ let fileName = path.resolve(file);
44
+
45
+ // 截取路径 app/extend/custom-extend.js => custom-extend
46
+ fileName = fileName.substring(
47
+ fileName.lastIndexOf(`extend${sep}`) + `extend${sep}`.length,
48
+ fileName.lastIndexOf("."),
49
+ );
50
+
51
+ // 把 '-' 统一改为驼峰式,costom-extend => costomExtend
52
+ fileName = fileName.replace(/[_-][a-z]/gi, (s) =>
53
+ s.substring(1).toUpperCase(),
54
+ ); // s:-a或者_a
55
+
56
+ // 过滤 app 已经存在的 key
57
+ for (const key in app) {
58
+ if (key === fileName) {
59
+ console.log(`[extend load error] name:${fileName} is already in app`);
60
+ return;
61
+ }
62
+ }
63
+
64
+ // 将 extend 挂载到 app 上
65
+ app[fileName] = require(path.resolve(file))(app);
66
+ }
67
+ };
@@ -0,0 +1,77 @@
1
+ const glob = require("glob");
2
+ const path = require("path");
3
+ const { sep } = path;
4
+
5
+ /**
6
+ * middleware loader
7
+ * @param {*} app koa实例
8
+ * @description 加载所有 middleware,可通过 'app.middlewares.${目录}.${文件}' 访问
9
+ * @example app/middleware
10
+ * |
11
+ * | -- custom-module
12
+ * |
13
+ * | -- custom-middleware.js
14
+ * => app.middlewares.customModule.costomMiddleware
15
+ *
16
+ */
17
+ module.exports = (app) => {
18
+ const middlewares = {};
19
+
20
+ // 读取 elpis/app/middleware/**/**.js 下的所有文件
21
+ const elpisMiddlewarePath = path.resolve(
22
+ __dirname,
23
+ `..${sep}..${sep}app${sep}middleware`,
24
+ );
25
+ const elpisFileList = glob.sync(
26
+ path.resolve(elpisMiddlewarePath, `.${sep}**${sep}**.js`),
27
+ );
28
+ // 遍历所有文件目录,把内容加载到 app.middlewares 中
29
+ elpisFileList.forEach((file) => {
30
+ handleFile(file);
31
+ });
32
+
33
+ // 读取业务根目录 app/middleware/**/**.js 下的所有文件
34
+ const businessMiddlewarePath = path.resolve(
35
+ app.businessPath,
36
+ `.${sep}middleware`,
37
+ );
38
+ const businessFileList = glob.sync(
39
+ path.resolve(businessMiddlewarePath, `.${sep}**${sep}**.js`),
40
+ );
41
+ // 遍历所有文件目录,把内容加载到 app.middlewares 中
42
+ businessFileList.forEach((file) => {
43
+ handleFile(file);
44
+ });
45
+
46
+ function handleFile(file) {
47
+ // 提取文件名称
48
+ let fileName = path.resolve(file);
49
+
50
+ // 截取路径 app/middleware/custom-module/custom-middleware.js => custom-module/custom-middleware
51
+ fileName = fileName.substring(
52
+ fileName.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length,
53
+ fileName.lastIndexOf("."),
54
+ );
55
+
56
+ // 把 '-' 统一改为驼峰式,custom-module/custom-middleware => customModule/customMiddleware
57
+ fileName = fileName.replace(/[_-][a-z]/gi, (s) =>
58
+ s.substring(1).toUpperCase(),
59
+ ); // s:-a或者_a
60
+
61
+ let tempMiddleware = middlewares; // {}
62
+ const splitFileNames = fileName.split(`${sep}`);
63
+ for (let i = 0, len = splitFileNames.length; i < len; ++i) {
64
+ if (i === len - 1) {
65
+ tempMiddleware[splitFileNames[i]] = require(path.resolve(file))(app); // { a: { b: file }}
66
+ } else {
67
+ if (!tempMiddleware[splitFileNames[i]]) {
68
+ tempMiddleware[splitFileNames[i]] = {}; // tempMiddleware: { a:{} }
69
+ }
70
+ tempMiddleware = tempMiddleware[splitFileNames[i]]; // tempMiddleware = {}
71
+ }
72
+ }
73
+ }
74
+
75
+ // 将 middlewares 对象挂载到内存中的 app 对象上
76
+ app.middlewares = middlewares;
77
+ };
@@ -0,0 +1,57 @@
1
+ const glob = require("glob");
2
+ const path = require("path");
3
+ const { sep } = path;
4
+
5
+ /**
6
+ * router-schema loader
7
+ * @param {object} app Koa实例
8
+ * @description 通过 'json-schema' & 'ajv' 对 API 规则进行约束,配合 api-params-verify 中间件进行验证
9
+ * 路由router会定义好接口的路径、请求方式、调用哪个controller等
10
+ * 而router-schema做的事情是定义好这个接口接收什么参数,哪些参数是必传项、是什么类型
11
+ * @example app/router-schema/**.js
12
+ * 输出:
13
+ * app.routerSchema = {
14
+ * '${api1}': ${jsonSchema},
15
+ * '${api2}': ${jsonSchema},
16
+ * '${api3}': ${jsonSchema},
17
+ * '${api4}': ${jsonSchema},
18
+ * }
19
+ */
20
+ module.exports = (app) => {
21
+ let routerSchema = {};
22
+
23
+ // 读取 elpis/app/router-schema/**/**.js 下的所有文件
24
+ const elpisRouterSchemaPath = path.resolve(
25
+ __dirname,
26
+ `..${sep}..${sep}app${sep}router-schema`,
27
+ );
28
+ const elpisFileList = glob.sync(
29
+ path.resolve(elpisRouterSchemaPath, `.${sep}**${sep}**.js`),
30
+ );
31
+ // 注册所有 routerSchema ,使得可以通过 'app.routerSchema' 的方式访问
32
+ elpisFileList.forEach((file) => {
33
+ handleFile(file);
34
+ });
35
+
36
+ // 读取业务 app/router-schema/**/**.js 下的所有文件
37
+ const businessRouterSchemaPath = path.resolve(
38
+ app.businessPath,
39
+ `.${sep}router-schema`,
40
+ );
41
+ const businessFileList = glob.sync(
42
+ path.resolve(businessRouterSchemaPath, `.${sep}**${sep}**.js`),
43
+ );
44
+ // 注册所有 routerSchema ,使得可以通过 'app.routerSchema' 的方式访问
45
+ businessFileList.forEach((file) => {
46
+ handleFile(file);
47
+ });
48
+
49
+ function handleFile(file) {
50
+ routerSchema = {
51
+ ...routerSchema,
52
+ ...require(path.resolve(file)),
53
+ };
54
+ }
55
+
56
+ app.routerSchema = routerSchema;
57
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * router loader 将路由注册到KoaRouter上
3
+ * @param {*} app
4
+ *
5
+ * 解析所有 app/router/ 下所有js文件,加载到 KoaRouter 上
6
+ */
7
+
8
+ const KoaRouter = require("koa-router");
9
+ const path = require("node:path");
10
+ const { sep } = path;
11
+ const glob = require("glob");
12
+
13
+ module.exports = (app) => {
14
+ // 实例化 KoaRouter 实例
15
+ const router = new KoaRouter();
16
+
17
+ // 找到 elpis 所有路由文件
18
+ const elpisRouterPath = path.resolve(
19
+ __dirname,
20
+ `..${sep}..${sep}app${sep}router`,
21
+ );
22
+ // 注册 elpis 所有路由
23
+ const elpisFileList = glob.sync(
24
+ path.resolve(elpisRouterPath, `.${sep}**${sep}**.js`),
25
+ );
26
+ elpisFileList.forEach((file) => {
27
+ // router 文件如下:
28
+ // module.exports = (app, router) => {
29
+ // router.get('/**', **Controller)
30
+ // }
31
+ require(path.resolve(file))(app, router);
32
+ });
33
+
34
+ // 找到业务所有路由文件
35
+ const businessRouterPath = path.resolve(app.businessPath, `.${sep}router`);
36
+ // 注册业务所有路由
37
+ const businessFileList = glob.sync(
38
+ path.resolve(businessRouterPath, `.${sep}**${sep}**.js`),
39
+ );
40
+ businessFileList.forEach((file) => {
41
+ // router 文件如下:
42
+ // module.exports = (app, router) => {
43
+ // router.get('/**', **Controller)
44
+ // }
45
+ require(path.resolve(file))(app, router);
46
+ });
47
+
48
+ // 路由兜底 (健壮性)
49
+ router.get("*", async (ctx, next) => {
50
+ ctx.status = 302; // 临时重定向
51
+ ctx.redirect(`${app?.options?.homePage ?? "/"}`);
52
+ });
53
+
54
+ // 路由注册到 app 上
55
+ app.use(router.routes());
56
+ app.use(router.allowedMethods());
57
+ };
@@ -0,0 +1,76 @@
1
+ const glob = require("glob");
2
+ const path = require("path");
3
+ const { sep } = path;
4
+
5
+ /**
6
+ * service loader
7
+ * @param {*} app koa实例
8
+ * @description 加载所有 service,可通过 'app.services.${目录}.${文件}' 访问
9
+ * @example app/service
10
+ * |
11
+ * | -- custom-module
12
+ * |
13
+ * | -- custom-service.js
14
+ * => app.services.customModule.costomService
15
+ *
16
+ */
17
+ module.exports = (app) => {
18
+ const services = {};
19
+
20
+ // 读取 elpis/app/service/**/**.js 下的所有文件
21
+ const elpisServicePath = path.resolve(
22
+ __dirname,
23
+ `..${sep}..${sep}app${sep}service`,
24
+ );
25
+ const elpisFileList = glob.sync(
26
+ path.resolve(elpisServicePath, `.${sep}**${sep}**.js`),
27
+ );
28
+ // 遍历所有文件目录,把内容加载到 app.services 中
29
+ elpisFileList.forEach((file) => {
30
+ handleFile(file);
31
+ });
32
+
33
+ // 读取业务 app/service/**/**.js 下的所有文件
34
+ const businessServicePath = path.resolve(app.businessPath, `.${sep}service`);
35
+ const businessFileList = glob.sync(
36
+ path.resolve(businessServicePath, `.${sep}**${sep}**.js`),
37
+ );
38
+ // 遍历所有文件目录,把内容加载到 app.services 中
39
+ businessFileList.forEach((file) => {
40
+ handleFile(file);
41
+ });
42
+
43
+ function handleFile(file) {
44
+ // 提取文件名称
45
+ let fileName = path.resolve(file);
46
+
47
+ // 截取路径 app/service/custom-module/custom-service.js => custom-module/custom-service
48
+ fileName = fileName.substring(
49
+ fileName.lastIndexOf(`service${sep}`) + `service${sep}`.length,
50
+ fileName.lastIndexOf("."),
51
+ );
52
+
53
+ // 把 '-' 统一改为驼峰式,custom-module/custom-service => customModule/customService
54
+ fileName = fileName.replace(/[_-][a-z]/gi, (s) =>
55
+ s.substring(1).toUpperCase(),
56
+ ); // s:-a或者_a
57
+
58
+ let tempService = services; // {}
59
+ const splitFileNames = fileName.split(`${sep}`);
60
+ for (let i = 0, len = splitFileNames.length; i < len; ++i) {
61
+ if (i === len - 1) {
62
+ // service 是一些 class类
63
+ const ServiceMoule = require(path.resolve(file))(app);
64
+ tempService[splitFileNames[i]] = new ServiceMoule(); // tempService = { b: file }、services = { a: { b: file }}
65
+ } else {
66
+ if (!tempService[splitFileNames[i]]) {
67
+ tempService[splitFileNames[i]] = {}; // tempService: { a:{} }
68
+ }
69
+ tempService = tempService[splitFileNames[i]]; // tempMiddleware = {}
70
+ }
71
+ }
72
+ }
73
+
74
+ // 将 services 对象挂载到内存中的 app 对象上
75
+ app.services = services;
76
+ };
package/index.js ADDED
@@ -0,0 +1,39 @@
1
+ const ElpisCore = require("./elpis-core");
2
+
3
+ // 引入前端工程化构建
4
+ const FEBuildDev = require("./app/webpack/build-dev");
5
+ const FEBuildProd = require("./app/webpack/build-prod");
6
+
7
+ module.exports = {
8
+ /**
9
+ * 服务端基础
10
+ */
11
+ Controller: {
12
+ Base: require("./app/controller/base"),
13
+ },
14
+ Service: {
15
+ Base: require("./app/service/base"),
16
+ },
17
+
18
+ /**
19
+ * 编译构建前端工程化
20
+ * @param {*} env
21
+ */
22
+ frontendBuild(env) {
23
+ if (env === "local") {
24
+ FEBuildDev();
25
+ } else if (env === "prod") {
26
+ FEBuildProd();
27
+ }
28
+ },
29
+
30
+ /**
31
+ * 启动 elpis
32
+ * @param {*} options
33
+ * @returns
34
+ */
35
+ serverStart(options = {}) {
36
+ const app = ElpisCore.start(options);
37
+ return app;
38
+ },
39
+ };
package/model/index.js ADDED
@@ -0,0 +1,128 @@
1
+ const _ = require("lodash");
2
+ const glob = require("glob");
3
+ const path = require("path");
4
+ const { sep } = path;
5
+
6
+ /**
7
+ * project 继承 model
8
+ * @param {*} model
9
+ * @param {*} project
10
+ * @returns
11
+ */
12
+ const projectExtendModel = (model, project) => {
13
+ // 第一个参数 {} 是目标对象,最终返回的
14
+ // 第二和第三个参数 model、project 是源对象,可有多个
15
+ // 第三个参数是自定义合并函数,函数的第一个参数是目标对象的属性值,第二个参数是源对象的属性值,如果目标对象是个空对象,且有多个源对象,则目标对象会填充第一个源对象的属性
16
+ // 源对象中的属性值会覆盖目标对象中的属性值
17
+
18
+ return _.mergeWith({}, model, project, (modelValue, projValue) => {
19
+ // 处理数组合并的特殊情况
20
+ if (Array.isArray(modelValue) && Array.isArray(projValue)) {
21
+ let result = [];
22
+
23
+ // 因为 project 继承 model,所以需要处理新增和修改内容的情况
24
+ // project 有的键值,model 也有 => 修改 (重载)
25
+ // project 有的键值,model 没有 => 新增 (拓展)
26
+ // model 有的键值,project 没有 => 保留 (继承)
27
+
28
+ // 处理修改
29
+ for (let i = 0; i < modelValue.length; ++i) {
30
+ let modelItem = modelValue[i];
31
+ const projItem = projValue.find(
32
+ (projItem) => projItem.key === modelItem.key,
33
+ );
34
+ // project有的键值,model 也有,则递归调用 projectExtendModel 方法覆盖修改
35
+ result.push(
36
+ projItem ? projectExtendModel(modelItem, projItem) : modelItem,
37
+ );
38
+ }
39
+
40
+ // 处理新增
41
+ for (let i = 0; i < projValue.length; ++i) {
42
+ const projItem = projValue[i];
43
+ const modelItem = modelValue.find(
44
+ (modelItem) => modelItem.key === projItem.key,
45
+ );
46
+ if (!modelItem) {
47
+ result.push(projItem);
48
+ }
49
+ }
50
+
51
+ return result;
52
+ }
53
+ });
54
+ };
55
+
56
+ /**
57
+ * 解析 model 配置,并返回组织且继承后的数据结构
58
+ * [
59
+ * {
60
+ * model:${model},
61
+ * project:{
62
+ * proj1Key:${proj1},
63
+ * proj2Key:${proj2}
64
+ * }
65
+ * }
66
+ * ]
67
+ * @param {*} app
68
+ */
69
+ module.exports = (app) => {
70
+ const modelList = [];
71
+
72
+ // 遍历当前文件夹,构造模型数据结构,挂载到 modelList 上
73
+ const modelPath = path.resolve(app.baseDir, `.${sep}model`);
74
+ const fileList = glob.sync(path.resolve(modelPath, `.${sep}**${sep}**.js`));
75
+
76
+ fileList.forEach((file) => {
77
+ if (file.indexOf("index.js") > -1) {
78
+ return;
79
+ }
80
+
81
+ // 区分配置类型 model/project
82
+ const type = file.indexOf(`${sep}project${sep}`) > -1 ? "project" : "model";
83
+
84
+ if (type === "project") {
85
+ const modelKey = file.match(/\/model\/(.*?)\/project/)?.[1];
86
+ const projectKey = file.match(/\/project\/(.*?)\.js/)?.[1];
87
+ let modelItem = modelList.find((item) => item.model?.key === modelKey);
88
+ // 初始化 model 数据结构
89
+ if (!modelItem) {
90
+ modelItem = {};
91
+ modelList.push(modelItem);
92
+ }
93
+
94
+ // 初始化 project 数据结构
95
+ if (!modelItem.project) {
96
+ modelItem.project = {};
97
+ }
98
+
99
+ modelItem.project[projectKey] = require(path.resolve(file));
100
+ // 注入 projectKey
101
+ modelItem.project[projectKey].key = projectKey;
102
+ modelItem.project[projectKey].modelKey = modelKey;
103
+ }
104
+
105
+ if (type === "model") {
106
+ const modelKey = file.match(/\/model\/(.*?)\/model.js/)?.[1];
107
+ let modelItem = modelList.find((item) => item.model?.key === modelKey);
108
+ // 初始化 model 数据结构
109
+ if (!modelItem) {
110
+ modelItem = {};
111
+ modelList.push(modelItem);
112
+ }
113
+ modelItem.model = require(path.resolve(file));
114
+ // 注入 modelKey
115
+ modelItem.model.key = modelKey;
116
+ }
117
+ });
118
+
119
+ // 处理继承
120
+ modelList.forEach((item) => {
121
+ const { model, project } = item;
122
+ for (const key in project) {
123
+ project[key] = projectExtendModel(model, project[key]);
124
+ }
125
+ });
126
+
127
+ return modelList;
128
+ };