432 lines
9.0 KiB
Vue
432 lines
9.0 KiB
Vue
<template>
|
||
<view class="generation-loading">
|
||
<!-- 背景图 -->
|
||
<image class="background-image" src="/static/background/exhibitionSuccess.png" mode="aspectFill" />
|
||
|
||
<!-- 礼盒区域 -->
|
||
<view class="gift-box">
|
||
<view class="gift-container">
|
||
<view class="gift-bow"></view>
|
||
<view class="gift-body">
|
||
<text class="gift-text">TOPFANS</text>
|
||
<view class="gift-window">
|
||
<text class="question-mark">?</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 进度条区域 -->
|
||
<view class="progress-container">
|
||
<view class="progress-bar-wrapper">
|
||
<view class="progress-bar">
|
||
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||
</view>
|
||
<view class="progress-icon" :style="{ left: progress + '%' }">
|
||
<view class="icon-circle"></view>
|
||
</view>
|
||
</view>
|
||
<text class="progress-text">{{ Math.round(progress) }}%</text>
|
||
<text class="loading-text">Loading</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue';
|
||
import { imageGenerationApi } from '@/utils/api.js';
|
||
|
||
const progress = ref(0);
|
||
let progressTimer = null;
|
||
let generationData = null;
|
||
|
||
// 模拟进度增长
|
||
const simulateProgress = () => {
|
||
progressTimer = setInterval(() => {
|
||
if (progress.value < 90) {
|
||
// 进度到90%前缓慢增长
|
||
const increment = Math.random() * 5 + 2;
|
||
progress.value = Math.min(90, progress.value + increment);
|
||
}
|
||
}, 500);
|
||
};
|
||
|
||
// 停止进度模拟
|
||
const stopProgress = () => {
|
||
if (progressTimer) {
|
||
clearInterval(progressTimer);
|
||
progressTimer = null;
|
||
}
|
||
};
|
||
|
||
// 完成进度
|
||
const completeProgress = () => {
|
||
stopProgress();
|
||
const finalInterval = setInterval(() => {
|
||
if (progress.value < 100) {
|
||
progress.value = Math.min(100, progress.value + 5);
|
||
} else {
|
||
clearInterval(finalInterval);
|
||
// 进度完成后延迟跳转
|
||
setTimeout(() => {
|
||
handleSuccess();
|
||
}, 500);
|
||
}
|
||
}, 50);
|
||
};
|
||
|
||
// 回退进度
|
||
const revertProgress = () => {
|
||
stopProgress();
|
||
const revertInterval = setInterval(() => {
|
||
if (progress.value > 0) {
|
||
progress.value = Math.max(0, progress.value - 10);
|
||
} else {
|
||
clearInterval(revertInterval);
|
||
// 回退完成后返回上一页
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 500);
|
||
}
|
||
}, 100);
|
||
};
|
||
|
||
// 调用图生图API - 同步模式
|
||
const callImageGeneration = async () => {
|
||
try {
|
||
const res = await imageGenerationApi(generationData);
|
||
|
||
if (res.data && res.data.images && res.data.images.length > 0) {
|
||
// 保存生成的图片
|
||
uni.setStorageSync('generated_images', JSON.stringify(res.data.images));
|
||
completeProgress();
|
||
} else {
|
||
uni.showToast({
|
||
title: '未生成图片',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
revertProgress();
|
||
}
|
||
} catch (err) {
|
||
console.error('[GenerationLoading] 生成失败:', err);
|
||
uni.showToast({
|
||
title: err.message || '生成失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
revertProgress();
|
||
}
|
||
};
|
||
|
||
// 处理成功
|
||
const handleSuccess = () => {
|
||
uni.showToast({
|
||
title: '生成成功',
|
||
icon: 'success',
|
||
duration: 1500
|
||
});
|
||
|
||
// 跳转到结果页面
|
||
setTimeout(() => {
|
||
uni.navigateTo({
|
||
url: '/pages/discover/generation-result'
|
||
});
|
||
}, 1500);
|
||
};
|
||
|
||
onMounted(() => {
|
||
// 从存储中获取传递的数据
|
||
try {
|
||
const requestDataStr = uni.getStorageSync('generation_request_data');
|
||
if (!requestDataStr) {
|
||
uni.showToast({
|
||
title: '数据错误',
|
||
icon: 'none'
|
||
});
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
return;
|
||
}
|
||
|
||
// 解析请求数据
|
||
generationData = JSON.parse(requestDataStr);
|
||
|
||
// 从castlove_form_data获取base64图片
|
||
const castloveDataStr = uni.getStorageSync('castlove_form_data');
|
||
if (castloveDataStr) {
|
||
const castloveData = JSON.parse(castloveDataStr);
|
||
// 将base64图片填充到请求数据中
|
||
if (generationData.subject_reference && generationData.subject_reference[0]) {
|
||
generationData.subject_reference[0].image_file = castloveData.imageBase64;
|
||
}
|
||
}
|
||
|
||
// 清除generation_request_data存储,避免重复使用
|
||
uni.removeStorageSync('generation_request_data');
|
||
|
||
console.log('[GenerationLoading] 接收到生成数据');
|
||
|
||
// 开始模拟进度
|
||
simulateProgress();
|
||
|
||
// 调用API
|
||
callImageGeneration();
|
||
} catch (e) {
|
||
console.error('[GenerationLoading] 读取数据失败:', e);
|
||
uni.showToast({
|
||
title: '数据错误',
|
||
icon: 'none'
|
||
});
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 1500);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.generation-loading {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
background: #000;
|
||
}
|
||
|
||
.background-image {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 1;
|
||
}
|
||
|
||
.gift-box {
|
||
position: absolute;
|
||
top: 20%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 450rpx;
|
||
height: 450rpx;
|
||
z-index: 2;
|
||
animation: float 3s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% {
|
||
transform: translateX(-50%) translateY(0) rotate(0deg);
|
||
}
|
||
50% {
|
||
transform: translateX(-50%) translateY(-20rpx) rotate(2deg);
|
||
}
|
||
}
|
||
|
||
.gift-container {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.gift-bow {
|
||
position: absolute;
|
||
top: -30rpx;
|
||
width: 200rpx;
|
||
height: 80rpx;
|
||
background: linear-gradient(135deg, #FFB6D9 0%, #FFA8C5 50%, #FFB6D9 100%);
|
||
border-radius: 50rpx 50rpx 20rpx 20rpx;
|
||
box-shadow: 0 8rpx 24rpx rgba(255, 107, 157, 0.4);
|
||
z-index: 3;
|
||
}
|
||
|
||
.gift-bow::before,
|
||
.gift-bow::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 10rpx;
|
||
width: 80rpx;
|
||
height: 60rpx;
|
||
background: linear-gradient(135deg, #FFB6D9 0%, #FFA8C5 100%);
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.gift-bow::before {
|
||
left: -40rpx;
|
||
transform: rotate(-20deg);
|
||
}
|
||
|
||
.gift-bow::after {
|
||
right: -40rpx;
|
||
transform: rotate(20deg);
|
||
}
|
||
|
||
.gift-body {
|
||
position: relative;
|
||
width: 350rpx;
|
||
height: 350rpx;
|
||
background: linear-gradient(135deg, #FFE5F0 0%, #FFD4E8 50%, #FFC9E3 100%);
|
||
border-radius: 30rpx;
|
||
box-shadow: 0 16rpx 48rpx rgba(255, 107, 157, 0.3);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.gift-body::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 60rpx;
|
||
height: 100%;
|
||
background: linear-gradient(180deg, rgba(255, 182, 217, 0.6) 0%, rgba(255, 168, 197, 0.6) 100%);
|
||
}
|
||
|
||
.gift-body::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 0;
|
||
transform: translateY(-50%);
|
||
width: 100%;
|
||
height: 60rpx;
|
||
background: linear-gradient(90deg, rgba(255, 182, 217, 0.6) 0%, rgba(255, 168, 197, 0.6) 100%);
|
||
}
|
||
|
||
.gift-text {
|
||
position: absolute;
|
||
top: 40rpx;
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #FF6B9D;
|
||
letter-spacing: 4rpx;
|
||
text-shadow: 0 2rpx 8rpx rgba(255, 107, 157, 0.3);
|
||
z-index: 2;
|
||
}
|
||
|
||
.gift-window {
|
||
position: relative;
|
||
width: 180rpx;
|
||
height: 180rpx;
|
||
background: linear-gradient(135deg, #FFF5FA 0%, #FFEBF3 100%);
|
||
border-radius: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: inset 0 4rpx 12rpx rgba(255, 107, 157, 0.2);
|
||
z-index: 2;
|
||
}
|
||
|
||
.question-mark {
|
||
font-size: 120rpx;
|
||
font-weight: bold;
|
||
color: #FFB6D9;
|
||
text-shadow: 0 4rpx 12rpx rgba(255, 107, 157, 0.3);
|
||
animation: questionPulse 2s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes questionPulse {
|
||
0%, 100% {
|
||
opacity: 0.8;
|
||
transform: scale(1);
|
||
}
|
||
50% {
|
||
opacity: 1;
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
.progress-container {
|
||
position: absolute;
|
||
bottom: 25%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 600rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
z-index: 3;
|
||
}
|
||
|
||
.progress-bar-wrapper {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 40rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 40rpx;
|
||
background: rgba(255, 255, 255, 0.3);
|
||
border-radius: 20rpx;
|
||
overflow: hidden;
|
||
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
||
backdrop-filter: blur(10rpx);
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #FF6B9D 0%, #FFA8C5 50%, #FFB6D9 100%);
|
||
border-radius: 20rpx;
|
||
transition: width 0.3s ease;
|
||
box-shadow: 0 0 20rpx rgba(255, 107, 157, 0.6);
|
||
}
|
||
|
||
.progress-icon {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
transition: left 0.3s ease;
|
||
}
|
||
|
||
.icon-circle {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #FFB6D9 0%, #FF6B9D 100%);
|
||
border-radius: 50%;
|
||
border: 4rpx solid #FFFFFF;
|
||
box-shadow: 0 4rpx 12rpx rgba(255, 107, 157, 0.5), 0 0 20rpx rgba(255, 107, 157, 0.4);
|
||
animation: pulse 1.5s ease-in-out infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% {
|
||
transform: scale(1);
|
||
box-shadow: 0 4rpx 12rpx rgba(255, 107, 157, 0.5), 0 0 20rpx rgba(255, 107, 157, 0.4);
|
||
}
|
||
50% {
|
||
transform: scale(1.1);
|
||
box-shadow: 0 6rpx 16rpx rgba(255, 107, 157, 0.7), 0 0 30rpx rgba(255, 107, 157, 0.6);
|
||
}
|
||
}
|
||
|
||
.progress-text {
|
||
font-size: 56rpx;
|
||
font-weight: bold;
|
||
color: #FFFFFF;
|
||
text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.4), 0 0 20rpx rgba(255, 107, 157, 0.5);
|
||
margin-bottom: 10rpx;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 36rpx;
|
||
color: #FFFFFF;
|
||
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.4);
|
||
letter-spacing: 6rpx;
|
||
font-weight: 500;
|
||
}
|
||
</style>
|