UNIVPLMDataIntegration/Web/src/views/system/infoSetting/index.vue

357 lines
13 KiB
Vue

<template>
<div>
<el-card shadow="hover" v-loading="state.isLoading">
<el-descriptions title="系统信息配置" :column="2" :border="true">
<template #title>
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-Setting /> </el-icon> 系统信息配置
</template>
<el-descriptions-item label="系统图标">
<template #label>
<el-icon><ele-School /></el-icon> 系统图标
</template>
<el-upload ref="uploadRef" class="avatar-uploader" :showFileList="false" :autoUpload="false" accept=".jpg,.png,.svg" action :limit="1" :onChange="handleUploadChange">
<img v-if="state.sysInfo.logo" :src="state.sysInfo.logo" class="avatar" />
<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" :size="28" />
</el-upload>
</el-descriptions-item>
<el-descriptions-item label="租户标识">
<template #label>
<el-icon><ele-User /></el-icon> 租户标识
</template>
{{ state.sysInfo.tenantId }}
<p>
<el-tag style="border: 1 solid var(--el-border-color)">访问地址:{{ host }}/#/login?tid={{ state.sysInfo.tenantId }}</el-tag>
</p>
</el-descriptions-item>
<el-descriptions-item label="系统主标题">
<template #label>
<el-icon><ele-Star /></el-icon> 系统主标题
</template>
<el-input v-model="state.sysInfo.title" />
</el-descriptions-item>
<el-descriptions-item label="系统副标题">
<template #label>
<el-icon><ele-Star /></el-icon> 系统副标题
</template>
<el-input v-model="state.sysInfo.viceTitle" />
</el-descriptions-item>
<el-descriptions-item label="系统描述" :span="2">
<template #label>
<el-icon><ele-Guide /></el-icon> 系统描述
</template>
<el-input v-model="state.sysInfo.viceDesc" type="textarea" />
</el-descriptions-item>
<el-descriptions-item label="水印内容">
<template #label>
<el-icon><ele-Football /></el-icon> 水印内容
</template>
<el-input v-model="state.sysInfo.watermark" placeholder="若此处留空,则不显示水印" />
</el-descriptions-item>
<el-descriptions-item label="版权说明">
<template #label>
<el-icon><ele-Stamp /></el-icon> 版权说明
</template>
<el-input v-model="state.sysInfo.copyright" />
</el-descriptions-item>
<el-descriptions-item label="版本号">
<template #label>
<el-icon><ele-Clock /></el-icon> 版本号
</template>
<el-input v-model="state.sysInfo.version" />
</el-descriptions-item>
<el-descriptions-item label="主题颜色">
<template #label>
<el-icon><ele-Grid /></el-icon> 主题颜色
</template>
<el-input v-model="state.sysInfo.themeColor">
<template #prepend>
<div :style="`background-color: ${state.sysInfo.themeColor}; color: white; width: 100px; height: 100%; margin: -20px; text-align: center;`">{{ state.colorName }}</div>
<!-- <div style="background-color: red; color: white; width: 100px; height: 100%; margin: -20px; text-align: center">{{ state.colorName }}</div> -->
</template>
<template #append>
<el-button type="primary" icon="ele-Grid" @click="state.dialogChineseColorVisible = true" style="display: flex">主题色</el-button>
</template>
</el-input>
</el-descriptions-item>
<el-descriptions-item label="布局模式">
<template #label>
<el-icon><ele-Menu /></el-icon> 布局模式
</template>
<el-select v-model="state.sysInfo.layout" placeholder="布局模式">
<el-option label="默认布局" value="defaults" />
<el-option label="经典布局" value="classic" />
<el-option label="横向布局" value="transverse" />
<el-option label="分栏布局" value="columns" />
</el-select>
</el-descriptions-item>
<el-descriptions-item label="页面动画">
<template #label>
<el-icon><ele-Position /></el-icon> 页面动画
</template>
<el-select v-model="state.sysInfo.animation" placeholder="页面动画">
<el-option label="slide-right" value="slide-right"></el-option>
<el-option label="slide-left" value="slide-left"></el-option>
<el-option label="opacitys" value="opacitys"></el-option>
<el-option label="fade" value="fade"></el-option>
<el-option label="fadeUp" value="fadeUp"></el-option>
<el-option label="fadeDown" value="fadeDown"></el-option>
<el-option label="fadeLeft" value="fadeLeft"></el-option>
<el-option label="fadeRight" value="fadeRight"></el-option>
<el-option label="lightSpeedLeft" value="lightSpeedLeft"></el-option>
<el-option label="lightSpeedRight" value="lightSpeedRight"></el-option>
<el-option label="zoom" value="zoom"></el-option>
<el-option label="zoomUp" value="zoomUp"></el-option>
<el-option label="zoomDown" value="zoomDown"></el-option>
<el-option label="zoomLeft" value="zoomLeft"></el-option>
<el-option label="zoomRight" value="zoomRight"></el-option>
<el-option label="flip" value="flip"></el-option>
<el-option label="flipX" value="flipX"></el-option>
<el-option label="flipY" value="flipY"></el-option>
<el-option label="backUp" value="backUp"></el-option>
<el-option label="backDown" value="backDown"></el-option>
<el-option label="backLeft" value="backLeft"></el-option>
<el-option label="backRight" value="backRight"></el-option>
<el-option label="bounce" value="bounce"></el-option>
<el-option label="bounceUp" value="bounceUp"></el-option>
<el-option label="bounceDown" value="bounceDown"></el-option>
<el-option label="bounceLeft" value="bounceLeft"></el-option>
<el-option label="bounceRight" value="bounceRight"></el-option>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="ICP备案号">
<template #label>
<el-icon><ele-Share /></el-icon> ICP备案号
</template>
<el-input v-model="state.sysInfo.icp" />
</el-descriptions-item>
<el-descriptions-item label="ICP地址">
<template #label>
<el-icon><ele-Link /></el-icon> ICP地址
</template>
<el-input v-model="state.sysInfo.icpUrl" />
</el-descriptions-item>
<el-descriptions-item label="图形验证码">
<template #label>
<el-icon><ele-Unlock /></el-icon> 图形验证码
</template>
<el-radio-group v-model="state.sysInfo.captcha">
<el-radio :value="true">启用</el-radio>
<el-radio :value="false">禁用</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="登录二次验证">
<template #label>
<el-icon><ele-Unlock /></el-icon> 登录二次验证
</template>
<el-radio-group v-model="state.sysInfo.secondVer">
<el-radio :value="true">启用</el-radio>
<el-radio :value="false">禁用</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="首页轮播图" :rowspan="5">
<template #label>
<el-icon><ele-Picture /></el-icon> 首页轮播图
</template>
<el-upload :file-list="state.carouselFileList" list-type="picture-card" :http-request="uploadCarouselFile" :on-preview="previewCarouselFile" :before-remove="beforeRemoveCarouselFile">
<el-icon><ele-Plus /></el-icon>
</el-upload>
</el-descriptions-item>
<template #extra>
<el-button type="primary" icon="ele-SuccessFilled" @click="saveSysInfo">保存</el-button>
</template>
</el-descriptions>
</el-card>
<el-dialog v-model="state.dialogChineseColorVisible">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-MagicStick /> </el-icon>
<span> 中国传统颜色 </span>
</div>
</template>
<div style="height: 70vh; overflow-y: scroll; overflow-x: hidden">
<el-row :gutter="20">
<el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="3" class="mb15" v-for="i in chineseColors" :key="i" @click="setThemeColor(i)">
<div class="traditionalColors" :style="'background:' + i.hex">
<el-icon class="traditionalColors-circleCheck" v-if="state.sysInfo.themeColor == i.hex" size="20" color="#fff"><ele-CircleCheck /></el-icon>
</div>
<div class="traditionalColors-chines mt10" style="cursor: grab">{{ i.name }}</div>
<div class="traditionalColors-chines" style="cursor: grab; color: gray">{{ i.hex }}</div>
</el-col>
</el-row>
</div>
</el-dialog>
<el-dialog v-model="state.dialogImagePreviewVisible">
<img w-full :src="state.dialogImagePreviewUrl" alt="" />
</el-dialog>
</div>
</template>
<script setup lang="ts" name="sysInfoSetting">
import { nextTick, onMounted, reactive, ref } from 'vue';
import { ElMessage, ElMessageBox, UploadInstance } from 'element-plus';
import { fileToBase64 } from '/@/utils/base64Conver';
import chineseColors from '/@/layout/navBars/topBar/colors.json';
import { getAPI } from '/@/utils/axios-utils';
import { SysFileApi, SysInfoInput, SysTenantApi } from '/@/api-services';
const host = window.location.host;
const uploadRef = ref<UploadInstance>();
const state = reactive({
isLoading: false,
sysInfo: {} as SysInfoInput | any, // 系统信息数据
logoFile: undefined as any, // logo上传文件
dialogChineseColorVisible: false, // 中国传统颜色弹窗
colorName: '飞燕草蓝', // 主题颜色名称
dialogImagePreviewVisible: false, // 预览图片弹窗
dialogImagePreviewUrl: '', // 预览图片地址
isDelete: false, // 是否已删除图片
carouselFileList: [] as any, // 轮播图片文件列表
});
// 页面初始化
onMounted(async () => {
await loadSysInfoData();
});
// 通过onChange方法获得文件列表
const handleUploadChange = (file: any) => {
uploadRef.value!.clearFiles();
state.logoFile = file;
state.sysInfo.logo = URL.createObjectURL(state.logoFile.raw); // 显示预览logo
};
// 保存
const saveSysInfo = async () => {
// 如果有选择图标,则转换为 base64
if (state.logoFile) {
state.sysInfo.logoBase64 = (await fileToBase64(state.logoFile.raw)) as string;
state.sysInfo.logoFileName = state.logoFile.raw.name;
}
try {
state.isLoading = true;
await getAPI(SysTenantApi).apiSysTenantSaveSysInfoPost(state.sysInfo);
state.logoFile = undefined;
ElMessage.success('保存成功');
} finally {
nextTick(() => {
state.isLoading = false;
});
}
};
// 加载系统信息数据
const loadSysInfoData = async () => {
try {
state.isLoading = true;
const res = await getAPI(SysTenantApi).apiSysTenantSysInfoTenantIdGet(0);
if (res.data!.type !== 'success') return;
state.sysInfo = res.data.result;
if (state.sysInfo.carouselFiles) state.carouselFileList = state.sysInfo.carouselFiles;
} finally {
nextTick(() => {
state.isLoading = false;
});
}
};
// 图片转file
// const onlineImageToFile = async (imageUrl: string | URL | Request, fileName: string) => {
// try {
// const response = await fetch(imageUrl);
// const blob = await response.blob();
// const file = new File([blob], fileName, { type: blob.type });
// return file;
// } catch (error) {
// return null;
// }
// };
// 上传轮播图文件
const uploadCarouselFile = async (e: any) => {
await getAPI(SysTenantApi).apiSysTenantUploadCarouselFilePostForm(e.file);
};
// 删除轮播图文件
const beforeRemoveCarouselFile = (file: any, fileList: any) => {
const result = new Promise((resolve, reject) => {
ElMessageBox.confirm(`确定删除此轮播图?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
state.isDelete = true;
let index = fileList.indexOf(file);
await getAPI(SysFileApi).apiSysFileDeletePost(fileList[index]);
fileList.splice(index, 1);
state.carouselFileList.splice(index, 1);
})
.catch(() => {
reject(false);
});
});
return result;
};
// 预览轮播图
const previewCarouselFile = (file: any) => {
state.dialogImagePreviewUrl = file.url!;
state.dialogImagePreviewVisible = true;
};
// 选择主题色
const setThemeColor = (e: any) => {
navigator.clipboard.writeText(e.hex);
state.sysInfo.themeColor = e.hex;
state.colorName = e.name;
state.dialogChineseColorVisible = false;
};
</script>
<style lang="scss" scoped>
.avatar-uploader .avatar {
width: 100px;
height: 100px;
display: block;
object-fit: contain;
}
:deep(.avatar-uploader) .el-upload {
border: 1px dashed var(--el-border-color);
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
:deep(.avatar-uploader) .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
color: #8c939d;
width: 100px;
height: 100px;
text-align: center;
}
.traditionalColors {
height: 50px;
position: relative;
}
.traditionalColors-chines {
text-align: center;
}
.traditionalColors-circleCheck {
position: absolute;
left: calc(50% - 10px);
top: calc(50% - 10px);
}
</style>