Ver Fonte

fix(frontend): restore article reading timer + recordRead积分发放 + fix response code

- article-detail.vue: restore readSeconds timer (startTimer/stopTimer on onLoad/onUnload)
- article-detail.vue: call recordArticleRead(id,durationSeconds) on 阅读完成 click
  → backend creates completed Task, awards points, calls EnergyService.awardEnergy
  → shows earned toast / already-completed / below-threshold feedback
- article-center/index.vue: fix res.code === 0 → 200 (backend Result.success = code 200)
Xiaogang Liao há 3 meses atrás
pai
commit
65760d3da8

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

@@ -108,7 +108,7 @@
 </template>
 
 <script>
-import { getArticleDetail, getAiQuestions, submitAnswers } from '@/utils/api.js'
+import { getArticleDetail, getAiQuestions, submitAnswers, recordArticleRead } from '@/utils/api.js'
 
 export default {
   data() {
@@ -118,7 +118,8 @@ export default {
       loading: true,
       error: false,
       errorMsg: '',
-      // timer removed
+      readSeconds: 0,
+      readTimer: null,
       showQuiz: false,
       quizLoading: false,
       quizError: false,
@@ -145,13 +146,15 @@ export default {
     if (options && options.id) {
       this.articleId = options.id
       this.loadDetail(options.id)
+      this.startTimer()
     } else {
       this.error = true
       this.errorMsg = '参数错误'
       this.loading = false
     }
   },
-  onUnload() {
+  onUnload: function() {
+    this.stopTimer()
   },
   methods: {
     async loadDetail(id) {
@@ -172,7 +175,18 @@ export default {
         this.loading = false
       }
     },
-    // timer methods removed
+    startTimer: function() {
+      var self = this
+      this.readTimer = setInterval(function() {
+        self.readSeconds++
+      }, 1000)
+    },
+    stopTimer: function() {
+      if (this.readTimer) {
+        clearInterval(this.readTimer)
+        this.readTimer = null
+      }
+    },
     formatDate(dateStr) {
       if (!dateStr) return ''
       return dateStr.slice(0, 10)
@@ -206,7 +220,34 @@ export default {
       // 滚动到底部
     },
     async onReadComplete() {
-      // 计时器已移除,直接进入答题
+      // Stop timer and record the reading
+      this.stopTimer()
+      // Record read with duration (only meaningful if childId present)
+      var childId = uni.getStorageSync('currentChildId')
+      var userId = uni.getStorageSync('userId')
+      if (childId && userId && this.article && this.article.id) {
+        try {
+          var readRes = await recordArticleRead({
+            id: this.article.id,
+            userId: userId,
+            childId: childId,
+            durationSeconds: this.readSeconds
+          })
+          if (readRes && readRes.code === 200 && readRes.data) {
+            var earned = readRes.data.pointsEarned || 0
+            if (earned > 0) {
+              uni.showToast({ title: '阅读完成,获得 ' + earned + ' 积分', icon: 'success' })
+            } else if (readRes.data.alreadyCompleted) {
+              uni.showToast({ title: '已计过积分啦', icon: 'none' })
+            } else if (readRes.data.belowThreshold) {
+              var minSec = readRes.data.minSeconds || 60
+              uni.showToast({ title: '阅读需满' + minSec + '秒计入积分', icon: 'none' })
+            }
+          }
+        } catch (e) {
+          // silent fail - reading still counted
+        }
+      }
       this.showQuiz = true
       this.loadQuiz()
     },

+ 1 - 1
cfc-frontend/pages/article-center/index.vue

@@ -225,7 +225,7 @@ export default {
       self.recommendLoading = true
       try {
         var res = await getFeaturedArticles({ size: 8 })
-        if (res && res.code === 0 && res.data) {
+        if (res && res.code === 200 && res.data) {
           self.recommendedArticles = res.data.list || res.data || []
         }
       } catch (e) {