refactor(logs): update date filtering logic and improve UI for log entries
This commit is contained in:
+51
-57
@@ -1,18 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page">
|
<view class="page">
|
||||||
<view class="status-bar" :style="{ height: navBarHeight + 'px' }"></view>
|
|
||||||
|
|
||||||
<view class="filters-sticky">
|
<view class="filters-sticky">
|
||||||
<view class="filters" :style="{ top: navBarHeight + 'px' }">
|
<view class="filters">
|
||||||
<view class="tabs">
|
<view class="date-filters">
|
||||||
<view
|
<view
|
||||||
v-for="tab in tabs"
|
v-for="option in dateFilters"
|
||||||
:key="tab.value"
|
:key="option.value"
|
||||||
class="tab"
|
class="date-filter"
|
||||||
:class="{ 'tab-active': currentTab === tab.value }"
|
:class="{ 'date-filter-active': currentDateFilter === option.value }"
|
||||||
@tap="currentTab = tab.value"
|
@tap="currentDateFilter = option.value"
|
||||||
>
|
>
|
||||||
{{ tab.label }}
|
{{ option.label }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -45,7 +43,7 @@
|
|||||||
|
|
||||||
<view class="section-head">
|
<view class="section-head">
|
||||||
<text class="section-label">时间记录</text>
|
<text class="section-label">时间记录</text>
|
||||||
<text class="section-note">{{ currentTab === 'smoke' ? '仅看抽烟记录' : '按日期倒序' }}</text>
|
<text class="section-note">{{ currentDateFilterLabel }} · 按日期倒序</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="logsStore.loading && logsStore.logs.length === 0" class="skeleton">
|
<view v-if="logsStore.loading && logsStore.logs.length === 0" class="skeleton">
|
||||||
@@ -162,14 +160,15 @@ import { useLogin } from '@/hooks/useLogin'
|
|||||||
|
|
||||||
const { waitForLogin } = useLogin()
|
const { waitForLogin } = useLogin()
|
||||||
const logsStore = useLogsStore()
|
const logsStore = useLogsStore()
|
||||||
const navBarHeight = ref(0)
|
|
||||||
|
|
||||||
const tabs = [
|
const dateFilters = [
|
||||||
{ label: '全部', value: 'all' },
|
{ label: '全部', value: 'all' },
|
||||||
{ label: '抽烟记录', value: 'smoke' }
|
{ label: '今天', value: 'today' },
|
||||||
|
{ label: '近7天', value: 'week' },
|
||||||
|
{ label: '本月', value: 'month' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const currentTab = ref('all')
|
const currentDateFilter = ref('all')
|
||||||
const showEditDialog = ref(false)
|
const showEditDialog = ref(false)
|
||||||
const editType = ref('smoke')
|
const editType = ref('smoke')
|
||||||
const editData = ref(null)
|
const editData = ref(null)
|
||||||
@@ -177,11 +176,12 @@ const editingLogId = ref(null)
|
|||||||
|
|
||||||
// 筛选后的记录
|
// 筛选后的记录
|
||||||
const filteredLogs = computed(() => {
|
const filteredLogs = computed(() => {
|
||||||
const logs = logsStore.formattedLogs
|
const logs = logsStore.formattedLogs.filter(log => log.type === 'smoke')
|
||||||
if (currentTab.value === 'all') {
|
return logs.filter(log => isInDateFilter(log.displayDate, currentDateFilter.value))
|
||||||
return logs
|
})
|
||||||
}
|
|
||||||
return logs.filter(log => log.type === currentTab.value)
|
const currentDateFilterLabel = computed(() => {
|
||||||
|
return dateFilters.find(item => item.value === currentDateFilter.value)?.label || '全部'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 按日期分组
|
// 按日期分组
|
||||||
@@ -218,6 +218,25 @@ function localDateStr(d) {
|
|||||||
return `${y}-${m}-${day}`
|
return `${y}-${m}-${day}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isInDateFilter(dateStr, filter) {
|
||||||
|
if (!dateStr || filter === 'all') return true
|
||||||
|
const today = new Date()
|
||||||
|
const target = new Date(`${dateStr}T00:00:00`)
|
||||||
|
if (Number.isNaN(target.getTime())) return false
|
||||||
|
const todayText = localDateStr(today)
|
||||||
|
if (filter === 'today') return dateStr === todayText
|
||||||
|
if (filter === 'week') {
|
||||||
|
const start = new Date(today)
|
||||||
|
start.setDate(today.getDate() - 6)
|
||||||
|
start.setHours(0, 0, 0, 0)
|
||||||
|
return target >= start && dateStr <= todayText
|
||||||
|
}
|
||||||
|
if (filter === 'month') {
|
||||||
|
return target.getFullYear() === today.getFullYear() && target.getMonth() === today.getMonth()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 格式化分组标题
|
// 格式化分组标题
|
||||||
function formatGroupTitle(dateStr) {
|
function formatGroupTitle(dateStr) {
|
||||||
if (!dateStr) return ''
|
if (!dateStr) return ''
|
||||||
@@ -241,7 +260,7 @@ function formatGroupTitle(dateStr) {
|
|||||||
|
|
||||||
// 下拉刷新
|
// 下拉刷新
|
||||||
async function onRefresh() {
|
async function onRefresh() {
|
||||||
await logsStore.fetchLogs(true, currentTab.value)
|
await logsStore.fetchLogs(true, 'smoke')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上拉加载
|
// 上拉加载
|
||||||
@@ -300,25 +319,13 @@ function handleDelete(log) {
|
|||||||
async function initPage() {
|
async function initPage() {
|
||||||
try {
|
try {
|
||||||
await waitForLogin()
|
await waitForLogin()
|
||||||
await logsStore.fetchLogs(true, currentTab.value)
|
await logsStore.fetchLogs(true, 'smoke')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('initPage error:', e)
|
console.error('initPage error:', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupNavBar() {
|
|
||||||
const systemInfo = uni.getSystemInfoSync()
|
|
||||||
const statusBarH = systemInfo.statusBarHeight || 0
|
|
||||||
try {
|
|
||||||
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
|
||||||
navBarHeight.value = menuBtn.bottom + (menuBtn.top - statusBarH)
|
|
||||||
} catch (e) {
|
|
||||||
navBarHeight.value = statusBarH + 44
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setupNavBar()
|
|
||||||
initPage()
|
initPage()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -342,10 +349,6 @@ function levelLabel(level) {
|
|||||||
return '极强'
|
return '极强'
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(currentTab, async (value) => {
|
|
||||||
await logsStore.fetchLogs(true, value)
|
|
||||||
})
|
|
||||||
|
|
||||||
onShareAppMessage(() => {
|
onShareAppMessage(() => {
|
||||||
return {
|
return {
|
||||||
title: '戒烟助手 - 我的戒烟记录',
|
title: '戒烟助手 - 我的戒烟记录',
|
||||||
@@ -365,32 +368,23 @@ onShareAppMessage(() => {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-bar {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters-sticky {
|
.filters-sticky {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 96rpx;
|
height: 88rpx;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
position: fixed;
|
position: relative;
|
||||||
left: 32rpx;
|
z-index: 1;
|
||||||
right: 32rpx;
|
padding: 10rpx 0 12rpx;
|
||||||
z-index: 50;
|
|
||||||
padding-top: 8rpx;
|
|
||||||
padding-bottom: 14rpx;
|
|
||||||
background: rgba(246, 248, 246, 0.9);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-webkit-backdrop-filter: blur(14px);
|
|
||||||
backdrop-filter: blur(14px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs {
|
.date-filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 8rpx;
|
||||||
background: rgba(255, 255, 255, 0.82);
|
background: rgba(255, 255, 255, 0.82);
|
||||||
border: 1rpx solid rgba(226, 232, 240, 0.82);
|
border: 1rpx solid rgba(226, 232, 240, 0.82);
|
||||||
border-radius: 22rpx;
|
border-radius: 22rpx;
|
||||||
@@ -399,17 +393,17 @@ onShareAppMessage(() => {
|
|||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.date-filter {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 15rpx 0;
|
padding: 14rpx 0;
|
||||||
border-radius: 18rpx;
|
border-radius: 18rpx;
|
||||||
font-size: 25rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
color: #64748B;
|
color: #64748B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-active {
|
.date-filter-active {
|
||||||
background: linear-gradient(135deg, #10B981, #06B6D4);
|
background: linear-gradient(135deg, #10B981, #06B6D4);
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
box-shadow: 0 8rpx 18rpx rgba(16, 185, 129, 0.16);
|
box-shadow: 0 8rpx 18rpx rgba(16, 185, 129, 0.16);
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ const profileStore = useProfileStore()
|
|||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const { waitForLogin } = useLogin()
|
const { waitForLogin } = useLogin()
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
|
const MEDALLION_IMAGE = '../../static/achievements/theme-medallion.png'
|
||||||
|
|
||||||
const navBarHeight = ref(0)
|
const navBarHeight = ref(0)
|
||||||
const latestNSTIResult = ref(null)
|
const latestNSTIResult = ref(null)
|
||||||
@@ -529,7 +530,7 @@ async function handleSaveAchievementPoster() {
|
|||||||
await fetchPosterData()
|
await fetchPosterData()
|
||||||
const [qrPath, medallionInfo] = await Promise.all([
|
const [qrPath, medallionInfo] = await Promise.all([
|
||||||
downloadMiniProgramTestCode({ path: 'pages/index/index', width: 240 }).catch(() => ''),
|
downloadMiniProgramTestCode({ path: 'pages/index/index', width: 240 }).catch(() => ''),
|
||||||
getImageInfo('/static/achievements/theme-medallion.png')
|
getImageInfo(MEDALLION_IMAGE)
|
||||||
])
|
])
|
||||||
const posterPath = await drawAchievementPoster(qrPath, medallionInfo)
|
const posterPath = await drawAchievementPoster(qrPath, medallionInfo)
|
||||||
await savePosterToAlbum(posterPath)
|
await savePosterToAlbum(posterPath)
|
||||||
|
|||||||
Reference in New Issue
Block a user