Explorar o código

屏蔽小程序文章评论及AI问答功能

Xiaogang Liao hai 1 mes
pai
achega
66e3062d6f

+ 3 - 103
cfc-frontend/components/AIFloatingAvatar.vue

@@ -1,109 +1,9 @@
 <template>
-  <view class="ai-float-wrapper" @click="goToChat">
-    <view class="ai-float-avatar" :class="mascotCode">
-      <text class="ai-float-icon">{{ mascotIcon }}</text>
-    </view>
-  </view>
+  <!-- AI问答功能已屏蔽 -->
 </template>
 
 <script>
 export default {
-  name: 'AIFloatingAvatar',
-  data() {
-    return {
-      mascotCode: 'xibao',
-      mascotIcon: '🌟'
-    }
-  },
-  mounted() {
-    this.loadMascot()
-  },
-  methods: {
-    loadMascot() {
-      var userInfo = uni.getStorageSync('userInfo')
-      if (userInfo && userInfo.mascot) {
-        if (userInfo.mascot === 'xibao') {
-          this.mascotCode = 'xibao'
-          this.mascotIcon = '🌟'
-        } else if (userInfo.mascot === 'fubao') {
-          this.mascotCode = 'fubao'
-          this.mascotIcon = '💪'
-        }
-      } else {
-        // 默认浠宝
-        this.mascotCode = 'xibao'
-        this.mascotIcon = '🌟'
-      }
-    },
-    goToChat() {
-      // 获取当前页面路径作为来源标识
-      var pages = getCurrentPages()
-      var currentPage = pages[pages.length - 1]
-      var fromPage = ''
-      if (currentPage) {
-        fromPage = currentPage.route || ''
-      }
-      var url = '/pages/ai/chat?fromPage=' + encodeURIComponent(fromPage)
-      // 健康维度页面(身/智/心)自动切换为健康教练模式
-      if (fromPage === 'pages/body/index' || fromPage === 'pages/wisdom/index' || fromPage === 'pages/mind/index') {
-        url += '&mode=health'
-      }
-      uni.navigateTo({ url: url })
-    }
-  }
+  name: 'AIFloatingAvatar'
 }
-</script>
-
-<style scoped>
-.ai-float-wrapper {
-  position: fixed;
-  right: 32rpx;
-  bottom: calc(160rpx + constant(safe-area-inset-bottom));
-  bottom: calc(160rpx + env(safe-area-inset-bottom));
-  z-index: 999;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 112rpx;
-  height: 112rpx;
-}
-
-.ai-float-avatar {
-  width: 96rpx;
-  height: 96rpx;
-  border-radius: 50%;
-  background: #fff;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.15), 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
-  animation: floatBounce 3s ease-in-out infinite;
-  position: relative;
-  z-index: 2;
-  transition: transform 0.2s;
-}
-
-.ai-float-avatar:active {
-  transform: scale(0.92);
-}
-
-.ai-float-avatar.xibao {
-  background: linear-gradient(135deg, #FFF7ED 0%, #FFE4CC 100%);
-  border: 3rpx solid #FF8C42;
-}
-
-.ai-float-avatar.fubao {
-  background: linear-gradient(135deg, #FFFBEB 0%, #FEF3C7 100%);
-  border: 3rpx solid #F59E0B;
-}
-
-.ai-float-icon {
-  font-size: 48rpx;
-  line-height: 1;
-}
-
-@keyframes floatBounce {
-  0%, 100% { transform: translateY(0); }
-  50% { transform: translateY(-8rpx); }
-}
-</style>
+</script>

+ 5 - 175
cfc-frontend/pages/article-center/article-detail.vue

@@ -34,58 +34,7 @@
         <view class="divider"></view>
         <view class="detail-body"><rich-text :nodes="article.content"></rich-text></view>
 
-        <!-- 评论区 -->
-        <view class="comment-section">
-          <view class="comment-header">
-            <text class="comment-title">评论 ({{ comments.length }})</text>
-          </view>
-          <view class="comment-input-row">
-            <input class="comment-input" v-model="commentText" :placeholder="commentPlaceholder" confirm-type="send" @confirm="submitComment" />
-            <button class="comment-submit" @click="submitComment">发送</button>
-          </view>
-          <view v-if="comments.length === 0" class="comment-empty">暂无评论,来写第一条吧</view>
-          <view v-for="(c, i) in comments" :key="getCommentKey(c, i)" class="comment-item">
-            <view class="comment-user">
-              <text class="comment-avatar">{{ (c.userName || '?').charAt(0) }}</text>
-              <text class="comment-name">{{ c.userName || '匿名' }}</text>
-              <text class="comment-time">{{ formatDate(c.createdAt) }}</text>
-            </view>
-            <view class="comment-content">{{ c.content }}</view>
-            <view class="comment-actions">
-              <text class="comment-reply-btn" @click="startReply(c)">回复</text>
-            </view>
-            <!-- 回复列表 -->
-            <view class="reply-list" v-if="c.replies && c.replies.length > 0">
-              <view v-for="(r, ri) in c.replies" :key="ri" class="reply-item">
-                <view class="reply-user">
-                  <text class="reply-avatar">{{ (r.userName || '?').charAt(0) }}</text>
-                  <text class="reply-name">{{ r.userName || '匿名' }}</text>
-                  <text class="reply-time">{{ formatDate(r.createdAt) }}</text>
-                  <text class="reply-to" v-if="r.replyToId">回复</text>
-                </view>
-                <view class="reply-content">{{ r.content }}</view>
-              </view>
-            </view>
-          </view>
-        </view>
-        <!-- 作者审核区 -->
-        <view class="review-section" v-if="isArticleAuthor && hasPendingComments">
-          <view class="review-header">
-            <text class="review-title">待审核评论 ({{ pendingComments.length }})</text>
-          </view>
-          <view v-for="(c, i) in pendingComments" :key="getPendingKey(i)" class="review-item">
-            <view class="review-user">
-              <text class="review-avatar">{{ (c.userName || '?').charAt(0) }}</text>
-              <text class="review-name">{{ c.userName || '匿名' }}</text>
-              <text class="review-time">{{ formatDate(c.createdAt) }}</text>
-            </view>
-            <view class="review-content">{{ c.content }}</view>
-            <view class="review-actions">
-              <button class="review-btn approve" @click="approveComment(c.id)">通过</button>
-              <button class="review-btn reject" @click="rejectComment(c.id)">驳回</button>
-            </view>
-          </view>
-        </view>
+        <!-- 评论区(已屏蔽) -->
         <view style="height: 200rpx;"></view>
       </scroll-view>
 
@@ -135,7 +84,7 @@
 </template>
 
 <script>
-import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, getArticleComments, createArticleComment, generateQuiz, submitQuiz, getPendingComments, auditArticleComment } from '@/utils/api.js'
+import { getArticleDetail, reportReadingTime, getShareQrCode, completeArticleRead, generateQuiz, submitQuiz } from '@/utils/api.js'
 import shareMixin from '../../components/share-mixin.js'
 import ContentSharePoster from '@/components/ContentSharePoster.vue'
 
@@ -148,62 +97,17 @@ export default {
       readingSeconds: 0, lastReportedSeconds: 0, readingCompleted: false,
       isTimerRunning: false, timerHandle: null, syncHandle: null,
       showPoster: false, posterQrCode: '',
-      // 评论
-      comments: [], commentText: '', replyTarget: null,
-      // 作者审核
-      pendingComments: [], currentUserId: null, currentRole: null,
-    // 作者审核
-    async loadPendingComments() {
-      try {
-        var res = await getPendingComments({ articleId: this.articleId })
-        if (res.code === 200) { this.pendingComments = res.data || [] }
-      } catch (e) {}
-    },
-    async approveComment(commentId) {
-      try {
-        var res = await auditArticleComment({ commentId: commentId, status: 'approved' })
-        if (res.code === 200) {
-          uni.showToast({ title: '已通过', icon: 'success' })
-          this.pendingComments = this.pendingComments.filter(function(c) { return c.id !== commentId })
-        } else {
-          uni.showToast({ title: res.message || '操作失败', icon: 'none' })
-        }
-      } catch (e) { uni.showToast({ title: '网络错误', icon: 'none' }) }
-    },
-    async rejectComment(commentId) {
-      try {
-        var res = await auditArticleComment({ commentId: commentId, status: 'rejected' })
-        if (res.code === 200) {
-          uni.showToast({ title: '已驳回', icon: 'success' })
-          this.pendingComments = this.pendingComments.filter(function(c) { return c.id !== commentId })
-        } else {
-          uni.showToast({ title: res.message || '操作失败', icon: 'none' })
-        }
-      } catch (e) { uni.showToast({ title: '网络错误', icon: 'none' }) }
-    },
-    // 答题
+      // 答题
       showQuiz: false, quizQuestions: [], quizAnswers: [], showResult: false, quizResult: {},
       mascotList: [{ icon: '🐶', name: '浠宝' }, { icon: '🐼', name: '福宝' }],
       mascotIcon: '🐶', mascotName: '浠宝'
     }
   },
-  computed: {
-    commentPlaceholder: function() {
-      return this.replyTarget ? '回复 ' + (this.replyTarget.userName || '') + ':' : '写下你的评论...'
-    },
-    isArticleAuthor: function() {
-      return this.article && this.currentUserId && this.article.createdBy === this.currentUserId
-    },
-    hasPendingComments: function() {
-      return this.pendingComments && this.pendingComments.length > 0
-    }
-  },
+  computed: {},
   onLoad(options) {
     this.mascotIcon = this.mascotList[Math.floor(Math.random() * 2)].icon
     this.mascotName = this.mascotList[Math.floor(Math.random() * 2)].name
-    this.currentUserId = parseInt(uni.getStorageSync('userId') || 0)
-    this.currentRole = uni.getStorageSync('currentRole') || ''
-    if (options && options.id) { this.articleId = options.id; this.loadDetail(options.id); this.loadComments() }
+    if (options && options.id) { this.articleId = options.id; this.loadDetail(options.id) }
     else { this.error = true; this.errorMsg = '参数错误'; this.loading = false }
   },
   onShow() { if (this.article && !this.error) this.startReadingTimer() },
@@ -218,18 +122,10 @@ export default {
           this.article = res.data
           this.setShareInfo('推荐阅读: ' + (res.data.title || ''), '/pages/article-center/article-detail?id=' + id)
           this.startReadingTimer()
-          // 如果当前用户是文章作者,加载待审核评论
-          if (this.currentUserId && res.data.createdBy === this.currentUserId) {
-            this.loadPendingComments()
-          }
         } else { this.error = true; this.errorMsg = '文章不存在或无权限查看' }
       } catch (e) { this.error = true; this.errorMsg = '加载失败' }
       finally { this.loading = false }
     },
-    async loadComments() {
-      try { var res = await getArticleComments({ articleId: this.articleId }); if (res.code === 200) this.comments = res.data || [] }
-      catch (e) {}
-    },
     formatDate(d) { return d ? d.slice(0, 10) : '' },
     parseDimensions: function(article) {
       var dimMap = { body: { code: 'body', color: '#FF8C42', name: '身' }, mind: { code: 'mind', color: '#FF6B9D', name: '心' }, wisdom: { code: 'wisdom', color: '#6366F1', name: '智' }, action: { code: 'action', color: '#10B981', name: '行' }, wealth: { code: 'wealth', color: '#F59E0B', name: '富' } }
@@ -290,25 +186,6 @@ export default {
       } catch (e) { uni.showToast({ title: '生成失败', icon: 'none' }) }
       finally { uni.hideLoading() }
     },
-    // 评论
-    startReply: function(comment) {
-      this.replyTarget = comment
-      this.commentText = ''
-      uni.pageScrollTo({ selector: '.comment-input-row', duration: 300 })
-    },
-    async submitComment() {
-      var text = this.commentText.trim()
-      if (!text) return
-      try {
-        var params = { articleId: this.articleId, content: text }
-        if (this.replyTarget) { params.parentId = this.replyTarget.id; params.replyToId = this.replyTarget.id }
-        var res = await createArticleComment(params)
-        if (res.code === 200) {
-          uni.showToast({ title: '评论已提交,等待审核', icon: 'success' })
-          this.commentText = ''; this.replyTarget = null
-        } else { uni.showToast({ title: res.message || '评论失败', icon: 'none' }) }
-      } catch (e) { uni.showToast({ title: '网络错误', icon: 'none' }) }
-    },
     // 答题
     async startQuiz() {
       try {
@@ -335,12 +212,6 @@ export default {
         }
       } catch (e) {}
     },
-    getCommentKey: function(c, i) {
-      return c.id || i
-    },
-    getPendingKey: function(i) {
-      return 'p' + i
-    },
     closePoster: function() {
       this.showPoster = false
     },
@@ -384,47 +255,6 @@ export default {
 .divider { height: 1rpx; background: #eee; margin: 24rpx 30rpx; }
 .detail-body { padding: 0 30rpx; font-size: 28rpx; color: #444; line-height: 1.8; }
 
-/* 评论区 */
-.comment-section { padding: 30rpx; border-top: 16rpx solid #F5F7FA; }
-.comment-header { margin-bottom: 20rpx; }
-.comment-title { font-size: 30rpx; font-weight: 700; color: #333; }
-.comment-input-row { display: flex; gap: 12rpx; margin-bottom: 24rpx; }
-.comment-input { flex: 1; border: 2rpx solid #E5E7EB; border-radius: 12rpx; padding: 16rpx 20rpx; font-size: 26rpx; height: 72rpx; box-sizing: border-box; }
-.comment-submit { width: 120rpx; height: 72rpx; line-height: 72rpx; background: #5B9BD5; color: #fff; font-size: 26rpx; border-radius: 12rpx; text-align: center; border: none; }
-.comment-empty { text-align: center; padding: 40rpx 0; color: #999; font-size: 26rpx; }
-.comment-item { padding: 20rpx 0; border-bottom: 2rpx solid #F5F5F5; }
-.comment-user { display: flex; align-items: center; margin-bottom: 8rpx; }
-.comment-avatar { width: 40rpx; height: 40rpx; border-radius: 50%; background: #5B9BD5; color: #fff; font-size: 20rpx; text-align: center; line-height: 40rpx; margin-right: 12rpx; }
-.comment-name { font-size: 26rpx; color: #333; font-weight: 500; }
-.comment-time { font-size: 20rpx; color: #999; margin-left: 12rpx; }
-.comment-content { font-size: 26rpx; color: #444; line-height: 1.5; padding-left: 52rpx; }
-.comment-actions { padding-left: 52rpx; margin-top: 8rpx; }
-.comment-reply-btn { font-size: 22rpx; color: #5B9BD5; }
-.reply-list { padding-left: 52rpx; margin-top: 12rpx; background: #FAFAFA; border-radius: 8rpx; padding: 12rpx; }
-.reply-item { padding: 8rpx 0; }
-.reply-user { display: flex; align-items: center; }
-.reply-avatar { width: 32rpx; height: 32rpx; border-radius: 50%; background: #94A3B8; color: #fff; font-size: 16rpx; text-align: center; line-height: 32rpx; margin-right: 8rpx; }
-.reply-name { font-size: 24rpx; color: #333; }
-.reply-time { font-size: 18rpx; color: #999; margin-left: 8rpx; }
-.reply-to { font-size: 18rpx; color: #5B9BD5; margin-left: 8rpx; }
-.reply-content { font-size: 24rpx; color: #444; padding-left: 40rpx; margin-top: 4rpx; }
-
-/* 作者审核区 */
-.review-section { padding: 30rpx; border-top: 16rpx solid #FFF3E0; background: #FFFBF5; }
-.review-header { margin-bottom: 16rpx; }
-.review-title { font-size: 28rpx; font-weight: 700; color: #E65100; }
-.review-item { padding: 16rpx 0; border-bottom: 2rpx solid #F5F5F5; }
-.review-user { display: flex; align-items: center; margin-bottom: 8rpx; }
-.review-avatar { width: 40rpx; height: 40rpx; border-radius: 50%; background: #E65100; color: #fff; font-size: 20rpx; text-align: center; line-height: 40rpx; margin-right: 12rpx; }
-.review-name { font-size: 26rpx; color: #333; font-weight: 500; }
-.review-time { font-size: 20rpx; color: #999; margin-left: 12rpx; }
-.review-content { font-size: 26rpx; color: #444; line-height: 1.5; padding-left: 52rpx; }
-.review-actions { display: flex; gap: 16rpx; padding-left: 52rpx; margin-top: 8rpx; }
-.review-btn { height: 56rpx; line-height: 56rpx; font-size: 24rpx; border-radius: 28rpx; padding: 0 24rpx; border: none; min-width: 100rpx; text-align: center; }
-.review-btn.approve { background: #10B981; color: #fff; }
-.review-btn.reject { background: #EF4444; color: #fff; }
-.review-btn::after { border: none; }
-
 .detail-footer { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; padding: 20rpx 30rpx; display: flex; align-items: center; gap: 16rpx; box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.06); z-index: 10; }
 .share-btn { height: 72rpx; line-height: 72rpx; background: #f5f5f5; color: #666; font-size: 24rpx; border-radius: 36rpx; padding: 0 24rpx; display: flex; align-items: center; border: none; }
 .share-btn::after { border: none; }

+ 4 - 8
cfc-frontend/pages/body-detail/health-report.vue

@@ -177,11 +177,11 @@
     <!-- 底部占位 -->
     <view class="bottom-spacer"></view>
 
-    <!-- 营养分析入口按钮 -->
+    <!-- 营养分析入口按钮(已屏蔽)
     <view class="nutrition-fab" @click="goNutritionChat" v-if="report">
       <text class="fab-icon">🥗</text>
       <text class="fab-text">精准营养分析</text>
-    </view>
+    </view> -->
   </view>
 </template>
 
@@ -404,12 +404,8 @@ export default {
     goBack: function() {
       uni.navigateBack()
     },
-    goNutritionChat: function() {
-      if (!this.reportId) return
-      uni.navigateTo({
-        url: '/pages/ai/chat?mode=nutrition&reportId=' + this.reportId + '&firstMessage=' + encodeURIComponent('请根据这份菌群检测报告,分析我孩子的营养状况并提出建议')
-      })
-    },
+    // AI问答功能已屏蔽
+    goNutritionChat: function() {},
     loadDeficiencyRecords: function() {
       if (!this.childId) return
       var self = this

+ 1 - 1
cfc-frontend/pages/body/index.vue

@@ -183,7 +183,7 @@ export default {
         { icon: '\u{1F634}', label: '作息', needLogin: true, page: '/pages/body/sleep-record' },
         { icon: '\u{1F9D8}', label: '冥想', needLogin: true, page: '/pages/health/meditation-index' },
         { icon: '\u{1F4CA}', label: '舌诊', needLogin: true, page: '/pages/health/report-upload?reportType=tongue' },
-        { icon: '\u{1F3E5}', label: '健康管家', needLogin: true, page: '/pages/ai/chat?mode=butler&fromPage=pages/body/index' },
+        // AI问答功能已屏蔽: { icon: '\u{1F3E5}', label: '健康管家', needLogin: true, page: '/pages/ai/chat?mode=butler&fromPage=pages/body/index' },
         { icon: '\u{1F9EC}', label: '健康维度', needLogin: true, page: 'health-dimensions' }
       ]
     }

+ 2 - 6
cfc-frontend/pages/health/gut-flora-detail.vue

@@ -389,12 +389,8 @@ export default {
     goToIndicators: function() {
       this.accordionOpen.nutri = true
     },
-    goAIChat: function() {
-      if (!this.reportId) return
-      uni.navigateTo({
-        url: '/pages/ai/chat?mode=nutrition&reportId=' + this.reportId + '&firstMessage=' + encodeURIComponent('请根据这份肠道菌群检测报告,分析我孩子的肠道健康状况并提出建议')
-      })
-    }
+    // AI问答功能已屏蔽
+    goAIChat: function() {}
   }
 }
 </script>

+ 4 - 8
cfc-frontend/pages/health/physical-exam-detail.vue

@@ -71,11 +71,11 @@
 
 <view class="bottom-spacer"></view>
 
-<!-- AI 解读入口 -->
+<!-- AI 解读入口(已屏蔽)
 <view class="ai-fab" @click="goAIChat" v-if="report && reportId">
   <text class="fab-icon">🤖</text>
   <text class="fab-text">AI 解读报告</text>
-</view>
+</view> -->
 </view>
 </template>
 
@@ -200,12 +200,8 @@ export default {
       }
       return ''
     },
-goAIChat: function() {
-  if (!this.reportId) return
-  uni.navigateTo({
-    url: '/pages/ai/chat?mode=nutrition&reportId=' + this.reportId + '&firstMessage=' + encodeURIComponent('请根据这份体检报告,分析我孩子的健康状况并提出建议')
-  })
-},
+// AI问答功能已屏蔽
+goAIChat: function() {},
 goBack: function() {
   uni.navigateBack()
 }

+ 5 - 4
cfc-frontend/pages/health/report-survey.vue

@@ -622,10 +622,11 @@ export default {
           uni.hideLoading()
           if (res.code === 200) {
             uni.showToast({ title: '提交成功', icon: 'success' })
-            setTimeout(function() {
-              var params = 'reportId=' + self.reportId + '&surveyId=' + self.surveyId + '&firstMessage=' + encodeURIComponent('请根据报告和问卷信息,提供个性化的健康建议')
-              uni.redirectTo({ url: '/pages/ai/chat?' + params })
-            }, 500)
+            // AI问答功能已屏蔽
+            // setTimeout(function() {
+            //   var params = 'reportId=' + self.reportId + '&surveyId=' + self.surveyId + '&firstMessage=' + encodeURIComponent('请根据报告和问卷信息,提供个性化的健康建议')
+            //   uni.redirectTo({ url: '/pages/ai/chat?' + params })
+            // }, 500)
           } else {
             uni.showToast({ title: res.message || '提交失败', icon: 'none' })
             self.submitting = false