Просмотр исходного кода

fix(family): 家庭成员编辑页合并为单次member/list调用,移除onLoad前端建家庭逻辑

修复首次进入页面接口被调用4次的问题:删除ensureFamily分支与独立loadFamilyInfo请求,成员与家庭信息取自同一includeFamily响应(含旧版后端members字段缺失兜底)。同页附带邀请按钮改为小程序原生分享(open-type=share + onShareAppMessage + prepareInviteToken预取令牌),与后续邀请令牌复用后端改动配套。

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
liaoxg 2 месяцев назад
Родитель
Сommit
17ac266002
1 измененных файлов с 76 добавлено и 79 удалено
  1. 76 79
      cfc-frontend/pages/profile-extra/family-members.vue

+ 76 - 79
cfc-frontend/pages/profile-extra/family-members.vue

@@ -28,7 +28,7 @@
       <text class="empty-icon">👨‍👩‍👧‍👦</text>
       <text class="empty-title">还没有家庭成员</text>
       <text class="empty-desc">邀请家人加入,一起记录成长</text>
-      <button class="empty-invite-btn" @click="onInvite">📨 邀请家人</button>
+      <button class="empty-invite-btn" open-type="share">📨 邀请家人</button>
     </view>
 
     <!-- ===== 成员详情弹窗 ===== -->
@@ -90,7 +90,7 @@
     <!-- ===== 底部操作栏 ===== -->
     <view class="bottom-bar">
       <button class="bottom-btn btn-add" @click="onAddMember">+ 添加成员</button>
-      <button class="bottom-btn btn-invite" @click="onInvite">📨 邀请成员</button>
+      <button class="bottom-btn btn-invite" open-type="share">📨 邀请成员</button>
     </view>
 
     <!-- ===== 加载状态 ===== -->
@@ -109,7 +109,6 @@ import {
   updateFamilyMember
 } from '../../utils/api.js'
 import store from '../../store/index.js'
-import { ensureFamily } from '../../utils/api.js'
 
 export default {
   components: {},
@@ -128,7 +127,9 @@ export default {
       detailMember: null,
       memberScores: {},
       userNickname: '',
-      userAvatar: ''
+      userAvatar: '',
+
+      inviteToken: ''
     }
   },
   computed: {
@@ -138,19 +139,6 @@ export default {
     detailMemberScores() {
       if (!this.detailMember) return {}
       return this.memberScores[this.detailMember.id] || {}
-    },
-    hasFamily: function() {
-      if (this.members && this.members.length > 0) return true
-      return this.$store.getters.hasFamily
-    }
-  },
-  onLoad(options) {
-    // 无家庭时自动创建
-    if (!this.hasFamily) {
-      var self = this
-      ensureFamily().then(function() {
-        self.loadMembers()
-      })
     }
   },
   onShow() {
@@ -158,17 +146,57 @@ export default {
     this.userId = (userInfo && userInfo.id) || 0
     this.userNickname = uni.getStorageSync('nickname') || (userInfo && userInfo.nickname) || ''
     this.userAvatar = uni.getStorageSync('avatar') || (userInfo && userInfo.avatar) || ''
+    // 家庭在用户注册时已由后端创建(登录接口另有兜底),此处不再触发建家庭逻辑;
+    // 数据加载统一入口:单次 includeFamily 请求同时获取成员列表 + 家庭信息
     this.loadMembers()
+    // 预取邀请令牌(后端复用同家庭未用尽的有效令牌),保证点击分享时立即可用
+    this.prepareInviteToken()
+  },
+  // 页面级分享:转发邀请卡片,接收人点击直接进入加入家庭页(信息补充、家庭申请)
+  onShareAppMessage() {
+    var self = this
+    var title = '邀请你加入「' + (this.familyName || '我的家庭') + '」'
+    var buildResult = function(token) {
+      return {
+        title: title,
+        path: '/pages/invite/join?token=' + (token || ''),
+        success: function() {},
+        fail: function() {}
+      }
+    }
+    if (this.inviteToken) {
+      return buildResult(this.inviteToken)
+    }
+    // 令牌未就绪时异步获取(基础库 >=2.6.0 支持 promise,超时约 3 秒)
+    return {
+      title: title,
+      path: '/pages/index/index',
+      promise: new Promise(function(resolve) {
+        self.prepareInviteToken(function(token) {
+          resolve(token ? buildResult(token) : { path: '/pages/index/index' })
+        })
+      })
+    }
   },
   methods: {
     async loadMembers() {
       this.loading = true
       try {
-        var res = await getFamilyMemberList()
+        var res = await getFamilyMemberList({ includeFamily: true })
         if (res.code === 200 && res.data) {
-          this.members = res.data || []
-          this.buildScoreMap(res.data)
-          this.loadFamilyInfo()
+          var data = res.data
+          this.familyId = data.familyId
+          this.familyName = data.familyName
+          this.creatorId = data.creatorId
+          this.isAdmin = this.creatorId === this.userId
+          var arr = data.members
+          if (!(arr instanceof Array)) {
+            // 后端旧版本未返回 members 字段时的兼容:补一次无参请求
+            var legacy = await getFamilyMemberList()
+            arr = (legacy && legacy.code === 200 && legacy.data instanceof Array) ? legacy.data : []
+          }
+          this.members = arr || []
+          this.buildScoreMap(this.members)
         }
       } catch (e) {
         uni.showToast({ title: '加载失败', icon: 'none' })
@@ -190,26 +218,6 @@ export default {
       }
       this.memberScores = map
     },
-    async loadFamilyInfo() {
-      try {
-        var res = await getFamilyMemberList({ includeFamily: true })
-        if (res.code === 200 && res.data) {
-          var data = res.data
-          this.familyId = data.familyId
-          this.familyName = data.familyName
-          // inviteCode no longer needed
-          this.creatorId = data.creatorId
-          this.isAdmin = this.creatorId === this.userId
-        } else if (res.code === 5001 || (res.message && res.message.indexOf('未加入家庭') >= 0)) {
-          // 无家庭:自动创建
-          ensureFamily().then(function() {
-            self.loadMembers()
-          })
-        }
-      } catch (e) {
-        // 静默处理
-      }
-    },
     showMemberDetail(member) {
       this.detailMember = member
       this.showMemberDetailModal = true
@@ -268,46 +276,30 @@ export default {
         uni.showToast({ title: '操作失败', icon: 'none' })
       }
     },
-    async onInvite() {
-      uni.showLoading({ title: '生成邀请...' })
-      try {
-        var res = await generateFamilyInvite()
-        if (res.code === 200 && res.data) {
-          var token = res.data.token
-          uni.share({
-            provider: 'weixin',
-            scene: 'WXSceneSession',
-            type: 5,
-            title: '加入「' + (this.familyName || '我的家庭') + '」',
-            miniProgram: {
-              id: '',
-              path: 'pages/invite/join?token=' + token,
-              type: 0,
-              webUrl: 'https://cfc.etotem.com.cn/invite/join?token=' + token
-            },
-            success: function() {
-              uni.hideLoading()
-              uni.showToast({ title: '分享成功', icon: 'success' })
-            },
-            fail: function(err) {
-              uni.hideLoading()
-              if (err.errMsg.indexOf('cancel') >= 0) return
-              uni.setClipboardData({
-                data: 'https://cfc.etotem.com.cn/invite/join?token=' + token,
-                success: function() {
-                  uni.showToast({ title: '链接已复制', icon: 'success' })
-                }
-              })
-            }
-          })
-        } else {
-          uni.showToast({ title: res.message || '生成失败', icon: 'none' })
-          uni.hideLoading()
+    // 生成/复用邀请令牌(小程序原生分享卡片路径使用),完成后回调 callback(token)
+    prepareInviteToken(callback) {
+      var self = this
+      var done = function(token) {
+        if (typeof callback === 'function') {
+          callback(token)
         }
-      } catch (e) {
-        uni.showToast({ title: '生成失败', icon: 'none' })
-        uni.hideLoading()
       }
+      if (this.inviteToken) {
+        done(this.inviteToken)
+        return
+      }
+      generateFamilyInvite().then(function(res) {
+        if (res && res.code === 200 && res.data && res.data.token) {
+          self.inviteToken = res.data.token
+          done(self.inviteToken)
+        } else {
+          uni.showToast({ title: (res && res.message) || '生成邀请失败', icon: 'none' })
+          done('')
+        }
+      }).catch(function() {
+        uni.showToast({ title: '生成邀请失败', icon: 'none' })
+        done('')
+      })
     },
     onEditRelation(member) {
       this.showMemberDetailModal = false
@@ -481,6 +473,11 @@ export default {
   text-align: center;
   border: none;
 }
+/* 微信小程序 button 默认边框来自 ::after 伪元素,分享按钮同样需要重置 */
+.empty-invite-btn::after,
+.bottom-btn::after {
+  border: none;
+}
 .bottom-btn:active {
   opacity: 0.85;
 }