hku-class/miniprogram/pages/timeline-detail/index.js
2026-05-16 23:59:13 +08:00

270 lines
7.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
});
}
});