@jiangliffey/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 (81) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +55 -0
  3. package/CLAUDE.md +81 -0
  4. package/README.md +200 -0
  5. package/app/controller/base.js +38 -0
  6. package/app/controller/project.js +74 -0
  7. package/app/controller/view.js +22 -0
  8. package/app/extend/logger.js +35 -0
  9. package/app/middleware/api-params-verify.js +81 -0
  10. package/app/middleware/api-sign-verify.js +35 -0
  11. package/app/middleware/error-handler.js +33 -0
  12. package/app/middleware/project-handler.js +27 -0
  13. package/app/middleware.js +37 -0
  14. package/app/pages/asserts/custom.css +12 -0
  15. package/app/pages/boot.js +50 -0
  16. package/app/pages/common/curl.js +89 -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 +21 -0
  19. package/app/pages/dashboard/complex-view/header-view/header-view.vue +123 -0
  20. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +40 -0
  22. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +124 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +87 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +100 -0
  26. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +118 -0
  27. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +124 -0
  28. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +80 -0
  29. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +21 -0
  30. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +135 -0
  31. package/app/pages/dashboard/dashboard.vue +96 -0
  32. package/app/pages/dashboard/entry.dashboard.js +45 -0
  33. package/app/pages/dashboard/todo/todo.vue +11 -0
  34. package/app/pages/store/index.js +4 -0
  35. package/app/pages/store/menu.js +58 -0
  36. package/app/pages/store/project.js +14 -0
  37. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  38. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  39. package/app/pages/widgets/header-container/header-container.vue +106 -0
  40. package/app/pages/widgets/schema-form/complex-view/input/input.vue +134 -0
  41. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +136 -0
  42. package/app/pages/widgets/schema-form/complex-view/select/select.vue +116 -0
  43. package/app/pages/widgets/schema-form/form-item-config.js +23 -0
  44. package/app/pages/widgets/schema-form/schema-form.vue +135 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +50 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +67 -0
  47. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +44 -0
  48. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +51 -0
  49. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +129 -0
  50. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  51. package/app/pages/widgets/schema-table/schema-table.vue +235 -0
  52. package/app/pages/widgets/sider-container/sider-container.vue +31 -0
  53. package/app/public/static/logo.png +0 -0
  54. package/app/public/static/normalize.css +239 -0
  55. package/app/router/project.js +6 -0
  56. package/app/router/view.js +8 -0
  57. package/app/router-schema/project.js +30 -0
  58. package/app/service/base.js +11 -0
  59. package/app/service/project.js +56 -0
  60. package/app/view/entry.tpl +26 -0
  61. package/app/webpack/config/webpack.base.js +203 -0
  62. package/app/webpack/config/webpack.dev.js +59 -0
  63. package/app/webpack/config/webpack.prod.js +107 -0
  64. package/app/webpack/dev.js +53 -0
  65. package/app/webpack/libs/blank.js +3 -0
  66. package/app/webpack/prod.js +17 -0
  67. package/config/config.default.js +3 -0
  68. package/docs/dashboard-model.js +153 -0
  69. package/elpis-core/env.js +23 -0
  70. package/elpis-core/index.js +96 -0
  71. package/elpis-core/loader/config.js +50 -0
  72. package/elpis-core/loader/controller.js +54 -0
  73. package/elpis-core/loader/extend.js +49 -0
  74. package/elpis-core/loader/middleware.js +53 -0
  75. package/elpis-core/loader/router-schema.js +41 -0
  76. package/elpis-core/loader/router.js +45 -0
  77. package/elpis-core/loader/service.js +54 -0
  78. package/index.js +40 -0
  79. package/model/index.js +99 -0
  80. package/package.json +92 -0
  81. package/test/controller/project.test.js +225 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * projectHandler 相关项目处理内容
3
+ */
4
+ module.exports = (app) => {
5
+ return async (ctx, next) => {
6
+ // 只对业务API进行 proj_key 处理
7
+ if(ctx.path.indexOf('/api/proj/') < 0) {
8
+ return await next();
9
+ }
10
+ // 获取 projKey
11
+ const { proj_key: projKey } = ctx.request.headers;
12
+
13
+ if(!projKey) {
14
+ ctx.status = 200;
15
+ ctx.body = {
16
+ success: false,
17
+ message: 'proj_key not found',
18
+ code: 446
19
+ };
20
+ return;
21
+ }
22
+
23
+ ctx.projKey = projKey;
24
+
25
+ await next();
26
+ }
27
+ }
@@ -0,0 +1,37 @@
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
+
8
+ // 模板渲染引擎
9
+ const koaNunjucks = require('koa-nunjucks-2');
10
+ app.use(koaNunjucks({
11
+ ext: 'tpl',
12
+ path: path.resolve(process.cwd(), './app/public'),
13
+ nunjucksConfig: {
14
+ noCache: true,
15
+ trimBlocks: true
16
+ }
17
+ }));
18
+
19
+ // 引入 ctx.body 解析中间件
20
+ const bodyParser = require('koa-bodyparser');
21
+ app.use(bodyParser({
22
+ formLimit: '1000mb',
23
+ enableTypes: ['json', 'form', 'text']
24
+ }));
25
+
26
+ // 引入异常捕获中间件
27
+ app.use(app.middlewares.errorHandler);
28
+
29
+ // 签名合法性校验
30
+ app.use(app.middlewares.apiSignVerify);
31
+
32
+ // 引入 API 参数校验
33
+ app.use(app.middlewares.apiParamsVerify);
34
+
35
+ // 引入 项目处理中间件
36
+ app.use(app.middlewares.projectHandler);
37
+ }
@@ -0,0 +1,12 @@
1
+ html, body {
2
+ height: 100%;
3
+ }
4
+
5
+ #root {
6
+ height: 100%;
7
+ }
8
+
9
+ input:-webkit-autofill {
10
+ /* 覆盖自动填充背景颜色 */
11
+ -webkit-box-shadow: 0 0 0px 1000px #121212 inset;
12
+ }
@@ -0,0 +1,50 @@
1
+ import { createApp } from "vue";
2
+
3
+ // 引入elementUI
4
+ import ElementPlus from 'element-plus';
5
+ import 'element-plus/theme-chalk/index.css';
6
+ import 'element-plus/theme-chalk/dark/css-vars.css'
7
+
8
+ import './asserts/custom.css';
9
+
10
+ import pinia from '$elpisStore';
11
+
12
+ import { createRouter, createWebHistory } from "vue-router";
13
+
14
+
15
+ /**
16
+ * vue页面主入口,用于启动vue
17
+ * @params pageComponent vue 入口组件
18
+ * @params routes 路由列表
19
+ * @params libs 页面依赖的第三包
20
+ */
21
+ export default (pageComponent, { routes, libs } = {}) => {
22
+ const app = createApp(pageComponent);
23
+
24
+ // 应用elementUI
25
+ app.use(ElementPlus); //顺序不能反:先注册 再挂载
26
+
27
+ // 引入 pinia
28
+ app.use(pinia);
29
+
30
+ // 引入 第三方包
31
+ if(libs && libs.length) {
32
+ for (let i = 0; i < libs.length; i++) {
33
+ app.use(libs[i]);
34
+ }
35
+ }
36
+
37
+ // 页面路由
38
+ if(routes && routes.length) {
39
+ const router = createRouter({
40
+ history: createWebHistory('/view/dashboard'), // 采用history模式
41
+ routes,
42
+ })
43
+ app.use(router);
44
+ router.isReady().then(() => {
45
+ app.mount('#root');
46
+ })
47
+ } else {
48
+ app.mount('#root');
49
+ }
50
+ }
@@ -0,0 +1,89 @@
1
+ const md5 = require('md5');
2
+ import axios from 'axios';
3
+ import { ElMessage } from 'element-plus'
4
+
5
+ /**
6
+ * 前端封装的 curl 方法
7
+ * @params options 请求参数
8
+ */
9
+
10
+ const curl = ({
11
+ url, // 请求地址
12
+ method = 'post', // 请求方法
13
+ headers = {}, // 请求头
14
+ query = {}, // 请求参数:query
15
+ data = {}, // post body
16
+ responseType = 'json', // response data type
17
+ timeout = 6000,
18
+ errorMessage = '网络异常'
19
+ }) => {
20
+
21
+ // 接口签名处理(让接口便动态)
22
+ const signKey = 'dftgyh84adsuh462wef46ef5s6d4fiop';
23
+ const st = Date.now();
24
+
25
+ const dtoHeaders = {
26
+ ...headers,
27
+ s_t: st,
28
+ s_sign: md5(`${signKey}_${st}`)
29
+ }
30
+ if(url.indexOf('/api/proj/') > -1 && window.projKey) {
31
+ dtoHeaders.proj_key = window.projKey;
32
+ }
33
+
34
+ // 构造请求参数(把参数转换为axios参数)
35
+ const ajaxStting = {
36
+ url,
37
+ method,
38
+ params: query,
39
+ data,
40
+ responseType,
41
+ timeout,
42
+ headers: dtoHeaders
43
+ };
44
+
45
+ return axios.request(ajaxStting).then((response) => {
46
+ const resData = response.data || {};
47
+
48
+ // 后端API返回格式
49
+ const { success } = resData;
50
+
51
+
52
+ // 失败
53
+ if(!success) {
54
+ const { message, code } = resData;
55
+ if(code === 442) {
56
+ ElMessage.error('请求参数异常');
57
+ } else if(code === 445) {
58
+ ElMessage.error('请求不合法');
59
+ } else if(code === 446) {
60
+ ElMessage.error('缺少项目必要参数');
61
+ } else if(code === 50000) {
62
+ ElMessage.error(message);
63
+ } else {
64
+ ElMessage.error(errorMessage);
65
+ }
66
+
67
+ console.error(message);
68
+
69
+ return Promise.resolve({ success, code, message });
70
+ }
71
+
72
+ // 成功
73
+ const { data, metadata } = resData;
74
+ return Promise.resolve({ success, data, metadata });
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
+
85
+ return Promise.resolve(error);
86
+ });
87
+ }
88
+
89
+ export default curl;
@@ -0,0 +1,2 @@
1
+ const utils = {};
2
+ export default utils;
@@ -0,0 +1,21 @@
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
6
+ v-if="item.subMenu && item.subMenu.length > 0"
7
+ :menu-item="item"
8
+ >
9
+ </sub-menu>
10
+ <el-menu-item v-else :index="item.key">{{ item.name }}</el-menu-item>
11
+ </div>
12
+ </el-sub-menu>
13
+ </template>
14
+
15
+ <script setup>
16
+ const { menuItem } = defineProps([ 'menuItem' ]);
17
+ </script>
18
+
19
+ <style lang="less" scoped>
20
+
21
+ </style>
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <header-container :title="projName">
3
+ <template #menu-content>
4
+ <!-- 根据menujStore.menuList 渲染 -->
5
+ <el-menu
6
+ :default-active="activeKey"
7
+ :ellipsis="false"
8
+ mode="horizontal"
9
+ @select="onMenuSelect"
10
+ >
11
+ <template v-for="item in menuStore.menuList" :key="item.key">
12
+ <sub-menu
13
+ v-if="item.subMenu && item.subMenu.length > 0" :menu-item="item"
14
+ ></sub-menu>
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
+ <!-- 根据projStore.projectList 渲染 -->
21
+ <el-dropdown @command="handleProjectCommand">
22
+ <span class="project-list">
23
+ {{ projName }}
24
+ <el-icon v-if="projectStore.projectList.length > 1" class="el-icon--right"><ArrowDown /></el-icon>
25
+ </span>
26
+ <template v-if="projectStore.projectList.length > 1" #dropdown>
27
+ <el-dropdown-menu>
28
+ <el-dropdown-item
29
+ v-for="item in projectStore.projectList"
30
+ :key="item.key"
31
+ :command="item.key"
32
+ :disabled="item.name == projName"
33
+ >{{ item.name }}</el-dropdown-item>
34
+ </el-dropdown-menu>
35
+ </template>
36
+ </el-dropdown>
37
+ </template>
38
+ <template #main-content>
39
+ <slot name="main-content"></slot>
40
+ </template>
41
+ </header-container>
42
+ </template>
43
+
44
+ <script setup>
45
+ import { ref, onMounted, watch } from 'vue';
46
+ import { useRoute } from 'vue-router';
47
+ import { ArrowDown } from '@element-plus/icons-vue';
48
+ import HeaderContainer from '$elpisWidgets/header-container/header-container.vue';
49
+ import SubMenu from './complex-view/sub-menu/sub-menu.vue';
50
+ import { useMenuStore } from '$elpisStore/menu.js';
51
+ import { useProjectStore } from '$elpisStore/project.js';
52
+
53
+ const route = useRoute();
54
+ const menuStore = useMenuStore();
55
+ const projectStore = useProjectStore();
56
+
57
+ defineProps({
58
+ projName: String
59
+ });
60
+
61
+ const emit = defineEmits([ 'menu-select' ]);
62
+
63
+ const activeKey = ref('');
64
+ const setActiveKey = () => {
65
+ const menuItem = menuStore.findMenuItem({
66
+ key: 'key',
67
+ value: route.query.key
68
+ });
69
+ activeKey.value = menuItem?.key;
70
+ }
71
+
72
+ // watch(() => route.query.key, () => {
73
+ // setActiveKey();
74
+ // })
75
+ // watch(() => menuStore.menuList, () => {
76
+ // setActiveKey();
77
+ // },{ deep: true })
78
+ // onMounted(() => {
79
+ // setActiveKey();
80
+ // })
81
+
82
+ watch(
83
+ [() => route.query.key, () => menuStore.menuList],
84
+ () => {
85
+ setActiveKey();
86
+ },
87
+ {
88
+ immediate: true,
89
+ deep: true
90
+ }
91
+ );
92
+
93
+ const onMenuSelect = (menuKey) => {
94
+ const menuItem = menuStore.findMenuItem({
95
+ key: 'key',
96
+ value: menuKey
97
+ });
98
+ emit('menu-select', menuItem);
99
+ }
100
+ const handleProjectCommand = (event) => {
101
+ const projectItem = projectStore.projectList.find(item => item.key === event);
102
+ if(!projectItem || !projectItem.homePage) { return; }
103
+ const { origin } = window.location;
104
+ window.location.replace(`${origin}/view/dashboard${projectItem.homePage}`);
105
+ };
106
+ </script>
107
+
108
+ <style lang="less" scoped>
109
+ :deep(.el-menu--horizontal.el-menu) {
110
+ border-bottom: 0;
111
+ }
112
+ :deep(.el-menu) {
113
+ background-color: unset;
114
+ }
115
+ .project-list {
116
+ margin-right: 20px;
117
+ cursor: pointer;
118
+ color: var(--el-color-primary);
119
+ display: flex;
120
+ align-items: center;
121
+ outline: none;
122
+ }
123
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <iframe :src="path" class="iframe"></iframe>
3
+ </template>
4
+
5
+ <script setup>
6
+ import { 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
+ const setPath = () => {
15
+ const { key, sider_key: siderKey } = route.query;
16
+
17
+ const menuItem = menuStore.findMenuItem({
18
+ key: 'key',
19
+ value: siderKey ?? key
20
+ });
21
+
22
+ path.value = menuItem?.iframeConfig?.path ?? '';
23
+ };
24
+
25
+ watch(
26
+ [() => route.query.key, () => route.query.sider_key, () => menuStore.menuList],
27
+ () => {
28
+ setPath();
29
+ },
30
+ {
31
+ immediate: true,
32
+ deep: true
33
+ }
34
+ );
35
+ </script>
36
+
37
+ <style lang="less" scoped>
38
+ .iframe {
39
+ border: 0;
40
+ width: 100%;
41
+ height: 100%;
42
+ }
43
+ </style>
@@ -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 { ref, inject } from 'vue';
14
+ import SchemaSearchBar from '$elpisWidgets/schema-search-bar/schema-search-bar.vue';
15
+
16
+ const { searchSchema } = inject('schemaViewData');
17
+
18
+ const emit = defineEmits([ 'search' ]);
19
+
20
+ const onLoad = (searchValObj) => {
21
+ emit('search', searchValObj);
22
+ }
23
+
24
+ const onSearch = (searchValObj) => {
25
+ emit('search', searchValObj);
26
+ }
27
+
28
+ const onReset = (searchValObj) => {
29
+ emit('search', searchValObj);
30
+ }
31
+ </script>
32
+
33
+ <style lang="less" scoped>
34
+ .search-panel {
35
+ margin: 10px 10px 0 10px;
36
+ }
37
+ :deep(.el-card__body) {
38
+ padding-bottom: 2px;
39
+ }
40
+ </style>
@@ -0,0 +1,124 @@
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
+ </el-row>
15
+ <!-- schema-table(组件 widget) -->
16
+ <schema-table
17
+ ref="schemaTableRef"
18
+ :schema="tableSchema"
19
+ :api="api"
20
+ :apiParams="apiParams"
21
+ :buttons="tableConfig?.rowButtons ?? []"
22
+ @operate="operationHandler"
23
+ >
24
+ </schema-table>
25
+ </el-card>
26
+ </template>
27
+
28
+ <script setup>
29
+ import { ref, inject } from 'vue';
30
+ import { ElMessageBox, ElNotification } from 'element-plus';
31
+ import $curl from '$elpisCommon/curl.js';
32
+ import SchemaTable from '$elpisWidgets/schema-table/schema-table.vue';
33
+
34
+ const emit = defineEmits([ 'operate' ]);
35
+
36
+ const { api, apiParams, tableSchema, tableConfig } = inject('schemaViewData')
37
+
38
+ const schemaTableRef = ref(null);
39
+
40
+ const EventHandlerMap = {
41
+ remove: removeData
42
+ }
43
+ const operationHandler = ({ btnConfig, rowData }) => {
44
+ const { eventKey } = btnConfig;
45
+ if(EventHandlerMap[eventKey]) {
46
+ EventHandlerMap[eventKey]({ btnConfig, rowData });
47
+ } else {
48
+ emit('operate', { btnConfig, rowData })
49
+ }
50
+ }
51
+ function removeData ({ btnConfig, rowData }) {
52
+ const { eventOption } = btnConfig;
53
+ if(!eventOption?.params) { return; }
54
+
55
+ const { params } = eventOption;
56
+
57
+ const removeKey = Object.keys(params)[0];
58
+
59
+ let removeValue;
60
+ const removeValueList = params[removeKey].split('::');
61
+ if(removeValueList[0] === 'schema' && removeValueList[1]) {
62
+ removeValue = rowData[removeValueList[1]];
63
+ }
64
+
65
+ ElMessageBox.confirm(
66
+ `确认删除 ${removeKey} 为:${removeValue} 数据?`,
67
+ 'Warning',
68
+ {
69
+ confirmButtonText: '确认',
70
+ cancelButtonText: '取消',
71
+ type: 'warning'
72
+ }
73
+ ).then(async () => {
74
+ schemaTableRef.value.showLoading();
75
+ const res = await $curl({
76
+ method: 'delete',
77
+ url: api.value,
78
+ data: {
79
+ [removeKey]: removeValue
80
+ },
81
+ errorMessages: '删除失败'
82
+ });
83
+ schemaTableRef.value.hideLoading();
84
+
85
+ if(!res || !res.success || !res.data) {
86
+ return;
87
+ }
88
+
89
+ ElNotification({
90
+ title: '删除成功',
91
+ message: '删除成功',
92
+ type: 'success'
93
+ });
94
+
95
+ await initTableData();
96
+ });
97
+ }
98
+
99
+ const initTableData = async() => {
100
+ await schemaTableRef.value.initData();
101
+ }
102
+
103
+ const loadTableData = async() => {
104
+ await schemaTableRef.value.loadTableData();
105
+ }
106
+
107
+ defineExpose({ loadTableData })
108
+ </script>
109
+
110
+ <style lang="less" scoped>
111
+ .table-panel {
112
+ flex: 1;
113
+ margin: 10px;
114
+
115
+ .operation-panel {
116
+ margin-bottom: 10px;
117
+ }
118
+ }
119
+ :deep(.el-card__body) {
120
+ height: 98%;
121
+ display: flex;
122
+ flex-direction: column;
123
+ }
124
+ </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
+ <schema-form ref="schemaFormRef" v-loading="loading" :schema="components[name]?.schema"></schema-form>
13
+ </template>
14
+ <template #footer>
15
+ <el-button type="primary" @click="save">{{ saveBtnText }}</el-button>
16
+ </template>
17
+ </el-drawer>
18
+ </template>
19
+
20
+ <script setup>
21
+ import { ref, inject } from 'vue';
22
+ import $curl from '$elpisCommon/curl.js';
23
+ import { ElNotification } from 'element-plus';
24
+ import SchemaForm from '$elpisWidgets/schema-form/schema-form.vue';
25
+
26
+ const { api, components } = inject('schemaViewData');
27
+
28
+ const emit = defineEmits([ 'command' ])
29
+
30
+ const name = ref('createForm');
31
+
32
+ const schemaFormRef = ref(null);
33
+ const isShow = ref(false);
34
+ const loading = ref(false);
35
+ const title = ref('');
36
+ const saveBtnText = ref('');
37
+
38
+ const show = () => {
39
+ const { config } = components.value[name.value];
40
+
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
+ const save = async() => {
51
+ if(loading.value) { return; }
52
+
53
+ // 校验表单
54
+ if(!schemaFormRef.value.validate()) { return; }
55
+
56
+ loading.value = true;
57
+
58
+ const res = await $curl({
59
+ method: 'post',
60
+ url: api.value,
61
+ data: {
62
+ ...schemaFormRef.value.getValue(),
63
+ },
64
+ });
65
+ loading.value = false;
66
+ if(res?.success) {
67
+ ElNotification.success({
68
+ title: '创建成功',
69
+ message: '创建成功'
70
+ });
71
+ isShow.value = false;
72
+ } else {
73
+ ElNotification.error({
74
+ title: '创建失败',
75
+ message: '创建失败'
76
+ });
77
+ }
78
+ close();
79
+ emit('command', {event: 'loadTableData'});
80
+ }
81
+
82
+ defineExpose({ name, show })
83
+ </script>
84
+
85
+ <style lang="less" scoped>
86
+
87
+ </style>