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:
74
miniprogram/pages/plan-detail/plan-detail.js
Normal file
74
miniprogram/pages/plan-detail/plan-detail.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const app = getApp();
|
||||
const planSvc = require('../../services/plan');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
id: '',
|
||||
plan: null,
|
||||
exercises: [],
|
||||
loading: true
|
||||
},
|
||||
|
||||
onLoad(query) {
|
||||
const id = query.id || '';
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20, id });
|
||||
this.load();
|
||||
},
|
||||
|
||||
load() {
|
||||
this.setData({ loading: true });
|
||||
planSvc.get(this.data.id).then((plan) => {
|
||||
const raw = plan && plan.updatedAt;
|
||||
const updatedAtText = typeof raw === 'string'
|
||||
? raw.slice(0, 10)
|
||||
: (raw ? String(raw).slice(0, 10) : '');
|
||||
this.setData({
|
||||
plan: { ...plan, updatedAtText },
|
||||
exercises: (plan && plan.exercises) || [],
|
||||
loading: false
|
||||
});
|
||||
}).catch(() => {
|
||||
this.setData({ loading: false });
|
||||
});
|
||||
},
|
||||
|
||||
onRemoveExercise(e) {
|
||||
const exerciseId = e.currentTarget.dataset.id;
|
||||
planSvc.removeExercise(this.data.id, exerciseId).then(() => {
|
||||
this.setData({ exercises: this.data.exercises.filter(i => i.id !== exerciseId) });
|
||||
wx.showToast({ title: '已移除', icon: 'none' });
|
||||
}).catch(() => {});
|
||||
},
|
||||
|
||||
onExercise(e) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/detail/detail?planId=' + encodeURIComponent(this.data.id) +
|
||||
'&id=' + encodeURIComponent(e.detail.id)
|
||||
});
|
||||
},
|
||||
|
||||
onAdd() {
|
||||
wx.navigateTo({ url: '/pages/search/search?mode=select&planId=' + encodeURIComponent(this.data.id) });
|
||||
},
|
||||
|
||||
onEdit() {
|
||||
wx.navigateTo({ url: '/pages/plan-edit/plan-edit?mode=edit&id=' + encodeURIComponent(this.data.id) });
|
||||
},
|
||||
|
||||
onDelete() {
|
||||
wx.showModal({
|
||||
title: '删除计划',
|
||||
content: '确定要删除该训练计划吗?此操作不可恢复。',
|
||||
confirmColor: '#E5544B',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
planSvc.remove(this.data.id).then(() => {
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
setTimeout(() => wx.navigateBack(), 500);
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
8
miniprogram/pages/plan-detail/plan-detail.json
Normal file
8
miniprogram/pages/plan-detail/plan-detail.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {
|
||||
"navbar": "/components/navbar/index",
|
||||
"exercise-card": "/components/exercise-card/index",
|
||||
"section-header": "/components/section-header/index"
|
||||
}
|
||||
}
|
||||
39
miniprogram/pages/plan-detail/plan-detail.wxml
Normal file
39
miniprogram/pages/plan-detail/plan-detail.wxml
Normal file
@@ -0,0 +1,39 @@
|
||||
<view class="page" wx:if="{{plan}}">
|
||||
<navbar title="{{plan.name}}" show-back />
|
||||
|
||||
<view class="header" style="background: linear-gradient(135deg, {{plan.color}}26, var(--surface));">
|
||||
<view class="header__emoji" style="background: {{plan.color}}22; color: {{plan.color}};">{{plan.emoji}}</view>
|
||||
<view class="header__name" style="color: {{plan.color}};">{{plan.name}}</view>
|
||||
<view wx:if="{{plan.description}}" class="header__desc">{{plan.description}}</view>
|
||||
<view class="header__meta">共 {{exercises.length}} 个动作<text wx:if="{{plan.updatedAtText}}"> · 更新于 {{plan.updatedAtText}}</text></view>
|
||||
</view>
|
||||
|
||||
<view class="section" style="padding-top: 8rpx;">
|
||||
<section-header eyebrow="EXERCISES" title="动作列表" subtitle="点击查看详情 · 可在动作页加入本计划" />
|
||||
|
||||
<view class="list" wx:if="{{exercises.length}}">
|
||||
<view class="list__item" wx:for="{{exercises}}" wx:key="id">
|
||||
<view class="list__card">
|
||||
<exercise-card exercise="{{item}}" bind:tap="onExercise" />
|
||||
</view>
|
||||
<view class="list__remove" data-id="{{item.id}}" catchtap="onRemoveExercise">移除</view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:elif="{{!loading}}" class="empty-box">
|
||||
<view class="empty-box__emoji">🏋️</view>
|
||||
<view class="empty-box__t">这个计划还没有动作,去添加吧</view>
|
||||
<view class="empty-box__btn" bindtap="onAdd">+ 添加动作</view>
|
||||
</view>
|
||||
<view wx:else class="empty">加载中…</view>
|
||||
</view>
|
||||
|
||||
<view class="actionbar">
|
||||
<view class="btn btn--gold" bindtap="onAdd">+ 添加动作</view>
|
||||
<view class="btn btn--ghost" bindtap="onEdit">编辑</view>
|
||||
<view class="btn btn--del" bindtap="onDelete">删除计划</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="empty-page">
|
||||
<view class="empty">{{ loading ? '加载中…' : '未找到该计划' }}</view>
|
||||
</view>
|
||||
50
miniprogram/pages/plan-detail/plan-detail.wxss
Normal file
50
miniprogram/pages/plan-detail/plan-detail.wxss
Normal file
@@ -0,0 +1,50 @@
|
||||
.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__desc { font-size: 26rpx; color: var(--text-2); margin-top: 12rpx; line-height: 1.5; }
|
||||
.header__meta { font-size: 24rpx; color: var(--text-2); margin-top: 16rpx; }
|
||||
|
||||
.list { display: flex; flex-direction: column; gap: 16rpx; }
|
||||
.list__item { position: relative; }
|
||||
.list__card { width: 100%; }
|
||||
.list__remove {
|
||||
position: absolute; right: 12rpx; top: 12rpx; z-index: 5;
|
||||
background: rgba(229,84,75,0.92); color: #fff;
|
||||
font-size: 22rpx; padding: 8rpx 18rpx; border-radius: 999rpx;
|
||||
}
|
||||
|
||||
.empty { color: var(--text-3); font-size: 26rpx; text-align: center; padding: 120rpx 0; }
|
||||
.empty-page { min-height: 100vh; background: var(--bg-grad); }
|
||||
|
||||
.empty-box { display: flex; flex-direction: column; align-items: center; padding: 100rpx 40rpx; }
|
||||
.empty-box__emoji {
|
||||
width: 150rpx; height: 150rpx; border-radius: 36rpx;
|
||||
background: var(--surface-2); display: flex; align-items: center; justify-content: center;
|
||||
font-size: 80rpx;
|
||||
}
|
||||
.empty-box__t { font-size: 28rpx; color: var(--text-2); margin-top: 32rpx; text-align: center; }
|
||||
.empty-box__btn {
|
||||
margin-top: 40rpx; padding: 22rpx 64rpx; border-radius: 999rpx;
|
||||
background: linear-gradient(135deg, var(--gold) 0%, var(--gold-2) 100%);
|
||||
color: #0E1110; font-weight: 700; font-size: 30rpx;
|
||||
}
|
||||
|
||||
.actionbar {
|
||||
position: fixed; left: 0; right: 0; bottom: 0;
|
||||
display: flex; gap: 16rpx; padding: 20rpx 24rpx;
|
||||
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: 24rpx 10rpx; font-size: 28rpx; 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(--line); flex: 0 0 auto; width: 180rpx; }
|
||||
.btn--del { background: rgba(229,84,75,0.16); color: #E5544B; border: 1rpx solid rgba(229,84,75,0.4); flex: 0 0 auto; width: 180rpx; }
|
||||
Reference in New Issue
Block a user