@dmqweb/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 +3 -0
- package/.eslintrc +59 -0
- package/.vscode/settings.json +15 -0
- package/README.md +198 -0
- package/app/controller/base.js +41 -0
- package/app/controller/project.js +98 -0
- package/app/controller/view.js +24 -0
- package/app/extend/logger.js +43 -0
- package/app/middleware/api-params-verify.js +89 -0
- package/app/middleware/api-sign-verify.js +47 -0
- package/app/middleware/error-handler.js +41 -0
- package/app/middleware/project-handler.js +27 -0
- package/app/middleware.js +40 -0
- package/app/pages/asserts/custom.css +12 -0
- package/app/pages/boot.js +59 -0
- package/app/pages/common/curl.js +88 -0
- package/app/pages/common/util.js +3 -0
- package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +40 -0
- package/app/pages/dashboard/complex-view/header-view/header-view.vue +141 -0
- package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +39 -0
- package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +146 -0
- package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +24 -0
- package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +118 -0
- package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +177 -0
- package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +157 -0
- package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +150 -0
- package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +113 -0
- package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +35 -0
- package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +134 -0
- package/app/pages/dashboard/dashboard.vue +127 -0
- package/app/pages/dashboard/entry.dashboard.js +46 -0
- package/app/pages/store/index.js +5 -0
- package/app/pages/store/menu.js +61 -0
- package/app/pages/store/project.js +13 -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 +144 -0
- package/app/pages/widgets/schema-form/complex-view/input/input.vue +165 -0
- package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +166 -0
- package/app/pages/widgets/schema-form/complex-view/select/select.vue +144 -0
- package/app/pages/widgets/schema-form/form-item.config.js +24 -0
- package/app/pages/widgets/schema-form/schema-form.vue +144 -0
- package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +57 -0
- package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +77 -0
- package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +51 -0
- package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +58 -0
- package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +138 -0
- package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
- package/app/pages/widgets/schema-table/schema-table.vue +254 -0
- package/app/pages/widgets/sider-container/sider-container.vue +32 -0
- package/app/router/business.js +15 -0
- package/app/router/project.js +10 -0
- package/app/router/view.js +11 -0
- package/app/router-schema/business.js +82 -0
- package/app/router-schema/project.js +40 -0
- package/app/service/base.js +13 -0
- package/app/service/project.js +55 -0
- package/app/view/entry.tpl +27 -0
- package/app/webpack/config/blank.js +3 -0
- package/app/webpack/config/webpack.base.js +269 -0
- package/app/webpack/config/webpack.dev.js +61 -0
- package/app/webpack/config/webpack.prod.js +149 -0
- package/app/webpack/dev.js +58 -0
- package/app/webpack/prod.js +21 -0
- package/config/config.default.js +3 -0
- package/elpis-core/env.js +22 -0
- package/elpis-core/index.js +99 -0
- package/elpis-core/loader/config.js +51 -0
- package/elpis-core/loader/controller.js +75 -0
- package/elpis-core/loader/extend.js +54 -0
- package/elpis-core/loader/middleware.js +69 -0
- package/elpis-core/loader/router-schema.js +50 -0
- package/elpis-core/loader/router.js +52 -0
- package/elpis-core/loader/service.js +74 -0
- package/index.js +29 -0
- package/jsconfig.json +16 -0
- package/logs/applocation.log +3 -0
- package/model/index.js +119 -0
- package/package.json +93 -0
- package/test/controller/project.test.js +216 -0
|
@@ -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,134 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<sider-container>
|
|
3
|
+
<!-- 侧边栏 -->
|
|
4
|
+
<template #menu-content>
|
|
5
|
+
<el-menu
|
|
6
|
+
:default-active="activeKey"
|
|
7
|
+
:ellipsis="false"
|
|
8
|
+
@select="onMenuSelect"
|
|
9
|
+
>
|
|
10
|
+
<template v-for="item in menuList">
|
|
11
|
+
<!-- group -->
|
|
12
|
+
<sub-menu
|
|
13
|
+
v-if="item.subMenu && item.subMenu.length > 0"
|
|
14
|
+
:menu-item="item"
|
|
15
|
+
>
|
|
16
|
+
<!-- -->
|
|
17
|
+
</sub-menu>
|
|
18
|
+
<!-- module -->
|
|
19
|
+
<el-menu-item
|
|
20
|
+
v-else
|
|
21
|
+
:key="item.key"
|
|
22
|
+
:index="item.key"
|
|
23
|
+
>
|
|
24
|
+
{{ item.name }}
|
|
25
|
+
</el-menu-item>
|
|
26
|
+
</template>
|
|
27
|
+
</el-menu>
|
|
28
|
+
</template>
|
|
29
|
+
<!-- 主内容 -->
|
|
30
|
+
<template #main-content>
|
|
31
|
+
<router-view />
|
|
32
|
+
</template>
|
|
33
|
+
</sider-container>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
import { ref, watch, onMounted } from 'vue';
|
|
38
|
+
import { useRouter, useRoute } from 'vue-router';
|
|
39
|
+
import { useMenuStore } from '$elpisStore/menu.js'
|
|
40
|
+
import siderContainer from '$elpisWidgets/sider-container/sider-container.vue';
|
|
41
|
+
import subMenu from './complex-view/sub-menu/sub-menu.vue';
|
|
42
|
+
|
|
43
|
+
const router = useRouter();
|
|
44
|
+
const route = useRoute();
|
|
45
|
+
const menuStore = useMenuStore();
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
const menuList = ref([])
|
|
49
|
+
const setMenuList = function() {
|
|
50
|
+
const menuItem = menuStore.findMenuItem({
|
|
51
|
+
key: 'key',
|
|
52
|
+
value: route.query.key
|
|
53
|
+
})
|
|
54
|
+
if (menuItem && menuItem.siderConfig && menuItem.siderConfig.menu) {
|
|
55
|
+
menuList.value = menuItem.siderConfig.menu
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const activeKey = ref('');
|
|
60
|
+
// 设置 activeKey
|
|
61
|
+
const setActiveKey = function() {
|
|
62
|
+
let siderMenuItem = menuStore.findMenuItem({
|
|
63
|
+
key: 'key',
|
|
64
|
+
value: route.query.sider_key
|
|
65
|
+
})
|
|
66
|
+
// 首次加载时,没有 sider_key ,用户没有选择侧边栏菜单,则默认选择第一个菜单
|
|
67
|
+
if (!siderMenuItem) {
|
|
68
|
+
const hMenuList = menuStore.findMenuItem({
|
|
69
|
+
key: 'key',
|
|
70
|
+
value: route.query.key
|
|
71
|
+
})
|
|
72
|
+
if (hMenuList && hMenuList.siderConfig && hMenuList.siderConfig.menu) {
|
|
73
|
+
const siderMenuList = hMenuList.siderConfig.menu
|
|
74
|
+
siderMenuItem = menuStore.findFirstMenuItem(siderMenuList) // 递归查找第一个菜单
|
|
75
|
+
if (siderMenuItem) {
|
|
76
|
+
handleMenuSelect(siderMenuItem.key)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
activeKey.value = siderMenuItem?.key
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 监听路由变化,设置 activeKey
|
|
84
|
+
watch( [
|
|
85
|
+
() => route.query.key,
|
|
86
|
+
() => menuStore.getMenuList
|
|
87
|
+
], () => {
|
|
88
|
+
setActiveKey()
|
|
89
|
+
setMenuList()
|
|
90
|
+
},{ deep: true })
|
|
91
|
+
|
|
92
|
+
// 当页面加载完成并且该组件被挂载到DOM上时
|
|
93
|
+
onMounted(() => {
|
|
94
|
+
setActiveKey()
|
|
95
|
+
setMenuList()
|
|
96
|
+
})
|
|
97
|
+
const onMenuSelect = function(menuKey) {
|
|
98
|
+
handleMenuSelect(menuKey)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 菜单选择处理
|
|
102
|
+
const handleMenuSelect = function(menuKey) {
|
|
103
|
+
const siderMenuItem = menuStore.findMenuItem({
|
|
104
|
+
key: 'key',
|
|
105
|
+
value: menuKey
|
|
106
|
+
})
|
|
107
|
+
if (!siderMenuItem) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
const { key, moduleType, customConfig } = siderMenuItem
|
|
111
|
+
|
|
112
|
+
if (key === route.query.sider_key) {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
const pathMap = {
|
|
116
|
+
schema: '/schema',
|
|
117
|
+
iframe: '/iframe',
|
|
118
|
+
custom: customConfig?.path
|
|
119
|
+
}
|
|
120
|
+
router.push({
|
|
121
|
+
path: `/view/dashboard/sider${pathMap[moduleType]}`,
|
|
122
|
+
query: {
|
|
123
|
+
key: route.query.key,
|
|
124
|
+
sider_key: key,
|
|
125
|
+
proj_key: route.query.proj_key
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<style lang="scss" scoped>
|
|
133
|
+
|
|
134
|
+
</style>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-config-provider :locale="zhCn">
|
|
3
|
+
<header-view
|
|
4
|
+
:proj-name="projName"
|
|
5
|
+
@menu-select="onMenuSelect"
|
|
6
|
+
>
|
|
7
|
+
<!-- 主内容区域插槽插入 -->
|
|
8
|
+
<template #main-content>
|
|
9
|
+
<router-view />
|
|
10
|
+
</template>
|
|
11
|
+
</header-view>
|
|
12
|
+
</el-config-provider>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
|
17
|
+
import HeaderView from './complex-view/header-view/header-view.vue'
|
|
18
|
+
import { ref, onMounted } from 'vue'
|
|
19
|
+
import { useProjectStore } from '$elpisStore/project.js'
|
|
20
|
+
import { useMenuStore } from '$elpisStore/menu.js'
|
|
21
|
+
import $curl from '$elpisCommon/curl.js'
|
|
22
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
23
|
+
|
|
24
|
+
const projectStore = useProjectStore()
|
|
25
|
+
const menuStore = useMenuStore()
|
|
26
|
+
const projName = ref('')
|
|
27
|
+
const route = useRoute()
|
|
28
|
+
const router = useRouter()
|
|
29
|
+
const isLoading = ref(true)
|
|
30
|
+
|
|
31
|
+
onMounted( async () => {
|
|
32
|
+
try {
|
|
33
|
+
await getProjectList()
|
|
34
|
+
const configLoaded = await getProjectConfig()
|
|
35
|
+
|
|
36
|
+
if (configLoaded) {
|
|
37
|
+
// 等待一小段时间确保菜单数据完全设置
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
isLoading.value = false
|
|
40
|
+
}, 200)
|
|
41
|
+
} else {
|
|
42
|
+
console.error('项目配置加载失败')
|
|
43
|
+
isLoading.value = false
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error('初始化失败:', error)
|
|
47
|
+
isLoading.value = false
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// 请求 /api/project/list 并缓存到 project-store
|
|
52
|
+
async function getProjectList() {
|
|
53
|
+
const res = await $curl({
|
|
54
|
+
method: 'get',
|
|
55
|
+
url: '/api/project/list',
|
|
56
|
+
params: {
|
|
57
|
+
// todo 动态获取
|
|
58
|
+
proj_key: route.query.proj_key,
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
if (!res || !res.data || !res.success) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
projectStore.setProjectList(res.data)
|
|
66
|
+
}
|
|
67
|
+
// 请求 /api/project 并缓存到 menu-store
|
|
68
|
+
async function getProjectConfig() {
|
|
69
|
+
try {
|
|
70
|
+
const res = await $curl({
|
|
71
|
+
method: 'get',
|
|
72
|
+
url: '/api/project',
|
|
73
|
+
params: {
|
|
74
|
+
proj_key: route.query.proj_key,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!res || !res.data || !res.success) {
|
|
79
|
+
return false; // 返回失败状态
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { name, menu} = res.data
|
|
83
|
+
projName.value = name
|
|
84
|
+
menuStore.setMenuList(menu)
|
|
85
|
+
|
|
86
|
+
return true; // 返回成功状态
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('获取项目配置失败:', error)
|
|
89
|
+
return false; // 返回失败状态
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 点击菜单回调方法
|
|
94
|
+
const onMenuSelect = function(menuItem) {
|
|
95
|
+
const { moduleType, key, customConfig} = menuItem
|
|
96
|
+
|
|
97
|
+
if (key === route.query.key) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
// 菜单项的 moduleType 映射到对应的路由
|
|
101
|
+
const pathMap = {
|
|
102
|
+
sider: '/sider',
|
|
103
|
+
schema: '/schema',
|
|
104
|
+
iframe: '/iframe',
|
|
105
|
+
custom: customConfig?.path
|
|
106
|
+
}
|
|
107
|
+
router.push({
|
|
108
|
+
path: `/view/dashboard${pathMap[moduleType]}`,
|
|
109
|
+
query: {
|
|
110
|
+
key,
|
|
111
|
+
proj_key: route.query.proj_key
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<style scoped lang="less">
|
|
119
|
+
.global-loading {
|
|
120
|
+
width: 100vw;
|
|
121
|
+
height: 100vh;
|
|
122
|
+
position: relative;
|
|
123
|
+
}
|
|
124
|
+
:depp(el-main) {
|
|
125
|
+
padding: 0%;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import boot from '$elpisPage/boot.js'
|
|
2
|
+
import dashboard from './dashboard.vue'
|
|
3
|
+
import businessDashboardRouterConfig from "$businessDashboardRouterConfig";
|
|
4
|
+
|
|
5
|
+
const routes = []
|
|
6
|
+
|
|
7
|
+
// 头部菜单路由
|
|
8
|
+
routes.push({
|
|
9
|
+
path: '/view/dashboard/iframe',
|
|
10
|
+
component: () => import('./complex-view/iframe-view/iframe-view.vue')
|
|
11
|
+
})
|
|
12
|
+
routes.push({
|
|
13
|
+
path: '/view/dashboard/schema',
|
|
14
|
+
component: () => import('./complex-view/schema-view/schema-view.vue')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const siderRouters = [
|
|
18
|
+
{
|
|
19
|
+
path: 'schema',
|
|
20
|
+
component: () => import('./complex-view/schema-view/schema-view.vue')
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
path: 'iframe',
|
|
24
|
+
component: () => import('./complex-view/iframe-view/iframe-view.vue')
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// 侧边栏路由
|
|
29
|
+
routes.push({
|
|
30
|
+
path: '/view/dashboard/sider',
|
|
31
|
+
component: () => import('./complex-view/sider-view/sider-view.vue'),
|
|
32
|
+
children: siderRouters
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// 业务扩展路由
|
|
36
|
+
if(typeof businessDashboardRouterConfig === "function"){
|
|
37
|
+
businessDashboardRouterConfig({ routes , siderRouters })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 侧边栏路由兜底
|
|
41
|
+
routes.push({
|
|
42
|
+
path: '/view/dashboard/sider/:chapters+',
|
|
43
|
+
component: () => import('./complex-view/sider-view/sider-view.vue')
|
|
44
|
+
})
|
|
45
|
+
// 启动页面
|
|
46
|
+
boot(dashboard, { routes } )
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
export const useMenuStore = defineStore('menu', () => {
|
|
5
|
+
// 菜单列表
|
|
6
|
+
const menuList = ref([]);
|
|
7
|
+
|
|
8
|
+
// 设置菜单列表配置
|
|
9
|
+
const setMenuList = (list) => {
|
|
10
|
+
menuList.value = list;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 找出菜单目录
|
|
15
|
+
* @param key 搜索字段
|
|
16
|
+
* @param value 搜索值
|
|
17
|
+
* @param mlist 要搜索的菜单列表
|
|
18
|
+
*/
|
|
19
|
+
const findMenuItem = function({ key, value }, mlist = menuList.value) {
|
|
20
|
+
// 遍历要搜索的菜单列表
|
|
21
|
+
for (let i = 0; i < mlist.length; i++) {
|
|
22
|
+
// 获取当前菜单项
|
|
23
|
+
const menuItem = mlist[i];
|
|
24
|
+
// 如果菜单项不存在,继续下一个
|
|
25
|
+
if (!menuItem) continue;
|
|
26
|
+
// 获取菜单项的菜单枚举值和模块枚举值
|
|
27
|
+
const { menuType, moduleType } = menuItem;
|
|
28
|
+
// 如果菜单项的 key 对应的值等于搜索值,返回该菜单项
|
|
29
|
+
if (menuItem[key] === value) {
|
|
30
|
+
return menuItem;
|
|
31
|
+
}
|
|
32
|
+
// 如果菜单项是分组类型,并且有子菜单,递归查找子菜单
|
|
33
|
+
if (menuType === 'group' && menuItem.subMenu) {
|
|
34
|
+
const mItem = findMenuItem({ key, value }, menuItem.subMenu);
|
|
35
|
+
if (mItem) return mItem;
|
|
36
|
+
}
|
|
37
|
+
// 如果菜单项模块类型是侧边栏类型,并且有侧边栏配置,并且有侧边栏配置和侧边栏菜单,递归查找侧边栏菜单
|
|
38
|
+
if (moduleType === 'sider' && menuItem.siderConfig && menuItem.siderConfig.menu) {
|
|
39
|
+
const mItem = findMenuItem({ key, value }, menuItem.siderConfig.menu);
|
|
40
|
+
if (mItem) return mItem;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 找出第一个菜单项
|
|
48
|
+
* @param mlist 要搜索的菜单列表
|
|
49
|
+
*/
|
|
50
|
+
const findFirstMenuItem = function(mlist = menuList.value) {
|
|
51
|
+
if (!mlist || !mlist[0]) return ;
|
|
52
|
+
let firstMenuItem = mlist[0];
|
|
53
|
+
if (firstMenuItem.subMenu && firstMenuItem.subMenu.length > 0) {
|
|
54
|
+
firstMenuItem = findFirstMenuItem(firstMenuItem.subMenu);
|
|
55
|
+
}
|
|
56
|
+
return firstMenuItem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
return { menuList, setMenuList, findMenuItem, findFirstMenuItem }
|
|
61
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
export const useProjectStore = defineStore('project', () => {
|
|
5
|
+
const projectList = ref([])
|
|
6
|
+
|
|
7
|
+
// 设置项目列表
|
|
8
|
+
const setProjectList = (list) => {
|
|
9
|
+
projectList.value = list;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return { projectList, setProjectList }
|
|
13
|
+
})
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 布局模板 -->
|
|
3
|
+
<el-container class="header-container">
|
|
4
|
+
<!-- 头部 -->
|
|
5
|
+
<el-header class="header">
|
|
6
|
+
<el-row
|
|
7
|
+
type="flex"
|
|
8
|
+
align="middle"
|
|
9
|
+
class="header-row"
|
|
10
|
+
>
|
|
11
|
+
<!-- 左上方 title -->
|
|
12
|
+
<el-row
|
|
13
|
+
type="flex"
|
|
14
|
+
align="middle"
|
|
15
|
+
class="title-panel"
|
|
16
|
+
>
|
|
17
|
+
<img
|
|
18
|
+
src="./asserts/logo.png"
|
|
19
|
+
class="logo"
|
|
20
|
+
>
|
|
21
|
+
<el-row class="text">
|
|
22
|
+
{{ title }}
|
|
23
|
+
</el-row>
|
|
24
|
+
</el-row>
|
|
25
|
+
|
|
26
|
+
<!-- 插槽: 中间菜单区域 -->
|
|
27
|
+
<slot name="menu-content" />
|
|
28
|
+
<!-- 右上方 设置区域 -->
|
|
29
|
+
<el-row
|
|
30
|
+
type="flex"
|
|
31
|
+
align="middle"
|
|
32
|
+
justify="end"
|
|
33
|
+
class="setting-panel"
|
|
34
|
+
>
|
|
35
|
+
<!-- 插槽: 设置区域 -->
|
|
36
|
+
<slot name="setting-content" />
|
|
37
|
+
<img
|
|
38
|
+
src="./asserts/avatar.png"
|
|
39
|
+
class="avatar"
|
|
40
|
+
>
|
|
41
|
+
<el-dropdown @command="handleUserCommand">
|
|
42
|
+
<span class="username">
|
|
43
|
+
{{ userName }} <i class="el-icon-arrow-down el-icon--right" />
|
|
44
|
+
</span>
|
|
45
|
+
<template #dropdown>
|
|
46
|
+
<el-dropdown-item command="logout">
|
|
47
|
+
退出登录
|
|
48
|
+
</el-dropdown-item>
|
|
49
|
+
</template>
|
|
50
|
+
</el-dropdown>
|
|
51
|
+
</el-row>
|
|
52
|
+
</el-row>
|
|
53
|
+
</el-header>
|
|
54
|
+
|
|
55
|
+
<!-- 主要区域 -->
|
|
56
|
+
<el-main class="main-container">
|
|
57
|
+
<!-- 插槽: 外部扩展区域 -->
|
|
58
|
+
<slot name="main-content" />
|
|
59
|
+
</el-main>
|
|
60
|
+
</el-container>
|
|
61
|
+
</template>
|
|
62
|
+
<script setup>
|
|
63
|
+
import { ref } from 'vue'
|
|
64
|
+
|
|
65
|
+
defineProps({
|
|
66
|
+
title: {
|
|
67
|
+
type: String,
|
|
68
|
+
default: ''
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const userName = ref('小吴')
|
|
73
|
+
const handleUserCommand = function(event) {
|
|
74
|
+
console.log(event)
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<style lang="less">
|
|
79
|
+
// 外层容器
|
|
80
|
+
.header-container {
|
|
81
|
+
height: 100%;
|
|
82
|
+
min-width: 1000px;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
|
|
85
|
+
// 顶栏容器
|
|
86
|
+
.header {
|
|
87
|
+
max-height: 120px;
|
|
88
|
+
border-bottom: 1px solid #e8e8e8;
|
|
89
|
+
// background-color: #e8e8e8;
|
|
90
|
+
// 左上方title
|
|
91
|
+
.header-row {
|
|
92
|
+
height: 60px;
|
|
93
|
+
padding: 0 20px;
|
|
94
|
+
|
|
95
|
+
.title-panel {
|
|
96
|
+
width: 180px;
|
|
97
|
+
min-width: 180px;
|
|
98
|
+
|
|
99
|
+
.logo {
|
|
100
|
+
margin-right: 10px;
|
|
101
|
+
width: 25px;
|
|
102
|
+
height: 25px;
|
|
103
|
+
border-radius: 50%;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.text {
|
|
107
|
+
font-size: 15px;
|
|
108
|
+
font-weight: 500;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 右上方 设置区域
|
|
114
|
+
.setting-panel {
|
|
115
|
+
margin-left: auto;
|
|
116
|
+
width: 180px;
|
|
117
|
+
min-width: 180px;
|
|
118
|
+
|
|
119
|
+
.avatar {
|
|
120
|
+
margin-right: 10px;
|
|
121
|
+
width: 25px;
|
|
122
|
+
height: 25px;
|
|
123
|
+
border-radius: 50%;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.username {
|
|
127
|
+
font-size: 15px;
|
|
128
|
+
font-weight: 500;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
height: 60px;
|
|
131
|
+
line-height: 60px;
|
|
132
|
+
outline: none;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 主要区域容器
|
|
138
|
+
// .main-container{}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
:deep(.el-header) {
|
|
142
|
+
padding: 0;
|
|
143
|
+
}
|
|
144
|
+
</style>
|