topfans/frontend/pages/castlove/success.vue
2026-05-17 23:33:45 +08:00

482 lines
11 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="success-container">
<!-- 背景图片 -->
<image class="background-image" src="/static/background/exhibitionSuccess.png" mode="aspectFill"></image>
<!-- 蒙层 -->
<view class="background-overlay"></view>
<!-- Header组件 -->
<!-- <Header :showBack="true" :showGuideIcon="false" :showTaskIcon="false" :showStarActivityIcon="false" backIconColor="#e6e6e6" /> -->
<!-- 内容区域 -->
<view class="content-wrapper">
<!-- 成功提示文字 -->
<view class="success-title">
<text class="title-text">铸造成功</text>
</view>
<!-- 藏品展示区域 -->
<view class="nft-display-section">
<!-- 光栅卡单张工作台预览陀螺仪 -->
<view v-if="isLenticular" class="lenticular-result-wrap">
<view class="lenticular-result-card">
<view class="card-wrapper craft-card-wrapper">
<image
class="card-frame"
src="/static/square/gerenzhongxincangpinkuang.png"
mode="aspectFit"
/>
<view class="craft-lenticular-slot">
<LenticularCard
v-if="lenticularLayers.length > 0"
class="craft-lenticular-card"
:layers="lenticularLayers"
:transforms="layerTransforms"
:gyro-source="gyroSourceLabel"
:skip-built-in-touch="true"
tilt-hint-text="晃动查看"
:shimmer-mid-opacity="0.16"
@simulate="simulate"
/>
</view>
</view>
</view>
</view>
</view>
<!-- 铸造成功角色图片 -->
<view class="character-section">
<image
class="character-image"
src="/static/nft/mint-success-char.png"
mode="aspectFit"
></image>
</view>
<!-- 查看详情按钮 -->
<view class="button-section">
<button class="btn-primary" @click="handleViewDetails">查看详情</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onUnload } from '@dcloudio/uni-app';
import Header from '../components/Header.vue';
import NftCard from '../components/NftCard.vue';
import LenticularCard from '@/components/lenticular/LenticularCard.vue';
import { useLenticularCraftTiltPreview } from '@/composables/useLenticularCraftTiltPreview.js';
import { buildLenticularLayersTwo } from '@/utils/castloveMintForm.js';
import { getAssetDetailApi, getAssetMaterialsApi } from '@/utils/api.js';
// 藏品数据
const nftData = ref({
image: '',
name: '',
event: '',
remark: '',
materialType: '',
is_lenticular: false,
bg_image: '',
});
// 是否显示为光栅卡
const isLenticular = ref(false)
// 光栅卡图层
const lenticularLayers = ref([])
const {
layerTransforms,
simulate,
gyroSourceLabel,
scheduleTiltStart,
stopTiltPreview,
} = useLenticularCraftTiltPreview(lenticularLayers);
// NftCard 样式
const nftCardStyle = {
position: 'relative',
transform: 'rotate(-5deg)',
overflow: 'hidden'
};
// 页面加载时获取数据
onMounted(async () => {
// 从全局存储读取数据
try {
const tempNftData = uni.getStorageSync('temp_nft_data');
if (tempNftData) {
const data = JSON.parse(tempNftData);
// 优先使用 API 获取最新数据
if (data.asset_id) {
try {
const res = await getAssetDetailApi(data.asset_id);
console.log('[success] asset detail API 返回:', res);
if (res.code === 200 && res.data?.asset) {
const asset = res.data.asset;
console.log('[success] asset:', asset);
// 获取主图和背景图(通过 materials 接口)
let imageUrl = asset.image || data.image || '';
let bgImageUrl = asset.bg_image || data.bg_image || '';
try {
const materialsRes = await getAssetMaterialsApi(data.asset_id);
console.log('[success] materials API 返回:', materialsRes);
if (materialsRes.code === 200 && materialsRes.data) {
const materials = Array.isArray(materialsRes.data) ? materialsRes.data : materialsRes.data.materials || [];
console.log('[success] materials 数组:', materials);
// 找到 type 为主图和背景图的素材
const mainMat = materials.find(m => m.material_type === 'main');
const bgMat = materials.find(m => m.material_type === 'bg');
console.log('[success] mainMat:', mainMat, 'bgMat:', bgMat);
if (mainMat?.material_url_signed) imageUrl = mainMat.material_url_signed;
if (bgMat?.material_url_signed) bgImageUrl = bgMat.material_url_signed;
console.log('[success] imageUrl:', imageUrl, 'bgImageUrl:', bgImageUrl);
}
} catch (e) {
console.error('获取素材详情失败:', e);
}
nftData.value = {
image: imageUrl,
name: asset.name || data.name || '未命名藏品',
event: asset.event || data.event || '',
remark: asset.remark || data.remark || '',
materialType: asset.material_type || data.materialType || '',
is_lenticular: asset.is_lenticular || data.is_lenticular || false,
bg_image: bgImageUrl,
};
console.log('[success] nftData 设置后:', nftData.value);
// 如果是光栅卡,构建图层
if ((asset.is_lenticular || data.is_lenticular) && bgImageUrl && imageUrl) {
isLenticular.value = true
lenticularLayers.value = buildLenticularLayersTwo(bgImageUrl, imageUrl)
scheduleTiltStart()
}
} else {
// API 返回异常,使用本地数据
applyLocalNftData(data);
}
} catch (e) {
console.error('获取藏品详情失败,使用本地数据:', e);
applyLocalNftData(data);
}
} else {
applyLocalNftData(data);
}
}
} catch (e) {
console.error('读取藏品数据失败:', e);
uni.showToast({
title: '数据加载失败',
icon: 'none'
});
}
});
// 应用本地存储的数据
function applyLocalNftData(data) {
nftData.value = {
image: data.image || '',
name: data.name || '未命名藏品',
event: data.event || '',
remark: data.remark || '',
materialType: data.materialType || '',
is_lenticular: data.is_lenticular || false,
bg_image: data.bg_image || '',
};
// 如果是光栅卡,构建图层
if (data.is_lenticular && data.image && data.bg_image) {
isLenticular.value = true
lenticularLayers.value = buildLenticularLayersTwo(data.bg_image, data.image)
scheduleTiltStart()
}
}
onUnload(() => {
stopTiltPreview()
try {
uni.removeStorageSync('temp_nft_data');
} catch (e) {
/* noop */
}
});
// 查看详情(保留 temp_nft_data避免第二次点击时 order_id 丢失)
const handleViewDetails = () => {
let orderId = '';
let assetId = '';
try {
const raw = uni.getStorageSync('temp_nft_data');
if (raw) {
const parsed = JSON.parse(raw);
orderId = parsed.order_id || '';
assetId = parsed.asset_id || '';
}
} catch (e) {
console.error('读取铸造结果失败:', e);
}
if (!orderId && !assetId) {
uni.showToast({ title: '订单信息已失效,请从星册查看', icon: 'none' });
return;
}
const query = assetId
? `asset_id=${encodeURIComponent(assetId)}`
: `order_id=${encodeURIComponent(orderId)}`;
uni.navigateTo({
url: `/pages/asset-detail/asset-detail?${query}&from=castlove`,
});
};
onUnload(() => {
try {
uni.removeStorageSync('temp_nft_data');
} catch (e) {
/* noop */
}
});
</script>
<style scoped>
.success-container {
position: relative;
width: 100vw;
height: 100vh;
min-height: 100vh;
overflow: hidden;
}
.background-image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 0;
object-fit: cover;
min-width: 100%;
min-height: 100%;
}
.background-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 0;
background: rgba(0, 0, 0, 0.2);
}
.content-wrapper {
position: relative;
z-index: 1;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 200rpx 40rpx 100rpx;
box-sizing: border-box;
}
/* 成功提示文字 */
.success-title {
margin-bottom: 60rpx;
animation: fadeInDown 0.6s ease-out;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.title-text {
font-size: 72rpx;
font-weight: bold;
font-family: 'yt', sans-serif;
color: #e6e6e6;
text-shadow:
0 4rpx 20rpx rgba(255, 107, 157, 0.8),
0 2rpx 10rpx rgba(0, 0, 0, 0.5);
}
/* 藏品展示区域 */
.nft-display-section {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 60rpx;
animation: zoomIn 0.8s ease-out 0.2s both;
}
/* 光栅卡容器 */
.lenticular-card-wrap {
width: 420rpx;
height: 560rpx;
display: flex;
align-items: center;
justify-content: center;
}
.lenticular-preview {
width: 420rpx;
height: 560rpx;
}
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.5);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* 铸造成功角色图片区域 */
.character-section {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 60rpx;
animation: fadeInUp 0.8s ease-out 0.4s both;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.character-image {
width: 500rpx;
height: 500rpx;
object-fit: contain;
}
/* 按钮区域 */
.button-section {
width: 100%;
max-width: 600rpx;
display: flex;
justify-content: center;
animation: fadeIn 1s ease-out 0.6s both;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.btn-primary {
width: 400rpx;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 36rpx;
font-family: 'yt', sans-serif;
font-weight: 600;
border: none;
background: linear-gradient(165deg, #F0E4B1 0%, #F08399 50%, #B94E73 90%, #834B9E 100%);
color: #e6e6e6;
box-shadow:
0 0 20rpx rgba(255, 107, 157, 0.6),
0 0 40rpx rgba(255, 140, 66, 0.4),
0 4rpx 20rpx rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
}
.btn-primary::after {
border: none;
}
.btn-primary:active {
opacity: 0.9;
transform: scale(0.98);
}
/* 光栅卡样式 */
.lenticular-result-wrap {
display: flex;
justify-content: center;
z-index: 8;
}
.lenticular-result-card {
display: flex;
flex-direction: column;
align-items: center;
}
.lenticular-result-card .card-wrapper {
position: relative;
width: 352rpx;
height: 520rpx;
}
.lenticular-result-card .craft-card-wrapper {
margin-bottom: 32rpx;
}
.lenticular-result-card .card-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
transform: rotate(-10deg);
}
.lenticular-result-card .craft-lenticular-slot {
position: absolute;
left: 50%;
top: 50%;
width: 87%;
height: 96%;
border-radius: 48rpx;
transform: translate(-50%, -50%) rotate(-10deg);
z-index: 2;
overflow: hidden;
}
.lenticular-result-card .craft-lenticular-card {
width: 100%;
height: 100%;
}
</style>