Files
aida_front/src/component/HomePage/index/model/mannequin/edit.vue
X1627315083 b6e5f05f06 fix
2025-04-01 15:25:15 +08:00

1553 lines
48 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 ref="placementModal" v-if="placementShow">
<a-modal class="generalModel fullScreen"
v-model:visible="placementShow"
:footer="null"
width="100%"
:get-container="() => $refs.placementModal"
height="100%"
:maskClosable="false"
:keyboard="false"
:centered="true"
:closable="false"
>
<div class="generalModel_btn">
<div class="generalModel_closeIcon" @click.stop="closeModal()">
<!-- <i class="fi fi-rr-cross-small"></i> -->
<svg width="46" height="46" 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="models_placement_body" >
<div class="palcement_modal_header">
<div class="models_placement_title">{{ $t('ModelPlacement.Registration') }}</div>
<div class="placement_operate_list">
<div class="operate_item" v-show="locationList.length == 6" @click="setProportion(true)">
<!-- <div class="icon iconfont icon-fanhui1 operate_icon"></div> -->
<i class="fi fi-rr-comment-image operate_icon"></i>
<div class="operate_item_des">Proportion</div>
</div>
<div class="operate_item" @click="setProportion(false)">
<i class="fi fi-br-dot-circle operate_icon"></i>
<div class="operate_item_des">{{ $t('ModelPlacement.Point') }}</div>
</div>
<div class="operate_item" v-show="locationList.length == 6 || proportion.base64" @click="printPreview">
<div class="icon iconfont icon-shengchengyulan operate_icon"></div>
<div class="operate_item_des">{{ $t('ModelPlacement.Preview') }}</div>
</div>
<div class="operate_item" v-show="locationList.length == 6 || proportion.base64" @click="submitPlacement">
<div class="icon iconfont icon-baocun1 operate_icon"></div>
<div class="operate_item_des">{{ $t('ModelPlacement.Submit') }}</div>
</div>
<div class="operate_item" v-show="perviewUrl" @click="backPreview">
<div class="icon iconfont icon-fanhui1 operate_icon"></div>
<div class="operate_item_des">{{ $t('ModelPlacement.Back') }}</div>
</div>
<!-- <div class="operate_item" v-show="!perviewUrl" @click="restoreLocationList">
<div class="icon iconfont icon-huifu operate_icon"></div>
<div class="operate_item_des">{{ $t('ModelPlacement.Restore') }}</div>
</div> -->
</div>
</div>
<div class="plcaement_point_content" v-if="userDetail.userId == 88 || userDetail.userId == 83">
<div style="display: flex; align-items: center;">
<div style="display: flex; align-items: center;">
<input type="checkbox" model="false" @click="()=>{modelType = 'System'}">
{{ $t('ModelPlacement.System') }}
</div>
<div style="display: flex; align-items: center;">
<input type="checkbox" model="false" @click="()=>{modelType = 'Library'}">
{{ $t('ModelPlacement.Library') }}
</div>
</div>
</div>
<div class="models_placement_content">
<div class="plcaement_point_content" v-show="!brushProportion">
<div class="select_block">
<!-- <a-select
ref="select"
v-model:value="sex.value"
:options="sexList"
>
<template #suffixIcon
><span
class="icon iconfont icon-xiala"
style="color: #343579"
></span
></template>
</a-select> -->
<div>{{ sex.label }}</div>
</div>
<div class="placement_point_item" v-for="(point,index) in pointList" :key="index" @mousemove="mouseMove" @touchmove="touchmove($event)">
<div class="ponit_title">{{point.title}}</div>
<div class="point_list">
<div class="point_item" v-for="item in point.pointList" :key="item.color" :style="{borderColor:item.color,visibility:item.show?'inherit':'hidden'}" @mousedown="AddDian(item)" @touchstart="AddDian(item)"><div class="point_block" :style="{background:item.color}"></div></div>
</div>
</div>
<div class="placement_point_item placement_point_item_btn">
<span class="started_btn" @click="setPoint">{{ $t('ModelPlacement.addPoint') }}</span>
<span class="started_btn" v-show="!perviewUrl" @click="restoreLocationList">{{ $t('ModelPlacement.Restore') }}</span>
</div>
</div>
<!-- <div class="placement_content_operate_list">
<div class="placement_content_operate_item" @click="changeRemoveStatus">
<div class="placement_remove_point_block"></div>
<div class="placement_content_operate_des">{{ $t('ModelPlacement.RemovePoint') }}</div>
</div>
</div> -->
<div class="placement_tip_content">{{ $t('ModelPlacement.mannequinHint') }}</div>
<div class="img_preview_block" >
<div class="perview_mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
<div class="img_content_block" style="height: 100%;" ref="imgbox" v-show="!brushProportion">
<div :style="{width: imgBox.width+'px', height:imgBox.height +'px',top:imgBox.y+'px',left:imgBox.x+'px',position:'absolute'}">
<div :class="['ponit_click',isRemoveStatus?'remove_point_click':'']" v-show="!perviewUrl" v-for="(item,index) in locationList" :key="item" :style="{left:item.left+'px', top:item.top+'px',borderColor:item.color}" @mousedown="getMouseDown($event,item,index)" @touchstart="getMouseDown(getMousePosition($event),item,index)" @mousemove="mouseMove($event)" @touchmove="touchmove($event)">
<div class="placement_add_point_content" :style="{background:item.color}" v-show="!isRemoveStatus"></div>
<div class="icon iconfont icon-guanbi" v-show="isRemoveStatus"></div>
</div>
</div>
<vue-cropper
v-show="!perviewUrl"
class="cropper"
ref="cropper"
:img="option.img"
:outputSize="option.outputSize"
:outputType="option.outputType"
:info="option.info"
:canScale="option.canScale"
:autoCrop="option.autoCrop"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:full="option.full"
:fixedBox="option.fixedBox"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:centerBox="option.centerBox"
:height="option.height"
:infoTrue="option.infoTrue"
:limitMinSize="option.limitMinSize"
:enlarge="option.enlarge"
@real-time="realTime"
:autoCropArea="1"
:autoCropHeight="option.autoCropHeight"
:autoCropWidth="option.autoCropWidth"
:mode="option.mode">
</vue-cropper>
<img class="placement_img" v-show="perviewUrl" :src="perviewUrl || printObject?.url">
</div>
<div class="placement_point_scale" v-show="!brushProportion">
<div class="cur_picture_opterate_item" @click="changeScale(-1)"><span class="operate_icon icon_font">-</span></div>
<div class="cur_picture_opterate_item" @click="changeScale(1)"><span class="operate_icon icon_font">+</span></div>
</div>
<div class="img_content_block" v-show="brushProportion" ref="placement">
<!-- <img class="placement_img" :src="option.img"> -->
<div class="placementBG_img" ref="placementBG" :style="{'border-image-source':`url(${option.img})`}"></div>
<div class="placement_btn" ref="placementContent">
<div class="top"
@mousedown.stop="placementMove(getMousePosition($event,false),'top')"
@touchstart.passive="placementMove(getMousePosition($event,true),'top')"
>
<i class="fi fi-bs-arrow-up-right-and-arrow-down-left-from-center"></i>
</div>
<div class="bottom"
@mousedown.stop="placementMove(getMousePosition($event,false),'bottom')"
@touchstart.passive="placementMove(getMousePosition($event,true),'bottom')"
>
<i class="fi fi-bs-arrow-up-right-and-arrow-down-left-from-center"></i>
</div>
</div>
</div>
<div class="input_blok" v-show="brushProportion">
<div class="label">
<div class="text">Stretch</div>
<a-slider class="slider" v-model:value="slider" :tooltipVisible="false" @change="sliderChange"/>
<div class="gallery_btn" @click="stretchOK">完成</div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,createVNode,nextTick,computed,toRefs, reactive} from 'vue'
import { Https } from "@/tool/https";
import {dataURLtoFile,base64toFile,getMinioUrl} from "@/tool/util"
import 'vue-cropper/dist/index.css'
import { VueCropper } from "vue-cropper";
import { useStore } from "vuex";
import { Modal,message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { getMousePosition } from "@/tool/mdEvent";
import { useI18n } from 'vue-i18n';
import domTurnImg from '@/tool/domTurnImg'
export default defineComponent({
components:{
VueCropper,
},
emits:['submit'],
setup() {
const store = useStore()
let userDetail:any= computed(()=>{
return store.state.UserHabit.userDetail
})
let data = reactive({
placementShow:false,
collectionIndex:0,
startDian:false,
moveOriginal:{posX: 0, posY: 0},
isRemoveStatus:false,
placement_sacle:30,
perviewUrl:'',//预览的图片地址
isShowMark:false,
modelType:'Library',
slider:50,
editOrUpload:'edit',//edit 编辑 upload 上传
})
const dataDom = reactive({
placement:null as any,
placementBG:null as any,
placementContent:null as any,
})
let oldLocationList:any = ref([])
let locationList:any = ref([])
let printObject:any = ref({})
let imgBox:any = ref({})
let intObj:any = ref(null)
let currentSign:any = ref({})
let oldPointList:any = ref([]) //备份点
let pointList:any = ref([])
let isSubmit:any = ref(false) //判断历史是否有提交过
let manager:any = ref(false)
let sex:any = ref({})
let sexList:any = ref([
])
let cropperTime:any = ref()
let brushProportion:any = ref(false)
let proportion:any = ref({
base64:'',
width:200,
height:100,
scale:0,
style:{
height:100,
top:200,
}
})
let {t} = useI18n()
const getImgDetail = (url:any)=>{
data.isShowMark=true
let img = new Image()
img.onload = function(){
let width = dataDom.placement.offsetWidth
let scale = img.width/img.height
// proportion.value.width = width
// proportion.value.height = width/scale
proportion.value.scale = img.height/imgBox.value.height
proportion.value.width = imgBox.value.width
proportion.value.height = imgBox.value.height
dataDom.placementContent.style.height = proportion.value.style.height + 'px'
dataDom.placementContent.style.top = proportion.value.style.top + 'px'
let top = proportion.value.style.top;
let bottom = proportion.value.height - (proportion.value.style.top + proportion.value.style.height)
stretch(top,bottom,data.slider - 50,true)
data.isShowMark=false
}
img.src = url
}
const stretch = (top=0,bottom=0,add=0,isfill=true) =>{
const width = proportion.value.width;
const height = proportion.value.height;
let lashen = dataDom.placementBG
lashen.style.setProperty("--o-width",width);
lashen.style.setProperty("--o-height",height);
lashen.style.setProperty("--top-width",top);
lashen.style.setProperty("--bottom-width",bottom);
lashen.style.setProperty("--add-height",add + "px");
lashen.style.borderImageSlice = `${top / height * 100}% 0 ${bottom / height * 100}% 0` + (isfill ? " fill" : "");
}
//设置拖拽滚动
const sliderChange = ()=>{
let top = proportion.value.style.top;
let imgHeight = dataDom.placementBG.offsetHeight
let bottom = Number(imgHeight) - (proportion.value.style.top + proportion.value.style.height)
dataDom.placementContent.style.height = `${(data.slider - 50) + proportion.value.style.height}px`;
stretch(top,bottom,data.slider - 50,true)
}
const placementMove = (e:any,str:string)=>{
let startY = e.clientY
let top = proportion.value.style.top;
let height = proportion.value.style.height
let moveFun = (e:any) => {
let Y = e.clientY - startY + top;
let imgHeight = proportion.value.height
let y = Y > 0 ? Y>Number(imgHeight)? imgHeight : Y : 0
let H = e.clientY - startY + (Number(height))
if(str == 'top'){
if(y == 0)return
H = Number(height) - (e.clientY - startY)
}else{
y = top
}
if(H < 0)return
dataDom.placementContent.style.top = `${y}px`;
dataDom.placementContent.style.height = `${H}px`;
proportion.value.style.top = y;
proportion.value.style.height = H;
// item.el.style.top = `${Y}px`;
};
let mouseUpFun = ()=>{
document.removeEventListener('mousemove',mouseMove)
document.removeEventListener('touchmove',touchmove)
document.removeEventListener('mouseup',mouseUpFun)
document.removeEventListener('touchend',mouseUpFun)
// moveItem();
}
let mouseMove = function(event:any){
let e = getMousePosition(event,false)
moveFun(e)
}
let touchmove = function(event:any){
let e = getMousePosition(event,true)
moveFun(e)
}
document.addEventListener('mousemove',mouseMove)
document.addEventListener('touchmove',touchmove)
document.addEventListener('mouseup',mouseUpFun)
document.addEventListener('touchend',mouseUpFun)
}
return {
store,
userDetail,
...toRefs(data),
...toRefs(dataDom),
oldLocationList,
locationList,
printObject,
imgBox,
intObj,
currentSign,
oldPointList,
pointList,
isSubmit,
manager,
sex,
sexList,
cropperTime,
t,
getMousePosition,
brushProportion,
proportion,
placementMove,
getImgDetail,
sliderChange,
}
},
data(){
return{
option:{
img: '', //裁剪图片的地址
outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
outputType: 'png', //裁剪生成图片的格式jpeg || png || webp
info: false, //图片大小信息
canScale: true, //图片是否允许滚轮缩放
autoCrop: true, //是否默认生成截图框
autoCropWidth: '0', //默认生成截图框宽度
autoCropHeight: '0', //默认生成截图框高度
fixed: true, //是否开启截图框宽高固定比例
// fixedBox: false, //固定截图框大小,不允许改变//上传系统模特使用
fixedBox: true, //固定截图框大小,不允许改变
fixedNumber: [1, 2.125], //截图框的宽高比例
// full: true, //false按原比例裁切图片不失真
full: false, //false按原比例裁切图片不失真//上传模特使用
// canMove: false, //上传图片是否可以移动//上传系统模特使用
canMove: true, //上传图片是否可以移动
canMoveBox: false, //截图框能否拖动
original: false, //上传图片按照原始比例渲染
centerBox: false, //截图框是否被限制在图片里面
height: true, //是否按照设备的dpr 输出等比例图片
// infoTrue: false, //true为展示真实输出图片宽高false展示看到的截图框宽高
infoTrue: true, //true为展示真实输出图片宽高false展示看到的截图框宽高
maxImgSize:'2000', //限制图片最大宽度和高度
enlarge: 1, //图片根据截图框输出比例倍数
// enlarge: 7, //图片根据截图框输出比例倍数
mode: 'auto 90%', //图片默认渲染方式
limitMinSize:'100%',
imgLoad:()=>{
}
},
}
},
mounted(){
// this.getSex()
},
methods:{
formatter(value:number){
return `${value}%`;
},
getMouseDetail(data:any,type:any){
return new Promise((resolve,reject)=>{
let value = {
id:data.id,
type,
}
Https.axiosPost(Https.httpUrls.getMannequinDetail,value).then((rv)=>{
rv.id == data.id
let libraryModelPoint = {
...rv.libraryModelPoint
}
libraryModelPoint.designType = rv.designType
libraryModelPoint.name = rv.name
libraryModelPoint.url = rv.minIOPath
resolve(libraryModelPoint)
})
})
},
async showPlacementModal(value:any,sex:any,type:any,editOrUpload:any){
// this.sex = arr[0].value
this.editOrUpload = editOrUpload
this.placementShow = true
this.isShowMark = true
let detail:any={}
if(value.id){
// data = Object.assign({}, data, await this.getMouseDetail(data,type));
detail = await this.getMouseDetail(value,type)
this.option.canMove = false
}else{
detail.designType = type
detail.url = value.url
detail.file = value.file
this.option.canMove = true
}
this.sex = sex
this.printObject = {
...detail,
}
this.option.img = this.printObject.url
if(!this.brushProportion){
this.openDot()
}else{
this.openProportion()
}
},
openDot(){
setTimeout(()=>{
nextTick().then(()=>{
let image:any = new Image()
image.src = this.option.img
let imgbox:any = this.$refs.imgbox
let imgBoxSize = imgbox.getElementsByClassName('cropper-crop-box')[0]
let imgBoxSizeBG = imgbox.getElementsByClassName('cropper-view-box')[0]
let divTop:any = document.createElement('div');
let divBottom:any = document.createElement('div');
let divCenter:any = document.createElement('div');
if(imgbox.getElementsByClassName('cropper-view-box-Bg').length >= 1){
}else{
divTop.classList.add('cropper-view-box-Bg')
divBottom.classList.add('cropper-view-box-Bg')
divCenter.classList.add('cropper-view-box-Bg')
divTop.classList.add('cropper-view-box-Top')
divBottom.classList.add('cropper-view-box-Bottom')
divCenter.classList.add('cropper-view-box-Center')
imgBoxSizeBG.appendChild(divTop)
imgBoxSizeBG.appendChild(divBottom)
imgBoxSizeBG.appendChild(divCenter)
// imgBoxSizeBG.appendChild(div)
}
// imgBoxSize.style.backgroundImage = 'url('+require('@assets/images/library/lemaleBG.png')')'
imgBoxSize.addEventListener('mousemove',this.mouseMove)
imgBoxSize.addEventListener('touchmove',this.touchmove)
this.setImageSize()
this.isShowMark = false
})
},800)
},
openProportion(){
},
setCropperWH(){
let cropper:any = this.$refs.cropper
if(cropper.h != cropper.cropH && this.locationList.length < 6){
this.getDefaultPointList(this.imgBox,' ')
return
}else if(cropper.h == cropper.cropH){
cropper.cropH = cropper.scale*cropper.trueHeight
cropper.cropW = cropper.cropH/2.125
cropper.cropOffsertX = cropper.getImgAxis().x1+(cropper.scale*cropper.trueWidth/2-cropper.cropW/2)
cropper.cropOffsertY = cropper.getImgAxis().y1
}
},
realTime(data:any) {
let cropper:any = this.$refs.cropper
// if(cropper.h == cropper.cropH){
this.cropperTime = setTimeout(()=>{
this.setImageSize()
clearTimeout(this.cropperTime)
},100)
// }
},
setImageSize(){
this.setCropperWH()
let imgbox:any = this.$refs.imgbox
let imgBoxSize = imgbox.getElementsByClassName('cropper-crop-box')[0]
let position = imgBoxSize.getBoundingClientRect()
let position1 = imgbox.getBoundingClientRect()
let cropper:any = this.$refs.cropper
this.imgBox = {
width:cropper.cropW,
height:cropper.cropH,
left : position1.left,
top:position1.top,
scrollTop:imgBoxSize.scrollTop || 0,
x:cropper.getCropAxis().x1,
y:cropper.getCropAxis().y1,
}
},
getSex(){
Https.axiosGet(Https.httpUrls.workspaceenumValues,{params:{enumName:'Sex'}}).then((rv: any) => {
if (rv) {
let arr:any = []
rv.forEach((item:any) => {
arr.push({
value:item.name,
label:item.value,
})
});
this.sexList = arr
}
})
},
//截屏框移动
setMove(){
},
//初始化可以使用的点位
getDefaultPointList(imgBox:any,str:any){
this.isSubmit = false
this.locationList=[]
this.pointList = [
{
title:this.t('ModelPlacement.SHOULDER'),
pointList:[{type:'shoulderLeft',color:'#6E70FF',show:true,field:'shoulder'},{type:'shoulderRight',color:'#6E70FF',show:true,field:'shoulder'}]
},
{
title:this.t('ModelPlacement.WAISTBAND'),
pointList:[{type:'waistbandLeft',color:'#6FCEFF',show:true,field:'waistband'},{type:'waistbandRight',color:'#6FCEFF',show:true,field:'waistband'}]
},
{
title:this.t('ModelPlacement.HAND'),
pointList:[{type:'handLeft',color:'#d88e8e',show:true,field:'hand'},{type:'handRight',color:'#d88e8e',show:true,field:'hand'}]
},
]
for(let ponit of this.pointList){
for(let pointItem of ponit.pointList){
let arr
if(!this.printObject[pointItem.type])return
if(this.printObject[pointItem.type] instanceof Object && this.printObject[pointItem.type] !== null){
arr = this.printObject[pointItem.type]
}else{
arr = JSON.parse(this.printObject[pointItem.type])
}
if(arr?.length){
pointItem.show = false
let data = {
left:arr[0] * imgBox.width - 12,
top:arr[1] * imgBox.height - 12,
color:pointItem.color,
type:pointItem.type,
field:pointItem.field,
}
this.locationList.push(data)
}
}
}
if(str != 'setPoint'){//编辑
this.isSubmit = true
// this.option.canScale = false
// this.option.canMove = false
this.oldLocationList = JSON.parse(JSON.stringify(this.locationList))
this.oldPointList = JSON.parse(JSON.stringify(this.pointList))
}else{
this.option.canScale = true
// this.option.fixedBox = false
this.option.canMove = true
// this.option.canMoveBox = true
}
},
setPoint(){
let file = this.printObject.file
let url = this.printObject.url
let designType = this.printObject.designType
this.printObject = {
"shoulderLeft": [
0.3338,
0.1858
],
"shoulderRight": [
0.6644,
0.1858
],
"waistbandLeft": [
0.3758,
0.364
],
"waistbandRight": [
0.6103,
0.364
],
"handLeft": [
0.3277,
0.4687
],
"handRight": [
0.6764,
0.4715
],
file:file,
url:url,
designType:designType,
}
this.getDefaultPointList(this.imgBox,'setPoint')
},
AddDian(point:any){
if(!point.show){
return
}
this.startDian = true
this.isRemoveStatus = false
this.intObj = point
},
changeRemoveStatus(){
this.isRemoveStatus = true
},
mouseMove(event:any){
let e = getMousePosition(event,false)
this.startMove(e)
},
touchmove(event:any){
let e = getMousePosition(event,true)
this.startMove(e)
},
startMove(event:any){
if(this.isRemoveStatus){
return
}
let imgbox:any = this.$refs.imgbox
let imgBoxSize = imgbox.getElementsByClassName('cropper-crop-box')[0]
let scrollTop = imgBoxSize.scrollTop;
if(this.intObj){
this.currentSign.left = event.clientX - this.imgBox.left
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top
this.currentSign.color = this.intObj.color
this.currentSign.type= this.intObj.type
this.currentSign.field = this.intObj.field
this.locationList.push(this.currentSign)
this.intObj.show = false
this.intObj = null
}else{
//鼠标移动
if(this.startDian){
this.currentSign.left = event.clientX - this.imgBox.left - this.imgBox.x - this.moveOriginal.posX -12
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top - this.imgBox.y -this.moveOriginal.posY -12
document.addEventListener('mouseup', this.getMouseOver);
document.addEventListener('touchend', this.getMouseOver);
this.$forceUpdate()
this.setBoundarySign()
}
}
},
// 在边界上的签名域处理
setBoundarySign() {
let imgbox:any = this.$refs.imgbox
let imgBoxSize = imgbox.getElementsByClassName('cropper-crop-box')[0]
let top = (this.$refs.cropper as any).getCropAxis().y1
let left = (this.$refs.cropper as any).getCropAxis().x1
let height = imgBoxSize.offsetHeight;
// let height = imgBoxSize.offsetHeight + imgBoxSize.scrollTop;
// 2 为签名域的边框
let maxPosHeight = height - 24
let maxPosWidth = imgBoxSize.clientWidth - 24 //+ this.signBox.paddLeft;
if (this.currentSign.top+top <= 0) {
this.currentSign.top = 0
} else if (this.currentSign.top >= maxPosHeight+top ) {
this.currentSign.top = maxPosHeight+top;
}
if (this.currentSign.left+left <= 0) {
this.currentSign.left = 0
} else if (this.currentSign.left >= maxPosWidth+left) {
this.currentSign.left = maxPosWidth+left;
}
},
getMouseDown(event:any,item:any,index:number){
if(this.isRemoveStatus){
//删除
for(let itemPoint of this.pointList){
for(let point of itemPoint.pointList){
if(item.type == point.type){
point.show = true
break
}
}
}
this.locationList.splice(index,1)
}else{
this.currentSign = item
// 计算出鼠标在签名域上的偏移
// this.moveOriginal.posX = event.offsetX
// this.moveOriginal.posY = event.offsetY // 1为边框
this.moveOriginal.posX = 0
this.moveOriginal.posY = 0 // 1为边框
this.startDian = true
}
},
getMouseOver(){//鼠标抬起
this.startDian = false
this.currentSign = {}
document.removeEventListener('mouseup', this.getMouseOver);
document.removeEventListener('touchend', this.getMouseOver);
document.removeEventListener('mousemove',this.mouseMove)
document.removeEventListener('touchmove',this.touchmove)
},
closeModal(){
let _this = this
// if(!this.isSubmit){
// Modal.confirm({
// title: this.t('ModelPlacement.jsContent1'),
// icon: createVNode(ExclamationCircleOutlined),
// okText: 'Yes',
// cancelText: 'No',
// mask:false,
// centered:true,
// onOk() {
// // _this.getDefaultPointList(_this.imgBox)
// _this.oldLocationList = []
// _this.locationList = []
// _this.intObj = null
// _this.currentSign = {}
// _this.isRemoveStatus = false
// _this.placementShow = false
// _this.perviewUrl = ''
// _this.proportion = {}
// _this.proportion = {
// base64:'',
// width:200,
// height:100,
// scale:0,
// style:{
// height:100,
// top:200,
// }
// }
// _this.slider=50
// }
// });
// }else{
// // _this.getDefaultPointList(_this.imgBox)
// }
this.oldLocationList = []
this.locationList = []
this.intObj = null
this.currentSign = {}
this.isRemoveStatus = false
this.placementShow = false
this.perviewUrl = ''
this.proportion = {}
this.proportion = {
base64:'',
width:200,
height:100,
scale:0,
style:{
height:100,
top:200,
}
}
this.slider=50
this.brushProportion = false
this.$emit('submit')
},
restoreLocationList(){
this.locationList = []
this.pointList = JSON.parse(JSON.stringify(this.oldPointList))
this.locationList = JSON.parse(JSON.stringify(this.oldLocationList))
// this.locationList = JSON.parse(JSON.stringify(this.locationList))
},
submitPlacement(){
// let cropper:any = this.$refs.cropper,
// that = this
// cropper.getCropData((data:any) => {
// // 转换为File对象
// let file = base64toFile(data,this.cropperFileData.name);
// this.$emit('handleCropperSuccess',{file:file, fileData:this.cropperFileData})
// })
let cropper:any = this.$refs.cropper,
that = this
if((this.modelType == 'System' && this.userDetail.userId == 88) || (this.modelType == 'System' &&this.userDetail.userId == 83)){
if(this.printObject.templateId){
this.printObject.id = this.printObject.relationId
this.confrimSubmit()
}else{
this.customRequest().then((rv:any)=>{
this.isShowMark = false
this.printObject.id = rv.id
this.confrimSubmit()
}).catch((res:any)=>{
this.isShowMark = false
})
}
}else{
cropper.getCropData(async (value:any) => {
// 转换为File对象
if(this.printObject.templateId){
this.printObject.id = this.printObject.relationId
this.confrimSubmit()
}else{
let file:any = base64toFile(value,this.printObject.file.name || '-');
// file.uid = this.printObject.file.uid
this.printObject.file = file
this.customRequest().then((rv:any)=>{
this.isShowMark = false
this.printObject.id = rv.id
this.confrimSubmit()
}).catch((res:any)=>{
this.isShowMark = false
})
}
})
}
},
async setProportionData(url:any){
let top = this.proportion.style.top
let height = this.proportion.style.height
let data = {
"bottom": (top+height)*this.proportion.scale,
// "handLeft": [],
// "handRight": [],
"id": this.printObject.id,
"modelPath": getMinioUrl(url),
// "shoulderLeft": [],
// "shoulderRight": [],
"stretch": (this.slider-50) * this.proportion.scale,
"top": top*this.proportion.scale,
"type": this.printObject.designType,
// "waistbandLeft": [],
// "waistbandRight": []
...await this.getPrintLocation()
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.modifyProportion, data).then(
(rv: any) => {
// this.getImgDetail(url)
this.printObject.rv
this.setProportion(false)
this.isShowMark = false
}
).catch(res=>{
this.isShowMark = false
});
},
stretchOK(){
if(this.printObject.templateId){
this.printObject.id = this.printObject.relationId
this.setProportionData(this.printObject.url)
}else{
let cropper:any = this.$refs.cropper
cropper.getCropData(async (value:any) => {
let file:any = base64toFile(value,this.printObject.file.name || '-');
// file.uid = this.printObject.file.uid
this.printObject.file = file
this.customRequest().then((rv:any)=>{
this.isShowMark = false
this.printObject.id = rv.id
this.setProportionData(rv.url)
}).catch((res:any)=>{
this.isShowMark = false
})
})
}
},
changeScale(num:any) {
num = num || 1;
let cropper:any = this.$refs.cropper
cropper.changeScale(num);
},
async confrimSubmit(){
let modelType = 'Library'
if(this.userDetail.userId == 88 || this.userDetail.userId == 83){
modelType = this.modelType
}
let param = {
libraryId:this.printObject.id,
templateId:this.printObject.templateId || null,
modelType:modelType,
modelSex:this.sex,
checkMd5:1,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
...await this.getPrintLocation()
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.saveOrEditTemplatePoint, param).then(
(rv: any) => {
this.isShowMark = false
this.isSubmit = true
this.closeModal()
}
).catch(res=>{
this.isShowMark = false
});
},
customRequest(){
let modelType = 'Library'
if(this.userDetail.userId == 88 || this.userDetail.userId == 83){
modelType = this.modelType
}
let new_data = {
file:this.printObject.file,
level1Type:'Models',
level2Type:'',
checkMd5:1,
sex:this.sex,
modelType:modelType,
ageGroup:this.store.state.Workspace.probjects.ageGroup,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.isShowMark = true
return new Promise((resolve,reject)=>{
Https.axiosPost(Https.httpUrls.libraryUpload, new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
if(!rv.checkMd5){
resolve(this.affirmCstomRequest(new_data))
}else{
resolve(rv)
}
}
).catch((res)=>{
reject(res)
});
})
},
affirmCstomRequest(data:any){
let _this = this
return new Promise((resolve,reject)=>{
Modal.confirm({
title: this.t('ModelPlacement.jsContent2'),
icon: createVNode(ExclamationCircleOutlined),
okText: 'Yes',
cancelText: 'No',
centered:true,
mask:false,
onOk() {
data.checkMd5 = 0
Https.axiosPost(Https.httpUrls.libraryUpload, data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
_this.isShowMark = false
resolve(rv)
}
).catch((res)=>{
reject(res)
});
},
onCancel(){
_this.isShowMark = false
}
});
})
},
async getPrintLocation(){
let {width , height} = this.imgBox
// if(this.modelType == 'System'){
// await new Promise((resolve, reject) => {
// let img = new Image()
// img.src = this.option.img
// img.onload = () => {
// width = img.width
// height = img.height
// resolve(true)
// }
// })
// }
let locationData:any = {}
let returnData:any = {}
let newLocationList = JSON.parse(JSON.stringify(this.locationList))
//进行字段归类
for(let item of newLocationList){
locationData[item.field] = locationData[item.field] || []
locationData[item.field].push(item)
}
for(let key in locationData){
locationData[key].sort(this.sortBy("left")) //通过left字段进行排序
locationData[key].forEach((v:any,index:any) => {
v.type = !index ?v.field + 'Left' :v.field +'Right' //第一个是left第二个是right
v.left = ((v.left + 12) / width).toFixed(4)
v.top = ((v.top + 12) / height).toFixed(4)
returnData[v.type] = [v.left, v.top]
});
}
return returnData
},
sortBy(field:any) {
return function(a:any,b:any) {
return a[field] - b[field];
}
},
async printPreview(){
let file = this.printObject.templateId ? null :this.printObject.file,
models = {
libraryId:this.printObject.relationId || null,
templateId:this.printObject.templateId || null,
sex:this.sex,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
...await this.getPrintLocation()
}
let cropper:any = this.$refs.cropper
await cropper.getCropData((value:any)=>{
file = base64toFile(value,this.printObject.name);
file.uid = this.printObject.file?.uid?this.printObject.file.uid:''
let formData = new FormData();
formData.append('file', file);
formData.append("models", new Blob([JSON.stringify(models)], {type: "application/json"}));
if(this.isShowMark){
return
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.libraryModelsDot, formData,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
this.perviewUrl = rv
this.isShowMark = false
}
).catch(res=>{
this.isShowMark = false
});
})
},
async setProportion(boolean:any){
this.brushProportion = boolean
if(boolean){
let url
if(this.printObject.url){
url = this.printObject.url
}else{
let cropper:any = this.$refs.cropper
await cropper.getCropData(async (value:any) => {
url = value
})
}
this.getImgDetail(url)
}else{
this.openDot()
}
},
backPreview(){
this.perviewUrl = ''
}
}
})
</script>
<style lang="less" scoped>
:deep(.ant-modal-body){
padding: 4rem 5rem;
margin-bottom: 0;
.generalModel_btn {
.generalModel_closeIcon{
transform: translate(-100%, 100%);
svg{
color: #000;
}
}
}
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.models_placement_body{
width: 100%;
height: 100%;
.palcement_modal_header{
position: relative;
height: 6.6rem;
width: 100%;
.models_placement_title{
position: absolute;
height: 100%;
line-height: 6.6rem;
left: 3.7rem;
top: 0;
font-size: 1.8rem;
color: #030303;
}
.placement_operate_list{
display: flex;
align-items: center;
margin:0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 100%;
.operate_item{
margin-right: 4rem;
text-align: center;
cursor: pointer;
.operate_icon{
font-size: 2.1rem;
color: #64686D;
}
.operate_item_des{
height: 1.2rem;
font-size: 1.3rem;
color: #64686D;
}
&:last-child{
margin-right: 0;
}
}
}
}
.models_placement_content{
position: relative;
height: calc(100% - 6.6rem);
width: 100%;
padding: 1.1rem 0;
overflow-y: auto;
.plcaement_point_content{
width: 22rem;
position: absolute;
left: 0;
top: 18rem;
left: 30rem;
.select_block{
// background: #FFFFFF;
margin-bottom: 3rem;
color: #1A1A1A !important;
.ant-select{
width: 100%;
.ant-select-selector{
padding: 0;
width: 100%;
margin: 0;
background: rgba(0, 0, 0, 0);
font-size: 1.3rem;
color: #64686D;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
height: 3rem;
.ant-select-selection-item, .select_block .ant-select-single .ant-select-selector .ant-select-selection-placeholder{
font-weight: 300 !important;
line-height: 1.5715 !important;
width: 100%;
display: block;
position: relative;
padding: 0;
}
}
}
.icon-xiala{
color: #1A1A1A !important;
}
}
.placement_point_item{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
.ponit_title{
font-size: 1.3rem;
color: #64686D;
user-select:none; /* CSS3属性 */
}
.point_list{
display: flex;
align-items: center;
width: 6.2rem;
justify-content: space-between;
.point_item{
width: 2.4rem;
height: 2.4rem;
border-radius: 50%;
border:solid 0.2rem transparent;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
.point_block{
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
}
}
}
&.placement_point_item_btn{
display: flex;
justify-content: flex-start;
// justify-content: center;
.started_btn{
margin-right: 1rem;
}
}
}
}
.placement_content_operate_list{
width: 10.6rem;
background: #EBECF4;
position: absolute;
right: 0;
top:18.4rem;
.placement_content_operate_item{
padding: 1.5rem 0;
text-align: center;
cursor: pointer;
.placement_content_operate_des{
width: 100%;
font-size: 1.3rem;
color: #64686D;
-moz-user-select:none;
user-select:none
}
.print_scale_value{
height: 1.1rem;
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.3rem;
color: #64686D;
}
.ant-tooltip-placement-top{
top: -37px !important;
}
.ant-slider-track{
background: #343579;
}
.ant-slider-handle{
border-color: #343579;
}
.placement_remove_point_block{
width: 2.4rem;
height: 2.4rem;
border: 2px solid #000000;
border-radius: 50%;
margin: 0 auto 0.4rem;
}
}
}
.placement_tip_content{
position: absolute;
right: 2rem;
bottom: 2rem;
width: 30rem;
font-size: 1.3rem;
color: #64686D;
}
.placement_point_scale{
justify-content: center;
border: 1px solid #9a9a9a;
border-radius: 1rem;
width: 10rem;
// margin: 0 auto;
display: flex;
position: absolute;
bottom: -2rem;
left: 50%;
transform: translate(-50%,100%);
div:nth-child(1){
border-right: 1px solid #9a9a9a;
}
div{
font-size: 2rem;
cursor: pointer;
width: 3rem;
display: flex;
align-items: center;
justify-content: center;
}
}
.img_preview_block{
background: #ffffff;
position: relative;
user-select:none;
-moz-user-select:none;
position: relative;
// height: 57.6rem;
// width: 40.8rem;
height: 68rem;
width: 47rem;
margin: 0 auto;
.img_content_block{
// width: 40.8rem;
width: 100%;
// height: 100%;
height: auto;
// max-height: 63.2rem;
overflow-y: auto;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
position: relative;
&::-webkit-scrollbar { width: 0 !important }
:deep(.cropper){
.cropper-view-box-Bg{
width: 100%;
position: absolute;
}
.cropper-view-box-Bg::before{
transform: translateY(-40%);
background: #fff;
color: #000;
position: absolute;
}
.cropper-view-box-Top{
// border-top: 1px dashed;
/*虚线2 css*/
background: linear-gradient(to left,transparent 0%,transparent 50%,#64646461 50%,#64646461 100%);background-size: 10px 1px;background-repeat: repeat-x;
height: 1rem;
top: 6%;
}
.cropper-view-box-Top::before{
content: 'Head';
}
.cropper-view-box-Bottom{
bottom: 6%;
// border-top: 1px dashed;
height: 1rem;
background: linear-gradient(to left,transparent 0%,transparent 50%,#64646461 50%,#64646461 100%);background-size: 10px 1px;background-repeat: repeat-x;
}
.cropper-view-box-Bottom::before{
content: 'Foot';
}
.cropper-view-box-Center{
// border-left: 1px dashed;
left: 50%;
background: linear-gradient(to bottom,transparent 0%,transparent 50%,#64646461 50%,#64646461 100%);background-size: 1px 10px;background-repeat: repeat-y;
top: 0;
width: 1rem;
height: 100%;
}
.cropper-view-box-Center::before{
content: 'Centre';
transform: translateX(-50%);
}
.cropper-crop-box{
background: #fff;
pointer-events: none;
}
}
.placementBG_img{
border-style: solid;
height: 100%;
height: calc((var(--o-height) - var(--top-width) - var(--bottom-width)) * 1px + var(--add-height));
width: calc(var(--o-width) * 1px);
border-width: calc(var(--top-width) * 1px) 0 calc(var(--bottom-width) * 1px) 0;
margin: 0 auto;
box-sizing: content-box;
}
.placement_btn{
width: 100%;
background: rgba(0,0,0,.2);
position: absolute;
.top,.bottom{
text-align: center;
position: absolute;
left: 50%;
transform: translate(-50%,-50%) rotate(135deg);
top: 0;
cursor: pointer;
i{
display: flex;
width: 3.5rem;
height: 3.5rem;
border: 2px solid #fff;
border-radius: 50%;
align-items: center;
background: rgb(0, 0, 0);
justify-content: center;
color: #fff;
}
&.bottom{
top: auto;
bottom: 0;
transform: translate(-50%,50%) rotate(135deg);
}
}
}
}
.input_blok{
> .label{
display: flex;
align-items: center;
:deep(.ant-slider){
flex: 1;
margin: 0 2rem;
.ant-slider-track{
background: rgb(245, 245, 245);
}
}
}
.text{
font-size: 1.8rem;
font-weight: 900;
}
}
.perview_mark_loading{
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 9;
display: flex;
align-items: center;
justify-content: center;
}
.placement_img{
height: 100%;
width: auto;
position: relative;
left: 50%;
transform: translateX(-50%);
user-select:none;
-moz-user-select:none;
}
.ponit_click{
width: 24px;
height: 24px;
position: absolute;
border: 2px solid transparent;
border-radius: 50%;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
cursor: pointer;
z-index: 22;
&.remove_point_click{
border-color: transparent;
background: #EF3C3C;
}
.placement_add_point_content{
width: 4px;
height: 4px;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.icon-guanbi{
font-size: 20px;
line-height: 20px;
color:#ffffff;
}
}
}
}
}
</style>