make page

This commit is contained in:
zzc
2026-01-15 08:43:10 +08:00
parent f34899eb81
commit 3d2d20dd5f
21 changed files with 4315 additions and 737 deletions

524
pages/detail/index.vue Normal file
View File

@@ -0,0 +1,524 @@
<template>
<view class="detail-page" :style="{ paddingTop: navBarHeight + 'px' }">
<!-- Custom Navigation Bar -->
<view
class="nav-bar"
:style="{
height: navBarHeight + 'px',
paddingTop: statusBarHeight + 'px',
}"
>
<text class="nav-title">新春祝福详情</text>
</view>
<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="banner-card">
<view class="banner-icon">
<image
src="/static/logo.png"
mode="aspectFit"
style="width: 100%; height: 100%"
v-if="false"
/>
<view class="placeholder-icon"></view>
</view>
<view class="banner-content">
<view class="banner-title">领取我的马年头像框</view>
<view class="banner-desc">定制专属新春社交形象</view>
</view>
<button class="banner-btn">去领取</button>
</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, onMounted } from "vue";
import { getBavBarHeight } from "@/utils/system";
import { onLoad } from "@dcloudio/uni-app";
import { getCardDetail } from "@/api/card.js";
const navBarHeight = ref(44);
const statusBarHeight = ref(20);
const cardId = ref("");
const cardDetail = ref({});
onLoad(async (options) => {
if (options.shareToken) {
const card = await getCardDetail(options.shareToken);
cardId.value = card.id;
cardDetail.value = card;
}
});
onMounted(() => {
const sysInfo = uni.getSystemInfoSync();
statusBarHeight.value = sysInfo.statusBarHeight;
navBarHeight.value = getBavBarHeight();
});
const goBack = () => {
uni.navigateBack();
};
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",
},
]);
</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;
}
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
align-items: center;
padding-left: 20rpx;
background: #fff6f6; /* Match page bg */
}
.nav-left {
padding: 10rpx 20rpx;
font-size: 48rpx;
line-height: 1;
}
.nav-title {
font-size: 32rpx;
font-weight: 600;
margin-left: 10rpx;
}
.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;
}
/* 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>

View File

@@ -4,14 +4,14 @@
<view class="hero">
<view class="hero-badge">
<text class="badge-dot"></text>
<text class="badge-text">距春节还有 25 </text>
<text class="badge-text">距春节还有 30 </text>
</view>
<view class="hero-title">
<text class="year">2026</text>
<text class="main">新春祝福</text>
</view>
<text class="hero-sub">新年快乐万事如意!</text>
<image class="hero-decor" src="https://file.lihailezzc.com/resource/58c8d19e5f2d9c958a7b8b9f44b8c3e3.png" mode="aspectFill" />
<!-- <image class="hero-decor" src="https://file.lihailezzc.com/resource/58c8d19e5f2d9c958a7b8b9f44b8c3e3.png" mode="aspectFill" /> -->
</view>
<!-- 功能入口宫格 -->
@@ -22,9 +22,14 @@
class="feature-item"
@tap="onFeatureTap(item)"
>
<image class="feature-icon" :src="item.icon" mode="aspectFill" :style="{
backgroundColor: idx < 2 ? '#FEF2F2' : '#FFFBEC'
}"/>
<image
class="feature-icon"
:src="item.icon"
mode="aspectFill"
:style="{
backgroundColor: idx < 2 ? '#FEF2F2' : '#FFFBEC',
}"
/>
<view class="feature-texts">
<text class="feature-title">{{ item.title }}</text>
<text class="feature-sub">{{ item.subtitle }}</text>
@@ -53,10 +58,17 @@
<view class="use-right">
<view class="title-line">
<text class="use-title">{{ card.title }}</text>
<text v-if="card.tag" class="tag" :class="`tag--${card.tagType || 'default'}`">{{ card.tag }}</text>
<text
v-if="card.tag"
class="tag"
:class="`tag--${card.tagType || 'default'}`"
>{{ card.tag }}</text
>
</view>
<text class="use-desc">{{ card.desc }}</text>
<text class="use-cta" @tap.stop="onCta(card)">{{ card.cta }} ></text>
<text class="use-cta" @tap.stop="onCta(card)"
>{{ card.cta }} ></text
>
</view>
</view>
</view>
@@ -65,75 +77,112 @@
</template>
<script setup>
import { ref } from 'vue'
import { onPullDownRefresh } from '@dcloudio/uni-app'
import { getBavBarHeight } from '@/utils/system'
import { ref } from "vue";
import { onPullDownRefresh, onShareAppMessage } from "@dcloudio/uni-app";
import { getBavBarHeight } from "@/utils/system";
const features = ref([
{ title: '新春祝福卡片', subtitle: '定制专属贺卡', icon:'/static/icon/celebrate.png', type: 'card' },
{ title: '红包封面', subtitle: '获取新年红包封面', icon: '/static/icon/hongbao.png', type: 'video' },
{ title: '新春头像挂饰', subtitle: '焕上节日新饰', icon: '/static/icon/guashi.png', type: 'avatar_decor' },
{ title: '新年运势', subtitle: '抽取新年关键词', icon: '/static/icon/yunshi.png', type: 'avatar_frame' },
])
{
title: "新春祝福卡片",
subtitle: "定制专属贺卡",
icon: "/static/icon/celebrate.png",
type: "card",
},
{
title: "红包封面",
subtitle: "获取新年红包封面",
icon: "/static/icon/hongbao.png",
type: "video",
},
{
title: "新春头像挂饰",
subtitle: "焕上节日新饰",
icon: "/static/icon/guashi.png",
type: "avatar_decor",
},
{
title: "新年运势",
subtitle: "抽取新年关键词",
icon: "/static/icon/yunshi.png",
type: "avatar_frame",
},
]);
const popularCards = ref([
{
title: '招财进宝金框',
tag: '热门',
tagType: 'hot',
desc: '2026马年限定汉字金框金光闪烁财运亨通。适合送亲友的新春祝福。',
cta: '立即制作',
cover: 'https://file.lihailezzc.com/9a929a32-439f-453b-b603-fda7b04cbe08.png'
title: "招财进宝金框",
tag: "热门",
tagType: "hot",
desc: "2026马年限定汉字金框金光闪烁财运亨通。适合送亲友的新春祝福。",
cta: "立即制作",
cover:
"https://file.lihailezzc.com/9a929a32-439f-453b-b603-fda7b04cbe08.png",
},
{
title: '大吉大利卡片',
tag: '精选',
tagType: 'featured',
desc: '经典红色大拜年卡片,适合送长辈、老师、同学,传递满满的新春喜气。',
cta: '去写祝福',
cover: 'https://file.lihailezzc.com/b5fe8ffb-5901-48d2-94fb-48191e36cbf5.png'
title: "大吉大利卡片",
tag: "精选",
tagType: "featured",
desc: "经典红色大拜年卡片,适合送长辈、老师、同学,传递满满的新春喜气。",
cta: "去写祝福",
cover:
"https://file.lihailezzc.com/b5fe8ffb-5901-48d2-94fb-48191e36cbf5.png",
},
{
title: '合家团圆模板',
tag: '爆款',
tagType: 'hot2',
desc: '一键生成合家福贺图,支持换装、特效装饰、朋友圈海报等。',
cta: '开始创作',
cover: 'https://file.lihailezzc.com/91cd1611-bb87-442b-a338-24e9d79e4ee9.png',
type: 'video'
}
])
title: "合家团圆模板",
tag: "爆款",
tagType: "hot2",
desc: "一键生成合家福贺图,支持换装、特效装饰、朋友圈海报等。",
cta: "开始创作",
cover:
"https://file.lihailezzc.com/91cd1611-bb87-442b-a338-24e9d79e4ee9.png",
type: "video",
},
]);
const onFeatureTap = (item) => {
uni.showToast({ title: `进入:${item.title}`, icon: 'none' })
uni.showToast({ title: `进入:${item.title}`, icon: "none" });
// uni.navigateTo({ url: `/pages/${item.type}/index` })
}
};
const previewCard = (card) => {
uni.previewImage({ urls: [card.cover] })
}
uni.previewImage({ urls: [card.cover] });
};
const onMore = () => {
uni.showToast({ title: '更多模板即将上线~', icon: 'none' })
}
uni.showToast({ title: "更多模板即将上线~", icon: "none" });
};
const onCta = (card) => {
uni.showToast({ title: `${card.cta} · ${card.title}`, icon: 'none' })
}
uni.showToast({ title: `${card.cta} · ${card.title}`, icon: "none" });
};
onPullDownRefresh(() => {
setTimeout(() => {
uni.stopPullDownRefresh()
uni.showToast({ title: '已为你更新内容', icon: 'success' })
}, 600)
})
uni.stopPullDownRefresh();
uni.showToast({ title: "已为你更新内容", icon: "success" });
}, 600);
});
onShareAppMessage(() => {
return {
title: "新春祝福",
path: "/pages/detail/index",
imageUrl: "/static/images/bg.jpg",
success: function (res) {
uni.showToast({ title: "分享成功", icon: "success" });
},
fail: function (res) {
uni.showToast({ title: "分享失败", icon: "none" });
},
};
});
</script>
<style lang="scss" scoped>
.spring-page {
min-height: 100vh;
box-sizing: border-box;
background: #F8F6F6;
background: #f8f6f6;
}
/* 顶部 Banner */
@@ -152,23 +201,41 @@ onPullDownRefresh(() => {
.hero-badge {
display: inline-flex;
align-items: center;
background: rgba(255,255,255,0.2);
background: rgba(255, 255, 255, 0.2);
border-radius: 999rpx;
padding: 8rpx 16rpx;
font-size: 22rpx;
.badge-dot { margin-right: 8rpx; }
.badge-dot {
margin-right: 8rpx;
}
}
.hero-title {
margin-top: 24rpx;
display: flex;
align-items: baseline;
.year { font-size: 44rpx; font-weight: 700; margin-right: 12rpx; }
.main { font-size: 44rpx; font-weight: 700; }
.year {
font-size: 44rpx;
font-weight: 700;
margin-right: 12rpx;
}
.main {
font-size: 44rpx;
font-weight: 700;
}
}
.hero-sub {
margin-top: 8rpx;
font-size: 24rpx;
opacity: 0.9;
}
.hero-sub { margin-top: 8rpx; font-size: 24rpx; opacity: 0.9; }
.hero-decor {
position: absolute; right: 12rpx; bottom: 12rpx;
width: 160rpx; height: 160rpx; opacity: 0.3; border-radius: 16rpx;
position: absolute;
right: 12rpx;
bottom: 12rpx;
width: 160rpx;
height: 160rpx;
opacity: 0.3;
border-radius: 16rpx;
}
}
@@ -181,13 +248,14 @@ onPullDownRefresh(() => {
margin-top: 8rpx;
.feature-item {
position: relative;
display: flex;
position: relative;
display: flex;
align-items: left;
flex-direction: column;
padding: 20rpx; border-radius: 18rpx;
background: #fff;
box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.04);
padding: 20rpx;
border-radius: 18rpx;
background: #fff;
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
}
.feature-item::after {
content: "";
@@ -198,66 +266,147 @@ onPullDownRefresh(() => {
height: 60rpx;
border-bottom-left-radius: 80rpx;
z-index: 1;
}
.feature-item:nth-child(1)::after,
.feature-item:nth-child(2)::after {
background: #FEF2F2; /* 可换成你的主题粉 */
}
.feature-item:nth-child(3)::after,
.feature-item:nth-child(4)::after {
background: #FFFBEC; /* 温柔一点的黄 */
}
}
.feature-item:nth-child(1)::after,
.feature-item:nth-child(2)::after {
background: #fef2f2; /* 可换成你的主题粉 */
}
.feature-item:nth-child(3)::after,
.feature-item:nth-child(4)::after {
background: #fffbec; /* 温柔一点的黄 */
}
.feature-icon {
width: 60rpx;
height: 60rpx;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
padding: 5rpx;
}
.feature-texts {
margin-top: 20rpx;
display: flex;
display: flex;
flex-direction: column;
.feature-title { font-size: 28rpx; color: #222; font-weight: 600; }
.feature-sub { font-size: 22rpx; color: #888; margin-top: 4rpx; }
.feature-title {
font-size: 28rpx;
color: #222;
font-weight: 600;
}
.feature-sub {
font-size: 22rpx;
color: #888;
margin-top: 4rpx;
}
}
}
/* 通用区块标题 */
.section { margin-top: 28rpx; }
.section {
margin-top: 28rpx;
}
.section-header {
display: flex; align-items: center; padding: 0 24rpx;
.section-bar { width: 10rpx; height: 30rpx; border-radius: 6rpx; background: #ff3b30; margin-right: 12rpx; }
.section-title { font-size: 28rpx; color: #222; flex: 1; font-weight: 600; }
.section-more { font-size: 24rpx; color: #ff3b30; }
display: flex;
align-items: center;
padding: 0 24rpx;
.section-bar {
width: 10rpx;
height: 30rpx;
border-radius: 6rpx;
background: #ff3b30;
margin-right: 12rpx;
}
.section-title {
font-size: 28rpx;
color: #222;
flex: 1;
font-weight: 600;
}
.section-more {
font-size: 24rpx;
color: #ff3b30;
}
}
/* 大家都在用 - 竖向列表 */
.use-list { padding: 0 24rpx; margin-top: 16rpx; }
.use-list {
padding: 0 24rpx;
margin-top: 16rpx;
}
.use-row {
display: flex; align-items: center; background: #fff;
border-radius: 18rpx; box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.06);
padding: 16rpx; margin-bottom: 18rpx;
display: flex;
align-items: center;
background: #fff;
border-radius: 18rpx;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.06);
padding: 16rpx;
margin-bottom: 18rpx;
}
.thumb-wrap {
position: relative; width: 120rpx; height: 120rpx;
border-radius: 16rpx; overflow: hidden; margin-right: 16rpx;
position: relative;
width: 120rpx;
height: 120rpx;
border-radius: 16rpx;
overflow: hidden;
margin-right: 16rpx;
}
.thumb {
width: 100%;
height: 100%;
}
.thumb { width: 100%; height: 100%; }
.thumb-play {
position: absolute; right: 8rpx; bottom: 8rpx;
width: 40rpx; height: 40rpx; border-radius: 50%;
background: rgba(0,0,0,0.55); color: #fff; font-size: 22rpx;
display: flex; align-items: center; justify-content: center;
position: absolute;
right: 8rpx;
bottom: 8rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.55);
color: #fff;
font-size: 22rpx;
display: flex;
align-items: center;
justify-content: center;
}
.use-right {
flex: 1;
display: flex;
flex-direction: column;
}
.title-line {
display: flex;
align-items: center;
}
.use-title {
font-size: 28rpx;
color: #222;
font-weight: 600;
margin-right: 12rpx;
}
.use-right { flex: 1; display: flex; flex-direction: column; }
.title-line { display: flex; align-items: center; }
.use-title { font-size: 28rpx; color: #222; font-weight: 600; margin-right: 12rpx; }
.tag {
font-size: 22rpx; border-radius: 999rpx; padding: 4rpx 10rpx; margin-left: 4rpx;
&.tag--hot { color: #ff6a00; background: #fff4eb; }
&.tag--featured { color: #ff4d6d; background: #fff0f3; }
&.tag--hot2 { color: #7c4dff; background: #f3efff; }
font-size: 22rpx;
border-radius: 999rpx;
padding: 4rpx 10rpx;
margin-left: 4rpx;
&.tag--hot {
color: #ff6a00;
background: #fff4eb;
}
&.tag--featured {
color: #ff4d6d;
background: #fff0f3;
}
&.tag--hot2 {
color: #7c4dff;
background: #f3efff;
}
}
.use-desc { margin-top: 6rpx; font-size: 24rpx; color: #777; line-height: 1.5; }
.use-cta { margin-top: 10rpx; font-size: 24rpx; color: #ff3b30; }
</style>
.use-desc {
margin-top: 6rpx;
font-size: 24rpx;
color: #777;
line-height: 1.5;
}
.use-cta {
margin-top: 10rpx;
font-size: 24rpx;
color: #ff3b30;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,70 +1,102 @@
<template>
<view class="mine-content">
<!-- 顶部区域 -->
<view class="mine-top-panel" :style="{ paddingTop: getBavBarHeight() + 'px' }">
<view class="user-info">
<!-- 根据登录状态显示不同内容 -->
<view v-if="isLoggedIn" class="user-logged-in">
<image :src="userInfo.avatarUrl" class="avatar" mode="aspectFill" />
<view class="user-logged-in-info">
<text class="nickname">{{ userInfo.nickName }}</text>
<text class="phone">19969024553</text>
</view>
</view>
<view v-else class="user-not-logged-in">
<image :src="defaultAvatarUrl" class="avatar" mode="aspectFill" />
<button class="login-button" @tap="openPopup">点击登录</button>
</view>
</view>
</view>
<view class="mine-middle-panel">
<view class="mine-info-panel">
<view>0.00</view>
<view>我的余额</view>
</view>
<view class="mine-info-panel">
<view>0</view>
<view>优惠卷</view>
</view>
<view class="mine-info-panel">
<view>0</view>
<view>积分</view>
</view>
<view class="mine-info-panel">
<view>0</view>
<view>我的收藏</view>
</view>
</view>
<!-- 登录弹窗 -->
<uni-popup ref="popupRef" type="bottom" :safe-area="false">
<view class="popup-container">
<view class="popup-header">
<text class="popup-title">登录授权</text>
</view>
<view class="avatar-nickname">
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" class="avatar-selector">
<image v-if="avatarUrl" :src="avatarUrl" class="avatar-preview" />
<text v-else>获取头像</text>
</button>
<input
class="nickname-input"
type="nickname"
v-model="nickname"
placeholder="请输入昵称"
/>
</view>
<button class="confirm-btn" @tap="confirmLogin">确认登录</button>
</view>
</uni-popup>
</view>
<view class="mine-page">
<!-- Custom Navbar -->
<view class="nav-bar" :style="{ paddingTop: navBarTop + 'px', height: navBarHeight + 'px' }">
<!-- <text class="nav-title">我的</text> -->
</view>
<scroll-view scroll-y class="content-scroll" :style="{ paddingTop: (navBarTop + navBarHeight) + 'px' }">
<view class="content-wrap">
<!-- User Card -->
<view class="user-card" @tap="handleUserClick">
<view class="avatar-box">
<image :src="userInfo.avatarUrl" class="avatar" mode="aspectFill" />
<view class="red-badge"><text class="fire">🔥</text></view>
</view>
<view class="user-info">
<view class="row-1">
<text class="nickname">{{ userInfo.nickName }}</text>
<view class="vip-tag" v-if="isLoggedIn">
<text class="vip-text">VIP 祥瑞会员</text>
</view>
</view>
<view class="row-2" v-if="isLoggedIn">
<text class="arrow-icon"></text>
<text class="stats-text">已发送 <text class="num">3</text> 条新春祝福</text>
</view>
<view class="row-2" v-else>
<text class="stats-text">点击登录解锁更多功能</text>
</view>
</view>
<view class="card-arrow"></view>
</view>
<!-- My Creations -->
<view class="section-title">我的创作</view>
<view class="menu-group">
<view class="menu-item" @tap="navTo('greetings')">
<view class="icon-box red-bg"><text>🧧</text></view>
<text class="menu-text">我的新春祝福</text>
<text class="arrow"></text>
</view>
<view class="menu-item" @tap="navTo('videos')">
<view class="icon-box orange-bg"><text>📹</text></view>
<text class="menu-text">我的拜年视频</text>
<text class="arrow"></text>
</view>
<view class="menu-item" @tap="navTo('decorations')">
<view class="icon-box pink-bg"><text></text></view>
<text class="menu-text">我的头像挂饰</text>
<text class="arrow"></text>
</view>
<view class="menu-item" @tap="navTo('frames')">
<view class="icon-box yellow-bg"><text>🖼</text></view>
<text class="menu-text">我的马年头像</text>
<view class="new-badge">NEW</view>
<text class="arrow"></text>
</view>
</view>
<!-- History -->
<view class="section-title">历史记录</view>
<view class="menu-group">
<view class="menu-item" @tap="navTo('history')">
<view class="icon-box gray-bg"><text>🕒</text></view>
<text class="menu-text">新春祝福记录</text>
<text class="arrow"></text>
</view>
<view class="menu-item" @tap="navTo('archive')">
<view class="icon-box gray-bg"><text>📂</text></view>
<text class="menu-text">历年祝福存档</text>
<text class="arrow"></text>
</view>
</view>
<!-- Other Actions -->
<view class="menu-group mt-30">
<button class="menu-item share-btn" open-type="share">
<view class="icon-left"><text class="share-icon">🔗</text></view>
<text class="menu-text">分享给好友</text>
<text class="arrow"></text>
</button>
<view class="menu-item" @tap="navTo('help')">
<view class="icon-left"><text class="help-icon"></text></view>
<text class="menu-text">使用说明 / 帮助</text>
<text class="arrow"></text>
</view>
</view>
<!-- Footer -->
<view class="version-info">2026 丙午马年 · 新春助手 v1.0.2</view>
<!-- Bottom Spacer for TabBar -->
<view style="height: 120rpx;"></view>
</view>
</scroll-view>
<!-- Login Popup -->
<LoginPopup ref="loginPopupRef" @logind="handleLogind"/>
</view>
</template>
<script setup>
@@ -74,230 +106,261 @@ import { getPlatformProvider, getBavBarHeight } from '@/utils/system'
import { useUserStore } from '@/stores/user'
import { apiLogin } from '@/api/auth.js'
import LoginPopup from '@/components/LoginPopup/LoginPopup.vue'
const userStore = useUserStore()
const popupRef = ref(null)
const loginPopupRef = ref(null)
// 用户输入的临时信息
const avatarUrl = ref('')
const nickname = ref('')
// Navigation Bar
const navBarTop = ref(20)
const navBarHeight = ref(44)
// User Info
const defaultAvatarUrl = 'https://file.lihailezzc.com/resource/d9b329082b32f8305101f708593a4882.png'
// 从store获取用户信息改为计算属性
const userInfo = computed(() => ({
nickName: userStore.userInfo.nickName || '登录',
nickName: userStore.userInfo.nickName || '点击登录',
avatarUrl: userStore.userInfo.avatarUrl || defaultAvatarUrl
}))
// 判断用户是否已登录
const isLoggedIn = computed(() => !!userStore.userInfo.nickName)
// 默认头像
const defaultAvatarUrl = 'https://file.lihailezzc.com/resource/d9b329082b32f8305101f708593a4882.png'
// 获取状态栏高度
const bavBarHeight = ref(0)
onMounted(() => {
// 确保高度值在组件挂载后获取
bavBarHeight.value = getBavBarHeight()
const sysInfo = uni.getSystemInfoSync()
navBarTop.value = sysInfo.statusBarHeight
// Assuming standard nav bar height
navBarHeight.value = 44
})
const openPopup = () => {
popupRef.value.open()
const handleUserClick = () => {
if (!isLoggedIn.value) {
loginPopupRef.value.open()
} else {
// Navigate to profile details or do nothing
}
}
const onChooseAvatar = (e) => {
avatarUrl.value = e.detail.avatarUrl
const handleLogind = async () => {
// Logic after successful login if needed
}
const confirmLogin = async () => {
if (!nickname.value || !avatarUrl.value) {
return uni.showToast({ title: '请填写完整信息', icon: 'none' })
}
try {
const platform = getPlatformProvider()
if (platform === 'mp-weixin') {
const code = await wxLogin()
console.log('准备登录:', { code, nickname: nickname.value, avatarUrl: avatarUrl.value })
// console.log('准备登录:', { code, nickname: nickname.value, avatarUrl: 'http://tmp/HXhtcEwQ5A3B58476c91ba545ab67c6bf9c67d9c2559.jpeg' })
const fileKeyRes = await uni.uploadFile({
url: 'https://apis.lihailezzc.com/api/common/upload',
filePath: avatarUrl.value,
name: 'file', // 和后端接收文件字段名一致
header: {
'x-app-id': '6846f093fdf841f6189ef0b5',
},
})
if(fileKeyRes.statusCode < 400) {
const keyJson = JSON.parse(fileKeyRes.data)
const url = `https://file.lihailezzc.com/${keyJson?.data.key}`
const loginRes = await apiLogin({ code, nickname: nickname.value, avatarUrl: url })
// 保存用户信息到store
userStore.setUserInfo({
nickName: nickname.value,
avatarUrl: avatarUrl.value,
})
userStore.setToken(loginRes.token)
uni.showToast({ title: '登录成功', icon: 'success' })
popupRef.value.close()
// 重置临时变量
avatarUrl.value = ''
nickname.value = ''
} else {
throw Error('获取失败')
}
}
} catch (err) {
uni.showToast({ title: '登录失败', icon: 'none' })
console.error(err)
}
const navTo = (page) => {
uni.showToast({ title: '功能开发中', icon: 'none' })
}
</script>
<style lang="scss">
.mine-content {
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
background: #F9F6F2;
button {
border: none;
outline: none;
background-color: transparent;
padding: 0;
margin: 0;
line-height: normal;
font-family: inherit;
}
button::after {
border: none;
}
.mine-top-panel{
width: 100vw;
height: 500rpx;
background-color: #beecd8;
border-bottom-left-radius: 50% 50rpx;
border-bottom-right-radius: 50% 50rpx;
overflow: hidden;
.user-info{
padding-left: 40rpx;
image {
width: 150rpx;
height: 150rpx;
border-radius: 50%;
}
.user-logged-in{
display: flex;
align-items: center;
.user-logged-in-info{
padding-left: 20rpx;
display: flex;
flex-direction: column;
.nickname{
color: #1a1a1a;
font-weight: 800;
}
.phone{
color: #000;
}
}
}
.user-not-logged-in{
display: flex;
align-items: center;
.login-button{
padding-left: 20rpx;
}
}
}
}
.mine-middle-panel{
width: 90vw;
height: 200rpx;
background-color: #fff;
margin-top: -100rpx;
border-radius: 20rpx; /* 四角小圆角 */
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.05); /* 柔和阴影 */
display: flex;
justify-content: space-between;
padding-left: 20rpx;
padding-right: 20rpx;
.mine-info-panel{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 23%;
}
}
<style lang="scss" scoped>
.mine-page {
min-height: 100vh;
background: #f9f9f9;
box-sizing: border-box;
}
/* 弹窗样式 */
.popup-container {
background-color: #fff;
padding: 40rpx 30rpx 60rpx;
border-top-left-radius: 30rpx;
border-top-right-radius: 30rpx;
.popup-header {
text-align: center;
margin-bottom: 30rpx;
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
background: #f9f9f9;
}
.nav-title {
font-size: 32rpx;
font-weight: bold;
color: #000;
}
.popup-title {
font-size: 36rpx;
font-weight: bold;
}
}
.content-scroll {
height: 100vh;
}
.content-wrap {
padding: 20rpx 30rpx 40rpx;
}
.avatar-nickname {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30rpx;
/* User Card */
.user-card {
background: #fff;
border-radius: 30rpx;
padding: 40rpx;
display: flex;
align-items: center;
margin-bottom: 40rpx;
position: relative;
box-shadow: 0 10rpx 30rpx rgba(0,0,0,0.03);
}
.avatar-box {
position: relative;
margin-right: 30rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 4rpx solid #fff;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
}
.red-badge {
position: absolute;
top: 0;
right: -10rpx;
width: 40rpx;
height: 40rpx;
background: #ff3b30;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid #fff;
}
.fire {
font-size: 24rpx;
color: #fff;
}
.avatar-selector {
width: 145rpx;
height: 145rpx;
border-radius: 50%;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
background-color: #eee;
}
.avatar-preview {
width: 100%;
height: 100%;
border-radius: 50%;
}
.user-info {
flex: 1;
}
.row-1 {
display: flex;
align-items: center;
margin-bottom: 12rpx;
}
.nickname {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-right: 16rpx;
}
.vip-tag {
background: #ffecec;
padding: 4rpx 16rpx;
border-radius: 999rpx;
}
.vip-text {
color: #ff3b30;
font-size: 20rpx;
font-weight: bold;
}
.row-2 {
display: flex;
align-items: center;
}
.arrow-icon {
color: #ff3b30;
font-size: 20rpx;
margin-right: 8rpx;
}
.stats-text {
font-size: 24rpx;
color: #666;
}
.num {
font-weight: bold;
color: #333;
margin: 0 4rpx;
}
.card-arrow {
font-size: 40rpx;
color: #ccc;
margin-left: 10rpx;
}
.nickname-input {
width: 80%;
border: 1rpx solid #ccc;
border-radius: 20rpx;
padding: 20rpx;
font-size: 26rpx;
text-align: center;
}
}
/* Section Title */
.section-title {
font-size: 26rpx;
font-weight: bold;
color: #999;
margin-bottom: 20rpx;
padding-left: 10rpx;
}
.confirm-btn {
background-color: #07c160;
color: white;
font-size: 30rpx;
border-radius: 50rpx;
padding: 20rpx 0;
width: 100%;
}
/* Menu Group */
.menu-group {
background: #fff;
border-radius: 24rpx;
overflow: hidden;
margin-bottom: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.02);
}
.menu-group.mt-30 {
margin-top: 30rpx;
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx;
background: #fff;
position: relative;
}
.menu-item:active {
background: #f9f9f9;
}
/* For button reset */
.menu-item.share-btn {
width: 100%;
text-align: left;
line-height: normal;
border-radius: 0;
}
.menu-item.share-btn::after {
border: none;
}
.icon-box {
width: 72rpx;
height: 72rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 24rpx;
font-size: 36rpx;
}
.red-bg { background: #fff0f0; color: #ff3b30; }
.orange-bg { background: #fff8e6; color: #ff9500; }
.pink-bg { background: #fff0f5; color: #ff2d55; }
.yellow-bg { background: #fffae0; color: #ffcc00; }
.gray-bg { background: #f5f5f5; color: #666; }
.icon-left {
width: 40rpx;
display: flex;
justify-content: center;
margin-right: 24rpx;
margin-left: 16rpx;
}
.share-icon, .help-icon {
font-size: 36rpx;
color: #666;
}
.menu-text {
flex: 1;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.new-badge {
background: #ff3b30;
color: #fff;
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
margin-right: 16rpx;
}
.arrow {
color: #ccc;
font-size: 32rpx;
}
/* Version Info */
.version-info {
text-align: center;
color: #ccc;
font-size: 22rpx;
margin-top: 60rpx;
}
</style>