diff --git a/README.md b/README.md index b65cc60..794f0f0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,22 @@ [更新信息] -2025.8.8 小程序实现页面跳转和首页的基本框架 + +-2025.10.8 小程序实现对话框回复 【2.10.5】 + + +-2025.10.8 剩余需求列表 +· 用户评论发布功能 +· 评论回复功能 +· 文评发布功能 +· 用户[我的发布]查看功能 +· 用户消息通知查看功能 +· 设置中用户信息修改功能 +· 修改oss地址,取消过度使用 +· 意见反馈功能 +---------------------- +· 帮助中心[暂删除] +· 每日签到[暂删除] +· 抽奖券功能[暂删除] +· 内推吗发布功能[暂删除] + + diff --git a/miniprogram/pages/articledetail/articledetail.ts b/miniprogram/pages/articledetail/articledetail.ts index c170ad9..4ff6396 100644 --- a/miniprogram/pages/articledetail/articledetail.ts +++ b/miniprogram/pages/articledetail/articledetail.ts @@ -25,9 +25,14 @@ Component({ error: null as string | null, totalCommentsCount: 0, // *** 新增:存储所有评论的总数 (包括回复) *** cardReviewData: null as any | null, - showReplyInput: false, - currentReplyId: '', - replyContent: '', + + + + showReplyInput: false, // 控制输入框是否显示 + currentReplyId: '', // 当前正在回复的评论ID + currentReplyUsername: '', // 当前正在回复的用户名(用于 placeholder) + replyContent: '', // 输入框中的内容 + isSubmitDisabled: true, @@ -50,6 +55,165 @@ Component({ }, methods: { + closeInput() { + if (this.data.showReplyInput) { + this.setData({ + showReplyInput: false, + currentReplyId: null, + currentReplyUsername: '', + replyContent: '', + isSubmitDisabled: true, + keyboardHeight: 0 + }); + } + }, + + /** + * 页面滚动时,调用关闭函数 + */ + onPageScroll() { + this.closeInput(); + }, + + /** + * 点击“空白”区域(现在是整个 scroll-view)时,调用关闭函数 + */ + handleBlankTap() { + console.log("scroll-view 区域被点击,准备关闭输入框"); + this.closeInput(); + }, + + /** + * ✅ 核心修改:处理点击评论项的逻辑 + */ + handleCommentTap(e: WechatMiniprogram.TouchEvent) { + const wasShowing = this.data.showReplyInput; + const tappedCommentId = e.currentTarget.dataset.item?.id; + + // 步骤 1: 立刻关闭当前可能已打开的输入框 + this.closeInput(); + + // 步骤 2: 使用延时来重新打开输入框 + // 这是一个技巧,确保关闭操作完成后再执行打开操作,避免冲突 + setTimeout(() => { + const commentData = e.currentTarget.dataset.item; + if (commentData) { + // 如果刚刚输入框是开着的,并且点的是同一个评论,那么我们其实是想关闭它,而不是重新打开 + if (wasShowing && this.data.currentReplyId === tappedCommentId) { + return; + } + this.setData({ + showReplyInput: true, + currentReplyId: commentData.id, + currentReplyUsername: commentData.username || '匿名用户', + replyContent: '', + isSubmitDisabled: true, + }); + } + }, 50); // 50毫秒的延时足够 + }, + + /** + * ✅ 核心修改:处理点击主评论入口的逻辑 + */ + handleTapPrimaryCommentInput() { + // 同样,先关闭 + this.closeInput(); + + // 延时后打开 + setTimeout(() => { + this.setData({ + showReplyInput: true, + currentReplyId: null, + currentReplyUsername: '', + }); + }, 50); + }, + + /** + * ✅ 修改:提交时智能判断是“回复”还是“新评论” + */ + handleReplySubmit() { + if (this.data.isSubmitDisabled) return; + + const { replyContent, currentReplyId, cardReviewData } = this.data; + const articleId = cardReviewData.article_id; + + // 根据 currentReplyId 是否有值来判断 + if (currentReplyId) { + // --- 这是回复 --- + console.log(`[提交回复] 内容: "${replyContent}" | 回复目标ID: ${currentReplyId} | 文章ID: ${articleId}`); + // 在此处对接您的【回复】API + // wx.request({ url: ..., data: { content: replyContent, parent_id: currentReplyId, article_id: articleId } }) + } else { + // --- 这是新的一级评论 --- + console.log(`[提交新评论] 内容: "${replyContent}" | 文章ID: ${articleId}`); + // 在此处对接您的【发表新评论】API + // wx.request({ url: ..., data: { content: replyContent, article_id: articleId } }) + } + + wx.showToast({ title: '评论成功(模拟)', icon: 'success' }); + + // 提交后清空并隐藏输入框 + this.setData({ + showReplyInput: false, + currentReplyId: null, + currentReplyUsername: '', + replyContent: '', + isSubmitDisabled: true + }); + + // (可选) 成功后可以延时刷新评论列表 + // setTimeout(() => { + // this.getCardDetail(this.properties.id); + // }, 1000); + }, + + + /** + * 实时同步输入框内容 + */ + + noop() { + return; + }, + + /** + * 输入框失去焦点 + */ + handleInputBlur() { + // 目前主要靠 handleBlankTap 和 handleReplySubmit 隐藏,此函数可留空 + }, + + /** + * 提交回复 + */ + handleReplySubmit() { + const { replyContent, currentReplyId } = this.data; + if (!replyContent.trim()) { + wx.showToast({ title: '回复内容不能为空', icon: 'none' }); + return; + } + + console.log(`[准备发送] 回复内容: "${replyContent}" | 回复目标评论ID: ${currentReplyId}`); + + // --- 在此处对接您的后端API,发送回复请求 --- + // wx.request({ ... }); + + wx.showToast({ title: '回复成功(模拟)', icon: 'success' }); + + this.setData({ + showReplyInput: false, + currentReplyId: '', + currentReplyUsername: '', + replyContent: '' + }); + }, + + + + + onShareAppMessage: function (res) { // 1. 获取文评数据,添加容错(避免数据为空导致报错) const { cardReviewData = {} } = this.data; @@ -104,7 +268,6 @@ Component({ getCardDetail(id: string) { console.log("正在加载文章ID:", id); - // 1. 验证和转换 ID const articleId = parseInt(id, 10); if (isNaN(articleId) || articleId <= 0) { this.setData({ @@ -114,29 +277,32 @@ Component({ return; } + // 开始加载,重置状态 this.setData({ loading: true, error: null }); - - // 2. 调用获取评论的方法 + this.getComments(articleId) .then(commentsData => { - console.log("获取到commentsData:",commentsData) + // --- ✅ 核心修复逻辑在这里 --- + // 无论 commentsData 是有内容的数组还是空数组,都是成功状态 + + console.log("获取到 commentsData:", commentsData); - // *** 核心修改:计算总评论数 *** const totalCount = this.calculateTotalComments(commentsData); - console.log(`文章ID ${articleId} 评论获取成功,总评论数: ${totalCount}`); this.setData({ - comments: commentsData, // 存储树形结构的数据 - totalCommentsCount: totalCount, // 存储总数 + comments: commentsData || [], // 确保 comments 是一个数组 + totalCommentsCount: totalCount, loading: false, + error: null // 确保成功时,error 状态被清空 }); - console.log(this.data.comments[0]) }) .catch(error => { - console.error(`获取评论失败: ${error.message}`); + // 只有当 getComments promise被 reject (即网络或服务器真出错了) 才会进入这里 + console.error(`获取评论失败123: ${error.message}`); this.setData({ loading: false, + // 这里只显示真实的错误信息 error: error.message || "获取评论失败,请检查网络" }); }); @@ -151,15 +317,25 @@ Component({ articleId: articleId }, success: (res) => { + console.log('[getComments] 收到服务器原始响应:', res.data); const response = res.data as CommentResponse; - if (response.success && Array.isArray(response.data)) { - resolve(response.data as Comment[]); + // ✅ 核心修复 1: 同时接受 data 为数组 或 data 为 null 的情况 + if (response.success && (Array.isArray(response.data) || response.data === null)) { + console.log('[getComments] 数据校验成功, resolve 数据'); + + // ✅ 核心修复 2: 如果 data 是 null,我们将其视为空数组 [] 返回 + // 这样可以保证后续的 .then 代码接收到的永远是一个数组 + resolve(response.data || []); + } else { - reject(new Error(response.message || "服务器返回数据异常")); + // 只有当服务器明确告知失败, 或数据格式不对时, 才 reject + console.error('[getComments] 服务器返回数据异常, reject 错误'); + reject(new Error(response.message || "服务器返回数据格式不正确")); } }, fail: (err) => { + console.error('[getComments] 网络请求失败, reject 错误:', err); reject(new Error("网络请求失败,请检查连接")); } }); diff --git a/miniprogram/pages/articledetail/articledetail.wxml b/miniprogram/pages/articledetail/articledetail.wxml index 75517cd..dc934da 100644 --- a/miniprogram/pages/articledetail/articledetail.wxml +++ b/miniprogram/pages/articledetail/articledetail.wxml @@ -1,11 +1,13 @@ - - - + + - - - + - {{cardReviewData.user_has_voted ? '已投票' : (cardReviewData.is_ended ? '已结束' : '进行中')}} - - - + {{cardReviewData.article_title}} • 您已投票 @@ -36,21 +35,18 @@ {{cardReviewData.article_desc || ''}} - - {{(cardReviewData.user_has_voted && option.is_voted) ? '✓' : (option.isSelected ? '✓' : '○')}} - {{option.name}} @@ -60,18 +56,14 @@ - AI - {{option.percentage || 0}}% - - @@ -79,20 +71,18 @@ - - + 已有 {{cardReviewData.total_voters || 0}} 人参与投票 {{cardReviewData.is_ended ? '已结束' : '截止至 ' + (cardReviewData.end_time || '0天')}} - + class="share-btn" + open-type="share" + > + + - 暂无投票数据 投票数据加载中... 加载失败:{{error}} - - - + + + 快来写下你的评论吧~ + + - 共 {{totalCommentsCount}} 条评论 - -