Merge branch 'main' of http://18.167.251.121:10003/aidlab/lanecarford_front
All checks were successful
git提交控制 AiDA WEB-Node.js main 分支构建部署 / build (20.19.0) (push) Has been skipped

This commit is contained in:
李志鹏
2025-12-29 14:50:33 +08:00
16 changed files with 312 additions and 149 deletions

View File

@@ -19,20 +19,6 @@ const navDisabledList = ref([])
// const data = reactive({
// })
const clickSwitchVIPID = ()=>{
showConfirmDialog({
title: 'Switch VIP ID?',
message: 'You have unsaved changes. Your progress will be lost.',
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
})
.then(() => {
MyEvent.emit('clear-generate-state')
MyEvent.emit('clearAllCache')
router.push({ name: 'customer', query: { demo: 1 } })
})
.catch(() => {})
}
const openFlow = (item: any)=>{
item.click && item.click()
const query = route.query

View File

@@ -21,8 +21,11 @@
<header-title @clickProfile="handleClickProfile" />
<RouteCache view-type="1" />
<footer-navigation v-if="notShowFooter" />
<template>
<profile ref="profileRef" />
</template>
</div>
<profile ref="profileRef" />
</template>
<style scoped lang="less">
.workshop {

View File

@@ -166,6 +166,7 @@
// 打开customer选择时关闭profile弹窗 如果不是点击confirem关闭则重新打开profile弹窗
const handleShowPopup = (flag: boolean) => {
showSwitchCustomerPopup.value = flag
if (props.isCustomer) return
show.value = !flag
if (flag) {
loadCustomers(true)
@@ -197,15 +198,15 @@
}
MyEvent.add('update-customer-list', handleFetchCustomerList)
const openSwitchCustomerPopup = (flag = true) => {
showSwitchCustomerPopup.value = flag
}
// const openSwitchCustomerPopup = (flag = true) => {
// showSwitchCustomerPopup.value = flag
// }
onMounted(() => {
handleFetchCustomerList()
})
defineExpose({ open, close, openSwitchCustomerPopup })
defineExpose({ open, close, handleShowPopup })
</script>
<template>
@@ -319,12 +320,13 @@
<img v-show="item.checked" class="checked-icon" src="@/assets/images/checked.png" />
</div>
</div>
</div>
<div class="list-footer">
<div v-if="pager.loading">Loading...</div>
<div v-else-if="pager.noMore">No more</div>
<div class="list-footer">
<div v-if="pager.loading">Loading...</div>
<div v-else-if="pager.noMore">No more</div>
</div>
</div>
<div class="confirm-btn" @click="handleSelectCustomer">Confirm</div>
<div class="van-safe-area-bottom"></div>
</van-popup>
</template>

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import { onMounted, onUnmounted, reactive, toRefs, computed, ref } from "vue";
import SelectItem from "@/components/selectStyle/selectItem.vue";
import { useRouter, useRoute } from 'vue-router'
import { useGenerateStore, useUserInfoStore, useHGenerateStore } from '@/stores'
import { showToast } from 'vant';
@@ -9,7 +8,7 @@ import { generateRequestOutfit, getRequestOutfit, setStyleFavorite, cancelStyleF
import { FlowType, IsHistoryFlow } from '@/types/enum'
import GenerateLoading from '@/views/asistant/components/GenerateLoading.vue'
import gradientButton from '@/components/gradientButton.vue'
import StyleListDom from '@/views/Workshop/selectStyle/styleList.vue'
const router = useRouter()
const route = useRoute()
//const props = defineProps({
@@ -32,7 +31,10 @@ const loadingTitle = computed(()=>{
let data = reactive({
select:computed(()=>generateStore.style),
// styleList:computed(()=>generateStore.styleList),
styleList:computed(()=>generateStore.styleList),
})
let dataDom = reactive({
styleListVue:null,
})
let getGenerateTime = null as any
@@ -40,7 +42,7 @@ let getGenerateTime = null as any
const updateStyle = ()=>{
// generateStore.updateStyle(item)
// data.styleList[index] = {}
requestOutfit({num:1})
requestOutfit({num:4})
}
const setLikeStyle = (likeStyle)=>{
if(!select.value.id)return
@@ -71,7 +73,7 @@ const toProduct = ()=>{
}
const requestOutfit = async ({num})=>{
let rv = await new Promise<void>((resolve, reject) => {
let rv:any = await new Promise<void>((resolve, reject) => {
if(isHistoryFlow.value){
retrieveAndRegenerate({tryOnEffectsId:hGenerateStore.originalTryOn.id}).then((rv:any)=>{
resolve(rv)
@@ -93,41 +95,59 @@ const requestOutfit = async ({num})=>{
isLoading.value = true
generateStore.clearStyle()
data.select.taskId = rv[0]
rv.forEach((item,index)=>data.styleList[index].taskId = item)
getRequestOutfitList(rv)
}
const getRequestOutfitList = (generateList)=>{
let value = {requestIDs:generateList.join(',')}
getRequestOutfit(value).then((rv:any)=>{
let selectIndex = rv.findIndex((item)=>item.requestId == data.select.taskId)
if(selectIndex != -1){
data.select.id = rv[selectIndex].id
data.select.path = rv[selectIndex].path
data.select.status = rv[selectIndex].status
}
rv.forEach((item)=>{
data.select.id = item.id
data.select.path = item.path
data.select.status = item.status
let index = data.styleList.findIndex((styleListItem)=>styleListItem?.taskId == item.requestId)
data.styleList[index] = {
id: item.id,
taskId: item.requestId,
status: item.status,
path: item.path,
}
})
if(['RUNNING','PENDING'].includes(data.select.status)){
if(['SUCCEEDED'].includes(data.select.status))isLoading.value = false
const taskIdList = data.styleList
.filter(item => item?.taskId && item?.status !== 'SUCCEEDED')
.map(item => item.taskId);
if(taskIdList.length > 0){
getGenerateTime = setTimeout(()=>{
getRequestOutfitList([data.select.taskId])
getRequestOutfitList(taskIdList)
},3000)
}else{
isLoading.value = false
}
})
}
const styleListInit = ()=>{
dataDom.styleListVue.init(data.select)
}
onMounted(()=>{
// generateStore.clearProductData()
// if(!data.styleList[0]?.id)getRequestOutfitList(0)
if(getGenerateTime)clearTimeout(getGenerateTime)
if(data.select.status == 'SUCCEEDED'){
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:1})
}else if(data.select.status != 'SUCCEEDED'){
isLoading.value = true
// let generateList = [data.styleList[0].taskId]
getRequestOutfitList([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(()=>{
@@ -135,6 +155,7 @@ onUnmounted(()=>{
})
defineExpose({})
const { select } = toRefs(data);
const { styleListVue } = toRefs(dataDom);
</script>
<template>
<div class="selectStyle">
@@ -151,14 +172,24 @@ const { select } = toRefs(data);
<div class="imgBox">
<img :src="select.path" alt="">
</div>
<div class="btn">
<div class="chooseMore" @click.stop="styleListInit">
<gradientButton>
<template #content>
<div class="text">
Choose More
</div>
</template>
</gradientButton>
<div></div>
</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="btn">
<div class="btnItem style1" @click.stop="updateStyle()">
@@ -170,7 +201,6 @@ const { select } = toRefs(data);
</span>
Re-try
</div>
</template>
</gradientButton>
</div>
@@ -181,6 +211,7 @@ const { select } = toRefs(data);
<div class="loading-container" v-if="isLoading">
<GenerateLoading :title="loadingTitle"/>
</div>
<StyleListDom ref="styleListVue"></StyleListDom>
</template>
<style lang="less" scoped>
.header-title {
@@ -231,18 +262,28 @@ const { select } = toRefs(data);
.selectContent{
// padding: 0 4rem;
margin: 0 auto;
overflow: auto;
width: 73.7rem;
margin-bottom: 19.4rem;
margin-bottom: 19rem;
> .imgBox{
height: 73.7rem;
width: 100%;
margin-bottom: 4.4rem;
margin-bottom: 5.6rem;
> img{
width: 100%;
height: 100%;
}
}
> .chooseMore{
--borderRadius: 5.4rem;
--borderWidth: 2px;
width: 24.8rem;
margin: 0 auto;
height: 7.6rem;
.text{
font-size: 3.1rem;
font-family: satoshiMedium;
}
}
> .btn{
display: flex;
align-items: center;

View File

@@ -0,0 +1,120 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, reactive, toRefs } from "vue";
import SelectItem from "@/components/selectStyle/selectItem.vue";
import { useGenerateStore, } from '@/stores'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
const generateStore = useGenerateStore()
let data = reactive({
showStyleList:false,
list:computed(()=>generateStore.styleList),
selectStyle:computed(()=>generateStore.style),
oldSelectStyle:{} as any,
})
const close = ()=>{
showStyleList.value = false;
}
const init = (item)=>{
data.showStyleList = true
data.oldSelectStyle = JSON.parse(JSON.stringify(item))
}
const confirm = ()=>{
if(data.selectStyle.id != data.oldSelectStyle.id){
data.selectStyle.id = data.oldSelectStyle.id
data.selectStyle.path = data.oldSelectStyle.path
data.selectStyle.status = data.oldSelectStyle.status
data.selectStyle.taskId = data.oldSelectStyle.taskId
data.selectStyle.isLike = false
}
close();
}
const setStyle = (item)=>{
data.oldSelectStyle = item
}
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({init})
const {showStyleList,list,oldSelectStyle} = toRefs(data);
</script>
<template>
<van-popup
class="user-popup"
v-model:show="showStyleList"
round
position="bottom"
teleport="body"
>
<div class="profile">
<div class="header">
<span class="title">Outfit Result</span>
<van-icon name="cross" class="close" @click="close" />
</div>
<div class="content">
<SelectItem :selectList="list" :select="oldSelectStyle" @selectItem="setStyle"></SelectItem>
</div>
<div class="bottom">
<div @click="confirm">Confirm</div>
</div>
</div>
</van-popup>
</template>
<style lang="less" scoped>
.van-popup {
max-height: 90%;
--van-popup-round-radius: 7.8rem;
}
.profile {
margin: 11.1rem 0 5.6rem;
display: flex;
flex-direction: column;
align-items: center;
> .header {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 0 8rem 0 5.2rem;
margin-bottom: 8rem;
> .title {
font-family: satoshiBold;
font-size: 4.6rem;
color: #181725;
}
> .close {
margin-left: auto;
font-size: 5rem;
color: #a1a1a1;
}
}
> .content{
width: 96.2rem;
}
> .bottom{
margin: 3rem 0 4rem;
width: 100%;
> div{
width: 24.8rem;
line-height: 6.7rem;
font-family: satoshiMedium;
font-size: 3.6rem;
text-align: center;
border-radius: .7rem;
background-color: #000;
color: #fff;
margin-right: 4.2rem;
margin-left: auto;
}
}
}
</style>

View File

@@ -113,7 +113,7 @@ onMounted(() => {
.loading-image {
width: 36.4rem;
height: 36.4rem;
animation: rotate 1s linear infinite;
animation: rotate 1.5s ease-in-out infinite;
}
.loading-shadow {
@@ -146,11 +146,14 @@ onMounted(() => {
}
@keyframes rotate {
from {
transform: rotate(0deg);
0% {
transform: translateY(0px);
}
to {
transform: rotate(360deg);
50% {
transform: translateY(-100px);
}
100% {
transform: translateY(0px);
}
}
</style>

View File

@@ -55,6 +55,7 @@ const goToLogin = () => {
.title {
font-family: 'satoshiMedium';
line-height: 120%;
font-size: 11rem;
// letter-spacing: -0.02em;
}
.subtitle {

View File

@@ -74,7 +74,7 @@
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useGenerateStore, useUserInfoStore } from '@/stores'
import { showToast } from 'vant'
import { showToast, closeToast } from 'vant'
import { customerCheckin, createCustomer, type CreateCustomerParams } from '@/api/workshop'
import Profile from '../Workshop/profile.vue'
import MyEvent from '@/utils/myEvent'
@@ -86,6 +86,7 @@ const handleOpenProfile = () => {
const router = useRouter()
const generateStore = useGenerateStore()
const loading = ref(false)
type PageMode = 'form' | 'entry' | 'create'
const pageMode = ref<PageMode>('entry')
@@ -104,50 +105,45 @@ const customerData = ref({
})
const handleConfirm = async () => {
if (pageMode.value === 'form') {
if (customerData.value.nickname === '') {
showToast({
message: 'please input the nickname'
})
return
}
if (loading.value) return
const nickname = (customerData.value.nickname || '').trim()
const vipId = (customerData.value.vipId || '').trim()
customerCheckin({ nickname: customerData.value.nickname }).then((res) => {
useUserInfoStore().resetGenerateParams()
generateStore.setCustomerInfo(res)
MyEvent.emit('clear-generate-state')
router.push('/workshop/home')
})
} else {
if (customerData.value.vipId === '') {
showToast({
message: 'please input the VIP ID'
})
return
}
if (customerData.value.nickname === '') {
showToast({
message: 'please input the nickname'
})
return
}
if (!nickname) {
showToast({ message: 'please input the nickname' })
return
}
createCustomer({
nickname: customerData.value.nickname,
vipId: customerData.value.vipId
} as CreateCustomerParams).then((res) => {
showToast({
message: 'Customer created successfully'
})
handleBack()
if (pageMode.value === 'create' && !vipId) {
showToast({ message: 'please input the VIP ID' })
return
}
loading.value = true
showToast({ message: 'Processing...', duration: 0, type: 'loading' })
try {
if (pageMode.value === 'create') {
await createCustomer({ nickname, vipId } as CreateCustomerParams)
showToast({ message: 'Customer created successfully' })
MyEvent.emit('update-customer-list')
})
}
const res = await customerCheckin({ nickname })
useUserInfoStore().resetGenerateParams()
generateStore.setCustomerInfo(res)
MyEvent.emit('clear-generate-state')
router.push('/workshop/home')
} catch (err: any) {
showToast({ message: err?.message || 'Operation failed' })
} finally {
loading.value = false
closeToast()
}
}
const handleShowPopup = (flag: Boolean) => {
// showPopup.value = flag
profileRef.value.openSwitchCustomerPopup(flag)
profileRef.value.handleShowPopup(flag)
}
const handleSelectCustomer = (value) => {

View File

@@ -220,7 +220,7 @@ onUnmounted(() => {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
padding: 6rem 0 0 0;
padding: 15.9rem 0 0 0;
.content {
.loading-container {
:deep(.loading-image) {
@@ -229,10 +229,11 @@ onUnmounted(() => {
animation: none;
}
:deep(.loading-shadow) {
background-color: #000;
width: 9.2rem;
height: 2.4rem;
filter: blur(6px);
opacity: 0.5;
opacity: 0.2;
margin: 2.4rem 0 0;
// background-color: #d9d9d9;
}
@@ -247,8 +248,10 @@ onUnmounted(() => {
font-weight: 700;
line-height: 1.12;
background: #b3b3b3;
background: linear-gradient(120deg, #b3b3b3 1%, rgba(0, 0, 0, 0) 48%),
linear-gradient(344deg, #b3b3b2 16%, #000000 66%);
background: radial-gradient(80.79% 50% at 50% 50%, #d1c7c2 0%, rgba(255, 255, 255, 0) 100%),
radial-gradient(99.56% 93.08% at 99.56% 93.08%, #e6e6e6 0%, #000000 100%)
/* warning: gradient uses a rotation that is not supported by CSS and may not behave as expected */,
linear-gradient(120.09deg, #b3b3b3 0%, rgba(255, 255, 255, 0) 35.41%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -325,7 +328,7 @@ onUnmounted(() => {
text-align: center;
border-radius: 4.6rem;
padding: 0 2.15rem;
&.active{
&.active {
background-color: #f5f5f5;
}
}

View File

@@ -166,7 +166,7 @@ const handleContinue = () => {
display: flex;
flex-direction: column;
padding: 2rem;
padding-top: 6rem;
padding-top: 10rem;
}
.header {
@@ -178,6 +178,8 @@ const handleContinue = () => {
color: white;
line-height: 96%;
font-family: 'satoshiBold';
letter-spacing: -0.04rem;
margin-bottom: 3.2rem;
}
.sub-title{
font-family: 'satoshiRegular';

View File

@@ -59,11 +59,14 @@ const handleSelect = (value: string) => {
font-weight: 700;
font-size: 11rem;
line-height: 106%;
letter-spacing: -0.02rem;
margin-bottom: 4.6rem;
}
.desc {
font-family: 'satoshiRegular';
font-size: 4rem;
font-size: 6rem;
line-height: 132%;
letter-spacing: 0.02rem;
}
.select-list {
display: flex;