Browse Source

feat(mini-program): wire all pages to fontScale + calc conversions (2nd batch)

- patch_mixin4: root binding on first <view|scroll-view> after <template> (with/without class),
  import fontScaleMixin, add mixins:[fontScaleMixin] — 286 pages processed
- fontscale_batch3: font-size: XXrpx → calc(XXrpx * var(--font-scale, 1)) with exclude list
  (icon/arrow/btn-/price/tag/badge/count/stat/score/nav-/tab-/legend/axis/slider/fab etc.)
  — 335 files, 2562 replacements
- Fix structural bugs from patch_mixin4 regex:
  * AbilityDiagram / OctopusDiagram: > in v-if attr split tag → merged into single :style
  * DimensionSubDims (action-detail & wealth): double :style → merged into one
  * PearlDiagram: double :style → merged
  * FamilyTianpanCard: Vue2 invalid spread ...themeStyle → inject --font-scale into computed themeStyle
  * countdown-tag: double :style → merged
  * index-home: binding landed on nested splash-overlay instead of root <view> → moved to root
- Result: 338 files changed (+3676/-3096), 0 audit errors, all pages + content components wired
E2E Test Bot 3 days ago
parent
commit
a9887ec9b0
100 changed files with 878 additions and 770 deletions
  1. 4 4
      cfc-frontend/components/ArticleBookshelf.vue
  2. 1 1
      cfc-frontend/components/BadgeGrid.vue
  3. 1 1
      cfc-frontend/components/BaseBadge.vue
  4. 4 4
      cfc-frontend/components/BaseEmpty.vue
  5. 1 1
      cfc-frontend/components/BaseLoading.vue
  6. 4 4
      cfc-frontend/components/ConfigurableGuide.vue
  7. 2 2
      cfc-frontend/components/ContentSharePoster.vue
  8. 6 6
      cfc-frontend/components/DimensionActivities.vue
  9. 8 8
      cfc-frontend/components/DimensionArticles.vue
  10. 6 6
      cfc-frontend/components/DimensionIntroCard.vue
  11. 2 2
      cfc-frontend/components/DimensionMemberTabs.vue
  12. 5 5
      cfc-frontend/components/DimensionProducts.vue
  13. 6 6
      cfc-frontend/components/DimensionTasks.vue
  14. 5 5
      cfc-frontend/components/DimensionVisitorCard.vue
  15. 13 13
      cfc-frontend/components/FamilyChallengeCard.vue
  16. 3 3
      cfc-frontend/components/FamilyEmptyState/FamilyEmptyState.vue
  17. 5 5
      cfc-frontend/components/FamilyEnergyBar.vue
  18. 8 8
      cfc-frontend/components/FamilyFeed.vue
  19. 6 6
      cfc-frontend/components/FamilyMemberCard.vue
  20. 8 8
      cfc-frontend/components/FamilyMemberStrip.vue
  21. 3 3
      cfc-frontend/components/FamilyRelationGraph.vue
  22. 3 3
      cfc-frontend/components/GenerationPicker.vue
  23. 1 1
      cfc-frontend/components/HealthBadge.vue
  24. 4 4
      cfc-frontend/components/HealthTimeline.vue
  25. 2 2
      cfc-frontend/components/LoginGuideCard.vue
  26. 4 4
      cfc-frontend/components/OnboardingGuide.vue
  27. 3 3
      cfc-frontend/components/OnboardingProgressBar.vue
  28. 3 3
      cfc-frontend/components/PageBanner.vue
  29. 1 1
      cfc-frontend/components/PlayfulButton.vue
  30. 3 3
      cfc-frontend/components/PlayfulCard.vue
  31. 2 2
      cfc-frontend/components/ProfileBadges.vue
  32. 4 4
      cfc-frontend/components/ProfileGrowth.vue
  33. 1 1
      cfc-frontend/components/RadarChart.vue
  34. 4 4
      cfc-frontend/components/RecommendedFeed.vue
  35. 6 6
      cfc-frontend/components/RelatedContent.vue
  36. 1 1
      cfc-frontend/components/TagChip.vue
  37. 1 1
      cfc-frontend/components/TrendChart.vue
  38. 5 5
      cfc-frontend/components/address-picker.vue
  39. 8 8
      cfc-frontend/components/daily-task-card.vue
  40. 4 4
      cfc-frontend/components/gate-lock.vue
  41. 2 2
      cfc-frontend/components/hand-signature/hand-signature.vue
  42. 7 7
      cfc-frontend/components/login-sheet.vue
  43. 2 2
      cfc-frontend/components/report-upload-card.vue
  44. 2 2
      cfc-frontend/components/tab-transition.vue
  45. 6 6
      cfc-frontend/components/wuxing-sandbox.vue
  46. 3 3
      cfc-frontend/custom-tab-bar/index.vue
  47. 9 7
      cfc-frontend/pages/achievement/index.vue
  48. 6 4
      cfc-frontend/pages/action-detail/components/AbilityDiagram.vue
  49. 10 8
      cfc-frontend/pages/action-detail/components/DimensionSubDims.vue
  50. 9 7
      cfc-frontend/pages/action-detail/components/OctopusDiagram.vue
  51. 6 4
      cfc-frontend/pages/action-detail/components/PearlDiagram.vue
  52. 21 19
      cfc-frontend/pages/action-detail/contact-detail.vue
  53. 20 18
      cfc-frontend/pages/action-detail/index.vue
  54. 16 14
      cfc-frontend/pages/action-detail/interaction-log.vue
  55. 11 9
      cfc-frontend/pages/action-detail/member-action-detail.vue
  56. 15 13
      cfc-frontend/pages/action-detail/octopus-add-effect.vue
  57. 13 11
      cfc-frontend/pages/action-detail/octopus-add-key-person.vue
  58. 11 9
      cfc-frontend/pages/action-detail/octopus-effects-list.vue
  59. 12 10
      cfc-frontend/pages/action-detail/pearl-add-resource.vue
  60. 12 10
      cfc-frontend/pages/action-detail/relationship-questionnaire.vue
  61. 14 12
      cfc-frontend/pages/activity/create.vue
  62. 13 11
      cfc-frontend/pages/activity/order-pay/order-pay.vue
  63. 18 16
      cfc-frontend/pages/ai/chat.vue
  64. 9 7
      cfc-frontend/pages/ai/components/AITaskCard.vue
  65. 4 2
      cfc-frontend/pages/ai/components/QuotaProgressBar.vue
  66. 5 3
      cfc-frontend/pages/ai/components/UpgradeGuideModal.vue
  67. 13 11
      cfc-frontend/pages/article-center/article-edit.vue
  68. 9 7
      cfc-frontend/pages/article-center/my-posts.vue
  69. 11 9
      cfc-frontend/pages/assessment-plan/detail.vue
  70. 10 8
      cfc-frontend/pages/assessment-plan/list.vue
  71. 13 11
      cfc-frontend/pages/assessment/apply.vue
  72. 13 11
      cfc-frontend/pages/assessment/execution.vue
  73. 13 11
      cfc-frontend/pages/assessment/purchase.vue
  74. 12 10
      cfc-frontend/pages/assessment/quota.vue
  75. 11 9
      cfc-frontend/pages/assessment/rating.vue
  76. 19 17
      cfc-frontend/pages/assessment/results.vue
  77. 11 9
      cfc-frontend/pages/assessment/upload-report.vue
  78. 15 13
      cfc-frontend/pages/body-detail/checkin.vue
  79. 16 14
      cfc-frontend/pages/body-detail/dimension-detail.vue
  80. 16 14
      cfc-frontend/pages/body-detail/dimension-questionnaire.vue
  81. 16 14
      cfc-frontend/pages/body-detail/health-dimensions.vue
  82. 9 7
      cfc-frontend/pages/body-detail/member-body-detail.vue
  83. 10 8
      cfc-frontend/pages/butler/apply.vue
  84. 14 12
      cfc-frontend/pages/butler/select.vue
  85. 8 6
      cfc-frontend/pages/child/rewards.vue
  86. 7 5
      cfc-frontend/pages/child/tasks.vue
  87. 14 12
      cfc-frontend/pages/cognitive-hall.vue
  88. 14 12
      cfc-frontend/pages/cognitive-test/language-test.vue
  89. 16 14
      cfc-frontend/pages/cognitive-test/logic-test.vue
  90. 17 15
      cfc-frontend/pages/cognitive-test/memory-test.vue
  91. 13 11
      cfc-frontend/pages/cognitive-test/perception-test.vue
  92. 17 15
      cfc-frontend/pages/cognitive-test/spatial-test.vue
  93. 12 10
      cfc-frontend/pages/cognitive-test/speed-test.vue
  94. 8 6
      cfc-frontend/pages/dan-assessment/comparison.vue
  95. 30 28
      cfc-frontend/pages/dan-assessment/report-result.vue
  96. 14 12
      cfc-frontend/pages/diet/food-query.vue
  97. 23 21
      cfc-frontend/pages/diet/index.vue
  98. 11 9
      cfc-frontend/pages/diet/meal-config.vue
  99. 12 10
      cfc-frontend/pages/diet/preferences.vue
  100. 14 12
      cfc-frontend/pages/discover/circles.vue

+ 4 - 4
cfc-frontend/components/ArticleBookshelf.vue

@@ -181,7 +181,7 @@ export default {
   justify-content: center;
 }
 .bs-empty-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
 }
 
@@ -279,7 +279,7 @@ export default {
   box-sizing: border-box;
 }
 .bs-cover-title {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   font-weight: 700;
   line-height: 1.5;
   letter-spacing: 1rpx;
@@ -305,7 +305,7 @@ export default {
   background: linear-gradient(180deg, transparent 0%, rgba(0,0,0,0.55) 100%);
 }
 .bs-cover-title-overlay {
-  font-size: 18rpx;
+  font-size: calc(18rpx * var(--font-scale, 1));
   font-weight: 700;
   line-height: 1.4;
   color: $app-surface;
@@ -323,7 +323,7 @@ export default {
 .bs-card-name {
   display: block;
   margin-top: 8rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.4;
   overflow: hidden;

+ 1 - 1
cfc-frontend/components/BadgeGrid.vue

@@ -53,4 +53,4 @@ export default {
 .badge-icon-wrap--locked { background: $uni-border-color-light; }
 .badge-icon { font-size: 36rpx; }
 .badge-name { font-size: 22rpx; color: $facade-text-strong; text-align: center; }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/BaseBadge.vue

@@ -58,4 +58,4 @@ export default {
   background: rgba(148, 163, 184, 0.12);
   color: var(--muted, $app-text-subtle);
 }
-</style>
+</style>

+ 4 - 4
cfc-frontend/components/BaseEmpty.vue

@@ -42,19 +42,19 @@ export default {
   margin-bottom: 24rpx;
 }
 .base-empty__emoji {
-  font-size: 80rpx;
+  font-size: calc(80rpx * var(--font-scale, 1));
   display: block;
   text-align: center;
 }
 .base-empty__title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: var(--text, #3D2E1E);
   margin-bottom: 12rpx;
   text-align: center;
 }
 .base-empty__description {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: var(--text-secondary, #6B5A4A);
   text-align: center;
   line-height: 1.6;
@@ -63,4 +63,4 @@ export default {
 .base-empty__action {
   margin-top: 32rpx;
 }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/BaseLoading.vue

@@ -73,4 +73,4 @@ export default {
     opacity: 1;
   }
 }
-</style>
+</style>

+ 4 - 4
cfc-frontend/components/ConfigurableGuide.vue

@@ -138,7 +138,7 @@ export default {
 .cg-icon { font-size: 80rpx; margin-bottom: 32rpx; display: block; }
 .cg-img { width: 160rpx; height: 160rpx; margin-bottom: 32rpx; }
 .cg-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $uni-text-color;
   text-align: center;
@@ -146,9 +146,9 @@ export default {
   display: block;
   line-height: 1.3;
 }
-.cg-title--intro { font-size: 32rpx; font-weight: 800; }
+.cg-title--intro { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: 800; }
 .cg-desc {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
   text-align: center;
   line-height: 1.6;
@@ -170,4 +170,4 @@ export default {
   align-items: center;
   justify-content: center;
 }
-</style>
+</style>

+ 2 - 2
cfc-frontend/components/ContentSharePoster.vue

@@ -815,7 +815,7 @@ export default {
   display: flex;
   align-items: center;
   margin: 12rpx 0;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 .tpl-label {
   margin-right: 20rpx;
@@ -841,7 +841,7 @@ export default {
   box-sizing: border-box;
 }
 .tpl-text {
-  font-size: 14rpx;
+  font-size: calc(14rpx * var(--font-scale, 1));
   text-align: center;
   color: $facade-text-body;
 }

+ 6 - 6
cfc-frontend/components/DimensionActivities.vue

@@ -252,7 +252,7 @@ export default {
   font-size: 24rpx;
 }
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $uni-text-color;
   letter-spacing: 1rpx;
@@ -266,7 +266,7 @@ export default {
   border-radius: 24rpx;
 }
 .section-more-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
   margin-right: 4rpx;
 }
@@ -287,7 +287,7 @@ export default {
   margin-bottom: 16rpx;
 }
 .empty-tip {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
 
@@ -366,7 +366,7 @@ export default {
 
 /* 标题 */
 .card-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 8rpx;
@@ -399,7 +399,7 @@ export default {
 }
 
 .meta-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
 }
 
@@ -436,7 +436,7 @@ export default {
 }
 
 .card-status {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 2rpx 10rpx;
   border-radius: 8rpx;
   background: $mat-green-tint;

+ 8 - 8
cfc-frontend/components/DimensionArticles.vue

@@ -151,12 +151,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .section-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .article-list {
@@ -180,12 +180,12 @@ export default {
   margin-bottom: 14rpx;
 }
 .article-category-text {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 500;
 }
 .article-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -205,7 +205,7 @@ export default {
   font-weight: 500;
 }
 .article-summary {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   line-height: 1.5;
   display: block;
@@ -227,12 +227,12 @@ export default {
   margin-right: 6rpx;
 }
 .meta-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .article-date {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-ghost-light;
   margin-left: auto;
 }
-</style>
+</style>

+ 6 - 6
cfc-frontend/components/DimensionIntroCard.vue

@@ -87,13 +87,13 @@ export default {
   flex: 1;
 }
 .dim-intro-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
 }
 .dim-intro-subtitle {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 4rpx;
   display: block;
@@ -108,19 +108,19 @@ export default {
   margin-bottom: 8rpx;
 }
 .dim-intro-bullet {
-  font-size: 16rpx;
+  font-size: calc(16rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-right: 8rpx;
 }
 .dim-intro-feature-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .dim-intro-footer {
   text-align: right;
 }
 .dim-intro-link {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
-</style>
+</style>

+ 2 - 2
cfc-frontend/components/DimensionMemberTabs.vue

@@ -251,7 +251,7 @@ $tab-dims: (
 }
 
 .tabs-empty-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-secondary;
   line-height: 1.5;
 }
@@ -287,4 +287,4 @@ $tab-dims: (
     }
   }
 }
-</style>
+</style>

+ 5 - 5
cfc-frontend/components/DimensionProducts.vue

@@ -187,7 +187,7 @@ export default {
 }
 .product-name {
   display: block;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.4;
   margin-bottom: 4rpx;
@@ -221,7 +221,7 @@ export default {
 }
 .product-name-mall {
   display: -webkit-box;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   line-height: 1.4;
   margin-bottom: 8rpx;
   text-overflow: ellipsis;
@@ -238,7 +238,7 @@ export default {
   padding: 40rpx 0;
 }
 .empty-tip {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .loading-state {
@@ -264,7 +264,7 @@ export default {
   width: 100%;
 }
 .no-more-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
-</style>
+</style>

+ 6 - 6
cfc-frontend/components/DimensionTasks.vue

@@ -71,12 +71,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .section-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .task-list {
@@ -124,7 +124,7 @@ export default {
   align-items: center;
 }
 .task-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .task-name.done {
@@ -137,12 +137,12 @@ export default {
   align-items: center;
 }
 .task-points {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $status-success-2;
   margin-right: 12rpx;
 }
 .task-penalty {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $status-danger;
 }
-</style>
+</style>

+ 5 - 5
cfc-frontend/components/DimensionVisitorCard.vue

@@ -114,14 +114,14 @@ export default {
   margin-bottom: 22rpx;
 }
 .dvc-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-gray-800;
   display: block;
   line-height: 1.4;
 }
 .dvc-sub {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 6rpx;
   display: block;
@@ -144,7 +144,7 @@ export default {
   flex-shrink: 0;
 }
 .dvc-benefit-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.5;
 }
@@ -194,9 +194,9 @@ export default {
   margin-bottom: 14rpx;
 }
 .dvc-preview-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   text-align: center;
   line-height: 1.6;
 }
-</style>
+</style>

+ 13 - 13
cfc-frontend/components/FamilyChallengeCard.vue

@@ -197,12 +197,12 @@ export default {
   margin-bottom: 4rpx;
 }
 .card-title {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $uni-text-color;
 }
 .card-status {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 2rpx 10rpx;
   border-radius: 999rpx;
 }
@@ -210,7 +210,7 @@ export default {
 .status-completed { background: $facade-fill-slate; color: $uni-text-color-secondary; }
 .status-cancelled { background: $status-danger-soft; color: $status-danger-deep; }
 .card-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
   line-height: 1.4;
   margin-bottom: 8rpx;
@@ -225,7 +225,7 @@ export default {
   margin-bottom: 6rpx;
 }
 .pending-hint {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $status-warning-strong-2;
   font-weight: 600;
 }
@@ -260,8 +260,8 @@ export default {
   align-items: center;
   margin-bottom: 6rpx;
 }
-.target-label { font-size: 22rpx; color: $facade-text-slate-deep; font-weight: 600; }
-.target-value { font-size: 26rpx; color: $status-success; font-weight: 700; }
+.target-label { font-size: calc(22rpx * var(--font-scale, 1)); color: $facade-text-slate-deep; font-weight: 600; }
+.target-value { font-size: calc(26rpx * var(--font-scale, 1)); color: $status-success; font-weight: 700; }
 
 .card-progress {
   display: flex;
@@ -283,7 +283,7 @@ export default {
   transition: width 0.5s ease;
 }
 .progress-text {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $status-success;
   font-weight: 600;
   min-width: 90rpx;
@@ -301,7 +301,7 @@ export default {
   margin-top: 6rpx;
 }
 .member-name {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-slate-deep;
   width: 90rpx;
   overflow: hidden;
@@ -321,13 +321,13 @@ export default {
   border-radius: 999rpx;
 }
 .member-val {
-  font-size: 18rpx;
+  font-size: calc(18rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
   min-width: 80rpx;
   text-align: right;
 }
 .member-done {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $status-success;
   font-weight: 700;
 }
@@ -340,8 +340,8 @@ export default {
   margin-top: 6rpx;
   flex-wrap: wrap;
 }
-.detail-label { font-size: 20rpx; color: $app-text-subtle; }
-.detail-val { font-size: 20rpx; color: $facade-text-slate-700; }
+.detail-label { font-size: calc(20rpx * var(--font-scale, 1)); color: $app-text-subtle; }
+.detail-val { font-size: calc(20rpx * var(--font-scale, 1)); color: $facade-text-slate-700; }
 .detail-val.reward { color: $brand-primary; font-weight: 600; }
 .detail-val.badge { color: $dim-wisdom; }
 
@@ -374,4 +374,4 @@ export default {
   color: $status-danger-deep;
   border: 2rpx solid $status-danger-light-2;
 }
-</style>
+</style>

+ 3 - 3
cfc-frontend/components/FamilyEmptyState/FamilyEmptyState.vue

@@ -33,6 +33,6 @@ export default {
 .family-empty-block { padding: 60rpx 24rpx; }
 .family-empty-list { padding: 40rpx 16rpx; }
 .empty-icon { font-size: 48rpx; margin-bottom: 12rpx; }
-.empty-title { font-size: 28rpx; color: $facade-text-strong; margin-bottom: 8rpx; }
-.empty-desc { font-size: 24rpx; color: $facade-text-muted; margin-bottom: 16rpx; }
-</style>
+.empty-title { font-size: calc(28rpx * var(--font-scale, 1)); color: $facade-text-strong; margin-bottom: 8rpx; }
+.empty-desc { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-muted; margin-bottom: 16rpx; }
+</style>

+ 5 - 5
cfc-frontend/components/FamilyEnergyBar.vue

@@ -181,8 +181,8 @@ export default {
   margin-bottom: 20rpx;
 }
 .bar-icon { font-size: 32rpx; margin-right: 8rpx; }
-.bar-title { font-size: 28rpx; font-weight: bold; color: $facade-text-strong; flex: 1; }
-.bar-total-score { font-size: 40rpx; font-weight: bold; color: $brand-primary; margin-right: 12rpx; }
+.bar-title { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; flex: 1; }
+.bar-total-score { font-size: calc(40rpx * var(--font-scale, 1)); font-weight: bold; color: $brand-primary; margin-right: 12rpx; }
 .bar-expand-icon {
   font-size: 20rpx;
   color: $facade-text-ghost-light;
@@ -198,7 +198,7 @@ export default {
 .bar-row:last-child { margin-bottom: 0; }
 .bar-row-member:active { opacity: 0.6; }
 .bar-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   width: 80rpx;
   flex-shrink: 0;
@@ -217,7 +217,7 @@ export default {
   transition: width 0.5s ease;
 }
 .bar-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   width: 60rpx;
@@ -268,4 +268,4 @@ export default {
   font-size: 22rpx;
   color: $facade-text-muted;
 }
-</style>
+</style>

+ 8 - 8
cfc-frontend/components/FamilyFeed.vue

@@ -254,7 +254,7 @@ export default {
   margin-right: 12rpx;
 }
 
-.feed-title { font-size: 24rpx; font-weight: bold; color: $facade-text-strong; }
+.feed-title { font-size: calc(24rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; }
 .feed-icon  { font-size: 20rpx; }
 
 @keyframes spin {
@@ -313,7 +313,7 @@ export default {
 
 .feed-item-text {
   flex: 1; min-width: 0;
-  font-size: 24rpx; color: $facade-text-body;
+  font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-body;
   white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
 }
 
@@ -333,7 +333,7 @@ export default {
 .feed-empty {
   height: 48rpx; line-height: 48rpx; text-align: center;
 }
-.feed-empty-text { font-size: 24rpx; color: $facade-text-ghost; }
+.feed-empty-text { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-ghost; }
 
 /* ===== 消息详情弹层 ===== */
 .feed-detail-mask {
@@ -366,23 +366,23 @@ export default {
 .feed-detail-icon { font-size: 34rpx; }
 
 .feed-detail-head-texts { flex: 1; min-width: 0; display: flex; flex-direction: column; }
-.feed-detail-type { font-size: 26rpx; font-weight: bold; color: $facade-text-strong; }
-.feed-detail-time { font-size: 20rpx; color: $facade-text-muted; margin-top: 4rpx; }
+.feed-detail-type { font-size: calc(26rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; }
+.feed-detail-time { font-size: calc(20rpx * var(--font-scale, 1)); color: $facade-text-muted; margin-top: 4rpx; }
 .feed-detail-close { font-size: 40rpx; color: $facade-text-ghost-light; line-height: 1; padding: 0 8rpx; flex-shrink: 0; }
 
 .feed-detail-title {
-  display: block; font-size: 30rpx; font-weight: bold; color: $facade-text-strong;
+  display: block; font-size: calc(30rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong;
   line-height: 1.4; margin-top: 24rpx;
 }
 .feed-detail-content {
-  display: block; font-size: 26rpx; color: $facade-text-body; line-height: 1.6; margin-top: 12rpx;
+  display: block; font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-body; line-height: 1.6; margin-top: 12rpx;
 }
 .feed-detail-amount {
   display: inline-block; margin-top: 16rpx;
   background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
   border-radius: 999rpx; padding: 6rpx 20rpx;
 }
-.feed-detail-amount-text { font-size: 24rpx; color: $app-surface; font-weight: bold; }
+.feed-detail-amount-text { font-size: calc(24rpx * var(--font-scale, 1)); color: $app-surface; font-weight: bold; }
 .feed-detail-btn {
   margin-top: 28rpx; height: 76rpx; border-radius: 38rpx;
   background: linear-gradient(135deg, $brand-primary, $brand-primary-light);

+ 6 - 6
cfc-frontend/components/FamilyMemberCard.vue

@@ -141,7 +141,7 @@ export default {
   max-width: 84rpx;
 }
 .card-relation-text {
-  font-size: 16rpx;
+  font-size: calc(16rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 500;
   line-height: 1.4;
@@ -173,7 +173,7 @@ export default {
   margin: 0 4rpx;
 }
 .card-nickname {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-gray-700;
   font-weight: 600;
   text-align: center;
@@ -187,7 +187,7 @@ export default {
   margin-top: 2rpx;
 }
 .card-generation-text {
-  font-size: 14rpx;
+  font-size: calc(14rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
 }
 .card-contact-row {
@@ -200,7 +200,7 @@ export default {
   font-size: 18rpx;
 }
 .contact-phone {
-  font-size: 16rpx;
+  font-size: calc(16rpx * var(--font-scale, 1));
   color: $status-info;
   margin-left: 2rpx;
 }
@@ -211,12 +211,12 @@ export default {
   margin-top: 2rpx;
 }
 .energy-value {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $brand-primary;
   font-weight: bold;
 }
 .energy-unit {
-  font-size: 16rpx;
+  font-size: calc(16rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   margin-left: 2rpx;
 }

+ 8 - 8
cfc-frontend/components/FamilyMemberStrip.vue

@@ -399,12 +399,12 @@ export default {
   padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
 }
 .action-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-gray-800;
 }
 .action-relation {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   margin-top: 4rpx;
 }
@@ -422,7 +422,7 @@ export default {
   margin-right: 16rpx;
 }
 .action-item-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-gray-700;
 }
 .action-danger .action-item-text {
@@ -437,7 +437,7 @@ export default {
   color: $facade-text-slate;
 }
 .action-time {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   margin-left: 4rpx;
 }
@@ -456,8 +456,8 @@ export default {
   align-items: center;
 }
 .empty-icon { font-size: 56rpx; }
-.empty-title { font-size: 30rpx; font-weight: 600; color: $facade-text-gray-800; margin-top: 12rpx; }
-.empty-desc { font-size: 24rpx; color: $facade-text-gray-400; margin-top: 8rpx; }
+.empty-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 600; color: $facade-text-gray-800; margin-top: 12rpx; }
+.empty-desc { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-gray-400; margin-top: 8rpx; }
 .empty-btn {
   margin-top: 24rpx;
   padding: 16rpx 48rpx;
@@ -497,7 +497,7 @@ export default {
 }
 .score-label {
   width: 110rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-slate;
 }
 .score-bar-track {
@@ -517,7 +517,7 @@ export default {
 .score-value {
   width: 70rpx;
   text-align: right;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-gray-800;
   font-weight: 600;
 }

+ 3 - 3
cfc-frontend/components/FamilyRelationGraph.vue

@@ -948,7 +948,7 @@ simulationTick: function() {
   box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 }
 .gear-text {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
 /* ⚙ 维护页提示 */
@@ -972,7 +972,7 @@ simulationTick: function() {
   transform: scale(1);
 }
 .add-hint-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
   line-height: 1;
@@ -987,7 +987,7 @@ simulationTick: function() {
   margin: 10rpx 0;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
 </style>

+ 3 - 3
cfc-frontend/components/GenerationPicker.vue

@@ -103,7 +103,7 @@ export default {
   border: 1rpx solid $facade-border-soft;
   border-radius: 10rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
   background: $app-surface;
 }
@@ -161,7 +161,7 @@ export default {
   border-radius: 50%;
 }
 .radio-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/HealthBadge.vue

@@ -99,4 +99,4 @@ export default {
   margin-top: 4rpx;
   display: block;
 }
-</style>
+</style>

+ 4 - 4
cfc-frontend/components/HealthTimeline.vue

@@ -34,7 +34,7 @@ export default {
   margin-bottom: 32rpx;
 }
 .timeline-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $uni-text-color;
   margin-bottom: 16rpx;
@@ -70,14 +70,14 @@ export default {
 }
 .timeline-content { flex: 1; min-width: 0; }
 .timeline-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-slate-700;
   line-height: 1.5;
 }
 .timeline-date {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 4rpx;
   display: block;
 }
-</style>
+</style>

+ 2 - 2
cfc-frontend/components/LoginGuideCard.vue

@@ -44,7 +44,7 @@ export default {
 }
 .guide-icon { font-size: 48rpx; }
 .guide-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin: 16rpx 0;
@@ -52,7 +52,7 @@ export default {
 }
 .guide-desc { margin-bottom: 24rpx; }
 .guide-desc-item {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   line-height: 1.8;
   display: block;

+ 4 - 4
cfc-frontend/components/OnboardingGuide.vue

@@ -201,7 +201,7 @@ export default {
 }
 
 .onboarding-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: 700;
   color: var(--text, $uni-text-color);
   text-align: center;
@@ -211,7 +211,7 @@ export default {
 }
 
 .onboarding-desc {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: var(--text-secondary, $uni-text-color-secondary);
   text-align: center;
   line-height: 1.6;
@@ -227,7 +227,7 @@ export default {
 }
 
 .onboarding-title--intro {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 800;
   color: var(--color-primary, $brand-primary);
   line-height: 1.4;
@@ -293,4 +293,4 @@ export default {
   background: var(--color-primary, $brand-primary);
   box-shadow: 0 4rpx 16rpx rgba(249, 115, 22, 0.30);
 }
-</style>
+</style>

+ 3 - 3
cfc-frontend/components/OnboardingProgressBar.vue

@@ -86,7 +86,7 @@ export default {
   margin-bottom: 14rpx;
 }
 .opb-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $mat-orange-deep;
 }
@@ -107,7 +107,7 @@ export default {
 }
 .opb-tip {
   margin-top: 12rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $brand-primary-deep;
 }
-</style>
+</style>

+ 3 - 3
cfc-frontend/components/PageBanner.vue

@@ -117,7 +117,7 @@ export default {
 }
 
 .banner-name {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 700;
   letter-spacing: 4rpx;
   line-height: 1.3;
@@ -137,11 +137,11 @@ export default {
 }
 
 .banner-quote {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   opacity: 0.92;
   line-height: 1.4;
   display: inline-block;
   text-align: right;
   letter-spacing: 1rpx;
 }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/PlayfulButton.vue

@@ -123,4 +123,4 @@ export default {
   outline: 2px solid rgba(249,115,22,0.4);
   outline-offset: 2px;
 }
-</style>
+</style>

+ 3 - 3
cfc-frontend/components/PlayfulCard.vue

@@ -89,14 +89,14 @@ export default {
 }
 .playful-card__header {
   font-weight: 700;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   margin-bottom: 16rpx;
   color: var(--text, $uni-text-color);
 }
 .playful-card__content {
   color: var(--text, $uni-text-color);
   line-height: 1.6;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
 }
 .playful-card__actions {
   margin-top: 16rpx;
@@ -105,4 +105,4 @@ export default {
   gap: 16rpx;
   flex-wrap: wrap;
 }
-</style>
+</style>

+ 2 - 2
cfc-frontend/components/ProfileBadges.vue

@@ -122,12 +122,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .section-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 

+ 4 - 4
cfc-frontend/components/ProfileGrowth.vue

@@ -93,12 +93,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .section-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -117,12 +117,12 @@ export default {
   align-items: center;
 }
 .report-stat {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $accent-indigo;
 }
 .report-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 8rpx;
 }

+ 1 - 1
cfc-frontend/components/RadarChart.vue

@@ -918,4 +918,4 @@ export default {
   color: $uni-text-color-secondary;
   font-weight: 500;
 }
-</style>
+</style>

+ 4 - 4
cfc-frontend/components/RecommendedFeed.vue

@@ -149,12 +149,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .section-more {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .feed-list {
@@ -228,7 +228,7 @@ export default {
 .status-ongoing { background: $status-success-soft; color: $status-success-strong-2; }
 .status-ended { background: $facade-fill-gray-100; color: $facade-text-gray-400; }
 .feed-title {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -258,7 +258,7 @@ export default {
   margin-top: 4rpx;
 }
 .feed-date {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-ghost-light;
 }
 .feed-sub-placeholder {

+ 6 - 6
cfc-frontend/components/RelatedContent.vue

@@ -330,13 +330,13 @@ export default {
   margin-bottom: 20rpx;
 }
 .related-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-gray-800;
   margin-right: 12rpx;
 }
 .related-subtitle {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
 }
 .ra-list {
@@ -368,7 +368,7 @@ export default {
   flex-direction: column;
 }
 .ra-title {
-  font-size: 27rpx;
+  font-size: calc(27rpx * var(--font-scale, 1));
   font-weight: 500;
   color: $facade-text-gray-800;
   line-height: 1.4;
@@ -378,7 +378,7 @@ export default {
   overflow: hidden;
 }
 .ra-summary {
-  font-size: 23rpx;
+  font-size: calc(23rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   line-height: 1.4;
   margin-top: 6rpx;
@@ -393,7 +393,7 @@ export default {
   margin-top: 8rpx;
 }
 .ra-status {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 2rpx 12rpx;
   border-radius: 20rpx;
   margin-right: 12rpx;
@@ -428,4 +428,4 @@ export default {
 .related-loading-hint.dim {
   color: $facade-text-gray-300;
 }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/TagChip.vue

@@ -88,4 +88,4 @@ export default {
   color: $dim-body;
   font-weight: 400;
 }
-</style>
+</style>

+ 1 - 1
cfc-frontend/components/TrendChart.vue

@@ -300,4 +300,4 @@ export default {
   font-size: 22rpx;
   color: $facade-text-slate-deep;
 }
-</style>
+</style>

+ 5 - 5
cfc-frontend/components/address-picker.vue

@@ -383,7 +383,7 @@ export default {
 }
 
 .address-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   flex: 1;
 }
@@ -453,7 +453,7 @@ export default {
 }
 
 .crumb {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   padding: 8rpx 16rpx;
   background: $facade-hairline-2;
@@ -488,12 +488,12 @@ export default {
 }
 
 .item-text {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 
 .item-check {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $brand-primary;
   font-weight: bold;
 }
@@ -509,4 +509,4 @@ export default {
   color: $facade-text-muted;
   font-size: 28rpx;
 }
-</style>
+</style>

+ 8 - 8
cfc-frontend/components/daily-task-card.vue

@@ -138,12 +138,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .daily-task-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-gray-800;
 }
 .daily-task-date {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
 }
 .daily-task-state {
@@ -154,7 +154,7 @@ export default {
   padding: 24rpx 0;
 }
 .daily-task-state-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
 }
 .daily-task-group {
@@ -163,7 +163,7 @@ export default {
   margin-bottom: 16rpx;
 }
 .daily-task-group-title {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   margin-bottom: 8rpx;
 }
@@ -179,16 +179,16 @@ export default {
   border-bottom: none;
 }
 .daily-task-item-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-gray-700;
 }
 .daily-task-go {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $brand-primary;
   font-weight: 500;
 }
 .daily-task-done {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $status-success;
   font-weight: 600;
 }
@@ -200,7 +200,7 @@ export default {
   padding: 12rpx 0;
 }
 .daily-task-all-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $status-success;
   font-weight: 500;
 }

+ 4 - 4
cfc-frontend/components/gate-lock.vue

@@ -104,13 +104,13 @@ export default {
   opacity: 0.8;
 }
 .gate-name {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $brand-primary-light;
   margin-bottom: 12rpx;
 }
 .gate-desc {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: rgba(251,146,60,0.7);
   margin-bottom: 20rpx;
   line-height: 1.5;
@@ -122,11 +122,11 @@ export default {
   margin-bottom: 24rpx;
 }
 .reward-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: rgba(251,146,60,0.5);
 }
 .reward-points, .reward-energy {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   padding: 4rpx 14rpx;
   border-radius: 16rpx;
 }

+ 2 - 2
cfc-frontend/components/hand-signature/hand-signature.vue

@@ -287,13 +287,13 @@ export default {
   border-color: $accent-indigo;
 }
 .agree-tick {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $app-surface;
   line-height: 1;
 }
 .agree-text {
   flex: 1;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   line-height: 1.5;
 }

+ 7 - 7
cfc-frontend/components/login-sheet.vue

@@ -303,18 +303,18 @@ export default {
   border-radius: 32rpx;
 }
 .app-name {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-top: 16rpx;
 }
 .identity {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $brand-primary;
   margin-top: 8rpx;
 }
 .slogan {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 12rpx;
   text-align: center;
@@ -328,7 +328,7 @@ export default {
   margin-top: 28rpx;
 }
 .concept-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-deep;
   line-height: 1.6;
 }
@@ -351,7 +351,7 @@ export default {
   align-items: center;
   border-radius: 999rpx;
   padding: 6rpx 12rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   flex-shrink: 0;  /* 防止被压缩导致文本换行 */
   white-space: nowrap;
 }
@@ -447,10 +447,10 @@ export default {
   justify-content: center;
   flex-wrap: wrap;
   margin-top: 24rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .link {
   color: $brand-primary;
 }
-</style>
+</style>

+ 2 - 2
cfc-frontend/components/report-upload-card.vue

@@ -59,14 +59,14 @@ export default {
   flex: 1;
 }
 .report-upload-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $mat-green-strong;
   display: block;
   margin-bottom: 6rpx;
 }
 .report-upload-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: #558B2F;
   line-height: 1.5;
   display: block;

+ 2 - 2
cfc-frontend/components/tab-transition.vue

@@ -122,7 +122,7 @@ export default {
 }
 
 .dim-char {
-  font-size: 120rpx;
+  font-size: calc(120rpx * var(--font-scale, 1));
   font-weight: 700;
   line-height: 1.2;
   margin-bottom: 8rpx;
@@ -135,7 +135,7 @@ export default {
 }
 
 .dim-label {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 500;
   line-height: 1;
   margin-bottom: 40rpx;

+ 6 - 6
cfc-frontend/components/wuxing-sandbox.vue

@@ -695,7 +695,7 @@ export default {
   position: relative;
   z-index: 5;
 }
-.sandbox-title { font-size: 26rpx; font-weight: bold; color: #8FC5E8; margin-left: 8rpx; }
+.sandbox-title { font-size: calc(26rpx * var(--font-scale, 1)); font-weight: bold; color: #8FC5E8; margin-left: 8rpx; }
 .sandbox-logo { width: 32rpx; height: 32rpx; flex-shrink: 0; }
 .sandbox-badge {
   font-size: 20rpx;
@@ -843,7 +843,7 @@ export default {
 .point-icon { font-size: 26rpx; line-height: 1; }
 
 .point-label {
-  font-size: 22rpx; font-weight: bold; color: rgba(255,255,255,0.9);
+  font-size: calc(22rpx * var(--font-scale, 1)); font-weight: bold; color: rgba(255,255,255,0.9);
   margin-top: 6rpx; text-shadow: 0 1rpx 4rpx rgba(0,0,0,0.5);
   letter-spacing: 2rpx;
 }
@@ -852,7 +852,7 @@ export default {
   margin-top: 0;
 }
 .point-energy {
-  font-size: 18rpx; color: rgba(143,197,232,0.8);
+  font-size: calc(18rpx * var(--font-scale, 1)); color: rgba(143,197,232,0.8);
   background: rgba(143,197,232,0.12);
   padding: 1rpx 10rpx; border-radius: 12rpx;
   margin-top: 2rpx;
@@ -881,7 +881,7 @@ export default {
   position: relative; z-index: 5; flex-wrap: wrap;
 }
 .dim-item {
-  font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 10rpx; white-space: nowrap;
+  font-size: calc(20rpx * var(--font-scale, 1)); padding: 4rpx 12rpx; border-radius: 10rpx; white-space: nowrap;
 }
 .dim-item--wood { color: $mat-green; background: rgba(76,175,80,0.12); }
 .dim-item--fire { color: $mind-accent; background: rgba(255,107,53,0.12); }
@@ -906,7 +906,7 @@ export default {
   align-items: center;
   justify-content: center;
   padding: 8rpx 28rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: rgba(143,197,232,0.6);
   background: rgba(143,197,232,0.08);
   border: 1rpx solid rgba(143,197,232,0.15);
@@ -929,4 +929,4 @@ export default {
 .toggle-text {
   font-weight: bold;
 }
-</style>
+</style>

+ 3 - 3
cfc-frontend/custom-tab-bar/index.vue

@@ -294,11 +294,11 @@ export default {
   transform: scale(1);
 }
 .dim-fan-emoji {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   line-height: 1;
 }
 .dim-fan-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 600;
   margin-top: 8rpx;
@@ -316,4 +316,4 @@ export default {
   from { opacity: 0; }
   to { opacity: 1; }
 }
-</style>
+</style>

+ 9 - 7
cfc-frontend/pages/achievement/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 顶部导航 -->
 
     <!-- 统计概览 -->
@@ -55,8 +55,10 @@
 
 <script>
 import { getChildBadges } from '@/utils/api'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       badges: [],
@@ -132,7 +134,7 @@ export default {
 }
 .stat-label {
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 8rpx;
 }
@@ -143,7 +145,7 @@ export default {
   padding: 30rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   margin-bottom: 24rpx;
@@ -197,13 +199,13 @@ export default {
 }
 .empty-text {
   display: block;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-bottom: 12rpx;
 }
 .empty-hint {
   display: block;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
 .goal-item {
@@ -218,11 +220,11 @@ export default {
   margin-bottom: 12rpx;
 }
 .goal-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .goal-progress {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .progress-bar {

+ 6 - 4
cfc-frontend/pages/action-detail/components/AbilityDiagram.vue

@@ -1,6 +1,6 @@
-<template>
+<template>
   <!-- 能力图 - 径向布局 Canvas 组件 -->
-  <view class="ability-graph-wrapper" v-if="abilities && abilities.length > 0" :style="{ height: canvasHeight + 'px' }">
+  <view class="ability-graph-wrapper" v-if="abilities && abilities.length > 0" :style="{ '--font-scale': fontScale, height: canvasHeight + 'px' }">
     <canvas
       class="ability-graph-canvas"
       canvas-id="abilityGraphCanvas"
@@ -59,7 +59,9 @@ import { BrandColors } from '../../../utils/brand-colors.js'
  *
  * 数据源:父组件通过 abilities prop 传入
  */
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'AbilityDiagram',
   props: {
     /** 当前用户ID */
@@ -685,13 +687,13 @@ export default {
   margin-bottom: 16rpx;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
   margin-bottom: 8rpx;
 }
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-bottom: 24rpx;
 }

+ 10 - 8
cfc-frontend/pages/action-detail/components/DimensionSubDims.vue

@@ -1,5 +1,5 @@
-<template>
-  <view class="dim-subdims" :style="{ '--accent': accentColor }">
+<template>
+  <view class="dim-subdims" :style="{ '--accent': accentColor, '--font-scale': fontScale }">
     <view class="dim-header">
       <text class="dim-title">{{ title }}</text>
       <text class="dim-subtitle">{{ subtitle }}</text>
@@ -40,7 +40,9 @@
 
 <script>
 import { BrandColors } from '../../../utils/brand-colors.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'DimensionSubDims',
   props: {
     title: { type: String, default: '维度评分' },
@@ -72,13 +74,13 @@ export default {
   margin-bottom: 24rpx;
 }
 .dim-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $app-ink-night;
   display: block;
 }
 .dim-subtitle {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 6rpx;
   display: block;
@@ -110,14 +112,14 @@ export default {
   min-width: 0;
 }
 .dim-item-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
   display: block;
   line-height: 1.4;
 }
 .dim-item-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 4rpx;
   display: block;
@@ -129,7 +131,7 @@ export default {
   margin-left: 16rpx;
 }
 .dim-item-score {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: 700;
   line-height: 1;
 }
@@ -137,7 +139,7 @@ export default {
 .score-ok { color: $status-warning-deep; }
 .score-low { color: $status-danger-deep; }
 .dim-item-level {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   font-weight: 500;
   display: block;
   margin-top: 4rpx;

+ 9 - 7
cfc-frontend/pages/action-detail/components/OctopusDiagram.vue

@@ -1,6 +1,6 @@
-<template>
+<template>
   <!-- 章鱼图 - 关键人拓展图谱 -->
-  <view class="octopus-wrapper" v-if="effects && effects.list && effects.list.length > 0" :style="{ height: canvasHeight + 'px' }">
+  <view class="octopus-wrapper" v-if="effects && effects.list && effects.list.length > 0" :style="{ '--font-scale': fontScale, height: canvasHeight + 'px' }">
     <canvas
       class="octopus-canvas"
       canvas-id="octopusCanvas"
@@ -62,7 +62,9 @@ import { BrandColors } from '../../../utils/brand-colors.js'
  * 2. 第1层:成效记录节点(标签:金额大/频次高/新成交)
  * 3. 第2层:拓展方向节点(虚线,≤8个)
  */
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'OctopusDiagram',
   props: {
     selfId: { type: [Number, String], default: null },
@@ -571,13 +573,13 @@ export default {
   margin-bottom: 16rpx;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
   margin-bottom: 8rpx;
 }
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-bottom: 24rpx;
 }
@@ -660,7 +662,7 @@ export default {
   margin-bottom: 6rpx;
 }
 .kp-item {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-slate-deep;
   display: block;
   margin-bottom: 4rpx;
@@ -682,7 +684,7 @@ export default {
   padding: 8rpx 0;
 }
 .empty-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
 .popup-actions {
@@ -692,4 +694,4 @@ export default {
   padding-top: 12rpx;
   border-top: 1rpx solid $facade-fill-slate;
 }
-</style>
+</style>

+ 6 - 4
cfc-frontend/pages/action-detail/components/PearlDiagram.vue

@@ -1,6 +1,6 @@
-<template>
+<template>
   <!-- 珍珠图 - 珍珠项链资源清单 -->
-  <view class="pearl-graph-wrapper" v-if="hasData" :style="{ minHeight: canvasHeight + 'px' }">
+  <view class="pearl-graph-wrapper" v-if="hasData" :style="{ '--font-scale': fontScale, minHeight: canvasHeight + 'px' }">
     <canvas
       class="pearl-graph-canvas"
       canvas-id="pearlGraphCanvas"
@@ -74,7 +74,9 @@ import { BrandColors, INDUSTRY_COLORS, danger, primary, success, white } from '@
  * 数据源:父组件通过 resources prop 传入
  * 布局方式:环形均分布局(非力导向)
  */
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'PearlDiagram',
   props: {
     /** 资源数据 { groups: [{ type, typeName, items }] } */
@@ -1019,13 +1021,13 @@ export default {
   margin-bottom: 16rpx;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
   margin-bottom: 8rpx;
 }
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-bottom: 24rpx;
 }

+ 21 - 19
cfc-frontend/pages/action-detail/contact-detail.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="detail-page">
+  <view class="detail-page" :style="{ '--font-scale': fontScale }">
     <!-- 头部 -->
     <view class="detail-header">
       <view class="header-top">
@@ -113,8 +113,10 @@
 <script>
 import { BrandColors } from '../../utils/brand-colors.js'
 import { getContactDetail, updateContact, deleteContact, recordContactInteraction } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data: function() {
     return {
       contactId: null,
@@ -277,7 +279,7 @@ export default {
   font-size: 28rpx;
   padding: 10rpx 20rpx;
 }
-.page-title { font-size: 32rpx; font-weight: bold; }
+.page-title { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: bold; }
 .header-avatar {
   width: 120rpx;
   height: 120rpx;
@@ -288,14 +290,14 @@ export default {
   margin-bottom: 16rpx;
   border: 4rpx solid rgba(255,255,255,0.4);
 }
-.avatar-text { font-size: 48rpx; font-weight: bold; color: $app-surface; }
-.header-name { font-size: 36rpx; font-weight: bold; margin-bottom: 8rpx; }
-.header-meta { font-size: 26rpx; opacity: 0.9; margin-bottom: 4rpx; }
-.header-known { font-size: 24rpx; opacity: 0.7; margin-bottom: 12rpx; }
+.avatar-text { font-size: calc(48rpx * var(--font-scale, 1)); font-weight: bold; color: $app-surface; }
+.header-name { font-size: calc(36rpx * var(--font-scale, 1)); font-weight: bold; margin-bottom: 8rpx; }
+.header-meta { font-size: calc(26rpx * var(--font-scale, 1)); opacity: 0.9; margin-bottom: 4rpx; }
+.header-known { font-size: calc(24rpx * var(--font-scale, 1)); opacity: 0.7; margin-bottom: 12rpx; }
 .header-intimacy { display: flex; align-items: center; gap: 8rpx; }
-.intimacy-heart { font-size: 32rpx; }
-.intimacy-num { font-size: 40rpx; font-weight: bold; }
-.intimacy-label { font-size: 24rpx; opacity: 0.8; }
+.intimacy-heart { font-size: calc(32rpx * var(--font-scale, 1)); }
+.intimacy-num { font-size: calc(40rpx * var(--font-scale, 1)); font-weight: bold; }
+.intimacy-label { font-size: calc(24rpx * var(--font-scale, 1)); opacity: 0.8; }
 
 .info-section, .interaction-section {
   background: $app-surface;
@@ -304,7 +306,7 @@ export default {
   padding: 30rpx;
 }
 .section-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -316,14 +318,14 @@ export default {
   margin-bottom: 16rpx;
 }
 .info-icon { font-size: 28rpx; margin-right: 12rpx; width: 40rpx; }
-.info-value { font-size: 26rpx; color: $facade-text-deep; flex: 1; }
+.info-value { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-deep; flex: 1; }
 .countdown { color: $accent-pink; }
 
 .edit-row {
   margin-bottom: 20rpx;
 }
 .edit-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 8rpx;
@@ -332,7 +334,7 @@ export default {
   border: 1rpx solid $facade-border-soft;
   border-radius: 12rpx;
   padding: 24rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   width: 100%;
   box-sizing: border-box;
   min-height: 80rpx;
@@ -341,7 +343,7 @@ export default {
   border: 1rpx solid $facade-border-soft;
   border-radius: 12rpx;
   padding: 24rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   width: 100%;
   box-sizing: border-box;
   min-height: 160rpx;
@@ -350,7 +352,7 @@ export default {
   border: 1rpx solid $facade-border-soft;
   border-radius: 12rpx;
   padding: 24rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   min-height: 80rpx;
   display: flex;
   align-items: center;
@@ -373,9 +375,9 @@ export default {
   padding: 16rpx 0;
   border-bottom: 1rpx solid $facade-fill;
 }
-.interaction-date { font-size: 24rpx; color: $facade-text-muted; }
-.interaction-desc { font-size: 26rpx; color: $facade-text-deep; }
-.interaction-empty { text-align: center; padding: 30rpx; color: $facade-text-muted; font-size: 26rpx; }
+.interaction-date { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-muted; }
+.interaction-desc { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-deep; }
+.interaction-empty { text-align: center; padding: 30rpx; color: $facade-text-muted; font-size: calc(26rpx * var(--font-scale, 1)); }
 .btn-interaction {
   width: 100%;
   padding: 24rpx;
@@ -398,4 +400,4 @@ export default {
   color: $status-danger-2;
   text-align: center;
 }
-</style>
+</style>

+ 20 - 18
cfc-frontend/pages/action-detail/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 登录浮层(全局组件,页面内弹出底部登录) -->
     <login-sheet ref="loginSheet" @success="onSheetLoginSuccess" />
     <!-- Tabbar 切换过渡页 -->
@@ -275,8 +275,10 @@ import RadarChart from '../../components/RadarChart.vue'
 import DimensionSubDims from './components/DimensionSubDims.vue'
 import DimensionPageSkeleton from '../../components/DimensionPageSkeleton.vue'
 import { getVisibleSections, getEnergyOverview, getChildren, getFamilyEnergySandbox, getEnergySandbox, getFamilyMemberList, getOctopusTentacles, getPearlResources, deletePearlResource, getAbilityMap, getRadarData, getPearlReminders, getOctopusEffects, getOctopusAnalysisSummary, getOctopusExpansionSuggest, getOctopusEffectKeyPersons } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { TabTransition, PageBanner, FamilyEnergyBar, FamilyRelationGraph, PearlDiagram, AbilityDiagram, OctopusDiagram, FamilyMemberStrip, DimensionTasks, DimensionActivities, DimensionProducts, DimensionIntroCard, DimensionVisitorCard, FloatingAvatar, RadarChart, DimensionSubDims, DimensionPageSkeleton },
   data() {
     return {
@@ -921,7 +923,7 @@ $c-tint-mint: $c-tint-mint-wash;
   border-radius: 50%;
 }
 .brand-strap-text {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 600;
   text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
@@ -943,7 +945,7 @@ $c-tint-mint: $c-tint-mint-wash;
 }
 .guidance-icon { font-size: 36rpx; }
 .guidance-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $status-success-strong;
   font-weight: 500;
 }
@@ -1010,13 +1012,13 @@ $c-tint-mint: $c-tint-mint-wash;
   transform: scale(1.1);
 }
 .section-title {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $app-text;
   letter-spacing: 0.5rpx;
 }
 .section-sub {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 4rpx;
   line-height: 1.4;
@@ -1026,7 +1028,7 @@ $c-tint-mint: $c-tint-mint-wash;
   align-items: center;
   padding: 12rpx 28rpx;
   border-radius: 40rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   white-space: nowrap;
   transition: opacity 0.2s $ease-standard, transform 0.2s $ease-standard;
@@ -1106,13 +1108,13 @@ $c-tint-mint: $c-tint-mint-wash;
   flex-direction: column;
 }
 .explain-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $app-text;
   line-height: 1.3;
 }
 .explain-score {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: 800;
   line-height: 1;
   letter-spacing: -2rpx;
@@ -1121,14 +1123,14 @@ $c-tint-mint: $c-tint-mint-wash;
 .score-explain-warn .explain-score { color: $status-warning-deep; }
 .score-explain-bad .explain-score { color: $status-danger-deep; }
 .explain-score-unit {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   color: $app-text-subtle;
   margin-left: 2rpx;
   letter-spacing: 0;
 }
 .explain-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $c-text-soft;
   line-height: 1.7;
 }
@@ -1241,7 +1243,7 @@ $c-tint-mint: $c-tint-mint-wash;
   font-size: 44rpx;
 }
 .func-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $c-text-deep;
   font-weight: 500;
 }
@@ -1260,7 +1262,7 @@ $c-tint-mint: $c-tint-mint-wash;
   border: 2rpx solid rgba(16, 185, 129, 0.1);
 }
 .portrait-tier {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $dim-action;
   font-weight: bold;
   margin-left: 16rpx;
@@ -1269,7 +1271,7 @@ $c-tint-mint: $c-tint-mint-wash;
   margin-bottom: 24rpx;
 }
 .portrait-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $app-text-secondary;
   line-height: 1.6;
   display: block;
@@ -1297,12 +1299,12 @@ $c-tint-mint: $c-tint-mint-wash;
   background: linear-gradient(135deg, $status-success-soft, $c-success-light);
 }
 .portrait-dim-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text;
   flex: 1;
 }
 .portrait-dim-score {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $dim-action;
   margin-right: 12rpx;
@@ -1321,7 +1323,7 @@ $c-tint-mint: $c-tint-mint-wash;
   transition: width 0.3s ease;
 }
 .portrait-dim-desc {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $app-text-secondary;
   display: block;
 }
@@ -1333,8 +1335,8 @@ $c-tint-mint: $c-tint-mint-wash;
   margin-top: 16rpx;
 }
 .portrait-tip-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $status-success-strong;
   line-height: 1.5;
 }
-</style>
+</style>

+ 16 - 14
cfc-frontend/pages/action-detail/interaction-log.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">记录互动</text>
     </view>
@@ -129,8 +129,10 @@ import { getFamilyMemberList, addInteraction, reportAppEnter
 } from '../../utils/api.js'
 import config from '../../config.js'
 import { pickImage } from '../../utils/image-picker.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       members: [],
@@ -427,7 +429,7 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -438,7 +440,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -460,12 +462,12 @@ export default {
   background: $uni-primary-pale;
 }
 .member-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   display: block;
 }
 .member-rel {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .type-grid {
@@ -491,7 +493,7 @@ export default {
   border: 2rpx solid $facade-hairline;
   border-radius: 12rpx;
   padding: 16rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   background: $facade-fill-ghost;
 }
 .type-icon {
@@ -500,7 +502,7 @@ export default {
   margin-bottom: 8rpx;
 }
 .type-name {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .desc-input {
@@ -509,7 +511,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .time-selector {
@@ -521,7 +523,7 @@ export default {
   padding: 16rpx 32rpx;
   border: 2rpx solid $facade-hairline;
   border-radius: 12rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .time-option.selected {
@@ -536,7 +538,7 @@ export default {
   padding: 20rpx;
   background: $facade-fill-ghost;
   border-radius: 12rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 
@@ -545,7 +547,7 @@ export default {
   margin-bottom: 16rpx;
 }
 .media-subtitle {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 12rpx;
@@ -602,7 +604,7 @@ export default {
 }
 .video-name,
 .audio-name {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 8rpx;
   overflow: hidden;
@@ -626,7 +628,7 @@ export default {
   color: $facade-text-muted;
 }
 .media-add-text {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 8rpx;
 }
@@ -647,4 +649,4 @@ export default {
 .btn-submit[disabled] {
   background: $facade-text-ghost;
 }
-</style>
+</style>

+ 11 - 9
cfc-frontend/pages/action-detail/member-action-detail.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="detail-container">
+  <view class="detail-container" :style="{ '--font-scale': fontScale }">
     <!-- 顶部导航 -->
 <!-- 品牌定位语(登录前显示) -->
     <view class="brand-strap" v-if="!isLoggedIn">
@@ -88,8 +88,10 @@ import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
 import DimensionIntroCard from '../../components/DimensionIntroCard.vue'
 import { getEnergyOverview, getFamilyEnergySandbox, getChildren } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { FamilyEnergyBar, FamilyRelationGraph, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, DimensionIntroCard },
   data() {
     return {
@@ -258,7 +260,7 @@ export default {
   background: linear-gradient(135deg, $status-success, $status-success-light-3);
 }
 .avatar-text {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
 }
@@ -268,12 +270,12 @@ export default {
   flex-direction: column;
 }
 .member-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .member-role {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
 }
@@ -283,7 +285,7 @@ export default {
   align-items: center;
 }
 .score-value {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $mat-green;
 }
@@ -291,7 +293,7 @@ export default {
   color: $status-success;
 }
 .score-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .bottom-spacer {
@@ -307,7 +309,7 @@ export default {
   border-left: 4rpx solid $status-success;
 }
 .brand-strap-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $status-success-strong;
   font-weight: 500;
 }
@@ -325,8 +327,8 @@ export default {
 }
 .guidance-icon { font-size: 32rpx; }
 .guidance-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $status-success-strong;
   font-weight: 500;
 }
-</style>
+</style>

+ 15 - 13
cfc-frontend/pages/action-detail/octopus-add-effect.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">感恩记录</text>
     </view>
@@ -77,8 +77,10 @@
 
 <script>
 import { addOctopusEffect, getOctopusKeyPersons, matchOctopusKeyPersonByPhone, bindOctopusKeyPersonSystemUser } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     var now = new Date()
     var y = now.getFullYear()
@@ -223,7 +225,7 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -234,7 +236,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -249,7 +251,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .desc-input {
@@ -258,7 +260,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 /* 关键人选择 */
@@ -271,7 +273,7 @@ export default {
   margin-bottom: 0;
 }
 .kp-add-link {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $brand-primary;
 }
 .kp-list {
@@ -294,11 +296,11 @@ export default {
   justify-content: space-between;
 }
 .kp-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .kp-org {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .kp-match-btn {
@@ -336,7 +338,7 @@ export default {
   color: $app-surface;
 }
 .empty-hint {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .submit-bar {
@@ -360,7 +362,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   display: flex;
   align-items: center;
@@ -372,7 +374,7 @@ export default {
   gap: 16rpx;
 }
 .datetime-sep {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
 /* 手机号匹配 */
@@ -387,7 +389,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .phone-match-btn {
@@ -401,7 +403,7 @@ export default {
   flex-shrink: 0;
 }
 .phone-match-result {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-info;
   margin-top: 12rpx;
   display: block;

+ 13 - 11
cfc-frontend/pages/action-detail/octopus-add-key-person.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">添加关键人</text>
     </view>
@@ -81,8 +81,10 @@
 
 <script>
 import { addOctopusKeyPerson, getOctopusKeyPersons } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       name: '',
@@ -171,7 +173,7 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -182,7 +184,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -197,7 +199,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .desc-input {
@@ -206,7 +208,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .form-picker {
@@ -215,7 +217,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   display: flex;
   align-items: center;
@@ -233,7 +235,7 @@ export default {
   box-sizing: border-box;
 }
 .referrer-selected {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $brand-primary;
 }
 .referrer-placeholder {
@@ -245,7 +247,7 @@ export default {
   color: $facade-text-muted;
 }
 .empty-referrer {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 /* 介绍人弹窗 */
@@ -292,13 +294,13 @@ export default {
   border-bottom: 1rpx solid $facade-fill-gray-100;
 }
 .referrer-option-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
 }
 .referrer-option-org {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
   display: block;
@@ -318,4 +320,4 @@ export default {
 .btn-submit[disabled] {
   background: $facade-text-ghost;
 }
-</style>
+</style>

+ 11 - 9
cfc-frontend/pages/action-detail/octopus-effects-list.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">感恩记录</text>
       <text class="page-sub">管理你的感恩时刻与成效记录</text>
@@ -38,8 +38,10 @@
 
 <script>
 import { getOctopusEffects, deleteOctopusEffect } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       records: [],
@@ -114,13 +116,13 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
 }
 .page-sub {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
   display: block;
@@ -143,7 +145,7 @@ export default {
   align-items: center;
 }
 .record-amount {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $brand-primary;
 }
@@ -159,12 +161,12 @@ export default {
   border-radius: 8rpx;
 }
 .record-date {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 12rpx;
 }
 .record-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 8rpx;
 }
@@ -194,13 +196,13 @@ export default {
   margin-bottom: 16rpx;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   margin-bottom: 8rpx;
 }
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .fab {
@@ -221,4 +223,4 @@ export default {
   color: $app-surface;
   font-weight: 300;
 }
-</style>
+</style>

+ 12 - 10
cfc-frontend/pages/action-detail/pearl-add-resource.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">登记资源</text>
     </view>
@@ -56,8 +56,10 @@
 
 <script>
 import { getContactList, getConnectionTypes, addPearlResource } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       contacts: [],
@@ -149,7 +151,7 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -160,7 +162,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .section-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -178,7 +180,7 @@ export default {
   padding: 12rpx 32rpx;
   border: 2rpx solid $facade-hairline;
   border-radius: 999rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   background: $facade-fill-ghost;
 }
@@ -205,7 +207,7 @@ export default {
   background: $uni-primary-pale;
 }
 .type-name {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .name-input {
@@ -214,7 +216,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .desc-input {
@@ -223,7 +225,7 @@ export default {
   background: $facade-fill-ghost;
   border-radius: 12rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .member-select {
@@ -242,16 +244,16 @@ export default {
   background: $uni-primary-pale;
 }
 .member-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   display: block;
 }
 .member-rel {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .empty-hint {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .submit-bar {

+ 12 - 10
cfc-frontend/pages/action-detail/relationship-questionnaire.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="page-header">
       <text class="page-title">关系问卷</text>
       <text class="page-subtitle" v-if="memberName">为「{{ memberName }}」评估关系质量</text>
@@ -73,8 +73,10 @@
 
 <script>
 import { generateQuestionnaire, submitQuestionnaire, getQuestionnaireSnapshot } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       memberId: null,
@@ -190,13 +192,13 @@ export default {
   padding: 20rpx 0 30rpx;
 }
 .page-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
 }
 .page-subtitle {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 8rpx;
   display: block;
@@ -210,7 +212,7 @@ export default {
   color: $facade-text-muted;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   display: block;
   margin-bottom: 30rpx;
@@ -246,7 +248,7 @@ export default {
 .dimension-tag.intimacy { background: $accent-pink-tint; color: $accent-pink-deep; }
 .dimension-tag.communication { background: $accent-indigo-tint; color: $accent-indigo-ink; }
 .question-text {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.6;
   display: block;
@@ -277,7 +279,7 @@ export default {
   text-align: center;
   background: $facade-fill;
   border-radius: 50%;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .option-item.selected .option-letter {
@@ -286,7 +288,7 @@ export default {
 }
 .option-text {
   flex: 1;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .submit-bar {
@@ -317,7 +319,7 @@ export default {
   padding: 40rpx;
 }
 .result-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -337,7 +339,7 @@ export default {
 }
 .result-score-label {
   width: 60rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .result-bar-bg {
@@ -356,7 +358,7 @@ export default {
 .result-bar-fill.communication { background: $dim-wisdom; }
 .result-score-value {
   width: 50rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   text-align: right;
 }

+ 14 - 12
cfc-frontend/pages/activity/create.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="form-card">
       <!-- 活动标题 -->
       <view class="form-item">
@@ -179,8 +179,10 @@ import { pickImage } from '../../utils/image-picker.js'
 import ContentSharePoster from '../../components/ContentSharePoster.vue'
 
 var BASE_URL = config.api('')
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { ContentSharePoster },
   computed: {
     // 后台活动管理员可直接发布;服务商账号只能保存后提交审核
@@ -582,7 +584,7 @@ export default {
 }
 
 .form-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $uni-text-color;
   margin-bottom: 24rpx;
@@ -604,7 +606,7 @@ export default {
 }
 
 .form-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-slate-deep;
   font-weight: 600;
   margin-bottom: 12rpx;
@@ -617,7 +619,7 @@ export default {
   border: 1rpx solid $uni-border-color-light;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $uni-text-color;
   box-sizing: border-box;
 }
@@ -628,7 +630,7 @@ export default {
   border: 1rpx solid $uni-border-color-light;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $uni-text-color;
   box-sizing: border-box;
   display: flex;
@@ -646,7 +648,7 @@ export default {
   border: 1rpx solid $uni-border-color-light;
   border-radius: 12rpx;
   padding: 16rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $uni-text-color;
   box-sizing: border-box;
 }
@@ -679,7 +681,7 @@ export default {
 }
 
 .upload-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
   margin-top: 8rpx;
 }
@@ -692,13 +694,13 @@ export default {
 }
 
 .cover-action {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-slate-deep;
   text-decoration: underline;
 }
 
 .cover-action-danger {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $status-danger;
   text-decoration: underline;
 }
@@ -742,7 +744,7 @@ export default {
 }
 
 .tpl-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-text-color;
   text-align: center;
 }
@@ -756,7 +758,7 @@ export default {
 }
 
 .poster-preview-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
 }
 
@@ -825,4 +827,4 @@ export default {
 @keyframes spin {
   to { transform: rotate(360deg); }
 }
-</style>
+</style>

+ 13 - 11
cfc-frontend/pages/activity/order-pay/order-pay.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view v-if="loading" class="loading-wrap">
       <text class="loading-text">加载中...</text>
     </view>
@@ -56,8 +56,10 @@
 
 <script>
 import { payActivityOrder, handleActivityOrderSuccess } from '@/utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       orderNo: '',
@@ -202,7 +204,7 @@ export default {
 }
 
 .header-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
 }
@@ -215,7 +217,7 @@ export default {
 
 .header-cancelled {
   margin-top: 12rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-brand-tint-2;
 }
 
@@ -228,7 +230,7 @@ export default {
 
 .section-title {
   display: block;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
   margin-bottom: 20rpx;
@@ -243,12 +245,12 @@ export default {
 }
 
 .info-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
 }
 
 .info-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $uni-text-color;
   max-width: 400rpx;
   word-break: break-all;
@@ -256,7 +258,7 @@ export default {
 }
 
 .order-amount {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $brand-primary;
 }
@@ -281,12 +283,12 @@ export default {
 }
 
 .payment-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $uni-text-color;
 }
 
 .payment-checked {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $status-success;
 }
 
@@ -316,7 +318,7 @@ export default {
 
 .cancel-link {
   margin-top: 24rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
-</style>
+</style>

+ 18 - 16
cfc-frontend/pages/ai/chat.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="chat-container">
+  <view class="chat-container" :style="{ '--font-scale': fontScale }">
     <!-- 导航栏 -->
     <view class="chat-nav" :class="'mascot-' + mascotCode">
       <view class="nav-back" @click="goBack">
@@ -169,8 +169,10 @@ import TaskCard from '@/pages/ai/components/AITaskCard.vue'
 import QuotaProgressBar from '@/pages/ai/components/QuotaProgressBar.vue'
 import UpgradeGuideModal from '@/pages/ai/components/UpgradeGuideModal.vue'
 import config from '@/config.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { BaseEmpty, TaskCard, QuotaProgressBar, UpgradeGuideModal },
   data() {
     return {
@@ -593,13 +595,13 @@ export default {
 }
 
 .conv-header-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: var(--text, $uni-text-color);
 }
 
 .conv-header-new {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: var(--color-primary, $brand-primary);
   font-weight: 500;
 }
@@ -619,7 +621,7 @@ export default {
 }
 
 .conv-item-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: var(--text, $uni-text-color);
   display: block;
   margin-bottom: 6rpx;
@@ -629,7 +631,7 @@ export default {
 }
 
 .conv-item-time {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: var(--muted, $app-text-subtle);
 }
 
@@ -669,7 +671,7 @@ export default {
 }
 
 .welcome-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   color: var(--text, $uni-text-color);
   display: block;
@@ -677,7 +679,7 @@ export default {
 }
 
 .welcome-desc {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: var(--text-secondary, $uni-text-color-secondary);
   display: block;
   margin-bottom: 32rpx;
@@ -705,7 +707,7 @@ export default {
 }
 
 .suggestion-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: var(--text, $uni-text-color);
 }
 
@@ -727,7 +729,7 @@ export default {
 .message-avatar {
   width: 56rpx;
   height: 56rpx;
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   margin-right: 12rpx;
   flex-shrink: 0;
   display: flex;
@@ -749,7 +751,7 @@ export default {
 .message-bubble {
   max-width: 70%;
   padding: 16rpx 20rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   line-height: 1.6;
   border-radius: 16rpx;
   word-break: break-word;
@@ -808,7 +810,7 @@ export default {
 
 .chat-input {
   height: 72rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: var(--text, $uni-text-color);
 }
 
@@ -841,7 +843,7 @@ export default {
 }
 
 .typing-dot {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   line-height: 1;
   animation: typingBounce 1.4s infinite;
 }
@@ -886,7 +888,7 @@ export default {
 /* 报告来源标识 */
 .source-label {
   margin-top: 16rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: var(--muted, $app-text-subtle);
   text-align: right;
 }
@@ -928,7 +930,7 @@ export default {
 }
 
 .rec-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: 600;
   color: var(--text, $uni-text-color);
   overflow: hidden;
@@ -937,7 +939,7 @@ export default {
 }
 
 .rec-desc {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: var(--text-secondary, $uni-text-color-secondary);
   overflow: hidden;
   text-overflow: ellipsis;
@@ -969,7 +971,7 @@ export default {
 }
 .chat-disclaimer {
   text-align: center;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   padding: 16rpx 0 20rpx;
   background: $facade-fill-2;

+ 9 - 7
cfc-frontend/pages/ai/components/AITaskCard.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="ai-task-card">
+  <view class="ai-task-card" :style="{ '--font-scale': fontScale }">
     <view class="card-header">
       <text class="card-title">{{ task.title }}</text>
       <view class="dimension-badge" :style="{ backgroundColor: dimensionColor }">
@@ -31,7 +31,9 @@
 
 <script>
 import { BrandColors } from '../../../utils/brand-colors.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'TaskCard',
 
   props: {
@@ -149,7 +151,7 @@ export default {
 }
 
 .card-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-gray-800;
   flex: 1;
@@ -163,7 +165,7 @@ export default {
 }
 
 .dimension-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   font-weight: 500;
   color: $app-surface;
 }
@@ -173,7 +175,7 @@ export default {
 }
 
 .card-description {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-slate;
   line-height: 44rpx;
 }
@@ -194,13 +196,13 @@ export default {
 }
 
 .reward-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-gray-400;
   margin-right: 12rpx;
 }
 
 .reward-points {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $brand-primary;
 }
@@ -227,4 +229,4 @@ export default {
 .btn-text {
   color: $app-surface;
 }
-</style>
+</style>

+ 4 - 2
cfc-frontend/pages/ai/components/QuotaProgressBar.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="quota-progress-bar">
+  <view class="quota-progress-bar" :style="{ '--font-scale': fontScale }">
     <view class="quota-label">
       <text class="quota-name">{{ name }}</text>
       <text class="quota-count">{{ remaining }} / {{ total }}</text>
@@ -11,7 +11,9 @@
 </template>
 
 <script>
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'QuotaProgressBar',
   props: {
     remaining: { type: Number, default: 0 },
@@ -34,7 +36,7 @@ export default {
 .quota-label {
   display: flex;
   justify-content: space-between;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-bottom: 8rpx;
 }

+ 5 - 3
cfc-frontend/pages/ai/components/UpgradeGuideModal.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="upgrade-guide-mask" v-if="visible" @click="handleMaskClick">
+  <view class="upgrade-guide-mask" v-if="visible" @click="handleMaskClick" :style="{ '--font-scale': fontScale }">
     <view class="upgrade-guide-content" :class="{ 'hard-modal': type === 'hard' }" @click.stop>
       <view class="upgrade-guide-icon">{{ icon }}</view>
       <view class="upgrade-guide-title">{{ title }}</view>
@@ -14,7 +14,9 @@
 </template>
 
 <script>
+import fontScaleMixin from '@/mixins/font-scale.js'
 export default {
+  mixins: [fontScaleMixin],
   name: 'UpgradeGuideModal',
   data() {
     return { visible: false }
@@ -91,13 +93,13 @@ export default {
   margin-bottom: 24rpx;
 }
 .upgrade-guide-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   margin-bottom: 16rpx;
 }
 .upgrade-guide-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   line-height: 1.6;
   margin-bottom: 36rpx;

+ 13 - 11
cfc-frontend/pages/article-center/article-edit.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="edit-container">
+  <view class="edit-container" :style="{ '--font-scale': fontScale }">
     <!-- 自定义导航 -->
     <view class="edit-header">
       <view class="header-left" @click="onBack">
@@ -100,8 +100,10 @@ import { BrandColors } from '../../utils/brand-colors.js'
 import { publishArticle } from '@/utils/api.js'
 import config from '@/config.js'
 import { pickImage } from '@/utils/image-picker.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       whiteColor: BrandColors.white,
@@ -258,9 +260,9 @@ export default {
 .header-left { display: flex; align-items: center; }
 .back-icon { font-size: 36rpx; margin-right: 8rpx; }
 
-.header-title { font-size: 32rpx; font-weight: bold; color: $facade-text-strong; }
+.header-title { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; }
 .header-right { }
-.history-text { font-size: 26rpx; color: $brand-primary; }
+.history-text { font-size: calc(26rpx * var(--font-scale, 1)); color: $brand-primary; }
 .edit-form { padding: 20rpx 30rpx; }
 /* 封面 */
 .form-cover {
@@ -281,7 +283,7 @@ export default {
   height: 100%;
 }
 .cover-icon { font-size: 60rpx; margin-bottom: 10rpx; }
-.cover-hint { font-size: 24rpx; color: $facade-text-muted; }
+.cover-hint { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-muted; }
 .cover-change {
   position: absolute;
   right: 16rpx;
@@ -290,7 +292,7 @@ export default {
   color: $app-surface;
   padding: 6rpx 20rpx;
   border-radius: 20rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
 }
 /* 表单组 */
 .form-group {
@@ -301,14 +303,14 @@ export default {
 }
 .form-input {
   width: 100%;
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   border: none;
   outline: none;
 }
 .title-input { font-weight: bold; }
 .char-count { display: block; text-align: right; font-size: 20rpx; color: $facade-text-ghost-light; margin-top: 8rpx; }
-.form-label { font-size: 24rpx; color: $facade-text-body; display: block; margin-bottom: 16rpx; }
+.form-label { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-body; display: block; margin-bottom: 16rpx; }
 /* 维度 */
 .dimension-chips { display: flex; flex-wrap: wrap; gap: 16rpx; }
 .dim-chip {
@@ -323,7 +325,7 @@ export default {
 .form-textarea {
   width: 100%;
   height: 300rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.6;
   border: none;
@@ -341,8 +343,8 @@ export default {
 }
 .vis-option.active { border-color: $brand-primary; background: $uni-primary-pale; }
 .vis-icon { font-size: 40rpx; display: block; margin-bottom: 8rpx; }
-.vis-text { font-size: 26rpx; font-weight: bold; color: $facade-text-strong; display: block; }
-.vis-desc { font-size: 20rpx; color: $facade-text-muted; display: block; margin-top: 4rpx; }
+.vis-text { font-size: calc(26rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; display: block; }
+.vis-desc { font-size: calc(20rpx * var(--font-scale, 1)); color: $facade-text-muted; display: block; margin-top: 4rpx; }
 /* 发布按钮 */
 .publish-btn {
   width: 100%;
@@ -359,4 +361,4 @@ export default {
 }
 .publish-btn[disabled] { opacity: 0.4; }
 .publish-btn::after { border: none; }
-</style>
+</style>

+ 9 - 7
cfc-frontend/pages/article-center/my-posts.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="posts-container">
+  <view class="posts-container" :style="{ '--font-scale': fontScale }">
     <scroll-view scroll-y class="posts-list" @scrolltolower="onLoadMore">
       <view v-if="loading && posts.length === 0" class="loading-wrap">
         <text class="loading-text">加载中...</text>
@@ -49,8 +49,10 @@
 <script>
 import { getMyPosts } from '@/utils/api.js'
 import config from '@/config.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       posts: [],
@@ -136,7 +138,7 @@ export default {
 .loading-wrap, .empty-wrap { display: flex; flex-direction: column; align-items: center; padding-top: 200rpx; }
 .loading-text { font-size: 26rpx; color: $facade-text-muted; }
 .empty-icon { font-size: 100rpx; margin-bottom: 24rpx; }
-.empty-text { font-size: 28rpx; color: $facade-text-muted; margin-bottom: 30rpx; }
+.empty-text { font-size: calc(28rpx * var(--font-scale, 1)); color: $facade-text-muted; margin-bottom: 30rpx; }
 .write-btn { width: 240rpx; height: 72rpx; line-height: 72rpx; background: $brand-primary; color: $app-surface; font-size: 28rpx; border-radius: 36rpx; border: none; }
 .write-btn::after { border: none; }
 .post-list { padding: 20rpx 24rpx; }
@@ -150,15 +152,15 @@ export default {
 }
 .post-cover { width: 200rpx; height: 160rpx; flex-shrink: 0; }
 .post-body { flex: 1; padding: 20rpx; display: flex; flex-direction: column; justify-content: center; }
-.post-title { font-size: 28rpx; font-weight: bold; color: $facade-text-strong; line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 8rpx; }
-.post-meta { display: flex; align-items: center; font-size: 22rpx; }
+.post-title { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; line-height: 1.4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 8rpx; }
+.post-meta { display: flex; align-items: center; font-size: calc(22rpx * var(--font-scale, 1)); }
 .post-date { color: $facade-text-muted; margin-right: 16rpx; }
 .post-status { padding: 2rpx 12rpx; border-radius: 8rpx; }
 .status-approved { color: $status-success-2; background: rgba(34,197,94,0.1); }
 .status-pending { color: $dim-wealth; background: rgba(245,158,11,0.1); }
 .status-rejected { color: $status-danger; background: rgba(239,68,68,0.1); }
 .status-draft { color: $facade-text-muted; background: rgba(153,153,153,0.1); }
-.post-reason { font-size: 20rpx; color: $status-danger; margin-top: 6rpx; display: block; }
+.post-reason { font-size: calc(20rpx * var(--font-scale, 1)); color: $status-danger; margin-top: 6rpx; display: block; }
 .loading-more, .no-more { text-align: center; padding: 30rpx; }
-.no-more-text { font-size: 24rpx; color: $facade-text-ghost; }
-</style>
+.no-more-text { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-ghost; }
+</style>

+ 11 - 9
cfc-frontend/pages/assessment-plan/detail.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="detail-container">
+  <view class="detail-container" :style="{ '--font-scale': fontScale }">
     <!-- 加载状态 -->
     <view class="loading-wrap" v-if="loading">
       <text class="loading-text">加载中...</text>
@@ -62,8 +62,10 @@
 <script>
 import { getMyAssessmentPlans } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       plan: null,
@@ -174,14 +176,14 @@ export default {
   margin-bottom: 24rpx;
 }
 .detail-title {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   flex: 1;
   min-width: 0;
 }
 .plan-status {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   padding: 4rpx 16rpx;
   border-radius: 20rpx;
   margin-left: 12rpx;
@@ -207,14 +209,14 @@ export default {
 }
 .meta-label {
   width: 160rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   flex-shrink: 0;
   line-height: 1.5;
 }
 .meta-value {
   flex: 1;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.5;
   word-break: break-all;
@@ -241,7 +243,7 @@ export default {
   border-radius: 8rpx;
 }
 .progress-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -257,13 +259,13 @@ export default {
   margin-bottom: 24rpx;
 }
 .empty-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 12rpx;
 }
 .empty-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   text-align: center;
   line-height: 1.5;
@@ -273,4 +275,4 @@ export default {
 .bottom-spacer {
   height: 60rpx;
 }
-</style>
+</style>

+ 10 - 8
cfc-frontend/pages/assessment-plan/list.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="list-container">
+  <view class="list-container" :style="{ '--font-scale': fontScale }">
     <!-- 加载状态 -->
     <view class="loading-wrap" v-if="loading">
       <text class="loading-text">加载中...</text>
@@ -45,8 +45,10 @@
 <script>
 import { getMyAssessmentPlans } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       plans: [],
@@ -147,14 +149,14 @@ export default {
   justify-content: space-between;
 }
 .plan-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   flex: 1;
   min-width: 0;
 }
 .plan-status {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   padding: 4rpx 16rpx;
   border-radius: 20rpx;
   margin-left: 12rpx;
@@ -172,7 +174,7 @@ export default {
   margin-top: 12rpx;
 }
 .plan-meta-item {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-faint;
 }
 
@@ -197,7 +199,7 @@ export default {
   border-radius: 6rpx;
 }
 .progress-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -223,13 +225,13 @@ export default {
   margin-bottom: 24rpx;
 }
 .empty-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 12rpx;
 }
 .empty-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   text-align: center;
   margin-bottom: 40rpx;
@@ -240,4 +242,4 @@ export default {
 .bottom-spacer {
   height: 60rpx;
 }
-</style>
+</style>

+ 13 - 11
cfc-frontend/pages/assessment/apply.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">申请测评</text>
       <text class="subtitle">专业的DAN测评,助力家庭成员专注力 development</text>
@@ -138,8 +138,10 @@
 <script>
 import { getAvailableGuides, createAssessmentAppointment, getChildren, getAssessmentQuotas, createAssessmentAppointmentWithQuota, reportAppEnter
 } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       quotaId: null,
@@ -362,7 +364,7 @@ export default {
 }
 
 .title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -370,7 +372,7 @@ export default {
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
@@ -382,7 +384,7 @@ export default {
 }
 
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 20rpx;
@@ -431,7 +433,7 @@ export default {
 
 .guide-name,
 .child-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 5rpx;
@@ -444,7 +446,7 @@ export default {
 }
 
 .child-age {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -461,7 +463,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 
 .type-icon {
@@ -471,7 +473,7 @@ export default {
 }
 
 .type-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -479,7 +481,7 @@ export default {
 }
 
 .type-desc {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -492,7 +494,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   margin-right: 20rpx;
 }
@@ -561,4 +563,4 @@ export default {
   font-weight: bold;
   margin-top: 40rpx;
 }
-</style>
+</style>

+ 13 - 11
cfc-frontend/pages/assessment/execution.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 执行状态头部 -->
     <view class="header">
       <text class="title">服务执行进度</text>
@@ -106,8 +106,10 @@
 <script>
 import config from '@/config.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       executionId: null,
@@ -235,7 +237,7 @@ export default {
 }
 
 .title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -243,7 +245,7 @@ export default {
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -354,7 +356,7 @@ export default {
 }
 
 .status-text {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -514,7 +516,7 @@ export default {
 }
 
 .timeline-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -522,14 +524,14 @@ export default {
 }
 
 .timeline-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 5rpx;
 }
 
 .timeline-time {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -541,7 +543,7 @@ export default {
 }
 
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -553,13 +555,13 @@ export default {
 }
 
 .note-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
   font-weight: bold;
 }
 
 .note-content {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 
@@ -593,4 +595,4 @@ export default {
   color: $facade-text-body;
   border: 2rpx solid $facade-border-soft;
 }
-</style>
+</style>

+ 13 - 11
cfc-frontend/pages/assessment/purchase.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">选择测评任务模板</text>
       <text class="subtitle">选择适合测评人的测评任务模板</text>
@@ -87,8 +87,10 @@
 
 <script>
 import { getAvailableGuides, getPackagePrice, createAssessmentOrder, createVirtualPayOrder, requestVirtualPayment, getAssessmentOrderDetail } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       guideId: null,
@@ -366,7 +368,7 @@ export default {
 }
 
 .title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -374,7 +376,7 @@ export default {
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
@@ -386,7 +388,7 @@ export default {
 }
 
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 20rpx;
@@ -427,7 +429,7 @@ export default {
 }
 
 .guide-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -449,7 +451,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 
 .package-item {
@@ -473,7 +475,7 @@ export default {
 }
 
 .package-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -497,7 +499,7 @@ export default {
 }
 
 .package-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-bottom: 15rpx;
 }
@@ -523,7 +525,7 @@ export default {
 }
 
 .feature-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 
@@ -539,7 +541,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
 }
 
 .price-breakdown {
@@ -599,4 +601,4 @@ export default {
 .btn-submit[disabled] {
   background: $facade-text-ghost;
 }
-</style>
+</style>

+ 12 - 10
cfc-frontend/pages/assessment/quota.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">我的测评额度</text>
       <text class="subtitle">购买测评任务模板后获得可使用次数</text>
@@ -49,8 +49,10 @@
 <script>
 import { getAssessmentQuotas } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       quotas: []
@@ -108,14 +110,14 @@ export default {
   padding: 40rpx 0 30rpx;
 }
 .title {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
   margin-bottom: 16rpx;
 }
 .subtitle {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .quota-list {
@@ -136,7 +138,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .product-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -172,7 +174,7 @@ export default {
   border-radius: 6rpx;
 }
 .progress-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   white-space: nowrap;
 }
@@ -186,17 +188,17 @@ export default {
   margin-bottom: 8rpx;
 }
 .info-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .info-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .info-value.highlight {
   color: $accent-indigo;
   font-weight: bold;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
 }
 .info-value.expired {
   color: $mat-red;
@@ -225,7 +227,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-bottom: 40rpx;
 }
@@ -239,4 +241,4 @@ export default {
   font-size: 28rpx;
   text-align: center;
 }
-</style>
+</style>

+ 11 - 9
cfc-frontend/pages/assessment/rating.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 头部 -->
     <view class="header">
       <text class="title">服务评价</text>
@@ -93,8 +93,10 @@
 
 <script>
 import config from '@/config.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       executionId: null,
@@ -212,7 +214,7 @@ export default {
 }
 
 .title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -220,7 +222,7 @@ export default {
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
@@ -279,7 +281,7 @@ export default {
 }
 
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
@@ -291,7 +293,7 @@ export default {
 }
 
 .star-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-right: 20rpx;
 }
@@ -302,7 +304,7 @@ export default {
 }
 
 .star {
-  font-size: 60rpx;
+  font-size: calc(60rpx * var(--font-scale, 1));
   color: $facade-hairline;
   transition: color 0.2s ease, text-shadow 0.2s ease;
   line-height: 1;
@@ -318,7 +320,7 @@ export default {
 }
 
 .rating-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $mat-orange-base;
   margin-left: 16rpx;
   font-weight: bold;
@@ -334,7 +336,7 @@ export default {
   padding: 20rpx;
   border: 2rpx solid $facade-hairline;
   border-radius: 10rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 
@@ -367,4 +369,4 @@ export default {
   color: $facade-text-body;
   border: 2rpx solid $facade-border-soft;
 }
-</style>
+</style>

+ 19 - 17
cfc-frontend/pages/assessment/results.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">测评报告</text>
       <text class="subtitle">查看下级成长规划师的测评报告</text>
@@ -172,8 +172,10 @@
 <script>
 import { getMyAssessmentResults, getChildAssessmentResults } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       currentTab: 'my',
@@ -242,7 +244,7 @@ export default {
 }
 
 .title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
@@ -250,7 +252,7 @@ export default {
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
@@ -284,7 +286,7 @@ export default {
 }
 
 .section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 20rpx;
@@ -310,18 +312,18 @@ export default {
 }
 
 .report-child {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 
 .report-date {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 
 .report-guide {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $accent-indigo;
 }
 
@@ -338,20 +340,20 @@ export default {
 }
 
 .score-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 5rpx;
 }
 
 .score-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 
 .report-preview {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   line-height: 1.5;
 }
@@ -368,14 +370,14 @@ export default {
 }
 
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   display: block;
   margin-bottom: 10rpx;
 }
 
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
 
@@ -429,7 +431,7 @@ export default {
 }
 
 .detail-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 15rpx;
@@ -442,12 +444,12 @@ export default {
 }
 
 .detail-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
 .detail-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: bold;
 }
@@ -459,7 +461,7 @@ export default {
 }
 
 .content-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   line-height: 1.6;
 }
@@ -478,4 +480,4 @@ export default {
   font-size: 28rpx;
   font-weight: bold;
 }
-</style>
+</style>

+ 11 - 9
cfc-frontend/pages/assessment/upload-report.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">上传测评报告</text>
       <text class="subtitle">支持 PDF / JPG / PNG 格式</text>
@@ -40,8 +40,10 @@
 <script>
 import { uploadAssessmentReport } from '../../utils/api.js'
 import { pickImage } from '../../utils/image-picker.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       children: [],
@@ -121,14 +123,14 @@ export default {
   padding: 40rpx 0 30rpx;
 }
 .title {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   display: block;
   margin-bottom: 16rpx;
 }
 .subtitle {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .section {
@@ -138,7 +140,7 @@ export default {
   margin-bottom: 24rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 20rpx;
@@ -162,7 +164,7 @@ export default {
   background: $dim-wisdom-tint-3;
 }
 .child-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .child-check {
@@ -176,7 +178,7 @@ export default {
   border-radius: 50%;
   line-height: 36rpx;
   text-align: center;
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
 }
 .file-upload {
   display: flex;
@@ -192,7 +194,7 @@ export default {
   font-size: 48rpx;
 }
 .upload-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 .textarea {
@@ -201,7 +203,7 @@ export default {
   background: $facade-fill-page;
   border-radius: 10rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .btn-submit {
@@ -217,4 +219,4 @@ export default {
 .btn-submit[disabled] {
   opacity: 0.5;
 }
-</style>
+</style>

+ 15 - 13
cfc-frontend/pages/body-detail/checkin.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="checkin-container">
+  <view class="checkin-container" :style="{ '--font-scale': fontScale }">
     <!-- 顶部导航 -->
 
     <!-- 能量奖励提示 -->
@@ -125,8 +125,10 @@ const healthRequest = function(url, data) {
     })
   })
 }
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       memberId: null,
@@ -306,7 +308,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   margin-right: 12rpx;
 }
 .tip-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $mat-orange-strong;
 }
 
@@ -319,7 +321,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
 }
 .form-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 24rpx;
@@ -328,7 +330,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   margin-bottom: 28rpx;
 }
 .form-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 12rpx;
@@ -343,7 +345,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   background: $app-bg;
   border-radius: 12rpx;
   padding: 16rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .date-arrow {
@@ -388,10 +390,10 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   background: $mat-amber-tint;
 }
 .mood-emoji {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
 }
 .mood-label {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 4rpx;
 }
@@ -403,7 +405,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   background: $app-bg;
   border-radius: 12rpx;
   padding: 16rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   min-height: 120rpx;
 }
@@ -428,7 +430,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   margin: 30rpx 30rpx 0;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 16rpx;
@@ -452,7 +454,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   flex: 1;
 }
 .history-date {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -478,10 +480,10 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   align-items: flex-end;
 }
 .history-mood {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
 }
 .history-energy {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $mat-green;
   margin-top: 4rpx;
 }
@@ -489,7 +491,7 @@ $c-tint-amber-edge: #FFECB3;  // 能量提示渐变终点(amber-100;与全
   text-align: center;
   padding: 40rpx;
   color: $facade-text-muted;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
 }
 
 /* ===== 底部 ===== */

+ 16 - 14
cfc-frontend/pages/body-detail/dimension-detail.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="dd-container">
+  <view class="dd-container" :style="{ '--font-scale': fontScale }">
     <!-- Loading -->
     <view class="dd-loading" v-if="loading">
       <text class="loading-text">加载中...</text>
@@ -125,8 +125,10 @@ var SUGGESTIONS = {
     '家长以身作则,全家一起运动效果更好'
   ]
 }
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       loading: true,
@@ -374,21 +376,21 @@ export default {
   margin: 0 auto 20rpx;
 }
 .dd-score-value {
-  font-size: 56rpx;
+  font-size: calc(56rpx * var(--font-scale, 1));
   font-weight: 700;
   line-height: 1;
 }
 .dd-score-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   opacity: 0.8;
 }
 .dd-dim-name {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: 600;
   display: block;
 }
 .dd-dim-level {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   padding: 6rpx 24rpx;
   border-radius: 20rpx;
   display: inline-block;
@@ -403,7 +405,7 @@ export default {
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
 }
 .dd-section-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   margin-bottom: 20rpx;
@@ -422,11 +424,11 @@ export default {
   padding: 40rpx 0;
 }
 .empty-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .empty-sub {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
   margin-top: 10rpx;
 }
@@ -435,12 +437,12 @@ export default {
   padding: 20rpx 0;
 }
 .dd-percentile-value {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $brand-primary;
 }
 .dd-percentile-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   margin-top: 10rpx;
   display: block;
@@ -462,13 +464,13 @@ export default {
   border-radius: 50%;
   text-align: center;
   line-height: 40rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   flex-shrink: 0;
   margin-right: 16rpx;
   margin-top: 4rpx;
 }
 .dd-sug-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-deep;
   line-height: 1.6;
   flex: 1;
@@ -496,7 +498,7 @@ export default {
   justify-content: center;
 }
 .dd-prod-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
 }
@@ -526,4 +528,4 @@ export default {
   color: $brand-primary;
   border: 2rpx solid $brand-primary;
 }
-</style>
+</style>

+ 16 - 14
cfc-frontend/pages/body-detail/dimension-questionnaire.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="qd-container">
+  <view class="qd-container" :style="{ '--font-scale': fontScale }">
     <!-- Loading -->
     <view class="qd-loading" v-if="loading">
       <text class="loading-text">加载中...</text>
@@ -86,8 +86,10 @@
 
 <script>
 import { submitDimensionQuestionnaire } from '@/utils/api'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       loading: false,
@@ -468,12 +470,12 @@ export default {
   padding: 30rpx 0;
 }
 .qd-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
 }
 .qd-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   margin-top: 10rpx;
 }
@@ -504,7 +506,7 @@ export default {
   margin-bottom: 10rpx;
 }
 .qd-dim-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
 }
@@ -519,10 +521,10 @@ export default {
   border-radius: 50%;
   text-align: center;
   line-height: 36rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
 }
 .qd-progress {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $brand-primary;
   margin-top: 10rpx;
 }
@@ -546,7 +548,7 @@ export default {
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
 }
 .qd-q-text {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: 500;
   color: $facade-text-strong;
   line-height: 1.5;
@@ -569,7 +571,7 @@ export default {
   background: $brand-primary-soft;
 }
 .qd-opt-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   flex: 1;
 }
@@ -581,7 +583,7 @@ export default {
   border-radius: 50%;
   text-align: center;
   line-height: 36rpx;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
 }
 .qd-footer {
   display: flex;
@@ -621,18 +623,18 @@ export default {
   font-size: 80rpx;
 }
 .qd-result-title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   margin: 20rpx 0;
 }
 .qd-result-score {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-bottom: 20rpx;
 }
 .qd-result-level {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   padding: 8rpx 24rpx;
   border-radius: 20rpx;
   display: inline-block;
@@ -643,10 +645,10 @@ export default {
 .qd-result-level.level-fair { background: $mat-amber-tint; color: $mat-amber-strong; }
 .qd-result-level.level-poor { background: $fortune-0-tint; color: $status-danger-strong-2; }
 .qd-result-tip {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   margin-top: 20rpx;
   line-height: 1.6;
   padding: 0 30rpx;
 }
-</style>
+</style>

+ 16 - 14
cfc-frontend/pages/body-detail/health-dimensions.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="hd-container">
+  <view class="hd-container" :style="{ '--font-scale': fontScale }">
     <view class="hd-header">
       <text class="hd-title">健康维度全景</text>
       <text class="hd-subtitle" v-if="memberName">{{ memberName }}的健康档案</text>
@@ -118,8 +118,10 @@
 <script>
 import { BrandColors } from '../../utils/brand-colors.js'
 import { getDimensionOverview, uploadDimensionScore } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       memberId: null,
@@ -353,12 +355,12 @@ export default {
   color: $app-surface;
 }
 .hd-title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   display: block;
 }
 .hd-subtitle {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   opacity: 0.9;
   display: block;
   margin-top: 8rpx;
@@ -381,12 +383,12 @@ export default {
   color: $app-surface;
 }
 .index-value {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   line-height: 1;
 }
 .index-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   opacity: 0.9;
   margin-top: 8rpx;
 }
@@ -396,7 +398,7 @@ export default {
   padding: 30rpx;
 }
 .radar-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
   margin-bottom: 30rpx;
@@ -426,12 +428,12 @@ export default {
   margin-bottom: 16rpx;
 }
 .dim-label {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .dim-score {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $dim-body;
 }
@@ -460,7 +462,7 @@ export default {
 .dim-bar-fill.fill-fair { background: $status-warning-2; }
 .dim-bar-fill.fill-poor { background: $status-danger; }
 .dim-norms {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .dim-footer {
@@ -480,7 +482,7 @@ export default {
 .dim-level-tag.tag-fair { background: $status-warning-soft; color: $status-warning-2; }
 .dim-level-tag.tag-poor { background: $status-danger-soft; color: $status-danger; }
 .dim-source {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .hd-empty {
@@ -488,13 +490,13 @@ export default {
   text-align: center;
 }
 .empty-tip {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   display: block;
   margin-bottom: 16rpx;
 }
 .empty-sub {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
   display: block;
 }
@@ -567,7 +569,7 @@ export default {
   margin-bottom: 30rpx;
 }
 .form-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
   display: block;
   margin-bottom: 12rpx;
@@ -586,7 +588,7 @@ export default {
   border: 1px solid $facade-hairline;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
 }
 .modal-footer {
   display: flex;

+ 9 - 7
cfc-frontend/pages/body-detail/member-body-detail.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="detail-container">
+  <view class="detail-container" :style="{ '--font-scale': fontScale }">
     <!-- 顶部导航 -->
 
     <!-- 五维能量条 -->
@@ -71,8 +71,10 @@ import DimensionActivities from '../../components/DimensionActivities.vue'
 import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
 import { getEnergyOverview, getFamilyEnergySandbox, getChildren } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { FamilyEnergyBar, FamilyRelationGraph, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles },
   data() {
     return {
@@ -215,7 +217,7 @@ export default {
   margin-right: 20rpx;
 }
 .avatar-text {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
 }
@@ -225,12 +227,12 @@ export default {
   flex-direction: column;
 }
 .member-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .member-role {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
 }
@@ -240,15 +242,15 @@ export default {
   align-items: center;
 }
 .score-value {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $mat-green;
 }
 .score-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .bottom-spacer {
   height: 40rpx;
 }
-</style>
+</style>

+ 10 - 8
cfc-frontend/pages/butler/apply.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">成为管家</text>
       <text class="subtitle">提交您的管家资质,为更多家庭提供专业服务</text>
@@ -42,8 +42,10 @@
 
 <script>
 import { butlerApply } from '@/utils/api'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   onLoad() {
     uni.redirectTo({ url: '/pages/profile/service-role-apply' })
   },
@@ -118,12 +120,12 @@ export default {
   padding: 40rpx 0;
 }
 .title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $facade-text-strong;
 }
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 16rpx;
   display: block;
@@ -137,7 +139,7 @@ export default {
   margin-bottom: 40rpx;
 }
 .label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   display: block;
   margin-bottom: 20rpx;
@@ -149,7 +151,7 @@ export default {
   border: 1rpx solid $facade-hairline;
   border-radius: 10rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .picker {
@@ -158,7 +160,7 @@ export default {
   border: 1rpx solid $facade-hairline;
   border-radius: 10rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   display: flex;
   align-items: center;
   justify-content: space-between;
@@ -177,7 +179,7 @@ export default {
   border: 1rpx solid $facade-hairline;
   border-radius: 10rpx;
   padding: 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .counter {
@@ -200,4 +202,4 @@ export default {
 .btn-submit[disabled] {
   opacity: 0.6;
 }
-</style>
+</style>

+ 14 - 12
cfc-frontend/pages/butler/select.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="select-page">
+  <view class="select-page" :style="{ '--font-scale': fontScale }">
     <!-- 顶部状态区 -->
     <view class="status-card" v-if="pageState === 'bound'">
       <view class="current-label">我的管家</view>
@@ -44,8 +44,10 @@
 
 <script>
 import { getAvailableButlers, getMyButler, selectButler } from '@/utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       loading: false,
@@ -142,27 +144,27 @@ export default {
 <style scoped lang="scss">
 .select-page { min-height: 100vh; background: $facade-fill-blue-ghost; padding: 24rpx; box-sizing: border-box; display: flex; flex-direction: column; }
 .status-card { background: $app-surface; border-radius: 20rpx; padding: 32rpx; margin-bottom: 24rpx; }
-.current-label { font-size: 24rpx; color: $facade-text-muted; margin-bottom: 16rpx; }
+.current-label { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-muted; margin-bottom: 16rpx; }
 .current-row { display: flex; align-items: center; }
 .current-avatar { width: 96rpx; height: 96rpx; border-radius: 50%; margin-right: 20rpx; }
 .current-info { display: flex; flex-direction: column; }
-.current-name { font-size: 34rpx; font-weight: bold; color: $facade-text-strong; }
-.current-date { font-size: 22rpx; color: $facade-text-muted; margin-top: 6rpx; }
-.current-desc { font-size: 26rpx; color: $facade-text-body; margin-top: 20rpx; line-height: 1.6; }
+.current-name { font-size: calc(34rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; }
+.current-date { font-size: calc(22rpx * var(--font-scale, 1)); color: $facade-text-muted; margin-top: 6rpx; }
+.current-desc { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-body; margin-top: 20rpx; line-height: 1.6; }
 .btn-change { margin-top: 24rpx; background: $brand-primary; color: $app-surface; font-size: 28rpx; border-radius: 40rpx; }
 .upgrade-banner { display: flex; justify-content: space-between; align-items: center; background: $uni-primary-pale; border: 1rpx solid #ffb56b; border-radius: 16rpx; padding: 24rpx; margin-bottom: 24rpx; }
-.upgrade-text { font-size: 26rpx; color: #d4770a; flex: 1; }
+.upgrade-text { font-size: calc(26rpx * var(--font-scale, 1)); color: #d4770a; flex: 1; }
 .upgrade-arrow { font-size: 36rpx; color: #d4770a; margin-left: 12rpx; }
-.section-title { font-size: 30rpx; font-weight: bold; color: $facade-text-strong; margin: 8rpx 0 20rpx; }
+.section-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; margin: 8rpx 0 20rpx; }
 .butler-card { display: flex; align-items: center; background: $app-surface; border-radius: 20rpx; padding: 28rpx; margin-bottom: 20rpx; }
 .butler-card.active { border: 2rpx solid $brand-primary; }
 .card-avatar { width: 88rpx; height: 88rpx; border-radius: 50%; margin-right: 20rpx; flex-shrink: 0; }
 .card-body { flex: 1; min-width: 0; }
 .card-top { display: flex; align-items: center; justify-content: space-between; }
-.card-name { font-size: 30rpx; font-weight: bold; color: $facade-text-strong; }
-.card-slots { font-size: 22rpx; color: $status-success; }
-.card-desc { display: block; font-size: 24rpx; color: $facade-text-faint; margin-top: 8rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.card-name { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: bold; color: $facade-text-strong; }
+.card-slots { font-size: calc(22rpx * var(--font-scale, 1)); color: $status-success; }
+.card-desc { display: block; font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-faint; margin-top: 8rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
 .btn-select { width: 120rpx; height: 60rpx; line-height: 60rpx; padding: 0; font-size: 26rpx; background: $brand-primary; color: $app-surface; border-radius: 30rpx; flex-shrink: 0; margin-left: 16rpx; }
 .btn-select[disabled] { background: $facade-text-ghost; color: $app-surface; }
-.empty-tip { text-align: center; color: $facade-text-muted; font-size: 26rpx; padding: 60rpx 0; }
-</style>
+.empty-tip { text-align: center; color: $facade-text-muted; font-size: calc(26rpx * var(--font-scale, 1)); padding: 60rpx 0; }
+</style>

+ 8 - 6
cfc-frontend/pages/child/rewards.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 退出切换按钮 -->
     <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
       <text>🔄 退出切换</text>
@@ -45,8 +45,10 @@
 <script>
 import { BrandColors } from '@/utils/brand-colors.js'
 import { getWishlist, createReward as createRewardApi, getPointsBalance, getChildren, switchBackToParent, verifyPassword } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       trackColor: BrandColors.hairline2,
@@ -142,18 +144,18 @@ export default {
 .container { padding: 30rpx; padding-bottom: 120rpx; }
 .exit-switch { background: $facade-fill-2; padding: 20rpx; border-radius: 10rpx; margin-bottom: 20rpx; text-align: center; color: $facade-text-body; font-size: 28rpx; }
 .reward-item { background: $app-surface; border-radius: 16rpx; padding: 30rpx; margin-bottom: 20rpx; }
-.reward-title { font-size: 30rpx; color: $facade-text-strong; margin-bottom: 15rpx; }
+.reward-title { font-size: calc(30rpx * var(--font-scale, 1)); color: $facade-text-strong; margin-bottom: 15rpx; }
 .reward-progress { width: 100%; }
-.progress-text { font-size: 22rpx; color: $facade-text-muted; display: block; margin-top: 8rpx; }
+.progress-text { font-size: calc(22rpx * var(--font-scale, 1)); color: $facade-text-muted; display: block; margin-top: 8rpx; }
 .add-btn { position: fixed; bottom: 30rpx; left: 30rpx; right: 30rpx; }
 .empty { text-align: center; color: $facade-text-muted; padding: 100rpx; }
 .modal-mask { 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; }
 .modal { background: $app-surface; border-radius: 20rpx; padding: 40rpx; width: 80%; }
 .modal-title { font-size: 32rpx; font-weight: bold; margin-bottom: 30rpx; text-align: center; }
 .form-item { margin-bottom: 20rpx; }
-.form-label { font-size: 28rpx; color: $facade-text-strong; margin-bottom: 10rpx; }
+.form-label { font-size: calc(28rpx * var(--font-scale, 1)); color: $facade-text-strong; margin-bottom: 10rpx; }
 .required { color: $brand-primary; }
-.form-tip { font-size: 24rpx; color: $facade-text-muted; padding: 20rpx; background: $facade-fill-2; border-radius: 10rpx; margin-bottom: 20rpx; }
+.form-tip { font-size: calc(24rpx * var(--font-scale, 1)); color: $facade-text-muted; padding: 20rpx; background: $facade-fill-2; border-radius: 10rpx; margin-bottom: 20rpx; }
 .modal-btns { display: flex; gap: 20rpx; margin-top: 30rpx; }
 .modal-btns button { flex: 1; }
-</style>
+</style>

+ 7 - 5
cfc-frontend/pages/child/tasks.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page-bg">
+  <view class="page-bg" :style="{ '--font-scale': fontScale }">
     <!-- 退出切换(家长切换到孩子状态时显示) -->
     <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
       <text class="exit-switch__icon">🔄</text>
@@ -128,8 +128,10 @@ import BaseEmpty from '@/components/BaseEmpty.vue'
 import BaseLoading from '@/components/BaseLoading.vue'
 import { getTodayTasks, completeTask as completeTaskApi, getChildren, switchBackToParent, verifyPassword } from '../../utils/api.js'
 import { parseDate } from '../../utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { PlayfulButton, BaseBadge, BaseEmpty, BaseLoading },
   data() {
     return {
@@ -593,7 +595,7 @@ export default {
 }
 
 .task-title {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: var(--font-weight-bold, 600);
   color: var(--text, $uni-text-color);
   line-height: 1.4;
@@ -617,12 +619,12 @@ export default {
 }
 
 .points-text {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   line-height: 1.4;
 }
 
 .task-time {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: var(--text-secondary, $uni-text-color-secondary);
   line-height: 1.4;
 }
@@ -711,4 +713,4 @@ export default {
     opacity: 1;
   }
 }
-</style>
+</style>

+ 14 - 12
cfc-frontend/pages/cognitive-hall.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <view class="header">
       <text class="title">认知能力测评</text>
       <text class="subtitle">通过小游戏评估七项核心认知能力</text>
@@ -59,8 +59,10 @@
 <script>
 import { getCognitiveChildScores } from '../utils/api.js'
 import { getFamilyMemberList } from '../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       memberId: '',
@@ -176,13 +178,13 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
 }
 
 .title {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   display: block;
 }
 
 .subtitle {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   opacity: 0.85;
   margin-top: 10rpx;
   display: block;
@@ -198,7 +200,7 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
 }
 
 .selector-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
@@ -214,7 +216,7 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
   border-radius: 30rpx;
   margin: 8rpx 8rpx 0 0;
   background: $c-border-hair;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
 }
 
@@ -258,28 +260,28 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
 }
 
 .game-name {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $c-ink-night;
   display: block;
 }
 
 .game-desc {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   margin-top: 6rpx;
   display: block;
 }
 
 .game-status {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $dim-action;
   margin-top: 8rpx;
   display: block;
 }
 
 .game-status-pending {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $c-text-ghost-3;
   margin-top: 8rpx;
   display: block;
@@ -305,7 +307,7 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
 }
 
 .empty-hint {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-ghost-light;
   margin-top: 10rpx;
   display: block;
@@ -320,7 +322,7 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
   padding: 24rpx 0;
   border-radius: 50rpx;
   text-align: center;
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   box-sizing: border-box;
 }
@@ -334,4 +336,4 @@ $c-ink-night:    $app-ink-night;   // 深夜蓝黑(本页深色文字)
 .btn--outline:active {
   background: rgba($dim-wisdom, 0.08);
 }
-</style>
+</style>

+ 14 - 12
cfc-frontend/pages/cognitive-test/language-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="test-container">
+  <view class="test-container" :style="{ '--font-scale': fontScale }">
 
     <!-- 步骤一:测试说明 -->
     <view class="step-panel" v-if="step === 'instruction'">
@@ -96,8 +96,10 @@ var QUESTION_BANK = [
 
 var ROUND_COUNT = 6
 var TIMER_SECONDS = 12
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       step: 'instruction',
@@ -263,21 +265,21 @@ export default {
 }
 
 .test-title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 32rpx;
 }
 
 .test-desc {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
   line-height: 1.7;
   text-align: center;
 }
 
 .test-meta {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.45);
   margin-top: 24rpx;
   margin-bottom: 80rpx;
@@ -328,7 +330,7 @@ export default {
 }
 
 .progress-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
 }
 
@@ -349,7 +351,7 @@ export default {
 
 .timer-text {
   display: block;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $dim-wealth;
   margin-top: 12rpx;
   text-align: center;
@@ -357,7 +359,7 @@ export default {
 
 .question-hint {
   display: block;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin: 40rpx 0 32rpx;
@@ -390,7 +392,7 @@ export default {
 }
 
 .option-text {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 500;
 }
@@ -407,7 +409,7 @@ export default {
 
 /* ===== 结果页 ===== */
 .result-title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 48rpx;
@@ -438,7 +440,7 @@ export default {
 }
 
 .score-label {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
   margin-right: 20rpx;
 }
@@ -456,7 +458,7 @@ export default {
 }
 
 .result-tip-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.6);
 }
-</style>
+</style>

+ 16 - 14
cfc-frontend/pages/cognitive-test/logic-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- 引导页 -->
     <view class="step-intro" v-if="step === 'intro'">
       <view class="intro-icon">
@@ -109,8 +109,10 @@ var QUESTION_BANK = [
   { seq: '30, 28, 24, 18, 10, ?', options: ['0', '2', '4', '6'], answer: '0' },
   { seq: '7, 14, 28, 56, ?', options: ['84', '96', '108', '112'], answer: '112' }
 ]
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       step: 'intro',
@@ -297,14 +299,14 @@ export default {
   font-size: 72rpx;
 }
 .intro-title {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $accent-gold;
   margin-bottom: 16rpx;
   display: block;
 }
 .intro-desc {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.7);
   margin-bottom: 50rpx;
   display: block;
@@ -327,11 +329,11 @@ export default {
   border-top: 1rpx solid rgba(255, 255, 255, 0.08);
 }
 .info-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.7);
 }
 .info-value {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $accent-gold;
   font-weight: bold;
 }
@@ -344,12 +346,12 @@ export default {
   margin-bottom: 20rpx;
 }
 .quiz-progress {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
 }
 .quiz-timer {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $accent-gold;
   font-weight: bold;
 }
@@ -373,7 +375,7 @@ export default {
   box-sizing: border-box;
 }
 .q-text {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
   text-align: center;
@@ -405,7 +407,7 @@ export default {
   transform: scale(0.98);
 }
 .q-option-text {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
 }
@@ -432,12 +434,12 @@ export default {
   margin-bottom: 30rpx;
 }
 .score-value {
-  font-size: 80rpx;
+  font-size: calc(80rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-ink-night;
 }
 .score-label {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $accent-gold;
   margin-bottom: 50rpx;
   display: block;
@@ -460,11 +462,11 @@ export default {
   border-top: 1rpx solid rgba(255, 255, 255, 0.08);
 }
 .result-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.7);
 }
 .result-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: bold;
 }
@@ -486,7 +488,7 @@ export default {
   padding: 26rpx 0;
   border-radius: 50rpx;
   text-align: center;
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: bold;
   box-sizing: border-box;
   margin-bottom: 24rpx;

+ 17 - 15
cfc-frontend/pages/cognitive-test/memory-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
 
     <!-- ============ 1. 说明页 ============ -->
     <view class="intro" v-if="step === 'intro'">
@@ -98,8 +98,10 @@
 
 <script>
 import { submitCognitiveSelfTest } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       step: 'intro',          // intro | playing | result
@@ -373,13 +375,13 @@ export default {
   font-size: 80rpx;
 }
 .intro-title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 30rpx;
 }
 .intro-desc {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.75);
   line-height: 1.7;
   text-align: center;
@@ -393,7 +395,7 @@ export default {
   margin-top: 40rpx;
 }
 .rule-item {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $indigo-light;
   background: rgba(99, 102, 241, 0.12);
   border-radius: 24rpx;
@@ -415,12 +417,12 @@ export default {
   margin-top: 20rpx;
 }
 .progress-level {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
 }
 .progress-digit {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $indigo-light;
   margin-top: 8rpx;
 }
@@ -448,7 +450,7 @@ export default {
   padding-top: 120rpx;
 }
 .show-hint {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.5);
   margin-bottom: 60rpx;
 }
@@ -469,7 +471,7 @@ export default {
   border-radius: 16rpx;
 }
 .show-digit text {
-  font-size: 120rpx;
+  font-size: calc(120rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
 }
@@ -497,7 +499,7 @@ export default {
   padding-top: 60rpx;
 }
 .input-hint {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.5);
   margin-bottom: 50rpx;
 }
@@ -543,7 +545,7 @@ export default {
   box-sizing: border-box;
 }
 .pad-key text {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   color: $app-surface;
   font-weight: 500;
 }
@@ -555,7 +557,7 @@ export default {
   background: rgba(255, 255, 255, 0.03);
 }
 .pad-key-ctrl text {
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   color: $indigo-light;
 }
 
@@ -579,7 +581,7 @@ export default {
   background: rgba(239, 68, 68, 0.3);
 }
 .feedback-text {
-  font-size: 56rpx;
+  font-size: calc(56rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   padding: 24rpx 60rpx;
@@ -627,7 +629,7 @@ export default {
   line-height: 1;
 }
 .score-unit {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.8);
   margin-top: 8rpx;
 }
@@ -638,12 +640,12 @@ export default {
   margin-top: 60rpx;
 }
 .max-level-label {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.6);
   margin-right: 16rpx;
 }
 .max-level-value {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
 }

+ 13 - 11
cfc-frontend/pages/cognitive-test/perception-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="test-container">
+  <view class="test-container" :style="{ '--font-scale': fontScale }">
 
     <!-- 步骤一:测试说明 -->
     <view class="step-panel" v-if="step === 'instruction'">
@@ -95,8 +95,10 @@ var QUESTION_BANK = [
   { items: ['⬢','⬢','⬢','⬢','⬢','⬡'], oddIndex: 2, hint: '找出不同的形状' },
   { items: ['◇','◇','◇','◇','◇','○'], oddIndex: 5, hint: '找出不同的形状' }
 ]
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       step: 'instruction',
@@ -261,21 +263,21 @@ export default {
 }
 
 .test-title {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 32rpx;
 }
 
 .test-desc {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
   line-height: 1.7;
   text-align: center;
 }
 
 .test-meta {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.45);
   margin-top: 24rpx;
   margin-bottom: 80rpx;
@@ -326,7 +328,7 @@ export default {
 }
 
 .progress-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
 }
 
@@ -347,7 +349,7 @@ export default {
 
 .timer-text {
   display: block;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $flat-teal;
   margin-top: 12rpx;
   text-align: center;
@@ -355,7 +357,7 @@ export default {
 
 .question-hint {
   display: block;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin: 40rpx 0 32rpx;
@@ -387,7 +389,7 @@ export default {
 }
 
 .cell-emoji {
-  font-size: 50rpx;
+  font-size: calc(50rpx * var(--font-scale, 1));
 }
 
 .cell-correct {
@@ -402,7 +404,7 @@ export default {
 
 /* ===== 结果页 ===== */
 .result-title {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 48rpx;
@@ -433,7 +435,7 @@ export default {
 }
 
 .score-label {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.7);
   margin-right: 20rpx;
 }
@@ -451,7 +453,7 @@ export default {
 }
 
 .result-tip-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255,255,255,0.6);
 }
 </style>

+ 17 - 15
cfc-frontend/pages/cognitive-test/spatial-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <!-- 开始引导 -->
     <view v-if="step === 'instruction'" class="container">
       <view class="hero-icon">
@@ -123,8 +123,10 @@ function buildQuestionBank() {
 }
 
 const QUESTION_BANK = buildQuestionBank()
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       memberId: '',
@@ -299,18 +301,18 @@ export default {
   margin-bottom: 40rpx;
 }
 .hero-symbol {
-  font-size: 80rpx;
+  font-size: calc(80rpx * var(--font-scale, 1));
   color: $status-info;
   line-height: 1;
 }
 .hero-title {
-  font-size: 44rpx;
+  font-size: calc(44rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 24rpx;
 }
 .hero-desc {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.7);
   line-height: 1.7;
   text-align: center;
@@ -340,7 +342,7 @@ export default {
   margin-right: 16rpx;
 }
 .rule-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.8);
 }
 
@@ -353,11 +355,11 @@ export default {
   margin-bottom: 20rpx;
 }
 .progress-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.85);
 }
 .timer-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: #60A5FA;
   font-weight: bold;
 }
@@ -386,7 +388,7 @@ export default {
   margin-bottom: 60rpx;
 }
 .direction-label {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.5);
   margin-bottom: 20rpx;
 }
@@ -397,7 +399,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .rotation-tip {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $tint-blue-300;
 }
 .options-wrap {
@@ -430,7 +432,7 @@ export default {
   margin-top: 10rpx;
 }
 .feedback-text {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
 }
 .feedback-correct {
   color: $status-success-light-3;
@@ -444,7 +446,7 @@ export default {
 
 /* --- 结果页 --- */
 .result-title {
-  font-size: 36rpx;
+  font-size: calc(36rpx * var(--font-scale, 1));
   color: $app-surface;
   margin-top: 60rpx;
   margin-bottom: 20rpx;
@@ -467,11 +469,11 @@ export default {
   line-height: 1.1;
 }
 .score-unit {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.6);
 }
 .score-detail {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.8);
   margin-bottom: 30rpx;
 }
@@ -483,7 +485,7 @@ export default {
   margin-bottom: 80rpx;
 }
 .dimension-name {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $tint-blue-300;
 }
 
@@ -493,7 +495,7 @@ export default {
   height: 96rpx;
   line-height: 96rpx;
   border-radius: 48rpx;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   text-align: center;
   margin-bottom: 30rpx;
   padding: 0;

+ 12 - 10
cfc-frontend/pages/cognitive-test/speed-test.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page-container">
+  <view class="page-container" :style="{ '--font-scale': fontScale }">
     <!-- 说明页 -->
     <view v-if="step === 'instruction'" class="step-wrap">
       <text class="title">加工速度测试</text>
@@ -84,8 +84,10 @@
 
 <script>
 import { submitCognitiveSelfTest } from '../../utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       SYMBOLS: ['★', '●', '■', '▲', '◆', '◇', '○', '△'],
@@ -333,14 +335,14 @@ export default {
 }
 
 .title {
-  font-size: 52rpx;
+  font-size: calc(52rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-top: 40rpx;
 }
 
 .subtitle {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.5);
   margin-top: 16rpx;
 }
@@ -355,7 +357,7 @@ export default {
 
 .desc-title {
   display: block;
-  font-size: 32rpx;
+  font-size: calc(32rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $brand-primary;
   margin-bottom: 24rpx;
@@ -363,7 +365,7 @@ export default {
 
 .desc-line {
   display: block;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.85);
   line-height: 1.9;
 }
@@ -411,7 +413,7 @@ export default {
 }
 
 .round-text {
-  font-size: 34rpx;
+  font-size: calc(34rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
   margin-bottom: 20rpx;
@@ -433,7 +435,7 @@ export default {
 }
 
 .phase-hint {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.6);
   margin: 70rpx 0 40rpx;
 }
@@ -531,7 +533,7 @@ export default {
 }
 
 .score-label {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.9);
   margin-top: 8rpx;
 }
@@ -550,13 +552,13 @@ export default {
 }
 
 .stat-value {
-  font-size: 40rpx;
+  font-size: calc(40rpx * var(--font-scale, 1));
   font-weight: bold;
   color: $app-surface;
 }
 
 .stat-label {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: rgba(255, 255, 255, 0.5);
   margin-top: 10rpx;
 }

+ 8 - 6
cfc-frontend/pages/dan-assessment/comparison.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="page">
+  <view class="page" :style="{ '--font-scale': fontScale }">
     <view class="filter-bar">
       <view class="filter-item">{{ currentMemberName }} ▾</view>
       <picker :range="reportIds" @change="onReportIdChange">
@@ -56,8 +56,10 @@
 
 <script>
 import { getFamilyMemberList, getDanReportList, compareDanReports } from '@/utils/api'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: {},
   data() {
     return {
@@ -173,7 +175,7 @@ export default {
   border-radius: 16rpx;
   padding: 16rpx 24rpx;
   margin-right: 16rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $uni-text-color;
   text-align: center;
 }
@@ -181,15 +183,15 @@ export default {
 
 /* 对比区 */
 .comparison-wrap { background: $app-surface; border-radius: 20rpx; padding: 24rpx; margin-bottom: 24rpx; box-shadow: 0 4rpx 16rpx rgba(30,41,59,0.06); }
-.section-title { font-size: 30rpx; font-weight: 600; color: $uni-text-color; margin-bottom: 20rpx; }
+.section-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 600; color: $uni-text-color; margin-bottom: 20rpx; }
 .info-item { display: flex; align-items: center; margin-bottom: 16rpx; }
-.label { font-size: 24rpx; color: $uni-text-color-secondary; margin-right: 12rpx; }
-.value { font-size: 24rpx; color: $uni-text-color; }
+.label { font-size: calc(24rpx * var(--font-scale, 1)); color: $uni-text-color-secondary; margin-right: 12rpx; }
+.value { font-size: calc(24rpx * var(--font-scale, 1)); color: $uni-text-color; }
 .deltas-list { margin-top: 24rpx; }
 .delta-item { padding: 12rpx 0; border-bottom: 1rpx solid $uni-border-color-light; display: flex; align-items: center; }
 .delta-code { flex: 1; font-size: 24rpx; color: $uni-text-color-secondary; }
 .delta-added { color: #32CD32; }
 .delta-removed { color: $accent-coral; }
 .delta-modified { color: $accent-gold-deep; }
-.empty-tip { padding: 60rpx 0; text-align: center; font-size: 26rpx; color: $app-text-subtle; }
+.empty-tip { padding: 60rpx 0; text-align: center; font-size: calc(26rpx * var(--font-scale, 1)); color: $app-text-subtle; }
 </style>

+ 30 - 28
cfc-frontend/pages/dan-assessment/report-result.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="container">
+  <view class="container" :style="{ '--font-scale': fontScale }">
     <!-- ==================== Hero 头部 ==================== -->
     <view class="hero">
       <view class="hero-bg-circle hero-bg-circle-1"></view>
@@ -243,8 +243,10 @@ var NOISE_NAME_KEYS = ['联系电话', '报告编码', '测试时间', '档案',
   '出生', '年份', '编码', '编号', '手机', '身份证', '总均分', '邮箱']
 // 百分位制 category(0-100)
 var PERCENT_CATEGORIES = ['overall', 'cognitive']
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { RadarChart },
   data() {
     return {
@@ -670,7 +672,7 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
 .hero-bg-circle-2 { width: 220rpx; height: 220rpx; left: -80rpx; bottom: -60rpx; }
 
 .hero-top { position: relative; z-index: 1; }
-.hero-name { font-size: 44rpx; font-weight: 700; color: $app-surface; display: block; }
+.hero-name { font-size: calc(44rpx * var(--font-scale, 1)); font-weight: 700; color: $app-surface; display: block; }
 .hero-dim-row { display: flex; align-items: center; margin-top: 14rpx; flex-wrap: wrap; }
 .hero-dim-badge {
   font-size: 22rpx; color: $app-surface;
@@ -684,7 +686,7 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   border-radius: 24rpx; padding: 6rpx 18rpx;
   margin-right: 14rpx;
 }
-.hero-date { font-size: 24rpx; color: rgba(255,255,255,0.75); }
+.hero-date { font-size: calc(24rpx * var(--font-scale, 1)); color: rgba(255,255,255,0.75); }
 
 .hero-score-wrap {
   position: relative; z-index: 1;
@@ -695,8 +697,8 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
 .hero-score-divider { width: 1rpx; height: 72rpx; background: rgba(255,255,255,0.25); }
 .hero-score-num { font-size: 88rpx; font-weight: 700; color: $app-surface; line-height: 1; }
 .hero-score-num-pct { font-size: 72rpx; }
-.hero-score-pct-unit { font-size: 32rpx; font-weight: 400; margin-left: 2rpx; }
-.hero-score-label { font-size: 24rpx; color: rgba(255,255,255,0.75); margin-top: 12rpx; }
+.hero-score-pct-unit { font-size: calc(32rpx * var(--font-scale, 1)); font-weight: 400; margin-left: 2rpx; }
+.hero-score-label { font-size: calc(24rpx * var(--font-scale, 1)); color: rgba(255,255,255,0.75); margin-top: 12rpx; }
 
 .hero-pct-bar-wrap { position: relative; z-index: 1; margin-top: 32rpx; }
 .hero-pct-track {
@@ -712,7 +714,7 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   background: $app-surface; border-radius: 2rpx; transform: translateX(-2rpx);
 }
 .hero-pct-foot { margin-top: 12rpx; text-align: center; }
-.hero-pct-foot-text { font-size: 22rpx; color: rgba(255,255,255,0.85); }
+.hero-pct-foot-text { font-size: calc(22rpx * var(--font-scale, 1)); color: rgba(255,255,255,0.85); }
 
 /* ==================== 通用卡片 ==================== */
 .body { padding: 28rpx 24rpx 0; }
@@ -730,18 +732,18 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   margin-right: 12rpx; align-self: center;
 }
 .card-title-bar-gold { background: linear-gradient(180deg, $dim-wealth, $brand-primary); }
-.card-title { font-size: 30rpx; font-weight: 600; color: $facade-text-gray-800; }
-.card-title-sub { font-size: 22rpx; color: $facade-text-gray-400; margin-left: 14rpx; }
+.card-title { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 600; color: $facade-text-gray-800; }
+.card-title-sub { font-size: calc(22rpx * var(--font-scale, 1)); color: $facade-text-gray-400; margin-left: 14rpx; }
 
 /* ==================== 指标条 ==================== */
 .metric-row { margin-bottom: 26rpx; }
 .metric-row:last-child { margin-bottom: 4rpx; }
 .metric-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12rpx; }
-.metric-name { font-size: 26rpx; color: $facade-text-gray-700; font-weight: 500; }
+.metric-name { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-gray-700; font-weight: 500; }
 .metric-value-wrap { display: flex; align-items: center; }
-.metric-value { font-size: 30rpx; font-weight: 700; color: $dim-wisdom-deep; }
+.metric-value { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 700; color: $dim-wisdom-deep; }
 .metric-value-warn { color: $brand-primary-dark; }
-.metric-unit { font-size: 20rpx; font-weight: 400; }
+.metric-unit { font-size: calc(20rpx * var(--font-scale, 1)); font-weight: 400; }
 .metric-warn-badge {
   font-size: 20rpx; color: $brand-primary-dark;
   background: $uni-primary-pale; border: 1rpx solid $c-rpt-orange;
@@ -762,14 +764,14 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   display: flex; justify-content: space-between; align-items: center;
   padding: 10rpx 0;
 }
-.metric-plain-value { font-size: 26rpx; color: $dim-wisdom-deep; font-weight: 600; }
+.metric-plain-value { font-size: calc(26rpx * var(--font-scale, 1)); color: $dim-wisdom-deep; font-weight: 600; }
 
 /* ==================== 大五人格 ==================== */
 .bf-row { margin-bottom: 24rpx; }
 .bf-row:last-child { margin-bottom: 4rpx; }
 .bf-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10rpx; }
-.bf-name { font-size: 26rpx; color: $facade-text-gray-700; font-weight: 500; }
-.bf-value { font-size: 30rpx; font-weight: 700; color: $facade-violet-deep; }
+.bf-name { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-gray-700; font-weight: 500; }
+.bf-value { font-size: calc(30rpx * var(--font-scale, 1)); font-weight: 700; color: $facade-violet-deep; }
 .bf-track { position: relative; height: 14rpx; border-radius: 7rpx; background: $c-rpt-violet-grid; }
 .bf-fill { height: 100%; border-radius: 7rpx; }
 .bf-neutral { background: linear-gradient(90deg, $c-rpt-violet-soft, $facade-violet); }
@@ -779,7 +781,7 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   position: absolute; top: -5rpx; left: 60%; width: 2rpx; height: 24rpx;
   background: $facade-text-gray-400; border-radius: 1rpx;
 }
-.bf-hint { display: block; font-size: 20rpx; color: $facade-text-gray-400; margin-top: 6rpx; }
+.bf-hint { display: block; font-size: calc(20rpx * var(--font-scale, 1)); color: $facade-text-gray-400; margin-top: 6rpx; }
 
 /* ==================== 情绪状态 ==================== */
 .emo-row { display: flex; align-items: center; margin-bottom: 20rpx; }
@@ -789,8 +791,8 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   background: $facade-violet-tint-2; border-radius: 14rpx;
   padding: 10rpx 18rpx; margin-right: 18rpx; flex-shrink: 0;
 }
-.emo-name { font-size: 24rpx; color: $c-rpt-violet-text; margin-right: 12rpx; }
-.emo-value { font-size: 28rpx; font-weight: 700; color: $facade-violet-deep; }
+.emo-name { font-size: calc(24rpx * var(--font-scale, 1)); color: $c-rpt-violet-text; margin-right: 12rpx; }
+.emo-value { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 700; color: $facade-violet-deep; }
 .emo-track { flex: 1; height: 12rpx; border-radius: 6rpx; background: $c-rpt-violet-grid; overflow: hidden; }
 .emo-fill { height: 100%; border-radius: 6rpx; background: linear-gradient(90deg, $facade-violet-light, $facade-violet-deep); }
 
@@ -809,7 +811,7 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   padding: 16rpx 20rpx;
   margin-bottom: 20rpx;
 }
-.emo-summary-text { font-size: 24rpx; color: $c-rpt-violet-text; }
+.emo-summary-text { font-size: calc(24rpx * var(--font-scale, 1)); color: $c-rpt-violet-text; }
 
 /* ==================== 体质健康 ==================== */
 .habit-row {
@@ -820,8 +822,8 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   border-bottom: 1rpx solid $c-rpt-line;
 }
 .habit-row:last-child { border-bottom: none; }
-.habit-name { font-size: 26rpx; color: $facade-text-gray-700; }
-.habit-value { font-size: 26rpx; color: $dim-wisdom-deep; font-weight: 600; }
+.habit-name { font-size: calc(26rpx * var(--font-scale, 1)); color: $facade-text-gray-700; }
+.habit-value { font-size: calc(26rpx * var(--font-scale, 1)); color: $dim-wisdom-deep; font-weight: 600; }
 
 /* ==================== 基本信息 ==================== */
 .info-grid { display: flex; flex-wrap: wrap; }
@@ -829,13 +831,13 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   width: 33.33%; display: flex; flex-direction: column; align-items: center;
   margin-bottom: 16rpx;
 }
-.info-value { font-size: 36rpx; font-weight: 700; color: $facade-text-gray-800; }
-.info-unit { font-size: 20rpx; font-weight: 400; color: $facade-text-gray-400; margin-left: 4rpx; }
-.info-name { font-size: 22rpx; color: $facade-text-gray-400; margin-top: 6rpx; }
+.info-value { font-size: calc(36rpx * var(--font-scale, 1)); font-weight: 700; color: $facade-text-gray-800; }
+.info-unit { font-size: calc(20rpx * var(--font-scale, 1)); font-weight: 400; color: $facade-text-gray-400; margin-left: 4rpx; }
+.info-name { font-size: calc(22rpx * var(--font-scale, 1)); color: $facade-text-gray-400; margin-top: 6rpx; }
 
 /* ==================== 成长建议/评语 ==================== */
 .advice-content {
-  font-size: 26rpx; color: $c-rpt-body; line-height: 1.8;
+  font-size: calc(26rpx * var(--font-scale, 1)); color: $c-rpt-body; line-height: 1.8;
   white-space: pre-wrap; word-break: break-all;
 }
 .advice-clamped {
@@ -844,15 +846,15 @@ $c-rpt-mask-ink:     #000;    // 遮罩渐变异色(mask-image)
   mask-image: linear-gradient(180deg, $c-rpt-mask-ink 60%, transparent 100%);
 }
 .advice-toggle { text-align: center; margin-top: 16rpx; }
-.advice-toggle-text { font-size: 24rpx; color: $dim-wisdom; font-weight: 500; }
+.advice-toggle-text { font-size: calc(24rpx * var(--font-scale, 1)); color: $dim-wisdom; font-weight: 500; }
 
 .foot-note { text-align: center; padding: 18rpx 0 8rpx; }
-.foot-note-text { font-size: 20rpx; color: $c-rpt-foot; }
+.foot-note-text { font-size: calc(20rpx * var(--font-scale, 1)); color: $c-rpt-foot; }
 
 /* ==================== 其他 ==================== */
 .loading-wrap { display: flex; justify-content: center; padding: 140rpx 0; }
 .loading-text { font-size: 28rpx; color: $facade-text-muted; }
 .empty-wrap { display: flex; justify-content: center; padding: 140rpx 0; }
-.empty-text { font-size: 28rpx; color: $facade-text-muted; }
+.empty-text { font-size: calc(28rpx * var(--font-scale, 1)); color: $facade-text-muted; }
 .bottom-spacer { height: 60rpx; }
-</style>
+</style>

+ 14 - 12
cfc-frontend/pages/diet/food-query.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="food-query-page">
+  <view class="food-query-page" :style="{ '--font-scale': fontScale }">
     <!-- 成员切换条 -->
     <view class="member-bar" v-if="memberList.length > 1 || familyMode">
       <view class="member-tab"
@@ -141,8 +141,10 @@
 
 <script>
 import config from '@/config.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       searchQuery: '',
@@ -440,7 +442,7 @@ export default {
   border-radius: 20rpx;
   background: $facade-fill-2;
   color: $facade-text-body;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   font-weight: 500;
 }
 .member-tab.active {
@@ -481,7 +483,7 @@ export default {
   border: 1rpx solid $facade-border-soft;
   border-radius: 30rpx;
   padding: 16rpx 24rpx;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   background-color: $facade-fill-ghost;
 }
 .search-btn {
@@ -532,7 +534,7 @@ export default {
   padding: 12rpx 24rpx;
   border: 1rpx solid $facade-border-soft;
   border-radius: 30rpx;
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-body;
   background-color: $app-surface;
 }
@@ -550,7 +552,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .overview-title {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   margin-bottom: 16rpx;
@@ -576,7 +578,7 @@ export default {
   gap: 8rpx;
 }
 .category-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .member-scores {
@@ -585,7 +587,7 @@ export default {
   gap: 12rpx;
 }
 .member-score {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   padding: 4rpx 12rpx;
   border-radius: 12rpx;
   background: $facade-fill-2;
@@ -652,7 +654,7 @@ export default {
   overflow: hidden;
 }
 .food-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $text-charcoal;
   display: block;
@@ -668,7 +670,7 @@ export default {
 }
 .meta-item {
   flex-shrink: 0;
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $facade-text-faint;
   background: $facade-fill-2;
   padding: 4rpx 14rpx;
@@ -681,7 +683,7 @@ export default {
   flex-shrink: 0;
 }
 .score-value {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 700;
   min-width: 60rpx;
   text-align: right;
@@ -714,7 +716,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .empty-text {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
   display: block;
@@ -729,4 +731,4 @@ export default {
   color: $facade-text-muted;
 }
 .bottom-spacer { height: 40rpx; }
-</style>
+</style>

+ 23 - 21
cfc-frontend/pages/diet/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="diet-page">
+  <view class="diet-page" :style="{ '--font-scale': fontScale }">
     <scroll-view class="content" scroll-y>
       <!-- ===== 今日餐桌主视觉 ===== -->
       <view class="dining-hero">
@@ -162,8 +162,10 @@
 import { BrandColors } from '@/utils/brand-colors.js'
 import { getDietIngredients, refreshDietIngredients, addDietIngredient, removeDietIngredient, generateDietRecommendation, getMealConfig, searchDietFoods, reportAppEnter} from '@/utils/api.js'
 import { parseDate } from '@/utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data: function() {
     return {
       placeholderStyle: 'color:' + BrandColors.textHint,
@@ -425,8 +427,8 @@ export default {
   margin-right: 20rpx; flex-shrink: 0;
 }
 .hero-icon { font-size: 44rpx; }
-.hero-title { font-size: 38rpx; font-weight: 700; color: $app-surface; display: block; }
-.hero-subtitle { font-size: 24rpx; color: rgba(255,255,255,0.85); margin-top: 6rpx; display: block; }
+.hero-title { font-size: calc(38rpx * var(--font-scale, 1)); font-weight: 700; color: $app-surface; display: block; }
+.hero-subtitle { font-size: calc(24rpx * var(--font-scale, 1)); color: rgba(255,255,255,0.85); margin-top: 6rpx; display: block; }
 .hero-meals { display: flex; }
 .hero-meal {
   flex: 1; margin: 0 8rpx;
@@ -436,11 +438,11 @@ export default {
 }
 .hero-meal:first-child { margin-left: 0; }
 .hero-meal:last-child { margin-right: 0; }
-.hero-meal-emoji { font-size: 40rpx; margin-bottom: 8rpx; }
-.hero-meal-label { font-size: 24rpx; color: $app-surface; }
+.hero-meal-emoji { font-size: calc(40rpx * var(--font-scale, 1)); margin-bottom: 8rpx; }
+.hero-meal-label { font-size: calc(24rpx * var(--font-scale, 1)); color: $app-surface; }
 .hero-meal-count { font-size: 22rpx; color: rgba(255,255,255,0.9); margin-top: 6rpx; font-weight: 600; }
 .hero-empty { display: flex; flex-direction: column; align-items: center; padding: 12rpx 0; }
-.hero-empty-text { font-size: 26rpx; color: $app-surface; margin-bottom: 20rpx; }
+.hero-empty-text { font-size: calc(26rpx * var(--font-scale, 1)); color: $app-surface; margin-bottom: 20rpx; }
 .hero-empty-btn {
   background: $app-surface; color: $brand-primary-deep; font-size: 28rpx; font-weight: 600;
   padding: 18rpx 44rpx; border-radius: 999rpx;
@@ -473,9 +475,9 @@ export default {
   display: flex; align-items: center; justify-content: center;
   margin-right: 16rpx; flex-shrink: 0;
 }
-.card-basket-emoji { font-size: 32rpx; }
+.card-basket-emoji { font-size: calc(32rpx * var(--font-scale, 1)); }
 .card-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
 }
@@ -558,17 +560,17 @@ export default {
   flex: 1;
 }
 .ingredient-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
   font-weight: 500;
 }
 .ingredient-reason {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
 }
 .ingredient-balance {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $dim-body;
   margin-top: 2rpx;
 }
@@ -581,7 +583,7 @@ export default {
   flex-shrink: 0;
 }
 .remove-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
 
@@ -590,7 +592,7 @@ export default {
   padding: 8rpx 0 16rpx;
 }
 .section-label-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
 }
@@ -655,17 +657,17 @@ export default {
   background: #FDE8D0;
 }
 .trend-num {
-  font-size: 48rpx;
+  font-size: calc(48rpx * var(--font-scale, 1));
   font-weight: 700;
   color: $dim-body;
 }
 .trend-unit {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-top: 4rpx;
 }
 .trend-label {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-top: 4rpx;
 }
@@ -682,11 +684,11 @@ export default {
   margin-bottom: 12rpx;
 }
 .empty-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .empty-sub {
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
   margin-top: 8rpx;
 }
@@ -749,7 +751,7 @@ export default {
   border: 1rpx solid $facade-hairline-2;
   border-radius: 40rpx;
   padding: 20rpx 28rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   background: $facade-fill-page;
 }
 .food-list {
@@ -763,7 +765,7 @@ export default {
   border-bottom: 1rpx solid $facade-fill-2;
 }
 .food-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $facade-text-strong;
 }
 .food-tag {
@@ -778,4 +780,4 @@ export default {
 .bottom-space {
   height: 40rpx;
 }
-</style>
+</style>

+ 11 - 9
cfc-frontend/pages/diet/meal-config.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="meal-config-page">
+  <view class="meal-config-page" :style="{ '--font-scale': fontScale }">
 
     <scroll-view class="content" scroll-y>
       <!-- 日期切换:两段式胶囊 tabs -->
@@ -63,8 +63,10 @@
 <script>
 import config from '@/config.js'
 import { getMealConfig, saveMealConfig } from '@/utils/api.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       dateType: 'weekday',
@@ -252,7 +254,7 @@ export default {
 .meal-icon-dinner    { background: linear-gradient(135deg, $facade-violet-light, $accent-violet-300); }
 .meal-count { font-size: 24rpx; color: $brand-primary; margin-left: auto; }
 .meal-name {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $uni-text-color;
 }
@@ -287,7 +289,7 @@ export default {
   border-radius: 50%;
   background-color: $app-surface;
   color: $brand-primary;
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   font-weight: 900;
   display: flex;
   align-items: center;
@@ -298,13 +300,13 @@ export default {
 .member-avatar {
   width: 48rpx; height: 48rpx; border-radius: 50%;
   color: $app-surface; display: flex; align-items: center; justify-content: center;
-  font-size: 24rpx; font-weight: 600;
+  font-size: calc(24rpx * var(--font-scale, 1)); font-weight: 600;
 }
 .member-avatar-male   { background: linear-gradient(135deg, $brand-primary, $brand-primary-light); }
 .member-avatar-female { background: linear-gradient(135deg, #F472B6, #F9A8D4); }
 .member-avatar-unknown{ background: linear-gradient(135deg, $uni-border-color, $uni-border-color-light); }
 .member-name {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $uni-text-color-secondary;
   max-width: 80rpx;
   overflow: hidden;
@@ -324,7 +326,7 @@ export default {
   text-align: center;
 }
 .member-empty-text {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $app-text-subtle;
 }
 .add-member-entry {
@@ -348,7 +350,7 @@ export default {
   margin-right: 12rpx;
 }
 .add-member-entry-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   color: $brand-primary;
   font-weight: 600;
 }
@@ -364,7 +366,7 @@ export default {
   margin-bottom: 30rpx; 
 }
 .tip-text { 
-  font-size: 24rpx; 
+  font-size: calc(24rpx * var(--font-scale, 1)); 
   color: $uni-info; 
   line-height: 1.6; 
 }
@@ -382,4 +384,4 @@ export default {
   opacity: 0.9;
   transform: scale(0.98);
 }
-</style>
+</style>

+ 12 - 10
cfc-frontend/pages/diet/preferences.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="preferences-page">
+  <view class="preferences-page" :style="{ '--font-scale': fontScale }">
     <!-- 顶部进度条 -->
     <view class="progress-bar">
       <view class="progress-track">
@@ -232,8 +232,10 @@ const PRESET_CUISINE = ['川', '粤', '鲁', '淮扬', '日料', '西餐', '东
 const PRESET_COOKING = ['蒸', '煮', '炒', '烤', '炖', '凉拌', '煎', '炸']
 const PRESET_MUSTEAT = ['蔬菜', '水果', '粗粮', '鱼类', '鸡蛋', '豆制品', '菌菇']
 const PRESET_GOALS = ['减脂', '增肌', '控糖', '肠道调理', '增强免疫']
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   data() {
     return {
       familyMemberId: null,
@@ -406,7 +408,7 @@ $c-dp-footer-line: #FFE9D4; // 底部操作条描边
   border-radius: 6rpx; transition: width 0.3s ease;
 }
 .progress-labels { display: flex; justify-content: space-between; margin-top: 12rpx; }
-.progress-label { font-size: 22rpx; color: $c-dp-label; flex: 1; text-align: center; }
+.progress-label { font-size: calc(22rpx * var(--font-scale, 1)); color: $c-dp-label; flex: 1; text-align: center; }
 .progress-label-active { color: $dim-body; font-weight: 600; }
 
 /* ===== 内容 ===== */
@@ -414,15 +416,15 @@ $c-dp-footer-line: #FFE9D4; // 底部操作条描边
 .step-head { display: flex; align-items: center; margin: 20rpx 0 24rpx; }
 .step-icon { font-size: 52rpx; margin-right: 20rpx; }
 .step-head-text { display: flex; flex-direction: column; }
-.step-title { font-size: 34rpx; font-weight: 700; color: $c-dp-ink; }
-.step-sub { font-size: 24rpx; color: $c-dp-muted; margin-top: 6rpx; }
+.step-title { font-size: calc(34rpx * var(--font-scale, 1)); font-weight: 700; color: $c-dp-ink; }
+.step-sub { font-size: calc(24rpx * var(--font-scale, 1)); color: $c-dp-muted; margin-top: 6rpx; }
 
 /* ===== 卡片 ===== */
 .card {
   background: $app-surface; border-radius: 24rpx; padding: 28rpx;
   margin-bottom: 24rpx; box-shadow: 0 4rpx 20rpx rgba(255, 140, 66, 0.08);
 }
-.card-title { font-size: 28rpx; font-weight: 600; color: $c-dp-ink; margin-bottom: 20rpx; display: block; }
+.card-title { font-size: calc(28rpx * var(--font-scale, 1)); font-weight: 600; color: $c-dp-ink; margin-bottom: 20rpx; display: block; }
 
 /* ===== chip ===== */
 .chip-group { display: flex; flex-wrap: wrap; }
@@ -438,15 +440,15 @@ $c-dp-footer-line: #FFE9D4; // 底部操作条描边
 
 /* ===== 自定义添加 ===== */
 .custom-add {
-  padding: 14rpx 0; font-size: 26rpx; color: $dim-body; font-weight: 500;
+  padding: 14rpx 0; font-size: calc(26rpx * var(--font-scale, 1)); color: $dim-body; font-weight: 500;
 }
 .custom-row { display: flex; align-items: center; margin-top: 8rpx; margin-bottom: 12rpx; }
 .custom-input {
   flex: 1; border: 2rpx solid $c-dp-line; border-radius: 999rpx;
-  padding: 14rpx 24rpx; font-size: 26rpx; background: $c-dp-input;
+  padding: 14rpx 24rpx; font-size: calc(26rpx * var(--font-scale, 1)); background: $c-dp-input;
 }
 .custom-confirm {
-  background: $dim-body; color: $app-surface; font-size: 26rpx; font-weight: 600;
+  background: $dim-body; color: $app-surface; font-size: calc(26rpx * var(--font-scale, 1)); font-weight: 600;
   padding: 14rpx 32rpx; border-radius: 999rpx; margin-left: 16rpx;
 }
 
@@ -454,7 +456,7 @@ $c-dp-footer-line: #FFE9D4; // 底部操作条描边
 .slider-row { display: flex; align-items: center; }
 .slider-label { font-size: 24rpx; color: $c-dp-muted; width: 72rpx; }
 .slider { flex: 1; }
-.spice-level-label { font-size: 24rpx; color: $dim-body; text-align: center; margin-top: 8rpx; display: block; }
+.spice-level-label { font-size: calc(24rpx * var(--font-scale, 1)); color: $dim-body; text-align: center; margin-top: 8rpx; display: block; }
 
 /* ===== 底栏 ===== */
 .footer-bar {
@@ -471,4 +473,4 @@ $c-dp-footer-line: #FFE9D4; // 底部操作条描边
 .footer-btn-primary {
   background: linear-gradient(135deg, $dim-body, $dim-body-light); color: $app-surface;
 }
-</style>
+</style>

+ 14 - 12
cfc-frontend/pages/discover/circles.vue

@@ -1,5 +1,5 @@
 <template>
-  <view class="circles-container">
+  <view class="circles-container" :style="{ '--font-scale': fontScale }">
     <!-- 自定义导航栏 -->
     <view class="custom-nav">
       <view class="nav-header">
@@ -146,8 +146,10 @@ import CircleDetail from '@/pages/discover/components/CircleDetail.vue'
 import { discoverCircles, getMyCircles, joinGeneralCircle, leaveGeneralCircle, getPendingCircleMembers, approveCircleMember, updateCircle, reportAppEnter
 } from '../../utils/api.js'
 import { parseDate } from '@/utils/format.js'
+import fontScaleMixin from '@/mixins/font-scale.js'
 
 export default {
+  mixins: [fontScaleMixin],
   components: { CircleCard, CircleDetail },
   computed: {
     detailCircle: function() {
@@ -400,7 +402,7 @@ export default {
   margin-bottom: 16rpx;
 }
 .section-title {
-  font-size: 30rpx;
+  font-size: calc(30rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
 }
@@ -440,7 +442,7 @@ export default {
   font-size: 28rpx;
 }
 .circle-edit-text {
-  font-size: 20rpx;
+  font-size: calc(20rpx * var(--font-scale, 1));
   color: $mat-orange-base;
   margin-top: 4rpx;
 }
@@ -484,7 +486,7 @@ export default {
 }
 .form-label {
   display: block;
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-body;
   margin-bottom: 12rpx;
 }
@@ -494,7 +496,7 @@ export default {
   background: $facade-fill-cool;
   border-radius: 12rpx;
   padding: 0 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .form-textarea {
@@ -503,7 +505,7 @@ export default {
   background: $facade-fill-cool;
   border-radius: 12rpx;
   padding: 16rpx 20rpx;
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   box-sizing: border-box;
 }
 .cond-options {
@@ -523,7 +525,7 @@ export default {
   margin-right: 0;
 }
 .cond-opt-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-muted;
 }
 .cond-active {
@@ -583,7 +585,7 @@ export default {
   overflow: hidden;
 }
 .pending-name-text {
-  font-size: 28rpx;
+  font-size: calc(28rpx * var(--font-scale, 1));
   font-weight: 600;
   color: $facade-text-strong;
   max-width: 200rpx;
@@ -592,7 +594,7 @@ export default {
   text-overflow: ellipsis;
 }
 .pending-circle {
-  font-size: 24rpx;
+  font-size: calc(24rpx * var(--font-scale, 1));
   color: $facade-text-muted;
   margin-left: 12rpx;
   overflow: hidden;
@@ -601,7 +603,7 @@ export default {
 }
 .pending-time {
   display: block;
-  font-size: 22rpx;
+  font-size: calc(22rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
   margin-top: 6rpx;
 }
@@ -636,7 +638,7 @@ export default {
   text-align: center;
 }
 .empty-text {
-  font-size: 26rpx;
+  font-size: calc(26rpx * var(--font-scale, 1));
   color: $facade-text-ghost;
 }
-</style>
+</style>

Some files were not shown because too many files changed in this diff