2024-07-09 09:50:37 +00:00
|
|
|
|
<template>
|
2024-07-16 09:32:27 +00:00
|
|
|
|
<div class="theme-setting" v-loading="loading">
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<h4 class="p-16-24">外观设置</h4>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
<el-scrollbar>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<div class="p-24 pt-0">
|
|
|
|
|
|
<div class="app-card p-24">
|
|
|
|
|
|
<h5 class="mb-16">平台显示主题</h5>
|
|
|
|
|
|
<el-radio-group
|
|
|
|
|
|
v-model="themeForm.theme"
|
|
|
|
|
|
class="app-radio-button-group"
|
2024-07-16 09:32:27 +00:00
|
|
|
|
@change="changeThemeHandle"
|
2024-07-12 09:13:11 +00:00
|
|
|
|
>
|
|
|
|
|
|
<template v-for="(item, index) in themeList" :key="index">
|
|
|
|
|
|
<el-radio-button :label="item.label" :value="item.value" />
|
|
|
|
|
|
</template>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</div>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<div class="app-card p-24 mt-16">
|
|
|
|
|
|
<h5 class="mb-16">平台登陆设置</h5>
|
|
|
|
|
|
<el-card shadow="never" class="layout-bg">
|
|
|
|
|
|
<div class="flex-between">
|
|
|
|
|
|
<h5 class="mb-16">页面预览</h5>
|
2024-07-16 09:32:27 +00:00
|
|
|
|
<el-button type="primary" link @click="resetForm"> 恢复默认 </el-button>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</div>
|
2024-07-17 07:24:53 +00:00
|
|
|
|
<el-scrollbar>
|
|
|
|
|
|
<div class="theme-preview">
|
|
|
|
|
|
<el-row :gutter="8">
|
|
|
|
|
|
<el-col :span="16">
|
|
|
|
|
|
<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-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,支持 JPG、PNG、SVG,大小不超过
|
|
|
|
|
|
200KB</el-text
|
2024-07-16 09:32:27 +00:00
|
|
|
|
>
|
2024-07-17 07:24:53 +00:00
|
|
|
|
</el-card>
|
|
|
|
|
|
<el-card shadow="never" class="mb-8">
|
|
|
|
|
|
<div class="flex-between mb-8">
|
|
|
|
|
|
<span class="lighter">登录 Logo</span>
|
|
|
|
|
|
<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,支持 JPG、PNG、SVG,大小不超过
|
|
|
|
|
|
200KB</el-text
|
2024-07-16 09:32:27 +00:00
|
|
|
|
>
|
2024-07-17 07:24:53 +00:00
|
|
|
|
</el-card>
|
|
|
|
|
|
<el-card shadow="never" class="mb-8">
|
|
|
|
|
|
<div class="flex-between mb-8">
|
|
|
|
|
|
<span class="lighter">登录背景图</span>
|
|
|
|
|
|
<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;支持
|
|
|
|
|
|
JPG、PNG、SVG,大小不超过 5M
|
|
|
|
|
|
</el-text>
|
|
|
|
|
|
</el-card>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
|
2024-07-17 07:24:53 +00:00
|
|
|
|
<el-form
|
|
|
|
|
|
ref="themeFormRef"
|
|
|
|
|
|
:model="themeForm"
|
|
|
|
|
|
label-position="top"
|
|
|
|
|
|
require-asterisk-position="right"
|
|
|
|
|
|
:rules="rules"
|
|
|
|
|
|
@submit.prevent
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-form-item label="网站名称" prop="title">
|
|
|
|
|
|
<el-input v-model="themeForm.title" placeholder="请输入网站名称">
|
|
|
|
|
|
</el-input>
|
|
|
|
|
|
<el-text type="info"> 显示在网页 Tab 的平台名称 </el-text>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="欢迎语" prop="slogan">
|
2024-07-24 03:00:19 +00:00
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="themeForm.slogan"
|
|
|
|
|
|
placeholder="请输入欢迎语"
|
|
|
|
|
|
maxlength="64"
|
|
|
|
|
|
show-word-limit
|
|
|
|
|
|
>
|
2024-07-17 07:24:53 +00:00
|
|
|
|
</el-input>
|
|
|
|
|
|
<el-text type="info"> 产品 Logo 下的 欢迎语 </el-text>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</div></el-col
|
|
|
|
|
|
>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-scrollbar>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<div class="mt-16">
|
|
|
|
|
|
<el-text type="info">默认为 MaxKB 登录界面,支持自定义设置</el-text>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</div>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
</el-card>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-scrollbar>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<div class="theme-setting__operate w-full p-16-24">
|
2024-07-12 11:04:08 +00:00
|
|
|
|
<el-button @click="resetTheme">放弃更新</el-button>
|
2024-07-16 09:32:27 +00:00
|
|
|
|
<el-button type="primary" @click="updataTheme(themeFormRef)"> 保存并应用 </el-button>
|
2024-07-12 09:13:11 +00:00
|
|
|
|
</div>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</div>
|
2024-07-09 09:50:37 +00:00
|
|
|
|
</template>
|
2024-07-11 10:13:52 +00:00
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2024-07-16 10:50:44 +00:00
|
|
|
|
import { ref, reactive, onMounted, computed, watch, nextTick } from 'vue'
|
2024-07-22 10:52:56 +00:00
|
|
|
|
import { useRouter, onBeforeRouteLeave } from 'vue-router'
|
2024-07-16 09:32:27 +00:00
|
|
|
|
import type { FormInstance, FormRules, UploadFiles } from 'element-plus'
|
|
|
|
|
|
import { cloneDeep } from 'lodash'
|
2024-07-12 09:13:11 +00:00
|
|
|
|
import LoginPreview from './LoginPreview.vue'
|
2024-07-16 10:26:26 +00:00
|
|
|
|
import { themeList, defaultSetting } from '@/utils/theme'
|
2024-07-16 09:32:27 +00:00
|
|
|
|
import ThemeApi from '@/api/theme'
|
|
|
|
|
|
import { MsgSuccess, MsgError } from '@/utils/message'
|
2024-07-15 06:09:01 +00:00
|
|
|
|
import useStore from '@/stores'
|
2024-07-16 09:32:27 +00:00
|
|
|
|
|
|
|
|
|
|
const { user } = useStore()
|
2024-07-22 10:52:56 +00:00
|
|
|
|
const router = useRouter()
|
2024-07-16 09:32:27 +00:00
|
|
|
|
|
|
|
|
|
|
onBeforeRouteLeave((to, from) => {
|
|
|
|
|
|
user.setTheme(cloneTheme.value)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const themeInfo = computed(() => user.themeInfo)
|
|
|
|
|
|
|
2024-07-12 09:13:11 +00:00
|
|
|
|
const themeFormRef = ref<FormInstance>()
|
2024-07-16 09:32:27 +00:00
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const cloneTheme = ref(null)
|
|
|
|
|
|
const themeForm = ref<any>({
|
2024-07-24 03:19:30 +00:00
|
|
|
|
theme: '',
|
2024-07-12 09:13:11 +00:00
|
|
|
|
icon: '',
|
|
|
|
|
|
loginLogo: '',
|
|
|
|
|
|
loginImage: '',
|
|
|
|
|
|
title: 'MaxKB',
|
|
|
|
|
|
slogan: '欢迎使用 MaxKB 智能知识库'
|
2024-07-11 10:13:52 +00:00
|
|
|
|
})
|
2024-07-12 09:13:11 +00:00
|
|
|
|
|
|
|
|
|
|
const rules = reactive<FormRules>({
|
|
|
|
|
|
title: [{ required: true, message: '请输入网站标题', trigger: 'blur' }],
|
|
|
|
|
|
slogan: [{ required: true, message: '请输入欢迎语', trigger: 'blur' }]
|
2024-07-11 10:13:52 +00:00
|
|
|
|
})
|
2024-07-12 09:13:11 +00:00
|
|
|
|
|
2024-07-16 09:32:27 +00:00
|
|
|
|
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
|
2024-07-24 04:39:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
themeForm.value[attr] = file.raw
|
2024-07-16 09:32:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const isLimit = file?.size / 1024 < 200
|
|
|
|
|
|
if (!isLimit) {
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
MsgError(`文件大小超过 200KB`)
|
|
|
|
|
|
return false
|
2024-07-24 04:39:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
themeForm.value[attr] = file.raw
|
2024-07-16 09:32:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-07-15 10:08:02 +00:00
|
|
|
|
|
2024-07-16 09:32:27 +00:00
|
|
|
|
function changeThemeHandle(val: string) {
|
|
|
|
|
|
themeForm.value.theme = val
|
|
|
|
|
|
user.setTheme(themeForm.value)
|
|
|
|
|
|
}
|
2024-07-12 11:04:08 +00:00
|
|
|
|
|
|
|
|
|
|
function resetTheme() {
|
2024-07-16 09:32:27 +00:00
|
|
|
|
user.setTheme(cloneTheme.value)
|
|
|
|
|
|
themeForm.value = cloneDeep(themeInfo.value)
|
2024-07-12 11:04:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-16 09:32:27 +00:00
|
|
|
|
function resetForm() {
|
|
|
|
|
|
themeForm.value = {
|
|
|
|
|
|
theme: themeForm.value.theme,
|
2024-07-16 10:26:26 +00:00
|
|
|
|
...defaultSetting
|
2024-07-16 09:32:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
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('外观设置成功')
|
|
|
|
|
|
})
|
2024-07-12 11:04:08 +00:00
|
|
|
|
}
|
2024-07-16 09:32:27 +00:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
2024-07-22 10:52:56 +00:00
|
|
|
|
if (user.isExpire()) {
|
|
|
|
|
|
router.push({ path: `/application` })
|
|
|
|
|
|
}
|
2024-07-16 09:32:27 +00:00
|
|
|
|
if (themeInfo.value) {
|
|
|
|
|
|
themeForm.value = themeInfo.value
|
|
|
|
|
|
cloneTheme.value = cloneDeep(themeInfo.value)
|
2024-07-12 11:04:08 +00:00
|
|
|
|
}
|
2024-07-16 09:32:27 +00:00
|
|
|
|
})
|
2024-07-11 10:13:52 +00:00
|
|
|
|
</script>
|
|
|
|
|
|
|
2024-07-12 09:13:11 +00:00
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.theme-setting {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2024-07-11 10:13:52 +00:00
|
|
|
|
box-sizing: border-box;
|
2024-07-12 09:13:11 +00:00
|
|
|
|
position: relative;
|
|
|
|
|
|
padding-bottom: 64px;
|
|
|
|
|
|
|
|
|
|
|
|
&__operate {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
background: #ffffff;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
box-shadow: 0px -2px 4px 0px rgba(31, 35, 41, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
.theme-preview {
|
|
|
|
|
|
min-width: 1000px;
|
2024-07-11 10:13:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|