6176f2c341
- records: 底部列表与月份选择器联动,新增 [本月|最近] 分段控件;标题/空态随模式切换 - leaderboard: 领奖台布局(冠军居中+皇冠)、次数标注于底座且三档水平对齐;头像 cloud:// 批量预解析提速(云函数需重新部署) - index/timer: 主色底图标改白色变体修复隐形;目标数字按微信字体缩放补偿真机遮挡 - settings: 配色方案横滑渐变色卡;头像上传前压缩至 200px - theme: 新增 teal 主题;暗黑背景统一对齐 - 圆形头像双保险(image 自身 border-radius)修复月/年榜方图 注: cloudfunctions/leaderboard 改动须在开发者工具重新部署才生效。
154 lines
7.1 KiB
Plaintext
154 lines
7.1 KiB
Plaintext
<view class="container page-enter" style="{{themeStyle}}">
|
|
<!-- 加载骨架屏 (200ms 最小显示) -->
|
|
<block wx:if="{{loading}}">
|
|
<ui-skeleton variant="card" />
|
|
<view style="height: 24rpx;" />
|
|
<ui-skeleton variant="card" />
|
|
</block>
|
|
|
|
<!-- 真实内容 (loading 时隐藏) -->
|
|
<view hidden="{{loading}}">
|
|
<!-- 首次空状态: 完全没训练记录时显示引导卡 -->
|
|
<view class="first-train-prompt" wx:if="{{totalSessions === 0}}">
|
|
<view class="empty-illus first-train-illus">
|
|
<view class="empty-illus-body"></view>
|
|
<view class="empty-illus-arm empty-illus-arm--l"></view>
|
|
<view class="empty-illus-arm empty-illus-arm--r"></view>
|
|
<view class="empty-illus-bubble">开始</view>
|
|
</view>
|
|
<text class="first-train-title">开始你的第一次训练</text>
|
|
<text class="first-train-sub">每一次坚持都值得被记录</text>
|
|
<view class="first-train-cta" bindtap="onStartTrain">
|
|
<text>开始训练</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 统计卡片 (有数据时才显示) -->
|
|
<ui-card variant="in" hidden="{{totalSessions === 0}}">
|
|
<view class="stats">
|
|
<view class="stat-item">
|
|
<image class="stat-icon" src="{{icons.rankFill}}" mode="aspectFit"></image>
|
|
<text class="stat-num">{{totalSessions}}次</text>
|
|
<text class="stat-label">训练次数</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<image class="stat-icon" src="{{icons.timeFill}}" mode="aspectFit"></image>
|
|
<text class="stat-num">{{totalDurationText}}</text>
|
|
<text class="stat-label">累计时长</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<image class="stat-icon" src="{{icons.crownFill}}" mode="aspectFit"></image>
|
|
<text class="stat-num">{{maxDurationText}}</text>
|
|
<text class="stat-label">最长记录</text>
|
|
</view>
|
|
</view>
|
|
</ui-card>
|
|
|
|
<!-- 日历热力图 -->
|
|
<ui-card variant="in" hidden="{{totalSessions === 0}}">
|
|
<view class="calendar-section">
|
|
<view class="month-picker">
|
|
<view class="month-arrow" bindtap="onPrevMonth">
|
|
<image class="month-arrow-img" src="{{icons.back}}" mode="aspectFit"></image>
|
|
</view>
|
|
<view class="month-title-wrap">
|
|
<image class="month-icon" src="{{icons.calendarFill}}" mode="aspectFit"></image>
|
|
<text class="month-title">{{currentYear}}年 {{currentMonth}}月</text>
|
|
</view>
|
|
<view class="month-arrow" bindtap="onNextMonth">
|
|
<image class="month-arrow-img" src="{{icons.right}}" mode="aspectFit"></image>
|
|
</view>
|
|
</view>
|
|
<calendar-heatmap
|
|
year="{{currentYear}}"
|
|
month="{{currentMonth}}"
|
|
records="{{monthRecords}}"
|
|
primaryColor="{{theme.primary}}"
|
|
binddaytap="onDayTap"
|
|
></calendar-heatmap>
|
|
</view>
|
|
</ui-card>
|
|
|
|
<!-- 历史记录 -->
|
|
<ui-card variant="in" hidden="{{totalSessions === 0}}">
|
|
<view class="history-section">
|
|
<view class="history-header">
|
|
<view class="history-title-wrap">
|
|
<image class="history-title-icon" src="{{icons.formFill}}" mode="aspectFit"></image>
|
|
<text class="section-title">{{listMode === 'month' ? currentYear + '年' + currentMonth + '月记录' : '最近记录'}}</text>
|
|
</view>
|
|
<view class="rec-seg">
|
|
<view class="rec-seg-item {{listMode === 'month' ? 'active' : ''}}" data-mode="month" bindtap="onToggleListMode">本月</view>
|
|
<view class="rec-seg-item {{listMode === 'recent' ? 'active' : ''}}" data-mode="recent" bindtap="onToggleListMode">最近</view>
|
|
</view>
|
|
</view>
|
|
<text class="history-hint" wx:if="{{displayList.length > 0}}">长按可删除</text>
|
|
<view wx:if="{{displayList.length === 0}}" class="empty-state">
|
|
<view class="empty-illus">
|
|
<view class="empty-illus-body"></view>
|
|
<view class="empty-illus-arm empty-illus-arm--l"></view>
|
|
<view class="empty-illus-arm empty-illus-arm--r"></view>
|
|
<view class="empty-illus-bubble">开始</view>
|
|
</view>
|
|
<text class="empty-text">{{listMode === 'month' ? '本月还没有训练记录' : '还没有训练记录'}}</text>
|
|
<text class="empty-sub">{{listMode === 'month' ? '换个有训练的月份看看吧' : '完成第一次训练,开启你的坚持!'}}</text>
|
|
</view>
|
|
<view class="history-list">
|
|
<view class="history-item" wx:for="{{displayList}}" wx:key="id" data-id="{{item.id}}" bindlongpress="onLongPressDelete">
|
|
<image class="history-item-icon"
|
|
src="{{item.duration >= 120 ? icons.hotFill : item.duration >= 60 ? icons.likeFill : icons.roundCheckFill}}"
|
|
mode="aspectFit"
|
|
></image>
|
|
<view class="history-left">
|
|
<text class="history-date">{{item.date}}</text>
|
|
<text class="history-plan">{{item.day === 0 ? '自由训练' : '第 ' + item.day + ' 天'}}</text>
|
|
</view>
|
|
<view class="history-right">
|
|
<text class="history-duration">{{item.duration}}s</text>
|
|
<view class="history-delete-btn" catch:tap="onDeleteRecord" data-id="{{item.id}}">
|
|
<image class="history-delete-icon" src="{{icons.deleteActive}}" mode="aspectFit"></image>
|
|
<text class="history-delete-text">删除</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</ui-card>
|
|
</view>
|
|
<!-- /hidden wrapper -->
|
|
|
|
</view>
|
|
<!-- 日期详情弹窗:放在 .container 外。 .page-enter 的 transform 让 .container
|
|
成为 fixed 的包含块,mask 降级相对 .container(高>>视口),body 居中到
|
|
.container 中心(视口外),真机看不到。移到 .container 外,fixed 相对视口;
|
|
style 注入 themeStyle 拿暗黑变量。 -->
|
|
<view wx:if="{{showDayDetail}}" class="day-detail-mask" style="{{themeStyle}}" 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-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-close" bindtap="onCloseDayDetail">
|
|
<text>关闭</text>
|
|
</view>
|
|
</view>
|
|
</view>
|