tryon 反推style

This commit is contained in:
X1627315083
2025-12-23 14:00:30 +08:00
parent 51336fff77
commit 665194f18e
3 changed files with 211 additions and 117 deletions

View File

@@ -58,7 +58,7 @@ onMounted(()=>{
flowTypeList: [FlowType.H_TRYON,FlowType.H_AI], flowTypeList: [FlowType.H_TRYON,FlowType.H_AI],
}, },
{ {
path: 'recommended', path: 'product',
imgPath: new URL('@/assets/images/nav2.png',import.meta.url).href, imgPath: new URL('@/assets/images/nav2.png',import.meta.url).href,
flowTypeList: [FlowType.H_OUTFIT], flowTypeList: [FlowType.H_OUTFIT],
}, },

View File

@@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref, toRefs } from "vue"; import { onMounted, onUnmounted, reactive, ref, toRefs, computed } from "vue";
import HeaderTitle from '@/components/HeaderTitle.vue'
import FooterNavigation from '@/components/FooterNavigation.vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue' import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue'
import { useGenerateStore } from '@/stores' import { useGenerateStore, useHGenerateStore } from '@/stores'
import { generateTryOnEffect, setTryOnEffectFavorite, cancelTryOnEffectFavorite, addTryOnEffectComment } from '@/api/workshop' import { generateTryOnEffect, setTryOnEffectFavorite, cancelTryOnEffectFavorite, addTryOnEffectComment } from '@/api/workshop'
import { FlowType } from '@/types/enum' import { FlowType, IsHistoryFlow } from '@/types/enum'
const router = useRouter() const router = useRouter()
//const props = defineProps({ //const props = defineProps({
@@ -19,8 +17,11 @@ let data = reactive({
], ],
isLoading: false, isLoading: false,
}) })
const query = computed(() => router.currentRoute.value.query)
const generateStore = useGenerateStore() const generateStore = useGenerateStore()
const hGenerateStore = useHGenerateStore()
const isHistoryFlow = computed(() => IsHistoryFlow(query.value.flowType))
const vanDialogShow = ref(false) const vanDialogShow = ref(false)
const feedbackForm = ref({ const feedbackForm = ref({
@@ -34,11 +35,10 @@ const feedbackForm = ref({
const onContinue = ()=>{ const onContinue = ()=>{
const query = router.currentRoute.value.query if(!isHistoryFlow.value){
if(query?.flowType == FlowType.MAIN){ router.push({ path: 'uploadFace', query: {...query.value} })
router.push({ path: 'uploadFace', query: {...query} })
}else{ }else{
router.push({ path: 'creation', query: {...query} }) router.push({ path: 'creation', query: {...query.value} })
} }
} }
@@ -51,7 +51,7 @@ const startGenerate = ()=>{
let value = { let value = {
customerId:generateStore.customerId, customerId:generateStore.customerId,
visitRecordId:generateStore.visitRecordId, visitRecordId:generateStore.visitRecordId,
styleId:generateStore.styleId, styleId:isHistoryFlow.value ? hGenerateStore.styleId : generateStore.styleId,
// customerPhotoId:null, // customerPhotoId:null,
// modelPhotoId:null, // modelPhotoId:null,
// prompt:null, // prompt:null,
@@ -63,7 +63,7 @@ const startGenerate = ()=>{
generateStore.originalTryOn.isLike = false generateStore.originalTryOn.isLike = false
generateStore.originalTryOn.id = res.tryOnId generateStore.originalTryOn.id = res.tryOnId
generateStore.originalTryOn.tryOnUrl = res.tryOnUrl generateStore.originalTryOn.tryOnUrl = res.tryOnUrl
generateStore.useStyleGenerate()//生成后需要对选择衣服页面设置不可选中样式 // generateStore.useStyleGenerate()//生成后需要对选择衣服页面设置不可选中样式
generateStore.setIsGenerate(false) generateStore.setIsGenerate(false)
generateStore.clearCustomizeInfo() generateStore.clearCustomizeInfo()

View File

@@ -1,16 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, reactive, toRefs, computed, onActivated } from "vue"; import { onMounted, onUnmounted, reactive, toRefs, computed, ref } from "vue";
import SelectItem from "@/components/selectStyle/selectItem.vue"; import SelectItem from "@/components/selectStyle/selectItem.vue";
import HeaderTitle from '@/components/HeaderTitle.vue' import { useRouter, useRoute } from 'vue-router'
import FooterNavigation from '@/components/FooterNavigation.vue' import { useGenerateStore, useUserInfoStore, useHGenerateStore } from '@/stores'
import { useRouter } from 'vue-router'
import { useGenerateStore, useUserInfoStore } from '@/stores'
import { showToast } from 'vant'; import { showToast } from 'vant';
import { generateRequestOutfit, getRequestOutfit } from '@/api/workshop' import { shareImageToWhatsapp } from '@/utils/tools'
import { FlowType } from '@/types/enum' import { generateRequestOutfit, getRequestOutfit, setStyleFavorite, cancelStyleFavorite, retrieveAndRegenerate } from '@/api/workshop'
import { FlowType, IsHistoryFlow } from '@/types/enum'
import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue'
import gradientButton from '@/components/gradientButton.vue'
const router = useRouter() const router = useRouter()
const route = useRoute()
//const props = defineProps({ //const props = defineProps({
//}) //})
const emit = defineEmits([ const emit = defineEmits([
@@ -18,125 +19,190 @@ const emit = defineEmits([
]) ])
const generateStore = useGenerateStore() const generateStore = useGenerateStore()
const userInfoStore = useUserInfoStore() const userInfoStore = useUserInfoStore()
const hGenerateStore = useHGenerateStore()
const query = computed(() => route.query)
const isHistoryFlow = computed(() => IsHistoryFlow(query.value.flowType))
const isLoading = ref(false)
const loadingTitle= ref('Analyzing the Outfit...')
// const loadingTitle = computed(()=>{
// let str = ''
// if(!select.value.status)str = 'Analyzing the Outfit...'
// if(select.value.status == 'RUNNING')str = 'Generating Results...'
// if(select.value.status == 'PENDING')str = 'Almost there...'
// return str
// })
let data = reactive({ let data = reactive({
select:computed(()=>generateStore.style), select:computed(()=>generateStore.style),
styleList:computed(()=>generateStore.styleList), // styleList:computed(()=>generateStore.styleList),
}) })
let getGenerateTime = null as any let getGenerateTime = null as any
const selectItem = (item)=>{ const updateStyle = ()=>{
if(!item.id || item.status != 'SUCCEEDED'){ // generateStore.updateStyle(item)
return // data.styleList[index] = {}
requestOutfit({num:1})
}
const setLikeStyle = (likeStyle)=>{
if(!select.value.id)return
if(likeStyle){
cancelStyleFavorite(select.value.id).then(()=>{
select.value.isLike = false
})
}else{
setStyleFavorite(select.value.id).then(()=>{
select.value.isLike = true
})
} }
generateStore.selectStyle(item)
} }
const updateStyle = ({item,index})=>{ const setDownload = ()=>{
generateStore.updateStyle(item) if(select.value.path)shareImageToWhatsapp(select.value.path)
data.styleList[index] = {}
requestOutfit({num:1,index})
} }
const toProduct = ()=>{ const toProduct = ()=>{
if(!generateStore.style.id){ // if(generateStore.style.id){
showToast({ message: 'Please select a style.' }); // generateStore.setIsGenerate(true)
return // }
} if(!isHistoryFlow.value){
if(generateStore.style.id != generateStore.style.oldId){ router.push({ path: 'product', query: {...query.value} })
generateStore.setIsGenerate(true)
}
const query = router.currentRoute.value.query
if(query?.flowType == FlowType.MAIN){
router.push({ path: 'product', query: {...query} })
}else{ }else{
router.push({ path: 'creation', query: {...query} }) router.push({ path: 'creation', query: {...query.value, active: FlowType.H_OUTFIT} })
} }
} }
const requestOutfit = ({num,index})=>{ const requestOutfit = async ({num})=>{
let value = { let rv = await new Promise<void>((resolve, reject) => {
"customerId": generateStore.customerId, if(isHistoryFlow.value){
"checkInId": generateStore.visitRecordId, retrieveAndRegenerate({tryOnEffectsId:hGenerateStore.originalTryOn.id}).then((rv:any)=>{
"stylist": userInfoStore.state.generateParams.stylist, resolve(rv)
"gender": userInfoStore.state.generateParams.sex, })
"sessionId": generateStore.sessionId, }else{
num, let value = {
} "customerId": generateStore.customerId,
generateRequestOutfit(value).then((rv)=>{ "checkInId": generateStore.visitRecordId,
let rvIndex = 0 "stylist": userInfoStore.state.generateParams.stylist,
data.styleList.forEach((item,styleIndex)=>{ "gender": userInfoStore.state.generateParams.sex,
if(styleIndex < index)return "sessionId": generateStore.sessionId,
item.taskId = rv[rvIndex] num,
rvIndex++ }
}) generateRequestOutfit(value).then((rv:any)=>{
getRequestOutfitList(rv) resolve(rv)
})
}
}) })
isLoading.value = true
generateStore.clearStyle()
data.select.taskId = rv[0]
getRequestOutfitList(rv)
} }
const getRequestOutfitList = (generateList)=>{ const getRequestOutfitList = (generateList)=>{
let value = {requestIDs:generateList.join(',')} let value = {requestIDs:generateList.join(',')}
getRequestOutfit(value).then((rv:any)=>{ getRequestOutfit(value).then((rv:any)=>{
let pendingList = []
rv.forEach((item)=>{ rv.forEach((item)=>{
if(['RUNNING','PENDING'].includes(item.status))pendingList.push(item.requestId) data.select.id = item.id
let index = data.styleList.findIndex((styleItem)=>styleItem.taskId == item.requestId) data.select.path = item.path
if(index != -1){ data.select.status = item.status
data.styleList[index].id = item.id
data.styleList[index].path = item.path
data.styleList[index].status = item.status
}
}) })
if(pendingList.length > 0){ if(['RUNNING','PENDING'].includes(data.select.status)){
getGenerateTime = setTimeout(()=>{ getGenerateTime = setTimeout(()=>{
getRequestOutfitList(pendingList) getRequestOutfitList([data.select.taskId])
},3000) },3000)
}else{
isLoading.value = false
} }
}) })
} }
onMounted(()=>{ onMounted(()=>{
// generateStore.clearProductData() // generateStore.clearProductData()
emit('view-type', 1) emit('view-type', 1)
// if(!data.styleList[0]?.id)getRequestOutfitList(0) // if(!data.styleList[0]?.id)getRequestOutfitList(0)
if(getGenerateTime)clearTimeout(getGenerateTime) if(getGenerateTime)clearTimeout(getGenerateTime)
if(!data.styleList[0]?.taskId){ if(data.select.status == 'SUCCEEDED'){
requestOutfit({num:4,index:0}) return
}else if(data.styleList.filter((item)=>item?.status != 'SUCCEEDED').length > 0){ }else if(!data.select?.taskId){
let generateList = data.styleList.map((item)=>item.taskId) requestOutfit({num:1})
getRequestOutfitList(generateList) }else if(data.select.status != 'SUCCEEDED'){
isLoading.value = true
// let generateList = [data.styleList[0].taskId]
getRequestOutfitList([data.select.taskId])
} }
}) })
onUnmounted(()=>{ onUnmounted(()=>{
if(getGenerateTime)clearTimeout(getGenerateTime) if(getGenerateTime)clearTimeout(getGenerateTime)
}) })
defineExpose({}) defineExpose({})
const { styleList, select } = toRefs(data); const { select } = toRefs(data);
</script> </script>
<template> <template>
<div class="selectStyle"> <div class="selectStyle">
<div class="text"> <div class="text">
<div class="title"> <div class="title">
Whats your Style? Outfit Result
</div> </div>
<div class="info"> <div class="info">
Select the outfit that matches you the most. Refine your Look
</div> </div>
</div> </div>
<div class="selectContent flex-1"> <div class="selectContent">
<SelectItem :selectList="styleList" v-model:select="select" @selectItem="selectItem" @updateStyle="updateStyle" /> <!-- {{ select }} -->
<div class="imgBox">
<img :src="select.path" alt="">
</div>
<div class="btn">
<div class="like" @click.stop="setLikeStyle(select.isLike)">
<SvgIcon :name="`love_${select.isLike?1:0}`" size="35" />
</div>
<div class="down" @click.stop="setDownload()">
<SvgIcon name="download" size="35" />
</div>
</div>
</div> </div>
<div class="footer"> <div class="btn">
<button class="flex flex-center" @click.stop="toProduct">Continue</button> <div class="btnItem style1" @click.stop="updateStyle()">
<gradientButton>
<template #content>
<div class="text">
<span class="icon">
<SvgIcon name="reTry" size="40" />
</span>
Re-try
</div>
</template>
</gradientButton>
</div>
<div class="btnItem style2" @click.stop="toProduct">Continue</div>
</div> </div>
</div> </div>
<!-- <div class="footer placeholder"></div> --> <!-- <div class="footer placeholder"></div> -->
<div class="loading-container" v-if="isLoading">
<GenerateLoading :title="loadingTitle"/>
</div>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.header-title { .header-title {
// --header-title-background: #f6f6f6; // --header-title-background: #f6f6f6;
} }
.loading-container{
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.selectStyle{ .selectStyle{
width: 100%; width: 100%;
flex: 1; flex: 1;
@@ -149,12 +215,12 @@ const { styleList, select } = toRefs(data);
> .text{ > .text{
text-align: center; text-align: center;
width: 100%; width: 100%;
margin-top: 3rem; margin-top: 8.5rem;
margin-bottom: 4.9rem; margin-bottom: 8.5rem;
> .title{ > .title{
font-family: satoshiBold; font-family: satoshiBold;
font-weight: 700; font-weight: 700;
font-size: 9.6rem; font-size: 8.6rem;
line-height: 124%; line-height: 124%;
color: #000; color: #000;
} }
@@ -162,46 +228,74 @@ const { styleList, select } = toRefs(data);
font-size: 4rem; font-size: 4rem;
font-weight: 400; font-weight: 400;
line-height: 124%; line-height: 124%;
margin-top: 1.3rem; margin-top: 3.2rem;
color: rgba(0, 0, 0, 0.6); color: rgba(0, 0, 0, 0.6);
} }
} }
.selectContent{ .selectContent{
padding: 0 4rem; // padding: 0 4rem;
margin: 0 auto;
overflow: auto; overflow: auto;
width: 73.7rem;
margin-bottom: 19.4rem;
> .imgBox{
height: 73.7rem;
width: 100%;
margin-bottom: 4.4rem;
> img{
width: 100%;
height: 100%;
}
}
> .btn{
display: flex;
align-items: center;
justify-content: flex-end;
gap: 2rem;
> div{
color: #000;
border-radius: 50%;
width: 7rem;
height: 7rem;
padding: 1rem;
background-color: #fff;
&:hover{
color: #000;
}
}
}
} }
} > .btn{
.footer { display: flex;
// position: fixed; gap: 6.6rem;
// margin-top: 4.4rem; justify-content: center;
// padding: 4rem 4rem 0 0; > div {
margin-top: auto; border-radius: .96rem;
margin-bottom: 5.6rem; width: 33.7rem;
margin-right: 4rem; font-size: 4.8rem;
display: flex; font-family: satoshiMedium;
align-items: center; line-height: 9.2rem;
justify-content: flex-end; display: flex;
// position: absolute; justify-content: center;
// right: 4rem; &.style1{
// bottom: 4rem; --borderRadius: .96rem;
height: 6.7rem; --borderWidth: 2px;
// background-color: #f6f6f6; .text{
&.placeholder{ width: 100%;
position: relative; text-align: center;
} > .icon{
> button { left: 4rem;
// margin-right: 5rem; top: 50%;
border-radius: .7rem; transform: translateY(-50%);
border: 3px solid #000; position: absolute;
background-color: #000; }
text-align: center; }
color: #fff; }
font-family: satoshiMedium; &.style2{
font-size: 3.6rem; color: #fff;
width: 24.6rem; background-color: #000;
height: 6.7rem; }
box-sizing: border-box; }
line-height: 6.7rem;
} }
} }
</style> </style>