Files
spring-festival-greetings/pages/detail/index.vue
2026-02-08 18:57:45 +08:00

587 lines
12 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="detail-page">
<NavBar title="祝福贺卡" />
<scroll-view scroll-y class="content-scroll">
<view class="content-wrap">
<!-- User Info -->
<view class="user-header">
<image
class="avatar"
:src="
cardDetail?.from?.avatar ||
'https://file.lihailezzc.com/resource/b48c41054c2633c478463ac1b1f1ca23.png'
"
mode="aspectFill"
/>
<view class="user-meta">
<view class="user-name">{{ cardDetail?.blessingFrom }}</view>
<view class="user-msg">给你发来了一条新春祝福</view>
<view class="year-tag">
<text class="fire-icon">🎉</text> {{ cardDetail?.year || 2026 }}
{{ cardDetail?.festival || "丙午马年" }}
</view>
</view>
</view>
<!-- Card Preview Area -->
<view class="card-container">
<view class="card-inner">
<image
class="card-img"
:src="cardDetail?.imageUrl"
mode="widthFix"
/>
</view>
</view>
<!-- Action Buttons -->
<view class="action-buttons">
<button class="btn primary" @tap="makeGreeting">
<text class="btn-icon"></text> 我也要制作回赠祝福
</button>
<button class="btn secondary" @tap="saveCard">
<text class="btn-icon">📥</text> 保存这张精美贺卡
</button>
</view>
<!-- Recommendations -->
<!-- <view class="recommend-section">
<view class="section-header">
<text class="section-title">大家都在玩的头像挂饰</text>
<text class="more-link">查看更多</text>
</view>
<scroll-view scroll-x class="decor-scroll" show-scrollbar="false">
<view class="decor-list">
<view
class="decor-item"
v-for="(item, index) in decorList"
:key="index"
>
<view class="decor-img-box" :class="'style-' + (index % 3)">
<image :src="item.img" mode="aspectFit" class="decor-img" />
</view>
<text class="decor-name">{{ item.name }}</text>
</view>
</view>
</scroll-view>
</view> -->
<!-- Banner -->
<view class="wallpaper-banner" @tap="goToFortune">
<view class="banner-icon">
<text>🏮</text>
</view>
<view class="banner-content">
<text class="banner-title">去抽取新年运势</text>
<text class="banner-desc">每日一签开启你的新年好运</text>
</view>
<text class="banner-arrow"></text>
</view>
<view class="wallpaper-banner" @tap="goToGreeting">
<view class="banner-icon">
<text>🧧</text>
</view>
<view class="banner-content">
<text class="banner-title">去制作新年头像</text>
<text class="banner-desc">定制专属头像传递浓浓年味</text>
</view>
<text class="banner-arrow"></text>
</view>
<view class="wallpaper-banner" @tap="goToWallpaper">
<view class="banner-icon">
<text>🖼</text>
</view>
<view class="banner-content">
<text class="banner-title">去挑选新年壁纸</text>
<text class="banner-desc">精选新年壁纸让手机也过年</text>
</view>
<text class="banner-arrow"></text>
</view>
<!-- Footer -->
<view class="page-footer">
<view class="footer-line">
<text class="line"></text>
<text class="text">2026 HAPPY NEW YEAR</text>
<text class="line"></text>
</view>
<view class="footer-sub">新春祝福 · 传递温情</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref } from "vue";
import { onLoad, onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app";
import { getPageDetail } from "@/api/system.js";
import { saveViewRequest } from "@/utils/common.js";
import NavBar from "@/components/NavBar/NavBar.vue";
const cardId = ref("");
const cardDetail = ref({});
onLoad(async (options) => {
if (options.shareToken) {
const card = await getPageDetail(options.shareToken);
cardId.value = card.id;
cardDetail.value = card;
saveViewRequest(options.shareToken, "card_generate", card.id);
}
});
onShareAppMessage(() => {
return {
title: "送你一张精美的新春祝福卡片 🎊",
path: `/pages/detail/index?shareToken=${cardDetail.value?.shareToken || ""}`,
imageUrl:
cardDetail.value?.imageUrl ||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
};
});
onShareTimeline(() => {
return {
title: "送你一张精美的新春祝福卡片 🎊",
query: `shareToken=${cardDetail.value?.shareToken || ""}`,
imageUrl:
cardDetail.value?.imageUrl ||
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
};
});
const makeGreeting = () => {
uni.switchTab({ url: "/pages/make/index" });
};
const saveCard = async () => {
uni.showLoading({ title: "保存中..." });
const localPath = await loadImage(cardDetail?.value?.imageUrl || "");
uni.saveImageToPhotosAlbum({
filePath: localPath,
success() {
uni.hideLoading();
uni.showToast({ title: "已保存到相册" });
},
fail(err) {
uni.hideLoading();
// handleSaveAuth(err);
},
});
};
const loadImage = (url) => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: url,
success: (res) => {
resolve(res.path); // 本地路径
},
fail: (err) => {
reject(err);
},
});
});
};
const decorList = ref([
{
name: "如意马年",
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
},
{
name: "大吉大利",
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
},
{
name: "春意盎然",
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
},
{
name: "万事顺遂",
img: "https://file.lihailezzc.com/resource/1463f294244c11cf274a5eaae115872a.jpeg",
},
]);
const goToMake = () => {
uni.navigateTo({
url: "/pages/avatar/index",
});
};
const goToFortune = () => {
uni.navigateTo({
url: "/pages/fortune/index",
});
};
const goToGreeting = () => {
uni.navigateTo({
url: "/pages/avatar/index",
});
};
const goToWallpaper = () => {
uni.navigateTo({
url: "/pages/wallpaper/index",
});
};
</script>
<style lang="scss" scoped>
.detail-page {
min-height: 100vh;
background: #fff;
background-image: linear-gradient(to bottom, #fff6f6 0%, #fff 400rpx);
box-sizing: border-box;
}
.content-scroll {
height: 100%;
}
.content-wrap {
padding: 20rpx 30rpx 60rpx;
}
/* User Header */
.user-header {
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
margin-right: 24rpx;
border: 4rpx solid rgba(215, 180, 150, 0.3);
}
.user-meta {
display: flex;
flex-direction: column;
}
.user-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.user-msg {
font-size: 24rpx;
color: #666;
margin-top: 4rpx;
}
.year-tag {
display: inline-flex;
align-items: center;
margin-top: 8rpx;
font-size: 20rpx;
color: #ff3b30;
background: rgba(255, 59, 48, 0.08);
padding: 4rpx 12rpx;
border-radius: 8rpx;
align-self: flex-start;
}
.fire-icon {
margin-right: 6rpx;
}
.wallpaper-banner {
background: #f8f8f8;
border-radius: 24rpx;
padding: 30rpx;
display: flex;
align-items: center;
margin-bottom: 60rpx;
}
.banner-icon {
width: 80rpx;
height: 80rpx;
background: #fff;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
}
.banner-icon text {
font-size: 40rpx;
color: #ff3b30;
}
.banner-content {
flex: 1;
}
.banner-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.banner-desc {
font-size: 22rpx;
color: #999;
}
.banner-arrow {
font-size: 36rpx;
color: #ccc;
}
/* Card Container */
.card-container {
background: #fff;
border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 16rpx 40rpx rgba(0, 0, 0, 0.08);
margin-bottom: 40rpx;
margin: 24rpx auto;
}
.card-inner {
position: relative;
margin: 0 auto;
width: 540rpx;
height: 960rpx;
background: #f0f0f0;
}
.card-img {
width: 100%;
height: 100%;
}
.card-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 40rpx;
color: #fff;
background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
}
.card-year {
font-size: 36rpx;
letter-spacing: 10rpx;
opacity: 0.9;
text-align: center;
margin-bottom: 10rpx;
}
.card-sub {
font-size: 20rpx;
text-align: center;
opacity: 0.8;
margin-bottom: 40rpx;
}
.card-greeting-en {
font-size: 20rpx;
opacity: 0.8;
}
.card-greeting-cn {
font-size: 40rpx;
font-weight: bold;
line-height: 1.5;
margin-top: 10rpx;
}
.card-footer {
padding: 30rpx 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
}
.card-info {
display: flex;
flex-direction: column;
}
.card-info .label {
font-size: 24rpx;
color: #999;
margin-bottom: 8rpx;
}
.card-info .value {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.qr-code {
width: 80rpx;
height: 80rpx;
background: #ffecec;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
}
.qr-icon {
color: #ff3b30;
font-size: 40rpx;
}
/* Buttons */
.action-buttons {
margin-bottom: 50rpx;
}
.btn {
height: 96rpx;
border-radius: 999rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
font-weight: 600;
margin-bottom: 24rpx;
border: none;
}
.btn.primary {
background: #ff3b30;
color: #fff;
box-shadow: 0 12rpx 24rpx rgba(255, 59, 48, 0.3);
}
.btn.secondary {
background: #f5f5f5;
color: #333;
}
.btn-icon {
margin-right: 12rpx;
font-size: 36rpx;
}
/* Recommendations */
.recommend-section {
margin-bottom: 40rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.more-link {
font-size: 24rpx;
color: #ff3b30;
}
.decor-list {
display: flex;
}
.decor-item {
margin-right: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
width: 140rpx;
}
.decor-img-box {
width: 140rpx;
height: 140rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12rpx;
border: 4rpx solid transparent;
}
.style-0 {
border-color: #ff3b30;
background: #fff0f0;
}
.style-1 {
border-color: #d4a017;
background: #fffcf0;
}
.style-2 {
border-color: #ffadd2;
background: #fff0f5;
}
.decor-img {
width: 100rpx;
height: 100rpx;
}
.decor-name {
font-size: 22rpx;
color: #666;
}
/* Banner */
.banner-card {
background: #fff6f6;
border-radius: 24rpx;
padding: 24rpx;
display: flex;
align-items: center;
border: 2rpx solid #ffebeb;
margin-bottom: 60rpx;
}
.banner-icon {
width: 80rpx;
height: 80rpx;
background: #ff3b30;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
}
.placeholder-icon {
color: #fff;
font-size: 40rpx;
}
.banner-content {
flex: 1;
}
.banner-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.banner-desc {
font-size: 22rpx;
color: #999;
margin-top: 4rpx;
}
.banner-btn {
background: #ff3b30;
color: #fff;
font-size: 24rpx;
padding: 10rpx 30rpx;
border-radius: 999rpx;
line-height: 1.5;
margin: 0;
}
/* Footer */
.page-footer {
text-align: center;
padding-bottom: 40rpx;
}
.footer-line {
display: flex;
align-items: center;
justify-content: center;
color: #ccc;
font-size: 24rpx;
font-weight: bold;
letter-spacing: 2rpx;
margin-bottom: 8rpx;
}
.line {
width: 60rpx;
height: 2rpx;
background: #ddd;
margin: 0 20rpx;
}
.footer-sub {
font-size: 20rpx;
color: #ccc;
}
</style>