fix: polish logs filter and stats money display
This commit is contained in:
+42
-88
@@ -1,27 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page">
|
<view class="page">
|
||||||
<view class="hero-card card">
|
<view class="filters-sticky">
|
||||||
<text class="hero-title">记录历史</text>
|
<view class="filters">
|
||||||
<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="tabs">
|
<view class="tabs">
|
||||||
<view
|
<view
|
||||||
v-for="tab in tabs"
|
v-for="tab in tabs"
|
||||||
@@ -169,9 +149,6 @@ const filteredLogs = computed(() => {
|
|||||||
return logs.filter(log => log.type === currentTab.value)
|
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(() => {
|
const groupedLogs = computed(() => {
|
||||||
return filteredLogs.value.reduce((groups, log) => {
|
return filteredLogs.value.reduce((groups, log) => {
|
||||||
@@ -321,14 +298,11 @@ onShareAppMessage(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: linear-gradient(180deg, #E6F7F2 0%, #F0FBF7 40%, #FAFFFE 100%);
|
background: linear-gradient(180deg, #E6F7F2 0%, #F0FBF7 40%, #FAFFFE 100%);
|
||||||
padding: 24rpx 28rpx 0;
|
padding: 0 28rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-card,
|
|
||||||
.section,
|
|
||||||
.filters,
|
.filters,
|
||||||
.scroll-container,
|
|
||||||
.fab {
|
.fab {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@@ -342,83 +316,60 @@ onShareAppMessage(() => {
|
|||||||
padding: 24rpx;
|
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 {
|
.section-label {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 0 14rpx 6rpx;
|
margin: 0 0 18rpx 6rpx;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1a5c45;
|
color: #1a5c45;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filters-sticky {
|
||||||
|
position: relative;
|
||||||
|
height: 164rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
.filters {
|
.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 {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
background: rgba(255, 255, 255, 0.82);
|
background: rgba(248, 252, 250, 0.92);
|
||||||
border-radius: 22rpx;
|
border-radius: 22rpx;
|
||||||
padding: 6rpx;
|
padding: 6rpx;
|
||||||
border: 1.5rpx solid rgba(52, 200, 160, 0.14);
|
border: 1.5rpx solid rgba(52, 200, 160, 0.12);
|
||||||
box-shadow: 0 4rpx 16rpx rgba(52, 200, 160, 0.07);
|
box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 14rpx 0;
|
padding: 16rpx 0;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -428,12 +379,15 @@ onShareAppMessage(() => {
|
|||||||
.tab-active {
|
.tab-active {
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
color: #0D3D2E;
|
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 {
|
.scroll-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
padding-top: 0;
|
||||||
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
|
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
|
||||||
box-sizing: border-box;
|
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) {
|
function calDotClass(count) {
|
||||||
if (count === 0) return 'cal-dot-zero'
|
if (count === 0) return 'cal-dot-zero'
|
||||||
if (count <= 3) return 'cal-dot-low'
|
if (count <= 3) return 'cal-dot-low'
|
||||||
@@ -290,10 +296,15 @@ function calDotClass(count) {
|
|||||||
return 'cal-dot-high'
|
return 'cal-dot-high'
|
||||||
}
|
}
|
||||||
|
|
||||||
const savedMoneyText = computed(() => {
|
const savedMoneyCent = computed(() => {
|
||||||
const money = statsData.value?.money
|
const money = statsData.value?.money
|
||||||
if (!money || !money.available) return '--'
|
if (!money || !money.available) return 0
|
||||||
return `¥${(money.saved_cent / 100).toFixed(2)}`
|
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)
|
const moneyAvailable = computed(() => !!statsData.value?.money?.available)
|
||||||
@@ -301,13 +312,13 @@ const moneyAvailable = computed(() => !!statsData.value?.money?.available)
|
|||||||
const moneyExpectedTotal = computed(() => {
|
const moneyExpectedTotal = computed(() => {
|
||||||
const money = statsData.value?.money
|
const money = statsData.value?.money
|
||||||
if (!money || !money.available) return 0
|
if (!money || !money.available) return 0
|
||||||
return Number(money.expected_total) || 0
|
return safeNumber(money.expected_total)
|
||||||
})
|
})
|
||||||
|
|
||||||
const moneyActualTotal = computed(() => {
|
const moneyActualTotal = computed(() => {
|
||||||
const money = statsData.value?.money
|
const money = statsData.value?.money
|
||||||
if (!money || !money.available) return 0
|
if (!money || !money.available) return 0
|
||||||
return Number(money.actual_total) || 0
|
return safeNumber(money.actual_total)
|
||||||
})
|
})
|
||||||
|
|
||||||
const moneySubtitle = computed(() => {
|
const moneySubtitle = computed(() => {
|
||||||
@@ -318,16 +329,17 @@ const moneySubtitle = computed(() => {
|
|||||||
const moneyTargetCent = computed(() => {
|
const moneyTargetCent = computed(() => {
|
||||||
const money = statsData.value?.money
|
const money = statsData.value?.money
|
||||||
if (!money || !money.available) return 0
|
if (!money || !money.available) return 0
|
||||||
const { expected_total, pack_price_cent, cigs_per_pack } = money
|
const expectedTotal = safeNumber(money.expected_total)
|
||||||
if (!expected_total || !pack_price_cent || !cigs_per_pack) return 0
|
const packPriceCent = safeNumber(money.pack_price_cent)
|
||||||
return Math.round((expected_total / cigs_per_pack) * 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 moneyPercent = computed(() => {
|
||||||
const money = statsData.value?.money
|
|
||||||
const target = moneyTargetCent.value
|
const target = moneyTargetCent.value
|
||||||
if (!money || !money.available || target <= 0) return 0
|
if (!moneyAvailable.value || target <= 0) return 0
|
||||||
const percent = Math.round((money.saved_cent / target) * 100)
|
const percent = Math.round((savedMoneyCent.value / target) * 100)
|
||||||
return Math.min(Math.max(percent, 0), 100)
|
return Math.min(Math.max(percent, 0), 100)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user