feat: 修改请求时机
All checks were successful
git提交控制 AiDA WEB-Node.js main 分支构建部署 / build (20.19.0) (push) Has been skipped

This commit is contained in:
2026-02-27 15:02:08 +08:00
parent 8100459c4e
commit df5cfc5eba
2 changed files with 340 additions and 335 deletions

View File

@@ -1,10 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onUnmounted, reactive, toRefs, computed, ref } from "vue"; import { onMounted, onUnmounted, reactive, toRefs, computed, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { useGenerateStore, useUserInfoStore, useHGenerateStore } from '@/stores' import { useGenerateStore, useUserInfoStore, useHGenerateStore } from '@/stores'
import { showToast } from 'vant'; import { showToast } from 'vant'
import { shareImageToWhatsapp } from '@/utils/tools' import { shareImageToWhatsapp } from '@/utils/tools'
import { generateRequestOutfit, getRequestOutfit, setStyleFavorite, cancelStyleFavorite, retrieveAndRegenerate } from '@/api/workshop' import {
generateRequestOutfit,
getRequestOutfit,
setStyleFavorite,
cancelStyleFavorite,
retrieveAndRegenerate
} from '@/api/workshop'
import { FlowType, IsHistoryFlow } from '@/types/enum' import { FlowType, IsHistoryFlow } from '@/types/enum'
import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue' import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue'
import gradientButton from '@/components/gradientButton.vue' import gradientButton from '@/components/gradientButton.vue'
@@ -20,366 +26,366 @@ const hGenerateStore = useHGenerateStore()
const query = computed(() => route.query) const query = computed(() => route.query)
const isHistoryFlow = computed(() => IsHistoryFlow(query.value.flowType)) const isHistoryFlow = computed(() => IsHistoryFlow(query.value.flowType))
const isLoading = ref(true) const isLoading = ref(false)
// const loadingTitle= ref('Analyzing the Outfit...') // const loadingTitle= ref('Analyzing the Outfit...')
const loadingTitle = computed(()=>{ const loadingTitle = computed(() => {
let str = 'Analyzing the Outfit...' let str = 'Analyzing the Outfit...'
if(!select.value.status)str = 'Analyzing the Outfit...' if (!select.value.status) str = 'Analyzing the Outfit...'
if(select.value.status == 'RUNNING')str = 'Generating Results...' if (select.value.status == 'RUNNING') str = 'Generating Results...'
if(select.value.status == 'PENDING' || select.value.status == 'ALMOST_DONE')str = 'Almost there...' if (select.value.status == 'PENDING' || select.value.status == 'ALMOST_DONE')
return str 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 dataDom = reactive({ let dataDom = reactive({
styleListVue:null, styleListVue: null
}) })
let getGenerateTime = null as any let getGenerateTime = null as any
const updateStyle = ()=>{ const updateStyle = () => {
// generateStore.updateStyle(item) // generateStore.updateStyle(item)
// data.styleList[index] = {} // data.styleList[index] = {}
requestOutfit({num:4}) requestOutfit({ num: 4 })
} }
const setLikeStyle = (likeStyle)=>{ const setLikeStyle = (likeStyle) => {
if(!select.value.id)return if (!select.value.id) return
if(likeStyle){ if (likeStyle) {
cancelStyleFavorite(select.value.id).then(()=>{ cancelStyleFavorite(select.value.id).then(() => {
select.value.isLike = false select.value.isLike = false
}) })
}else{ } else {
setStyleFavorite(select.value.id).then(()=>{ setStyleFavorite(select.value.id).then(() => {
select.value.isLike = true select.value.isLike = true
}) })
} }
} }
const setDownload = ()=>{ const setDownload = () => {
if(select.value.path)shareImageToWhatsapp(select.value.path) if (select.value.path) shareImageToWhatsapp(select.value.path)
} }
const toProduct = ()=>{ const toProduct = () => {
// if(generateStore.style.id){ // if(generateStore.style.id){
// generateStore.setIsGenerate(true) // generateStore.setIsGenerate(true)
// } // }
router.push({ path: 'product', query: {...query.value} }) router.push({ path: 'product', query: { ...query.value } })
// if(!isHistoryFlow.value){ // if(!isHistoryFlow.value){
// router.push({ path: 'product', query: {...query.value} }) // router.push({ path: 'product', query: {...query.value} })
// }else{ // }else{
// router.push({ path: 'creation', query: {...query.value, active: FlowType.H_OUTFIT} }) // router.push({ path: 'creation', query: {...query.value, active: FlowType.H_OUTFIT} })
// } // }
} }
const requestOutfit = async ({num})=>{ const requestOutfit = async ({ num }) => {
let rv:any = await new Promise<void>((resolve, reject) => {
if(isHistoryFlow.value){
retrieveAndRegenerate({tryOnEffectsId:hGenerateStore.originalTryOn.id,checkInId:generateStore.visitRecordId}).then((rv:any)=>{
resolve(rv)
})
}else{
let value = {
"customerId": generateStore.customerId,
"checkInId": generateStore.visitRecordId,
"stylist": userInfoStore.state.generateParams.stylist,
"gender": userInfoStore.state.generateParams.sex,
"sessionId": generateStore.sessionId,
num,
}
generateRequestOutfit(value).then((rv:any)=>{
resolve(rv)
})
}
})
isLoading.value = true isLoading.value = true
generateStore.clearProductData() let rv: any = await new Promise<void>((resolve, reject) => {
data.select.taskId = rv[0] if (isHistoryFlow.value) {
rv.forEach((item,index)=>data.styleList[index].taskId = item) retrieveAndRegenerate({
getRequestOutfitList(rv) tryOnEffectsId: hGenerateStore.originalTryOn.id,
checkInId: generateStore.visitRecordId
}).then((rv: any) => {
resolve(rv)
})
} else {
let value = {
customerId: generateStore.customerId,
checkInId: generateStore.visitRecordId,
stylist: userInfoStore.state.generateParams.stylist,
gender: userInfoStore.state.generateParams.sex,
sessionId: generateStore.sessionId,
num
}
generateRequestOutfit(value).then((rv: any) => {
resolve(rv)
})
}
})
generateStore.clearProductData()
data.select.taskId = rv[0]
rv.forEach((item, index) => (data.styleList[index].taskId = item))
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 selectIndex = rv.findIndex((item)=>item.requestId == data.select.taskId) let selectIndex = rv.findIndex((item) => item.requestId == data.select.taskId)
console.log(selectIndex) console.log(selectIndex)
if(selectIndex != -1){ if (selectIndex != -1) {
data.select.id = rv[selectIndex].id data.select.id = rv[selectIndex].id
data.select.path = rv[selectIndex].path data.select.path = rv[selectIndex].path
data.select.status = rv[selectIndex].status data.select.status = rv[selectIndex].status
} }
rv.forEach((item)=>{ rv.forEach((item) => {
let index = data.styleList.findIndex((styleListItem)=>styleListItem?.taskId == item.requestId) let index = data.styleList.findIndex(
data.styleList[index] = { (styleListItem) => styleListItem?.taskId == item.requestId
id: item.id, )
taskId: item.requestId, data.styleList[index] = {
status: item.status, id: item.id,
path: item.path, taskId: item.requestId,
} status: item.status,
}) path: item.path
}
})
if(['SUCCEEDED'].includes(data.select.status)){ if (['SUCCEEDED'].includes(data.select.status)) {
isLoading.value = false isLoading.value = false
if(isHistoryFlow.value){ if (isHistoryFlow.value) {
hGenerateStore.uploadStyle({ hGenerateStore.uploadStyle({
id: data.select.id, id: data.select.id,
path: data.select.path, path: data.select.path
}) })
} }
} }
if(data.styleList.filter((item)=>item?.status == 'FAILED').length > 0){ if (data.styleList.filter((item) => item?.status == 'FAILED').length > 0) {
showToast({ showToast({
message: 'One of the outfits failed to generate. Please try generating again.', message: 'One of the outfits failed to generate. Please try generating again.',
duration: 2000, duration: 2000
}) })
isLoading.value = false isLoading.value = false
} }
const taskIdList = data.styleList const taskIdList = data.styleList
.filter(item => item?.taskId && (item?.status !== 'SUCCEEDED' && item?.status !== 'FAILED')) .filter((item) => item?.taskId && item?.status !== 'SUCCEEDED' && item?.status !== 'FAILED')
.map(item => item.taskId); .map((item) => item.taskId)
if(taskIdList.length > 0){ if (taskIdList.length > 0) {
getGenerateTime = setTimeout(()=>{ getGenerateTime = setTimeout(() => {
getRequestOutfitList(taskIdList) getRequestOutfitList(taskIdList)
},3000) }, 3000)
} }
}) })
} }
const styleListInit = ()=>{ const styleListInit = () => {
dataDom.styleListVue.init(data.select) dataDom.styleListVue.init(data.select)
} }
// 使用 useStreamChat在流式请求成功后执行原本的逻辑 // 使用 useStreamChat在流式请求成功后执行原本的逻辑
const { fetchMessage, isGenerating } = useStreamChat(() => { const { fetchMessage, isGenerating } = useStreamChat()
// 流式请求成功后,执行原本的请求逻辑
requestOutfit({ num: 4 }) onMounted(() => {
// generateStore.clearProductData()
// if(!data.styleList[0]?.id)getRequestOutfitList(0)
if (getGenerateTime) clearTimeout(getGenerateTime)
// 检查是否有从 dressfor 传递过来的消息
const message = query.value.message as string
const sessionId = query.value.sessionId as string
if (message && sessionId) {
// 有消息,说明是从 dressfor 跳转过来的,先发起流式请求
generateStore.setSessionId(sessionId)
fetchMessage(message, sessionId)
.then(() => {
console.log('对话请求完成')
// 清除 URL 参数避免返回时再次触发
router.replace({ path: '/workshop/selectStyle' })
// 开始生成outfit
requestOutfit({ num: 4 })
})
.catch(() => {
// 错误处理
})
}
// 原本的逻辑
const taskIdList = data.styleList
.filter((item) => item?.taskId && item?.status !== 'SUCCEEDED')
.map((item) => item.taskId)
if (data.select.status == 'SUCCEEDED' && taskIdList.length == 0) {
return
} else if (!data.select?.taskId) {
requestOutfit({ num: 4 })
} else if (data.select.status != 'SUCCEEDED' || taskIdList.length > 0) {
if (data.select.status != 'SUCCEEDED') isLoading.value = true
getRequestOutfitList(taskIdList)
}
}) })
onUnmounted(() => {
onMounted(()=>{ if (getGenerateTime) clearTimeout(getGenerateTime)
// generateStore.clearProductData()
// if(!data.styleList[0]?.id)getRequestOutfitList(0)
if(getGenerateTime)clearTimeout(getGenerateTime)
// 检查是否有从 dressfor 传递过来的消息
const message = query.value.message as string
const sessionId = query.value.sessionId as string
if (message && sessionId) {
// 有消息,说明是从 dressfor 跳转过来的,先发起流式请求
generateStore.setSessionId(sessionId)
fetchMessage(message, sessionId)
.then(() => {
// 流式请求完成后(失败或成功)继续执行
})
.catch(() => {
// 错误处理
})
return
}
// 原本的逻辑
const taskIdList = data.styleList
.filter(item => item?.taskId && item?.status !== 'SUCCEEDED')
.map(item => item.taskId);
if(data.select.status == 'SUCCEEDED' && taskIdList.length == 0){
return
}else if(!data.select?.taskId){
requestOutfit({num:4})
}else if(data.select.status != 'SUCCEEDED' || taskIdList.length > 0){
if(data.select.status != 'SUCCEEDED')isLoading.value = true
getRequestOutfitList(taskIdList)
}
})
onUnmounted(()=>{
if(getGenerateTime)clearTimeout(getGenerateTime)
}) })
defineExpose({}) defineExpose({})
const { select } = toRefs(data); const { select } = toRefs(data)
const { styleListVue } = toRefs(dataDom); const { styleListVue } = toRefs(dataDom)
</script> </script>
<template> <template>
<div class="selectStyle"> <div class="selectStyle">
<div class="text"> <div class="text">
<div class="title"> <div class="title">Outfit Result</div>
Outfit Result <div class="info">Refine your Look</div>
</div>
<div class="info">
Refine your Look
</div>
</div>
<div class="selectContent">
<!-- {{ select }} -->
<div class="imgBox">
<img :src="select.path" alt="">
</div>
<div v-if="!isHistoryFlow" class="chooseMore" @click.stop="styleListInit">
<gradientButton>
<template #content>
<div class="text">
Choose More
</div>
</template>
</gradientButton>
<div></div>
</div>
<div class="btn" v-else>
<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 class="btn">
<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 class="footer placeholder"></div> -->
<div class="loading-container" v-if="isGenerating || isLoading">
<GenerateLoading :title="loadingTitle"/>
</div> </div>
<StyleListDom ref="styleListVue"></StyleListDom> <div class="selectContent">
<!-- {{ select }} -->
<div class="imgBox">
<img :src="select.path" alt="" />
</div>
<div v-if="!isHistoryFlow" class="chooseMore" @click.stop="styleListInit">
<gradientButton>
<template #content>
<div class="text">Choose More</div>
</template>
</gradientButton>
<div></div>
</div>
<div class="btn" v-else>
<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 class="btn">
<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 class="footer placeholder"></div> -->
<div class="loading-container" v-if="isGenerating || isLoading">
<GenerateLoading :title="loadingTitle" />
</div>
<StyleListDom ref="styleListVue"></StyleListDom>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
.header-title { .header-title {
// --header-title-background: #f6f6f6; // --header-title-background: #f6f6f6;
} }
.loading-container{ .loading-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 2; z-index: 2;
background-color: #fff; background-color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.selectStyle{ .selectStyle {
width: 100%; width: 100%;
flex: 1; flex: 1;
// height: 100%; // height: 100%;
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: #f6f6f6; background-color: #f6f6f6;
overflow: hidden; overflow: hidden;
> .text{ > .text {
text-align: center; text-align: center;
width: 100%; width: 100%;
margin-top: 8.5rem; margin-top: 8.5rem;
margin-bottom: 8.5rem; margin-bottom: 8.5rem;
> .title{ > .title {
font-family: satoshiBold; font-family: satoshiBold;
font-weight: 700; font-weight: 700;
font-size: 8.6rem; font-size: 8.6rem;
line-height: 124%; line-height: 124%;
color: #000; color: #000;
} }
> .info{ > .info {
font-size: 4rem; font-size: 4rem;
font-weight: 400; font-weight: 400;
line-height: 124%; line-height: 124%;
margin-top: 3.2rem; 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; margin: 0 auto;
width: 73.7rem; width: 73.7rem;
margin-bottom: 19rem; margin-bottom: 19rem;
> .imgBox{ > .imgBox {
height: 73.7rem; height: 73.7rem;
width: 100%; width: 100%;
margin-bottom: 5.6rem; margin-bottom: 5.6rem;
> img{ > img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
> .chooseMore{ > .chooseMore {
--borderRadius: 5.4rem; --borderRadius: 5.4rem;
--borderWidth: 2px; --borderWidth: 2px;
width: 24.8rem; width: 24.8rem;
margin: 0 auto; margin: 0 auto;
height: 7.6rem; height: 7.6rem;
.text{ .text {
font-size: 3.1rem; font-size: 3.1rem;
color: #000; color: #000;
font-family: satoshiMedium; font-family: satoshiMedium;
} }
} }
> .btn{ > .btn {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
gap: 2rem; gap: 2rem;
> div{ > div {
color: #000; color: #000;
border-radius: 50%; border-radius: 50%;
width: 7rem; width: 7rem;
height: 7rem; height: 7rem;
padding: 1rem; padding: 1rem;
background-color: #fff; background-color: #fff;
&:hover{ &:hover {
color: #000; color: #000;
} }
} }
} }
} }
> .btn{ > .btn {
display: flex; display: flex;
gap: 6.6rem; gap: 6.6rem;
justify-content: center; justify-content: center;
> div { > div {
border-radius: .96rem; border-radius: 0.96rem;
width: 33.7rem; width: 33.7rem;
font-size: 4.8rem; font-size: 4.8rem;
font-family: satoshiMedium; font-family: satoshiMedium;
line-height: 9.2rem; line-height: 9.2rem;
display: flex; display: flex;
justify-content: center; justify-content: center;
&.style1{ &.style1 {
--borderRadius: .96rem; --borderRadius: 0.96rem;
--borderWidth: 2px; --borderWidth: 2px;
.text{ .text {
width: 100%; width: 100%;
text-align: center; text-align: center;
> .icon{ > .icon {
left: 4rem; left: 4rem;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
position: absolute; position: absolute;
} }
} }
} }
&.style2{ &.style2 {
color: #fff; color: #fff;
background-color: #000; background-color: #000;
} }
} }
.btnItem .text{ .btnItem .text {
color: #000; color: #000;
} }
} }
} }
</style> </style>

View File

@@ -100,7 +100,6 @@ const tagListShort = [
// const tagListLong = ['Linen Suit For Summer Gaka', 'Recomment Evening Bags'] // const tagListLong = ['Linen Suit For Summer Gaka', 'Recomment Evening Bags']
const inputValue = ref('') const inputValue = ref('')
const sessionId = ref('')
const isRecording = ref(false) const isRecording = ref(false)
const audioVisualizerRef = ref<InstanceType<typeof AudioVisualizer> | null>(null) const audioVisualizerRef = ref<InstanceType<typeof AudioVisualizer> | null>(null)
let speechRecognition: any = null let speechRecognition: any = null
@@ -216,14 +215,14 @@ const stopRecording = () => {
const handleClickTag = (tag: string) => { const handleClickTag = (tag: string) => {
inputValue.value = tag inputValue.value = tag
sessionId.value = Math.floor(Date.now() / 1000).toString() const sessionId = Math.floor(Date.now() / 1000).toString()
generateStore.setSessionId(sessionId.value) generateStore.setSessionId(sessionId.value)
// 直接跳转到 selectStyle 页面,传递消息和 sessionId // 直接跳转到 selectStyle 页面,传递消息和 sessionId
router.push({ router.push({
path: '/workshop/selectStyle', path: '/workshop/selectStyle',
query: { query: {
message: tag, message: tag,
sessionId: sessionId.value sessionId
} }
}) })
} }