const { del, get, post } = require("../../utils/api"); const { showError } = require("../../utils/page-helpers"); function initialOf(name) { return String(name || "班").slice(0, 1); } function formatTime(value) { return String(value || "").replace("T", " ").slice(0, 16); } function sameId(left, right) { return Number(left) === Number(right); } function datasetBoolean(value) { return value === true || value === "true" || value === 1 || value === "1"; } function normalizePost(post, currentUserId = null) { if (!post) return null; const comments = Array.isArray(post.comments) ? post.comments : []; return { ...post, author_initial: initialOf(post.author_name), created_at_text: formatTime(post.created_at), like_action_text: post.has_liked ? "已赞" : "赞", like_action_class: post.has_liked ? "active" : "", comments: comments.map((comment) => ({ ...comment, created_at_text: formatTime(comment.created_at), can_delete: sameId(currentUserId, comment.author_id) })) }; } Page({ data: { id: null, post: null, canDelete: false, commentText: "", replyToName: "", inputPlaceholder: "写评论", inputFocus: false, keyboardOpen: false, loading: false, submitting: false }, onLoad(options) { wx.setNavigationBarTitle({ title: "班级圈" }); this.setData({ id: options.id }); this.load(); }, async onPullDownRefresh() { await this.load(); wx.stopPullDownRefresh(); }, async load() { if (!this.data.id) return; this.setData({ loading: true }); try { const postDetail = await get(`/api/timeline/${this.data.id}`); const currentUser = getApp().globalData.user || wx.getStorageSync("auth_user") || {}; this.setData({ post: normalizePost(postDetail, currentUser.id), canDelete: postDetail.author_id === currentUser.id }); } catch (error) { showError(error, "加载动态失败"); } finally { this.setData({ loading: false }); } }, async toggleLike() { if (!this.data.id || this.data.submitting) return; this.setData({ submitting: true }); try { const result = await post(`/api/timeline/${this.data.id}/like`); this.setData({ post: normalizePost({ ...this.data.post, has_liked: Boolean(result.liked), like_count: Number(result.like_count || 0) }, (getApp().globalData.user || wx.getStorageSync("auth_user") || {}).id) }); } catch (error) { showError(error, "操作失败"); } finally { this.setData({ submitting: false }); } }, onCommentInput(event) { this.setData({ commentText: event.detail.value }); }, onCommentFocus(event) { const height = event.detail.height || 0; this.setData({ keyboardOpen: height > 0, inputFocus: true }); }, onKeyboardHeightChange(event) { const height = event.detail.height || 0; this.setData({ keyboardOpen: height > 0 }); }, onCommentBlur() { this.setData({ keyboardOpen: false, inputFocus: false }); }, previewImage(event) { const current = event.currentTarget.dataset.src; const urls = this.data.post && this.data.post.image_urls ? this.data.post.image_urls : []; if (!current || !urls.length) return; wx.previewImage({ current, urls }); }, openActions() { wx.showActionSheet({ itemList: ["删除动态"], itemColor: "#b42318", success: () => { wx.showModal({ title: "删除动态", content: "删除后无法恢复,确认删除这条动态?", confirmText: "删除", confirmColor: "#b42318", success: async (res) => { if (!res.confirm) return; try { await del(`/api/timeline/${this.data.id}`); wx.showToast({ title: "已删除", icon: "success" }); const pages = getCurrentPages(); const previousPage = pages[pages.length - 2]; if (previousPage && previousPage.load) previousPage.load(); setTimeout(() => wx.navigateBack(), 500); } catch (error) { showError(error, "删除失败"); } } }); } }); }, openComment() { const post = this.data.post; this.setData({ replyToName: "", inputPlaceholder: post ? `评论 ${post.author_name}` : "写评论", inputFocus: false }, () => { this.focusCommentInput(); }); }, replyComment(event) { const commentId = Number(event.currentTarget.dataset.commentId); const name = event.currentTarget.dataset.name || ""; const canDelete = datasetBoolean(event.currentTarget.dataset.canDelete); if (canDelete && commentId) { this.openOwnCommentActions(commentId, name); return; } this.startReply(name); }, startReply(name) { this.setData({ replyToName: name, inputPlaceholder: name ? `回复 ${name}` : "写评论", inputFocus: false }, () => { this.focusCommentInput(); }); }, cancelReply() { this.setData({ replyToName: "", inputPlaceholder: "写评论", inputFocus: false, keyboardOpen: false }); }, focusCommentInput() { const focus = () => { if (this.data.post) { this.setData({ inputFocus: true }); } }; if (wx.nextTick) { wx.nextTick(() => setTimeout(focus, 120)); return; } setTimeout(focus, 120); }, async submitComment() { const text = this.data.commentText.trim(); if (!text) { wx.showToast({ title: "请输入评论", icon: "none" }); return; } const content = this.data.replyToName ? `回复 @${this.data.replyToName}:${text}` : text; this.setData({ submitting: true }); try { await post(`/api/timeline/${this.data.id}/comments`, { content }); this.setData({ commentText: "", replyToName: "", inputPlaceholder: "写评论", inputFocus: false, keyboardOpen: false }); await this.load(); } catch (error) { showError(error, "评论失败"); } finally { this.setData({ submitting: false }); } }, deleteComment(commentId) { wx.showModal({ title: "删除评论", content: "确认删除这条评论?", confirmText: "删除", confirmColor: "#b42318", success: async (res) => { if (!res.confirm) return; try { await del(`/api/timeline/comments/${commentId}`); await this.load(); wx.showToast({ title: "已删除", icon: "success" }); } catch (error) { showError(error, "删除失败"); } } }); }, openOwnCommentActions(commentId, name) { wx.showActionSheet({ itemList: ["回复", "删除评论"], itemColor: "#6b1f2b", success: (res) => { if (res.tapIndex === 0) { this.startReply(name); } if (res.tapIndex === 1) { this.deleteComment(commentId); } } }); } });