feat: 外观设置

This commit is contained in:
wangdan-fit2cloud 2024-07-16 17:32:27 +08:00
parent 80a54401b0
commit 7a9d8bf96d
25 changed files with 381 additions and 619 deletions

View File

@ -1,7 +1,6 @@
import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import type { TeamMember } from '@/api/type/team'
import type { Ref } from 'vue'
const prefix = '/display'
/**
@ -13,7 +12,7 @@ const getThemeInfo: () => Promise<Result<any>> = () => {
/**
*
* @param
* @param
* * formData {
* theme
* icon
@ -23,12 +22,14 @@ const getThemeInfo: () => Promise<Result<any>> = () => {
* slogan
* }
*/
const postThemeInfo: (data: any) => Promise<Result<boolean>> = (data) => {
return post(`${prefix}/update`, data)
const postThemeInfo: (data: any, loading?: Ref<boolean>) => Promise<Result<boolean>> = (
data,
loading
) => {
return post(`${prefix}/update`, data, undefined, loading)
}
export default {
getThemeInfo,
postThemeInfo
}
getThemeInfo,
postThemeInfo
}

View File

@ -1 +1 @@
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 232.4409 232.4409"><title>MaxKB</title><path class="cls-1" d="M128.4532,177H98.7785L87.78,187.9985a4.6069,4.6069,0,0,0,3.2576,7.8644h45.1569a4.6069,4.6069,0,0,0,3.2575-7.8644Z"/><path class="cls-1" d="M210.0008,90.7042h-5.85v41.1511h5.85a4.4537,4.4537,0,0,0,4.4537-4.4537V95.1579A4.4537,4.4537,0,0,0,210.0008,90.7042Z"/><path class="cls-1" d="M28.29,90.7042H22.44a4.4538,4.4538,0,0,0-4.4538,4.4537v32.2437a4.4538,4.4538,0,0,0,4.4538,4.4537h5.85Z"/><path class="cls-1" d="M138.8087,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,138.8087,96.1512Z"/><path class="cls-1" d="M95.3622,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,95.3622,96.1512Z"/><path class="cls-1" d="M166.8344,48.8968H65.6064A33.7544,33.7544,0,0,0,31.89,82.6131v57.07A33.7548,33.7548,0,0,0,65.6064,173.4h101.228a33.7549,33.7549,0,0,0,33.7168-33.7168v-57.07A33.7545,33.7545,0,0,0,166.8344,48.8968Zm2.831,90.4457a6.0733,6.0733,0,0,1-6.0732,6.0733H114.2168a43.5922,43.5922,0,0,0-21.3313,5.5757l-16.5647,9.2946v-14.87h-7.472a6.0733,6.0733,0,0,1-6.0733-6.0733v-60.5a6.0733,6.0733,0,0,1,6.0733-6.0733h94.7434a6.0733,6.0733,0,0,1,6.0732,6.0733Z"/></svg>
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 232.4409 232.4409"><defs><style>.cls-1{fill:#fff;}</style></defs><title>MaxKB</title><path class="cls-1" d="M128.4532,177H98.7785L87.78,187.9985a4.6069,4.6069,0,0,0,3.2576,7.8644h45.1569a4.6069,4.6069,0,0,0,3.2575-7.8644Z"/><path class="cls-1" d="M210.0008,90.7042h-5.85v41.1511h5.85a4.4537,4.4537,0,0,0,4.4537-4.4537V95.1579A4.4537,4.4537,0,0,0,210.0008,90.7042Z"/><path class="cls-1" d="M28.29,90.7042H22.44a4.4538,4.4538,0,0,0-4.4538,4.4537v32.2437a4.4538,4.4538,0,0,0,4.4538,4.4537h5.85Z"/><path class="cls-1" d="M138.8087,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,138.8087,96.1512Z"/><path class="cls-1" d="M95.3622,96.1512a8.33,8.33,0,0,0-8.33,8.33v5.9727a8.33,8.33,0,1,0,16.6607,0v-5.9727A8.33,8.33,0,0,0,95.3622,96.1512Z"/><path class="cls-1" d="M166.8344,48.8968H65.6064A33.7544,33.7544,0,0,0,31.89,82.6131v57.07A33.7548,33.7548,0,0,0,65.6064,173.4h101.228a33.7549,33.7549,0,0,0,33.7168-33.7168v-57.07A33.7545,33.7545,0,0,0,166.8344,48.8968Zm2.831,90.4457a6.0733,6.0733,0,0,1-6.0732,6.0733H114.2168a43.5922,43.5922,0,0,0-21.3313,5.5757l-16.5647,9.2946v-14.87h-7.472a6.0733,6.0733,0,0,1-6.0733-6.0733v-60.5a6.0733,6.0733,0,0,1,6.0733-6.0733h94.7434a6.0733,6.0733,0,0,1,6.0732,6.0733Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -955,7 +955,7 @@ export const iconMap: any = {
])
}
},
'app-minify': {
'app-magnify': {
iconReader: () => {
return h('i', [
h(
@ -976,7 +976,7 @@ export const iconMap: any = {
])
}
},
'app-magnify': {
'app-minify': {
iconReader: () => {
return h('i', [
h(
@ -1071,5 +1071,5 @@ export const iconMap: any = {
)
])
}
},
}
}

View File

@ -3,9 +3,7 @@
<div class="login-container w-full h-full">
<el-row class="container w-full h-full">
<el-col :xs="0" :sm="0" :md="10" :lg="10" :xl="10" class="left-container">
<div class="login-image">
<img :src="`../src/assets/theme/${themeImg}.jpg`" class="login-image" />
</div>
<div class="login-image" :style="loginImageStyle"></div>
</el-col>
<el-col :xs="24" :sm="24" :md="14" :lg="14" :xl="14" class="right-container flex-center">
<slot></slot>
@ -15,12 +13,33 @@
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { computed } from 'vue'
import { getThemeImg } from '@/utils/theme'
import useStore from '@/stores'
defineOptions({ name: 'LoginLayout' })
const props = defineProps({
themeImg: {
type: String,
default: 'default'
const { user } = useStore()
const fileURL = computed(() => {
if (user.themeInfo.loginImage) {
if (typeof user.themeInfo.loginImage === 'string') {
return user.themeInfo.loginImage
} else {
return URL.createObjectURL(user.themeInfo.loginImage)
}
} else {
return ''
}
})
const loginImageStyle = computed(() => {
if (user.themeInfo.loginImage) {
return {
backgroundImage: `url(${fileURL.value})`
}
} else {
return {
backgroundImage: `url(../src/assets/theme/${getThemeImg(user.themeInfo?.theme)}.jpg)`
}
}
})
</script>
@ -29,7 +48,9 @@ const props = defineProps({
height: 100vh;
.login-image {
object-fit: cover;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
width: 100%;
height: 100%;
}

View File

@ -1,59 +1,62 @@
<template>
<svg
v-if="!isDefaultTheme"
viewBox="0 0 122 36"
xmlns="http://www.w3.org/2000/svg"
:height="height"
:class="!isDefaultTheme ? 'custom-logo-color' : ''"
>
<g clip-path="url(#clip0_5682_1471)" fill-rule="evenodd">
<path
d="M75.3094 19.0805V27.05H71.8274L71.8109 26.2436C70.5933 26.8762 69.4033 27.1925 68.2412 27.1923H67.8972C66.7033 27.1923 65.7546 26.7337 65.051 25.8166C64.5855 25.1007 64.342 24.2631 64.3513 23.4092V23.3143C64.3513 21.7489 64.9008 20.7092 65.9997 20.1953C66.4505 19.8949 67.5929 19.7447 69.4271 19.7447H71.3008V19.3058C71.3008 18.4045 71.1703 17.8867 70.9094 17.7523C70.6249 17.5388 70.1228 17.4321 69.4033 17.4321H65.6678L65.7312 14.2396L70.032 14.1233C72.5857 14.1233 74.1669 14.7558 74.7758 16.0208C75.1315 16.756 75.3094 17.7759 75.3094 19.0805ZM68.6032 22.3901C68.4844 22.5315 68.3597 22.9902 68.3597 23.3143C68.3597 24.0259 68.7234 24.3817 69.4508 24.3817C69.8855 24.3817 70.5022 24.2038 71.3008 23.848V22.1112C71.3008 22.1112 69.0361 21.875 68.6032 22.3901Z"
fill="currentColor"
/>
<path
d="M56.6308 27.3317L55.4162 15.1815L52.0028 27.3317H48.028L44.6928 15.1815L43.4348 27.3317L37.9399 27.2849L40.6207 9.35034H47.6212L50.0211 17.8845L52.4444 9.35034H59.281L62.0087 27.3317H56.6308Z"
fill="currentColor"
/>
<path
d="M85.3943 26.9654L83.5118 23.1105L81.6291 26.9654H77.2017L80.831 20.5778L77.3644 14.6084H81.6525L83.5118 18.2543L85.313 14.6084H89.6009L86.1576 20.5778L89.7637 26.9654H85.3943Z"
fill="currentColor"
/>
<path
d="M101.114 26.9656C101.029 26.8419 96.8966 20.1336 96.8966 20.1336L95.5396 22.2226V26.9656H90.9727V9.11621H95.5396V16.3526L99.7128 9.17639H104.477L99.514 17.1079L105.855 26.9656H101.114Z"
fill="currentColor"
/>
<path
d="M121.036 22.145C121.036 24.745 119.74 27.1282 115.097 27.1282H107.032V9.02689L113.203 8.90869C113.203 8.90869 116.858 8.74751 118.706 10.153C120.068 11.1885 120.515 13.0021 120.384 14.5197C120.254 16.0373 119.553 17.0129 118.405 17.727C119.979 18.354 121.036 19.5451 121.036 22.145ZM114.228 16.3325C115.766 16.3325 116.62 15.5559 116.62 14.45C116.62 13.2735 115.833 12.5837 114.228 12.5837L111.576 12.5906V16.3325H114.228ZM114.365 23.5374C116.497 23.5374 117.022 22.393 117.022 21.6316C117.022 20.4308 116.17 19.563 114.752 19.563H111.576V23.5374H114.365Z"
fill="currentColor"
/>
<path
d="M17.4213 26.7354H12.8296L11.1277 28.4372C11.028 28.5369 10.9601 28.6639 10.9326 28.8022C10.9051 28.9405 10.9193 29.0838 10.9732 29.2141C11.0272 29.3443 11.1185 29.4557 11.2358 29.534C11.353 29.6123 11.4908 29.6541 11.6318 29.6541H18.6192C18.7602 29.6541 18.898 29.6123 19.0153 29.534C19.1325 29.4557 19.2239 29.3443 19.2778 29.2141C19.3318 29.0838 19.3459 28.9405 19.3184 28.8022C19.2909 28.6639 19.223 28.5369 19.1233 28.4372L17.4213 26.7354Z"
fill="currentColor"
/>
<path
d="M30.04 13.3823H29.1348V19.7499H30.04C30.1305 19.7499 30.2201 19.732 30.3037 19.6974C30.3873 19.6628 30.4633 19.612 30.5273 19.548C30.5913 19.484 30.642 19.4081 30.6767 19.3244C30.7113 19.2408 30.7291 19.1512 30.7291 19.0607V14.0715C30.7291 13.8887 30.6565 13.7134 30.5273 13.5842C30.398 13.4549 30.2227 13.3823 30.04 13.3823Z"
fill="currentColor"
/>
<path
d="M1.92296 13.3823H1.01776C0.834985 13.3823 0.659698 13.4549 0.530458 13.5842C0.401219 13.7134 0.328613 13.8887 0.328613 14.0715V19.0607C0.328611 19.1512 0.346435 19.2408 0.381067 19.3244C0.415699 19.4081 0.466461 19.484 0.530455 19.548C0.594448 19.612 0.670419 19.6628 0.754031 19.6974C0.837643 19.732 0.927258 19.7499 1.01776 19.7499H1.92296V13.3823Z"
fill="currentColor"
/>
<path
d="M19.0238 14.2251C18.682 14.2251 18.3541 14.3609 18.1124 14.6026C17.8707 14.8443 17.7349 15.1722 17.7349 15.514V16.4382C17.7349 16.7801 17.8707 17.108 18.1124 17.3497C18.3541 17.5914 18.682 17.7272 19.0239 17.7272C19.3657 17.7272 19.6936 17.5914 19.9353 17.3497C20.1771 17.108 20.3129 16.7801 20.3129 16.4382V15.5141C20.3129 15.3448 20.2796 15.1772 20.2148 15.0208C20.15 14.8644 20.055 14.7223 19.9353 14.6026C19.8156 14.4829 19.6735 14.388 19.5171 14.3232C19.3607 14.2584 19.1931 14.2251 19.0238 14.2251Z"
fill="currentColor"
/>
<path
d="M12.3012 14.2251C11.9593 14.2251 11.6315 14.3609 11.3897 14.6026C11.148 14.8443 11.0122 15.1722 11.0122 15.514V16.4382C11.0122 16.7801 11.148 17.108 11.3897 17.3497C11.6315 17.5914 11.9593 17.7272 12.3012 17.7272C12.6431 17.7272 12.9709 17.5914 13.2127 17.3497C13.4544 17.108 13.5902 16.7801 13.5902 16.4382V15.5141C13.5902 15.3448 13.5569 15.1772 13.4921 15.0208C13.4273 14.8644 13.3324 14.7223 13.2127 14.6026C13.093 14.4829 12.9509 14.388 12.7945 14.3232C12.6381 14.2584 12.4704 14.2251 12.3012 14.2251Z"
fill="currentColor"
/>
<path
d="M23.3607 6.91333H7.69709C6.3139 6.91489 4.98782 7.46505 4.00976 8.44311C3.0317 9.42117 2.48154 10.7473 2.47998 12.1304V20.9612C2.48154 22.3444 3.03169 23.6705 4.00975 24.6486C4.98781 25.6266 6.3139 26.1768 7.69709 26.1784H23.3607C24.7439 26.1768 26.07 25.6267 27.0481 24.6486C28.0262 23.6705 28.5764 22.3444 28.5779 20.9612V12.1304C28.5763 10.7472 28.0262 9.42115 27.0481 8.44309C26.07 7.46503 24.7439 6.91487 23.3607 6.91333ZM23.7988 20.9085C23.7988 21.1577 23.6998 21.3968 23.5235 21.573C23.3473 21.7492 23.1083 21.8482 22.859 21.8482H15.2189C14.0629 21.8482 12.9263 22.1453 11.9181 22.711L9.355 24.1492V21.8483H8.19882C7.94958 21.8483 7.71055 21.7493 7.53432 21.573C7.35808 21.3968 7.25907 21.1578 7.25906 20.9085V11.547C7.25907 11.2978 7.35808 11.0588 7.53432 10.8825C7.71056 10.7063 7.94958 10.6073 8.19882 10.6073H22.859C23.1082 10.6073 23.3472 10.7063 23.5235 10.8825C23.6997 11.0588 23.7987 11.2978 23.7987 11.5471L23.7988 20.9085Z"
fill="currentColor"
/>
</g>
</svg>
<img v-else src="@/assets/logo/MaxKB-logo.svg" :height="height" />
<img v-if="user.themeInfo.loginLogo" :src="fileURL" alt="" height="45px" class="mr-8" />
<template v-else>
<svg
v-if="!isDefaultTheme"
viewBox="0 0 122 36"
xmlns="http://www.w3.org/2000/svg"
:height="height"
:class="!isDefaultTheme ? 'custom-logo-color' : ''"
>
<g clip-path="url(#clip0_5682_1471)" fill-rule="evenodd">
<path
d="M75.3094 19.0805V27.05H71.8274L71.8109 26.2436C70.5933 26.8762 69.4033 27.1925 68.2412 27.1923H67.8972C66.7033 27.1923 65.7546 26.7337 65.051 25.8166C64.5855 25.1007 64.342 24.2631 64.3513 23.4092V23.3143C64.3513 21.7489 64.9008 20.7092 65.9997 20.1953C66.4505 19.8949 67.5929 19.7447 69.4271 19.7447H71.3008V19.3058C71.3008 18.4045 71.1703 17.8867 70.9094 17.7523C70.6249 17.5388 70.1228 17.4321 69.4033 17.4321H65.6678L65.7312 14.2396L70.032 14.1233C72.5857 14.1233 74.1669 14.7558 74.7758 16.0208C75.1315 16.756 75.3094 17.7759 75.3094 19.0805ZM68.6032 22.3901C68.4844 22.5315 68.3597 22.9902 68.3597 23.3143C68.3597 24.0259 68.7234 24.3817 69.4508 24.3817C69.8855 24.3817 70.5022 24.2038 71.3008 23.848V22.1112C71.3008 22.1112 69.0361 21.875 68.6032 22.3901Z"
fill="currentColor"
/>
<path
d="M56.6308 27.3317L55.4162 15.1815L52.0028 27.3317H48.028L44.6928 15.1815L43.4348 27.3317L37.9399 27.2849L40.6207 9.35034H47.6212L50.0211 17.8845L52.4444 9.35034H59.281L62.0087 27.3317H56.6308Z"
fill="currentColor"
/>
<path
d="M85.3943 26.9654L83.5118 23.1105L81.6291 26.9654H77.2017L80.831 20.5778L77.3644 14.6084H81.6525L83.5118 18.2543L85.313 14.6084H89.6009L86.1576 20.5778L89.7637 26.9654H85.3943Z"
fill="currentColor"
/>
<path
d="M101.114 26.9656C101.029 26.8419 96.8966 20.1336 96.8966 20.1336L95.5396 22.2226V26.9656H90.9727V9.11621H95.5396V16.3526L99.7128 9.17639H104.477L99.514 17.1079L105.855 26.9656H101.114Z"
fill="currentColor"
/>
<path
d="M121.036 22.145C121.036 24.745 119.74 27.1282 115.097 27.1282H107.032V9.02689L113.203 8.90869C113.203 8.90869 116.858 8.74751 118.706 10.153C120.068 11.1885 120.515 13.0021 120.384 14.5197C120.254 16.0373 119.553 17.0129 118.405 17.727C119.979 18.354 121.036 19.5451 121.036 22.145ZM114.228 16.3325C115.766 16.3325 116.62 15.5559 116.62 14.45C116.62 13.2735 115.833 12.5837 114.228 12.5837L111.576 12.5906V16.3325H114.228ZM114.365 23.5374C116.497 23.5374 117.022 22.393 117.022 21.6316C117.022 20.4308 116.17 19.563 114.752 19.563H111.576V23.5374H114.365Z"
fill="currentColor"
/>
<path
d="M17.4213 26.7354H12.8296L11.1277 28.4372C11.028 28.5369 10.9601 28.6639 10.9326 28.8022C10.9051 28.9405 10.9193 29.0838 10.9732 29.2141C11.0272 29.3443 11.1185 29.4557 11.2358 29.534C11.353 29.6123 11.4908 29.6541 11.6318 29.6541H18.6192C18.7602 29.6541 18.898 29.6123 19.0153 29.534C19.1325 29.4557 19.2239 29.3443 19.2778 29.2141C19.3318 29.0838 19.3459 28.9405 19.3184 28.8022C19.2909 28.6639 19.223 28.5369 19.1233 28.4372L17.4213 26.7354Z"
fill="currentColor"
/>
<path
d="M30.04 13.3823H29.1348V19.7499H30.04C30.1305 19.7499 30.2201 19.732 30.3037 19.6974C30.3873 19.6628 30.4633 19.612 30.5273 19.548C30.5913 19.484 30.642 19.4081 30.6767 19.3244C30.7113 19.2408 30.7291 19.1512 30.7291 19.0607V14.0715C30.7291 13.8887 30.6565 13.7134 30.5273 13.5842C30.398 13.4549 30.2227 13.3823 30.04 13.3823Z"
fill="currentColor"
/>
<path
d="M1.92296 13.3823H1.01776C0.834985 13.3823 0.659698 13.4549 0.530458 13.5842C0.401219 13.7134 0.328613 13.8887 0.328613 14.0715V19.0607C0.328611 19.1512 0.346435 19.2408 0.381067 19.3244C0.415699 19.4081 0.466461 19.484 0.530455 19.548C0.594448 19.612 0.670419 19.6628 0.754031 19.6974C0.837643 19.732 0.927258 19.7499 1.01776 19.7499H1.92296V13.3823Z"
fill="currentColor"
/>
<path
d="M19.0238 14.2251C18.682 14.2251 18.3541 14.3609 18.1124 14.6026C17.8707 14.8443 17.7349 15.1722 17.7349 15.514V16.4382C17.7349 16.7801 17.8707 17.108 18.1124 17.3497C18.3541 17.5914 18.682 17.7272 19.0239 17.7272C19.3657 17.7272 19.6936 17.5914 19.9353 17.3497C20.1771 17.108 20.3129 16.7801 20.3129 16.4382V15.5141C20.3129 15.3448 20.2796 15.1772 20.2148 15.0208C20.15 14.8644 20.055 14.7223 19.9353 14.6026C19.8156 14.4829 19.6735 14.388 19.5171 14.3232C19.3607 14.2584 19.1931 14.2251 19.0238 14.2251Z"
fill="currentColor"
/>
<path
d="M12.3012 14.2251C11.9593 14.2251 11.6315 14.3609 11.3897 14.6026C11.148 14.8443 11.0122 15.1722 11.0122 15.514V16.4382C11.0122 16.7801 11.148 17.108 11.3897 17.3497C11.6315 17.5914 11.9593 17.7272 12.3012 17.7272C12.6431 17.7272 12.9709 17.5914 13.2127 17.3497C13.4544 17.108 13.5902 16.7801 13.5902 16.4382V15.5141C13.5902 15.3448 13.5569 15.1772 13.4921 15.0208C13.4273 14.8644 13.3324 14.7223 13.2127 14.6026C13.093 14.4829 12.9509 14.388 12.7945 14.3232C12.6381 14.2584 12.4704 14.2251 12.3012 14.2251Z"
fill="currentColor"
/>
<path
d="M23.3607 6.91333H7.69709C6.3139 6.91489 4.98782 7.46505 4.00976 8.44311C3.0317 9.42117 2.48154 10.7473 2.47998 12.1304V20.9612C2.48154 22.3444 3.03169 23.6705 4.00975 24.6486C4.98781 25.6266 6.3139 26.1768 7.69709 26.1784H23.3607C24.7439 26.1768 26.07 25.6267 27.0481 24.6486C28.0262 23.6705 28.5764 22.3444 28.5779 20.9612V12.1304C28.5763 10.7472 28.0262 9.42115 27.0481 8.44309C26.07 7.46503 24.7439 6.91487 23.3607 6.91333ZM23.7988 20.9085C23.7988 21.1577 23.6998 21.3968 23.5235 21.573C23.3473 21.7492 23.1083 21.8482 22.859 21.8482H15.2189C14.0629 21.8482 12.9263 22.1453 11.9181 22.711L9.355 24.1492V21.8483H8.19882C7.94958 21.8483 7.71055 21.7493 7.53432 21.573C7.35808 21.3968 7.25907 21.1578 7.25906 20.9085V11.547C7.25907 11.2978 7.35808 11.0588 7.53432 10.8825C7.71056 10.7063 7.94958 10.6073 8.19882 10.6073H22.859C23.1082 10.6073 23.3472 10.7063 23.5235 10.8825C23.6997 11.0588 23.7987 11.2978 23.7987 11.5471L23.7988 20.9085Z"
fill="currentColor"
/>
</g>
</svg>
<img v-else src="@/assets/logo/MaxKB-logo.svg" :height="height" />
</template>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
@ -66,9 +69,21 @@ defineProps({
default: '36px'
}
})
const { common } = useStore()
const { user } = useStore()
const isDefaultTheme = computed(() => {
return common.isDefaultTheme()
return user.isDefaultTheme()
})
const fileURL = computed(() => {
if (user.themeInfo.loginLogo) {
if (typeof user.themeInfo.loginLogo === 'string') {
return user.themeInfo.loginLogo
} else {
return URL.createObjectURL(user.themeInfo.loginLogo)
}
} else {
return ''
}
})
</script>
<style lang="scss" scoped>

View File

@ -45,9 +45,9 @@ defineProps({
default: '36px'
}
})
const { common } = useStore()
const { user } = useStore()
const isDefaultTheme = computed(() => {
return common.isDefaultTheme()
return user.isDefaultTheme()
})
</script>
<style lang="scss" scoped>

View File

@ -8,9 +8,9 @@
import { ref, computed, onMounted } from 'vue'
import TopBar from '../top-bar/index.vue'
import useStore from '@/stores'
const { common } = useStore()
const { user } = useStore()
const isDefaultTheme = computed(() => {
return common.isDefaultTheme()
return user.isDefaultTheme()
})
</script>

View File

@ -35,9 +35,9 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import useStore from '@/stores'
const { common, user } = useStore()
const { user } = useStore()
const isDefaultTheme = computed(() => {
return common.isDefaultTheme()
return user.isDefaultTheme()
})
const aboutDialogVisible = ref(false)

View File

@ -4,7 +4,6 @@ import * as ElementPlusIcons from '@element-plus/icons-vue'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import { createApp } from 'vue'
import { store } from '@/stores'
import theme from '@/theme'
import directives from '@/directives'
import App from './App.vue'
import router from '@/router'
@ -56,8 +55,6 @@ app.use(ElementPlus, {
locale: zhCn
})
app.use(theme)
app.use(router)
app.use(i18n)
app.use(Components)

View File

@ -4,7 +4,7 @@ import { Role, ComplexPermission } from '@/utils/permission/type'
const settingRouter = {
path: '/setting',
name: 'setting',
meta: { icon: 'Setting', title: '系统设置', permission: 'SETTING:READ' },
meta: { icon: 'Setting', title: '系统管理', permission: 'SETTING:READ' },
redirect: () => {
if (hasPermission(new Role('ADMIN'), 'AND')) {
return '/user'
@ -59,7 +59,7 @@ const settingRouter = {
meta: {
icon: 'app-setting',
iconActive: 'app-setting-active',
title: '系统设置',
title: '系统管理',
activeMenu: '/setting',
parentPath: '/setting',
parentName: 'setting',

View File

@ -8,7 +8,6 @@ export interface commonTypes {
paginationConfig: any | null
search: any
device: string
theme: string
}
const useCommonStore = defineStore({
@ -18,16 +17,9 @@ const useCommonStore = defineStore({
// 搜索和分页缓存
paginationConfig: {},
search: {},
device: DeviceType.Desktop,
theme: ''
device: DeviceType.Desktop
}),
actions: {
isDefaultTheme() {
return !this.theme || this.theme === '#3370FF'
},
setTheme(val: string) {
this.theme = val
},
saveBreadcrumb(data: any) {
this.breadcrumb = data
},

View File

@ -2,6 +2,8 @@ import { defineStore } from 'pinia'
import type { User } from '@/api/type/user'
import UserApi from '@/api/user'
import ThemeApi from '@/api/theme'
import { useElementPlusTheme } from 'use-element-plus-theme'
const { changeTheme } = useElementPlusTheme()
export interface userStateTypes {
userType: number // 1 系统操作者 2 对话用户
@ -26,6 +28,13 @@ const useUserStore = defineStore({
themeInfo: null
}),
actions: {
isDefaultTheme() {
return !this.themeInfo?.theme || this.themeInfo?.theme === '#3370FF'
},
setTheme(data: any) {
changeTheme(data?.['theme'])
this.themeInfo = data
},
isExpire() {
return this.isXPack && !this.XPACK_LICENSE_IS_VALID
},
@ -82,8 +91,14 @@ const useUserStore = defineStore({
},
async theme() {
return ThemeApi.getThemeInfo().then((ok) => {
return await ThemeApi.getThemeInfo().then((ok) => {
this.themeInfo = ok.data
changeTheme(this.themeInfo['theme'])
window.document.title = this.themeInfo['title'] || 'MaxKB'
const link = document.querySelector('link[rel="icon"]') as any
if (link) {
link['href'] = this.themeInfo['icon'] || '/favicon.ico'
}
})
},

View File

@ -369,8 +369,8 @@ h5 {
/* tag */
.default-tag {
background: var(--tag-default-bg);
color: var(--tag-default-color);
background: var(--el-color-primary-light-7);
color: var(--el-color-primary);
border: none;
}
.success-tag {

View File

@ -1,13 +0,0 @@
import type { InferData } from "./type";
const inferData: Array<InferData> = [
{
key: "primary",
value: "#3370FF",
},
{ key: "success", value: "#67c23a" },
{ key: "warning", value: "#e6a23c" },
{ key: "danger", value: "#f56c6c" },
{ key: "error", value: "#F54A45" },
{ key: "info", value: "#909399" },
];
export default inferData;

View File

@ -1,5 +0,0 @@
import type { KeyValueData } from './type'
const keyValueData: KeyValueData = {
'--el-header-padding': '0px'
}
export default keyValueData

View File

@ -1,281 +0,0 @@
import type {
ThemeSetting,
InferData,
KeyValueData,
UpdateInferData,
UpdateKeyValueData
} from './type'
import { TinyColor } from '@ctrl/tinycolor'
// 引入默认推断数据
import inferData from './defaultInferData'
// 引入默认keyValue数据
import keyValueData from './defaultKeyValueData'
// 引入设置对象
import setting from './setting'
import type { App } from 'vue'
declare global {
interface ChildNode {
innerText: string
}
}
class Theme {
/**
*
*/
themeSetting: ThemeSetting
/**
*
*/
keyValue: KeyValueData
/**
*
*/
inferData: Array<InferData>
/**
*
*/
isFirstWriteStyle: boolean
/**
*
*/
colorWhite: string
/**
*
*/
colorBlack: string
constructor(themeSetting: ThemeSetting, keyValue: KeyValueData, inferData: Array<InferData>) {
this.themeSetting = themeSetting
this.keyValue = keyValue
this.inferData = inferData
this.isFirstWriteStyle = true
this.colorWhite = '#ffffff'
this.colorBlack = '#000000'
this.initDefaultTheme()
}
/**
*
* @param setting
* @param names
* @returns
*/
getVarName = (setting: ThemeSetting, ...names: Array<string>) => {
return (
setting.startDivision + setting.namespace + setting.division + names.join(setting.division)
)
}
/**
*
* @param setting
* @param inferData
* @returns
*/
mapInferMainStyle = (setting: ThemeSetting, inferData: InferData) => {
const key: string = this.getVarName(
setting,
inferData.setting ? inferData.setting.type : setting.colorInferSetting.type,
inferData.key
)
return {
[key]: inferData.value,
...this.mapInferDataStyle(setting, inferData)
}
}
/**
*
* @param setting
* @param inferData
*/
mapInferData = (setting: ThemeSetting, inferData: Array<InferData>) => {
return inferData
.map((itemData) => {
return this.mapInferMainStyle(setting, itemData)
})
.reduce((pre, next) => {
return { ...pre, ...next }
}, {})
}
/**
*
* @param setting
* @param inferData
* @returns
*/
mapInferDataStyle = (setting: ThemeSetting, inferData: InferData) => {
const inferSetting = inferData.setting ? inferData.setting : setting.colorInferSetting
if (inferSetting.type === 'color') {
return Object.keys(inferSetting)
.map((key: string) => {
if (key === 'light' || key === 'dark') {
return inferSetting[key]
.map((l: any) => {
const varName = this.getVarName(
setting,
inferSetting.type,
inferData.key,
key,
l.toString()
)
return {
[varName]: new TinyColor(inferData.value)
.mix(key === 'light' ? this.colorWhite : this.colorBlack, l * 10)
.toHexString()
}
})
.reduce((pre: any, next: any) => {
return { ...pre, ...next }
}, {})
}
return {}
})
.reduce((pre, next) => {
return { ...pre, ...next }
}, {})
}
return {}
}
/**
*
* @param themeSetting
* @param keyValueData
* @returns
*/
mapKeyValue = (themeSetting: ThemeSetting, keyValueData: KeyValueData) => {
return Object.keys(keyValueData)
.map((key: string) => {
return {
[this.updateKeyBySetting(key, themeSetting)]: keyValueData[key]
}
})
.reduce((pre, next) => {
return { ...pre, ...next }
}, {})
}
/**
* Key
* @param key key
* @param themeSetting
* @returns
*/
updateKeyBySetting = (key: string, themeSetting: ThemeSetting) => {
return key.startsWith(themeSetting.startDivision)
? key
: key.startsWith(themeSetting.namespace)
? themeSetting.startDivision + key
: key.startsWith(themeSetting.division)
? themeSetting.startDivision + themeSetting.namespace
: themeSetting.startDivision + themeSetting.namespace + themeSetting.division + key
}
/**
*
* @param setting
* @param keyValue
* @param inferData
* @returns
*/
tokeyValueStyle = () => {
return {
...this.mapInferData(this.themeSetting, this.inferData),
...this.mapKeyValue(this.themeSetting, this.keyValue)
}
}
/**
* keyValue对象转换为S
* @param keyValue
* @returns
*/
toString = (keyValue: KeyValueData) => {
const inner = Object.keys(keyValue)
.map((key: string) => {
return key + ':' + keyValue[key] + ';'
})
.join('')
return `@charset "UTF-8";:root{${inner}}`
}
/**
*
* @param elNewStyle
*/
writeNewStyle = (elNewStyle: string) => {
if (this.isFirstWriteStyle) {
const style = document.createElement('style')
style.innerText = elNewStyle
document.head.appendChild(style)
this.isFirstWriteStyle = false
} else {
if (document.head.lastChild) {
document.head.lastChild.innerText = elNewStyle
}
}
}
/**
* dom
* @param updateInferData
* @param updateKeyvalueData keyValue数据修改
*/
updateWrite = (updateInferData?: UpdateInferData, updateKeyvalueData?: UpdateKeyValueData) => {
this.update(updateInferData, updateKeyvalueData)
const newStyle = this.tokeyValueStyle()
const newStyleString = this.toString(newStyle)
this.writeNewStyle(newStyleString)
}
/**
*
* @param inferData
* @param keyvalueData
*/
update = (updateInferData?: UpdateInferData, updateKeyvalueData?: UpdateKeyValueData) => {
if (updateInferData) {
this.updateInferData(updateInferData)
}
if (updateKeyvalueData) {
this.updateOrCreateKeyValueData(updateKeyvalueData)
}
}
/**
* ,
* @param inferData
*/
updateInferData = (updateInferData: UpdateInferData) => {
Object.keys(updateInferData).forEach((key) => {
const findInfer = this.inferData.find((itemInfer) => {
return itemInfer.key === key
})
if (findInfer) {
findInfer.value = updateInferData[key]
} else {
this.inferData.push({ key, value: updateInferData[key] })
}
})
}
/**
*
*/
initDefaultTheme = () => {
this.updateWrite()
}
/**
* KeyValue数据
* @param keyvalueData keyValue数据
*/
updateOrCreateKeyValueData = (updateKeyvalueData: UpdateKeyValueData) => {
Object.keys(updateKeyvalueData).forEach((key) => {
const newKey = this.updateKeyBySetting(key, this.themeSetting)
this.keyValue[newKey] = updateKeyvalueData[newKey]
})
}
}
const install = (app: App) => {
app.config.globalProperties.theme = new Theme(setting, keyValueData, inferData)
}
export default { install }

View File

@ -1,12 +0,0 @@
import type { ThemeSetting } from "./type";
const setting: ThemeSetting = {
namespace: "el",
division: "-",
startDivision: "--",
colorInferSetting: {
light: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
dark: [2],
type: "color",
},
};
export default setting;

View File

@ -1,71 +0,0 @@
interface ThemeSetting {
/**
*element-ui Namespace
*/
namespace: string;
/**
*
*/
division: string;
/**
*
*/
startDivision: string;
/**
*
*/
colorInferSetting: ColorInferSetting;
}
/**
*
*/
interface ColorInferSetting {
/**
*
*/
light: Array<number>;
/**
*
*/
dark: Array<number>;
/**
*
*/
type: string;
}
/**
*
*/
interface KeyValueData {
[propName: string]: string;
}
type UpdateInferData = KeyValueData;
type UpdateKeyValueData = KeyValueData;
/**
*
*/
interface InferData {
/**
*
*/
setting?: ColorInferSetting | any;
/**
*
*/
key: string;
/**
*
*/
value: string;
}
export type {
KeyValueData,
InferData,
ThemeSetting,
UpdateInferData,
UpdateKeyValueData,
};

44
ui/src/utils/theme.ts Normal file
View File

@ -0,0 +1,44 @@
export const themeList = [
{
label: '默认',
value: '#3370FF',
loginBackground: 'default'
},
{
label: '活力橙',
value: '#FF8800',
loginBackground: 'orange'
},
{
label: '松石绿',
value: '#00B69D',
loginBackground: 'green'
},
{
label: '商务蓝',
value: '#4954E6',
loginBackground: 'default'
},
{
label: '神秘紫',
value: '#7F3BF5',
loginBackground: 'purple'
},
{
label: '胭脂红',
value: '#F01D94',
loginBackground: 'red'
}
]
export function getThemeImg(val: string) {
return themeList.filter((v) => v.value === val)?.[0]?.loginBackground || 'default'
}
export const defautSetting = {
icon: '',
loginLogo: '',
loginImage: '',
title: 'MaxKB',
slogan: '欢迎使用 MaxKB 智能知识库'
}

View File

@ -64,7 +64,7 @@
<div class="mr-16">
<el-button link @click="enlarge = !enlarge">
<AppIcon
:iconName="enlarge ? 'app-magnify' : 'app-minify'"
:iconName="enlarge ? 'app-minify' : 'app-magnify'"
class="color-secondary"
style="font-size: 20px"
></AppIcon>

View File

@ -1,6 +1,6 @@
<template>
<div class="authentication-setting p-24">
<h4>{{$t('login.authentication')}}</h4>
<h4>{{ $t('login.authentication') }}</h4>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<template v-for="(item, index) in tabList" :key="index">
<el-tab-pane :label="item.label" :name="item.name">
@ -29,13 +29,6 @@ const tabList = [
}
]
//
const loadComponent = async (componentName: string) => {
await import(`./component/${componentName}.vue`).then((res) => res.default)
}
const currentComponent = computed(() => loadComponent(activeName.value))
function handleClick() {}
onMounted(() => {})

View File

@ -1,21 +1,21 @@
<template>
<login-layout v-loading="loading">
<LoginContainer subTitle="欢迎使用 MaxKB 智能知识库">
<LoginContainer :subTitle="user.themeInfo?.slogan || '欢迎使用 MaxKB 智能知识库'">
<h2 class="mb-24">{{ loginMode || '普通登录' }}</h2>
<el-form
class="login-form"
:rules="rules"
:model="loginForm"
ref="loginFormRef"
@keyup.enter="login"
class="login-form"
:rules="rules"
:model="loginForm"
ref="loginFormRef"
@keyup.enter="login"
>
<div class="mb-24">
<el-form-item prop="username">
<el-input
size="large"
class="input-item"
v-model="loginForm.username"
placeholder="请输入用户名"
size="large"
class="input-item"
v-model="loginForm.username"
placeholder="请输入用户名"
>
</el-input>
</el-form-item>
@ -23,12 +23,12 @@
<div class="mb-24">
<el-form-item prop="password">
<el-input
type="password"
size="large"
class="input-item"
v-model="loginForm.password"
placeholder="请输入密码"
show-password
type="password"
size="large"
class="input-item"
v-model="loginForm.password"
placeholder="请输入密码"
show-password
>
</el-input>
</el-form-item>
@ -40,10 +40,10 @@
注册
</el-button> -->
<el-button
class="forgot-password"
@click="router.push('/forgot_password')"
link
type="primary"
class="forgot-password"
@click="router.push('/forgot_password')"
link
type="primary"
>
忘记密码?
</el-button>
@ -55,21 +55,21 @@
<div class="text-center mt-16">
<template v-for="item in modeList">
<el-button
v-if="item !== ''&&loginMode !== item"
circle
:key="item"
class="login-button-circle color-secondary"
@click="changeMode(item)"
>{{ item }}
v-if="item !== '' && loginMode !== item"
circle
:key="item"
class="login-button-circle color-secondary"
@click="changeMode(item)"
>{{ item }}
</el-button>
<el-button
v-if="item === ''&&loginMode !== ''"
circle
:key="item"
class="login-button-circle color-secondary"
style="font-size: 24px"
icon="UserFilled"
@click="changeMode('')"
v-if="item === '' && loginMode !== ''"
circle
:key="item"
class="login-button-circle color-secondary"
style="font-size: 24px"
icon="UserFilled"
@click="changeMode('')"
/>
</template>
</div>
@ -77,14 +77,14 @@
</login-layout>
</template>
<script setup lang="ts">
import {onMounted, ref} from 'vue'
import type {LoginRequest} from '@/api/type/user'
import {useRouter} from 'vue-router'
import type {FormInstance, FormRules} from 'element-plus'
import { onMounted, ref } from 'vue'
import type { LoginRequest } from '@/api/type/user'
import { useRouter } from 'vue-router'
import type { FormInstance, FormRules } from 'element-plus'
import useStore from '@/stores'
const loading = ref<boolean>(false)
const {user} = useStore()
const { user } = useStore()
const router = useRouter()
const loginForm = ref<LoginRequest>({
username: '',
@ -109,8 +109,7 @@ const rules = ref<FormRules<LoginRequest>>({
})
const loginFormRef = ref<FormInstance>()
const modeList = ref<string[]>(['']);
const modeList = ref<string[]>([''])
const loginMode = ref('')
function changeMode(val: string) {
@ -126,25 +125,28 @@ const login = () => {
loginFormRef.value?.validate().then(() => {
loading.value = true
user
.login(loginMode.value, loginForm.value.username, loginForm.value.password)
.then(() => {
router.push({name: 'home'})
})
.finally(() => (loading.value = false))
.login(loginMode.value, loginForm.value.username, loginForm.value.password)
.then(() => {
router.push({ name: 'home' })
})
.finally(() => (loading.value = false))
})
}
onMounted(() => {
user.theme()
user.asyncGetProfile().then((res) => {
if (user.isXPack) {
loading.value = true
user.getAuthType().then((res) => {
modeList.value = [...modeList.value, ...res];
}).finally(() => (loading.value = false))
user
.getAuthType()
.then((res) => {
modeList.value = [...modeList.value, ...res]
})
.finally(() => (loading.value = false))
}
})
})
</script>
<style lang="scss" scope>
.login-gradient-divider {

View File

@ -3,14 +3,15 @@
<div class="header">
<div class="tag flex-between">
<div class="flex align-center">
<LogoIcon height="24px" class="mr-8" />
<span class="ellipsis">{{ title }}</span>
<img v-if="props.data.icon" :src="fileURL" alt="" height="20px" class="mr-8" />
<img v-else src="@/assets/logo/logo.svg" height="24px" class="mr-8" />
<span class="ellipsis">{{ data.title }}</span>
</div>
<el-icon><Close /></el-icon>
</div>
</div>
<login-layout style="height: 530px" :themeImg="themeImg">
<LoginContainer :subTitle="slogan" class="login-container">
<login-layout style="height: 530px">
<LoginContainer :subTitle="data.slogan" class="login-container">
<div class="mask"></div>
<h2 class="mb-24">{{ '普通登录' }}</h2>
<el-form class="login-form">
@ -42,18 +43,24 @@
</template>
<script lang="ts" setup>
import { computed } from 'vue'
const props = defineProps({
themeImg: {
type: String,
default: 'default'
},
slogan: {
type: String,
default: '欢迎使用 MaxKB 智能知识库'
},
title: {
type: String,
default: 'MaxKB'
data: {
type: Object,
default: null
}
})
const fileURL = computed(() => {
if (props.data.icon) {
if (typeof props.data.icon === 'string') {
return props.data.icon
} else {
return URL.createObjectURL(props.data.icon)
}
} else {
return ''
}
})
</script>

View File

@ -1,5 +1,5 @@
<template>
<div class="theme-setting">
<div class="theme-setting" v-loading="loading">
<h4 class="p-16-24">外观设置</h4>
<el-scrollbar>
<div class="p-24 pt-0">
@ -8,7 +8,7 @@
<el-radio-group
v-model="themeForm.theme"
class="app-radio-button-group"
@change="changeTheme"
@change="changeThemeHandle"
>
<template v-for="(item, index) in themeList" :key="index">
<el-radio-button :label="item.label" :value="item.value" />
@ -20,19 +20,30 @@
<el-card shadow="never" class="layout-bg">
<div class="flex-between">
<h5 class="mb-16">页面预览</h5>
<el-button type="primary" link> 恢复默认 </el-button>
<el-button type="primary" link @click="resetForm"> 恢复默认 </el-button>
</div>
<div class="theme-preview">
<el-row :gutter="8">
<el-col :span="16">
<LoginPreview :themeImg="themeImg" :slogan="themeForm.slogan" :title="themeForm.title" />
<LoginPreview :data="themeForm" />
</el-col>
<el-col :span="8">
<div class="theme-form">
<el-card shadow="never" class="mb-8">
<div class="flex-between mb-8">
<span class="lighter">网站 Logo</span>
<el-button size="small"> 替换图片 </el-button>
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:show-file-list="false"
accept="image/*"
:on-change="
(file: any, fileList: any) => onChange(file, fileList, 'icon')
"
>
<el-button size="small"> 替换图片 </el-button>
</el-upload>
</div>
<el-text type="info" size="small"
>顶部网站显示的 Logo建议尺寸 48 x 48支持 JPGPNGSVG大小不超过
@ -42,7 +53,18 @@
<el-card shadow="never" class="mb-8">
<div class="flex-between mb-8">
<span class="lighter">登录 Logo</span>
<el-button size="small"> 替换图片 </el-button>
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:show-file-list="false"
accept="image/*"
:on-change="
(file: any, fileList: any) => onChange(file, fileList, 'loginLogo')
"
>
<el-button size="small"> 替换图片 </el-button>
</el-upload>
</div>
<el-text type="info" size="small"
>登录页面右侧 Logo建议尺寸 204*52支持 JPGPNGSVG大小不超过
@ -52,7 +74,18 @@
<el-card shadow="never" class="mb-8">
<div class="flex-between mb-8">
<span class="lighter">登录背景图</span>
<el-button size="small"> 替换图片 </el-button>
<el-upload
ref="uploadRef"
action="#"
:auto-upload="false"
:show-file-list="false"
accept="image/*"
:on-change="
(file: any, fileList: any) => onChange(file, fileList, 'loginImage')
"
>
<el-button size="small"> 替换图片 </el-button>
</el-upload>
</div>
<el-text type="info" size="small">
左侧背景图矢量图建议尺寸 576*900位图建议尺寸1152*1800支持
@ -92,53 +125,34 @@
</el-scrollbar>
<div class="theme-setting__operate w-full p-16-24">
<el-button @click="resetTheme">放弃更新</el-button>
<el-button type="primary"> 保存并应用 </el-button>
<el-button type="primary" @click="updataTheme(themeFormRef)"> 保存并应用 </el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { ref, reactive, onMounted, computed, watch } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
import type { FormInstance, FormRules, UploadFiles } from 'element-plus'
import { cloneDeep } from 'lodash'
import LoginPreview from './LoginPreview.vue'
import { useElementPlusTheme } from 'use-element-plus-theme'
import { themeList, defautSetting } from '@/utils/theme'
import ThemeApi from '@/api/theme'
import { MsgSuccess, MsgError } from '@/utils/message'
import useStore from '@/stores'
const { common } = useStore()
const themeList = [
{
label: '默认',
value: '#3370FF',
loginBackground: 'default'
},
{
label: '活力橙',
value: '#FF8800',
loginBackground: 'orange'
},
{
label: '松石绿',
value: '#00B69D',
loginBackground: 'green'
},
{
label: '商务蓝',
value: '#4954E6',
loginBackground: 'default'
},
{
label: '神秘紫',
value: '#7F3BF5',
loginBackground: 'purple'
},
{
label: '胭脂红',
value: '#F01D94',
loginBackground: 'red'
}
]
const { user } = useStore()
onBeforeRouteLeave((to, from) => {
user.setTheme(cloneTheme.value)
})
const themeInfo = computed(() => user.themeInfo)
const themeFormRef = ref<FormInstance>()
const themeForm = ref({
const loading = ref(false)
const cloneTheme = ref(null)
const themeForm = ref<any>({
theme: '#3370FF',
icon: '',
loginLogo: '',
@ -152,24 +166,67 @@ const rules = reactive<FormRules>({
slogan: [{ required: true, message: '请输入欢迎语', trigger: 'blur' }]
})
const themeImg = ref('default')
const { changeTheme } = useElementPlusTheme(themeForm.value.theme)
function resetTheme() {
themeForm.value.theme = '#3370FF'
changeTheme(themeForm.value.theme)
}
watch(
() => themeForm.value.theme,
(val) => {
if (val) {
common.setTheme(val)
themeImg.value = themeList.filter((v) => v.value === val)[0].loginBackground
const onChange = (file: any, fileList: UploadFiles, attr: string) => {
if (attr === 'loginImage') {
const isLimit = file?.size / 1024 / 1024 < 5
if (!isLimit) {
// @ts-ignore
MsgError(`文件大小超过 5M`)
return false
}
} else {
const isLimit = file?.size / 1024 < 200
if (!isLimit) {
// @ts-ignore
MsgError(`文件大小超过 200KB`)
return false
}
}
)
themeForm.value[attr] = file.raw
}
function changeThemeHandle(val: string) {
themeForm.value.theme = val
user.setTheme(themeForm.value)
}
function resetTheme() {
user.setTheme(cloneTheme.value)
themeForm.value = cloneDeep(themeInfo.value)
}
function resetForm() {
themeForm.value = {
theme: themeForm.value.theme,
...defautSetting
}
user.setTheme(themeForm.value)
}
const updataTheme = async (formEl: FormInstance | undefined, test?: string) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
let fd = new FormData()
Object.keys(themeForm.value).map((item) => {
fd.append(item, themeForm.value[item])
})
ThemeApi.postThemeInfo(fd, loading).then((res) => {
user.theme()
cloneTheme.value = cloneDeep(themeForm.value)
MsgSuccess('外观设置成功')
})
}
})
}
onMounted(() => {
if (themeInfo.value) {
themeForm.value = themeInfo.value
cloneTheme.value = cloneDeep(themeInfo.value)
}
})
</script>
<style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<template>
<AppAvatar shape="square avatar-blue">
<AppAvatar shape="square" class="avatar-blue">
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
</template>