Răsfoiți Sursa

fix(index-home): 问候条成员圆按设计实现 — 无头像时显示昵称首字文字头像

设计稿 cfc-home-redesign.html §2 要求头像为彩色圆形+成员首字,而非加载默认图。
- computed greetAvatarMembers 增加 hasAvatar / initial(首字) / tone(4色轮换)
- 模板改为 v-if 有头像显示 image,无头像或加载失败显示首字文字
- 新增 greetAvatarErrors 记录加载失败 key,失败自动降级首字
- CSS 增加 .greet-avatar-img/.greet-avatar-text 及 4 色调色变体(品牌橙/智靛/行绿/心玫)
Agnes Agent 1 săptămână în urmă
părinte
comite
d02ef4f21c

+ 0 - 0
cfc-frontend/components/IndicatorTrendArrow.vue → cfc-frontend/pages/health/components/IndicatorTrendArrow.vue


+ 1 - 1
cfc-frontend/pages/health/indicator-quicklook.vue

@@ -75,7 +75,7 @@ import { getIndicatorQuickLookup } from '@/utils/api'
 import { getFamilyMemberList } from '@/utils/api'
 import { getFamilyMemberList } from '@/utils/api'
 import { resolveChange } from '@/utils/indicator-change'
 import { resolveChange } from '@/utils/indicator-change'
 import IndicatorChangeRow from '@/pages/health/components/IndicatorChangeRow.vue'
 import IndicatorChangeRow from '@/pages/health/components/IndicatorChangeRow.vue'
-import IndicatorTrendArrow from '@/components/IndicatorTrendArrow.vue'
+import IndicatorTrendArrow from '@/pages/health/components/IndicatorTrendArrow.vue'
 import fontScaleMixin from '@/mixins/font-scale.js'
 import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {

+ 1 - 1
cfc-frontend/pages/health/indicator-timeline.vue

@@ -151,7 +151,7 @@ import { consumeChartMode, buildAllPeriodDates, buildPeriodRows, formatPeriodDat
 import IndicatorIncompleteBanner from '@/pages/health/components/IndicatorIncompleteBanner.vue'
 import IndicatorIncompleteBanner from '@/pages/health/components/IndicatorIncompleteBanner.vue'
 import IndicatorDegrade from '@/pages/health/components/IndicatorDegrade.vue'
 import IndicatorDegrade from '@/pages/health/components/IndicatorDegrade.vue'
 import TrendChart from '@/pages/health/components/TrendChart.vue'
 import TrendChart from '@/pages/health/components/TrendChart.vue'
-import IndicatorTrendArrow from '@/components/IndicatorTrendArrow.vue'
+import IndicatorTrendArrow from '@/pages/health/components/IndicatorTrendArrow.vue'
 import fontScaleMixin from '@/mixins/font-scale.js'
 import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {

+ 51 - 4
cfc-frontend/pages/index-home/index.vue

@@ -54,12 +54,19 @@
     <!-- ⓪.b 问候条 — 家庭成员 + 按时间问候语(设计稿 §2 视觉焦点) -->
     <!-- ⓪.b 问候条 — 家庭成员 + 按时间问候语(设计稿 §2 视觉焦点) -->
     <view class="greet-bar">
     <view class="greet-bar">
       <view class="greet-avatars">
       <view class="greet-avatars">
-        <image
+        <view
           v-for="m in greetAvatarMembers"
           v-for="m in greetAvatarMembers"
           :key="m._key"
           :key="m._key"
           class="greet-avatar"
           class="greet-avatar"
-          :src="m.avatar || '/static/default-avatar.png'"
-          mode="aspectFill" />
+          :class="'greet-avatar-tone-' + m.tone">
+          <image
+            v-if="m.hasAvatar && !greetAvatarErrors[m._key]"
+            class="greet-avatar-img"
+            :src="m.avatar"
+            mode="aspectFill"
+            @error="_onGreetAvatarError(m._key)" />
+          <text v-else class="greet-avatar-text">{{ m.initial }}</text>
+        </view>
         <view v-if="greetExtraCount > 0" class="greet-avatar greet-avatar-more">
         <view v-if="greetExtraCount > 0" class="greet-avatar greet-avatar-more">
           <text class="greet-avatar-more-text">+{{ greetExtraCount }}</text>
           <text class="greet-avatar-more-text">+{{ greetExtraCount }}</text>
         </view>
         </view>
@@ -526,6 +533,8 @@ components: {
 
 
       // 登录态数据
       // 登录态数据
       familyMembersVisible: [],
       familyMembersVisible: [],
+      // 问候条头像加载失败记录(key -> true,失败则降级为首字文字头像)
+      greetAvatarErrors: {},
       // 接口数据是否已检查(避免"暂无数据"闪烁)
       // 接口数据是否已检查(避免"暂无数据"闪烁)
       childrenChecked: false,
       childrenChecked: false,
       membersChecked: false,
       membersChecked: false,
@@ -731,9 +740,16 @@ title: '添加家庭成员',
       var out = []
       var out = []
       for (var i = 0; i < arr.length && i < 4; i++) {
       for (var i = 0; i < arr.length && i < 4; i++) {
         var m = arr[i] || {}
         var m = arr[i] || {}
+        var avatar = m.avatar || m.headImg || m.headImage || ''
+        var name = m.nickname || m.name || m.realName || ''
         out.push({
         out.push({
           _key: 'ga-' + i + '-' + (m.id || m.memberId || 'x'),
           _key: 'ga-' + i + '-' + (m.id || m.memberId || 'x'),
-          avatar: m.avatar || m.headImg || m.headImage || ''
+          avatar: avatar,
+          hasAvatar: !!avatar,
+          // 设计稿 §2:无头像时用昵称/姓名首字显示文字头像
+          initial: (name.trim().charAt(0)) || '家',
+          // 4 色轮换(首个=当前用户=品牌橙,其余为五行辅助色)
+          tone: i % 4
         })
         })
       }
       }
       return out
       return out
@@ -1796,6 +1812,12 @@ title: '添加家庭成员',
     goNotifications: function() {
     goNotifications: function() {
       uni.navigateTo({ url: '/pages/teacher/messages' })
       uni.navigateTo({ url: '/pages/teacher/messages' })
     },
     },
+    // 问候条头像加载失败 → 记录并降级为首字文字头像
+    _onGreetAvatarError: function(key) {
+      if (key && !this.greetAvatarErrors[key]) {
+        this.$set(this.greetAvatarErrors, key, true)
+      }
+    },
     // ===== Next Best Action 引导条点击 =====
     // ===== Next Best Action 引导条点击 =====
     onGuideTap: function(action) {
     onGuideTap: function(action) {
       if (!action) return
       if (!action) return
@@ -2949,8 +2971,33 @@ $c-warm-tint:     #FFF3E7;
   margin-left: -16rpx;
   margin-left: -16rpx;
   background: $warm-base-alt;
   background: $warm-base-alt;
   flex-shrink: 0;
   flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
 }
 }
 .greet-avatar:first-child { margin-left: 0; }
 .greet-avatar:first-child { margin-left: 0; }
+/* 头像图片铺满圆形 */
+.greet-avatar-img {
+  width: 100%;
+  height: 100%;
+  border-radius: $radius-full;
+}
+/* 无头像时的首字文字头像(设计稿 §2 avatar 配色变体) */
+.greet-avatar-text {
+  font-size: 28rpx;
+  font-weight: 600;
+  line-height: 1;
+  color: $brand-primary-deep;
+}
+.greet-avatar-tone-0 { background: $brand-primary-soft; }
+.greet-avatar-tone-0 .greet-avatar-text { color: $brand-primary-deep; }
+.greet-avatar-tone-1 { background: $dim-wisdom-tint; }
+.greet-avatar-tone-1 .greet-avatar-text { color: $dim-wisdom-deep; }
+.greet-avatar-tone-2 { background: $dim-action-tint; }
+.greet-avatar-tone-2 .greet-avatar-text { color: $dim-action-deep; }
+.greet-avatar-tone-3 { background: $dim-mind-tint; }
+.greet-avatar-tone-3 .greet-avatar-text { color: $dim-mind-deep; }
 .greet-avatar-more {
 .greet-avatar-more {
   background: $brand-primary-soft;
   background: $brand-primary-soft;
   display: flex;
   display: flex;