Merge pull request #8181 from dataease/pr@dev-v2@perf_appearance

perf(X-Pack): 外观配置相关页面
This commit is contained in:
fit2cloud-chenyw 2024-02-27 15:10:04 +08:00 committed by GitHub
commit 8a2ef36945
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 311 additions and 38 deletions

View File

@ -70,7 +70,6 @@ const getTimeOut = () => {
xhr.open('get', url, false)
xhr.send()
console.log(time)
return time
}

View File

@ -11,6 +11,9 @@ import AboutPage from '@/views/about/index.vue'
import LangSelector from './LangSelector.vue'
import router from '@/router'
import { useCache } from '@/hooks/web/useCache'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const { wsCache } = useCache()
const userStore = useUserStoreWithOut()
const { t } = useI18n()
@ -88,7 +91,12 @@ if (uid.value === '1') {
</script>
<template>
<div class="top-info-container" ref="buttonRef" v-click-outside="openPopover">
<div
class="top-info-container"
:class="{ 'is-light-top-info': navigateBg && navigateBg === 'light' }"
ref="buttonRef"
v-click-outside="openPopover"
>
<el-icon class="main-color">
<Icon name="user-img" />
</el-icon>
@ -163,6 +171,14 @@ if (uid.value === '1') {
height: 12px;
font-size: 14px !important;
}
.is-light-top-info {
.uname-span {
color: var(--ed-color-black) !important;
}
&:hover {
background-color: var(--ed-menu-hover-bg-color) !important;
}
}
.top-info-container {
height: 32px;
display: flex;

View File

@ -13,6 +13,8 @@ import TopDoc from '@/layout/components/TopDoc.vue'
import AccountOperator from '@/layout/components/AccountOperator.vue'
import { isDesktop } from '@/utils/ModelUtil'
import { XpackComponent } from '@/components/plugin'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const { push } = useRouter()
const route = useRoute()
@ -47,6 +49,8 @@ const initShowSystem = () => {
const initShowToolbox = () => {
showToolbox.value = permissionStore.getRouters.some(route => route.path === '/toolbox')
}
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const navigate = computed(() => appearanceStore.getNavigate)
onMounted(() => {
initShowSystem()
initShowToolbox()
@ -54,8 +58,9 @@ onMounted(() => {
</script>
<template>
<el-header class="header-flex">
<Icon @click="handleIconClick" className="logo" name="logo"></Icon>
<el-header class="header-flex" :class="{ 'header-light': navigateBg && navigateBg === 'light' }">
<img class="logo" v-if="navigate" :src="navigate" alt="" />
<Icon v-else @click="handleIconClick" className="logo" name="logo"></Icon>
<el-menu
:default-active="activeIndex"
class="el-menu-demo"
@ -76,7 +81,23 @@ onMounted(() => {
</template>
<style lang="less" scoped>
.header-light {
background-color: #ffffff !important;
box-shadow: 0px 0.5px 0px 0px #1f232926 !important;
.ed-menu {
background-color: #ffffff !important;
}
.ed-menu--horizontal {
.ed-menu-item {
color: var(--ed-color-black) !important;
}
:deep(.ed-sub-menu__title) {
color: var(--ed-color-black) !important;
}
}
}
.header-flex {
margin-bottom: 0.5px;
display: flex;
align-items: center;
height: 56px;
@ -143,4 +164,11 @@ onMounted(() => {
}
}
}
.header-light {
.operate-setting {
.ed-icon {
color: var(--ed-color-black) !important;
}
}
}
</style>

View File

@ -1,8 +1,11 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { ElHeader } from 'element-plus-secondary'
import { useRouter } from 'vue-router'
import AccountOperator from '@/layout/components/AccountOperator.vue'
import { propTypes } from '@/utils/propTypes'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const { push } = useRouter()
const props = defineProps({
title: propTypes.string.def('系统设置')
@ -10,11 +13,17 @@ const props = defineProps({
const backToMain = () => {
push('/workbranch/index')
}
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const navigate = computed(() => appearanceStore.getNavigate)
</script>
<template>
<el-header class="header-flex system-header">
<Icon className="logo" name="logo"></Icon>
<el-header
class="header-flex system-header"
:class="{ 'header-light': navigateBg && navigateBg === 'light' }"
>
<img class="logo" v-if="navigate" :src="navigate" alt="" />
<Icon v-else className="logo" name="logo"></Icon>
<el-divider direction="vertical" />
<span class="system">{{ props.title || '系统设置' }}</span>
<div class="operate-setting">
@ -69,7 +78,15 @@ const backToMain = () => {
margin: 0 -7px 0 20px !important;
}
}
.header-light {
background-color: #ffffff !important;
box-shadow: 0px 0.5px 0px 0px #1f232926 !important;
:deep(.work-bar) {
color: var(--ed-color-black) !important;
}
}
.header-flex {
margin-bottom: 0.5px;
display: flex;
align-items: center;
height: 56px;
@ -96,4 +113,11 @@ const backToMain = () => {
}
}
}
.header-light {
.operate-setting {
.ed-icon {
color: var(--ed-color-black) !important;
}
}
}
</style>

View File

@ -1,16 +1,25 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { ElHeader } from 'element-plus-secondary'
import { useRouter } from 'vue-router'
import AccountOperator from '@/layout/components/AccountOperator.vue'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const { push } = useRouter()
const backToMain = () => {
push('/workbranch/index')
}
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const navigate = computed(() => appearanceStore.getNavigate)
</script>
<template>
<el-header class="header-flex system-header">
<Icon className="logo" name="logo"></Icon>
<el-header
class="header-flex system-header"
:class="{ 'header-light': navigateBg && navigateBg === 'light' }"
>
<img class="logo" v-if="navigate" :src="navigate" alt="" />
<Icon v-else className="logo" name="logo"></Icon>
<el-divider direction="vertical" />
<span class="system">模板中心</span>
<div class="operate-setting">
@ -64,6 +73,13 @@ const backToMain = () => {
margin: 0 -7px 0 20px !important;
}
}
.header-light {
background-color: #ffffff !important;
box-shadow: 0px 0.5px 0px 0px #1f232926 !important;
:deep(.work-bar) {
color: var(--ed-color-black) !important;
}
}
.header-flex {
display: flex;
align-items: center;
@ -91,4 +107,11 @@ const backToMain = () => {
}
}
}
.header-light {
.operate-setting {
.ed-icon {
color: var(--ed-color-black) !important;
}
}
}
</style>

View File

@ -1,5 +1,9 @@
<script lang="ts" setup>
import { useRouter } from 'vue-router'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { computed } from 'vue'
const appearanceStore = useAppearanceStoreWithOut()
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const { push, resolve } = useRouter()
const redirectUser = () => {
const sysMenu = resolve('/system')
@ -10,7 +14,7 @@ const redirectUser = () => {
<template>
<el-tooltip class="box-item" effect="dark" content="组织管理中心" placement="top">
<div class="sys-setting">
<div class="sys-setting" :class="{ 'is-light-setting': navigateBg && navigateBg === 'light' }">
<el-icon @click="redirectUser">
<Icon class="icon-setting" name="icon-setting" />
</el-icon>
@ -31,4 +35,9 @@ const redirectUser = () => {
background-color: #1e2738;
}
}
.is-light-setting {
&:hover {
background-color: var(--ed-menu-hover-bg-color) !important;
}
}
</style>

View File

@ -1,7 +1,10 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import TopDocCard from '@/layout/components/TopDocCard.vue'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const { push, resolve } = useRouter()
const showToolbox = ref(true)
@ -54,7 +57,13 @@ onMounted(() => {
@click="toRouter(item)"
></top-doc-card>
<template #reference>
<div class="sys-setting" :class="{ 'hidden-toolbox': !showToolbox }">
<div
class="sys-setting"
:class="{
'hidden-toolbox': !showToolbox,
'is-light-setting': navigateBg && navigateBg === 'light'
}"
>
<el-icon>
<Icon name="sys-tools" />
</el-icon>
@ -90,4 +99,9 @@ onMounted(() => {
background-color: #1e2738;
}
}
.is-light-setting {
&:hover {
background-color: var(--ed-menu-hover-bg-color) !important;
}
}
</style>

View File

@ -1,14 +1,14 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { computed } from 'vue'
import { Icon } from '@/components/icon-custom'
import TopDocCard from '@/layout/components/TopDocCard.vue'
const helpLink = ref('https://dataease.io/docs/v2/')
const openBlank = () => {
window.open(helpLink.value)
}
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const navigateBg = computed(() => appearanceStore.getNavigateBg)
const help = computed(() => appearanceStore.getHelp)
const cardInfoList = [
{ name: '帮助文档', url: 'https://dataease.io/docs/v2/', icon: 'top-help-doc' },
{ name: '帮助文档', url: help.value || 'https://dataease.io/docs/v2/', icon: 'top-help-doc' },
{ name: '产品论坛', url: 'https://bbs.fit2cloud.com/c/de/6', icon: 'top-product-bbs' },
{
name: '技术博客',
@ -36,7 +36,10 @@ const cardInfoList = [
></top-doc-card>
</el-row>
<template #reference>
<div class="sys-setting">
<div
class="sys-setting"
:class="{ 'is-light-setting': navigateBg && navigateBg === 'light' }"
>
<el-icon>
<Icon name="docs" />
</el-icon>
@ -58,6 +61,11 @@ const cardInfoList = [
background-color: #1e2738;
}
}
.is-light-setting {
&:hover {
background-color: var(--ed-menu-hover-bg-color) !important;
}
}
</style>
<style lang="less">

View File

@ -9,6 +9,9 @@ import { getRoleRouters } from '@/api/common'
import { useCache } from '@/hooks/web/useCache'
import { isMobile } from '@/utils/utils'
import { interactiveStoreWithOut } from '@/store/modules/interactive'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
const appearanceStore = useAppearanceStoreWithOut()
const { wsCache } = useCache()
const permissionStore = usePermissionStoreWithOut()
const interactiveStore = interactiveStoreWithOut()
@ -35,6 +38,7 @@ router.beforeEach(async (to, from, next) => {
await appStore.setAppModel()
isDesktop = appStore.getDesktop
}
await appearanceStore.setAppearance()
if (wsCache.get('user.token') || isDesktop) {
if (!userStore.getUid) {
await userStore.setUser()

View File

@ -0,0 +1,153 @@
import { defineStore } from 'pinia'
import { store } from '@/store/index'
import { uiLoadApi } from '@/api/login'
import { useCache } from '@/hooks/web/useCache'
const basePath = import.meta.env.VITE_API_BASEPATH
const baseUrl = basePath + '/appearance/image/'
interface AppearanceState {
themeColor?: string
customColor?: string
navigateBg?: string
navigate?: string
help?: string
bg?: string
login?: string
slogan?: string
web?: string
name?: string
loaded: boolean
}
const { wsCache } = useCache()
export const useAppearanceStore = defineStore('appearanceStore', {
state: (): AppearanceState => {
return {
themeColor: '',
customColor: '',
navigateBg: '',
navigate: '',
help: '',
bg: '',
login: '',
slogan: '',
web: '',
name: '',
loaded: false
}
},
getters: {
getNavigate(): string {
if (this.navigate) {
return baseUrl + this.navigate
}
return null
},
getHelp(): string {
return this.help
},
getThemeColor(): string {
return this.themeColor
},
getCustomColor(): string {
return this.customColor
},
getNavigateBg(): string {
return this.navigateBg
},
getBg(): string {
if (this.bg) {
return baseUrl + this.bg
}
return null
},
getLogin(): string {
if (this.login) {
return baseUrl + this.login
}
return null
},
getSlogan(): string {
return this.slogan
},
getWeb(): string {
if (this.web) {
return baseUrl + this.web
}
return null
},
getName(): string {
return this.name
},
getLoaded(): boolean {
return this.loaded
}
},
actions: {
setNavigate(data: string) {
this.navigate = data
},
setHelp(data: string) {
this.help = data
},
setNavigateBg(data: string) {
this.navigateBg = data
},
setThemeColor(data: string) {
this.themeColor = data
},
setCustomColor(data: string) {
this.customColor = data
},
setLoaded(data: boolean) {
this.loaded = data
},
async setAppearance() {
const desktop = wsCache.get('app.desktop')
if (desktop) {
this.loaded = true
}
if (this.loaded) {
return
}
const res = await uiLoadApi()
this.loaded = true
const resData = res.data
if (!resData?.length) {
return
}
const data: AppearanceState = { loaded: false }
resData.forEach(item => {
data[item.pkey] = item.pval
})
this.navigate = data.navigate
this.help = data.help
this.navigateBg = data.navigateBg
this.themeColor = data.themeColor
this.customColor = data.customColor
if (this.themeColor === 'custom' && this.customColor) {
document.documentElement.style.setProperty('--ed-color-primary', this.customColor)
} else if (document.documentElement.style.getPropertyValue('--ed-color-primary')) {
document.documentElement.style.setProperty('--ed-color-primary', '#3370FF')
}
this.bg = data.bg
this.login = data.login
this.slogan = data.slogan
this.web = data.web
this.name = data.name
if (this.name) {
document.title = this.name
}
const link = document.querySelector('link[rel="icon"]')
if (link) {
if (this.web) {
link['href'] = baseUrl + this.web
} else {
link['href'] = '/dataease.svg'
}
}
}
}
})
export const useAppearanceStoreWithOut = () => {
return useAppearanceStore(store)
}

View File

@ -3,11 +3,12 @@ import { ref, reactive, onMounted, computed, nextTick } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { FormRules, FormInstance } from 'element-plus-secondary'
import { Icon } from '@/components/icon-custom'
import { loginApi, queryDekey, uiLoadApi } from '@/api/login'
import { loginApi, queryDekey } from '@/api/login'
import { useCache } from '@/hooks/web/useCache'
import { useAppStoreWithOut } from '@/store/modules/app'
import { CustomPassword } from '@/components/custom-password'
import { useUserStoreWithOut } from '@/store/modules/user'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { rsaEncryp } from '@/utils/encryption'
import router from '@/router'
import { ElMessage } from 'element-plus-secondary'
@ -16,14 +17,14 @@ import { logoutHandler } from '@/utils/logout'
import DeImage from '@/assets/login-desc-de.png'
import elementResizeDetectorMaker from 'element-resize-detector'
import { isLarkPlatform } from '@/utils/utils'
const basePath = import.meta.env.VITE_API_BASEPATH
const { wsCache } = useCache()
const appStore = useAppStoreWithOut()
const userStore = useUserStoreWithOut()
const appearanceStore = useAppearanceStoreWithOut()
const { t } = useI18n()
const contentShow = ref(true)
const loading = ref(false)
const axiosFinished = ref(false)
const axiosFinished = ref(true)
const showFoot = ref(false)
const loginLogoUrl = ref(null)
@ -172,23 +173,17 @@ const showLoginErrorMsg = () => {
}
ElMessage.error(loginErrorMsg.value)
}
const loadArrearance = () => {
const imgUrlPrefix = basePath + '/appearance/image/'
uiLoadApi().then(res => {
axiosFinished.value = true
const items = res.data
items.forEach(item => {
const pkey = item.pkey
const pval = item.pval
if (pkey === 'bg') {
loginImageUrl.value = imgUrlPrefix + pval
} else if (pkey === 'login') {
loginLogoUrl.value = imgUrlPrefix + pval
} else if (pkey === 'slogan') {
slogan.value = pval
}
})
})
if (appearanceStore.getBg) {
loginImageUrl.value = appearanceStore.getBg
}
if (appearanceStore.getLogin) {
loginLogoUrl.value = appearanceStore.getLogin
}
if (appearanceStore.getSlogan) {
slogan.value = appearanceStore.getSlogan
}
}
onMounted(() => {
loadArrearance()

@ -1 +1 @@
Subproject commit 7614b60f695b438e28bed0e2c7a987aef7aa8f3f
Subproject commit 26bcec35ff7c37bd80d8d9192780b1b1d4ea19a0