feat: init fitness-coach (backend + miniprogram)

- backend: NestJS service with exercise/plan data
- miniprogram: WeChat mini program client
- exclude node_modules, dist, runtime data-store, local env
This commit is contained in:
2026-07-22 00:35:40 +08:00
commit b3b58e66fb
103 changed files with 154759 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<view class="page" style="padding-top: {{statusBarHeight}}px;">
<view class="topbar">
<view class="topbar__back" bindtap="onBack"></view>
<view class="topbar__title">智能推荐</view>
</view>
<!-- 步骤 1选择目标肌群 -->
<block wx:if="{{step === 1}}">
<view class="hero2">
<view class="hero2__eyebrow">SMART MATCH</view>
<view class="hero2__title">选择你的目标肌群</view>
<view class="hero2__sub">为你智能匹配最合适动作,并给出训练理由</view>
</view>
<view class="section">
<view class="group" wx:for="{{bodyGroups}}" wx:key="label" wx:for-item="group">
<view class="group__label eyebrow">{{group.label}}</view>
<view class="group__chips">
<view
wx:for="{{group.targets}}"
wx:key="value"
wx:for-item="t"
class="tgt {{selectedTarget === t.value ? 'tgt--active' : ''}}"
data-value="{{t.value}}"
data-label="{{t.label}}"
bindtap="onSelectTarget">
<text>{{t.label}}</text>
<text class="tgt__count">{{t.count}}</text>
</view>
</view>
</view>
<view class="group" wx:if="{{equipments.length}}">
<view class="group__label eyebrow">器械偏好(可选)</view>
<view class="group__chips">
<view
wx:for="{{equipments}}"
wx:key="value"
wx:for-item="eq"
class="tgt {{selectedEquipment === eq.value ? 'tgt--active' : ''}}"
data-value="{{eq.value}}"
bindtap="onSelectEquipment">
<text>{{eq.label}}</text>
</view>
</view>
</view>
</view>
<view class="confirm">
<view class="confirm__bar">
<text wx:if="{{selectedTargetLabel}}" class="confirm__sel">已选:{{selectedTargetLabel}}</text>
<text wx:else class="confirm__hint">请选择目标肌群</text>
</view>
<view class="cta" bindtap="onConfirm">
<text>智能匹配动作</text>
<text class="cta__arrow"></text>
</view>
</view>
</block>
<!-- 步骤 2结果列表 -->
<block wx:else>
<view class="section" style="padding-top: 8rpx;">
<view class="result-head">
<text class="result-head__title">为你匹配 · {{selectedTargetLabel}}</text>
<text class="result-head__count">{{results.length}} 个动作</text>
</view>
<view class="rlist" wx:if="{{results.length}}">
<view class="rlist__item" wx:for="{{results}}" wx:key="id" wx:for-item="item">
<exercise-card
exercise="{{item}}"
score="{{item.score}}"
reason="{{item.reason}}"
bind:tap="onExercise" />
</view>
</view>
<view wx:else class="empty">{{ loading ? '匹配中…' : '暂无匹配结果' }}</view>
</view>
</block>
</view>