orgManager/src/views/operations/gameManage/platform/components/AddDialog.vue

581 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<!-- 新增 -->
<el-dialog :title="addEditStatus=='add' ? t('新增') : t('修改')" align-center :close-on-click-modal="false" v-model="showDialog" :width="formAll.promotionalStyle==1 ?'1900px':'700px'" append-to-body>
<!-- <el-scrollbar max-height="900px" > -->
<el-form ref="formRef" :model="formAll" :rules="rules" label-width="130px" class="add-form">
<el-row :gutter="20">
<el-col :span="formAll.promotionalStyle==1?12:24">
<el-form-item :label="t('版式风格')" prop="iconType">
<el-radio-group v-model="formAll.iconType" @change="generateImage" style="margin-bottom: 0px">
<el-radio-button :value="1">{{ t('方形图标') }}</el-radio-button>
<el-radio-button :value="2">{{ t('竖版图标') }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('平台名称')" prop="platformName">
<el-input v-model="formAll.platformName" disabled />
</el-form-item>
<el-form-item :label="t('最低准入')" prop="minAmount">
<number-input v-model="formAll.minAmount" ></number-input>
</el-form-item>
<el-form-item :label="t('平台宣传语')" prop="promotionalText">
<el-input v-model="formAll.promotionalText" :placeholder="t('请输入平台宣传语')" />
</el-form-item>
<el-form-item :label="t('平台跳转方式')" prop="iosJump">
<div style="width: 100%;display: flex;">
<div style="width: 80px;text-align: right;margin-right: 10px;">IOS:</div>
<el-radio-group v-model="formAll.iosJump" style="margin-bottom: 0px">
<el-radio :value="1">{{ t('内嵌') }}</el-radio>
<el-radio :value="2">{{ t('外链') }}</el-radio>
</el-radio-group>
</div>
<div style="width: 100%;display: flex;">
<div style="width: 80px;text-align: right;margin-right: 10px;">Android:</div>
<el-radio-group v-model="formAll.androidJump" style="margin-bottom: 0px">
<el-radio :value="1">{{ t('内嵌') }}</el-radio>
<el-radio :value="2">{{ t('外链') }}</el-radio>
</el-radio-group>
</div>
<div style="width: 100%;display: flex;">
<div style="width: 80px;text-align: right;margin-right: 10px;">H5:</div>
<el-radio-group v-model="formAll.h5Jump" style="margin-bottom: 0px">
<el-radio :value="1">{{ t('内嵌') }}</el-radio>
<el-radio :value="2">{{ t('外链') }}</el-radio>
</el-radio-group>
</div>
</el-form-item>
<el-form-item :label="t('宣传图样式')" prop="promotionalStyle">
<el-radio-group v-model="formAll.promotionalStyle">
<el-radio :value="1">{{ t('默认') }}</el-radio>
<el-radio :value="2">{{ t('自定义') }}</el-radio>
</el-radio-group>
</el-form-item>
<div v-if="formAll.promotionalStyle == 1">
<el-form-item :label="t('宣传图图标')" prop="promotionalIcon">
<banner-icon @clickSelect="handleSelection('three',$event)" :disabled="shouwLoding" :imageUrl="formAll.promotionalIcon" :query="materialIcon" url="/game/material/group/select"></banner-icon>
</el-form-item>
</div>
<div v-if="formAll.promotionalStyle == 2">
<el-form-item :label="t('宣传图')" prop="customPromotionalImage">
<div v-if="formAll.iconType == 2" class="upload-box-vioce11">
<image-upload v-model="formAll.customPromotionalImage" :typeUpImg="3" :limit="1" :isShowTip="false"
:isdrag="true"></image-upload>
</div>
<div v-if="formAll.iconType == 1" class="upload-box-vioce22">
<image-upload v-model="formAll.customPromotionalImage" :typeUpImg="3" :limit="1" :isShowTip="false"
:isdrag="true"></image-upload>
</div>
<div >{{ t('只能上传png文件且不超过1MB图片尺寸为300px * 400px') }}</div>
</el-form-item>
<el-form-item :label="t('热门图')" prop="customPopularStyle">
<div v-if="formAll.iconType == 2" class="upload-box-vioce11">
<image-upload v-model="formAll.customPopularStyle" :typeUpImg="3" :limit="1" :isShowTip="false"
:isdrag="true"></image-upload>
</div>
<div v-if="formAll.iconType == 1" class="upload-box-vioce22">
<image-upload v-model="formAll.customPopularStyle" :typeUpImg="3" :limit="1" :isShowTip="false"
:isdrag="true"></image-upload>
</div>
<div >{{ t('只能上传png文件且不超过1MB图片尺寸为300px * 400px') }}</div>
</el-form-item>
</div>
</el-col>
<el-col :span="12" v-if="formAll.promotionalStyle == 1">
<div v-if="formAll.promotionalStyle == 1">
<el-form-item :label="t('图片背景')" prop="promotionalBackground">
<BannerColour @clickSelect="handleSelection('two',$event)" :disabled="shouwLoding" :backgroundColor="formAll.promotionalBackground" :query="materialTypess" url="/game/material/group/select"></BannerColour>
</el-form-item>
<el-form-item v-if="formAll.promotionalStyle == 1" :label="t('品牌LOGO')" prop="platformLogo">
<div class="upload-box-vioce" style="border:1px solid #409eff;border-radius: 5px;width: 213px;height:90px !important;text-align: center;display: flex;justify-content: center;align-items: center;">
<img style="width: 100px;" :src="fileHost+formAll.platformLogo"/>
</div>
</el-form-item>
<el-form-item v-if="formAll.promotionalStyle == 2" :label="t('品牌LOGO')" prop="customPlatformLogo">
<div class="upload-box-vioce">
<image-upload v-model="formAll.customPlatformLogo" :typeUpImg="3" :limit="1" :isShowTip="false"
:isdrag="true"></image-upload>
</div>
</el-form-item>
<el-form-item :label="t('宣传图预览')">
<div style=" position: absolute; top: -9999px; left: -9999px; visibility: hidden; ">
<div class="" v-if="formAll.iconType == 1" ref="captureArea" :style="`display: flex;align-items: center;justify-content: space-between;width: 400px;height: 150px;background: url(${formAll.popularStyleGb}) no-repeat;background-size: 100% 100%;`">
<div class="" style="width: 40%;">
<p style="margin: 0;text-align: center;"><img style="width: 100px;height: auto;" :src="formAll.platformLogoGb"/></p>
<p style="margin: 0;text-align: center;font-size: 16px;font-weight: 600;"> </p>
</div>
<div style="width: 60%;">
<div style="width: 260px;height: 150px;">
<img style="width: 100%;height: 100%;" :src="formAll.promotionalImageGb"/>
</div>
</div>
</div>
<div v-if="formAll.iconType == 2" class="" ref="captureArea" :style="`display: flex;align-items: center;justify-content: space-between;width: 210px;height: 280px;background: url(${formAll.popularStyleGb}) no-repeat;background-size: 100% 100%;`">
<div :style="`width: 210px; height: 280px;display: flex;align-items: center;position: relative;background: url(${formAll.promotionalImageGb});
background-size: cover;
background-position: center;
background-repeat: no-repeat;`">
<div class="" :style="`position: absolute;bottom: 0;left: 0;width: 100%;`">
<div style="margin: 0;text-align: center;position: relative;top: 0px;"><img style="width: 58px;height: auto;" crossorigin="anonymous" :src="formAll.platformLogoGb"/></div>
<div style="margin: 0;text-align: center;font-size: 16px;font-weight: 600;color: #fff;height: 35px;"> </div>
</div>
</div>
</div>
</div>
<img :src="resolvedImageUrl" style="border-radius: 5px;" alt="Generated Image" />
</el-form-item>
<el-form-item :label="t('热门图预览')">
<div style="position: absolute; top: -8999px; left: -8999px; visibility: hidden;">
<div class="" v-if="formAll.iconType == 1" ref="captureAreaPop" :style="`display: flex;align-items: center;justify-content: space-between;width: 400px;height: 150px;background: url(${formAll.popularStyleGb}) no-repeat;background-size: 100% 100%;`">
<div class="" style="width: 40%;">
<p style="margin: 0;text-align: center;"><img style="width: 100px;height: auto;" :src="formAll.platformLogoGb"/></p>
<p style="margin: 0;text-align: center;font-size: 16px;font-weight: 600;"> </p>
</div>
<div style="width: 60%;">
<div style="width: 260px;height: 150px;">
<img style="width: 100%;height: 100%;" :src="formAll.promotionalImageGb"/>
</div>
</div>
</div>
<div v-if="formAll.iconType == 2" class="" ref="captureAreaPop" :style="`display: flex;align-items: center;justify-content: space-between;width: 210px;height: 280px;background: url(${formAll.popularStyleGb}) no-repeat;background-size: 100% 100%;`">
<div :style="`width: 210px; height: 245px;display: flex;align-items: center;margin-top:35px; position: relative;background: url(${formAll.promotionalImageGb});
background-size: cover;
background-position: center;
background-repeat: no-repeat;`">
<div class="" :style="`position: absolute;top: -40px;left: 0;width: 100%;`">
<div style="margin: 0;text-align: center;"><img style="width: 70px;height: auto;" crossorigin="anonymous" :src="formAll.platformLogoGb"/></div>
</div>
<div class="" :style="`position: absolute;height:80px;bottom: 0;left: 0;width: 100%;`">
<div style="margin: 0;text-align: center;font-size: 16px;font-weight: 600;color: #fff;margin-top: 45px;height: 35px;"> </div>
</div>
</div>
</div>
</div>
<img :src="resolvedPopularStyle" style="border-radius: 5px;" alt="Generated Image" />
</el-form-item>
</div>
</el-col>
</el-row>
</el-form>
<!-- </el-scrollbar> -->
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm" :loading="loadingButton">{{ t(' ') }}</el-button>
<el-button @click="closeDialog">{{ t(' ') }}</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { formatTime,finalTimestamp } from '@/utils/ruoyi'; // 时间格式化
import ImageUpload from "@/components/ImageUpload";
import NumberInput from "@/components/NumberInput";
import { updatePlatform } from "@/api/game/platform";
import BannerColour from "@/components/BannerColour"; // Banner图颜色
import BannerIcon from "@/components/BannerIcon"; // Banner图标
import { getToken } from '@/utils/auth'
import { nextTick, onMounted, ref } from "vue"; // 获取当前实例
import { getLocalStorage } from "@/utils/auth";
const fileHost = getLocalStorage('fileUrl') || ''; // 文件host
import html2canvas from 'html2canvas';
const uploadUrl = getLocalStorage('uploadUrl');
const uploadImgUrl = ref(uploadUrl + "/file/upload/localSysFile/3"); // 上传的图片服务器地址
const loadingButton = ref(false);
const oldForm = shallowRef({ });
const langList = getLocalStorage('langList')?.filter(v => v.langType == 1 && v.langStatus).map(item => {
return {
label: item.name,
value: item.id
};
}); // 语种选项
const { proxy } = getCurrentInstance() // 获取当前实例
const emits = defineEmits(['submit', 'update:show']) // 自定义事件
const props = defineProps({ // 父组件向子组件传值
data: {
type: Object, // 父组件传值
default: {}
},
show: {
type: Boolean, // 显示
default: false
},
addEditStatus:{ // 添加/修改
type: String,
default: 'add'
},
modifyDate: { //修改数据
type: Object,
default: {}
}
})
const materialIcon = ref({ //图标请求参数
materialTypes:'2'
});
const materialTypess = ref({ //颜色请求参数
materialTypes:'1'
});
const showDialog = computed({ //弹窗显示控制
get() {
return props.show
},
set(value) {
emits('update:show', value)
}
})
const activeNameLang = ref(0);//语言切换选中
const langOptionAll = ref([]); // 语言tabs切换的数据
const formAll = reactive({
iconType:1, // 平台类型 1:方形图标 2:竖版图标
})
const loadImageAsBase64 = async(url)=> {
const res = await fetch(uploadUrl+url, { mode: 'cors' })
const blob = await res.blob()
return await new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
}
// 修改时数据更新相关内容
nextTick(async () => {
if (props.addEditStatus != 'edit') return;
Object.assign(formAll, props.modifyDate)
formAll.id = props.modifyDate.id;
formAll.iconType = props.modifyDate.iconType|| 1;
formAll.platformName = props.modifyDate.platformName;
formAll.minAmount = props.modifyDate.minAmount;
if (props.modifyDate.promotionalStyle == 1){
formAll.promotionalImage = props.modifyDate.promotionalImage;
formAll.platformLogoGb = await loadImageAsBase64(props.modifyDate.platformLogo);
formAll.popularStyleGb = await loadImageAsBase64(props.modifyDate.promotionalBackground);
formAll.promotionalImageGb = await loadImageAsBase64(props.modifyDate.promotionalIcon);
formAll.popularStyle = props.modifyDate.popularStyle;
}
formAll.promotionalStyle = props.modifyDate.promotionalStyle;
setTimeout(() => {
let objForm = { ...formAll }
oldForm.value = JSON.stringify(objForm);
}, 500);
});
const captureArea = ref(null);
const captureAreaPop = ref(null);
// 加入图片加载检测
const waitForImagesLoaded = async (container) => {
const imgs = container.querySelectorAll('img');
await Promise.all([...imgs].map(img => {
return new Promise(resolve => {
if (img.complete) return resolve();
img.onload = img.onerror = () => resolve();
});
}));
};
const shouwLoding = ref(false);
const generateImage = async () => {
shouwLoding.value = true;
const el = captureArea.value;
const el2 = captureAreaPop.value;
if (!el || !el2) return;
el.style.visibility = 'visible';
el2.style.visibility = 'visible';
await nextTick();
await waitForImagesLoaded(el);
await waitForImagesLoaded(el2);
await new Promise(resolve => setTimeout(resolve, 100));
const canvas = await html2canvas(el, {
useCORS: true,
backgroundColor: '#fff'
});
formAll.promotionalImage = canvas.toDataURL('image/png');
await new Promise(resolve => setTimeout(resolve, 100)); // 控制节奏
const canvas2 = await html2canvas(el2, {
useCORS: true,
backgroundColor: '#fff'
});
formAll.popularStyle = canvas2.toDataURL('image/png');
shouwLoding.value = false;
el.style.visibility = 'hidden';
el2.style.visibility = 'hidden';
};
//表单验证规则
const rules = reactive({
promotionalStyle: [
{ required: true, message: proxy.t('请选择icon图样式'), trigger: 'change' },
],
minAmount: [
{ required: true, message: proxy.t('请输入最小投注金额'), trigger: 'change' },
]
})
// 关闭弹窗
const closeDialog = () => {
showDialog.value = false
}
const resolvedImageUrl = computed(() => {
const url = formAll.promotionalImage
if (!url) return ''
if (url.startsWith('data:image/')) {
return url // base64 图片
}
if (url.startsWith('http://') || url.startsWith('https://')) {
return url // 完整 URL不加 fileHost
}
return fileHost + url // 相对路径,加上 fileHost
})
const resolvedPopularStyle = computed(() => {
const url = formAll.popularStyle
if (!url) return ''
if (url.startsWith('data:image/')) {
return url // base64 图片
}
if (url.startsWith('http://') || url.startsWith('https://')) {
return url // 完整 URL不加 fileHost
}
return fileHost + url // 相对路径,加上 fileHost
})
const getColorFromUrl = (url) => {
// 匹配最后一个斜杠后的颜色字符串,不带扩展名
const match = url.match(/\/([^\/]+)\.png$/)
if (match && match[1]) {
return `#${match[1]}` // 加上 #
}
return null
}
const colorGb = ref('');
const isShow = ref(true); // 是否显示
// 处理选中排版、颜色、图标和图片上传后的数据更新
const handleSelection = async(type, en) => {
switch (type) {
case 'two':
isShow.value = false;
const color = getColorFromUrl(en.url);
colorGb.value = color;
if (formAll.promotionalBackground == en.url){
return
}
formAll.popularStyleGb = await loadImageAsBase64(en.url);
formAll.promotionalBackground = en.url;
nextTick(() => {
isShow.value = true;
generateImage();
});
break;
case 'three':
isShow.value = false;
if (formAll.promotionalIcon == en.url){
return
}
formAll.promotionalImageGb = await loadImageAsBase64(en.url);
formAll.promotionalIcon = en.url;
nextTick(() => {
isShow.value = true;
generateImage();
});
break;
default:
break;
}
};
function base64ToFile(base64, filename = 'image.png') {
const arr = base64.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
}
const uploadBase64Image = async(base64) =>{
if (!/^data:image\/(png|jpeg|jpg|gif|bmp);base64,/.test(base64)) {
// 不是 Base64说明已经是 URL直接返回
return { url: base64 };
}
const file = base64ToFile(base64, 'upload.png')
const formData = new FormData()
formData.append('file', file)
const res = await fetch(uploadImgUrl.value, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + getToken(),
},
body: formData
})
return await res.json()
}
// 提交
const formRef = ref(null)
// 提交修改和新增数据表单
const submitForm = async() => {
// 验证表单
formRef.value.validate(async(valid) => {
if (valid) {
loadingButton.value = true;
let promotionalImages = await uploadBase64Image(formAll.promotionalImage)
let popularStyles = await uploadBase64Image(formAll.popularStyle)
// 初始化表单数据
let formData = {
...formAll,
promotionalImage:promotionalImages.url,
popularStyle:popularStyles.url,
};
delete formData.platformLogoGb;
delete formData.popularStyleGb;
delete formData.promotionalImageGb;
if (JSON.stringify(formAll) != oldForm.value) {
updatePlatform(formData).then(res => {
loadingButton.value = false;
proxy.$modal.msgSuccess(proxy.t('修改成功!'));
emits('submit');
closeDialog();
}).catch(error => {
loadingButton.value = false;
});
}else{
loadingButton.value = false;
closeDialog();
}
}
});
};
</script>
<style scope lang="scss">
.w100 {
width: 100%;
}
.upload-box-vioce{
height: 90px !important;
overflow: hidden;
.upload-tips {
color: #999;
font-size: 12px;
line-height: 1.5;
padding-left: 10px;
}
.component-upload-image .el-upload--picture-card {
width: 180px !important;
height: 90px !important;
}
.el-upload-list--picture-card .el-upload-list__item {
width: 180px!important;
height: 90px!important;
}
:deep(.el-upload-list) {
width:180px!important;
height: 90px!important;
.el-upload,
.el-upload-list--picture-card .el-upload-list__item {
width: 180px!important;
height: 90px!important;
}
.el-upload-list__item {
margin: 0;
border: none;
width: 180px!important;
height: 90px!important;
}
}
}
.upload-box-vioce11{
height: 400px !important;
overflow: hidden;
.upload-tips {
color: #999;
font-size: 12px;
line-height: 1.5;
padding-left: 10px;
}
.component-upload-image .el-upload--picture-card {
width: 300px !important;
height: 400px !important;
}
.el-upload-list--picture-card .el-upload-list__item {
width: 300px!important;
height: 400px!important;
}
:deep(.el-upload-list) {
width:300px!important;
height: 400px!important;
.el-upload,
.el-upload-list--picture-card .el-upload-list__item {
width: 300px!important;
height: 400px!important;
}
.el-upload-list__item {
margin: 0;
border: none;
width: 300px!important;
height: 400px!important;
}
}
}
.upload-box-vioce22{
height: 200px !important;
overflow: hidden;
.upload-tips {
color: #999;
font-size: 12px;
line-height: 1.5;
padding-left: 10px;
}
.component-upload-image .el-upload--picture-card {
width: 400px !important;
height: 200px !important;
}
.el-upload-list--picture-card .el-upload-list__item {
width: 400px!important;
height: 200px!important;
}
:deep(.el-upload-list) {
width:400px!important;
height: 200px!important;
.el-upload,
.el-upload-list--picture-card .el-upload-list__item {
width: 400px!important;
height: 200px!important;
}
.el-upload-list__item {
margin: 0;
border: none;
width: 400px!important;
height: 200px!important;
}
}
}
.disable-click {
pointer-events: none;
}
</style>