Kaynağa Gözat

refactor(beautify): D11 relation-detail 关系详情页清理 (debt 81->9)

- script 角色/维度/分数色板全收编 BrandColors.*(member1/2Color, dimMap, getScoreColor)
- canvas 连线 #E5E7EB->BrandColors.gray200、#F97316->BrandColors.primary
- style 全局映射:#D1D5DB->\-border-strong, #FFF8F0->\-body-tint
- #7C2D12 收编局部 \-rel-brown(无全局令牌)
- brand-colors.js 补 gray200
- hex 27->0(palette 声明除外);P1 13->12
liaoxg 6 gün önce
ebeveyn
işleme
bf2ff6aaf8

+ 31 - 27
cfc-frontend/pages/tianpan/relation-detail.vue

@@ -109,6 +109,7 @@
 
 <script>
 import { mapActions } from 'vuex'
+import { BrandColors } from '../../utils/brand-colors.js'
 
 export default {
   data: function() {
@@ -124,41 +125,41 @@ export default {
   computed: {
     member1Color: function() {
       if (!this.relation || !this.relation.fromMemberRole) {
-        return '#6B7280'
+        return BrandColors.textSlate
       }
       var colorMap = {
-        'parent': '#F97316',
-        'child': '#3B82F6',
-        'teacher': '#8B5CF6'
+        'parent': BrandColors.primary,
+        'child': BrandColors.infoBlue,
+        'teacher': BrandColors.violet
       }
-      return colorMap[this.relation.fromMemberRole] || '#6B7280'
+      return colorMap[this.relation.fromMemberRole] || BrandColors.textSlate
     },
     member2Color: function() {
       if (!this.relation || !this.relation.toMemberRole) {
-        return '#6B7280'
+        return BrandColors.textSlate
       }
       var colorMap = {
-        'parent': '#F97316',
-        'child': '#3B82F6',
-        'teacher': '#8B5CF6'
+        'parent': BrandColors.primary,
+        'child': BrandColors.infoBlue,
+        'teacher': BrandColors.violet
       }
-      return colorMap[this.relation.toMemberRole] || '#6B7280'
+      return colorMap[this.relation.toMemberRole] || BrandColors.textSlate
     },
     dimensions: function() {
       if (!this.relation || !this.relation.dimensions) {
         return []
       }
       var dimMap = {
-        'communication': { label: '沟通', description: '沟通频率与质量', color: '#10B981' },
-        'trust': { label: '信任', description: '相互信任程度', color: '#3B82F6' },
-        'understanding': { label: '理解', description: '相互理解程度', color: '#8B5CF6' },
-        'support': { label: '支持', description: '相互支持力度', color: '#F59E0B' },
-        'harmony': { label: '和谐', description: '关系和谐度', color: '#F97316' }
+        'communication': { label: '沟通', description: '沟通频率与质量', color: BrandColors.success },
+        'trust': { label: '信任', description: '相互信任程度', color: BrandColors.infoBlue },
+        'understanding': { label: '理解', description: '相互理解程度', color: BrandColors.violet },
+        'support': { label: '支持', description: '相互支持力度', color: BrandColors.wealth },
+        'harmony': { label: '和谐', description: '关系和谐度', color: BrandColors.primary }
       }
       var result = []
       for (var key in this.relation.dimensions) {
         var value = this.relation.dimensions[key]
-        var info = dimMap[key] || { label: key, description: '', color: '#6B7280' }
+        var info = dimMap[key] || { label: key, description: '', color: BrandColors.textSlate }
         result.push({
           type: key,
           label: info.label,
@@ -245,7 +246,7 @@ export default {
       // 绘制背景圆
       ctx.beginPath()
       ctx.arc(cx, cy, r, 0, Math.PI * 2)
-      ctx.strokeStyle = '#E5E7EB'
+      ctx.strokeStyle = BrandColors.gray200
       ctx.lineWidth = 20
       ctx.stroke()
       
@@ -297,7 +298,7 @@ export default {
       ctx.moveTo(padding, padding)
       ctx.lineTo(padding, h - padding)
       ctx.lineTo(w - padding, h - padding)
-      ctx.strokeStyle = '#E5E7EB'
+      ctx.strokeStyle = BrandColors.gray200
       ctx.lineWidth = 1
       ctx.stroke()
       
@@ -321,7 +322,7 @@ export default {
           ctx.lineTo(x, y)
         }
       }
-      ctx.strokeStyle = '#F97316'
+      ctx.strokeStyle = BrandColors.primary
       ctx.lineWidth = 2
       ctx.stroke()
       
@@ -333,21 +334,21 @@ export default {
         
         ctx.beginPath()
         ctx.arc(x2, y2, 4, 0, Math.PI * 2)
-        ctx.fillStyle = '#F97316'
+        ctx.fillStyle = BrandColors.primary
         ctx.fill()
       }
     },
 
     getScoreColor: function(score) {
       if (!score) {
-        return '#6B7280'
+        return BrandColors.textSlate
       }
       if (score >= 80) {
-        return '#10B981'
+        return BrandColors.success
       } else if (score >= 60) {
-        return '#F59E0B'
+        return BrandColors.wealth
       } else {
-        return '#EF4444'
+        return BrandColors.danger
       }
     },
 
@@ -410,6 +411,9 @@ export default {
 </script>
 
 <style lang="scss">
+// ===== 关系详情页专属色阶(单页专用;约定见 uni.scss §14)=====
+$c-rel-brown: #7C2D12; // 深棕文字(暖橙卡内)
+
 .relation-detail-container {
   min-height: 100vh;
   background: $facade-fill-gray-50;
@@ -587,7 +591,7 @@ export default {
 
 .relation-icon {
   font-size: 48rpx;
-  color: #D1D5DB;
+  color: $app-border-strong;
   padding: 0 16rpx;
 }
 
@@ -653,14 +657,14 @@ export default {
 
 .advice-content {
   padding: 24rpx;
-  background: #FFF8F0;
+  background: $dim-body-tint;
   border-radius: 16rpx;
 }
 
 .advice-text {
   font-size: 28rpx;
   line-height: 1.6;
-  color: #7C2D12;
+  color: $c-rel-brown;
 }
 
 .action-buttons {

+ 82 - 0
cfc-frontend/scripts/d11-relation-detail.js

@@ -0,0 +1,82 @@
+#!/usr/bin/env node
+/**
+ * D11: relation-detail.vue 天盘关系详情页清理 (debt 81)
+ *
+ * script 颜色映射全部收编 BrandColors(含 import);
+ * canvas 连线灰 gray200;
+ * style 全局映射 + 1 个局部变量。
+ */
+const fs = require('fs');
+const F = 'pages/tianpan/relation-detail.vue';
+let src = fs.readFileSync(F, 'utf8');
+let replaced = 0;
+
+function repl(from, to, count) {
+  const n = src.split(from).length - 1;
+  if (n === 0) { console.warn('NOT FOUND:', from.slice(0, 80)); return; }
+  if (count && n !== count) console.warn('count mismatch:', n, 'expected', count, '-', from.slice(0, 50));
+  src = src.split(from).join(to);
+  replaced += n;
+}
+
+// ---- 1. import ----
+repl(
+  "import { mapActions } from 'vuex'",
+  "import { mapActions } from 'vuex'\nimport { BrandColors } from '../../utils/brand-colors.js'"
+);
+
+// ---- 2. script 角色/维度/分数颜色 ----
+repl("        return '#6B7280'\n      }\n      var colorMap = {\n        'parent': '#F97316',\n        'child': '#3B82F6',\n        'teacher': '#8B5CF6'\n      }",
+     "        return BrandColors.textSlate\n      }\n      var colorMap = {\n        'parent': BrandColors.primary,\n        'child': BrandColors.infoBlue,\n        'teacher': BrandColors.violet\n      }", 1);
+// member2Color 那份(缩进相同)
+repl("        return '#6B7280'\n      }\n      var colorMap = {\n        'parent': '#F97316',\n        'child': '#3B82F6',\n        'teacher': '#8B5CF6'\n      }",
+     "        return BrandColors.textSlate\n      }\n      var colorMap = {\n        'parent': BrandColors.primary,\n        'child': BrandColors.infoBlue,\n        'teacher': BrandColors.violet\n      }", 1);
+repl("return colorMap[this.relation.fromMemberRole] || '#6B7280'", "return colorMap[this.relation.fromMemberRole] || BrandColors.textSlate");
+repl("return colorMap[this.relation.toMemberRole] || '#6B7280'", "return colorMap[this.relation.toMemberRole] || BrandColors.textSlate");
+repl("        'communication': { label: '沟通', description: '沟通频率与质量', color: '#10B981' },", "        'communication': { label: '沟通', description: '沟通频率与质量', color: BrandColors.success },");
+repl("        'trust': { label: '信任', description: '相互信任程度', color: '#3B82F6' },", "        'trust': { label: '信任', description: '相互信任程度', color: BrandColors.infoBlue },");
+repl("        'understanding': { label: '理解', description: '相互理解程度', color: '#8B5CF6' },", "        'understanding': { label: '理解', description: '相互理解程度', color: BrandColors.violet },");
+repl("        'support': { label: '支持', description: '相互支持力度', color: '#F59E0B' },", "        'support': { label: '支持', description: '相互支持力度', color: BrandColors.wealth },");
+repl("        'harmony': { label: '和谐', description: '关系和谐度', color: '#F97316' }", "        'harmony': { label: '和谐', description: '关系和谐度', color: BrandColors.primary }");
+repl("{ label: key, description: '', color: '#6B7280' }", "{ label: key, description: '', color: BrandColors.textSlate }");
+
+// ---- 3. canvas ----
+repl("ctx.strokeStyle = '#E5E7EB'", "ctx.strokeStyle = BrandColors.gray200", 2);
+repl("ctx.strokeStyle = '#F97316'", "ctx.strokeStyle = BrandColors.primary");
+repl("ctx.fillStyle = '#F97316'", "ctx.fillStyle = BrandColors.primary");
+
+// ---- 4. getScoreColor ----
+repl("      if (!score) {\n        return '#6B7280'\n      }", "      if (!score) {\n        return BrandColors.textSlate\n      }");
+repl("      if (score >= 80) {\n        return '#10B981'\n      } else if (score >= 60) {\n        return '#F59E0B'\n      } else {\n        return '#EF4444'\n      }",
+     "      if (score >= 80) {\n        return BrandColors.success\n      } else if (score >= 60) {\n        return BrandColors.wealth\n      } else {\n        return BrandColors.danger\n      }");
+
+// ---- 5. style 块 ----
+const styleIdx = src.indexOf('<style');
+const before = src.slice(0, styleIdx);
+let styleBody = src.slice(styleIdx);
+
+styleBody = styleBody.replace(/#D1D5DB(?![0-9a-fA-F])/g, '$app-border-strong');
+styleBody = styleBody.replace(/#FFF8F0(?![0-9a-fA-F])/g, '$dim-body-tint');
+styleBody = styleBody.replace(/#7C2D12(?![0-9a-fA-F])/g, '$c-rel-brown');
+
+const palette = [
+  '// ===== 关系详情页专属色阶(单页专用;约定见 uni.scss §14)=====',
+  '$c-rel-brown: #7C2D12; // 深棕文字(暖橙卡内)',
+  ''
+].join('\n');
+styleBody = styleBody.replace(/(<style[^>]*>\s*\n)/, '$1' + palette + '\n');
+
+src = before + styleBody;
+fs.writeFileSync(F, src);
+console.log('total replaced:', replaced);
+
+// 校验
+const lines = src.split('\n');
+let n = 0;
+for (let i = 0; i < lines.length; i++) {
+  if (/#[0-9a-fA-F]{3,8}\b/.test(lines[i])) {
+    const L = lines[i].trim();
+    if (L.indexOf('$c-') !== 0) { console.log('HEX ' + (i + 1) + ': ' + L); n++; }
+  }
+}
+console.log('remaining hex (excl palette decl):', n);

+ 40 - 0
cfc-frontend/scripts/d11b-relation-detail.js

@@ -0,0 +1,40 @@
+#!/usr/bin/env node
+/**
+ * D11b: relation-detail 多行块因 CRLF 未命中,逐行补齐
+ */
+const fs = require('fs');
+const F = 'pages/tianpan/relation-detail.vue';
+let src = fs.readFileSync(F, 'utf8');
+const MAP = [
+  ["        return '#6B7280'", "        return BrandColors.textSlate"],
+  ["        'parent': '#F97316',", "        'parent': BrandColors.primary,"],
+  ["        'child': '#3B82F6',", "        'child': BrandColors.infoBlue,"],
+  ["        'teacher': '#8B5CF6'", "        'teacher': BrandColors.violet"],
+  ["return colorMap[this.relation.fromMemberRole] || '#6B7280'", "return colorMap[this.relation.fromMemberRole] || BrandColors.textSlate"],
+  ["return colorMap[this.relation.toMemberRole] || '#6B7280'", "return colorMap[this.relation.toMemberRole] || BrandColors.textSlate"],
+  ["        return '#10B981'", "        return BrandColors.success"],
+  ["        return '#F59E0B'", "        return BrandColors.wealth"],
+  ["        return '#EF4444'", "        return BrandColors.danger"],
+];
+let n = 0;
+for (const [f, t] of MAP) {
+  const cnt = src.split(f).length - 1;
+  if (cnt === 0) { console.warn('NOT FOUND:', f); continue; }
+  src = src.split(f).join(t);
+  n += cnt;
+}
+// getScoreColor 的 if (!score) return '#6B7280'(4 空格缩进)
+if (src.includes("      if (!score) {\n        return '#6B7280'")) { /* noop */ }
+const sCount = src.split("      if (!score) {").length - 1;
+console.log('if(!score) blocks:', sCount);
+fs.writeFileSync(F, src);
+console.log('replaced:', n);
+const lines = src.split('\n');
+let h = 0;
+for (let i = 0; i < lines.length; i++) {
+  if (/#[0-9a-fA-F]{3,8}\b/.test(lines[i])) {
+    const L = lines[i].trim();
+    if (L.indexOf('$c-') !== 0) { console.log('HEX ' + (i + 1) + ': ' + L); h++; }
+  }
+}
+console.log('remaining non-palette hex:', h);

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

@@ -71,6 +71,7 @@ export const BrandColors = {
   textSlate: '#6B7280',
   hairline2: '#EEE',
   textFaint: '#888',
+  gray200: '#E5E7EB',      // gray-200 浅灰(canvas 连线/分隔)
 
   // Plutchik 八基本情绪色板(情绪打卡专属;单一事实源)
   emotionJoy: '#FFD93D',       // 开心