فهرست منبع

fix(beautify): D33 修复品牌色字符串/游离 import/缺失具名导出三处历史 bug

- d33: 7 文件 70 处 'BrandColors.xxx' 字符串字面量改为真正变量引用(原值无效,
  canvas 填充/渐变拼接/色板数组全部失效)
- d34: 9 文件把落在 </script> 与 <style> 之间的 import 搬回 script 内并合并去重
  (C 批脚本追加位置错误 -> 运行时标识符未定义)
- d35: utils/brand-colors.js 补 7 个具名快捷导出 primaryPale/body/primary/success/
  white/wisdom/danger(10 文件按名引入但此前并不存在这些 export)
- 9 个 + 7 个 .vue node --check 全通过;ESM 具名导出实跑校验通过;hex 保持 570
liaoxg 5 روز پیش
والد
کامیت
73b1604e98

+ 2 - 3
cfc-frontend/components/ArticleBookshelf.vue

@@ -55,6 +55,7 @@
 </template>
 
 <script>
+import { primaryPale, BrandColors } from '@/utils/brand-colors.js'
 // 五维配色体系(书脊颜色)
 import config from '@/config.js'
 
@@ -72,7 +73,7 @@ var FALLBACK_GRADIENTS = [
   { bg: 'linear-gradient(180deg, #06B6D4 0%, #0891B2 100%)', text: '#ECFEFF' },
   { bg: 'linear-gradient(180deg, #EC4899 0%, #DB2777 100%)', text: '#FDF2F8' },
   { bg: 'linear-gradient(180deg, #14B8A6 0%, #0D9488 100%)', text: '#F0FDFA' },
-  { bg: 'linear-gradient(180deg, #F97316 0%, #EA580C 100%)', text: 'BrandColors.primaryPale' }
+  { bg: 'linear-gradient(180deg, #F97316 0%, #EA580C 100%)', text: BrandColors.primaryPale }
 ]
 
 export default {
@@ -161,8 +162,6 @@ export default {
   }
 }
 </script>
-import { primaryPale } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 /* ======================================
    ArticleBookshelf — 四列网格推荐阅读组件

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

@@ -40,6 +40,7 @@
 </template>
 
 <script>
+import { body, primary, primaryPale, success, white, wisdom, BrandColors } from '@/utils/brand-colors.js'
 import { getFontScale } from '@/utils/fontScale.js'
 
 export default {
@@ -130,7 +131,7 @@ export default {
       // 选中的管理端模板 id(未使用管理端模板时为 null)
       activeTemplateId: null,
       // 可选的背景色(渐变模板下展示)
-      bgColors: ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind, '#1E293B', 'BrandColors.white']
+      bgColors: [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind, '#1E293B', BrandColors.white]
     }
   },
   methods: {
@@ -179,19 +180,19 @@ export default {
       var tpl = this.getActiveTemplate()
       if (tpl) {
         return {
-          main: tpl.mainColor || 'BrandColors.primary',
+          main: tpl.mainColor || BrandColors.primary,
           dark: tpl.darkColor || BrandColors.orangeDeep,
-          light: tpl.lightColor || 'BrandColors.primaryPale'
+          light: tpl.lightColor || BrandColors.primaryPale
         }
       }
       var map = {
-        body: { main: 'BrandColors.body', dark: BrandColors.orangeDeep, light: 'BrandColors.primaryPale' },
+        body: { main: BrandColors.body, dark: BrandColors.orangeDeep, light: BrandColors.primaryPale },
         mind: { main: BrandColors.mind, dark: '#DB2777', light: '#FDF2F8' },
-        wisdom: { main: 'BrandColors.wisdom', dark: '#4F46E5', light: '#EEF2FF' },
-        action: { main: 'BrandColors.success', dark: '#059669', light: '#ECFDF5' },
+        wisdom: { main: BrandColors.wisdom, dark: '#4F46E5', light: '#EEF2FF' },
+        action: { main: BrandColors.success, dark: '#059669', light: '#ECFDF5' },
         wealth: { main: BrandColors.wealth, dark: '#D97706', light: '#FFFBEB' }
       }
-      return map[this.dimensionCode] || { main: 'BrandColors.primary', dark: BrandColors.orangeDeep, light: 'BrandColors.primaryPale' }
+      return map[this.dimensionCode] || { main: BrandColors.primary, dark: BrandColors.orangeDeep, light: BrandColors.primaryPale }
     },
     // 海报模板配色
     getTemplateConfig() {
@@ -209,7 +210,7 @@ export default {
         return { template: 'minimal', bgColor: dark, main: colors.main, dark: colors.dark, light: colors.light }
       }
       // 卡片模板:浅色背景+彩色顶栏
-      return { template: 'card', bgColor: bgColor || 'BrandColors.white', main: colors.main, dark: colors.dark, light: colors.light }
+      return { template: 'card', bgColor: bgColor || BrandColors.white, main: colors.main, dark: colors.dark, light: colors.light }
     },
     // 获取当前模板的背景样式
     getBgStyle() {
@@ -221,7 +222,7 @@ export default {
       if (cfg.template === 'minimal') {
         return 'linear-gradient(135deg, ' + cfg.bgColor + ', ' + cfg.dark + ')'
       }
-      return 'linear-gradient(135deg, ' + cfg.main + ', ' + (cfg.bgColor || 'BrandColors.white') + ')'
+      return 'linear-gradient(135deg, ' + cfg.main + ', ' + (cfg.bgColor || BrandColors.white) + ')'
     },
     drawPoster() {
       var self = this
@@ -267,7 +268,7 @@ export default {
       }
       // 【模板3 · card】白色背景
       else {
-        ctx.setFillStyle('BrandColors.white')
+        ctx.setFillStyle(BrandColors.white)
         ctx.fillRect(0, 0, w, h)
       }
 
@@ -342,7 +343,7 @@ export default {
 
     _drawTopDecoration(ctx, w, colors) {
       var centerX = w / 2
-      var dotColors = ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind]
+      var dotColors = [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind]
       var dotY = 28
       var dotR = 5
       var dotSpacing = 26
@@ -357,7 +358,7 @@ export default {
         ctx.fill()
       }
 
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       ctx.setFontSize(this._fs(20))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -390,7 +391,7 @@ export default {
       this._roundRect(ctx, x, y, w, h, 8)
       ctx.fill()
 
-      ctx.setFillStyle('BrandColors.primary')
+      ctx.setFillStyle(BrandColors.primary)
       ctx.setFontSize(this._fs(16))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')
@@ -402,7 +403,7 @@ export default {
       var data = this.energyData || {}
       var dims = data.dims || []
 
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       this._roundRect(ctx, x, y, w, h, 8)
       ctx.fill()
 
@@ -446,7 +447,7 @@ export default {
         ctx.arc(cx, y + 94, 17, 0, 2 * Math.PI)
         ctx.fill()
 
-        ctx.setFillStyle('BrandColors.white')
+        ctx.setFillStyle(BrandColors.white)
         ctx.setFontSize(this._fs(15))
         ctx.setTextAlign('center')
         ctx.setTextBaseline('middle')
@@ -487,7 +488,7 @@ export default {
       this._roundRect(ctx, x, y, w, h, 8)
       ctx.fill()
 
-      var dotColors = ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind]
+      var dotColors = [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind]
       var centerX = x + w / 2
       for (var i = 0; i < 5; i++) {
         ctx.setFillStyle(dotColors[i])
@@ -496,7 +497,7 @@ export default {
         ctx.fill()
       }
 
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       ctx.setFontSize(this._fs(24))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -579,7 +580,7 @@ export default {
           data: base64Data,
           encoding: 'base64',
           success: function() {
-            ctx.setFillStyle('BrandColors.white')
+            ctx.setFillStyle(BrandColors.white)
             self._roundRect(ctx, qrX - 10, qrY - 10, qrSize + 20, qrSize + 20, 8)
             ctx.fill()
 
@@ -637,7 +638,7 @@ export default {
     },
 
     _drawQrPlaceholder(ctx, x, y, size) {
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.fill()
 
@@ -680,7 +681,7 @@ export default {
       ctx.setTextBaseline('top')
       ctx.fillText(this.ctaText || '长按识别二维码 · 查看详情', centerX, bottomY)
 
-      var dotColors = ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind]
+      var dotColors = [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind]
       var dotY = h - 22
       var dotR = 4
       var dotSpacing = 20
@@ -765,8 +766,6 @@ export default {
   }
 }
 </script>
-import { body, primary, primaryPale, success, white, wisdom, BrandColors } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 .poster-overlay {
   position: fixed;

+ 7 - 8
cfc-frontend/components/PageBanner.vue

@@ -14,6 +14,7 @@
 </template>
 
 <script>
+import { white, BrandColors } from '@/utils/brand-colors.js'
 /**
  * 各主题对应沙盘颜色的渐变背景
  * 五行色来源:wuxing-sandbox 组件和 render.js
@@ -26,15 +27,15 @@
 var THEME_STYLES = {
   home: {
     background: 'linear-gradient(135deg, #FF8A65 0%, #FFB74D 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   },
   body: {
     background: 'linear-gradient(135deg, #8D6E63 0%, #A1887F 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   },
   mind: {
     background: 'linear-gradient(135deg, #FF6B35 0%, #E65100 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   },
   wisdom: {
     background: 'linear-gradient(135deg, #FFD700 0%, #FFA000 100%)',
@@ -42,15 +43,15 @@ var THEME_STYLES = {
   },
   'mind-wisdom': {
     background: 'linear-gradient(135deg, #FF6B35 0%, #FFD700 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   },
   action: {
     background: 'linear-gradient(135deg, #4CAF50 0%, #66BB6A 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   },
   wealth: {
     background: 'linear-gradient(135deg, #F59E0B 0%, #FBBF24 100%)',
-    color: 'BrandColors.white'
+    color: BrandColors.white
   }
 }
 
@@ -83,8 +84,6 @@ export default {
   }
 }
 </script>
-import { white } from '@/utils/brand-colors.js'
-
 <style scoped>
 .page-banner {
   display: flex;

+ 13 - 15
cfc-frontend/pages/action-detail/components/PearlDiagram.vue

@@ -59,7 +59,7 @@
 
 <script>
 import { addPearlInteraction, updatePearlPriority } from '@/utils/api.js'
-import { BrandColors, INDUSTRY_COLORS } from '@/utils/brand-colors.js'
+import { BrandColors, INDUSTRY_COLORS, danger, primary, success, white } from '@/utils/brand-colors.js'
 
 /**
  * PearlDiagram - 珍珠图 Canvas 组件
@@ -128,8 +128,8 @@ export default {
       // 颜色盘:内圈偏暖(红橙),外圈偏冷(蓝紫绿)
       groupConfigs: [
         // ===== 内圈:必备 12 组(radiusPct 0.28)=====
-        { type: 'MEDICAL', typeName: '医疗', color: 'BrandColors.danger', radiusPct: 0.28, ring: 'inner' },
-        { type: 'EDUCATION', typeName: '教育', color: 'BrandColors.primary', radiusPct: 0.28, ring: 'inner' },
+        { type: 'MEDICAL', typeName: '医疗', color: BrandColors.danger, radiusPct: 0.28, ring: 'inner' },
+        { type: 'EDUCATION', typeName: '教育', color: BrandColors.primary, radiusPct: 0.28, ring: 'inner' },
         { type: 'PUBLIC_SECURITY', typeName: '公安', color: INDUSTRY_COLORS.PUBLIC_SECURITY, radiusPct: 0.28, ring: 'inner' },
         { type: 'AUTO', typeName: '汽车相关', color: INDUSTRY_COLORS.AUTO, radiusPct: 0.28, ring: 'inner' },
         { type: 'REAL_ESTATE', typeName: '房产服务', color: INDUSTRY_COLORS.REAL_ESTATE, radiusPct: 0.28, ring: 'inner' },
@@ -149,7 +149,7 @@ export default {
         { type: 'TRAVEL', typeName: '旅游', color: INDUSTRY_COLORS.TRAVEL, radiusPct: 0.55, ring: 'outer' },
         { type: 'LEADING_ENTERPRISE', typeName: '领军企业', color: INDUSTRY_COLORS.LEADING_ENTERPRISE, radiusPct: 0.55, ring: 'outer' },
         { type: 'INDUSTRY_BENCHMARK', typeName: '行业标杆', color: INDUSTRY_COLORS.INDUSTRY_BENCHMARK, radiusPct: 0.55, ring: 'outer' },
-        { type: 'OVERSEAS', typeName: '国外', color: 'BrandColors.success', radiusPct: 0.55, ring: 'outer' },
+        { type: 'OVERSEAS', typeName: '国外', color: BrandColors.success, radiusPct: 0.55, ring: 'outer' },
         { type: 'UNIVERSITY', typeName: '高校', color: INDUSTRY_COLORS.UNIVERSITY, radiusPct: 0.55, ring: 'outer' },
         { type: 'FINANCE', typeName: '金融', color: INDUSTRY_COLORS.FINANCE, radiusPct: 0.55, ring: 'outer' },
         { type: 'SENIOR_LOCAL', typeName: '资深土著', color: INDUSTRY_COLORS.SENIOR_LOCAL, radiusPct: 0.55, ring: 'outer' },
@@ -465,21 +465,21 @@ export default {
       // 外圈光晕
       ctx.beginPath()
       ctx.arc(cx, cy, r + 4, 0, Math.PI * 2)
-      ctx.fillStyle = this._hexToRgba('BrandColors.success', 0.15)
+      ctx.fillStyle = this._hexToRgba(BrandColors.success, 0.15)
       ctx.fill()
 
       // 实心圆
       ctx.beginPath()
       ctx.arc(cx, cy, r, 0, Math.PI * 2)
-      ctx.fillStyle = 'BrandColors.success'
+      ctx.fillStyle = BrandColors.success
       ctx.fill()
-      ctx.strokeStyle = 'BrandColors.white'
+      ctx.strokeStyle = BrandColors.white
       ctx.lineWidth = 3
       ctx.stroke()
 
       // "我" 字
       ctx.font = 'bold 18px PingFang SC, sans-serif'
-      ctx.fillStyle = 'BrandColors.white'
+      ctx.fillStyle = BrandColors.white
       ctx.textAlign = 'center'
       ctx.textBaseline = 'middle'
       ctx.fillText('我', cx, cy + 1)
@@ -509,7 +509,7 @@ export default {
       ctx.fill()
 
       // 白边
-      ctx.strokeStyle = 'BrandColors.white'
+      ctx.strokeStyle = BrandColors.white
       ctx.lineWidth = 2
       ctx.stroke()
 
@@ -518,13 +518,13 @@ export default {
         ctx.beginPath()
         ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2)
         ctx.lineWidth = 2
-        ctx.strokeStyle = 'BrandColors.white'
+        ctx.strokeStyle = BrandColors.white
         ctx.stroke()
       }
 
       // 首字
       ctx.font = 'bold ' + Math.max(12, r * 0.65) + 'px PingFang SC, sans-serif'
-      ctx.fillStyle = 'BrandColors.white'
+      ctx.fillStyle = BrandColors.white
       ctx.textAlign = 'center'
       ctx.textBaseline = 'middle'
       ctx.fillText(node.displayName, x, y + 1)
@@ -584,9 +584,9 @@ export default {
         // 红底白字小徽标
         ctx.beginPath()
         ctx.arc(bx, by, 9, 0, Math.PI * 2)
-        ctx.fillStyle = 'BrandColors.danger'
+        ctx.fillStyle = BrandColors.danger
         ctx.fill()
-        ctx.fillStyle = 'BrandColors.white'
+        ctx.fillStyle = BrandColors.white
         ctx.font = 'bold 10px sans-serif'
         ctx.textAlign = 'center'
         ctx.textBaseline = 'middle'
@@ -852,8 +852,6 @@ export default {
   }
 }
 </script>
-import { danger, primary, success, white } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 .pearl-graph-wrapper {
   position: relative;

+ 1 - 2
cfc-frontend/pages/energy/index.vue

@@ -140,6 +140,7 @@
 </template>
 
 <script>
+import { primary, success } from '@/utils/brand-colors.js'
 import RadarChart from '../../components/RadarChart.vue'
 import { getFamilyEnergySandbox, getFamilyMemberList } from '../../utils/api.js'
 import { BrandColors } from '../../utils/brand-colors.js'
@@ -418,8 +419,6 @@ export default {
   }
 }
 </script>
-import { primary, success } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 // ===== 能量页专属色阶(导航/卡面深海军蓝,单页专用;约定见 uni.scss §14)=====
 $c-energy-deep-1: #0F1B2D; // 导航渐变起(深夜蓝)

+ 2 - 3
cfc-frontend/pages/mind-detail/components/FamilyTianpanCard.vue

@@ -116,6 +116,7 @@
 </template>
 
 <script>
+import { body, success, white, wisdom, BrandColors } from '@/utils/brand-colors.js'
 /**
  * FamilyTianpanCard — 家庭天盘概览卡片(嵌入心维度页面)
  *
@@ -518,7 +519,7 @@ export default {
       ctx.arc(cx, cy, 5, 0, Math.PI * 2)
       ctx.fillStyle = luckyColor
       ctx.fill()
-      ctx.strokeStyle = 'BrandColors.white'
+      ctx.strokeStyle = BrandColors.white
       ctx.lineWidth = 1.5
       ctx.stroke()
     },
@@ -573,8 +574,6 @@ export default {
   },
 }
 </script>
-import { body, success, white, wisdom } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 // ===== 页面级局部调色板(单页专有色阶;同值才映射全局令牌,约定见 uni.scss §14) =====
 $c-col-bg:     #FAFBFC;   // 三栏列背景(蓝灰近白)

+ 1 - 2
cfc-frontend/pages/mind-detail/emotion-checkin.vue

@@ -200,6 +200,7 @@
 </template>
 
 <script>
+import { body, danger, success } from '@/utils/brand-colors.js'
 import config from '../../config'
 import PsychCrisisBanner from '@/pages/mind-detail/components/PsychCrisisBanner.vue'
 import { pickImage } from '@/utils/image-picker.js'
@@ -808,8 +809,6 @@ export default {
   }
 }
 </script>
-import { body, danger, success } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 // ===== 页面级局部调色板(单页专有色阶;同值才映射全局令牌,约定见 uni.scss §14) =====
 $c-tint-magenta: #FFF0FF;   // 效价-激活度网格渐变 25% 档

+ 12 - 13
cfc-frontend/pages/promotion/components/SharePoster.vue

@@ -11,6 +11,7 @@
 </template>
 
 <script>
+import { body, primary, success, white, wisdom, BrandColors } from '@/utils/brand-colors.js'
 export default {
   name: 'SharePoster',
   props: {
@@ -64,7 +65,7 @@ export default {
 
       // 1. Background gradient — warm orange
       var gradient = ctx.createLinearGradient(0, 0, w * 0.3, h)
-      gradient.addColorStop(0, 'BrandColors.primary')
+      gradient.addColorStop(0, BrandColors.primary)
       gradient.addColorStop(0.55, BrandColors.orangeDeep)
       gradient.addColorStop(1, '#D94F0A')
       ctx.setFillStyle(gradient)
@@ -120,7 +121,7 @@ export default {
     // ============================================================
     _drawTopDecoration(ctx, w) {
       var centerX = w / 2
-      var dotColors = ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind]
+      var dotColors = [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind]
       var dotY = 28
       var dotR = 5
       var dotSpacing = 26
@@ -137,7 +138,7 @@ export default {
       }
 
       // Brand name
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       ctx.setFontSize(18)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -176,7 +177,7 @@ export default {
       // Corner decorative brackets
       var br = 10
       var bl = 22
-      ctx.setStrokeStyle('BrandColors.primary')
+      ctx.setStrokeStyle(BrandColors.primary)
       ctx.setLineWidth(1.5)
 
       // Top-left
@@ -220,7 +221,7 @@ export default {
       ctx.stroke()
 
       // Solid ring
-      ctx.setStrokeStyle('BrandColors.primary')
+      ctx.setStrokeStyle(BrandColors.primary)
       ctx.setLineWidth(2.5)
       ctx.beginPath()
       ctx.arc(x, y, r + 4, 0, 2 * Math.PI)
@@ -251,7 +252,7 @@ export default {
       ctx.fill()
 
       // Draw a simple person silhouette with Canvas primitives
-      ctx.setFillStyle('BrandColors.primary')
+      ctx.setFillStyle(BrandColors.primary)
 
       // Head (smaller circle, upper portion)
       var headR = r * 0.32
@@ -312,7 +313,7 @@ export default {
 
       // --- 简单介绍:品牌 / 五维 / 定位 ---
       var brandY = dividerY + 14
-      ctx.setFillStyle('BrandColors.primary')
+      ctx.setFillStyle(BrandColors.primary)
       ctx.setFontSize(14)
       ctx.fillText(this.familyName ? this.familyName + ' · 家庭健康俱乐部' : '浠艾福 · 家庭健康俱乐部', centerX, brandY)
 
@@ -349,7 +350,7 @@ export default {
           encoding: 'base64',
           success: function() {
             // White background behind QR
-            ctx.setFillStyle('BrandColors.white')
+            ctx.setFillStyle(BrandColors.white)
             self._roundRect(ctx, qrX - 10, qrY - 10, qrSize + 20, qrSize + 20, 8)
             ctx.fill()
 
@@ -377,7 +378,7 @@ export default {
     //  QR PLACEHOLDER (fallback when QR write fails)
     // ============================================================
     _drawQrPlaceholder(ctx, x, y, size) {
-      ctx.setFillStyle('BrandColors.white')
+      ctx.setFillStyle(BrandColors.white)
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.fill()
 
@@ -421,14 +422,14 @@ export default {
       ctx.fill()
 
       // CTA text
-      ctx.setFillStyle('BrandColors.primary')
+      ctx.setFillStyle(BrandColors.primary)
       ctx.setFontSize(17)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
       ctx.fillText('长按识别二维码,了解浠艾福', centerX, bottomY)
 
       // 5 dimension dots in the bottom area (outside card)
-      var dotColors = ['BrandColors.body', 'BrandColors.wisdom', BrandColors.wealth, 'BrandColors.success', BrandColors.mind]
+      var dotColors = [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.success, BrandColors.mind]
       var dotY = h - 22
       var dotR = 4
       var dotSpacing = 20
@@ -495,8 +496,6 @@ export default {
   }
 }
 </script>
-import { body, primary, success, white, wisdom, BrandColors } from '@/utils/brand-colors.js'
-
 <style scoped lang="scss">
 .poster-overlay {
   position: fixed;

+ 5 - 6
cfc-frontend/pages/tianpan/index.vue

@@ -162,6 +162,7 @@
 </template>
 
 <script>
+import { body, danger, primary, success, wisdom } from '@/utils/brand-colors.js'
 import { mapState, mapGetters, mapActions } from 'vuex'
 import { BrandColors } from '../../utils/brand-colors.js'
 
@@ -356,7 +357,7 @@ export default {
         ctx.closePath()
         ctx.fillStyle = 'rgba(249, 114, 22, 0.2)'
         ctx.fill()
-        ctx.strokeStyle = 'BrandColors.primary'
+        ctx.strokeStyle = BrandColors.primary
         ctx.lineWidth = 2
         ctx.stroke()
 
@@ -531,11 +532,11 @@ export default {
         // 根据分数设置颜色
         var score = rel.score || 0
         if (score >= 80) {
-          ctx.strokeStyle = 'BrandColors.success'
+          ctx.strokeStyle = BrandColors.success
         } else if (score >= 60) {
           ctx.strokeStyle = BrandColors.wealth
         } else {
-          ctx.strokeStyle = 'BrandColors.danger'
+          ctx.strokeStyle = BrandColors.danger
         }
         ctx.lineWidth = 2
         ctx.stroke()
@@ -544,7 +545,7 @@ export default {
     
     getMemberColor: function(role) {
       var colorMap = {
-        'parent': 'BrandColors.primary',
+        'parent': BrandColors.primary,
         'child': BrandColors.infoBlue,
         'teacher': BrandColors.violet
       }
@@ -693,8 +694,6 @@ export default {
   }
 }
 </script>
-import { body, danger, primary, success, wisdom } from '@/utils/brand-colors.js'
-
 <style lang="scss">
 // ===== 天盘页专属色阶(暖橙提示 + 紫罗兰软阶;单页专用,约定见 uni.scss §14)=====
 $c-tp-orange:       $mat-orange-300; // 暖橙(徽章渐变档)

+ 50 - 0
cfc-frontend/scripts/d33-fix-brandcolor-strings.js

@@ -0,0 +1,50 @@
+#!/usr/bin/env node
+/**
+ * D33: 修复 C 批遗留 bug —— 脚本/样式中的 'BrandColors.x' 字符串字面量
+ * (字符串不是变量引用,作为颜色值无效:canvas setFillStyle、渐变拼接、色板数组等)
+ * 统一改为真正的变量引用 BrandColors.x(键均已在 utils/brand-colors.js 存在)
+ */
+const fs = require('fs');
+const path = require('path');
+
+const ROOT = path.resolve(__dirname, '..');
+const EXCLUDE_DIRS = new Set(['node_modules', 'dist', 'unpackage', '.git', 'scripts', '.tmp_equiv']);
+
+function walk(dir, out = []) {
+  for (const name of fs.readdirSync(dir)) {
+    if (EXCLUDE_DIRS.has(name)) continue;
+    const p = path.join(dir, name);
+    const st = fs.statSync(p);
+    if (st.isDirectory()) walk(p, out);
+    else if (name.endsWith('.vue')) out.push(p);
+  }
+  return out;
+}
+
+let files = 0;
+let count = 0;
+for (const abs of walk(ROOT)) {
+  const src = fs.readFileSync(abs, 'utf8');
+  if (!/['"]BrandColors\.\w+['"]/.test(src)) continue;
+  let n = 0;
+  let out = src.replace(/['"]BrandColors\.(\w+)['"]/g, (m, key) => {
+    n++;
+    return 'BrandColors.' + key;
+  });
+  if (!/import\s*\{[^}]*\bBrandColors\b[^}]*\}\s*from\s*['"][^'"]*brand-colors/.test(out) &&
+      !/import\s*\{[^}]*\bBrandColors\b[^}]*\}\s*from\s*['"][^'"]*brand-colors/.test(src)) {
+    const rel = path.relative(path.dirname(abs), path.join(ROOT, 'utils/brand-colors.js')).split(path.sep).join('/');
+    const existing = out.match(/import\s*\{([^}]*)\}\s*from\s*(['"][^'"]*brand-colors(?:\.js)?['"])/);
+    if (existing) {
+      out = out.replace(existing[0], 'import {' + existing[1].replace(/\s*$/, '') + (existing[1].trim().endsWith(',') ? ' ' : ', ') + 'BrandColors } from ' + existing[2]);
+    } else {
+      const t = out.match(/<script[^>]*>\r?\n/);
+      if (t) out = out.replace(t[0], t[0] + "import { BrandColors } from '" + rel + "'" + (t[0].includes('\r\n') ? '\r\n' : '\n'));
+    }
+  }
+  fs.writeFileSync(abs, out, 'utf8');
+  files++;
+  count += n;
+  console.log(String(n).padStart(3) + '  ' + path.relative(ROOT, abs).split(path.sep).join('/'));
+}
+console.log('文件:', files, '修复字符串引用:', count);

+ 83 - 0
cfc-frontend/scripts/d34-fix-stray-imports.js

@@ -0,0 +1,83 @@
+#!/usr/bin/env node
+/**
+ * D34: 修复「import 落在 </script> 之后」的历史残留
+ * C 批脚本把品牌色 import 追加到了 </script> 与 <style> 之间 -> 模块作用域外,运行期标识符未定义。
+ * 处理:把这段的 import 行搬回 <script> 内;已存在同路径 import 则合并去重。
+ */
+const fs = require('fs');
+const path = require('path');
+const DRY = process.argv.includes('--dry');
+
+const ROOT = path.resolve(__dirname, '..');
+const SKIP = new Set(['components/mp-html/node/node.vue']); // mp-html 自带多 script 结构
+
+function walk(dir, out = []) {
+  for (const name of fs.readdirSync(dir)) {
+    if (['node_modules', 'dist', 'unpackage', '.git', 'scripts', '.tmp_equiv'].includes(name)) continue;
+    const p = path.join(dir, name);
+    const st = fs.statSync(p);
+    if (st.isDirectory()) walk(p, out);
+    else if (name.endsWith('.vue')) out.push(p);
+  }
+  return out;
+}
+
+function parseNames(imp) {
+  const m = imp.match(/import\s*\{([^}]*)\}\s*from\s*(['"][^'"]+['"])/);
+  if (!m) return null;
+  return {
+    names: m[1].split(',').map(s => s.trim()).filter(Boolean),
+    from: m[2],
+  };
+}
+
+let fixedFiles = 0;
+let movedImports = 0;
+
+for (const abs of walk(ROOT)) {
+  const rel = path.relative(ROOT, abs).split(path.sep).join('/');
+  if (SKIP.has(rel)) continue;
+  let src = fs.readFileSync(abs, 'utf8');
+  const open = src.match(/<script[^>]*>/);
+  const closeIdx = src.indexOf('</script>');
+  const styleIdx = src.search(/<style/);
+  if (!open || closeIdx === -1) continue;
+  const endRegion = styleIdx === -1 ? src.length : styleIdx;
+  if (endRegion <= closeIdx) continue;
+
+  const after = src.slice(closeIdx + 9, endRegion);
+  const importLines = after.match(/^\s*import\s[^\n]*$/gm);
+  if (!importLines) continue;
+
+  // 从尾部区域删除这些 import 行
+  let newAfter = after;
+  for (const line of importLines) newAfter = newAfter.replace(line + '\n', '').replace(line + '\r\n', '').replace(line, '');
+  const eol = src.includes('\r\n') ? '\r\n' : '\n';
+
+  // 逐个搬回 script 内
+  const openIdx = src.indexOf(open[0]);
+  let scriptBodyStart = openIdx + open[0].length;
+  let scriptBody = src.slice(scriptBodyStart, closeIdx);
+
+  for (const line of importLines) {
+    const parsed = parseNames(line);
+    if (!parsed) continue;
+    const escFrom = parsed.from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+    const existingRe = new RegExp("import\\s*\\{([^}]*)\\}\\s*from\\s*" + escFrom + ';?');
+    const ex = scriptBody.match(existingRe);
+    if (ex) {
+      const merged = [...new Set([...ex[1].split(',').map(s => s.trim()).filter(Boolean), ...parsed.names])];
+      scriptBody = scriptBody.replace(ex[0], 'import { ' + merged.join(', ') + ' } from ' + parsed.from);
+    } else {
+      const lead = (scriptBody.match(/^\r?\n/) || [''])[0];
+      scriptBody = lead + 'import { ' + parsed.names.join(', ') + ' } from ' + parsed.from + eol + scriptBody.slice(lead.length);
+    }
+    movedImports++;
+  }
+
+  const out = src.slice(0, scriptBodyStart) + scriptBody + src.slice(closeIdx, closeIdx + 9) + newAfter + src.slice(endRegion);
+  if (!DRY) fs.writeFileSync(abs, out, 'utf8');
+  fixedFiles++;
+  console.log((DRY ? '[DRY] ' : '') + rel + '  imports:' + importLines.length);
+}
+console.log('文件:', fixedFiles, '搬移 import:', movedImports);

+ 23 - 0
cfc-frontend/scripts/d35-named-exports.js

@@ -0,0 +1,23 @@
+const fs = require('fs');
+const F = 'utils/brand-colors.js';
+let s = fs.readFileSync(F, 'utf8');
+const marker = 'export const primaryPale';
+if (s.includes(marker)) {
+  console.log('already present');
+  process.exit(0);
+}
+const add = [
+  '',
+  '// 具名快捷导出(历史写法:页面按名引入,如 import { body, primary } from ...;与 BrandColors.xxx 等价)',
+  'export const primaryPale = BrandColors.primaryPale',
+  'export const body = BrandColors.body',
+  'export const primary = BrandColors.primary',
+  'export const success = BrandColors.success',
+  'export const white = BrandColors.white',
+  'export const wisdom = BrandColors.wisdom',
+  'export const danger = BrandColors.danger',
+  '',
+].join('\n');
+s = s.replace(/\s*$/, '\n') + add;
+fs.writeFileSync(F, s, 'utf8');
+console.log('appended; len', s.length);

+ 9 - 0
cfc-frontend/utils/brand-colors.js

@@ -160,3 +160,12 @@ export const INDUSTRY_COLORS = {
   SENIOR_LOCAL:       '#65A30D', // 资深土著(lime-600)
   KEY_CITY:           '#4D7C0F', // 北上广等(lime-700)
 }
+
+// 具名快捷导出(历史写法:页面按名引入,如 import { body, primary } from ...;与 BrandColors.xxx 等价)
+export const primaryPale = BrandColors.primaryPale
+export const body = BrandColors.body
+export const primary = BrandColors.primary
+export const success = BrandColors.success
+export const white = BrandColors.white
+export const wisdom = BrandColors.wisdom
+export const danger = BrandColors.danger