Przeglądaj źródła

refactor(beautify): D10 family-members 家庭成员页清理 (debt 90->27)

- 修复 C 批缺失:本页 canvas 色板未收编。新增 CANVAS_COLORS 常量引用 BrandColors
- script 11 处 canvas 色收编(渐变/setFillStyle/dotColors)
- style 全局映射:#FF6B9D->\-mind, #EEF2FF->\-wisdom-tint-2
- style 专属色收编局部变量:暖米族(\-fam-*) + 紫罗兰族(\-fam-violet-*) +
  Element UI 浅底族(\-elm-*)
- brand-colors.js 补 bodyLight(#FFB366)/primaryDeep(#C2410C)
- hex 26->13(余 palette 声明,§14 合法);canvas 离屏 500x400px 按 B 批约定保留
liaoxg 5 dni temu
rodzic
commit
385ec61754

+ 42 - 26
cfc-frontend/pages/profile-extra/family-members.vue

@@ -167,6 +167,7 @@
 </template>
 
 <script>
+import { BrandColors } from '../../utils/brand-colors.js'
 import {
   getFamilyMemberList,
   switchToFamilyMember,
@@ -588,8 +589,8 @@ export default {
       var ctx = uni.createCanvasContext(canvasId, self)
       // 暖橙渐变背景
       var bgGrad = ctx.createLinearGradient(0, 0, W * 0.6, H)
-      bgGrad.addColorStop(0, '#FF8C42')
-      bgGrad.addColorStop(1, '#FFB366')
+      bgGrad.addColorStop(0, CANVAS_COLORS.gradStart)
+      bgGrad.addColorStop(1, CANVAS_COLORS.gradEnd)
       ctx.setFillStyle(bgGrad)
       ctx.fillRect(0, 0, W, H)
       // 白色内容卡片
@@ -597,7 +598,7 @@ export default {
       ctx.setFillStyle('rgba(0,0,0,0.04)')
       roundRect(ctx, cx + 2, cy + 4, cw, ch, cr)
       ctx.fill()
-      ctx.setFillStyle('#FFFCF5')
+      ctx.setFillStyle(CANVAS_COLORS.cardFace)
       roundRect(ctx, cx, cy, cw, ch, cr)
       ctx.fill()
       // 四角装饰框
@@ -610,7 +611,7 @@ export default {
       ctx.beginPath(); ctx.moveTo(cx+cw-br-bl, cy+ch-br); ctx.lineTo(cx+cw-br, cy+ch-br); ctx.lineTo(cx+cw-br, cy+ch-br-bl); ctx.stroke()
       // 主文案
       var title = '邀请你加入「' + (self.familyName || '我的家庭') + '」'
-      ctx.setFillStyle('#C2410C')
+      ctx.setFillStyle(CANVAS_COLORS.cardInk)
       ctx.setFontSize(26)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('top')
@@ -633,14 +634,14 @@ export default {
         ctx.save()
         ctx.beginPath()
         ctx.arc(ax, avatarY, avatarR, 0, 2 * Math.PI)
-        ctx.setFillStyle('#FFF0E0')
+        ctx.setFillStyle(CANVAS_COLORS.cardFaceAlt)
         ctx.fill()
         ctx.restore()
         ctx.save()
         ctx.beginPath()
         ctx.arc(ax, avatarY, avatarR, 0, 2 * Math.PI)
         ctx.clip()
-        ctx.setFillStyle('#FF8C42')
+        ctx.setFillStyle(CANVAS_COLORS.gradStart)
         ctx.setFontSize(28)
         ctx.setTextAlign('center')
         ctx.setTextBaseline('middle')
@@ -648,7 +649,7 @@ export default {
         ctx.restore()
       }
       // 成员数量
-      ctx.setFillStyle('#999999')
+      ctx.setFillStyle(CANVAS_COLORS.hintText)
       ctx.setFontSize(16)
       ctx.setTextAlign('center')
       ctx.fillText(members.length + ' 位家庭成员', W / 2, avatarY + avatarR + 18)
@@ -657,12 +658,12 @@ export default {
       var btnX = (W - btnW) / 2
       var btnY = cy + ch - 70
       var btnGrad = ctx.createLinearGradient(btnX, btnY, btnX + btnW, btnY)
-      btnGrad.addColorStop(0, '#FF8C42')
-      btnGrad.addColorStop(1, '#FFB366')
+      btnGrad.addColorStop(0, CANVAS_COLORS.btnStart)
+      btnGrad.addColorStop(1, CANVAS_COLORS.btnEnd)
       ctx.setFillStyle(btnGrad)
       roundRect(ctx, btnX, btnY, btnW, btnH, 26)
       ctx.fill()
-      ctx.setFillStyle('#FFFFFF')
+      ctx.setFillStyle(CANVAS_COLORS.btnInk)
       ctx.setFontSize(20)
       ctx.setTextAlign('center')
       ctx.setTextBaseline('middle')
@@ -672,7 +673,7 @@ export default {
       ctx.setFontSize(13)
       ctx.fillText('浠艾福 · 家庭成长俱乐部', W / 2, H - 30)
       // 五维点装饰
-      var dotColors = ['#FF8C42', '#6366F1', '#F59E0B', '#10B981', '#FF6B9D']
+      var dotColors = CANVAS_COLORS.dotColors
       var dotY = H - 16
       for (var d = 0; d < dotColors.length; d++) {
         ctx.setFillStyle(dotColors[d])
@@ -780,10 +781,25 @@ export default {
 </script>
 
 <style lang="scss">
+// ===== 家员管理页专属色阶(暖米卡片 + 紫罗兰 + Element UI 浅底;单页专用,约定见 uni.scss §14)=====
+$c-fam-page:         #F5F0EB; // 页面底(暖灰米)
+$c-fam-card:         #FFFCF5; // 卡片底(米白)
+$c-fam-line:         #F0EAE2; // 暖分隔线
+$c-fam-tint:         #FFF1E8; // 浅橙底
+$c-fam-violet-text:  #6D28D9; // 紫罗兰文字
+$c-fam-violet-bg:    #EDE9FE; // 紫罗兰底
+$c-fam-violet-line:  #C7D2FE; // 紫罗兰深底(亲密条)
+$c-elm-info-bg:      #f0f9ff; // Element UI 信息浅底
+$c-elm-info-bg-2:    #EEF0FF; // Element UI 蓝浅底
+$c-elm-success-bg:   #f0f9eb; // Element UI 成功浅底
+$c-elm-success-text: #67c23a; // Element UI 成功文字
+$c-elm-danger-bg:    #fef0f0; // Element UI 危险浅底
+$c-elm-danger-text:  #f56c6c; // Element UI 危险文字
+
 .container {
   padding: 30rpx 30rpx 140rpx;
   min-height: 100vh;
-  background: #F5F0EB;
+  background: $c-fam-page;
 }
 
 /* ===== 家庭信息头部 ===== */
@@ -834,7 +850,7 @@ export default {
   box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
 }
 .member-card:active {
-  background: #FFFCF5;
+  background: $c-fam-card;
 }
 
 /* ===== 加入申请区块 ===== */
@@ -864,7 +880,7 @@ export default {
   display: flex;
   align-items: center;
   padding: 16rpx 0;
-  border-top: 1rpx solid #F0EAE2;
+  border-top: 1rpx solid $c-fam-line;
 }
 .jr-avatar {
   width: 72rpx;
@@ -908,7 +924,7 @@ export default {
   color: $app-surface;
 }
 .jr-reject {
-  background: #FFF1E8;
+  background: $c-fam-tint;
   color: $brand-primary-deep;
 }
 .member-avatar {
@@ -932,8 +948,8 @@ export default {
 .member-admin-tag {
   display: inline-block;
   font-size: 20rpx;
-  color: #6D28D9;
-  background: #EDE9FE;
+  color: $c-fam-violet-text;
+  background: $c-fam-violet-bg;
   padding: 2rpx 10rpx;
   border-radius: 8rpx;
   margin-top: 6rpx;
@@ -1146,7 +1162,7 @@ export default {
   transition: width 0.3s ease;
 }
 .detail-score-bar-fill.trust { background: $status-success; }
-.detail-score-bar-fill.intimacy { background: #FF6B9D; }
+.detail-score-bar-fill.intimacy { background: $dim-mind; }
 .detail-score-bar-fill.communication { background: $dim-wisdom; }
 .detail-score-value {
   width: 44rpx;
@@ -1259,8 +1275,8 @@ export default {
   padding: 12rpx 0;
 }
 .perm-add-btn[disabled] {
-  background: #C7D2FE;
-  color: #EEF2FF;
+  background: $c-fam-violet-line;
+  color: $dim-wisdom-tint-2;
 }
 .detail-action-btn.action-perm {
   background: $dim-wealth;
@@ -1286,15 +1302,15 @@ export default {
   opacity: 0.8;
 }
 .action-switch {
-  background: #f0f9ff;
+  background: $c-elm-info-bg;
   color: $uni-info;
 }
 .action-edit {
-  background: #f0f9eb;
-  color: #67c23a;
+  background: $c-elm-success-bg;
+  color: $c-elm-success-text;
 }
 .action-questionnaire {
-  background: #EEF0FF;
+  background: $c-elm-info-bg-2;
   color: $dim-wisdom;
 }
 .action-interaction {
@@ -1302,8 +1318,8 @@ export default {
   color: $brand-primary;
 }
 .action-kick {
-  background: #fef0f0;
-  color: #f56c6c;
+  background: $c-elm-danger-bg;
+  color: $c-elm-danger-text;
 }
 
 /* ===== 加载 ===== */

+ 16 - 0
cfc-frontend/scripts/d10-check-family-members.js

@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+const fs = require('fs');
+const src = fs.readFileSync('pages/profile-extra/family-members.vue', 'utf8');
+const lines = src.split('\n');
+const tplEnd = src.indexOf('<script');
+console.log('--- template lines with hex/style ---');
+for (let i = 0; i < lines.length && i < tplEnd; i++) {
+  if (/#[0-9a-fA-F]{3,8}\b/.test(lines[i]) || /style="[^"]*(background|color):/.test(lines[i])) {
+    console.log((i + 1) + ': ' + lines[i].trim().slice(0, 130));
+  }
+}
+console.log('--- script line first---');
+const scriptStart = lines.findIndex(l => /^<script>/.test(l)) + 1;
+for (let i = 0; i < lines.length; i++) {
+  if (/brand-colors|BrandColors/.test(lines[i])) { console.log((i + 1) + ': ' + lines[i].trim()); }
+}

+ 124 - 0
cfc-frontend/scripts/d10-family-members.js

@@ -0,0 +1,124 @@
+#!/usr/bin/env node
+/**
+ * D10: family-members.vue 家庭成员管理页清理 (debt 90)
+ *
+ * 1) script canvas 15 处色收编为 CANVAS_COLORS 常量(引用 BrandColors + import)
+ * 2) style 全局令牌映射:#FF6B9D->$dim-mind, #EEF2FF->$dim-wisdom-tint-2
+ * 3) style 专属色收编局部变量:暖米族($c-fam-*) + 紫罗兰族($c-fam-violet-*)
+ *    + Element UI 浅底族($c-elm-*)
+ * 4) brand-colors.js 补 bodyLight(#FFB366)/primaryDeep(#C2410C)
+ */
+const fs = require('fs');
+const F = 'pages/profile-extra/family-members.vue';
+let src = fs.readFileSync(F, 'utf8');
+let replaced = 0;
+
+function repl(from, to) {
+  const cnt = src.split(from).length - 1;
+  if (cnt === 0) { console.warn('NOT FOUND:', from.slice(0, 80)); return; }
+  src = src.split(from).join(to);
+  replaced += cnt;
+}
+
+// ---- 1. import + CANVAS_COLORS ----
+repl(
+  "<script>\nexport default {",
+  [
+    "<script>",
+    "import { BrandColors } from '../../utils/brand-colors.js'",
+    "",
+    "// canvas 画布色板(引用 BrandColors;画布专属浅色保留集中定义,约定见 uni.scss §14)",
+    "var CANVAS_COLORS = {",
+    "  gradStart:   BrandColors.body,        // #FF8C42 背景渐变起",
+    "  gradEnd:     BrandColors.bodyLight,   // #FFB366 背景渐变终",
+    "  cardFace:    '#FFFCF5',               // 卡片面(米白)",
+    "  cardInk:     BrandColors.primaryDeep, // #C2410C 深橙文字",
+    "  cardFaceAlt: '#FFF0E0',               // 卡片内底(浅橙)",
+    "  hintText:    BrandColors.textMuted,   // #999999 占位灰",
+    "  btnStart:    BrandColors.body,",
+    "  btnEnd:      BrandColors.bodyLight,",
+    "  btnInk:      BrandColors.white,",
+    "  dotColors: [BrandColors.body, BrandColors.wisdom, BrandColors.wealth, BrandColors.action, BrandColors.mind]",
+    "};",
+    "",
+    "export default {",
+  ].join('\n')
+);
+
+// ---- 2. canvas 调用处 ----
+repl("bgGrad.addColorStop(0, '#FF8C42')", "bgGrad.addColorStop(0, CANVAS_COLORS.gradStart)");
+repl("bgGrad.addColorStop(1, '#FFB366')", "bgGrad.addColorStop(1, CANVAS_COLORS.gradEnd)");
+repl("ctx.setFillStyle('#FFFCF5')", "ctx.setFillStyle(CANVAS_COLORS.cardFace)");
+repl("ctx.setFillStyle('#C2410C')", "ctx.setFillStyle(CANVAS_COLORS.cardInk)");
+repl("ctx.setFillStyle('#FFF0E0')", "ctx.setFillStyle(CANVAS_COLORS.cardFaceAlt)");
+repl("ctx.setFillStyle('#FF8C42')", "ctx.setFillStyle(CANVAS_COLORS.gradStart)");
+repl("ctx.setFillStyle('#999999')", "ctx.setFillStyle(CANVAS_COLORS.hintText)");
+repl("btnGrad.addColorStop(0, '#FF8C42')", "btnGrad.addColorStop(0, CANVAS_COLORS.btnStart)");
+repl("btnGrad.addColorStop(1, '#FFB366')", "btnGrad.addColorStop(1, CANVAS_COLORS.btnEnd)");
+repl("ctx.setFillStyle('#FFFFFF')", "ctx.setFillStyle(CANVAS_COLORS.btnInk)");
+repl("var dotColors = ['#FF8C42', '#6366F1', '#F59E0B', '#10B981', '#FF6B9D']",
+     "var dotColors = CANVAS_COLORS.dotColors");
+
+// ---- 3. style 块 ----
+const styleIdx = src.indexOf('<style');
+const before = src.slice(0, styleIdx);
+let styleBody = src.slice(styleIdx);
+
+// 全局令牌
+styleBody = styleBody.replace(/#FF6B9D(?![0-9a-fA-F])/g, '$dim-mind');
+styleBody = styleBody.replace(/#EEF2FF(?![0-9a-fA-F])/g, '$dim-wisdom-tint-2');
+
+// 局部变量
+const PAL_MAP = [
+  ['#F5F0EB', '$c-fam-page'],
+  ['#FFFCF5', '$c-fam-card'],
+  ['#F0EAE2', '$c-fam-line'],
+  ['#FFF1E8', '$c-fam-tint'],
+  ['#6D28D9', '$c-fam-violet-text'],
+  ['#EDE9FE', '$c-fam-violet-bg'],
+  ['#C7D2FE', '$c-fam-violet-line'],
+  ['#f0f9ff', '$c-elm-info-bg'],
+  ['#EEF0FF', '$c-elm-info-bg-2'],
+  ['#f0f9eb', '$c-elm-success-bg'],
+  ['#67c23a', '$c-elm-success-text'],
+  ['#fef0f0', '$c-elm-danger-bg'],
+  ['#f56c6c', '$c-elm-danger-text'],
+];
+for (const [from, to] of PAL_MAP) {
+  styleBody = styleBody.split(from).join(to);
+}
+
+const palette = [
+  '// ===== 家员管理页专属色阶(暖米卡片 + 紫罗兰 + Element UI 浅底;单页专用,约定见 uni.scss §14)=====',
+  '$c-fam-page:         #F5F0EB; // 页面底(暖灰米)',
+  '$c-fam-card:         #FFFCF5; // 卡片底(米白)',
+  '$c-fam-line:         #F0EAE2; // 暖分隔线',
+  '$c-fam-tint:         #FFF1E8; // 浅橙底',
+  '$c-fam-violet-text:  #6D28D9; // 紫罗兰文字',
+  '$c-fam-violet-bg:    #EDE9FE; // 紫罗兰底',
+  '$c-fam-violet-line:  #C7D2FE; // 紫罗兰深底(亲密条)',
+  '$c-elm-info-bg:      #f0f9ff; // Element UI 信息浅底',
+  '$c-elm-info-bg-2:    #EEF0FF; // Element UI 蓝浅底',
+  '$c-elm-success-bg:   #f0f9eb; // Element UI 成功浅底',
+  '$c-elm-success-text: #67c23a; // Element UI 成功文字',
+  '$c-elm-danger-bg:    #fef0f0; // Element UI 危险浅底',
+  '$c-elm-danger-text:  #f56c6c; // Element UI 危险文字',
+  ''
+].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 (!/^\$c-/.test(L)) { console.log('HEX ' + (i + 1) + ': ' + L); n++; }
+  }
+}
+console.log('remaining hex (excl palette decl):', n);

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

@@ -32,6 +32,8 @@ export const BrandColors = {
   primaryLight: '#FB923C',
   primaryPale: '#FFF7ED',
   primaryDark: '#EA580C',
+  primaryDeep: '#C2410C',  // 深橙(画布卡片文字档)
+  bodyLight: '#FFB366',    // 身体维度亮档(画布渐变终)
 
   // 五维身份色
   body: '#FF8C42',