feat: 小程序连接服务器IP + 同步未提交开发
- miniprogram/config.js: BASE_URL 指向 http://192.227.237.8:3001 - 动作标题中文化(nameZh),搜索匹配 name/nameZh/nameEn - 新增计划/收藏/我的 等页面与组件 - 后端 Docker 化(Dockerfile/.dockerignore)与翻译脚本 - .gitignore 补充 .DS_Store
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
const app = getApp();
|
||||
const svc = require('../../services/exercise');
|
||||
const planSvc = require('../../services/plan');
|
||||
const favSvc = require('../../services/favorite');
|
||||
const auth = require('../../utils/auth');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -7,24 +9,25 @@ Page({
|
||||
slug: '',
|
||||
collection: null,
|
||||
exercises: [],
|
||||
total: 0,
|
||||
loading: true,
|
||||
page: 1,
|
||||
pageSize: 30,
|
||||
total: 0
|
||||
favorited: false
|
||||
},
|
||||
|
||||
onLoad(query) {
|
||||
const slug = query.slug || '';
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20, slug });
|
||||
this.load();
|
||||
if (auth.isLogin()) {
|
||||
favSvc.planStatus(slug).then((r) => {
|
||||
this.setData({ favorited: !!(r && r.favorited) });
|
||||
}).catch(() => {});
|
||||
}
|
||||
},
|
||||
|
||||
load() {
|
||||
this.setData({ loading: true });
|
||||
svc.getCollectionExercises(this.data.slug, {
|
||||
page: this.data.page,
|
||||
pageSize: this.data.pageSize
|
||||
}).then((res) => {
|
||||
planSvc.officialExercises(this.data.slug, 1, 60).then((res) => {
|
||||
this.setData({
|
||||
collection: res.collection,
|
||||
exercises: (res && res.items) || [],
|
||||
@@ -36,7 +39,39 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
// 收藏 / 取消收藏官方计划
|
||||
onToggleFav() {
|
||||
auth.ensureLogin().then(() => {
|
||||
const slug = this.data.slug;
|
||||
const wasFav = this.data.favorited;
|
||||
const op = wasFav ? favSvc.removePlan(slug) : favSvc.addPlan(slug);
|
||||
op.then(() => {
|
||||
this.setData({ favorited: !wasFav });
|
||||
wx.showToast({ title: wasFav ? '已取消收藏' : '已收藏', icon: 'none' });
|
||||
}).catch(() => {});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
// 导入到我的计划
|
||||
onImport() {
|
||||
auth.ensureLogin().then(() => {
|
||||
wx.showLoading({ title: '导入中…', mask: true });
|
||||
planSvc.importOfficial(this.data.slug).then(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '已导入到我的计划', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
wx.navigateTo({ url: '/pages/my-plans/my-plans' });
|
||||
}, 600);
|
||||
}).catch(() => {
|
||||
wx.hideLoading();
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
onExercise(e) {
|
||||
wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id) });
|
||||
wx.navigateTo({
|
||||
url: '/pages/detail/detail?from=collection&slug=' +
|
||||
encodeURIComponent(this.data.slug) + '&id=' + encodeURIComponent(e.detail.id)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {
|
||||
"navbar": "/components/navbar/index",
|
||||
"exercise-card": "/components/exercise-card/index"
|
||||
"exercise-card": "/components/exercise-card/index",
|
||||
"section-header": "/components/section-header/index",
|
||||
"level-tag": "/components/level-tag/index"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,42 @@
|
||||
|
||||
<view class="header" style="background: linear-gradient(135deg, {{collection.color}}26, var(--surface));">
|
||||
<view class="header__emoji" style="background: {{collection.color}}22; color: {{collection.color}};">{{collection.emoji}}</view>
|
||||
<view class="header__name">{{collection.name}}</view>
|
||||
<view class="header__name" style="color: {{collection.color}};">{{collection.name}}</view>
|
||||
<view wx:if="{{collection.nameEn}}" class="header__en">{{collection.nameEn}}</view>
|
||||
<view class="header__desc">{{collection.description}}</view>
|
||||
<view class="header__count" style="color: {{collection.color}};">共 {{total}} 个动作</view>
|
||||
|
||||
<view class="header__meta">
|
||||
<level-tag level="{{collection.level}}" />
|
||||
<text class="header__sep">·</text>
|
||||
<text class="header__m" wx:if="{{collection.sessionsPerWeek}}">每周 {{collection.sessionsPerWeek}} 次</text>
|
||||
<text class="header__sep" wx:if="{{collection.sessionsPerWeek && collection.durationWeeks}}">·</text>
|
||||
<text class="header__m" wx:if="{{collection.durationWeeks}}">约 {{collection.durationWeeks}} 周</text>
|
||||
<text class="header__sep" wx:if="{{collection.focus}}">·</text>
|
||||
<text class="header__m" wx:if="{{collection.focus}}">{{collection.focus}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section" style="padding-top: 8rpx;">
|
||||
<section-header eyebrow="EXERCISES" title="动作列表" subtitle="共 {{total}} 个动作" />
|
||||
<view class="grid" wx:if="{{exercises.length}}">
|
||||
<view class="grid__item" wx:for="{{exercises}}" wx:key="id">
|
||||
<exercise-card exercise="{{item}}" bind:tap="onExercise" />
|
||||
</view>
|
||||
</view>
|
||||
<view wx:elif="{{!loading}}" class="empty">暂无数据</view>
|
||||
<view wx:elif="{{!loading}}" class="empty">该计划暂无动作</view>
|
||||
<view wx:else class="empty">加载中…</view>
|
||||
</view>
|
||||
|
||||
<view class="actionbar">
|
||||
<view class="btn btn--ghost {{favorited ? 'btn--faved' : ''}}" bindtap="onToggleFav">
|
||||
<text>{{favorited ? '♥ 已收藏' : '♡ 收藏'}}</text>
|
||||
</view>
|
||||
<view class="btn btn--gold" bindtap="onImport">
|
||||
<text>+ 导入我的计划</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="empty-page">
|
||||
<view class="empty">{{ loading ? '加载中…' : '未找到该训练组合' }}</view>
|
||||
<view class="empty">{{ loading ? '加载中…' : '未找到该训练计划' }}</view>
|
||||
</view>
|
||||
|
||||
@@ -1,14 +1,33 @@
|
||||
.page { min-height: 100vh; background: var(--bg-grad); padding-bottom: 60rpx; }
|
||||
.page { min-height: 100vh; background: var(--bg-grad); padding-bottom: 160rpx; }
|
||||
.header { padding: 32rpx; border-bottom: 1rpx solid var(--line); }
|
||||
.header__emoji {
|
||||
width: 120rpx; height: 120rpx; border-radius: 28rpx;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 64rpx;
|
||||
}
|
||||
.header__name { font-size: 44rpx; font-weight: 700; margin-top: 20rpx; }
|
||||
.header__en { font-size: 24rpx; color: var(--text-3); margin-top: 6rpx; letter-spacing: 1rpx; }
|
||||
.header__desc { font-size: 26rpx; color: var(--text-2); margin-top: 12rpx; line-height: 1.5; }
|
||||
.header__count { font-size: 24rpx; margin-top: 16rpx; }
|
||||
.header__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 12rpx; margin-top: 20rpx; }
|
||||
.header__sep { color: var(--text-3); font-size: 22rpx; }
|
||||
.header__m { font-size: 24rpx; color: var(--text-2); }
|
||||
|
||||
.grid { display: flex; flex-wrap: wrap; gap: 18rpx; }
|
||||
.grid__item { width: calc((100% - 18rpx) / 2); }
|
||||
.empty { color: var(--text-3); font-size: 26rpx; text-align: center; padding: 120rpx 0; }
|
||||
.empty-page { min-height: 100vh; background: var(--bg-grad); }
|
||||
|
||||
.actionbar {
|
||||
position: fixed; left: 0; right: 0; bottom: 0;
|
||||
display: flex; gap: 20rpx; padding: 20rpx 32rpx;
|
||||
background: rgba(14,17,16,0.92);
|
||||
backdrop-filter: blur(12px);
|
||||
border-top: 1rpx solid var(--line);
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
.btn {
|
||||
flex: 1; display: flex; align-items: center; justify-content: center;
|
||||
border-radius: 999rpx; padding: 26rpx; font-size: 30rpx; font-weight: 700;
|
||||
}
|
||||
.btn--gold { background: linear-gradient(135deg, var(--gold) 0%, var(--gold-2) 100%); color: #0E1110; }
|
||||
.btn--ghost { background: var(--surface-2); color: var(--text); border: 1rpx solid var(--gold-line); }
|
||||
.btn--faved { color: var(--gold-2); border-color: var(--gold); }
|
||||
|
||||
Reference in New Issue
Block a user