@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.
Files changed (85) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +52 -0
  3. package/.vscode/settings.json +8 -0
  4. package/REMADE.md +228 -0
  5. package/app/controller/base.js +43 -0
  6. package/app/controller/project.js +106 -0
  7. package/app/controller/view.js +21 -0
  8. package/app/extend/logger.js +36 -0
  9. package/app/middleware/api-params-verify.js +73 -0
  10. package/app/middleware/api-sign-verify.js +43 -0
  11. package/app/middleware/error-handler.js +33 -0
  12. package/app/middleware/project-handle.js +26 -0
  13. package/app/middleware.js +41 -0
  14. package/app/pages/asserts/custom.css +11 -0
  15. package/app/pages/boot.js +43 -0
  16. package/app/pages/common/curl.js +88 -0
  17. package/app/pages/common/utils.js +2 -0
  18. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +19 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +138 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +51 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +41 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +128 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +20 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +95 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +98 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +123 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +129 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +98 -0
  29. package/app/pages/dashboard/complex-view/silder-view/silder-view.vue +127 -0
  30. package/app/pages/dashboard/dashboard.vue +96 -0
  31. package/app/pages/dashboard/entry.dashboard.js +48 -0
  32. package/app/pages/store/index.js +5 -0
  33. package/app/pages/store/menu.js +70 -0
  34. package/app/pages/store/project.js +17 -0
  35. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  36. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  37. package/app/pages/widgets/header-container/header-container.vue +102 -0
  38. package/app/pages/widgets/schema-form/complex-view/input/input.vue +137 -0
  39. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +136 -0
  40. package/app/pages/widgets/schema-form/complex-view/select/select.vue +122 -0
  41. package/app/pages/widgets/schema-form/form-item-config.js +20 -0
  42. package/app/pages/widgets/schema-form/schema-form.vue +136 -0
  43. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +55 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +69 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +45 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +53 -0
  47. package/app/pages/widgets/schema-search-bar/schema-item-config.js +24 -0
  48. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +115 -0
  49. package/app/pages/widgets/schema-table/schema-table.vue +255 -0
  50. package/app/pages/widgets/sider-container/complex-view/sub-menu/sub-menu.vue +18 -0
  51. package/app/pages/widgets/sider-container/sider-container.vue +29 -0
  52. package/app/public/dist/entry.dashboard.tpl +27 -0
  53. package/app/public/dist/entry.page1.tpl +25 -0
  54. package/app/public/dist/entry.page2.tpl +25 -0
  55. package/app/public/dist/entry.project-list.tpl +27 -0
  56. package/app/public/static/logo.png +0 -0
  57. package/app/public/static/normalize.css +239 -0
  58. package/app/router/project.js +12 -0
  59. package/app/router/view.js +7 -0
  60. package/app/router-schema/project.js +30 -0
  61. package/app/service/base.js +13 -0
  62. package/app/service/project.js +58 -0
  63. package/app/view/entry.tpl +27 -0
  64. package/app/webpack/config/webpack.base.js +305 -0
  65. package/app/webpack/config/webpack.dev.js +62 -0
  66. package/app/webpack/config/webpack.prod.js +120 -0
  67. package/app/webpack/dev.js +62 -0
  68. package/app/webpack/libs/blank.js +1 -0
  69. package/app/webpack/prod.js +22 -0
  70. package/config/config.beta.js +3 -0
  71. package/config/config.default.js +3 -0
  72. package/config/config.prod.js +3 -0
  73. package/elpis-core/env.js +20 -0
  74. package/elpis-core/index.js +97 -0
  75. package/elpis-core/loader/config.js +66 -0
  76. package/elpis-core/loader/controller.js +86 -0
  77. package/elpis-core/loader/extend.js +66 -0
  78. package/elpis-core/loader/middleware.js +74 -0
  79. package/elpis-core/loader/router-schema.js +56 -0
  80. package/elpis-core/loader/router.js +49 -0
  81. package/elpis-core/loader/service.js +82 -0
  82. package/index.js +42 -0
  83. package/model/index.js +109 -0
  84. package/package.json +92 -0
  85. 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,11 @@
1
+ html, body {
2
+ height: 100%;
3
+ }
4
+
5
+ #root {
6
+ height: 100%;
7
+ }
8
+
9
+ input:-webkit-autofill{
10
+ -webkit-box-shadow: 0 0 0 1000px #121212 inset;
11
+ }
@@ -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,2 @@
1
+ const utils = {};
2
+ export default utils;
@@ -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>
@@ -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>