Files
2026-02-12 17:22:47 +08:00

391 lines
8.2 KiB
Vue
Raw Permalink 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="record-page">
<NavBar title="我的运势记录" />
<scroll-view
scroll-y
:lower-threshold="80"
class="content-scroll"
@scrolltolower="loadMore"
>
<view class="container">
<!-- 统计卡片 -->
<view class="stats-card">
<view class="stats-header">
<text class="stats-icon"></text>
<text class="stats-sub">2026 灵驹贺岁</text>
</view>
<view class="stats-body">
<view class="stats-row">
<text class="stats-label">已收集</text>
<text class="stats-num">{{ totalCount }}</text>
<text class="stats-label">张好运卡</text>
</view>
<view class="progress-bar">
<view
class="progress-inner"
:style="{ width: progressWidth }"
></view>
</view>
</view>
</view>
<!-- 列表标题 -->
<view class="list-header">
<text class="list-title">我的宝藏锦囊</text>
<text class="list-subtitle">ARCHIVES</text>
</view>
<!-- 卡片列表 -->
<view class="card-grid">
<view
class="grid-item"
v-for="(item, index) in records"
:key="index"
@tap="goDetail(item)"
>
<view class="item-image-box">
<image
:src="getThumbUrl(item.imageUrl)"
mode="aspectFill"
class="item-image"
/>
<view class="item-tag" :class="getTagClass(item.fortuneLevel)">
{{ getFortuneName(item.fortuneLevel) }}
</view>
</view>
<view class="item-info">
<text class="item-title">{{ item.title }}</text>
<view class="item-footer">
<text class="item-date">{{
formatDate(item.day, "YYYY-MM-DD")
}}</text>
</view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view class="loading-status" v-if="records.length > 0">
<text v-if="loading">加载中...</text>
<text v-else-if="!hasMore">没有更多了</text>
</view>
<!-- 空状态 -->
<view v-if="!loading && records.length === 0" class="empty-state">
<text class="empty-text">暂无运势记录快去抽取吧</text>
<button class="go-draw-btn" @tap="goDraw">去抽签</button>
</view>
<view style="height: 40px"></view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { getList } from "@/api/fortune.js";
import NavBar from "@/components/NavBar/NavBar.vue";
import { formatDate } from "@/utils/date.js";
import { trackRecord } from "@/utils/common.js";
// 状态管理
const records = ref([]);
const page = ref(1);
const totalCount = ref(0);
const loading = ref(false);
const hasMore = ref(true);
const progressWidth = computed(() => {
const total = 75; // 假设总共有20种卡片
const current = records.value.length;
const percentage = Math.min((current / total) * 100, 100);
return `${percentage}%`;
});
const getFortuneName = (level) => {
const map = {
1: "吉签",
2: "中吉签",
3: "上吉签",
4: "上上签",
5: "大吉签",
};
return map[level] || "吉签";
};
const getTagClass = (level) => {
const map = {
1: "tag-blue",
2: "tag-green",
3: "tag-orange",
4: "tag-red",
5: "tag-gold",
};
return map[level] || "tag-blue";
};
const getThumbUrl = (url) => {
return `${url}?imageView2/1/w/360/h/480/q/80`;
};
const loadData = async () => {
if (loading.value || !hasMore.value) return;
loading.value = true;
try {
const res = await getList(page.value);
// 兼容返回格式可能是数组或包含list的对象
const list = Array.isArray(res) ? res : res.list || res.data || [];
if (list.length > 0) {
records.value = [...records.value, ...list];
page.value++;
// 简单判断是否还有更多数据
hasMore.value = res.hasNext;
totalCount.value = res.totalCount || 0;
} else {
hasMore.value = false;
}
} catch (error) {
console.error("加载记录失败:", error);
uni.showToast({
title: "加载失败",
icon: "none",
});
} finally {
loading.value = false;
}
};
const loadMore = () => {
loadData();
trackRecord({
eventName: "fortune_record_page_visit",
eventType: `visit`,
});
};
const goDetail = (item) => {
uni.previewImage({
current: item.imageUrl,
urls: records.value.map((r) => r.imageUrl),
});
};
const goDraw = () => {
uni.navigateBack();
};
onLoad(() => {
loadData();
});
</script>
<style scoped>
.loading-status {
text-align: center;
padding: 20px 0;
color: #999;
font-size: 12px;
}
.record-page {
height: 100vh;
background-color: #1a1a1a;
color: #fff;
display: flex;
flex-direction: column;
overflow: hidden;
}
.content-scroll {
flex: 1;
height: 0; /* Important for scroll-view in flex container */
}
.container {
padding: 20px 16px;
}
/* 统计卡片 */
.stats-card {
background: linear-gradient(135deg, #2a2a2a 0%, #222 100%);
border-radius: 20px;
padding: 24px;
margin-bottom: 30px;
border: 1px solid rgba(255, 215, 0, 0.2);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
}
.stats-header {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.stats-icon {
margin-right: 6px;
font-size: 16px;
}
.stats-sub {
color: #999;
font-size: 14px;
}
.stats-body {
display: flex;
flex-direction: column;
}
.stats-row {
display: flex;
align-items: baseline;
margin-bottom: 12px;
}
.stats-label {
font-size: 16px;
color: #fff;
font-weight: bold;
}
.stats-num {
font-size: 32px;
color: #ffd700;
font-weight: bold;
margin: 0 8px;
font-family: serif;
}
.progress-bar {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
}
.progress-inner {
height: 100%;
background: linear-gradient(90deg, #ffd700 0%, #ffa500 100%);
border-radius: 3px;
}
/* 列表标题 */
.list-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 20px;
}
.list-title {
font-size: 18px;
font-weight: bold;
color: #fff;
}
.list-subtitle {
font-size: 12px;
color: #666;
letter-spacing: 2px;
font-weight: bold;
}
/* Grid List */
.card-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.grid-item {
width: 48%;
margin-bottom: 24px;
display: flex;
flex-direction: column;
}
.item-image-box {
width: 100%;
height: 220px; /* Adjust based on aspect ratio */
border-radius: 12px;
overflow: hidden;
position: relative;
margin-bottom: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.item-image {
width: 100%;
height: 100%;
display: block;
}
.item-tag {
position: absolute;
left: 10px;
bottom: 10px;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
color: #fff;
backdrop-filter: blur(4px);
}
.tag-blue {
background: rgba(0, 122, 255, 0.9);
}
.tag-green {
background: rgba(52, 199, 89, 0.9);
}
.tag-orange {
background: rgba(255, 149, 0, 0.9);
}
.tag-red {
background: rgba(255, 59, 48, 0.9);
}
.tag-gold {
background: rgba(212, 175, 55, 0.9);
color: #fff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.item-info {
display: flex;
flex-direction: column;
}
.item-title {
font-size: 16px;
font-weight: bold;
color: #fff;
margin-bottom: 6px;
}
.item-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.item-date {
font-size: 12px;
color: #666;
}
.item-link {
display: flex;
align-items: center;
font-size: 12px;
color: #ffd700;
}
.arrow {
margin-left: 4px;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 0;
}
.empty-text {
color: #666;
font-size: 14px;
margin-bottom: 20px;
}
.go-draw-btn {
background: #ffd700;
color: #333;
font-size: 14px;
padding: 8px 24px;
border-radius: 20px;
font-weight: bold;
}
</style>