新版前端UI,预发布2.6.4版本。 (#1735)

* fix: 修改 layout 中相关 emit 和 重复声明的 theme ,采用最新的vue api

* fix:修改 eslintrc 的配置文件,删除大多数无用配置

* fix: 修复 layout 切换手机样式模糊层的 bug

* feature: 重构 layout , 添加暗黑模式 , 删除侧边栏颜色

* fix:细节调整,activeColor摘除。

* feature:右侧滚动模式调整

* feature:无用代码剔除

* fix: 修复暗黑模式相关细节

* fix: custome config layout

* feature:样式细节调整

* fix: 增加前端样式配置文件

* feature:调整基础配置,增加表格边框

* feature:buttomInfo取消底色,a标签更改为活跃色

* feature:调整阴影颜色和配置同步

* feature:版本调整2.6.3==>2.6.4

---------

Co-authored-by: bypanghu <bypanghu@163.com>
This commit is contained in:
PiexlMax(奇淼
2024-05-09 21:35:39 +08:00
committed by GitHub
parent 9d58390e11
commit df1d68a724
60 changed files with 2414 additions and 2344 deletions

View File

@@ -1,374 +1,96 @@
<template>
<el-container class="layout-cont">
<el-container :class="[isSider?'openside':'hideside',isMobile ? 'mobile': '']">
<el-row
:class="[isShadowBg && isMobile?'bg-black opacity-30 w-full h-full absolute top-0 left-0 z-[1001]':'']"
@click="changeShadow()"
/>
<el-aside
class="main-cont gva-aside"
:style="{width:asideWidth()}"
>
<div
class="min-h-[60px] text-center transition-all duration-300 flex items-center justify-center gap-2"
:style="{background: backgroundColor}"
>
<img
alt
class="w-9 h-9 p-1 bg-white rounded-full"
:src="$GIN_VUE_ADMIN.appLogo"
>
<div
v-if="isSider"
class="inline-flex font-bold text-2xl"
:style="{color:textColor}"
>{{ $GIN_VUE_ADMIN.appName }}</div>
<div class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800 w-screen h-screen">
<el-watermark v-if="config.show_watermark" :font="font" class="absolute inset-0 z-[999] pointer-events-none" :content="userStore.userInfo.nickName" />
<gva-header />
<div class="flex flex-row w-full gva-container pt-16">
<gva-aside />
<div class="flex-1 w-0 h-full">
<gva-tabs v-if="config.showTabs" />
<div class="overflow-auto" :class="config.showTabs? 'gva-container2' :'gva-container pt-1'">
<router-view v-if="reloadFlag" v-slot="{ Component }">
<div id="gva-base-load-dom" class="gva-body-h bg-gray-50 dark:bg-slate-800">
<transition mode="out-in" name="el-fade-in-linear">
<keep-alive :include="routerStore.keepAliveRouters">
<component :is="Component" />
</keep-alive>
</transition>
</div>
</router-view>
<BottomInfo />
</div>
<Aside class="aside" />
</el-aside>
<!-- 分块滑动功能 -->
<el-main class="main-cont main-right">
<transition
:duration="{ enter: 800, leave: 100 }"
mode="out-in"
name="el-fade-in-linear"
>
<div
:style="{width: `calc(100% - ${getAsideWidth()})`}"
class="fixed top-0 box-border z-50"
>
<el-row>
<el-col>
<el-header class="header-cont">
<el-row class="p-0 h-full">
<el-col
:xs="2"
:lg="1"
:md="1"
:sm="1"
:xl="1"
class="z-50 flex items-center pl-3"
>
<div
class="text-black cursor-pointer text-lg leading-5"
@click="totalCollapse"
>
<div
v-if="isCollapse"
class="gvaIcon gvaIcon-arrow-double-right"
/>
<div
v-else
class="gvaIcon gvaIcon-arrow-double-left"
/>
</div>
</el-col>
<el-col
:xs="10"
:lg="14"
:md="14"
:sm="9"
:xl="14"
:pull="1"
class="flex items-center"
>
<!-- 修改为手机端不显示顶部标签 -->
<el-breadcrumb
v-show="!isMobile"
class="breadcrumb"
>
<el-breadcrumb-item
v-for="item in matched.slice(1,matched.length)"
:key="item.path"
>{{ fmtTitle(item.meta.title,route) }}</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
<el-col
:xs="12"
:lg="9"
:md="9"
:sm="14"
:xl="9"
class="flex items-center justify-end"
>
<div class="mr-1.5 flex items-center">
<Search />
<el-dropdown>
<div class="flex justify-center items-center h-full w-full">
<span class="cursor-pointer flex justify-center items-center">
<CustomPic />
<span
v-show="!isMobile"
style="margin-left: 5px"
>{{ userStore.userInfo.nickName }}</span>
<el-icon>
<arrow-down />
</el-icon>
</span>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<span class="font-bold">
当前角色{{ userStore.userInfo.authority.authorityName }}
</span>
</el-dropdown-item>
<template v-if="userStore.userInfo.authorities">
<el-dropdown-item
v-for="item in userStore.userInfo.authorities.filter(i=>i.authorityId!==userStore.userInfo.authorityId)"
:key="item.authorityId"
@click="changeUserAuth(item.authorityId)"
>
<span>
切换为{{ item.authorityName }}
</span>
</el-dropdown-item>
</template>
<el-dropdown-item icon="avatar">
<div
class="command-box"
style="display: flex"
@click="handleCommand"
>
<div>指令菜单</div>
<div style="margin-left: 8px">
<span class="button">{{ first }}</span>
+
<span class="button">K</span>
</div>
</div>
</el-dropdown-item>
<el-dropdown-item
icon="avatar"
@click="toPerson"
>个人信息</el-dropdown-item>
<el-dropdown-item
icon="reading-lamp"
@click="userStore.LoginOut"
> </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-col>
</el-row>
</el-header>
</el-col>
</el-row>
<!-- 当前面包屑用路由自动生成可根据需求修改 -->
<!--
:to="{ path: item.path }" 暂时注释不用-->
<HistoryComponent ref="layoutHistoryComponent" />
</div>
</transition>
<router-view
v-if="reloadFlag"
v-slot="{ Component }"
class="admin-box"
>
<div
id="gva-base-load-dom"
>
<transition
mode="out-in"
name="el-fade-in-linear"
>
<keep-alive :include="routerStore.keepAliveRouters">
<component :is="Component" />
</keep-alive>
</transition>
</div>
</router-view>
<BottomInfo />
<setting />
<CommandMenu ref="command" />
</el-main>
</el-container>
</el-container>
</div>
</div>
</div>
</template>
<script setup>
import Aside from '@/view/layout/aside/index.vue'
import HistoryComponent from '@/view/layout/aside/historyComponent/history.vue'
import Search from '@/view/layout/search/search.vue'
import BottomInfo from '@/view/layout/bottomInfo/bottomInfo.vue'
import CustomPic from '@/components/customPic/index.vue'
import CommandMenu from '@/components/commandMenu/index.vue'
import Setting from './setting/index.vue'
import { setUserAuthority } from '@/api/user'
import { emitter } from '@/utils/bus.js'
import { computed, ref, onMounted, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useRouterStore } from '@/pinia/modules/router'
import { fmtTitle } from '@/utils/fmtRouterTitle'
import { useUserStore } from '@/pinia/modules/user'
import GvaAside from "@/view/layout/aside/index.vue";
import GvaHeader from "@/view/layout/header/index.vue";
import useResponsive from "@/hooks/responsive";
import GvaTabs from "./tabs/index.vue"
import BottomInfo from "@/view/layout/bottomInfo/bottomInfo.vue";
import { emitter } from "@/utils/bus.js";
import { ref, onMounted, nextTick, reactive, watchEffect} from "vue";
import { useRouter, useRoute } from "vue-router";
import { useRouterStore } from "@/pinia/modules/router";
import { useUserStore } from "@/pinia/modules/user";
import { useAppStore } from '@/pinia'
import { storeToRefs } from 'pinia'
const appStore = useAppStore()
const { config, theme } = storeToRefs(appStore)
defineOptions({
name: 'Layout',
name: "GvaLayout",
});
useResponsive(true)
const font = reactive({
color: 'rgba(0, 0, 0, .15)',
})
const router = useRouter()
const route = useRoute()
const routerStore = useRouterStore()
// 三种窗口适配
const isCollapse = ref(false)
const isSider = ref(true)
const isMobile = ref(false)
watchEffect(()=>{
font.color = theme.value === 'dark' ? 'rgba(255,255,255, .15)' : 'rgba(0, 0, 0, .15)'
const first = ref('')
const initPage = () => {
// 判断当前用户的操作系统
if (window.localStorage.getItem('osType') === 'WIN') {
first.value = 'Ctrl'
} else {
first.value = '⌘'
}
// 当用户同时按下ctrl和k键的时候
const handleKeyDown = (e) => {
if (e.ctrlKey && e.key === 'k') {
// 阻止浏览器默认事件
e.preventDefault()
handleCommand()
}
}
window.addEventListener('keydown', handleKeyDown)
})
const screenWidth = document.body.clientWidth
if (screenWidth < 1000) {
isMobile.value = true
isSider.value = false
isCollapse.value = true
} else if (screenWidth >= 1000 && screenWidth < 1200) {
isMobile.value = false
isSider.value = false
isCollapse.value = true
} else {
isMobile.value = false
isSider.value = true
isCollapse.value = false
}
}
initPage()
const command = ref()
const handleCommand = () => {
command.value.open()
}
const router = useRouter();
const route = useRoute();
const routerStore = useRouterStore();
onMounted(() => {
// 挂载一些通用的事件
emitter.emit('collapse', isCollapse.value)
emitter.emit('mobile', isMobile.value)
emitter.on('reload', reload)
window.onresize = () => {
return (() => {
initPage()
emitter.emit('collapse', isCollapse.value)
emitter.emit('mobile', isMobile.value)
})()
}
emitter.on("reload", reload);
if (userStore.loadingInstance) {
userStore.loadingInstance.close()
userStore.loadingInstance.close();
}
})
});
const userStore = useUserStore()
const userStore = useUserStore();
const asideWidth = () => {
if (isMobile.value) {
return isCollapse.value ? '0px' : '220px'
}
return isCollapse.value ? '54px' : '220px'
}
const getAsideWidth = () => {
if (isMobile.value) return '0px'
return isCollapse.value ? '54px' : '220px'
}
const textColor = computed(() => {
if (userStore.sideMode === 'dark') {
return '#fff'
} else if (userStore.sideMode === 'light') {
return '#191a23'
} else {
return userStore.baseColor
}
})
const backgroundColor = computed(() => {
if (userStore.sideMode === 'dark') {
return '#191a23'
} else if (userStore.sideMode === 'light') {
return '#fff'
} else {
return userStore.sideMode
}
})
const matched = computed(() => route.meta.matched)
const changeUserAuth = async(id) => {
const res = await setUserAuthority({
authorityId: id
})
if (res.code === 0) {
window.sessionStorage.setItem('needCloseAll', 'true')
window.location.reload()
}
}
const reloadFlag = ref(true)
let reloadTimer = null
const reload = async() => {
const reloadFlag = ref(true);
let reloadTimer = null;
const reload = async () => {
if (reloadTimer) {
window.clearTimeout(reloadTimer)
window.clearTimeout(reloadTimer);
}
reloadTimer = window.setTimeout(async() => {
reloadTimer = window.setTimeout(async () => {
if (route.meta.keepAlive) {
reloadFlag.value = false
await nextTick()
reloadFlag.value = true
reloadFlag.value = false;
await nextTick();
reloadFlag.value = true;
} else {
const title = route.meta.title
router.push({ name: 'Reload', params: { title }})
const title = route.meta.title;
router.push({ name: "Reload", params: { title } });
}
}, 400)
}
}, 400);
};
const isShadowBg = ref(false)
const totalCollapse = () => {
isCollapse.value = !isCollapse.value
isSider.value = !isCollapse.value
isShadowBg.value = !isCollapse.value
emitter.emit('collapse', isCollapse.value)
}
const toPerson = () => {
router.push({ name: 'person' })
}
const changeShadow = () => {
isShadowBg.value = !isShadowBg.value
isSider.value = !!isCollapse.value
totalCollapse()
}
</script>
<style lang="scss">
.button {
font-size: 12px;
color: #666;
background: rgb(250,250,250);
width: 25px!important;
padding: 4px 8px !important;
border: 1px solid #eaeaea;
margin-right: 4px;
border-radius: 4px;
}
:deep .el-overlay {
background-color: hsla(0,0%,100%,.9) !important;
}
</style>