Files
sundynix-pets/pets-fe/pages/community/community.js
T
Blizzard c7135424e5 fix(fe): 保存到相册的方法根本没写进去 + 重构社区版式
## 保存到相册点了没反应

上次改的时候,插入方法的锚点用的是「// AI 聊天」那段注释,而它在
AI 独立成页时已经被删掉了 —— 替换没匹配上,onSavePoster / drawPoster /
saveToAlbum 三个方法一个都没进 js,按钮绑了个不存在的方法。

我的检查器没拦住,是因为「事件绑定是否有实现」那条写在临时的 audit.js
里,日常只跑 check.js。已经把这条并进 check.js —— 加完立刻抓出了本次
新写的 13 处缺样式 class,说明它管用。

## 社区

帖子操作栏原来是 space-around 排三个宽度不一的项:点赞数从 9 变 10
整行就会跳。改成三等分,图标 32rpx 居中对齐,没有数字时显示「点赞/评论」
而不是一个孤零零的 0,加了按下态。

帖子头部原来副标题固定写死「宠友」两个字,等于没有信息。换成发布时间
(刚刚 / 12 分钟前 / 3 天前)。

评论弹层原来拿 .record-row 当评论用 —— 那是个「左右两端对齐」的行,
昵称在左内容在右,评论一长就被挤扁,完全不是评论该有的样子。重做成
头像 + 昵称/时间 + 内容的正常结构;没有头像字段就用昵称首字做色块,
比一律显示同一个 emoji 强。发送按钮有输入才点亮,支持键盘回车发送。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 15:25:18 +08:00

169 lines
5.5 KiB
JavaScript

const store = require('../../utils/store.js');
const api = require('../../utils/api.js');
const { toastErr } = require('../../utils/ui.js');
// 相对时间。社区里关心的是「多久以前发的」,精确到秒没意义
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);
const sameYear = d.getFullYear() === new Date().getFullYear();
return (sameYear ? '' : d.getFullYear() + '-') + p(d.getMonth() + 1) + '-' + p(d.getDate());
}
const TAG_CLASS = { 求助: 'warn', 经验: 'blue', 精选: 'purple', 避坑: 'red', 晒宠: '' };
function mapPost(p) {
const tags = p.tags || [];
const tag = tags[0] || '';
return {
id: p.id,
author_name: p.author_name,
author_emoji: p.author_emoji || '🐾',
content: p.content,
images: p.images || [],
like_count: p.like_count,
comment_count: p.comment_count,
liked: false,
tag,
tagClass: TAG_CLASS[tag] || '',
is_ai: !!p.is_ai,
user_id: p.user_id,
followed: !!p.followed,
is_self: !!p.is_self,
timeText: fmtAgo(p.created_at),
};
}
Page({
data: {
pet: {},
feedTabs: ['推荐', '关注', '新手求助', '晒宠', '经验'],
feedIdx: 0,
posts: [],
sheetShow: false,
sheetType: '',
sheetPostId: '',
loaded: false,
loadErr: '',
},
onLoad() {
this._unsub = store.subscribe((pet) => this.setData({ pet }));
},
onUnload() {
if (this._unsub) this._unsub();
},
onShow() {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 4 });
}
store
.ready()
.then(() => {
this.setData({ pet: store.getPet() });
this.loadPosts();
})
.catch((e) => wx.showToast({ title: e.message || '加载失败', icon: 'none' }));
},
loadPosts() {
const tab = this.data.feedTabs[this.data.feedIdx];
this.setData({ loadErr: '' });
api
.listPosts(tab, 1)
.then((page) => this.setData({ posts: (page.list || []).map(mapPost), loaded: true }))
.catch((e) => {
// 不能让「加载失败」显示成「还没有帖子」,那是在骗用户
this.setData({ loadErr: e.message || '加载失败', loaded: true });
toastErr(e);
});
},
// 来自 seg-tabs 的 change 事件
switchFeedTab(e) {
this.setData({ feedIdx: Number(e.detail.index) });
this.loadPosts();
},
likePost(e) {
const i = e.currentTarget.dataset.index;
const post = this.data.posts[i];
api
.likePost(post.id)
.then((res) => {
this.setData({ [`posts[${i}].like_count`]: res.like_count, [`posts[${i}].liked`]: true });
})
.catch((e) => toastErr(e, '点赞失败'));
},
openComments(e) {
this.setData({ sheetPostId: e.currentTarget.dataset.id, sheetType: 'comments', sheetShow: true });
},
openSheet(e) {
this.setData({ sheetType: e.currentTarget.dataset.type, sheetPostId: '', sheetShow: true });
},
closeSheet() {
this.setData({ sheetShow: false });
},
onPosted() {
this.setData({ sheetShow: false });
this.loadPosts();
},
onCommented() {
this.loadPosts();
},
goLearn() {
wx.navigateTo({ url: '/pages/learn/learn' });
},
onFab() {
wx.navigateTo({ url: '/pages/ai/ai' });
},
// 长按自己的帖子可删除
onLongPressPost(e) {
const p = this.data.posts[e.currentTarget.dataset.index];
if (!p || !p.is_self) return;
wx.showModal({
title: '删除帖子',
content: '确定删除这条帖子?删除后其他人将看不到。',
confirmColor: '#D9534F',
success: (res) => {
if (!res.confirm) return;
api.deletePost(p.id)
.then(() => { wx.showToast({ title: '已删除', icon: 'success' }); this.loadPosts(); })
.catch((err) => wx.showToast({ title: err.message || '删除失败', icon: 'none' }));
},
});
},
// 关注 / 取关帖子作者
toggleFollow(e) {
const i = e.currentTarget.dataset.index;
const p = this.data.posts[i];
if (!p || !p.user_id || p.is_self) return;
const fn = p.followed ? api.unfollowUser : api.followUser;
fn(p.user_id)
.then(() => {
// 同一作者的所有帖子一起更新状态
const posts = this.data.posts.map((x) =>
x.user_id === p.user_id ? { ...x, followed: !p.followed } : x,
);
this.setData({ posts });
wx.showToast({ title: p.followed ? '已取消关注' : '已关注', icon: 'none' });
if (this.data.feedTabs[this.data.feedIdx] === '关注') this.loadPosts();
})
.catch((err) => wx.showToast({ title: err.message || '操作失败', icon: 'none' }));
},
onShareAppMessage(e) {
// 从帖子上的分享按钮转发:带上该帖内容做标题
if (e && e.from === 'button') {
const c = (e.target.dataset.content || '').slice(0, 40);
return { title: c ? '宠友圈:' + c : '来宠友圈看看大家的毛孩子', path: '/pages/community/community' };
}
return { title: '宠友圈 · 和铲屎官们交流养宠经验', path: '/pages/community/community' };
},
onShareTimeline() {
return { title: '宠友圈 · 和铲屎官们交流养宠经验' };
},
});