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

261 lines
5.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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="我的壁纸" />
<!-- Header Stats -->
<view class="header-stats">
<view class="stats-card">
<view class="stats-left">
<text class="label">我的收藏</text>
<view class="value-wrap">
<text class="prefix">已保存</text>
<text class="value">{{ totalCount }}</text>
<text class="suffix">张壁纸</text>
</view>
</view>
<view class="stats-right">
<view class="icon-circle">
<text>🖼</text>
</view>
</view>
</view>
</view>
<!-- List Section -->
<view class="list-section">
<view class="list-container">
<view v-for="item in list" :key="item.id" class="grid-item" @tap="onPreview(item)">
<image :src="item.imageUrl" mode="aspectFill" class="wallpaper-img" />
<view class="date-badge">
<text>{{ formatDate(item.createdAt) }}</text>
</view>
</view>
</view>
<!-- Loading State -->
<view class="loading-state" v-if="loading">
<text>加载中...</text>
</view>
<view class="empty-state" v-if="!loading && list.length === 0">
<text>暂无壁纸记录</text>
</view>
<view class="no-more" v-if="!loading && !hasMore && list.length > 0">
<text>没有更多了</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
import { getMyWallpaper } from "@/api/mine.js";
import NavBar from "@/components/NavBar/NavBar.vue";
const list = ref([]);
const page = ref(1);
const loading = ref(false);
const hasMore = ref(true);
const isRefreshing = ref(false);
const totalCount = ref(0);
onMounted(() => {
fetchList(true);
});
onPullDownRefresh(() => {
onRefresh();
});
onReachBottom(() => {
loadMore();
});
const fetchList = async (reset = false) => {
if (loading.value) return;
if (reset) {
page.value = 1;
hasMore.value = true;
}
if (!hasMore.value) return;
loading.value = true;
try {
const res = await getMyWallpaper(page.value);
const dataList = res?.list || [];
totalCount.value = res?.totalCount || 0;
if (reset) {
list.value = dataList;
} else {
list.value = [...list.value, ...dataList];
}
hasMore.value = res.hasNext;
if (hasMore.value) {
page.value++;
}
} catch (e) {
console.error("Failed to fetch wallpaper list", e);
uni.showToast({ title: "加载失败", icon: "none" });
} finally {
loading.value = false;
isRefreshing.value = false;
uni.stopPullDownRefresh();
}
};
const loadMore = () => {
fetchList();
};
const onRefresh = () => {
isRefreshing.value = true;
fetchList(true);
};
const formatDate = (dateStr) => {
if (!dateStr) return "";
const date = new Date(dateStr);
const m = String(date.getMonth() + 1).padStart(2, "0");
const d = String(date.getDate()).padStart(2, "0");
return `${m}-${d}`;
};
const onPreview = (item) => {
uni.previewImage({
urls: [item.imageUrl],
current: item.imageUrl
});
};
</script>
<style lang="scss" scoped>
.wallpaper-page {
min-height: 100vh;
background: #f9f9f9;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.header-stats {
padding: 20px;
background: #f9f9f9;
margin-top: 0; // Initial offset for fixed nav
.stats-card {
background: #fff;
border-radius: 20px;
padding: 24px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
.stats-left {
display: flex;
flex-direction: column;
.label {
font-size: 12px;
color: #999;
margin-bottom: 8px;
}
.value-wrap {
display: flex;
align-items: baseline;
.prefix {
font-size: 16px;
color: #333;
font-weight: 600;
margin-right: 4px;
}
.value {
font-size: 24px;
font-weight: bold;
color: #ff3b30;
margin: 0 4px;
}
.suffix {
font-size: 14px;
color: #333;
font-weight: 600;
}
}
}
.stats-right {
.icon-circle {
width: 48px;
height: 48px;
border-radius: 16px;
background: #fff8e1;
display: flex;
align-items: center;
justify-content: center;
text {
font-size: 24px;
}
}
}
}
}
.list-section {
flex: 1;
padding: 0 16px;
.list-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
padding-bottom: 40px;
}
.grid-item {
position: relative;
border-radius: 16px;
overflow: hidden;
background: #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03);
aspect-ratio: 9/16; // Standard wallpaper ratio
.wallpaper-img {
width: 100%;
height: 100%;
display: block;
}
.date-badge {
position: absolute;
bottom: 8px;
right: 8px;
background: rgba(0, 0, 0, 0.3);
padding: 2px 6px;
border-radius: 4px;
backdrop-filter: blur(4px);
text {
color: #fff;
font-size: 10px;
font-weight: 500;
}
}
}
}
.loading-state,
.empty-state,
.no-more {
text-align: center;
padding: 20px;
color: #999;
font-size: 12px;
}
</style>