@yukihong/schema-admin-x 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 +55 -0
- package/README.md +208 -0
- package/app/controller/base.js +39 -0
- package/app/controller/project.js +80 -0
- package/app/controller/view.js +20 -0
- package/app/extend/logger.js +39 -0
- package/app/middleware/api-params-verify.js +79 -0
- package/app/middleware/api-sign-verify.js +34 -0
- package/app/middleware/error-handler.js +34 -0
- package/app/middleware/project-handler.js +27 -0
- package/app/middleware.js +40 -0
- package/app/pages/asserts/custom.css +13 -0
- package/app/pages/boot.js +53 -0
- package/app/pages/common/curl.js +91 -0
- package/app/pages/common/utils.js +3 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +21 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +127 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +44 -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 +131 -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 +100 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +106 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +131 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +126 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +102 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +26 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +128 -0
- package/app/pages/dashboard/dashboard.vue +99 -0
- package/app/pages/dashboard/entry.dashboard.js +44 -0
- package/app/pages/store/index.js +4 -0
- package/app/pages/store/menu.js +61 -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 +109 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +146 -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 +121 -0
- package/app/pages/widgets/schema-form/form-item-config.js +23 -0
- package/app/pages/widgets/schema-form/schema-form.vue +131 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +50 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +65 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +44 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +51 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +127 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
- package/app/pages/widgets/schema-table/schema-table.vue +248 -0
- package/app/pages/widgets/sider-container/sider-container.vue +28 -0
- package/app/public/static/logo.png +0 -0
- package/app/public/static/normalize.css +239 -0
- package/app/router/project.js +7 -0
- package/app/router/view.js +10 -0
- package/app/router-schema/project.js +30 -0
- package/app/service/base.js +13 -0
- package/app/service/project.js +50 -0
- package/app/view/entry.tpl +25 -0
- package/app/webpack/config/webpack.base.js +213 -0
- package/app/webpack/config/webpack.dev.js +61 -0
- package/app/webpack/config/webpack.prod.js +124 -0
- package/app/webpack/dev.js +63 -0
- package/app/webpack/libs/blank.js +1 -0
- package/app/webpack/prod.js +19 -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 +99 -0
- package/elpis-core/loader/config.js +52 -0
- package/elpis-core/loader/controller.js +75 -0
- package/elpis-core/loader/extend.js +55 -0
- package/elpis-core/loader/middleware.js +64 -0
- package/elpis-core/loader/router-schema.js +47 -0
- package/elpis-core/loader/router.js +59 -0
- package/elpis-core/loader/service.js +75 -0
- package/index.js +40 -0
- package/model/index.js +102 -0
- package/package.json +93 -0
- package/test/controller/project.test.js +217 -0
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
<h4>{{title}}</h4>
|
|
10
|
+
</template>
|
|
11
|
+
<template #default>
|
|
12
|
+
<el-card v-loading="loading" shadow="always" class="detail-panel">
|
|
13
|
+
<el-row
|
|
14
|
+
v-for="(item,key) in components[name]?.schema?.properties"
|
|
15
|
+
:key="key"
|
|
16
|
+
type="flex"
|
|
17
|
+
align="middle"
|
|
18
|
+
class="row-item"
|
|
19
|
+
>
|
|
20
|
+
<el-row class="item-label">{{item.label}}:</el-row>
|
|
21
|
+
<el-row class="item-value">{{dtoModel[key]}}:</el-row>
|
|
22
|
+
</el-row>
|
|
23
|
+
</el-card>
|
|
24
|
+
</template>
|
|
25
|
+
</el-drawer>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup>
|
|
29
|
+
import { ref, inject } from 'vue';
|
|
30
|
+
import $curl from '$elpisCommon/curl.js';
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
api,
|
|
34
|
+
components
|
|
35
|
+
} = inject('schemaViewData');
|
|
36
|
+
|
|
37
|
+
const name = ref('detailPanel');
|
|
38
|
+
const isShow = ref(false);
|
|
39
|
+
const loading = ref(false);
|
|
40
|
+
const title = ref('');
|
|
41
|
+
const mainKey = ref('');
|
|
42
|
+
const mainValue = ref();
|
|
43
|
+
const dtoModel = ref({});
|
|
44
|
+
|
|
45
|
+
const show = (rowData) => {
|
|
46
|
+
const { config } = components.value[name.value];
|
|
47
|
+
|
|
48
|
+
title.value = config.title;
|
|
49
|
+
mainKey.value = config.mainKey; // 表单主键
|
|
50
|
+
mainValue.value = rowData[config.mainKey]; // 表单主键值
|
|
51
|
+
dtoModel.value = {};
|
|
52
|
+
|
|
53
|
+
isShow.value = true;
|
|
54
|
+
|
|
55
|
+
fetchFormData();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const fetchFormData = async () => {
|
|
60
|
+
if(loading.value) { return; }
|
|
61
|
+
|
|
62
|
+
loading.value = true;
|
|
63
|
+
const res = await $curl({
|
|
64
|
+
method: 'get',
|
|
65
|
+
url: api.value,
|
|
66
|
+
query: {
|
|
67
|
+
[mainKey.value]: mainValue.value
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
loading.value = false;
|
|
71
|
+
|
|
72
|
+
if(!res || !res.success || !res.data) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
dtoModel.value = res.data;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
defineExpose({
|
|
80
|
+
name,
|
|
81
|
+
show
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<style lang="less" scoped>
|
|
87
|
+
.detail-panel {
|
|
88
|
+
border: 1px solid #a6a6a6;
|
|
89
|
+
padding: 30px;
|
|
90
|
+
|
|
91
|
+
.row-item {
|
|
92
|
+
height: 40px;
|
|
93
|
+
line-height: 40px;
|
|
94
|
+
font-size: 20px;
|
|
95
|
+
|
|
96
|
+
.item-label {
|
|
97
|
+
margin-right: 20px;
|
|
98
|
+
width: 120px;
|
|
99
|
+
color: #fff;
|
|
100
|
+
}
|
|
101
|
+
.item-value {
|
|
102
|
+
color: #d2dae4;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
</style>
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
<h4>{{title}}</h4>
|
|
10
|
+
</template>
|
|
11
|
+
<template #default>
|
|
12
|
+
<schema-form
|
|
13
|
+
ref="schemaFormRef"
|
|
14
|
+
v-loading="loading"
|
|
15
|
+
:schema="components[name]?.schema"
|
|
16
|
+
:model="dtoModel"
|
|
17
|
+
></schema-form>
|
|
18
|
+
</template>
|
|
19
|
+
<template #footer>
|
|
20
|
+
<el-button
|
|
21
|
+
type="primary"
|
|
22
|
+
@click="save"
|
|
23
|
+
>{{saveBtnText}}</el-button>
|
|
24
|
+
</template>
|
|
25
|
+
</el-drawer>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup>
|
|
29
|
+
import { ref, inject } from 'vue';
|
|
30
|
+
import { ElNotification } from 'element-plus';
|
|
31
|
+
import $curl from '$elpisCommon/curl.js';
|
|
32
|
+
import SchemaForm from '$elpisWidgets/schema-form/schema-form.vue';
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
api,
|
|
36
|
+
components
|
|
37
|
+
} = inject('schemaViewData');
|
|
38
|
+
|
|
39
|
+
const emit = defineEmits([ 'command' ]);
|
|
40
|
+
|
|
41
|
+
const name = ref('editForm');
|
|
42
|
+
|
|
43
|
+
const schemaFormRef = ref(null);
|
|
44
|
+
const isShow = ref(false);
|
|
45
|
+
const loading = ref(false);
|
|
46
|
+
const title = ref('');
|
|
47
|
+
const saveBtnText = ref('');
|
|
48
|
+
const mainKey = ref('');
|
|
49
|
+
const mainValue = ref();
|
|
50
|
+
const dtoModel = ref({});
|
|
51
|
+
|
|
52
|
+
const show = (rowData) => {
|
|
53
|
+
const { config } = components.value[name.value];
|
|
54
|
+
title.value = config.title;
|
|
55
|
+
saveBtnText.value = config.saveBtnText;
|
|
56
|
+
mainKey.value = config.mainKey; // 表单主键
|
|
57
|
+
mainValue.value = rowData[config.mainKey]; // 表单主键值
|
|
58
|
+
dtoModel.value = {};
|
|
59
|
+
|
|
60
|
+
isShow.value = true;
|
|
61
|
+
|
|
62
|
+
fetchFormData();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const close = () => {
|
|
66
|
+
isShow.value = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const fetchFormData = async () => {
|
|
70
|
+
if(loading.value) { return; }
|
|
71
|
+
|
|
72
|
+
loading.value = true;
|
|
73
|
+
const res = await $curl({
|
|
74
|
+
method: 'get',
|
|
75
|
+
url: api.value,
|
|
76
|
+
query: {
|
|
77
|
+
[mainKey.value]: mainValue.value
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
loading.value = false;
|
|
81
|
+
|
|
82
|
+
if(!res || !res.success || !res.data) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
dtoModel.value = res.data;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const save = async () => {
|
|
90
|
+
if(loading.value) { return; }
|
|
91
|
+
|
|
92
|
+
if(!schemaFormRef.value.validate()) { return; }
|
|
93
|
+
|
|
94
|
+
loading.value = true;
|
|
95
|
+
|
|
96
|
+
const res = await $curl({
|
|
97
|
+
method: 'put',
|
|
98
|
+
url: api.value,
|
|
99
|
+
data: {
|
|
100
|
+
[mainKey.value]: mainValue.value,
|
|
101
|
+
...schemaFormRef.value.getValue()
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
loading.value = false;
|
|
106
|
+
|
|
107
|
+
if(!res || !res.success) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
ElNotification({
|
|
112
|
+
title: '修改成功',
|
|
113
|
+
message: '修改成功',
|
|
114
|
+
type: 'success'
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
close();
|
|
118
|
+
|
|
119
|
+
emit('command', {
|
|
120
|
+
event: 'loadTableData'
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
defineExpose({
|
|
125
|
+
name,
|
|
126
|
+
show
|
|
127
|
+
});
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<style>
|
|
131
|
+
</style>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ref, watch, onMounted, nextTick } from 'vue';
|
|
2
|
+
import { useRoute } from 'vue-router';
|
|
3
|
+
import { useMenuStore } from '$elpisStore/menu.js';
|
|
4
|
+
|
|
5
|
+
export const useSchema = function() {
|
|
6
|
+
const route = useRoute();
|
|
7
|
+
const menuStore = useMenuStore();
|
|
8
|
+
|
|
9
|
+
const api = ref('');
|
|
10
|
+
const tableSchema = ref({});
|
|
11
|
+
const tableConfig = ref();
|
|
12
|
+
const searchSchema = ref({});
|
|
13
|
+
const searchConfig = ref();
|
|
14
|
+
const components = ref({});
|
|
15
|
+
|
|
16
|
+
// 构造 schemaConfig 相关配置,输送给 schemaView 解析
|
|
17
|
+
const buildData = function() {
|
|
18
|
+
const { key, sider_key: siderKey } = route.query;
|
|
19
|
+
const mItem = menuStore.findMenuItem({
|
|
20
|
+
key: 'key',
|
|
21
|
+
value: siderKey ?? key
|
|
22
|
+
});
|
|
23
|
+
if(mItem && mItem.schemaConfig) {
|
|
24
|
+
const { schemaConfig: sConfig } = mItem;
|
|
25
|
+
|
|
26
|
+
const configSchema = JSON.parse(JSON.stringify(sConfig.schema));
|
|
27
|
+
|
|
28
|
+
api.value = sConfig.api ?? '';
|
|
29
|
+
tableSchema.value = {};
|
|
30
|
+
tableConfig.value = undefined;
|
|
31
|
+
searchSchema.value = {};
|
|
32
|
+
searchSchema.value = undefined;
|
|
33
|
+
components.value = {};
|
|
34
|
+
|
|
35
|
+
nextTick(() => {
|
|
36
|
+
// 构造 tableSchema 和 tableConfig
|
|
37
|
+
tableSchema.value = buildDtoSchema(configSchema, 'table');
|
|
38
|
+
tableConfig.value = sConfig.tableConfig;
|
|
39
|
+
|
|
40
|
+
// 构造 searchSchema 和 searchConfig
|
|
41
|
+
const dtoSearchSchema = buildDtoSchema(configSchema, 'search');
|
|
42
|
+
// 处理当路由带指定搜索项和内容时,给搜索控件赋默认值
|
|
43
|
+
for(const key in dtoSearchSchema.properties) {
|
|
44
|
+
if(route.query[key] !== undefined) {
|
|
45
|
+
dtoSearchSchema.properties[key].option.default = route.query[key];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
searchSchema.value = dtoSearchSchema;
|
|
49
|
+
searchConfig.value = sConfig.searchConfig;
|
|
50
|
+
|
|
51
|
+
// 构造 components = { comKey: { schema: {}, config: {} }}
|
|
52
|
+
const { componentConfig } = sConfig;
|
|
53
|
+
if(componentConfig && Object.keys(componentConfig).length > 0) {
|
|
54
|
+
const dtoComponents = {};
|
|
55
|
+
|
|
56
|
+
for(const comName in componentConfig) {
|
|
57
|
+
dtoComponents[comName] = {
|
|
58
|
+
schema: buildDtoSchema(configSchema, comName),
|
|
59
|
+
config: componentConfig[comName]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
components.value = dtoComponents;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 通用构建 schema 方法(清除噪音)
|
|
69
|
+
const buildDtoSchema = (_schema, comName) => {
|
|
70
|
+
if(!_schema?.properties) { return {}; }
|
|
71
|
+
|
|
72
|
+
const dtoSchema = {
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 提取有效 schema 字段信息
|
|
78
|
+
for(const key in _schema.properties) {
|
|
79
|
+
const props = _schema.properties[key];
|
|
80
|
+
// tableOption searchBarOption ...
|
|
81
|
+
if(props[`${comName}Option`]) {
|
|
82
|
+
let dtoProps = {};
|
|
83
|
+
// 提取 props 中非 option 的部分,存放到 dtoProps 中
|
|
84
|
+
for(const pKey in props) {
|
|
85
|
+
if(pKey.indexOf(Option) < 0) {
|
|
86
|
+
dtoProps[pKey] = props[pKey];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// 处理 comName Option
|
|
90
|
+
dtoProps = Object.assign({}, dtoProps, { 'option': props[`${comName}Option`]});
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
// 处理 required 字段
|
|
94
|
+
const { required } = _schema;
|
|
95
|
+
if(required && required.find(pk => pk === key)) {
|
|
96
|
+
dtoProps.option.required = true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
dtoSchema.properties[key] = dtoProps;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return dtoSchema;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
watch([
|
|
107
|
+
() => route.query.key,
|
|
108
|
+
() => route.query.sider_key,
|
|
109
|
+
() => menuStore.menuList
|
|
110
|
+
], () => {
|
|
111
|
+
buildData();
|
|
112
|
+
}, { deep: true})
|
|
113
|
+
|
|
114
|
+
onMounted(() => {
|
|
115
|
+
buildData();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
api,
|
|
120
|
+
tableSchema,
|
|
121
|
+
tableConfig,
|
|
122
|
+
searchSchema,
|
|
123
|
+
searchConfig,
|
|
124
|
+
components
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-row class="schema-view">
|
|
3
|
+
<search-panel
|
|
4
|
+
v-if="searchSchema?.properties && Object.keys(searchSchema.properties).length > 0"
|
|
5
|
+
@search="onSearch"
|
|
6
|
+
></search-panel>
|
|
7
|
+
<table-panel
|
|
8
|
+
ref="tablePanelRef"
|
|
9
|
+
@operate="onTableOperate"
|
|
10
|
+
></table-panel>
|
|
11
|
+
<!-- 动态组件 -->
|
|
12
|
+
<component
|
|
13
|
+
v-for="(item,key) in components"
|
|
14
|
+
:key="key"
|
|
15
|
+
:is="ComponentConfig[key]?.component"
|
|
16
|
+
ref="comListRef"
|
|
17
|
+
@command="onComponentCommand"
|
|
18
|
+
></component>
|
|
19
|
+
</el-row>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup>
|
|
23
|
+
import { ref, provide } from 'vue';
|
|
24
|
+
import SearchPanel from './complex-view/search-panel/search-panel.vue';
|
|
25
|
+
import TablePanel from './complex-view/table-panel/table-panel.vue';
|
|
26
|
+
import ComponentConfig from './components/component-config';
|
|
27
|
+
import { useSchema } from './hook/schema.js';
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
api,
|
|
31
|
+
tableSchema,
|
|
32
|
+
tableConfig,
|
|
33
|
+
searchSchema,
|
|
34
|
+
searchConfig,
|
|
35
|
+
components
|
|
36
|
+
} = useSchema();
|
|
37
|
+
|
|
38
|
+
const apiParams = ref({});
|
|
39
|
+
provide('schemaViewData', {
|
|
40
|
+
api,
|
|
41
|
+
apiParams,
|
|
42
|
+
tableSchema,
|
|
43
|
+
tableConfig,
|
|
44
|
+
searchSchema,
|
|
45
|
+
searchConfig,
|
|
46
|
+
components
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const tablePanelRef = ref(null);
|
|
50
|
+
const comListRef = ref([]);
|
|
51
|
+
|
|
52
|
+
const onSearch = (searchValObj) => {
|
|
53
|
+
apiParams.value = searchValObj;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// table 事件映射
|
|
57
|
+
const EventHandlerMap = {
|
|
58
|
+
showComponent: showComponent
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const onTableOperate = ({ btnConfig, rowData }) => {
|
|
62
|
+
const { eventKey } = btnConfig;
|
|
63
|
+
if(EventHandlerMap[eventKey]) {
|
|
64
|
+
EventHandlerMap[eventKey]({ btnConfig, rowData })
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 展示动态组件
|
|
69
|
+
function showComponent({ btnConfig, rowData }) {
|
|
70
|
+
const { comName } = btnConfig.eventOption;
|
|
71
|
+
if(!comName) {
|
|
72
|
+
console.error(`未配置组件名`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const comRef = comListRef.value.find(item => {
|
|
76
|
+
return item.name === comName
|
|
77
|
+
});
|
|
78
|
+
if(!comRef || typeof comRef.show !== 'function' ) {
|
|
79
|
+
console.error(`找不到组件:${comName}`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
comRef.show(rowData);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 响应组件事件
|
|
86
|
+
const onComponentCommand = (data) => {
|
|
87
|
+
const { event } = data;
|
|
88
|
+
if(event === 'loadTableData') {
|
|
89
|
+
tablePanelRef.value.loadTableData();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style lang="less" scoped>
|
|
96
|
+
.schema-view {
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
height: 100%;
|
|
100
|
+
width: 100%;
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-sub-menu :index="menuItem.key" >
|
|
3
|
+
<template #title>
|
|
4
|
+
{{ menuItem.name }}
|
|
5
|
+
</template>
|
|
6
|
+
<div :key="item.key" v-for="item in menuItem.subMenu">
|
|
7
|
+
<sub-menu
|
|
8
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
9
|
+
:menu-item="item"
|
|
10
|
+
></sub-menu>
|
|
11
|
+
<el-menu-item
|
|
12
|
+
v-else
|
|
13
|
+
:index="item.key"
|
|
14
|
+
>
|
|
15
|
+
{{ item.name }}
|
|
16
|
+
</el-menu-item>
|
|
17
|
+
</div>
|
|
18
|
+
</el-sub-menu>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup>
|
|
22
|
+
const { menuItem } = defineProps(['menuItem']);
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<style lang="less" scoped>
|
|
26
|
+
</style>
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<sider-container>
|
|
3
|
+
<template #menu-content>
|
|
4
|
+
<el-menu
|
|
5
|
+
:default-active="activeKey"
|
|
6
|
+
:ellipsis="false"
|
|
7
|
+
@select="onMenuSelect"
|
|
8
|
+
>
|
|
9
|
+
<template v-for="item in menuList">
|
|
10
|
+
<!-- group -->
|
|
11
|
+
<sub-menu
|
|
12
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
13
|
+
:menu-item="item"
|
|
14
|
+
></sub-menu>
|
|
15
|
+
<!-- module -->
|
|
16
|
+
<el-menu-item
|
|
17
|
+
v-else
|
|
18
|
+
:index="item.key"
|
|
19
|
+
>
|
|
20
|
+
{{item.name}}
|
|
21
|
+
</el-menu-item>
|
|
22
|
+
</template>
|
|
23
|
+
</el-menu>
|
|
24
|
+
</template>
|
|
25
|
+
<template #main-content>
|
|
26
|
+
<router-view></router-view>
|
|
27
|
+
</template>
|
|
28
|
+
</sider-container>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup>
|
|
32
|
+
import { ref, watch, onMounted } from 'vue';
|
|
33
|
+
import { useRouter, useRoute } from 'vue-router';
|
|
34
|
+
import { useMenuStore } from '$elpisStore/menu.js';
|
|
35
|
+
import SiderContainer from '$elpisWidgets/sider-container/sider-container';
|
|
36
|
+
import SubMenu from './complex-view/sub-menu/sub-menu.vue';
|
|
37
|
+
|
|
38
|
+
const router = useRouter();
|
|
39
|
+
const route = useRoute();
|
|
40
|
+
const menuStore = useMenuStore();
|
|
41
|
+
|
|
42
|
+
const menuList = ref([]);
|
|
43
|
+
const setMenuList = function () {
|
|
44
|
+
const menuItem = menuStore.findMenuItem({
|
|
45
|
+
key: 'key',
|
|
46
|
+
value: route.query.key
|
|
47
|
+
});
|
|
48
|
+
if(menuItem && menuItem.siderConfig && menuItem.siderConfig.menu) {
|
|
49
|
+
menuList.value = menuItem.siderConfig.menu;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const activeKey = ref('');
|
|
55
|
+
const setActiveKey = function () {
|
|
56
|
+
let siderMenuItem = menuStore.findMenuItem({
|
|
57
|
+
key: 'key',
|
|
58
|
+
value: route.query.sider_key
|
|
59
|
+
});
|
|
60
|
+
// 如果首次加载 sider-view,用户未选中左侧菜单,需要默认选中第一个
|
|
61
|
+
if(!siderMenuItem) {
|
|
62
|
+
const hMenuItem = menuStore.findMenuItem({
|
|
63
|
+
key: 'key',
|
|
64
|
+
value: route.query.key
|
|
65
|
+
});
|
|
66
|
+
if(hMenuItem && hMenuItem.siderConfig && hMenuItem.siderConfig.menu) {
|
|
67
|
+
const siderMenuList = hMenuItem.siderConfig.menu;
|
|
68
|
+
siderMenuItem = menuStore.findFirstMenuItem(siderMenuList); // 找出左侧菜单中的第一项
|
|
69
|
+
if(siderMenuItem) {
|
|
70
|
+
handleMenuSelect(siderMenuItem.key);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
activeKey.value = siderMenuItem?.key;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
watch(() => route.query.key, () => {
|
|
80
|
+
setMenuList();
|
|
81
|
+
setActiveKey();
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
watch(() => menuStore.menuList, () => {
|
|
85
|
+
setMenuList();
|
|
86
|
+
setActiveKey();
|
|
87
|
+
}, { deep: true})
|
|
88
|
+
|
|
89
|
+
onMounted(() => {
|
|
90
|
+
setMenuList();
|
|
91
|
+
setActiveKey();
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const onMenuSelect = function (menuKey) {
|
|
95
|
+
handleMenuSelect(menuKey);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const handleMenuSelect = function(menuKey) {
|
|
99
|
+
const menuItem = menuStore.findMenuItem({
|
|
100
|
+
key: 'key',
|
|
101
|
+
value: menuKey
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const { moduleType, key, customConfig } = menuItem;
|
|
105
|
+
|
|
106
|
+
// 如果是当前页面,不处理
|
|
107
|
+
if(key === route.query.sider_key) { return; }
|
|
108
|
+
|
|
109
|
+
const pathMap = {
|
|
110
|
+
iframe: '/iframe',
|
|
111
|
+
schema: '/schema',
|
|
112
|
+
custom: customConfig?.path
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
router.push({
|
|
116
|
+
path: `/view/dashboard/sider${pathMap[moduleType]}`,
|
|
117
|
+
query: {
|
|
118
|
+
key:route.query.key,
|
|
119
|
+
sider_key: key,
|
|
120
|
+
proj_key: route.query.proj_key
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<style lang="less" scoped>
|
|
128
|
+
</style>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<el-config-provider :locale="zhCn">
|
|
4
|
+
<header-view :proj-name="projName" @menu-select="onMenuSelect">
|
|
5
|
+
<template #main-content>
|
|
6
|
+
<router-view></router-view>
|
|
7
|
+
</template>
|
|
8
|
+
</header-view>
|
|
9
|
+
</el-config-provider>
|
|
10
|
+
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup>
|
|
14
|
+
import { ref, onMounted } from 'vue';
|
|
15
|
+
import { useRouter, useRoute } from 'vue-router';
|
|
16
|
+
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
|
17
|
+
import HeaderView from './complex-view/header-view/header-view.vue';
|
|
18
|
+
import $curl from '$elpisCommon/curl.js';
|
|
19
|
+
import { useMenuStore } from '$elpisStore/menu';
|
|
20
|
+
import { useProjectStore } from '$elpisStore/project';
|
|
21
|
+
|
|
22
|
+
const router = useRouter();
|
|
23
|
+
const route = useRoute();
|
|
24
|
+
const menuStore = useMenuStore();
|
|
25
|
+
const projectStore = useProjectStore();
|
|
26
|
+
|
|
27
|
+
onMounted(() => {
|
|
28
|
+
getProjectList();
|
|
29
|
+
getProjectConfig();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const projName = ref('');
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// 请求 /api/project/list 接口,并缓存到 project-store 中
|
|
36
|
+
async function getProjectList() {
|
|
37
|
+
const res = await $curl({
|
|
38
|
+
method: 'get',
|
|
39
|
+
url: '/api/project/list',
|
|
40
|
+
query: {
|
|
41
|
+
proj_key: route.query.proj_key,
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if(!res || !res.success || !res.data) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
projectStore.setProjectList(res.data);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// 请求 /api/project 接口,并缓存到 menu-store 中
|
|
53
|
+
async function getProjectConfig() {
|
|
54
|
+
const res = await $curl({
|
|
55
|
+
method: 'get',
|
|
56
|
+
url: '/api/project',
|
|
57
|
+
query: {
|
|
58
|
+
proj_key: route.query.proj_key,
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if(!res || !res.success || !res.data) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const { name, menu } = res.data;
|
|
66
|
+
projName.value = name;
|
|
67
|
+
menuStore.setMenuList(menu);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 点击菜单回调方法
|
|
71
|
+
const onMenuSelect = function(menuItem) {
|
|
72
|
+
const { moduleType, key, customConfig } = menuItem;
|
|
73
|
+
|
|
74
|
+
// 如果是当前页面,不处理
|
|
75
|
+
if(key === route.query.key) { return; }
|
|
76
|
+
|
|
77
|
+
const pathMap = {
|
|
78
|
+
sider: '/sider',
|
|
79
|
+
iframe: '/iframe',
|
|
80
|
+
schema: '/schema',
|
|
81
|
+
custom: customConfig?.path
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
router.push({
|
|
85
|
+
path: `/view/dashboard${pathMap[moduleType]}`,
|
|
86
|
+
query: {
|
|
87
|
+
key,
|
|
88
|
+
proj_key: route.query.proj_key
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style lang="less" scoped>
|
|
96
|
+
:deep(.el-main) {
|
|
97
|
+
padding: 0;
|
|
98
|
+
}
|
|
99
|
+
</style>
|