Support personal records and persistent smoking visibility. Add upload quota preflight, file cleanup, privacy entry, image caching and revision-based page refresh across the backend, admin and mini program.
283 lines
11 KiB
JavaScript
283 lines
11 KiB
JavaScript
const { tryLoginRenewal } = require('../../utils/subscribe');
|
|
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({
|
|
onLoginSubscribeTap: function() { return tryLoginRenewal(); },
|
|
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: String(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, {avatar_url:getImageUrl(comment.avatar_url || comment.avatar || ''),_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 || {};
|
|
newComment.avatar_url = getImageUrl(newComment.avatar_url || newComment.avatar || "");
|
|
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"]}));
|