first commit

This commit is contained in:
LiaoFJ
2023-01-06 16:00:15 +08:00
parent d196571ac8
commit e54be8d510
66 changed files with 36155 additions and 0 deletions

View File

@@ -0,0 +1,344 @@
<template>
<a-modal class="accessory_replace_modal"
v-model:visible="accessoryReplaceShow"
:footer="null"
width="40rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="accessory_replace_content">
<div class="new_accessory_block">
<div class="new_accessory_title">New {{othersData?.type}}</div>
<div class="new_accessory_img_block">
<img class="element_img" :src="othersData?.path">
<div class="element_img_loading" v-show="loadingShow">
<a-spin :indicator="indicator"/>
</div>
</div>
<div class="new_accessory_operate_list">
<div class="new_accessory_operate_button pervious_button" @click="changeElement('PREV')">Previous</div>
<div class="new_accessory_operate_button fetch_button" @click="changeElement('NEXT')">Re-fetch</div>
</div>
</div>
<div class="accessory_color_block" v-show="othersData?.type !== 'Earring' && othersData?.type !== 'Hairstyle'">
<div class="accessory_color_block_header">Modify Color</div>
<div class="accessory_color_block_body">
<div class="review_color_block" :style="{background:`rgb(${modifyColor.r},${modifyColor.g},${modifyColor.b})`}"></div>
<div class="setting_color_block">
<div class="setting_color_content">
<Chrome class="chrome_color" v-model="selectColor"></Chrome>
<Slider class="sileder_color" v-model="selectColor"></Slider>
</div>
<div class="color_rgb_block">
<div class="rgb_item">R:{{getSelectRGB(selectColor).r}}</div>
<div class="rgb_item">G:{{getSelectRGB(selectColor).g}}</div>
<div class="rgb_item">B:{{getSelectRGB(selectColor).b}}</div>
</div>
</div>
</div>
</div>
<div class="submit_button" @click="submitOthers()">Submit</div>
</div>
</a-modal>
</template>
<script lang="ts">
import { defineComponent,ref,h} from 'vue'
import { Chrome,Slider } from '@ans1998/vue3-color'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { LoadingOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components:{Chrome,Slider},
setup(){
let selectColor:any = ref({rgba:{}}) //顔色选择器默认颜色
let othersData:any = ref({})
const store = useStore();
return {
selectColor,
othersData,
store
}
},
data(){
return{
loadingShow:false,
accessoryReplaceShow:false,
modifyColor:{r:255,g:255,b:255},
othersIndex:0, //该元素在列表中的索引
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
}
},
watch:{
selectColor(newVal:any,oldVal:any){
this.modifyColor = newVal.rgba || {}
}
},
computed:{
getSelectRGB(selectColor){
return (selectColor:any)=>{
let rgba = selectColor.rgba
let data = {
r:rgba?.r || 255,
g:rgba?.g || 255,
b:rgba?.b || 255
}
return data
}
},
},
methods:{
showAccessoryReplaceModal(data:any){
this.othersData = JSON.parse(JSON.stringify(data.others))
this.othersIndex = data.index
this.accessoryReplaceShow = true
let color = this.othersData.color ? this.othersData.color.split(' ') :''
this.selectColor = {rgba:{r:color[0],g:color[1],b:color[2]}}
},
//关闭弹窗
closeModal(){
this.accessoryReplaceShow = false
this.othersData = {}
this.othersIndex = 0
},
//切换元素
changeElement(type:string){
let url = Https.httpUrls.getNextSysElement + `?id=${this.othersData.id}&operateType=${type}&type=${this.othersData.type}`
this.loadingShow = true
Https.axiosGet(url).then(
(rv: any) => {
this.othersData.id = rv.id
this.othersData.path = rv.path
this.loadingShow = false
}
).catch(rv=>{
this.loadingShow = false
})
},
//提交
submitOthers(){
this.othersData.color = this.othersData.color ? `${this.modifyColor.r} ${this.modifyColor.g} ${this.modifyColor.b}` : ''
let data = {
others:this.othersData,
index:this.othersIndex
}
this.store.commit('setDesignItemOthers',data)
this.closeModal()
}
}
})
</script>
<style lang="less">
.accessory_replace_modal{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
padding: 2rem 1.8rem 3rem;
box-sizing: border-box;
background: #F2F3FB;
overflow-y: hidden;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.accessory_replace_content{
.new_accessory_block{
padding: 2rem 2rem 1.2rem;
background: #ffffff;
width: 100%;
.new_accessory_title{
font-size: 1.6rem;
line-height: 1.6rem;
color: #030303;
margin-bottom: 1.3rem;
}
.new_accessory_img_block{
width: 20rem;
height: 16rem;
background: #FFFFFF;
border: 0.1rem solid #F5F5F5;
display: flex;
justify-content: center;
align-items: center;
margin:0 auto 1.7rem;
position: relative;
.element_img{
max-width: 100%;
max-height: 100%;
}
.element_img_loading{
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
position: absolute;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
}
}
.new_accessory_operate_list{
display: flex;
justify-content: center;
.new_accessory_operate_button{
padding: 0 1.5rem;
height: 3.2rem;
text-align: center;
line-height: 3.2rem;
font-size: 1.2rem;
cursor: pointer;
}
.pervious_button{
background: #343579;
color: #ffffff;
margin-right: 2rem;
}
.fetch_button{
background: #E6E6F6;
color: #343579;
}
}
}
.accessory_color_block{
width: 100%;
background: #FFFFFF;
padding: 0 2rem;
margin: 1.3rem 0 1.8rem;
.accessory_color_block_header{
display: flex;
justify-content: space-between;
align-items: center;
height: 3.7rem;
font-size: 1.6rem;
color: #030303;
}
.accessory_color_block_body{
padding:0 1.5rem 1.5rem;
display: flex;
justify-content: space-between;
.review_color_block{
width: 11.5rem;
height: 11.5rem;
border: 0.1rem solid #343579;
}
.setting_color_block{
.setting_color_content{
.vc-chrome-body{
display: none;
}
.chrome_color{
width: 11.5rem;
height: 11.5rem;
overflow: hidden;
.vc-chrome-saturation-wrap{
height: 100%;
}
.vc-chrome-saturation-wrap .vc-saturation-circle{
width: 1rem;
height: 1rem;
}
}
.sileder_color{
width: 1.6rem;
.vc-slider-swatches{
display:none
}
.vc-slider-hue-warp {
width: 11.5rem;
height: 1.6rem;
border-radius: 0.8rem;
overflow: hidden;
.vc-hue-picker{
width: 1.2rem;
height: 1.2rem;
border-radius: 50%;
transform: translate(-0.6rem, -0.4rem);
}
}
.vc-hue-pointer{
top: 0.5rem !important;
}
}
}
.color_rgb_block{
margin-top: 0.5rem;
display: flex;
justify-content: space-between;
font-size: 1.4rem;
color: #343579;
}
}
}
}
.submit_button{
width: 9.8rem;
height: 3.6rem;
text-align: center;
background: #343579;
font-size: 1.4rem;
line-height: 3.6rem;
color: #FFFFFF;
margin: 1.8rem auto 0;
cursor: pointer;
}
}
}
</style>

View File

@@ -0,0 +1,529 @@
<template>
<div>
<a-modal class="design_detail_modal_component"
v-model:visible="designDetailShow"
:footer="null"
title="Mailbox binding"
width="80%"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="turn_button turn_left_button" v-show="designShowPrview == 1" @click="changeDesignItem('last')"><span class="icon iconfont icon_turn icon-shangyibu"></span></div>
<div class="turn_button turn_right_button" v-show="designShowPrview == 1" @click="changeDesignItem('next')"><span class="icon iconfont icon_turn icon-xiayibu"></span></div>
<div class="design_detail_modal_body" v-show="designShowPrview == 1">
<div class="detail_modal_body_left" @click="showDesignImgDetail()">
<img class="detial_img" :src="designItemDetail.designItemUrl">
</div>
<div class="detail_modal_body_right">
<div class="detail_modal_right_top scroll_style">
<div class="clothes_detail_item">
<div class="clothes_item_header"><span class="icon iconfont icon-dangqianweizhi"></span>Apparel</div>
<div class="clothes_item_content">
<Draggable :list="designItemDetail.clothes" item-key="id" :animation="100">
<template #item="{ element,index }">
<div class="clothes_item_img_block" @click="clothesDetail(element,index)">
<img class="clothes_item_img" :src="element.path">
</div>
</template>
</Draggable>
</div>
</div>
<div class="clothes_detail_item" v-show="designItemDetail.others && designItemDetail.others.length">
<div class="clothes_item_header"><span class="icon iconfont icon-dangqianweizhi"></span>Others</div>
<div class="clothes_item_content others_clothes_item_content">
<div class="clothes_item_img_block" v-for="(element,index) in designItemDetail.others" :key="element.path" @click="othersDetail(element,index)">
<img class="clothes_item_img" :src="element.path">
</div>
</div>
</div>
</div>
<div class="detail_modal_right_bottom">
<div class="detail_page_num">{{parentData.index + 1}}/{{parentData.collectionList.length}}</div>
<div class="detail_redesign_button" @click="redesignItem()">Redesign</div>
</div>
</div>
</div>
<div class="design_detail_perview" v-show="designShowPrview == 2">
<div class="design_detail_perview_content" >
<img class="perview_img" v-lazy="designItemDetail.designItemUrl || ''" :key="designItemDetail.designItemUrl">
<!-- <div class="generate_button" v-show="designItemDetail.singleOverall == 'overall'" @click="generateHighDesign()">Generate Product lmage</div> -->
</div>
</div>
<div class="design_detail_perview design_detail_perview_second" v-show="designShowPrview == 3">
<div class="design_detail_perview_content" >
<img class="perview_img" v-lazy="designItemDetail.designItemUrl || ''" :key="designItemDetail.designItemUrl">
</div>
<div class="design_detail_perview_content" >
<img class="perview_img" v-lazy="generateHighDesignImg || ''" :key="generateHighDesignImg">
<div class="img_item_hover">
<div class="img_operate_block delete_img_block" @click.stop="deleteGeneratePic()">
<span class="icon iconfont icon-shanchu operate_icon"></span>
</div>
</div>
</div>
</div>
</a-modal>
<ElementReplace ref="ElementReplace"></ElementReplace>
<AccessoryReplace ref="AccessoryReplace"></AccessoryReplace>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,computed,ref } from 'vue'
import ElementReplace from '@/component/Detail/ElementReplace.vue'
import AccessoryReplace from '@/component/Detail/AccessoryReplaceModal.vue'
import Draggable from 'vuedraggable'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
export default defineComponent({
components:{
ElementReplace,
AccessoryReplace,
Draggable,
},
setup() {
const store = useStore();
let designItemDetail :any = computed(()=>{return store.state.DesignDetailModule.designItemDetail})
let parentData:any = ref({
design:{},
index:0,
collectionList:[],
type:'',
})//父组件传过来的数据
return{
designItemDetail,
store,
parentData
}
},
data(){
return{
loadingShow:false,
designDetailShow:false,
designShowPrview:1, //展示图片预览步骤
generateHighDesignImg:'',//点击generate按钮生成的高级设计图
}
},
methods:{
closeModal(){
if(this.designShowPrview == 1){
this.designDetailShow = false
}else if(this.designShowPrview == 2){
this.designShowPrview = this.designShowPrview - 1
}else if(this.designShowPrview == 3){
this.designShowPrview = 1
}
},
showDesignDetailModal(data:any){
let url = Https.httpUrls.getDesignDetail + `?designItemId=${data.design.designItemId}`
this.parentData = data
this.loadingShow = true
Https.axiosGet(url).then(
(rv: any) => {
this.store.commit('setDesignItemDetail',rv)
this.generateHighDesignImg = rv.highDesignUrl
this.designShowPrview = 1
this.designDetailShow = true
this.loadingShow = false
}
).catch(rv=>{
this.loadingShow = false
})
},
//切换上一张或下一张图的详情
changeDesignItem(type:string){
let {design,index,collectionList} = this.parentData
let newDesign = {}
let newIndex = 0
if(type === 'last'){
if(index>0){
newIndex = this.parentData.index - 1
}else{
newIndex = this.parentData.collectionList.length - 1
}
}else{
if(index < this.parentData.collectionList.length - 1){
newIndex = this.parentData.index + 1
}else{
newIndex = 0
}
}
newDesign = collectionList[newIndex]
let data = {
design:newDesign,
index:newIndex,
collectionList:collectionList
}
this.showDesignDetailModal(data)
},
//显示图片详情
showDesignImgDetail(){
if(this.generateHighDesignImg){
this.designShowPrview = 3
}else{
this.designShowPrview = 2
}
},
//生成高级图片
generateHighDesign(){
let design:any = this.parentData.design
let data = {
designItemId: design.designItemId,
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.loadingShow = true
Https.axiosPost(Https.httpUrls.generateHighDesign,data).then(
(rv: any) => {
this.generateHighDesignImg = rv
this.loadingShow = false
this.designShowPrview = 3
}
).catch(rv=>{
this.loadingShow = false
})
},
//删除生成的真人图
deleteGeneratePic(){
let design:any = this.parentData.design
let data = {
designItemId: design.designItemId,
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.loadingShow = true
Https.axiosPost(Https.httpUrls.deleteHighDesign,data).then(
(rv: any) => {
this.loadingShow = false
this.generateHighDesignImg = ''
this.designShowPrview = 2
}
).catch(rv=>{
this.loadingShow = false
})
},
//元素替换
clothesDetail(clothes:any, index:number){
let elementReplace:any = this.$refs.ElementReplace
let data ={
clothes:clothes,
index:index,
}
elementReplace.showelementReplaceModal(data)
},
othersDetail(others:any, index:number){
let accessoryReplace:any = this.$refs.AccessoryReplace
let data ={
others:others,
index:index,
}
accessoryReplace.showAccessoryReplaceModal(data)
},
//重新设计
redesignItem(){
let designItemDetail = JSON.parse(JSON.stringify(this.store.state.DesignDetailModule.designItemDetail))
delete designItemDetail.designItemUrl
let priority = designItemDetail.clothes.map((v:any)=>{
return v.type
})
let data = {
...designItemDetail,
priority:priority,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.loadingShow = true
Https.axiosPost(Https.httpUrls.designSingle, data).then(
(rv: any) => {
this.parentData.design.designItemUrl = rv.designItemUrl
this.$emit('finishRedesign',this.parentData)
this.closeModal()
this.loadingShow = false
this.closeModal()
}
).catch(res=>{
this.loadingShow = false
});
}
}
})
</script>
<style lang="less">
.design_detail_modal_component{
color: #000;
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
height: 80vh;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.turn_button{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
position: absolute;
top: calc(50% - 1.8rem);
cursor: pointer;
line-height: 3.6rem;
text-align: center;
&.turn_left_button{
left: -8rem;
}
&.turn_right_button{
right: -8rem;
}
.icon_turn{
font-size: 2.4rem;
color: #ffffff;
}
}
.design_detail_modal_body{
display: flex;
justify-content: space-between;
width: 100%;
height: 100%;
padding: 1.5rem 1rem 2.5rem;
box-sizing: border-box;
.detail_modal_body_left{
width: 43.3rem;
height: 100%;
background: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
.detial_img{
max-width: 100%;
max-height: 100%;
}
}
.detail_modal_body_right{
width: calc(100% - 44rem);
height: 100%;
.detail_modal_right_top{
width: 100%;
height: calc(100% - 3.9rem);
background: #fff;
overflow-y: auto;
.clothes_detail_item{
padding-left: 1.5rem;
.clothes_item_header{
height: 6.4rem;
display: flex;
align-items: center;
font-size: 18px;
color: #000000;
.icon-dangqianweizhi{
font-size: 1.8rem;
color: #000000;
margin-right: 1rem;
}
}
.clothes_item_content{
padding:0 0.5rem 2.3rem;
border-bottom: 0.1rem solid #F2F3FB;
&.others_clothes_item_content{
border-bottom:none
}
.clothes_item_img_block{
width: 20.5rem;
height: 20.5rem;
border: 0.1rem solid #F5F5F5;
display: inline-block;
text-align: center;
line-height: 21.3rem;
margin-right: 1rem;
margin-bottom: 1rem;
.clothes_item_img{
max-width: 100%;
max-height: 100%;
}
}
}
}
}
.detail_modal_right_bottom{
position: relative;
.detail_page_num{
position: absolute;
top: 2rem;
left: 12.4rem;
font-size: 1.8rem;
font-family: Roboto;
font-weight: 400;
color: #000000;
}
.detail_redesign_button{
position: absolute;
top: 1.4rem;
right: 0;
padding: 0 1.8rem;
text-align: center;
height: 3.6rem;
line-height: 3.6rem;
background: #343579;
font-size: 14px;
font-family: Roboto;
color: #FFFFFF;
cursor: pointer;
}
}
}
}
.design_detail_perview{
width: 100%;
height: 100%;
padding: 0.7rem 0 0.6rem;
&.design_detail_perview_second{
width: 100%;
height: 100%;
padding: 0.7rem 9.1rem 0.6rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.design_detail_perview_content{
width: 46.2rem;
height: 100%;
background: #fff;
position: relative;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
.perview_img{
max-width: 100%;
max-height: 100%;
}
.generate_button{
position: absolute;
top: 0;
right: -20.2rem;
padding: 0 1.5rem;
text-align: center;
height: 3.6rem;
line-height: 3.6rem;
background: #343579;
font-size: 14px;
font-family: Roboto;
color: #FFFFFF;
cursor: pointer;
}
&:hover .img_item_hover{
display: block;
}
.img_item_hover{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top:0;
background: rgba(0,0,0,0.4);
display: none;
.img_operate_block{
width: 3.6rem;
height: 3.6rem;
background: rgba(0,0,0,0.6);
border-radius: 50%;
position: absolute;
right: 2.2rem;
text-align: center;
line-height: 3.6rem;
cursor: pointer;
&.delete_img_block{
top: 2rem;
}
.operate_icon{
font-size: 1.8rem;
color: #fff;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,900 @@
<template>
<div>
<a-modal class="element_replace_modal"
v-model:visible="elementReplaceShow"
:footer="null"
width="80%"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="element_replace_content">
<div class="element_replace_content_left">
<div class="content_left_block">
<div class="content_left_block_header">New {{swtich_type}}</div>
<div class="content_left_block_body">
<div class="content_body_img_block">
<img class="element_img" :src="clothesData?.path">
<div class="upload_block">
<a-upload
:action="uploadUrl + '/api/element/upload'"
:data="{
...upload,
level1Type:clothesData?.level1Type
}"
:headers="{Authorization:token}"
:before-upload="beforeUpload"
:maxCount="1"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file)=>fileUploadChange(file,'top')"
:showUploadList="false"
>
<div class="upload_icon_block">
<span class="icon iconfont icon-tianjiatupian_huaban"></span>
</div>
</a-upload>
</div>
<div class="operate_file_block">
<div class="select_category" @click.stop="showNewTopOperate()">
{{clothesData?.type}}
<div :class="['icon','iconfont', 'icon-xiala', newTopOperateShow?'icon_rotate':'']"></div>
</div>
<div class="category_list" v-show="newTopOperateShow">
<div :class="['category_item', clothesData?.type == cate.value?'select_category_item':'']" v-for="(cate,index) in sketchCatecoryList" :key="index" @click="selectNewTopOperate(cate)">{{cate.label}}</div>
</div>
</div>
</div>
</div>
</div>
<div class="content_left_block">
<div class="content_left_block_header">
<div>New Print</div>
<div class="placement_button" @click="placementClick()" v-show="clothesData?.printObject?.path && clothesData?.printObject?.path != 'none'">Placement</div>
</div>
<div class="content_left_block_body">
<div class="content_body_img_block">
<img class="element_img print_element_img" :src="clothesData?.printObject?.path" v-if="clothesData?.printObject?.path && clothesData?.printObject?.path != 'none'">
<img class="element_null_img" src="@/assets/images/homePage/null_img.png" v-else />
<div class="upload_block">
<a-upload
:action="uploadUrl + '/api/element/upload'"
:data="{
...upload,
level1Type:clothesData?.printObject?.level1Type || Printboard
}"
:headers="{Authorization:token}"
:before-upload="beforeUpload"
:maxCount="1"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file)=>fileUploadChange(file,'print')"
:showUploadList="false"
>
<div class="upload_icon_block">
<span class="icon iconfont icon-tianjiatupian_huaban"></span>
</div>
</a-upload>
</div>
<div class="delete_file_block" @click="deletePrintFile()">
<span class="icon iconfont icon-shanchu"></span>
</div>
</div>
</div>
</div>
<div class="content_left_block">
<div class="content_left_block_header content_color_block_header">Edit Color</div>
<div class="content_left_block_body content_color_block_body">
<div class="review_color_block" :style="{background:`rgb(${modifyColor.r},${modifyColor.g},${modifyColor.b})`}"></div>
<div class="setting_color_block">
<div class="setting_color_content">
<Chrome class="chrome_color" v-model="selectColor"></Chrome>
<Slider class="sileder_color" v-model="selectColor"></Slider>
</div>
<div class="color_rgb_block">
<div class="rgb_item">R:{{getSelectRGB(selectColor).r}}</div>
<div class="rgb_item">G:{{getSelectRGB(selectColor).g}}</div>
<div class="rgb_item">B:{{getSelectRGB(selectColor).b}}</div>
</div>
</div>
</div>
</div>
<div class="submit_button" @click="submitElement()">Submit</div>
</div>
<div class="element_replace_content_right">
<div class="content_right_header"><div class="content_right_header_content">Select from library</div></div>
<div class="content_right_search_block">
<input class="search_input" placeholder="Search by your style code" v-model="searchPictureName" @keydown.enter="getLibraryList()">
<div class="search_icon_block" @click="getLibraryList()"><span class="icon iconfont icon-sousuo"></span></div>
</div>
<div class="content_right_table_block">
<div class="table_block_header">
<div class="table_block_header_left">
<div v-show="['Outwear','Dress','Blouse'].indexOf(clothesData.type) > -1" @click="select_type('Top')" :class="['switch_type_item', swtich_type === 'Top' ? 'select_swtich' : '']">
<span>Top</span>
</div>
<div v-show="['Skirt','Trousers'].indexOf(clothesData.type) > -1" @click="select_type('Bottom')" :class="['switch_type_item', swtich_type === 'Bottom' ? 'select_swtich' : '']">
<span>Bottom</span>
</div>
<div @click="select_type('Print')" :class="['switch_type_item', swtich_type === 'Print' ? 'select_swtich' : '']">
<span>Print</span>
</div>
</div>
<div class="table_header_select_block select_block" v-show="swtich_type != 'Print'">
<a-select
ref="select"
placeholder="All"
v-model:value="designType"
:allowClear="true"
:options="disignTypeList"
@change="handleChange"
>
<template #suffixIcon
><span
class="icon iconfont icon-xiala"
style="color: #343579"
></span
></template>
</a-select>
</div>
</div>
<div class="table_img_list scroll_style">
<div class="table_img_item_block" v-for="img in imgList" :key="img" @click="selectImgItem(img)">
<div class="img_item_block">
<img :class="[swtich_type === 'Print'?'print_img_body':'img_item_body']" v-lazy="img.url" :key="img.url">
</div>
<div class="img_item_name">{{img.name}}</div>
</div>
<div class="no_data_block" v-show="!imgList.length && !isShowLoading">
<img src="@/assets/images/homePage/null_img.png">
</div>
<div class="no_data_block" v-show="isShowLoading">
<a-spin size="large"></a-spin>
</div>
</div>
<div class="table_pagination" v-show="imgList.length">
<a-pagination
v-model:current="currentPage"
v-model:pageSize="pageSize"
:total="total"
:showQuickJumper="true"
:showSizeChanger="false"
@change="changePage"
/>
</div>
</div>
</div>
</div>
</a-modal>
<PlacementModal ref="PlacementModal" @submitPlacement="submitPlacement"></PlacementModal>
<PlacementModalMobile ref="PlacementModalMobile" @submitPlacement="submitPlacement"></PlacementModalMobile>
</div>
</template>
<script lang="ts">
import { defineComponent,ref } from 'vue'
import {getCookie} from '@/tool/cookie'
import {getUploadUrl,isMoible} from '@/tool/util'
import { message, Upload } from 'ant-design-vue';
import { Chrome,Slider } from '@ans1998/vue3-color'
import PlacementModal from '@/component/Detail/PlacementModal.vue'
import PlacementModalMobile from '@/component/Detail/PlacementModalMobile.vue'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
export default defineComponent({
components:{Chrome,Slider,PlacementModal,PlacementModalMobile},
setup(){
const store = useStore();
let selectColor:any = ref({rgba:{}}) //顔色选择器默认颜色
let clothesData:any = ref({})
let disignTypeList:any = ref([])
return {
store,
selectColor,
clothesData,
disignTypeList
}
},
data(){
return{
elementReplaceShow:false,
newTopOperateShow:false,
sketchCatecoryList:[
{
value: 'Outwear',
label: "Outwear",
},
{
value: 'Blouse',
label: "Blouse",
},
{
value: 'Dress',
label: "Dress",
},
{
value: 'Trousers',
label: "Trousers",
},
{
value: 'Skirt',
label: "Skirt",
},
],
upload:{
isPin:0,
level1Type:'Moodboard',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
modifyColor:{r:255,g:255,b:255},
designType:null,
swtich_type:'Top',
imgList:[], //图片列表
currentPage:1, //当前页码
pageSize:20,
total:0,//图片总数
clothesIndex:0, //该元素在列表中的索引
isShowLoading:false,
searchPictureName:'',//搜索图片的名称
}
},
watch:{
selectColor(newVal:any,oldVal:any){
this.modifyColor = newVal.rgba || {}
}
},
computed:{
getSelectRGB(selectColor){
return (selectColor:any)=>{
let rgba = selectColor.rgba
let data = {
r:rgba?.r || 255,
g:rgba?.g || 255,
b:rgba?.b || 255
}
return data
}
},
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
select_type(type:string){
this.imgList = []
this.currentPage = 1
this.searchPictureName = ''
this.designType = null
this.swtich_type = type
this.getLibraryList()
},
showNewTopOperate(){
this.newTopOperateShow = !this.newTopOperateShow
document.addEventListener('click', this.hiddenNewTopOperate)
},
selectNewTopOperate(cate:any){
this.clothesData.type = cate.value
},
hiddenNewTopOperate(){
this.newTopOperateShow = false
document.removeEventListener('click', this.hiddenNewTopOperate)
},
fileUploadChange(data:any,type:any){
let file = data.file
if(file.status === 'done'){
let res = JSON.parse(file.xhr.response)
if(type === 'top'){
this.clothesData.path = res.data.url
this.clothesData.type = 'Outwear'
}else if(type === 'print'){
this.clothesData.printObject.path = res.data.url
this.clothesData.printObject.location = []
}
}
},
beforeUpload(file:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
},
//改变页码
changePage(current: number, pageSize: number){
this.currentPage = current
this.pageSize = pageSize
this.getLibraryList()
},
handleChange(){
this.getLibraryList()
},
showelementReplaceModal(data:any){
this.clothesData = JSON.parse(JSON.stringify(data.clothes))
this.clothesIndex = data.index
this.elementReplaceShow = true
let color = this.clothesData.color.split(' ')
this.selectColor = {rgba:{r:color[0],g:color[1],b:color[2]}}
let topList = ['Outwear','Dress','Blouse']
if(topList.indexOf(this.clothesData.type) > -1){
this.swtich_type = 'Top'
this.disignTypeList = [{
value: "Outwear",
label: "Outwear",
},
{
value: "Blouse",
label: "Blouse",
},
{
value: "Dress",
label: "Dress",
}]
}else{
this.swtich_type = 'Bottom'
this.disignTypeList = [{
value: "Trousers",
label: "Trousers",
},
{
value: "Skirt",
label: "Skirt",
},]
}
this.getLibraryList()
},
//关闭弹窗
closeModal(){
this.elementReplaceShow = false
this.swtich_type = 'Top'
this.clothesData = {}
this.clothesIndex = 0
},
//提交元素
submitElement(){
this.clothesData.color = `${this.modifyColor.r} ${this.modifyColor.g} ${this.modifyColor.b}`
let data = {
clothes:this.clothesData,
index:this.clothesIndex
}
this.store.commit('setDesignItemColthes',data)
this.closeModal()
},
//删除print的图片
deletePrintFile(){
this.clothesData.printObject.path = ''
},
placementClick(){
let placementModal:any = isMoible() ? this.$refs.PlacementModalMobile : this.$refs.PlacementModal
let data = {
clothesData:this.clothesData,
index:this.clothesIndex
}
placementModal.showPlacementModal(data)
},
//placement提交
submitPlacement(e:any){
this.clothesData.printObject = e
},
getLibraryList(){
let data = {
level2Type:this.designType,
page:this.currentPage,
pictureName:this.searchPictureName,
size:this.pageSize,
type:this.swtich_type
}
this.isShowLoading = true
Https.axiosPost(Https.httpUrls.queryLibraryTopAndBottomPage,data).then(
(rv: any) => {
this.imgList = rv.content
this.total = rv.total
this.isShowLoading = false
}
).catch((res)=>{
this.isShowLoading = false
});
},
//选择库里的图片
selectImgItem(img:any){
if(this.swtich_type != 'Print'){
this.clothesData.path = img.url
}else{
this.clothesData.printObject.path = img.url
}
}
}
})
</script>
<style lang="less">
.element_replace_modal{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
height: 80vh;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.element_replace_content{
display: flex;
justify-content: space-between;
width: 100%;
height: 100%;
padding: 1.5rem 1rem 2rem;
box-sizing: border-box;
.element_replace_content_left{
width: 36.4rem;
height: 100%;
.content_left_block{
width: 100%;
background: #FFFFFF;
padding: 0 2rem;
margin-bottom: 1rem;
.content_left_block_header{
display: flex;
justify-content: space-between;
align-items: center;
height: 5rem;
font-size: 1.6rem;
color: #030303;
&.content_color_block_header{
height: 3.7rem;
}
.placement_button{
padding: 0 0.9rem;
height: 3.2rem;
line-height: 3.2rem;
background: #E6E6F6;
font-size: 1.2rem;
color: #343579;
cursor: pointer;
}
}
.content_left_block_body{
width: 100%;
&.content_color_block_body{
padding:0 1.5rem 1.5rem;
display: flex;
justify-content: space-between;
}
.content_body_img_block{
width: 20rem;
height: 15.8rem;
background: #FFFFFF;
border: 0.1rem solid #F5F5F5;
display: flex;
justify-content: center;
align-items: center;
margin:0 auto;
position: relative;
.element_img{
max-width: 100%;
max-height: 100%;
&.print_element_img{
width: 100%;
height: 100%;
}
}
.element_null_img{
width: 50%;
}
.operate_file_block{
display: none;
width: 100%;
height: 3.2rem;
line-height: 3.2rem;
font-size: 1.6rem;
color: #FFFFFF;
position: absolute;
left: 0;
bottom: 0;
background: rgba(0,0,0,0.6);
text-align: center;
cursor: pointer;
.select_category{
display: flex;
align-items: center;
justify-content: center;
.icon-xiala{
margin-left: 0.8rem;
}
}
.icon_rotate{
-moz-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
transform: rotate(180deg);
animation-direction: 0.5s;
}
.category_list{
position: absolute;
width: 100%;
cursor: pointer;
position: absolute;
top: 3.3rem;
left: 0;
background: #FFFFFF;
border: 0.1rem solid #000000;
box-shadow: 0 0.4rem 0.4rem 0 rgba(0,0,0,0.1);
overflow: hidden;
z-index: 2;
color: #4D4D4D;
.category_item{
text-align: center;
font-size: 1.4rem;
height: 3.5rem;
line-height:3.5rem;
&.select_category_item{
background: #F7F7F7;
}
&:hover{
background: #F7F7F7;
}
}
}
}
.upload_block{
display: none;
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: 1.1rem;
right: 0.9rem;
border-radius: 50%;
.upload_icon_block{
width: 3.6rem;
height: 3.6rem;
background: rgba(0,0,0,0.6);
border-radius: 50%;
text-align: center;
line-height: 3.6rem;
cursor: pointer;
.icon-tianjiatupian_huaban{
font-size: 1.8rem;
color: #fff;
}
}
}
.delete_file_block{
display: none;
width: 3.6rem;
height: 3.6rem;
background: rgba(0,0,0,0.6);
border-radius: 50%;
position: absolute;
top: 1.1rem;
right: 5.5rem;
text-align: center;
line-height: 3.6rem;
cursor: pointer;
.icon-shanchu{
font-size: 1.8rem;
color: #fff;
}
}
&:hover .delete_file_block, &:hover .operate_file_block, &:hover .upload_block{
display: block;
}
}
.review_color_block{
width: 11.5rem;
height: 11.5rem;
border: 0.1rem solid #343579;
}
.setting_color_block{
.setting_color_content{
.vc-chrome-body{
display: none;
}
.chrome_color{
width: 11.5rem;
height: 11.5rem;
overflow: hidden;
.vc-chrome-saturation-wrap{
height: 100%;
}
.vc-chrome-saturation-wrap .vc-saturation-circle{
width: 1rem;
height: 1rem;
}
}
.sileder_color{
width: 1.6rem;
.vc-slider-swatches{
display:none
}
.vc-slider-hue-warp {
width: 11.5rem;
height: 1.6rem;
border-radius: 0.8rem;
overflow: hidden;
.vc-hue-picker{
width: 1.2rem;
height: 1.2rem;
border-radius: 50%;
transform: translate(-0.6rem, -0.4rem);
}
}
.vc-hue-pointer{
top: 0.5rem !important;
}
}
}
.color_rgb_block{
margin-top: 0.5rem;
display: flex;
justify-content: space-between;
font-size: 1.4rem;
color: #343579;
}
}
}
}
.submit_button{
width: 9.8rem;
height: 3.6rem;
text-align: center;
background: #343579;
font-size: 1.4rem;
line-height: 3.6rem;
color: #FFFFFF;
margin: 1.8rem auto 0;
cursor: pointer;
}
}
.element_replace_content_right{
width: calc(100% - 37rem);
height: 100%;
background: #FFFFFF;
.content_right_header{
padding: 1.8rem 2.2rem 2.2rem;
font-size: 1.6rem;
color: #030303;
.content_right_header_content{
height: 1.7rem;
}
}
.content_right_search_block{
padding: 0 2.2rem;
display: flex;
.search_input{
width: 50.3rem;
padding-left: 1.5rem;
height: 4.8rem;
line-height: 4.6rem;
background: #FFFFFF;
border: 0.1rem solid #F1F1F1;
font-size: 1.6rem;
font-weight: 400;
&::placeholder {
color: #C2C2C2;
}
}
.search_icon_block{
width: 7.2rem;
height: 4.8rem;
line-height: 4.8rem;
text-align: center;
background: #343579;
cursor: pointer;
.icon-sousuo{
font-size: 2rem;
color: #FFFFFF;
}
}
}
.content_right_table_block{
height: calc(100% - 10.5rem);
.table_block_header{
display: flex;
justify-content: space-between;
padding: 1.7rem 1.7rem 0 2.3rem;
border-bottom: 0.1rem solid #EBEBEC;
.table_block_header_left{
display: flex;
align-items: center;
.switch_type_item{
height: 4.2rem;
width: 6rem;
text-align: center;
line-height: 4.2rem;
line-height: 4rem;
font-size: 1.6rem;
margin-right: 3rem;
border-bottom: 0.2rem solid transparent;
color: #343579;
cursor: pointer;
&.select_swtich{
color: #343579;
border-bottom: 0.2rem solid #343579;
}
}
}
.select_block {
.ant-select-selector{
min-width: 8rem;
}
.icon-xiala{
color: #1A1A1A !important;
}
}
}
.table_img_list{
padding: 2rem 0 0 2.3rem;
height: calc(100% - 13rem);
overflow-y: auto;
.table_img_item_block{
display: inline-block;
vertical-align: top;
margin:0 1.6rem 3rem 0;
cursor: pointer;
.img_item_block{
width: 16.5rem;
height: 16.5rem;
border: 0.1rem solid #343579;
display: flex;
justify-content: center;
align-items: center;
.print_img_body{
width: 100%;
height: 100%;
}
.img_item_body{
max-width: 100%;
max-height: 100%;
}
}
.img_item_name{
white-space: nowrap;
overflow:hidden;
text-overflow: ellipsis;
font-size: 1.4rem;
color: #343579;
text-align: center;
width: 16.5rem;
}
}
.no_data_block{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table_pagination{
text-align: center;
margin-top: 2rem;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,116 @@
<template>
<a-modal class="hsitory_detail_modal_component"
v-model:visible="hsitoryDetailShow"
:footer="null"
:title="collectionName"
width="80%"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="changeDetailShow()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="history_detail_content scroll_style">
<div class="history_img_block" v-for="img in groupDetails" :key="img">
<div class="history_img_item" >
<img class="element_img" :src="img.url">
</div>
</div>
</div>
</a-modal>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props:{
groupDetails:{
default:{},
},
collectionName:{
default:''
}
},
setup() {
},
data(){
return{
hsitoryDetailShow:false,
}
},
methods:{
changeDetailShow(){
this.hsitoryDetailShow = !this.hsitoryDetailShow
}
}
})
</script>
<style lang="less">
.hsitory_detail_modal_component{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
background: #F7F7F7;
}
.ant-modal-body{
background: #F2F3FB;
height: 80vh;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.history_detail_content{
padding: 2.6rem 2.0rem 2.6rem 3.7rem;
height: 100%;
width: 100%;
overflow-y:auto;
background: #FFFFFF;
.history_img_block{
width: 16.5rem;
height: 16.5rem;
border: 0.1rem solid #343579;
margin: 0 1.7rem 1.7rem 0;
display: inline-block;
.history_img_item{
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.element_img{
max-width: 100%;
max-height: 100%;
}
}
}
}
</style>

View File

@@ -0,0 +1,565 @@
<template>
<div v-show="placementShow">
<a-modal class="placement_modal_component"
v-model:visible="placementShow"
:footer="null"
width="111.5rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="placement_modal_body" >
<div class="palcement_modal_header">
<div class="placement_modal_title">Placement</div>
<div class="placement_operate_list">
<div class="operate_item" @click="submitPlacement">
<div class="icon iconfont icon-baocun1 operate_icon"></div>
<div class="operate_item_des">Submit</div>
</div>
<div class="operate_item" @click="printPreview">
<div class="icon iconfont icon-shengchengyulan operate_icon"></div>
<div class="operate_item_des">Preview</div>
</div>
<div class="operate_item" v-show="perviewUrl" @click="backPreview">
<div class="icon iconfont icon-fanhui1 operate_icon"></div>
<div class="operate_item_des">Back</div>
</div>
<div class="operate_item" @click="restoreLocationList">
<div class="icon iconfont icon-huifu operate_icon"></div>
<div class="operate_item_des">Restore</div>
</div>
</div>
</div>
<div class="placement_modal_content">
<div class="placement_content_operate_list">
<!-- <div class="placement_content_operate_item" @click="overallClick()">
<div class="placement_overall_icon">
<div class="placement_overall_content" v-show="!printObject.ifSingle"></div>
</div>
<div class="placement_content_operate_des">Overall</div>
</div> -->
<div class="placement_content_operate_item">
<div class="print_scale_value">{{placement_sacle}}%</div>
<a-slider
id="placement_silder"
:tooltipVisible="false"
v-model:value="placement_sacle"
:min="30"
:max="300"
/>
<div class="placement_content_operate_des">Print Scale</div>
</div>
<!-- <div class="placement_content_operate_item" @mousedown="AddDian()" v-show="!perviewUrl">
<div class="placement_add_point_block">
<div class="placement_add_point_content"></div>
</div>
<div class="placement_content_operate_des" >Add Point</div>
</div>
<div class="placement_content_operate_item" @click="changeRemoveStatus" v-show="!perviewUrl">
<div class="placement_remove_point_block"></div>
<div class="placement_content_operate_des">Remove Point</div>
</div> -->
</div>
<div class="img_preview_block" >
<div class="perview_mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
<div class="img_content_block" ref="imgbox" @mousemove="startMove($event)">
<img class="placement_img" v-lazy="perviewUrl || clothesData?.path" :key="perviewUrl || clothesData?.path">
<div :class="['ponit_click',isRemoveStatus?'remove_point_click':'']" v-show="!perviewUrl" v-for="(item,index) in locationList" :key="item" :style="{left:item.left+'px', top:item.top+'px'}" @mousedown="getMouseDown($event,item,index)" @mousemove="startMove($event)">
<div class="placement_add_point_content" v-show="!isRemoveStatus"></div>
<div class="icon iconfont icon-guanbi" v-show="isRemoveStatus"></div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref} from 'vue'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
export default defineComponent({
setup() {
const store = useStore()
let oldLocationList:any = ref([])
let locationList:any = ref([])
let printObject:any = ref({})
let imgBox:any = ref({})
let intObj:any = ref(null)
let currentSign:any = ref({})
let clothesData:any = ref({})
return {
store,
oldLocationList,
locationList,
printObject,
imgBox,
intObj,
currentSign,
clothesData
}
},
data(){
return{
placementShow:false,
collectionIndex:0,
startDian:false,
moveOriginal:{posX: 0, posY: 0},
isRemoveStatus:false,
placement_sacle:30,
perviewUrl:'',//预览的图片地址
isShowMark:false,
}
},
methods:{
formatter(value:number){
return `${value}%`;
},
showPlacementModal(data:any){
this.clothesData = JSON.parse(JSON.stringify(data.clothesData))
this.printObject = this.clothesData.printObject
this.collectionIndex = data.index
this.placement_sacle = this.printObject.scale ? this.printObject.scale * 100 : 30
this.placementShow = true
setTimeout(()=>{
let imgbox:any = this.$refs.imgbox
let position = imgbox.getBoundingClientRect()
this.imgBox = {
width:imgbox.clientWidth,
height:imgbox.scrollHeight,
left : position.left,
top:position.top,
scrollTop:imgbox.scrollTop || 0,
}
this.getLocationList(this.imgBox)
},500)
},
getLocationList(imgBox:any){
if(this.printObject.location){
this.locationList = this.printObject.location.map((v:any)=>{
let data = {
left:(v[0] * imgBox.width) - 12,
top:(v[1] * imgBox.height) -12
}
return data
})
this.oldLocationList = JSON.parse(JSON.stringify(this.locationList))
}
},
overallClick(){
this.printObject.ifSingle = !this.printObject.ifSingle
},
AddDian(){
this.startDian = true
this.isRemoveStatus = false
this.intObj = true
},
changeRemoveStatus(){
this.isRemoveStatus = true
},
startMove(event:any){
if(this.isRemoveStatus){
return
}
let imgbox:any = this.$refs.imgbox
let scrollTop = imgbox.scrollTop;
if(this.intObj){
this.currentSign.left = event.clientX - this.imgBox.left
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top
this.locationList.push(this.currentSign)
this.printObject.ifSingle = true
this.intObj = null
}else{
if(this.startDian){
this.currentSign.left = event.clientX - this.imgBox.left - this.moveOriginal.posX
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top -this.moveOriginal.posY
document.addEventListener('mouseup', this.getMouseOver);
this.$forceUpdate()
this.setBoundarySign()
}
}
},
// 在边界上的签名域处理
setBoundarySign() {
let imgbox:any = this.$refs.imgbox
let height = imgbox.offsetHeight + imgbox.scrollTop;
// 2 为签名域的边框
let maxPosHeight = height - 24
let maxPosWidth = imgbox.clientWidth - 24 //+ this.signBox.paddLeft;
if (this.currentSign.top <= 0) {
this.currentSign.top = 0
} else if (this.currentSign.top >= maxPosHeight ) {
this.currentSign.top = maxPosHeight;
}
if (this.currentSign.left <= 0) {
this.currentSign.left = 0
} else if (this.currentSign.left >= maxPosWidth) {
this.currentSign.left = maxPosWidth;
}
},
getMouseDown(event:any,item:any,index:number){
if(this.isRemoveStatus){
this.locationList.splice(index,1)
}else{
this.currentSign = item
// 计算出鼠标在签名域上的偏移
this.moveOriginal.posX = event.offsetX
this.moveOriginal.posY = event.offsetY // 1为边框
this.startDian = true
}
},
getMouseOver(){
this.startDian = false
this.currentSign = {}
document.removeEventListener('mouseup', this.getMouseOver);
},
closeModal(){
this.oldLocationList = []
this.locationList = []
this.printObject = {}
this.intObj = null
this.currentSign = {}
this.isRemoveStatus = false
this.placementShow = false
this.perviewUrl = ''
},
restoreLocationList(){
this.locationList = JSON.parse(JSON.stringify(this.oldLocationList))
},
submitPlacement(){
this.printObject.scale = this.placement_sacle / 100
this.printObject.location = this.printObject.ifSingle ? this.getPrintLocation() : []
this.$emit('submitPlacement',this.printObject)
this.closeModal()
},
getPrintLocation(){
let {width , height} = this.imgBox
let location = this.locationList.map((v:any)=>{
let left = ((v.left + 12) / width).toFixed(4)
let top = ((v.top + 12) / height).toFixed(4)
let data = [left,top]
return data
})
return location
},
printPreview(){
this.printObject.scale = this.placement_sacle / 100
this.printObject.location = this.printObject.ifSingle ? this.getPrintLocation() : []
let designItemDetail = JSON.parse(JSON.stringify(this.store.state.DesignDetailModule.designItemDetail))
designItemDetail.clothes[this.collectionIndex] = this.clothesData
delete designItemDetail.designItemUrl
let priority = designItemDetail.clothes.map((v:any)=>{
return v.type
})
let data = {
...designItemDetail,
priority:priority,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
if(this.isShowMark){
return
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.detailPrintDot, data).then(
(rv: any) => {
this.perviewUrl = rv
this.isShowMark = false
}
).catch(res=>{
this.isShowMark = false
});
},
backPreview(){
this.perviewUrl = ''
}
}
})
</script>
<style lang="less">
.placement_modal_component{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.placement_modal_body{
width: 100%;
height: 100%;
.palcement_modal_header{
position: relative;
height: 6.6rem;
width: 100%;
background: #F7F7F7;
.placement_modal_title{
position: absolute;
height: 100%;
line-height: 6.6rem;
left: 3.7rem;
top: 0;
font-size: 1.8rem;
color: #030303;
}
.placement_operate_list{
display: flex;
align-items: center;
margin:0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 100%;
.operate_item{
margin-right: 4rem;
text-align: center;
cursor: pointer;
.operate_icon{
font-size: 2.1rem;
color: #64686D;
}
.operate_item_des{
height: 1.2rem;
font-size: 1.3rem;
color: #64686D;
}
&:last-child{
margin-right: 0;
}
}
}
}
.placement_modal_content{
position: relative;
height: calc(100% - 6.6rem);
width: 100%;
padding: 1.1rem 0;
.placement_content_operate_list{
width: 9rem;
background: #EBECF4;
position: absolute;
left: 0;
top:6.8rem;
.placement_content_operate_item{
padding: 1.5rem 0;
text-align: center;
cursor: pointer;
.placement_overall_icon{
width: 2.4rem;
height: 2.4rem;
padding: 0.3rem;
background: #EBECF4;
border: 0.1rem solid #64686D;
margin: 0 auto 0.4rem;
.placement_overall_content{
width: 100%;
height: 100%;
background: #343579;
}
}
.placement_content_operate_des{
width: 100%;
font-size: 1.3rem;
color: #64686D;
-moz-user-select:none;
user-select:none
}
.print_scale_value{
height: 1.1rem;
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.3rem;
color: #64686D;
}
.ant-tooltip-placement-top{
top: -37px !important;
}
.ant-slider-track{
background: #343579;
}
.ant-slider-handle{
border-color: #343579;
}
.placement_add_point_block{
width: 2.4rem;
height: 2.4rem;
position: relative;
border: 2px solid #6E70FF;
border-radius: 50%;
margin: 0 auto 0.4rem;
.placement_add_point_content{
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.placement_remove_point_block{
width: 2.4rem;
height: 2.4rem;
border: 2px solid #000000;
border-radius: 50%;
margin: 0 auto 0.4rem;
}
}
}
.img_preview_block{
width: 40.8rem;
background: #ffffff;
margin: 0 auto;
position: relative;
user-select:none;
-moz-user-select:none;
position: relative;
.img_content_block{
width: 40.8rem;
height: 100%;
max-height: 63.2rem;
overflow-y: auto;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
position: relative;
&::-webkit-scrollbar { width: 0 !important }
}
.perview_mark_loading{
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 9;
display: flex;
align-items: center;
justify-content: center;
}
.placement_img{
width: 100%;
user-select:none;
-moz-user-select:none;
}
.ponit_click{
width: 24px;
height: 24px;
position: absolute;
border: 2px solid #6E70FF;
border-radius: 50%;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
cursor: pointer;
&.remove_point_click{
border-color: transparent;
background: #EF3C3C;
}
.placement_add_point_content{
width: 4px;
height: 4px;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.icon-guanbi{
font-size: 20px;
line-height: 20px;
color:#ffffff;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,570 @@
<template>
<div v-show="placementShow">
<a-modal class="placement_modal_mobile_component"
v-model:visible="placementShow"
:footer="null"
width="111.5rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="placement_modal_body" >
<div class="palcement_modal_header">
<div class="placement_modal_title">Placement</div>
<div class="placement_operate_list">
<div class="operate_item" @click="submitPlacement">
<div class="icon iconfont icon-baocun1 operate_icon"></div>
<div class="operate_item_des">Submit</div>
</div>
<div class="operate_item" @click="printPreview">
<div class="icon iconfont icon-shengchengyulan operate_icon"></div>
<div class="operate_item_des">Preview</div>
</div>
<div class="operate_item" v-show="perviewUrl" @click="backPreview">
<div class="icon iconfont icon-fanhui1 operate_icon"></div>
<div class="operate_item_des">Back</div>
</div>
<div class="operate_item" @click="restoreLocationList">
<div class="icon iconfont icon-huifu operate_icon"></div>
<div class="operate_item_des">Restore</div>
</div>
</div>
</div>
<div class="placement_modal_content" @touchmove="startMove($event)">
<div class="placement_content_operate_list">
<!-- <div class="placement_content_operate_item" @click="overallClick()">
<div class="placement_overall_icon">
<div class="placement_overall_content" v-show="!printObject.ifSingle"></div>
</div>
<div class="placement_content_operate_des">Overall</div>
</div> -->
<div class="placement_content_operate_item">
<div class="print_scale_value">{{placement_sacle}}%</div>
<a-slider
id="placement_silder"
:tooltipVisible="false"
v-model:value="placement_sacle"
:min="30"
:max="300"
/>
<div class="placement_content_operate_des">Print Scale</div>
</div>
<!--
<div class="placement_content_operate_item" @touchstart="AddDian()">
<div class="placement_add_point_block">
<div class="placement_add_point_content"></div>
</div>
<div class="placement_content_operate_des" >Add Point</div>
</div>
<div class="placement_content_operate_item" @click="changeRemoveStatus">
<div class="placement_remove_point_block"></div>
<div class="placement_content_operate_des">Remove Point</div>
</div> -->
</div>
<div class="img_preview_block" >
<div class="perview_mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
<div class="img_content_block" ref="imgbox" @touchmove="startMove($event)">
<img class="placement_img" v-lazy="perviewUrl || clothesData?.path" :key="perviewUrl || clothesData?.path">
<div :class="['ponit_click',isRemoveStatus?'remove_point_click':'']" v-for="(item,index) in locationList" :key="item" :style="{left:item.left+'px', top:item.top+'px'}" @touchstart="getMouseDown($event,item,index)" @touchmove="startMove($event)">
<div class="placement_add_point_content" v-show="!isRemoveStatus"></div>
<div class="icon iconfont icon-guanbi" v-show="isRemoveStatus"></div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref} from 'vue'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
export default defineComponent({
setup() {
const store = useStore()
let oldLocationList:any = ref([])
let locationList:any = ref([])
let printObject:any = ref({})
let imgBox:any = ref({})
let intObj:any = ref(null)
let currentSign:any = ref({})
let clothesData:any = ref({})
return {
store,
oldLocationList,
locationList,
printObject,
imgBox,
intObj,
currentSign,
clothesData
}
},
data(){
return{
placementShow:false,
collectionIndex:0,
startDian:false,
moveOriginal:{posX: 0, posY: 0},
isRemoveStatus:false,
placement_sacle:30,
isShowMark:false,
perviewUrl:'',//预览的图片地址
}
},
methods:{
formatter(value:number){
return `${value}%`;
},
showPlacementModal(data:any){
this.clothesData = JSON.parse(JSON.stringify(data.clothesData))
this.printObject = this.clothesData.printObject
this.collectionIndex = data.index
this.placement_sacle = this.printObject.scale ? this.printObject.scale * 100 : 30
this.placementShow = true
setTimeout(()=>{
let imgbox:any = this.$refs.imgbox
let position = imgbox.getBoundingClientRect()
this.imgBox = {
width:imgbox.clientWidth,
height:imgbox.scrollHeight,
left : position.left,
top:position.top,
scrollTop:imgbox.scrollTop || 0,
}
this.getLocationList(this.imgBox)
},500)
},
getLocationList(imgBox:any){
if(this.printObject.location){
this.locationList = this.printObject.location.map((v:any)=>{
let data = {
left:v[0] * imgBox.width,
top:v[1] * imgBox.height
}
return data
})
this.oldLocationList = JSON.parse(JSON.stringify(this.locationList))
}
},
overallClick(){
this.printObject.ifSingle = !this.printObject.ifSingle
},
AddDian(){
this.startDian = true
this.isRemoveStatus = false
this.intObj = true
},
changeRemoveStatus(){
this.isRemoveStatus = true
},
startMove(event:any){
if(this.isRemoveStatus){
return
}
let imgbox:any = this.$refs.imgbox
let scrollTop = imgbox.scrollTop;
if(event.targetTouches[0].pageX > this.imgBox.left){
if(this.intObj){
this.currentSign.left = event.targetTouches[0].pageX - this.imgBox.left
this.currentSign.top = event.targetTouches[0].pageY + scrollTop - this.imgBox.top
this.locationList.push(this.currentSign)
this.printObject.ifSingle = true
this.intObj = null
}else{
if(this.startDian){
this.currentSign.left = event.targetTouches[0].pageX - this.imgBox.left - this.moveOriginal.posX
this.currentSign.top = event.targetTouches[0].pageY + scrollTop - this.imgBox.top -this.moveOriginal.posY
document.addEventListener('touchend', this.getMouseOver);
this.$forceUpdate()
this.setBoundarySign()
}
}
}
},
// 在边界上的签名域处理
setBoundarySign() {
let imgbox:any = this.$refs.imgbox
let height = imgbox.offsetHeight + imgbox.scrollTop;
// 2 为签名域的边框
let maxPosHeight = height - 24
let maxPosWidth = imgbox.clientWidth - 24 //+ this.signBox.paddLeft;
if (this.currentSign.top <= 0) {
this.currentSign.top = 0
} else if (this.currentSign.top >= maxPosHeight ) {
this.currentSign.top = maxPosHeight;
}
if (this.currentSign.left <= 0) {
this.currentSign.left = 0
} else if (this.currentSign.left >= maxPosWidth) {
this.currentSign.left = maxPosWidth;
}
},
getMouseDown(event:any,item:any,index:number){
if(this.isRemoveStatus){
this.locationList.splice(index,1)
}else{
this.currentSign = item
// 计算出鼠标在签名域上的偏移
this.moveOriginal.posX = event.targetTouches[0].pageX - this.imgBox.left - this.currentSign.left
this.moveOriginal.posY = event.targetTouches[0].pageY - this.imgBox.top- this.currentSign.top // 1为边框
this.startDian = true
}
},
getMouseOver(){
this.startDian = false
this.currentSign = {}
document.removeEventListener('touchend', this.getMouseOver);
},
closeModal(){
this.oldLocationList = []
this.locationList = []
this.printObject = {}
this.intObj = null
this.currentSign = {}
this.isRemoveStatus = false
this.placementShow = false
this.perviewUrl = ''
},
restoreLocationList(){
this.locationList = JSON.parse(JSON.stringify(this.oldLocationList))
},
submitPlacement(){
this.printObject.scale = (this.placement_sacle / 100).toFixed(2)
this.printObject.location = this.printObject.ifSingle ? this.getPrintLocation() :[]
this.$emit('submitPlacement',this.printObject)
this.closeModal()
},
getPrintLocation(){
let {width , height} = this.imgBox
let location = this.locationList.map((v:any)=>{
let left = (v.left + 12) / width
let top = (v.top + 12) / height
let data = [left,top]
return data
})
return location
},
//preview打点图
printPreview(){
this.printObject.scale = this.placement_sacle / 100
this.printObject.location = this.printObject.ifSingle ? this.getPrintLocation() :[]
let designItemDetail = JSON.parse(JSON.stringify(this.store.state.DesignDetailModule.designItemDetail))
designItemDetail.clothes[this.collectionIndex] = this.clothesData
delete designItemDetail.designItemUrl
let priority = designItemDetail.clothes.map((v:any)=>{
return v.type
})
let data = {
...designItemDetail,
priority:priority,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
if(this.isShowMark){
return
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.detailPrintDot, data).then(
(rv: any) => {
this.perviewUrl = rv
this.isShowMark = false
}
).catch(res=>{
this.isShowMark = false
});
},
backPreview(){
this.perviewUrl = ''
}
}
})
</script>
<style lang="less">
.placement_modal_mobile_component{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.placement_modal_body{
width: 100%;
height: 100%;
.palcement_modal_header{
position: relative;
height: 6.6rem;
width: 100%;
background: #F7F7F7;
.placement_modal_title{
position: absolute;
height: 100%;
line-height: 6.6rem;
left: 3.7rem;
top: 0;
font-size: 1.8rem;
color: #030303;
}
.placement_operate_list{
display: flex;
align-items: center;
margin:0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 100%;
.operate_item{
margin-right: 4rem;
text-align: center;
cursor: pointer;
.operate_icon{
font-size: 2.1rem;
color: #64686D;
}
.operate_item_des{
height: 1.2rem;
font-size: 1.3rem;
color: #64686D;
}
&:last-child{
margin-right: 0;
}
}
}
}
.placement_modal_content{
position: relative;
height: calc(100% - 6.6rem);
width: 100%;
padding: 1.1rem 0;
.placement_content_operate_list{
width: 9rem;
background: #EBECF4;
position: absolute;
left: 0;
top:6.8rem;
.placement_content_operate_item{
padding: 1.5rem 0;
text-align: center;
cursor: pointer;
.placement_overall_icon{
width: 2.4rem;
height: 2.4rem;
padding: 0.3rem;
background: #EBECF4;
border: 0.1rem solid #64686D;
margin: 0 auto 0.4rem;
.placement_overall_content{
width: 100%;
height: 100%;
background: #343579;
}
}
.placement_content_operate_des{
width: 100%;
font-size: 1.3rem;
color: #64686D;
-moz-user-select:none;
user-select:none
}
.print_scale_value{
height: 1.1rem;
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.3rem;
color: #64686D;
}
.ant-tooltip-placement-top{
top: -37px !important;
}
.ant-slider-track{
background: #343579;
}
.ant-slider-handle{
border-color: #343579;
}
.placement_add_point_block{
width: 2.4rem;
height: 2.4rem;
position: relative;
border: 2px solid #6E70FF;
border-radius: 50%;
margin: 0 auto 0.4rem;
.placement_add_point_content{
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.placement_remove_point_block{
width: 2.4rem;
height: 2.4rem;
border: 2px solid #000000;
border-radius: 50%;
margin: 0 auto 0.4rem;
}
}
}
.img_preview_block{
width: 40.8rem;
background: #ffffff;
margin: 0 auto;
position: relative;
user-select:none;
-moz-user-select:none;
position: relative;
.img_content_block{
width: 100%;
height: 100%;
max-height: 63.2rem;
overflow-y: auto;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
position: relative;
&::-webkit-scrollbar { width: 0 !important }
}
.perview_mark_loading{
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 9;
display: flex;
align-items: center;
justify-content: center;
}
.placement_img{
width: 100%;
user-select:none;
-moz-user-select:none;
}
.ponit_click{
width: 24px;
height: 24px;
position: absolute;
border: 2px solid #6E70FF;
border-radius: 50%;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
cursor: pointer;
&.remove_point_click{
border-color: transparent;
background: #EF3C3C;
}
.placement_add_point_content{
width: 4px;
height: 4px;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.icon-guanbi{
font-size: 20px;
line-height: 20px;
color:#ffffff;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,546 @@
<template>
<div class="colorboard_upload_modal">
<div class="colorboard_upload_left">
<div class="upload_left_header">
<span class="color_list icon iconfont icon-diaosebanpalette3"></span>
<span>My Color Palette</span>
</div>
<div class="upload_left_content scroll_style">
<div class="upload_color_block" v-for="(color,index) in colorList" :key="color">
<div @click="selectColorItem(index,color)" :class="['upload_color',selectIndex === index ? 'select_upload_color' : '']" :style="{background:`rgb(${color?.r},${color?.g},${color?.b})`}"></div>
</div>
</div>
</div>
<div class="colorboard_upload_right">
<div class="upload_right_content">
<div class="right_content_line">
<div class="upload_right_header">
<span class="color_edit icon iconfont icon-yansefangan"></span>
<span>Choose Color</span>
</div>
<div class="color_setting_block">
<Chrome class="chrome_color" v-model="selectColor"></Chrome>
<Slider class="sileder_color" v-model="selectColor"></Slider>
<div class="color_rgb_block">
<div class="rgb_item">R:{{getSelectRGB(selectColor).r}}</div>
<div class="rgb_item">G:{{getSelectRGB(selectColor).g}}</div>
<div class="rgb_item">B:{{getSelectRGB(selectColor).b}}</div>
</div>
</div>
<div class="color_review_block">
<div class="color_review_content" :style="{background: reviewColor?.r || reviewColor?.r===0 ?`rgb(${reviewColor?.r},${reviewColor?.g},${reviewColor?.b})` : 'none'}"></div>
<div class="pantong_name" v-show="pantongName">{{pantongName}}</div>
<div class="clear_button" @click="clearCurrentColor()">Clear</div>
</div>
</div>
<div class="right_content_line">
<div class="upload_right_header">
<span class="color_edit icon iconfont icon-yansefangan"></span>
<span>Upload Color</span>
</div>
<div class="upload_item">
<div class="upload_file_item" v-for="(file) in fileList" :key="file">
<div class="upload_file_item_content" v-show="file.status !== 'done'">
<a-spin :indicator="indicator" tip="Uploading..."/>
</div>
<div class="upload_file_item_content" v-show="file.status === 'done'">
<img :src="file?.imgUrl" class="upload_img" ref="colorImage">
<div class="delete_file_block" @click="deleteFile(index)">Delete</div>
</div>
</div>
<a-upload
v-show="fileList.length < 1"
list-type="picture-card"
:customRequest="function(){}"
@change="fileUploadChange"
:before-upload="beforeUpload"
accept=".jpg,.png,.jpeg,.bmp"
>
<div class="upload_tip_block">
<img class="upload_img_icon" src="@/assets/images/homePage/add_file.png">
</div>
</a-upload>
</div>
<div class="upload_right_header">
<span class="color_edit icon iconfont icon-yansefangan"></span>
<span>Key in Color Code</span>
</div>
<div class="get_color_block">
<input class="get_color_input" placeholder="tcx value (e.g.: 19-4052)" v-model="tcxColor" @keydown.enter="getTcxColor()"/>
<div class="get_color_button" @click="getTcxColor()">
<span class="icon iconfont icon-huoquduixiang"></span>
<span class="get_color_des">Extract Color</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Chrome,Slider } from '@ans1998/vue3-color'
import { Https } from "@/tool/https";
import { defineComponent, h,ref } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue';
import {getCookie} from '@/tool/cookie'
import {getUploadUrl,rgbToHsv} from '@/tool/util'
import {useStore} from 'vuex'
import ColorThief from '@/tool/colorthief/colorthief'
import { message,Upload} from 'ant-design-vue';
export default defineComponent({
components:{
Chrome,
Slider
},
setup(){
let fileList:any = ref([])
let colorList:any = [{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]
let selectColor:any = ref({rgba:{}}) //顔色选择器默认颜色
return {
fileList,
colorList,
selectColor,
}
},
watch:{
selectColor(newVal:any,oldVal:any){
this.reviewColor = newVal.rgba || {}
this.colorList[this.selectIndex] = newVal.rgba
let colorList =this.colorList.filter((v:any) => v && Object.keys(v).length)
this.setColorboardList(colorList)
}
},
computed:{
getSelectRGB(selectColor){
return (selectColor:any)=>{
let rgba = selectColor.rgba
let data = {
r:rgba?.r || rgba?.r===0 ? rgba?.r : 255,
g:rgba?.g || rgba?.g===0 ? rgba?.g : 255,
b:rgba?.b || rgba?.b===0 ? rgba?.b : 255,
}
return data
}
},
},
data(){
return{
reviewColor:{}, //预览的颜色
selectIndex:0,//选中的文件索引
tcxColor:'',
pantongName:'',//潘通值
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
upload:{
isPin:0,
level1Type:'Moodboard',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
store:useStore()
}
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
//选择不同的色块
selectColorItem(index:any,color:any){
this.selectIndex = index
this.reviewColor = color?.r + ''? {r:color.r,g:color.g ,b:color.b } : {}
this.selectColor = color?.r + ''? {rgba:{r:color.r,g:color.g,b:color.b,a:1}} : {}
this.fileList = []
this.tcxColor = ''
this.pantongName = ''
},
//通过tcx获取颜色
getTcxColor(){
if(!this.tcxColor){
return
}
Https.axiosGet(Https.httpUrls.getRgbByTcx + '?tcx=' + this.tcxColor).then((rv) =>{
if(rv && rv.name){
this.reviewColor = {r:rv.r, g:rv.g, b:rv.b}
this.colorList[this.selectIndex] = {r:rv.r, g:rv.g, b:rv.b}
this.pantongName = rv.name
let colorList =this.colorList.filter((v:any) => Object.keys(v).length)
this.setColorboardList(colorList)
}else{
message.error("Can't find the TCX color")
}
})
},
//清除当前的颜色
clearCurrentColor(){
this.selectColor = {}
this.fileList = []
this.pantongName = ''
this.tcxColor = ''
},
fileUploadChange(data:any){
let file = data.file
let fileData = file.originFileObj
var reader = new FileReader();
reader.onload = (e:any) => {
let data_new;
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data_new = window.URL.createObjectURL(new Blob([e.target.result]));
} else {
data_new = e.target.result;
}
file.imgUrl = data_new
file.status = 'done'
this.fileList.push(file)
setTimeout(()=>{
const colorThief = new ColorThief();
let colorImage:any = this.$refs.colorImage
let domImg:any = colorImage[0];
let color = colorThief.getColor(domImg)
this.getHsvColor(color)
this.reviewColor = {r:color[0],g:color[1],b:color[2]}
this.selectColor = {rgba:{r:color[0],g:color[1],b:color[2],a:1}}
},100)
};
// 转化为base64S
reader.readAsDataURL(fileData)
},
beforeUpload(file:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
},
deleteFile(index:any){
this.fileList.splice(index, 1)
},
//通过HSV获取颜色
getHsvColor(color:any){
let hsv = rgbToHsv(color)
this.pantongName = ''
Https.axiosGet(Https.httpUrls.getRgbByHsv + `?h=${hsv[0]}&s=${hsv[0]}&v=${hsv[1]}`).then((rv) =>{
if(rv){
this.pantongName = rv.name
}
})
},
setColorboardList(colorList:any){
let newColorList = colorList.map((v:any)=>{
let data = {
id:'',
name:'',
rgbValue:v
}
return data
})
this.store.commit('setColorboardList',newColorList)
},
recollection(){
let colorList = this.store.state.UploadFilesModule.allBoardData.colorBoards
colorList.forEach((ele:any, index:number) => {
this.colorList[index] = ele.rgbValue
});
this.reviewColor = this.colorList[0]
this.selectColor = {rgba:this.colorList[0]}, //顔色选择器默认颜色
this.store.commit('setColorboardList',colorList)
}
}
})
</script>
<style lang="less">
.colorboard_upload_modal{
padding: 1rem 1rem 1.8rem 1rem;
height: 100%;
background: #F2F3FB;
display: flex;
justify-content: space-between;
.colorboard_upload_left{
width: calc(100% - 48rem);
height: 100%;
background: #FFFFFF;
.upload_left_header{
padding: 1.4rem 2rem 1.6rem;
font-size: 1.6rem;
color: #333333;
font-weight: bold;
display: flex;
align-items: center;
line-height: 2.4rem;
.color_list{
font-size: 2.2rem;
margin-right: 0.7rem;
}
}
.upload_left_content{
padding: 1rem 1.6rem;
height: calc(100% - 5.4rem);
overflow-y: auto;
.upload_color_block{
padding: 0 0.4rem;
margin-bottom: 2.6rem;
display: inline-block;
vertical-align: top;
.upload_color{
width: 11.5rem;
height: 11.5rem;
border: 0.1rem solid #DCDCEC;
cursor: pointer;
}
.select_upload_color{
border-color: #343579;
}
}
}
}
.colorboard_upload_right{
width: 47rem;
height: 100%;
background: #FFFFFF;
.upload_right_header{
padding: 0.4rem 0 1.6rem 0;
font-weight: bold;
line-height: 2.4rem;
font-size: 1.6rem;
color: #333333;
display: flex;
align-items: center;
.color_edit{
font-size: 2.4rem;
margin-right: 0.7rem;
}
}
.upload_right_content{
padding: 1rem 2.8rem;
height: calc(100% - 5.4rem);
overflow-y: auto;
overflow-x: hidden;
display: flex;
.right_content_line{
margin-bottom: 2.3rem;
.color_review_block{
margin-right: 4rem;
.color_review_content{
width: 16.5rem;
height: 16.5rem;
background: #FFFFFF;
border: 0.1rem solid #DCDCEC;
}
.pantong_name{
margin-top: 1rem;
font-size: 1.6rem;
font-weight: 400;
color: #030303;
text-align: left;
font-weight: bold;
}
.clear_button{
padding: 0 2.8rem;
height: 3.2rem;
line-height: 3.2rem;
background: #EFEEFF;
font-size: 1.2rem;
font-family: Roboto;
color: #343579;
display: inline-block;
margin-top: 1rem;
cursor: pointer;
}
}
.upload_file_item{
margin: 0 2rem 2rem 0;
display: inline-block;
width: 16.5rem;
height: 16.5rem;
border: 1px solid #F5F5F5;
vertical-align: top;
.upload_file_item_content{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: relative;
cursor: pointer;
&:hover .delete_file_block{
display: block;
}
.upload_img{
display: block;
max-height: 100%;
max-width: 100%;
}
.delete_file_block{
display: none;
width: 100%;
height: 4rem;
background: rgba(0,0,0,0.2);
font-size: 1.6rem;
color: #FFFFFF;
line-height: 4rem;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
}
}
.upload_img_icon{
width: 4.6rem;
}
.color_setting_block{
width: 16.5rem;
margin-right: 4rem;
margin-bottom: 7rem;
.vc-chrome-body{
display: none;
}
.chrome_color{
width: 16.5rem;
height: 16.5rem;
overflow: hidden;
.vc-chrome-saturation-wrap{
height: 100%;
}
.vc-chrome-saturation-wrap .vc-saturation-circle{
width: 1rem;
height: 1rem;
}
}
.sileder_color{
margin-top:1.3rem;
.vc-slider-swatches{
display:none
}
.vc-slider-hue-warp {
width: 16.5rem;
height: 2.4rem;
border-radius: 1.2rem;
overflow: hidden;
.vc-hue-picker{
width: 1.4rem;
height: 1.4rem;
border-radius: 50%;
transform: translate(-0.7rem, -0.2rem);
}
}
.vc-hue-pointer{
top: 0.5rem !important;
}
}
.color_rgb_block{
margin-top: 1rem;
display: flex;
justify-content: space-between;
font-size: 1.6rem;
color: #343579;
}
}
.get_color_block{
.get_color_input{
width: 19.4rem;
height: 3.8rem;
background: #FFFFFF;
border: 0.1rem solid #DCDCEC;
padding: 1rem 1.3rem;
box-sizing: border-box;
font-size: 1.4rem;
text-align: left;
&::placeholder {
color: #B7B7B7;
}
}
.get_color_button{
margin-top: 1.5rem;
padding: 0 2.2rem;
height: 3.2rem;
background: #EFEEFF;
display: inline-block;
line-height: 3rem;
font-size: 1.2rem;
color: #343579;
vertical-align: middle;
cursor: pointer;
.icon-huoquduixiang{
margin-right: 0.5rem;
font-size: 2rem;
color:#343579;
vertical-align: middle;
}
.get_color_des{
vertical-align: middle;
}
}
}
}
.upload_item{
margin-bottom: 11.6rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,316 @@
<template>
<a-modal class="modal_component cut_pricture_modal"
v-model:visible="cutPicuterModal"
:footer="null"
title="Cut picture"
width="115rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="header_right_block" @click.stop="">
<div class="next_step_button" @click.stop="finishCropper()">Finish</div>
<div class="header_cancel_button" @click.stop="cancleCropper()">Cancel</div>
</div>
</template>
<div class="collection_modal_body">
<div class="cut_picture_left">
<div class="cut_picture_body">
<VueCropper
ref="cropper"
:original="option.original"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:auto-crop="option.autoCrop"
:auto-crop-width="option.autoCropWidth"
:auto-crop-height="option.autoCropHeight"
:center-box="option.centerBox"
:can-move="option.canMove" :can-move-box="option.canMoveBox"
@real-time="realTime"
></VueCropper>
</div>
<div class="cur_picture_opterate">
<div class="cur_picture_opterate_item" @click="rotateLeft()"><span class="icon iconfont icon-chexiao operate_icon"></span></div>
<div class="cur_picture_opterate_item" @click="rotateRight()"><span class="icon iconfont icon-chexiao operate_icon icon_chexiao_sec"></span></div>
<div class="cur_picture_opterate_item" @click="changeScale(-1)"><span class="operate_icon icon_font">-</span></div>
<div class="cur_picture_opterate_item" @click="changeScale(1)"><span class="operate_icon icon_font">+</span></div>
<div class="cur_picture_opterate_item" @click="refreshCrop()"><span class="icon iconfont icon-shuaxin operate_icon"></span></div>
</div>
</div>
<div class="cut_picture_right">
<div class="cur_picture_right_header">
<div class="review_logo icon iconfont icon-yulan"></div>
<div>Crop Preview</div>
</div>
<div class="cut_picture_review_block">
<div class="cut_picture_review_item">
<div class="cut_picture_review_content" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden'}">
<div :style="previews.div" >
<img class="previews_image" :style="previews.img" :src="previews.url">
</div>
</div>
</div>
<div class="cut_picture_review_item">
<div class="cut_picture_review_block_sec" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden'}">
<div :style="previews.div" >
<img class="previews_image" :style="previews.img" :src="previews.url">
</div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import 'vue-cropper/dist/index.css'
import { VueCropper } from "vue-cropper";
import {base64toFile} from '@/tool/util'
export default defineComponent({
props:['cropperFileData','isUpload'],
components:{
VueCropper,
},
data(){
return {
cutPicuterModal:false,
option: {
original:false,
img: '',
size: 1,
full: false,
outputType: 'png',
autoCrop: true,
// 只有自动截图开启 宽度高度才生效
autoCropWidth: 360,
autoCropHeight: 360,
max: 99999,
centerBox:true,
canMove:true,
canMoveBox:true,
},
previews:{},
}
},
methods:{
rotateLeft() {
let cropper:any = this.$refs.cropper
cropper.rotateLeft();
},
rotateRight() {
let cropper:any = this.$refs.cropper
cropper.rotateRight();
},
refreshCrop() {
let cropper:any = this.$refs.cropper
cropper.refresh();
},
changeScale(num:any) {
num = num || 1;
let cropper:any = this.$refs.cropper
cropper.changeScale(num);
},
// 实时预览函数
realTime(data:any) {
this.previews = data;
},
getOptionImg(img:any){
this.option.img = img
},
changeShowModal(type:any){
this.cutPicuterModal = type
},
finishCropper(){
let cropper:any = this.$refs.cropper,
that = this
cropper.getCropData((data:any) => {
// 转换为File对象
let file = base64toFile(data,this.cropperFileData.name);
this.$emit('handleCropperSuccess',{file:file, fileData:this.cropperFileData})
})
},
closeCropper(){
this.cutPicuterModal = false
this.option.img = ''
},
cancleCropper(){
this.cutPicuterModal = false
this.option.img = ''
this.$emit('closeCropper')
}
}
})
</script>
<style lang="less" scoped>
.cut_pricture_modal{
.header_right_block{
display: flex;
align-items: center;
position: absolute;
right: 2.1rem;
height: 100%;
.next_step_button{
padding: 0 1.2rem;
height: 3.2rem;
background: linear-gradient(160deg, #AC2A3B, #292161);
border-radius: 1.6rem;
font-size: 1.4rem;
color: #FFFFFF;
line-height: 3.2rem;
margin-right: 1.6rem;
white-space: nowrap;
cursor: pointer;
}
.header_cancel_button{
padding: 0 2.1rem;
height: 3.2rem;
background: #E4E5EB;
border-radius: 1.6rem;
font-size: 1.4rem;
color: #030303;
line-height: 3.2rem;
white-space: nowrap;
cursor: pointer;
}
}
.collection_modal_body{
height: 100%;
padding: 1rem 2.5rem 1.4rem 1.4rem;
box-sizing: border-box;
background: #F2F3FB;
display: flex;
justify-content: space-between;
.cut_picture_left{
width: 70.7rem;
height: 100%;
background: #fff;
border-radius: 2rem;
padding: 1.3rem 1.3rem 2rem;
box-sizing: border-box;
.cut_picture_body{
width: 100%;
height: 53rem;
background: yellow;
}
.cur_picture_opterate{
margin: 2.7rem auto 0;
border-radius: 1.6rem;
display: flex;
overflow: hidden;
border: 1px solid #E2E2E4;
width: 24rem;
.cur_picture_opterate_item{
width: 4.7rem;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
border-right: 0.1rem solid #E6E8EA;
cursor: pointer;
.icon_chexiao_sec{
transform: rotateY(180deg); /* 垂直镜像翻转 */
}
.operate_icon{
font-size: 1.8rem;
color: rgba(102, 102, 102, 1);
font-weight: bold;
}
.icon_font{
font-size: 2.5rem;
position: relative;
top: -0.3rem;
user-select:none;
}
.icon-shuaxin{
font-size: 1.4rem;
}
&:last-child{
border: none;
}
}
}
}
.cut_picture_right{
width: 39.2rem;
height: 100%;
background: #fff;
border-radius: 2rem;
.cur_picture_right_header{
padding: 2rem;
display: flex;
align-items: center;
font-size: 1.6rem;
font-weight: 400;
color: #030303;
line-height: 1.8rem;
font-weight: bold;
.review_logo{
font-size: 1.8rem;
color: #333;
margin-right: 1rem;
}
}
.cut_picture_review_block{
width: 100%;
padding: 0 2rem;
height: calc(100% - 5.8rem);
.cut_picture_review_item{
width: 100%;
height: 50%;
position: relative;
.cut_picture_review_content{
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
transform: scale(0.45) translate(-50%, -50%);
background: rgba(91,94,105,0.8);
box-shadow: 0 0.2rem 0.5rem 0 rgba(216,213,239,0.3);
border-radius: 1rem;
}
.cut_picture_review_block_sec{
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
transform: scale(0.45) translate(-50%, -50%);
border-radius: 100%;
background: rgba(91,94,105,0.8);
box-shadow: 0 0.2rem 0.5rem 0 rgba(216,213,239,0.3);
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,177 @@
<template>
<!-- 生成collention缩略图用的 -->
<div class="export_new_collection_review">
<div class="img_block_item" v-if="allBoardData?.moodTemplateId">
<MoodTemplate :fileList="allBoardData?.moodboardFiles" :moodTemplateId="allBoardData?.moodTemplateId"></MoodTemplate>
</div>
<div class="img_block_item" v-else>
<div class="lager_img_item" v-for="(mood) in allBoardData.moodboardFiles" :key="mood">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="mood.imgUrl" >
</div>
</div>
</div>
<div class="img_block_item">
<div class="small_img_item" v-for="(print) in allBoardData.printboardFiles" :key="print">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="print.imgUrl">
</div>
</div>
<div class="small_img_item" v-for="(generate) in allBoardData.generatePrintFiles" :key="generate">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="generate.imgUrl">
</div>
</div>
</div>
<div class="img_block_item">
<div class="color_item" v-for="(color) in allBoardData.colorBoards" :key="color">
<div class="color_content" :style="{background:`rgb(${color?.rgbValue?.r},${color?.rgbValue?.g},${color?.rgbValue?.b})`}"></div>
<div class="color_content_body">
<div class="color_des">{{color.tcx}}</div>
<div class="color_des">{{color.name}}</div>
</div>
</div>
</div>
<div class="img_block_item">
<div class="lager_img_item" v-for="(skecth) in allBoardData.skecthboardFiles" :key="skecth">
<div class="all_img_item_block">
<img class="all_img_content" :src="skecth.imgUrl">
</div>
</div>
</div>
<div class="img_block_item">
<div class="lager_img_item" v-for="(marketing) in allBoardData.marketingSketchFiles" :key="marketing">
<div class="all_img_item_block">
<img class="all_img_content" :src="marketing.imgUrl">
</div>
</div>
</div>
<div class="img_block_item">
<div class="lager_img_item" v-for="(design) in likeDesignCollectionList" :key="design.designItemUrl">
<div class="all_img_item_block">
<img class="all_img_content" :src="design.designItemUrl">
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import MoodTemplate from '@/component/HomePage/MoodTemplate.vue'
import { useStore } from "vuex";
export default defineComponent({
components:{MoodTemplate},
setup() {
const store = useStore();
let allBoardData:any = computed(()=>{return store.state.UploadFilesModule.allBoardData})
let likeDesignCollectionList : any = computed(()=>{return store.state.HomeStoreModule.likeDesignCollectionList})
return {
allBoardData,
likeDesignCollectionList,
}
}
})
</script>
<style lang="less" scoped>
.export_new_collection_review{
width: 40.8rem;
background: #fff;
position: fixed;
left: -100rem;
top: 0;
.img_block_item{
margin-bottom: 2rem;
// &.color_block_item{
// padding: 0 0.5rem 0 0.3rem;
// }
.lager_img_item{
display: inline-block;
width: 20.4rem;
height: 20.4rem;
vertical-align: top;
}
.sketch_img_item{
display: inline-block;
width: 20.4rem;
height: 42.2rem;
vertical-align: top;
}
.small_img_item{
width: 6.8rem;
height: 6.8rem;
display: inline-block;
vertical-align: top;
}
.color_item{
display: inline-block;
vertical-align: top;
// padding: 0 0.5rem;
margin-right: 1.6rem;
margin-bottom: 0.5rem;
&:nth-child(4n){
margin-right: 0;
}
}
.color_content{
width: 9rem;
height:6.2rem
}
.color_content_body{
width: 9rem;
padding: 0.7rem 0.2rem;
background: #FEFEFE;
border: 1px solid #E6E6E6;
.color_des{
font-size: 1rem;
font-family: Roboto;
font-weight: 500;
color: #000000;
margin-bottom: 0.5rem;
line-height: 1.3rem;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&:last-child{
margin-bottom: 0;
}
}
}
.all_img_item_block{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
.all_img_content{
max-height: 100%;
max-width: 100%;
&.cover_img{
width: 100%;
height: 100%;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,486 @@
<template>
<div>
<header class="header_component">
<img class="header_logo" @click="turnToNewPage('https://www.aidlab.hk/en/')" src="@/assets/images/loginPage/aida_logo.png" />
<nav class="header_nav_content">
<div :class="['nav_item', $route.name === 'home'?'select_nav':'']" @click="turnToPage('home')">HOME</div>
<div :class="['nav_item', $route.name === 'library'?'select_nav':'']" @click="turnToPage('library')">LIBRARY</div>
<div :class="['nav_item', $route.name === 'history'?'select_nav':'']" @click="turnToPage('history')">HISTORY</div>
</nav>
<div class="header_right_content">
<div class="header_icon icon iconfont icon-touxiang3"></div>
<div class="header_user_content">
<div class="username">{{userInfo?.userName}}</div>
<div :class="['icon','iconfont', 'icon-xiala', isShowOperate?'icon_rotate':'']" @click.stop="changeShowOperateContent()"></div>
<nav class="select_block" v-show="isShowOperate">
<!-- <div class="select_item" @click="showBindEmailModal()">
<span class="icon iconfont icon-youxiang"></span><span class="select_item_des">bind email</span>
</div> -->
<div class="select_item" @click="logout()">
<span class="icon iconfont icon-tuichu"></span><span class="select_item_des">log off</span>
</div>
</nav>
</div>
</div>
</header>
<a-modal class="modal_component"
v-model:visible="bindEmailVisible"
:footer="null"
title="Mailbox binding"
width="56rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon v-if="!isHaveBindEmail && bindEmailStep === 1">
<div class="skip_content">skip</div>
</template>
<div class="bind_email_content" v-if="isHaveBindEmail">
<div class="bind_email_tip">you have binded email</div>
<div class="bind_email">{{userInfo.email}}</div>
</div>
<div class="bind_email_content" v-else>
<!-- 绑定邮箱第一步 start -->
<div v-show="bindEmailStep === 1">
<div class="bind_email_form_content">
<div class="bind_email_form_title">Email</div>
<input class="bind_email_form_input" placeholder="Enter a new email" v-model="email" @keydown.enter="emailNextStepFun()">
</div>
<div class="bind_email_submit_button" @click="emailNextStepFun()">Next step</div>
</div>
<!-- 绑定邮箱第一步 end -->
<!-- 绑定邮箱第二步 start -->
<div v-show="bindEmailStep === 2">
<div @click="emailLastStepFun()">
<span class="icon iconfont icon--shangyibu"></span><span class="email_last_step_content">Enter verification code</span>
</div>
<div class="email_last_step_des">
<div class="sent_email_content">Sent to {{email}}</div>
<div class="tip_content">
<span v-show="time">{{time}}s</span>
<span v-show="!time" @click="emailNextStepFun()">Resend</span>
</div>
</div>
<VerificationCodeInput :ct="emailCode" @sendCaptcha="submitBindEmail($event)"></VerificationCodeInput>
</div>
<!-- 绑定邮箱第一步 end -->
</div>
</a-modal>
</div>
</template>
<script >
import { defineComponent ,createVNode} from 'vue'
import {isEmail} from '@/tool/util'
import {setCookie, getCookie, WriteCookie} from '@/tool/cookie'
import VerificationCodeInput from '@/component/LoginPage/verificationCodeInput.vue'
import { Https } from "@/tool/https";
import { Modal,message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
export default defineComponent({
components:{
VerificationCodeInput,
},
data(){
return{
isShowOperate:false,
bindEmailVisible:false,
isHaveBindEmail:false,
bindEmailStep:1,
email:'',
emailCode:['','','','','',''],//邮箱验证码
time:60,//60秒倒计时
timer: 0,
userInfo:{},
timerOperate:null,
numTime:30,
timerSec:null,
modalWarning:null
}
},
mounted(){
this.userInfo = JSON.parse(getCookie('userInfo'))
if(!this.userInfo){
this.$router.replace('/login')
}else{
this.accountIsLogin(this.userInfo)
}
this.isHaveBindEmail = this.userInfo?.email ? true : false
this.operateClick()
document.addEventListener('click',this.operateClick)
},
methods:{
turnToNewPage(url){
window.open(url)
},
turnToPage(name){
let noRefresh = name === 'home' ? true :false
this.$router.push({name:name,params: {noRefresh:noRefresh}})
},
//点击下拉图标出现操作
changeShowOperateContent(){
this.isShowOperate = !this.isShowOperate
document.addEventListener('click',this.closeShowOperateContent,false)
},
//关闭下拉图标
closeShowOperateContent(){
this.isShowOperate = false
document.removeEventListener('click',this.closeShowOperateContent)
},
//打开绑定邮箱弹窗
showBindEmailModal(){
this.bindEmailVisible = true
},
emailNextStepFun(){
if(!isEmail(this.email)){
message.error('The email format is incorrect');
return
}
let data = {
email:this.email,
operationType: "BIND_MAILBOX",
}
const hide = message.loading('loading', 0);
Https.axiosPost(Https.httpUrls.accountSendEmail, data).then((rv) =>{
if(rv){
this.bindEmailStep = 2
this.emailCode = ['','','','','',''],
this.createTimer()
hide()
message.success('Succeeded in binding the mailbox.')
}
}).catch(res=>{
hide()
})
},
//绑定邮箱的上一步
emailLastStepFun(){
this.bindEmailStep = 1
this.email = ''
this.emailCode = ['','','','','',''],
this.clearTimer()
},
//创建定时器
createTimer(){
this.timer = setInterval(()=>{
this.time--
if(!this.time){
clearInterval(this.timer)
}
},1000)
},
//清除定时器
clearTimer(){
this.time = 60
if(this.timer){
clearInterval(this.timer)
}
},
//登出
logout(){
let data = {
userId:this.userInfo.userId
}
Https.axiosPost(Https.httpUrls.accountLogout, data).then((rv) =>{
this.$router.replace('/login')
WriteCookie('token')
})
},
//绑定邮箱
submitBindEmail(emailVerifyCode){
let data = {
userEmail:this.email,
userId: this.userInfo.userId,
emailVerifyCode:emailVerifyCode
}
Https.axiosPost(Https.httpUrls.accountBindEmail, data).then((rv) =>{
if(rv){
this.userInfo.email = this.email
setCookie('userInfo',JSON.stringify(this.userInfo))
this.bindEmailVisible = false,
this.bindEmailStep = 1
this.clearTimer()
this.emailCode = ['','','','','','']
}
})
},
//判断是否登录
accountIsLogin(userInfo){
let data ={
userId:userInfo.userId
}
Https.axiosPost(Https.httpUrls.accountIsLogin, data).then((rv) =>{
if(!rv){
this.$router.replace('/login')
}
})
},
//点击重置判断是否长时间五操作
operateClick(){
if(this.timer){
clearTimeout(this.timer)
}
let _this = this
let timeNum = 1000 * 60 *120
this.timer = setTimeout(()=>{
this.modalWarning = Modal.warning ({
title: () => `You have not performed any operation for a long time. You must be active;otherwise, you will log out in ${_this.numTime} S`,
icon: createVNode(ExclamationCircleOutlined),
okText: 'Ok',
onOk() {
_this.numTime = 30
clearInterval(_this.timerSec)
}
});
_this.numCounter()
},timeNum)
},
numCounter(){
this.timerSec = setInterval(()=>{
if(this.numTime > 0){
this.numTime = this.numTime - 1
}else{
clearTimeout(this.timer)
clearInterval(this.timerSec)
this.logout()
this.modalWarning.destroy()
}
},1000)
}
}
})
</script>
<style lang="less" scoped>
.header_component{
display: flex;
width: 100%;
height: 7rem;
background: rgba(255, 255, 255, 0.2);
border-bottom: 0.1rem solid rgba(3,3,3,0.1);
position: relative;
.header_logo{
width: 14.4rem;
height: 3.2rem;
margin: 2.1rem 0 0 2.8rem;
}
.header_nav_content{
display: flex;
margin-left: 28.9rem;
align-items: center;
.nav_item{
padding: 1.1rem 1rem;
border-bottom: 0.1rem solid transparent;
margin-right: 3.4rem;
font-size: 1.6rem;
line-height: 1.3rem;
color: #333333;
cursor: pointer;
font-weight: 500;
&.select_nav{
background: #E6E6F6;
}
}
}
.header_right_content{
position: absolute;
top: 0;
right: 3.2rem;
display: flex;
.header_icon{
font-size: 3.6rem;
position: relative;
top: 0.3rem;
}
.header_user_content{
margin-left: 1rem;
display: flex;
align-items: center;
position: relative;
top: 1.2rem;
height: 3.7rem;
.username{
font-size: 1.6rem;
color: #1A1A1A;
margin-right: 0.8rem;
}
.icon-xiala{
font-size: 1.4rem;
cursor: pointer;
}
.icon_rotate{
-moz-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
transform: rotate(180deg);
animation-direction: 0.5s;
}
.select_block{
position: absolute;
right: -1.5rem;
top: 3.7rem;
width: 11.4rem;
background: #FFFFFF;
box-shadow: 0px 0.4rem 0.4rem 0px rgba(0,0,0,0.1);
z-index: 9;
overflow: hidden;
border: 1px solid #000000;
.select_item{
padding-left: 1.5rem;
height: 4.1rem;
color: #4D4D4D;
display: flex;
align-items: center;
cursor: pointer;
user-select:none;
&:hover{
background: #F7F7F7;
}
.iconfont{
font-size: 1.4rem;
}
.select_item_des{
font-size: 1.3rem;
margin-left: 0.8rem;
}
}
}
}
}
}
.modal_component{
.skip_content{
width: 6rem;
height: 3rem;
line-height: 2.8rem;
border: 0.1rem solid #343579;
font-size: 1.4rem;
color: #343579;
position: absolute;
top: 1.8rem;
right: 1.8rem;
cursor: pointer;
}
.bind_email_content{
padding: 4.8rem 9.2rem 6rem;
.bind_email_tip{
font-size: 1.8rem;
color: #A5B0C2;
line-height: 1.9rem;
text-align: center;
}
.bind_email{
margin-top: 2rem;
font-size: 2.2rem;
font-weight: 400;
color: #030303;
text-align: center;
}
.bind_email_form_content{
.bind_email_form_title{
font-size: 2.2rem;
font-weight: bold;
color: #030303;
line-height: 2.4rem;
}
.bind_email_form_input{
width: 100%;
height: 4.6rem;
margin-top: 1rem;
border: 0.1rem solid #B4BED7;
padding-left: 2.1rem;
line-height: 4.6rem;
font-size: 1.8rem;
box-sizing: border-box;
&::placeholder {
color:#A5B0C2,
}
}
}
.bind_email_submit_button{
height: 4.6rem;
line-height: 4.6rem;
background: #343579;
font-size: 1.6rem;
font-weight: 500;
color: #FFFFFF;
width: 12.8rem;
text-align: center;
cursor: pointer;
margin: 3rem auto 0;
}
.icon--shangyibu{
font-size: 2.5rem;
font-weight: bold;
color: #030303;
}
.email_last_step_content{
margin-left: 1rem;
font-size: 2.2rem;
font-family: PingFang SC;
font-weight: bold;
color: #030303;
}
.tip_content{
font-size: 1.3rem;
font-weight: bold;
color: #343579;
cursor: pointer;
}
.email_last_step_des{
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 2.5rem;
margin-bottom: 1.5rem;
.sent_email_content{
font-size: 1.8rem;
font-weight: bold;
color: #A5B0C2;
}
}
}
}
</style>

View File

@@ -0,0 +1,272 @@
<template>
<div class="collection_modal_item">
<div class="switch_type_list">
<div class="switch_type_item select_swtich">
<span>Upload</span>
</div>
<div @click="openLibrary()" class="switch_type_item">
<span>My Library</span>
</div>
</div>
<div class="marketingUpload_body" v-show="swtich_type==='upload'">
<div class="upload_img_body scroll_style">
<div class="upload_item">
<div class="upload_file_item" v-for="(file, index) in fileList" :key="file">
<div class="upload_file_item_content" v-show="file?.status === 'uploading'">
<a-spin :indicator="indicator" tip="Uploading..."/>
</div>
<div class="upload_file_item_content" v-show="file?.status === 'done'">
<img :src="file?.imgUrl" class="upload_img">
<div class="delete_file_block" @click="deleteFile(index)">Delete</div>
</div>
</div>
<div class="upload_file_item upload_component" v-show="fileList.length < 15">
<a-upload
:action="uploadUrl + '/api/element/upload'"
list-type="picture-card"
:data="{
...upload
}"
:before-upload="beforeUpload"
:headers="{Authorization:token}"
v-model:file-list="fileList"
multiple
:maxCount="15"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file)=>fileUploadChange(file)"
>
<div class="upload_tip_block" v-show="fileList.length < 15">
<img class="upload_img_icon" src="@/assets/images/homePage/add_file.png">
</div>
</a-upload>
</div>
</div>
</div>
<div class="upload_max_tip">
<span class="icon iconfont icon-zhuyi"></span>
<span>Maximum 15 images can be uploaded, Maximum 2M per image</span>
</div>
</div>
<Material ref="Material" @confirmSelect="confirmSelect"></Material>
</div>
</template>
<script lang="ts">
import { defineComponent, h,ref } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue';
import {getCookie} from '@/tool/cookie'
import {getUploadUrl} from '@/tool/util'
import {useStore} from 'vuex'
import { message,Upload} from 'ant-design-vue';
import Material from '@/component/HomePage/Material.vue'
export default defineComponent({
components:{Material},
setup(){
let fileList:any = ref([])
return {
fileList
}
},
data(){
return{
swtich_type:'upload',
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
upload:{
isPin:0,
level1Type:'MarketingSketch',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
store:useStore()
}
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
openLibrary(){
let material:any = this.$refs.Material
material.init('MarketingSketch')
},
fileUploadChange(data:any){
let file = data.file
if(file.status === 'done'){
let res = JSON.parse(file.xhr.response)
file.imgUrl = res.data.url
file.resData = res.data
let fileList = this.fileList.filter((v:any)=> v.status === 'done')
this.store.commit('setMarketingSketchFile',fileList)
}else if(file.status === 'error'){
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(file.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
message.error(file.name + 'upload failed')
}
},
beforeUpload(file:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
},
deleteFile(index:any){
this.fileList.splice(index, 1)
this.store.commit('setMarketingSketchFile',this.fileList)
},
recollection(){
this.fileList = JSON.parse(JSON.stringify(this.store.state.UploadFilesModule.allBoardData.marketingSketchFiles))
this.store.commit('setMarketingSketchFile',this.fileList)
},
confirmSelect(event:any){
for(let item of event){
let data = {
imgUrl:item.url,
resData:item,
status:'done',
}
if(this.fileList.length == 15){
message.error('Maximum number of allowable file uploads has been exceeded')
break
}
this.fileList.push(data)
}
this.store.commit('setMarketingSketchFile',this.fileList)
}
}
})
</script>
<style lang="less" scoped>
.collection_modal_item{
padding: 1.5rem 2.6rem 4rem;
height: 100%;
.switch_type_list{
display: flex;
align-items: center;
.switch_type_item{
display: flex;
align-items: center;
padding: 0 2rem;
height: 4rem;
background: #fff;
border-radius: 0.8rem;
line-height: 4rem;
font-size: 1.6rem;
margin-right: 2.2rem;
color: #5B5E69;
cursor: pointer;
&.select_swtich{
color: #343579;
}
.switch_icon{
font-size: 1.8rem;
margin-right: 0.8rem;
}
}
}
.marketingUpload_body{
margin-top: 1rem;
height: calc(100% - 5rem);
.upload_img_body{
height: calc(100% - 3rem);
overflow-y: auto;
margin-bottom: 1rem;
}
.upload_file_item{
margin: 0 2rem 2rem 0;
display: inline-block;
width: 16.5rem;
height: 16.5rem;
border: 1px solid #F5F5F5;
vertical-align: top;
&.upload_component{
border: none;
}
.upload_file_item_content{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: relative;
&:hover .delete_file_block{
display: block;
}
.upload_img{
display: block;
max-height: 100%;
max-width: 100%;
}
.delete_file_block{
display: none;
width: 100%;
cursor: pointer;
height: 4rem;
background: rgba(0,0,0,0.2);
font-size: 1.6rem;
color: #FFFFFF;
line-height: 4rem;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
}
.upload_img_icon{
width: 4.6rem;
}
}
.upload_max_tip{
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
color: #030303;
.icon-zhuyi{
font-size: 1.6rem;
margin-right: 0.7rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,470 @@
<template>
<div>
<a-modal class="my_material_modal"
v-model:visible="myMaterialModalShow"
:footer="null"
width="80%"
:maskClosable="false"
:centered="true"
>
<div class="my_material_header">
<div class="my_material_title">My Library</div>
<div class="my_material_header_right">
<div class="content_search_block">
<input class="search_input" placeholder="Please input" v-model="searchPictureName" @keydown.enter="getLibraryList()">
<div class="search_icon_block" @click="getLibraryList()"><span class="icon iconfont icon-sousuo"></span></div>
</div>
<div class="icon iconfont icon-guanbi icon_close" @click="closeModal"></div>
</div>
</div>
<div class="my_material_content">
<div class="material_content_top">
<div class="material_content_top_title"></div>
<div class="material_content_top_right">
<div class="select_block" v-show="selectCode == 'Sketchboard' || selectCode == 'MarketingSketch'">
<a-select
ref="select"
v-model:value="designType"
:options="disignTypeList"
placeholder="All"
:allowClear="true"
@change="handleChange"
>
<template #suffixIcon
><span
class="icon iconfont icon-xiala"
style="color: #343579"
></span
></template>
</a-select>
</div>
<div :class="['check_all_block',selectImgList.length == imgList.length ? 'check_all' : '']" @click="selectAllImg()" v-show="imgList.length">
<div class="check_block"><div class="check_block_body" v-show="selectImgList.length == imgList.length && imgList.length"></div></div>
<div>all</div>
</div>
</div>
</div>
<div class="material_content_body scroll_style">
<div class="content_img_item" v-for="(img) in imgList" :key="img.id" @click="selectImgItem(img)">
<div :class="['content_img_item_block', selectImgListIds.indexOf(img.id) > -1 ? 'select_item_img' :'']">
<img :class="[selectCode == 'Moodboard' || selectCode == 'Printboard' ? 'print_content_img' : 'content_img']" v-lazy="img.url" :key="img.url"/>
</div>
<div class="content_img_name">{{img.name}}</div>
</div>
<div class="no_data_block" v-show="!imgList.length && !isShowLoading">
<img src="@/assets/images/homePage/null_img.png">
</div>
</div>
<div class="no_data_block loading_block" v-show="isShowLoading">
<a-spin size="large"></a-spin>
</div>
<div class="material_confirm" @click="confirmSelect()" v-show="imgList.length">Confirm</div>
<div class="table_pagination" v-show="imgList.length">
<a-pagination
v-model:current="currentPage"
v-model:pageSize="pageSize"
:total="total"
:showSizeChanger="false"
:showQuickJumper="true"
@change="changePage"
/>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent, ref} from 'vue'
import { Https } from "@/tool/https";
import { message } from 'ant-design-vue';
export default defineComponent({
setup() {
let myMaterialModalShow = ref(false)
let imgList = ref([])
let selectImgList:any = ref([])
let selectImgListIds:any = ref([])
let isShowLoading:any = ref(false)
let selectCode:any = ref('')
let currentPage:any = ref(1)
let searchPictureName = ref('')
let pageSize = ref(20)
let total = ref(0)
let searcMaterialhName:any = ref('') //搜索名字
let designType:any = ref(null)
let disignTypeList = [
{
value: "Outwear",
label: "Outwear",
},
{
value: "Blouse",
label: "Blouse",
},
{
value: "Dress",
label: "Dress",
},
{
value: "Trousers",
label: "Trousers",
},
{
value: "Skirt",
label: "Skirt",
},
]
let boardList = {
Moodboard:'Mood',
Printboard:'Print',
Sketchboard:'Sketch',
MarketingSketch:'MarketingSketch'
}
return{
myMaterialModalShow,
imgList,
selectImgList,
selectImgListIds,
isShowLoading,
selectCode,
currentPage,
searchPictureName,
pageSize,
total,
searcMaterialhName,
designType,
disignTypeList,
boardList
}
},
methods:{
init(code:any){
this.selectCode = code
this.myMaterialModalShow = true
this.getLibraryList()
},
selectImgItem(imgData:any){
this.selectImgListIds = this.selectImgList.map((v:any)=>v.id)
if(this.selectImgListIds.indexOf(imgData.id) === -1){
this.selectImgList.push(imgData)
this.selectImgListIds.push(imgData.id)
}else{
let index = this.selectImgListIds.indexOf(imgData.id)
this.selectImgList.splice(index,1)
this.selectImgListIds.splice(index,1)
}
},
//改变页码
changePage(current: number, pageSize: number){
this.currentPage = current
this.pageSize = pageSize
this.getLibraryList()
},
handleChange(){
this.getLibraryList()
},
//选择所有的图片
selectAllImg(){
if(this.selectImgListIds.length == this.imgList.length){
this.selectImgListIds = []
this.selectImgList = []
}else{
this.selectImgListIds = this.imgList.map((v:any) => v.id)
this.selectImgList = this.imgList
}
},
getLibraryList(){
let data = {
level1Type:this.selectCode,
level2Type:this.designType,
page:this.currentPage,
pictureName:this.searchPictureName,
size:this.pageSize,
}
this.isShowLoading = true
Https.axiosPost(Https.httpUrls.queryLibraryPage,data).then(
(rv: any) => {
this.imgList = rv.content
this.total = rv.total
this.isShowLoading = false
}
).catch((res)=>{
this.isShowLoading = false
});
},
confirmSelect(){
if(!this.selectImgList.length){
message.error('Please select at least one image')
return
}
this.$emit('confirmSelect',this.selectImgList)
this.closeModal()
},
closeModal(){
this.myMaterialModalShow = false
this.searchPictureName = ''
this.designType = null
this.selectImgList = []
this.selectImgListIds = []
this.imgList = []
this.currentPage = 1
this.pageSize = 10
this.total = 0
}
}
})
</script>
<style lang="less">
.my_material_modal{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
height: 80vh;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.my_material_header{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 6.6rem;
background: #F7F7F7;
padding: 0 3.4rem 0 3.1rem;
.my_material_title{
font-size: 1.8rem;
color: #030303;
font-weight: 500;
}
.my_material_header_right{
display: flex;
justify-content: space-between;
align-items: center;
.content_search_block{
margin-right: 5rem;
display: flex;
.search_input{
width: 30rem;
padding-left: 1.5rem;
height: 4rem;
line-height: 3.8rem;
background: #FFFFFF;
border: 0.1rem solid #F1F1F1;
font-size: 1.6rem;
font-weight: 400;
&::placeholder {
color: #C2C2C2;
}
}
.search_icon_block{
width: 6rem;
height: 4rem;
line-height: 4rem;
text-align: center;
background: #343579;
cursor: pointer;
.icon-sousuo{
font-size: 2rem;
color: #FFFFFF;
}
}
}
.icon_close{
color: rgba(174, 178, 183, 1);
font-size: 2.4rem;
cursor: pointer;
}
}
}
.my_material_content{
padding: 0 3rem 3.5rem 3rem;
height: calc(100% - 6.6rem);
position: relative;
.material_content_top{
padding: 1.3rem 0 2.1rem;
height: 7rem;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
.material_content_top_title{
font-size: 20px;
color: #030303;
}
.material_content_top_right{
display: flex;
align-items: center;
.select_block{
background: #FFFFFF;
color: #1A1A1A !important;
margin-right: 2.3rem;
.icon-xiala{
color: #1A1A1A !important;
}
}
.check_all_block{
display: flex;
align-items: center;
font-size: 1.6rem;
color: #64686D;
cursor: pointer;
&.check_all{
color: #1A1A1A;
}
.check_block{
width: 2.4rem;
height: 2.4rem;
background: #EBECF4;
border: 0.1rem solid #64686D;
padding: 0.3rem;
margin-right: 0.7rem;
.check_block_body{
width: 100%;
height: 100%;
background: #343579;
}
}
}
}
}
.material_content_body{
width: 100%;
height: calc(100% - 19rem);
overflow-y: auto;
position: relative;
.content_img_item{
display: inline-block;
vertical-align: top;
padding: 0 1.4rem;
margin-bottom: 2.8rem;
.content_img_item_block{
border: 0.1rem solid transparent;
width: 16.5rem;
height: 16.5rem;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
&.select_item_img{
border-color: #343579;
}
.print_content_img{
width: 100%;
height: 100%;
}
.content_img{
max-width: 100%;
max-height: 100%;
}
}
.content_img_name{
width: 16.5rem;
height: 3.5rem;
line-height: 3.5rem;
white-space: nowrap;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.4rem;
color: #030303;
}
}
}
.no_data_block{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
top: 0;
z-index: 99;
&.loading_block{
background: rgba(0,0,0,0.2);
}
}
.material_confirm{
width: 9.8rem;
height: 3.6rem;
line-height: 3.6rem;
font-size: 1.4rem;
text-align: center;
margin: 0 auto;
color: #FFFFFF;
background: #343579;
cursor: pointer;
margin-top: 2rem;
}
.table_pagination{
position: absolute;
bottom: 3.5rem;
left: 0;
width: 100%;
text-align: center;
margin-top: 5rem;
}
}
}
</style>

View File

@@ -0,0 +1,446 @@
<template>
<div class="mood_template_component">
<div class="mood_template_item template_three" v-show="moodTemplateId == 3">
<div class="img_template three_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template three_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template three_1" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_four" v-show="moodTemplateId == 4">
<div class="img_template four_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template four_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template four_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template four_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_five" v-show="moodTemplateId == 5">
<div class="img_template five_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template five_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template five_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template five_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template five_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_six" v-show="moodTemplateId == 6">
<div class="img_template six_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template six_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template six_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template six_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template six_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
<div class="img_template six_6" :style="{backgroundImage:`url(${fileList[5]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_seven" v-show="moodTemplateId == 7">
<div class="img_template seven_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template seven_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template seven_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template seven_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template seven_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
<div class="img_template seven_6" :style="{backgroundImage:`url(${fileList[5]?.imgUrl})`}"></div>
<div class="img_template seven_7" :style="{backgroundImage:`url(${fileList[6]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_eight" v-show="moodTemplateId == 8">
<div class="img_template eight_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template eight_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template eight_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template eight_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template eight_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
<div class="img_template eight_6" :style="{backgroundImage:`url(${fileList[5]?.imgUrl})`}"></div>
<div class="img_template eight_7" :style="{backgroundImage:`url(${fileList[6]?.imgUrl})`}"></div>
<div class="img_template eight_8" :style="{backgroundImage:`url(${fileList[7]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_nine" v-show="moodTemplateId == 9">
<div class="img_template nine_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template nine_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template nine_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template nine_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template nine_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
<div class="img_template nine_6" :style="{backgroundImage:`url(${fileList[5]?.imgUrl})`}"></div>
<div class="img_template nine_7" :style="{backgroundImage:`url(${fileList[6]?.imgUrl})`}"></div>
<div class="img_template nine_8" :style="{backgroundImage:`url(${fileList[7]?.imgUrl})`}"></div>
<div class="img_template nine_9" :style="{backgroundImage:`url(${fileList[8]?.imgUrl})`}"></div>
</div>
<div class="mood_template_item template_ten" v-show="moodTemplateId == 10">
<div class="img_template ten_1" :style="{backgroundImage:`url(${fileList[0]?.imgUrl})`}"></div>
<div class="img_template ten_2" :style="{backgroundImage:`url(${fileList[1]?.imgUrl})`}"></div>
<div class="img_template ten_3" :style="{backgroundImage:`url(${fileList[2]?.imgUrl})`}"></div>
<div class="img_template ten_4" :style="{backgroundImage:`url(${fileList[3]?.imgUrl})`}"></div>
<div class="img_template ten_5" :style="{backgroundImage:`url(${fileList[4]?.imgUrl})`}"></div>
<div class="img_template ten_6" :style="{backgroundImage:`url(${fileList[5]?.imgUrl})`}"></div>
<div class="img_template ten_7" :style="{backgroundImage:`url(${fileList[6]?.imgUrl})`}"></div>
<div class="img_template ten_8" :style="{backgroundImage:`url(${fileList[7]?.imgUrl})`}"></div>
<div class="img_template ten_9" :style="{backgroundImage:`url(${fileList[8]?.imgUrl})`}"></div>
<div class="img_template ten_10" :style="{backgroundImage:`url(${fileList[9]?.imgUrl})`}"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props:['fileList','moodTemplateId'],
setup() {
},
})
</script>
<style lang="less" scoped>
.mood_template_component{
width: 40.8rem;
background: #fff;
.mood_template_item{
width: 100%;
position: relative;
}
.template_three{
height: 18.7rem;
display: flex;
.img_template{
position: relative;
}
.three_1{
width: 10.2rem;
height: 100%;
}
.three_2{
width: 19.6rem;
margin: 0 0.4rem;
}
}
.template_four{
height: 21.1rem;
.four_1{
left: 0;
top: 0;
width: 20.1rem;
height: 10.7rem;
}
.four_2{
left: 0;
top: 11.1rem;
width: 9.6rem;
height: 10rem;
}
.four_3{
left: 9.9rem;
top: 11.1rem;
width: 10.2rem;
height: 10rem;
}
.four_4{
right: 0;
top: 0;
width: 20.1rem;
height: 21.1rem;
}
}
.template_five{
height: 24.2rem;
.five_1{
left: 0;
top: 0;
width: 15.2rem;
height: 15.3rem;
}
.five_2{
left: 0;
top: 15.3rem;
width: 15.2rem;
height: 8.7rem;
}
.five_3{
left: 15.2rem;
top: 0;
width: 14.5rem;
height: 24rem;
}
.five_4{
right: 0;
top: 0;
width: 11.1rem;
height: 12rem;
}
.five_5{
right: 0;
top: 12rem;
width: 11.1rem;
height: 12rem;
}
}
.template_six{
height: 27.4rem;
.six_1{
left: 0;
top: 0;
width: 13.4rem;
height: 13.8rem;
}
.six_2{
left: 0;
top: 13.8rem;
width: 14.3rem;
height: 13.6rem;
}
.six_3{
left: 13.4rem;
top: 0;
width: 13.9rem;
height: 13.8rem;
}
.six_4{
left: 14.3rem;
top: 13.8rem;
width: 18.6rem;
height: 13.6rem;
}
.six_5{
right: 0;
top: 0;
width: 13.5rem;
height: 13.8rem;
}
.six_6{
right: 0;
top: 13.8rem;
width: 7.9rem;
height: 13.6rem;
}
}
.template_seven{
height: 21rem;
.seven_1{
left: 0;
top: 0;
width: 7.3rem;
height: 7.6rem;
}
.seven_2{
left: 0;
top: 7.5rem;
width: 7.3rem;
height: 13.2rem;
}
.seven_3{
left: 7.5rem;
top: 0;
width: 12.1rem;
height: 11.7rem;
}
.seven_4{
left: 7.5rem;
top: 11.9rem;
width: 12.1rem;
height: 9.1rem;
}
.seven_5{
left: 19.7rem;
top: 0;
width: 10.4rem;
height: 10.1rem;
}
.seven_6{
left: 19.7rem;
top: 10.3rem;
width: 10.4rem;
height: 10.7rem;
}
.seven_7{
right: 0;
top: 0;
width: 10.6rem;
height: 21rem;
}
}
.template_eight{
height: 24.9rem;
.eight_1{
left: 0;
top: 0;
width: 8.5rem;
height: 9.1rem;
}
.eight_2{
left: 0;
top: 9.3rem;
width: 8.5rem;
height: 15.5rem;
}
.eight_3{
left: 8.7rem;
top: 0;
width: 13.8rem;
height: 13.8rem;
}
.eight_4{
left: 8.7rem;
top: 14rem;
width: 10.9rem;
height: 10.8rem;
}
.eight_5{
left: 19.8rem;
top: 14rem;
width: 4.9rem;
height: 10.8rem;
}
.eight_6{
right: 0;
top: 0;
width: 18.1rem;
height: 13.8rem;
}
.eight_7{
left: 24.9rem;
top: 14rem;
width: 10.5rem;
height: 10.8rem;
}
.eight_8{
right: 0;
top: 14rem;
width: 5.2rem;
height: 10.8rem;
}
}
.template_nine{
height: 19.3rem;
.nine_1{
left: 0;
top: 0;
width: 6rem;
height: 6.4rem;
}
.nine_2{
left: 0;
top: 6.6rem;
width: 6rem;
height: 12.5rem;
}
.nine_3{
left: 6.3rem;
top: 0;
width: 10.2rem;
height: 19.1rem;
}
.nine_4{
left: 16.7rem;
top: 0;
width: 5.9rem;
height: 5.8rem;
}
.nine_5{
left: 16.7rem;
top: 5.9rem;
width: 5.9rem;
height: 13.2rem;
}
.nine_6{
left: 22.7rem;
top: 0;
width: 9.3rem;
height: 9.4rem;
}
.nine_7{
left: 22.7rem;
top: 9.5rem;
width: 9.3rem;
height: 9.6rem;
}
.nine_8{
right: 0;
top: 0;
width: 8.7rem;
height: 6.7rem;
}
.nine_9{
right: 0;
top: 6.8rem;
width: 8.7rem;
height: 12.3rem;
}
}
.template_ten{
height: 21.2rem;
.ten_1{
left: 0;
top: 0;
width: 9.9rem;
height: 10.6rem;
}
.ten_2{
left: 0;
top: 10.8rem;
width: 9.9rem;
height: 10.4rem;
}
.ten_3{
left: 10rem;
top: 0;
width: 9.9rem;
height: 21.2rem;
}
.ten_4{
left: 20rem;
top: 0;
width: 8.1rem;
height: 15rem;
}
.ten_5{
left: 20rem;
top: 15.3rem;
width: 8.1rem;
height: 5.9rem;
}
.ten_6{
left:28.2rem;
top: 0;
width: 6.4rem;
height: 6.3rem;
}
.ten_7{
left:28.2rem;
top: 6.4rem;
width: 6.4rem;
height: 14.7rem;
}
.ten_8{
right: 0;
top: 0;
width: 6.1rem;
height: 6rem;
}
.ten_9{
right: 0;
top: 6.2rem;
width: 6.1rem;
height: 6.1rem;
}
.ten_10{
right: 0;
top: 12.5rem;
width: 6.1rem;
height: 8.7rem;
}
}
.img_template{
position: absolute;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
}
</style>

View File

@@ -0,0 +1,422 @@
<template>
<div class="collection_modal_item">
<div class="switch_type_list">
<div class="switch_type_item select_swtich">
<span>Upload</span>
</div>
<div @click="openLibrary()" class="switch_type_item">
<span>My Library</span>
</div>
<div class="design_template_button" @click.stop="changeTemplateModal()" v-show="fileList.length>2">Design</div>
</div>
<div class="moodboard_body">
<div class="upload_img_body scroll_style" >
<div class="upload_item">
<div class="upload_file_item" v-for="(file, index) in fileList" :key="file">
<div class="upload_file_item_content" v-show="file?.status === 'uploading'">
<a-spin :indicator="indicator" tip="Uploading..."/>
</div>
<div class="upload_file_item_content" v-show="file?.status === 'done'">
<img :src="file?.imgUrl" class="upload_img">
<div class="delete_file_block" @click="deleteFile(index)">Delete</div>
</div>
</div>
<div class="upload_file_item upload_component" v-show="fileList.length < 10">
<a-upload
:action="uploadUrl + '/api/element/upload'"
list-type="picture-card"
:data="{
...upload
}"
:headers="{Authorization:token}"
v-model:file-list="fileList"
:before-upload="beforeUpload"
multiple
:maxCount="10"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file)=>fileUploadChange(file)"
>
<div class="upload_tip_block" v-show="fileList.length < 10">
<img class="upload_img_icon" src="@/assets/images/homePage/add_file.png">
</div>
</a-upload>
</div>
</div>
</div>
<div class="upload_max_tip">
<span class="icon iconfont icon-zhuyi"></span>
<span>Maximum 10 images can be uploaded, Maximum 2M per image</span>
</div>
</div>
<Material ref="Material" @confirmSelect="confirmSelect"></Material>
<a-modal class="moodboard_template_modal"
v-model:visible="templateModal"
:footer="null"
width="47rem"
:maskClosable="false"
:centered="true"
:closable="false"
>
<div class="moodboard_template_content">
<div class="moodboard_template_header">
<div class="moodboard_template_title">MoodBoard Design</div>
<div class="icon iconfont icon-guanbi close_icon" @click.stop="changeTemplateModal()"></div>
</div>
<div class="moodboard_template_block">
<div class="moodboard_template_info">
<MoodTemplate :fileList="this.templateFileList" :moodTemplateId="moodTemplateId"></MoodTemplate>
<div class="moodboard_template_refetch_content">
<div class="button_second" @click="refetchTemplate()">Re-fetch</div>
</div>
</div>
</div>
<div class="button_second submit_button" @click="submitTemplate()">Submit</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent, h,ref } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue';
import {getCookie} from '@/tool/cookie'
import {getUploadUrl} from '@/tool/util'
import {useStore} from 'vuex'
import { message, Upload } from 'ant-design-vue';
import Material from '@/component/HomePage/Material.vue'
import MoodTemplate from '@/component/HomePage/MoodTemplate.vue'
export default defineComponent({
components:{Material,MoodTemplate},
setup(){
let fileList:any = ref([])
let templateModal:any = ref(false)
let templateFileList:any = ref([])
return {
fileList,
templateModal,
templateFileList
}
},
data(){
return{
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
upload:{
isPin:0,
level1Type:'Moodboard',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
moodTemplateId:'',//模板id
store:useStore()
}
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
openLibrary(){
let material:any = this.$refs.Material
material.init('Moodboard')
},
fileUploadChange(data:any){
let file = data.file
if(file.status === 'done'){
let res = JSON.parse(file.xhr.response)
file.imgUrl = res.data.url
file.resData = res.data
let fileList = this.fileList.filter((v:any)=> v.status === 'done')
this.store.commit('setMoodboardFile',fileList)
this.store.commit('clearMoodTemplateId')
}else if(file.status === 'error'){
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(file.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
message.error(file.name + 'upload failed')
}
},
beforeUpload(file:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
},
deleteFile(index:any){
this.fileList.splice(index, 1)
this.store.commit('setMoodboardFile',this.fileList)
this.store.commit('clearMoodTemplateId')
},
recollection(){
this.fileList = JSON.parse(JSON.stringify(this.store.state.UploadFilesModule.allBoardData.moodboardFiles))
let moodTemplateId = this.store.state.UploadFilesModule.allBoardData.moodTemplateId
this.store.commit('setMoodboardFile',this.fileList)
this.store.commit('setMoodTemplateId',moodTemplateId)
},
confirmSelect(event:any){
for(let item of event){
let data = {
imgUrl:item.url,
resData:item,
status:'done',
}
if(this.fileList.length == 10){
message.error('Maximum number of allowable file uploads has been exceeded')
break
}
this.fileList.push(data)
}
this.store.commit('setMoodboardFile',this.fileList)
this.store.commit('clearMoodTemplateId')
},
changeTemplateModal(){
this.templateModal = !this.templateModal
if(this.templateModal){
this.templateFileList = this.fileList.map((v:any)=>{
let data = {
...v,
imgUrl:v.imgUrl.replace(/\s/g, encodeURIComponent(' '))
}
return data
})
this.moodTemplateId = this.store.state.UploadFilesModule.moodTemplateId || this.templateFileList.length
}
},
randomRange(min:any, max:any, num:any) { // min最小值max最大值 num排除的值
let index = Math.floor(Math.random() * (max - min)) + min;
while(index === num){
index = Math.floor(Math.random() * (max - min)) + min;
}
return index
},
//随机重置图片顺序
refetchTemplate(){
let arr= Array.from({length:this.templateFileList.length})
for(let item of this.templateFileList){
let index = this.randomRange(0,this.templateFileList.length,-1)
while(arr[index]){
index = this.randomRange(0,this.templateFileList.length,-1)
}
arr[index] = item
}
this.templateFileList = arr
},
//提交模板
submitTemplate(){
this.fileList = JSON.parse(JSON.stringify(this.templateFileList))
this.store.commit('setMoodboardFile',this.fileList)
this.store.commit('setMoodTemplateId',this.moodTemplateId)
this.changeTemplateModal()
}
}
})
</script>
<style lang="less" scoped>
.collection_modal_item{
padding: 1.5rem 2.6rem 4rem;
height: 100%;
.switch_type_list{
display: flex;
align-items: center;
position: relative;
.switch_type_item{
display: flex;
align-items: center;
padding: 0 2rem;
height: 4rem;
background: #fff;
border-radius: 0.8rem;
line-height: 4rem;
font-size: 1.6rem;
margin-right: 2.2rem;
color: #5B5E69;
cursor: pointer;
&.select_swtich{
color: #343579;
}
.switch_icon{
font-size: 1.8rem;
margin-right: 0.8rem;
}
}
.design_template_button{
background: #E6E6F6;
padding: 0 2.7rem;
font-size: 1.4rem;
height: 3.2rem;
line-height: 3.2rem;
cursor: pointer;
color: #343579;
position: absolute;
right: 0;
top: 0;
}
}
.moodboard_body{
margin-top: 1rem;
height: calc(100% - 5rem);
.upload_img_body{
height: calc(100% - 3rem);
overflow-y: auto;
margin-bottom: 1rem;
}
.upload_file_item{
margin: 0 2rem 2rem 0;
display: inline-block;
width: 16.5rem;
height: 16.5rem;
border: 1px solid #F5F5F5;
vertical-align: top;
&.upload_component{
border: none;
}
.upload_file_item_content{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: relative;
&:hover .delete_file_block{
display: block;
}
.upload_img{
display: block;
height: 100%;
width: 100%;
}
.delete_file_block{
display: none;
width: 100%;
cursor: pointer;
height: 4rem;
background: rgba(0,0,0,0.2);
font-size: 1.6rem;
color: #FFFFFF;
line-height: 4rem;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
}
.upload_img_icon{
width: 4.6rem;
}
}
.upload_max_tip{
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
color: #030303;
.icon-zhuyi{
font-size: 1.6rem;
margin-right: 0.7rem;
}
}
}
}
</style>
<style lang="less">
.moodboard_template_modal{
.ant-modal-body{
padding: 0;
}
.moodboard_template_content{
background: #F2F3FB;
padding-bottom: 2.9rem;
.moodboard_template_header{
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 2rem 0 2.5rem;
height: 6.6rem;
.moodboard_template_title{
font-size: 1.8rem;
font-weight: 500;
color: #030303;
}
.close_icon{
font-size: 1.8rem;
color: #AEB2B7;
cursor: pointer;
}
}
.moodboard_template_block{
padding: 0 3.1rem 0;
.moodboard_template_info{
background: #fff;
.moodboard_template_refetch_content{
padding: 3.1rem 0 2rem;
.button_second{
margin: 0 auto;
}
}
}
}
.submit_button{
margin: 2rem auto 0;
}
}
}
</style>

View File

@@ -0,0 +1,174 @@
<template>
<!-- 生成collention缩略图用的 -->
<div class="collection_review">
<div class="collection_review_mark"></div>
<div class="img_block_item" v-if="allBoardData?.moodTemplateId">
<MoodTemplate :fileList="allBoardData?.moodboardFiles" :moodTemplateId="allBoardData?.moodTemplateId"></MoodTemplate>
</div>
<div class="img_block_item" v-else>
<div class="lager_img_item" v-for="(mood) in allBoardData.moodboardFiles" :key="mood">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="mood.imgUrl" >
</div>
</div>
</div>
<div class="img_block_item">
<div class="small_img_item" v-for="(print) in allBoardData.printboardFiles" :key="print">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="print.imgUrl">
</div>
</div>
<div class="small_img_item" v-for="(generate) in allBoardData.generatePrintFiles" :key="generate">
<div class="all_img_item_block">
<img class="all_img_content cover_img" :src="generate.imgUrl">
</div>
</div>
</div>
<div class="img_block_item">
<div class="color_item" v-for="(color) in allBoardData.colorBoards" :key="color">
<div class="color_content" :style="{background:`rgb(${color?.rgbValue?.r},${color?.rgbValue?.g},${color?.rgbValue?.b})`}"></div>
<div class="color_content_body">
<div class="color_des">{{color.tcx}}</div>
<div class="color_des">{{color.name}}</div>
</div>
</div>
</div>
<div class="img_block_item">
<div class="lager_img_item" v-for="(skecth) in allBoardData.skecthboardFiles" :key="skecth">
<div class="all_img_item_block">
<img class="all_img_content" :src="skecth.imgUrl">
</div>
</div>
</div>
<div class="img_block_item">
<div class="lager_img_item" v-for="(marketing) in allBoardData.marketingSketchFiles" :key="marketing">
<div class="all_img_item_block">
<img class="all_img_content" :src="marketing.imgUrl">
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import MoodTemplate from '@/component/HomePage/MoodTemplate.vue'
import { useStore } from "vuex";
export default defineComponent({
components:{MoodTemplate},
setup() {
const store = useStore();
let allBoardData:any = computed(()=>{return store.state.UploadFilesModule.allBoardData})
return {
allBoardData,
}
}
})
</script>
<style lang="less" scoped>
.collection_review{
width: 40.8rem;
background: #fff;
position: relative;
.collection_review_mark{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
}
.img_block_item{
margin-bottom: 2rem;
// &.color_block_item{
// padding: 0 0.5rem 0 0.3rem;
// }
.lager_img_item{
display: inline-block;
width: 20.4rem;
height: 20.4rem;
vertical-align: top;
}
.sketch_img_item{
display: inline-block;
width: 20.4rem;
height: 42.2rem;
vertical-align: top;
}
.small_img_item{
width: 6.8rem;
height: 6.8rem;
display: inline-block;
vertical-align: top;
}
.color_item{
display: inline-block;
vertical-align: top;
// padding: 0 0.5rem;
margin-right: 1.6rem;
margin-bottom: 0.5rem;
&:nth-child(4n){
margin-right: 0;
}
}
.color_content{
width: 9rem;
height:6.2rem
}
.color_content_body{
width: 9rem;
padding: 0.7rem 0.2rem;
background: #FEFEFE;
border: 1px solid #E6E6E6;
.color_des{
font-size: 1rem;
font-family: Roboto;
font-weight: 500;
color: #000000;
margin-bottom: 0.5rem;
line-height: 1.3rem;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&:last-child{
margin-bottom: 0;
}
}
}
.all_img_item_block{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
.all_img_content{
max-height: 100%;
max-width: 100%;
&.cover_img{
width: 100%;
height: 100%;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,733 @@
<template>
<div class="printboard_upload_modal">
<div class="printboard_left_upload">
<div class="left_upload_header">
<div class="upload_header_item">
<div class="switch_type_list">
<div class="switch_type_item select_swtich">
<span>Upload</span>
</div>
<div @click="openLibrary()" class="switch_type_item">
<span>My Library</span>
</div>
</div>
</div>
<div class="upload_header_item">
<div><span class="select_img_num">{{getPinLength}}</span><span class="select_tip">selected</span></div>
<div v-show="fileList.length>1 || (moodBoards.length && fileList.length)" class="recollection_button" @click="generatePrint()">Generate</div>
</div>
</div>
<div class="printboard_body">
<div class="upload_img_body">
<div class="upload_item">
<div :class="['upload_file_item']" v-for="(file, index) in fileList" :key="file">
<div class="upload_file_img_block">
<div class="upload_file_item_content" v-show="file?.status === 'uploading'">
<a-spin :indicator="indicator" tip="Uploading..."/>
</div>
<div class="upload_file_item_content" @click="selectImg(file)" v-show="file?.status === 'done'">
<img v-lazy="file.imgUrl" class="upload_img" :key="file.imgUrl">
<div class="delete_file_block" @click.stop="deleteFile(index,file)">Delete</div>
</div>
</div>
<div class="pin_block" v-show="file?.status === 'done'">
<a-checkbox v-model:checked="file.pin">PIN</a-checkbox>
</div>
</div>
<div class="upload_file_item upload_component" v-show="fileList.length < 15">
<a-upload
v-show="fileList.length < 15"
:action="uploadUrl + '/api/element/upload'"
list-type="picture-card"
:before-upload="beforeUpload"
:data="{
...upload
}"
:headers="{Authorization:token}"
v-model:file-list="fileList"
:customRequest="function(){}"
multiple
:maxCount="15"
accept=".jpg,.png,.jpeg,.bmp"
@change="fileUploadChange"
>
<div class="upload_tip_block" >
<img class="upload_img_icon" src="@/assets/images/homePage/add_file.png">
</div>
</a-upload>
</div>
</div>
</div>
<div class="upload_max_tip">
<span class="icon iconfont icon-zhuyi"></span>
<span>Maximum 15 images can be uploaded, Maximum 2M per image</span>
</div>
</div>
</div>
<div class="generate_print">
<div class="generate_print_header">
<div class="generate_title">Generate New Print</div>
<div class="generate_save_button" @click="savePrint()">Save</div>
</div>
<div class="generate_print_content_block">
<div class="generate_print_content scroll_style">
<div class="image_block" v-for="(img, index) in printImgList" :key="index">
<div class="image_block_content">
<img class="image_body" v-lazy="img.imgUrl" :key="img.imgUrl">
<div class="delete_file_block" @click="deleteGenerateFile(index)">Delete</div>
</div>
</div>
</div>
<div class="generate_loading_mark" v-show="generateloading">
<a-spin size="large" />
</div>
</div>
</div>
<Cropper ref="Cropper" @handleCropperSuccess="handleCropperSuccess" @closeCropper="deletUploadFile()" :cropperFileData="cropperFileData" :isUpload="isUpload"></Cropper>
<Material ref="Material" @confirmSelect="confirmSelect"></Material>
</div>
</template>
<script lang="ts">
import { defineComponent,h,ref,computed } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue';
import {getCookie} from '@/tool/cookie'
import {getUploadUrl} from '@/tool/util'
import {useStore} from 'vuex'
import { Https } from "@/tool/https";
import { message,Upload} from 'ant-design-vue';
import Cropper from '@/component/HomePage/Cropper.vue'
import Material from '@/component/HomePage/Material.vue'
export default defineComponent({
components:{
Cropper,
Material
},
setup(){
let store:any =useStore()
let fileList:any = ref([]),//选中的文件id数据
printImgList:any = ref([]), //print的印花图片
moodBoards:any = computed(()=>{return store.state.UploadFilesModule.moodboardFiles})
return {
fileList,
printImgList,
moodBoards
}
},
computed:{
getPinLength(){
let selectLength:any = 0
for(let item of this.fileList){
if(item.pin){
selectLength++
}
}
return selectLength
}
},
data(){
return {
swtich_type:'upload',
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
upload:{
isPin:0,
level1Type:'Printboard',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
store:useStore(),
cropperFileData:{name:'',uid:''}, //裁剪的原始文件数据
currentFileNum:0, //当前上传的文件数
isUpload:false,
generateloading:false,
}
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
openLibrary(){
let material:any = this.$refs.Material
material.init('Printboard')
},
fileUploadChange(data:any){
let file = data.file
let Cropper:any = this.$refs.Cropper
if(this.currentFileNum === 1){
var reader = new FileReader();
reader.onload = (e:any) => {
let data_new;
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data_new = window.URL.createObjectURL(new Blob([e.target.result]));
} else {
data_new = e.target.result;
}
Cropper.getOptionImg(data_new)
};
// 转化为base64
// reader.readAsDataURL(file)
// 转化为blob
reader.readAsArrayBuffer(file.originFileObj);
this.cropperFileData = file
Cropper.changeShowModal(true)
}else{
this.customRequest(file)
}
},
beforeUpload(file:any,fileList:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
if(isJpgOrPng && isLt2M){
this.currentFileNum = fileList.length
}else{
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
}
},
deleteFile(index:any,file:any){
this.fileList.splice(index, 1)
this.store.commit('setPrintboardFile',this.fileList)
},
deleteGenerateFile(index:any){
this.printImgList.splice(index, 1)
this.store.commit('setGeneratePrintFile',this.printImgList)
},
randomRange(min:any, max:any, num:any) { // min最小值max最大值 num排除的值
let index = Math.floor(Math.random() * (max - min)) + min;
while(index === num){
index = Math.floor(Math.random() * (max - min)) + min;
}
return index
},
generatePrint(){
let data:any = {}
//随机获取图片id
if(!this.moodBoards.length){ //mood没有图片
let index1 = -1
let index2 = -2
if(!this.getPinLength){ //没pin住
index1 = this.randomRange(0, this.fileList.length, -1)
index2 = this.randomRange(0, this.fileList.length, index1)
}else if(this.getPinLength === 1){ //pin住1个
this.fileList.forEach((element:any,index:number) => {
if(element.pin){
index1 = index
}
});
index2 = this.randomRange(0, this.fileList.length, index1)
}else{ //pin住多个
let selectIndexList:any = []
this.fileList.forEach((element:any,index:number) => {
if(element.pin){
selectIndexList.push(index)
}
});
index1 = this.randomRange(0, selectIndexList.length, -1) //pin住的中随机选一个
index2 = this.randomRange(0, this.fileList.length, selectIndexList[index1]) //除了选中的外再来一个
}
data = {
select1Id:this.fileList[index1].id,
select2Id:this.fileList[index2].id
}
}else{
let index1 = this.randomRange(0, this.moodBoards.length, -1)
let index2 = -2
if(!this.getPinLength){ //没pin住
index2 = this.randomRange(0, this.fileList.length, -1)
}else if(this.getPinLength === 1){ //pin住1个
this.fileList.forEach((element:any,index:number) => {
if(element.pin){
index2 = index
}
});
}else{ //pin住多个
let selectIndexList:any = []
this.fileList.forEach((element:any,index:number) => {
if(element.pin){
selectIndexList.push(index)
}
});
index2 = this.randomRange(0, selectIndexList.length, -1) //pin住的中随机选一个
}
data = {
select1Id:this.moodBoards[index1].resData.id,
select2Id:this.fileList[index2].id
}
}
data.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
this.generateloading = true
Https.axiosPost(Https.httpUrls.elementGeneratePrint, data).then((rv) =>{
if(rv){
let data = {
imgUrl:rv.url,
resData:rv
}
this.printImgList.push(data)
this.store.commit('setGeneratePrintFile',this.printImgList)
this.generateloading = false
}
}).catch(res=>{
this.generateloading = false
})
},
savePrint(){
let printId = this.printImgList.map((v:any) => v.resData.id)
let data = {
printId:printId,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
Https.axiosPost(Https.httpUrls.elementSavePrint, data).then((rv) =>{
if(rv){
message.success('Save successfully')
}
})
},
customRequest(data:any){
let new_data = {
...this.upload,
file:data.originFileObj
}
let fileUid = data.uid
Https.axiosPost('/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
if (rv) {
for(let file of this.fileList){
if(fileUid === file.uid){
file.status = 'done'
file.imgUrl = rv.url
file.pin = false
file.id = rv.id
file.resData = rv
}
}
let fileList = this.fileList.filter((v:any)=> v.status === 'done')
this.store.commit('setPrintboardFile',fileList)
}
}
).catch((res)=>{
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(fileUid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
});
},
closeCropper(type:any){
if(this.isUpload){
return
}
if(type == 'error'){
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(this.cropperFileData.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
}
let Cropper:any = this.$refs.Cropper
Cropper.closeCropper()
},
deletUploadFile(){
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(this.cropperFileData.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
},
handleCropperSuccess(event:any){
let {file, fileData} =event
let new_data = {
...this.upload,
file:file
}
if(this.isUpload){
return
}
this.isUpload = true
const hide = message.loading('loading', 0);
Https.axiosPost('/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
for(let file of this.fileList){
if(fileData.uid === file.uid){
file.status = 'done'
file.imgUrl = rv.url
file.id = rv.id
file.resData = rv
}
}
let fileList = this.fileList.filter((v:any)=> v.status === 'done')
this.isUpload = false
this.closeCropper('success')
this.cropperFileData = {name:'',uid:''}
this.store.commit('setPrintboardFile',fileList)
hide()
}
).catch(res=>{
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(fileData.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
this.cropperFileData = {name:'',uid:''}
this.isUpload = false
this.closeCropper('error')
hide()
});
},
recollection(){
this.fileList = JSON.parse(JSON.stringify(this.store.state.UploadFilesModule.allBoardData.printboardFiles))
this.printImgList = JSON.parse(JSON.stringify(this.store.state.UploadFilesModule.allBoardData.generatePrintFiles))
this.store.commit('setPrintboardFile',this.fileList)
this.store.commit('setGeneratePrintFile',this.printImgList)
},
confirmSelect(event:any){
for(let item of event){
let data = {
imgUrl:item.url,
resData:item,
pin:false,
id:item.id,
status:'done',
}
if(this.fileList.length == 15){
message.error('Maximum number of allowable file uploads has been exceeded')
break
}
this.fileList.push(data)
}
this.store.commit('setPrintboardFile',this.fileList)
}
}
})
</script>
<style lang="less" scoped>
.printboard_upload_modal{
padding: 1rem 1rem 1.8rem 1rem;
height: 100%;
background: #F2F3FB;
display: flex;
justify-content: space-between;
.printboard_left_upload{
width: calc(100% - 39.8rem);
height: 100%;
background: #fff;
padding: 0.5rem 2.2rem 2rem 2.6rem;
box-sizing: border-box;
.left_upload_header{
display: flex;
justify-content: space-between;
.upload_header_item{
display: flex;
align-items: center;
.switch_type_list{
display: flex;
align-items: center;
.switch_type_item{
display: flex;
align-items: center;
padding: 0 2rem;
height: 4rem;
background: #fff;
line-height: 4rem;
font-size: 1.6rem;
margin-right: 2.2rem;
color: #5B5E69;
cursor: pointer;
&.select_swtich{
color: #343579;
}
.switch_icon{
font-size: 1.8rem;
margin-right: 0.8rem;
}
}
}
.select_img_num{
font-size: 2rem;
color: #030303;
font-weight: bold;
}
.select_tip{
font-size: 1.6rem;
margin-left: 0.9rem;
color: #B7B7B7;
}
.recollection_button{
padding: 0 1rem;
height: 3.2rem;
line-height: 3.2rem;
background: #E6E6F6;
font-size: 1.2rem;
color: #343579;
margin-left: 0.9rem;
cursor: pointer;
}
}
}
.printboard_body{
margin-top: 1rem;
height: calc(100% - 5rem);
.upload_img_body{
height: calc(100% - 3rem);
overflow-y: auto;
margin-bottom: 1rem;
}
.upload_file_item{
margin: 0 2rem 2rem 0;
display: inline-block;
vertical-align: top;
.upload_file_img_block{
width: 16.5rem;
height: 16.5rem;
border: 1px solid #F5F5F5;
}
.pin_block{
text-align: center;
margin-top:1.6rem;
}
&.upload_component{
border: none;
}
.upload_file_item_content{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: relative;
cursor: pointer;
&:hover .delete_file_block{
display: block;
}
.upload_img{
display: block;
height: 100%;
width: 100%;
}
.delete_file_block{
display: none;
width: 100%;
height: 4rem;
background: rgba(0,0,0,0.2);
font-size: 1.6rem;
color: #FFFFFF;
line-height: 4rem;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
}
.upload_img_icon{
width: 4.6rem;
}
}
.upload_max_tip{
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
color: #030303;
.icon-zhuyi{
font-size: 1.6rem;
margin-right: 0.7rem;
}
}
}
}
.generate_print{
width: 38.4rem;
height: 100%;
background: #fff;
.generate_print_header{
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1rem 2.5rem 2.5rem;
.generate_title{
font-size: 1.6rem;
font-weight: bold;
color: #030303;
}
.generate_save_button{
background: #E6E6F6;
padding: 0.1rem;
padding: 0 2.7rem;
font-size: 1.4rem;
height: 3.2rem;
line-height: 3.2rem;
cursor: pointer;
color: #343579;
}
}
.generate_print_content_block{
height: calc(100% - 6.7rem);
position: relative;
.generate_loading_mark{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.4);
z-index: 2;
}
.generate_print_content{
overflow-y: auto;
height: 100%;
padding:0 0.8rem;
position: relative;
.image_block{
display: inline-block;
margin-right: 1.6rem;
margin-bottom: 1.6rem;
width: 16.5rem;
height: 16.5rem;
border: 0.1rem solid #F5F5F5;
vertical-align: top;
&:nth-child(2n){
margin-right: 0;
}
.image_block_content{
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
position: relative;
&:hover .delete_file_block{
display: block;
}
.delete_file_block{
display: none;
width: 100%;
height: 4rem;
background: rgba(0,0,0,0.2);
font-size: 1.6rem;
color: #FFFFFF;
line-height: 4rem;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
cursor: pointer;
}
}
.image_body{
max-width: 100%;
max-height: 100%;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,420 @@
<template>
<div class="sketchboard_upload_modal">
<div class="switch_type_list">
<div class="switch_type_item select_swtich">
<span>Upload</span>
</div>
<div @click="openLibrary()" class="switch_type_item">
<span>My Library</span>
</div>
</div>
<div class="sketchboard_body">
<div class="upload_img_body scroll_style">
<div class="upload_item">
<div class="upload_file_item" v-for="(file,index) in fileList" :key="file">
<div class="upload_file_item_content" v-show="file?.status === 'uploading'">
<a-spin :indicator="indicator" tip="Uploading..."/>
</div>
<div class="upload_file_item_content" v-show="file?.status === 'done'">
<img :src="file?.imgUrl" class="upload_img">
<div class="operate_file_block" >
<!-- <div class="delete_file_block" @click="deleteFile(index)">Delete</div> -->
<div class="select_img_type">
<div class="select_category" @click.stop="showFileCategory(file)">
{{getSketchLabel(file.category)}}
<div :class="['icon','iconfont', 'icon-xiala', file.categoryShow?'icon_rotate':'']"></div>
</div>
<div class="category_list" v-show="file.categoryShow">
<div :class="['category_item', file.category == cate.value?'select_category_item':'']" v-for="(cate,index) in sketchCatecoryList" :key="index" @click="selectFileCategory(file,cate)">{{cate.label}}</div>
</div>
</div>
</div>
<div class="delete_file_block" @click="deleteFile(index)">
<span class="icon iconfont icon-shanchu"></span>
</div>
</div>
<div class="pin_block" v-show="file?.status === 'done'">
<a-checkbox v-model:checked="file.pin">PIN</a-checkbox>
</div>
</div>
<div class="upload_file_item upload_component" v-show="fileList.length < 15">
<a-upload
:action="uploadUrl + '/api/element/upload'"
list-type="picture-card"
:data="{
...upload
}"
:before-upload="beforeUpload"
:headers="{Authorization:token}"
v-model:file-list="fileList"
multiple
:maxCount="15"
accept=".jpg,.png,.jpeg,.bmp"
@change="(file)=>fileUploadChange(file)"
>
<div class="upload_tip_block" v-show="fileList.length < 15">
<img class="upload_img_icon" src="@/assets/images/homePage/add_file.png">
</div>
</a-upload>
</div>
</div>
</div>
<div class="upload_max_tip">
<span class="icon iconfont icon-zhuyi"></span>
<span>Maximum 15 images can be uploaded, Maximum 2M per image</span>
</div>
</div>
<Material ref="Material" @confirmSelect="confirmSelect"></Material>
</div>
</template>
<script lang="ts">
import { defineComponent, h,ref } from 'vue'
import { LoadingOutlined } from '@ant-design/icons-vue';
import {getCookie} from '@/tool/cookie'
import {getUploadUrl} from '@/tool/util'
import {useStore} from 'vuex'
import { message,Upload} from 'ant-design-vue';
import Material from '@/component/HomePage/Material.vue'
export default defineComponent({
components:{Material},
setup(){
let fileList:any = ref([])
return {
fileList
}
},
data(){
return{
swtich_type:'upload',
indicator : h(LoadingOutlined, {
style: {
fontSize: '2.4rem',
},
spin: true,
}),
upload:{
isPin:0,
level1Type:'Sketchboard',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
},
token:'',
uploadUrl:'',
store:useStore(),
sketchCatecoryList:[
{
value: 'Outwear',
label: "Outwear",
},
{
value: 'Blouse',
label: "Blouse",
},
{
value: 'Dress',
label: "Dress",
},
{
value: 'Trousers',
label: "Trousers",
},
{
value: 'Skirt',
label: "Skirt",
},
],
}
},
computed:{
getSketchLabel(value){
return (value:any)=>{
let lable = '';
for(let item of this.sketchCatecoryList){
if(item.value === value){
lable = item.label
break
}
}
return lable
}
}
},
mounted(){
this.token = getCookie('token') || ''
this.uploadUrl = getUploadUrl()
},
methods:{
openLibrary(){
let material:any = this.$refs.Material
material.init('Sketchboard')
},
fileUploadChange(data:any){
let file = data.file
if(file.status === 'done'){
let res = JSON.parse(file.xhr.response)
file.imgUrl = res.data.url
file.resData = res.data
file.pin = false
file.category = 'Outwear'
file.categoryShow = false
let fileList = this.fileList.filter((v:any)=> v.status === 'done')
this.store.commit('setSketchboardFile',fileList)
}else if(file.status === 'error'){
let index = -1
this.fileList.forEach((ele:any,index1:any) => {
if(file.uid === ele.uid){
index = index1
}
});
if(index > -1){
this.fileList.splice(index, 1)
}
message.error(file.name + 'upload failed')
}
},
beforeUpload(file:any){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/bmp';
if (!isJpgOrPng) {
message.error('You can only upload Image file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 5MB!');
}
return (isJpgOrPng && isLt2M) || Upload.LIST_IGNORE;
},
showFileCategory(file:any){
file.categoryShow = true
document.addEventListener('click', this.hiddenFileCategory)
},
selectFileCategory(file:any,cate:any){
file.category = cate.value
this.store.commit('setSketchboardFile',this.fileList)
},
hiddenFileCategory(){
for(let item of this.fileList){
item.categoryShow = false
}
document.removeEventListener('click', this.hiddenFileCategory)
},
deleteFile(index:any){
this.fileList.splice(index, 1)
this.store.commit('setSketchboardFile',this.fileList)
},
recollection(){
this.fileList = JSON.parse(JSON.stringify(this.store.state.UploadFilesModule.allBoardData.skecthboardFiles))
this.store.commit('setSketchboardFile',this.fileList)
},
confirmSelect(event:any){
for(let item of event){
let data = {
imgUrl:item.url,
resData:item,
pin:false,
status:'done',
category:item.level2Type || 'Outwear',
categoryShow:false,
}
if(this.fileList.length == 15){
message.error('Maximum number of allowable file uploads has been exceeded')
break
}
this.fileList.push(data)
}
this.store.commit('setSketchboardFile',this.fileList)
}
}
})
</script>
<style lang="less" scoped>
.sketchboard_upload_modal{
padding: 1.5rem 2.6rem 4rem;
height: 100%;
.switch_type_list{
display: flex;
align-items: center;
.switch_type_item{
display: flex;
align-items: center;
padding: 0 2rem;
height: 4rem;
background: #fff;
border-radius: 0.8rem;
line-height: 4rem;
font-size: 1.6rem;
margin-right: 2.2rem;
color: #5B5E69;
cursor: pointer;
&.select_swtich{
color: #343579;
}
.switch_icon{
font-size: 1.8rem;
margin-right: 0.8rem;
}
}
}
.sketchboard_body{
margin-top: 1rem;
height: calc(100% - 5rem);
.upload_img_body{
height: calc(100% - 3rem);
overflow-y: auto;
margin-bottom: 1rem;
}
.upload_file_item{
margin: 0 2rem 2rem 0;
display: inline-block;
width: 16.5rem;
border: 1px solid #F5F5F5;
vertical-align: top;
&.upload_component{
border: none;
}
.upload_file_item_content{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
height: 16.5rem;
position: relative;
cursor: pointer;
.upload_img{
display: block;
max-height: 100%;
max-width: 100%;
}
.delete_file_block{
display: none;
width: 3.2rem;
height: 3.2rem;
background: rgba(0,0,0,0.6);
border-radius: 0.4rem;
position: absolute;
top: 0.9rem;
right: 0.9rem;
text-align: center;
line-height: 3.2rem;
.icon-shanchu{
font-size: 1.6rem;
color: #fff;
}
}
&:hover .delete_file_block{
display: block;
}
.operate_file_block{
width: 100%;
height: 4rem;
font-size: 1.6rem;
color: #FFFFFF;
position: absolute;
left: 0;
bottom: 0;
.select_img_type{
height: 100%;
line-height: 4rem;
text-align: center;
background: rgba(0,0,0,0.6);
position: relative;
.select_category{
display: flex;
align-items: center;
justify-content: center;
.icon-xiala{
margin-left: 0.8rem;
}
}
.icon_rotate{
-moz-transform:rotate(180deg);
-webkit-transform:rotate(180deg);
transform: rotate(180deg);
animation-direction: 0.5s;
}
.category_list{
position: absolute;
width: 100%;
cursor: pointer;
position: absolute;
top: 4.1rem;
left: 0;
background: rgba(0,0,0,0.4);
border: 1px solid #343579;
border-radius: 0.8rem;
overflow: hidden;
z-index: 2;
.category_item{
text-align: left;
font-size: 1.4rem;
padding: 1rem 1.9rem;
line-height: 1.6rem;
&.select_category_item{
background: linear-gradient(160deg, #AC2A3B, #292161);
}
&:hover{
background: linear-gradient(160deg, #AC2A3B, #292161);
}
}
}
}
}
}
.pin_block{
text-align: center;
margin-top:1.6rem;
}
.upload_img_icon{
width: 4.6rem;
}
}
.upload_max_tip{
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
color: #030303;
.icon-zhuyi{
font-size: 1.6rem;
margin-right: 0.7rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,157 @@
<template>
<div v-if="showCollectionModal">
<a-modal class="modal_component collection_modal"
v-model:visible="showCollectionModal"
:footer="null"
width="80%"
:maskClosable="false"
:centered="true"
>
<template #title>
<div v-show="collectionStep === 1">Moodboard Upload</div>
<div v-show="collectionStep === 2"><span class="icon iconfont icon-fanhui header_icon_fanhui" @click="lastStep()"></span>Printboard Upload</div>
<div v-show="collectionStep === 3"><span class="icon iconfont icon-fanhui header_icon_fanhui" @click="lastStep()"></span>Colorboard Upload</div>
<div v-show="collectionStep === 4"><span class="icon iconfont icon-fanhui header_icon_fanhui" @click="lastStep()"></span>Sketchboard Upload</div>
<div v-show="collectionStep === 5"><span class="icon iconfont icon-fanhui header_icon_fanhui" @click="lastStep()"></span>Markets Sketch</div>
</template>
<template #closeIcon>
<div class="header_right_block" @click.stop="">
<div v-if="collectionStep < 5" class="next_step_button" @click.stop="nextStep()">Next Step</div>
<div v-else class="next_step_button" @click.stop="finishCollection()">Finish</div>
<div class="header_cancel_button" @click.stop="cancelDsign()">Cancel</div>
</div>
</template>
<div class="collection_modal_body">
<MoodboardUpload ref="MoodboardUpload" v-show="collectionStep === 1"></MoodboardUpload>
<PrintboardUpload ref="PrintboardUpload" v-show="collectionStep === 2"></PrintboardUpload>
<ColorboardUpload ref="ColorboardUpload" v-show="collectionStep === 3"></ColorboardUpload>
<SketchboardUpload ref="SketchboardUpload" v-show="collectionStep === 4"></SketchboardUpload>
<MarketingSketchUpload ref="MarketingSketchUpload" v-show="collectionStep === 5"></MarketingSketchUpload>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent ,createVNode } from 'vue'
import MoodboardUpload from '@/component/HomePage/MoodboardUpload.vue'
import PrintboardUpload from '@/component/HomePage/PrintboardUpload.vue'
import ColorboardUpload from '@/component/HomePage/ColorboardUpload.vue'
import SketchboardUpload from '@/component/HomePage/SketchboardUpload.vue'
import MarketingSketchUpload from '@/component/HomePage/MarketingSketchUpload.vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { Modal,message } from 'ant-design-vue';
import {useStore} from 'vuex'
export default defineComponent({
components:{
MoodboardUpload,
PrintboardUpload,
ColorboardUpload,
SketchboardUpload,
MarketingSketchUpload
},
data(){
return{
showCollectionModal:false,
collectionStep:1,
store:useStore()
}
},
methods:{
nextStep(){
this.collectionStep = this.collectionStep + 1
},
lastStep(){
this.collectionStep = this.collectionStep - 1
},
changeCollectionModal(type:boolean){
this.showCollectionModal = type
},
recollection(){
setTimeout(()=>{
let childredCom = ['MoodboardUpload','PrintboardUpload','ColorboardUpload','SketchboardUpload','MarketingSketchUpload']
for(let child of childredCom){
let childRef:any = this.$refs[child]
childRef.recollection()
}
},200)
},
//取消
cancelDsign(){
let _this = this
Modal.confirm({
title: 'The uploaded files will not be saved, being sure to continue? ',
icon: createVNode(ExclamationCircleOutlined),
okText: 'Yes',
cancelText: 'No',
// centered:true,
onOk() {
_this.showCollectionModal = false
_this.store.commit('clearAllData')
_this.collectionStep = 1
}
});
},
//完成
finishCollection(){
let colorBoards = this.store.state.UploadFilesModule.colorBoards
if(!colorBoards || colorBoards?.length < 1){
message.error('You must choose one or more colors for further process.')
return
}
this.showCollectionModal =false
this.collectionStep = 1
this.$emit('finishCollection')
}
}
})
</script>
<style lang="less" scoped>
.collection_modal{
.header_icon_fanhui{
margin-right: 1rem;
font-size: 2rem;
cursor: pointer;
}
.header_right_block{
display: flex;
align-items: center;
position: absolute;
right: 2.1rem;
height: 100%;
.next_step_button{
padding: 0 1.2rem;
height: 3.2rem;
background: #343579;
font-size: 1.4rem;
color: #FFFFFF;
line-height: 3.2rem;
margin-right: 1.6rem;
white-space: nowrap;
cursor: pointer;
}
.header_cancel_button{
padding: 0 2.1rem;
height: 3.2rem;
background: #E4E5EB;
font-size: 1.4rem;
color: #030303;
line-height: 3.2rem;
white-space: nowrap;
cursor: pointer;
}
}
.collection_modal_body{
height: 100%;
}
}
</style>

View File

@@ -0,0 +1,708 @@
<template>
<div v-show="placementShow">
<a-modal class="models_placement_component"
v-model:visible="placementShow"
:footer="null"
width="111.5rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="models_placement_body" >
<div class="palcement_modal_header">
<div class="models_placement_title">Registration</div>
<div class="placement_operate_list">
<div class="operate_item" v-show="locationList.length == 6" @click="submitPlacement">
<div class="icon iconfont icon-baocun1 operate_icon"></div>
<div class="operate_item_des">Submit</div>
</div>
<div class="operate_item" v-show="locationList.length == 6" @click="printPreview">
<div class="icon iconfont icon-shengchengyulan operate_icon"></div>
<div class="operate_item_des">Preview</div>
</div>
<div class="operate_item" v-show="perviewUrl" @click="backPreview">
<div class="icon iconfont icon-fanhui1 operate_icon"></div>
<div class="operate_item_des">Back</div>
</div>
<div class="operate_item" @click="restoreLocationList">
<div class="icon iconfont icon-huifu operate_icon"></div>
<div class="operate_item_des">Restore</div>
</div>
</div>
</div>
<div class="models_placement_content">
<div class="plcaement_point_content">
<div class="placement_point_item" v-for="(point,index) in pointList" :key="index" >
<div class="ponit_title">{{point.title}}</div>
<div class="point_list">
<div class="point_item" v-for="item in point.pointList" :key="item.color" :style="{borderColor:item.color,visibility:item.show?'inherit':'hidden'}" @mousedown="AddDian(item)"><div class="point_block" :style="{background:item.color}"></div></div>
</div>
</div>
</div>
<div class="placement_content_operate_list">
<div class="placement_content_operate_item" @click="changeRemoveStatus">
<div class="placement_remove_point_block"></div>
<div class="placement_content_operate_des">Remove Point</div>
</div>
</div>
<div class="placement_tip_content">Please change the pure white inside the mannequin for another color to enhance your experience</div>
<div class="img_preview_block" >
<div class="perview_mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
<div class="img_content_block" ref="imgbox" @mousemove="startMove($event)">
<img class="placement_img" :src="perviewUrl || printObject?.url">
<div :class="['ponit_click',isRemoveStatus?'remove_point_click':'']" v-show="!perviewUrl" v-for="(item,index) in locationList" :key="item" :style="{left:item.left+'px', top:item.top+'px',borderColor:item.color}" @mousedown="getMouseDown($event,item,index)" @mousemove="startMove($event)">
<div class="placement_add_point_content" :style="{background:item.color}" v-show="!isRemoveStatus"></div>
<div class="icon iconfont icon-guanbi" v-show="isRemoveStatus"></div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,createVNode} from 'vue'
import { Https } from "@/tool/https";
import {dataURLtoFile} from "@/tool/util"
import { useStore } from "vuex";
import { Modal,message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
export default defineComponent({
setup() {
const store = useStore()
let oldLocationList:any = ref([])
let locationList:any = ref([])
let printObject:any = ref({})
let imgBox:any = ref({})
let intObj:any = ref(null)
let currentSign:any = ref({})
let oldPointList:any = ref([]) //备份点
let pointList:any = ref([])
let isSubmit:any = ref(false) //判断历史是否有提交过
return {
store,
oldLocationList,
locationList,
printObject,
imgBox,
intObj,
currentSign,
oldPointList,
pointList,
isSubmit
}
},
data(){
return{
placementShow:false,
collectionIndex:0,
startDian:false,
moveOriginal:{posX: 0, posY: 0},
isRemoveStatus:false,
placement_sacle:30,
perviewUrl:'',//预览的图片地址
isShowMark:false,
}
},
methods:{
formatter(value:number){
return `${value}%`;
},
showPlacementModal(data:any){
this.placementShow = true
this.printObject = {
...data
}
setTimeout(()=>{
let imgbox:any = this.$refs.imgbox
let position = imgbox.getBoundingClientRect()
this.imgBox = {
width:imgbox.clientWidth,
height:imgbox.scrollHeight,
left : position.left,
top:position.top,
scrollTop:imgbox.scrollTop || 0,
}
this.getDefaultPointList(this.imgBox)
},500)
},
//初始化可以使用的点位
getDefaultPointList(imgBox:any){
this.isSubmit = false
this.pointList = [
{
title:'SHOULDER',
pointList:[{type:'shoulderLeft',color:'#6E70FF',show:true,field:'shoulder'},{type:'shoulderRight',color:'#6E70FF',show:true,field:'shoulder'}]
},
{
title:'WAISTBAND',
pointList:[{type:'waistbandLeft',color:'#6FCEFF',show:true,field:'waistband'},{type:'waistbandRight',color:'#6FCEFF',show:true,field:'waistband'}]
},
{
title:'HAND',
pointList:[{type:'handLeft',color:'#CCFF7B',show:true,field:'hand'},{type:'handRight',color:'#CCFF7B',show:true,field:'hand'}]
},
]
if(this.printObject.templateId){//编辑
this.isSubmit = true
for(let ponit of this.pointList){
for(let pointItem of ponit.pointList){
if(this.printObject[pointItem.type]?.length){
pointItem.show = false
let data = {
left:this.printObject[pointItem.type][0] * imgBox.width - 12,
top:this.printObject[pointItem.type][1] * imgBox.height - 12,
color:pointItem.color,
type:pointItem.type,
field:pointItem.field,
}
this.locationList.push(data)
}
}
}
this.oldLocationList = JSON.parse(JSON.stringify(this.locationList))
}
this.oldPointList = JSON.parse(JSON.stringify(this.pointList))
},
AddDian(point:any){
if(!point.show){
return
}
this.startDian = true
this.isRemoveStatus = false
this.intObj = point
},
changeRemoveStatus(){
this.isRemoveStatus = true
},
startMove(event:any){
if(this.isRemoveStatus){
return
}
let imgbox:any = this.$refs.imgbox
let scrollTop = imgbox.scrollTop;
if(this.intObj){
this.currentSign.left = event.clientX - this.imgBox.left
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top
this.currentSign.color = this.intObj.color
this.currentSign.type= this.intObj.type
this.currentSign.field = this.intObj.field
this.locationList.push(this.currentSign)
this.intObj.show = false
this.intObj = null
}else{
if(this.startDian){
this.currentSign.left = event.clientX - this.imgBox.left - this.moveOriginal.posX
this.currentSign.top = event.clientY + scrollTop - this.imgBox.top -this.moveOriginal.posY
document.addEventListener('mouseup', this.getMouseOver);
this.$forceUpdate()
this.setBoundarySign()
}
}
},
// 在边界上的签名域处理
setBoundarySign() {
let imgbox:any = this.$refs.imgbox
let height = imgbox.offsetHeight + imgbox.scrollTop;
// 2 为签名域的边框
let maxPosHeight = height - 24
let maxPosWidth = imgbox.clientWidth - 24 //+ this.signBox.paddLeft;
if (this.currentSign.top <= 0) {
this.currentSign.top = 0
} else if (this.currentSign.top >= maxPosHeight ) {
this.currentSign.top = maxPosHeight;
}
if (this.currentSign.left <= 0) {
this.currentSign.left = 0
} else if (this.currentSign.left >= maxPosWidth) {
this.currentSign.left = maxPosWidth;
}
},
getMouseDown(event:any,item:any,index:number){
if(this.isRemoveStatus){
for(let itemPoint of this.pointList){
for(let point of itemPoint.pointList){
if(item.type == point.type){
point.show = true
break
}
}
}
this.locationList.splice(index,1)
}else{
this.currentSign = item
// 计算出鼠标在签名域上的偏移
this.moveOriginal.posX = event.offsetX
this.moveOriginal.posY = event.offsetY // 1为边框
this.startDian = true
}
},
getMouseOver(){
this.startDian = false
this.currentSign = {}
document.removeEventListener('mouseup', this.getMouseOver);
},
closeModal(){
let _this = this
if(!this.isSubmit){
Modal.confirm({
title: "You haven't marked the image yet, and the model will not be uploaded. Are you sure you want to close it?",
icon: createVNode(ExclamationCircleOutlined),
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
// _this.getDefaultPointList(_this.imgBox)
_this.oldLocationList = []
_this.locationList = []
_this.intObj = null
_this.currentSign = {}
_this.isRemoveStatus = false
_this.placementShow = false
_this.perviewUrl = ''
}
});
}else{
// _this.getDefaultPointList(_this.imgBox)
_this.oldLocationList = []
_this.locationList = []
_this.intObj = null
_this.currentSign = {}
_this.isRemoveStatus = false
_this.placementShow = false
_this.perviewUrl = ''
}
},
restoreLocationList(){
this.pointList = JSON.parse(JSON.stringify(this.oldPointList))
this.locationList = JSON.parse(JSON.stringify(this.oldLocationList))
},
submitPlacement(){
if(this.printObject.templateId){
this.printObject.id = this.printObject.libraryId
this.confrimSubmit()
}else{
this.customRequest().then((rv:any)=>{
this.isShowMark = false
this.printObject.id = rv.id
this.confrimSubmit()
}).catch((res:any)=>{
this.isShowMark = false
})
}
},
confrimSubmit(){
let param = {
libraryId:this.printObject.id,
templateId:this.printObject.templateId || null,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
...this.getPrintLocation()
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.saveOrEditTemplatePoint, param).then(
(rv: any) => {
this.isShowMark = false
this.isSubmit = true
this.$emit('submitModelPlacement')
this.closeModal()
}
).catch(res=>{
this.isShowMark = false
});
},
customRequest(){
let new_data = {
file:this.printObject.file,
level1Type:'Models',
level2Type:'',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.isShowMark = true
return new Promise((resolve,reject)=>{
Https.axiosPost(Https.httpUrls.libraryUpload, new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
resolve(rv)
}
).catch((res)=>{
reject(res)
});
})
},
getPrintLocation(){
let {width , height} = this.imgBox
let locationData:any = {}
let returnData:any = {}
let newLocationList = JSON.parse(JSON.stringify(this.locationList))
//进行字段归类
for(let item of newLocationList){
locationData[item.field] = locationData[item.field] || []
locationData[item.field].push(item)
}
for(let key in locationData){
locationData[key].sort(this.sortBy("left")) //通过left字段进行排序
locationData[key].forEach((v:any,index:any) => {
v.type = !index ?v.field + 'Left' :v.field +'Right' //第一个是left第二个是right
v.left = ((v.left + 12) / width).toFixed(4)
v.top = ((v.top + 12) / height).toFixed(4)
returnData[v.type] = [v.left, v.top]
});
}
return returnData
},
sortBy(field:any) {
return function(a:any,b:any) {
return a[field] - b[field];
}
},
printPreview(){
let file = this.printObject.templateId ? null :this.printObject.file,
models = {
libraryId:this.printObject.libraryId || null,
templateId:this.printObject.templateId || null,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
...this.getPrintLocation()
}
let formData = new FormData();
formData.append('file', file);
formData.append("models", new Blob([JSON.stringify(models)], {type: "application/json"}));
if(this.isShowMark){
return
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.libraryModelsDot, formData,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
this.perviewUrl = rv
this.isShowMark = false
}
).catch(res=>{
this.isShowMark = false
});
},
backPreview(){
this.perviewUrl = ''
}
}
})
</script>
<style lang="less">
.models_placement_component{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.models_placement_body{
width: 100%;
height: 100%;
.palcement_modal_header{
position: relative;
height: 6.6rem;
width: 100%;
background: #F7F7F7;
.models_placement_title{
position: absolute;
height: 100%;
line-height: 6.6rem;
left: 3.7rem;
top: 0;
font-size: 1.8rem;
color: #030303;
}
.placement_operate_list{
display: flex;
align-items: center;
margin:0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 100%;
.operate_item{
margin-right: 4rem;
text-align: center;
cursor: pointer;
.operate_icon{
font-size: 2.1rem;
color: #64686D;
}
.operate_item_des{
height: 1.2rem;
font-size: 1.3rem;
color: #64686D;
}
&:last-child{
margin-right: 0;
}
}
}
}
.models_placement_content{
position: relative;
height: calc(100% - 6.6rem);
width: 100%;
padding: 1.1rem 0;
.plcaement_point_content{
width: 22rem;
background: #EBECF4;
position: absolute;
left: 0;
top:18.4rem;
padding: 3rem 2.7rem 0 1.4rem;
.placement_point_item{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
.ponit_title{
font-size: 1.3rem;
color: #64686D;
user-select:none; /* CSS3属性 */
}
.point_list{
display: flex;
align-items: center;
width: 6.2rem;
justify-content: space-between;
.point_item{
width: 2.4rem;
height: 2.4rem;
border-radius: 50%;
border:solid 0.2rem transparent;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
.point_block{
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
}
}
}
}
}
.placement_content_operate_list{
width: 10.6rem;
background: #EBECF4;
position: absolute;
right: 0;
top:18.4rem;
.placement_content_operate_item{
padding: 1.5rem 0;
text-align: center;
cursor: pointer;
.placement_content_operate_des{
width: 100%;
font-size: 1.3rem;
color: #64686D;
-moz-user-select:none;
user-select:none
}
.print_scale_value{
height: 1.1rem;
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.3rem;
color: #64686D;
}
.ant-tooltip-placement-top{
top: -37px !important;
}
.ant-slider-track{
background: #343579;
}
.ant-slider-handle{
border-color: #343579;
}
.placement_remove_point_block{
width: 2.4rem;
height: 2.4rem;
border: 2px solid #000000;
border-radius: 50%;
margin: 0 auto 0.4rem;
}
}
}
.placement_tip_content{
position: absolute;
right: 2rem;
bottom: 2rem;
width: 30rem;
font-size: 1.3rem;
color: #64686D;
}
.img_preview_block{
width: 40.8rem;
background: #ffffff;
margin: 0 auto;
position: relative;
user-select:none;
-moz-user-select:none;
position: relative;
.img_content_block{
width: 40.8rem;
height: 100%;
max-height: 63.2rem;
overflow-y: auto;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
position: relative;
&::-webkit-scrollbar { width: 0 !important }
}
.perview_mark_loading{
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 9;
display: flex;
align-items: center;
justify-content: center;
}
.placement_img{
width: 100%;
user-select:none;
-moz-user-select:none;
}
.ponit_click{
width: 24px;
height: 24px;
position: absolute;
border: 2px solid transparent;
border-radius: 50%;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
cursor: pointer;
&.remove_point_click{
border-color: transparent;
background: #EF3C3C;
}
.placement_add_point_content{
width: 4px;
height: 4px;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.icon-guanbi{
font-size: 20px;
line-height: 20px;
color:#ffffff;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,711 @@
<template>
<div v-show="placementShow">
<a-modal class="models_placement_mobile_component"
v-model:visible="placementShow"
:footer="null"
width="111.5rem"
:maskClosable="false"
:centered="true"
>
<template #closeIcon>
<div class="close_icon" @click.stop="closeModal()"><span class="icon iconfont icon-guanbi"></span></div>
</template>
<div class="models_placement_body" >
<div class="palcement_modal_header">
<div class="models_placement_title">Registration</div>
<div class="placement_operate_list">
<div class="operate_item" v-show="locationList.length == 6" @click="submitPlacement">
<div class="icon iconfont icon-baocun1 operate_icon"></div>
<div class="operate_item_des">Submit</div>
</div>
<div class="operate_item" v-show="locationList.length == 6" @click="printPreview">
<div class="icon iconfont icon-shengchengyulan operate_icon"></div>
<div class="operate_item_des">Preview</div>
</div>
<div class="operate_item" v-show="perviewUrl" @click="backPreview">
<div class="icon iconfont icon-fanhui1 operate_icon"></div>
<div class="operate_item_des">Back</div>
</div>
<div class="operate_item" @click="restoreLocationList">
<div class="icon iconfont icon-huifu operate_icon"></div>
<div class="operate_item_des">Restore</div>
</div>
</div>
</div>
<div class="models_placement_content" @touchmove="startMove($event)">
<div class="plcaement_point_content">
<div class="placement_point_item" v-for="(point,index) in pointList" :key="index" >
<div class="ponit_title">{{point.title}}</div>
<div class="point_list">
<div class="point_item" v-for="item in point.pointList" :key="item.color" :style="{borderColor:item.color,visibility:item.show?'inherit':'hidden'}" @touchstart="AddDian(item)"><div class="point_block" :style="{background:item.color}"></div></div>
</div>
</div>
</div>
<div class="placement_content_operate_list">
<div class="placement_content_operate_item" @click="changeRemoveStatus">
<div class="placement_remove_point_block"></div>
<div class="placement_content_operate_des">Remove Point</div>
</div>
</div>
<div class="placement_tip_content">Please change the pure white inside the mannequin for another color to enhance your experience</div>
<div class="img_preview_block" >
<div class="perview_mark_loading" v-show="isShowMark">
<a-spin size="large" />
</div>
<div class="img_content_block" ref="imgbox">
<img class="placement_img" :src="perviewUrl || printObject?.url">
<div :class="['ponit_click',isRemoveStatus?'remove_point_click':'']" v-for="(item,index) in locationList" :key="item" :style="{left:item.left+'px', top:item.top+'px',borderColor:item.color}" @touchstart="getMouseDown($event,item,index)" @touchmove="startMove($event)">
<div class="placement_add_point_content" :style="{background:item.color}" v-show="!isRemoveStatus"></div>
<div class="icon iconfont icon-guanbi" v-show="isRemoveStatus"></div>
</div>
</div>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,createVNode} from 'vue'
import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { Modal,message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
export default defineComponent({
setup() {
const store = useStore()
let oldLocationList:any = ref([])
let locationList:any = ref([])
let printObject:any = ref({})
let imgBox:any = ref({})
let intObj:any = ref(null)
let currentSign:any = ref({})
let oldPointList:any = ref([]) //备份点
let pointList:any = ref([])
let isSubmit:any = ref(false) //判断历史是否有提交过
return {
store,
oldLocationList,
locationList,
printObject,
imgBox,
intObj,
currentSign,
oldPointList,
pointList,
isSubmit
}
},
data(){
return{
placementShow:false,
collectionIndex:0,
startDian:false,
moveOriginal:{posX: 0, posY: 0},
isRemoveStatus:false,
placement_sacle:30,
perviewUrl:'',//预览的图片地址
isShowMark:false,
}
},
methods:{
formatter(value:number){
return `${value}%`;
},
showPlacementModal(data:any){
this.placementShow = true
this.printObject = {
...data
}
setTimeout(()=>{
let imgbox:any = this.$refs.imgbox
let position = imgbox.getBoundingClientRect()
this.imgBox = {
width:imgbox.clientWidth,
height:imgbox.scrollHeight,
left : position.left,
top:position.top,
scrollTop:imgbox.scrollTop || 0,
}
this.getDefaultPointList(this.imgBox)
},400)
},
//初始化可以使用的点位
getDefaultPointList(imgBox:any){
this.isSubmit = false
this.pointList = [
{
title:'SHOULDER',
pointList:[{type:'shoulderLeft',color:'#6E70FF',show:true,field:'shoulder'},{type:'shoulderRight',color:'#6E70FF',show:true,field:'shoulder'}]
},
{
title:'WAISTBAND',
pointList:[{type:'waistbandLeft',color:'#6FCEFF',show:true,field:'waistband'},{type:'waistbandRight',color:'#6FCEFF',show:true,field:'waistband'}]
},
{
title:'HAND',
pointList:[{type:'handLeft',color:'#CCFF7B',show:true,field:'hand'},{type:'handRight',color:'#CCFF7B',show:true,field:'hand'}]
},
]
if(this.printObject.templateId){//编辑
this.isSubmit = true
for(let ponit of this.pointList){
for(let pointItem of ponit.pointList){
if(this.printObject[pointItem.type]?.length){
pointItem.show = false
let data = {
left:this.printObject[pointItem.type][0] * imgBox.width - 12,
top:this.printObject[pointItem.type][1] * imgBox.height - 12,
color:pointItem.color,
type:pointItem.type,
field:pointItem.field,
}
this.locationList.push(data)
}
}
}
this.oldLocationList = JSON.parse(JSON.stringify(this.locationList))
}
this.oldPointList = JSON.parse(JSON.stringify(this.pointList))
},
AddDian(point:any){
if(!point.show){
return
}
this.startDian = true
this.isRemoveStatus = false
this.intObj = point
},
changeRemoveStatus(){
this.isRemoveStatus = true
},
startMove(event:any){
if(this.isRemoveStatus){
return
}
let imgbox:any = this.$refs.imgbox
let scrollTop = imgbox.scrollTop;
if(event.targetTouches[0].pageX > this.imgBox.left){
if(this.intObj){
this.currentSign.left = event.targetTouches[0].pageX - this.imgBox.left
this.currentSign.top = event.targetTouches[0].pageY + scrollTop - this.imgBox.top
this.currentSign.color = this.intObj.color
this.currentSign.type= this.intObj.type
this.currentSign.field = this.intObj.field
this.locationList.push(this.currentSign)
this.intObj.show = false
this.intObj = null
}else{
if(this.startDian){
this.currentSign.left = event.targetTouches[0].pageX - this.imgBox.left - this.moveOriginal.posX
this.currentSign.top = event.targetTouches[0].pageY + scrollTop - this.imgBox.top -this.moveOriginal.posY
document.addEventListener('touchend', this.getMouseOver);
this.$forceUpdate()
this.setBoundarySign()
}
}
}
},
// 在边界上的签名域处理
setBoundarySign() {
let imgbox:any = this.$refs.imgbox
let height = imgbox.offsetHeight + imgbox.scrollTop;
// 2 为签名域的边框
let maxPosHeight = height - 24
let maxPosWidth = imgbox.clientWidth - 24 //+ this.signBox.paddLeft;
if (this.currentSign.top <= 0) {
this.currentSign.top = 0
} else if (this.currentSign.top >= maxPosHeight ) {
this.currentSign.top = maxPosHeight;
}
if (this.currentSign.left <= 0) {
this.currentSign.left = 0
} else if (this.currentSign.left >= maxPosWidth) {
this.currentSign.left = maxPosWidth;
}
},
getMouseDown(event:any,item:any,index:number){
if(this.isRemoveStatus){
for(let itemPoint of this.pointList){
for(let point of itemPoint.pointList){
if(item.id == point.id){
point.show = true
break
}
}
}
this.locationList.splice(index,1)
}else{
this.currentSign = item
// 计算出鼠标在签名域上的偏移
this.moveOriginal.posX = event.targetTouches[0].pageX - this.imgBox.left - this.currentSign.left
this.moveOriginal.posY = event.targetTouches[0].pageY - this.imgBox.top- this.currentSign.top // 1为边框
this.startDian = true
}
},
getMouseOver(){
this.startDian = false
this.currentSign = {}
document.removeEventListener('touchend', this.getMouseOver);
},
closeModal(){
let _this = this
if(!this.isSubmit){
Modal.confirm({
title: "You haven't marked the image yet, and the model will not be uploaded. Are you sure you want to close it?",
icon: createVNode(ExclamationCircleOutlined),
okText: 'Ok',
cancelText: 'Cancel',
// centered:true,
onOk() {
// _this.getDefaultPointList(_this.imgBox)
_this.oldLocationList = []
_this.locationList = []
_this.intObj = null
_this.currentSign = {}
_this.isRemoveStatus = false
_this.placementShow = false
}
});
}else{
// _this.getDefaultPointList(_this.imgBox)
_this.oldLocationList = []
_this.locationList = []
_this.intObj = null
_this.currentSign = {}
_this.isRemoveStatus = false
_this.placementShow = false
}
},
restoreLocationList(){
this.pointList = JSON.parse(JSON.stringify(this.oldPointList))
this.locationList = JSON.parse(JSON.stringify(this.oldLocationList))
},
submitPlacement(){
if(this.printObject.templateId){
this.printObject.id = this.printObject.libraryId
this.confrimSubmit()
}else{
this.customRequest().then((rv:any)=>{
this.isShowMark = false
this.printObject.id = rv.id
this.confrimSubmit()
}).catch((res:any)=>{
this.isShowMark = false
})
}
},
confrimSubmit(){
let param = {
libraryId:this.printObject.id,
templateId:this.printObject.templateId || null,
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
...this.getPrintLocation()
}
this.isShowMark = true
Https.axiosPost(Https.httpUrls.saveOrEditTemplatePoint, param).then(
(rv: any) => {
this.isShowMark = false
this.isSubmit = true
this.$emit('submitModelPlacement')
this.closeModal()
}
).catch(res=>{
this.isShowMark = false
});
},
customRequest(){
let new_data = {
file:this.printObject.file,
level1Type:'Models',
level2Type:'',
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
}
this.isShowMark = true
return new Promise((resolve,reject)=>{
Https.axiosPost(Https.httpUrls.libraryUpload, new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
(rv: any) => {
resolve(rv)
}
).catch((res)=>{
reject(res)
});
})
},
getPrintLocation(){
let {width , height} = this.imgBox
let locationData:any = {}
let returnData:any = {}
let newLocationList = JSON.parse(JSON.stringify(this.locationList))
//进行字段归类
for(let item of newLocationList){
locationData[item.field] = locationData[item.field] || []
locationData[item.field].push(item)
}
for(let key in locationData){
locationData[key].sort(this.sortBy("left")) //通过left字段进行排序
locationData[key].forEach((v:any,index:any) => {
v.type = !index ?v.field + 'Left' :v.field +'Right' //第一个是left第二个是right
v.left = ((v.left + 12) / width).toFixed(4)
v.top = ((v.top + 12) / height).toFixed(4)
returnData[v.type] = [v.left, v.top]
});
}
return returnData
},
sortBy(field:any) {
return function(a:any,b:any) {
return a[field] - b[field];
}
},
printPreview(){
// this.printObject.scale = this.placement_sacle / 100
// this.printObject.location = this.printObject.ifSingle ? this.getPrintLocation() : []
// let designItemDetail = JSON.parse(JSON.stringify(this.store.state.DesignDetailModule.designItemDetail))
// designItemDetail.clothes[this.collectionIndex] = this.clothesData
// delete designItemDetail.designItemUrl
// let priority = designItemDetail.clothes.map((v:any)=>{
// return v.type
// })
// let data = {
// ...designItemDetail,
// priority:priority,
// timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
// }
// if(this.isShowMark){
// return
// }
// this.isShowMark = true
// Https.axiosPost(Https.httpUrls.detailPrintDot, data).then(
// (rv: any) => {
// this.perviewUrl = rv
// this.isShowMark = false
// }
// ).catch(res=>{
// this.isShowMark = false
// });
},
backPreview(){
this.perviewUrl = ''
}
}
})
</script>
<style lang="less">
.models_placement_mobile_component{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.close_icon{
width: 3.6rem;
height: 3.6rem;
background: #000000;
border-radius: 50%;
line-height: 3.6rem;
text-align: center;
.icon-guanbi{
font-size: 2rem;
color: #ffffff;
}
}
.models_placement_body{
width: 100%;
height: 100%;
.palcement_modal_header{
position: relative;
height: 6.6rem;
width: 100%;
background: #F7F7F7;
.models_placement_title{
position: absolute;
height: 100%;
line-height: 6.6rem;
left: 3.7rem;
top: 0;
font-size: 1.8rem;
color: #030303;
}
.placement_operate_list{
display: flex;
align-items: center;
margin:0 auto;
position: absolute;
left: 50%;
transform: translateX(-50%);
height: 100%;
.operate_item{
margin-right: 4rem;
text-align: center;
cursor: pointer;
.operate_icon{
font-size: 2.1rem;
color: #64686D;
}
.operate_item_des{
height: 1.2rem;
font-size: 1.3rem;
color: #64686D;
}
&:last-child{
margin-right: 0;
}
}
}
}
.models_placement_content{
position: relative;
height: calc(100% - 6.6rem);
width: 100%;
padding: 1.1rem 0;
.plcaement_point_content{
width: 22rem;
background: #EBECF4;
position: absolute;
left: 0;
top:18.4rem;
padding: 3rem 2.7rem 0 1.4rem;
.placement_point_item{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 3rem;
.ponit_title{
font-size: 1.3rem;
color: #64686D;
user-select:none; /* CSS3属性 */
}
.point_list{
display: flex;
align-items: center;
width: 6.2rem;
justify-content: space-between;
.point_item{
width: 2.4rem;
height: 2.4rem;
border-radius: 50%;
border:solid 0.2rem transparent;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
.point_block{
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
}
}
}
}
}
.placement_content_operate_list{
width: 10.6rem;
background: #EBECF4;
position: absolute;
right: 0;
top:18.4rem;
.placement_content_operate_item{
padding: 1.5rem 0;
text-align: center;
cursor: pointer;
.placement_content_operate_des{
width: 100%;
font-size: 1.3rem;
color: #64686D;
-moz-user-select:none;
user-select:none
}
.print_scale_value{
height: 1.1rem;
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.3rem;
color: #64686D;
}
.ant-tooltip-placement-top{
top: -37px !important;
}
.ant-slider-track{
background: #343579;
}
.ant-slider-handle{
border-color: #343579;
}
.placement_remove_point_block{
width: 2.4rem;
height: 2.4rem;
border: 2px solid #000000;
border-radius: 50%;
margin: 0 auto 0.4rem;
}
}
}
.placement_tip_content{
position: absolute;
right: 2rem;
bottom: 2rem;
width: 30rem;
font-size: 1.3rem;
color: #64686D;
}
.img_preview_block{
width: 40.8rem;
background: #ffffff;
margin: 0 auto;
position: relative;
user-select:none;
-moz-user-select:none;
position: relative;
.img_content_block{
width: 40.8rem;
height: 100%;
max-height: 63.2rem;
overflow-y: auto;
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
position: relative;
&::-webkit-scrollbar { width: 0 !important }
}
.perview_mark_loading{
position: absolute;
left: 0;
height: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.2);
z-index: 9;
display: flex;
align-items: center;
justify-content: center;
}
.placement_img{
width: 100%;
user-select:none;
-moz-user-select:none;
}
.ponit_click{
width: 24px;
height: 24px;
position: absolute;
border: 2px solid transparent;
border-radius: 50%;
-moz-user-select:none; /* Firefox私有属性 */
-webkit-user-select:none; /* WebKit内核私有属性 */
-ms-user-select:none; /* IE私有属性(IE10及以后) */
-khtml-user-select:none; /* KHTML内核私有属性 */
-o-user-select:none; /* Opera私有属性 */
user-select:none; /* CSS3属性 */
cursor: pointer;
&.remove_point_click{
border-color: transparent;
background: #EF3C3C;
}
.placement_add_point_content{
width: 4px;
height: 4px;
border-radius: 50%;
background: #6E70FF;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.icon-guanbi{
font-size: 20px;
line-height: 20px;
color:#ffffff;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1,386 @@
<template>
<div>
<a-modal class="models_modal"
v-model:visible="modelsModalShow"
:footer="null"
width="80%"
:maskClosable="false"
:centered="true"
>
<div class="models_header">
<div class="models_title">Select Mannequin</div>
<div class="models_header_right">
<div class="content_search_block">
<input class="search_input" placeholder="Search by name" v-model="searchPictureName" @keydown.enter="getLibraryList()">
<div class="search_icon_block" @click="getLibraryList()"><span class="icon iconfont icon-sousuo"></span></div>
</div>
<div class="icon iconfont icon-guanbi icon_close" @click="closeModal"></div>
</div>
</div>
<div class="models_content">
<div class="models_content_left">
<div class="content_left_header">
<div class="left_header_title">Current Mannequin</div>
<div class="system_button" @click="setSystemModel()">Standard Mannequin</div>
</div>
<div class="content_left_perview">
<img class="perview_img" :src="selectImg"/>
</div>
<div class="sure_button" @click="confimSure()">ok</div>
</div>
<div class="models_content_right">
<div class="models_content_body scroll_style">
<div class="content_img_item" v-for="(img) in imgList" :key="img.id" @click="selectImgItem(img)">
<div :class="['content_img_item_block', selectImgListId == img.libraryModelPoint.templateId ? 'select_item_img' :'']">
<img :src="img.url" class="content_img"/>
</div>
<div class="content_img_name">{{img.name}}</div>
</div>
<div class="no_data_block" v-show="!imgList.length && !isShowLoading">
<img src="@/assets/images/homePage/null_img.png">
</div>
<div class="no_data_block" v-show="isShowLoading">
<a-spin size="large"></a-spin>
</div>
</div>
<div class="table_pagination">
<a-pagination
v-model:current="currentPage"
v-model:pageSize="pageSize"
:total="total"
:showQuickJumper="true"
:showSizeChanger="false"
@change="changePage"
/>
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent, ref} from 'vue'
import { Https } from "@/tool/https";
import {useStore} from 'vuex'
import { message } from 'ant-design-vue';
const systemImg = require('../../assets/images/homePage/system_model.png')
export default defineComponent({
setup() {
const store = useStore();
let searchPictureName = ref('')
let modelsModalShow = ref(false)
let currentPage:any = ref(1)
let pageSize = ref(12)
let total = ref(0)
let imgList:any = ref([])
let isShowLoading:any = ref(false)
let selectImgListId:any = ref('')
let selectImg:any = ref('')
return{
store,
searchPictureName,
modelsModalShow,
currentPage,
pageSize,
total,
imgList,
isShowLoading,
selectImgListId,
selectImg
}
},
methods:{
init(code:any){
this.modelsModalShow = true
this.selectImg = this.store.state.HomeStoreModule.templateImgUrl || systemImg
this.selectImgListId = this.store.state.HomeStoreModule.templateId
this.getLibraryList()
},
selectImgItem(imgData:any){
this.selectImgListId = imgData.libraryModelPoint.templateId
this.selectImg = imgData.url
},
//改变页码
changePage(current: number, pageSize: number){
this.currentPage = current
this.pageSize = pageSize
this.getLibraryList()
},
getLibraryList(){
let data = {
level1Type:'Models',
level2Type:'',
page:this.currentPage,
pictureName:this.searchPictureName,
size:this.pageSize,
}
this.isShowLoading = true
Https.axiosPost(Https.httpUrls.queryLibraryPage,data).then(
(rv: any) => {
this.imgList = rv.content
this.total = rv.total
this.isShowLoading = false
}
).catch((res)=>{
this.isShowLoading = false
});
},
closeModal(){
this.modelsModalShow = false
this.searchPictureName = ''
this.imgList = []
this.currentPage = 1
this.pageSize = 10
this.total = 0
},
setSystemModel(){
this.selectImg = systemImg
this.selectImgListId = ''
},
//确定选择model
confimSure(){
this.$emit('sureSelectModel',{id:this.selectImgListId,url:this.selectImg})
this.closeModal()
}
}
})
</script>
<style lang="less">
.models_modal{
.ant-modal-close{
width: 3.6rem;
height: 3.6rem;
position: absolute;
top: -1.8rem;
right: -1.8rem;
}
.ant-modal-header{
display: none;
}
.ant-modal-body{
background: #F2F3FB;
height: 80vh;
min-height: 72rem;
overflow-y: hidden;
padding: 0;
}
.models_header{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 6.6rem;
background: #F7F7F7;
padding: 0 3.4rem 0 3rem;
.models_title{
font-size: 1.8rem;
color: #030303;
font-weight: 500;
}
.models_header_right{
display: flex;
justify-content: space-between;
align-items: center;
.content_search_block{
margin-right: 5rem;
display: flex;
.search_input{
width: 30rem;
padding-left: 1.5rem;
height: 4rem;
line-height: 3.8rem;
background: #FFFFFF;
border: 0.1rem solid #F1F1F1;
font-size: 1.6rem;
font-weight: 400;
&::placeholder {
color: #C2C2C2;
}
}
.search_icon_block{
width: 6rem;
height: 4rem;
line-height: 4rem;
text-align: center;
background: #343579;
cursor: pointer;
.icon-sousuo{
font-size: 2rem;
color: #FFFFFF;
}
}
}
.icon_close{
color: rgba(174, 178, 183, 1);
font-size: 2.4rem;
cursor: pointer;
}
}
}
.models_content{
padding-right: 1.4rem;
height: calc(100% - 6.6rem);
position: relative;
display: flex;
justify-content: space-between;
.models_content_left{
width: 36.4rem;
height: 100%;
background: #FFFFFF;
flex-shrink: 0;
.content_left_header{
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.3rem 1rem 0.9rem 3rem;
.left_header_title{
font-size: 1.6rem;
color: #333333;
}
.system_button{
padding: 0 1rem;
height: 3.2rem;
line-height: 3.2rem;
background: #E6E6F6;
font-size: 1.2rem;
color: #343579;
cursor: pointer;
}
}
.content_left_perview{
width: 100%;
height: calc(100% - 13.8rem);
padding: 1.9rem 3rem 0;
box-sizing: border-box;
margin-bottom: 1.3rem;
display: flex;
align-items: center;
justify-content: center;
.perview_img{
max-width: 100%;
max-height: 100%;
}
}
.sure_button{
width: 9.8rem;
height: 3.6rem;
background: #343579;
font-size: 1.4rem;
color: #FFFFFF;
text-align: center;
line-height: 3.6rem;
margin: 0 auto;
cursor: pointer;
}
}
.models_content_right{
width: calc(100% - 37rem);
height: 100%;
background: #FFFFFF;
padding: 1.5rem 1rem 1rem 1rem;
.models_content_body{
width: 100%;
height: calc(100% - 6rem);
overflow-y: auto;
.content_img_item{
display: inline-block;
vertical-align: top;
padding: 0 0.91rem;
margin-bottom: 1rem;
.content_img_item_block{
border: 0.1rem solid #F5F5F5;;
width: 16.5rem;
height: 25.1rem;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
&.select_item_img{
border-color: #343579;
}
.content_img{
max-width: 100%;
max-height: 100%;
}
}
.content_img_name{
width: 16.5rem;
height: 3.4rem;
line-height: 3.4rem;
white-space: nowrap;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1.4rem;
color: #030303;
}
}
.no_data_block{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table_pagination{
width: 100%;
text-align: center;
margin-top: 2rem;
}
}
}
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<div id="app">
<div class="captcha">
<input v-for="(c, index) in getCtData" :key="index"
v-model="getCtData[index]" ref="input"
@input="e => {onInput(e.target.value, index)}"
@keydown.delete="e=>{onKeydown(e.target.value, index)}"
@focus="onFocus"
:disabled="loading"
>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
props:['ct'],
data() {
return {
loading: false,
}
},
computed: {
getCtData(){
return this.ct
},
ctSize() {
return this.getCtData.length;
},
cIndex() {
let i = this.getCtData.findIndex(item => item === '');
i = (i + this.ctSize) % this.ctSize;
return i;
},
lastCode() {
return this.getCtData[this.ctSize - 1];
}
},
watch: {
cIndex() {
this.resetCaret();
},
lastCode(val) {
if (val) {
this.$refs.input[this.ctSize - 1].blur();
this.sendCaptcha();
}
}
},
mounted() {
this.resetCaret();
},
methods: {
onInput(val, index) {
val = val.replace(/\D/g, '');
if (index == this.ctSize - 1) {
this.getCtData[this.ctSize - 1] = val[0]; // 最后一个码,只允许输入一个字符。
} else if(val.length > 1) {
let i = index;
for (i = index; i < this.ctSize && i - index < val.length; i++) {
this.getCtData[i] = val[i];
}
this.resetCaret();
}else if(!(val+'')){
this.getCtData[index] = ''
}
},
// 重置光标位置。
resetCaret() {
this.$refs.input[this.ctSize-1].focus();
},
onFocus() {
// 监听 focus 事件,将光标重定位到“第一个空白符的位置”。
let index = this.getCtData.findIndex(item => item === '');
index = (index + this.ctSize) % this.ctSize;
this.$refs.input[index].focus();
},
onKeydown(val, index) {
if (val === '') {
// 删除上一个input里的值并对其focus。
if (index > 0) {
this.getCtData[index - 1] = '';
this.$refs.input[index - 1].focus();
}
}
},
sendCaptcha() {
let password = this.getCtData.map(item => item).join('');
this.$emit('sendCaptcha',password)
},
reset() {
// 重置。一般是验证码错误时触发。
this.getCtData = this.getCtData.map(item => '');
this.resetCaret();
}
}
})
</script>
<style scoped lang="less">
.captcha {
display: flex;
justify-content: space-between;
}
input {
width: 4.8rem;
height: 4.8rem;
border: 0.1rem solid #B4BED7;
border-radius: 0.8rem;
text-align: center;
font-size: 2.4rem;
line-height: 4.8rem;
outline: none;
}
input:last-of-type {
margin-right: 0;
}
input:disabled {
color: #000;
background-color: #fff;
}
.msg {
text-align: center;
}
</style>