2026-02-02 17:44:10 +08:00

1390 lines
31 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.

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="navbox">
<view class="status_bar"></view>
<uni-nav-bar
left-icon="left"
title="积分"
@clickLeft="goBack"
color="#8B2316"
:border="false"
backgroundColor="#eeeeee"
>
<template v-slot:right>
<view class="nav-actions">
<view class="btn" @click="showRules">规则</view>
</view>
</template>
</uni-nav-bar>
</view>
<view class="topfix">
<view class="imgbox" style="position:absolute;top:0;width:100%;z-index:0">
<up-image :src="myjifen_big" width="100%" height="392rpx" ></up-image>
</view>
<view class="checkin-progress">
<view class="progress-bar">
<view
class="day-circle"
v-for="(day, index) in weekDays"
:key="index"
:class="{ active: day.checked }"
>
<text class="day-text">{{ day.name }}</text>
<view class="day-icon">
<up-image :src="day.checked ? signinImg : nosigninImg" width="44rpx" height="44rpx" ></up-image>
</view>
</view>
</view>
<view class="meeting-days">
<text class="meeting-text">今天是我们相识的第{{ meetingDays }}</text>
</view>
</view>
<!-- 积分概览卡片 -->
<view class="points-summary">
<view v-if="loading && totalPoints === 0" class="loading-overlay">
<text class="loading-text">加载中...</text>
</view>
<view v-else class="summary-content">
<view class="summary-item">
<text class="points-number">{{ totalPoints }}</text>
<text class="points-label">积分</text>
</view>
<view class="barbox"></view>
<view class="summary-item">
<text class="consecutive-days">{{ consecutiveDays }}</text>
<text class="consecutive-label">本周连续签到</text>
</view>
<view class="barbox"></view>
<view class="summary-item">
<text class="checkin-count">{{ checkinCount }}</text>
<text class="checkin-label">签到次数</text>
</view>
</view>
</view>
</view>
<view class="my-point-page">
<!-- 顶部导航栏 -->
<!-- 每日签到进度条 -->
<!-- 交易记录标签页 -->
<view class="transaction-tabs">
<view
class="tab-item"
:class="{ active: activeTab === 'income' }"
@click="switchTab('income')"
>
<text class="tab-text">收益</text>
</view>
<view class="bar"></view>
<view
class="tab-item"
:class="{ active: activeTab === 'expense' }"
@click="switchTab('expense')"
>
<text class="tab-text">支出</text>
</view>
</view>
<!-- 交易记录列表scroll-view 实现上拉加载 + 下拉刷新 -->
<scroll-view
class="transaction-list"
scroll-y="true"
refresher-enabled="true"
:refresher-triggered="refresherTriggered"
@scrolltolower="onScrollToLower"
@refresherrefresh="onRefresherRefresh"
>
<view v-if="error" class="error-message">
<text class="error-text">{{ error }}</text>
<view class="retry-btn" @click="retryLoad">重试</view>
</view>
<view
v-else-if="loading && getCurrentList().length === 0"
class="loading-message"
>
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="getCurrentList().length === 0" class="empty-message">
<text class="empty-text"
>暂无{{ activeTab === "income" ? "收益" : "支出" }}记录</text
>
</view>
<view v-else>
<view
class="transaction-item"
v-for="(item, index) in getCurrentList()"
:key="index"
>
<view class="transaction-info">
<text class="transaction-type">{{ item.type }}</text>
<text class="transaction-time">{{ item.time }}</text>
</view>
<view class="transaction-amount">
<text
class="amount-text"
:class="{
positive: item.amount > 0,
negative: item.amount < 0,
}"
>
{{ item.amount > 0 ? "+" : "" }}{{ item.amount }}
</text>
</view>
</view>
</view>
</scroll-view>
<!-- 浮动签到按钮 -->
<!-- <view class="floating-checkin" @click="performCheckin" :class="{ loading: loading }">
<view class="checkin-icon">
<text class="calendar-icon">📅</text>
<text class="checkmark"></text>
</view>
<view class="checkin-text">
<text class="checkin-label">{{ loading ? '签到中...' : '点击签到' }}</text>
<text class="checkin-reward">+2</text>
</view>
</view> -->
<!-- 底部导航 -->
<view class="bottom-nav">
<!-- <view class="nav-item" @click="goToPointsCoupon">
<view class="nav-icon">🎫</view>
<up-image :src="pointImg" width="44rpx" height="44rpx" ></up-image>
<text class="nav-text">积分券</text>
</view> -->
<view class="nav-item active" @click="goToBuyPoints">
<!-- <view class="nav-icon">📷</view> -->
<up-image :src="buyPointImg" width="44rpx" height="44rpx" ></up-image>
<text class="nav-text">购买积分</text>
</view>
<view class="nav-item" @click="goToPointsMall">
<!-- <view class="nav-icon">🛍</view> -->
<up-image :src="pointMallImg" width="44rpx" height="44rpx" ></up-image>
<text class="nav-text">积分商城</text>
</view>
</view>
</view>
<view class="signfix" @click="onSignClick">
<up-image :src="isSign ? signTrueImg : signFalseImg" width="154rpx" height="80rpx" ></up-image>
</view>
<unidialog :visible="hasSign" content="今日已签到,每天只能签到一次。<br>请明日继续哦~" @close="hasSign=false" :showCancel="true" cancelText="关闭"></unidialog>
<up-overlay :show="showSign" >
<view class="signwrap">
<view class="signbox">
<view class="close" @click="showSign=false"></view>
<view class="signbg">
<up-image :src="signImg" width="604rpx" height="964rpx" ></up-image>
</view>
<view class="signcontent">
<view class="day">今天是我们相识的第{{signInfo.gdxzday}}</view>
<view class="signtotal">本周共签到<text class="day-red" decode="true">&nbsp;{{signInfo.totalDay}}&nbsp;</text></view>
<view class="signcontinue">已连续签到<text class="day-red" decode="true">&nbsp;{{signInfo.continuous_day}}&nbsp;</text></view>
<view class="tip">连续签到获取更多积分</view>
<view class="news twoline" @click.stop="goNews">
{{signInfo.news.title}}
</view>
</view>
</view>
</view>
</up-overlay>
</template>
<script setup>
import api from "@/api/api.js";
import docUrl from '@/utils/docUrl.js';
import {onBackPress} from '@dcloudio/uni-app';
import { reactive,ref,onMounted } from "vue";
import unidialog from '@/components/dialog/dialog.vue'
onBackPress(() => {
plus.runtime.quit();
return true;
});
import navTo from "@/utils/navTo.js";
import nosigninImg from "@/static/sign_day_false.png"
import signinImg from "@/static/sign_day_true.png"
import myjifen_big from "@/static/myjifen_big.png"
import pointImg from "@/static/integralticket.png"
import buyPointImg from "@/static/buy_points.png"
import pointMallImg from "@/static/point_shop.png"
import signTrueImg from "@/static/signin_true.png"
import signFalseImg from "@/static/signin_false.png"
import dayjs from "dayjs"
// 响应式数据
const activeTab = ref("income");
const totalPoints = ref(0); // 初始化为0等待接口数据
const consecutiveDays = ref(0); // 连续签到天数
const checkinCount = ref(0); // 总签到次数
const meetingDays = ref(0); // 相识天数
const loading = ref(false);
const error = ref(null);
const isSign = ref(false);
const hasSign = ref(false)
import signImg from "@/static/sign_in_bng_big.png"
const showSign = ref(false)
const signInfo=reactive({
news:{
summary:'',
title:''
}
})
// 分页相关数据 - 收益
const incomeCurrentPage = ref(1);
const incomePageSize = ref(10);
const incomeTotalRows = ref(0);
const incomeTotalPages = ref(0);
// 分页相关数据 - 支出
const expenseCurrentPage = ref(1);
const expensePageSize = ref(10);
const expenseTotalRows = ref(0);
const expenseTotalPages = ref(0);
// 一周七天数据 - 初始化为未签到状态
const weekDays = ref([
{ name: "日", checked: false, date: "" },
{ name: "一", checked: false, date: "" },
{ name: "二", checked: false, date: "" },
{ name: "三", checked: false, date: "" },
{ name: "四", checked: false, date: "" },
{ name: "五", checked: false, date: "" },
{ name: "六", checked: false, date: "" },
]);
// 交易记录数据 - 初始化为空数组,等待接口数据
const transactionList = ref([]); // 收益记录
const expenseList = ref([]); // 支出记录
// scroll-view 下拉刷新状态
const refresherTriggered = ref(false);
// 方法
const goBack = () => {
plus.runtime.quit();
};
const showRules = () => {
navTo({
url: '/pages_app/webview/webview?url='+encodeURIComponent('https://doc.igandan.com/app/integral/integral_doctor.html')+'&title=积分规则'
})
};
const switchTab = (tab) => {
activeTab.value = tab;
refresherTriggered.value=false;
let pagination = getCurrentPagination();
pagination.hasMore=true;
// 根据tab切换不同的数据
if (tab === "income") {
transactionList.value=[]
// 显示收益记录
if (transactionList.value.length === 0) {
getBonusPointsList(1, false);
}
} else if (tab === "expense") {
expenseList.value=[]
// 显示支出记录
if (expenseList.value.length === 0) {
getBonusPointsPayList(1, false);
}
}
};
const performCheckin = () => {
if (loading.value) return;
loading.value = true;
// 执行签到逻辑
setTimeout(() => {
// uni.showToast({
// title: "签到成功 +2积分",
// icon: "none",
// });
//showSign.value = true;
// 签到成功后刷新数据
getMyBonusPoints();
getBonusPointsList(); // 刷新积分记录列表
loading.value = false;
}, 1000);
};
const goNews=()=>{
let url=docUrl+signInfo.news.path;
const encoded = encodeURIComponent(url);
navTo({
url: `/pages_app/webview/webview?url=${encoded}&type=news&share=1&sharetitle=${signInfo.news.title}`
});
}
// 底部导航方法
const goToPointsCoupon = () => {
uni.navigateTo({
url: "/pages_goods/coupon/coupon",
});
// uni.showToast({
// title: '积分券功能开发中',
// icon: 'none'
// });
};
const goToBuyPoints = () => {
uni.navigateTo({
url: "/pages_app/buyPoint/buyPoint",
});
};
const onSignClick = async () => {
if(isSign.value){
hasSign.value = true;
return;
}
try {
// 调用添加积分接口
const res = await api.addBonusPointsN({
score_type:1
});
if (res && res.code ==1) {
// 签到成功
isSign.value = true;
showSign.value = true;
// 签到成功后刷新数据
getMyBonusPoints();
getBonusPointsList();
// uni.showToast({
// title: '签到成功,获得'+res.bonuspoints+'积分',
// icon: 'none'
// });
console.log(res)
console.log(123)
Object.assign(signInfo,res);
} else {
uni.showToast({
title: res?.msg || '签到失败',
icon: 'none'
});
}
} catch (error) {
console.error('签到失败:', error);
uni.showToast({
title: '签到失败,请重试',
icon: 'none'
});
}
};
const goToPointsMall = () => {
uni.navigateTo({
url: "/pages_goods/pointMall/pointMall?from=myPoint",
});
};
const retryLoad = () => {
error.value = null;
loading.value = true;
// 重新加载当前标签页的数据
refreshCurrentTab();
};
// 根据当前标签页获取对应的数据列表
const getCurrentList = () => {
return activeTab.value === "income"
? transactionList.value
: expenseList.value;
};
// 获取当前标签页的分页信息
const getCurrentPagination = () => {
if (activeTab.value === "income") {
return {
currentPage: incomeCurrentPage.value,
totalPages: incomeTotalPages.value,
totalRows: incomeTotalRows.value,
hasMore: true,
};
} else {
return {
currentPage: expenseCurrentPage.value,
totalPages: expenseTotalPages.value,
totalRows: expenseTotalRows.value,
hasMore:true,
};
}
};
// 加载更多数据
const loadMore = async () => {
const pagination = getCurrentPagination();
if (!pagination.hasMore || loading.value) return;
const nextPage = pagination.currentPage + 1;
console.log(activeTab.value);
if (activeTab.value === "income") {
await getBonusPointsList(nextPage, true);
} else {
console.log("加载更多支出记录1222");
await getBonusPointsPayList(nextPage, true);
}
};
// 刷新当前标签页数据
const refreshCurrentTab = async () => {
if (activeTab.value === "income") {
await getBonusPointsList(1, false);
} else {
await getBonusPointsPayList(1, false);
}
};
const getMyBonusPoints = async () => {
try {
loading.value = true;
const res = await api.myBonusPoints();
console.log("积分数据接口返回:", res);
if (res && res.code === 200) {
// 更新积分数据
totalPoints.value = res.data.totalPoints;
consecutiveDays.value = res.data.continuous_day;
checkinCount.value = res.data.totalDay;
meetingDays.value = res.data.gdxzday;
// 更新本周签到状态
updateWeekDaysStatus(res.data.thisWeek);
console.log("数据更新完成:", {
totalPoints: totalPoints.value,
consecutiveDays: consecutiveDays.value,
checkinCount: checkinCount.value,
meetingDays: meetingDays.value,
});
} else {
console.error("接口返回错误:", res);
uni.showToast({
title: res?.msg || "获取积分数据失败",
icon: "none",
});
}
} catch (error) {
console.error("获取积分数据异常:", error);
uni.showToast({
title: "网络异常,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
const updateWeekDaysStatus = (checkedDates) => {
// 获取本周的日期范围
const now = new Date();
const currentDay = now.getDay(); // 当前是星期几 (0-6)
const currentDate = now.getDate(); // 当前日期
// 计算本周的起始日期(周日)
const startOfWeek = new Date(now);
startOfWeek.setDate(currentDate - currentDay);
// 重置所有天数为未签到状态,并设置对应的日期
weekDays.value.forEach((day, index) => {
day.checked = false;
day.date = "";
// 计算对应的日期
const dayDate = new Date(startOfWeek);
dayDate.setDate(startOfWeek.getDate() + index);
day.date = dayDate.toISOString().split("T")[0]; // 格式化为 YYYY-MM-DD
});
// 根据接口返回的日期设置签到状态
if (checkedDates && checkedDates.length > 0) {
checkedDates.forEach((dateStr) => {
// 找到对应的星期几并设置为已签到
const targetDate = new Date(dateStr);
const targetDateStr = targetDate.toISOString().split("T")[0];
if(dateStr == new Date().toISOString().split("T")[0]){
isSign.value = true;
}
// 在 weekDays 中找到对应的日期并设置为已签到
const dayIndex = weekDays.value.findIndex(
(day) => day.date === targetDateStr
);
if (dayIndex !== -1) {
weekDays.value[dayIndex].checked = true;
}
});
}
console.log("本周签到状态更新完成:", weekDays.value);
};
const getBonusPointsList = async (page = 1, isLoadMore = false) => {
try {
// 只有在列表为空时才显示加载状态
if (transactionList.value.length === 0 && !isLoadMore) {
loading.value = true;
}
const res = await api.bonusPointsList({ page: page });
console.log("积分收益接口返回:", res);
if (res && res.code === 200) {
// 处理积分记录列表数据
const listData = res.data.list || [];
let pagination = getCurrentPagination();
if(listData.length < res.data.pageSize){
pagination.hasMore=false;
}
// 转换数据格式以匹配现有的transactionList结构
const formattedList = listData.map((item) => ({
type: item.score_type_name,
time: dayjs(item.create_date).format('YYYY-MM-DD HH:mm'),
amount: item.score,
}));
// 更新交易记录列表
if (isLoadMore) {
transactionList.value = [...transactionList.value, ...formattedList];
} else {
transactionList.value = formattedList;
}
// 更新分页信息
incomeCurrentPage.value = res.data.pageNumber;
incomePageSize.value = res.data.pageSize;
incomeTotalRows.value = res.data.totalRow;
incomeTotalPages.value = res.data.totalPage;
console.log("积分记录列表更新完成:", {
total: res.data.totalRow,
pageSize: res.data.pageSize,
currentPage: res.data.pageNumber,
list: formattedList,
});
} else {
console.error("积分收益接口返回错误:", res);
error.value = res?.msg || "获取积分记录失败";
uni.showToast({
title: res?.msg || "获取积分记录失败",
icon: "none",
});
}
} catch (error) {
console.error("获取积分记录异常:", error);
error.value = "网络异常,请重试";
uni.showToast({
title: "网络异常,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
const getBonusPointsPayList = async (page = 1, isLoadMore = false) => {
try {
// 只有在列表为空时才显示加载状态
if (expenseList.value.length === 0 && !isLoadMore) {
loading.value = true;
}
const res = await api.bonusPointsPayList({ page: page });
console.log("积分支出接口返回:", res);
if (res && res.code === 200) {
// 处理积分支出记录列表数据
const listData = res.data.list || [];
let pagination = getCurrentPagination();
if(listData.length < res.data.pageSize){
pagination.hasMore=false;
}
// 转换数据格式以匹配现有的transactionList结构
const formattedList = listData.map((item) => ({
type: item.score_type_name,
time: dayjs(item.create_date).format('YYYY-MM-DD HH:mm'),
amount: item.score, // 支出为负数
}));
// 更新支出记录列表
if (isLoadMore) {
expenseList.value = [...expenseList.value, ...formattedList];
} else {
expenseList.value = formattedList;
}
// 更新分页信息
expenseCurrentPage.value = res.data.pageNumber;
expensePageSize.value = res.data.pageSize;
expenseTotalRows.value = res.data.totalRow;
expenseTotalPages.value = res.data.totalPage;
console.log("积分支出记录列表更新完成:", {
total: res.data.totalRow,
pageSize: res.data.pageSize,
currentPage: res.data.pageNumber,
list: formattedList,
});
} else {
console.error("积分支出接口返回错误:", res);
error.value = res?.msg || "获取积分支出记录失败";
uni.showToast({
title: res?.msg || "获取积分支出记录失败",
icon: "none",
});
}
} catch (error) {
console.error("获取积分支出异常:", error);
error.value = "网络异常,请重试";
uni.showToast({
title: "网络异常,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
// scroll-view 上拉触底加载更多
const onScrollToLower = async () => {
await loadMore();
};
// scroll-view 下拉刷新
const onRefresherRefresh = async () => {
if (refresherTriggered.value) return;
refresherTriggered.value = true;
try {
loading.value = true;
await getMyBonusPoints();
await refreshCurrentTab();
} finally {
loading.value = false;
refresherTriggered.value = false;
}
};
onMounted(() => {
// 页面加载时的初始化逻辑
console.log("页面加载完成");
getMyBonusPoints();
getBonusPointsList(1, false);
getBonusPointsPayList(1, false);
});
</script>
<style scoped lang="scss">
.my-point-page {
background-color: #f5f5f5;
position: relative;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
/* 为底部导航留出空间 */
padding-bottom: 160rpx;
}
.signfix{
position: fixed;
bottom: 300rpx;
right: 0;
z-index: 10;
}
/* 每日签到进度条 */
.checkin-progress {
position: relative;
z-index: 1;
padding: 30rpx;
}
.progress-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.day-circle {
display: flex;
flex-direction: column;
align-items: center;
width: 80rpx;
transition: transform 0.3s ease;
}
.nav-actions .btn {
font-size: 28rpx;
color: #8b2316;
}
.day-circle:hover {
transform: scale(1.05);
}
.day-icon{
position: relative;
width: 44rpx;
height: 44rpx;
border-radius: 50%;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.day-icon::after{
content: "";
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 44rpx;
width: 100rpx;
height:1rpx;
background: #e5e5e5;
}
.day-circle:last-child .day-icon::after{
width:0;
}
.day-circle.active {
color: #e74c3c;
}
.coin-icon {
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
background-color: #eee;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10rpx;
font-size: 24rpx;
position: relative;
}
.coin-icon::before {
content: "🪙";
font-size: 32rpx;
}
.empty-icon {
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
background-color: #eee;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10rpx;
font-size: 24rpx;
position: relative;
}
.empty-icon::before {
content: "⚪";
font-size: 32rpx;
}
.day-text {
margin-bottom: 20rpx;
font-size: 28rpx;
color: #fff;
}
.day-date {
font-size: 20rpx;
color: #999;
}
.meeting-days {
text-align: center;
}
.meeting-text {
font-size: 26rpx;
color: #fff;
}
/* 积分概览卡片 */
.points-summary {
position: relative;
z-index: 1;
background-color: #ffffff;
margin: 0rpx 30rpx;
border-radius: 20rpx;
padding: 20rpx 20rpx;
display: flex !important;
flex-direction: row !important;
justify-content: space-between;
align-items: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
position: relative;
box-sizing: border-box;
/* 确保flexbox布局正常工作 */
flex-wrap: nowrap;
overflow: visible;
}
.summary-content {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.points-summary:hover {
transform: translateY(-2rpx);
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
}
.topfix{
position: fixed;
top: calc(var(--status-bar-height) + 44px);
left: 0;
right: 0;
z-index: 10;
}
.summary-item {
display: flex !important;
flex-direction: column !important;
align-items: center;
flex: 1;
min-width: 0;
text-align: center;
}
.points-number {
font-size: 30rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
width: 100%;
text-align: center;
}
.consecutive-days {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
width: 100%;
text-align: center;
}
.barbox{
width: 1px;
height: 80rpx;
background: #e5e5e5;
}
.checkin-count {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
width: 100%;
text-align: center;
}
.points-label,
.consecutive-label,
.checkin-label {
font-size: 24rpx;
color: #999 !important;
display: block;
width: 100%;
text-align: center;
}
/* 加载覆盖层 */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.9);
display: flex;
align-items: center;
justify-content: center;
border-radius: 20rpx;
z-index: 10;
}
.loading-overlay .loading-text {
font-size: 28rpx;
color: #666;
}
/* 交易记录标签页 */
.transaction-tabs {
position: fixed;
top: calc(var(--status-bar-height) + 44px + 392rpx);
left: 0;
right: 0;
z-index: 10;
background-color: #ffffff;
width:100%;
display: flex;
overflow: hidden;
align-items: center;
}
.tab-item {
flex: 1;
padding: 30rpx;
text-align: center;
position: relative;
transition: all 0.3s ease;
cursor: pointer;
color: #999;
}
.bar{
width: 1px;
height: 30rpx;
background: #e5e5e5;
}
.tab-item.active .tab-text {
color: #8B2316;
}
.tab-text {
font-size: 28rpx;
color: #999;
}
/* 交易记录列表 */
.transaction-list {
position: fixed;
top: calc(var(--status-bar-height) + 44px + 392rpx + 120rpx);
left: 0;
right: 0;
height: calc(100vh - calc(var(--status-bar-height) + 44px + 392rpx + 120rpx + 145rpx));
z-index: 10;
bottom: 100rpx;
background-color: #ffffff;
margin: 0 0rpx 20rpx;
padding: 20rpx 0;
}
.error-message,
.loading-message,
.empty-message {
text-align: center;
padding: 60rpx 30rpx;
}
.error-text {
color: #e74c3c;
font-size: 28rpx;
margin-bottom: 20rpx;
display: block;
}
.retry-btn {
background-color: #e74c3c;
color: #ffffff;
padding: 20rpx 40rpx;
border-radius: 10rpx;
font-size: 26rpx;
display: inline-block;
cursor: pointer;
transition: background-color 0.3s ease;
}
.retry-btn:hover {
background-color: #c0392b;
}
.loading-text,
.empty-text {
color: #999;
font-size: 28rpx;
}
.transaction-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 2rpx solid #eee;
transition: background-color 0.3s ease;
}
.transaction-item:hover {
background-color: #f8f8f8;
}
.transaction-item:last-child {
border-bottom: none;
}
.transaction-info {
display: flex;
flex-direction: column;
}
.transaction-type {
font-size: 28rpx;
color: #333;
margin-bottom: 10rpx;
}
.transaction-time {
font-size: 24rpx;
color: #999;
}
.transaction-amount {
display: flex;
align-items: center;
}
.amount-text {
font-size: 32rpx;
color: #e74c3c;
}
.amount-text.positive {
color: #e74c3c;
}
.amount-text.negative {
color: #e74c3c;
}
/* 分页信息 */
.pagination-info {
text-align: center;
padding: 30rpx;
border-top: 1rpx solid #f0f0f0;
}
.pagination-text {
font-size: 24rpx;
color: #999;
}
/* 加载更多按钮 */
.load-more-container {
text-align: center;
padding: 20rpx 30rpx 30rpx;
}
.load-more-btn {
background-color: #f8f8f8;
border: 1rpx solid #e0e0e0;
border-radius: 25rpx;
padding: 20rpx 40rpx;
display: inline-block;
cursor: pointer;
transition: all 0.3s ease;
}
.load-more-btn:hover {
background-color: #e8e8e8;
border-color: #d0d0d0;
}
.load-more-btn.loading {
opacity: 0.7;
pointer-events: none;
}
.load-more-text {
font-size: 26rpx;
color: #666;
}
.load-more-btn .loading-text {
font-size: 26rpx;
color: #999;
}
/* 浮动签到按钮 */
.floating-checkin {
position: fixed;
right: 30rpx;
bottom: 200rpx; /* 调整位置,确保在底部导航上方有足够空间 */
background-color: #e74c3c;
border-radius: 50rpx;
padding: 20rpx 30rpx;
display: flex;
align-items: center;
box-shadow: 0 8rpx 30rpx rgba(231, 76, 60, 0.3);
z-index: 100;
cursor: pointer;
transition: all 0.3s ease;
}
.floating-checkin:hover {
transform: scale(1.05);
box-shadow: 0 12rpx 40rpx rgba(231, 76, 60, 0.4);
}
.floating-checkin.loading {
opacity: 0.7;
pointer-events: none;
}
.floating-checkin.loading .checkin-icon {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
.checkin-icon {
position: relative;
margin-right: 20rpx;
}
.calendar-icon {
font-size: 40rpx;
color: #ffffff;
}
.checkmark {
position: absolute;
top: -10rpx;
right: -10rpx;
background-color: #27ae60;
color: #ffffff;
border-radius: 50%;
width: 30rpx;
height: 30rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
}
.checkin-text {
display: flex;
flex-direction: column;
align-items: center;
}
.checkin-label {
font-size: 24rpx;
color: #ffffff;
margin-bottom: 5rpx;
}
.checkin-reward {
font-size: 28rpx;
font-weight: bold;
color: #ffffff;
}
/* 底部导航 */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #3cc7c0;
display: flex;
padding: 32rpx 0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 99;
}
.nav-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.nav-item.active {
color: #fff;
}
@keyframes slideIn {
from {
width: 0;
opacity: 0;
}
to {
width: 40rpx;
opacity: 1;
}
}
.nav-icon {
font-size: 40rpx;
margin-bottom: 10rpx;
}
.nav-text {
margin-left: 5rpx;
font-size: 24rpx;
color: #fff;
}
/* 页面整体响应式设计 */
@media (max-width: 750rpx) {
.transaction-tabs,
.transaction-list {
margin: 15rpx 20rpx;
}
.floating-checkin {
right: 20rpx;
bottom: 180rpx; /* 响应式下调整位置 */
}
}
.honorwrap{
width:100%;
height:100vh;
display: flex;
align-items: center;
justify-content: center;
.honorbox{
width:80%;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
min-height:200rpx;
background:linear-gradient(to bottom, #54049b, #da4ee2);
border-radius: 20rpx;
padding: 20rpx;
.row{
display: grid;
grid-template-columns: repeat(2, 1fr); /* 创建两列,每列等宽 */
gap: 20px;
.row_item{
font-size: 26rpx;
color: #da4ee2;
margin-right: 20rpx;
text-align: center;
padding: 10rpx 20rpx;
background:#fff;
white-space: nowrap;
border-radius: 10rpx;
border:1rpx solid #da4ee2;
}
}
.close_honor{
position: absolute;
top:20rpx;
right:20rpx;
}
.honor_image{
width:269rpx;
height:213rpx;
position: absolute;
top:-76rpx;
left:50%;
transform: translateX(-50%);
}
.content{
margin-top:73rpx;
background:#fff;
border-radius: 5rpx;
padding: 20rpx;
.content_title{
font-weight: bold;
padding: 35rpx 0 20rpx;
text-align: center;
font-size: 36rpx;
color: #da4ee2;
}
.content_content{
font-size: 26rpx;
color: #333;
margin-top: 20rpx;
line-height: 1.5;
}
}
}
}
.signwrap{
display: flex;
align-items: center;
justify-content: center;
height:100%;
.signbox{
display: flex;
flex-direction: column;
align-items: center;
position: relative;
z-index:0;
.close{
position:absolute;
right:0;
height:60rpx;
width:60rpx;
opacity: 0;
background:#fff;
z-index:2;
border-radius: 50%;
}
}
}
.signwrap .signcontent{
width:100%;
top:0;
position: absolute;
z-index:1;
}
.signwrap .signcontent .day{
margin-top: 384rpx;
text-align: center;
}
.signwrap .signtotal{
margin-top: 30rpx;
text-align: center;
font-size:28rpx;
color:#999;
}
.signwrap .signcontinue{
font-size: 28rpx;
color:#999;
text-align: center;
}
.signwrap .day-red{
color:red;
font-size: 34rpx;
}
.signwrap .signcontent .tip{
margin-top: 40rpx;
color:red;
font-size: 28rpx;
text-align: center;
}
.signwrap .signcontent .news{
margin: 208rpx 60rpx 0;
height:86rpx;
font-size: 30rpx;
}
.signwrap .signbg{
width:604rpx;
height:964rpx;
}
</style>