@siven-li/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 (78) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc +55 -0
  3. package/README.md +201 -0
  4. package/app/controller/base.js +37 -0
  5. package/app/controller/project.js +65 -0
  6. package/app/controller/view.js +20 -0
  7. package/app/extend/logger.js +35 -0
  8. package/app/middleware/api-params-verify.js +97 -0
  9. package/app/middleware/api-sign-verify.js +30 -0
  10. package/app/middleware/error-handler.js +34 -0
  11. package/app/middleware/project-handler.js +22 -0
  12. package/app/middleware.js +37 -0
  13. package/app/pages/assets/custom.css +16 -0
  14. package/app/pages/boot.js +53 -0
  15. package/app/pages/common/curl.js +74 -0
  16. package/app/pages/common/utils.js +2 -0
  17. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +35 -0
  18. package/app/pages/dashboard/complex-view/header-view/header-view.vue +132 -0
  19. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +45 -0
  20. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +37 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +130 -0
  22. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +23 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +90 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +110 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +133 -0
  26. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +125 -0
  27. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +97 -0
  28. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +35 -0
  29. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +127 -0
  30. package/app/pages/dashboard/dashboard.vue +94 -0
  31. package/app/pages/dashboard/entry.dashboard.js +43 -0
  32. package/app/pages/store/index.js +3 -0
  33. package/app/pages/store/menu.js +59 -0
  34. package/app/pages/store/project.js +17 -0
  35. package/app/pages/widgets/header-container/assets/avatar.png +0 -0
  36. package/app/pages/widgets/header-container/assets/logo.png +0 -0
  37. package/app/pages/widgets/header-container/header-container.vue +124 -0
  38. package/app/pages/widgets/schema-form/complex-view/input/input.vue +143 -0
  39. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +141 -0
  40. package/app/pages/widgets/schema-form/complex-view/select/select.vue +127 -0
  41. package/app/pages/widgets/schema-form/form-item-config.js +22 -0
  42. package/app/pages/widgets/schema-form/schema-form.vue +129 -0
  43. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +49 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +43 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +50 -0
  47. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +133 -0
  48. package/app/pages/widgets/schema-search-bar/search-item-config.js +26 -0
  49. package/app/pages/widgets/schema-table/schema-table.vue +234 -0
  50. package/app/pages/widgets/sider-container/sider-container.vue +32 -0
  51. package/app/public/static/logo.png +0 -0
  52. package/app/public/static/normalize.css +239 -0
  53. package/app/router/project.js +6 -0
  54. package/app/router/view.js +9 -0
  55. package/app/router-schema/project.js +30 -0
  56. package/app/service/base.js +12 -0
  57. package/app/service/project.js +44 -0
  58. package/app/view/entry.tpl +26 -0
  59. package/app/webpack/config/webpack.base.js +194 -0
  60. package/app/webpack/config/webpack.dev.js +58 -0
  61. package/app/webpack/config/webpack.prod.js +114 -0
  62. package/app/webpack/dev.js +48 -0
  63. package/app/webpack/libs/blank.js +1 -0
  64. package/app/webpack/prod.js +18 -0
  65. package/config/config.default.js +3 -0
  66. package/elpis-core/env.js +20 -0
  67. package/elpis-core/index.js +88 -0
  68. package/elpis-core/loader/config.js +55 -0
  69. package/elpis-core/loader/controller.js +56 -0
  70. package/elpis-core/loader/extend.js +45 -0
  71. package/elpis-core/loader/middleware.js +58 -0
  72. package/elpis-core/loader/router-schema.js +38 -0
  73. package/elpis-core/loader/router.js +40 -0
  74. package/elpis-core/loader/service.js +56 -0
  75. package/index.js +39 -0
  76. package/model/index.js +104 -0
  77. package/package.json +93 -0
  78. package/test/controll/project.test.js +203 -0
@@ -0,0 +1,53 @@
1
+ // Vue 使用 createSSRApp 创建应用,并在客户端调用 hydrate 方法
2
+ // createSSRApp 是 Vue 3 SSR 开发的标准入口,用于确保服务端渲染的内容能在客户端被高效、无缝地复用
3
+ import { createSSRApp } from 'vue';
4
+
5
+ // 引入 ElemnetPlus 组件库
6
+ import ElementPlus from 'element-plus';
7
+ import 'element-plus/theme-chalk/index.css';
8
+ import 'element-plus/theme-chalk/dark/css-vars.css';
9
+
10
+ import './assets/custom.css'
11
+
12
+ import pinia from '$elpisStore';
13
+
14
+ import { createRouter, createWebHistory } from 'vue-router';
15
+
16
+
17
+ /**
18
+ * vue 页面主入口,用于启动 vue
19
+ * @params pageComponent vue 入口组件
20
+ * @params routes 页面路由配置
21
+ * @params libs 页面所需的第三方库
22
+ */
23
+ export default (pageComponent, { routes, libs } = {}) => {
24
+ // 挂载时自动尝试水合
25
+ const app = createSSRApp(pageComponent);
26
+
27
+ // 应用 elementui
28
+ app.use(ElementPlus);
29
+
30
+ // 应用 pinia
31
+ app.use(pinia);
32
+
33
+ // 引入第三方包
34
+ if (libs && libs.length) {
35
+ for (let i = 0; i < libs.length; i++) {
36
+ app.use(libs[i]);
37
+ }
38
+ };
39
+
40
+ // 页面路由
41
+ if (routes && routes.length) {
42
+ const router = createRouter({
43
+ history: createWebHistory(), // 使用 history 路由
44
+ routes
45
+ })
46
+ app.use(router);
47
+ router.isReady().then(() => {
48
+ app.mount('#root');
49
+ })
50
+ } else {
51
+ app.mount('#root');
52
+ }
53
+ }
@@ -0,0 +1,74 @@
1
+ const md5 = require('md5');
2
+ import { ElMessage } from 'element-plus';
3
+
4
+ /**
5
+ * 前端封装 curl 方法
6
+ * @params options 请求参数
7
+ */
8
+ const curl = ({
9
+ url, // 请求地址
10
+ method = 'post', // 请求方法
11
+ query = {}, // url query参数
12
+ data = {}, // post body参数
13
+ headers = {}, // 请求头
14
+ timeout = 60000, // 请求超时时间
15
+ responseType = 'json', // 响应类型
16
+ errorMsg = '网络异常'
17
+ }) => {
18
+ // 接口签名处理
19
+ const signKey = 'li11shi08z2cx3shi0wen920';
20
+ const st = Date.now();
21
+ const dtoHeaders = {
22
+ ...headers,
23
+ s_t: st,
24
+ s_sign: md5(`${signKey}_${st}`)
25
+ }
26
+ if (url.indexOf('/api/proj/') > -1 && window.projKey) {
27
+ dtoHeaders.proj_key = window.projKey;
28
+ }
29
+
30
+ // 构造请求参数(把参数转为 axios 参数)
31
+ const axiosParams = {
32
+ url,
33
+ method,
34
+ params: query,
35
+ data,
36
+ responseType,
37
+ timeout,
38
+ headers: dtoHeaders
39
+ }
40
+ return axios.request(axiosParams).then((response) => {
41
+ const resData = response.data || {};
42
+ const { success } = resData;
43
+ // 失败
44
+ if (!success) {
45
+ const { message, code } = resData;
46
+ if (code === 442) {
47
+ ElMessage.error('请求参数异常');
48
+ } else if (code === 445) {
49
+ ElMessage.error('请求不合法');
50
+ } else if (code === 446) {
51
+ ElMessage.error('缺少项目必要参数');
52
+ } else if (code === 50000) {
53
+ ElMessage.error(message);
54
+ } else {
55
+ ElMessage.error(errorMsg);
56
+ }
57
+ console.log(message);
58
+ return Promise.resolve({ success, code, message });
59
+ }
60
+ // 成功
61
+ const { data, metadata } = resData;
62
+ return Promise.resolve({ success, data, metadata });
63
+ }).catch((error) => {
64
+ const { message } = error;
65
+ if (message.match(/timeout/i)) {
66
+ return Promise.resolve({
67
+ message: '请求超时',
68
+ code: 504
69
+ })
70
+ };
71
+ return Promise.resolve(error);
72
+ });
73
+ }
74
+ export default curl;
@@ -0,0 +1,2 @@
1
+ const utils = {};
2
+ export default utils;
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <el-sub-menu :index="menuItem.key">
3
+ <template #title>
4
+ {{ menuItem.name }}
5
+ </template>
6
+ <div
7
+ v-for="item in menuItem.subMenu"
8
+ :key="item.key"
9
+ >
10
+ <sub-menu
11
+ v-if="item.subMenu && item.subMenu.length > 0"
12
+ :menu-item="item"
13
+ />
14
+ <el-menu-item
15
+ v-else
16
+ :index="item.key"
17
+ >
18
+ {{ item.name }}
19
+ </el-menu-item>
20
+ </div>
21
+ </el-sub-menu>
22
+ </template>
23
+
24
+ <script setup>
25
+ const { menuItem } = defineProps({
26
+ menuItem: {
27
+ type: Object,
28
+ required: true
29
+ }
30
+ });
31
+ </script>
32
+
33
+ <style lang="less" scoped>
34
+
35
+ </style>
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <header-container :title="projName">
3
+ <template #menu-panel>
4
+ <!-- 根据 menuStore.menuList 渲染菜单 -->
5
+ <el-menu
6
+ :default-active="activeKey"
7
+ :ellipsis="false"
8
+ mode="horizontal"
9
+ @select="onMenuSelect"
10
+ >
11
+ <template
12
+ v-for="item in menuStore.menuList"
13
+ >
14
+ <sub-menu
15
+ v-if="item.subMenu && item.subMenu.length > 0"
16
+ :key="item.key"
17
+ :menu-item="item"
18
+ />
19
+ <el-menu-item
20
+ v-else
21
+ :key="item.name + item.key"
22
+ :index="item.key"
23
+ >
24
+ {{ item.name }}
25
+ </el-menu-item>
26
+ </template>
27
+ </el-menu>
28
+ </template>
29
+ <template #setting-content>
30
+ <!-- 根据 projectStore.projectList 渲染 -->
31
+ <el-dropdown @command="handleProjCommand">
32
+ <span class="project-list">
33
+ {{ projName }}
34
+ <el-icon
35
+ v-if="projectStore.projectList.length > 1"
36
+ class="el-icon--right"
37
+ >
38
+ <ArrowDown />
39
+ </el-icon>
40
+ </span>
41
+ <template
42
+ v-if="projectStore.projectList.length > 1"
43
+ #dropdown
44
+ >
45
+ <el-dropdown-menu>
46
+ <el-dropdown-item
47
+ v-for="item in projectStore.projectList"
48
+ :key="item.key"
49
+ :command="item.key"
50
+ :disabled="item.name === projName"
51
+ >
52
+ {{ item.name }}
53
+ </el-dropdown-item>
54
+ </el-dropdown-menu>
55
+ </template>
56
+ </el-dropdown>
57
+ </template>
58
+ <template #main-content>
59
+ <slot name="main-content" />
60
+ </template>
61
+ </header-container>
62
+ </template>
63
+ <script setup>
64
+ import { ref, watch, onMounted } from 'vue';
65
+ import { useRoute } from 'vue-router';
66
+ import { ArrowDown } from '@element-plus/icons-vue';
67
+ import HeaderContainer from '$elpisWidgets/header-container/header-container.vue';
68
+ import SubMenu from './complex-view/sub-menu/sub-menu.vue'
69
+ import { useMenuStore } from '$elpisStore/menu.js'
70
+ import { useProjectStore } from '$elpisStore/project.js'
71
+
72
+ const route = useRoute();
73
+
74
+ const menuStore = useMenuStore();
75
+ const projectStore = useProjectStore();
76
+
77
+ defineProps({
78
+ projName: {
79
+ type: String,
80
+ default: ''
81
+ }
82
+ });
83
+
84
+ const emit = defineEmits([ 'menu-select' ]);
85
+
86
+ const activeKey = ref('');
87
+
88
+ watch(() => route.query.key, () => {
89
+ setActiveKey();
90
+ });
91
+ watch(() => menuStore.menuList, () => {
92
+ setActiveKey();
93
+ }, { deep: true })
94
+ onMounted(() => {
95
+ setActiveKey();
96
+ })
97
+
98
+ const setActiveKey = () => {
99
+ const menuItem = menuStore.findMenuItem({
100
+ key: 'key',
101
+ value: route.query.key
102
+ })
103
+ activeKey.value = menuItem?.key;
104
+ }
105
+
106
+ const onMenuSelect = (menuKey) => {
107
+ const menuItem = menuStore.findMenuItem({
108
+ key: 'key',
109
+ value: menuKey
110
+ });
111
+ emit('menu-select', menuItem);
112
+ }
113
+ const handleProjCommand = (event) => {
114
+ const projItem = projectStore.projectList.find(item => item.key === event);
115
+ if (!projItem || !projItem.homePage) return;
116
+ const { origin } = window.location;
117
+ window.location.replace(`${origin}/view/dashboard${projItem.homePage}`);
118
+ }
119
+ </script>
120
+ <style lang="less" scoped>
121
+ .project-list {
122
+ margin-right: 20px;
123
+ cursor: pointer;
124
+ color: var(--el-color-primary);
125
+ display: flex;
126
+ align-items: center;
127
+ outline: none;
128
+ }
129
+ :deep(.el-menu--horizontal.el-menu) {
130
+ border-bottom: 0px;
131
+ }
132
+ </style>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <iframe
3
+ :src="path"
4
+ class="iframe"
5
+ />
6
+ </template>
7
+
8
+ <script setup>
9
+ import {ref, watch, onMounted} from 'vue';
10
+ import { useRoute } from 'vue-router';
11
+ import { useMenuStore } from '$elpisStore/menu.js';
12
+
13
+ const route = useRoute();
14
+ const menuStore = useMenuStore();
15
+
16
+ const path = ref('');
17
+ const setPath = () => {
18
+ const { key, sider_key: siderKey } = route.query;
19
+ const menuItem = menuStore.findMenuItem({
20
+ key: 'key',
21
+ value: siderKey ?? key
22
+ });
23
+ path.value = menuItem?.iframeConfig?.path ?? '';
24
+ };
25
+
26
+ watch([
27
+ () => route.query.key,
28
+ () => route.query.sider_key,
29
+ () => menuStore.menuList
30
+ ], () => {
31
+ setPath();
32
+ }, { deep: true });
33
+
34
+ onMounted(() => {
35
+ setPath();
36
+ });
37
+ </script>
38
+
39
+ <style lang="less" scoped>
40
+ .iframe {
41
+ width: 100%;
42
+ height: 100%;
43
+ border: 0;
44
+ }
45
+ </style>
@@ -0,0 +1,37 @@
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
+ />
9
+ </el-card>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { inject } from 'vue';
14
+ import schemaSearchBar from '$elpisWidgets/schema-search-bar/schema-search-bar.vue';
15
+ const { searchSchema } = inject('schemaViewData');
16
+
17
+ const emit = defineEmits(['search']);
18
+
19
+ const onLoad = (searchValObj) => {
20
+ emit('search', searchValObj);
21
+ }
22
+ const onSearch = (searchValObj) => {
23
+ emit('search', searchValObj);
24
+ }
25
+ const onReset = () => {
26
+ emit('search', {});
27
+ }
28
+ </script>
29
+
30
+ <style lang="less" scoped>
31
+ .search-panel {
32
+ margin: 10px 10px 0 10px;
33
+ }
34
+ :deep(.el-card__body) {
35
+ padding-bottom: 2px;
36
+ };
37
+ </style>
@@ -0,0 +1,130 @@
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
+ :key="item"
12
+ v-bind="item"
13
+ @click="operationHandler( { 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
+ :api-params="apiParams"
24
+ :buttons="tableConfig?.rowButtons ?? []"
25
+ @operate="operationHandler"
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 {
39
+ api,
40
+ apiParams,
41
+ tableSchema,
42
+ tableConfig
43
+ } = inject('schemaViewData');
44
+
45
+ const schemaTableRef = ref(null);
46
+
47
+ const EventHandlerMap = {
48
+ remove: removeData
49
+ };
50
+
51
+ const operationHandler = ({ btnConfig, rowData }) => {
52
+ const { eventKey } = btnConfig;
53
+ if (EventHandlerMap[eventKey]) {
54
+ EventHandlerMap[eventKey]({ btnConfig, rowData })
55
+ } else {
56
+ emit('operate', { btnConfig, rowData })
57
+ }
58
+ }
59
+
60
+ function removeData({ btnConfig, rowData }) {
61
+ const { eventOption } = btnConfig;
62
+ if (!eventOption?.params) return;
63
+
64
+ const { params } = eventOption;
65
+ const removeKey = Object.keys(params)[0];
66
+ let removeValue;
67
+ const removeValueList = params[removeKey].split('::');
68
+ if (removeValueList[0] === 'schema' && removeValueList[1]) {
69
+ removeValue = rowData[removeValueList[1]];
70
+ }
71
+ ElMessageBox.confirm(
72
+ `确认删除${removeKey}为:${removeValue}数据?`,
73
+ 'Warning',
74
+ {
75
+ confirmButtonText: '确认',
76
+ cancelButtonText: '取消',
77
+ type: 'warning'
78
+ }
79
+ ).then(async () => {
80
+ schemaTableRef.value.showLoading();
81
+ const res = await $curl({
82
+ method: 'delete',
83
+ url: api.value,
84
+ data: {
85
+ [removeKey]: removeValue
86
+ },
87
+ errorMsg: '删除失败'
88
+ })
89
+ schemaTableRef.value.hideLoading();
90
+
91
+ if (!res || !res.success || !res.data) return;
92
+ ElNotification({
93
+ title: '提示',
94
+ message: '删除成功',
95
+ type: 'success'
96
+ });
97
+ await initTableData();
98
+ })
99
+ }
100
+
101
+ const loadTableData = async () => {
102
+ await schemaTableRef.value.loadTableData();
103
+ }
104
+
105
+ const initTableData = async () => {
106
+ await schemaTableRef.value.initData();
107
+ }
108
+
109
+ defineExpose({
110
+ loadTableData,
111
+ initTableData
112
+ })
113
+
114
+ </script>
115
+
116
+ <style lang="less" scoped>
117
+ .table-panel{
118
+ flex: 1;
119
+ margin: 10px;
120
+
121
+ .operation-panel {
122
+ margin-bottom: 10px;
123
+ }
124
+ }
125
+ :deep(.el-card__body) {
126
+ height: 98%;
127
+ display: flex;
128
+ flex-direction: column;
129
+ }
130
+ </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,90 @@
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>
10
+ {{ title }}
11
+ </h3>
12
+ </template>
13
+ <template #default>
14
+ <SchemaForm
15
+ ref="schemaFormRef"
16
+ v-loading="loading"
17
+ :schema="components[name]?.schema"
18
+ />
19
+ </template>
20
+ <template #footer>
21
+ <el-button
22
+ type="primary"
23
+ @click="save"
24
+ >
25
+ {{ saveBtnText }}
26
+ </el-button>
27
+ </template>
28
+ </el-drawer>
29
+ </template>
30
+ <script setup>
31
+ import { ref, inject } from 'vue';
32
+ import $curl from '$elpisCommon/curl.js';
33
+ import { ElNotification } from 'element-plus';
34
+ import SchemaForm from '$elpisWidgets/schema-form/schema-form.vue';
35
+
36
+ const { api, components } = inject('schemaViewData');
37
+
38
+ const emit = defineEmits('command');
39
+
40
+ const name = ref('createForm');
41
+ const isShow = ref(false);
42
+ const title = ref('');
43
+ const saveBtnText = ref('');
44
+ const schemaFormRef = ref(null);
45
+ const loading = ref(false);
46
+
47
+ const show = () => {
48
+ const { title: ttileCon, saveBtnText: saveBtnTextCon } = components.value[name.value].config;
49
+ title.value = ttileCon;
50
+ saveBtnText.value = saveBtnTextCon;
51
+ isShow.value = true;
52
+ }
53
+
54
+ const close = () => {
55
+ isShow.value = false;
56
+ }
57
+
58
+ const save = async () => {
59
+ if (loading.value) return;
60
+ if (!schemaFormRef.value.validate()) return;
61
+
62
+ loading.value = true;
63
+ const res = await $curl({
64
+ method: 'post',
65
+ url: api.value,
66
+ data: {
67
+ ... schemaFormRef.value.getValue()
68
+ }
69
+ })
70
+ loading.value = false;
71
+
72
+ if (!res || !res.success) return;
73
+ ElNotification({
74
+ title: '创建成功',
75
+ message: '创建成功'
76
+ });
77
+ close();
78
+ emit('command', {
79
+ event: 'loadTableData'
80
+ });
81
+ }
82
+
83
+ defineExpose({
84
+ name,
85
+ show
86
+ })
87
+ </script>
88
+ <style lang="less" scoped>
89
+
90
+ </style>