Skip to content

Commit 0f5185b

Browse files
style: Dynamic Layout
1 parent 846b8cd commit 0f5185b

File tree

4 files changed

+208
-40
lines changed

4 files changed

+208
-40
lines changed
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

frontend/src/components/layout/index.vue

Lines changed: 204 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<div class="app-container">
3-
<div class="sidebar">
2+
<div class="app-container" :class="{ 'app-topbar-container': topLayout }">
3+
<div class="main-menu" :class="{ 'main-menu-sidebar': !topLayout, 'main-menu-topbar': topLayout }">
44
<div class="logo">SQLBot</div>
55

6-
<div class="workspace-area">
6+
<div v-if="!topLayout || !showSubmenu" :class="{ 'workspace-area': !topLayout, 'topbar-workspace-area': topLayout }">
77
<el-select
88
v-model="workspace"
99
placeholder="Select"
@@ -26,21 +26,57 @@
2626
</el-select>
2727
</div>
2828
<el-menu
29+
v-if="!topLayout || !showSubmenu"
2930
:default-active="activeMenu"
30-
class="menu-container">
31-
31+
class="menu-container"
32+
:mode="topLayout ? 'horizontal' : 'vertical'"
33+
>
3234
<el-menu-item v-for="item in routerList" :key="item.path" :index="item.path" @click="menuSelect">
3335
<el-icon v-if="item.meta.icon">
3436
<component :is="resolveIcon(item.meta.icon)" />
3537
</el-icon>
3638
<span>{{ item.meta.title }}</span>
3739
</el-menu-item>
38-
3940
</el-menu>
41+
42+
<div v-else class="top-bar-title">
43+
<span class="split" />
44+
<span>System manage</span>
45+
</div>
46+
47+
48+
<div class="main-topbar-right" v-if="topLayout">
49+
50+
<div class="top-back-area" v-if="showSubmenu">
51+
<el-button type="primary" text="primary" @click="backMain">
52+
<el-icon class="el-icon--right"><ArrowLeftBold /></el-icon>Back
53+
</el-button>
54+
</div>
55+
56+
<el-tooltip content="System manage" placement="bottom" v-else>
57+
<div class="header-icon-btn" @click="toSystem">
58+
<el-icon><iconsystem /></el-icon>
59+
<!-- <span>System manage</span> -->
60+
</div>
61+
</el-tooltip>
62+
63+
<el-dropdown trigger="click">
64+
<div class="user-info">
65+
<el-avatar size="small">{{ name?.charAt(0) }}</el-avatar>
66+
<span class="user-name">{{ name }}</span>
67+
</div>
68+
<template #dropdown>
69+
<el-dropdown-menu>
70+
<el-dropdown-item @click="switchLayout">Switch Layout</el-dropdown-item>
71+
<el-dropdown-item @click="logout">Logout</el-dropdown-item>
72+
</el-dropdown-menu>
73+
</template>
74+
</el-dropdown>
75+
</div>
4076
</div>
4177

42-
<div class="main-content">
43-
<div class="header-container">
78+
<div class="main-content" :class="{'main-conntent-withbar': topLayout}">
79+
<div class="header-container" v-if="!topLayout">
4480
<div class="header">
4581
<h1>{{ currentPageTitle }}</h1>
4682
<div class="header-actions">
@@ -50,25 +86,15 @@
5086
<span>System manage</span>
5187
</div>
5288
</el-tooltip>
53-
<!-- <el-tooltip content="Help" placement="bottom">
54-
<div class="header-icon-btn">
55-
<el-icon><question-filled /></el-icon>
56-
<span>Help</span>
57-
</div>
58-
</el-tooltip>
59-
<el-tooltip content="Notice" placement="bottom">
60-
<div class="header-icon-btn">
61-
<el-icon><BellFilled /></el-icon>
62-
<span>Notice</span>
63-
</div>
64-
</el-tooltip> -->
89+
6590
<el-dropdown trigger="click">
6691
<div class="user-info">
6792
<el-avatar size="small">{{ name?.charAt(0) }}</el-avatar>
6893
<span class="user-name">{{ name }}</span>
6994
</div>
7095
<template #dropdown>
7196
<el-dropdown-menu>
97+
<el-dropdown-item @click="switchLayout">Switch Layout</el-dropdown-item>
7298
<el-dropdown-item @click="logout">Logout</el-dropdown-item>
7399
</el-dropdown-menu>
74100
</template>
@@ -77,11 +103,11 @@
77103
</div>
78104
</div>
79105

80-
<div v-if="sysRouterList.length && showHead" class="sys-setting-container">
106+
<div v-if="sysRouterList.length && showSubmenu" class="sub-menu-container">
81107
<el-menu
82108
:default-active="activeMenu"
83109
class="el-menu-demo"
84-
mode="horizontal"
110+
:mode="!topLayout ? 'horizontal' : 'vertical'"
85111
>
86112
<el-menu-item v-for="item in sysRouterList" :key="item.path" :index="item.path" @click="menuSelect">
87113
<el-icon v-if="item.meta.icon">
@@ -92,7 +118,7 @@
92118
</el-menu>
93119
</div>
94120

95-
<div v-if="sysRouterList.length && showHead" class="sys-page-content">
121+
<div v-if="sysRouterList.length && showSubmenu" class="sys-page-content">
96122
<div class="sys-inner-container">
97123
<router-view />
98124
</div>
@@ -105,7 +131,7 @@
105131
</template>
106132

107133
<script lang="ts" setup>
108-
import { ref, computed } from 'vue'
134+
import { ref, computed, onMounted } from 'vue'
109135
import { useRouter, useRoute } from 'vue-router'
110136
import { useUserStore } from '@/stores/user'
111137
import folder from '@/assets/svg/folder.svg'
@@ -114,11 +140,12 @@ import dashboard from '@/assets/svg/dashboard.svg'
114140
import chat from '@/assets/svg/chat.svg'
115141
import iconsetting from '@/assets/svg/setting.svg'
116142
import iconsystem from '@/assets/svg/system.svg'
117-
/* import {
118-
QuestionFilled,
119-
BellFilled
120-
} from '@element-plus/icons-vue' */
121-
143+
import icon_user from '@/assets/svg/icon_user.svg'
144+
import icon_ai from '@/assets/svg/icon_ai.svg'
145+
import { ArrowLeftBold } from '@element-plus/icons-vue'
146+
import { useCache } from '@/utils/useCache'
147+
const { wsCache } = useCache()
148+
const topLayout = ref(false)
122149
const router = useRouter()
123150
const route = useRoute()
124151
const userStore = useUserStore()
@@ -134,7 +161,7 @@ const sysRouterList = computed(() => {
134161
return router.getRoutes().filter(route => route.path.includes('/system'))
135162
})
136163
137-
const showHead = computed(() => {
164+
const showSubmenu = computed(() => {
138165
return route.path.includes('/system')
139166
})
140167
const workspace = ref('1')
@@ -154,7 +181,9 @@ const resolveIcon = (iconName: any) => {
154181
'ds': ds,
155182
'dashboard': dashboard,
156183
'chat': chat,
157-
'setting': iconsetting
184+
'setting': iconsetting,
185+
'icon_user': icon_user,
186+
'icon_ai': icon_ai,
158187
}
159188
return typeof icons[iconName] === 'function' ? icons[iconName]() : icons[iconName]
160189
}
@@ -169,21 +198,30 @@ const logout = () => {
169198
const toSystem = () => {
170199
router.push('/system')
171200
}
201+
const backMain = () => {
202+
router.push('/')
203+
}
204+
const switchLayout = () => {
205+
topLayout.value = !topLayout.value
206+
wsCache.set('sqlbot-topbar-layout', topLayout.value)
207+
}
208+
onMounted(() => {
209+
topLayout.value = wsCache.get('sqlbot-topbar-layout') || true
210+
})
172211
</script>
173212

174213
<style lang="less" scoped>
214+
.app-topbar-container {
215+
flex-direction: column;
216+
}
175217
.app-container {
176218
display: flex;
177219
height: 100vh;
178-
179-
.sidebar {
180-
width: 240px;
181-
background: #fff;
182-
border-right: 1px solid #e6e6e6;
220+
.main-menu {
183221
display: flex;
184-
flex-direction: column;
185222
.workspace-area {
186223
margin: 8px 16px;
224+
width: 208px;
187225
overflow: hidden;
188226
.workspace-select {
189227
width: 100% !important;
@@ -220,10 +258,114 @@ const toSystem = () => {
220258
.menu-container {
221259
flex: 1;
222260
border-right: none;
261+
border-bottom: none;
262+
}
263+
}
264+
.main-menu-sidebar {
265+
width: 240px;
266+
background: #fff;
267+
border-right: 1px solid #e6e6e6;
268+
display: flex;
269+
flex-direction: column;
270+
}
271+
.main-menu-topbar {
272+
height: 60px;
273+
line-height: 60px;
274+
font-size: 24px;
275+
font-weight: bold;
276+
color: var(--el-color-primary);
277+
text-align: left;
278+
justify-content: space-between;
279+
border-bottom: 1px solid var(--el-menu-border-color);
280+
text-align: center;
281+
.logo {
282+
height: 60px;
283+
line-height: 60px;
284+
}
285+
286+
.main-topbar-right {
287+
display: flex;
288+
height: 60px;
289+
align-items: center;
290+
padding-right: 24px;
291+
.header-icon-btn {
292+
display: flex;
293+
column-gap: 12px;
294+
align-items: center;
295+
padding: 8px 16px;
296+
border-radius: 4px;
297+
cursor: pointer;
298+
border: none;
299+
font-weight: 500;
300+
transition: all 0.3s;
301+
font-size: 14px;
302+
color: #5f6368;
303+
&:hover {
304+
background-color: rgba(0, 0, 0, 0.05);
305+
}
306+
}
307+
:deep(.user-info) {
308+
display: flex;
309+
column-gap: 4px;
310+
align-items: center;
311+
.el-avatar {
312+
background-color: var(--el-color-primary);
313+
color: #fff;
314+
}
315+
.user-name {
316+
font-size: 14px;
317+
font-weight: 500;
318+
color: #202124;
319+
}
320+
}
321+
.top-back-area {
322+
align-items: center;
323+
display: flex;
324+
}
325+
}
326+
.topbar-workspace-area {
327+
margin: 0 32px;
328+
height: auto;
329+
width: 208px;
330+
line-height: 54px;
331+
.workspace-select {
332+
width: 100% !important;
333+
:deep(.el-select__wrapper) {
334+
border-radius: 10px;
335+
box-shadow: none !important;
336+
background-color: #f1f3f4;
337+
line-height: 24px;
338+
min-height: 32px;
339+
.workspace-label {
340+
color: #2d2e31;
341+
font-weight: 600;
342+
display: flex;
343+
column-gap: 8px;
344+
align-items: center;
345+
height: 32px;
346+
}
347+
}
348+
}
349+
}
350+
.top-bar-title {
351+
font-size: 14px;
352+
color: var(--el-color-info);
353+
display: flex;
354+
align-items: center;
355+
left: 132px;
356+
width: 200px;
357+
position: fixed;
358+
.split {
359+
color: #bbbbbb;
360+
border: 0.5px solid;
361+
margin-right: 16px;
362+
height: 12px;
363+
}
223364
}
224365
}
225366
226367
.main-content {
368+
width: calc(100% - 288px);
227369
flex: 1;
228370
display: flex;
229371
flex-direction: column;
@@ -299,17 +441,41 @@ const toSystem = () => {
299441
padding: 24px;
300442
box-shadow: var(--shadow);
301443
margin-top: 24px;
444+
flex: 1;
302445
.sys-inner-container {
303446
background: #fff;
304447
border-radius: 8px;
305448
padding: 20px;
306449
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
307450
}
308451
}
309-
.sys-setting-container {
452+
.sub-menu-container {
310453
overflow: hidden;
311454
border-radius: 8px;
312455
}
313456
}
457+
.main-conntent-withbar {
458+
padding: 0;
459+
width: 100%;
460+
display: flex;
461+
flex-direction: row;
462+
.sub-menu-container {
463+
flex: 0 0 auto;
464+
background-color: lightblue;
465+
resize: horizontal;
466+
overflow: auto;
467+
border-right: 1px solid var(--el-menu-border-color);
468+
border-radius: 0;
469+
background-color: var(--white);
470+
:deep(.el-menu) {
471+
border: none;
472+
}
473+
}
474+
.sys-page-content {
475+
margin: 0;
476+
border-radius: 0;
477+
width: calc(100% - 288px);
478+
}
479+
}
314480
}
315481
</style>

frontend/src/router/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ const router = createRouter({
7676
path: 'user',
7777
name: 'user',
7878
component: () => import('@/views/system/user/index.vue'),
79-
meta: { title: 'User Management', icon: 'setting' }
79+
meta: { title: 'User Management', icon: 'icon_user' }
8080
},
8181
{
8282
path: 'model',
8383
name: 'model',
8484
component: () => import('@/views/system/model/index.vue'),
85-
meta: { title: 'AI Model Configuration', icon: 'setting' }
85+
meta: { title: 'AI Model Configuration', icon: 'icon_ai' }
8686
}
8787
]
8888
}

0 commit comments

Comments
 (0)