@xujingquan/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/.browserslistrc +3 -0
- package/.eslintignore +4 -0
- package/.eslintrc +63 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +16 -0
- package/.prettierrc +10 -0
- package/README.md +248 -0
- package/app/controller/base.js +41 -0
- package/app/controller/project.js +75 -0
- package/app/controller/view.js +28 -0
- package/app/extend/logger.js +39 -0
- package/app/middleware/api-params-verify.js +90 -0
- package/app/middleware/api-sign-veriyf.js +47 -0
- package/app/middleware/error-handler.js +33 -0
- package/app/middleware/project-handler.js +30 -0
- package/app/middleware.js +45 -0
- package/app/pages/asserts/custom.css +13 -0
- package/app/pages/boot.js +56 -0
- package/app/pages/common/api/business-api.js +19 -0
- package/app/pages/common/api/project-api.js +27 -0
- package/app/pages/common/request.js +119 -0
- package/app/pages/common/utils.js +2 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +20 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +116 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +44 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +37 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +122 -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 +86 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +82 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +115 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +135 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +93 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +21 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +115 -0
- package/app/pages/dashboard/dashboard.vue +93 -0
- package/app/pages/dashboard/entry.dashboard.js +45 -0
- package/app/pages/store/index.js +4 -0
- package/app/pages/store/menu.js +61 -0
- package/app/pages/store/project.js +17 -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 +111 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +141 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +142 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
- package/app/pages/widgets/schema-form/form-item-config.js +23 -0
- package/app/pages/widgets/schema-form/schema-form.vue +130 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +50 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +62 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +40 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +48 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +121 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
- package/app/pages/widgets/schema-table/schema-table.vue +243 -0
- package/app/pages/widgets/sider-container/sider-container.vue +26 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/md5.js +950 -0
- package/app/public/static/normalize.css +267 -0
- package/app/router/project.js +11 -0
- package/app/router/view.js +13 -0
- package/app/router-schema/project.js +33 -0
- package/app/service/base.js +14 -0
- package/app/service/project.js +43 -0
- package/app/view/entry.tpl +27 -0
- package/app/webpack/config/utils.js +49 -0
- package/app/webpack/config/webpack-dev.js +55 -0
- package/app/webpack/config/webpack-prod.js +192 -0
- package/app/webpack/config/webpack.base.js +273 -0
- package/app/webpack/dev.js +60 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +27 -0
- package/babel.config.js +15 -0
- package/commitlint.config.js +3 -0
- package/config/config.default.js +4 -0
- package/elpis-core/env.js +20 -0
- package/elpis-core/index.js +86 -0
- package/elpis-core/loader/config.js +54 -0
- package/elpis-core/loader/controller.js +69 -0
- package/elpis-core/loader/extend.js +57 -0
- package/elpis-core/loader/middleware.js +66 -0
- package/elpis-core/loader/router-schema.js +49 -0
- package/elpis-core/loader/router.js +50 -0
- package/elpis-core/loader/service.js +69 -0
- package/index.js +47 -0
- package/jsconfig.json +19 -0
- package/model/index.js +103 -0
- package/package.json +105 -0
- package/test/controller/project.test.js +200 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* config loader
|
|
6
|
+
* @param {object} app Koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 配置区分 本地/测试/生成 环境,通过 env 环境读取不同文件配置 env.config
|
|
9
|
+
* 通过 env.config 覆盖 default.config 加载到 app.config 中
|
|
10
|
+
*
|
|
11
|
+
* 目录下对应的 config 配置
|
|
12
|
+
* 默认配置 config/config.default.js(框架|业务)
|
|
13
|
+
* 本地配置 config/config.local.js(业务)
|
|
14
|
+
* 测试配置 config/config.beta.js(业务)
|
|
15
|
+
* 生产配置 config/config.prod.js(业务)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
// 01、获取 elpis config 目录及相关文件
|
|
20
|
+
const elipsConfigPath = path.resolve(__dirname, `..${sep}..${sep}config`);
|
|
21
|
+
let defaultConfig = require(path.resolve(elipsConfigPath, `.${sep}config.default.js`));
|
|
22
|
+
|
|
23
|
+
// 02、获取 业务 config 目录及相关文件
|
|
24
|
+
const businessConfigPath = path.resolve(process.cwd(), `.${sep}config`);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
defaultConfig = {
|
|
28
|
+
...defaultConfig,
|
|
29
|
+
...require(path.resolve(businessConfigPath, `.${sep}config.default.js`)),
|
|
30
|
+
};
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.log('[exception] there is no default.config.js file');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 03、获取 env.config
|
|
36
|
+
let envConfig = {};
|
|
37
|
+
try {
|
|
38
|
+
if (app.env.isLocal()) {
|
|
39
|
+
// 本地环境
|
|
40
|
+
envConfig = require(path.resolve(businessConfigPath, `.${sep}config.local.js`));
|
|
41
|
+
} else if (app.env.isBeta()) {
|
|
42
|
+
// 测试环境
|
|
43
|
+
envConfig = require(path.resolve(businessConfigPath, `.${sep}config.beta.js`));
|
|
44
|
+
} else if (app.env.isProduction()) {
|
|
45
|
+
// 生产环境
|
|
46
|
+
envConfig = require(path.resolve(businessConfigPath, `.${sep}config.prod.js`));
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.log(e, '/loader/config.js');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 04、覆盖并加载 config 配置
|
|
53
|
+
app.config = Object.assign({}, defaultConfig, envConfig);
|
|
54
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
/**
|
|
5
|
+
* controller loader
|
|
6
|
+
* @param {object} app Koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 加载使用 controller,可通过 'app.controller.${目录}.${文件}' 访问
|
|
9
|
+
*
|
|
10
|
+
* 例子:
|
|
11
|
+
* app/controller
|
|
12
|
+
* |
|
|
13
|
+
* |—— custom-module
|
|
14
|
+
* |—— custom-controller.js
|
|
15
|
+
*
|
|
16
|
+
* => app.controller.customModule.customController (通过这个loader可以实现这个方式去访问上面目录中的文件)
|
|
17
|
+
* */
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
// 01、读取 elpis/app/controller/**/**.js 下的所有文件 (当前框架)
|
|
20
|
+
const elpisControllerPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}controller`);
|
|
21
|
+
const elpisFileList = glob.sync(path.resolve(elpisControllerPath, `.${sep}**${sep}**.js`));
|
|
22
|
+
|
|
23
|
+
// 02、读取业务根目录 app/controller/**/**.js 下的所有文件(客户业务项目)
|
|
24
|
+
const businessControllerPath = path.resolve(app.businessPath, `.${sep}controller`);
|
|
25
|
+
const businessFileList = glob.sync(path.resolve(businessControllerPath, `.${sep}**${sep}**.js`));
|
|
26
|
+
|
|
27
|
+
// 03、遍历所有文件目录,把内容加载到 app.controller 下
|
|
28
|
+
const controller = {};
|
|
29
|
+
elpisFileList.forEach((file) => {
|
|
30
|
+
handleFile(file);
|
|
31
|
+
});
|
|
32
|
+
businessFileList.forEach((file) => {
|
|
33
|
+
handleFile(file);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function handleFile(file) {
|
|
37
|
+
// 提取文件名称
|
|
38
|
+
let name = path.resolve(file); // 将文件名拼接到文件路径上
|
|
39
|
+
// 截取路径 app/controller/custom-module/custom-controller.js => custom-module/custom-controller
|
|
40
|
+
name = name.slice(
|
|
41
|
+
name.lastIndexOf(`controller${sep}`) + `controller${sep}`.length,
|
|
42
|
+
name.lastIndexOf('.')
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// 04、把 '-' 统一改为驼峰式,custom-module/custom-controller => customModule/customController
|
|
46
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.slice(1).toUpperCase());
|
|
47
|
+
|
|
48
|
+
// 05、挂载 controller 到内存 app 对象中
|
|
49
|
+
let tempController = controller;
|
|
50
|
+
const names = name.split(sep); // => [ customModule(目录), customController(文件) ]
|
|
51
|
+
for (let i = 0, len = names.length; i < len; ++i) {
|
|
52
|
+
if (i === len - 1) {
|
|
53
|
+
// 文件
|
|
54
|
+
const ControllerMoule = require(path.resolve(file))(app); // 导入文件并且传入 app 实例
|
|
55
|
+
tempController[names[i]] = new ControllerMoule();
|
|
56
|
+
} else {
|
|
57
|
+
// 目录
|
|
58
|
+
if (!tempController[names[i]]) {
|
|
59
|
+
tempController[names[i]] = {};
|
|
60
|
+
}
|
|
61
|
+
tempController = tempController[names[i]];
|
|
62
|
+
// tempController === {}
|
|
63
|
+
// tempController = { customModule: { a: { b: { } } } }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
app.controller = controller;
|
|
69
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
/**
|
|
5
|
+
* extend loader
|
|
6
|
+
* @param {object} app Koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 加载使用 extend,可通过 'app.extend.${文件}' 访问
|
|
9
|
+
*
|
|
10
|
+
* 例子:
|
|
11
|
+
* app/extend
|
|
12
|
+
* |
|
|
13
|
+
* |—— custom-extend.js
|
|
14
|
+
*
|
|
15
|
+
* => app.extend.customExtend (通过这个loader可以实现这个方式去访问上面目录中的文件)
|
|
16
|
+
* */
|
|
17
|
+
module.exports = (app) => {
|
|
18
|
+
// 01、读取 elpis/app/extend/**/**.js 下的所有文件(当前框架)
|
|
19
|
+
const elipsExtendPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}extend`);
|
|
20
|
+
const elpisFileList = glob.sync(path.resolve(elipsExtendPath, `.${sep}**${sep}**.js`));
|
|
21
|
+
|
|
22
|
+
// 02、读取业务根目录 app/extend/**/**.js 下的所有文件(客户业务项目)
|
|
23
|
+
const businessExtendPath = path.resolve(app.businessPath, `.${sep}extend`);
|
|
24
|
+
const businessFileList = glob.sync(path.resolve(businessExtendPath, `.${sep}**${sep}**.js`));
|
|
25
|
+
|
|
26
|
+
// 03、遍历所有文件目录,把内容加载到 app.extend 下
|
|
27
|
+
elpisFileList.forEach((file) => {
|
|
28
|
+
handleFile(file);
|
|
29
|
+
});
|
|
30
|
+
businessFileList.forEach((file) => {
|
|
31
|
+
handleFile(file);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function handleFile(file) {
|
|
35
|
+
// 提取文件名称
|
|
36
|
+
let name = path.resolve(file); // 将文件名拼接到文件路径上
|
|
37
|
+
// 截取路径 app/extend/custom-extend.js => custom-extend
|
|
38
|
+
name = name.slice(
|
|
39
|
+
name.lastIndexOf(`extend${sep}`) + `extend${sep}`.length,
|
|
40
|
+
name.lastIndexOf('.')
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// 04、把 '-' 统一改为驼峰式,custom-extend => customExtend
|
|
44
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.slice(1).toUpperCase());
|
|
45
|
+
|
|
46
|
+
// 05、过滤 app 已存在的 key
|
|
47
|
+
for (const key in app) {
|
|
48
|
+
if (key === name) {
|
|
49
|
+
console.log(`[extend load error] name:${name} is already in app`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 06、挂载 extend 到 app 上
|
|
55
|
+
app[name] = require(path.resolve(file))(app);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
/**
|
|
5
|
+
* middleware loader
|
|
6
|
+
* @param {object} app Koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 加载使用 middleware,可通过 'app.middleware.${目录}.${文件}' 访问
|
|
9
|
+
*
|
|
10
|
+
* 例子:
|
|
11
|
+
* app/middleware
|
|
12
|
+
* |
|
|
13
|
+
* |—— custom-module
|
|
14
|
+
* |—— custom-middleware.js
|
|
15
|
+
*
|
|
16
|
+
* => app.middleware.customModule.customMiddleware (通过这个loader可以实现这个方式去访问上面目录中的文件)
|
|
17
|
+
* */
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
// 01、读取 elpis/app/middleware/**/**.js 下的所有文件(当前框架)
|
|
20
|
+
const elpisMiddlewarePath = path.resolve(__dirname, `..${sep}..${sep}app${sep}middleware`);
|
|
21
|
+
const elpisFileList = glob.sync(path.resolve(elpisMiddlewarePath, `.${sep}**${sep}**.js`));
|
|
22
|
+
|
|
23
|
+
// 02、读取业务根目录 app/middleware/**/**.js 下的所有文件(客户业务项目)
|
|
24
|
+
const businessMiddlewarePath = path.resolve(app.businessPath, `.${sep}middleware`);
|
|
25
|
+
const businessFileList = glob.sync(path.resolve(businessMiddlewarePath, `.${sep}**${sep}**.js`));
|
|
26
|
+
|
|
27
|
+
// 03、遍历所有文件目录,把内容加载到 app.middleware 下
|
|
28
|
+
const middlewares = {};
|
|
29
|
+
elpisFileList.forEach((file) => {
|
|
30
|
+
handleFile(file);
|
|
31
|
+
});
|
|
32
|
+
businessFileList.forEach((file) => {
|
|
33
|
+
handleFile(file);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function handleFile(file) {
|
|
37
|
+
// 提取文件名称
|
|
38
|
+
let name = path.resolve(file); // 将文件名拼接到文件路径上
|
|
39
|
+
// 截取路径 app/middleware/custom-module/custom-middleware.js => custom-module/custom-middleware
|
|
40
|
+
name = name.slice(
|
|
41
|
+
name.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length,
|
|
42
|
+
name.lastIndexOf('.')
|
|
43
|
+
);
|
|
44
|
+
// 04、把 '-' 统一改为驼峰式,custom-module/custom-middleware => customModule/customMiddleware
|
|
45
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.slice(1).toUpperCase());
|
|
46
|
+
|
|
47
|
+
// 05、挂载 middleware 到内存 app 对象中
|
|
48
|
+
let tempMiddleware = middlewares;
|
|
49
|
+
const names = name.split(sep);
|
|
50
|
+
for (let i = 0, len = names.length; i < len; ++i) {
|
|
51
|
+
if (i === len - 1) {
|
|
52
|
+
// 文件
|
|
53
|
+
tempMiddleware[names[i]] = require(path.resolve(file))(app); // 导入文件并且传入 app 实例
|
|
54
|
+
} else {
|
|
55
|
+
// 目录
|
|
56
|
+
if (!tempMiddleware[names[i]]) {
|
|
57
|
+
tempMiddleware[names[i]] = {};
|
|
58
|
+
}
|
|
59
|
+
tempMiddleware = tempMiddleware[names[i]];
|
|
60
|
+
// tempMiddleware === {}
|
|
61
|
+
// tempMiddleware = { customModule: { a: { b: { } } } }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
app.middlewares = middlewares;
|
|
66
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
/**
|
|
5
|
+
* router-schema loader
|
|
6
|
+
* @param {object} app koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 通过 'json-schema & ajv' 对 API 规则进行约束,配合 api-params-verify 中间件使用
|
|
9
|
+
*
|
|
10
|
+
* app/routerSchema/**.js
|
|
11
|
+
*
|
|
12
|
+
* 输出:
|
|
13
|
+
* app.rouShcema = {
|
|
14
|
+
* `${api1}: ${jsonSchema}`,
|
|
15
|
+
* `${api2}: ${jsonSchema}`,
|
|
16
|
+
* `${api3}: ${jsonSchema}`,
|
|
17
|
+
* `${api4}: ${jsonSchema}`,
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
module.exports = (app) => {
|
|
22
|
+
// 01、读取 elpis/app/router-schema/**/**.js 下的所有文件(当前框架)
|
|
23
|
+
const elpisRouterSchemaPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}router-schema`);
|
|
24
|
+
const elpisFileList = glob.sync(path.resolve(elpisRouterSchemaPath, `.${sep}**${sep}**.js`));
|
|
25
|
+
|
|
26
|
+
// 02、读取业务根目录 app/router-schema/**/**.js 下的所有文件(客户业务项目)
|
|
27
|
+
const businessRouterSchemaPath = path.resolve(app.businessPath, `.${sep}router-schema`);
|
|
28
|
+
const businessFileList = glob.sync(
|
|
29
|
+
path.resolve(businessRouterSchemaPath, `.${sep}**${sep}**.js`)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// 03、注册所有 routerSchema,使得可以 'app.routerSchema' 这样访问
|
|
33
|
+
let routerSchema = {};
|
|
34
|
+
elpisFileList.forEach((file) => {
|
|
35
|
+
handleFile(file);
|
|
36
|
+
});
|
|
37
|
+
businessFileList.forEach((file) => {
|
|
38
|
+
handleFile(file);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function handleFile(file) {
|
|
42
|
+
routerSchema = {
|
|
43
|
+
...routerSchema,
|
|
44
|
+
...require(path.resolve(file)),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
app.routerSchema = routerSchema;
|
|
49
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const KoaRouter = require('koa-router');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
const glob = require('glob');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* router loader
|
|
8
|
+
* @param {object} app Koa 实例
|
|
9
|
+
*
|
|
10
|
+
* 解析所有 app/router/ 下的所有 js 文件,加载到 KoaRouter 下
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
module.exports = (app) => {
|
|
14
|
+
// 01、实例化 KoaRouter
|
|
15
|
+
const router = new KoaRouter();
|
|
16
|
+
|
|
17
|
+
// 02、elips 路由
|
|
18
|
+
const elipsRouterPath = path.resolve(__dirname, `..${sep}..${sep}app${sep}router`);
|
|
19
|
+
const elipsFileList = glob.sync(path.resolve(elipsRouterPath, `.${sep}**${sep}**.js`));
|
|
20
|
+
|
|
21
|
+
// 03、业务路由
|
|
22
|
+
const businessRouterPath = path.resolve(app.businessPath, `.${sep}router`);
|
|
23
|
+
const businessFileList = glob.sync(path.resolve(businessRouterPath, `.${sep}**${sep}**.js`));
|
|
24
|
+
|
|
25
|
+
// 04、注册所有路由
|
|
26
|
+
elipsFileList.forEach((file) => {
|
|
27
|
+
handleFile(file);
|
|
28
|
+
});
|
|
29
|
+
businessFileList.forEach((file) => {
|
|
30
|
+
handleFile(file);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function handleFile(file) {
|
|
34
|
+
// router 文件的写法
|
|
35
|
+
// module.exports = (app, router) => {
|
|
36
|
+
// router.get('url', Function)
|
|
37
|
+
// }
|
|
38
|
+
require(path.resolve(file))(app, router);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 05、路由兜底(健壮性)
|
|
42
|
+
router.get('*', async (ctx, next) => {
|
|
43
|
+
ctx.status = 302; // 临时重定向
|
|
44
|
+
ctx.redirect(`${app?.options?.homePage ?? '/'}`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 06、路由注册到 app实例上
|
|
48
|
+
app.use(router.routes());
|
|
49
|
+
app.use(router.allowedMethods());
|
|
50
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
/**
|
|
5
|
+
* service loader
|
|
6
|
+
* @param {object} app Koa 实例
|
|
7
|
+
*
|
|
8
|
+
* 加载使用 service,可通过 'app.service.${目录}.${文件}' 访问
|
|
9
|
+
*
|
|
10
|
+
* 例子:
|
|
11
|
+
* app/service
|
|
12
|
+
* |
|
|
13
|
+
* |—— custom-module
|
|
14
|
+
* |—— custom-service.js
|
|
15
|
+
*
|
|
16
|
+
* => app.service.customModule.customService (通过这个loader可以实现这个方式去访问上面目录中的文件)
|
|
17
|
+
* */
|
|
18
|
+
module.exports = (app) => {
|
|
19
|
+
// 01、读取 elips/app/service/**/**.js 下的所有文件(当前框架)
|
|
20
|
+
const elipsServicePath = path.resolve(__dirname, `..${sep}..${sep}app${sep}service`);
|
|
21
|
+
const elipsFileList = glob.sync(path.resolve(elipsServicePath, `.${sep}**${sep}**.js`));
|
|
22
|
+
|
|
23
|
+
// 02、读取业务根目录 app/service/**/**.js 下的所有文件(客户业务项目)
|
|
24
|
+
const businessServicePath = path.resolve(app.businessPath, `.${sep}service`);
|
|
25
|
+
const businessFileList = glob.sync(path.resolve(businessServicePath, `.${sep}**${sep}**.js`));
|
|
26
|
+
|
|
27
|
+
// 03、遍历所有文件目录,把内容加载到 app.service 下
|
|
28
|
+
const service = {};
|
|
29
|
+
elipsFileList.forEach((file) => {
|
|
30
|
+
handleFile(file);
|
|
31
|
+
});
|
|
32
|
+
businessFileList.forEach((file) => {
|
|
33
|
+
handleFile(file);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function handleFile(file) {
|
|
37
|
+
// 提取文件名称
|
|
38
|
+
let name = path.resolve(file); // 将文件名拼接到文件路径上
|
|
39
|
+
// 截取路径 app/service/custom-module/custom-service.js => custom-module/custom-service
|
|
40
|
+
name = name.slice(
|
|
41
|
+
name.lastIndexOf(`service${sep}`) + `service${sep}`.length,
|
|
42
|
+
name.lastIndexOf('.')
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// 04、把 '-' 统一改为驼峰式,custom-module/custom-service => customModule/customService
|
|
46
|
+
name = name.replace(/[_-][a-z]/gi, (s) => s.slice(1).toUpperCase());
|
|
47
|
+
|
|
48
|
+
// 05、挂载 service 到内存 app 对象中
|
|
49
|
+
let tempService = service;
|
|
50
|
+
const names = name.split(sep); // => [ customModule(目录), customService(文件) ]
|
|
51
|
+
for (let i = 0, len = names.length; i < len; ++i) {
|
|
52
|
+
if (i === len - 1) {
|
|
53
|
+
// 文件
|
|
54
|
+
const ServiceMoule = require(path.resolve(file))(app); // 导入文件并且传入 app 实例
|
|
55
|
+
tempService[names[i]] = new ServiceMoule();
|
|
56
|
+
} else {
|
|
57
|
+
// 目录
|
|
58
|
+
if (!tempService[names[i]]) {
|
|
59
|
+
tempService[names[i]] = {};
|
|
60
|
+
}
|
|
61
|
+
tempService = tempService[names[i]];
|
|
62
|
+
// tempService === {}
|
|
63
|
+
// tempService = { customModule: { a: { b: { } } } }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
app.service = service;
|
|
69
|
+
};
|
package/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const consoler = require('consoler');
|
|
2
|
+
const ElpisCore = require('./elpis-core/index');
|
|
3
|
+
|
|
4
|
+
// 引入前端工程化构建方法
|
|
5
|
+
const FEBuildDev = require('./app/webpack/dev');
|
|
6
|
+
const FEBuildProd = require('./app/webpack/prod');
|
|
7
|
+
|
|
8
|
+
// 启动 koa 服务
|
|
9
|
+
// ElpisCore.start({ name: 'Elpis', homePage: '/view/project-list' });
|
|
10
|
+
|
|
11
|
+
// 导出 SKD 入口给外部使用
|
|
12
|
+
module.exports = {
|
|
13
|
+
/**
|
|
14
|
+
* 服务端基础
|
|
15
|
+
* */
|
|
16
|
+
Controller: {
|
|
17
|
+
Base: require('./app/controller/base.js'),
|
|
18
|
+
},
|
|
19
|
+
Service: {
|
|
20
|
+
Base: require('./app/service/base.js'),
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* 编译构建前端工程
|
|
24
|
+
* @param env 环境变量 local/production
|
|
25
|
+
*/
|
|
26
|
+
frontendBuild(env) {
|
|
27
|
+
switch (env) {
|
|
28
|
+
case 'local':
|
|
29
|
+
FEBuildDev();
|
|
30
|
+
break;
|
|
31
|
+
case 'production':
|
|
32
|
+
FEBuildProd();
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
consoler.log('请传入正确的环境变量值 local/production');
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* 启动 elpis
|
|
41
|
+
* @param options 项目配置,透传到 elpis-core
|
|
42
|
+
*/
|
|
43
|
+
serverStart(options = {}) {
|
|
44
|
+
const app = ElpisCore.start(options);
|
|
45
|
+
return app;
|
|
46
|
+
},
|
|
47
|
+
};
|
package/jsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"target": "ES2017",
|
|
5
|
+
"checkJs": false,
|
|
6
|
+
"lib": ["ES2017", "dom"],
|
|
7
|
+
"types": ["node", "koa"],
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"baseUrl": ".",
|
|
10
|
+
"paths": {
|
|
11
|
+
"$elpisPages/*": ["app/pages/*"],
|
|
12
|
+
"$elpisCommon/*": ["app/pages/common/*"],
|
|
13
|
+
"$elpisWidgets/*": ["app/pages/widgets/*"],
|
|
14
|
+
"$elpisStore/*": ["app/pages/store/*"]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"include": ["**/*.js", "**/*.vue"],
|
|
18
|
+
"exclude": ["node_modules"]
|
|
19
|
+
}
|
package/model/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
const glob = require('glob');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { sep } = path;
|
|
4
|
+
const _ = require('lodash');
|
|
5
|
+
|
|
6
|
+
// project 继承 model 方法
|
|
7
|
+
const projectExtentModel = (model, project) => {
|
|
8
|
+
return _.mergeWith({}, model, project, (modelValue, projValue) => {
|
|
9
|
+
// 处理数组合并的特殊情况
|
|
10
|
+
if (Array.isArray(modelValue) && Array.isArray(projValue)) {
|
|
11
|
+
let result = [];
|
|
12
|
+
|
|
13
|
+
// 因为 project 继承 model,所以需要处理修改和新增内容的情况
|
|
14
|
+
// project 有的键值,model也有 => 修改(重载)
|
|
15
|
+
// project 有的键值,model没有 => 新增(扩展)
|
|
16
|
+
// model 有的键值,project没有 => 保留(继承)
|
|
17
|
+
|
|
18
|
+
// 处理修改和保留
|
|
19
|
+
for (let i = 0; i < modelValue.length; i++) {
|
|
20
|
+
let modelItem = modelValue[i];
|
|
21
|
+
const projItem = projValue.find((projItem) => projItem.key === modelItem.key);
|
|
22
|
+
// project 有的键值,model也有,则递归调用 projectExtentModel 方法覆盖修改
|
|
23
|
+
result.push(projItem ? projectExtentModel(modelItem, projItem) : modelItem);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 处理新增
|
|
27
|
+
for (let i = 0; i < projValue.length; i++) {
|
|
28
|
+
const projItem = projValue[i];
|
|
29
|
+
const modelItem = modelValue.find((modelItem) => modelItem.key === projItem.key);
|
|
30
|
+
if (!modelItem) {
|
|
31
|
+
result.push(projItem);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 解析 model 配置,并返回组织且继承后的数据结构
|
|
42
|
+
* [{
|
|
43
|
+
* model: ${model},
|
|
44
|
+
* project: {
|
|
45
|
+
* proj1Key: ${proj1},
|
|
46
|
+
* proj2Key: ${proj2},
|
|
47
|
+
* }
|
|
48
|
+
* }, ...]
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
module.exports = (app) => {
|
|
52
|
+
const modelList = [];
|
|
53
|
+
|
|
54
|
+
// 01.遍历当前文件夹,构造模型数据结构,挂载到 modelList 上
|
|
55
|
+
const modelPath = path.resolve(app.baseDir, `.${sep}model`);
|
|
56
|
+
const fileList = glob.sync(path.resolve(modelPath, `.${sep}**${sep}**.js`)); // 获取model文件下的所有文件路径
|
|
57
|
+
fileList.forEach((file) => {
|
|
58
|
+
if (file.indexOf('index.js') > -1) return; // 排出当前解析文件
|
|
59
|
+
|
|
60
|
+
// 02.区分配置类型 (model / project)
|
|
61
|
+
const type = file.indexOf(`${sep}project${sep}`) > -1 ? 'project' : 'model';
|
|
62
|
+
|
|
63
|
+
if (type === 'project') {
|
|
64
|
+
const modelKey = file.match(/\/model\/(.*?)\/project/)?.[1];
|
|
65
|
+
const projKey = file.match(/\/project\/(.*?)\.js/)?.[1];
|
|
66
|
+
let modelItem = modelList.find((item) => item.model?.key === modelKey);
|
|
67
|
+
if (!modelItem) {
|
|
68
|
+
// 初始化 model 数据结构
|
|
69
|
+
modelItem = {};
|
|
70
|
+
modelList.push(modelItem);
|
|
71
|
+
}
|
|
72
|
+
if (!modelItem.project) {
|
|
73
|
+
// 初始化 project 数据结构
|
|
74
|
+
modelItem.project = {};
|
|
75
|
+
}
|
|
76
|
+
modelItem.project[projKey] = require(path.resolve(file));
|
|
77
|
+
modelItem.project[projKey].key = projKey; // 注入 projectKey
|
|
78
|
+
modelItem.project[projKey].modelKey = modelKey; // 注入 modelKey
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (type === 'model') {
|
|
82
|
+
const modelKey = file.match(/\/model\/(.*?)\/model\.js/)?.[1];
|
|
83
|
+
let modelItem = modelList.find((item) => item.model?.key === modelKey);
|
|
84
|
+
if (!modelItem) {
|
|
85
|
+
// 初始化 model 数据结构
|
|
86
|
+
modelItem = {};
|
|
87
|
+
modelList.push(modelItem);
|
|
88
|
+
}
|
|
89
|
+
modelItem.model = require(path.resolve(file));
|
|
90
|
+
modelItem.model.key = modelKey; // 注入 modelKey
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 数据进一步整理,project => 继承 model
|
|
95
|
+
modelList.forEach((item) => {
|
|
96
|
+
const { model, project } = item;
|
|
97
|
+
for (const key in project) {
|
|
98
|
+
project[key] = projectExtentModel(model, project[key]);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return modelList;
|
|
103
|
+
};
|