346d46cb27
- 复用 ui-modal(position:center) + ui-btn,不新建组件,风格统一且自动跟随暗黑 - config.js 新增 releaseNotes 数组(每条一行短句),复用已有 version 字段 - 首页 _checkUpdateNote() 在 onShow 检测 storage 版本 vs config.version, 不一致则居中弹通知并写回 storage 防重复;onCloseUpdateNote 关闭 - 绿色渐变徽章 + sparkleWhite 图标 + 版本标题 + 要点列表 + 知道了按钮 - 纯通知不重启应用;发版时改 version 同步更新 releaseNotes 即可
201 lines
7.3 KiB
Plaintext
201 lines
7.3 KiB
Plaintext
<view class="container page-enter index-page" style="{{themeStyle}}">
|
||
|
||
<!-- 全宽渐变头图 hero -->
|
||
<view class="hero">
|
||
<view class="hero-top">
|
||
<!-- 圆形头像:无头像时白底 + peopleFill 占位(橙图标在白底清晰);
|
||
有头像时透明描边,远程(cloud://)头像靠外层 overflow:hidden 裁圆 -->
|
||
<view class="hero-avatar {{avatarUrl ? 'has-avatar' : ''}}">
|
||
<image
|
||
class="hero-avatar-img"
|
||
src="{{avatarUrl || icons.peopleFill}}"
|
||
mode="{{avatarUrl ? 'aspectFill' : 'aspectFit'}}"
|
||
></image>
|
||
</view>
|
||
<view class="hero-user">
|
||
<text class="hero-greet">{{greetText}},{{nickName || '运动达人'}}</text>
|
||
<text class="hero-social">{{streakText}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="hero-challenge">
|
||
<text class="hero-time">「{{todayTargetText}}」</text>
|
||
<text class="hero-cta-text">敢不敢来挑战?</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 闯关进度地图(上浮叠在 hero 下) -->
|
||
<ui-card variant="in" index="0" class="quest-card {{justCompleted ? 'just-completed' : ''}}">
|
||
<view class="quest-head">
|
||
<text class="quest-title">{{planName}}<text class="quest-sub">第 {{planDay}} / {{planTotal}} 天</text></text>
|
||
</view>
|
||
<view class="quest-map">
|
||
<block wx:for="{{questNodes}}" wx:key="label">
|
||
<view class="q-node {{item.state}} {{item.final ? 'final' : ''}}">{{item.label}}</view>
|
||
<view wx:if="{{index < questNodes.length - 1}}" class="q-link {{item.state === 'done' ? 'done' : ''}}"></view>
|
||
</block>
|
||
</view>
|
||
<text class="quest-tip">{{questTip}}</text>
|
||
</ui-card>
|
||
|
||
<!-- 今日目标时长(无圆环, 大字流光时间) -->
|
||
<view class="timer-wrap">
|
||
<text class="time-display">{{todayTargetText}}</text>
|
||
<text class="time-label">今日目标时长</text>
|
||
<view class="benefit">⚡ 预计消耗 <text class="benefit-hl">{{estKcal}}</text> 千卡</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮区 -->
|
||
<view class="action-buttons">
|
||
<ui-btn
|
||
variant="primary"
|
||
size="xl"
|
||
block
|
||
text="{{todayDone ? '再战一次 ' : '立即挑战 '}}{{todayTargetText}}"
|
||
icon-src="{{icons.playWhite}}"
|
||
bindtap="onStartTrain"
|
||
custom-style="border-radius:16rpx;box-shadow:0 8rpx 20rpx rgba(var(--primary-rgb),0.35);animation:ctaPulse 2s ease-in-out infinite;"
|
||
></ui-btn>
|
||
|
||
<view class="action-row">
|
||
<ui-btn
|
||
class="action-cell"
|
||
variant="ghost"
|
||
size="xl"
|
||
block
|
||
text="自由训练"
|
||
icon-src="{{icons.timeFill}}"
|
||
bindtap="onFreeTrain"
|
||
custom-style="border-radius:16rpx;"
|
||
></ui-btn>
|
||
|
||
<ui-btn
|
||
class="action-cell"
|
||
variant="ghost"
|
||
size="xl"
|
||
block
|
||
text="循环训练"
|
||
icon-src="{{icons.repeatFill}}"
|
||
bindtap="onCircuitTrain"
|
||
custom-style="border-radius:16rpx;"
|
||
></ui-btn>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 时间选择弹窗 -->
|
||
<ui-modal
|
||
visible="{{showPicker}}"
|
||
position="bottom"
|
||
bind:close="onClosePicker"
|
||
>
|
||
<text class="picker-title">选择训练时长</text>
|
||
<view class="preset-grid">
|
||
<view
|
||
class="preset-item {{customDuration === item ? 'selected' : ''}}"
|
||
wx:for="{{presets}}"
|
||
wx:key="*this"
|
||
data-value="{{item}}"
|
||
bindtap="onSelectPreset"
|
||
>
|
||
<text class="preset-num">{{item}}</text>
|
||
<text class="preset-unit">秒</text>
|
||
</view>
|
||
</view>
|
||
<view class="custom-input-row">
|
||
<text class="custom-label">自定义:</text>
|
||
<input
|
||
class="custom-input"
|
||
type="number"
|
||
placeholder="输入秒数"
|
||
value="{{customInput}}"
|
||
focus="{{pickerInputFocus}}"
|
||
bindinput="onCustomInput"
|
||
bindfocus="onPickerInputFocus"
|
||
/>
|
||
<text class="custom-label">秒</text>
|
||
</view>
|
||
<ui-btn
|
||
variant="primary"
|
||
size="lg"
|
||
block
|
||
text="开始自由训练"
|
||
bindtap="onConfirmFree"
|
||
custom-style="border-radius:16rpx;"
|
||
></ui-btn>
|
||
<text class="picker-cancel" bindtap="onClosePicker">取消</text>
|
||
</ui-modal>
|
||
|
||
<!-- 循环训练配置弹窗:每组时长 / 组数 / 休息 / 每周次数,保存后持久化 -->
|
||
<ui-modal
|
||
visible="{{showCircuitPicker}}"
|
||
position="bottom"
|
||
bind:close="onCloseCircuitPicker"
|
||
>
|
||
<text class="picker-title">循环训练设置</text>
|
||
<text class="picker-sub">自定义每组时长、组数与组间休息</text>
|
||
|
||
<view class="circuit-row">
|
||
<text class="circuit-row-label">每组时长</text>
|
||
<view class="stepper">
|
||
<view class="stepper-btn" data-field="hold" data-delta="-10" bindtap="onCircuitStep">−</view>
|
||
<text class="stepper-val">{{cHold}}秒</text>
|
||
<view class="stepper-btn" data-field="hold" data-delta="10" bindtap="onCircuitStep">+</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="circuit-row">
|
||
<text class="circuit-row-label">组数</text>
|
||
<view class="stepper">
|
||
<view class="stepper-btn" data-field="sets" data-delta="-1" bindtap="onCircuitStep">−</view>
|
||
<text class="stepper-val">{{cSets}}组</text>
|
||
<view class="stepper-btn" data-field="sets" data-delta="1" bindtap="onCircuitStep">+</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="circuit-row">
|
||
<text class="circuit-row-label">组间休息</text>
|
||
<view class="stepper">
|
||
<view class="stepper-btn" data-field="rest" data-delta="-10" bindtap="onCircuitStep">−</view>
|
||
<text class="stepper-val">{{cRest}}秒</text>
|
||
<view class="stepper-btn" data-field="rest" data-delta="10" bindtap="onCircuitStep">+</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="circuit-row">
|
||
<text class="circuit-row-label">每周目标</text>
|
||
<view class="stepper">
|
||
<view class="stepper-btn" data-field="sessions" data-delta="-1" bindtap="onCircuitStep">−</view>
|
||
<text class="stepper-val">{{cSessions}}次/周</text>
|
||
<view class="stepper-btn" data-field="sessions" data-delta="1" bindtap="onCircuitStep">+</view>
|
||
</view>
|
||
</view>
|
||
|
||
<ui-btn
|
||
variant="primary"
|
||
size="lg"
|
||
block
|
||
text="保存并开始"
|
||
bindtap="onConfirmCircuit"
|
||
custom-style="border-radius:16rpx;"
|
||
></ui-btn>
|
||
<text class="picker-cancel" bindtap="onCloseCircuitPicker">取消</text>
|
||
</ui-modal>
|
||
|
||
<!-- 新版本更新通知(What's New),首次进入当期版本弹一次 -->
|
||
<ui-modal visible="{{showUpdateNote}}" position="center" bind:close="onCloseUpdateNote">
|
||
<view class="update-note">
|
||
<view class="update-note__badge">
|
||
<image class="update-note__icon" src="{{icons.sparkleWhite}}" mode="aspectFit"></image>
|
||
</view>
|
||
<text class="update-note__title">版本更新 {{updateNoteVersion}}</text>
|
||
<text class="update-note__date" wx:if="{{updateNoteDate}}">更新于 {{updateNoteDate}}</text>
|
||
<view class="update-note__list">
|
||
<view class="update-note__item" wx:for="{{updateNoteItems}}" wx:key="*this">
|
||
<text class="update-note__dot">·</text>
|
||
<text class="update-note__text">{{item}}</text>
|
||
</view>
|
||
</view>
|
||
<ui-btn variant="primary" size="lg" block text="知道了" bindtap="onCloseUpdateNote" custom-style="border-radius:16rpx;margin-top:28rpx;"></ui-btn>
|
||
</view>
|
||
</ui-modal>
|
||
</view>
|