fix: 修复头像存储、日历详情数据与弹窗定位问题

- settings: 补上缺失的 util 导入,onChooseAvatar 不再抛
  ReferenceError,头像走 data URI 永久存储主路径
- records: 日历详情改用 dateOnly 比较,修复详情永远显示 0 次/0 时长
- records: 日历详情弹窗从 ui-modal 改为普通 view + fixed,
  修复被底部 dock 遮挡/不居中;补暗黑阴影描边与滚动穿透处理

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 08:46:17 +08:00
parent ac0db6118d
commit 1d13b49682
6 changed files with 91 additions and 30 deletions
+6 -1
View File
@@ -108,7 +108,9 @@ Page({
const { year, month, day } = e.detail
const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
const allRecords = Object.values(storage.getRecords()).flat()
const sessions = allRecords.filter(r => r.date === dateStr)
// record.date 是 "YYYY-MM-DD HH:MM:SS"(formatDate 生成),dateStr 只有
// 日期部分,直接 === 永远不匹配,必须用 dateOnly 截取后再比。
const sessions = allRecords.filter(r => util.dateOnly(r.date) === dateStr)
const totalDur = sessions.reduce((sum, r) => sum + r.duration, 0)
const calories = Math.round(totalDur * 0.068)
this.setData({
@@ -127,6 +129,9 @@ Page({
this.setData({ showDayDetail: false })
},
// Swallow touchmove on the popup so the background page doesn't scroll.
onNoop() { /* swallow */ },
onLongPressDelete(e) {
this.onDeleteRecord(e)
},
+1 -2
View File
@@ -1,8 +1,7 @@
{
"usingComponents": {
"calendar-heatmap": "/components/calendar-heatmap/calendar-heatmap",
"ui-card": "/components/ui-card/ui-card",
"ui-modal": "/components/ui-modal/ui-modal"
"ui-card": "/components/ui-card/ui-card"
},
"navigationBarTitleText": "训练记录"
}
+29 -23
View File
@@ -113,31 +113,37 @@
</view>
<!-- /hidden wrapper -->
<!-- 日期详情弹窗 -->
<ui-modal visible="{{showDayDetail}}" position="center" bind:close="onCloseDayDetail">
<view class="detail-date-row">
<image class="detail-icon" src="{{icons.calendarFill}}" mode="aspectFit"></image>
<text class="detail-date">{{dayDetail.date}}</text>
</view>
<view class="detail-grid">
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.rankFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.sessions}}</text>
<text class="detail-label">训练次数</text>
<!-- 日期详情弹窗:普通 view 实现,不用 ui-modal。
自定义组件根元素的 position: fixed 会被小程序运行时吞掉,叠加
.page-enter 的 transform 会让 fixed 降级相对 .container,导致弹窗
落到容器末尾而非视口居中。普通 view 的 fixed 100% 生效。 -->
<view wx:if="{{showDayDetail}}" class="day-detail-mask" catchtouchmove="onNoop">
<view class="day-detail-mask__bg" bindtap="onCloseDayDetail"></view>
<view class="day-detail-body" catchtap="onNoop">
<view class="detail-date-row">
<image class="detail-icon" src="{{icons.calendarFill}}" mode="aspectFit"></image>
<text class="detail-date">{{dayDetail.date}}</text>
</view>
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.timeFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.durationText}}</text>
<text class="detail-label">总时长</text>
<view class="detail-grid">
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.rankFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.sessions}}次</text>
<text class="detail-label">训练次数</text>
</view>
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.timeFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.durationText}}</text>
<text class="detail-label">总时长</text>
</view>
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.hotFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.calories}}</text>
<text class="detail-label">约消耗 (千卡)</text>
</view>
</view>
<view class="detail-item">
<image class="detail-item-icon" src="{{icons.hotFill}}" mode="aspectFit"></image>
<text class="detail-num">{{dayDetail.calories}}</text>
<text class="detail-label">约消耗 (千卡)</text>
<view class="detail-close" bindtap="onCloseDayDetail">
<text>关闭</text>
</view>
</view>
<view class="detail-close" bindtap="onCloseDayDetail">
<text>关闭</text>
</view>
</ui-modal>
</view>
</view>
+51 -1
View File
@@ -221,7 +221,57 @@
line-height: 1;
}
/* ---- day detail popup ---- */
/* ---- day detail popup ----
普通 view 实现,不用 ui-modal:自定义组件根元素的 position: fixed
会被小程序运行时吞掉(见 settings.wxss plan-editor 注释),叠加
.page-enter 的 transform 会让 fixed 降级相对 .container,导致弹窗
落到容器末尾而非视口居中。普通 view 的 fixed 100% 生效。 */
.day-detail-mask {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.day-detail-mask__bg {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.45);
animation: dayDetailFade 0.25s ease;
}
.day-detail-body {
position: relative;
width: 560rpx;
border-radius: 28rpx;
padding: 48rpx 40rpx 36rpx;
background: var(--card-bg);
box-sizing: border-box;
text-align: center;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.25);
animation: dayDetailPop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@media (prefers-color-scheme: dark) {
.day-detail-body {
/* 暗黑下 body(#1C1C1E)与页面(#0F0F12)都偏深,加深阴影 + 微亮描边拉开层次 */
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.6), 0 0 0 1rpx rgba(255, 255, 255, 0.06);
}
}
@keyframes dayDetailFade {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes dayDetailPop {
from { transform: scale(0); opacity: 0; }
60% { transform: scale(1.05); }
to { transform: scale(1); opacity: 1; }
}
.detail-date-row {
display: flex;
align-items: center;