Files
spring-festival-greetings/pages/wallpaper/index.vue
2026-02-24 20:36:36 +08:00

464 lines
10 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="wallpaper-page">
<NavBar title="精美壁纸" />
<!-- Category Tabs -->
<view class="category-tabs">
<scroll-view scroll-x class="tabs-scroll" :show-scrollbar="false">
<view class="tabs-content">
<view
v-for="(item, index) in categories"
:key="index"
class="tab-item"
:class="{ active: currentCategoryId === item.id }"
@tap="switchCategory(item.id)"
>
{{ item.name }}
</view>
</view>
</scroll-view>
</view>
<!-- Points Info -->
<view class="points-bar">
<view class="points-left">
<uni-icons type="download" size="14" color="#ff9800" />
<text>每次下载消耗 {{ downloadCost }} 积分</text>
</view>
<view class="points-right">
<text>当前积分</text>
<text class="score-val">{{ userScore }}</text>
</view>
</view>
<!-- Wallpaper Grid -->
<scroll-view
scroll-y
class="wallpaper-scroll"
@scrolltolower="loadMore"
refresher-enabled
:refresher-triggered="isRefreshing"
@refresherrefresh="onRefresh"
>
<view class="grid-container">
<view
class="grid-item"
v-for="(item, index) in wallpapers"
:key="index"
>
<image
:src="getThumbUrl(item.imageUrl)"
mode="aspectFill"
class="wallpaper-img"
@tap="previewImage(index)"
/>
<view class="action-overlay">
<button
class="action-btn share"
open-type="share"
:data-item="item"
@tap.stop="shareWallpaper(item)"
>
<text class="icon"></text>
</button>
<view
class="action-btn download"
@tap.stop="downloadWallpaper(item)"
>
<text class="icon"></text>
</view>
</view>
</view>
</view>
<!-- Loading State -->
<view class="loading-state" v-if="loading">
<text>加载中...</text>
</view>
<view class="empty-state" v-if="!loading && wallpapers.length === 0">
<text>暂无壁纸</text>
</view>
<view
class="no-more"
v-if="!loading && !hasMore && wallpapers.length > 0"
>
<text>没有更多了</text>
</view>
</scroll-view>
<LoginPopup
ref="loginPopupRef"
@logind="handleLogind"
:share-token="shareToken"
/>
</view>
</template>
<script setup>
import { ref, computed } from "vue";
import { getWallpaperList, getWallpaperCategoryList } from "@/api/wallpaper.js";
import {
saveRemoteImageToLocal,
saveRecordRequest,
getShareToken,
} from "@/utils/common.js";
import { onShareAppMessage, onShareTimeline, onLoad } from "@dcloudio/uni-app";
import { getShareReward, abilityCheck } from "@/api/system.js";
import { useUserStore } from "@/stores/user";
import { saveViewRequest, trackRecord } from "@/utils/common.js";
import NavBar from "@/components/NavBar/NavBar.vue";
const userStore = useUserStore();
const loginPopupRef = ref(null);
const isLoggedIn = computed(() => !!userStore.userInfo.nickName);
const userScore = computed(() => userStore.userInfo.score || 0);
const downloadCost = ref(20);
const categories = ref([]);
const currentCategoryId = ref(null);
const wallpapers = ref([]);
const page = ref(1);
const loading = ref(false);
const hasMore = ref(true);
const isRefreshing = ref(false);
const shareToken = ref("");
onShareAppMessage(async (options) => {
if (!isLoggedIn.value) {
const shareToken = await getShareToken("wallpaper_download_index", "");
return {
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
path: `/pages/index/index?shareToken=${shareToken}`,
imageUrl:
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
};
}
getShareReward({ scene: "wallpaper_download" });
if (options.from === "button") {
const shareToken = await getShareToken(
"wallpaper_download",
options?.target?.dataset?.item?.id,
);
return {
title: "快来挑选喜欢的新春壁纸吧",
path: `/pages/wallpaper/detail?shareToken=${shareToken}`,
};
} else {
const shareToken = await getShareToken("wallpaper_download_index", "");
return {
title: "新年好运已送达 🎊|祝福卡·头像·壁纸",
path: `/pages/index/index?shareToken=${shareToken}`,
imageUrl:
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
};
}
});
onShareTimeline(async () => {
const shareToken = await getShareToken("wallpaper_timeline");
return {
title: "精选新年壁纸,让手机也过年 🖼",
query: `shareToken=${shareToken}`,
imageUrl:
"https://file.lihailezzc.com/resource/8dd026d76ef7a63d123b7fd698fb989b.png",
};
});
onLoad((options) => {
fetchCategories();
if (options.shareToken) {
shareToken.value = options.shareToken;
saveViewRequest(options.shareToken, "wallpaper_download");
}
trackRecord({
eventName: "wallpaper_page_visit",
eventType: `visit`,
});
});
const getThumbUrl = (url) => {
return `${url}?imageView2/1/w/340/h/600/q/80`;
};
const fetchCategories = async () => {
try {
const res = await getWallpaperCategoryList();
const list = Array.isArray(res) ? res : res?.list || [];
if (list.length > 0) {
categories.value = list;
currentCategoryId.value = list[0].id;
loadWallpapers(true);
}
} catch (e) {
console.error("Failed to fetch categories", e);
uni.showToast({ title: "获取分类失败", icon: "none" });
}
};
const switchCategory = (id) => {
if (currentCategoryId.value === id) return;
currentCategoryId.value = id;
loadWallpapers(true);
trackRecord({
eventName: "wallpaper_category_click",
eventType: `select`,
elementId: id || "",
});
};
const loadWallpapers = async (reset = false) => {
if (loading.value) return;
if (reset) {
page.value = 1;
hasMore.value = true;
wallpapers.value = [];
}
if (!hasMore.value) return;
loading.value = true;
try {
const res = await getWallpaperList(currentCategoryId.value, page.value);
const list = res?.list || [];
hasMore.value = !!res?.hasNext;
if (reset) {
wallpapers.value = list;
} else {
wallpapers.value = [...wallpapers.value, ...list];
}
if (hasMore.value) {
page.value++;
}
} catch (e) {
console.error("Failed to fetch wallpapers", e);
uni.showToast({ title: "获取壁纸失败", icon: "none" });
} finally {
loading.value = false;
isRefreshing.value = false;
}
};
const loadMore = () => {
loadWallpapers();
};
const handleLogind = async () => {
// Logic after successful login if needed
};
const onRefresh = () => {
isRefreshing.value = true;
loadWallpapers(true);
};
const previewImage = (index) => {
// const urls = wallpapers.value.map((item) => item.url);
// uni.previewImage({
// urls,
// current: index,
// });
const item = wallpapers.value[index];
trackRecord({
eventName: "wallpaper_preview_click",
eventType: `select`,
elementId: item?.id || "",
});
};
const downloadWallpaper = async (item) => {
trackRecord({
eventName: "wallpaper_download_click",
eventType: `click`,
elementId: item?.id || "",
});
if (!isLoggedIn.value) {
loginPopupRef.value.open();
return;
}
const abilityRes = await abilityCheck("wallpaper_download");
if (!abilityRes.canUse) {
if (
abilityRes?.blockType === "need_share" &&
abilityRes?.message === "分享可继续"
) {
uni.showToast({
title: "分享给好友即可下载",
icon: "none",
});
return;
}
uni.showToast({
title: "您今日壁纸下载次数已用完,明日再试",
icon: "none",
});
return;
}
uni.showLoading({ title: "下载中..." });
await saveRemoteImageToLocal(item.imageUrl);
saveRecordRequest("", item.id, "wallpaper_download", item.imageUrl);
};
const shareWallpaper = (item) => {};
</script>
<style lang="scss" scoped>
.wallpaper-page {
height: 100vh;
background-color: #ffffff;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.category-tabs {
padding: 0;
background-color: #ffffff;
border-bottom: 1rpx solid #eeeeee;
position: sticky;
top: 0;
z-index: 100;
}
.points-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 30rpx;
background-color: #fffbf0;
font-size: 24rpx;
color: #666;
}
.points-left {
display: flex;
align-items: center;
gap: 8rpx;
color: #ff9800;
}
.points-right {
display: flex;
align-items: center;
}
.score-val {
color: #d81e06;
font-weight: bold;
font-size: 28rpx;
margin-left: 4rpx;
}
.tabs-scroll {
white-space: nowrap;
width: 100%;
}
.tabs-content {
display: inline-flex;
padding: 0 30rpx;
}
.tab-item {
padding: 24rpx 30rpx;
font-size: 30rpx;
color: #999999;
position: relative;
transition: all 0.3s;
font-weight: 500;
}
.tab-item.active {
color: #e60012;
font-weight: bold;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 80rpx;
height: 4rpx;
background-color: #e60012;
border-radius: 2rpx;
}
}
.wallpaper-scroll {
flex: 1;
overflow: hidden;
box-sizing: border-box;
}
.grid-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 30rpx;
padding: 30rpx;
}
.grid-item {
height: 600rpx;
border-radius: 32rpx;
overflow: hidden;
position: relative;
background: #f5f5f5;
}
.wallpaper-img {
width: 100%;
height: 100%;
}
.action-overlay {
position: absolute;
bottom: 20rpx;
right: 20rpx;
display: flex;
flex-direction: column;
gap: 16rpx;
}
.action-btn {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(4px);
display: flex;
align-items: center;
justify-content: center;
border: 1rpx solid rgba(255, 255, 255, 0.2);
padding: 0;
margin: 0;
line-height: 1;
&::after {
border: none;
}
}
.action-btn.share .icon {
font-size: 30rpx;
}
.action-btn .icon {
color: #fff;
font-size: 36rpx;
font-weight: normal;
}
.loading-state,
.empty-state,
.no-more {
text-align: center;
padding: 40rpx;
color: #999999;
font-size: 24rpx;
}
</style>