@isxiaoyuan/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 +3 -0
- package/.eslintrc +52 -0
- package/.vscode/settings.json +8 -0
- package/REMADE.md +228 -0
- package/app/controller/base.js +43 -0
- package/app/controller/project.js +106 -0
- package/app/controller/view.js +21 -0
- package/app/extend/logger.js +36 -0
- package/app/middleware/api-params-verify.js +73 -0
- package/app/middleware/api-sign-verify.js +43 -0
- package/app/middleware/error-handler.js +33 -0
- package/app/middleware/project-handle.js +26 -0
- package/app/middleware.js +41 -0
- package/app/pages/asserts/custom.css +11 -0
- package/app/pages/boot.js +43 -0
- package/app/pages/common/curl.js +88 -0
- package/app/pages/common/utils.js +2 -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 +138 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +51 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +41 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +128 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +20 -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 +98 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +123 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +129 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +98 -0
- package/app/pages/dashboard/complex-view/silder-view/silder-view.vue +127 -0
- package/app/pages/dashboard/dashboard.vue +96 -0
- package/app/pages/dashboard/entry.dashboard.js +48 -0
- package/app/pages/store/index.js +5 -0
- package/app/pages/store/menu.js +70 -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 +102 -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 +136 -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 +136 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +55 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +69 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +45 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +53 -0
- package/app/pages/widgets/schema-search-bar/schema-item-config.js +24 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +115 -0
- package/app/pages/widgets/schema-table/schema-table.vue +255 -0
- package/app/pages/widgets/sider-container/complex-view/sub-menu/sub-menu.vue +18 -0
- package/app/pages/widgets/sider-container/sider-container.vue +29 -0
- package/app/public/dist/entry.dashboard.tpl +27 -0
- package/app/public/dist/entry.page1.tpl +25 -0
- package/app/public/dist/entry.page2.tpl +25 -0
- package/app/public/dist/entry.project-list.tpl +27 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +12 -0
- package/app/router/view.js +7 -0
- package/app/router-schema/project.js +30 -0
- package/app/service/base.js +13 -0
- package/app/service/project.js +58 -0
- package/app/view/entry.tpl +27 -0
- package/app/webpack/config/webpack.base.js +305 -0
- package/app/webpack/config/webpack.dev.js +62 -0
- package/app/webpack/config/webpack.prod.js +120 -0
- package/app/webpack/dev.js +62 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +22 -0
- package/config/config.beta.js +3 -0
- package/config/config.default.js +3 -0
- package/config/config.prod.js +3 -0
- package/elpis-core/env.js +20 -0
- package/elpis-core/index.js +97 -0
- package/elpis-core/loader/config.js +66 -0
- package/elpis-core/loader/controller.js +86 -0
- package/elpis-core/loader/extend.js +66 -0
- package/elpis-core/loader/middleware.js +74 -0
- package/elpis-core/loader/router-schema.js +56 -0
- package/elpis-core/loader/router.js +49 -0
- package/elpis-core/loader/service.js +82 -0
- package/index.js +42 -0
- package/model/index.js +109 -0
- package/package.json +92 -0
- package/test/controller/project.test.js +188 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
module.exports = (app) => {
|
|
4
|
+
//配置静态跟目录
|
|
5
|
+
const koaStatic = require("koa-static");
|
|
6
|
+
app.use(koaStatic(path.resolve(process.cwd(), "./app/public")));
|
|
7
|
+
//模板渲染引擎 核心作用是让 Koa 能够高效地进行服务端模板渲染(SSR)
|
|
8
|
+
const koaNunjucks = require("koa-nunjucks-2");
|
|
9
|
+
app.use(
|
|
10
|
+
koaNunjucks({
|
|
11
|
+
ext: "tpl", // 模板文件后缀
|
|
12
|
+
// path: path.resolve(app.businessPath, "public"), // 模板文件目录
|
|
13
|
+
path: path.resolve(process.cwd(), "./app/public"), // 模板文件目录
|
|
14
|
+
nunjucksConfig: {
|
|
15
|
+
trimBlocks: true, // 去除模板中的空格
|
|
16
|
+
noCache: true,
|
|
17
|
+
// lstripBlocks: true,
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
//引入 ctx.body 解析中间件
|
|
23
|
+
const bodyParser = require("koa-bodyparser");
|
|
24
|
+
app.use(
|
|
25
|
+
bodyParser({
|
|
26
|
+
formLimit: "1000MB", //请求体大小限制
|
|
27
|
+
enableTypes: ["json", "form", "text"],
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
// 引入运行时异常错误处理中间件
|
|
31
|
+
app.use(app.middlewares.errorHandler);
|
|
32
|
+
|
|
33
|
+
//签名合法性校验
|
|
34
|
+
app.use(app.middlewares.apiSignVerify);
|
|
35
|
+
|
|
36
|
+
//参数校验
|
|
37
|
+
app.use(app.middlewares.apiParamsVerify);
|
|
38
|
+
|
|
39
|
+
// 项目相关处理中间件
|
|
40
|
+
app.use(app.middlewares.projectHandle);
|
|
41
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createApp } from "vue";
|
|
2
|
+
// 引入 element-plus 组件库
|
|
3
|
+
import ElementPlus from "element-plus";
|
|
4
|
+
import "element-plus/dist/index.css";
|
|
5
|
+
import "element-plus/theme-chalk/dark/css-vars.css";
|
|
6
|
+
|
|
7
|
+
import "./asserts/custom.css";
|
|
8
|
+
import pinia from "$elpisStore";
|
|
9
|
+
import { createRouter, createWebHistory } from "vue-router";
|
|
10
|
+
/**
|
|
11
|
+
* vue 页面主入口 初始化vue
|
|
12
|
+
* @params pageComponent vue 入口组件
|
|
13
|
+
*/
|
|
14
|
+
export default (pageComponent, { routes, libs } = {}) => {
|
|
15
|
+
const app = createApp(pageComponent);
|
|
16
|
+
app.use(ElementPlus);
|
|
17
|
+
|
|
18
|
+
app.use(pinia);
|
|
19
|
+
|
|
20
|
+
// 引入第三方包
|
|
21
|
+
if (libs && libs.length > 0) {
|
|
22
|
+
// libs.forEach((lib) => {
|
|
23
|
+
// app.use(lib);
|
|
24
|
+
// });
|
|
25
|
+
for (let i = 0; i < libs.length; i++) {
|
|
26
|
+
app.use(libs[i]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 配置路由
|
|
31
|
+
if (routes && routes.length > 0) {
|
|
32
|
+
const router = createRouter({
|
|
33
|
+
history: createWebHistory(),
|
|
34
|
+
routes,
|
|
35
|
+
});
|
|
36
|
+
app.use(router);
|
|
37
|
+
router.isReady().then(() => {
|
|
38
|
+
app.mount("#root");
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
app.mount("#root");
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
const md5 = require("md5");
|
|
3
|
+
import { ElMessage } from "element-plus";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 前端封装的 curl 方法
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
const curl = ({
|
|
10
|
+
url,
|
|
11
|
+
method = "post",
|
|
12
|
+
headers = {}, //请求头
|
|
13
|
+
query = {}, //查询参数url
|
|
14
|
+
data = {}, //请求体参数body
|
|
15
|
+
responseType = "json", //响应体类型
|
|
16
|
+
timeout = 60000, //超时时间
|
|
17
|
+
errorMessage = "网络异常",
|
|
18
|
+
}) => {
|
|
19
|
+
// 接口签名处理(让接口变动态)
|
|
20
|
+
const signKey = "isyuankkkkkll123kasd2444";
|
|
21
|
+
const st = Date.now();
|
|
22
|
+
const dtoHeaders = {
|
|
23
|
+
...headers,
|
|
24
|
+
s_t: st,
|
|
25
|
+
s_sign: md5(`${signKey}_${st}`),
|
|
26
|
+
}
|
|
27
|
+
if(url.indexOf('/api/proj/') > -1 && window.projKey) {
|
|
28
|
+
dtoHeaders.proj_key = window.projKey;
|
|
29
|
+
}
|
|
30
|
+
// 构造请求参数(把参数转换为 axios 参数)
|
|
31
|
+
const ajaxStting = {
|
|
32
|
+
url,
|
|
33
|
+
method,
|
|
34
|
+
params: query,
|
|
35
|
+
data, //请求体参数body
|
|
36
|
+
responseType, //响应体类型
|
|
37
|
+
timeout, //超时时间
|
|
38
|
+
headers: dtoHeaders,
|
|
39
|
+
};
|
|
40
|
+
return axios
|
|
41
|
+
.request(ajaxStting)
|
|
42
|
+
.then((response) => {
|
|
43
|
+
const resData = response.data || {};
|
|
44
|
+
|
|
45
|
+
//后端api返回格式
|
|
46
|
+
const { success } = resData;
|
|
47
|
+
//失败
|
|
48
|
+
if (!success) {
|
|
49
|
+
const { code, message } = resData;
|
|
50
|
+
if (code === 442) {
|
|
51
|
+
ElMessage.error("请求参数异常");
|
|
52
|
+
} else if (code === 445) {
|
|
53
|
+
ElMessage.error("请求不合法");
|
|
54
|
+
}else if (code === 446) {
|
|
55
|
+
ElMessage.error("缺少项目必要参数");
|
|
56
|
+
} else if (code === 50000) {
|
|
57
|
+
ElMessage.error(message);
|
|
58
|
+
} else {
|
|
59
|
+
ElMessage.error(errorMessage);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return Promise.resolve({
|
|
63
|
+
success,
|
|
64
|
+
message,
|
|
65
|
+
code,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const { data, metadata } = resData;
|
|
69
|
+
|
|
70
|
+
return Promise.resolve({
|
|
71
|
+
success,
|
|
72
|
+
data,
|
|
73
|
+
metadata,
|
|
74
|
+
});
|
|
75
|
+
})
|
|
76
|
+
.catch((error) => {
|
|
77
|
+
const { message } = error;
|
|
78
|
+
if (message.match(/timeout/)) {
|
|
79
|
+
return Promise.resolve({
|
|
80
|
+
message: "Request timeout",
|
|
81
|
+
code: 504,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return Promise.resolve(error);
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default curl;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-sub-menu :index="menuItem.key">
|
|
3
|
+
<template #title>
|
|
4
|
+
{{ menuItem.name }}
|
|
5
|
+
</template>
|
|
6
|
+
<div v-for="item in menuItem.subMenu" :key="item.key">
|
|
7
|
+
<sub-menu
|
|
8
|
+
:menu-item="item"
|
|
9
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
10
|
+
/>
|
|
11
|
+
<el-menu-item v-else :index="item.key">{{ item.name }}</el-menu-item>
|
|
12
|
+
</div>
|
|
13
|
+
</el-sub-menu>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
const { menuItem } = defineProps(["menuItem"]);
|
|
18
|
+
</script>
|
|
19
|
+
<style lang="less" scoped></style>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<header-container :title="projName">
|
|
3
|
+
<template #menu-content>
|
|
4
|
+
<el-menu
|
|
5
|
+
:default-active="activeKey"
|
|
6
|
+
:ellipsis="false"
|
|
7
|
+
mode="horizontal"
|
|
8
|
+
@select="handleSelect"
|
|
9
|
+
>
|
|
10
|
+
<template v-for="item in menuStore.menuList">
|
|
11
|
+
<sub-menu
|
|
12
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
13
|
+
:menu-item="item"
|
|
14
|
+
/>
|
|
15
|
+
<el-menu-item v-else :index="item.key">{{ item.name }}</el-menu-item>
|
|
16
|
+
</template>
|
|
17
|
+
</el-menu>
|
|
18
|
+
</template>
|
|
19
|
+
<template #setting-content>
|
|
20
|
+
<el-dropdown @command="handleProjectCommand">
|
|
21
|
+
<span class="project-list">
|
|
22
|
+
{{ projName }}
|
|
23
|
+
<el-icon
|
|
24
|
+
v-if="projectStore.projectList.length > 1"
|
|
25
|
+
class="el-icon--right"
|
|
26
|
+
>
|
|
27
|
+
<ArrowDown />
|
|
28
|
+
</el-icon>
|
|
29
|
+
</span>
|
|
30
|
+
<template v-if="projectStore.projectList.length > 1" #dropdown>
|
|
31
|
+
<el-dropdown-menu>
|
|
32
|
+
<el-dropdown-item
|
|
33
|
+
v-for="item in projectStore.projectList"
|
|
34
|
+
:key="item.key"
|
|
35
|
+
:command="item.key"
|
|
36
|
+
:disabled="item.name === projName"
|
|
37
|
+
>
|
|
38
|
+
{{ item.name }}
|
|
39
|
+
</el-dropdown-item>
|
|
40
|
+
</el-dropdown-menu>
|
|
41
|
+
</template>
|
|
42
|
+
</el-dropdown>
|
|
43
|
+
</template>
|
|
44
|
+
<template #main-content>
|
|
45
|
+
<slot name="main-content"></slot>
|
|
46
|
+
</template>
|
|
47
|
+
</header-container>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script setup>
|
|
51
|
+
import { ref, watch, onMounted } from "vue";
|
|
52
|
+
import { useRoute } from "vue-router";
|
|
53
|
+
import { ArrowDown } from "@element-plus/icons-vue";
|
|
54
|
+
import HeaderContainer from "$elpisWidgets/header-container/header-container.vue";
|
|
55
|
+
import SubMenu from "./complex-view/sub-menu/sub-menu.vue";
|
|
56
|
+
import { useMenuStore } from "$elpisStore/menu";
|
|
57
|
+
import { useProjectStore } from "$elpisStore/project";
|
|
58
|
+
|
|
59
|
+
const route = useRoute();
|
|
60
|
+
const menuStore = useMenuStore();
|
|
61
|
+
const projectStore = useProjectStore();
|
|
62
|
+
|
|
63
|
+
const emit = defineEmits(["menu-select"]);
|
|
64
|
+
|
|
65
|
+
defineProps({
|
|
66
|
+
projName: {
|
|
67
|
+
type: String,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const activeKey = ref("");
|
|
72
|
+
|
|
73
|
+
const setActiveKey = () => {
|
|
74
|
+
const menuItem = menuStore.findMenuItem({
|
|
75
|
+
key: "key",
|
|
76
|
+
value: route.query.key,
|
|
77
|
+
});
|
|
78
|
+
activeKey.value = menuItem?.key || "";
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const handleSelect = (menuKey) => {
|
|
82
|
+
const menuItem = menuStore.findMenuItem({
|
|
83
|
+
key: "key",
|
|
84
|
+
value: menuKey,
|
|
85
|
+
});
|
|
86
|
+
emit("menu-select", menuItem);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleProjectCommand = (command) => {
|
|
90
|
+
const projectItem = projectStore.projectList.find(
|
|
91
|
+
(item) => item.key === command,
|
|
92
|
+
);
|
|
93
|
+
if (!projectItem || !projectItem.homePage) return;
|
|
94
|
+
// hash 模式
|
|
95
|
+
// const { origin, pathname } = window.location;
|
|
96
|
+
// window.location.replace(`${origin}${pathname}#${projectItem.homePage}`);
|
|
97
|
+
// window.location.reload();
|
|
98
|
+
// history模式
|
|
99
|
+
const { host } = window.location;
|
|
100
|
+
window.location.replace(
|
|
101
|
+
`https://${host}/view/dashboard${projectItem.homePage}`,
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
watch(
|
|
106
|
+
() => route.query.key,
|
|
107
|
+
() => {
|
|
108
|
+
setActiveKey();
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
watch(
|
|
113
|
+
() => menuStore.menuList,
|
|
114
|
+
() => {
|
|
115
|
+
setActiveKey();
|
|
116
|
+
},
|
|
117
|
+
{ deep: true },
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
onMounted(() => {
|
|
121
|
+
setActiveKey();
|
|
122
|
+
});
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<style lang="less" scoped>
|
|
126
|
+
.project-list {
|
|
127
|
+
margin-right: 20px;
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
color: var(--el-color-primary);
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: center;
|
|
132
|
+
outline: none;
|
|
133
|
+
}
|
|
134
|
+
:deep(.el-menu--horizontal.el-menu) {
|
|
135
|
+
border-bottom: 0;
|
|
136
|
+
background-color: transparent;
|
|
137
|
+
}
|
|
138
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<iframe
|
|
3
|
+
:src="path"
|
|
4
|
+
class="iframe"
|
|
5
|
+
sandbox="allow-scripts allow-same-origin allow-forms"
|
|
6
|
+
></iframe>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup>
|
|
10
|
+
import { ref, watch, onMounted } from "vue";
|
|
11
|
+
import { useRoute } from "vue-router";
|
|
12
|
+
import { useMenuStore } from "$elpisStore/menu.js";
|
|
13
|
+
|
|
14
|
+
const route = useRoute();
|
|
15
|
+
const menuStore = useMenuStore();
|
|
16
|
+
|
|
17
|
+
const path = ref("");
|
|
18
|
+
const setPath = () => {
|
|
19
|
+
const { key, sider_key: siderKey } = route.query;
|
|
20
|
+
|
|
21
|
+
const menuItem = menuStore.findMenuItem({
|
|
22
|
+
key: "key",
|
|
23
|
+
value: siderKey ?? key,
|
|
24
|
+
});
|
|
25
|
+
path.value = menuItem?.iframeConfig?.path ?? "";
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
watch(
|
|
29
|
+
[
|
|
30
|
+
() => route.query.sider_key,
|
|
31
|
+
() => route.query.key,
|
|
32
|
+
() => menuStore.menuList,
|
|
33
|
+
],
|
|
34
|
+
() => {
|
|
35
|
+
setPath();
|
|
36
|
+
},
|
|
37
|
+
{ deep: true },
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
onMounted(() => {
|
|
41
|
+
setPath();
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<style scoped lang="less">
|
|
46
|
+
.iframe {
|
|
47
|
+
width: 100%;
|
|
48
|
+
height: 100%;
|
|
49
|
+
border: 0;
|
|
50
|
+
}
|
|
51
|
+
</style>
|
package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-card class="search-panel">
|
|
3
|
+
<schema-search-bar
|
|
4
|
+
ref="SchemaSearchBarRef"
|
|
5
|
+
:schema="searchSchema"
|
|
6
|
+
@load="onLoad"
|
|
7
|
+
@search="onSearch"
|
|
8
|
+
@reset="onReset"
|
|
9
|
+
/>
|
|
10
|
+
</el-card>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup>
|
|
14
|
+
import { inject } from "vue";
|
|
15
|
+
import SchemaSearchBar from "$elpisWidgets/schema-search-bar/schema-search-bar.vue";
|
|
16
|
+
|
|
17
|
+
const { searchSchema } = inject("schemaViewData");
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits(["search"]);
|
|
20
|
+
|
|
21
|
+
const onLoad = (searchValObj) => {
|
|
22
|
+
emit("search", searchValObj);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const onSearch = (searchValObj) => {
|
|
26
|
+
emit("search", searchValObj);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const onReset = () => {
|
|
30
|
+
emit("search", {});
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<style scoped lang="less">
|
|
35
|
+
.search-panel {
|
|
36
|
+
margin: 10px 10px 0 10px;
|
|
37
|
+
}
|
|
38
|
+
:deep(.el-card__body) {
|
|
39
|
+
padding-bottom: 2px;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-card class="table-panel">
|
|
3
|
+
<!-- operation-panel -->
|
|
4
|
+
<el-row
|
|
5
|
+
v-if="tableConfig?.headerButtons?.length > 0"
|
|
6
|
+
justify="end"
|
|
7
|
+
class="operation-panel"
|
|
8
|
+
>
|
|
9
|
+
<el-button
|
|
10
|
+
v-for="item in tableConfig?.headerButtons"
|
|
11
|
+
v-bind="item"
|
|
12
|
+
:key="item.eventKey"
|
|
13
|
+
@click="operationHandle({ btnConfig: item })"
|
|
14
|
+
>
|
|
15
|
+
{{ item.label }}
|
|
16
|
+
</el-button>
|
|
17
|
+
</el-row>
|
|
18
|
+
<!-- schema-table(组件 widget) -->
|
|
19
|
+
<schema-table
|
|
20
|
+
ref="schemaTableRef"
|
|
21
|
+
:schema="tableSchema"
|
|
22
|
+
:api="api"
|
|
23
|
+
:apiParams="apiParams"
|
|
24
|
+
:buttons="tableConfig?.rowButtons ?? []"
|
|
25
|
+
@operate="operationHandle"
|
|
26
|
+
/>
|
|
27
|
+
</el-card>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script setup>
|
|
31
|
+
import { ref, inject } from "vue";
|
|
32
|
+
import { ElMessageBox, ElNotification } from "element-plus";
|
|
33
|
+
import $curl from "$elpisCommon/curl.js";
|
|
34
|
+
import SchemaTable from "$elpisWidgets/schema-table/schema-table.vue";
|
|
35
|
+
|
|
36
|
+
const emit = defineEmits(["operate"]);
|
|
37
|
+
|
|
38
|
+
const { api, tableSchema, tableConfig, apiParams } = inject("schemaViewData");
|
|
39
|
+
|
|
40
|
+
const schemaTableRef = ref(null);
|
|
41
|
+
|
|
42
|
+
const removeData = ({ btnConfig, rowData }) => {
|
|
43
|
+
const { eventOption } = btnConfig;
|
|
44
|
+
|
|
45
|
+
if (!eventOption?.params) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { params } = eventOption;
|
|
50
|
+
|
|
51
|
+
const removeKey = Object.keys(params)[0];
|
|
52
|
+
let removeValue;
|
|
53
|
+
const removeValueList = params[removeKey].split("::");
|
|
54
|
+
if (removeValueList[0] === "schema" && removeValueList[1]) {
|
|
55
|
+
removeValue = rowData[removeValueList[1]];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
ElMessageBox.confirm(`确认删除${removeKey}为: ${removeValue}数据?`, "", {
|
|
59
|
+
confirmButtonText: "确定",
|
|
60
|
+
cancelButtonText: "取消",
|
|
61
|
+
type: "warning",
|
|
62
|
+
})
|
|
63
|
+
.then(async () => {
|
|
64
|
+
schemaTableRef.value?.showLoading();
|
|
65
|
+
try {
|
|
66
|
+
await $curl({
|
|
67
|
+
url: api.value,
|
|
68
|
+
method: "delete",
|
|
69
|
+
data: {
|
|
70
|
+
[removeKey]: removeValue,
|
|
71
|
+
},
|
|
72
|
+
errorMessage: "删除失败",
|
|
73
|
+
});
|
|
74
|
+
schemaTableRef.value?.hideLoading();
|
|
75
|
+
ElNotification.success({
|
|
76
|
+
title: "删除成功",
|
|
77
|
+
message: `删除了 ${removeKey}为: ${removeValue}数据`,
|
|
78
|
+
type: "success",
|
|
79
|
+
});
|
|
80
|
+
await initData();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
schemaTableRef.value?.hideLoading();
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
.catch(() => {});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const EventHandleMap = {
|
|
89
|
+
remove: removeData,
|
|
90
|
+
};
|
|
91
|
+
// 点击事件处理
|
|
92
|
+
const operationHandle = ({ btnConfig, rowData }) => {
|
|
93
|
+
const { eventKey } = btnConfig;
|
|
94
|
+
if (EventHandleMap[eventKey]) {
|
|
95
|
+
EventHandleMap[eventKey]({ btnConfig, rowData });
|
|
96
|
+
} else {
|
|
97
|
+
emit("operate", { btnConfig, rowData });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const initData = async () => {
|
|
102
|
+
await schemaTableRef.value?.initData();
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const loadTableData = async () => {
|
|
106
|
+
await schemaTableRef.value?.loadTableData();
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
defineExpose({
|
|
110
|
+
loadTableData,
|
|
111
|
+
});
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<style scoped lang="less">
|
|
115
|
+
.table-panel {
|
|
116
|
+
flex: 1;
|
|
117
|
+
margin: 10px;
|
|
118
|
+
.operation-panel {
|
|
119
|
+
margin-bottom: 10px;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
:deep(.el-card__body) {
|
|
124
|
+
height: 98%;
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
// 业务扩展 component 配置
|
|
6
|
+
import BusinessComponentConfig from "$businessComponentConfig";
|
|
7
|
+
|
|
8
|
+
const ComponentConfig = {
|
|
9
|
+
createForm: {
|
|
10
|
+
component: createForm,
|
|
11
|
+
},
|
|
12
|
+
editForm: {
|
|
13
|
+
component: editForm,
|
|
14
|
+
},
|
|
15
|
+
detailPanel: {
|
|
16
|
+
component: detailPanel,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default { ...ComponentConfig, ...BusinessComponentConfig };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-drawer
|
|
3
|
+
v-model="isShow"
|
|
4
|
+
direction="rtl"
|
|
5
|
+
:destroy-on-close="true"
|
|
6
|
+
:size="550"
|
|
7
|
+
>
|
|
8
|
+
<template #header>
|
|
9
|
+
<h3 class="title">{{ title }}</h3>
|
|
10
|
+
</template>
|
|
11
|
+
<template #default>
|
|
12
|
+
<schema-form
|
|
13
|
+
v-loading="loading"
|
|
14
|
+
ref="schemaFormRef"
|
|
15
|
+
:schema="components[name]?.schema"
|
|
16
|
+
/>
|
|
17
|
+
</template>
|
|
18
|
+
<template #footer>
|
|
19
|
+
<el-button type="primary" @click="save">{{ saveBtnText }}</el-button>
|
|
20
|
+
</template>
|
|
21
|
+
</el-drawer>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref, inject } from "vue";
|
|
26
|
+
import { ElNotification } from "element-plus";
|
|
27
|
+
import $curl from "$elpisCommon/curl.js";
|
|
28
|
+
import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";
|
|
29
|
+
|
|
30
|
+
const { api, components } = inject("schemaViewData");
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits(["command"]);
|
|
33
|
+
|
|
34
|
+
const name = ref("createForm");
|
|
35
|
+
// const { components } = inject("schemaViewData");
|
|
36
|
+
|
|
37
|
+
const schemaFormRef = ref(null);
|
|
38
|
+
const isShow = ref(false);
|
|
39
|
+
const loading = ref(false);
|
|
40
|
+
const title = ref("");
|
|
41
|
+
const saveBtnText = ref("");
|
|
42
|
+
|
|
43
|
+
const show = (rowData) => {
|
|
44
|
+
const { config } = components.value[name.value];
|
|
45
|
+
|
|
46
|
+
title.value = config.title;
|
|
47
|
+
saveBtnText.value = config.saveBtnText;
|
|
48
|
+
|
|
49
|
+
isShow.value = true;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const close = () => {
|
|
53
|
+
isShow.value = false;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const save = async () => {
|
|
57
|
+
if (loading.value) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// 校验表单
|
|
61
|
+
if (!schemaFormRef.value.validate()) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
loading.value = true;
|
|
65
|
+
// 提交表单
|
|
66
|
+
// const formData = schemaFormRef.value.getFormData();
|
|
67
|
+
try {
|
|
68
|
+
await $curl({
|
|
69
|
+
url: api.value,
|
|
70
|
+
method: "post",
|
|
71
|
+
data: { ...schemaFormRef.value.getValue() },
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
ElNotification({
|
|
75
|
+
title: "创建成功",
|
|
76
|
+
message: "创建成功",
|
|
77
|
+
type: "success",
|
|
78
|
+
});
|
|
79
|
+
close();
|
|
80
|
+
emit("command", {
|
|
81
|
+
event: "loadTableData",
|
|
82
|
+
});
|
|
83
|
+
loading.value = false;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
loading.value = false;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
defineExpose({
|
|
90
|
+
name,
|
|
91
|
+
show,
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style scoped lang="less"></style>
|