@codertqy/elpis 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -0
- package/.eslintrc +55 -0
- package/README.md +218 -0
- package/app/controller/base.js +40 -0
- package/app/controller/project.js +81 -0
- package/app/controller/view.js +22 -0
- package/app/extend/logger.js +43 -0
- package/app/middleware/api-params-verify.js +73 -0
- package/app/middleware/api-sign-verify.js +49 -0
- package/app/middleware/error-handler.js +31 -0
- package/app/middleware/project-handler.js +26 -0
- package/app/middleware.js +44 -0
- package/app/pages/assets/custom.css +14 -0
- package/app/pages/boot.js +56 -0
- package/app/pages/common/curl.js +84 -0
- package/app/pages/common/index.css +3 -0
- package/app/pages/common/utils.js +1 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +126 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +45 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +35 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +120 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +87 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +100 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +122 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +161 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +95 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +19 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +135 -0
- package/app/pages/dashboard/dashboard.vue +86 -0
- package/app/pages/dashboard/entry.dashboard.js +48 -0
- package/app/pages/store/index.js +3 -0
- package/app/pages/store/menu.js +68 -0
- package/app/pages/store/project.js +12 -0
- package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
- package/app/pages/widgets/header-container/asserts/logo.png +0 -0
- package/app/pages/widgets/header-container/header-container.vue +107 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +138 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +140 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +122 -0
- package/app/pages/widgets/schema-form/form-item-config.js +20 -0
- package/app/pages/widgets/schema-form/schema-form.vue +135 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +51 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +63 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +41 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +49 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +126 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +22 -0
- package/app/pages/widgets/schema-table/schema-table.vue +259 -0
- package/app/pages/widgets/sider-container/sider-container.vue +27 -0
- package/app/public/output/entry.page1.tpl +40 -0
- package/app/public/output/entry.page2.tpl +11 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +22 -0
- package/app/router/view.js +17 -0
- package/app/router-schema/project.js +34 -0
- package/app/service/base.js +15 -0
- package/app/service/project.js +59 -0
- package/app/view/entry.tpl +25 -0
- package/app/webpack/config/webpack.base.js +280 -0
- package/app/webpack/config/webpack.dev.js +57 -0
- package/app/webpack/config/webpack.prod.js +127 -0
- package/app/webpack/dev.js +63 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +22 -0
- package/config/config.beta.js +1 -0
- package/config/config.default.js +3 -0
- package/config/config.prod.js +1 -0
- package/elpis-core/env.js +27 -0
- package/elpis-core/index.js +98 -0
- package/elpis-core/loader/config.js +58 -0
- package/elpis-core/loader/controller.js +93 -0
- package/elpis-core/loader/extend.js +63 -0
- package/elpis-core/loader/middleware.js +84 -0
- package/elpis-core/loader/router-schema.js +56 -0
- package/elpis-core/loader/router.js +50 -0
- package/elpis-core/loader/service.js +85 -0
- package/index.js +38 -0
- package/model/index.js +129 -0
- package/package.json +92 -0
- package/test/controller/project.test.js +214 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createApp } from "vue";
|
|
2
|
+
|
|
3
|
+
// 引入 elementUI
|
|
4
|
+
import ElementPlus from "element-plus";
|
|
5
|
+
import "element-plus/dist/index.css";
|
|
6
|
+
// 引入暗黑模式
|
|
7
|
+
import "element-plus/theme-chalk/dark/css-vars.css";
|
|
8
|
+
// 引入基础样式
|
|
9
|
+
import "./assets/custom.css";
|
|
10
|
+
|
|
11
|
+
import pinia from "$elpisStore/index.js";
|
|
12
|
+
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
|
13
|
+
import { createWebHistory, createRouter } from "vue-router";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* vue 页面的主入口,用于启动 vue
|
|
17
|
+
* @param {*} pageComponent vue 入口组件
|
|
18
|
+
* @param {*} routes 路由列表
|
|
19
|
+
* @param {*} libs 页面所依赖的第三方包
|
|
20
|
+
*/
|
|
21
|
+
export default (pageComponent, { routes, libs } = {}) => {
|
|
22
|
+
const app = createApp(pageComponent);
|
|
23
|
+
|
|
24
|
+
// 引入 ElementPlus
|
|
25
|
+
app.use(ElementPlus);
|
|
26
|
+
|
|
27
|
+
// 引入 pinia
|
|
28
|
+
app.use(pinia);
|
|
29
|
+
|
|
30
|
+
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
|
31
|
+
app.component(key, component);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 引入第三方包 因为原生的比forEach这种性能要好一点点,可以忽略不计
|
|
35
|
+
// 为什么elpis-core可以使用forEach,因为服务器启动的,用户无感知,并且为了方便维护
|
|
36
|
+
if (libs && libs.length) {
|
|
37
|
+
for (let i = 0; i < libs.length; i++) {
|
|
38
|
+
app.use(libs[i]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 页面路由
|
|
43
|
+
if (routes && routes.length) {
|
|
44
|
+
const router = createRouter({
|
|
45
|
+
history: createWebHistory(), // 采用 History 模式 #/
|
|
46
|
+
routes,
|
|
47
|
+
});
|
|
48
|
+
app.use(router);
|
|
49
|
+
// 必须等待执行完毕,否则路由无法正常跳转
|
|
50
|
+
router.isReady().then(() => {
|
|
51
|
+
app.mount("#root");
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
app.mount("#root");
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ElMessage } from "element-plus";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
const md5 = require("md5");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 前端封装 curl 方法
|
|
8
|
+
* @param {*} options 请求参数
|
|
9
|
+
*/
|
|
10
|
+
const curl = ({
|
|
11
|
+
url, // 请求地址
|
|
12
|
+
method = "post", //请求方法
|
|
13
|
+
headers = {}, // 请求头
|
|
14
|
+
query = {}, // url query
|
|
15
|
+
data = {}, // post body
|
|
16
|
+
responesType = "json", // 响应数据类型
|
|
17
|
+
timeout = 60000, // 超时时间
|
|
18
|
+
errorMessage = "网络异常", // 错误信息
|
|
19
|
+
}) => {
|
|
20
|
+
// 接口签名处理(让接口变动态)
|
|
21
|
+
const signKey = "bgkjibal2kbhkc4vbakjl3sdvhja";
|
|
22
|
+
const st = Date.now();
|
|
23
|
+
|
|
24
|
+
// 构造请求头
|
|
25
|
+
const dtoHeaders = {
|
|
26
|
+
...headers,
|
|
27
|
+
s_t: st,
|
|
28
|
+
s_sign: md5(`${signKey}_${st}`),
|
|
29
|
+
};
|
|
30
|
+
if (url.indexOf("/api/projk") > -1 && window.projKey) {
|
|
31
|
+
// 是请求 业务API接口,则将项目 key添加到请求头中
|
|
32
|
+
dtoHeaders.proj_key = window.projKey;
|
|
33
|
+
}
|
|
34
|
+
// 构造请求参数 (将参数转换为 axios 参数)
|
|
35
|
+
const ajaxSetting = {
|
|
36
|
+
url,
|
|
37
|
+
method,
|
|
38
|
+
params: query,
|
|
39
|
+
data,
|
|
40
|
+
timeout,
|
|
41
|
+
responesType,
|
|
42
|
+
headers: dtoHeaders,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return axios
|
|
46
|
+
.request(ajaxSetting)
|
|
47
|
+
.then((res) => {
|
|
48
|
+
const resData = res.data || {};
|
|
49
|
+
// 后端返回 API 格式
|
|
50
|
+
const { success } = resData;
|
|
51
|
+
// 失败
|
|
52
|
+
if (!success) {
|
|
53
|
+
const { code, message } = resData;
|
|
54
|
+
if (code === 442) {
|
|
55
|
+
ElMessage.error("请求参数异常");
|
|
56
|
+
} else if (code === 445) {
|
|
57
|
+
ElMessage.error("请求不合法");
|
|
58
|
+
} else if (code === 446) {
|
|
59
|
+
ElMessage.error("缺少必要参数");
|
|
60
|
+
} else if (code === 50000) {
|
|
61
|
+
ElMessage.error(message);
|
|
62
|
+
} else {
|
|
63
|
+
ElMessage.error(errorMessage);
|
|
64
|
+
}
|
|
65
|
+
return Promise.resolve({ success, code, message });
|
|
66
|
+
}
|
|
67
|
+
// 成功
|
|
68
|
+
const { data, metadata } = resData;
|
|
69
|
+
return Promise.resolve({ success, data, metadata });
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
72
|
+
const { message } = err;
|
|
73
|
+
// 针对一些错误做处理
|
|
74
|
+
if (message.match(/timeout/)) {
|
|
75
|
+
return Promise.resolve({
|
|
76
|
+
message: " Request TimeOut",
|
|
77
|
+
code: 504,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return Promise.resolve(err);
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default curl;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-sub-menu :index="menuItem.key">
|
|
3
|
+
<template #title> {{ menuItem.name }}</template>
|
|
4
|
+
<div :key="item.key" v-for="item in menuItem.subMenu">
|
|
5
|
+
<SubMenu
|
|
6
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
7
|
+
:menuItem="item"
|
|
8
|
+
></SubMenu>
|
|
9
|
+
<el-menu-item v-else :index="item.key">
|
|
10
|
+
{{ item.name }}
|
|
11
|
+
</el-menu-item>
|
|
12
|
+
</div>
|
|
13
|
+
</el-sub-menu>
|
|
14
|
+
</template>
|
|
15
|
+
<script setup>
|
|
16
|
+
defineProps(["menuItem"]);
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<style scoped></style>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<HeaderContainer :title="projName">
|
|
3
|
+
<template #menu-content>
|
|
4
|
+
<!-- 根据 menuStore.menuList 渲染 -->
|
|
5
|
+
<el-menu
|
|
6
|
+
:default-active="activeKey"
|
|
7
|
+
:ellipsis="false"
|
|
8
|
+
mode="horizontal"
|
|
9
|
+
class=""
|
|
10
|
+
@select="onMenuSelect"
|
|
11
|
+
>
|
|
12
|
+
<template v-for="item in menuStore.menuList">
|
|
13
|
+
<SubMenu
|
|
14
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
15
|
+
:menuItem="item"
|
|
16
|
+
></SubMenu>
|
|
17
|
+
<el-menu-item v-else :index="item.key">
|
|
18
|
+
{{ item.name }}
|
|
19
|
+
</el-menu-item>
|
|
20
|
+
</template>
|
|
21
|
+
</el-menu>
|
|
22
|
+
</template>
|
|
23
|
+
<template #setting-content>
|
|
24
|
+
<!-- 根据 projectStore.projectList 渲染 -->
|
|
25
|
+
<el-dropdown @command="handlProjectCommand">
|
|
26
|
+
<span class="project-list">
|
|
27
|
+
{{ projName }}
|
|
28
|
+
<el-icon
|
|
29
|
+
v-if="projectStore.projectList.length > 1"
|
|
30
|
+
class="el-icon--right"
|
|
31
|
+
><ArrowDown
|
|
32
|
+
/></el-icon>
|
|
33
|
+
</span>
|
|
34
|
+
<template v-if="projectStore.projectList.length > 1" #dropdown>
|
|
35
|
+
<el-dropdown-menu>
|
|
36
|
+
<el-dropdown-item
|
|
37
|
+
v-for="item in projectStore.projectList"
|
|
38
|
+
:key="item.key"
|
|
39
|
+
:command="item.key"
|
|
40
|
+
:disabled="item.name === projName"
|
|
41
|
+
>
|
|
42
|
+
{{ item.name }}
|
|
43
|
+
</el-dropdown-item>
|
|
44
|
+
</el-dropdown-menu>
|
|
45
|
+
</template>
|
|
46
|
+
</el-dropdown>
|
|
47
|
+
</template>
|
|
48
|
+
<template #main-content>
|
|
49
|
+
<slot name="main-content"> </slot>
|
|
50
|
+
</template>
|
|
51
|
+
</HeaderContainer>
|
|
52
|
+
</template>
|
|
53
|
+
<script setup>
|
|
54
|
+
import { ArrowDown } from "@element-plus/icons-vue";
|
|
55
|
+
import HeaderContainer from "$elpisWidgets/header-container/header-container.vue";
|
|
56
|
+
import SubMenu from "./complex-view/sub-menu/sub-menu.vue";
|
|
57
|
+
import { useMenuStore } from "$elpisStore/menu.js";
|
|
58
|
+
import { useProjectStore } from "$elpisStore/project.js";
|
|
59
|
+
import { onMounted, ref, watch } from "vue";
|
|
60
|
+
import { useRoute } from "vue-router";
|
|
61
|
+
const route = useRoute();
|
|
62
|
+
const menuStore = useMenuStore();
|
|
63
|
+
const projectStore = useProjectStore();
|
|
64
|
+
|
|
65
|
+
defineProps({ projName: String });
|
|
66
|
+
const emit = defineEmits(["menu-select"]);
|
|
67
|
+
|
|
68
|
+
const activeKey = ref("");
|
|
69
|
+
|
|
70
|
+
// 监听变化
|
|
71
|
+
watch(
|
|
72
|
+
() => route.query.key,
|
|
73
|
+
(key) => {
|
|
74
|
+
setActiveKey(key);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
// 数据获取到之后
|
|
78
|
+
watch(
|
|
79
|
+
() => menuStore.menuList,
|
|
80
|
+
(key) => {
|
|
81
|
+
setActiveKey(key);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
onMounted(() => {
|
|
85
|
+
setActiveKey();
|
|
86
|
+
});
|
|
87
|
+
const setActiveKey = () => {
|
|
88
|
+
// 权限搜索的
|
|
89
|
+
const menuItem = menuStore.findMenuItem({
|
|
90
|
+
key: "key",
|
|
91
|
+
value: route.query.key,
|
|
92
|
+
});
|
|
93
|
+
activeKey.value = menuItem?.key;
|
|
94
|
+
};
|
|
95
|
+
const onMenuSelect = (menuKey) => {
|
|
96
|
+
const menuItem = menuStore.findMenuItem({
|
|
97
|
+
key: "key",
|
|
98
|
+
value: menuKey,
|
|
99
|
+
});
|
|
100
|
+
emit("menu-select", menuItem);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// 同一模块切换,比如 b站 切换 抖音
|
|
104
|
+
const handlProjectCommand = (e) => {
|
|
105
|
+
const projectItem = projectStore.projectList.find((item) => item.key === e);
|
|
106
|
+
if (!projectItem || !projectItem.homePage) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const { host } = window.location;
|
|
110
|
+
window.location.replace(`http://${host}/view/dashboard${projectItem.homePage}`);
|
|
111
|
+
};
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<style scoped lang="less">
|
|
115
|
+
:deep(.el-menu--horizontal.el-menu) {
|
|
116
|
+
border-bottom: 1px solid #e8e8e8;
|
|
117
|
+
}
|
|
118
|
+
.project-list {
|
|
119
|
+
margin-right: 20px;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
color: var(--el-color-primary);
|
|
122
|
+
outline: none;
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<iframe :src="path" class="iframe"></iframe>
|
|
3
|
+
</template>
|
|
4
|
+
<script setup>
|
|
5
|
+
import { ref, watch, onMounted } from "vue";
|
|
6
|
+
import { useRoute } from "vue-router";
|
|
7
|
+
import { useMenuStore } from "$elpisStore/menu";
|
|
8
|
+
|
|
9
|
+
const route = useRoute();
|
|
10
|
+
const menuStore = useMenuStore();
|
|
11
|
+
|
|
12
|
+
const path = ref("");
|
|
13
|
+
const setPath = () => {
|
|
14
|
+
const { key, sider_key: siderKey } = route.query;
|
|
15
|
+
const menuItem = menuStore.findMenuItem({
|
|
16
|
+
key: "key",
|
|
17
|
+
value: siderKey ?? key,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
path.value = menuItem?.iframeConfig?.path ?? "";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
watch(
|
|
24
|
+
[
|
|
25
|
+
() => route.query.key,
|
|
26
|
+
() => route.query.sider_key,
|
|
27
|
+
() => menuStore.menuList,
|
|
28
|
+
],
|
|
29
|
+
() => {
|
|
30
|
+
setPath();
|
|
31
|
+
},
|
|
32
|
+
{ deep: true },
|
|
33
|
+
);
|
|
34
|
+
onMounted(() => {
|
|
35
|
+
setPath();
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<style scoped lang="less">
|
|
40
|
+
.iframe {
|
|
41
|
+
border: 0;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-card class="search-panel">
|
|
3
|
+
<SchemaSearchBar
|
|
4
|
+
:schema="searchSchema"
|
|
5
|
+
@load="onLoad"
|
|
6
|
+
@search="onSearch"
|
|
7
|
+
@reset="onReset"
|
|
8
|
+
></SchemaSearchBar>
|
|
9
|
+
</el-card>
|
|
10
|
+
</template>
|
|
11
|
+
<script setup>
|
|
12
|
+
import { inject } from "vue";
|
|
13
|
+
import SchemaSearchBar from "$elpisWidgets/schema-search-bar/schema-search-bar.vue";
|
|
14
|
+
const { searchSchema } = inject("schemaViewData");
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits(["search"]);
|
|
17
|
+
const onLoad = (searchValObj) => {
|
|
18
|
+
emit("search", searchValObj);
|
|
19
|
+
};
|
|
20
|
+
const onSearch = (searchValObj) => {
|
|
21
|
+
emit("search", searchValObj);
|
|
22
|
+
};
|
|
23
|
+
const onReset = () => {
|
|
24
|
+
emit("search", {});
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<style scoped lang="less">
|
|
29
|
+
.search-panel {
|
|
30
|
+
margin: 10px 10px 0 10px;
|
|
31
|
+
}
|
|
32
|
+
:deep(.el-card__body) {
|
|
33
|
+
padding-bottom: 2px;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
@click="operationHandler({ btnConfig: item })"
|
|
13
|
+
>{{ item.label }}</el-button
|
|
14
|
+
>
|
|
15
|
+
</el-row>
|
|
16
|
+
<!-- schema-table(组件 widget) -->
|
|
17
|
+
<SchemaTable
|
|
18
|
+
ref="schemaTableRef"
|
|
19
|
+
:schema="tableSchema"
|
|
20
|
+
:api="api"
|
|
21
|
+
:apiParams="apiParams"
|
|
22
|
+
:buttons="tableConfig?.rowButtons ?? []"
|
|
23
|
+
@operate="operationHandler"
|
|
24
|
+
></SchemaTable>
|
|
25
|
+
</el-card>
|
|
26
|
+
</template>
|
|
27
|
+
<script setup>
|
|
28
|
+
import SchemaTable from "$elpisWidgets/schema-table/schema-table.vue";
|
|
29
|
+
import { ref, inject } from "vue";
|
|
30
|
+
import $curl from "$elpisCommon/curl";
|
|
31
|
+
import { ElMessageBox, ElNotification } from "element-plus";
|
|
32
|
+
|
|
33
|
+
const emit = defineEmits(["operate"]);
|
|
34
|
+
const schemaTableRef = ref(null);
|
|
35
|
+
const { api, tableSchema, apiParams, tableConfig } = inject("schemaViewData");
|
|
36
|
+
|
|
37
|
+
const operationHandler = ({ btnConfig, rowData }) => {
|
|
38
|
+
const { eventKey } = btnConfig;
|
|
39
|
+
// 如果有该事件,透传下去
|
|
40
|
+
if (EventHandlerMap[eventKey]) {
|
|
41
|
+
EventHandlerMap[eventKey]({ btnConfig, rowData });
|
|
42
|
+
} else {
|
|
43
|
+
emit("operate", { btnConfig, rowData });
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const removeData = async ({ btnConfig, rowData }) => {
|
|
47
|
+
const { eventOption } = btnConfig;
|
|
48
|
+
if (!eventOption?.params) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const { params } = eventOption;
|
|
52
|
+
// 参数键
|
|
53
|
+
const removeKey = Object.keys(params)[0];
|
|
54
|
+
// 拿到 参数值
|
|
55
|
+
let removeValue = params[removeKey];
|
|
56
|
+
|
|
57
|
+
const removeValueList = removeValue.split("::");
|
|
58
|
+
if (removeValueList[0] === "schema" && removeValueList[1]) {
|
|
59
|
+
removeValue = rowData[removeValueList[1]];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ElMessageBox.confirm(
|
|
63
|
+
`确认删除${removeKey}为:${removeValue}的数据吗?`,
|
|
64
|
+
"warning",
|
|
65
|
+
{
|
|
66
|
+
confirmButtonText: "确认",
|
|
67
|
+
cancelButtonText: "取消",
|
|
68
|
+
},
|
|
69
|
+
).then(async () => {
|
|
70
|
+
schemaTableRef.value.showLoading();
|
|
71
|
+
const res = await $curl({
|
|
72
|
+
method: "delete",
|
|
73
|
+
url: api.value,
|
|
74
|
+
data: { [removeKey]: removeValue },
|
|
75
|
+
errorMessage: "删除失败",
|
|
76
|
+
});
|
|
77
|
+
schemaTableRef.value.hideLoading();
|
|
78
|
+
if (!res || !res.success || !res.data) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
ElNotification.success({
|
|
83
|
+
title: "删除成功",
|
|
84
|
+
message: "删除成功",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// 重新调用子组件身上的方法进行加载数据
|
|
88
|
+
await initTableData();
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const EventHandlerMap = {
|
|
93
|
+
remove: removeData,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const initTableData = async () => {
|
|
97
|
+
await schemaTableRef.value.initData();
|
|
98
|
+
};
|
|
99
|
+
const loadTableData = async () => {
|
|
100
|
+
await schemaTableRef.value.loadTableData();
|
|
101
|
+
};
|
|
102
|
+
defineExpose({
|
|
103
|
+
loadTableData,
|
|
104
|
+
});
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<style scoped lang="less">
|
|
108
|
+
.table-panel {
|
|
109
|
+
flex: 1;
|
|
110
|
+
margin-top: 10px;
|
|
111
|
+
.operation-panel {
|
|
112
|
+
margin-bottom: 10px;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
:deep(.el-card__body) {
|
|
116
|
+
height: 100%;
|
|
117
|
+
display: flex;
|
|
118
|
+
flex-direction: column;
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
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 {
|
|
21
|
+
...ComponentConfig,
|
|
22
|
+
...BusinessComponentConfig,
|
|
23
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
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>{{ title }}</h3>
|
|
10
|
+
</template>
|
|
11
|
+
<template #default>
|
|
12
|
+
<SchemaForm
|
|
13
|
+
ref="schemaFormRef"
|
|
14
|
+
v-loading="loading"
|
|
15
|
+
:schema="components[name]?.schema"
|
|
16
|
+
></SchemaForm>
|
|
17
|
+
</template>
|
|
18
|
+
<template #footer>
|
|
19
|
+
<el-button type="primary" @click="save">{{ saveBtnText }}</el-button>
|
|
20
|
+
</template>
|
|
21
|
+
</el-drawer>
|
|
22
|
+
</template>
|
|
23
|
+
<script setup>
|
|
24
|
+
import { ref, inject } from "vue";
|
|
25
|
+
import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";
|
|
26
|
+
import $curl from "$elpisCommon/curl.js";
|
|
27
|
+
import { ElNotification } from "element-plus";
|
|
28
|
+
|
|
29
|
+
const { api, components } = inject("schemaViewData");
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits(["command"]);
|
|
33
|
+
const name = ref("createForm");
|
|
34
|
+
const isShow = ref(false);
|
|
35
|
+
const title = ref("");
|
|
36
|
+
const saveBtnText = ref("");
|
|
37
|
+
const schemaFormRef = ref();
|
|
38
|
+
const loading = ref(false);
|
|
39
|
+
const show = () => {
|
|
40
|
+
const { config } = components.value[name.value];
|
|
41
|
+
title.value = config.title;
|
|
42
|
+
saveBtnText.value = config.saveBtnText;
|
|
43
|
+
|
|
44
|
+
isShow.value = true;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const close = () => {
|
|
48
|
+
isShow.value = false;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const save = async () => {
|
|
52
|
+
if (loading.value) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!schemaFormRef.value.validate()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
loading.value = true;
|
|
59
|
+
const res = await $curl({
|
|
60
|
+
method: "post",
|
|
61
|
+
url: api.value,
|
|
62
|
+
data: {
|
|
63
|
+
...schemaFormRef.value.getValue(),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
loading.value = false;
|
|
67
|
+
if (!res || !res.success) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
ElNotification({
|
|
71
|
+
title: "创建成功",
|
|
72
|
+
message: "创建成功",
|
|
73
|
+
type: "success",
|
|
74
|
+
});
|
|
75
|
+
close();
|
|
76
|
+
|
|
77
|
+
emit("command", {
|
|
78
|
+
event: "loadTableData",
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
defineExpose({
|
|
82
|
+
name,
|
|
83
|
+
show,
|
|
84
|
+
});
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<style scoped lang="less"></style>
|