fix: polish logs filter and stats money display
This commit is contained in:
+42
-88
@@ -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
@@ -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)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user