354 lines
10 KiB
Vue
354 lines
10 KiB
Vue
<script lang="ts" setup>
|
||
import { Modal, message } from 'ant-design-vue/lib';
|
||
import { FileType } from 'ant-design-vue/lib/upload/interface';
|
||
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
||
import IconFont from '@/components/IconFont/index.vue';
|
||
import { onMounted, reactive, watch, computed } from 'vue';
|
||
import useAppStore from '@/store/modules/app';
|
||
import useI18n from '@/hooks/useI18n';
|
||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||
import { uploadFile } from '@/api/tool/file';
|
||
import { changeValue } from '@/api/system/config';
|
||
import { sessionGet } from '@/utils/cache-session-utils';
|
||
import { transferStaticFile } from '@/api';
|
||
import { parseUrlPath } from '@/plugins/file-static-url';
|
||
const appStore = useAppStore();
|
||
const { t, currentLocale, optionsLocale } = useI18n();
|
||
|
||
type StateType = {
|
||
edite: boolean;
|
||
loading: boolean;
|
||
language: string;
|
||
filePath: string; // 是否上传文件
|
||
flag: string; // 是否变更标记
|
||
type: 'brand' | 'icon';
|
||
icon: string;
|
||
brand: string;
|
||
};
|
||
|
||
let state: StateType = reactive({
|
||
edite: false,
|
||
loading: false,
|
||
language: '',
|
||
filePath: '',
|
||
flag: '',
|
||
type: 'icon',
|
||
icon: '',
|
||
brand: '',
|
||
});
|
||
|
||
/**上传前检查或转换压缩 */
|
||
function fnBeforeUpload(file: FileType) {
|
||
if (state.loading) return false;
|
||
const isJpgOrPng = ['image/jpeg', 'image/png'].includes(file.type);
|
||
if (!isJpgOrPng) {
|
||
message.error(
|
||
t('views.system.setting.uploadFormat', { format: 'jpg、png' }),
|
||
3
|
||
);
|
||
}
|
||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||
if (!isLt2M) {
|
||
message.error(t('views.system.setting.uploadSize', { size: 2 }), 3);
|
||
}
|
||
return isJpgOrPng && isLt2M;
|
||
}
|
||
|
||
/**上传变更 */
|
||
function fnUpload(up: UploadRequestOption) {
|
||
Modal.confirm({
|
||
title: t('common.tipTitle'),
|
||
content: t('views.system.setting.sysLogoTipContentUpload'),
|
||
onOk() {
|
||
// 发送请求
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
state.loading = true;
|
||
let formData = new FormData();
|
||
formData.append('file', up.file);
|
||
formData.append('subPath', 'default');
|
||
uploadFile(formData).then(res => {
|
||
state.loading = false;
|
||
hide();
|
||
if (res.code === RESULT_CODE_SUCCESS) {
|
||
message.success(t('views.system.setting.uploadSuccess'), 3);
|
||
state.filePath = res.data.fileName;
|
||
// 兼容旧前端可改配置文件
|
||
const baseUrl = import.meta.env.PROD
|
||
? sessionGet('baseUrl') || import.meta.env.VITE_API_BASE_URL
|
||
: import.meta.env.VITE_API_BASE_URL;
|
||
if (state.type === 'icon') {
|
||
state.icon = `${baseUrl}${res.data.fileName}`;
|
||
}
|
||
if (state.type === 'brand') {
|
||
state.brand = `${baseUrl}${res.data.fileName}`;
|
||
}
|
||
} else {
|
||
message.error(res.msg, 3);
|
||
}
|
||
});
|
||
},
|
||
});
|
||
}
|
||
|
||
/**进入可编辑 */
|
||
function fnEdit(v: boolean) {
|
||
state.edite = v;
|
||
if (!v) {
|
||
Object.assign(state, {
|
||
filePath: '',
|
||
flag: `${appStore.logoType}/`,
|
||
type: appStore.logoType,
|
||
icon: getLogoURL('icon'),
|
||
brand: getLogoURL('brand'),
|
||
});
|
||
}
|
||
}
|
||
|
||
/**提交保存 */
|
||
function fnSave() {
|
||
Modal.confirm({
|
||
title: t('common.tipTitle'),
|
||
content: t('views.system.setting.sysLogoTipContent'),
|
||
onOk() {
|
||
const reqArr = [];
|
||
// 改变LOGO地址
|
||
if (state.filePath) {
|
||
let changeFilePath = appStore.filePathIcon;
|
||
if (state.type === 'brand') {
|
||
changeFilePath = appStore.filePathBrand;
|
||
}
|
||
reqArr.push(
|
||
transferStaticFile({
|
||
language: state.language,
|
||
uploadPath: state.filePath,
|
||
staticPath: changeFilePath,
|
||
})
|
||
);
|
||
}
|
||
// 判断类型是否改变
|
||
if (state.type !== appStore.logoType) {
|
||
reqArr.push(changeValue({ key: 'sys.logo.type', value: state.type }));
|
||
}
|
||
|
||
// 发送请求
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
state.loading = true;
|
||
Promise.all(reqArr).then(resArr => {
|
||
state.loading = false;
|
||
hide();
|
||
if (resArr[0].code === RESULT_CODE_SUCCESS) {
|
||
message.success(t('views.system.setting.saveSuccess'), 3);
|
||
if (state.type !== appStore.logoType) {
|
||
appStore.logoType = state.type;
|
||
}
|
||
fnEdit(false);
|
||
} else {
|
||
message.error(resArr[0].msg, 3);
|
||
}
|
||
});
|
||
},
|
||
});
|
||
}
|
||
|
||
/**有变更状态进行禁用提交按钮 */
|
||
const changeStatus = computed(() => {
|
||
const changeFlag = `${state.type}/${state.filePath}`;
|
||
if (changeFlag !== state.flag) {
|
||
return false;
|
||
}
|
||
return true;
|
||
});
|
||
|
||
// LOGO地址
|
||
function getLogoURL(type: 'brand' | 'icon') {
|
||
let url =
|
||
type === 'brand'
|
||
? parseUrlPath(appStore.filePathBrand)
|
||
: parseUrlPath(appStore.filePathIcon);
|
||
if (url.indexOf('{language}') === -1) {
|
||
return url;
|
||
}
|
||
// 语言参数替换
|
||
const local = state.language;
|
||
const lang = local.split('_')[0];
|
||
return url.replace('{language}', lang || 'en');
|
||
}
|
||
|
||
// 监听语言切换
|
||
watch(
|
||
() => state.language,
|
||
() => {
|
||
state.icon = getLogoURL('icon');
|
||
state.brand = getLogoURL('brand');
|
||
}
|
||
);
|
||
|
||
onMounted(() => {
|
||
Object.assign(state, {
|
||
language: currentLocale.value,
|
||
filePath: '',
|
||
flag: `${appStore.logoType}/`,
|
||
type: appStore.logoType,
|
||
icon: getLogoURL('icon'),
|
||
brand: getLogoURL('brand'),
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<a-row :gutter="16">
|
||
<a-col :lg="12" :md="12" :xs="24" style="margin-bottom: 30px">
|
||
<a-form layout="vertical">
|
||
<a-form-item style="margin-bottom: 12px">
|
||
<div class="header">
|
||
<div class="header-brand" v-show="state.type === 'brand'">
|
||
<img :width="174" :height="48" :src="state.brand" />
|
||
</div>
|
||
<div class="header-icon" v-show="state.type === 'icon'">
|
||
<img :src="state.icon" />
|
||
<h1 :title="appStore.appName">
|
||
{{ appStore.appName }}
|
||
</h1>
|
||
</div>
|
||
<div class="header-menu">
|
||
<IconFont
|
||
type="icon-pcduan"
|
||
style="margin-right: 10px"
|
||
></IconFont>
|
||
{{ t('router.index') }}
|
||
</div>
|
||
</div>
|
||
</a-form-item>
|
||
<a-form-item>
|
||
<a-select v-model:value="state.language" style="width: 100px">
|
||
<a-select-option
|
||
v-for="opt in optionsLocale"
|
||
:key="opt.value"
|
||
:value="opt.value"
|
||
>
|
||
{{ opt.label }}
|
||
</a-select-option>
|
||
</a-select>
|
||
</a-form-item>
|
||
</a-form>
|
||
|
||
<a-form layout="vertical" v-if="state.edite">
|
||
<a-form-item>
|
||
<a-space direction="horizontal" :size="18">
|
||
<a-radio-group v-model:value="state.type" button-style="solid">
|
||
<a-radio value="brand">
|
||
{{ t('views.system.setting.sysLogoBrand') }}
|
||
</a-radio>
|
||
<a-radio value="icon">
|
||
{{ t('views.system.setting.sysLogoIcon') }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
<a-upload
|
||
name="file"
|
||
list-type="picture"
|
||
accept=".jpg,.png"
|
||
:max-count="1"
|
||
:show-upload-list="false"
|
||
:before-upload="fnBeforeUpload"
|
||
:custom-request="fnUpload"
|
||
>
|
||
<a-button type="link" :loading="state.loading">
|
||
{{ t('views.system.setting.sysLogoUpload') }}
|
||
</a-button>
|
||
</a-upload>
|
||
</a-space>
|
||
</a-form-item>
|
||
|
||
<a-form-item>
|
||
<a-button type="primary" :disabled="changeStatus" @click="fnSave">
|
||
{{ t('views.system.setting.saveSubmit') }}
|
||
</a-button>
|
||
<a-button style="margin-left: 10px" @click="fnEdit(false)">
|
||
{{ t('common.cancel') }}
|
||
</a-button>
|
||
</a-form-item>
|
||
</a-form>
|
||
|
||
<a-button type="dashed" @click="fnEdit(true)" v-else>
|
||
{{ t('common.editText') }}
|
||
</a-button>
|
||
</a-col>
|
||
<a-col :lg="12" :md="12" :xs="24">
|
||
<a-typography>
|
||
<a-typography-paragraph>
|
||
{{ t('views.system.setting.sysLogoInstruction') }}<br />
|
||
{{ t('views.system.setting.sysLogoInstruction1') }}
|
||
</a-typography-paragraph>
|
||
<a-typography-title :level="5">{{
|
||
t('views.system.setting.sysLogoBrand')
|
||
}}</a-typography-title>
|
||
<a-typography-paragraph>
|
||
{{ t('views.system.setting.sysLogoInstruction2') }}
|
||
<a-typography-text mark>174x48</a-typography-text>
|
||
</a-typography-paragraph>
|
||
<a-typography-title :level="5">
|
||
{{ t('views.system.setting.sysLogoIcon') }}
|
||
</a-typography-title>
|
||
<a-typography-paragraph>
|
||
{{ t('views.system.setting.sysLogoInstruction3') }}<br />
|
||
{{ t('views.system.setting.sysLogoInstruction4') }}
|
||
<a-typography-text mark>1:1</a-typography-text>
|
||
eg:<a-typography-text mark>132x132</a-typography-text>
|
||
</a-typography-paragraph>
|
||
</a-typography>
|
||
</a-col>
|
||
</a-row>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.header {
|
||
display: flex;
|
||
align-content: center;
|
||
height: 48px;
|
||
padding-left: 16px;
|
||
background-color: #001529;
|
||
|
||
&-brand {
|
||
width: 174px;
|
||
height: 48px;
|
||
margin-right: 12px;
|
||
border: 1px var(--ant-primary-color) solid;
|
||
}
|
||
&-icon {
|
||
display: flex;
|
||
align-content: center;
|
||
min-width: 174px;
|
||
height: 100%;
|
||
align-items: center;
|
||
margin-right: 16px;
|
||
border: 1px var(--ant-primary-color) solid;
|
||
|
||
& > img {
|
||
height: 32px;
|
||
width: 32px;
|
||
vertical-align: middle;
|
||
border-style: none;
|
||
border-radius: 6.66px;
|
||
}
|
||
& > h1 {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
width: 130px;
|
||
color: #fff;
|
||
margin: 0 0 0 12px;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
&-menu {
|
||
width: 90px;
|
||
line-height: 40px;
|
||
color: #ffffff;
|
||
align-self: center;
|
||
text-align: center;
|
||
}
|
||
}
|
||
</style>
|