1584aabcc5
## profile-head 组件 头图 / 头像 / 昵称 / 签名 / 帖子关注粉丝 / 养宠数据 / 宠物名片墙, pages/mine 和 pages/user 用的是同一个组件、同一个接口 (GET /users/:id/profile)。 这件事必须一开始就做对:自己看和别人看要是两套渲染,会慢慢长歪, 装扮功能也就失去意义了——你调半天颜色,结果只有自己那页变了。 两边唯一的差别是底部按钮:自己看是「装扮我的主页」,别人看是「关注 TA」。 顺带把 mine 的头部从 /user/summary 切到了 /users/:id/profile。原来两边 字段对不上,装扮效果在「我的」页根本预览不到。 主题只在组件 wxss 里定义 --pf-a/--pf-b/--pf-ink 三个变量,下面所有着色 都走变量。后端存 key 不存色值,就是为了这套配色随时能在前端改。 ## pages/decorate 装扮页 头图上传 / 五套主题色 / 个性签名 60 字 / 宠物墙开关,顶部实时预览。 预览用的就是 profile-head 本身,不是仿一个——仿的迟早会和真的长得不一样。 喂给它一份改过的 card 就行,组件那边不需要知道自己在被预览。 头图有个坑单独处理了:bg_file_id 只在真动过的时候才传。新上传带新 id, 点「恢复默认渐变」带空串,都没动就不传字段。否则「只改个主题色」会把 已有头图冲掉。上传时先用本地临时路径顶上,不让用户对着转圈等。 联调验证(本地 9090,真上传了一张图走完存储链路): 上传 → file id + MinIO url 保存装扮 → bg_url 落库,主题 violet,签名落库 主页读回 → bio/theme/show_pets/bg_url/宠物墙/养宠数据 全对 只改主题 → theme 变 sky,头图还在(没被冲掉) 恢复默认渐变 → bg_url 清空,theme 和 bio 都没被动 别人视角 → is_self=false、followed=false,装扮和宠物墙都能看到 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
3.3 KiB
JavaScript
98 lines
3.3 KiB
JavaScript
const api = require('../../utils/api.js');
|
|
const store = require('../../utils/store.js');
|
|
const { toastErr } = require('../../utils/ui.js');
|
|
|
|
const TAG_CLASS = { 求助: 'warn', 经验: 'blue', 精选: 'purple', 避坑: 'red', 晒宠: '' };
|
|
|
|
function fmtAgo(iso) {
|
|
if (!iso) return '';
|
|
const d = new Date(iso);
|
|
if (isNaN(d.getTime())) return '';
|
|
const min = Math.floor((Date.now() - d.getTime()) / 60000);
|
|
if (min < 1) return '刚刚';
|
|
if (min < 60) return min + ' 分钟前';
|
|
if (min < 60 * 24) return Math.floor(min / 60) + ' 小时前';
|
|
if (min < 60 * 24 * 7) return Math.floor(min / 1440) + ' 天前';
|
|
const p = (n) => (n < 10 ? '0' + n : '' + n);
|
|
return p(d.getMonth() + 1) + '-' + p(d.getDate());
|
|
}
|
|
|
|
Page({
|
|
data: { uid: '', card: null, posts: [], page: 1, hasMore: false, loading: true },
|
|
onLoad(q) {
|
|
const uid = q && q.id;
|
|
if (!uid) return wx.showToast({ title: '缺少用户', icon: 'none' });
|
|
this.setData({ uid });
|
|
this.loadCard();
|
|
this.loadPosts(1);
|
|
},
|
|
loadCard() {
|
|
api
|
|
.userCard(this.data.uid)
|
|
.then((card) => this.setData({ card, loading: false }))
|
|
.catch((e) => {
|
|
this.setData({ loading: false });
|
|
toastErr(e);
|
|
});
|
|
},
|
|
loadPosts(page) {
|
|
api
|
|
.userPosts(this.data.uid, page)
|
|
.then((res) => {
|
|
const list = (res.list || []).map((p) => {
|
|
const tag = (p.tags || [])[0] || '';
|
|
return {
|
|
...p,
|
|
timeText: fmtAgo(p.created_at),
|
|
author_emoji: p.author_emoji || '🐾',
|
|
tag,
|
|
tagClass: TAG_CLASS[tag] || '',
|
|
};
|
|
});
|
|
const merged = page === 1 ? list : this.data.posts.concat(list);
|
|
this.setData({ posts: merged, page, hasMore: merged.length < (res.total || 0) });
|
|
})
|
|
.catch(() => {});
|
|
},
|
|
loadMore() {
|
|
if (this.data.hasMore) this.loadPosts(this.data.page + 1);
|
|
},
|
|
// 关注状态先本地翻转,请求失败再翻回去——等接口返回按钮才变会显得很迟钝
|
|
toggleFollow() {
|
|
const c = this.data.card;
|
|
if (!c || c.is_self) return;
|
|
const next = !c.followed;
|
|
this.setData({
|
|
'card.followed': next,
|
|
'card.follower_count': Math.max(0, c.follower_count + (next ? 1 : -1)),
|
|
});
|
|
(next ? api.followUser(c.id) : api.unfollowUser(c.id)).catch((e) => {
|
|
this.setData({ 'card.followed': !next, 'card.follower_count': c.follower_count });
|
|
toastErr(e, '操作失败');
|
|
});
|
|
},
|
|
goRelations(e) {
|
|
const kind = e.detail.kind;
|
|
wx.navigateTo({ url: `/pages/relations/relations?id=${this.data.uid}&kind=${kind}` });
|
|
},
|
|
// 自己看自己的主页时,头部按钮是「装扮」而不是「关注」
|
|
goDecorate() {
|
|
wx.navigateTo({ url: '/pages/decorate/decorate' });
|
|
},
|
|
// 别人的宠物只是名片,点了不跳;自己的才切过去看
|
|
goPet(e) {
|
|
const c = this.data.card;
|
|
if (!c || !c.is_self) return;
|
|
store.switchPet(e.detail.id);
|
|
wx.switchTab({ url: '/pages/home/home' });
|
|
},
|
|
previewImage(e) {
|
|
const { urls, cur } = e.currentTarget.dataset;
|
|
if (urls && urls.length) wx.previewImage({ urls, current: cur });
|
|
},
|
|
onShareAppMessage() {
|
|
const n = (this.data.card && this.data.card.nickname) || '宠友';
|
|
return { title: `${n} 的主页`, path: `/pages/user/user?id=${this.data.uid}` };
|
|
},
|
|
});
|