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:
48
miniprogram/pages/search/search.js
Normal file
48
miniprogram/pages/search/search.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const app = getApp();
|
||||
const svc = require('../../services/exercise');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 20,
|
||||
q: '',
|
||||
results: [],
|
||||
loading: false,
|
||||
searched: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20 });
|
||||
},
|
||||
|
||||
onInput(e) {
|
||||
const q = e.detail.value;
|
||||
this.setData({ q });
|
||||
this.debouncedSearch(q);
|
||||
},
|
||||
|
||||
debouncedSearch(q) {
|
||||
if (this._timer) clearTimeout(this._timer);
|
||||
this._timer = setTimeout(() => this.doSearch(q), 350);
|
||||
},
|
||||
|
||||
doSearch(q) {
|
||||
if (!q || !q.trim()) {
|
||||
this.setData({ results: [], searched: false, loading: false });
|
||||
return;
|
||||
}
|
||||
this.setData({ loading: true });
|
||||
svc.search(q.trim()).then((res) => {
|
||||
this.setData({
|
||||
results: (res && res.items) || [],
|
||||
searched: true,
|
||||
loading: false
|
||||
});
|
||||
}).catch(() => {
|
||||
this.setData({ searched: true, loading: false });
|
||||
});
|
||||
},
|
||||
|
||||
onExercise(e) {
|
||||
wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id) });
|
||||
}
|
||||
});
|
||||
7
miniprogram/pages/search/search.json
Normal file
7
miniprogram/pages/search/search.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"usingComponents": {
|
||||
"navbar": "/components/navbar/index",
|
||||
"exercise-card": "/components/exercise-card/index"
|
||||
}
|
||||
}
|
||||
26
miniprogram/pages/search/search.wxml
Normal file
26
miniprogram/pages/search/search.wxml
Normal file
@@ -0,0 +1,26 @@
|
||||
<view class="page">
|
||||
<navbar title="搜索" />
|
||||
<view class="searchbar">
|
||||
<view class="searchbar__box">
|
||||
<text class="searchbar__icon">🔍</text>
|
||||
<input
|
||||
class="searchbar__input"
|
||||
placeholder="搜索动作 / 器械 / 部位"
|
||||
placeholder-class="ph"
|
||||
value="{{q}}"
|
||||
confirm-type="search"
|
||||
bindinput="onInput" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="section" style="padding-top: 8rpx;">
|
||||
<view class="grid" wx:if="{{results.length}}">
|
||||
<view class="grid__item" wx:for="{{results}}" wx:key="id">
|
||||
<exercise-card exercise="{{item}}" bind:tap="onExercise" />
|
||||
</view>
|
||||
</view>
|
||||
<view wx:elif="{{loading}}" class="empty">搜索中…</view>
|
||||
<view wx:elif="{{searched}}" class="empty">未找到相关动作</view>
|
||||
<view wx:else class="empty">输入关键词开始搜索</view>
|
||||
</view>
|
||||
</view>
|
||||
14
miniprogram/pages/search/search.wxss
Normal file
14
miniprogram/pages/search/search.wxss
Normal file
@@ -0,0 +1,14 @@
|
||||
.page { min-height: 100vh; background: var(--bg-grad); }
|
||||
.searchbar { padding: 12rpx 32rpx; }
|
||||
.searchbar__box {
|
||||
display: flex; align-items: center;
|
||||
background: var(--surface); border: 1rpx solid var(--line);
|
||||
border-radius: 999rpx; padding: 20rpx 28rpx;
|
||||
}
|
||||
.searchbar__icon { font-size: 30rpx; margin-right: 16rpx; }
|
||||
.searchbar__input { flex: 1; color: var(--text); font-size: 28rpx; }
|
||||
.ph { color: var(--text-3); }
|
||||
|
||||
.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; }
|
||||
Reference in New Issue
Block a user