refactor: refactor admin console page layout

This commit is contained in:
RockYang 2023-08-02 15:00:18 +08:00
parent fdd659f393
commit 3529649ba9
15 changed files with 172 additions and 100 deletions

View File

@ -20,6 +20,8 @@ html, body {
#app { #app {
margin: 0 !important; margin: 0 !important;
padding: 0 !important; padding: 0 !important;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
} }
</style> </style>

View File

@ -1,6 +1,3 @@
.admin-home .header {
background-color: #242f42;
}
.admin-home .login-wrap { .admin-home .login-wrap {
background: #324157; background: #324157;
} }

View File

@ -1,6 +1,6 @@
.admin-home { .admin-home {
.header { .header {
background-color: #242f42;
} }
.login-wrap { .login-wrap {

View File

@ -11,7 +11,9 @@ body,
overflow: hidden; overflow: hidden;
} }
body { body {
font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
} }
.admin-home a { .admin-home a {
text-decoration: none; text-decoration: none;
@ -20,7 +22,7 @@ body {
position: absolute; position: absolute;
left: 250px; left: 250px;
right: 0; right: 0;
top: 70px; top: 0;
bottom: 0; bottom: 0;
padding-bottom: 30px; padding-bottom: 30px;
-webkit-transition: left 0.3s ease-in-out; -webkit-transition: left 0.3s ease-in-out;

View File

@ -13,7 +13,9 @@ body,
} }
body { body {
font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
} }
.admin-home { .admin-home {
@ -25,7 +27,7 @@ body {
position: absolute; position: absolute;
left: 250px; left: 250px;
right: 0; right: 0;
top: 70px; top: 0;
bottom: 0; bottom: 0;
padding-bottom: 30px; padding-bottom: 30px;
-webkit-transition: left .3s ease-in-out; -webkit-transition: left .3s ease-in-out;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,9 +1,5 @@
<template> <template>
<div class="header admin-header"> <div class="header admin-header">
<div class="logo">
<el-image :src="logo"/>
<span class="text">{{ title }}</span>
</div>
<!-- 折叠按钮 --> <!-- 折叠按钮 -->
<div class="collapse-btn" @click="collapseChange"> <div class="collapse-btn" @click="collapseChange">
<el-icon v-if="sidebar.collapse"> <el-icon v-if="sidebar.collapse">
@ -13,6 +9,12 @@
<Fold/> <Fold/>
</el-icon> </el-icon>
</div> </div>
<div class="breadcrumb">
<el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item v-for="item in breadcrumb">{{ item.title }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="header-right"> <div class="header-right">
<div class="header-user-con"> <div class="header-user-con">
<!-- 消息中心 --> <!-- 消息中心 -->
@ -26,12 +28,10 @@
</el-tooltip> </el-tooltip>
<span class="btn-bell-badge" v-if="message"></span> <span class="btn-bell-badge" v-if="message"></span>
</div> </div>
<!-- 用户头像 -->
<el-avatar class="user-avatar" :size="30" :src="avatar"/>
<!-- 用户名下拉菜单 --> <!-- 用户名下拉菜单 -->
<el-dropdown class="user-name" :hide-on-click="true" trigger="click"> <el-dropdown class="user-name" :hide-on-click="true" trigger="click">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
{{ username }} <el-avatar class="user-avatar" :size="30" :src="avatar"/>
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<arrow-down/> <arrow-down/>
</el-icon> </el-icon>
@ -77,28 +77,68 @@
</template> </template>
<script setup> <script setup>
import {onMounted, ref} from 'vue'; import {onMounted, ref} from 'vue';
import {useSidebarStore} from '@/store/sidebar'; import {getMenuItems, useSidebarStore} from '@/store/sidebar';
import {useRouter} from 'vue-router'; import {useRouter} from 'vue-router';
import {ArrowDown, Expand, Fold} from "@element-plus/icons-vue"; import {ArrowDown, ArrowRight, Expand, Fold} from "@element-plus/icons-vue";
import {httpGet} from "@/utils/http"; import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
const message = ref(5); const message = ref(5);
const username = ref('极客学长')
const avatar = ref('/images/user-info.jpg') const avatar = ref('/images/user-info.jpg')
const donateImg = ref('/images/wechat-pay.png') const donateImg = ref('/images/wechat-pay.png')
const showDialog = ref(false) const showDialog = ref(false)
const sidebar = useSidebarStore(); const sidebar = useSidebarStore();
const title = ref('Chat-Plus 控制台') const router = useRouter();
const logo = ref('/images/logo.png') const breadcrumb = ref([])
//
httpGet('/api/admin/config/get?key=system').then(res => { router.afterEach((to, from) => {
title.value = res.data['admin_title']; initBreadCrumb(to.path)
}).catch(e => { });
ElMessage.error("加载系统配置失败: " + e.message)
onMounted(() => {
initBreadCrumb(router.currentRoute.value.path)
}) })
//
const initBreadCrumb = (path) => {
breadcrumb.value = [{title: "首页"}]
const items = getMenuItems()
if (items) {
let bk = false
for (let i = 0; i < items.length; i++) {
if (items[i].index === path) {
breadcrumb.value.push({
title: items[i].title,
path: items[i].index
})
break
}
if (bk) {
break
}
if (items[i]['subs']) {
const subs = items[i]['subs']
for (let j = 0; j < subs.length; j++) {
if (subs[j].index === path) {
breadcrumb.value.push({
title: items[i].title,
path: items[i].index
})
breadcrumb.value.push({
title: subs[j].title,
path: subs[j].index
})
bk = true
break
}
}
}
}
}
}
// //
const collapseChange = () => { const collapseChange = () => {
sidebar.handleCollapse(); sidebar.handleCollapse();
@ -110,7 +150,6 @@ onMounted(() => {
} }
}); });
const router = useRouter();
const logout = function () { const logout = function () {
httpGet("/api/admin/logout").then(() => { httpGet("/api/admin/logout").then(() => {
router.replace('/admin/login') router.replace('/admin/login')
@ -123,10 +162,12 @@ const logout = function () {
.header { .header {
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
width: 100%; overflow hidden
height: 70px; height: 50px;
font-size: 22px; font-size: 22px;
color: #fff; color: #303133;
background-color #ffffff
border-bottom 1px solid #eaecef
.collapse-btn { .collapse-btn {
display: flex; display: flex;
@ -134,19 +175,19 @@ const logout = function () {
align-items: center; align-items: center;
height: 100%; height: 100%;
float: left; float: left;
padding: 0 21px; padding: 0 10px;
cursor: pointer; cursor: pointer;
&:hover {
background-color #eaecef
}
} }
.logo { .breadcrumb {
float: left; float left
padding-left 10px;
display flex display flex
align-items center
.text { height 50px
line-height: 66px;
margin-left 10px;
}
} }
.header-right { .header-right {
@ -155,7 +196,7 @@ const logout = function () {
.header-user-con { .header-user-con {
display: flex; display: flex;
height: 70px; height: 50px;
align-items: center; align-items: center;
.btn-bell { .btn-bell {
@ -176,7 +217,7 @@ const logout = function () {
height: 8px; height: 8px;
border-radius: 4px; border-radius: 4px;
background: #f56c6c; background: #f56c6c;
color: #fff; color: #303133;
} }
.icon-bell { .icon-bell {
@ -186,10 +227,14 @@ const logout = function () {
.user-name { .user-name {
margin-left: 10px; margin-left: 10px;
.el-icon {
color: #303133;
}
} }
.user-avatar { .user-avatar {
margin-left: 20px;
} }
} }
} }
@ -227,15 +272,7 @@ const logout = function () {
} }
.admin-header { .admin-header {
.logo {
.el-image {
padding-top 10px
.el-image__inner {
height 40px
}
}
}
} }
</style> </style>

View File

@ -1,5 +1,10 @@
<template> <template>
<div class="sidebar"> <div class="sidebar">
<div class="logo">
<el-image :src="logo"/>
<span class="text" v-show="!sidebar.collapse">{{ title }}</span>
</div>
<el-menu <el-menu
class="sidebar-el-menu" class="sidebar-el-menu"
:default-active="onRoutes" :default-active="onRoutes"
@ -47,15 +52,27 @@
</template> </template>
<script setup> <script setup>
import {computed} from 'vue'; import {computed, ref} from 'vue';
import {useSidebarStore} from '@/store/sidebar'; import {setMenuItems, useSidebarStore} from '@/store/sidebar';
import {useRoute} from 'vue-router'; import {useRoute} from 'vue-router';
import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus";
const title = ref('Chat-Plus-Admin')
const logo = ref('/images/logo.png')
//
httpGet('/api/admin/config/get?key=system').then(res => {
title.value = res.data['admin_title'];
}).catch(e => {
ElMessage.error("加载系统配置失败: " + e.message)
})
const items = [ const items = [
{ {
icon: 'home', icon: 'home',
index: '/admin/welcome', index: '/admin/welcome',
title: '系统首页', title: '仪表盘',
}, },
{ {
icon: 'config', icon: 'config',
@ -120,6 +137,7 @@ const onRoutes = computed(() => {
}); });
const sidebar = useSidebarStore(); const sidebar = useSidebarStore();
setMenuItems(items)
</script> </script>
<style scoped lang="stylus"> <style scoped lang="stylus">
@ -127,10 +145,35 @@ const sidebar = useSidebarStore();
display: block; display: block;
position: absolute; position: absolute;
left: 0; left: 0;
top: 70px; top: 0;
bottom: 0; bottom: 0;
overflow-y: scroll; overflow-y: scroll;
.logo {
display flex
width 219px
background-color #324157
padding 6px 15px;
.el-image {
width 30px;
height 30px;
padding-top 5px;
border-radius 100%
.el-image__inner {
height 40px
}
}
.text {
color #ffffff
font-weight bold
padding 12px 0 12px 10px;
transition: width 2s ease;
}
}
ul { ul {
height: 100%; height: 100%;
@ -140,6 +183,10 @@ const sidebar = useSidebarStore();
margin-right 5px; margin-right 5px;
} }
} }
.el-menu-item.is-active {
background-color rgb(40, 52, 70)
}
} }
.sidebar-el-menu:not(.el-menu--collapse) { .sidebar-el-menu:not(.el-menu--collapse) {

View File

@ -15,7 +15,7 @@
</ul> </ul>
<div class="tags-close-box"> <div class="tags-close-box">
<el-dropdown @command="handleTags"> <el-dropdown @command="handleTags">
<el-button size="small" type="primary"> <el-button size="small" type="info">
标签选项 标签选项
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<arrow-down/> <arrow-down/>
@ -115,7 +115,8 @@ const handleTags = (command) => {
overflow: hidden; overflow: hidden;
background: #fff; background: #fff;
padding-right: 120px; padding-right: 120px;
box-shadow: 0 5px 10px #ddd; -webkit-box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
} }
.tags ul { .tags ul {
@ -168,14 +169,13 @@ const handleTags = (command) => {
.tags-close-box { .tags-close-box {
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 2px;
box-sizing: border-box; box-sizing: border-box;
padding-top: 1px; padding-top: 1px;
text-align: center; text-align: center;
width: 110px; width: 110px;
height: 30px; height: 30px;
background: #fff; background: #fff;
box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1); //box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1); z-index: 10;
z-index: 10;
} }
</style> </style>

View File

@ -1,4 +1,5 @@
import {defineStore} from 'pinia'; import {defineStore} from 'pinia';
import Storage from "good-storage";
export const useSidebarStore = defineStore('sidebar', { export const useSidebarStore = defineStore('sidebar', {
state: () => { state: () => {
@ -13,3 +14,13 @@ export const useSidebarStore = defineStore('sidebar', {
} }
} }
}); });
const MENU_STORE_KEY = "admin_menu_items"
export function getMenuItems() {
return Storage.get(MENU_STORE_KEY)
}
export function setMenuItems(items) {
return Storage.set(MENU_STORE_KEY, items)
}

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="admin-home" v-if="isLogin"> <div class="admin-home" v-if="isLogin">
<admin-header/>
<admin-sidebar/> <admin-sidebar/>
<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }"> <div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
<admin-header/>
<admin-tags/> <admin-tags/>
<div class="content"> <div class="content">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">

View File

@ -1,11 +1,7 @@
<template> <template>
<div class="admin-login"> <div class="admin-login">
<div class="bg"></div>
<div class="main"> <div class="main">
<div class="contain"> <div class="contain">
<div class="logo">
<el-image src="../images/logo.png" fit="cover"/>
</div>
<div class="header">{{ title }}</div> <div class="header">{{ title }}</div>
<div class="content"> <div class="content">
<div class="block"> <div class="block">
@ -53,7 +49,7 @@ import {useRouter} from "vue-router";
import FooterBar from "@/components/FooterBar.vue"; import FooterBar from "@/components/FooterBar.vue";
const router = useRouter(); const router = useRouter();
const title = ref('ChatGPT-PLUS 控制台登录'); const title = ref('ChatGPT Plus Admin');
const username = ref(process.env.VUE_APP_ADMIN_USER); const username = ref(process.env.VUE_APP_ADMIN_USER);
const password = ref(process.env.VUE_APP_ADMIN_PASS); const password = ref(process.env.VUE_APP_ADMIN_PASS);
@ -86,51 +82,29 @@ const login = function () {
<style lang="stylus" scoped> <style lang="stylus" scoped>
.admin-login { .admin-login {
.bg { display flex
position fixed justify-content center
left 0 width: 100%
right 0 background #2D3A4B
top 0
bottom 0
background-color #313237
background-image url("~@/assets/img/admin-login-bg.jpg")
background-size cover
background-position center
background-repeat no-repeat
filter: blur(10px); /* 调整模糊程度,可以根据需要修改值 */
}
.main { .main {
width 400px;
display flex
justify-content center
align-items center
height 100vh
.contain { .contain {
position fixed width 100%
left 50%
top 40%
width 90%
max-width 400px;
transform translate(-50%, -50%)
padding 20px 40px; padding 20px 40px;
color #ffffff color #ffffff
border-radius 10px; border-radius 10px;
background rgba(255, 255, 255, 0.3) background rgba(255, 255, 255, 0.3)
.logo {
text-align center
.el-image {
width 120px;
.el-image__inner {
height 100%
}
}
}
.header { .header {
width 100% width 100%
margin-bottom 24px margin-bottom 20px
font-size 24px font-size 24px
color $white_v1
letter-space 2px
text-align center text-align center
} }
@ -169,6 +143,7 @@ const login = function () {
} }
} }
.footer { .footer {
color #ffffff; color #ffffff;

View File

@ -46,7 +46,6 @@ onMounted(() => {
// //
const fetchList = function (_page, _pageSize) { const fetchList = function (_page, _pageSize) {
console.log(_page, _pageSize)
httpGet(`/api/admin/user/loginLog?page=${_page}&page_size=${_pageSize}`).then((res) => { httpGet(`/api/admin/user/loginLog?page=${_page}&page_size=${_pageSize}`).then((res) => {
if (res.data) { if (res.data) {
items.value = res.data.items items.value = res.data.items