Files
2026-10-26 17:32:47 +08:00

280 lines
11 KiB
JavaScript

const { itemsOf, totalOf, mergeUnique } = require('../../utils/list-pagination');
const { withDataCache } = require('../../utils/page-cache');
const { getLayout } = require('../../utils/layout');
const { api, getImageUrl } = require('../../utils/request');
Page(withDataCache({
noop: function() {},
onResize: function() { this.setData(getLayout()); },
data: { loadError: false,
diary: null,
loading: true,
comments: [],
commentPage: 1, commentsLoadingMore: false, commentsMoreError: false, commentsTotal: 0,
hasMoreComments: true,
showCommentInput: false,
commentText: '',
commentInitialText: '',
commentLength: 0,
commentFocus: false,
commentKeyboardHeight: 0,
commentEditorHeight: 56,
commentSending: false,
replyTo: null,
coverSwiperIndex: 0,
previewImages: [],
previewIndex: 0,
showPreview: false,
myUid: 0
},
onLoad: function(options) {
this.setData(getLayout());
var diaryId = options.id;
if (!diaryId) { wx.showToast({ title: '参数错误', icon: 'none' }); return; }
this.setData({ diaryId: parseInt(diaryId), myUid: wx.getStorageSync('userId') || 0 });
this.loadDiary();
this.loadComments();
},
onShow: function() {
if (this.data.diaryId) { this.loadDiary(); this.loadComments(); }
},
loadDiary: async function() {
if (this._pageLoading) return;
this._pageLoading = true;
this.setData({loading: !this._hasCachedData, loadError:false});
try {
var data = await api.diaryDetail(this.data.diaryId);
data = this._formatDiary(data);
this.setData({ diary: data, myUid: wx.getStorageSync('userId') || 0, loading: false });
} catch (e) {
this.setData({loadError:true});
wx.showToast({ title: '加载失败', icon: 'none' });
this.setData({ loading: false });
}
finally { this._pageLoading = false; this.setData({loading:false}); }
},
_formatDiary: function(data) {
var myUid = wx.getStorageSync('userId') || 0;
data.creator_name = data.creator_name || (data.created_by == myUid ? '我' : 'TA');
data.creator_avatar = getImageUrl(data.creator_avatar);
data.created_time = data.created_at ? data.created_at.substring(0, 16).replace('T', ' ') : '';
var imgs = data.images || [];
if (typeof imgs === 'string') {
try { imgs = JSON.parse(imgs); } catch(e) { imgs = []; }
}
if (!Array.isArray(imgs)) imgs = [];
data.imageUrls = imgs.map(function(p) { return getImageUrl(p); });
data.comment_count = data.comment_count || 0;
// 地理位置:优先显示地址名称,其次显示经纬度(经纬度为0的不显示)
data.location_text = '';
var hasCoord = data.lat && data.lng && parseFloat(data.lat) !== 0 && parseFloat(data.lng) !== 0;
if (data.location) {
data.location_text = data.location;
} else if (hasCoord) {
data.location_text = data.lat + ', ' + data.lng;
}
return data;
},
loadComments: function() { return this._loadCommentsPage(1); },
_loadCommentsPage: async function(page) {
page = Number(page) || 1;
if (this._commentsFirst || (page > 1 && (this.data.commentsLoadingMore || !this.data.hasMoreComments))) return;
if (page === 1) { this._commentsFirst = true; this._commentsGeneration = (this._commentsGeneration || 0) + 1; }
var generation = this._commentsGeneration;
this.setData(page === 1 ? {commentsError:false,commentsMoreError:false,commentsLoadingMore:false} : {commentsLoadingMore:true,commentsMoreError:false});
try {
var result = await api.diaryCommentList({diary_id:this.data.diaryId,page:page,page_size:20});
if (generation !== this._commentsGeneration) return;
var added = itemsOf(result).map(function(comment) {
return Object.assign({}, comment, {_time:String(comment.created_at || comment.create_time || '').slice(0,16).replace('T',' ')});
});
this.setData({comments:page===1?added:mergeUnique(this.data.comments,added),commentPage:page,commentsTotal:totalOf(result),hasMoreComments:!Array.isArray(result)&&(result.has_more != null?!!result.has_more:page*20<totalOf(result))});
} catch(e) {
if (generation === this._commentsGeneration) this.setData(page===1?{commentsError:true}:{commentsMoreError:true});
} finally {
if (generation === this._commentsGeneration) { this._commentsFirst=false;this.setData({commentsLoadingMore:false}); }
}
},
loadMoreComments: function() { return this._loadCommentsPage(this.data.commentPage+1); },
onShareTap: function() {
wx.showActionSheet({
itemList: ['分享给微信好友', '分享到朋友圈', '生成分享海报'],
success: function(res) {
if (res.tapIndex === 0) {
wx.shareAppMessage ? wx.shareAppMessage() : wx.showToast({ title: '请点击右上角分享', icon: 'none' });
} else if (res.tapIndex === 1) {
wx.showToast({ title: '请点击右上角分享到朋友圈', icon: 'none' });
} else {
wx.showToast({ title: '功能开发中', icon: 'none' });
}
}
});
},
onCoverSwiperChange: function(e) {
this.setData({ coverSwiperIndex: e.detail.current });
},
onImageTap: function(e) {
var idx = this.data.coverSwiperIndex;
var imgs = this.data.diary.imageUrls || [];
this.setData({ showPreview: true, previewIndex: idx, previewImages: imgs });
},
closePreview: function() { this.setData({ showPreview: false }); },
onPreviewSwiperChange: function(e) { this.setData({ previewIndex: e.detail.current }); },
onCommentTap: function() {
this.openComment(null);
},
onReplyTap: function(e) {
var item = e.currentTarget.dataset.item;
this.openComment({ id: item.id, user_id: item.user_id, nickname: item.nickname });
},
openComment: function(replyTo) {
var sameTarget = (!replyTo && !this.data.replyTo) ||
(replyTo && this.data.replyTo && replyTo.id === this.data.replyTo.id);
var text = sameTarget ? this.data.commentText : '';
this.setData({ showCommentInput: true, replyTo: replyTo, commentText: text,
commentInitialText: text, commentLength: text.length, commentFocus: true,
commentKeyboardHeight: 0, commentEditorHeight: 56 });
},
onCommentInput: function(e) {
// 不把正文反复写回原生输入框,避免中文输入时光标跳动。
this.data.commentText = e.detail.value || '';
this.setData({ commentLength: this.data.commentText.length });
},
onCommentKeyboardHeight: function(e) {
var height = Math.max(0, Number(e.detail.height) || 0);
if (this.data.showCommentInput) this.setData({ commentKeyboardHeight: height });
},
onCommentLineChange: function(e) {
this.setData({ commentEditorHeight: Math.min(160, Math.max(56, Number(e.detail.height) || 56)) });
},
onCommentBlur: function() {
this.setData({ commentFocus: false });
},
cancelComment: function() {
if (this.data.commentSending) return;
this.setData({ showCommentInput: false, commentFocus: false, commentKeyboardHeight: 0 });
wx.hideKeyboard();
},
onHide: function() {
this.setData({ showCommentInput: false, commentFocus: false, commentKeyboardHeight: 0 });
},
submitComment: async function() {
if (this.data.commentSending) return;
var text = this.data.commentText.trim();
if (!text) { wx.showToast({ title: '请输入评论内容', icon: 'none' }); return; }
this.setData({ commentSending: true });
try {
var params = { diary_id: this.data.diaryId, content: text };
if (this.data.replyTo) {
params.parent_id = this.data.replyTo.id;
params.reply_to_user_id = this.data.replyTo.user_id;
params.reply_to_username = this.data.replyTo.nickname;
}
var res = await api.diaryCommentAdd(params);
if (res.success) {
this._commentsGeneration = (this._commentsGeneration || 0) + 1;
this._commentsFirst = false;
this.setData({commentsLoadingMore:false});
var newComment = res.comment || {};
if (newComment.created_at) {
newComment._time = newComment.created_at.substring(0, 16).replace('T', ' ');
} else if (newComment.create_time) {
newComment._time = newComment.create_time.substring(0, 16).replace('T', ' ');
} else {
var now = new Date();
newComment._time = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0') + '-' + String(now.getDate()).padStart(2,'0') + ' ' + String(now.getHours()).padStart(2,'0') + ':' + String(now.getMinutes()).padStart(2,'0');
}
var newComments = this.data.comments.slice();
newComments.unshift(newComment);
this.setData({
comments: newComments,
commentsTotal: this.data.commentsTotal + 1,
showCommentInput: false,
replyTo: null,
commentText: '',
commentInitialText: '',
commentLength: 0,
commentFocus: false,
commentKeyboardHeight: 0,
'diary.comment_count': (this.data.diary.comment_count || 0) + 1
});
wx.hideKeyboard();
wx.showToast({ title: '评论成功', icon: 'success' });
}
} catch (e) {
wx.showToast({ title: e.error || '评论失败', icon: 'none' });
} finally {
this.setData({ commentSending: false });
}
},
onCommentLongPress: function(e) {
var item = e.currentTarget.dataset.item;
if (item.user_id != this.data.myUid) return;
var self = this;
wx.showModal({
title: '删除评论',
content: '确定要删除这条评论吗?',
success: async function(res) {
if (res.confirm) {
try {
await api.diaryCommentDelete({ id: item.id });
var list = self.data.comments.filter(function(c) { return c.id != item.id; });
self.setData({
comments: list,
'diary.comment_count': Math.max(0, (self.data.diary.comment_count || 0) - 1)
});
wx.showToast({ title: '已删除', icon: 'success' });
} catch (e) { wx.showToast({ title: '删除失败', icon: 'none' }); }
}
}
});
},
onMoreTap: function() {
var self = this;
wx.showActionSheet({
itemList: ['编辑', '删除'],
success: function(res) {
if (res.tapIndex === 0) {
wx.navigateTo({ url: '/pages/diary_edit/diary_edit?id=' + self.data.diaryId });
} else if (res.tapIndex === 1) {
self._deleteDiary();
}
}
});
},
_deleteDiary: function() {
var self = this;
wx.showModal({
title: '删除日记',
content: '确定要删除这篇日记吗?',
success: async function(res) {
if (res.confirm) {
try {
await api.diaryDelete({ id: self.data.diaryId });
wx.showToast({ title: '已删除', icon: 'success' });
setTimeout(function() { wx.navigateBack(); }, 1500);
} catch (e) {
wx.showToast({ title: e.error || '删除失败', icon: 'none' });
}
}
}
});
},
goBack: function() { wx.navigateBack(); },
goHome: function() { wx.switchTab({ url: '/pages/index/index' }); }
}, {"loadDiary": ["diaryDetail"], "loadComments": ["diaryCommentList"]}));