修复动态发布与互动问题
This commit is contained in:
@@ -29,63 +29,116 @@ function formatTimeText(ts) {
|
||||
return `${d.getMonth() + 1}月${d.getDate()}日`
|
||||
}
|
||||
|
||||
function isCloudFileId(value) {
|
||||
return typeof value === 'string' && value.startsWith('cloud://')
|
||||
}
|
||||
|
||||
function extractMediaUrl(media) {
|
||||
if (!media) return ''
|
||||
if (typeof media === 'string') return media
|
||||
return media.url || media.fileId || media.fileID || ''
|
||||
}
|
||||
|
||||
async function resolveTempUrlMap(urls) {
|
||||
const fileIds = [...new Set(urls.filter(isCloudFileId))]
|
||||
if (!fileIds.length) return new Map()
|
||||
|
||||
try {
|
||||
const result = await cloud.getTempFileURL({ fileList: fileIds })
|
||||
const fileList = Array.isArray(result.fileList) ? result.fileList : []
|
||||
return new Map(fileList.map(file => [
|
||||
file.fileID || file.fileId,
|
||||
file.tempFileURL || file.tempFileUrl || ''
|
||||
]).filter(([fileId, tempUrl]) => fileId && tempUrl))
|
||||
} catch (e) {
|
||||
return new Map()
|
||||
}
|
||||
}
|
||||
|
||||
function readableUrl(url, tempUrlMap) {
|
||||
if (!url) return ''
|
||||
if (!isCloudFileId(url)) return url
|
||||
return tempUrlMap.get(url) || ''
|
||||
}
|
||||
|
||||
exports.main = async event => {
|
||||
const { OPENID } = cloud.getWXContext()
|
||||
const postId = String(event.postId || '').trim()
|
||||
if (!postId) throw new Error('postId is required')
|
||||
const commentPageSize = Math.max(1, Math.min(Number(event.commentPageSize || 50), 100))
|
||||
|
||||
const postRes = await db.collection('posts').doc(postId).get().catch(() => null)
|
||||
if (!postRes || !postRes.data) return { post: null, comments: [] }
|
||||
const post = postRes.data
|
||||
|
||||
// Resolve the author's current profile (fresh avatar), liked/favorited state.
|
||||
// Resolve the author's current profile (fresh avatar) and liked state.
|
||||
let author = null
|
||||
if (post.authorId) {
|
||||
const authorRes = await safeGet('users', { _id: post.authorId }, 1)
|
||||
author = authorRes.data[0] || null
|
||||
}
|
||||
if (!author && post.authorOpenid) {
|
||||
const authorRes = await safeGet('users', { openid: post.authorOpenid }, 1)
|
||||
author = authorRes.data[0] || null
|
||||
}
|
||||
|
||||
let likedByMe = false
|
||||
let favoritedByMe = false
|
||||
if (OPENID) {
|
||||
const [likedRes, favRes] = await Promise.all([
|
||||
safeGet('postLikes', { openid: OPENID, postId }, 1),
|
||||
safeGet('postFavorites', { openid: OPENID, postId }, 1)
|
||||
])
|
||||
const likedRes = await safeGet('postLikes', { openid: OPENID, postId }, 1)
|
||||
likedByMe = likedRes.data.length > 0
|
||||
favoritedByMe = favRes.data.length > 0
|
||||
}
|
||||
|
||||
const postAssetUrls = [
|
||||
(author && author.avatarUrl) || post.authorSnapshot?.avatarUrl || '',
|
||||
...(Array.isArray(post.media) ? post.media.map(extractMediaUrl) : [])
|
||||
]
|
||||
const postTempUrlMap = await resolveTempUrlMap(postAssetUrls)
|
||||
const postMedia = Array.isArray(post.media)
|
||||
? post.media
|
||||
.map(extractMediaUrl)
|
||||
.map(url => readableUrl(url, postTempUrlMap))
|
||||
.filter(Boolean)
|
||||
: []
|
||||
|
||||
const mappedPost = {
|
||||
_id: post._id,
|
||||
author: {
|
||||
id: post.authorId || '',
|
||||
id: (author && author._id) || post.authorId || '',
|
||||
name: (author && author.nickname) || post.authorSnapshot?.name || '用户',
|
||||
avatarKey: (author && author.avatarKey) || post.authorSnapshot?.avatarKey || 'gradient-avatar-1',
|
||||
avatarUrl: (author && author.avatarUrl) || post.authorSnapshot?.avatarUrl || ''
|
||||
avatarUrl: readableUrl((author && author.avatarUrl) || post.authorSnapshot?.avatarUrl || '', postTempUrlMap)
|
||||
},
|
||||
pet: post.petSnapshot || { name: '', breed: '' },
|
||||
body: post.content || '',
|
||||
topics: post.topics || [],
|
||||
media: Array.isArray(post.media)
|
||||
? post.media.map(m => (typeof m === 'string' ? m : m && (m.url || m.fileId))).filter(Boolean)
|
||||
: [],
|
||||
media: postMedia,
|
||||
mediaTone: post.mediaTone || 'pet-1',
|
||||
sticker: post.sticker || undefined,
|
||||
locationText: post.locationText || '',
|
||||
timeText: formatTimeText(post.createdAt || Date.now()),
|
||||
counts: {
|
||||
likes: post.counts?.likes || 0,
|
||||
comments: post.counts?.comments || 0,
|
||||
favorites: post.counts?.favorites || 0
|
||||
comments: post.counts?.comments || 0
|
||||
},
|
||||
likedByMe,
|
||||
favoritedByMe
|
||||
likedByMe
|
||||
}
|
||||
|
||||
// Comments, oldest first. Resolve each author's current profile for avatars.
|
||||
const commentsRes = await safeGet('comments', { postId }, 200, { field: 'createdAt', direction: 'asc' })
|
||||
const commentAuthorIds = [...new Set(commentsRes.data.map(c => c.authorId).filter(Boolean))]
|
||||
const commentWhere = { postId }
|
||||
const commentCursor = Number(event.commentCursor || 0)
|
||||
if (Number.isFinite(commentCursor) && commentCursor > 0) commentWhere.createdAt = _.gt(commentCursor)
|
||||
const commentsRes = await safeGet(
|
||||
'comments',
|
||||
commentWhere,
|
||||
commentPageSize + 1,
|
||||
{ field: 'createdAt', direction: 'asc' }
|
||||
)
|
||||
const commentPage = commentsRes.data.slice(0, commentPageSize)
|
||||
const commentsNextCursor = commentsRes.data.length > commentPageSize && commentPage[commentPage.length - 1]
|
||||
? String(commentPage[commentPage.length - 1].createdAt || '')
|
||||
: ''
|
||||
|
||||
const commentAuthorIds = [...new Set(commentPage.map(c => c.authorId).filter(Boolean))]
|
||||
const authorMap = new Map()
|
||||
for (let i = 0; i < commentAuthorIds.length; i += 100) {
|
||||
const chunk = commentAuthorIds.slice(i, i + 100)
|
||||
@@ -93,20 +146,34 @@ exports.main = async event => {
|
||||
usersRes.data.forEach(u => authorMap.set(u._id, u))
|
||||
}
|
||||
|
||||
const comments = commentsRes.data.map(c => {
|
||||
const u = authorMap.get(c.authorId)
|
||||
const commentAuthorOpenids = [...new Set(commentPage.map(c => c.openid).filter(Boolean))]
|
||||
const authorOpenidMap = new Map()
|
||||
for (let i = 0; i < commentAuthorOpenids.length; i += 100) {
|
||||
const chunk = commentAuthorOpenids.slice(i, i + 100)
|
||||
const usersRes = await safeGet('users', { openid: _.in(chunk) }, 100)
|
||||
usersRes.data.forEach(u => authorOpenidMap.set(u.openid, u))
|
||||
}
|
||||
const findCommentAuthor = comment => authorMap.get(comment.authorId) || authorOpenidMap.get(comment.openid)
|
||||
|
||||
const commentTempUrlMap = await resolveTempUrlMap(commentPage.map(c => {
|
||||
const u = findCommentAuthor(c)
|
||||
return (u && u.avatarUrl) || c.authorSnapshot?.avatarUrl || ''
|
||||
}))
|
||||
|
||||
const comments = commentPage.map(c => {
|
||||
const u = findCommentAuthor(c)
|
||||
return {
|
||||
_id: c._id,
|
||||
author: {
|
||||
id: c.authorId || '',
|
||||
id: (u && u._id) || c.authorId || '',
|
||||
name: (u && u.nickname) || c.authorSnapshot?.name || '用户',
|
||||
avatarKey: (u && u.avatarKey) || c.authorSnapshot?.avatarKey || 'gradient-avatar-1',
|
||||
avatarUrl: (u && u.avatarUrl) || c.authorSnapshot?.avatarUrl || ''
|
||||
avatarUrl: readableUrl((u && u.avatarUrl) || c.authorSnapshot?.avatarUrl || '', commentTempUrlMap)
|
||||
},
|
||||
content: c.content || '',
|
||||
timeText: formatTimeText(c.createdAt || Date.now())
|
||||
}
|
||||
})
|
||||
|
||||
return { post: mappedPost, comments }
|
||||
return { post: mappedPost, comments, commentsNextCursor }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user