Merge branch 'dev_vite' of http://18.167.251.121:10003/aidlab/aida_front into dev_vite

This commit is contained in:
李志鹏
2026-01-13 14:41:53 +08:00
34 changed files with 2059 additions and 586 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

View File

@@ -50,7 +50,7 @@
</div>
</div>
<div class="item detailLeft" :class="{isEditPattern:isEditPattern.value}">
<detailLeft v-if="currentDetailType" ref="detailLeft"></detailLeft>
<detailLeft v-if="currentDetailType" ref="detailLeft" :detailLeftColorKey="detailLeftColorKey"></detailLeft>
<!-- <detailLeft v-if="selectDetail && selectDetail.id && currentDetailType"></detailLeft> -->
<div class="btn" style="margin: 0;" v-show="currentDetailType == 'color'">
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
@@ -61,7 +61,6 @@
<model
ref="model"
:key="positionKey"
@addDetail="addDetail"
@canvasReload="canvasReload"
@detailEdit="detailEdit"
@addSketch="()=>isEditPattern.value = ''"
@@ -103,15 +102,14 @@
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
</div>
</div>
<div class="contentRight" v-if="selectDetail && selectDetail.id && currentDetailType && isEditPattern.value">
<canvasBox ref="canvasBox" :key="canvasKey || isEditPattern.value" :isEditPattern="isEditPattern.value"></canvasBox>
<div class="contentRight canvas" v-if="selectDetail && selectDetail.id && currentDetailType" :class="{'active': isEditPattern.value}">
<canvasBox ref="canvasBox" :key="canvasKey" @setSloganData="setSloganData" :isEditPattern="isEditPattern.value" :updateOtherLayers="updateOtherLayers"></canvasBox>
</div>
<!-- 画布 -->
<!-- <div class="content" v-else-if="selectDetail && selectDetail.id">
</div> -->
</div>
</div>
<addDetails ref="addDetails" @setSloganData="setSloganData"></addDetails>
</a-modal>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
@@ -130,14 +128,13 @@ import canvasBox from './canvas/index.vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https";
import { Modal,message } from 'ant-design-vue';
import {getUploadUrl,isMoible,setGradual} from '@/tool/util'
import {getUploadUrl,segmentImage,setGradual,rgbToHsv,rgbaToHex} from '@/tool/util'
import { useStore } from "vuex";
import { openGuide,driverObj__ } from "@/tool/guide";
import { useI18n } from 'vue-i18n'
import addDetails from '@/component/Detail/addDetails.vue'
export default defineComponent({
components:{
detailLeft,model,detailRight,canvasBox,addDetails
detailLeft,model,detailRight,canvasBox
},
emits:['destroy'],
setup(props,{emit}) {
@@ -148,7 +145,6 @@ export default defineComponent({
canvasBox,
detailRight,
detailLeft:null as any,
addDetails:null as any,
})
const userDetail = computed(()=>{
return store.state.UserHabit.userDetail
@@ -157,10 +153,12 @@ export default defineComponent({
selectObject:computed(()=>store.state.Workspace.probjects) as any,//选择的项目
designDetail:computed(()=>store.state.DesignDetail.designDetail),
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
frontBack:computed(()=>store.state.DesignDetail.frontBack),
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
designDetailShow:false,
loadingShow:false,
oppositeRevocationShow:-1,
imgDomIndex:-1,
revocationShow:-1,
isEditPattern:{
value:'' as any,
@@ -174,8 +172,13 @@ export default defineComponent({
},
positionKey:0,
isUndividedLayerWithSinglePrint:false,
detailLeftColorKey:0,
})
watch(()=>detailData.selectDetail,(newValue,oldValue)=>{
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
if(newValue?.undividedLayer)newValue.undividedLayer_ = newValue.undividedLayer
// privewDetail(oldValue)
},{immediate: true})
provide('getCanvasIfEdit',detailData.getCanvasIfEdit)
provide('singleOveral',detailData.singleOveral)
@@ -320,13 +323,15 @@ export default defineComponent({
const setCurrentDetail = (str:string)=>{
store.commit('DesignDetail/setCurrentDetailType',str)
}
const setClothes = async (list:any)=>{
const setClothes = async (list:any,str:string)=>{
let clothesList:any = []
await nextTick()
if(detailData.isEditPattern.value == 'editSketch')await detailDom.canvasBox.submitBase64Data().then((rv)=>{
detailData.selectDetail.sketchString = rv
})
for(let i = 0;i<list.length;i++){
detailData.selectDetail
let {scale,offset,priority,maskUrl,maskMinioUrl} = await (detailDom.model as any).getSubmitData(list[i],detailData.isUndividedLayerWithSinglePrint)
if(detailDom.canvasBox?.privewDetail)await (detailDom.canvasBox as any).privewDetail()
let {scale,offset,priority,transpose,rotate,maskUrl,maskMinioUrl} = await (detailDom.model as any).getSubmitData(list[i],detailData.isUndividedLayerWithSinglePrint)
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
let gradient = null
let newData = list[i]?.newDetail?.[detailData.currentDetailType]
@@ -362,7 +367,9 @@ export default defineComponent({
// 406.90964
// ],
offset,
partialDesign:list[i].partialDesign || {},
transpose,
rotate,
partialDesign:(detailData.currentDetailType == 'sketch' || detailData.isEditPattern.value == 'editSketch')?{}:list[i].partialDesign,
// partialDesign:detailData.isEditPattern.value?list[i].partialDesign:{},
path:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.minIOPath:list[i].minIOPath,
printObject:(newData && detailData.currentDetailType == 'print' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].printObject?list[i].printObject:{prints:[]},
@@ -392,9 +399,9 @@ export default defineComponent({
if(!detailData?.selectDetail?.path && !detailData?.selectDetail?.newDetail?.sketch?.minIOPath)return
let clothes:any
if(detailData.currentDetailType == 'models' || detailData.isUndividedLayerWithSinglePrint){
clothes = await setClothes(detailData.designDetail.clothes)
clothes = await setClothes(detailData.designDetail.clothes,str)
}else{
clothes = await setClothes([detailData.selectDetail])
clothes = await setClothes([detailData.selectDetail],str)
}
let data = {
designItemId:detailData.designDetail.designItemId,
@@ -417,7 +424,8 @@ export default defineComponent({
fun:setRevocation
}
if(detailData?.designDetail?.newModel)detailData.designDetail.oldModel = JSON.parse(JSON.stringify(detailData.designDetail.newModel))
delete detailData.designDetail.newModel
// delete detailData.designDetail.newModel
detailData.selectDetail.sketchString = null
store.commit('DesignDetail/setPraeview',value)
detailData.loadingShow = false
detailData.isUndividedLayerWithSinglePrint = false
@@ -429,7 +437,7 @@ export default defineComponent({
}
const submit = async ()=>{
let workspace = store.state.Workspace.probjects
let clothes:any = await setClothes(detailData.designDetail.clothes)
let clothes:any = await setClothes(detailData.designDetail.clothes,'sub')
let data = {
designItemId:detailData.designDetail.designItemId,
designSingleItemDTOList:clothes,
@@ -466,9 +474,41 @@ export default defineComponent({
detailData.loadingShow = false
});
}
const previwe = ()=>{
let data = getSubmitData('preview')
store.dispatch('DesignDetail/setSubmit',data)
const previwe = async ()=>{
if((detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
let data = getSubmitData('preview')
store.dispatch('DesignDetail/setSubmit',data)
}else{
//走画布合成图片并且直接分割
if(detailData.isEditPattern.value !== 'canvasEditor'){
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
}
await detailDom.canvasBox.privewDetail()
let img = new Image()
img.onload = ()=>{
let partialDesign = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath
let size = {
width:img.width,
height:img.height,
}
segmentImage(detailData.selectDetail.maskUrl,partialDesign,size).then(async (rv)=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
if(!front?.oldMaskUrl)store.commit('DesignDetail/updataDetailItem',{maskUrl:front.oldMaskUrl})
front.imageUrl = rv.targetFrontUrl
back.imageUrl = rv.targetBackUrl
detailData.selectDetail.undividedLayerWithSinglePrint = partialDesign
store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation})
})
}
img.src = detailData.selectDetail.path
}
}
const modelOnLoad = ()=>{
if(!detailData.isUndividedLayerWithSinglePrint)return
@@ -480,31 +520,132 @@ export default defineComponent({
const detailEdit = async (str:any)=>{
if(str){
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
await detailDom.canvasBox.saveCanvas()
// await detailDom.canvasBox.saveCanvas()
await (detailDom.canvasBox as any).privewDetail()
if(detailData.isEditPattern.value == 'canvasEditor')await uploadElement()
detailData.isEditPattern.value = ''
}else{
if(detailData.isEditPattern.value){
detailDom.canvasBox.editFront(str)
}
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
// detailDom.canvasBox.editFront(str)
// }
detailDom.canvasBox.editFront(str)
let otherData = await updateOtherLayers('single')
await detailDom.canvasBox.updateOtherLayers(otherData)
detailData.isEditPattern.value = str
}
}else{
detailData.isEditPattern.value = ''
}
}
const getColorName = (color:any)=>{
let rgb:any = [color.r, color.g, color.b];
let hsv = rgbToHsv(rgb);
let data = [{
h: hsv[0],
s: hsv[1],
v: hsv[2],
}]
return new Promise((resolve, reject) => {
Https.axiosPost(Https.httpUrls.getRgbByHsvBatch, data)
.then((rv) => {
if (rv) {
resolve(rv[0])
}
})
.catch((res) => {
resolve({name:'--',tcx:'--'})
});
})
}
const updateOtherLayers = async (str:any='all')=>{//更新到画布图层
let otherData:any = {}
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
if(str == 'all'){
otherData = {
color: detailData.selectDetail.newDetail?.color.r?detailData.selectDetail.newDetail?.color:detailData.selectDetail.color,
printObject: detailData.selectDetail.newDetail?.print?.length>0?{prints:detailData.selectDetail.newDetail?.print}:detailData.selectDetail.printObject || null,
trims: detailData.selectDetail.newDetail?.element?.length>0?detailData.selectDetail.newDetail?.element:detailData.selectDetail.trims || null,
}
}else if(str == 'single'){
otherData = {
color: detailData.selectDetail.color,
printObject: detailData.selectDetail.printObject || null,
trims: detailData.selectDetail.trims || null,
}
if(detailData.currentDetailType == 'color'){
let color = detailData.selectDetail.newDetail?.color
console.log(color)
// let colorData:any = await getColorName(color?.rgba)
if(detailData.selectDetail.newDetail?.color?.rgba?.r){
color.rgba = {r:color.r,g:color.g,b:color.b,a:color.a}
otherData.color = color
}
}
if(detailData.currentDetailType == 'print'){
otherData.printObject = detailData.selectDetail.newDetail?.print?.length>0?{prints:detailData.selectDetail.newDetail?.print}:detailData.selectDetail.printObject || null
}
if(detailData.currentDetailType == 'element'){
otherData.trims = detailData.selectDetail.newDetail?.element?.length>0?detailData.selectDetail.newDetail?.element:detailData.selectDetail.trims || null
}
}
console.log(otherData,'=======',detailData.selectDetail)
return otherData
}
const uploadElement = async ()=>{//取出画布数据更新到detail
if(detailData.isEditPattern.value == 'canvasEditor'){
// await detailDom.canvasBox.saveCanvas()
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
console.log(allInfo,'allInfo')
if(allInfo.trims?.length > 0){
// detailData.selectDetail.trims.prints = allInfo.trims
let value = {
data:allInfo.trims,
str:'element'
}
store.commit('DesignDetail/setNewDetail',value)
}
if(allInfo.prints?.length > 0){
// detailData.selectDetail.printObject.prints = allInfo.prints
let value = {
data:allInfo.prints,
str:'print'
}
store.commit('DesignDetail/setNewDetail',value)
}
if(allInfo.color?.color?.rgba){
let canvasColor = allInfo.color.color
let colorData:any = await getColorName(allInfo.color.color?.rgba)
let value:any = {
data:{
hsv:{
h:colorData.h,
s:colorData.s,
v:colorData.v,
},
name:colorData.name,
tcx:colorData.tcx,
rgba:canvasColor.rgba,
hex:rgbaToHex([canvasColor.rgba.r,canvasColor.rgba.g,canvasColor.rgba.b]),
},
str:'color'
}
if(canvasColor.gradient){
value.data.gradient = canvasColor.gradient
}
store.commit('DesignDetail/setNewDetail',value)
if(allInfo.color.color.gradient)detailData.selectDetail.color.gradient = allInfo.color.color.gradient
if(detailData.currentDetailType == 'color'){
detailData.detailLeftColorKey++
}
}
}
}
const canvasReload = async ()=>{
if(detailData.isEditPattern.value){
await detailDom.canvasBox.saveCanvas()
}
detailData.canvasKey += 1
}
let time = null as any
const handleResize = ()=>{
clearTimeout(time)
time = setTimeout(()=>{
store.commit('DesignDetail/setDesignDetail',detailData.designDetail)
},1000)
}
const sketchSysToLibrary = ()=>{//系统sketch添加到library更新library
coverRevocation()
detailDom.detailLeft.sketchSysToLibrary()
@@ -516,11 +657,6 @@ export default defineComponent({
sessionStorage.setItem('revocation', JSON.stringify(revocation));
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
}
const addDetail = () =>{
let addDetails:any = detailDom.addDetails
addDetails.init(detailData.selectDetail,'')
}
const setSloganData = (data:any)=>{
detailData.selectDetail.sketchString = data
if(detailData.currentDetailType == 'sketch' && detailData.selectDetail?.newDetail?.sketch){
@@ -528,14 +664,12 @@ export default defineComponent({
}
}
onMounted(()=>{
window.addEventListener('resize', handleResize);
})
onBeforeUnmount(()=>{
sessionStorage.removeItem('oppositeRevocation')
sessionStorage.removeItem('revocation')
store.commit('DesignDetail/clearDesignDetail')
window.removeEventListener('resize', handleResize);
})
return{
@@ -553,8 +687,8 @@ export default defineComponent({
canvasReload,
modelOnLoad,
sketchSysToLibrary,
addDetail,
setSloganData,
updateOtherLayers,//更新到画布图层 再canvasInit中执行
}
},
@@ -680,6 +814,24 @@ export default defineComponent({
flex: 1;
flex-direction: column;
overflow: hidden;
&.canvas{
opacity: 0;
position: absolute;
flex: auto;
width: 35vw;
height: 80vh;
pointer-events: none;
transform: translate(100vw,100vh);
}
&.active{
position: relative;
opacity: 1;
flex: 1;
width: auto;
height: auto;
pointer-events: auto;
transform: translate(0,0);
}
}
}
.btn{

View File

@@ -1,98 +0,0 @@
<template>
<div class="addDetailsModal generalModel" ref="addDetailsModal"></div>
<a-modal
class="addDetails_modal generalModel fullScreen"
v-model:visible="addDetails"
:footer="null"
:get-container="() => $refs.addDetailsModal"
width="100%"
height="100%"
:maskClosable="false"
:centered="true"
:closable="false"
:destroyOnClose="true"
wrapClassName="#app"
:keyboard="false"
:mask="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="addDetails_center">
<generalMiniCanvas :imgUrl="imgUrl" @submitBase64Data="submitBase64Data"></generalMiniCanvas>
</div>
<div></div>
</a-modal>
</template>
<script>
import { defineComponent, ref, reactive, watch, onMounted, nextTick, toRefs } from "vue";
import generalMiniCanvas from "../modules/generalMiniCanvas.vue";
export default defineComponent({
components: {
generalMiniCanvas,
},
emits: ['setSloganData'],
setup(props,{emit}) {
let addDetail = reactive({
imgUrl:''
});
let addDetails = ref(false);
let init = (data,index)=>{
addDetails.value = true
addDetail.imgUrl = data.sketchString || data.path
}
let submitBase64Data = (data)=>{
emit('setSloganData',data)
cancelDsign()
}
let cancelDsign = ()=>{
addDetails.value = false
}
return {
...toRefs(addDetail),
addDetails,
init,
submitBase64Data,
cancelDsign,
};
},
data() {
return {
};
},
mounted() {},
methods: {
},
});
</script>
<style lang="less" scoped>
.addDetailsModal{
width: 0;
height: 0;
}
.addDetails_modal {
.closeIcon {
z-index: 2;
}
.addDetails_center{
position: relative;
height: 100%;
display: flex;
flex-direction: column;
margin: 0 auto;
}
.exportCanvasBox_submit{
// margin-top: 2.4rem;
// text-align: center;
}
}
</style>

View File

@@ -6,16 +6,15 @@
<div class="content-bottom" ref="canvasContent">
<div class="contet">
<!-- :clothingImageUrl="selectDetail?.undividedLayerWithSinglePrint || selectDetail.undividedLayer || selectDetail.path" -->
<div class="canvas" v-if="currentView === 'canvasEditor'" @click.stop>
<div class="canvas" :class="{'active': currentView === 'canvasEditor'}"@click.stop>
<editCanvas v-if="canvasLoad" :config="canvasConfig"
@canvasInit="canvasInit"
@changeCanvas="changeCanvas"
is-edit
:clothingImageUrl="selectDetail.path"
:clothingImageUrl2="selectDetail.undividedLayer"
:clothingImageUrl2="selectDetail.undividedLayer_"
showFixedLayer
:canvasJSON="canvasJSON"
:otherData="otherData"
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
:clothing-image-opts="{
imageMode:'contains',
}"
@@ -25,12 +24,6 @@
<!-- <canvasContent ref="canvasContent"></canvasContent> -->
</div>
<div class="editFrontBack" v-if="currentView === 'redGreenExample'" @click.stop>
<!-- <editFrontBack
:patchData="frontBack"
:imgDomIndex="imgDomIndex"
ref="editFrontBack">
</editFrontBack> -->
<editCanvas v-if="canvasLoad" :config="canvasConfig"
@canvasInit="canvasInit"
:enabledRedGreenMode="true"
@@ -45,6 +38,9 @@
ref="editCanvasBackFront">
</editCanvas>
</div>
<div class="editSketch" v-if="currentView === 'editSketch'" @click.stop>
<generalMiniCanvas ref="generalMiniCanvas" :btnShow="false" :imgUrl="selectDetail.sketchString || selectDetail.path"></generalMiniCanvas>
</div>
</div>
<!-- <div class="Finish">
@@ -69,15 +65,20 @@ import { useI18n } from 'vue-i18n'
import editCanvas from "@/component/Canvas/CanvasEditor/index.vue";
import { formatTime,segmentImage,getMinioUrl } from "@/tool/util";
import { useRouter, useRoute } from 'vue-router'
import generalMiniCanvas from "../../modules/generalMiniCanvas.vue";
export default defineComponent({
components:{
editCanvas
editCanvas,generalMiniCanvas
},
props:{
isEditPattern:{
type:String,
default:''
},
updateOtherLayers:{
type:Function,
default:()=>{}
}
},
setup(props,{emit}) {
@@ -90,6 +91,7 @@ export default defineComponent({
editCanvas:null as any,
editCanvasBackFront:null as any,
canvasContent:null as any,
generalMiniCanvas:null as any,
})
const userDetail = computed(()=>{
return store.state.UserHabit.userDetail
@@ -130,14 +132,14 @@ export default defineComponent({
if(detailData.currentView === 'canvasEditor'){
sessionStorage.setItem('sketchEdit',detailDom.editCanvas.getJSON())
canvasJSON = sessionStorage.getItem('frontBackEdit');
}else{
}else if(detailData.currentView === 'redGreenExample'){
sessionStorage.setItem('frontBackEdit',detailDom.editCanvasBackFront.getJSON())
canvasJSON = sessionStorage.getItem('sketchEdit');
}
detailData.canvasLoad = false
// detailData.canvasLoad = false
detailData.currentView = str
if(canvasJSON){
detailData.canvasLoad = true
// detailData.canvasLoad = true
nextTick(()=>{
if(detailData.currentView === 'redGreenExample'){
detailDom.editCanvas.loadJSON(canvasJSON)
@@ -149,28 +151,38 @@ export default defineComponent({
if(detailData.currentView === 'redGreenExample'){
nextTick(()=>{
setCanvas(detailData.selectDetail?.undividedLayerWithSinglePrint || detailData.selectDetail.undividedLayer || detailData.selectDetail.path).then(()=>{
detailData.canvasLoad = true
// detailData.canvasLoad = true
})
})
}else{
nextTick(()=>{
setCanvas(detailData.frontBack.front[detailData.imgDomIndex].maskUrl).then(()=>{
detailData.canvasLoad = true
// detailData.canvasLoad = true
})
})
}
}
}
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
const updateOtherLayers = (obj:any)=>{
if(!detailDom.editCanvas)return
return new Promise(async (res,reject)=>{
console.log(obj,'====')
await detailDom?.editCanvas.updateOtherLayers(obj)
res('')
})
}
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
// if(!detailDom.editCanvas)return
return new Promise((res,reject)=>{
detailDom.editCanvas.exportImage({isContainBg:false,isContainFixed:false}).then((rv)=>{
detailDom.editCanvas.exportImage({isContainFixedOther:true,isContainFixed:true}).then((rv)=>{
if(oldSelectDetail?.partialDesign)oldSelectDetail.partialDesign.partialDesignBase64 = rv
res('')
})
})
}
const getCanvasElement = ()=>{
if(!detailDom?.editCanvas)return ''
return detailDom?.editCanvas.exportExtraInfo();
}
const setFrontBackColor = (data:any)=>{
detailDom.editFrontBack.setBackground(data)
@@ -258,7 +270,8 @@ export default defineComponent({
const canvasInit = (value:any)=>{
detailData.canvasInstance = value
detailData.getCanvasIfEdit.fun = getCanvasLength
detailData.isShowMark = false
detailData.isShowMark = false
console.log('初始化完成')
}
const getCanvasLength = ()=>{
return detailData.canvasInstance?.commandManager?.undoStack?.length
@@ -297,14 +310,21 @@ export default defineComponent({
});
})
}
let time = null as any
const changeCanvas = ()=>{
clearTimeout(time)
time = setTimeout(()=>{
saveCanvas('auto')
},3000)
// let time = null as any
// const changeCanvas = ()=>{
// clearTimeout(time)
// time = setTimeout(()=>{
// saveCanvas('auto')
// },3000)
// }
const canvasLoadJsonSuccess = async ()=>{
let otherData = await props.updateOtherLayers()
updateOtherLayers(otherData)
}
const submitBase64Data = ()=>{
return detailDom.generalMiniCanvas.submitBase64Data()
}
onBeforeUnmount(()=>{
let front = detailData.frontBack.front[detailData.imgDomIndex]
let back = detailData.frontBack.back[detailData.imgDomIndex]
@@ -353,7 +373,10 @@ export default defineComponent({
frontBackChange,
canvasInit,
saveCanvas,
changeCanvas,
getCanvasElement,
updateOtherLayers,
canvasLoadJsonSuccess,
submitBase64Data,
}
},
provide() {
@@ -434,7 +457,15 @@ export default defineComponent({
flex: 1;
overflow: hidden;
position: relative;
.canvas,.editFrontBack{
.canvas{
opacity: 0;
position: absolute;
&.active{
opacity: 1;
position: relative;
}
}
.canvas,.editFrontBack,.editSketch{
width: 100%;
height: 100%;
}

View File

@@ -61,6 +61,7 @@ import SelectImages from '@/component/common/SelectImages.vue'
import upload from './upload.vue'
import pallet from './pallet.vue'
import { select } from 'three/tsl';
export default defineComponent({
components:{
upload,pallet,SelectImages
@@ -99,13 +100,18 @@ export default defineComponent({
tcxToColor:'',
})
watch(()=>colorData.selectColor,async (newVal,oldVal)=>{
console.log(newVal)
if(newVal.rgba && newVal.rgba?.r){
let data:any = await getColorName(newVal.rgba)
newVal.name = data.name
newVal.tcx = data.tcx
colorData.colorList.list[colorData.selectDetail.id][colorData.colorList.index] = newVal
data.rgba = newVal.rgba
if(newVal.gradient){
data.gradient = newVal.gradient
}
let value = {
data:newVal,
data:data,
str:'color'
}
store.commit('DesignDetail/setNewDetail',value)
@@ -141,7 +147,6 @@ export default defineComponent({
JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient)
&& colorData.selectDetail.color.rgba?.r
){
console.log('---',index)
isNoSelect = true
colorData.selectColor = item
colorData.colorList.index = index
@@ -190,52 +195,11 @@ export default defineComponent({
colorData.colorList.index = num
colorData.colorList.list[newVal][num] = item
}
// for (let index = 0; index < 9; index++) {
// colorData.allBoardData.colorBoards
// let item:any = {}
// item = colorData.allBoardData.colorBoards[index]
// if(
// colorData.allBoardData.colorBoards?.[index] &&
// colorData.selectDetail.color.rgba?.r == colorData.allBoardData.colorBoards?.[index]?.rgba?.r &&
// colorData.selectDetail.color.rgba?.g == colorData.allBoardData.colorBoards?.[index]?.rgba?.g &&
// colorData.selectDetail.color.rgba?.b == colorData.allBoardData.colorBoards?.[index]?.rgba?.b &&
// JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(colorData.allBoardData.colorBoards?.[index]?.gradient)
// && colorData.selectDetail.color.rgba?.r
// ){
// console.log(13212)
// if(!isOneChecked){
// isOneChecked = true
// if(colorData.allBoardData.colorBoards?.[index].gradient){
// item.gradient = colorData.allBoardData.colorBoards?.[index].gradient
// }
// colorData.selectColor = item
// colorData.colorList.index = index
// }
// }else if(colorData.selectDetail.color.rgba?.r){
// if(!isNoSelect){
// item = {
// hex:rgbaToHex([colorData.selectDetail.color.rgba.r,colorData.selectDetail.color.rgba.g,colorData.selectDetail.color.rgba.b]),
// id:colorData.selectDetail.color.id,
// rgba:{
// r:colorData.selectDetail.color.rgba.r,
// g:colorData.selectDetail.color.rgba.g,
// b:colorData.selectDetail.color.rgba.b,
// },
// tcx:colorData.selectDetail.color.tcx,
// name:colorData.selectDetail.color.name,
// }
// if(colorData.selectDetail.color.gradient){
// item.gradient = colorData.selectDetail.color.gradient
// }
// colorData.colorList.index = index
// colorData.selectColor = item
// isNoSelect = true
// }else{
// item = {}
// }
// }
// colorData.colorList.list[newVal].push(item)
// let newData = colorData.selectDetail?.newDetail?.color
// console.log(newData,colorData.selectColor)
// if(newData){
// newData.hex = rgbaToHex([newData.rgba.r,newData.rgba.g,newData.rgba.b])
// colorData.selectColor = newData
// }
},{immediate: true})
const selectImgItem = ()=>{
@@ -281,7 +245,6 @@ export default defineComponent({
})
}
const handleShowListChange=(val:boolean)=>{
console.log('val',val)
showLibrary.value = !val
}

View File

@@ -2,7 +2,7 @@
<div class="detailLeft">
<sketch v-show="currentDetailType == 'sketch'" ref="sketch" @addDetail="addDetail"></sketch>
<print v-show="currentDetailType == 'print'"></print>
<color v-if="currentDetailType == 'color'"></color>
<color v-if="currentDetailType == 'color'" :key="detailLeftColorKey"></color>
<element v-show="currentDetailType == 'element'"></element>
<accessory v-show="currentDetailType == 'accessory'"></accessory>
<models v-show="currentDetailType == 'models'"></models>
@@ -26,6 +26,12 @@ export default defineComponent({
components:{
sketch,print,color,element,models,accessory
},
props:{
detailLeftColorKey:{
type:Number,
default:0,
},
},
emit:['addDetail'],
setup(props,{emit}) {
const store = useStore();

View File

@@ -69,7 +69,6 @@ export default defineComponent({
file.designType = file?.resData?.designType
}
}
// store.commit('DesignDetail/setNewDetail',file.resData)
emit('selectImgItem',file)
}

View File

@@ -98,7 +98,6 @@ export default defineComponent({
})
const selectImgItem = (file:any)=>{
// let data = JSON.parse(JSON.stringify(file))
// store.commit('DesignDetail/setNewDetail',file)
emit('selectImgItem',file)
}
const upFileUploadChange = (data:any)=>{

View File

@@ -88,7 +88,6 @@ export default defineComponent({
})
const selectImgItem = (file:any)=>{
// let data = JSON.parse(JSON.stringify(file))
// store.commit('DesignDetail/setNewDetail',file)
emit('selectImgItem',file)
}
const setUploadImgList = (list:any)=>{

View File

@@ -51,6 +51,25 @@
:tip-formatter="formatter"
>
</a-slider>
<a-popover
trigger="click"
destroyTooltipOnHide
:title="t('Canvas.repeatSetting')"
>
<template #content>
<repeat-setting
:object="overallDetail"
@inputFillAngle="inputFillAngle"
@inputFillOffset="inputFillOffset"
@inputFillScale="inputFillScale"
@inputFill_Gap="
(x, y) => inputFill_Gap(x, y)"
/>
</template>
<div class="btn">
<i class="iconfont icon-gengduo"></i>
</div>
</a-popover>
</div>
<div class="editPrintElementBox">
<div class="designOpenrtion_centent" id="designOpenrtionCentent">
@@ -70,9 +89,10 @@
</div>
</div>
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg"> -->
<img :src="selectDetail?.undividedLayer?selectDetail.undividedLayer:selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
<div class="designOpenrtion_btn">
<ul v-if="stateOverallSingle == 'single'" v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
<img :src="selectDetail?.undividedLayerWithSinglePrint?selectDetail.undividedLayerWithSinglePrint:selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
<img :src="selectDetail.sketchMask" alt="" class="designOpenrtion_sketchMask" ref="sketchMask">
<div class="designOpenrtion_btn" v-if="stateOverallSingle == 'single'" >
<ul v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
<li class="designOpenrtion_btn_top" @mousedown.stop="itemSizeMousedown('top',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('top',getMousePosition($event,true))"></li>
<li class="designOpenrtion_btn_bottom" @mousedown.stop="itemSizeMousedown('bottom',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('bottom',getMousePosition($event,true))"></li>
<li class="designOpenrtion_btn_left" @mousedown.stop="itemSizeMousedown('left',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('left',getMousePosition($event,true))"></li>
@@ -82,12 +102,15 @@
<img src="../../../assets/images/homePage/cuowu.svg" alt="">
</li>
</ul>
<div v-show="stateOverallSingle != 'single'"></div>
<!-- <div v-show="stateOverallSingle != 'single'"></div>
<ul v-if="stateOverallSingle != 'single' && printStyleList[type][stateOverallSingle][0]" class="designOpenrtion_Mouoverall active" :style="'left:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.left+';top:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.top+';'" @mousedown.stop="itemMoveMousedown(0,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(0,getMousePosition($event,true))">
<i class="fi fi-rr-arrows animtion1"></i>
<i class="fi fi-rr-arrows animtion2"></i>
<li class="designOpenrtion_rotote" v-rotote.stop="[0,printStyleList[type][stateOverallSingle][0]?.pattern?.transform,type]"></li>
</ul>
</ul> -->
</div>
<div class="designOpenrtion_pingpu" v-else>
<pingpu v-if="overallDetail.url" v-bind="overallDetail"></pingpu>
</div>
</div>
</div>
@@ -106,8 +129,13 @@ import { defineComponent,computed,ref,onMounted,nextTick,watch,toRefs, reactive,
// import setDesignItem from '@/component/Detail/setDesignItem2.vue'
import { useStore } from "vuex";
import { getMousePosition } from "@/tool/mdEvent";
import { sketchToMask } from "@/tool/util";
import pingpu from '@/component/Canvas/OverallCanvas/index.vue'
import RepeatSetting from "./overallSetting/RepeatSetting.vue";
import { useI18n } from 'vue-i18n'
export default defineComponent({
components:{
pingpu,RepeatSetting
},
props: {
type: {
@@ -116,6 +144,7 @@ export default defineComponent({
}
},
setup(props,{emit}) {
const { t } = useI18n()
const store = useStore();
const editPrintElementDom = reactive({
imgDom:null as any,
@@ -126,6 +155,15 @@ export default defineComponent({
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
currentPrintElement:computed(()=>store.state.DesignDetail.currentPrintElement),
systemDesignerPercentage:0,
overallDetail:{
url: '',
offsetX: 0, // px
offsetY: 0, // px
angle: 0, // 角度
scale: 100, // %
gapX: 0, // px
gapY: 0, // px
},
printStyleList:{
print:{
single:[],
@@ -215,6 +253,7 @@ export default defineComponent({
path:data.url,
priority:editPrintElementData.printZIndex,
scale,
globalCompositeOperation:'',
}
getItemPosition(item)
setItemPosition()
@@ -227,6 +266,7 @@ export default defineComponent({
let scale,location
let style = item.pattern.style
let sketchWH = editPrintElementData.sketchWH.scale
let overallDetail = {}
if(item.ifSingle){
scale = [style.width.replace(/px/g,'')/(editPrintElementData.sketchWH.width),(style.height.replace(/px/g,'')/(editPrintElementData.sketchWH.height))]
location = [style.left.replace(/px/g,'')*sketchWH[0],style.top.replace(/px/g,'')*sketchWH[1]]
@@ -237,6 +277,14 @@ export default defineComponent({
scale =[ editPrintElementData.systemDesignerPercentage/100, editPrintElementData.systemDesignerPercentage/100]
// scale = [item.pattern.style.width/item.pattern.style.height,item.pattern.style.height/item.pattern.style.width]
// location = [item.pattern.style.left,item.pattern.style.top]
overallDetail = {
offsetX: editPrintElementData.overallDetail.offsetX, // px
offsetY: editPrintElementData.overallDetail.offsetY, // px
angle: editPrintElementData.overallDetail.angle, // 角度
scale: editPrintElementData.overallDetail.scale, // %
gapX: editPrintElementData.overallDetail.gapX, // px
gapY: editPrintElementData.overallDetail.gapY, // px
}
}
let value ={
angle : item.pattern.transform.rotateZ,
@@ -249,6 +297,9 @@ export default defineComponent({
path:item.path,
minIOPath:item.minIOPath,
ifSingle:!!item.ifSingle,
globalCompositeOperation:'',
object:null,
// ...overallDetail,
}
return value
}
@@ -316,6 +367,15 @@ export default defineComponent({
editPrintElementData.printStyleList[props.type].single.push(item)
}else{
editPrintElementData.printStyleList[props.type].overall = []
editPrintElementData.overallDetail = {
url: item.path,
offsetX: 0, // px
offsetY: 0, // px
angle: 0, // 角度
scale: 100, // %
gapX: 0, // px
gapY: 0, // px
}
editPrintElementData.printStyleList[props.type].overall.push(item)
}
@@ -337,9 +397,9 @@ export default defineComponent({
if(!editPrintElementData.selectDetail.printObject.prints)return
let state = true
// editPrintElementData.stateOverallSingle = 'single'
let arr:any = editPrintElementData.selectDetail.printObject.prints
let arr:any = editPrintElementData.selectDetail.newDetail?.print || editPrintElementData.selectDetail.printObject.prints
if(props.type == 'element'){
arr = editPrintElementData.selectDetail.trims.prints
arr = editPrintElementData.selectDetail.newDetail?.element || editPrintElementData.selectDetail.trims.prints
}
if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
@@ -384,8 +444,28 @@ export default defineComponent({
single:[],
overall:[],
}
if(!editPrintElementData.selectDetail.sketchMask){
sketchToMask(newVal).then((res:any)=>{
editPrintElementData.selectDetail.sketchMask = res
})
}
setPosition()
},{immediate: true,})
watch(()=>editPrintElementData.stateOverallSingle,(newVal)=>{
if(newVal == 'overall'){
let overallPrint = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]?.[0]
if(!overallPrint?.path)return
editPrintElementData.overallDetail = {
url: overallPrint.path,
offsetX: overallPrint.offsetX || 0, // px
offsetY: overallPrint.offsetY || 0, // px
angle: overallPrint.angle || 0, // 角度
scale: overallPrint.scale || 100, // %
gapX: overallPrint.gapX || 0, // px
gapY: overallPrint.gapY || 0, // px
}
}
})
//设置移动
const itemMoveMousedown = (index:number,event:any)=>{
if (event.target.tagName === 'IMG' || event.target.nodeName === 'IMG')return
@@ -738,6 +818,20 @@ export default defineComponent({
collItemSize.prentWidth = (collItemSize.padding + remValue) * elArr.length + 'px'
moveItem()
}
const inputFillAngle = (angle:any)=>{
editPrintElementData.overallDetail.angle = angle
}
const inputFillOffset = (offset:any)=>{
editPrintElementData.overallDetail.offsetX = offset.left
editPrintElementData.overallDetail.offsetY = offset.top
}
const inputFillScale = (scale:any)=>{
editPrintElementData.overallDetail.scale = scale
}
const inputFill_Gap = (x:any,y:any)=>{
editPrintElementData.overallDetail.gapX = x
editPrintElementData.overallDetail.gapY = y
}
onMounted(()=>{
if(props.type == 'element'){
editPrintElementData.stateOverallSingle = 'single'
@@ -747,6 +841,7 @@ export default defineComponent({
previewDetailPrintData()
})
return{
t,
getMousePosition,
...toRefs(editPrintElementDom),
...toRefs(editPrintElementData),
@@ -760,6 +855,10 @@ export default defineComponent({
clearOverall,
designMousedown,
navDelete,
inputFillAngle,
inputFillOffset,
inputFillScale,
inputFill_Gap,
}
},
directives:{
@@ -983,7 +1082,13 @@ export default defineComponent({
// height: 100%;
max-width: 100%;
// width: 100%;
&.designOpenrtion_sketchMask{
position: absolute;
z-index: 3;
top: 0;
left: 0;
pointer-events: none;
}
}
.designOpenrtion_sketch_mask{
z-index: 2;
@@ -1013,8 +1118,13 @@ export default defineComponent({
}
}
}
.designOpenrtion_pingpu{
width: 100%;
height: 100%;
z-index: 2;
}
.designOpenrtion_btn{
z-index: 3;
z-index: 99;
>div{
width: 100%;
height: 100%;

View File

@@ -0,0 +1,124 @@
<template>
<div class="repeat-setting">
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.angle") }}</span>
<angle-tool
:angle="angle"
@input="(e) => emit('inputFillAngle', e)"
/>
</div>
<p></p>
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.scale") }}</span>
<slider
:min="1"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${scale}%`"
:value="scale"
@input="inputFillScale"
/>
</div>
<p></p>
<div class="repeat-setting-item">
<span class="label">Gap X</span>
<slider
:min="0"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapX"
@input="(e) => emit('inputFill_Gap', e, gapY)"
@change="(e) => emit('changeFill_Gap', e, gapY)"
/>
</div>
<p></p>
<div class="repeat-setting-item">
<span class="label">Gap Y</span>
<slider
:min="0"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapY"
@input="(e) => emit('inputFill_Gap', gapX, e)"
@change="(e) => emit('changeFill_Gap', gapX, e)"
/>
</div>
<p></p>
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.offset") }}</span>
<offset-tool
:top="(props.object.fill?.offsetY / props.object.height) * 100"
:left="(props.object.fill?.offsetX / props.object.width) * 100"
@input="(e) => emit('inputFillOffset', e)"
@change="(e) => emit('changeFillOffset', e)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, computed } from "vue";
import AngleTool from "./tools/AngleTool.vue";
import OffsetTool from "./tools/OffsetTool.vue";
import Slider from "./tools/Slider.vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps({
object: {
required: true,
type: Object,
},
});
const angle = computed(() => props.object?.angle || 0);
const scale = computed(() => {
// let scaleValue = props.object?.scale/10;
// return props.object?.scale/10;
return props.object?.scale
});
const gapX = computed(() => props.object?.gapX || 0);
const gapY = computed(() => props.object?.gapY || 0);
const emit = defineEmits([
"inputFillAngle",
"changeFillAngle",
"inputFillOffset",
"changeFillOffset",
"inputFillScale",
"changeFillScale",
"inputFill_Gap",
"changeFill_Gap",
]);
const inputFillScale = (e) => {
// const scale = e * 10;
emit("inputFillScale", e);
};
</script>
<style scoped lang="less">
.repeat-setting {
user-select: none;
> .repeat-setting-item {
display: flex;
align-items: center;
//虚线
> .label {
min-width: 50px;
font-size: 14px;
}
> .angle-tool {
width: 120px;
}
}
> p {
margin: 10px 0;
width: 100%;
height: 0;
border-bottom: 1px dashed #e5e5e5;
}
}
</style>

View File

@@ -0,0 +1,122 @@
<template>
<div class="angle-tool">
<div
ref="dishRef"
class="dish"
@mousedown.stop="mousedown"
@touchmove.stop="mousedown"
>
<div class="pointer" :style="{ transform: `rotate(${angle}deg)` }">
<span></span>
</div>
</div>
<div class="input">
<input type="number" v-model="angle" @input="onInput" @change="onChange" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
// Props
const props = defineProps({
angle: {
type: Number,
default: 0,
},
});
const emit = defineEmits(["change", "input"]);
const angle = ref(props.angle);
watch(() => props.angle, (value) => {
angle.value = value;
});
const dishRef = ref<HTMLDivElement>();
const mousedown = (e: MouseEvent | TouchEvent) => {
const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const { left, top, width, height } =
dishRef.value.getBoundingClientRect();
const centerX = left + width / 2;
const centerY = top + height / 2;
const { clientX, clientY } = e?.touches?.[0] || e;
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
console.log(angle.value)
onInput();
};
mousemove(e);
const mouseup = () => {
onChange();
document.removeEventListener("mousemove", mousemove);
document.removeEventListener("touchmove", mousemove);
document.removeEventListener("mouseup", mouseup);
document.removeEventListener("touchend", mouseup);
};
document.addEventListener("mousemove", mousemove);
document.addEventListener("touchmove", mousemove);
document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup);
};
const onInput = () => emit("input", angle.value);
var changeTime: any = null;
const onChange = () => {
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", angle.value), 500);
};
// var angleTime = null;
// watch(angle, (value) => {
// emit("input", value);
// clearTimeout(angleTime);
// angleTime = setTimeout(() => emit("change", value), 50);
// });
// defineExpose({
// open,
// close,
// });
</script>
<style scoped lang="less">
.angle-tool {
display: flex;
align-items: center;
width: 100%;
> .dish {
width: 24px;
height: 24px;
border: 1px solid #000;
border-radius: 50%;
cursor: pointer;
> .pointer {
pointer-events: none;
user-select: none;
position: relative;
width: 100%;
height: 100%;
> span {
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, 0);
width: 35%;
height: 35%;
background-color: #000;
border-radius: 50%;
}
}
}
> .input {
margin-left: 5px;
font-size: 14px;
color: #000;
flex: 1;
// min-width: 45px;
// max-width: 80px;
// width: 50px;
> input {
width: 100%;
border-radius: 3px;
outline: none;
}
}
}
</style>

View File

@@ -0,0 +1,66 @@
<template>
<a-select
class="my-select"
:size="size"
@change="change"
:defaultValue="defaultValue"
@dropdownVisibleChange="dropdownVisibleChange"
>
<a-select-option
v-for="v in list"
:key="v.value"
:value="v.value"
:title="v.tip"
@mouseover.stop.prevent="mouseover(v)"
@mouseleave="mouseleave(v)"
>{{ v.label }}</a-select-option
>
</a-select>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({
defaultValue: {
default: "",
},
list: {
type: Array,
default: () => [],
},
size: {
type: String,
default: "small",
},
});
const emit = defineEmits(["change", "active"]);
const isChange = ref(false);
const initValue = ref(props.defaultValue);
const activeValue = ref(props.defaultValue);
const timeout = ref(null);
const mouseover = (v) => {
clearTimeout(timeout.value);
if (v.value === activeValue.value) return;
emit("active", v.value, activeValue.value);
activeValue.value = v.value;
};
const mouseleave = () => {
clearTimeout(timeout.value);
timeout.value = setTimeout(() => {
dropdownVisibleChange(false);
}, 100);
};
const change = (v) => {
isChange.value = true;
emit("change", v, initValue.value);
};
const dropdownVisibleChange = (v) => {
if (v) {
isChange.value = false;
initValue.value = props.defaultValue;
} else if (!isChange.value) {
emit("active", initValue.value, activeValue.value);
activeValue.value = initValue.value;
}
};
</script>

View File

@@ -0,0 +1,190 @@
<template>
<div class="offset-tool">
<div
class="dish"
@mousedown="mousedown"
@touchstart="mousedown"
ref="dishRef"
>
<span
:style="{ top: data.top + '%', left: data.left + '%' }"
></span>
</div>
<input
class="top"
type="range"
:min="0"
:max="100"
:step="0.1"
v-model="data.top"
@input="onInput"
@change="onChange"
/>
<input
class="left"
type="range"
:min="0"
:max="100"
:step="0.1"
v-model="data.left"
@input="onInput"
@change="onChange"
/>
<span class="tip"
>x:{{ tofix(data.left) }}% y:{{ tofix(data.top) }}%</span
>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({
top: {
type: Number,
default: 50,
},
left: {
type: Number,
default: 50,
},
});
const tofix = (v: number | string) => Number(Number(v).toFixed(1));
const emit = defineEmits(["change", "input"]);
const data = reactive({
top: tofix(props.top),
left: tofix(props.left),
});
watch(
() => props.top,
(v) => (data.top = tofix(v))
);
watch(
() => props.left,
(v) => (data.left = tofix(v))
);
const dishRef = ref<HTMLDivElement>();
const mousedown = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const mousemove = (e: MouseEvent | TouchEvent) => {
if (!dishRef.value) return;
const { left, top, width, height } =
dishRef.value.getBoundingClientRect();
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
var x = ((X - left) / width) * 100;
var y = ((Y - top) / height) * 100;
if (x < 0) x = 0;
if (x > 100) x = 100;
if (y < 0) y = 0;
if (y > 100) y = 100;
data.left = tofix(x);
data.top = tofix(y);
onInput();
};
mousemove(e);
const mouseup = () => {
onChange();
document.removeEventListener("mousemove", mousemove);
document.removeEventListener("touchmove", mousemove);
document.removeEventListener("mouseup", mouseup);
document.removeEventListener("touchend", mouseup);
};
document.addEventListener("mousemove", mousemove);
document.addEventListener("touchmove", mousemove);
document.addEventListener("mouseup", mouseup);
document.addEventListener("touchend", mouseup);
};
const onInput = () => emit("input", { ...data });
var changeTime: any = null;
const onChange = () => {
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", { ...data }), 500);
};
// var offsetTime = null;
// watch(data, (v) => {
// const obj = { ...v };
// emit("input", obj);
// clearTimeout(offsetTime);
// offsetTime = setTimeout(() => emit("change", obj), 50);
// });
// defineExpose({
// open,
// close,
// });
</script>
<style scoped lang="less">
.offset-tool {
width: 125px;
height: 125px;
display: flex;
position: relative;
overflow: hidden;
--gap: 15px;
> .dish {
margin: var(--gap) 0 0 var(--gap);
flex: 1;
border: 1px solid #000;
border-radius: 5px;
cursor: pointer;
position: relative;
background-color: #fff;
> span {
pointer-events: none;
user-select: none;
position: absolute;
top: 0%;
left: 0%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
background-color: #000;
border-radius: 50%;
}
}
> .tip {
position: absolute;
right: 4px;
bottom: 0;
font-size: 10px;
pointer-events: none;
user-select: none;
color: #666;
}
> input.left {
right: 0;
}
> input.top {
bottom: 0;
left: 0;
transform-origin: left bottom;
transform: rotate(90deg) translateX(-100%);
}
> input {
position: absolute;
width: calc(100% - var(--gap));
-webkit-appearance: none;
appearance: none;
height: 8px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
// outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 8px;
height: 8px;
border-radius: 50%;
background: #4285f4; /* 蓝色滑块 */
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
&::-webkit-slider-thumb:hover {
background: #3b77db;
transform: scale(1.1);
}
}
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<div class="slider">
<div class="input-range">
<span
class="tip"
:style="{
'--progress': (value - props.min) / (props.max - props.min),
}"
>{{ props.tipFormatter(value) }}</span
>
<input
type="range"
v-model="value"
:min="props.min"
:max="props.max"
:step="props.step"
@input="onInput"
@change="onChange"
/>
</div>
<div class="input" v-show="isInput">
<input
type="number"
v-model="value"
:min="props.min"
:max="props.max"
:step="props.step"
@input="onInput"
@change="onChange"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from "vue";
const props = defineProps({
value: {
type: Number,
default: 0,
},
min: {
type: Number,
default: 0,
},
max: {
type: Number,
default: 100,
},
step: {
type: Number,
default: 1,
},
tipFormatter: {
type: Function,
default: (v) => v,
},
isInput: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["change", "input"]);
const value = ref(props.value);
watch(
() => props.value,
(v) => (value.value = v)
);
const onInput = () => emit("input", Number(value.value));
var changeTime: any = null;
const onChange = () => {
clearTimeout(changeTime);
changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
};
</script>
<style scoped lang="less">
.slider {
position: relative;
display: flex;
align-items: center;
--input-thumb-size: 12px;
width: 150px;
// &:focus-within,
&:hover {
> .input-range > .tip {
display: block;
}
}
> .input-range {
position: relative;
flex: 2;
> input {
width: 100%;
-webkit-appearance: none;
appearance: none;
height: 5px;
border-radius: 5px;
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: var(--input-thumb-size);
height: var(--input-thumb-size);
border-radius: 50%;
background: #4285f4; /* 蓝色滑块 */
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
&::-webkit-slider-thumb:hover {
background: #3b77db;
transform: scale(1.1);
}
}
> .tip {
position: absolute;
font-size: 10px;
pointer-events: none;
user-select: none;
color: #666;
top: 0;
left: calc(
(100% - var(--input-thumb-size)) * var(--progress) +
var(--input-thumb-size) / 2
);
transform: translate(-50%, -100%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 0.4rem 0.8rem;
border-radius: 0.4rem;
font-size: 1.2rem;
white-space: nowrap;
pointer-events: none;
display: none;
&::after {
content: "";
position: absolute;
top: 97%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid rgba(0, 0, 0, 0.8);
}
}
}
> .input {
flex: 1;
margin-left: 10px;
> input {
border-radius: 3px;
width: 100%;
}
}
}
</style>

View File

@@ -4,9 +4,9 @@
<div class="back" v-show="isEditPattern.value">
<i class="fi fi-br-angle-left" @click="setBack"></i>
</div>
<modelNav @canvasReload="()=>$emit('canvasReload')" @addSketch="()=>$emit('addSketch')" @sketchSysToLibrary="()=>$emit('sketchSysToLibrary')" @deleteItem="deleteItem"></modelNav>
<modelNav ref="modelNav" @canvasReload="()=>$emit('canvasReload')" @addSketch="()=>$emit('addSketch')" @sketchSysToLibrary="()=>$emit('sketchSysToLibrary')" @deleteItem="deleteItem"></modelNav>
</div>
<div class="modelindex_right">
<div class="modelindex_right" ref="modelindexRight">
<div class="detail_btn">
<!-- 全屏 -->
<!-- <i class="fi fi-bs-expand-arrows-alt" @click="showDesignImgDetail('2')"></i> -->
@@ -14,7 +14,7 @@
<i class="icon iconfont icon-chehui" @click="revocation"></i>
<i class="icon iconfont icon-fanchehui" @click="oppositeRevocation"></i>
<!-- 编辑 -->
<i class="fi fi-rs-pencil-paintbrush" :title="$t('DesignDetail.editSketchTitle')" :class="{'pointerEventsNone':!selectDetail?.id}" @click="()=>$emit('addDetail')"></i>
<i class="fi fi-rs-pencil-paintbrush" :title="$t('DesignDetail.editSketchTitle')" :class="{'pointerEventsNone':!selectDetail?.id,active:isEditPattern.value == 'editSketch'}" @click="showDesignImgDetail('editSketch')"></i>
<i class="fi fi-rr-edit" :title="$t('DesignDetail.editTitle')" :class="{active:isEditPattern.value == 'canvasEditor','pointerEventsNone':!selectDetail?.id}" @click="showDesignImgDetail('canvasEditor')"></i>
<i class="icon iconfont icon-clothes" :title="$t('Canvas.editFrontBack')" style="font-size: 3.2rem;" @click="showDesignImgDetail('redGreenExample')" :class="{active:isEditPattern.value == 'redGreenExample','pointerEventsNone':!selectDetail?.id}"></i>
@@ -51,7 +51,7 @@ export default defineComponent({
components:{
position,modelNav
},
emits:['detailEdit','canvasReload','addSketch','revocation','oppositeRevocation','modelOnLoad','sketchSysToLibrary','addDetail'],
emits:['detailEdit','canvasReload','addSketch','revocation','oppositeRevocation','modelOnLoad','sketchSysToLibrary'],
setup(props,{emit}) {
const {t} = useI18n()
const store = useStore();
@@ -68,36 +68,40 @@ export default defineComponent({
const getDetailListDom = reactive({
libraryList:null as any,
position:null as any,
modelindexRight:null as any,
modelNav:null as any,
})
const getSubmitData = (value:any,boolean)=>{
return getDetailListDom.position.getSubmitData(value,boolean)
}
const showDesignImgDetail = (str:any)=>{
new Promise((resolve, reject) => {
if(
getDetailListData.isEditPattern.value&&
detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
){
Modal.confirm({
title: t('collectionModal.jsContent2'),
icon: createVNode(ExclamationCircleOutlined),
okText: 'Yes',
cancelText: 'No',
mask:false,
centered:true,
onOk() {
resolve(true)
emit('detailEdit',str)
},
onCancel(){
resolve(false)
}
});
}else{
resolve(true)
emit('detailEdit',str)
}
})
emit('detailEdit',str)
// new Promise((resolve, reject) => {
// if(
// getDetailListData.isEditPattern.value&&
// detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
// ){
// Modal.confirm({
// title: t('collectionModal.jsContent2'),
// icon: createVNode(ExclamationCircleOutlined),
// okText: 'Yes',
// cancelText: 'No',
// mask:false,
// centered:true,
// onOk() {
// resolve(true)
// emit('detailEdit',str)
// },
// onCancel(){
// resolve(false)
// }
// });
// }else{
// resolve(true)
// emit('detailEdit',str)
// }
// })
}
const deleteItem = ()=>{
setRevocation()
@@ -117,22 +121,29 @@ export default defineComponent({
}
let time = null as any
const handleResize = ()=>{
const handleResize = ()=>{
clearTimeout(time)
time = setTimeout(()=>{
store.commit('DesignDetail/setDesignDetail',getDetailListData.designDetail)
getDetailListDom.position.updataPosition()
},1000)
getDetailListDom.position?.updataPosition?.()
getDetailListDom.modelNav?.setItemPosition?.()
getDetailListDom.position?.updateRect?.()
},500)
}
const setBack = ()=>{
emit('detailEdit')
showDesignImgDetail(getDetailListData.isEditPattern.value)
}
let observers = null as any
onMounted(()=>{
window.addEventListener('resize', handleResize);
observers = new ResizeObserver(entries => {
for (let entry of entries) {
handleResize()
}
});
observers.observe(getDetailListDom.modelindexRight);
})
onBeforeUnmount(()=>{
window.removeEventListener('resize', handleResize);
observers.disconnect();
})
return{
...toRefs(detailData),

View File

@@ -268,17 +268,8 @@ export default defineComponent({
let allPostition = store.state.Workspace.workspaceAllPosition
return allPostition.find(item => item.value === type)?.name
}
let observers = null as any
onMounted(()=>{
observers = new ResizeObserver(entries => {
for (let entry of entries) {
setItemPosition()
}
});
observers.observe(detailData.modelNavBox);
})
onBeforeUnmount(()=>{
observers.disconnect();
})
return{
...toRefs(detailData),

View File

@@ -1,21 +1,17 @@
<template>
<div class="molepositon" :class="{active:!imgDesignImg}">
<div class="designOpenrtion_imgMask" v-if="frontBack?.body?.path" :style="frontBack?.body?.style">
<div class="designOpenrtion_print" v-for="item,index in frontBack.back" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="frontBack.front[index].style">
<div class="designOpenrtion_print" v-for="item,index in frontBack.back" :style="frontBack.front[index].style">
<img :style="item.imageUrl?'':'display:none;'" :src="item.imageUrl" alt="">
</div>
<img class="perview_img" @load="setPrintSize()" ref="detailBody" :key="designDetail.designItemId" :src="frontBack?.body?.path" :style="'width:'+ frontBack?.body?.layersObject?.[0].imageSize?.[0] +';height:' + frontBack?.body?.layersObject?.[0].imageSize?.[0] +';'">
<div class="detail_modal_item_front" v-for="item,index in frontBack.front" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="item.style">
<!-- <div class="detail_modal_item_front" ref="target" v-for="item,index in frontBack.front" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="item.style">
<img :src="item.imageUrl" alt="">
</div> -->
<div class="detail_modal_item_front" :ref="el => { setElementRef(el, index) }" v-for="item,index in frontBack.front" :class="{'active':item.id == selectDetail?.id}" :style="item.style">
<img :src="item.imageUrl" alt="">
</div>
<div class="designOpenrtion_btnBox">
<ul v-for="item,index in frontBack.front" :key="item" :class="{active:item.designOpenrtionBtn}" class="designOpenrtion_btn" :style="item.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
<li class="designOpenrtion_btn_top" @mousedown.stop="itemSizeMousedown('top',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('top',getMousePosition($event,true))"></li>
<li class="designOpenrtion_btn_bottom" @mousedown.stop="itemSizeMousedown('bottom',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('bottom',getMousePosition($event,true))"></li>
<li class="designOpenrtion_btn_left" @mousedown.stop="itemSizeMousedown('left',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('left',getMousePosition($event,true))"></li>
<li class="designOpenrtion_btn_right" @mousedown.stop="itemSizeMousedown('right',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('right',getMousePosition($event,true))"></li>
</ul>
</div>
<div ref="moveableContainer" class="moveableContainer"></div>
</div>
<div class="designOpenrtion_imgMask" v-if="!frontBack?.body?.path">
<img :src="selectDetail?.undividedLayerWithSinglePrint || selectDetail?.undividedLayer || selectDetail?.path" style="object-fit: cover;" alt="">
@@ -40,8 +36,10 @@ import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { useI18n } from 'vue-i18n'
import { getMousePosition } from "@/tool/mdEvent";
import { Modal,message } from 'ant-design-vue';
import newFollowVue from '@/component/Account/message/newFollow.vue';
import Vue3Moveable from 'vue3-moveable';
import Moveable from 'moveable';
import { parse } from 'vue/compiler-sfc';
import { scale } from 'echarts/types/src/scale/helper.js';
export default defineComponent({
components:{
},
@@ -75,10 +73,7 @@ export default defineComponent({
imgDom:null as any,
direction:'',
})
watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{
if(!newValue && newValue?.id == oldValue?.id)return
selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
},{immediate: true,})
watch(()=>detailData.frontBack?.body?.path,(newVal)=>{
setPrintSize()
})
@@ -99,7 +94,6 @@ export default defineComponent({
if(entries[0].contentRect.width == 0)return
detailData.observerWH.width = Math.floor(entries[0].contentRect.width)
detailData.observerWH.height = Math.floor(entries[0].contentRect.height)
console.log(detailData.observerWH)
})
detailData.observer.observe(dom)
@@ -131,6 +125,7 @@ export default defineComponent({
}
for (const key in detailData.frontBack.back[index].style) {
if(key == 'zIndex')return
if(key == 'transform')return
let value = detailData.frontBack.back[index].style[key]
if(typeof value !== 'number'){
value = value.replace('px','')
@@ -143,6 +138,7 @@ export default defineComponent({
});
setTimeout(() => {
emit('modelOnLoad')
initMoveableForSelected()
},500);
};
img.src = detailData.frontBack?.body?.path;
@@ -150,203 +146,280 @@ export default defineComponent({
}
const getDetailListDom = reactive({
libraryList:null as any,
moveableContainer:null as any,//控件层
})
//设置尺寸
const itemSizeMousedown = (direction:any,event:any)=>{
selectItem.direction = direction
selectItem.imgDom = document.getElementsByClassName('molepositon')[0].getElementsByClassName("detail_modal_item_front")[selectItem.imgDomIndex]
detailData.frontBack.front[selectItem.imgDomIndex].designOpenrtionBtn = true
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
let li = (document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_btn_top")[0] as any).offsetWidth/2
if(selectItem.direction == 'right' || selectItem.direction == 'bottom'){
detailData.frontBack.front[selectItem.imgDomIndex].centers.left = imgDomWH.x+event.offsetX-li
detailData.frontBack.front[selectItem.imgDomIndex].centers.top = imgDomWH.y+event.offsetY-li
}else{
detailData.frontBack.front[selectItem.imgDomIndex].centers.left = imgDomWH.x+event.offsetX+imgDomWH.width-li
detailData.frontBack.front[selectItem.imgDomIndex].centers.top = imgDomWH.y+event.offsetY+imgDomWH.height-li
const elementRefs = ref([]) as any;
const moveableInstance = ref(null) as any;
const setElementRef = (el, index) => {
elementRefs.value[index] = el;
};
const updateRect = ()=>{
setTimeout(() => {
moveableInstance.value.updateRect()
}, 500);
}
const initMoveableForSelected = () => {
// 销毁旧的实例
if(selectItem.imgDomIndex == -1)return
if (moveableInstance.value) {
moveableInstance.value.destroy();
}
document.addEventListener('mousemove', sizeMouseMove);
document.addEventListener('touchmove', sizeTouchmove);
document.addEventListener('mouseup', sizeMouseup);
document.addEventListener('touchend', sizeMouseup);
}
const sizeMouseMove = (event:any)=>{
let e = getMousePosition(event,false)
sizeMouseMoveOperation(e)
}
const sizeTouchmove = (event:any)=>{
let e = getMousePosition(event,true)
sizeMouseMoveOperation(e)
}
const sizeMouseup = (e:any)=>{
detailData.frontBack.front[selectItem.imgDomIndex].style={
right:'auto',
left:selectItem.imgDom.offsetLeft+'px',
bottom:'auto',
top:selectItem.imgDom.offsetTop+'px',
height:selectItem.imgDom.offsetHeight+'px',
width:selectItem.imgDom.offsetWidth+'px',
zIndex:selectItem.imgDom.style.zIndex,
// zIndex:selectItem.printZIndex
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
if (!selectedEl) return;
if(!selectedEl.style.left)return
moveableInstance.value = new Moveable(getDetailListDom.moveableContainer, {
target: selectedEl,
draggable: true,
scalable: true,
rotatable: true,
keepRatio: false, // 等比缩放
snappable: true,
snapThreshold: 5,
edge: false,
});
let startPosition = {//记录初始位置
left: 0,
top: 0,
}
// detailData.frontBack.back[selectItem.imgDomIndex].style.zIndex = selectItem.printZIndex
document.removeEventListener('mousemove',sizeMouseMove)
document.removeEventListener('touchmove',sizeTouchmove)
document.removeEventListener('mouseup',sizeMouseup)
document.removeEventListener('touchend',sizeMouseup)
//鼠标抬起
setRevocation()
}
let isMove = false//表示是否移动,是否需要在鼠标抬起的时候保存数据
moveableInstance.value.on('scaleStart', ({ target, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror){
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
}
});
moveableInstance.value.on('rotateStart', ({ target, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror){
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
}
});
moveableInstance.value.on('dragStart', ({ target, clientX, clientY }) => {
startPosition = {
left:parseFloat(selectedEl.style.left.replace('px','')) || 0,
top:parseFloat(selectedEl.style.top.replace('px','')) || 0,
}
});
// 拖拽
moveableInstance.value.on('drag', ({ target, beforeTranslate }) => {
let x = startPosition.left + beforeTranslate[0]
let y = startPosition.top + beforeTranslate[1]
detailData.frontBack.front[selectItem.imgDomIndex].style.left = x + 'px'
detailData.frontBack.front[selectItem.imgDomIndex].style.top = y + 'px'
});
const updateElementTransform = (element, rotateDeg = null) => {
const currentTransform = element.style?.transform || '';
// 1. 提取当前的所有rotate
const currentRotates = (currentTransform.match(/rotate[XYZ]?\([^)]+\)/g) || []);
// 2. 获取除镜像和rotate外的其他所有变换
let otherTransforms = currentTransform
.replace(/scaleX\(-1\)|scaleY\(-1\)/g, '') // 移除镜像
.replace(/rotate[XYZ]?\([^)]+\)/g, '') // 移除rotate
.replace(/\s+/g, ' ')
.trim();
// 3. 构建新transform
const transforms = [];
// 镜像部分
if (element.mirror.x) transforms.push('scaleX(-1)');
if (element.mirror.y) transforms.push('scaleY(-1)');
if (otherTransforms) transforms.push(otherTransforms);
if (rotateDeg !== null) {
transforms.push(`rotate(${rotateDeg}deg)`);
} else if (currentRotates.length > 0) {
transforms.push(...currentRotates);
}
element.style.transform = transforms.join(' ').trim();
};
moveableInstance.value.on('scale', ({ target, delta, direction }) => {
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
const width = parseFloat(frontStyle.style.width);
const height = parseFloat(frontStyle.style.height);
let left = parseFloat(frontStyle.style.left) || 0;
let top = parseFloat(frontStyle.style.top) || 0;
let rotation = 0;
// 获取原始比例
const originalRatio = width / height;
if (frontStyle.style.transform) {
const transform = frontStyle.style.transform;
const match = transform.match(/rotate\(([-\d.]+)deg\)/);
if (match) {
rotation = parseFloat(match[1]);
}
}
// 根据旋转角度重新计算控制点的方向
function getAdjustedCorner(originalCorner, rotationAngle) {
const angleRad = rotationAngle * (Math.PI / 180);
const cosA = Math.cos(angleRad);
const sinA = Math.sin(angleRad);
const newX = originalCorner.x * cosA - originalCorner.y * sinA;
const newY = originalCorner.x * sinA + originalCorner.y * cosA;
const threshold = 0.5;
return {
x: Math.abs(newX) > threshold ? (newX > 0 ? 1 : -1) : 0,
y: Math.abs(newY) > threshold ? (newY > 0 ? 1 : -1) : 0
};
}
if (rotation !== 0) {
direction = getAdjustedCorner({x: direction[0], y: direction[1]}, rotation);
direction = [direction.x, direction.y];
}
// 判断是否是对角线方向(需要等比缩放)
const isDiagonal = Math.abs(direction[0]) === 1 && Math.abs(direction[1]) === 1;
// 处理轴缩放,包含镜像翻转逻辑
const processAxis = (axis, val, deltaVal, dir, originalPosition, originalSize, keepRatio = false, otherAxisResult = null) => {
let newVal = val * deltaVal;
const mirrorKey = axis === 'width' ? 'x' : 'y';
const isWidth = axis === 'width';
// 检查是否需要镜像翻转当值小于等于0时
if (newVal <= 0) {
frontStyle.mirror[mirrorKey] = !frontStyle.mirror[mirrorKey];
newVal = Math.abs(newVal);
updateElementTransform(frontStyle);
// 镜像翻转后,位置需要根据原始锚点调整
if (dir === -1) {
// 从左上/右上缩放时,位置保持不变
return {
newVal,
adjustPos: originalPosition,
shouldFlip: true
};
} else {
// 从左下/右下缩放时,位置需要调整
const newPosition = originalPosition + (originalSize - newVal) * (frontStyle.mirror[mirrorKey] ? -1 : 1);
return {
newVal,
adjustPos: newPosition,
shouldFlip: true
};
}
}
const shouldMove = (!frontStyle.mirror[mirrorKey] && dir === -1) ||
(frontStyle.mirror[mirrorKey] && dir === 1);
if (keepRatio && otherAxisResult) {
newVal = isWidth ?
otherAxisResult.newVal * originalRatio :
otherAxisResult.newVal / originalRatio;
}
let adjustPos;
if (shouldMove) {
adjustPos = originalPosition - (newVal - originalSize);
} else {
adjustPos = originalPosition;
}
return {
newVal,
adjustPos,
shouldFlip: false
};
};
// 自由缩放
const widthResult = processAxis('width', width, delta[0], direction[0], left, width);
const heightResult = processAxis('height', height, delta[1], direction[1], top, height);
frontStyle.style.left = widthResult.adjustPos + 'px';
frontStyle.style.top = heightResult.adjustPos + 'px';
frontStyle.style.width = widthResult.newVal + 'px';
frontStyle.style.height = heightResult.newVal + 'px';
// }
});
// 旋转
moveableInstance.value.on('rotate', ({ target, beforeRotate }) => {
let frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
// 确保镜像状态存在
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
const { x: isMirroredX, y: isMirroredY } = frontStyle.mirror;
// 计算实际旋转角度
let actualRotate = beforeRotate;
// 关键逻辑当镜像状态不同时一个true一个false旋转方向反转
if (isMirroredX !== isMirroredY) {
actualRotate = -beforeRotate;
}
// 确保角度在 0-360 度范围内
actualRotate = actualRotate % 360;
// 如果角度为负数,转换为正数
if (actualRotate < 0) {
actualRotate += 360;
}
// 确保角度在 [0, 360) 范围内
actualRotate = ((actualRotate % 360) + 360) % 360;
updateElementTransform(frontStyle, actualRotate.toFixed(2));
});
// 调整大小
moveableInstance.value.on('resize', ({ target, width, height }) => {
// console.log(width, height)
// detailData.frontBack.front[selectItem.imgDomIndex].style.width = width
// detailData.frontBack.front[selectItem.imgDomIndex].style.height = height
});
moveableInstance.value.on('dragEnd', ({ target, clientX, clientY }) => {
startPosition = {
left:0,
top:0,
}
upDataDetail()
});
moveableInstance.value.on('scaleEnd', () => {
upDataDetail()
});
moveableInstance.value.on('rotateEnd', () => {
upDataDetail()
});
};
watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{
if(!newValue && newValue?.id == oldValue?.id)return
selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
initMoveableForSelected()
},{immediate: true,})
const setRevocation = ()=>{
if(!isMove)return
isMove = false
let frontBack = JSON.parse(JSON.stringify(detailData.frontBack))
console.log(frontBack)
let revocation:any = JSON.parse((sessionStorage.getItem("revocation") as any))
revocation.push({designData:null,position:frontBack})
sessionStorage.setItem('revocation', JSON.stringify(revocation));
}
const sizeMouseMoveOperation = (e:any)=> {
isMove = true
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
let parentNode =selectItem.imgDom.parentNode
let width = imgDomWH.width
let height = imgDomWH.height
let w,h
let num = height/width
//判断移动四个边
if(selectItem.direction == 'right'){
w = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)
h = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)*num
width = w+'px'
// height = w*num+'px'
}else if(selectItem.direction == 'top'){
num = width/height
detailData.frontBack.front[selectItem.imgDomIndex].style.top = 'auto'
// this.printStyleList[selectItem.imgDomIndex].style.left = 'auto'
detailData.frontBack.front[selectItem.imgDomIndex].style.bottom = parentNode.offsetHeight -imgDomWH.height - selectItem.imgDom.offsetTop+'px'
w = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)*num
h = (detailData.frontBack.front[selectItem.imgDomIndex].centers.top - e.clientY)
height = h+'px'
// width = h*num+'px'
}else if(selectItem.direction == 'bottom'){
num = width/height
h = (e.clientY - detailData.frontBack.front[selectItem.imgDomIndex].centers.top)
height = h+'px'
// width = h*num+'px'
}else if(selectItem.direction == 'left'){
detailData.frontBack.front[selectItem.imgDomIndex].style.left = 'auto'
detailData.frontBack.front[selectItem.imgDomIndex].style.right = parentNode.offsetWidth -imgDomWH.width - selectItem.imgDom.offsetLeft+'px'
w = (detailData.frontBack.front[selectItem.imgDomIndex].centers.left - e.clientX)
width = w+'px'
// height = w*num+'px'
}
//判断尺寸是否到边
detailData.frontBack.front[selectItem.imgDomIndex].style.width = width
detailData.frontBack.front[selectItem.imgDomIndex].style.height = height
}
// 设置移动
const mouseMove = (event:any)=>{
let e = getMousePosition(event,false)
mouseMoveOperation(e)
}
const touchmove=(event:any)=>{
let e = getMousePosition(event,true)
mouseMoveOperation(e)
}
const mouseup = (e:any)=> {
document.removeEventListener('mousemove',mouseMove)
document.removeEventListener('touchmove',touchmove)
document.removeEventListener('mouseup',mouseup)
document.removeEventListener('touchend',mouseup)
///鼠标抬起
const upDataDetail = async ()=>{
//同步到selectDetail数据中
// getDetailListData.designDetail
let {scale,offset,priority,transpose,rotate,position,imageSize} = await getSubmitData(selectItem.selectDetail,false)
selectItem.selectDetail.layersObject[0].scale = scale
selectItem.selectDetail.layersObject[1].scale = scale
selectItem.selectDetail.layersObject[0].offset = offset
selectItem.selectDetail.layersObject[1].offset = offset
selectItem.selectDetail.layersObject[0].priority = priority
selectItem.selectDetail.layersObject[1].priority = priority
selectItem.selectDetail.layersObject[0].rotate = rotate
selectItem.selectDetail.layersObject[1].rotate = rotate
selectItem.selectDetail.layersObject[0].transpose = transpose
selectItem.selectDetail.layersObject[1].transpose = transpose
selectItem.selectDetail.layersObject[0].position = position
selectItem.selectDetail.layersObject[1].position = position
selectItem.selectDetail.layersObject[0].imageSize = imageSize
selectItem.selectDetail.layersObject[1].imageSize = imageSize
setRevocation()
}
const mouseMoveOperation = (e:any)=>{
isMove = true
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
let x = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)+'px'
let y = ( e.clientY - detailData.frontBack.front[selectItem.imgDomIndex].centers.top)+'px'
detailData.frontBack.front[selectItem.imgDomIndex].style.left = x
detailData.frontBack.front[selectItem.imgDomIndex].style.top = y
}
const clothesOpenActive = (index:number)=>{
// this.designItemDetail.clothes.forEach((item)=>{
// item.clothesOpenItem = false
// })
// if(index != -1){
// this.designItemDetail.clothes[index].clothesOpenItem = true
// }
}
const itemMoveMousedown = async (index:any,e:any)=>{
if(detailData.selectDetail.id != detailData.frontBack.front[index].id)return
let isModal = false
await new Promise((resolve, reject) => {
// if(
// detailData.isEditPattern.value &&
// selectItem.selectDetail?.id &&
// (detailData.frontBack.front[index].id != selectItem.selectDetail.id)
// ){
// isModal = true
// Modal.confirm({
// title: t('collectionModal.jsContent2'),
// icon: createVNode(ExclamationCircleOutlined),
// okText: 'Yes',
// cancelText: 'No',
// mask:false,
// centered:true,
// onOk() {
// resolve(true)
// isOpen = true
// },
// onCancel(){
// resolve(false)
// isOpen = false
// }
// });
// }else{
// if(detailData.frontBack.front[index].id != selectItem.selectDetail.id){
// isOpen = true
// }
// resolve(true)
// isModal = false
// }
resolve(true)
}).then((rv)=>{
})
// emit('canvasReload')
// store.commit('DesignDetail/setDesignColthes',detailData.frontBack.front[index].id)
if(isModal)return
store.commit('DesignDetail/setDesignColthes',detailData.frontBack.front[index].id)
selectItem.imgDomIndex = index
detailData.frontBack.front.forEach((v:any)=>{
v.designOpenrtionBtn = false
})
clothesOpenActive(index)
let event = e||window.event
selectItem.imgDom = document.getElementsByClassName('molepositon')[0].getElementsByClassName("detail_modal_item_front")[selectItem.imgDomIndex]
detailData.frontBack.front[index].designOpenrtionBtn = true
// detailData.frontBack.front[index].style.zIndex = selectItem.printZIndex++
// detailData.frontBack.back[index].style.zIndex = selectItem.printZIndex
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
let left = Number(detailData.frontBack.front[index].style.left.replace(/px/g,''))
let top = Number(detailData.frontBack.front[index].style.top.replace(/px/g,''))
detailData.frontBack.front[index].centers.left = imgDomWH.x+event.offsetX-left
detailData.frontBack.front[index].centers.top = imgDomWH.y+event.offsetY-top
document.addEventListener('mousemove', mouseMove);
document.addEventListener('touchmove', touchmove);
document.addEventListener('mouseup', mouseup);
document.addEventListener('touchend', mouseup);
}
const sort = (arr:any)=>{
arr.sort((a:any, b:any) => {
var a_num = a.style.zIndex;
@@ -355,7 +428,7 @@ export default defineComponent({
});
return arr
}
const getSubmitData = (value:any,isNoComputed)=>{
const getSubmitData = async (value:any,isNoComputed)=>{
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
if(!detailData.frontBack?.body?.layersObject?.[0]?.imageSize || isNoComputed){
return{
@@ -365,6 +438,17 @@ export default defineComponent({
}
}
let ratio = detailData.frontBack.body.layersObject[0].imageSize[0]/parentNode.width
let scale = 0
let dom:any = document.querySelector('.molepositon .perview_img')
const img = new Image();
img.src = detailData.frontBack?.body?.path;
await new Promise<void>((resolve, reject) => {
img.onload = () => {
scale = dom.parentNode.offsetWidth / img.width
resolve()
};
})
// let arr:any = sort(detailData.frontBack.front)
let arr:any = sort(JSON.parse(JSON.stringify(detailData.frontBack.front)))
let num = 10
@@ -377,6 +461,8 @@ export default defineComponent({
priority:'',
maskUrl:'',
maskMinioUrl:'',
position:null,
imageSize:null,
}
let state = false
for (let index = 0; index < arr.length; index++) {
@@ -384,13 +470,27 @@ export default defineComponent({
state = true
let y = ((arr[index]?.style?.top.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[0])
let x = ((arr[index]?.style?.left.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[1])
let positionX = Number((arr[index]?.style?.left.replace(/px/g,'')/scale)).toFixed(2)
let positionY = Number((arr[index]?.style?.top.replace(/px/g,'')/scale)).toFixed(2)
let imageSizeW = Number((arr[index]?.style?.width.replace(/px/g,'')/scale)).toFixed(2)
let imageSizeH = Number((arr[index]?.style?.height.replace(/px/g,'')/scale)).toFixed(2)
let scaleWidth = arr[index]?.imageSize?Number(((arr[index]?.style?.width.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[0]/arr[index].scale[0])).toFixed(2)):1
let scaleHeight = arr[index]?.imageSize?Number(((arr[index]?.style?.height.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[1]/arr[index].scale[1])).toFixed(2)):1
// let widthScale = (arr[index].style.width.replace(/px/g,'')/arr[index].style.height.replace(/px/g,'')).toFixed(2)
let transformStr = arr[index]?.style?.transform
let scaleX = transformStr.match(/scaleX\(([-\d.]+)\)/)
let scaleY = transformStr.match(/scaleY\(([-\d.]+)\)/)
let rotate = transformStr.match(/rotate\(([-\d.]+)deg\)/);
data.transpose = [parseFloat(scaleX?.[1] || 1),parseFloat(scaleY?.[1] || 1)]
data.rotate = parseFloat(rotate?.[1] || 0)
data.scale = [scaleWidth,scaleHeight]
let top = y == 0 ? value.layersObject[0].offset[1]:y+value.layersObject[0].offset[1]
let left = x == 0 ? value.layersObject[0].offset[0]:x+value.layersObject[0].offset[0]
data.offset = [left?left:0,top?top:0]
data.position = [positionY,positionX]
data.imageSize = [imageSizeW,imageSizeH]
// data.offset = [left?left:0,top?top:0]
data.maskUrl = arr[index].maskUrl
data.maskMinioUrl = arr[index].maskMinioUrl
@@ -410,15 +510,6 @@ export default defineComponent({
}
const deleteNav = ()=>{
}
const setpitch = (item:any,index:any)=>{
detailData.frontBack.front.forEach((v:any)=>{
v.designOpenrtionBtn = false
})
detailData.frontBack.front[index].designOpenrtionBtn = true
// detailData.frontBack.front[index].style.zIndex = selectItem.printZIndex++
// detailData.frontBack.back[index].style.zIndex = selectItem.printZIndex
clothesOpenActive(index)
}
const updataPosition = ()=>{
let url = detailData.frontBack?.body?.path
@@ -431,10 +522,12 @@ export default defineComponent({
detailData.frontBack.front.forEach((item:any,index:number) => {
for (const key in item.style) {
if(key == 'zIndex')return
if(key == 'transform')return
item.style[key] = item.style[key]*sacle+'px'
}
for (const key in detailData.frontBack.back[index].style) {
if(key == 'zIndex')return
if(key == 'transform')return
detailData.frontBack.back[index].style[key] = detailData.frontBack.back[index].style[key]*sacle+'px'
}
});
@@ -445,20 +538,22 @@ export default defineComponent({
if (detailData.observer) {
detailData.observer.disconnect()
}
if (moveableInstance.value) {
moveableInstance.value.destroy();
}
})
return{
...toRefs(detailData),
...toRefs(selectItem),
...toRefs(getDetailListDom),
setElementRef,
setPrintSize,
itemSizeMousedown,
itemMoveMousedown,
deleteNav,
setpitch,
getSubmitData,
getMousePosition,
updataPosition,
updateRect,
}
},
@@ -541,6 +636,11 @@ export default defineComponent({
}
}
}
.moveableContainer{
:deep(.moveable-origin){
opacity: 0;
}
}
> .designOpenrtion_imgMask{
width: auto;
height: auto;
@@ -561,10 +661,15 @@ export default defineComponent({
position: absolute;
top: 0;
}
.detail_modal_item_front,.designOpenrtion_print{
z-index: 2;
height: 100%;
width: 100%;
pointer-events: none;
&.active{
pointer-events: auto;
}
img{
width: 100%;
// height: ;
@@ -583,94 +688,6 @@ export default defineComponent({
.designOpenrtion_print{
z-index: 1 !important;
}
> .designOpenrtion_btnBox{
z-index: 99;
width: 100%;
height: 100%;
left: 0;
ul{
list-style: none;
// width: 100%;
// height: 100%;
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
border: 2px solid rgb(20, 188, 255);
padding: 0;
-webkit-user-drag: none;
user-select:none;
opacity: 0;
margin: 0;
li{
cursor: pointer;
// border-radius: 50%;
width: calc(2rem*1.2);
height: calc(2rem*1.2);
background-color: rgb(20, 188, 255);
position: absolute;
pointer-events: none;
}
&.active{
opacity: 1;
z-index: 999 !important;
li{
pointer-events: auto;
}
}
.designOpenrtion_btn_top,.designOpenrtion_btn_bottom{
left: 50%;
transform: translate(-50%,-50%) ;
cursor: n-resize;
}
.designOpenrtion_btn_top{
top: 0;
}
.designOpenrtion_btn_bottom{
top: 100%;
}
.designOpenrtion_btn_left,.designOpenrtion_btn_right{
top: 50%;
transform: translate(-50%,-50%) ;
cursor: e-resize;
}
.designOpenrtion_btn_left{
left: 0;
}
.designOpenrtion_btn_right{
left: 100%;
}
.designOpenrtion_rotote{
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 0;
height: 0;
}
.designOpenrtion_rotote::after{
position: absolute;
content: "";
background-color: #14bcff;
width: 2px;
height: 30px;
left: 50%;
bottom: 0;
transform: translateX(-50%);
}
.designOpenrtion_rotote::before{
position: absolute;
content: "";
background-color: #14bcff;
top: calc(50% - 30px);
left: 50%;
transform: translate(-50%,-50%) ;
width: calc(1.5rem*1.2);
height: calc(1.5rem*1.2);
border-radius: 50%;
}
}
}
}
}
</style>

View File

@@ -132,7 +132,25 @@ export default defineComponent({
url:rv.url,
designType:props.item.resData.designType || props.item.designType,
}
props.list.unshift(rv)
rv.type_ = {
type1: "material",
type2: props.level1Type
}
if(props.level1Type == 'Printboard'){
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
list.unshift(rv)
store.commit("setPrintboardMaterialFiles", list);
}else if(props.level1Type == 'Sketchboard'){
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
list.unshift(rv)
store.commit("setSketchboardMaterialFiles", list);
}else if(props.level1Type == 'Moodleboard'){
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
list.unshift(rv)
store.commit("setMoodleboardMaterialFiles", list);
}else{
props.list.unshift(rv)
}
}
}
).catch(res=>{

View File

@@ -9,7 +9,7 @@
:isBackgroundChangeable="false"
ref="editCanvas"></editCanvas>
</div>
<div class="btn">
<div class="btn" v-if="btnShow">
<div class="gallery_btn" @click="canvasSave" style="width: min-content;margin-top: auto;">{{ $t('exportModel.Save') }}</div>
<div class="gallery_btn" @click="exportElement">{{ $t('exportModel.Export') }}</div>
</div>
@@ -46,7 +46,11 @@ export default defineComponent({
isSubmitCanvasJSON:{
type:Boolean,
default:false
}
},
btnShow:{
type:Boolean,
default:true
},
},
emits:['submitBase64Data','canvasChangeGetJSON'],
setup(props,{emit}) {
@@ -99,6 +103,9 @@ export default defineComponent({
}
}
const submitBase64Data = (base64Data)=>{
return dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:true,isCropByBg:true})
}
const exportElement = ()=>{
dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:false,isCropByBg:true}).then((rv)=>{
downloadBase64Image(rv,'canvas')
@@ -174,6 +181,7 @@ export default defineComponent({
canvasInit,
exportElement,
changeCanvas,
submitBase64Data,
};
},
data(prop) {

View File

@@ -418,6 +418,14 @@ const routes: Array<RouteRecordRaw> = [
},
component: () => import("@/views/userManual.vue"),
},
{
path: "/award",
name: "award",
meta: {
enter: "all",
},
component: () => import("@/views/AwardPage/index.vue"),
},
{
path: "/:catchAll(.*)",
redirect: "/404",

View File

@@ -1,6 +1,7 @@
import {Module} from 'vuex'
import {RootState} from '../index'
import { forEach } from 'jszip'
import { transform } from 'typescript'
interface DesignDetail{
designDetail:any,
@@ -59,6 +60,7 @@ const DesignDetail : Module<DesignDetail,RootState> = {
left:v.layersObject[i].position?.[1],
width:v.layersObject[i].imageSize?.[0],
height:v.layersObject[i].imageSize?.[1],
transform:`rotate(${v.layersObject[i]?.rotate || 0}deg) scaleX(${v.layersObject[i].transpose?.[0] || 1}) scaleY(${v.layersObject[i].transpose?.[1] || 1})`,
}
v.layersObject[i].centers={
left:0,
@@ -69,7 +71,7 @@ const DesignDetail : Module<DesignDetail,RootState> = {
v.layersObject[i].designOpenrtionBtn = false
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
front[index] = v.layersObject[i]
// front[index].style.zIndex = v.priority
front[index].style.zIndex = v.priority + 10
front[index].id = v.id
front[index].undividedLayer = v.undividedLayer
front[index].undividedLayerWithSinglePrint = v?.undividedLayerWithSinglePrint
@@ -199,6 +201,9 @@ const DesignDetail : Module<DesignDetail,RootState> = {
trims:null,
type:null,
undividedLayer:null,
undividedLayer_:null,
transpose:[1,1],
rotate:0,
undividedLayerWithSinglePrint:null,
}
if(!state.currentDetailType)state.currentDetailType = 'sketch'
@@ -209,6 +214,28 @@ const DesignDetail : Module<DesignDetail,RootState> = {
});
state.selectDetail = data
},
canvasPreviewUpdata(state,{type,callBack}){
console.log(state.selectDetail,type)
// state.selectDetail.newDetail?.print?.forEach((item:any) => {
// state.selectDetail.printObject.prints = []
// state.selectDetail.printObject.push({
// })
// });
if(type == 'print' || type == 'all')state.selectDetail.printObject.prints = state.selectDetail.newDetail?.print
if(type == 'color' || type == 'all')state.selectDetail.color = {
...state.selectDetail.newDetail?.color,
...state.selectDetail.newDetail?.color?.rgba,
...state.selectDetail.newDetail?.color?.hsv,
}
console.log(state.selectDetail,type,state.selectDetail.newDetail)
if(type == 'element' || type == 'all')state.selectDetail.trims.prints = state.selectDetail.newDetail?.element
if(type == 'all'){
state.selectDetail.newDetail = {}
}else{
state.selectDetail.newDetail[type] = null
}
callBack()
},
async setPraeview(state,value){//preview
let data = value?.rv || value
let currentType = value?.currentType
@@ -228,7 +255,6 @@ const DesignDetail : Module<DesignDetail,RootState> = {
}else{
id_ = item.id
}
console.log(id_)
let el:any = document.querySelector('.molepositon .perview_img')
await new Promise((resolve, reject) => {
if(!state.frontBack?.body?.path){
@@ -252,7 +278,8 @@ const DesignDetail : Module<DesignDetail,RootState> = {
left:item.layersObject[i].position?.[1] * scale + 'px',
width:item.layersObject[i].imageSize?.[0] * scale + 'px',
height:item.layersObject[i].imageSize?.[1] * scale + 'px',
zIndex:v?.style?.zIndex?v.style.zIndex:v.priority?v.priority:state.frontBack.front.length
zIndex:v?.style?.zIndex?v.style.zIndex:v.priority?v.priority:state.frontBack.front.length,
transform:`rotate(${item.layersObject?.[i]?.rotate || 0}deg) scaleX(${item.layersObject[i].transpose?.[0] || 1}) scaleY(${item.layersObject[i].transpose?.[1] || 1})`,
}
item.layersObject[i].centers={
left:0,
@@ -293,6 +320,8 @@ const DesignDetail : Module<DesignDetail,RootState> = {
detailItem.minIOPath = item.minIOPath
detailItem.scale = [1,1]
detailItem.offset = [0,0]
detailItem.transpose = item.transpose || [1,1]
detailItem.rotate = item.rotate || 0
detailItem.printObject = item.printObject
detailItem.trims = item.trims
detailItem.type = item.type

View File

@@ -618,6 +618,60 @@ function segmentImage(markerImage,fullImage,size){
}
})
}
/**
* 处理PNG图片透明度转白色其他颜色转透明
* @param {string} sketchImage - 原始图片
* @returns {Promise} 处理后的ase64
*/
function sketchToMask(sketchImage) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function() {
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const a = data[i + 3];
if (a > 0) {
data[i] = 0;
data[i + 1] = 0;
data[i + 2] = 0;
data[i + 3] = 0;
} else {
// 完全透明的像素 -> 纯白色
data[i] = 255;
data[i + 1] = 255;
data[i + 2] = 255;
data[i + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
const base64 = canvas.toDataURL('image/png');
resolve(base64);
} catch (error) {
reject(error);
}
};
img.onerror = function() {
reject(new Error('图片加载失败'));
};
img.src = sketchImage;
});
}
export {
isEmail,
getUploadUrl,
@@ -640,5 +694,6 @@ export {
setGradual,
calculateGradientCoordinate,
segmentImage,
UrlToFile
UrlToFile,
sketchToMask
}

View File

@@ -0,0 +1,251 @@
<template>
<div class="award-page">
<div class="header flex align-center space-between">
<div class="header-left">
<img src="@/assets/images/award/code_create_logo.png" class="logo" />
</div>
<div class="header-right flex align-center">
<div class="text">Submit your Application</div>
<img src="@/assets/images/award/arrow.png" alt="" class="arrow" />
</div>
</div>
<div class="banner"></div>
<div class="blocks-list flex">
<div
class="block-item flex flex-col flex-center"
v-for="item in blocksList"
:key="item.number"
>
<div class="number">{{ item.number }}</div>
<div class="label">{{ item.label }}</div>
<div class="line"></div>
</div>
<div class="block-item flex flex-col flex-center">
<div class="number">
<img src="@/assets/images/award/∞.png" alt="" class="infinity" />
</div>
<div class="label">Possibilites</div>
</div>
</div>
<div class="bloom flex flex-col align-center">
<div class="title">Bloom Your Creativity</div>
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<div class="season">Theme of 2026</div>
<div class="desc">
Where imagination meets innovation, creativity blooms. This theme celebrates AI as
a catalyst for fashion design, allowing your vision to flourish beyond traditional
boundaries. Let your ideas blossom into extraordinary designs that merge human
artistry with artificial intelligence.
</div>
</div>
<div class="design-container">
<div class="design-title limit">Design Without Borders</div>
<div class="limit">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
</div>
<div class="global limit">Global Opportunity</div>
<div class="desc">
Open to visionary designers across the globe. From Seoul to Singapore, New York to
Shanghai, we're seeking the next generation of fashion innovators who dare to
reimagine the future of design.
</div>
</div>
<div class="timeline-container flex flex-col align-center">
<!-- <img src="@/assets/images/award/timeline_line.png" class="timeline" /> -->
<div class="timeline-title">Competition Timeline</div>
<img src="@/assets/images/award/bloom_logo.png" alt="" class="logo" />
<div class="desc">Shaping the Future</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const blocksList = ref([
{
number: '100',
label: 'Semi-finalists'
},
{
number: '20',
label: 'Finalists'
},
{
number: '3',
label: 'Winners'
}
])
</script>
<style lang="less" scoped>
.award-page {
overflow: auto;
height: 100vh;
}
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.flex-center {
justify-content: center;
align-items: center;
}
.align-center {
align-items: center;
}
.space-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.header {
height: 8rem;
background-color: #232323;
padding-left: 21.5rem;
padding-right: 8.6rem;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
}
.header-right {
column-gap: 1rem;
.text {
font-size: 1.6rem;
color: #fff;
}
.arrow {
width: 2.4rem;
height: 2.4rem;
}
}
}
.logo {
width: 2.4rem;
height: 2.4rem;
}
.banner {
height: 100rem;
background-color: violet;
}
.blocks-list {
height: 31.4rem;
background: linear-gradient(98.55deg, #232323 18.22%, #898989 101.1%);
.block-item {
flex: 1;
height: 100%;
color: #fff;
position: relative;
.number {
font-size: 6rem;
font-family: 'Poppins';
}
.label {
font-size: 2.8rem;
font-family: 'Arial';
letter-spacing: 0.05em;
}
.line {
position: absolute;
bottom: 50%;
right: 0;
transform: translate(0, 50%);
width: 0.1rem;
height: 27.4rem;
background-color: #8d8d8d;
}
}
}
.bloom {
height: 97rem;
padding-top: 12.8rem;
font-family: 'Poppins';
background: url('@/assets/images/award/bloom_bg.png') no-repeat;
background-size: 100% 100%;
.title {
font-size: 4rem;
color: #232323;
margin-bottom: 2.4rem;
}
.logo {
margin-bottom: 2.2rem;
}
.season {
font-size: 3rem;
color: #c7342c;
margin-bottom: 6.6rem;
}
.desc {
font-family: 'Arial';
font-size: 2.8rem;
color: #585858;
text-align: center;
padding: 0 21.5rem;
line-height: 4.5rem;
margin-bottom: 12.3rem;
}
}
.design-container {
height: 97rem;
background: url('@/assets/images/award/design_bg.png') no-repeat;
background-size: 100% 100%;
padding-left: 21.5rem;
padding-top: 16rem;
.limit {
width: 48.4rem;
text-align: center;
}
.design-title {
color: #fff;
font-size: 4rem;
font-weight: 600;
font-family: 'Poppins';
font-style: SemiBold;
vertical-align: middle;
text-transform: capitalize;
}
.logo {
margin-top: 2.4rem;
margin-bottom: 2.1rem;
}
.global {
font-family: 'Poppins';
font-size: 3rem;
color: #f95750;
margin-bottom: 19.8rem;
}
.desc {
font-family: 'Arial';
font-weight: 400;
font-size: 2.8rem;
color: #e0e0e0;
width: 54rem;
}
}
.timeline-container {
height: 97rem;
background: url('@/assets/images/award/timeline_bg.png') no-repeat;
background-size: 100% 100%;
position: relative;
padding-top: 12.8rem;
// .timeline {
// width: 148.7rem;
// height: 27.58rem;
// }
.logo {
margin: 2.4rem 0 2.2rem 0;
}
.desc {
font-family: 'Arial';
font-size: 3rem;
font-weight: 400;
color: #b10000;
}
}
</style>