@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.
- package/.eslintignore +2 -0
- package/.eslintrc +52 -0
- package/.idea/codeStyles/Project.xml +14 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/elpis.iml +12 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/vcs.xml +6 -0
- package/README.md +232 -0
- package/app/controller/base.js +42 -0
- package/app/controller/project.js +76 -0
- package/app/controller/view.js +19 -0
- package/app/extend/logger.js +42 -0
- package/app/middleware/api-params-verify.js +81 -0
- package/app/middleware/api-sign-verify.js +45 -0
- package/app/middleware/error-handler.js +41 -0
- package/app/middleware/project-handler.js +30 -0
- package/app/middleware.js +42 -0
- package/app/pages/assets/custom.css +14 -0
- package/app/pages/boot.js +51 -0
- package/app/pages/common/curl.js +91 -0
- package/app/pages/common/utils.js +7 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +18 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +154 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +46 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +127 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +104 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +129 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +137 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu.vue +21 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +141 -0
- package/app/pages/dashboard/dashboard.vue +96 -0
- package/app/pages/dashboard/entry.dashboard.js +53 -0
- package/app/pages/dashboard/todo/todo.vue +6 -0
- package/app/pages/store/index.js +5 -0
- package/app/pages/store/menu.js +73 -0
- package/app/pages/store/project.js +15 -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 +106 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +135 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +119 -0
- package/app/pages/widgets/schema-form/form-item-config.js +20 -0
- package/app/pages/widgets/schema-form/schema-form.vue +145 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +52 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +42 -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 +129 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +24 -0
- package/app/pages/widgets/schema-table/schema-table.vue +212 -0
- package/app/pages/widgets/sider-container/sider-container.vue +26 -0
- package/app/public/output/entry.page1.tpl +55 -0
- package/app/public/output/entry.page2.tpl +11 -0
- package/app/public/static/favicon.ico +0 -0
- package/app/public/static/normalize.css +267 -0
- package/app/router/project.js +14 -0
- package/app/router/view.js +9 -0
- package/app/router-schema/project.js +32 -0
- package/app/service/base.js +15 -0
- package/app/service/project.js +48 -0
- package/app/view/entry.tpl +22 -0
- package/app/webpack/build-dev.js +64 -0
- package/app/webpack/build-prod.js +29 -0
- package/app/webpack/config/webpack.base.js +352 -0
- package/app/webpack/config/webpack.dev.js +59 -0
- package/app/webpack/config/webpack.prod.js +145 -0
- package/app/webpack/libs/blank.js +1 -0
- package/config/config.default.js +4 -0
- package/elpis-core/env.js +20 -0
- package/elpis-core/index.js +106 -0
- package/elpis-core/loader/config.js +62 -0
- package/elpis-core/loader/controller.js +79 -0
- package/elpis-core/loader/extend.js +67 -0
- package/elpis-core/loader/middleware.js +77 -0
- package/elpis-core/loader/router-schema.js +57 -0
- package/elpis-core/loader/router.js +57 -0
- package/elpis-core/loader/service.js +76 -0
- package/index.js +39 -0
- package/model/index.js +128 -0
- package/package.json +90 -0
- package/test/controller/project.test.js +243 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时异常错误处理,兜底所有异常
|
|
3
|
+
* @param {*} app
|
|
4
|
+
*/
|
|
5
|
+
module.exports = (app) => {
|
|
6
|
+
// 中间件通过app.use挂载,app.use需要传入一个函数,所以中间件需要返回一个函数
|
|
7
|
+
// 函数参数一个是ctx上下文。一个next函数,代表向下一个中间件传递
|
|
8
|
+
return async (ctx, next) => {
|
|
9
|
+
try {
|
|
10
|
+
await next();
|
|
11
|
+
} catch (error) {
|
|
12
|
+
// 异常处理
|
|
13
|
+
const { status, message, detail } = error;
|
|
14
|
+
app.logger.info(JSON.stringify(error));
|
|
15
|
+
app.logger.error("[-- exception --]:", error);
|
|
16
|
+
app.logger.error("[-- exception --]:", status, message, detail);
|
|
17
|
+
|
|
18
|
+
if (message && message.indexOf("template not found") > -1) {
|
|
19
|
+
// 页面重定向
|
|
20
|
+
// 301: 永久重定向
|
|
21
|
+
// 如果设置为 301,当用户访问到一个目前不存在的页面(page3)时,会重定向到设置的页面。
|
|
22
|
+
// 而且在后面如果用户的客户端没清缓存或服务端没重启的情况下,访问 page3 会一直被重定向到其他页面
|
|
23
|
+
// 但如果这个页面马上上线了且此用户拥有访问此页面的权限,用户访问却还是会重定向到其他页面,这不太现实。
|
|
24
|
+
|
|
25
|
+
// 302: 临时重定向
|
|
26
|
+
ctx.status = 302;
|
|
27
|
+
ctx.redirect(`${app.options?.homePage}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const resBody = {
|
|
32
|
+
success: false,
|
|
33
|
+
code: 50000,
|
|
34
|
+
message: "网络异常 请稍候重试",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
ctx.status = 200; // 逻辑异常,但 http 状态正常
|
|
38
|
+
ctx.body = resBody;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* projectHandler 处理项目相关内容
|
|
3
|
+
* @param {*} app
|
|
4
|
+
*/
|
|
5
|
+
module.exports = (app) => {
|
|
6
|
+
return async (ctx, next) => {
|
|
7
|
+
// 只对业务API进行 proj_key 处理
|
|
8
|
+
if (ctx.path.indexOf("/api/proj/") < 0) {
|
|
9
|
+
return await next();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 获取 proj_key
|
|
13
|
+
const { proj_key: projKey } = ctx.request.headers;
|
|
14
|
+
|
|
15
|
+
if (!projKey) {
|
|
16
|
+
ctx.status = 200;
|
|
17
|
+
ctx.body = {
|
|
18
|
+
success: false,
|
|
19
|
+
message: "proj_key not found",
|
|
20
|
+
code: 446,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ctx.projKey = projKey;
|
|
27
|
+
|
|
28
|
+
await next();
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { sep } = path;
|
|
3
|
+
|
|
4
|
+
module.exports = (app) => {
|
|
5
|
+
// 配置静态根目录
|
|
6
|
+
const KoaStatic = require("koa-static");
|
|
7
|
+
app.use(KoaStatic(path.join(process.cwd(), `.${sep}app${sep}public`)));
|
|
8
|
+
|
|
9
|
+
// 模版渲染引擎
|
|
10
|
+
const koaNunjucks = require("koa-nunjucks-2");
|
|
11
|
+
app.use(
|
|
12
|
+
koaNunjucks({
|
|
13
|
+
ext: "tpl", // 不渲染html,以tpl作为文件结尾
|
|
14
|
+
path: path.join(process.cwd(), `.${sep}app${sep}public`),
|
|
15
|
+
nunjucksConfig: {
|
|
16
|
+
noCache: true,
|
|
17
|
+
trimBlocks: true, // 去掉多余行
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// 引入 ctx.body 解析中间件 解析请求参数
|
|
23
|
+
const bodyParser = require("koa-bodyparser");
|
|
24
|
+
app.use(
|
|
25
|
+
bodyParser({
|
|
26
|
+
formLimit: "1000mb",
|
|
27
|
+
enableTypes: ["form", "json", "text"],
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// 引入异常处理中间件
|
|
32
|
+
app.use(app.middlewares.errorHandler);
|
|
33
|
+
|
|
34
|
+
// 引入API签名校验中间件
|
|
35
|
+
app.use(app.middlewares.apiSignVerify);
|
|
36
|
+
|
|
37
|
+
// 引入接口参数校验中间件
|
|
38
|
+
app.use(app.middlewares.apiParamsVerify);
|
|
39
|
+
|
|
40
|
+
// 引入项目处理中间件
|
|
41
|
+
app.use(app.middlewares.projectHandler);
|
|
42
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// 入口启动文件
|
|
2
|
+
import { createApp } from "vue";
|
|
3
|
+
|
|
4
|
+
import "./assets/custom.css";
|
|
5
|
+
|
|
6
|
+
import ElementUI from "element-plus";
|
|
7
|
+
import "element-plus/theme-chalk/index.css";
|
|
8
|
+
|
|
9
|
+
import pinia from "$elpisStore";
|
|
10
|
+
|
|
11
|
+
import { createRouter, createWebHistory } from "vue-router";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* vue 页面主入口,用于启动 Vue
|
|
15
|
+
* @param pageComponent vue 入口组件
|
|
16
|
+
* @param routes 路由列表
|
|
17
|
+
* @param libs 页面独有的第三方依赖
|
|
18
|
+
*/
|
|
19
|
+
export default (pageComponent, { routes, libs } = {}) => {
|
|
20
|
+
const app = createApp(pageComponent);
|
|
21
|
+
|
|
22
|
+
// 引入element-plus组件
|
|
23
|
+
app.use(ElementUI);
|
|
24
|
+
|
|
25
|
+
// 引入状态管理
|
|
26
|
+
app.use(pinia);
|
|
27
|
+
|
|
28
|
+
// 引入第三方包
|
|
29
|
+
if (libs && libs?.length) {
|
|
30
|
+
for (let i = 0; i < libs?.length; ++i) {
|
|
31
|
+
app.use(libs[i]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 引入路由
|
|
36
|
+
if (routes && routes?.length) {
|
|
37
|
+
const router = createRouter({
|
|
38
|
+
history: createWebHistory(), // 采用 history 模式
|
|
39
|
+
routes,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
app.use(router);
|
|
43
|
+
|
|
44
|
+
router.isReady().then(() => {
|
|
45
|
+
// 挂载根节点
|
|
46
|
+
app.mount("#root");
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
app.mount("#root");
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const md5 = require("md5");
|
|
2
|
+
import { ElMessage } from "element-plus";
|
|
3
|
+
import Axios from "axios";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 前端封装的 curl 方法
|
|
7
|
+
* @param {*} param options 请求参数
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
const curl = ({
|
|
11
|
+
url, //请求地址
|
|
12
|
+
method = "post", // 请求方法
|
|
13
|
+
headers = {}, // 请求头
|
|
14
|
+
query = {}, // url query
|
|
15
|
+
data = {}, // post body
|
|
16
|
+
responseType = "json", // response data type
|
|
17
|
+
timeout = 60000, // 超时时长
|
|
18
|
+
errorMessage = "网络异常",
|
|
19
|
+
}) => {
|
|
20
|
+
// 接口签名处理
|
|
21
|
+
const signKey = "ajflskjflaskdjfqoiwefjlaskdjflka";
|
|
22
|
+
const st = Date.now();
|
|
23
|
+
|
|
24
|
+
const dtoHeaders = {
|
|
25
|
+
...headers,
|
|
26
|
+
s_t: st,
|
|
27
|
+
s_sign: md5(`${signKey}_${st}`),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (url.indexOf("/api/proj/") > -1 && window.projKey) {
|
|
31
|
+
dtoHeaders.proj_key = window.projKey;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 构造请求参数 (把参数转换为 axios 参数)
|
|
35
|
+
const axiosParams = {
|
|
36
|
+
url,
|
|
37
|
+
method,
|
|
38
|
+
params: query,
|
|
39
|
+
data,
|
|
40
|
+
responseType,
|
|
41
|
+
timeout,
|
|
42
|
+
headers: dtoHeaders,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return Axios.request(axiosParams)
|
|
46
|
+
.then((response) => {
|
|
47
|
+
const resData = response.data || {};
|
|
48
|
+
|
|
49
|
+
// 后端 API 返回格式
|
|
50
|
+
const { success } = resData;
|
|
51
|
+
|
|
52
|
+
// 失败情况
|
|
53
|
+
if (!success) {
|
|
54
|
+
const { message, code } = resData;
|
|
55
|
+
|
|
56
|
+
if (code === 442) {
|
|
57
|
+
ElMessage.error("请求参数错误");
|
|
58
|
+
} else if (code === 445) {
|
|
59
|
+
ElMessage.error("请求不合法");
|
|
60
|
+
} else if (code === 446) {
|
|
61
|
+
ElMessage.error("缺少项目必要参数");
|
|
62
|
+
} else if (code === 50000) {
|
|
63
|
+
ElMessage.error(message);
|
|
64
|
+
} else {
|
|
65
|
+
ElMessage.error(errorMessage);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.error(message);
|
|
69
|
+
|
|
70
|
+
return Promise.resolve({ success, code, message });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 成功情况
|
|
74
|
+
const { data, metadata } = resData;
|
|
75
|
+
return Promise.resolve({ success, data, metadata });
|
|
76
|
+
})
|
|
77
|
+
.catch((error) => {
|
|
78
|
+
const { message } = error;
|
|
79
|
+
|
|
80
|
+
if (message.match(/timeout/)) {
|
|
81
|
+
return Promise.resolve({
|
|
82
|
+
message: "Request Timeout",
|
|
83
|
+
code: 504,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return Promise.resolve(error);
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default curl;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-sub-menu :index="menuItem.key">
|
|
3
|
+
<template #title>{{ menuItem.name }}</template>
|
|
4
|
+
<div v-for="item in menuItem.subMenu" :key="item.key">
|
|
5
|
+
<sub-menu v-if="item.subMenu && item.subMenu.length > 0"> </sub-menu>
|
|
6
|
+
|
|
7
|
+
<el-menu-item v-else :index="item.key">
|
|
8
|
+
{{ item.name }}
|
|
9
|
+
</el-menu-item>
|
|
10
|
+
</div>
|
|
11
|
+
</el-sub-menu>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
const { menuItem } = defineProps(["menuItem"]);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<style lang="less" scoped></style>
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<header-container :title="projName">
|
|
3
|
+
<template #nemu-content>
|
|
4
|
+
<!-- 根据 menu-store 的 menuList 渲染 -->
|
|
5
|
+
<el-menu
|
|
6
|
+
mode="horizontal"
|
|
7
|
+
:default-active="activeKey"
|
|
8
|
+
:ellipsis="false"
|
|
9
|
+
@select="onMenuSelect"
|
|
10
|
+
>
|
|
11
|
+
<template v-for="item in menuStore.menuList">
|
|
12
|
+
<sub-menu
|
|
13
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
14
|
+
:menu-item="item"
|
|
15
|
+
>
|
|
16
|
+
</sub-menu>
|
|
17
|
+
<el-menu-item v-else :index="item.key">{{ item.name }}</el-menu-item>
|
|
18
|
+
</template>
|
|
19
|
+
</el-menu>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<template #setting-content>
|
|
23
|
+
<!-- 根据 project-store 的 projectList 渲染 -->
|
|
24
|
+
<el-dropdown @command="handleProjectCommand">
|
|
25
|
+
<span class="project-list">
|
|
26
|
+
{{ projName }}
|
|
27
|
+
<el-icon
|
|
28
|
+
v-if="projectStore.projectList.length > 1"
|
|
29
|
+
class="el-icon--right"
|
|
30
|
+
>
|
|
31
|
+
<ArrowDown />
|
|
32
|
+
</el-icon>
|
|
33
|
+
</span>
|
|
34
|
+
|
|
35
|
+
<template v-if="projectStore.projectList.length > 1" #dropdown>
|
|
36
|
+
<el-dropdown-menu>
|
|
37
|
+
<el-dropdown-item
|
|
38
|
+
v-for="item in projectStore.projectList"
|
|
39
|
+
:key="item.key"
|
|
40
|
+
:command="item.key"
|
|
41
|
+
:disabled="item.name === projName"
|
|
42
|
+
>
|
|
43
|
+
{{ item.name }}
|
|
44
|
+
</el-dropdown-item>
|
|
45
|
+
</el-dropdown-menu>
|
|
46
|
+
</template>
|
|
47
|
+
</el-dropdown>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<template #main-content>
|
|
51
|
+
<slot name="main-content"></slot>
|
|
52
|
+
</template>
|
|
53
|
+
</header-container>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup>
|
|
57
|
+
import { ref, watch, onMounted } from "vue";
|
|
58
|
+
import { useMenuStore } from "$elpisStore/menu";
|
|
59
|
+
import { useProjectStore } from "$elpisStore/project";
|
|
60
|
+
import HeaderContainer from "$elpisWidgets/header-container/header-container.vue";
|
|
61
|
+
import SubMenu from "./complex-view/sub-menu/sub-menu.vue";
|
|
62
|
+
import { ArrowDown } from "@element-plus/icons-vue";
|
|
63
|
+
import { useRoute } from "vue-router";
|
|
64
|
+
|
|
65
|
+
const route = useRoute();
|
|
66
|
+
|
|
67
|
+
defineProps({
|
|
68
|
+
projName: String,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const emits = defineEmits(["menu-select"]);
|
|
72
|
+
|
|
73
|
+
const menuStore = useMenuStore();
|
|
74
|
+
const projectStore = useProjectStore();
|
|
75
|
+
|
|
76
|
+
const activeKey = ref("");
|
|
77
|
+
|
|
78
|
+
watch(
|
|
79
|
+
() => route.query.key,
|
|
80
|
+
(val) => {
|
|
81
|
+
setActiveKey();
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
watch(
|
|
86
|
+
() => menuStore.menuList,
|
|
87
|
+
() => {
|
|
88
|
+
setActiveKey();
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
deep: true,
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
onMounted(() => {
|
|
96
|
+
setActiveKey();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 添加寻找步骤、考虑权限问题
|
|
101
|
+
* 判断用户传入的 key 是否在 menuList 中
|
|
102
|
+
* 而不是直接赋值给 activeKey
|
|
103
|
+
*/
|
|
104
|
+
const setActiveKey = function () {
|
|
105
|
+
const menuItem = menuStore.findMenuItem({
|
|
106
|
+
key: "key",
|
|
107
|
+
value: route.query.key,
|
|
108
|
+
});
|
|
109
|
+
activeKey.value = menuItem?.key;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 菜单 select 事件
|
|
114
|
+
* @param menuKey
|
|
115
|
+
*/
|
|
116
|
+
const onMenuSelect = (menuKey) => {
|
|
117
|
+
const menuItem = menuStore.findMenuItem({
|
|
118
|
+
key: "key",
|
|
119
|
+
value: menuKey,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
emits("menu-select", menuItem);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const handleProjectCommand = (event) => {
|
|
126
|
+
const projectItem = projectStore.projectList.find(
|
|
127
|
+
(item) => item.key === event,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
if (!projectItem || !projectItem.homePage) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// const { origin, pathname } = window.location;
|
|
135
|
+
// window.location.replace(`${origin}${pathname}#${projectItem.homePage}`);
|
|
136
|
+
// window.location.reload();
|
|
137
|
+
|
|
138
|
+
const { host } = window.location;
|
|
139
|
+
window.location.replace(
|
|
140
|
+
`http://${host}/view/dashboard${projectItem.homePage}`,
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<style lang="less" scoped>
|
|
146
|
+
.project-list {
|
|
147
|
+
margin-right: 20px;
|
|
148
|
+
cursor: pointer;
|
|
149
|
+
color: var(--el-color-primary);
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
outline: none;
|
|
153
|
+
}
|
|
154
|
+
</style>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<iframe :src="path" class="iframe" frameborder="0"></iframe>
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { onMounted, ref, watch } from "vue";
|
|
7
|
+
import { useRoute } from "vue-router";
|
|
8
|
+
import { useMenuStore } from "$elpisStore/menu.js";
|
|
9
|
+
|
|
10
|
+
const route = useRoute();
|
|
11
|
+
const menuStore = useMenuStore();
|
|
12
|
+
|
|
13
|
+
const path = ref("");
|
|
14
|
+
|
|
15
|
+
watch(
|
|
16
|
+
[
|
|
17
|
+
() => route.query.key,
|
|
18
|
+
() => route.query.sider_key,
|
|
19
|
+
() => menuStore.menuList,
|
|
20
|
+
],
|
|
21
|
+
() => setPath(),
|
|
22
|
+
{
|
|
23
|
+
deep: true,
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
onMounted(() => setPath());
|
|
28
|
+
|
|
29
|
+
const setPath = function () {
|
|
30
|
+
const { key, sider_key: siderKey } = route.query;
|
|
31
|
+
const menuItem = menuStore.findMenuItem({
|
|
32
|
+
key: "key",
|
|
33
|
+
value: siderKey ?? key,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
path.value = menuItem?.iframeConfig?.path ?? "";
|
|
37
|
+
};
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<style scoped lang="less">
|
|
41
|
+
.iframe {
|
|
42
|
+
border: 0;
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
45
|
+
}
|
|
46
|
+
</style>
|
package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-card class="search-panel">
|
|
3
|
+
<schema-search-bar
|
|
4
|
+
:schema="searchSchema"
|
|
5
|
+
@load="onLoad"
|
|
6
|
+
@search="onSearch"
|
|
7
|
+
@reset="onReset"
|
|
8
|
+
></schema-search-bar>
|
|
9
|
+
</el-card>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { inject } from 'vue'
|
|
14
|
+
import SchemaSearchBar from '../../../../../widgets/schema-search-bar/schema-search-bar.vue'
|
|
15
|
+
|
|
16
|
+
const { searchSchema } = inject('schemaViewData')
|
|
17
|
+
|
|
18
|
+
const emits = defineEmits(['search'])
|
|
19
|
+
|
|
20
|
+
const onLoad = (searchValueObj) => {
|
|
21
|
+
emits('search', searchValueObj)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const onSearch = (searchValueObj) => {
|
|
25
|
+
emits('search', searchValueObj)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const onReset = () => {
|
|
29
|
+
emits('search', {})
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<style scoped lang="less">
|
|
34
|
+
.search-panel {
|
|
35
|
+
margin: 10px 10px 0 10px;
|
|
36
|
+
:deep(.el-card__body) {
|
|
37
|
+
padding-bottom: 2px;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</style>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-card class="table-panel">
|
|
3
|
+
<el-row
|
|
4
|
+
v-if="tableConfig?.headerButtons?.length > 0"
|
|
5
|
+
justify="end"
|
|
6
|
+
class="operation-panel"
|
|
7
|
+
>
|
|
8
|
+
<el-button
|
|
9
|
+
v-for="item in tableConfig?.headerButtons"
|
|
10
|
+
v-bind="item"
|
|
11
|
+
@click="operationHander({ btnConfig: item })"
|
|
12
|
+
>
|
|
13
|
+
{{ item.label }}
|
|
14
|
+
</el-button>
|
|
15
|
+
</el-row>
|
|
16
|
+
<schema-table
|
|
17
|
+
ref="schemaTableRef"
|
|
18
|
+
:schema="tableSchema"
|
|
19
|
+
:api="api"
|
|
20
|
+
:apiParams="apiParams"
|
|
21
|
+
:buttons="tableConfig?.rowButtons ?? []"
|
|
22
|
+
@operate="operationHander"
|
|
23
|
+
></schema-table>
|
|
24
|
+
</el-card>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup>
|
|
28
|
+
import { inject, useTemplateRef } from "vue";
|
|
29
|
+
import $curl from "$elpisCommon/curl";
|
|
30
|
+
import { ElMessageBox, ElNotification } from "element-plus";
|
|
31
|
+
import SchemaTable from "../../../../../widgets/schema-table/schema-table.vue";
|
|
32
|
+
|
|
33
|
+
const emits = defineEmits(["operate"]);
|
|
34
|
+
|
|
35
|
+
const { api, apiParams, tableSchema, tableConfig } = inject("schemaViewData");
|
|
36
|
+
|
|
37
|
+
const schemaTableInstance = useTemplateRef("schemaTableRef");
|
|
38
|
+
|
|
39
|
+
const removeData = async ({ btnConfig, rowData }) => {
|
|
40
|
+
const {
|
|
41
|
+
eventOption: { params },
|
|
42
|
+
} = btnConfig;
|
|
43
|
+
|
|
44
|
+
if (!params) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const removeKey = Object.keys(params)[0];
|
|
49
|
+
let removeValue;
|
|
50
|
+
const removeValueList = params[removeKey]?.split("::");
|
|
51
|
+
if (removeValueList[0] === "schema" && removeValueList[1]) {
|
|
52
|
+
removeValue = rowData[removeValueList[1]];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
ElMessageBox.confirm(
|
|
56
|
+
`确认删除${removeKey}为:${removeValue}的数据?`,
|
|
57
|
+
"删除",
|
|
58
|
+
{
|
|
59
|
+
confirmButtonText: "确认",
|
|
60
|
+
cancelButtonText: "取消",
|
|
61
|
+
type: "warning",
|
|
62
|
+
},
|
|
63
|
+
).then(async () => {
|
|
64
|
+
schemaTableInstance.value.showLoading();
|
|
65
|
+
|
|
66
|
+
const res = await $curl({
|
|
67
|
+
method: "delete",
|
|
68
|
+
url: api.value,
|
|
69
|
+
data: {
|
|
70
|
+
[removeKey]: removeValue,
|
|
71
|
+
},
|
|
72
|
+
errorMessage: "删除失败",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
schemaTableInstance.value.hideLoading();
|
|
76
|
+
|
|
77
|
+
if (!res || !res.success || !res.data) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ElNotification({
|
|
82
|
+
title: "删除成功",
|
|
83
|
+
message: "删除成功",
|
|
84
|
+
type: "success",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await initTableData();
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const initTableData = async () => {
|
|
92
|
+
await schemaTableInstance.value.initData();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const loadTableData = async () => {
|
|
96
|
+
await schemaTableInstance.value.loadTableData();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const EventKeyMap = {
|
|
100
|
+
remove: removeData,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const operationHander = ({ btnConfig, rowData }) => {
|
|
104
|
+
const { eventKey } = btnConfig;
|
|
105
|
+
if (EventKeyMap[eventKey]) {
|
|
106
|
+
EventKeyMap[eventKey]({ btnConfig, rowData });
|
|
107
|
+
} else {
|
|
108
|
+
emits("operate", { btnConfig, rowData });
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
defineExpose({
|
|
113
|
+
initTableData,
|
|
114
|
+
loadTableData,
|
|
115
|
+
});
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<style scoped lang="less">
|
|
119
|
+
.table-panel {
|
|
120
|
+
flex: 1;
|
|
121
|
+
margin: 10px;
|
|
122
|
+
|
|
123
|
+
.operation-panel {
|
|
124
|
+
margin-bottom: 10px;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import CreateForm from "./create-form/create-form.vue";
|
|
2
|
+
import EditForm from "./edit-form/edit-form.vue";
|
|
3
|
+
import DetailPanel from "./detail-panel/detail-panel.vue";
|
|
4
|
+
|
|
5
|
+
import BusinessComponentConfig from "$businessComponentConfig";
|
|
6
|
+
|
|
7
|
+
const ComponentConfig = {
|
|
8
|
+
createForm: {
|
|
9
|
+
component: CreateForm,
|
|
10
|
+
},
|
|
11
|
+
editForm: {
|
|
12
|
+
component: EditForm,
|
|
13
|
+
},
|
|
14
|
+
detailPanel: {
|
|
15
|
+
component: DetailPanel,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
...ComponentConfig,
|
|
21
|
+
...BusinessComponentConfig,
|
|
22
|
+
};
|