Files
aida_front/src/component/home/batchGeneration/createCloud.vue
X1627315083@163.com d4e9462d39 fix
2026-05-05 14:34:12 +08:00

875 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="createCloud" ref="createCloud"></div>
<a-modal
class="createCloud_modal generalModel"
v-model:visible="operationsModal"
:footer="null"
:get-container="() => $refs.createCloud"
width="50%"
:height="'77rem'"
:maskClosable="false"
:centered="true"
:closable="false"
:mask="true"
wrapClassName="#app"
:keyboard="false"
>
<div class="generalModel_btn">
<div class="generalModel_closeIcon" @click.stop="cancelDsign()">
<svg
width="100%" height="100%"
viewBox="0 0 46 46"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="23" cy="23" r="23" fill="white" fill-opacity="0.3" />
<rect
x="32.5063"
y="12"
width="3"
height="29"
rx="1.5"
transform="rotate(45 32.5063 12)"
fill="#000"
/>
<rect
x="34.6274"
y="32.5059"
width="3"
height="29"
rx="1.5"
transform="rotate(135 34.6274 32.5059)"
fill="#000"
/>
</svg>
</div>
</div>
<div class="modal_title_text">
<div>{{$t('batchGeneration.title')}}</div>
</div>
<div class="allUserPoeration_center admin_page">
<div class="admin_state_item">
<span>{{$t('batchGeneration.TaskType')}} <span>*</span></span>
<a-select
v-model:value="buildType"
allowClear
style="width: 200px"
placeholder="Please select"
:options="cloudList"
@change="changeBuildType"
></a-select>
</div>
<div class="admin_state_item">
<span
>{{$t('batchGeneration.Project')}}
<span
v-show="
buildType == 'SERIES_DESIGN' || buildType == 'SINGLE_DESIGN'
"
>*</span
></span
>
<a-select
v-model:value="projectData"
show-search
allowClear
:show-arrow="false"
style="width: 200px"
:placeholder="$t('batchGeneration.PleaseSelect')"
:options="objectList"
@search="getHistoryProjectList"
@change="changeProject"
>
<template #option="{ value: val, label, icon, updateTime }">
<span :title="updateTime.replace('T', ' ')">{{ label }}</span>
</template>
</a-select>
</div>
<div class="admin_state_item">
<span>{{$t('batchGeneration.TaskName')}} <span>*</span></span>
<input
v-model="porjectName"
:placeholder="placeholder"
@focus="focus"
@blur="blur"
type="text"
style="width: 200px"
/>
</div>
<div class="admin_state_item" v-show="buildType">
<span>{{$t('batchGeneration.Quantity')}} <span>*</span></span>
<input
v-model="numberOfImages"
:placeholder="$t('batchGeneration.enterNumber')"
type="text"
style="width: 200px"
@input="changeNumberOfImages"
/>
</div>
<!-- toProductimg -->
<div v-show="buildType == 'TO_PRODUCT_IMAGE'" class="admin_state_item">
<span>{{ $t("ProductImg.Similarity") }} 0 - 100</span>
<div class="sliderAndImput" style="width: 200px">
<!-- <a-slider class="system_silder"
v-model:value="similarity"
range
:step="5"
>
</a-slider> -->
<div style="display: flex">
<input type="number" v-model="similarity[0]" />
<div style="margin: 0 1rem">-</div>
<input type="number" v-model="similarity[1]" />
</div>
</div>
</div>
<div v-show="buildType == 'RELIGHT'" class="admin_state_item">
<span>{{ $t("ProductImg.RelightDirection") }}</span>
<a-select
style="width: 200px"
v-model:value="relightDirection"
:options="relightDirectionList"
></a-select>
</div>
<div v-show="buildType == 'RELIGHT'" class="admin_state_item">
<span>{{ $t("ProductImg.Highlight") }}</span>
<div class="sliderAndImput" style="width: 200px">
<a-slider
class="system_silder"
v-model:value="brightenValue"
:tooltipVisible="false"
:max="3"
:min="1"
:step="0.1"
>
</a-slider>
<input type="number" readonly v-model="brightenValue" />
</div>
</div>
<div
v-show="buildType == 'TO_PRODUCT_IMAGE' || buildType == 'relight'"
class="admin_state_item"
>
<span>{{$t('batchGeneration.Keyword')}}</span>
<input
v-model="generateText"
:placeholder="$t('Generate.inputContent1')"
type="text"
style="width: 200px"
/>
</div>
<!-- <div class="selectImgList generalScroll" v-mousewheel v-show="exhibitionImgList.length>0">
<div v-for="item in exhibitionImgList" class="item">
<img :src="item.designOutfitUrl||item.url" alt="">
</div>
</div> -->
<div
class="productImg_content_item_imgBox generalScroll upload_item"
v-if="
buildType &&
buildType != 'SERIES_DESIGN' &&
buildType != 'SINGLE_DESIGN'
"
v-mousewheel
>
<div
class="content_item_imgBox_itemImg"
v-for="item in uploadElement"
:key="item"
>
<div class="imgBox" @click="() => (item.isChecked = !item.isChecked)">
<img
:class="[item?.isChecked ? 'active' : '']"
:src="item?.url"
class="upload_img"
/>
<a-checkbox v-model:checked="item.isChecked"></a-checkbox>
</div>
</div>
<div
class="content_item_imgBox_itemImg"
v-for="(file, index) in fileList"
:key="file"
>
<div
class="upload_file_item_content"
v-show="file?.status === 'uploading'"
style="display: flex; align-items: center"
>
<a-spin size="large" />
</div>
<div
class="imgBox"
v-show="file?.status === 'done'"
@click="() => (file.isChecked = !file.isChecked)"
>
<img
:class="[file?.isChecked ? 'active' : '']"
:src="file?.imgUrl"
class="upload_img"
/>
<a-checkbox v-model:checked="file.isChecked"></a-checkbox>
</div>
</div>
<div class="upload_file_item upload_component">
<!-- :action="uploadUrl + '/api/history/toProductImageElementUpload'" -->
<a-upload
:action="
getUploadUrl() + '/api/history/toProductImageElementUpload'
"
list-type="picture-card"
:capture="null"
:headers="{ Authorization: getCookie('token') }"
:before-upload="beforeUpload"
:data="{
projectId:projectData?.value?projectData?.value:''
}"
v-model:file-list="fileList"
:multiple="true"
:maxCount="8"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file) => fileUploadChange(file)"
>
<div class="upload_tip_block">
<i class="fi fi-br-upload"></i>
<!-- <img class="upload_img_icon" src="@/assets/images/homePage/add_file.png"> -->
</div>
</a-upload>
</div>
</div>
<!-- <div class="admin_state_item" style="width: 100%;">
<span style="margin: 0;">Generation time19min</span>
</div> -->
<div v-show="buildType" class="admin_state_item" style="width: 100%">
<span style="margin: 0"
>{{$t('batchGeneration.CostCredit')}}{{ credits * numberOfImages }}</span
>
</div>
</div>
<div class="allUserPoeration_btn admin_page">
<!-- <div class="admin_search_item" @click="cancelDsign">
Close
</div> -->
<div class="admin_search_item" @click="setOk">OK</div>
</div>
</a-modal>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
</div>
</template>
<script>
import {
defineComponent,
computed,
reactive,
watch,
onMounted,
h,
nextTick,
toRefs,
} from "vue";
import { LoadingOutlined } from "@ant-design/icons-vue";
import { Https } from "@/tool/https";
import { Modal, message } from "ant-design-vue";
import { getCookie, setCookie } from "@/tool/cookie";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import { getUploadUrl, isMoible } from "@/tool/util";
import dayjs, { Dayjs } from "dayjs";
import { useStore } from "vuex";
import { useI18n } from "vue-i18n";
import { getMinioUrl } from "@/tool/util";
import md5 from "md5";
export default defineComponent({
components: {},
props: {
cloudList: {
type: Array,
default: [],
},
},
emits: ["getContentList"],
setup(props, { emit }) {
const store = useStore();
let operations = reactive({
operationsModal: false,
loadingShow: false,
});
let operationsData = reactive({
buildType: "",
numberOfImages: "",
credits: 0,
exhibitionImgList: [], //选择的图片
projectData: {
id:'',
name:'',
}, //批量id
objectList: [],
porjectName: "", //任务名字
//toProduct
generateText: "", //输入的内容
similarity: [20, 40],
brightenValue: 1, //亮度
relightDirection: "Right Light", //打光方向
sequence:'',
relightDirectionList: [
{
value: "Right Light",
label: useI18n().t("ProductImg.RightLight"),
},
{
value: "Left Light",
label: useI18n().t("ProductImg.LeftLight"),
},
{
value: "Top Light",
label: useI18n().t("ProductImg.TopLight"),
},
{
value: "Bottom Light",
label: useI18n().t("ProductImg.BottomLight"),
},
],
fileList: [],
uploadElement: [],
placeholder: "",
});
const getUploadElement = () => {
operations.loadingShow = true;
let value = {
id: operationsData.projectData?.value,
moduleList: ["uploadElement"],
};
let str = setPlaceholder()
if(!str){
str = props.cloudList.filter((item)=>item.value == operationsData.buildType)[0].label
str = str.replace(/\s+/g, '_')
}
operationsData.placeholder = "Batch_" + str + '_' + operationsData.sequence;
Https.axiosPost(Https.httpUrls.getModuleContent, value)
.then(async (rv) => {
operationsData.uploadElement = rv.uploadElement;
operations.loadingShow = false;
})
.catch((err) => {
operations.loadingShow = false;
});
};
let init = (projectData, buildType,sequence) => {
operationsData.sequence = sequence
operations.operationsModal = true;
clearData();
if (projectData?.id) {
operationsData.projectData = {
label: projectData.label,
value: projectData.id,
};
getUploadElement();
}
if (buildType.value) operationsData.buildType = buildType.value;
};
const clearData = () => {
operationsData.porjectName = "";
operationsData.generateText = "";
operationsData.similarity = [20, 40];
operationsData.brightenValue = 1;
operationsData.fileList = [];
operationsData.uploadElement = [];
};
const changeProject = (rv) => {
let porjectData = operationsData.objectList.find(
(item) => item.id === rv
);
operationsData.projectData = {
value: porjectData?.id,
label: porjectData?.name,
}
getUploadElement();
};
const changeBuildType = () => {
// operationsData.exhibitionImgList = []
operationsData.projectData = {
label:'',
value:'',
};
props.cloudList.forEach((item) => {
if (item.value == operationsData.buildType) {
operationsData.credits = item.consumption;
}
});
getUploadElement();
getHistoryProjectList();
};
const getGenerateCloudImgList = (type) => {
let list = [];
if (type == "SINGLE_DESIGN" || type == "SERIES_DESIGN") return list;
let selectList = [];
let fileList = operationsData.fileList.filter((item) => item.isChecked);
let uploadElement = operationsData.uploadElement.filter(
(item) => item.isChecked
);
if (fileList) selectList.push(...fileList);
if (uploadElement) selectList.push(...uploadElement);
selectList.forEach((item) => {
let obj = {};
if (type == "POSE_TRANSFER") {
obj = {
poseId: 1,
elementId: item.id,
productImage: getMinioUrl(item.imgUrl),
elementType: item.type?item.type:"ProductElement",
};
} else {
obj = {
elementId: item.id,
elementType: item.type || "ProductElement",
};
}
list.push(obj);
});
return list;
};
let getPorductImg = () => {
let modularData = store.state.UploadFilesModule.modularData;
let list = [];
if (
operationsData.buildType == "toProductImage" ||
operationsData.buildType == "relight"
) {
let productOrRelight = [];
if (operationsData.buildType == "toProductImage")
productOrRelight = modularData.design.likeData;
if (operationsData.buildType == "relight")
productOrRelight = modularData.toProduct;
productOrRelight.forEach((item) => {
if (!item.id) return;
let obj = {
createTime: "",
elementId: 0,
elementType: "",
id: 0,
isLike: 0,
taskId: "",
toProductImageRecordId: 0,
url: "",
};
obj.elementId = item.designOutfitId;
obj.elementType = "DesignOutfit";
if (operationsData.buildType == "relight") {
obj.elementId = item.id;
obj.elementType = "ToProductImage";
}
list.push(obj);
});
}
return list;
};
const getImageStrength = (num) => {
let imageStrength = num == 100 ? 95 : num;
return imageStrength;
};
const getPoseTransformData = () => {
let list = [];
let toProduct = store.state.UploadFilesModule.modularData.toProduct;
toProduct.forEach((item) => {
let obj = {
poseId: 1,
productImage: getMinioUrl(item.url),
};
list.push(obj);
});
return list;
};
let setAddData = () => {
let buildTypeCorresponding = {
SINGLE_DESIGN: "design",
SERIES_DESIGN: "design",
TO_PRODUCT_IMAGE: "toProductImage",
RELIGHT: "relight",
POSE_TRANSFER: "poseTransfer",
};
return {
buildType: buildTypeCorresponding[operationsData.buildType],
nums: operationsData.numberOfImages,
sequence:operationsData.sequence,
projectId: operationsData.projectData?.value?operationsData.projectData?.value:'',
name: operationsData.porjectName || operationsData.placeholder,
//productimg
toProductImage: {
prompt: operationsData.generateText, //输入的内容
toProductImageVOList: getGenerateCloudImgList(
operationsData.buildType
), //选择的图片
// toProductImageVOList:getPorductImg(),//选择的图片
projectId: operationsData.projectData?.value?operationsData.projectData?.value:'',
direction: operationsData.relightDirection, //打光方向
brightenValue: operationsData.brightenValue,
imageStrength: (100 - getImageStrength()) / 100,
imageStrengthMin:
(100 - getImageStrength(operationsData.similarity[1])) / 100,
imageStrengthMax:
(100 - getImageStrength(operationsData.similarity[0])) / 100,
},
//poseTransform
// poseTransform:getPoseTransformData(),
poseTransform:
operationsData.buildType == "POSE_TRANSFER"
? getGenerateCloudImgList("POSE_TRANSFER")
: [],
private: operationsData.projectData?.value,
ToProductImageDTO: operationsData.projectData?.value,
};
};
let cancelDsign = () => {
operationsData.buildType = "";
operationsData.numberOfImages = "";
operations.operationsModal = false;
};
let setOk = () => {
let data;
data = setAddData();
if (operationsData.buildType == "TO_PRODUCT_IMAGE") {
if (data.toProductImage.toProductImageVOList.length == 0)
return message.warning("Please select or upload the picture first.");
// if(data.toProductImage.toProductImageVOList.length == 0)return message.warning("You need to go to the Design module and generate a design result first before you can use the 'To Product Image' cloud generation feature.")
} else if (operationsData.buildType == "RELIGHT") {
if (data.toProductImage.toProductImageVOList.length == 0)
return message.warning("Please select or upload the picture first.");
// if(data.toProductImage.toProductImageVOList.length == 0)return message.warning("You need to go to the 'To Product Image' module and generate a result first before you can use the 'Relight' cloud generation feature.")
} else if (operationsData.buildType == "POSE_TRANSFER") {
if (data.poseTransform.length == 0)
return message.warning("Please select or upload the picture first.");
// if(data.poseTransform.length == 0)return message.warning("You must first generate results in the 'To Product Image' module before you can use the 'Transfer Pose' cloud generation feature.")
}
if (operationsData.buildType == "DESIGN" && !operationsData.projectData?.value)
return message.warning("Please select a project");
if (
!data.buildType ||
!data.nums ||
!data.name ||
(operationsData.buildType == "DESIGN" && !operationsData.projectData?.value)
)
return message.warning("Please check the input box marked with *");
operations.loadingShow = true;
Https.axiosPost(Https.httpUrls.designCloud, data)
.then((rv) => {
if (rv) {
operations.loadingShow = false;
cancelDsign();
let porjectData = operationsData.objectList.find(
(item) => item.id === operationsData.projectData?.value
);
let project = {
value: porjectData?.id,
label: porjectData?.name,
};
emit("getContentList", project);
}
})
.catch((error) => {
operations.loadingShow = false;
});
};
const changeNumberOfImages = () => {
if (
operationsData.buildType == "relight" ||
operationsData.buildType == "poseTransfer"
) {
if (
operationsData.exhibitionImgList.length <
Number(operationsData.numberOfImages)
) {
operationsData.numberOfImages =
operationsData.exhibitionImgList.length;
}
}
};
let getHistoryTime = null;
const getHistoryProjectList = (event) => {
clearTimeout(getHistoryTime);
if (!event && !operationsData.buildType) {
operationsData.objectList = [];
return;
}
getHistoryTime = setTimeout(() => {
let value = {
projectName: event,
page: 1,
size: 9999,
asc: 0,
process: operationsData.buildType,
};
Https.axiosPost(Https.httpUrls.historyProject, value).then((rv) => {
rv.content.forEach((item) => {
item.value = item.id;
item.label = item.name;
});
operationsData.objectList = rv.content;
});
}, 1000);
};
let beforeUpload = async (file) => {
const isJpgOrPng =
file.type === "image/jpeg" ||
file.type === "image/png" ||
file.type === "image/jpg" ||
file.type === "image/bmp";
if (!isJpgOrPng) {
message.info(useI18n().t("MoodboardUpload.jsContent3"));
}
const isLt2M = file.size / 1024 / 1024 < 5;
if (!isLt2M) {
message.info(useI18n().t("MoodboardUpload.jsContent4"));
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
};
let fileUploadChange = (data) => {
let file = data.file;
let bor = true;
if (file.status === "done") {
let res = JSON.parse(file.xhr.response);
if (res.errCode == 0) {
file.imgUrl = res.data.url;
file.id = res.data.id;
file.isChecked = true;
file.type = "ProductElement";
operationsData.fileList.filter((v) => v.status === "done");
} else {
bor = false;
}
// this.showFileList = productImgData.fileList
} else if (file.status === "error") {
bor = false;
}
};
const setPlaceholder = () => {
if(operationsData.projectData?.label)return operationsData.projectData.label
if (!operationsData.projectData?.value) return "";
let index = operationsData.objectList.findIndex(
(item) => item.id === operationsData.projectData?.value
);
return operationsData.objectList[index].name;
};
const focus = () => {
if (operationsData.porjectName) return;
operationsData.porjectName = operationsData.placeholder;
};
const blur = () => {
if (operationsData.porjectName != operationsData.placeholder) return;
operationsData.porjectName = "";
};
return {
...toRefs(operations),
...toRefs(operationsData),
cancelDsign,
init,
changeProject,
focus,
blur,
setOk,
changeBuildType,
changeNumberOfImages,
getHistoryProjectList,
beforeUpload,
fileUploadChange,
getUploadUrl,
getCookie,
};
},
data() {
return {
indicator: h(LoadingOutlined, {
style: {
fontSize: "2.4rem",
},
spin: true,
}),
};
},
mounted() {},
methods: {},
directives: {
mousewheel: {
mounted(el) {
el.addEventListener("mouseenter", (e) => {
if (el.scrollWidth > el.clientWidth) {
el.parentElement.style.overflowY = "hidden";
}
});
// 鼠标移出事件
el.addEventListener("mouseleave", () => {
el.parentElement.style.overflowY = "auto";
});
el.addEventListener(
"wheel",
(e) => {
let num = 0;
if (e.deltaY > 0) {
num = 25;
} else {
num = -25;
}
el.scrollBy(num, 0);
},
{ passive: true }
);
},
},
},
});
</script>
<style lang="less" scoped>
:deep(.ant-modal-mask) {
background: rgba(0, 0, 0, 0.2);
}
:deep(.createCloud_modal) {
.ant-modal-body {
display: flex;
flex-direction: column;
}
}
</style>
<style lang="less" scoped>
.createCloud_modal {
.closeIcon {
z-index: 2;
}
.productImg_content_item_imgBox {
display: flex;
overflow-x: auto;
width: auto;
margin-bottom: 2rem;
align-items: center;
flex-wrap: nowrap;
width: 100%;
.content_item_imgBox_itemImg {
display: flex;
margin-right: 1rem;
position: relative;
height: 20rem;
max-height: 100%;
position: relative;
flex-shrink: 0;
img {
height: 100%;
width: 100%;
cursor: pointer;
object-fit: contain;
opacity: 0.5;
&.active {
opacity: 1;
}
}
.ant-checkbox-wrapper {
position: absolute;
right: 0;
top: 0;
}
&.content_item_imgBox_itemImg:hover {
.content_item_imgBox_itemImg_delete {
display: block;
cursor: pointer;
}
}
.content_item_imgBox_itemImg_delete {
display: none;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
position: absolute;
i {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: #fff;
}
}
}
:deep(.upload_file_item) {
flex-shrink: 0;
}
.content_item_imgBox_itemImg:last-child {
margin-right: 0;
}
}
.allUserPoeration_btn {
display: flex;
flex-direction: row;
height: auto;
justify-content: flex-end;
padding: 1rem 0;
.admin_search_item {
margin-bottom: 0;
}
}
.allUserPoeration_center {
flex: 1;
overflow-y: auto;
flex-direction: row;
flex-wrap: wrap;
align-content: flex-start;
padding: 0 2rem;
> .selectImgList {
width: 100%;
display: flex;
overflow-x: auto;
align-items: center;
flex-wrap: nowrap;
height: 20rem;
margin: 2rem 0;
> .item {
height: 100%;
margin-right: 1rem;
&:last-child {
margin-right: 0;
}
> img {
height: 100%;
}
}
//
}
> .admin_state_item {
width: auto;
// width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
> span {
text-align: left;
margin: 0;
margin-bottom: 1.5rem;
font-weight: 600;
}
:deep(> .ant-select > .ant-select-selector) {
border-radius: 1.6rem;
}
> input {
border-radius: 1.6rem;
}
> .sliderAndImput {
display: flex;
align-items: center;
flex: 1;
:deep(> .ant-slider) {
// border-radius: 1.6rem;
flex: 1;
}
input {
border-radius: 1.6rem;
width: 5rem;
padding: 4px 11px 4px;
margin-left: 1rem;
height: 100%;
text-align: center;
}
}
}
}
}
</style>