feat: Kinetic Dark 设计语言 + Lucide 图标迁移 + 首页轻量个性化
- 建立 Lucide 子集 iconfont(49 字形),全站 emoji 替换为 fc-icon 组件 - 重塑 Design Token(冷中性近黑底 + Volt 荧光绿 #B6F24E),消除硬编码颜色 - 首页登录后个性化:我的计划 / 我的收藏 / 今日推荐(纯前端复用现有 API) - 后端 DEFAULT_EMOJI→Lucide 名,PALETTE 对齐 Kinetic Dark 语义色板 - 修复 person-standing 缺失字形;14 个官方组合 seed emoji 全部映射到现有字形
This commit is contained in:
@@ -1,5 +1,22 @@
|
||||
const app = getApp();
|
||||
const svc = require('../../services/exercise');
|
||||
const planSvc = require('../../services/plan');
|
||||
const favSvc = require('../../services/favorite');
|
||||
const { iconName } = require('../../utils/icon-name');
|
||||
|
||||
function greeting() {
|
||||
const h = new Date().getHours();
|
||||
if (h < 6) return '夜深了,';
|
||||
if (h < 11) return '早上好,';
|
||||
if (h < 13) return '中午好,';
|
||||
if (h < 18) return '下午好,';
|
||||
if (h < 22) return '晚上好,';
|
||||
return '夜深了,';
|
||||
}
|
||||
|
||||
function isLogin() {
|
||||
return !!wx.getStorageSync('access_token');
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -11,13 +28,19 @@ Page({
|
||||
collections: [],
|
||||
loading: true,
|
||||
quickEntries: [
|
||||
{ key: 'recommend', label: '智能推荐', emoji: '✨', url: '/pages/recommend/recommend' },
|
||||
{ key: 'bodyPart', label: '按部位', emoji: '💪', url: '/pages/category/category?dimension=bodyPart' },
|
||||
{ key: 'equipment', label: '按器械', emoji: '🏋️', url: '/pages/category/category?dimension=equipment' },
|
||||
{ key: 'official', label: '官方计划', emoji: '📋', url: '/pages/collection/collection' },
|
||||
{ key: 'myPlans', label: '我的计划', emoji: '🗂️', url: '/pages/my-plans/my-plans' },
|
||||
{ key: 'mine', label: '我的', emoji: '👤', url: '/pages/profile/profile' }
|
||||
]
|
||||
{ key: 'recommend', label: '智能推荐', icon: 'sparkles', url: '/pages/recommend/recommend' },
|
||||
{ key: 'bodyPart', label: '按部位', icon: 'accessibility', url: '/pages/category/category?dimension=bodyPart' },
|
||||
{ key: 'equipment', label: '按器械', icon: 'dumbbell', url: '/pages/category/category?dimension=equipment' },
|
||||
{ key: 'official', label: '官方计划', icon: 'clipboard-list', url: '/pages/collection/collection' },
|
||||
{ key: 'myPlans', label: '我的计划', icon: 'folder-open', url: '/pages/my-plans/my-plans' },
|
||||
{ key: 'mine', label: '我的', icon: 'user', url: '/pages/profile/profile' }
|
||||
],
|
||||
// —— 轻量个性化(登录后)——
|
||||
isLogin: false,
|
||||
greeting: '',
|
||||
myPlans: [],
|
||||
myFavorites: [],
|
||||
todayRecommend: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -25,6 +48,11 @@ Page({
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// tab 切回:已登录则静默刷新个性化(优先缓存)
|
||||
if (isLogin()) this.loadPersonal(true);
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.setData({ loading: true });
|
||||
Promise.all([
|
||||
@@ -32,19 +60,70 @@ Page({
|
||||
svc.listExercises({ pageSize: 8 }).catch(() => ({ items: [] })),
|
||||
svc.listCollections().catch(() => [])
|
||||
]).then(([stats, list, collections]) => {
|
||||
const cols = (collections || []).map((c) => ({
|
||||
...c,
|
||||
icon: iconName(c.emoji)
|
||||
}));
|
||||
this.setData({
|
||||
stats,
|
||||
bodyParts: (stats && stats.bodyParts) || [],
|
||||
equipment: (stats && stats.equipment) || [],
|
||||
featured: (list && list.items) || [],
|
||||
collections: collections || [],
|
||||
collections: cols,
|
||||
loading: false
|
||||
});
|
||||
if (isLogin()) this.loadPersonal(false);
|
||||
}).catch(() => {
|
||||
this.setData({ loading: false });
|
||||
});
|
||||
},
|
||||
|
||||
// 轻量个性化:复用现有 API,纯前端聚合;silent=切 tab 静默刷新
|
||||
loadPersonal(silent) {
|
||||
if (!isLogin()) return;
|
||||
this.setData({ isLogin: true, greeting: greeting() });
|
||||
if (!silent) this.setData({ personalLoading: true });
|
||||
|
||||
const CACHE_KEY = 'fc_personal_cache';
|
||||
const cached = wx.getStorageSync(CACHE_KEY);
|
||||
const now = Date.now();
|
||||
if (cached && now - (cached.ts || 0) < 5 * 60 * 1000 && !silent) {
|
||||
this.applyPersonal(cached.data);
|
||||
return;
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
planSvc.listMine().catch(() => []),
|
||||
favSvc.listExercises().catch(() => [])
|
||||
]).then(([plans, favs]) => {
|
||||
const planArr = Array.isArray(plans) ? plans : (plans && plans.items) || [];
|
||||
const favArr = Array.isArray(favs) ? favs : (favs && favs.items) || [];
|
||||
const data = {
|
||||
myPlans: planArr.slice(0, 3).map((p) => ({
|
||||
id: p.id, name: p.name, count: p.exerciseCount || 0
|
||||
})),
|
||||
myFavorites: favArr.slice(0, 6),
|
||||
todayRecommend: (this.data.featured || []).slice(0, 3).map((e) => ({
|
||||
id: e.id, name: e.displayName || e.name,
|
||||
reason: '为你精选 · 高效入门'
|
||||
}))
|
||||
};
|
||||
wx.setStorageSync(CACHE_KEY, { ts: now, data });
|
||||
this.applyPersonal(data);
|
||||
}).catch(() => {
|
||||
this.setData({ personalLoading: false });
|
||||
});
|
||||
},
|
||||
|
||||
applyPersonal(data) {
|
||||
this.setData({
|
||||
myPlans: data.myPlans,
|
||||
myFavorites: data.myFavorites,
|
||||
todayRecommend: data.todayRecommend,
|
||||
personalLoading: false
|
||||
});
|
||||
},
|
||||
|
||||
goRecommend() {
|
||||
wx.navigateTo({ url: '/pages/recommend/recommend' });
|
||||
},
|
||||
@@ -57,6 +136,17 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/search/search' });
|
||||
},
|
||||
|
||||
onPlanTap(e) {
|
||||
const id = e.currentTarget.dataset.id;
|
||||
if (id) wx.navigateTo({ url: '/pages/plan-detail/plan-detail?id=' + encodeURIComponent(id) });
|
||||
},
|
||||
|
||||
onExercise(e) {
|
||||
const id = (e.detail && e.detail.id) || (e.currentTarget && e.currentTarget.dataset.id);
|
||||
if (!id) return;
|
||||
wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(id) });
|
||||
},
|
||||
|
||||
onScanBodyPart(e) {
|
||||
const { value, label } = e.currentTarget.dataset;
|
||||
wx.navigateTo({
|
||||
@@ -78,12 +168,5 @@ Page({
|
||||
url: '/pages/collection-detail/collection-detail?slug=' +
|
||||
encodeURIComponent(e.currentTarget.dataset.slug)
|
||||
});
|
||||
},
|
||||
|
||||
onExercise(e) {
|
||||
if (!e || !e.detail || !e.detail.id) return;
|
||||
wx.navigateTo({
|
||||
url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user