topfans/frontend/pages/discover/generation-loading.vue
2026-04-08 01:30:58 +08:00

432 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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.redirectTo({
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>