<template>
|
<Dialog style="width: 60%;" :title="dialogTitle" v-model="dialogVisible" @close="cancale" >
|
<el-form
|
ref="formRef"
|
:model="formData"
|
:rules="formRules"
|
label-width="200px"
|
v-loading="formLoading">
|
<el-row>
|
<el-col :span="12">
|
<el-form-item label="模板名称" prop="templateName">
|
<el-input v-model="formData.templateName" maxlength="50" placeholder="请输入模板名称" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="背景图片" prop="bgImage">
|
<el-upload
|
v-model:file-list="fileList"
|
class="upload-demo"
|
:action="getUploadUrl"
|
:auto-upload="false"
|
:limit="2"
|
:on-exceed="handleExceed"
|
:before-upload="beforeUpload"
|
:on-change="handleChange"
|
accept="image/*"
|
:show-file-list="false"
|
>
|
<el-button type="primary">上传图片</el-button>
|
<template #tip>
|
<div class="el-upload__tip">
|
只能上传jpg/png文件
|
</div>
|
</template>
|
</el-upload>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row v-if="ishasAdminRole==true">
|
<el-col :span="12">
|
<el-form-item label="模板类型" prop="zg">
|
<el-select v-model="formData.zg">
|
<el-option label="公用模板" :value="1">公用模板</el-option>
|
<el-option label="我的模板" :value="2">我的模板</el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-col :span="18">
|
<div ref="captureElement" style="width: 802px; height: 452px;border: 1px solid #C0C0C0;box-sizing: border-box;position: relative">
|
<img :src="lastUploadedFileUrl" style="width: 100%; height: 100%" v-if="lastUploadedFileUrl!=''" />
|
<Vue3DraggableResizable
|
v-if="isChecked1"
|
v-model:w="formData.humanW"
|
v-model:h="formData.humanH"
|
v-model:x="formData.humanX"
|
v-model:y="formData.humanY"
|
:initW="formData.humanW"
|
:initH="formData.humanH"
|
:lock-aspect-ratio="true"
|
:minW="350"
|
>
|
<img
|
src="@/assets/imgs/1.png"
|
style="width: 100%; height: 100%; object-fit: contain;"
|
/>
|
</Vue3DraggableResizable>
|
<Vue3DraggableResizable
|
v-if="isChecked"
|
:initW="formData.pptW"
|
:initH="formData.pptH"
|
v-model:w="formData.pptW"
|
v-model:h="formData.pptH"
|
v-model:x="formData.pptX"
|
v-model:y="formData.pptY"
|
:lock-aspect-ratio="false"
|
:parent="true"
|
:minW="350"
|
>
|
<img
|
src="@/assets/imgs/2.png"
|
style="width: 100%; height: 100%; object-fit: cover;"
|
/>
|
</Vue3DraggableResizable>
|
|
</div>
|
</el-col>
|
<el-col :span="6">
|
<div style="width: 100%;height: 452px;border: 1px solid #C0C0C0;box-sizing: border-box">
|
<div class="image-checkbox-wrapper" @click="toggleCheck">
|
<img src="@/assets/imgs/2.png" alt="ppt示例图片" class="checkbox-image" />
|
<input
|
type="checkbox"
|
v-model="isChecked"
|
class="checkbox-input"
|
/>
|
</div>
|
<div class="image-checkbox-wrapper" @click="toggleCheck1">
|
<img src="@/assets/imgs/1.png" alt="数字人示例图片" class="checkbox-image" />
|
<input
|
type="checkbox"
|
v-model="isChecked1"
|
class="checkbox-input"
|
/>
|
</div>
|
</div>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<el-button v-loading="IsUploadBack" @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
|
<el-button @click="cancale">{{ t('common.cancel') }}</el-button>
|
</template>
|
</Dialog>
|
</template>
|
<script setup lang="ts">
|
import { TemplateApi, TemplateVO } from '@/api/digitalcourse/template'
|
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
import {getUserProfile} from "@/api/system/user/profile";
|
import html2canvas from 'html2canvas';
|
/** 模板 表单 */
|
defineOptions({ name: 'TemplateForm' })
|
import { ElMessage } from 'element-plus';
|
import {updateFile} from "@/api/infra/file";
|
import Vue3DraggableResizable from 'vue3-draggable-resizable'
|
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css'
|
import { ca } from 'element-plus/es/locale';
|
import { rule } from 'postcss';
|
import { truncate } from 'lodash-es';
|
const getUploadUrl = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/infra/file/upload'
|
const fileList = ref([]);
|
const lastUploadedFileUrl = ref('');
|
|
const handleExceed = () => {
|
ElMessage.warning('只能上传一个文件');
|
};
|
// ppt
|
const isChecked = ref(false);
|
// 数字人
|
const isChecked1 = ref(false);
|
const toggleCheck = () => {
|
isChecked.value = !isChecked.value;
|
console.log(isChecked.value)
|
if (isChecked.value==true) {
|
formData.value.showPpt=1
|
}else if (isChecked.value==false) {
|
formData.value.showPpt=0
|
}
|
console.log(formData.value.showPpt)
|
};
|
const toggleCheck1 = () => {
|
isChecked1.value =!isChecked1.value;
|
if (isChecked1.value==true) {
|
formData.value.showDigitalHuman=1
|
}else if (isChecked1.value==false) {
|
formData.value.showDigitalHuman=0
|
}
|
}
|
// 当前是否在上传背景图
|
const IsUploadBack = ref(false)
|
const beforeUpload = (file) => {
|
console.log("beforeUpload")
|
const isImage = file.type.startsWith('image/');
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
|
if (!isImage) {
|
ElMessage.error('只能上传图片格式的文件!');
|
return false;
|
}
|
if (!isLt2M) {
|
ElMessage.error('图片大小不能超过2MB!');
|
return false;
|
}
|
|
return true;
|
};
|
async function updataImage(formData1) {
|
IsUploadBack.value = truncate
|
const response= await updateFile(formData1)
|
console.log(response.data)
|
if (response) {
|
formData.value.bgImage=response.data
|
IsUploadBack.value = false
|
ElMessage.success('上传成功');
|
}
|
}
|
|
const handleChange = (file, files) => {
|
// 当文件变化时,只保留最后一个文件
|
if (files.length > 1) {
|
fileList.value = [files[files.length - 1]];
|
}
|
console.log(file)
|
const raw=file.raw
|
console.log(raw)
|
lastUploadedFileUrl.value = URL.createObjectURL(raw);
|
console.log(lastUploadedFileUrl.value)
|
const formData1 = new FormData();
|
formData1.append('file', raw);
|
updataImage(formData1)
|
};
|
|
|
|
const { t } = useI18n() // 国际化
|
const message = useMessage() // 消息弹窗
|
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
const dialogTitle = ref('') // 弹窗的标题
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
const formData = ref({
|
id: undefined,
|
showBackground: 1,
|
templateName: undefined,
|
showDigitalHuman: 0,
|
showPpt: 0,
|
pptW: 505,
|
pptH: 290,
|
pptX: 40,
|
pptY: 50,
|
humanW: 640,
|
humanH: 360,
|
humanX: 349,
|
humanY: 92,
|
bgImage: undefined,
|
})
|
|
const formRules = reactive({
|
templateName: [{ required: true, message: t('template.name') + t('common.notEmpty'), trigger: 'blur' }],
|
showBackground: [{ required: true, message: t('template.isShowBackground') + t('common.notEmpty'), trigger: 'blur' }],
|
showDigitalHuman: [{ required: true, message: t('template.isShowDigitalPeople') + t('common.notEmpty'), trigger: 'blur' }],
|
showPpt: [{ required: true, message: t('template.isShowPPt') + t('common.notEmpty'), trigger: 'blur' }],
|
pptW: [{ required: true, message: t('template.pptWidth') + t('common.notEmpty'), trigger: 'blur' }],
|
pptH: [{ required: true, message: t('template.pptHeight') + t('common.notEmpty'), trigger: 'blur' }],
|
pptX: [{ required: true, message: t('template.topPositionPPT') + t('common.notEmpty'), trigger: 'blur' }],
|
pptY: [{ required: true, message: t('template.leftPositionPPT') + t('common.notEmpty'), trigger: 'blur' }],
|
humanW: [{ required: true, message: t('template.digitalPeopleWidth') + t('common.notEmpty'), trigger: 'blur' }],
|
templateSize: [{ required: true, message: t('template.templateSize') + t('common.notEmpty'), trigger: 'blur' }],
|
humanH: [{ required: true, message: t('template.digitalPeopleHeight') + t('common.notEmpty'), trigger: 'blur' }],
|
humanX: [{ required: true, message: t('template.topPositionDigitalPeople') + t('common.notEmpty'), trigger: 'blur' }],
|
humanY: [{ required: true, message: t('template.leftPositionDigitalPeople') + t('common.notEmpty'), trigger: 'blur' }],
|
zg: [{ required: true, message: '模板类型', trigger: 'blur' }],
|
bgImage: [{ required: true, message: '请上传背景图片', trigger: 'blur' }],
|
})
|
const formRef = ref() // 表单 Ref
|
let ishasAdminRole = ref(false)
|
let userInfo = ref()
|
/** 打开弹窗 */
|
const open = async (type: string, id?: number) => {
|
dialogVisible.value = true
|
dialogTitle.value = t('action.' + type)
|
formType.value = type
|
//获取当前登录人的信息
|
userInfo.value = await getUserProfile()
|
let hasAdminRole = userInfo.value.roles.some(role => role.name === '数字人管理员')
|
console.log(hasAdminRole)
|
resetForm()
|
if (hasAdminRole) {
|
ishasAdminRole=true
|
}else {
|
ishasAdminRole=false
|
formData.value.zg = '2'
|
}
|
fileList.value = []
|
// 修改时,设置数据
|
if (id) {
|
formLoading.value = true
|
try {
|
formData.value = await TemplateApi.getTemplate(id)
|
if( formData.value.showDigitalHuman === 1 ){
|
isChecked1.value = true
|
}
|
isChecked.value = true
|
lastUploadedFileUrl.value = formData.value.bgImage as unknown as string
|
} finally {
|
formLoading.value = false
|
}
|
}
|
}
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
/** 提交表单 */
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
const submitForm = async () => {
|
// 校验表单
|
await formRef.value.validate()
|
console.log(formData.value.showPpt)
|
if( formData.value.showPpt === 0 ){
|
message.error(t('common.NeedAddPpt'))
|
return
|
}
|
|
const imageFile = await saveAsImage();
|
if (imageFile) {
|
const formData1 = new FormData();
|
formData1.append('file', imageFile);
|
const response = await updateFile(formData1);
|
formData.value.previewImage = response.data;
|
// 提交请求
|
formLoading.value = true
|
try {
|
formData.value.humanX=formData.value.humanX.toString()
|
formData.value.humanY=formData.value.humanY.toString()
|
formData.value.pptX=formData.value.pptX.toString()
|
formData.value.pptY=formData.value.pptY.toString()
|
formData.value.pptW=formData.value.pptW.toString()
|
formData.value.pptH=formData.value.pptH.toString()
|
const data = formData.value as unknown as TemplateVO
|
|
console.log(formData.value)
|
if (formType.value === 'create') {
|
await TemplateApi.createTemplate(data)
|
message.success(t('common.createSuccess'))
|
} else {
|
await TemplateApi.updateTemplate(data)
|
message.success(t('common.updateSuccess'))
|
}
|
dialogVisible.value = false
|
// 发送操作成功的事件
|
emit('success')
|
} finally {
|
formLoading.value = false
|
}
|
}else {
|
ElMessage.error('保存截图失败');
|
formLoading.value = false
|
}
|
|
}
|
|
/** 重置表单 */
|
const resetForm = () => {
|
formData.value = {
|
id: undefined,
|
showBackground: 1,
|
showDigitalHuman: 0,
|
showPpt: 0,
|
pptW: 505,
|
pptH: 290,
|
pptX: 40,
|
pptY: 50,
|
humanW: 640,
|
humanH: 360,
|
humanX: 349,
|
humanY: 92,
|
bgImage: undefined,
|
zg:1,
|
templateSize: '16:9',
|
}
|
formRef.value?.resetFields()
|
}
|
// 取消按钮
|
const cancale = ()=>{
|
resetForm()
|
// 页面中不显示弹窗,背景图,数字人,ppt
|
lastUploadedFileUrl.value = ""
|
isChecked.value = false
|
isChecked1.value = false
|
dialogVisible.value = false
|
}
|
|
const captureElement = ref<HTMLElement | null>(null);
|
const saveAsImage = async () => {
|
if (!captureElement.value) {
|
console.error('DOM 元素未找到!');
|
return;
|
}
|
try {
|
const canvas = await html2canvas(captureElement.value, {
|
backgroundColor: null,
|
scale: 1,
|
useCORS: true,
|
});
|
|
return new Promise((resolve) => {
|
canvas.toBlob((blob) => {
|
const file = new File([blob], 'screenshot.png', {
|
type: 'image/png',
|
});
|
resolve(file);
|
}, 'image/png');
|
});
|
}
|
catch (error) {
|
console.error('生成图片失败:', error);
|
return null;
|
}
|
|
}
|
onMounted(() => {
|
console.log('DOM 已渲染:', captureElement.value);
|
});
|
|
</script>
|
<style scoped lang="scss">
|
.image-checkbox-container {
|
display: inline-block;
|
position: relative;
|
}
|
|
.image-checkbox-wrapper {
|
position: relative;
|
cursor: pointer;
|
}
|
|
.checkbox-image {
|
width: 230px;
|
height: 150px;
|
object-fit: cover;
|
border-radius: 4px;
|
border: 1px solid #ddd;
|
transition: all 0.3s;
|
margin-left: 20px;
|
margin-top: 20px;
|
}
|
|
.checkbox-input {
|
position: absolute;
|
top: 30px;
|
left: 30px;
|
width: 20px;
|
height: 20px;
|
cursor: pointer;
|
z-index: 2;
|
appearance: none; /* 隐藏默认样式 */
|
-webkit-appearance: none;
|
background-color: #fff;
|
border: 1px solid #ddd;
|
border-radius: 4px;
|
}
|
|
/* 选中状态样式 */
|
.checkbox-input:checked {
|
background-color: #409eff; /* 蓝色背景 */
|
border-color: #409eff; /* 蓝色边框 */
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z'/%3E%3C/svg%3E");
|
background-repeat: no-repeat;
|
background-position: center;
|
background-size: 14px;
|
}
|
|
.image-checkbox-wrapper:hover .checkbox-image {
|
border-color: #ddd;
|
}
|
|
.checkbox-input:checked ~ .checkbox-image {
|
border: 1px solid #ddd; /* 选中时保持灰色1px边框 */
|
}
|
</style>
|