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:
14
miniprogram/components/exercise-card/index.js
Normal file
14
miniprogram/components/exercise-card/index.js
Normal file
@@ -0,0 +1,14 @@
|
||||
Component({
|
||||
properties: {
|
||||
exercise: { type: Object, value: {} },
|
||||
score: { type: Number, value: 0 },
|
||||
reason: { type: String, value: '' },
|
||||
compact: { type: Boolean, value: false }
|
||||
},
|
||||
methods: {
|
||||
onTap() {
|
||||
const ex = this.data.exercise || {};
|
||||
this.triggerEvent('tap', { id: ex.id, exercise: ex });
|
||||
}
|
||||
}
|
||||
});
|
||||
4
miniprogram/components/exercise-card/index.json
Normal file
4
miniprogram/components/exercise-card/index.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
21
miniprogram/components/exercise-card/index.wxml
Normal file
21
miniprogram/components/exercise-card/index.wxml
Normal file
@@ -0,0 +1,21 @@
|
||||
<view class="ex-card {{compact ? 'ex-card--compact' : ''}}" bindtap="onTap">
|
||||
<view class="ex-card__media">
|
||||
<image
|
||||
wx:if="{{exercise.gifUrl || exercise.image}}"
|
||||
class="ex-card__img"
|
||||
src="{{exercise.gifUrl || exercise.image}}"
|
||||
mode="aspectFill"
|
||||
lazy-load="true" />
|
||||
<view wx:else class="ex-card__ph">🏋️</view>
|
||||
<view wx:if="{{exercise.typeLabel}}" class="ex-card__type">{{exercise.typeLabel}}</view>
|
||||
<view wx:if="{{score > 0}}" class="ex-card__score">匹配 {{score}}</view>
|
||||
</view>
|
||||
<view class="ex-card__body">
|
||||
<view class="ex-card__name">{{exercise.name}}</view>
|
||||
<view class="ex-card__chips">
|
||||
<text wx:if="{{exercise.targetLabel}}" class="tag tag--gold">{{exercise.targetLabel}}</text>
|
||||
<text wx:if="{{exercise.equipmentLabel}}" class="tag">{{exercise.equipmentLabel}}</text>
|
||||
</view>
|
||||
<view wx:if="{{reason}}" class="ex-card__reason">{{reason}}</view>
|
||||
</view>
|
||||
</view>
|
||||
40
miniprogram/components/exercise-card/index.wxss
Normal file
40
miniprogram/components/exercise-card/index.wxss
Normal file
@@ -0,0 +1,40 @@
|
||||
.ex-card {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
border: 1rpx solid var(--line);
|
||||
width: 100%;
|
||||
}
|
||||
.ex-card__media {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
background: var(--surface-2);
|
||||
}
|
||||
.ex-card--compact .ex-card__media { height: 160rpx; }
|
||||
.ex-card__img { width: 100%; height: 100%; display: block; }
|
||||
.ex-card__ph {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 64rpx;
|
||||
}
|
||||
.ex-card__type {
|
||||
position: absolute; left: 12rpx; top: 12rpx;
|
||||
font-size: 20rpx; color: var(--text-2);
|
||||
background: rgba(0,0,0,0.45); padding: 4rpx 14rpx; border-radius: 999rpx;
|
||||
}
|
||||
.ex-card__score {
|
||||
position: absolute; right: 12rpx; top: 12rpx;
|
||||
font-size: 20rpx; color: #0E1110; font-weight: 700;
|
||||
background: var(--gold); padding: 4rpx 14rpx; border-radius: 999rpx;
|
||||
}
|
||||
.ex-card__body { padding: 16rpx 18rpx 20rpx; }
|
||||
.ex-card__name {
|
||||
font-size: 28rpx; font-weight: 600; color: var(--text);
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.ex-card__chips { display: flex; gap: 10rpx; margin-top: 12rpx; flex-wrap: wrap; }
|
||||
.ex-card__reason {
|
||||
margin-top: 12rpx; font-size: 22rpx; color: var(--text-3);
|
||||
line-height: 1.45;
|
||||
}
|
||||
Reference in New Issue
Block a user