Procházet zdrojové kódy

feat(miniapp): 字号缩放扩展至饮食/会员/健康报告/canvas 海报

- mixins/font-scale.js 复用,19 个内容页统一接入(--font-scale + onShow 刷新)
- 健康报告页(report-detail/report-confirm/gut-flora*/health-report/cognitive-report/health-plan-summary)正文 310 处 calc 缩放,排除图标/角标/按钮/价格/大数字
- 会员中心/购买页只缩放权益文案,价格不动
- diet records/recommendation、meal recommend、discover circle-feed 接入
- ContentSharePoster canvas 20 处字号按 _fs() 缩放(海报区间收窄 0.9~1.25 防溢出)
- node --check 全过,CI 审计 0 error
E2E Test Bot před 1 týdnem
rodič
revize
6902054997

+ 31 - 22
cfc-frontend/components/ContentSharePoster.vue

@@ -10,6 +10,8 @@
 </template>
 </template>
 
 
 <script>
 <script>
+import { getFontScale } from '@/utils/fontScale.js'
+
 export default {
 export default {
   name: 'ContentSharePoster',
   name: 'ContentSharePoster',
   props: {
   props: {
@@ -48,6 +50,13 @@ export default {
     return {}
     return {}
   },
   },
   methods: {
   methods: {
+    // 海报画布文字按用户字号系数放大(画布有固定排版,放大区间比页面更保守,防止溢出裁切)
+    _fs(size) {
+      var scale = getFontScale()
+      if (!scale || scale < 0.9) scale = 0.9
+      if (scale > 1.25) scale = 1.25
+      return Math.round(size * scale)
+    },
     getColors() {
     getColors() {
       var map = {
       var map = {
         body: { main: '#FF8C42', dark: '#EA580C', light: '#FFF7ED' },
         body: { main: '#FF8C42', dark: '#EA580C', light: '#FFF7ED' },
@@ -222,12 +231,12 @@ export default {
       }
       }
 
 
       ctx.setFillStyle('#ffffff')
       ctx.setFillStyle('#ffffff')
-      ctx.setFontSize(20)
+      ctx.setFontSize(this._fs(20))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText('浠艾福', centerX, 52)
       ctx.fillText('浠艾福', centerX, 52)
 
 
-      ctx.setFontSize(14)
+      ctx.setFontSize(this._fs(14))
       ctx.setFillStyle('rgba(255,255,255,0.8)')
       ctx.setFillStyle('rgba(255,255,255,0.8)')
       ctx.fillText('给全家的一站式幸福提案', centerX, 76)
       ctx.fillText('给全家的一站式幸福提案', centerX, 76)
 
 
@@ -255,7 +264,7 @@ export default {
       ctx.fill()
       ctx.fill()
 
 
       ctx.setFillStyle('#F97316')
       ctx.setFillStyle('#F97316')
-      ctx.setFontSize(16)
+      ctx.setFontSize(this._fs(16))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')
       ctx.setTextBaseline('middle')
       ctx.fillText('暂无封面图', x + w / 2, y + h / 2)
       ctx.fillText('暂无封面图', x + w / 2, y + h / 2)
@@ -272,7 +281,7 @@ export default {
 
 
       // 顶部:左侧标题,右侧综合分
       // 顶部:左侧标题,右侧综合分
       ctx.setFillStyle('#78716C')
       ctx.setFillStyle('#78716C')
-      ctx.setFontSize(13)
+      ctx.setFontSize(this._fs(13))
       ctx.setTextAlign('left')
       ctx.setTextAlign('left')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText(data.label || '我们家的能量', x + 16, y + 16)
       ctx.fillText(data.label || '我们家的能量', x + 16, y + 16)
@@ -280,11 +289,11 @@ export default {
       var hasOverall = data.overall !== null && data.overall !== undefined && !isNaN(data.overall)
       var hasOverall = data.overall !== null && data.overall !== undefined && !isNaN(data.overall)
       if (hasOverall) {
       if (hasOverall) {
         ctx.setFillStyle(colors.main)
         ctx.setFillStyle(colors.main)
-        ctx.setFontSize(30)
+        ctx.setFontSize(this._fs(30))
         ctx.setTextAlign('right')
         ctx.setTextAlign('right')
         ctx.fillText(String(data.overall), x + w - 28, y + 8)
         ctx.fillText(String(data.overall), x + w - 28, y + 8)
         ctx.setFillStyle('#78716C')
         ctx.setFillStyle('#78716C')
-        ctx.setFontSize(13)
+        ctx.setFontSize(this._fs(13))
         ctx.fillText('分', x + w - 16, y + 28)
         ctx.fillText('分', x + w - 16, y + 28)
       }
       }
 
 
@@ -311,13 +320,13 @@ export default {
         ctx.fill()
         ctx.fill()
 
 
         ctx.setFillStyle('#FFFFFF')
         ctx.setFillStyle('#FFFFFF')
-        ctx.setFontSize(15)
+        ctx.setFontSize(this._fs(15))
         ctx.setTextAlign('center')
         ctx.setTextAlign('center')
         ctx.setTextBaseline('middle')
         ctx.setTextBaseline('middle')
         ctx.fillText(d.label || '', cx, y + 95)
         ctx.fillText(d.label || '', cx, y + 95)
 
 
         ctx.setFillStyle('#1C1917')
         ctx.setFillStyle('#1C1917')
-        ctx.setFontSize(18)
+        ctx.setFontSize(this._fs(18))
         ctx.setTextBaseline('top')
         ctx.setTextBaseline('top')
         ctx.fillText(String(score), cx, y + 120)
         ctx.fillText(String(score), cx, y + 120)
 
 
@@ -336,7 +345,7 @@ export default {
       }
       }
 
 
       ctx.setFillStyle('#A8A29E')
       ctx.setFillStyle('#A8A29E')
-      ctx.setFontSize(11)
+      ctx.setFontSize(this._fs(11))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText('五维能量 · 浠艾福家庭测评', x + w / 2, y + 172)
       ctx.fillText('五维能量 · 浠艾福家庭测评', x + w / 2, y + 172)
@@ -361,17 +370,17 @@ export default {
       }
       }
 
 
       ctx.setFillStyle('#FFFFFF')
       ctx.setFillStyle('#FFFFFF')
-      ctx.setFontSize(24)
+      ctx.setFontSize(this._fs(24))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText('浠艾福', centerX, y + 86)
       ctx.fillText('浠艾福', centerX, y + 86)
 
 
       ctx.setFillStyle('rgba(255,255,255,0.85)')
       ctx.setFillStyle('rgba(255,255,255,0.85)')
-      ctx.setFontSize(13)
+      ctx.setFontSize(this._fs(13))
       ctx.fillText('给全家的一站式幸福提案', centerX, y + 124)
       ctx.fillText('给全家的一站式幸福提案', centerX, y + 124)
 
 
       ctx.setFillStyle('rgba(255,255,255,0.7)')
       ctx.setFillStyle('rgba(255,255,255,0.7)')
-      ctx.setFontSize(12)
+      ctx.setFontSize(this._fs(12))
       ctx.fillText('测一测你家的五维能量', centerX, y + 152)
       ctx.fillText('测一测你家的五维能量', centerX, y + 152)
     },
     },
 
 
@@ -380,7 +389,7 @@ export default {
 
 
       var labelY = coverY + coverH + 16
       var labelY = coverY + coverH + 16
       ctx.setFillStyle(colors.main)
       ctx.setFillStyle(colors.main)
-      ctx.setFontSize(13)
+      ctx.setFontSize(this._fs(13))
       ctx.setTextAlign('left')
       ctx.setTextAlign('left')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText(this.typeLabel, cardX + 20, labelY)
       ctx.fillText(this.typeLabel, cardX + 20, labelY)
@@ -388,16 +397,16 @@ export default {
       // 标题(2行截断)
       // 标题(2行截断)
       var titleY = labelY + 22
       var titleY = labelY + 22
       ctx.setFillStyle('#1C1917')
       ctx.setFillStyle('#1C1917')
-      ctx.setFontSize(18)
+      ctx.setFontSize(this._fs(18))
       ctx.setTextAlign('left')
       ctx.setTextAlign('left')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
-      this._drawWrappedText(ctx, this.title || '精彩内容', cardX + 20, titleY, cardW - 40, 24, 2)
+      this._drawWrappedText(ctx, this.title || '精彩内容', cardX + 20, titleY, cardW - 40, this._fs(24), 2)
 
 
       // 价格行(商品用;空则跳过)
       // 价格行(商品用;空则跳过)
       var priceY = titleY + 56
       var priceY = titleY + 56
       if (this.priceText) {
       if (this.priceText) {
         ctx.setFillStyle(colors.main)
         ctx.setFillStyle(colors.main)
-        ctx.setFontSize(17)
+        ctx.setFontSize(this._fs(17))
         ctx.setTextAlign('left')
         ctx.setTextAlign('left')
         ctx.setTextBaseline('top')
         ctx.setTextBaseline('top')
         ctx.fillText(this.priceText, cardX + 20, priceY)
         ctx.fillText(this.priceText, cardX + 20, priceY)
@@ -407,16 +416,16 @@ export default {
       var summaryY = (this.priceText ? priceY + 34 : priceY)
       var summaryY = (this.priceText ? priceY + 34 : priceY)
       if (this.summary) {
       if (this.summary) {
         ctx.setFillStyle('#78716C')
         ctx.setFillStyle('#78716C')
-        ctx.setFontSize(13)
+        ctx.setFontSize(this._fs(13))
         ctx.setTextAlign('left')
         ctx.setTextAlign('left')
         ctx.setTextBaseline('top')
         ctx.setTextBaseline('top')
-        this._drawWrappedText(ctx, this.summary, cardX + 20, summaryY, cardW - 40, 20, 2)
+        this._drawWrappedText(ctx, this.summary, cardX + 20, summaryY, cardW - 40, this._fs(20), 2)
       }
       }
 
 
       // 邀请语(二维码上方)
       // 邀请语(二维码上方)
       var inviteY = (this.summary ? summaryY + 48 : summaryY)
       var inviteY = (this.summary ? summaryY + 48 : summaryY)
       ctx.setFillStyle('#A8A29E')
       ctx.setFillStyle('#A8A29E')
-      ctx.setFontSize(13)
+      ctx.setFontSize(this._fs(13))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText(this.inviteText || '长按识别二维码 · 查看详情', w / 2, inviteY)
       ctx.fillText(this.inviteText || '长按识别二维码 · 查看详情', w / 2, inviteY)
@@ -511,7 +520,7 @@ export default {
       ctx.stroke()
       ctx.stroke()
 
 
       ctx.setFillStyle('#A8A29E')
       ctx.setFillStyle('#A8A29E')
-      ctx.setFontSize(16)
+      ctx.setFontSize(this._fs(16))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')
       ctx.setTextBaseline('middle')
       ctx.fillText('二维码加载中', x + size / 2, y + size / 2)
       ctx.fillText('二维码加载中', x + size / 2, y + size / 2)
@@ -539,7 +548,7 @@ export default {
       ctx.fill()
       ctx.fill()
 
 
       ctx.setFillStyle(colors.main)
       ctx.setFillStyle(colors.main)
-      ctx.setFontSize(18)
+      ctx.setFontSize(this._fs(18))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText(this.ctaText || '长按识别二维码 · 查看详情', centerX, bottomY)
       ctx.fillText(this.ctaText || '长按识别二维码 · 查看详情', centerX, bottomY)
@@ -559,7 +568,7 @@ export default {
       }
       }
 
 
       ctx.setFillStyle('rgba(255,255,255,0.45)')
       ctx.setFillStyle('rgba(255,255,255,0.45)')
-      ctx.setFontSize(12)
+      ctx.setFontSize(this._fs(12))
       ctx.setTextAlign('center')
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.setTextBaseline('top')
       ctx.fillText('浠艾福 · 家庭健康俱乐部', centerX, dotY + 7)
       ctx.fillText('浠艾福 · 家庭健康俱乐部', centerX, dotY + 7)

+ 26 - 23
cfc-frontend/pages/body-detail/health-report.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="report-container">
+  <view class="report-container" :style="{ '--font-scale': fontScale }">
     <!-- 顶部导航 -->
     <!-- 顶部导航 -->
 
 
     <!-- 报告头部 -->
     <!-- 报告头部 -->
@@ -210,7 +210,10 @@ const healthRequest = function(url, data) {
   })
   })
 }
 }
 
 
+import fontScaleMixin from '@/mixins/font-scale.js'
+
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data() {
   data() {
     return {
     return {
       memberId: null,
       memberId: null,
@@ -576,14 +579,14 @@ export default {
   color: #2E7D32;
   color: #2E7D32;
 }
 }
 .score-unit {
 .score-unit {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #64B5F6;
   color: #64B5F6;
 }
 }
 .score-circle-green .score-unit {
 .score-circle-green .score-unit {
   color: #81C784;
   color: #81C784;
 }
 }
 .score-label {
 .score-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
 }
 }
 .report-info-row {
 .report-info-row {
@@ -600,7 +603,7 @@ export default {
   margin-right: 16rpx;
   margin-right: 16rpx;
 }
 }
 .report-date {
 .report-date {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
 }
 }
 
 
@@ -613,12 +616,12 @@ export default {
   flex-direction: row;
   flex-direction: row;
   align-items: baseline;
   align-items: baseline;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
 .section-sub {
 .section-sub {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   font-weight: normal;
   font-weight: normal;
   margin-left: 12rpx;
   margin-left: 12rpx;
@@ -634,7 +637,7 @@ export default {
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
 .category-name {
 .category-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
@@ -657,12 +660,12 @@ export default {
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
 .ind-name {
 .ind-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
 .ind-status {
 .ind-status {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   padding: 4rpx 16rpx;
   padding: 4rpx 16rpx;
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
@@ -695,19 +698,19 @@ export default {
   color: #1565C0;
   color: #1565C0;
 }
 }
 .ind-unit {
 .ind-unit {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-left: 8rpx;
   margin-left: 8rpx;
 }
 }
 .ind-ref {
 .ind-ref {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #bbb;
   color: #bbb;
 }
 }
 .empty-indicators {
 .empty-indicators {
   text-align: center;
   text-align: center;
   padding: 60rpx;
   padding: 60rpx;
   color: #999;
   color: #999;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
 }
 }
 
 
 /* ===== 底部 ===== */
 /* ===== 底部 ===== */
@@ -766,7 +769,7 @@ export default {
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .main-score-label {
 .main-score-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -798,7 +801,7 @@ export default {
   color: #fff;
   color: #fff;
 }
 }
 .flora-score-label {
 .flora-score-label {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
 }
 }
 
 
@@ -821,7 +824,7 @@ export default {
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
 .deficiency-nutrient {
 .deficiency-nutrient {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
@@ -867,18 +870,18 @@ export default {
   border-radius: 6rpx;
   border-radius: 6rpx;
 }
 }
 .severity-val {
 .severity-val {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #9CA3AF;
   color: #9CA3AF;
   width: 60rpx;
   width: 60rpx;
   text-align: right;
   text-align: right;
 }
 }
 .deficiency-meta {
 .deficiency-meta {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #6B7280;
   color: #6B7280;
   margin-bottom: 6rpx;
   margin-bottom: 6rpx;
 }
 }
 .deficiency-foods {
 .deficiency-foods {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #374151;
   color: #374151;
   margin-top: 8rpx;
   margin-top: 8rpx;
 }
 }
@@ -921,12 +924,12 @@ export default {
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .food-name {
 .food-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
 .food-score {
 .food-score {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   padding: 4rpx 16rpx;
   padding: 4rpx 16rpx;
   border-radius: 16rpx;
   border-radius: 16rpx;
   font-weight: 600;
   font-weight: 600;
@@ -951,7 +954,7 @@ export default {
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .food-category {
 .food-category {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #6B7280;
   color: #6B7280;
   background: #F3F4F6;
   background: #F3F4F6;
   padding: 2rpx 12rpx;
   padding: 2rpx 12rpx;
@@ -971,11 +974,11 @@ export default {
   min-width: 100rpx;
   min-width: 100rpx;
 }
 }
 .n-label {
 .n-label {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #9CA3AF;
   color: #9CA3AF;
 }
 }
 .n-value {
 .n-value {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #374151;
   color: #374151;
   font-weight: 500;
   font-weight: 500;
 }
 }

+ 14 - 11
cfc-frontend/pages/diet/recommendation.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="recommendation-page">
+  <view class="recommendation-page" :style="{ '--font-scale': fontScale }">
 
 
     <scroll-view class="content" scroll-y>
     <scroll-view class="content" scroll-y>
       <!-- 无推荐状态 -->
       <!-- 无推荐状态 -->
@@ -105,7 +105,10 @@
 <script>
 <script>
 import { getDietRecommendation, generateDietRecommendation, completeDietRecommendation, regenerateDietRecommendation } from '@/utils/api.js'
 import { getDietRecommendation, generateDietRecommendation, completeDietRecommendation, regenerateDietRecommendation } from '@/utils/api.js'
 
 
+import fontScaleMixin from '@/mixins/font-scale.js'
+
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data() {
   data() {
     return {
     return {
       recommendation: null,
       recommendation: null,
@@ -276,8 +279,8 @@ export default {
   margin-bottom: 40rpx;
   margin-bottom: 40rpx;
 }
 }
 .empty-icon { font-size: 72rpx; }
 .empty-icon { font-size: 72rpx; }
-.empty-title { font-size: 34rpx; font-weight: 700; color: #333; display: block; margin-bottom: 16rpx; }
-.empty-sub { font-size: 26rpx; color: #999; display: block; margin-bottom: 48rpx; }
+.empty-title { font-size: calc(34rpx * var(--font-scale, 1)); font-weight: 700; color: #333; display: block; margin-bottom: 16rpx; }
+.empty-sub { font-size: calc(26rpx * var(--font-scale, 1)); color: #999; display: block; margin-bottom: 48rpx; }
 .generate-btn {
 .generate-btn {
   background: linear-gradient(135deg, #FF8C42, #FFB366);
   background: linear-gradient(135deg, #FF8C42, #FFB366);
   color: #FFFFFF; padding: 28rpx 60rpx; border-radius: 999rpx;
   color: #FFFFFF; padding: 28rpx 60rpx; border-radius: 999rpx;
@@ -298,7 +301,7 @@ export default {
   padding: 30rpx;
   padding: 30rpx;
 }
 }
 .card-title {
 .card-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
@@ -310,7 +313,7 @@ export default {
   align-items: center;
   align-items: center;
 }
 }
 .date-text {
 .date-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -345,7 +348,7 @@ export default {
   margin-right: 12rpx;
   margin-right: 12rpx;
 }
 }
 .meal-name {
 .meal-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   flex: 1;
   flex: 1;
@@ -364,8 +367,8 @@ export default {
   justify-content: space-between;
   justify-content: space-between;
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
-.dish-name { font-size: 28rpx; font-weight: 600; color: #333; }
-.dish-cal { font-size: 24rpx; color: #C2410C; font-weight: 600; }
+.dish-name { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
+.dish-cal { font-size: calc(24rpx * var(--font-scale, 1)); color: #C2410C; font-weight: 600; }
 .dish-ingredients {
 .dish-ingredients {
   display: flex;
   display: flex;
   flex-wrap: wrap;
   flex-wrap: wrap;
@@ -383,7 +386,7 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .method-text {
 .method-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .dish-actions { display: flex; gap: 16rpx; margin-top: 8rpx; }
 .dish-actions { display: flex; gap: 16rpx; margin-top: 8rpx; }
@@ -401,11 +404,11 @@ export default {
 .nutrition-card .card-body { background: #FFF9F0; border-radius: 0 0 20rpx 20rpx; }
 .nutrition-card .card-body { background: #FFF9F0; border-radius: 0 0 20rpx 20rpx; }
 .nutrition-value { font-size: 40rpx; font-weight: 700; color: #C2410C; display: block; }
 .nutrition-value { font-size: 40rpx; font-weight: 700; color: #C2410C; display: block; }
 .nutrition-unit {
 .nutrition-unit {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .nutrition-label {
 .nutrition-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   display: block;
   display: block;
   margin-top: 4rpx;
   margin-top: 4rpx;

+ 4 - 3
cfc-frontend/pages/diet/record-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="record-detail-page">
+  <view class="record-detail-page" :style="{ '--font-scale': fontScale }">
 
 
     <scroll-view class="content" scroll-y v-if="record">
     <scroll-view class="content" scroll-y v-if="record">
       <!-- 照片 -->
       <!-- 照片 -->
@@ -75,9 +75,10 @@
 <script>
 <script>
 import { getDietDailyRecords } from '@/utils/api.js'
 import { getDietDailyRecords } from '@/utils/api.js'
 import shareMixin from '@/components/share-mixin.js'
 import shareMixin from '@/components/share-mixin.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
-  mixins: [shareMixin],
+  mixins: [shareMixin, fontScaleMixin],
   data() {
   data() {
     return {
     return {
       recordId: null,
       recordId: null,
@@ -212,7 +213,7 @@ export default {
   padding: 30rpx;
   padding: 30rpx;
 }
 }
 .card-title {
 .card-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;

+ 5 - 4
cfc-frontend/pages/diet/records.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <view class="member-bar" v-if="memberList.length > 1">
     <view class="member-bar" v-if="memberList.length > 1">
       <view class="member-tab" :class="{'active': currentMemberId === (item.id || item.userId)}"
       <view class="member-tab" :class="{'active': currentMemberId === (item.id || item.userId)}"
         v-for="(item, mi) in memberList" :key="mi"
         v-for="(item, mi) in memberList" :key="mi"
@@ -178,9 +178,10 @@
 import { getMealList, getMealDaily, getMealWeekly, getMealAlerts, getCautionFamilyMembers, createMealRecord } from '../../utils/api.js'
 import { getMealList, getMealDaily, getMealWeekly, getMealAlerts, getCautionFamilyMembers, createMealRecord } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
 import shareMixin from '../../components/share-mixin.js'
 import shareMixin from '../../components/share-mixin.js'
+import fontScaleMixin from '../../mixins/font-scale.js'
 
 
 export default {
 export default {
-  mixins: [shareMixin],
+  mixins: [shareMixin, fontScaleMixin],
   data() {
   data() {
     return {
     return {
       memberId: null,
       memberId: null,
@@ -417,7 +418,7 @@ export default {
 }
 }
 .card-accent { width: 8rpx; background: linear-gradient(180deg, #FF8C42, #FFB366); flex-shrink: 0; }
 .card-accent { width: 8rpx; background: linear-gradient(180deg, #FF8C42, #FFB366); flex-shrink: 0; }
 .card-body { flex: 1; padding: 24rpx 28rpx; }
 .card-body { flex: 1; padding: 24rpx 28rpx; }
-.card-title { font-size: 28rpx; font-weight: 600; color: #333; margin-bottom: 16rpx; display: block; }
+.card-title { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 600; color: #333; margin-bottom: 16rpx; display: block; }
 
 
 /* 统计行 */
 /* 统计行 */
 .stat-row { display: flex; justify-content: space-around; }
 .stat-row { display: flex; justify-content: space-around; }
@@ -483,7 +484,7 @@ export default {
 .record-time { font-size: 24rpx; color: #999; }
 .record-time { font-size: 24rpx; color: #999; }
 .record-backfill { font-size: 20rpx; padding: 2rpx 10rpx; background: #FFF3E0; color: #E65100; border-radius: 8rpx; }
 .record-backfill { font-size: 20rpx; padding: 2rpx 10rpx; background: #FFF3E0; color: #E65100; border-radius: 8rpx; }
 .record-body { margin-bottom: 8rpx; }
 .record-body { margin-bottom: 8rpx; }
-.record-foods { font-size: 26rpx; color: #333; line-height: 1.5; }
+.record-foods { font-size: calc(26rpx * var(--font-scale, 1)); color: #333; line-height: 1.5; }
 .record-footer { display: flex; gap: 20rpx; margin-bottom: 6rpx; }
 .record-footer { display: flex; gap: 20rpx; margin-bottom: 6rpx; }
 .record-cal { font-size: 22rpx; color: #FF8C42; font-weight: 600; }
 .record-cal { font-size: 22rpx; color: #FF8C42; font-weight: 600; }
 .record-nut { font-size: 22rpx; color: #999; }
 .record-nut { font-size: 22rpx; color: #999; }

+ 25 - 23
cfc-frontend/pages/discover/circle-feed.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="feed-page">
+  <view class="feed-page" :style="{ '--font-scale': fontScale }">
     <!-- 导航栏 -->
     <!-- 导航栏 -->
     <view class="nav-bar">
     <view class="nav-bar">
       <view class="nav-back" @tap="goBack">
       <view class="nav-back" @tap="goBack">
@@ -147,8 +147,10 @@
 <script>
 <script>
 import { getCircleFeed, getCircleMembers, createCirclePost, toggleCircleLike, addCircleComment, getCircleComments, deleteCirclePost } from '@/utils/api.js'
 import { getCircleFeed, getCircleMembers, createCirclePost, toggleCircleLike, addCircleComment, getCircleComments, deleteCirclePost } from '@/utils/api.js'
 import { parseDate } from '@/utils/format.js'
 import { parseDate } from '@/utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data: function() {
   data: function() {
     return {
     return {
       circleId: null,
       circleId: null,
@@ -491,7 +493,7 @@ export default {
   color: #333;
   color: #333;
 }
 }
 .nav-title {
 .nav-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
 }
 }
@@ -511,7 +513,7 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: linear-gradient(135deg, #FF8C42, #FFB366);
   background: linear-gradient(135deg, #FF8C42, #FFB366);
   color: #fff;
   color: #fff;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 700;
   font-weight: 700;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -521,13 +523,13 @@ export default {
 }
 }
 .ch-info { flex: 1; }
 .ch-info { flex: 1; }
 .ch-name {
 .ch-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   display: block;
   display: block;
 }
 }
 .ch-meta {
 .ch-meta {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-top: 4rpx;
   margin-top: 4rpx;
   display: block;
   display: block;
@@ -543,7 +545,7 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .pi-icon { font-size: 40rpx; margin-right: 20rpx; }
 .pi-icon { font-size: 40rpx; margin-right: 20rpx; }
-.pi-placeholder { font-size: 28rpx; color: #bbb; }
+.pi-placeholder { font-size: calc(28rpx * var(--font-scale, 1)); color: #bbb; }
 
 
 /* 滚动区域 */
 /* 滚动区域 */
 .feed-scroll {
 .feed-scroll {
@@ -567,7 +569,7 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #E3F2FD;
   background: #E3F2FD;
   color: #1976D2;
   color: #1976D2;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 700;
   font-weight: 700;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -576,8 +578,8 @@ export default {
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .fa-info { flex: 1; display: flex; flex-direction: column; }
 .fa-info { flex: 1; display: flex; flex-direction: column; }
-.fa-name { font-size: 26rpx; font-weight: 600; color: #333; }
-.fa-time { font-size: 20rpx; color: #999; margin-top: 2rpx; }
+.fa-name { font-size: calc(26rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
+.fa-time { font-size: calc(20rpx * var(--font-scale, 1)); color: #999; margin-top: 2rpx; }
 .fa-type-badge {
 .fa-type-badge {
   font-size: 20rpx;
   font-size: 20rpx;
   padding: 4rpx 12rpx;
   padding: 4rpx 12rpx;
@@ -588,7 +590,7 @@ export default {
 
 
 /* 内容 */
 /* 内容 */
 .feed-content { margin-bottom: 16rpx; }
 .feed-content { margin-bottom: 16rpx; }
-.fc-text { font-size: 28rpx; color: #333; line-height: 1.7; }
+.fc-text { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; line-height: 1.7; }
 .feed-images { display: flex; flex-wrap: wrap; margin-bottom: 16rpx; }
 .feed-images { display: flex; flex-wrap: wrap; margin-bottom: 16rpx; }
 .feed-img {
 .feed-img {
   width: 220rpx;
   width: 220rpx;
@@ -626,9 +628,9 @@ export default {
   margin-right: 10rpx;
   margin-right: 10rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
-.c-name { font-size: 24rpx; color: #FF8C42; font-weight: 600; margin-right: 8rpx; flex-shrink: 0; }
-.c-text { font-size: 24rpx; color: #666; flex: 1; line-height: 1.5; }
-.more-comments { font-size: 22rpx; color: #999; margin-top: 8rpx; display: block; padding: 8rpx 0; }
+.c-name { font-size: calc(24rpx * var(--font-scale, 1)); color: #FF8C42; font-weight: 600; margin-right: 8rpx; flex-shrink: 0; }
+.c-text { font-size: calc(24rpx * var(--font-scale, 1)); color: #666; flex: 1; line-height: 1.5; }
+.more-comments { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; margin-top: 8rpx; display: block; padding: 8rpx 0; }
 .comment-input-area {
 .comment-input-area {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -641,17 +643,17 @@ export default {
   background: #F5F5F5;
   background: #F5F5F5;
   border-radius: 30rpx;
   border-radius: 30rpx;
   padding: 12rpx 20rpx;
   padding: 12rpx 20rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   margin-right: 16rpx;
   margin-right: 16rpx;
 }
 }
-.ci-send { font-size: 26rpx; color: #FF8C42; font-weight: 600; }
+.ci-send { font-size: calc(26rpx * var(--font-scale, 1)); color: #FF8C42; font-weight: 600; }
 
 
 /* 加载状态 */
 /* 加载状态 */
 .loading-more, .end-hint { text-align: center; padding: 24rpx 0; }
 .loading-more, .end-hint { text-align: center; padding: 24rpx 0; }
-.lm-text, .eh-text { font-size: 24rpx; color: #ccc; }
+.lm-text, .eh-text { font-size: calc(24rpx * var(--font-scale, 1)); color: #ccc; }
 .empty-state { text-align: center; padding: 120rpx 0; }
 .empty-state { text-align: center; padding: 120rpx 0; }
 .empty-icon { font-size: 80rpx; display: block; margin-bottom: 16rpx; }
 .empty-icon { font-size: 80rpx; display: block; margin-bottom: 16rpx; }
-.empty-text { font-size: 26rpx; color: #ccc; }
+.empty-text { font-size: calc(26rpx * var(--font-scale, 1)); color: #ccc; }
 .bottom-space { height: 40rpx; }
 .bottom-space { height: 40rpx; }
 
 
 /* 弹窗 */
 /* 弹窗 */
@@ -678,7 +680,7 @@ export default {
   align-items: center;
   align-items: center;
   margin-bottom: 24rpx;
   margin-bottom: 24rpx;
 }
 }
-.modal-title { font-size: 32rpx; font-weight: 600; color: #333; }
+.modal-title { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
 .modal-close { font-size: 32rpx; color: #999; }
 .modal-close { font-size: 32rpx; color: #999; }
 .type-selector {
 .type-selector {
   display: flex;
   display: flex;
@@ -698,14 +700,14 @@ export default {
 }
 }
 .type-active { border-color: #FF8C42; background: #FFF0E0; }
 .type-active { border-color: #FF8C42; background: #FFF0E0; }
 .to-icon { font-size: 36rpx; margin-bottom: 6rpx; }
 .to-icon { font-size: 36rpx; margin-bottom: 6rpx; }
-.to-label { font-size: 22rpx; color: #666; }
+.to-label { font-size: calc(22rpx * var(--font-scale, 1)); color: #666; }
 .post-textarea {
 .post-textarea {
   width: 100%;
   width: 100%;
   height: 200rpx;
   height: 200rpx;
   background: #F8F8F8;
   background: #F8F8F8;
   border-radius: 16rpx;
   border-radius: 16rpx;
   padding: 20rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   line-height: 1.6;
   line-height: 1.6;
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
@@ -736,13 +738,13 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #E3F2FD;
   background: #E3F2FD;
   color: #1976D2;
   color: #1976D2;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 700;
   font-weight: 700;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
   justify-content: center;
   justify-content: center;
   margin-right: 16rpx;
   margin-right: 16rpx;
 }
 }
-.mi-name { font-size: 26rpx; color: #333; flex: 1; }
-.mi-role { font-size: 20rpx; color: #FF8C42; background: #FFF0E0; padding: 4rpx 12rpx; border-radius: 12rpx; }
+.mi-name { font-size: calc(26rpx * var(--font-scale, 1)); color: #333; flex: 1; }
+.mi-role { font-size: calc(20rpx * var(--font-scale, 1)); color: #FF8C42; background: #FFF0E0; padding: 4rpx 12rpx; border-radius: 12rpx; }
 </style>
 </style>

+ 45 - 43
cfc-frontend/pages/health/gut-flora-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
   <scroll-view class="content" scroll-y>
   <scroll-view class="content" scroll-y>
       <!-- 报告头部 -->
       <!-- 报告头部 -->
       <view class="report-header">
       <view class="report-header">
@@ -359,6 +359,7 @@ import HealthKnowledgePopup from '@/pages/health/components/health-knowledge-pop
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
 import { resolveChangeStyle, formatDelta, colorClassFor } from '../../utils/indicator-change.js'
 import { resolveChangeStyle, formatDelta, colorClassFor } from '../../utils/indicator-change.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 var INDICATOR_TYPE_MAP = {
 var INDICATOR_TYPE_MAP = {
   '维生素': 'vitamin',
   '维生素': 'vitamin',
@@ -371,6 +372,7 @@ var INDICATOR_TYPE_MAP = {
 }
 }
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { HealthKnowledgePopup, FeedbackPopup },
   components: { HealthKnowledgePopup, FeedbackPopup },
   data() {
   data() {
     return {
     return {
@@ -1071,16 +1073,16 @@ applyDraftPayload: function(payload) {
 .content { height: calc(100vh - 100rpx); }
 .content { height: calc(100vh - 100rpx); }
 
 
 .report-header { background: linear-gradient(135deg, #4A9BD7, #6366F1); padding: 40rpx 30rpx; color: #fff; }
 .report-header { background: linear-gradient(135deg, #4A9BD7, #6366F1); padding: 40rpx 30rpx; color: #fff; }
-.report-title { font-size: 36rpx; font-weight: 700; display: block; margin-bottom: 16rpx; }
+.report-title { font-size: calc(36rpx * var(--font-scale, 1)); font-weight: 700; display: block; margin-bottom: 16rpx; }
 .report-meta { display: flex; gap: 20rpx; margin-bottom: 6rpx; }
 .report-meta { display: flex; gap: 20rpx; margin-bottom: 6rpx; }
-.meta-item { font-size: 24rpx; opacity: 0.9; }
+.meta-item { font-size: calc(24rpx * var(--font-scale, 1)); opacity: 0.9; }
 .badge-row { display: flex; gap: 16rpx; margin-top: 12rpx; }
 .badge-row { display: flex; gap: 16rpx; margin-top: 12rpx; }
 .badge { padding: 6rpx 20rpx; background: rgba(255,255,255,0.2); border-radius: 20rpx; font-size: 22rpx; }
 .badge { padding: 6rpx 20rpx; background: rgba(255,255,255,0.2); border-radius: 20rpx; font-size: 22rpx; }
 
 
 .scores-wrap { display: flex; flex-wrap: wrap; padding: 20rpx 10rpx; background: #fff; }
 .scores-wrap { display: flex; flex-wrap: wrap; padding: 20rpx 10rpx; background: #fff; }
 .score-item { display: flex; flex-direction: column; align-items: center; margin: 12rpx 10rpx; width: calc(25% - 20rpx); }
 .score-item { display: flex; flex-direction: column; align-items: center; margin: 12rpx 10rpx; width: calc(25% - 20rpx); }
 .score-ring { width: 100rpx; height: 100rpx; border-radius: 50%; border: 6rpx solid; display: flex; align-items: center; justify-content: center; font-size: 32rpx; font-weight: 700; margin-bottom: 8rpx; }
 .score-ring { width: 100rpx; height: 100rpx; border-radius: 50%; border: 6rpx solid; display: flex; align-items: center; justify-content: center; font-size: 32rpx; font-weight: 700; margin-bottom: 8rpx; }
-.score-label { font-size: 22rpx; color: #666; }
+.score-label { font-size: calc(22rpx * var(--font-scale, 1)); color: #666; }
 
 
 .quick-nav { display: flex; padding: 20rpx; background: #fff; margin-bottom: 16rpx; }
 .quick-nav { display: flex; padding: 20rpx; background: #fff; margin-bottom: 16rpx; }
 .nav-card { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 16rpx 0; }
 .nav-card { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 16rpx 0; }
@@ -1091,13 +1093,13 @@ applyDraftPayload: function(payload) {
 }
 }
 .caution-count { color: #DC2626; font-weight: 700; }
 .caution-count { color: #DC2626; font-weight: 700; }
 .nav-icon { font-size: 40rpx; margin-bottom: 6rpx; }
 .nav-icon { font-size: 40rpx; margin-bottom: 6rpx; }
-.nav-label { font-size: 24rpx; color: #333; }
+.nav-label { font-size: calc(24rpx * var(--font-scale, 1)); color: #333; }
 .nav-count { font-size: 20rpx; color: #999; }
 .nav-count { font-size: 20rpx; color: #999; }
 
 
 .accordion-section { background: #fff; margin-bottom: 16rpx; }
 .accordion-section { background: #fff; margin-bottom: 16rpx; }
 .accordion-header { display: flex; justify-content: space-between; padding: 30rpx; border-bottom: 1rpx solid #f0f0f0; }
 .accordion-header { display: flex; justify-content: space-between; padding: 30rpx; border-bottom: 1rpx solid #f0f0f0; }
-.accordion-title { font-size: 30rpx; font-weight: 600; color: #333; }
-.accordion-stats { font-size: 22rpx; color: #999; margin-left: 16rpx; }
+.accordion-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
+.accordion-stats { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; margin-left: 16rpx; }
 .abnormal-num { color: #C62828; font-weight: 700; }
 .abnormal-num { color: #C62828; font-weight: 700; }
 .accordion-arrow { font-size: 24rpx; color: #999; }
 .accordion-arrow { font-size: 24rpx; color: #999; }
 .accordion-body { padding: 10rpx 30rpx 20rpx; }
 .accordion-body { padding: 10rpx 30rpx 20rpx; }
@@ -1114,37 +1116,37 @@ applyDraftPayload: function(payload) {
 .risk-card-inline.risk-level-warning { border-left-color: #F59E0B; }
 .risk-card-inline.risk-level-warning { border-left-color: #F59E0B; }
 .risk-card-inline.risk-level-high { border-left-color: #EF4444; }
 .risk-card-inline.risk-level-high { border-left-color: #EF4444; }
 .risk-card-inline.risk-level-abnormal { border-left-color: #C62828; }
 .risk-card-inline.risk-level-abnormal { border-left-color: #C62828; }
-.risk-name-inline { font-size: 28rpx; color: #333; flex: 1; }
+.risk-name-inline { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; flex: 1; }
 .risk-badge-inline { padding: 4rpx 16rpx; border-radius: 20rpx; font-size: 22rpx; flex-shrink: 0; }
 .risk-badge-inline { padding: 4rpx 16rpx; border-radius: 20rpx; font-size: 22rpx; flex-shrink: 0; }
 .risk-badge-inline.badge-low { background: #E8F5E9; color: #2E7D32; }
 .risk-badge-inline.badge-low { background: #E8F5E9; color: #2E7D32; }
 .risk-badge-inline.badge-warning { background: #FFF3E0; color: #E65100; }
 .risk-badge-inline.badge-warning { background: #FFF3E0; color: #E65100; }
 .risk-badge-inline.badge-high { background: #FFEBEE; color: #C62828; }
 .risk-badge-inline.badge-high { background: #FFEBEE; color: #C62828; }
 .risk-badge-inline.badge-abnormal { background: #C62828; color: #fff; }
 .risk-badge-inline.badge-abnormal { background: #C62828; color: #fff; }
-.risk-value-inline { font-size: 22rpx; color: #999; margin-left: 16rpx; }
+.risk-value-inline { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; margin-left: 16rpx; }
 
 
 /* 菌群风险分组手风琴 */
 /* 菌群风险分组手风琴 */
 .risk-group-item { padding: 12rpx 0; border-bottom: 1rpx solid #f5f5f5; }
 .risk-group-item { padding: 12rpx 0; border-bottom: 1rpx solid #f5f5f5; }
 .risk-group-header { display: flex; align-items: center; gap: 12rpx; padding: 8rpx 0; }
 .risk-group-header { display: flex; align-items: center; gap: 12rpx; padding: 8rpx 0; }
-.risk-group-name { font-size: 28rpx; color: #333; flex: 1; }
+.risk-group-name { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; flex: 1; }
 .risk-group-arrow { font-size: 24rpx; color: #999; }
 .risk-group-arrow { font-size: 24rpx; color: #999; }
 .risk-group-body { padding: 8rpx 0 12rpx; }
 .risk-group-body { padding: 8rpx 0 12rpx; }
-.risk-level { font-size: 22rpx; padding: 4rpx 14rpx; border-radius: 8rpx; }
+.risk-level { font-size: calc(22rpx * var(--font-scale, 1)); padding: 4rpx 14rpx; border-radius: 8rpx; }
 .risk-level.risk-good { background: #E8F5E9; color: #2E7D32; }
 .risk-level.risk-good { background: #E8F5E9; color: #2E7D32; }
 .risk-level.risk-warning { background: #FFF3E0; color: #E65100; }
 .risk-level.risk-warning { background: #FFF3E0; color: #E65100; }
 .risk-level.risk-danger { background: #FFEBEE; color: #C62828; }
 .risk-level.risk-danger { background: #FFEBEE; color: #C62828; }
-.risk-bacteria { font-size: 24rpx; color: #666; line-height: 1.6; }
+.risk-bacteria { font-size: calc(24rpx * var(--font-scale, 1)); color: #666; line-height: 1.6; }
 
 
 .sub-group { margin-bottom: 16rpx; }
 .sub-group { margin-bottom: 16rpx; }
-.sub-group-title { font-size: 26rpx; color: #4A9BD7; font-weight: 600; display: block; margin: 12rpx 0 8rpx; }
+.sub-group-title { font-size: calc(26rpx * var(--font-scale, 1)); color: #4A9BD7; font-weight: 600; display: block; margin: 12rpx 0 8rpx; }
 
 
 .indicator-card { padding: 16rpx 0; border-bottom: 1rpx solid #f5f5f5; }
 .indicator-card { padding: 16rpx 0; border-bottom: 1rpx solid #f5f5f5; }
 .indicator-row { display: flex; align-items: center; justify-content: space-between; }
 .indicator-row { display: flex; align-items: center; justify-content: space-between; }
-.indicator-name { font-size: 28rpx; color: #333; flex: 1; }
+.indicator-name { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; flex: 1; }
 .arrow-up { color: #C62828; font-size: 22rpx; }
 .arrow-up { color: #C62828; font-size: 22rpx; }
 .arrow-down { color: #E65100; font-size: 22rpx; }
 .arrow-down { color: #E65100; font-size: 22rpx; }
 .arrow-warn { color: #F59E0B; font-size: 22rpx; }
 .arrow-warn { color: #F59E0B; font-size: 22rpx; }
 
 
-.val-text { font-size: 28rpx; font-weight: 600; color: #333; }
+.val-text { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
 .val-high { color: #C62828; }
 .val-high { color: #C62828; }
 .val-excess { color: #C62828; }
 .val-excess { color: #C62828; }
 .val-low { color: #C62828; }
 .val-low { color: #C62828; }
@@ -1153,22 +1155,22 @@ applyDraftPayload: function(payload) {
 .val-abnormal { color: #C62828; }
 .val-abnormal { color: #C62828; }
 .val-warning { color: #F59E0B; }
 .val-warning { color: #F59E0B; }
 
 
-.indicator-range { font-size: 22rpx; color: #bbb; display: block; margin-top: 4rpx; }
+.indicator-range { font-size: calc(22rpx * var(--font-scale, 1)); color: #bbb; display: block; margin-top: 4rpx; }
 
 
 /* 指标知识库 "?" 按钮(与通用报告页一致) */
 /* 指标知识库 "?" 按钮(与通用报告页一致) */
 .ind-help-btn { display: inline-flex; align-items: center; justify-content: center; width: 36rpx; height: 36rpx; border-radius: 50%; background: #E3F2FD; color: #1976D2; font-size: 22rpx; font-weight: 600; margin-left: 8rpx; flex-shrink: 0; }
 .ind-help-btn { display: inline-flex; align-items: center; justify-content: center; width: 36rpx; height: 36rpx; border-radius: 50%; background: #E3F2FD; color: #1976D2; font-size: 22rpx; font-weight: 600; margin-left: 8rpx; flex-shrink: 0; }
 
 
 /* 综合评级行 */
 /* 综合评级行 */
 .rating-line { margin: 12rpx 0 0; }
 .rating-line { margin: 12rpx 0 0; }
-.rating-text { font-size: 24rpx; color: #666; display: block; }
+.rating-text { font-size: calc(24rpx * var(--font-scale, 1)); color: #666; display: block; }
 
 
 /* 指标单位与症状 */
 /* 指标单位与症状 */
-.indicator-unit { font-size: 22rpx; color: #999; margin-left: 6rpx; }
-.indicator-symptoms { font-size: 22rpx; color: #E65100; display: block; margin-top: 4rpx; }
+.indicator-unit { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; margin-left: 6rpx; }
+.indicator-symptoms { font-size: calc(22rpx * var(--font-scale, 1)); color: #E65100; display: block; margin-top: 4rpx; }
 
 
 .indicator-edit { display: flex; gap: 8rpx; align-items: center; }
 .indicator-edit { display: flex; gap: 8rpx; align-items: center; }
-.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 6rpx 10rpx; font-size: 26rpx; width: 100rpx; }
-.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 6rpx 10rpx; font-size: 24rpx; color: #333; }
+.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 6rpx 10rpx; font-size: calc(26rpx * var(--font-scale, 1)); width: 100rpx; }
+.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 6rpx 10rpx; font-size: calc(24rpx * var(--font-scale, 1)); color: #333; }
 
 
 .fab { position: fixed; right: 30rpx; bottom: 40rpx; width: 100rpx; height: 100rpx; background: #4A9BD7; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4rpx 16rpx rgba(74,155,215,0.4); }
 .fab { position: fixed; right: 30rpx; bottom: 40rpx; width: 100rpx; height: 100rpx; background: #4A9BD7; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4rpx 16rpx rgba(74,155,215,0.4); }
 .fab-icon { font-size: 40rpx; color: #fff; }
 .fab-icon { font-size: 40rpx; color: #fff; }
@@ -1177,7 +1179,7 @@ applyDraftPayload: function(payload) {
 .btn-discard { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
 .btn-discard { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
 .btn-confirm { flex: 1; padding: 20rpx; background: #4A9BD7; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #fff; }
 .btn-confirm { flex: 1; padding: 20rpx; background: #4A9BD7; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #fff; }
 .btn-parsing { flex: 1; padding: 20rpx; background: #f0f0f0; border-radius: 12rpx; text-align: center; }
 .btn-parsing { flex: 1; padding: 20rpx; background: #f0f0f0; border-radius: 12rpx; text-align: center; }
-.parsing-text { font-size: 28rpx; color: #999; }
+.parsing-text { font-size: calc(28rpx * var(--font-scale, 1)); color: #999; }
 
 
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; z-index: 100; }
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; z-index: 100; }
 .btn-cancel { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
 .btn-cancel { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
@@ -1192,7 +1194,7 @@ applyDraftPayload: function(payload) {
   border: 1rpx solid #f0f0f0;
   border: 1rpx solid #f0f0f0;
 }
 }
 .feedback-icon { font-size: 32rpx; margin-right: 12rpx; }
 .feedback-icon { font-size: 32rpx; margin-right: 12rpx; }
-.feedback-text { flex: 1; font-size: 26rpx; color: #4A9BD7; }
+.feedback-text { flex: 1; font-size: calc(26rpx * var(--font-scale, 1)); color: #4A9BD7; }
 .feedback-arrow { font-size: 28rpx; color: #ccc; }
 .feedback-arrow { font-size: 28rpx; color: #ccc; }
 
 
 .bottom-spacer { height: 40rpx; }
 .bottom-spacer { height: 40rpx; }
@@ -1206,7 +1208,7 @@ applyDraftPayload: function(payload) {
   border-left: 6rpx solid #FFB300;
   border-left: 6rpx solid #FFB300;
 }
 }
 .interp-text {
 .interp-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #795548;
   color: #795548;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -1217,7 +1219,7 @@ applyDraftPayload: function(payload) {
   border-left-color: #00897B;
   border-left-color: #00897B;
 }
 }
 .interp-label {
 .interp-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #00695C;
   color: #00695C;
   display: block;
   display: block;
@@ -1238,13 +1240,13 @@ applyDraftPayload: function(payload) {
   gap: 8rpx;
   gap: 8rpx;
 }
 }
 .summary-title {
 .summary-title {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #fff;
   color: #fff;
   opacity: 0.95;
   opacity: 0.95;
 }
 }
 .summary-text {
 .summary-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #fff;
   color: #fff;
   line-height: 1.6;
   line-height: 1.6;
   opacity: 0.95;
   opacity: 0.95;
@@ -1275,13 +1277,13 @@ applyDraftPayload: function(payload) {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .analysis-title {
 .analysis-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   display: block;
   display: block;
 }
 }
 .analysis-subtitle {
 .analysis-subtitle {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   display: block;
   display: block;
   margin-top: 4rpx;
   margin-top: 4rpx;
@@ -1301,7 +1303,7 @@ applyDraftPayload: function(payload) {
   align-items: center;
   align-items: center;
   padding: 12rpx 0;
   padding: 12rpx 0;
   border-bottom: 1rpx solid #f5f5f5;
   border-bottom: 1rpx solid #f5f5f5;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 }
 .change-row:last-child { border-bottom: none; }
 .change-row:last-child { border-bottom: none; }
 .change-name {
 .change-name {
@@ -1335,7 +1337,7 @@ applyDraftPayload: function(payload) {
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .change-trend {
 .change-trend {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   margin-left: 8rpx;
   margin-left: 8rpx;
   flex: 1;
   flex: 1;
@@ -1346,7 +1348,7 @@ applyDraftPayload: function(payload) {
   border-top: 1rpx solid #f0f0f0;
   border-top: 1rpx solid #f0f0f0;
 }
 }
 .change-more-text {
 .change-more-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #4A9BD7;
   color: #4A9BD7;
 }
 }
 .analysis-card {
 .analysis-card {
@@ -1357,7 +1359,7 @@ applyDraftPayload: function(payload) {
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
 }
 }
 .card-label {
 .card-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   display: block;
   display: block;
@@ -1374,7 +1376,7 @@ applyDraftPayload: function(payload) {
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .func-dim-name {
 .func-dim-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -1407,7 +1409,7 @@ applyDraftPayload: function(payload) {
 .fill-danger { background: #EF4444; }
 .fill-danger { background: #EF4444; }
 .fill-normal { background: #6B7280; }
 .fill-normal { background: #6B7280; }
 .func-dim-summary {
 .func-dim-summary {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   line-height: 1.5;
   line-height: 1.5;
 }
 }
@@ -1418,16 +1420,16 @@ applyDraftPayload: function(payload) {
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .pb-label {
 .pb-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
 }
 }
 .pb-ratio {
 .pb-ratio {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #6366F1;
   color: #6366F1;
   font-weight: bold;
   font-weight: bold;
 }
 }
 .pattern-name {
 .pattern-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #FF8C42;
   color: #FF8C42;
   display: block;
   display: block;
@@ -1443,12 +1445,12 @@ applyDraftPayload: function(payload) {
 }
 }
 .risk-item:last-child { border-bottom: none; }
 .risk-item:last-child { border-bottom: none; }
 .risk-name {
 .risk-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
 .risk-level {
 .risk-level {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 2rpx 14rpx;
   padding: 2rpx 14rpx;
   border-radius: 20rpx;
   border-radius: 20rpx;
   color: #fff;
   color: #fff;
@@ -1457,7 +1459,7 @@ applyDraftPayload: function(payload) {
 .risk-warning { background: #F59E0B; }
 .risk-warning { background: #F59E0B; }
 .risk-danger { background: #EF4444; }
 .risk-danger { background: #EF4444; }
 .risk-bacteria {
 .risk-bacteria {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   width: 100%;
   width: 100%;
   margin-top: 4rpx;
   margin-top: 4rpx;
@@ -1472,13 +1474,13 @@ applyDraftPayload: function(payload) {
 }
 }
 .probiotic-item:last-child { border-bottom: none; }
 .probiotic-item:last-child { border-bottom: none; }
 .probiotic-name {
 .probiotic-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   width: 120rpx;
   width: 120rpx;
 }
 }
 .probiotic-advice {
 .probiotic-advice {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   width: 100%;
   width: 100%;
   margin-top: 4rpx;
   margin-top: 4rpx;

+ 18 - 16
cfc-frontend/pages/health/gut-flora-foods-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
 
 
     <view class="member-bar" v-if="memberList.length > 1">
     <view class="member-bar" v-if="memberList.length > 1">
       <view class="member-tab" :class="{'active': currentMemberId === (item.id || item.userId)}"
       <view class="member-tab" :class="{'active': currentMemberId === (item.id || item.userId)}"
@@ -136,8 +136,10 @@
 <script>
 <script>
 import { getHealthFoods, editHealthReport, queryFoodKnowledge, getCautionFamilyMembers, getFoodCautionTrend } from '../../utils/api.js'
 import { getHealthFoods, editHealthReport, queryFoodKnowledge, getCautionFamilyMembers, getFoodCautionTrend } from '../../utils/api.js'
 import MiniTrend from '../growth/mini-trend.vue'
 import MiniTrend from '../growth/mini-trend.vue'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { MiniTrend },
   components: { MiniTrend },
   data() {
   data() {
     return {
     return {
@@ -398,7 +400,7 @@ methods: {
   border-radius: 20rpx;
   border-radius: 20rpx;
   background: #f5f5f5;
   background: #f5f5f5;
   color: #666;
   color: #666;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
 }
 }
 .member-tab.active {
 .member-tab.active {
@@ -416,7 +418,7 @@ methods: {
   padding: 12rpx 24rpx;
   padding: 12rpx 24rpx;
 }
 }
 .search-icon { font-size: 28rpx; margin-right: 12rpx; }
 .search-icon { font-size: 28rpx; margin-right: 12rpx; }
-.search-input { flex: 1; font-size: 28rpx; }
+.search-input { flex: 1; font-size: calc(28rpx * var(--font-scale, 1)); }
 .search-clear { font-size: 28rpx; color: #999; padding: 0 8rpx; }
 .search-clear { font-size: 28rpx; color: #999; padding: 0 8rpx; }
 
 
 /* 分类筛选 + 排序 */
 /* 分类筛选 + 排序 */
@@ -448,7 +450,7 @@ methods: {
 .food-card.band-null { border-left-color: #ccc; }
 .food-card.band-null { border-left-color: #ccc; }
 
 
 .food-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; }
 .food-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; }
-.food-name { font-size: 30rpx; font-weight: 600; color: #1a1a1a; flex: 1; min-width: 0; }
+.food-name { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 600; color: #1a1a1a; flex: 1; min-width: 0; }
 .food-right { display: flex; align-items: center; gap: 10rpx; flex-shrink: 0; }
 .food-right { display: flex; align-items: center; gap: 10rpx; flex-shrink: 0; }
 
 
 .status-tag {
 .status-tag {
@@ -478,7 +480,7 @@ methods: {
 .score-null { background: #F5F5F5; color: #999; }
 .score-null { background: #F5F5F5; color: #999; }
 
 
 .food-meta { margin-bottom: 12rpx; }
 .food-meta { margin-bottom: 12rpx; }
-.meta-item { font-size: 24rpx; color: #888; background: #f5f5f5; padding: 4rpx 12rpx; border-radius: 8rpx; }
+.meta-item { font-size: calc(24rpx * var(--font-scale, 1)); color: #888; background: #f5f5f5; padding: 4rpx 12rpx; border-radius: 8rpx; }
 
 
 .score-bar-wrap { display: flex; align-items: center; gap: 12rpx; margin-bottom: 10rpx; }
 .score-bar-wrap { display: flex; align-items: center; gap: 12rpx; margin-bottom: 10rpx; }
 .score-bar-bg { flex: 1; height: 12rpx; background: #fee2e2; border-radius: 6rpx; overflow: hidden; }
 .score-bar-bg { flex: 1; height: 12rpx; background: #fee2e2; border-radius: 6rpx; overflow: hidden; }
@@ -487,37 +489,37 @@ methods: {
 .score-bar-fill.mild   { background: #AFB42B; }
 .score-bar-fill.mild   { background: #AFB42B; }
 .score-bar-fill.warn   { background: #F57C00; }
 .score-bar-fill.warn   { background: #F57C00; }
 .score-bar-fill.danger { background: #C62828; }
 .score-bar-fill.danger { background: #C62828; }
-.score-val { font-size: 24rpx; font-weight: 600; color: #666; min-width: 50rpx; text-align: right; }
+.score-val { font-size: calc(24rpx * var(--font-scale, 1)); font-weight: 600; color: #666; min-width: 50rpx; text-align: right; }
 
 
-.change-row { display: flex; align-items: center; gap: 8rpx; margin-bottom: 8rpx; font-size: 24rpx; }
+.change-row { display: flex; align-items: center; gap: 8rpx; margin-bottom: 8rpx; font-size: calc(24rpx * var(--font-scale, 1)); }
 .change-label { color: #999; }
 .change-label { color: #999; }
 .change-up { color: #10B981; font-weight: 600; }
 .change-up { color: #10B981; font-weight: 600; }
 .change-down { color: #EF4444; font-weight: 600; }
 .change-down { color: #EF4444; font-weight: 600; }
 
 
 .food-nutrition { display: flex; gap: 20rpx; flex-wrap: wrap; }
 .food-nutrition { display: flex; gap: 20rpx; flex-wrap: wrap; }
-.nut-item { font-size: 22rpx; color: #999; }
+.nut-item { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; }
 
 
 .food-edit-row { display: flex; align-items: center; margin-top: 8rpx; }
 .food-edit-row { display: flex; align-items: center; margin-top: 8rpx; }
-.edit-label { font-size: 26rpx; color: #666; margin-right: 12rpx; }
-.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: 26rpx; width: 140rpx; color: #333; background: #fff; }
+.edit-label { font-size: calc(26rpx * var(--font-scale, 1)); color: #666; margin-right: 12rpx; }
+.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: calc(26rpx * var(--font-scale, 1)); width: 140rpx; color: #333; background: #fff; }
 
 
-.empty-hint { text-align: center; color: #ccc; padding: 60rpx 0; font-size: 28rpx; }
+.empty-hint { text-align: center; color: #ccc; padding: 60rpx 0; font-size: calc(28rpx * var(--font-scale, 1)); }
 .loading-state { text-align: center; padding: 80rpx 0; }
 .loading-state { text-align: center; padding: 80rpx 0; }
-.loading-text { font-size: 26rpx; color: #999; }
+.loading-text { font-size: calc(26rpx * var(--font-scale, 1)); color: #999; }
 .bottom-spacer { height: 40rpx; }
 .bottom-spacer { height: 40rpx; }
 
 
 /* 知识库弹窗 */
 /* 知识库弹窗 */
 .knowledge-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 999; }
 .knowledge-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 999; }
 .knowledge-popup { width: 80%; background: #fff; border-radius: 20rpx; overflow: hidden; }
 .knowledge-popup { width: 80%; background: #fff; border-radius: 20rpx; overflow: hidden; }
 .knowledge-header { display: flex; align-items: center; justify-content: space-between; padding: 30rpx; border-bottom: 1rpx solid #f0f0f0; }
 .knowledge-header { display: flex; align-items: center; justify-content: space-between; padding: 30rpx; border-bottom: 1rpx solid #f0f0f0; }
-.knowledge-title { font-size: 32rpx; font-weight: 600; color: #333; }
+.knowledge-title { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: 600; color: #333; }
 .knowledge-close { font-size: 32rpx; color: #999; padding: 0 8rpx; }
 .knowledge-close { font-size: 32rpx; color: #999; padding: 0 8rpx; }
 .knowledge-body { padding: 30rpx; max-height: 60vh; overflow-y: auto; }
 .knowledge-body { padding: 30rpx; max-height: 60vh; overflow-y: auto; }
 .knowledge-row { display: flex; align-items: center; padding: 12rpx 0; border-bottom: 1rpx solid #f5f5f5; }
 .knowledge-row { display: flex; align-items: center; padding: 12rpx 0; border-bottom: 1rpx solid #f5f5f5; }
-.knowledge-label { font-size: 26rpx; color: #999; width: 120rpx; }
-.knowledge-value { font-size: 26rpx; color: #333; flex: 1; }
+.knowledge-label { font-size: calc(26rpx * var(--font-scale, 1)); color: #999; width: 120rpx; }
+.knowledge-value { font-size: calc(26rpx * var(--font-scale, 1)); color: #333; flex: 1; }
 .knowledge-desc { margin-top: 16rpx; }
 .knowledge-desc { margin-top: 16rpx; }
-.knowledge-desc-text { font-size: 26rpx; color: #666; line-height: 1.6; }
+.knowledge-desc-text { font-size: calc(26rpx * var(--font-scale, 1)); color: #666; line-height: 1.6; }
 
 
 .edit-fab { position: fixed; right: 30rpx; bottom: 40rpx; background: linear-gradient(135deg, #FF8C42, #FFB366); color: #fff; border-radius: 40rpx; padding: 16rpx 32rpx; font-size: 26rpx; box-shadow: 0 4rpx 16rpx rgba(255,140,66,0.35); }
 .edit-fab { position: fixed; right: 30rpx; bottom: 40rpx; background: linear-gradient(135deg, #FF8C42, #FFB366); color: #fff; border-radius: 40rpx; padding: 16rpx 32rpx; font-size: 26rpx; box-shadow: 0 4rpx 16rpx rgba(255,140,66,0.35); }
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; }
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; }

+ 19 - 17
cfc-frontend/pages/health/gut-flora-risks-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <text class="nav-edit" @tap="toggleEdit">{{ isEditing ? '完成' : '编辑' }}</text>
     <text class="nav-edit" @tap="toggleEdit">{{ isEditing ? '完成' : '编辑' }}</text>
 
 
     <!-- 头部摘要 -->
     <!-- 头部摘要 -->
@@ -132,8 +132,10 @@
 <script>
 <script>
 import { getReportDetail, editHealthReport, queryKnowledgeBase, queryIndicatorKnowledge, queryDiseaseKnowledge } from '../../utils/api.js'
 import { getReportDetail, editHealthReport, queryKnowledgeBase, queryIndicatorKnowledge, queryDiseaseKnowledge } from '../../utils/api.js'
 import HealthKnowledgePopup from '@/pages/health/components/health-knowledge-popup.vue'
 import HealthKnowledgePopup from '@/pages/health/components/health-knowledge-popup.vue'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { HealthKnowledgePopup },
   components: { HealthKnowledgePopup },
   data() {
   data() {
     return {
     return {
@@ -331,7 +333,7 @@ export default {
 
 
 <style scoped>
 <style scoped>
 .page { min-height: 100vh; background: #f5f6fa; }
 .page { min-height: 100vh; background: #f5f6fa; }
-.nav-edit { font-size: 28rpx; color: #4A9BD7; padding: 10rpx 30rpx; text-align: right; display: block; }
+.nav-edit { font-size: calc(28rpx * var(--font-scale, 1)); color: #4A9BD7; padding: 10rpx 30rpx; text-align: right; display: block; }
 
 
 /* ===== 头部摘要 ===== */
 /* ===== 头部摘要 ===== */
 .header-summary {
 .header-summary {
@@ -356,7 +358,7 @@ export default {
 .stat-low { color: #d4edda; }
 .stat-low { color: #d4edda; }
 .stat-total { color: #fff; }
 .stat-total { color: #fff; }
 .stat-label {
 .stat-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.8);
   color: rgba(255,255,255,0.8);
   margin-top: 6rpx;
   margin-top: 6rpx;
 }
 }
@@ -378,7 +380,7 @@ export default {
   background: #4A9BD7;
   background: #4A9BD7;
 }
 }
 .section-label {
 .section-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
 }
 }
@@ -416,7 +418,7 @@ export default {
   min-width: 0;
   min-width: 0;
 }
 }
 .risk-name {
 .risk-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   flex: 1;
   flex: 1;
@@ -462,7 +464,7 @@ export default {
 .fill-high { background: #EF4444; }
 .fill-high { background: #EF4444; }
 .fill-abnormal { background: #C62828; }
 .fill-abnormal { background: #C62828; }
 .risk-value-text {
 .risk-value-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 
 
@@ -476,12 +478,12 @@ export default {
   border-radius: 10rpx;
   border-radius: 10rpx;
 }
 }
 .desc-label {
 .desc-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .desc-content {
 .desc-content {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   line-height: 1.5;
   line-height: 1.5;
   flex: 1;
   flex: 1;
@@ -495,7 +497,7 @@ export default {
   margin-bottom: 14rpx;
   margin-bottom: 14rpx;
 }
 }
 .bacteria-label {
 .bacteria-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   flex-shrink: 0;
   flex-shrink: 0;
   margin-right: 10rpx;
   margin-right: 10rpx;
@@ -515,11 +517,11 @@ export default {
   padding: 6rpx 12rpx;
   padding: 6rpx 12rpx;
 }
 }
 .bacteria-name {
 .bacteria-name {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
 }
 }
 .bacteria-cor {
 .bacteria-cor {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 2rpx 10rpx;
   padding: 2rpx 10rpx;
   border-radius: 6rpx;
   border-radius: 6rpx;
 }
 }
@@ -547,11 +549,11 @@ export default {
 .tag-high { background: #FFEBEE; color: #C62828; }
 .tag-high { background: #FFEBEE; color: #C62828; }
 .tag-abnormal { background: #C62828; color: #fff; }
 .tag-abnormal { background: #C62828; color: #fff; }
 .risk-value {
 .risk-value {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
 }
 }
 .risk-more {
 .risk-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #4A9BD7;
   color: #4A9BD7;
   margin-left: auto;
   margin-left: auto;
 }
 }
@@ -566,11 +568,11 @@ export default {
   border-top: 1rpx solid #f0f0f0;
   border-top: 1rpx solid #f0f0f0;
   margin-top: 4rpx;
   margin-top: 4rpx;
 }
 }
-.edit-label { font-size: 26rpx; color: #666; }
-.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: 26rpx; width: 120rpx; }
-.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: 26rpx; color: #333; }
+.edit-label { font-size: calc(26rpx * var(--font-scale, 1)); color: #666; }
+.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: calc(26rpx * var(--font-scale, 1)); width: 120rpx; }
+.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: calc(26rpx * var(--font-scale, 1)); color: #333; }
 
 
-.empty-hint { text-align: center; color: #ccc; padding: 80rpx 0; font-size: 28rpx; }
+.empty-hint { text-align: center; color: #ccc; padding: 80rpx 0; font-size: calc(28rpx * var(--font-scale, 1)); }
 .bottom-spacer { height: 40rpx; }
 .bottom-spacer { height: 40rpx; }
 
 
 /* 底栏 */
 /* 底栏 */

+ 11 - 9
cfc-frontend/pages/health/gut-flora-species-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
 <text class="nav-edit" @tap="toggleEdit">{{ isEditing ? '完成' : '编辑' }}</text>
 <text class="nav-edit" @tap="toggleEdit">{{ isEditing ? '完成' : '编辑' }}</text>
 
 
     <view class="tabs">
     <view class="tabs">
@@ -52,8 +52,10 @@
 <script>
 <script>
 import { getReportDetail, editHealthReport, queryKnowledgeBase, queryBacteriaKnowledge } from '../../utils/api.js'
 import { getReportDetail, editHealthReport, queryKnowledgeBase, queryBacteriaKnowledge } from '../../utils/api.js'
 import HealthKnowledgePopup from '@/pages/health/components/health-knowledge-popup.vue'
 import HealthKnowledgePopup from '@/pages/health/components/health-knowledge-popup.vue'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { HealthKnowledgePopup },
   components: { HealthKnowledgePopup },
   data() {
   data() {
     return {
     return {
@@ -249,15 +251,15 @@ export default {
 
 
 <style scoped>
 <style scoped>
 .page { min-height: 100vh; background: #f8f8f8; }
 .page { min-height: 100vh; background: #f8f8f8; }
-.nav-edit { font-size: 28rpx; color: #4A9BD7; padding: 10rpx 0; }
+.nav-edit { font-size: calc(28rpx * var(--font-scale, 1)); color: #4A9BD7; padding: 10rpx 0; }
 .tabs { background: #fff; padding: 10rpx 20rpx; display: flex; flex-wrap: wrap; border-bottom: 1rpx solid #eee; }
 .tabs { background: #fff; padding: 10rpx 20rpx; display: flex; flex-wrap: wrap; border-bottom: 1rpx solid #eee; }
-.tab-item { display: inline-block; padding: 12rpx 24rpx; margin: 6rpx; border-radius: 30rpx; font-size: 24rpx; background: #f0f0f0; color: #666; }
+.tab-item { display: inline-block; padding: 12rpx 24rpx; margin: 6rpx; border-radius: 30rpx; font-size: calc(24rpx * var(--font-scale, 1)); background: #f0f0f0; color: #666; }
 .tab-active { background: #4A9BD7; color: #fff; }
 .tab-active { background: #4A9BD7; color: #fff; }
 .tab-count { font-size: 20rpx; opacity: 0.7; margin-left: 6rpx; }
 .tab-count { font-size: 20rpx; opacity: 0.7; margin-left: 6rpx; }
 .content { padding: 20rpx 30rpx; height: calc(100vh - 200rpx); }
 .content { padding: 20rpx 30rpx; height: calc(100vh - 200rpx); }
 .flora-card { background: #fff; border-radius: 16rpx; padding: 24rpx; margin-bottom: 16rpx; }
 .flora-card { background: #fff; border-radius: 16rpx; padding: 24rpx; margin-bottom: 16rpx; }
 .flora-header { display: flex; align-items: center; margin-bottom: 10rpx; }
 .flora-header { display: flex; align-items: center; margin-bottom: 10rpx; }
-.flora-name { font-size: 28rpx; font-weight: 600; color: #333; flex: 1; }
+.flora-name { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 600; color: #333; flex: 1; }
 .flora-name.status-high { color: #C62828; }
 .flora-name.status-high { color: #C62828; }
 .flora-name.status-excess { color: #C62828; }
 .flora-name.status-excess { color: #C62828; }
 .flora-name.status-low { color: #C62828; }
 .flora-name.status-low { color: #C62828; }
@@ -267,12 +269,12 @@ export default {
 .arrow-down { color: #E65100; font-size: 22rpx; }
 .arrow-down { color: #E65100; font-size: 22rpx; }
 .flora-level-tag { padding: 2rpx 12rpx; background: #E3F2FD; border-radius: 16rpx; font-size: 20rpx; color: #4A9BD7; }
 .flora-level-tag { padding: 2rpx 12rpx; background: #E3F2FD; border-radius: 16rpx; font-size: 20rpx; color: #4A9BD7; }
 .flora-details { display: flex; align-items: center; }
 .flora-details { display: flex; align-items: center; }
-.detail-item { flex: 1; font-size: 22rpx; color: #999; text-align: center; white-space: nowrap; }
+.detail-item { flex: 1; font-size: calc(22rpx * var(--font-scale, 1)); color: #999; text-align: center; white-space: nowrap; }
 .flora-edit-row { display: flex; align-items: center; gap: 12rpx; flex-wrap: wrap; }
 .flora-edit-row { display: flex; align-items: center; gap: 12rpx; flex-wrap: wrap; }
-.edit-label { font-size: 26rpx; color: #666; }
-.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: 26rpx; width: 140rpx; }
-.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: 26rpx; color: #333; }
-.empty-hint { text-align: center; color: #ccc; padding: 60rpx 0; font-size: 28rpx; }
+.edit-label { font-size: calc(26rpx * var(--font-scale, 1)); color: #666; }
+.edit-input { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: calc(26rpx * var(--font-scale, 1)); width: 140rpx; }
+.edit-picker { border: 1rpx solid #ddd; border-radius: 8rpx; padding: 8rpx 12rpx; font-size: calc(26rpx * var(--font-scale, 1)); color: #333; }
+.empty-hint { text-align: center; color: #ccc; padding: 60rpx 0; font-size: calc(28rpx * var(--font-scale, 1)); }
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; }
 .bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; gap: 20rpx; }
 .btn-cancel { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
 .btn-cancel { flex: 1; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #666; }
 .btn-save { flex: 1; padding: 20rpx; background: #4A9BD7; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #fff; }
 .btn-save { flex: 1; padding: 20rpx; background: #4A9BD7; border-radius: 12rpx; text-align: center; font-size: 28rpx; color: #fff; }

+ 44 - 42
cfc-frontend/pages/health/health-plan-summary.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="plan-page">
+  <view class="plan-page" :style="{ '--font-scale': fontScale }">
     <!-- 步骤指示器 -->
     <!-- 步骤指示器 -->
     <view class="steps-bar" v-if="!viewMode">
     <view class="steps-bar" v-if="!viewMode">
       <view class="step" v-for="(s, i) in steps" :key="i"
       <view class="step" v-for="(s, i) in steps" :key="i"
@@ -185,8 +185,10 @@ import { generateHealthPlan, regenerateSection, confirmPlan, saveHealthPlan, get
 import { getHealthStatus, saveHealthStatus, getDietPreferences, saveDietPreferences, getMyMembership } from '../../utils/api'
 import { getHealthStatus, saveHealthStatus, getDietPreferences, saveDietPreferences, getMyMembership } from '../../utils/api'
 import MemberChipPicker from '@/pages/health/components/MemberChipPicker.vue'
 import MemberChipPicker from '@/pages/health/components/MemberChipPicker.vue'
 import ComprehensiveSurvey from '@/pages/health/components/ComprehensiveSurvey.vue'
 import ComprehensiveSurvey from '@/pages/health/components/ComprehensiveSurvey.vue'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { MemberChipPicker, ComprehensiveSurvey },
   components: { MemberChipPicker, ComprehensiveSurvey },
   data() {
   data() {
     return {
     return {
@@ -1078,7 +1080,7 @@ selectedMembers: function() {
   border-radius: 22rpx;
   border-radius: 22rpx;
   background: #e0e0e0;
   background: #e0e0e0;
   color: #999;
   color: #999;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -1088,7 +1090,7 @@ selectedMembers: function() {
 .step.active .step-num { background: #F97316; color: #fff; }
 .step.active .step-num { background: #F97316; color: #fff; }
 .step.done .step-num { background: #4CAF50; color: #fff; }
 .step.done .step-num { background: #4CAF50; color: #fff; }
 .step-label {
 .step-label {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   white-space: nowrap;
   white-space: nowrap;
   margin-top: 4rpx;
   margin-top: 4rpx;
@@ -1110,7 +1112,7 @@ selectedMembers: function() {
   margin-bottom: 10rpx;
   margin-bottom: 10rpx;
 }
 }
 .section-title {
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
@@ -1122,7 +1124,7 @@ selectedMembers: function() {
   border-radius: 20rpx;
   border-radius: 20rpx;
 }
 }
 .hint-text {
 .hint-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
@@ -1165,7 +1167,7 @@ selectedMembers: function() {
 .goal-textarea {
 .goal-textarea {
   width: 100%;
   width: 100%;
   min-height: 320rpx;
   min-height: 320rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   background: #F5F7FA;
   background: #F5F7FA;
   border: none;
   border: none;
@@ -1247,8 +1249,8 @@ selectedMembers: function() {
   padding: 80rpx 20rpx;
   padding: 80rpx 20rpx;
 }
 }
 .loading-icon { font-size: 80rpx; margin-bottom: 20rpx; }
 .loading-icon { font-size: 80rpx; margin-bottom: 20rpx; }
-.loading-text { font-size: 30rpx; color: #333; margin-bottom: 8rpx; }
-.loading-hint { font-size: 24rpx; color: #999; }
+.loading-text { font-size: calc(30rpx * var(--font-scale, 1)); color: #333; margin-bottom: 8rpx; }
+.loading-hint { font-size: calc(24rpx * var(--font-scale, 1)); color: #999; }
 
 
 /* 总览卡片 */
 /* 总览卡片 */
 .overview-card {
 .overview-card {
@@ -1259,7 +1261,7 @@ selectedMembers: function() {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .overview-text {
 .overview-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #555;
   color: #555;
   line-height: 1.8;
   line-height: 1.8;
 }
 }
@@ -1282,8 +1284,8 @@ selectedMembers: function() {
 }
 }
 .sec-icon { font-size: 40rpx; }
 .sec-icon { font-size: 40rpx; }
 .sec-info { flex: 1; }
 .sec-info { flex: 1; }
-.sec-title { font-size: 28rpx; color: #333; font-weight: 600; display: block; }
-.sec-status { font-size: 22rpx; color: #999; }
+.sec-title { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; font-weight: 600; display: block; }
+.sec-status { font-size: calc(22rpx * var(--font-scale, 1)); color: #999; }
 .sec-status.done { color: #4CAF50; }
 .sec-status.done { color: #4CAF50; }
 .sec-arrow { color: #ccc; font-size: 28rpx; }
 .sec-arrow { color: #ccc; font-size: 28rpx; }
 
 
@@ -1295,7 +1297,7 @@ selectedMembers: function() {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .content-text {
 .content-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.8;
   line-height: 1.8;
   white-space: pre-wrap;
   white-space: pre-wrap;
@@ -1304,7 +1306,7 @@ selectedMembers: function() {
 .edit-textarea {
 .edit-textarea {
   width: 100%;
   width: 100%;
   min-height: 300rpx;
   min-height: 300rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   background: #F5F7FA;
   background: #F5F7FA;
   border: 2rpx solid #F97316;
   border: 2rpx solid #F97316;
@@ -1321,7 +1323,7 @@ selectedMembers: function() {
   border: 2rpx solid #F97316;
   border: 2rpx solid #F97316;
   border-radius: 40rpx;
   border-radius: 40rpx;
   padding: 0 24rpx;
   padding: 0 24rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
@@ -1336,7 +1338,7 @@ selectedMembers: function() {
 }
 }
 .back-link {
 .back-link {
   text-align: center;
   text-align: center;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-top: 20rpx;
   margin-top: 20rpx;
 }
 }
@@ -1356,14 +1358,14 @@ selectedMembers: function() {
   border: 2rpx solid #eee;
   border: 2rpx solid #eee;
 }
 }
 .review-title {
 .review-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   display: block;
   display: block;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .review-preview {
 .review-preview {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -1379,7 +1381,7 @@ selectedMembers: function() {
   border-radius: 12rpx;
   border-radius: 12rpx;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
-.plan-meta-item { font-size: 24rpx; color: #92400E; }
+.plan-meta-item { font-size: calc(24rpx * var(--font-scale, 1)); color: #92400E; }
 .plan-preview {
 .plan-preview {
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 16rpx;
   border-radius: 16rpx;
@@ -1387,7 +1389,7 @@ selectedMembers: function() {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .plan-preview-text {
 .plan-preview-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.8;
   line-height: 1.8;
   white-space: pre-wrap;
   white-space: pre-wrap;
@@ -1416,8 +1418,8 @@ selectedMembers: function() {
   width: 560rpx;
   width: 560rpx;
 }
 }
 .success-icon { font-size: 100rpx; color: #4CAF50; margin-bottom: 20rpx; }
 .success-icon { font-size: 100rpx; color: #4CAF50; margin-bottom: 20rpx; }
-.success-title { font-size: 36rpx; font-weight: bold; color: #333; margin-bottom: 12rpx; }
-.success-sub { font-size: 28rpx; color: #888; margin-bottom: 40rpx; }
+.success-title { font-size: calc(36rpx * var(--font-scale, 1)); font-weight: bold; color: #333; margin-bottom: 12rpx; }
+.success-sub { font-size: calc(28rpx * var(--font-scale, 1)); color: #888; margin-bottom: 40rpx; }
 
 
 /* ===== 多成员调研 tab 页签 ===== */
 /* ===== 多成员调研 tab 页签 ===== */
 .member-tabs {
 .member-tabs {
@@ -1431,7 +1433,7 @@ selectedMembers: function() {
   border-radius: 32rpx;
   border-radius: 32rpx;
   background: #F1F5F9;
   background: #F1F5F9;
   border: 2rpx solid transparent;
   border: 2rpx solid transparent;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #334155;
   color: #334155;
   font-weight: 500;
   font-weight: 500;
   transition: all 0.2s;
   transition: all 0.2s;
@@ -1452,12 +1454,12 @@ selectedMembers: function() {
   border-radius: 12rpx;
   border-radius: 12rpx;
 }
 }
 .form-member-label {
 .form-member-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #92400E;
   color: #92400E;
   font-weight: 600;
   font-weight: 600;
 }
 }
 .form-member-save {
 .form-member-save {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #B45309;
   color: #B45309;
 }
 }
 
 
@@ -1469,7 +1471,7 @@ selectedMembers: function() {
   padding: 24rpx;
   padding: 24rpx;
 }
 }
 .form-title {
 .form-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
@@ -1481,7 +1483,7 @@ selectedMembers: function() {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .form-label {
 .form-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #555;
   color: #555;
 }
 }
 .form-input {
 .form-input {
@@ -1491,7 +1493,7 @@ selectedMembers: function() {
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
   padding: 0 20rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   text-align: right;
   text-align: right;
 }
 }
 
 
@@ -1503,7 +1505,7 @@ selectedMembers: function() {
   justify-content: space-between;
   justify-content: space-between;
   padding: 12rpx 0;
   padding: 12rpx 0;
 }
 }
-.group-title { font-size: 28rpx; font-weight: bold; color: #333; }
+.group-title { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: bold; color: #333; }
 .group-arrow { font-size: 24rpx; color: #999; }
 .group-arrow { font-size: 24rpx; color: #999; }
 .risk-badge { margin-left: 6rpx; color: #E64340; font-size: 24rpx; }
 .risk-badge { margin-left: 6rpx; color: #E64340; font-size: 24rpx; }
 .tag-wrap { display: flex; flex-wrap: wrap; }
 .tag-wrap { display: flex; flex-wrap: wrap; }
@@ -1519,7 +1521,7 @@ selectedMembers: function() {
 
 
 /* 已选疾病 */
 /* 已选疾病 */
 .selected-area { margin-top: 16rpx; padding: 16rpx; background: #FFF7E6; border-radius: 12rpx; }
 .selected-area { margin-top: 16rpx; padding: 16rpx; background: #FFF7E6; border-radius: 12rpx; }
-.selected-title { font-size: 26rpx; color: #8A6D3B; margin-bottom: 8rpx; }
+.selected-title { font-size: calc(26rpx * var(--font-scale, 1)); color: #8A6D3B; margin-bottom: 8rpx; }
 .sel-row {
 .sel-row {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
@@ -1527,8 +1529,8 @@ selectedMembers: function() {
   padding: 10rpx 0;
   padding: 10rpx 0;
   border-bottom: 1rpx solid #F0E6D0;
   border-bottom: 1rpx solid #F0E6D0;
 }
 }
-.sel-name { font-size: 28rpx; color: #333; flex: 1; }
-.sel-diag { font-size: 26rpx; color: #F97316; }
+.sel-name { font-size: calc(28rpx * var(--font-scale, 1)); color: #333; flex: 1; }
+.sel-diag { font-size: calc(26rpx * var(--font-scale, 1)); color: #F97316; }
 .sel-del { font-size: 30rpx; color: #E64340; margin-left: 16rpx; }
 .sel-del { font-size: 30rpx; color: #E64340; margin-left: 16rpx; }
 
 
 /* 自定义疾病输入 */
 /* 自定义疾病输入 */
@@ -1539,10 +1541,10 @@ selectedMembers: function() {
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
   padding: 0 20rpx;
   padding: 0 20rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   margin-right: 20rpx;
   margin-right: 20rpx;
 }
 }
-.add-link { font-size: 28rpx; color: #F97316; }
+.add-link { font-size: calc(28rpx * var(--font-scale, 1)); color: #F97316; }
 
 
 /* 药物行 */
 /* 药物行 */
 .med-row {
 .med-row {
@@ -1563,25 +1565,25 @@ selectedMembers: function() {
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
   padding: 0 16rpx;
   padding: 0 16rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   margin-right: 12rpx;
   margin-right: 12rpx;
 }
 }
 .med-picker {
 .med-picker {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   padding: 8rpx 16rpx;
   padding: 8rpx 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
 }
 }
-.med-forget { font-size: 26rpx; color: #999; margin-left: 16rpx; }
-.med-duration { font-size: 26rpx; color: #8A6D3B; }
+.med-forget { font-size: calc(26rpx * var(--font-scale, 1)); color: #999; margin-left: 16rpx; }
+.med-duration { font-size: calc(26rpx * var(--font-scale, 1)); color: #8A6D3B; }
 .med-time {
 .med-time {
   flex: 1;
   flex: 1;
   height: 64rpx;
   height: 64rpx;
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
   padding: 0 16rpx;
   padding: 0 16rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   margin-right: 12rpx;
   margin-right: 12rpx;
 }
 }
 .med-del { font-size: 26rpx; color: #E64340; }
 .med-del { font-size: 26rpx; color: #E64340; }
@@ -1593,7 +1595,7 @@ selectedMembers: function() {
   background: #F5F7FA;
   background: #F5F7FA;
   border-radius: 10rpx;
   border-radius: 10rpx;
   padding: 16rpx 20rpx;
   padding: 16rpx 20rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
 
 
@@ -1606,16 +1608,16 @@ selectedMembers: function() {
   padding: 40rpx 0 24rpx;
   padding: 40rpx 0 24rpx;
   box-sizing: border-box;
   box-sizing: border-box;
 }
 }
-.empty-text { font-size: 26rpx; color: #999; }
+.empty-text { font-size: calc(26rpx * var(--font-scale, 1)); color: #999; }
 .member-load-hint {
 .member-load-hint {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
 .empty-action {
 .empty-action {
   margin-top: 20rpx;
   margin-top: 20rpx;
   padding: 12rpx 32rpx;
   padding: 12rpx 32rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   border: 2rpx solid #F97316;
   border: 2rpx solid #F97316;
   border-radius: 32rpx;
   border-radius: 32rpx;

+ 51 - 49
cfc-frontend/pages/health/report-confirm.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="confirm-container">
+  <view class="confirm-container" :style="{ '--font-scale': fontScale }">
 
 
     <view class="tip-banner">
     <view class="tip-banner">
       <text class="tip-icon">✅</text>
       <text class="tip-icon">✅</text>
@@ -359,8 +359,10 @@
 import { confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, parseReportDraft } from '../../utils/api.js'
 import { confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, parseReportDraft } from '../../utils/api.js'
 import { addFamilyMember, getFamilyMemberList } from '../../utils/api.js'
 import { addFamilyMember, getFamilyMemberList } from '../../utils/api.js'
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { FeedbackPopup },
   components: { FeedbackPopup },
   data() {
   data() {
     return {
     return {
@@ -964,7 +966,7 @@ export default {
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
 .tip-icon { font-size: 32rpx; margin-right: 16rpx; flex-shrink: 0; }
 .tip-icon { font-size: 32rpx; margin-right: 16rpx; flex-shrink: 0; }
-.tip-text { font-size: 24rpx; color: #2E7D32; line-height: 1.5; }
+.tip-text { font-size: calc(24rpx * var(--font-scale, 1)); color: #2E7D32; line-height: 1.5; }
 
 
 .parsing-banner {
 .parsing-banner {
   display: flex;
   display: flex;
@@ -976,7 +978,7 @@ export default {
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
 .parsing-icon { font-size: 32rpx; margin-right: 16rpx; flex-shrink: 0; }
 .parsing-icon { font-size: 32rpx; margin-right: 16rpx; flex-shrink: 0; }
-.parsing-text { font-size: 24rpx; color: #F57F17; line-height: 1.5; }
+.parsing-text { font-size: calc(24rpx * var(--font-scale, 1)); color: #F57F17; line-height: 1.5; }
 
 
 .form-section { margin: 0 30rpx; }
 .form-section { margin: 0 30rpx; }
 
 
@@ -988,7 +990,7 @@ export default {
   box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.04);
   box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.04);
 }
 }
 .card-title {
 .card-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
@@ -1007,7 +1009,7 @@ export default {
   margin-left: 8rpx;
   margin-left: 8rpx;
 }
 }
 .title-abnormal {
 .title-abnormal {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: normal;
   font-weight: normal;
   color: #C62828;
   color: #C62828;
 }
 }
@@ -1061,7 +1063,7 @@ export default {
   transform: rotate(90deg);
   transform: rotate(90deg);
 }
 }
 .indicator-group-name {
 .indicator-group-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 600;
   font-weight: 600;
   flex: 1;
   flex: 1;
@@ -1079,7 +1081,7 @@ export default {
   margin-left: 12rpx;
   margin-left: 12rpx;
 }
 }
 .indicator-group-need {
 .indicator-group-need {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #E65100;
   color: #E65100;
   background: #FFF3E0;
   background: #FFF3E0;
   padding: 4rpx 12rpx;
   padding: 4rpx 12rpx;
@@ -1091,7 +1093,7 @@ export default {
   color: #94A3B8;
   color: #94A3B8;
 }
 }
 .indicator-group-abnormal {
 .indicator-group-abnormal {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #C62828;
   color: #C62828;
   font-weight: 500;
   font-weight: 500;
   margin-right: 8rpx;
   margin-right: 8rpx;
@@ -1107,13 +1109,13 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .field-label {
 .field-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   width: 160rpx;
   width: 160rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .field-value {
 .field-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   flex: 1;
   flex: 1;
@@ -1146,7 +1148,7 @@ export default {
 }
 }
 .field-input {
 .field-input {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 8rpx 16rpx;
   padding: 8rpx 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1155,7 +1157,7 @@ export default {
 .field-textarea {
 .field-textarea {
   width: 100%;
   width: 100%;
   min-height: 120rpx;
   min-height: 120rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 16rpx;
   padding: 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1172,7 +1174,7 @@ export default {
 }
 }
 .member-list-hint {
 .member-list-hint {
   width: 100%;
   width: 100%;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
@@ -1196,13 +1198,13 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #5B9BD5;
   background: #5B9BD5;
   color: #fff;
   color: #fff;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   text-align: center;
   text-align: center;
   line-height: 64rpx;
   line-height: 64rpx;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
-.member-name { font-size: 24rpx; color: #333; }
+.member-name { font-size: calc(24rpx * var(--font-scale, 1)); color: #333; }
 
 
 .indicator-item {
 .indicator-item {
   background: #F8FAFB;
   background: #F8FAFB;
@@ -1218,7 +1220,7 @@ export default {
 }
 }
 .ind-name {
 .ind-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
@@ -1241,8 +1243,8 @@ export default {
   margin-top: 8rpx;
   margin-top: 8rpx;
   gap: 16rpx;
   gap: 16rpx;
 }
 }
-.ind-ref { font-size: 22rpx; color: #94A3B8; }
-.ind-unit { font-size: 22rpx; color: #64748B; }
+.ind-ref { font-size: calc(22rpx * var(--font-scale, 1)); color: #94A3B8; }
+.ind-unit { font-size: calc(22rpx * var(--font-scale, 1)); color: #64748B; }
 .ind-symptoms {
 .ind-symptoms {
   display: flex;
   display: flex;
   flex-direction: row;
   flex-direction: row;
@@ -1250,10 +1252,10 @@ export default {
   margin-top: 8rpx;
   margin-top: 8rpx;
   gap: 8rpx;
   gap: 8rpx;
 }
 }
-.ind-symptom-label { font-size: 22rpx; color: #94A3B8; flex-shrink: 0; }
+.ind-symptom-label { font-size: calc(22rpx * var(--font-scale, 1)); color: #94A3B8; flex-shrink: 0; }
 .ind-symptom-input {
 .ind-symptom-input {
   flex: 1;
   flex: 1;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
@@ -1334,7 +1336,7 @@ export default {
   border-bottom: 2rpx solid #F0F0F0;
   border-bottom: 2rpx solid #F0F0F0;
 }
 }
 .help-popup-title {
 .help-popup-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   flex: 1;
   flex: 1;
@@ -1354,13 +1356,13 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .help-label {
 .help-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   width: 140rpx;
   width: 140rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .help-value {
 .help-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   flex: 1;
   flex: 1;
@@ -1377,13 +1379,13 @@ export default {
 }
 }
 .help-desc-label {
 .help-desc-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .help-desc-text {
 .help-desc-text {
   display: block;
   display: block;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -1400,7 +1402,7 @@ export default {
 }
 }
 .flora-name {
 .flora-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
@@ -1408,7 +1410,7 @@ export default {
 }
 }
 .flora-abundance {
 .flora-abundance {
   width: 140rpx;
   width: 140rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #1565C0;
   color: #1565C0;
   text-align: right;
   text-align: right;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
@@ -1424,7 +1426,7 @@ export default {
 }
 }
 .taxonomy-group-label {
 .taxonomy-group-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   color: #666;
   color: #666;
   padding: 8rpx 4rpx 6rpx;
   padding: 8rpx 4rpx 6rpx;
@@ -1438,7 +1440,7 @@ export default {
 }
 }
 .pathogen-group-label {
 .pathogen-group-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   color: #D32F2F;
   color: #D32F2F;
   padding: 8rpx 4rpx 6rpx;
   padding: 8rpx 4rpx 6rpx;
@@ -1456,14 +1458,14 @@ export default {
 }
 }
 .risk-name {
 .risk-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
   border-radius: 6rpx;
   border-radius: 6rpx;
 }
 }
 .risk-level {
 .risk-level {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   padding: 4rpx 12rpx;
   padding: 4rpx 12rpx;
   border-radius: 8rpx;
   border-radius: 8rpx;
@@ -1484,7 +1486,7 @@ export default {
 }
 }
 .food-name {
 .food-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
@@ -1492,7 +1494,7 @@ export default {
 }
 }
 .food-category {
 .food-category {
   width: 160rpx;
   width: 160rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #64748B;
   color: #64748B;
   text-align: right;
   text-align: right;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
@@ -1550,7 +1552,7 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .confidence-label {
 .confidence-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -1583,7 +1585,7 @@ export default {
 .fill-none { background: linear-gradient(90deg, #EF9A9A, #E53935); }
 .fill-none { background: linear-gradient(90deg, #EF9A9A, #E53935); }
 
 
 .confidence-desc {
 .confidence-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   line-height: 1.4;
   line-height: 1.4;
 }
 }
@@ -1594,7 +1596,7 @@ export default {
 }
 }
 .candidate-section-hint {
 .candidate-section-hint {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #64748B;
   color: #64748B;
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
@@ -1627,7 +1629,7 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #5B9BD5;
   background: #5B9BD5;
   color: #fff;
   color: #fff;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   text-align: center;
   text-align: center;
   line-height: 56rpx;
   line-height: 56rpx;
@@ -1639,18 +1641,18 @@ export default {
   min-width: 0;
   min-width: 0;
 }
 }
 .candidate-name {
 .candidate-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   display: block;
   display: block;
 }
 }
 .candidate-detail {
 .candidate-detail {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   display: block;
   display: block;
 }
 }
 .candidate-fields {
 .candidate-fields {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #5B9BD5;
   color: #5B9BD5;
   display: block;
   display: block;
   margin-top: 2rpx;
   margin-top: 2rpx;
@@ -1676,7 +1678,7 @@ export default {
   border-radius: 5rpx;
   border-radius: 5rpx;
 }
 }
 .score-text {
 .score-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #1565C0;
   color: #1565C0;
   font-weight: bold;
   font-weight: bold;
   min-width: 48rpx;
   min-width: 48rpx;
@@ -1702,7 +1704,7 @@ export default {
   margin-right: 8rpx;
   margin-right: 8rpx;
 }
 }
 .create-member-text {
 .create-member-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #5B9BD5;
   color: #5B9BD5;
 }
 }
 
 
@@ -1714,14 +1716,14 @@ export default {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .form-item-label {
 .form-item-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   width: 100rpx;
   width: 100rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .form-item-input {
 .form-item-input {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 12rpx 16rpx;
   padding: 12rpx 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1733,7 +1735,7 @@ export default {
   gap: 16rpx;
   gap: 16rpx;
 }
 }
 .gender-option {
 .gender-option {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 12rpx 32rpx;
   padding: 12rpx 32rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1774,7 +1776,7 @@ export default {
 }
 }
 .tongue-ind-label {
 .tongue-ind-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
@@ -1791,14 +1793,14 @@ export default {
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
 .tongue-summary-title {
 .tongue-summary-title {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #F59E0B;
   color: #F59E0B;
   font-weight: 600;
   font-weight: 600;
   display: block;
   display: block;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .tongue-summary-text {
 .tongue-summary-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -1817,7 +1819,7 @@ export default {
   z-index: 90;
   z-index: 90;
 }
 }
 .feedback-entry-icon { font-size: 32rpx; margin-right: 10rpx; }
 .feedback-entry-icon { font-size: 32rpx; margin-right: 10rpx; }
-.feedback-entry-text { font-size: 28rpx; color: #fff; font-weight: 500; }
+.feedback-entry-text { font-size: calc(28rpx * var(--font-scale, 1)); color: #fff; font-weight: 500; }
 .feedback-entry-arrow { font-size: 30rpx; color: #fff; margin-left: 6rpx; }
 .feedback-entry-arrow { font-size: 30rpx; color: #fff; margin-left: 6rpx; }
 .feedback-entry:active { opacity: 0.85; }
 .feedback-entry:active { opacity: 0.85; }
 </style>
 </style>

+ 52 - 50
cfc-frontend/pages/health/report-detail.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <!-- native navigation bar used, no custom header -->
     <!-- native navigation bar used, no custom header -->
     <scroll-view class="content" scroll-y>
     <scroll-view class="content" scroll-y>
       <!-- 报告头 -->
       <!-- 报告头 -->
@@ -409,8 +409,10 @@ import ReportBlocksRenderer from '../../components/report-blocks-renderer.vue'
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
 import FeedbackPopup from '@/pages/health/components/feedback-popup.vue'
 import { getReportDetail, getDanReportDetail, getReportPayload, editHealthReport, parseReportDraft, confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, getFamilyMemberList, addFamilyMember, queryIndicatorKnowledge, queryBacteriaKnowledge } from '../../utils/api.js'
 import { getReportDetail, getDanReportDetail, getReportPayload, editHealthReport, parseReportDraft, confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, getFamilyMemberList, addFamilyMember, queryIndicatorKnowledge, queryBacteriaKnowledge } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { ReportBlocksRenderer, FeedbackPopup },
   components: { ReportBlocksRenderer, FeedbackPopup },
   data() {
   data() {
     return {
     return {
@@ -1317,7 +1319,7 @@ export default {
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
 .head-name {
 .head-name {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
 }
 }
@@ -1335,13 +1337,13 @@ export default {
   border-radius: 8rpx;
   border-radius: 8rpx;
 }
 }
 .head-date {
 .head-date {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .empty-hint {
 .empty-hint {
   text-align: center;
   text-align: center;
   color: #999;
   color: #999;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   padding: 60rpx 0;
   padding: 60rpx 0;
 }
 }
 .edit-btn {
 .edit-btn {
@@ -1354,7 +1356,7 @@ export default {
   color: #fff;
   color: #fff;
   padding: 16rpx 60rpx;
   padding: 16rpx 60rpx;
   border-radius: 40rpx;
   border-radius: 40rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
 }
 }
 .title-count {
 .title-count {
   font-size: 24rpx;
   font-size: 24rpx;
@@ -1363,7 +1365,7 @@ export default {
   margin-left: 8rpx;
   margin-left: 8rpx;
 }
 }
 .title-abnormal {
 .title-abnormal {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: normal;
   font-weight: normal;
   color: #C62828;
   color: #C62828;
 }
 }
@@ -1439,7 +1441,7 @@ export default {
   transform: rotate(90deg);
   transform: rotate(90deg);
 }
 }
 .indicator-group-name {
 .indicator-group-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 600;
   font-weight: 600;
   flex: 1;
   flex: 1;
@@ -1457,7 +1459,7 @@ export default {
   margin-left: 12rpx;
   margin-left: 12rpx;
 }
 }
 .indicator-group-need {
 .indicator-group-need {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #E65100;
   color: #E65100;
   background: #FFF3E0;
   background: #FFF3E0;
   padding: 4rpx 12rpx;
   padding: 4rpx 12rpx;
@@ -1469,7 +1471,7 @@ export default {
   color: #94A3B8;
   color: #94A3B8;
 }
 }
 .indicator-group-abnormal {
 .indicator-group-abnormal {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #C62828;
   color: #C62828;
   font-weight: 500;
   font-weight: 500;
   margin-right: 8rpx;
   margin-right: 8rpx;
@@ -1485,13 +1487,13 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .field-label {
 .field-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   width: 160rpx;
   width: 160rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .field-value {
 .field-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   flex: 1;
   flex: 1;
@@ -1524,7 +1526,7 @@ export default {
 }
 }
 .field-input {
 .field-input {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 8rpx 16rpx;
   padding: 8rpx 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1533,7 +1535,7 @@ export default {
 .field-textarea {
 .field-textarea {
   width: 100%;
   width: 100%;
   min-height: 120rpx;
   min-height: 120rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 16rpx;
   padding: 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -1550,7 +1552,7 @@ export default {
 }
 }
 .member-list-hint {
 .member-list-hint {
   width: 100%;
   width: 100%;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
@@ -1574,13 +1576,13 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #5B9BD5;
   background: #5B9BD5;
   color: #fff;
   color: #fff;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   text-align: center;
   text-align: center;
   line-height: 64rpx;
   line-height: 64rpx;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
-.member-name { font-size: 24rpx; color: #333; }
+.member-name { font-size: calc(24rpx * var(--font-scale, 1)); color: #333; }
 
 
 .indicator-item {
 .indicator-item {
   background: #F8FAFB;
   background: #F8FAFB;
@@ -1596,7 +1598,7 @@ export default {
 }
 }
 .ind-name {
 .ind-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
@@ -1619,8 +1621,8 @@ export default {
   margin-top: 8rpx;
   margin-top: 8rpx;
   gap: 16rpx;
   gap: 16rpx;
 }
 }
-.ind-ref { font-size: 22rpx; color: #94A3B8; }
-.ind-unit { font-size: 22rpx; color: #64748B; }
+.ind-ref { font-size: calc(22rpx * var(--font-scale, 1)); color: #94A3B8; }
+.ind-unit { font-size: calc(22rpx * var(--font-scale, 1)); color: #64748B; }
 .ind-symptoms {
 .ind-symptoms {
   display: flex;
   display: flex;
   flex-direction: row;
   flex-direction: row;
@@ -1628,10 +1630,10 @@ export default {
   margin-top: 8rpx;
   margin-top: 8rpx;
   gap: 8rpx;
   gap: 8rpx;
 }
 }
-.ind-symptom-label { font-size: 22rpx; color: #94A3B8; flex-shrink: 0; }
+.ind-symptom-label { font-size: calc(22rpx * var(--font-scale, 1)); color: #94A3B8; flex-shrink: 0; }
 .ind-symptom-input {
 .ind-symptom-input {
   flex: 1;
   flex: 1;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
@@ -1712,7 +1714,7 @@ export default {
   border-bottom: 2rpx solid #F0F0F0;
   border-bottom: 2rpx solid #F0F0F0;
 }
 }
 .help-popup-title {
 .help-popup-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   flex: 1;
   flex: 1;
@@ -1732,13 +1734,13 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .help-label {
 .help-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   width: 140rpx;
   width: 140rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .help-value {
 .help-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   flex: 1;
   flex: 1;
@@ -1755,13 +1757,13 @@ export default {
 }
 }
 .help-desc-label {
 .help-desc-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .help-desc-text {
 .help-desc-text {
   display: block;
   display: block;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -1778,7 +1780,7 @@ export default {
 }
 }
 .flora-name {
 .flora-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
@@ -1786,7 +1788,7 @@ export default {
 }
 }
 .flora-abundance {
 .flora-abundance {
   width: 140rpx;
   width: 140rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #1565C0;
   color: #1565C0;
   text-align: right;
   text-align: right;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
@@ -1802,7 +1804,7 @@ export default {
 }
 }
 .taxonomy-group-label {
 .taxonomy-group-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   color: #666;
   color: #666;
   padding: 8rpx 4rpx 6rpx;
   padding: 8rpx 4rpx 6rpx;
@@ -1816,7 +1818,7 @@ export default {
 }
 }
 .pathogen-group-label {
 .pathogen-group-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   color: #D32F2F;
   color: #D32F2F;
   padding: 8rpx 4rpx 6rpx;
   padding: 8rpx 4rpx 6rpx;
@@ -1834,14 +1836,14 @@ export default {
 }
 }
 .risk-name {
 .risk-name {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 4rpx 8rpx;
   padding: 4rpx 8rpx;
   background: #fff;
   background: #fff;
   border-radius: 6rpx;
   border-radius: 6rpx;
 }
 }
 .risk-level {
 .risk-level {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   font-weight: 500;
   font-weight: 500;
   padding: 4rpx 12rpx;
   padding: 4rpx 12rpx;
   border-radius: 8rpx;
   border-radius: 8rpx;
@@ -1904,7 +1906,7 @@ export default {
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 .confidence-label {
 .confidence-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -1937,7 +1939,7 @@ export default {
 .fill-none { background: linear-gradient(90deg, #EF9A9A, #E53935); }
 .fill-none { background: linear-gradient(90deg, #EF9A9A, #E53935); }
 
 
 .confidence-desc {
 .confidence-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   line-height: 1.4;
   line-height: 1.4;
 }
 }
@@ -1948,7 +1950,7 @@ export default {
 }
 }
 .candidate-section-hint {
 .candidate-section-hint {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #64748B;
   color: #64748B;
   margin-bottom: 12rpx;
   margin-bottom: 12rpx;
 }
 }
@@ -1981,7 +1983,7 @@ export default {
   border-radius: 50%;
   border-radius: 50%;
   background: #5B9BD5;
   background: #5B9BD5;
   color: #fff;
   color: #fff;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   text-align: center;
   text-align: center;
   line-height: 56rpx;
   line-height: 56rpx;
@@ -1993,18 +1995,18 @@ export default {
   min-width: 0;
   min-width: 0;
 }
 }
 .candidate-name {
 .candidate-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
   display: block;
   display: block;
 }
 }
 .candidate-detail {
 .candidate-detail {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   display: block;
   display: block;
 }
 }
 .candidate-fields {
 .candidate-fields {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: #5B9BD5;
   color: #5B9BD5;
   display: block;
   display: block;
   margin-top: 2rpx;
   margin-top: 2rpx;
@@ -2030,7 +2032,7 @@ export default {
   border-radius: 5rpx;
   border-radius: 5rpx;
 }
 }
 .score-text {
 .score-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #1565C0;
   color: #1565C0;
   font-weight: bold;
   font-weight: bold;
   min-width: 48rpx;
   min-width: 48rpx;
@@ -2056,7 +2058,7 @@ export default {
   margin-right: 8rpx;
   margin-right: 8rpx;
 }
 }
 .create-member-text {
 .create-member-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #5B9BD5;
   color: #5B9BD5;
 }
 }
 
 
@@ -2068,14 +2070,14 @@ export default {
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
 }
 }
 .form-item-label {
 .form-item-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   width: 100rpx;
   width: 100rpx;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .form-item-input {
 .form-item-input {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 12rpx 16rpx;
   padding: 12rpx 16rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -2087,7 +2089,7 @@ export default {
   gap: 16rpx;
   gap: 16rpx;
 }
 }
 .gender-option {
 .gender-option {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   padding: 12rpx 32rpx;
   padding: 12rpx 32rpx;
   background: #F5F7FA;
   background: #F5F7FA;
@@ -2128,7 +2130,7 @@ export default {
 }
 }
 .tongue-ind-label {
 .tongue-ind-label {
   display: block;
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
@@ -2145,14 +2147,14 @@ export default {
   border-radius: 16rpx;
   border-radius: 16rpx;
 }
 }
 .tongue-summary-title {
 .tongue-summary-title {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #F59E0B;
   color: #F59E0B;
   font-weight: 600;
   font-weight: 600;
   display: block;
   display: block;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .tongue-summary-text {
 .tongue-summary-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.6;
   line-height: 1.6;
 }
 }
@@ -2195,13 +2197,13 @@ export default {
   flex: 1;
   flex: 1;
 }
 }
 .parsing-main-text {
 .parsing-main-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #D97706;
   color: #D97706;
   line-height: 1.5;
   line-height: 1.5;
 }
 }
 .parsing-sub-text {
 .parsing-sub-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #92400E;
   color: #92400E;
   line-height: 1.5;
   line-height: 1.5;
   margin-top: 6rpx;
   margin-top: 6rpx;
@@ -2223,7 +2225,7 @@ export default {
   z-index: 90;
   z-index: 90;
 }
 }
 .feedback-entry-icon { font-size: 32rpx; margin-right: 10rpx; }
 .feedback-entry-icon { font-size: 32rpx; margin-right: 10rpx; }
-.feedback-entry-text { font-size: 28rpx; color: #fff; font-weight: 500; }
+.feedback-entry-text { font-size: calc(28rpx * var(--font-scale, 1)); color: #fff; font-weight: 500; }
 .feedback-entry-arrow { font-size: 30rpx; color: #fff; margin-left: 6rpx; }
 .feedback-entry-arrow { font-size: 30rpx; color: #fff; margin-left: 6rpx; }
 .feedback-entry:active { opacity: 0.85; }
 .feedback-entry:active { opacity: 0.85; }
 </style>
 </style>

+ 14 - 11
cfc-frontend/pages/meal/recommend.vue

@@ -1,6 +1,6 @@
 <!-- DEPRECATED: 请使用 pages/diet/ 替代(功能已合并至 pages/diet/recommendation 和 pages/diet/index) -->
 <!-- DEPRECATED: 请使用 pages/diet/ 替代(功能已合并至 pages/diet/recommendation 和 pages/diet/index) -->
 <template>
 <template>
-  <view class="meal-recommend">
+  <view class="meal-recommend" :style="{ '--font-scale': fontScale }">
     <!-- 顶部配置 -->
     <!-- 顶部配置 -->
     <view class="config-section">
     <view class="config-section">
       <view class="config-item">
       <view class="config-item">
@@ -72,7 +72,10 @@
 <script>
 <script>
 import { getMealRecommend, replaceFood } from '@/utils/api'
 import { getMealRecommend, replaceFood } from '@/utils/api'
 
 
+import fontScaleMixin from '@/mixins/font-scale.js'
+
 export default {
 export default {
+  mixins: [fontScaleMixin],
   name: 'MealRecommend',
   name: 'MealRecommend',
   data() {
   data() {
     return {
     return {
@@ -152,12 +155,12 @@ export default {
 }
 }
 .label {
 .label {
   width: 140rpx;
   width: 140rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .picker-value {
 .picker-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: var(--color-primary, #F97316);
   color: var(--color-primary, #F97316);
   padding: 10rpx 20rpx;
   padding: 10rpx 20rpx;
   background: #FFF0E0;
   background: #FFF0E0;
@@ -165,7 +168,7 @@ export default {
 }
 }
 .input {
 .input {
   flex: 1;
   flex: 1;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   padding: 10rpx 20rpx;
   padding: 10rpx 20rpx;
   border: 1rpx solid #eee;
   border: 1rpx solid #eee;
   border-radius: 8rpx;
   border-radius: 8rpx;
@@ -184,7 +187,7 @@ export default {
   margin-top: 20rpx;
   margin-top: 20rpx;
 }
 }
 .section-title {
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #333;
   color: #333;
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
@@ -198,7 +201,7 @@ export default {
   box-shadow: var(--shadow-md, 0 2rpx 12rpx rgba(0,0,0,0.06));
   box-shadow: var(--shadow-md, 0 2rpx 12rpx rgba(0,0,0,0.06));
 }
 }
 .answer-text {
 .answer-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   line-height: 1.6;
   line-height: 1.6;
   white-space: pre-wrap;
   white-space: pre-wrap;
@@ -231,7 +234,7 @@ export default {
   background: #FFF0E0;
   background: #FFF0E0;
 }
 }
 .food-name {
 .food-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: var(--color-primary, #F97316);
   color: var(--color-primary, #F97316);
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -259,11 +262,11 @@ export default {
   align-items: center;
   align-items: center;
 }
 }
 .nutrition-key {
 .nutrition-key {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .nutrition-val {
 .nutrition-val {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: var(--color-primary, #F97316);
   color: var(--color-primary, #F97316);
   font-weight: 600;
   font-weight: 600;
   margin-top: 6rpx;
   margin-top: 6rpx;
@@ -278,7 +281,7 @@ export default {
   font-size: 80rpx;
   font-size: 80rpx;
 }
 }
 .empty-text {
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   margin-top: 20rpx;
   margin-top: 20rpx;
 }
 }
@@ -291,6 +294,6 @@ export default {
   color: #fff;
   color: #fff;
   padding: 16rpx 40rpx;
   padding: 16rpx 40rpx;
   border-radius: 40rpx;
   border-radius: 40rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
 }
 }
 </style>
 </style>

+ 7 - 5
cfc-frontend/pages/membership/benefits.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <scroll-view class="container" scroll-y>
+  <scroll-view class="container" scroll-y :style="{ '--font-scale': fontScale }">
     <view class="header">
     <view class="header">
       <text class="header-title">我的权益</text>
       <text class="header-title">我的权益</text>
       <text class="header-subtitle">Subscription Benefits</text>
       <text class="header-subtitle">Subscription Benefits</text>
@@ -112,8 +112,10 @@
 <script>
 <script>
 import { getMySubscription, checkBenefit } from '../../utils/api.js'
 import { getMySubscription, checkBenefit } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '../../mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data() {
   data() {
     return {
     return {
       subscription: null,
       subscription: null,
@@ -335,13 +337,13 @@ export default {
   padding: 40rpx 0 30rpx;
   padding: 40rpx 0 30rpx;
 }
 }
 .header-title {
 .header-title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #1E293B;
   color: #1E293B;
   display: block;
   display: block;
 }
 }
 .header-subtitle {
 .header-subtitle {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-top: 8rpx;
   margin-top: 8rpx;
   display: block;
   display: block;
@@ -368,7 +370,7 @@ export default {
   margin-right: 8rpx;
   margin-right: 8rpx;
 }
 }
 .badge-text {
 .badge-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #fff;
   color: #fff;
   font-weight: 600;
   font-weight: 600;
 }
 }
@@ -454,7 +456,7 @@ export default {
   margin-right: 16rpx;
   margin-right: 16rpx;
 }
 }
 .benefit-name {
 .benefit-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #1E293B;
   color: #1E293B;
   display: block;
   display: block;

+ 14 - 12
cfc-frontend/pages/membership/index.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="member-center">
+  <view class="member-center" :style="{ '--font-scale': fontScale }">
     <scroll-view class="page" scroll-y>
     <scroll-view class="page" scroll-y>
       <!-- 会员状态卡 -->
       <!-- 会员状态卡 -->
       <view class="status-card">
       <view class="status-card">
@@ -83,8 +83,10 @@
 import { getMyMembership, getMyButler, reportAppEnter, getMembershipBenefits
 import { getMyMembership, getMyButler, reportAppEnter, getMembershipBenefits
 } from '../../utils/api.js'
 } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '../../mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data() {
   data() {
     return {
     return {
       membership: null,
       membership: null,
@@ -222,11 +224,11 @@ export default {
   align-items: center;
   align-items: center;
 }
 }
 .expiry-label {
 .expiry-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.8);
   color: rgba(255,255,255,0.8);
 }
 }
 .expiry-value {
 .expiry-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #fff;
   color: #fff;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -242,7 +244,7 @@ export default {
   color: #FEF3C7;
   color: #FEF3C7;
 }
 }
 .days-unit {
 .days-unit {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
   color: rgba(255,255,255,0.7);
   margin-left: 8rpx;
   margin-left: 8rpx;
 }
 }
@@ -251,11 +253,11 @@ export default {
   margin-top: 16rpx;
   margin-top: 16rpx;
 }
 }
 .expired-text {
 .expired-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #FEF3C7;
   color: #FEF3C7;
 }
 }
 .free-hint {
 .free-hint {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.85);
   color: rgba(255,255,255,0.85);
   text-align: center;
   text-align: center;
   display: block;
   display: block;
@@ -270,7 +272,7 @@ export default {
   box-shadow: 0 4rpx 24rpx rgba(249, 115, 22, 0.08);
   box-shadow: 0 4rpx 24rpx rgba(249, 115, 22, 0.08);
 }
 }
 .benefit-card-title {
 .benefit-card-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #1E293B;
   color: #1E293B;
   display: block;
   display: block;
@@ -299,7 +301,7 @@ export default {
   flex-shrink: 0;
   flex-shrink: 0;
 }
 }
 .feature-text {
 .feature-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #334155;
   color: #334155;
 }
 }
 .btn-main {
 .btn-main {
@@ -336,7 +338,7 @@ export default {
   margin-right: 8rpx;
   margin-right: 8rpx;
 }
 }
 .benefits-entry-text {
 .benefits-entry-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -376,7 +378,7 @@ export default {
 }
 }
 .compare-cell {
 .compare-cell {
   flex: 1;
   flex: 1;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #475569;
   color: #475569;
   text-align: center;
   text-align: center;
   word-break: break-all;
   word-break: break-all;
@@ -396,7 +398,7 @@ export default {
 .butler-entry { display: flex; align-items: center; background: #fff; border-radius: 16rpx; padding: 28rpx; margin: 20rpx 0; }
 .butler-entry { display: flex; align-items: center; background: #fff; border-radius: 16rpx; padding: 28rpx; margin: 20rpx 0; }
 .butler-entry-icon { font-size: 48rpx; margin-right: 20rpx; }
 .butler-entry-icon { font-size: 48rpx; margin-right: 20rpx; }
 .butler-entry-main { flex: 1; display: flex; flex-direction: column; }
 .butler-entry-main { flex: 1; display: flex; flex-direction: column; }
-.butler-entry-title { font-size: 30rpx; font-weight: bold; color: #333; }
-.butler-entry-sub { font-size: 24rpx; color: #999; margin-top: 6rpx; }
+.butler-entry-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: bold; color: #333; }
+.butler-entry-sub { font-size: calc(24rpx * var(--font-scale, 1)); color: #999; margin-top: 6rpx; }
 .butler-entry-arrow { font-size: 40rpx; color: #ccc; }
 .butler-entry-arrow { font-size: 40rpx; color: #ccc; }
 </style>
 </style>

+ 14 - 12
cfc-frontend/pages/membership/pay.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="pay-page">
+  <view class="pay-page" :style="{ '--font-scale': fontScale }">
     <scroll-view class="page" scroll-y>
     <scroll-view class="page" scroll-y>
       <!-- 商品明细卡 -->
       <!-- 商品明细卡 -->
       <view class="order-card">
       <view class="order-card">
@@ -92,8 +92,10 @@
 
 
 <script>
 <script>
 import { getMembershipPlans, getCouponList, createOrder, requestVirtualPayment, nextOrder } from '../../utils/api.js'
 import { getMembershipPlans, getCouponList, createOrder, requestVirtualPayment, nextOrder } from '../../utils/api.js'
+import fontScaleMixin from '../../mixins/font-scale.js'
 
 
 export default {
 export default {
+  mixins: [fontScaleMixin],
   data() {
   data() {
     return {
     return {
       levelCode: 'FAMILY',
       levelCode: 'FAMILY',
@@ -394,13 +396,13 @@ export default {
   margin-bottom: 24rpx;
   margin-bottom: 24rpx;
 }
 }
 .order-title {
 .order-title {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #1E293B;
   color: #1E293B;
   display: block;
   display: block;
 }
 }
 .order-sub {
 .order-sub {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #94A3B8;
   color: #94A3B8;
   margin-top: 6rpx;
   margin-top: 6rpx;
   display: block;
   display: block;
@@ -436,7 +438,7 @@ export default {
   opacity: 0.7;
   opacity: 0.7;
 }
 }
 .coupon-row-label {
 .coupon-row-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   margin-right: 16rpx;
   margin-right: 16rpx;
 }
 }
@@ -475,7 +477,7 @@ export default {
 }
 }
 .member-hint-text {
 .member-hint-text {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   font-weight: 500;
   font-weight: 500;
 }
 }
@@ -508,14 +510,14 @@ export default {
   margin-top: 30rpx;
   margin-top: 30rpx;
 }
 }
 .split-title {
 .split-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   font-weight: 600;
   color: #92400E;
   color: #92400E;
   display: block;
   display: block;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 .split-desc {
 .split-desc {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #B45309;
   color: #B45309;
   display: block;
   display: block;
 }
 }
@@ -529,7 +531,7 @@ export default {
   text-align: center;
   text-align: center;
 }
 }
 .progress-text {
 .progress-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #F97316;
   color: #F97316;
   font-weight: 600;
   font-weight: 600;
 }
 }
@@ -630,13 +632,13 @@ export default {
   margin: 0 16rpx;
   margin: 0 16rpx;
 }
 }
 .picker-item-name {
 .picker-item-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   display: block;
   display: block;
   margin-bottom: 4rpx;
   margin-bottom: 4rpx;
 }
 }
 .picker-item-condition {
 .picker-item-condition {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .picker-item-check {
 .picker-item-check {
@@ -655,7 +657,7 @@ export default {
 .picker-empty {
 .picker-empty {
   text-align: center;
   text-align: center;
   padding: 60rpx 0;
   padding: 60rpx 0;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 .picker-footer {
 .picker-footer {
@@ -665,7 +667,7 @@ export default {
 .picker-btn-remove {
 .picker-btn-remove {
   background: #f5f5f5;
   background: #f5f5f5;
   color: #666;
   color: #666;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   border-radius: 12rpx;
   border-radius: 12rpx;
   border: none;
   border: none;
 }
 }

+ 31 - 28
cfc-frontend/pages/wisdom-detail/cognitive-report.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- ===== 报告卡片 ===== -->
     <!-- ===== 报告卡片 ===== -->
     <view class="report-card" v-if="report">
     <view class="report-card" v-if="report">
       <view class="report-header">
       <view class="report-header">
@@ -172,7 +172,10 @@
 <script>
 <script>
 import { getAssessmentLatestResult, getCognitiveRecommendations, createTaskFromRecommendation, getCognitiveNorms, getCognitiveTrend } from '../../utils/api.js'
 import { getAssessmentLatestResult, getCognitiveRecommendations, createTaskFromRecommendation, getCognitiveNorms, getCognitiveTrend } from '../../utils/api.js'
 
 
+import fontScaleMixin from '@/mixins/font-scale.js'
+
 export default {
 export default {
+  mixins: [fontScaleMixin],
   components: { },
   components: { },
   data: function() {
   data: function() {
     return {
     return {
@@ -370,13 +373,13 @@ export default {
 }
 }
 
 
 .report-title {
 .report-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
 
 
 .report-date {
 .report-date {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 
 
@@ -391,7 +394,7 @@ export default {
 }
 }
 
 
 .overall-label {
 .overall-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   opacity: 0.9;
   opacity: 0.9;
   display: block;
   display: block;
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
@@ -439,19 +442,19 @@ export default {
 }
 }
 
 
 .dimension-name {
 .dimension-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: 500;
   font-weight: 500;
 }
 }
 
 
 .dimension-score {
 .dimension-score {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #667eea;
   color: #667eea;
 }
 }
 
 
 .dimension-desc {
 .dimension-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   line-height: 1.4;
   line-height: 1.4;
 }
 }
@@ -472,7 +475,7 @@ export default {
   display: flex;
   display: flex;
   flex-direction: row;
   flex-direction: row;
   align-items: center;
   align-items: center;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
 }
 }
 
 
@@ -579,13 +582,13 @@ export default {
 }
 }
 
 
 .analysis-title {
 .analysis-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
 
 
 .analysis-content, .suggestion-content {
 .analysis-content, .suggestion-content {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #666;
   color: #666;
   line-height: 1.7;
   line-height: 1.7;
   display: block;
   display: block;
@@ -648,13 +651,13 @@ export default {
 }
 }
 
 
 .action-plan-title {
 .action-plan-title {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
 
 
 .action-plan-desc {
 .action-plan-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
   display: block;
   display: block;
@@ -668,7 +671,7 @@ export default {
 }
 }
 
 
 .overall-suggestion-text {
 .overall-suggestion-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #fff;
   color: #fff;
   line-height: 1.6;
   line-height: 1.6;
   display: block;
   display: block;
@@ -716,14 +719,14 @@ export default {
 }
 }
 
 
 .rec-label {
 .rec-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
   margin-right: 12rpx;
   margin-right: 12rpx;
 }
 }
 
 
 .rec-score {
 .rec-score {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
 }
 }
 
 
@@ -750,7 +753,7 @@ export default {
 }
 }
 
 
 .rec-suggestion {
 .rec-suggestion {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #555;
   color: #555;
   line-height: 1.6;
   line-height: 1.6;
   display: block;
   display: block;
@@ -811,7 +814,7 @@ export default {
 }
 }
 
 
 .loading-text {
 .loading-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
 }
 }
 
 
@@ -829,14 +832,14 @@ export default {
 }
 }
 
 
 .empty-title {
 .empty-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
   font-weight: bold;
   font-weight: bold;
   margin-bottom: 16rpx;
   margin-bottom: 16rpx;
 }
 }
 
 
 .empty-desc {
 .empty-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   text-align: center;
   text-align: center;
   line-height: 1.6;
   line-height: 1.6;
@@ -871,7 +874,7 @@ export default {
 }
 }
 
 
 .trend-title {
 .trend-title {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
@@ -893,14 +896,14 @@ export default {
 }
 }
 
 
 .trend-stat-label {
 .trend-stat-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #888;
   color: #888;
   display: block;
   display: block;
   margin-bottom: 8rpx;
   margin-bottom: 8rpx;
 }
 }
 
 
 .trend-stat-value {
 .trend-stat-value {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   display: block;
   display: block;
 }
 }
@@ -922,7 +925,7 @@ export default {
 }
 }
 
 
 .trend-stat-sub {
 .trend-stat-sub {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   margin-top: 4rpx;
   margin-top: 4rpx;
   display: block;
   display: block;
 }
 }
@@ -949,7 +952,7 @@ export default {
 }
 }
 
 
 .tc-title {
 .tc-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   color: #333;
   color: #333;
 }
 }
@@ -973,20 +976,20 @@ export default {
 
 
 .tc-dim-name {
 .tc-dim-name {
   flex: 2;
   flex: 2;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: #333;
   color: #333;
 }
 }
 
 
 .tc-old {
 .tc-old {
   flex: 1;
   flex: 1;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: #999;
   color: #999;
   text-align: center;
   text-align: center;
 }
 }
 
 
 .tc-new {
 .tc-new {
   flex: 1;
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: bold;
   font-weight: bold;
   text-align: center;
   text-align: center;
   color: #333;
   color: #333;
@@ -1003,7 +1006,7 @@ export default {
 .tc-change {
 .tc-change {
   flex: 1.5;
   flex: 1.5;
   text-align: right;
   text-align: right;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 }
 
 
 .change-up {
 .change-up {