fix: polish logs filter and stats money display

This commit is contained in:
nepiedg
2026-04-02 00:39:56 +08:00
parent 7282bbc373
commit a7f532fe41
2 changed files with 65 additions and 99 deletions
+42 -88
View File
@@ -1,27 +1,7 @@
<template>
<view class="page">
<view class="hero-card card">
<text class="hero-title">记录历史</text>
<text class="hero-subtitle">按时间查看抽烟和忍住记录随时回看自己的变化轨迹</text>
<view class="hero-stats">
<view class="hero-stat">
<text class="hero-stat-value">{{ filteredLogs.length }}</text>
<text class="hero-stat-label">当前筛选</text>
</view>
<view class="hero-stat">
<text class="hero-stat-value">{{ smokeCount }}</text>
<text class="hero-stat-label">抽烟</text>
</view>
<view class="hero-stat">
<text class="hero-stat-value">{{ resistedCount }}</text>
<text class="hero-stat-label">忍住</text>
</view>
</view>
</view>
<view class="section">
<text class="section-label">筛选记录</text>
<view class="filters card">
<view class="filters-sticky">
<view class="filters">
<view class="tabs">
<view
v-for="tab in tabs"
@@ -169,9 +149,6 @@ const filteredLogs = computed(() => {
return logs.filter(log => log.type === currentTab.value)
})
const smokeCount = computed(() => filteredLogs.value.filter(log => log.type === 'smoke').length)
const resistedCount = computed(() => filteredLogs.value.filter(log => log.type === 'resisted').length)
// 按日期分组
const groupedLogs = computed(() => {
return filteredLogs.value.reduce((groups, log) => {
@@ -321,14 +298,11 @@ onShareAppMessage(() => {
display: flex;
flex-direction: column;
background: linear-gradient(180deg, #E6F7F2 0%, #F0FBF7 40%, #FAFFFE 100%);
padding: 24rpx 28rpx 0;
padding: 0 28rpx;
box-sizing: border-box;
}
.hero-card,
.section,
.filters,
.scroll-container,
.fab {
position: relative;
z-index: 1;
@@ -342,83 +316,60 @@ onShareAppMessage(() => {
padding: 24rpx;
}
.hero-card {
margin-bottom: 20rpx;
}
.hero-title {
display: block;
font-size: 38rpx;
line-height: 1.2;
font-weight: 700;
color: #0D3D2E;
}
.hero-subtitle {
display: block;
margin-top: 10rpx;
font-size: 25rpx;
line-height: 1.5;
color: #52806E;
}
.hero-stats {
display: flex;
gap: 16rpx;
margin-top: 24rpx;
}
.hero-stat {
flex: 1;
background: rgba(52, 200, 160, 0.06);
border: 1.5rpx solid rgba(52, 200, 160, 0.1);
border-radius: 20rpx;
padding: 18rpx 14rpx;
}
.hero-stat-value {
display: block;
font-size: 40rpx;
font-weight: 700;
color: #0D3D2E;
}
.hero-stat-label {
display: block;
margin-top: 8rpx;
font-size: 22rpx;
color: #7aA898;
}
.section {
margin-bottom: 20rpx;
}
.section-label {
display: block;
margin: 0 0 14rpx 6rpx;
margin: 0 0 18rpx 6rpx;
font-size: 26rpx;
font-weight: 600;
color: #1a5c45;
}
.filters-sticky {
position: relative;
height: 164rpx;
flex-shrink: 0;
z-index: 20;
}
.filters {
padding: 24rpx;
position: fixed;
left: 28rpx;
right: 28rpx;
top: calc(88rpx + env(safe-area-inset-top));
z-index: 50;
margin: 12rpx 0 0;
padding: 12rpx;
border-radius: 28rpx;
background: rgba(255, 255, 255, 0.72);
border: 1.5rpx solid rgba(255, 255, 255, 0.75);
box-shadow: 0 10rpx 28rpx rgba(52, 200, 160, 0.1);
-webkit-backdrop-filter: blur(12px);
backdrop-filter: blur(12px);
}
.filters::before {
content: '';
position: absolute;
inset: -12rpx -8rpx -10rpx;
border-radius: 34rpx;
background: linear-gradient(180deg, rgba(230, 247, 242, 0.96) 0%, rgba(240, 251, 247, 0.88) 72%, rgba(240, 251, 247, 0) 100%);
z-index: -1;
pointer-events: none;
}
.tabs {
display: flex;
background: rgba(255, 255, 255, 0.82);
background: rgba(248, 252, 250, 0.92);
border-radius: 22rpx;
padding: 6rpx;
border: 1.5rpx solid rgba(52, 200, 160, 0.14);
box-shadow: 0 4rpx 16rpx rgba(52, 200, 160, 0.07);
border: 1.5rpx solid rgba(52, 200, 160, 0.12);
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.9);
}
.tab {
flex: 1;
text-align: center;
padding: 14rpx 0;
padding: 16rpx 0;
border-radius: 16rpx;
font-size: 24rpx;
font-weight: 600;
@@ -428,12 +379,15 @@ onShareAppMessage(() => {
.tab-active {
background: #FFFFFF;
color: #0D3D2E;
box-shadow: 0 4rpx 12rpx rgba(52, 200, 160, 0.12);
box-shadow: 0 8rpx 18rpx rgba(52, 200, 160, 0.12);
}
.scroll-container {
flex: 1;
min-height: 0;
position: relative;
z-index: 0;
padding-top: 0;
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
}
+23 -11
View File
@@ -283,6 +283,12 @@ const weeklyTrendItems = computed(() => {
})
})
function safeNumber(value) {
if (value === undefined || value === null || value === '') return 0
const num = Number(value)
return Number.isNaN(num) ? 0 : num
}
function calDotClass(count) {
if (count === 0) return 'cal-dot-zero'
if (count <= 3) return 'cal-dot-low'
@@ -290,10 +296,15 @@ function calDotClass(count) {
return 'cal-dot-high'
}
const savedMoneyText = computed(() => {
const savedMoneyCent = computed(() => {
const money = statsData.value?.money
if (!money || !money.available) return '--'
return `¥${(money.saved_cent / 100).toFixed(2)}`
if (!money || !money.available) return 0
return safeNumber(money.saved_cent)
})
const savedMoneyText = computed(() => {
if (!moneyAvailable.value) return '--'
return `¥${(savedMoneyCent.value / 100).toFixed(2)}`
})
const moneyAvailable = computed(() => !!statsData.value?.money?.available)
@@ -301,13 +312,13 @@ const moneyAvailable = computed(() => !!statsData.value?.money?.available)
const moneyExpectedTotal = computed(() => {
const money = statsData.value?.money
if (!money || !money.available) return 0
return Number(money.expected_total) || 0
return safeNumber(money.expected_total)
})
const moneyActualTotal = computed(() => {
const money = statsData.value?.money
if (!money || !money.available) return 0
return Number(money.actual_total) || 0
return safeNumber(money.actual_total)
})
const moneySubtitle = computed(() => {
@@ -318,16 +329,17 @@ const moneySubtitle = computed(() => {
const moneyTargetCent = computed(() => {
const money = statsData.value?.money
if (!money || !money.available) return 0
const { expected_total, pack_price_cent, cigs_per_pack } = money
if (!expected_total || !pack_price_cent || !cigs_per_pack) return 0
return Math.round((expected_total / cigs_per_pack) * pack_price_cent)
const expectedTotal = safeNumber(money.expected_total)
const packPriceCent = safeNumber(money.pack_price_cent)
const cigsPerPack = safeNumber(money.cigs_per_pack)
if (expectedTotal <= 0 || packPriceCent <= 0 || cigsPerPack <= 0) return 0
return Math.round((expectedTotal / cigsPerPack) * packPriceCent)
})
const moneyPercent = computed(() => {
const money = statsData.value?.money
const target = moneyTargetCent.value
if (!money || !money.available || target <= 0) return 0
const percent = Math.round((money.saved_cent / target) * 100)
if (!moneyAvailable.value || target <= 0) return 0
const percent = Math.round((savedMoneyCent.value / target) * 100)
return Math.min(Math.max(percent, 0), 100)
})