瀏覽代碼

fix(miniapp): 首页合并冲突采用 feed 集成方案,移除浮动通知条

liaoxg 1 天之前
父節點
當前提交
19ada8b543
共有 1 個文件被更改,包括 167 次插入 和 156 次删除
  1. 167 156
      cfc-frontend/pages/index-home/index.vue

+ 167 - 156
cfc-frontend/pages/index-home/index.vue

@@ -1,5 +1,7 @@
 <template>
 <view>
+  <!-- 通用登录浮层 -->
+  <login-sheet ref="loginSheet" @success="onSheetLoginSuccess" />
   <!-- 冷启动 splash overlay — 覆盖首页直到数据加载完毕(tab 切回时不显示) -->
   <view class="splash-overlay" :class="{'fade-out': splashOverlayFading}" v-if="splashOverlay || splashOverlayFading">
     <view class="splash-overlay-bg">
@@ -99,17 +101,10 @@
     <!-- ② 发现区 — 上传报告 -->
 
     <FamilyFeed
-      :items="familyFeed"
+      :items="feedItems"
       :notices="notices"
-      :showHeader="true" />
-
-    <!-- 能量/积分/CF值变更通知 - 从下滑动展示 -->
-    <view v-if="showEnergyBadge || showPointsBadge || showCfBadge" class="change-notification-bar" :class="{ 'visible': isNotificationVisible }" @click="handleNotificationClick">
-      <view v-if="showEnergyBadge" class="change-item energy" @click.stop="onEnergyClick">{{ formatEnergyNotification }}</view>
-      <view v-if="showPointsBadge" class="change-item points" @click.stop="onPointsClick">{{ formatPointsNotification }}</view>
-      <view v-if="showCfBadge" class="change-item cf" @click.stop="onCfClick">{{ formatCfNotification }}</view>
-      <view class="change-dismiss" @click="dismissAll">✕</view>
-    </view>
+      :showHeader="true"
+      @viewed="onFeedItemViewed" />
 
     <!-- ④ 内容区 — 推荐文章 -->
 
@@ -430,7 +425,7 @@ import ReportUploadCard from '../../components/report-upload-card.vue'
 import OnboardingProgressBar from '../../components/OnboardingProgressBar.vue'
 import OnboardingGuide from '../../components/OnboardingGuide.vue'
 import ConfigurableGuide from '../../components/ConfigurableGuide.vue'
-import { acceptParentInvite, getActivityList, getFeaturedArticles, getEnergySandbox, getEnergyOverview, getFamilyMemberList, getChallengeList, getGuideConfig, getGuidePopupList, consumeGuidePopup, switchToFamilyMember, getMyMembership, updateChallengeProgress, respondChallenge, getTodayTasks, completeTask as completeTaskApi, getTodayParentTasks, completeParentTask as completeParentTaskApi, getTaskHistory, getNotices, getNotificationList, getSurveyStatus, getSelfCheckStatus, getReferralCode, extractReferralCode, getAppLibrary, reportAppEnter, getEnergyLogs, getPointsLogs, getCfList, getCfSummary } from '../../utils/api.js'
+import { acceptParentInvite, getActivityList, getFeaturedArticles, getEnergySandbox, getEnergyOverview, getFamilyMemberList, getChallengeList, getGuideConfig, getGuidePopupList, consumeGuidePopup, switchToFamilyMember, getMyMembership, updateChallengeProgress, respondChallenge, getTodayTasks, completeTask as completeTaskApi, getTodayParentTasks, completeParentTask as completeParentTaskApi, getTaskHistory, getNotices, getNotificationList, readNotification, getSurveyStatus, getSelfCheckStatus, getReferralCode, extractReferralCode, getAppLibrary, reportAppEnter, getEnergyLogs, getPointsLogs, getCfList, getCfSummary } from '../../utils/api.js'
 import { findAppByKey, getShortcutableApps } from '../../utils/app-library.js'
 import nav from '../../utils/nav.js'
 import config from '@/config.js'
@@ -462,6 +457,9 @@ components: {
     return {
       currentRole: _currentRole,
 
+      // 已查看的动态提醒键(点击后从动态中移除;持久化,重启/刷新后不再出现)
+      viewedFeedKeys: (uni.getStorageSync('viewedFeedKeys') || []).slice(0, 200),
+
       // splash loading overlay(冷启动时展示,数据加载完关闭)
       splashOverlay: _isFirstLaunch,
       splashOverlayFading: false,
@@ -482,7 +480,7 @@ components: {
       gradientColors: [
         'linear-gradient(135deg, #10B981, #34D399)',
         'linear-gradient(135deg, #5B9BD5, #8FC5E8)',
-        'linear-gradient(135deg, #8B5CF6, #C084FC)',
+        'linear-gradient(135deg, #F59E0B, #FBBF24)',
         'linear-gradient(135deg, #F97316, #FB923C)',
         'linear-gradient(135deg, #6366F1, #818CF8)'
       ],
@@ -527,15 +525,10 @@ membershipDays: 0,
       appUsage: {},
       quickLoaded: false,
 
-      // 能量/积分/CF值变更通知
+      // 能量/积分/CF值变更记录(合并展示于首页动态提醒,带具体值)
       energyMessages: [],
       pointsMessages: [],
-      cfMessages: [],
-      showEnergyBadge: false,
-      showPointsBadge: false,
-      showCfBadge: false,
-      // 通知栏可见性(从下往上滑入)
-      isNotificationVisible: false
+      cfMessages: []
 
 
     }
@@ -693,36 +686,100 @@ title: '添加家庭成员',
         color: 'gray'
       }
     },
-    // ===== 能量/积分/CF值变更通知格式化(标题带具体数量) =====
-    formatEnergyNotification: function() {
-      var total = 0
-      var arr = this.energyMessages || []
-      for (var i = 0; i < arr.length; i++) {
-        total += (arr[i].amount || 0)
-      }
-      var sign = total > 0 ? '+' : ''
-      var first = arr.length > 0 ? arr[0].description : '能量变动'
-      return '⚡ 能量 ' + sign + total + ' · ' + first
-    },
-    formatPointsNotification: function() {
-      var total = 0
-      var arr = this.pointsMessages || []
-      for (var i = 0; i < arr.length; i++) {
-        total += (arr[i].amount || 0)
+    // ===== 首页动态提醒列表(含具体值)=====
+    // 顺序:今日能量/积分/CF 变更(带数值)→ 家庭动态(通知/公告/任务完成)
+    feedItems: function() {
+      var list = []
+      // 1) 今日能量/积分/CF 变更(每条携带获取到的具体数值)
+      var groups = [
+        { arr: this.energyMessages, icon: '⚡', unit: '能量' },
+        { arr: this.pointsMessages, icon: '🪙', unit: '积分' },
+        { arr: this.cfMessages, icon: '💰', unit: 'CF' }
+      ]
+      for (var g = 0; g < groups.length; g++) {
+        var grp = groups[g]
+        var arr = grp.arr || []
+        for (var i = 0; i < arr.length; i++) {
+          var m = arr[i] || {}
+          var amount = m.amount || 0
+          var amountStr = (amount > 0 ? '+' : '') + amount + grp.unit
+          var desc = m.description || m.title || (grp.unit + '变动')
+          // 能量描述不带数值 → 末位拼接;积分/CF 描述本身已含数值,避免重复
+          var lineDesc = desc
+          if (grp.unit === '能量' && amount) {
+            lineDesc = desc + ' ' + amountStr
+          }
+          list.push({
+            text: grp.icon + ' ' + lineDesc,
+            time: m.time || '',
+            type: m.type || 'change',
+            title: m.title || (grp.unit + '变动'),
+            content: lineDesc,
+            amount: '',
+            unread: false,
+            _feedKey: m.id || ''
+          })
+        }
       }
-      var sign = total > 0 ? '+' : ''
-      var first = arr.length > 0 ? arr[0].description : '积分变动'
-      return '🪙 积分 ' + sign + total + ' · ' + first
-    },
-    formatCfNotification: function() {
-      var total = 0
-      var arr = this.cfMessages || []
-      for (var i = 0; i < arr.length; i++) {
-        total += (arr[i].amount || 0)
+      // 2) 家庭动态(公告/通知/任务完成,任务完成已带 +N 分具体值)
+      var feed = this.familyFeed || []
+      for (var j = 0; j < feed.length; j++) {
+        var f = feed[j]
+        if (!f) continue
+        if (f.type === 'task') {
+          list.push({
+            text: f.text || '',
+            time: f.time || '',
+            type: 'task',
+            title: (f.who || '成员') + ' 完成「' + (f.taskTitle || '任务') + '」',
+            content: '',
+            amount: f.pointsText || '+' + (f.points || 0) + '分',
+            unread: false,
+            _feedKey: f.id || ''
+          })
+        } else if (f.type === 'notification') {
+          var nn = f.notice || {}
+          list.push({
+            text: f.text || '',
+            time: f.time || '',
+            type: 'notification',
+            title: nn.title || f.text || '通知',
+            content: nn.content || '',
+            amount: '',
+            unread: !!f.unread,
+            _feedKey: 'notification-' + (nn.id !== undefined ? nn.id : ''),
+            _srcId: nn.id || ''
+          })
+        } else if (f.type === 'notice') {
+          var nb = f.notice || {}
+          list.push({
+            text: f.text || '',
+            time: f.time || '',
+            type: 'notice',
+            title: nb.title || f.text || '公告',
+            content: nb.content || '',
+            amount: '',
+            unread: false,
+            _feedKey: 'notice-' + (nb.id !== undefined ? nb.id : '')
+          })
+        } else {
+          list.push({
+            text: f.text || '',
+            time: f.time || '',
+            type: f.type || 'feed',
+            title: f.text || '',
+            content: '',
+            amount: '',
+            unread: false,
+            _feedKey: f._feedKey || ''
+          })
+        }
       }
-      var sign = total > 0 ? '+' : ''
-      var first = arr.length > 0 ? arr[0].description : 'CF值变动'
-      return '💰 CF值 ' + sign + total + ' · ' + first
+      // 已查看过的动态不再展示(点击后从提醒中移除),只保留前 20 条
+      var viewed = this.viewedFeedKeys || []
+      return list.filter(function(item) {
+        return !item._feedKey || viewed.indexOf(item._feedKey) === -1
+      }).slice(0, 20)
     }
   },
   onLoad(options) {
@@ -994,7 +1051,7 @@ title: '添加家庭成员',
           var gradientColors = [
             'linear-gradient(135deg, #10B981, #34D399)',
             'linear-gradient(135deg, #5B9BD5, #8FC5E8)',
-            'linear-gradient(135deg, #8B5CF6, #C084FC)',
+            'linear-gradient(135deg, #F59E0B, #FBBF24)',
             'linear-gradient(135deg, #F97316, #FB923C)',
             'linear-gradient(135deg, #6366F1, #818CF8)'
           ]
@@ -1079,9 +1136,15 @@ title: '添加家庭成员',
             timeStr = t.completedAt.substring(11, 16)
           }
           return {
+            id: 'task-' + (t.id !== undefined ? t.id : (t.taskId !== undefined ? t.taskId : '')),
             text: '✅ ' + (child.nickname || '小名') + ' 完成「' + (t.title || '任务') + '」 +' + points + '分',
             time: timeStr,
-            type: 'task'
+            type: 'task',
+            // 补充详情字段(首页动态提醒点击弹窗使用)
+            who: child.nickname || '小名',
+            taskTitle: t.title || '任务',
+            points: points,
+            pointsText: '+' + points + '分'
           }
         })
         self.familyFeed = feed.slice(0, 10)
@@ -1108,9 +1171,15 @@ title: '添加家庭成员',
               notice: n
             }
           })
-          self.notices = notices
+          // 已查看过的公告不再进入动态(历史消息页仍可查)
+          var viewed = self.viewedFeedKeys || []
+          self.notices = notices.filter(function(item) {
+            var raw = item.notice || {}
+            var key = 'notice-' + (raw.id !== undefined ? raw.id : '')
+            return viewed.indexOf(key) === -1
+          })
           // 合并 notices 到 familyFeed(优先显示)
-          self.familyFeed = notices.concat(self.familyFeed).slice(0, 10)
+          self.familyFeed = self.notices.concat(self.familyFeed).slice(0, 10)
         }
       }).catch(function() {})
     },
@@ -1135,13 +1204,39 @@ title: '添加家庭成员',
               notice: n
             }
           })
+          // 只将「未读」通知合并到动态(已读通知归入历史消息页,不再回到动态)
           var unread = notifications.filter(function(n) { return n.unread })
-          var read = notifications.filter(function(n) { return !n.unread })
-          // 未读在前,已读在后,合并到 familyFeed 顶部
-          self.familyFeed = unread.concat(read, self.familyFeed).slice(0, 10)
+          self.familyFeed = unread.concat(self.familyFeed).slice(0, 10)
         }
       }).catch(function() {})
     },
+    // 动态提醒点击查看后:从动态中移除 + 系统通知同步标记已读(历史消息页仍可查)
+    onFeedItemViewed: function(item) {
+      if (!item || !item._feedKey) return
+      var key = item._feedKey
+      if (this.viewedFeedKeys.indexOf(key) === -1) {
+        this.viewedFeedKeys.push(key)
+        if (this.viewedFeedKeys.length > 200) {
+          this.viewedFeedKeys = this.viewedFeedKeys.slice(-200)
+        }
+        uni.setStorageSync('viewedFeedKeys', this.viewedFeedKeys)
+      }
+      // 公告同时从 notices 数组中移除(组件会经 notices prop 展示)
+      if (item.type === 'notice') {
+        var notices = this.notices || []
+        for (var ni = 0; ni < notices.length; ni++) {
+          var raw = notices[ni] && notices[ni].notice || {}
+          if (raw.id !== undefined && ('notice-' + raw.id) === key) {
+            notices.splice(ni, 1)
+            break
+          }
+        }
+      }
+      // 系统通知:服务端标记已读(下次加载不再进入动态)
+      if (item.type === 'notification' && item._srcId) {
+        readNotification({ id: item._srcId }).catch(function() {})
+      }
+    },
     // ===== 能量/积分/CF值变更通知 =====
     loadEnergyPointsCFChanges: function() {
       var self = this
@@ -1151,9 +1246,6 @@ title: '添加家庭成员',
         self.energyMessages = []
         self.pointsMessages = []
         self.cfMessages = []
-        self.showEnergyBadge = false
-        self.showPointsBadge = false
-        self.showCfBadge = false
         return
       }
       
@@ -1170,30 +1262,21 @@ title: '添加家庭成员',
         // 处理能量变更
         if (energyRes) {
           self.energyMessages = energyRes.messages
-          self.showEnergyBadge = energyRes.showBadge
         }
         
         // 处理积分变更
         if (pointsRes) {
           self.pointsMessages = pointsRes.messages
-          self.showPointsBadge = pointsRes.showBadge
         }
         
         // 处理CF值变更
         if (cfRes) {
           self.cfMessages = cfRes.messages
-          self.showCfBadge = cfRes.showBadge
         }
-        
-        // 通知栏滑入动画:数据加载完成后触发从下往上的展示
-        self.isNotificationVisible = true
       }).catch(function() {
         self.energyMessages = []
         self.pointsMessages = []
         self.cfMessages = []
-        self.showEnergyBadge = false
-        self.showPointsBadge = false
-        self.showCfBadge = false
       })
     },
     
@@ -1254,12 +1337,8 @@ title: '添加家庭成员',
             }
           }
           
-          // 存储到实例属性(供其他方法使用,或可单独暴露)
-          // 注意:这里的 messages 仅在该方法调用后有效,实际建议使用单独的数据存储
+          // 存储到实例属性(合并展示于首页动态提醒)
           self.energyMessages = messages
-          self.energyChangeTotal = totalAmount
-          self.energyChangeCount = count
-          self.showEnergyBadge = count > 0
         }
       }).catch(function() {})
     },
@@ -1324,9 +1403,6 @@ title: '添加家庭成员',
           }
           
           self.pointsMessages = messages
-          self.pointsChangeTotal = totalAmount
-          self.pointsChangeCount = count
-          self.showPointsBadge = count > 0
         }
       }).catch(function() {})
     },
@@ -1386,9 +1462,6 @@ title: '添加家庭成员',
               }
               
               self.cfMessages = messages
-              self.cfChangeTotal = totalAmount
-              self.cfChangeCount = count
-              self.showCfBadge = count > 0
             }
           }).catch(function() {})
         }
@@ -1410,43 +1483,14 @@ title: '添加家庭成员',
              date.getMonth() === today.getMonth() &&
              date.getFullYear() === today.getFullYear()
     },
-    
-    // ===== 能量/积分/CF值变更通知点击处理 =====
-    // 点击通知内容 → 跳转详情页 + 隐藏通知(点击后不再显示)
-    handleNotificationClick: function() {
-      // 点击空白区域:若有多个通知,跳转第一个可见的
-      if (this.showEnergyBadge) {
-        this.onEnergyClick()
-      } else if (this.showPointsBadge) {
-        this.onPointsClick()
-      } else if (this.showCfBadge) {
-        this.onCfClick()
-      } else {
-        this.dismissAll()
-      }
-    },
-    onEnergyClick: function() {
-      var memberId = this.currentChildId || uni.getStorageSync('currentMemberId') || ''
-      this.dismissAll()
-      uni.navigateTo({ url: '/pages/energy/detail?memberId=' + memberId })
-    },
-    onPointsClick: function() {
-      this.dismissAll()
-      uni.navigateTo({ url: '/pages/rewards/rewards' })
-    },
-    onCfClick: function() {
-      this.dismissAll()
-      uni.navigateTo({ url: '/pages/promotion/index' })
-    },
-    // 关闭按钮:仅隐藏,不跳转
-    dismissAll: function() {
-      this.isNotificationVisible = false
-      this.showEnergyBadge = false
-      this.showPointsBadge = false
-      this.showCfBadge = false
-      this.energyMessages = []
-      this.pointsMessages = []
-      this.cfMessages = []
+// ===== 时间格式化 =====
+    // 时间格式化 yyyy-MM-dd HH:mm(iOS 安全:经 utils/format.js parseDate 归一化)
+    formatTime: function(dateStr) {
+      var d = parseDate(dateStr)
+      if (!d) return ''
+      function pad2(n) { return n < 10 ? '0' + n : '' + n }
+      return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate()) +
+        ' ' + pad2(d.getHours()) + ':' + pad2(d.getMinutes())
     },
     quickCompleteTask: function(task) {
       var self = this
@@ -1830,7 +1874,7 @@ title: '添加家庭成员',
           var gradientColors = [
             'linear-gradient(135deg, #10B981, #34D399)',
             'linear-gradient(135deg, #5B9BD5, #8FC5E8)',
-            'linear-gradient(135deg, #8B5CF6, #C084FC)',
+            'linear-gradient(135deg, #F59E0B, #FBBF24)',
             'linear-gradient(135deg, #F97316, #FB923C)',
             'linear-gradient(135deg, #6366F1, #818CF8)'
           ]
@@ -1870,7 +1914,11 @@ title: '添加家庭成员',
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
     },
     handleLogin() {
-      uni.navigateTo({ url: '/pages/login/login?redirect=' + encodeURIComponent('/pages/index-home/index') })
+      this.openLoginSheet({ redirect: '/pages/index-home/index' })
+    },
+    // 登录成功:刷新首页登录态数据
+    onLoginSuccess() {
+      this.loadLoggedInData()
     },
     async handleParentInvite(code) {
       // 延迟显示,等待登录完成
@@ -2332,7 +2380,7 @@ title: '添加家庭成员',
 }
 .section-more {
   font-size: 24rpx;
-  color: #5B9BD5;
+  color: #F97316;
 }
 .empty-state {
   display: flex;
@@ -2659,7 +2707,7 @@ title: '添加家庭成员',
 /* ===== ① 了解区 — 自测大卡(引导"从了解开始") ===== */
 .self-test-card {
   margin: 20rpx 30rpx 16rpx;
-  background: linear-gradient(135deg, #667eea, #764ba2);
+  background: linear-gradient(135deg, #F97316, #FB923C);
   border-radius: 20rpx;
   padding: 24rpx 28rpx;
 }
@@ -2727,7 +2775,7 @@ title: '添加家庭成员',
 .guide-bar-purple .guide-bar-icon-wrap { background: rgba(139,92,246,0.12); }
 .guide-bar-purple .guide-bar-title { color: #4C1D95; }
 .guide-bar-purple .guide-bar-sub { color: #6D28D9; }
-.guide-bar-purple .guide-bar-btn { background: linear-gradient(135deg, #8B5CF6, #A78BFA); color: #fff; }
+.guide-bar-purple .guide-bar-btn { background: linear-gradient(135deg, #F97316, #FB923C); color: #fff; }
 
 .guide-bar-gray { background: #F8FAFC; border: 1rpx solid rgba(100,116,139,0.15); }
 .guide-bar-gray .guide-bar-icon-wrap { background: rgba(100,116,139,0.10); }
@@ -2861,41 +2909,4 @@ title: '添加家庭成员',
   border: none;
 }
 .self-test-badge { display: inline-block; align-self: flex-start; margin-top: 8rpx; font-size: 20rpx; color: #F97316; background: rgba(249,115,22,0.1); padding: 4rpx 14rpx; border-radius: 999rpx; }
-
-/* ===== 能量/积分/CF值变更通知条(从下滑入动画) ===== */
-.change-notification-bar {
-  position: fixed;
-  bottom: -80rpx;
-  left: 30rpx;
-  right: 30rpx;
-  padding: 16rpx 24rpx;
-  background: linear-gradient(135deg, #FFF7ED, #FFEDD5);
-  border-radius: 16rpx;
-  box-shadow: 0 2rpx 8rpx rgba(249,115,22,0.12);
-  transition: bottom 0.3s cubic-bezier(0.16,1,0.3,1) forwards;
-  z-index: 100;
-}
-.change-notification-bar.visible {
-  bottom: 0;
-  animation: slide-up-notice 0.4s cubic-bezier(0.16,1,0.3,1) forwards;
-}
-@keyframes slide-up-notice {
-  from { opacity: 0; transform: translateY(80rpx); }
-  to   { opacity: 1; transform: translateY(0); }
-}
-.change-item {
-  font-size: 22rpx;
-  font-weight: 500;
-  color: #333;
-}
-.change-item.energy { color: #F97316; }
-.change-item.points { color: #10B981; }
-.change-item.cf { color: #6366F1; }
-.change-dismiss {
-  margin-left: auto;
-  font-size: 24rpx;
-  color: #999;
-  flex-shrink: 0;
-  cursor: pointer;
-}
 </style>