Browse Source

refactor(beautify): D40 script 段重复色值收编 BrandColors (hex 387->349)

- utils/brand-colors.js 新增 30 个键:Tailwind stone/slate/gray 中性阶、amber50/
  emerald50/cyan500/indigo600/indigo50/pink600/pink50/orange300 彩色档、
  tint*Soft 浅底、elementDanger 等
- d31-script-hex-harvest.js MAP 扩充 36 条(含 #444/#999/#FFF 简写与等值长写)
- 23 文件 75 处 script 段色字面量改 BrandColors.*(仅整段字符串即 hex 的安全场景)
- 全量自检 383 文件模板/样式/脚本 0 失败;brandcolor 完整性四项 0;
  反模式审计 ERROR 0;硬编码色 387 -> 349
liaoxg 5 days ago
parent
commit
e917abf274

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

@@ -61,17 +61,17 @@ import config from '@/config.js'
 
 var DIMENSION_COLORS = {
   body:    { bg: 'linear-gradient(180deg, #FF8C42 0%, #E8762A 100%)', text: '#FFF5EE' },
-  mind:    { bg: 'linear-gradient(180deg, #FF6B9D 0%, #E84A7F 100%)', text: '#FFF0F5' },
-  wisdom:  { bg: 'linear-gradient(180deg, #6366F1 0%, #4F46E5 100%)', text: '#EEF2FF' },
-  action:  { bg: 'linear-gradient(180deg, #10B981 0%, #059669 100%)', text: '#ECFDF5' },
-  wealth:  { bg: 'linear-gradient(180deg, #F59E0B 0%, #D97706 100%)', text: '#FFFBEB' }
+  mind:    { bg: 'linear-gradient(180deg, #FF6B9D 0%, #E84A7F 100%)', text: BrandColors.mindTint },
+  wisdom:  { bg: 'linear-gradient(180deg, #6366F1 0%, #4F46E5 100%)', text: BrandColors.indigo50 },
+  action:  { bg: 'linear-gradient(180deg, #10B981 0%, #059669 100%)', text: BrandColors.emerald50 },
+  wealth:  { bg: 'linear-gradient(180deg, #F59E0B 0%, #D97706 100%)', text: BrandColors.amber50 }
 }
 
 // 回退渐变(用于无维度分类的文章)
 var FALLBACK_GRADIENTS = [
   { bg: 'linear-gradient(180deg, #8B5CF6 0%, #7C3AED 100%)', text: '#F5F3FF' },
   { bg: 'linear-gradient(180deg, #06B6D4 0%, #0891B2 100%)', text: '#ECFEFF' },
-  { bg: 'linear-gradient(180deg, #EC4899 0%, #DB2777 100%)', text: '#FDF2F8' },
+  { bg: 'linear-gradient(180deg, #EC4899 0%, #DB2777 100%)', text: BrandColors.pink50 },
   { bg: 'linear-gradient(180deg, #14B8A6 0%, #0D9488 100%)', text: '#F0FDFA' },
   { bg: 'linear-gradient(180deg, #F97316 0%, #EA580C 100%)', text: BrandColors.primaryPale }
 ]

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

@@ -131,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, BrandColors.slate800, BrandColors.white]
     }
   },
   methods: {
@@ -187,10 +187,10 @@ export default {
       }
       var map = {
         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' },
-        wealth: { main: BrandColors.wealth, dark: '#D97706', light: '#FFFBEB' }
+        mind: { main: BrandColors.mind, dark: BrandColors.pink600, light: BrandColors.pink50 },
+        wisdom: { main: BrandColors.wisdom, dark: BrandColors.indigo600, light: BrandColors.indigo50 },
+        action: { main: BrandColors.success, dark: '#059669', light: BrandColors.emerald50 },
+        wealth: { main: BrandColors.wealth, dark: '#D97706', light: BrandColors.amber50 }
       }
       return map[this.dimensionCode] || { main: BrandColors.primary, dark: BrandColors.orangeDeep, light: BrandColors.primaryPale }
     },
@@ -206,7 +206,7 @@ export default {
       // 极简模板:深色背景+白色卡片(管理端模板的 darkColor 作为默认底色)
       if (template === 'minimal') {
         var tpl = this.getActiveTemplate()
-        var dark = tpl ? (bgColor || colors.dark) : (bgColor || '#1E293B')
+        var dark = tpl ? (bgColor || colors.dark) : (bgColor || BrandColors.slate800)
         return { template: 'minimal', bgColor: dark, main: colors.main, dark: colors.dark, light: colors.light }
       }
       // 卡片模板:浅色背景+彩色顶栏
@@ -408,7 +408,7 @@ export default {
       ctx.fill()
 
       // 顶部:左侧标题,右侧综合分
-      ctx.setFillStyle('#78716C')
+      ctx.setFillStyle(BrandColors.stone500)
       ctx.setFontSize(this._fs(13))
       ctx.setTextAlign('left')
       ctx.setTextBaseline('top')
@@ -420,12 +420,12 @@ export default {
         ctx.setFontSize(this._fs(30))
         ctx.setTextAlign('right')
         ctx.fillText(String(data.overall), x + w - 28, y + 8)
-        ctx.setFillStyle('#78716C')
+        ctx.setFillStyle(BrandColors.stone500)
         ctx.setFontSize(this._fs(13))
         ctx.fillText('分', x + w - 16, y + 28)
       }
 
-      ctx.setStrokeStyle('#F5F5F4')
+      ctx.setStrokeStyle(BrandColors.stone100)
       ctx.setLineWidth(1)
       ctx.beginPath()
       ctx.moveTo(x + 16, y + 54)
@@ -453,7 +453,7 @@ export default {
         ctx.setTextBaseline('middle')
         ctx.fillText(d.label || '', cx, y + 95)
 
-        ctx.setFillStyle('#1C1917')
+        ctx.setFillStyle(BrandColors.stone900)
         ctx.setFontSize(this._fs(18))
         ctx.setTextBaseline('top')
         ctx.fillText(String(score), cx, y + 120)
@@ -462,7 +462,7 @@ export default {
         var barH = 4
         var barX = cx - barW / 2
         var barY = y + 148
-        ctx.setFillStyle('#F5F5F4')
+        ctx.setFillStyle(BrandColors.stone100)
         this._roundRect(ctx, barX, barY, barW, barH, 2)
         ctx.fill()
         if (score > 0) {
@@ -472,7 +472,7 @@ export default {
         }
       }
 
-      ctx.setFillStyle('#A8A29E')
+      ctx.setFillStyle(BrandColors.stone400)
       ctx.setFontSize(this._fs(11))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -524,7 +524,7 @@ export default {
 
       // 标题(2行截断)
       var titleY = labelY + 22
-      ctx.setFillStyle('#1C1917')
+      ctx.setFillStyle(BrandColors.stone900)
       ctx.setFontSize(this._fs(18))
       ctx.setTextAlign('left')
       ctx.setTextBaseline('top')
@@ -543,7 +543,7 @@ export default {
       // 简介(1-2行灰字;空则跳过)
       var summaryY = (this.priceText ? priceY + 34 : priceY)
       if (this.summary) {
-        ctx.setFillStyle('#78716C')
+        ctx.setFillStyle(BrandColors.stone500)
         ctx.setFontSize(this._fs(13))
         ctx.setTextAlign('left')
         ctx.setTextBaseline('top')
@@ -552,7 +552,7 @@ export default {
 
       // 邀请语(二维码上方)
       var inviteY = (this.summary ? summaryY + 48 : summaryY)
-      ctx.setFillStyle('#A8A29E')
+      ctx.setFillStyle(BrandColors.stone400)
       ctx.setFontSize(this._fs(13))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -584,7 +584,7 @@ export default {
             self._roundRect(ctx, qrX - 10, qrY - 10, qrSize + 20, qrSize + 20, 8)
             ctx.fill()
 
-            ctx.setStrokeStyle('#E7E5E4')
+            ctx.setStrokeStyle(BrandColors.stone200)
             ctx.setLineWidth(0.5)
             self._roundRect(ctx, qrX - 10, qrY - 10, qrSize + 20, qrSize + 20, 8)
             ctx.stroke()
@@ -642,12 +642,12 @@ export default {
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.fill()
 
-      ctx.setStrokeStyle('#E7E5E4')
+      ctx.setStrokeStyle(BrandColors.stone200)
       ctx.setLineWidth(0.5)
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.stroke()
 
-      ctx.setFillStyle('#A8A29E')
+      ctx.setFillStyle(BrandColors.stone400)
       ctx.setFontSize(this._fs(16))
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')

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

@@ -496,7 +496,7 @@ simulationTick: function() {
           // 无数据: 默认黑色实线 1px
           ctx.lineWidth = 1
           ctx.setLineDash([])
-          ctx.strokeStyle = '#000000'
+          ctx.strokeStyle = BrandColors.black
         } else {
           // 连线粗细 = 亲密度 (1-6px, 越高越粗)
           var intVal = intimacy != null ? intimacy : 50
@@ -621,7 +621,7 @@ simulationTick: function() {
         }
 
         // 第一字符 (昵称首字)
-        ctx.fillStyle = node.isSelf ? this.themeColor : '#4A5568'
+        ctx.fillStyle = node.isSelf ? this.themeColor : BrandColors.gray700
         ctx.font = 'bold ' + (r * 0.9) + 'px sans-serif'
         ctx.textAlign = 'center'
         ctx.textBaseline = 'middle'
@@ -657,7 +657,7 @@ simulationTick: function() {
           // 无数据: 默认黑色实线 1px
           ctx.setLineWidth(1)
           ctx.setLineDash([])
-          ctx.setStrokeStyle('#000000')
+          ctx.setStrokeStyle(BrandColors.black)
         } else {
           // 连线粗细 = 亲密度
           var intVal = intimacy != null ? intimacy : 50
@@ -735,7 +735,7 @@ simulationTick: function() {
           ctx.fill()
         }
 
-        ctx.setFillStyle(node.isSelf ? this.themeColor : '#4A5568')
+        ctx.setFillStyle(node.isSelf ? this.themeColor : BrandColors.gray700)
         ctx.setFontSize(Math.max(10, Math.round(r * 0.9)))
         ctx.setTextAlign('center')
         ctx.setTextBaseline('middle')

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

@@ -71,12 +71,12 @@ export default {
     /** 网格颜色(可选,默认浅灰) */
     gridColor: {
       type: String,
-      default: '#E2E8F0'
+      default: BrandColors.slate200
     },
     /** 标签颜色(可选,默认深灰) */
     labelColor: {
       type: String,
-      default: '#1E293B'
+      default: BrandColors.slate800
     },
     /** 图表标题(显示在中心) */
     childName: {
@@ -103,12 +103,12 @@ export default {
     /** 平均值填充颜色(可选,默认灰色) */
     avgFillColor: {
       type: String,
-      default: '#CBD5E1'
+      default: BrandColors.slate300
     },
     /** 平均值网格颜色(可选,默认浅灰) */
     avgGridColor: {
       type: String,
-      default: '#E2E8F0'
+      default: BrandColors.slate200
     },
     /** 平均值标签颜色(可选,默认浅灰) */
     avgLabelColor: {
@@ -367,7 +367,7 @@ export default {
 
       // 2. 绘制家庭平均分(灰色虚线)
       if (this.avgScores && this.avgScores.length >= n && n >= 3) {
-        this._drawAvgScoreArea(ctx, cx, cy, outerR, angles, n, this.avgFillColor || '#CBD5E1')
+        this._drawAvgScoreArea(ctx, cx, cy, outerR, angles, n, this.avgFillColor || BrandColors.slate300)
       }
 
       // 3. 绘制人群位置(蓝色虚线)
@@ -621,7 +621,7 @@ export default {
       var h = this.canvasHeight
 
       ctx.font = 'bold 13px -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif'
-      ctx.fillStyle = this.labelColor || '#1E293B'
+      ctx.fillStyle = this.labelColor || BrandColors.slate800
 
       for (var i = 0; i < n; i++) {
         var dim = dims[i]

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

@@ -172,7 +172,7 @@ export default {
 
       ctx.clearRect(0, 0, w, h)
       // 网格(4 条横线 + 2 条纵线)
-      ctx.strokeStyle = '#EEF2F7'
+      ctx.strokeStyle = BrandColors.slateGhost
       ctx.lineWidth = 1
       for (var gi = 0; gi <= 3; gi++) {
         var gy = padT + plotH * (gi / 3)
@@ -212,7 +212,7 @@ export default {
           ctx.fillStyle = color
           ctx.beginPath(); ctx.arc(x, y, 3.5, 0, 2 * Math.PI); ctx.fill()
           if (self.showValues) {
-            ctx.fillStyle = '#475569'
+            ctx.fillStyle = BrandColors.slate600
             ctx.font = '10px sans-serif'
             ctx.textAlign = 'center'
             ctx.fillText(self._fmtValue(p), x, y - 8)

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

@@ -103,7 +103,7 @@ export default {
       // 节点颜色:技能统一金色
       skillColor: BrandColors.wealth,
       // 边颜色
-      edgeColor: '#CBD5E1'
+      edgeColor: BrandColors.slate300
     }
   },
   computed: {
@@ -319,7 +319,7 @@ export default {
           labelX += perpX * 12
           labelY += perpY * 12
           ctx.font = '11px PingFang SC, sans-serif'
-          ctx.fillStyle = '#475569'
+          ctx.fillStyle = BrandColors.slate600
           ctx.textAlign = 'center'
           ctx.textBaseline = 'middle'
           ctx.fillText(label, labelX, labelY)

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

@@ -367,7 +367,7 @@ export default {
         var lx = node.x + (dx / dist) * 36
         var ly = node.y + (dy / dist) * 20
         ctx.font = '11px PingFang SC, sans-serif'
-        ctx.fillStyle = '#64748B'
+        ctx.fillStyle = BrandColors.slate500
         ctx.textAlign = 'center'
         ctx.textBaseline = 'middle'
         var label = ''
@@ -522,14 +522,14 @@ export default {
       return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')'
     },
     _getTypeColor: function(type) {
-      if (!type) return '#64748B'
+      if (!type) return BrandColors.slate500
       // 返回第一个类型对应的颜色
       var list = []
       if (type & 1) list.push('金额大')
       if (type & 2) list.push('频次高')
       if (type & 4) list.push('新成交')
-      if (list.length === 0) return '#64748B'
-      return this.effectColors[list[0]] || '#64748B'
+      if (list.length === 0) return BrandColors.slate500
+      return this.effectColors[list[0]] || BrandColors.slate500
     },
     formatDate: function(dateStr) {
       if (!dateStr) return ''

+ 2 - 2
cfc-frontend/pages/action-detail/index.vue

@@ -472,7 +472,7 @@ export default {
         { key: 'actionParental', label: '父母关系', color: BrandColors.wealth, desc: '与长辈的相处模式' },
         { key: 'actionLeadership', label: '领导关系', color: BrandColors.wisdom, desc: '职场上下级沟通能力' },
         { key: 'actionSociality', label: '社会性', color: BrandColors.body, desc: '社会交往与参与度' },
-        { key: 'actionInterpersonal', label: '人际韧性', color: '#06B6D4', desc: '应对人际关系挫折的能力' }
+        { key: 'actionInterpersonal', label: '人际韧性', color: BrandColors.cyan500, desc: '应对人际关系挫折的能力' }
       ]
       var childDims = [
         { key: 'actionChildParentChild', label: '亲子关系', color: BrandColors.success, desc: '与父母的互动质量' },
@@ -480,7 +480,7 @@ export default {
         { key: 'actionRelative', label: '亲属关系', color: BrandColors.wealth, desc: '与亲戚的交往频率' },
         { key: 'actionTeacherStudent', label: '师生关系', color: BrandColors.wisdom, desc: '与老师的沟通情况' },
         { key: 'actionChildSociality', label: '社会性', color: BrandColors.body, desc: '学校与社会参与度' },
-        { key: 'actionChildInterpersonal', label: '人际韧性', color: '#06B6D4', desc: '应对社交困难的能力' }
+        { key: 'actionChildInterpersonal', label: '人际韧性', color: BrandColors.cyan500, desc: '应对社交困难的能力' }
       ]
       var dims = isParent ? parentDims : childDims
       var result = { overall: 0, tierLabel: '', summary: '', dims: [], tip: '' }

+ 3 - 2
cfc-frontend/pages/activity/create.vue

@@ -134,8 +134,8 @@
           @click="selectPosterTemplate(tpl)"
         >
           <view class="tpl-colors">
-            <view class="tpl-dot tpl-main" :style="{ background: tpl.mainColor || '#F97316' }"></view>
-            <view class="tpl-dot tpl-dark" :style="{ background: tpl.darkColor || '#EA580C' }"></view>
+            <view class="tpl-dot tpl-main" :style="{ background: tpl.mainColor || BrandColors.primary }"></view>
+            <view class="tpl-dot tpl-dark" :style="{ background: tpl.darkColor || BrandColors.orangeDeep }"></view>
             <view class="tpl-dot tpl-light" :style="{ background: tpl.lightColor || '#FFF7ED' }"></view>
           </view>
           <text class="tpl-name">{{ tpl.name }}</text>
@@ -170,6 +170,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../utils/brand-colors.js'
 import { adminCreateActivity, adminUpdateActivity, adminPublishActivity, submitActivityForReview, getActivityDetail, getPosterTemplates } from '../../utils/api.js'
 import config from '../../config.js'
 import { parseDate } from '../../utils/format.js'

+ 2 - 2
cfc-frontend/pages/body-detail/dimension-detail.vue

@@ -244,7 +244,7 @@ export default {
         ctx.stroke()
         // Label
         var labelVal = 100 - i * 25
-        ctx.setFillStyle('#999')
+        ctx.setFillStyle(BrandColors.textMuted)
         ctx.setFontSize(20)
         ctx.fillText(labelVal + '', 10, y + 6)
       }
@@ -300,7 +300,7 @@ export default {
       if (points.length > 0) {
         for (var n = 0; n < points.length; n++) {
           var dateStr = this.formatShortDate(points[n].date)
-          ctx.setFillStyle('#999')
+          ctx.setFillStyle(BrandColors.textMuted)
           ctx.setFontSize(18)
           ctx.setTextAlign('center')
           ctx.fillText(dateStr, points[n].x, h - 8)

+ 5 - 4
cfc-frontend/pages/discover/components/CircleCard.vue

@@ -16,6 +16,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../../utils/brand-colors.js'
 export default {
   name: 'CircleCard',
   props: {
@@ -55,11 +56,11 @@ export default {
     iconBg: function(type) {
       var map = {
         activity: '#E0F7FA',
-        ability: '#F3E5F5',
-        health: '#FFF3E0',
-        product: '#E8F5E9',
+        ability: BrandColors.tintPurpleSoft,
+        health: BrandColors.tintOrangeSoft,
+        product: BrandColors.tintGreenSoft,
         provider: '#E3F2FD',
-        topic: '#FCE4EC',
+        topic: BrandColors.tintPinkSoft,
         hobby: '#FFF8E1'
       }
       return map[type] || '#F5F5F5'

+ 1 - 1
cfc-frontend/pages/growth/profile/index.vue

@@ -262,7 +262,7 @@ export default {
     },
     dimColor(dim) {
       var m = { body: BrandColors.body, wisdom: BrandColors.wisdom, mind: BrandColors.mind, action: BrandColors.success, wealth: BrandColors.wealth }
-      return m[dim] || '#999'
+      return m[dim] || BrandColors.textMuted
     },
     domainLabel(d) {
       var m = { sleep: '睡眠', attention: '注意力', emotion: '情绪' }

+ 1 - 1
cfc-frontend/pages/guide/packages/share.vue

@@ -118,7 +118,7 @@ export default {
       ctx.fillText('分享码: ' + this.shareCode, 30, 580)
       
       // 提示文字
-      ctx.setFillStyle('#999999')
+      ctx.setFillStyle(BrandColors.textMuted)
       ctx.setFontSize(20)
       ctx.fillText('微信扫码或输入分享码查看任务模板', 30, 640)
       

+ 2 - 2
cfc-frontend/pages/health/components/TrendChart.vue

@@ -172,7 +172,7 @@ export default {
 
       ctx.clearRect(0, 0, w, h)
       // 网格(4 条横线 + 2 条纵线)
-      ctx.strokeStyle = '#EEF2F7'
+      ctx.strokeStyle = BrandColors.slateGhost
       ctx.lineWidth = 1
       for (var gi = 0; gi <= 3; gi++) {
         var gy = padT + plotH * (gi / 3)
@@ -212,7 +212,7 @@ export default {
           ctx.fillStyle = color
           ctx.beginPath(); ctx.arc(x, y, 3.5, 0, 2 * Math.PI); ctx.fill()
           if (self.showValues) {
-            ctx.fillStyle = '#475569'
+            ctx.fillStyle = BrandColors.slate600
             ctx.font = '10px sans-serif'
             ctx.textAlign = 'center'
             ctx.fillText(self._fmtValue(p), x, y - 8)

+ 2 - 1
cfc-frontend/pages/health/report-blocks-renderer.vue

@@ -6,7 +6,7 @@
         <view class="block-title">{{ block.title }}</view>
         <view class="score-grid">
           <view class="score-item" v-for="(item, si) in block.items" :key="si">
-            <view class="score-circle" :style="'border-color:' + (item.color || '#F97316')">
+            <view class="score-circle" :style="'border-color:' + (item.color || BrandColors.primary)">
               <text class="score-value">{{ item.value }}</text>
             </view>
             <text class="score-label">{{ item.label }}</text>
@@ -77,6 +77,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../utils/brand-colors.js'
 export default {
   name: 'ReportBlocksRenderer',
   props: {

+ 3 - 2
cfc-frontend/pages/health/report-list.vue

@@ -159,6 +159,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../utils/brand-colors.js'
 import { parseDate } from '../../utils/format.js'
 import { getReportList, deleteReport, getFamilyMemberList, getCollectingReports, reassignReport, getReportTransferList, approveReportTransfer, denyReportTransfer } from '../../utils/api.js'
 
@@ -405,7 +406,7 @@ export default {
       uni.showModal({
         title: '同意转移',
         content: '同意后该报告将转入对方家庭,您的家庭将不再显示此报告。是否同意?',
-        confirmColor: '#F56C6C',
+        confirmColor: BrandColors.elementDanger,
         success: function(res) {
           if (!res.confirm) return
           approveReportTransfer(item.id).then(function(r) {
@@ -530,7 +531,7 @@ export default {
       uni.showModal({
         title: '删除报告',
         content: '确定删除该健康报告吗?删除后不可恢复。',
-        confirmColor: '#F56C6C',
+        confirmColor: BrandColors.elementDanger,
         success: function(res) {
           if (!res.confirm) return
           self.doDelete(item)

+ 1 - 1
cfc-frontend/pages/mind-detail/articles.vue

@@ -92,7 +92,7 @@ import { getArticleCategories, getArticleList } from '../../utils/api.js'
 import config from '@/config.js'
 
 var dimensionConfig = {
-  all:   { label: '全部', color: '#64748B', theme: 'mind-wisdom', tagline: '探索知识,滋养成长', quote: '学而时习之,不亦说乎' },
+  all:   { label: '全部', color: BrandColors.slate500, theme: 'mind-wisdom', tagline: '探索知识,滋养成长', quote: '学而时习之,不亦说乎' },
   body:  { label: '身', color: BrandColors.body, theme: 'health',       tagline: '主动健康,从知识开始', quote: '健康是人生的第一财富' },
   mind:  { label: '心', color: BrandColors.mind, theme: 'mind-wisdom',  tagline: '探索内心世界,培养健康心智', quote: '知己知彼,百战不殆' },
   wisdom: { label: '智', color: BrandColors.wisdom, theme: 'wisdom',       tagline: '聪明学习,快乐成长', quote: '学而不思则罔,思而不学则殆' },

+ 2 - 1
cfc-frontend/pages/mind-detail/innate-trajectory.vue

@@ -52,6 +52,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../utils/brand-colors.js'
 import { getInnateTrajectory } from '../../utils/api'
 export default {
   data() {
@@ -70,7 +71,7 @@ export default {
       return !!this.trajectory && !!this.trajectory.innateDimensionScores
     },
     growthColor() {
-      if (!this.trajectory || !this.trajectory.innateVsCurrent) return '#999'
+      if (!this.trajectory || !this.trajectory.innateVsCurrent) return BrandColors.textMuted
       var g = this.trajectory.innateVsCurrent.growth || '0'
       if (g.indexOf('-') === 0) return '#f56c6c'
       return '#07c160'

+ 1 - 1
cfc-frontend/pages/mind-detail/traditional-mirror.vue

@@ -74,7 +74,7 @@
           <text class="section-title">生命灵数</text>
         </view>
         <view class="numsoul-display">
-          <view class="numsoul-number" :style="{ background: numSoulData.colorHex || '#FF6B9D' }">
+          <view class="numsoul-number" :style="{ background: numSoulData.colorHex || BrandColors.mind }">
             <text class="numsoul-num">{{ lifeNumber }}</text>
           </view>
           <view class="numsoul-info">

+ 2 - 2
cfc-frontend/pages/mind-detail/training.vue

@@ -123,7 +123,7 @@ var DIMENSION_MAP = {
     name: '记忆训练',
     icon: '\u{1F9E0}',
     color: BrandColors.success,
-    lightColor: '#ECFDF5',
+    lightColor: BrandColors.emerald50,
     desc: '通过数字记忆、序列回忆等练习提升记忆力',
     tip: '记忆力可以通过科学训练显著提升。联想记忆法和间隔重复是最有效的两种方法。',
     games: [
@@ -160,7 +160,7 @@ var DIMENSION_MAP = {
     name: '加工速度训练',
     icon: '\u26A1',
     color: '#FFD700',
-    lightColor: '#FFFBEB',
+    lightColor: BrandColors.amber50,
     desc: '通过快速反应、速度测试等练习提升加工速度',
     tip: '加工速度影响学习和反应效率。速算、速读等限时练习是提升加工速度的有效方法。',
     games: [

+ 6 - 6
cfc-frontend/pages/promotion/components/SharePoster.vue

@@ -296,7 +296,7 @@ export default {
       // --- 邀请标题:XXX邀请你关注家庭健康 ---
       var name = this._shortName(this.nickname, 8)
       var headlineY = avatarY + 78
-      ctx.setFillStyle('#1C1917')
+      ctx.setFillStyle(BrandColors.stone900)
       ctx.setFontSize(21)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -318,12 +318,12 @@ export default {
       ctx.fillText(this.familyName ? this.familyName + ' · 家庭健康俱乐部' : '浠艾福 · 家庭健康俱乐部', centerX, brandY)
 
       var dimY = brandY + 24
-      ctx.setFillStyle('#78716C')
+      ctx.setFillStyle(BrandColors.stone500)
       ctx.setFontSize(13)
       ctx.fillText('身体 · 心理 · 智慧 · 行动 · 财富', centerX, dimY)
 
       var descY = dimY + 22
-      ctx.setFillStyle('#A8A29E')
+      ctx.setFillStyle(BrandColors.stone400)
       ctx.setFontSize(13)
       ctx.fillText('一家专注全家健康的成长平台', centerX, descY)
 
@@ -355,7 +355,7 @@ export default {
             ctx.fill()
 
             // Subtle border
-            ctx.setStrokeStyle('#E7E5E4')
+            ctx.setStrokeStyle(BrandColors.stone200)
             ctx.setLineWidth(0.5)
             self._roundRect(ctx, qrX - 10, qrY - 10, qrSize + 20, qrSize + 20, 8)
             ctx.stroke()
@@ -382,12 +382,12 @@ export default {
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.fill()
 
-      ctx.setStrokeStyle('#E7E5E4')
+      ctx.setStrokeStyle(BrandColors.stone200)
       ctx.setLineWidth(0.5)
       this._roundRect(ctx, x - 10, y - 10, size + 20, size + 20, 8)
       ctx.stroke()
 
-      ctx.setFillStyle('#A8A29E')
+      ctx.setFillStyle(BrandColors.stone400)
       ctx.setFontSize(14)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')

+ 3 - 3
cfc-frontend/pages/promotion/team.vue

@@ -215,7 +215,7 @@ export default {
       var chartHeight = canvasHeight - padding * 2
 
       // 绘制坐标轴
-      ctx.setStrokeStyle('#C0C0C0')
+      ctx.setStrokeStyle(BrandColors.silver)
       ctx.setLineWidth(1)
       ctx.beginPath()
       ctx.moveTo(padding, padding)
@@ -301,7 +301,7 @@ export default {
       var chartHeight = canvasHeight - padding * 2
 
       // 绘制坐标轴
-      ctx.setStrokeStyle('#C0C0C0')
+      ctx.setStrokeStyle(BrandColors.silver)
       ctx.setLineWidth(1)
       ctx.beginPath()
       ctx.moveTo(padding, padding)
@@ -387,7 +387,7 @@ export default {
       var chartHeight = canvasHeight - padding * 2
 
       // 绘制坐标轴
-      ctx.setStrokeStyle('#C0C0C0')
+      ctx.setStrokeStyle(BrandColors.silver)
       ctx.setLineWidth(1)
       ctx.beginPath()
       ctx.moveTo(padding, padding)

+ 2 - 1
cfc-frontend/pages/wealth/components/WealthEnergyRing.vue

@@ -13,7 +13,7 @@
           :stroke-dasharray="circumference" :stroke-dashoffset="progressOffset" />
         <defs>
           <linearGradient id="ringGradient" x1="0%" y1="0%" x2="100%" y2="0%">
-            <stop offset="0%" stop-color="#F59E0B" />
+            <stop offset="0%" stop-color=BrandColors.wealth />
             <stop offset="100%" stop-color="#FBBF24" />
           </linearGradient>
         </defs>
@@ -36,6 +36,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../../utils/brand-colors.js'
 export default {
   name: 'WealthEnergyRing',
   props: {

+ 36 - 0
cfc-frontend/scripts/d31-script-hex-harvest.js

@@ -33,6 +33,42 @@ const MAP = {
   '#4CAF50': 'matGreen',
   '#FF6B35': 'mindAccent',
   '#8D6E63': 'brownWarm',
+  // ---- D40:跨文件重复的 script 色值(≥2 处)----
+  '#A8A29E': 'stone400',
+  '#64748B': 'slate500',
+  '#444444': 'textDeep',
+  '#444': 'textDeep',
+  '#FFFBEB': 'amber50',
+  '#1E293B': 'slate800',
+  '#78716C': 'stone500',
+  '#E7E5E4': 'stone200',
+  '#999999': 'textMuted',
+  '#999': 'textMuted',
+  '#ECFDF5': 'emerald50',
+  '#06B6D4': 'cyan500',
+  '#1C1917': 'stone900',
+  '#CBD5E1': 'slate300',
+  '#475569': 'slate600',
+  '#F56C6C': 'elementDanger',
+  '#C0C0C0': 'silver',
+  '#FFF0F5': 'mindTint',
+  '#4F46E5': 'indigo600',
+  '#EEF2FF': 'indigo50',
+  '#DB2777': 'pink600',
+  '#FDF2F8': 'pink50',
+  '#F5F5F4': 'stone100',
+  '#000000': 'black',
+  '#4A5568': 'gray700',
+  '#FFB74D': 'orange300',
+  '#E2E8F0': 'slate200',
+  '#EEF2F7': 'slateGhost',
+  '#667EEA': 'indigoPeriwinkle',
+  '#FFF': 'white',
+  '#FFFFFF': 'white',
+  '#F3E5F5': 'tintPurpleSoft',
+  '#FFF3E0': 'tintOrangeSoft',
+  '#E8F5E9': 'tintGreenSoft',
+  '#FCE4EC': 'tintPinkSoft',
 };
 
 const bcSrc = fs.readFileSync(path.join(ROOT, 'utils/brand-colors.js'), 'utf8');

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

@@ -127,6 +127,44 @@ export const BrandColors = {
   dimAction: '#10B981',
   dimBody: '#FF8C42',
   dimWealth: '#F59E0B',
+
+  // Tailwind 中性色阶(组件脚本内散落色值收编:stone / slate / gray)
+  stone900: '#1C1917',
+  stone500: '#78716C',
+  stone400: '#A8A29E',
+  stone200: '#E7E5E4',
+  stone100: '#F5F5F4',
+  slate800: '#1E293B',
+  slate600: '#475569',
+  slate500: '#64748B',
+  slate300: '#CBD5E1',
+  slate200: '#E2E8F0',
+  slateGhost: '#EEF2F7',
+  gray700: '#4A5568',
+  silver: '#C0C0C0',
+  black: '#000000',
+  textDeep: '#444444',
+
+  // Tailwind 彩色档(琥珀 / 翠绿 / 青 / 靛 / 粉 / 橙)
+  amber50: '#FFFBEB',
+  emerald50: '#ECFDF5',
+  cyan500: '#06B6D4',
+  indigo600: '#4F46E5',
+  indigo50: '#EEF2FF',
+  indigoPeriwinkle: '#667EEA',
+  pink600: '#DB2777',
+  pink50: '#FDF2F8',
+  orange300: '#FFB74D',
+
+  // 浅底 tint(发现页圈层 / 分享海报 / 量表卡)
+  tintPurpleSoft: '#F3E5F5',
+  tintOrangeSoft: '#FFF3E0',
+  tintGreenSoft: '#E8F5E9',
+  tintPinkSoft: '#FCE4EC',
+  mindTint: '#FFF0F5',
+
+  // Element UI 语义色
+  elementDanger: '#F56C6C',
 }
 
 // 向后兼容导出(避免 import 路径散乱)