소스 검색

style: 建立全局设计token并清除游离色,统一品牌青绿色板

新增 PRODUCT.md/DESIGN.md 设计上下文;App.vue 扩展色板/动效变量与按压反馈工具类;uni.scss 对齐品牌青绿;style-button 重构增加按压态;shadow-card/style-bottom-view 扁平化;全局清除橙#ff6b35、蓝#347dff/#ecf3ff/#e0ebff/#1aa4f2、杂青绿#419D95/#44deba 等游离色
skyline 3 주 전
부모
커밋
89aadf4a3f

+ 79 - 0
DESIGN.md

@@ -0,0 +1,79 @@
+# Design
+
+> 由代码现状提取 + 本次 UI 改造目标 token("保持青绿色调,扁平清新,适度动效")。改造以本文件为准。
+
+## Theme
+
+浅色主题。场景:车主白天户外强光下或夜间车内看手机找桩、看充电进度,需要高可读性与清爽感。青绿作为品牌功能色(空闲状态、主按钮、选中态),不做深色主题。
+
+## Color
+
+品牌主色保持不变(青绿系)。策略:**Restrained**(青绿浅底大面积点缀 + 单一强调色)。
+
+| Token | 值 | 用途 |
+|---|---|---|
+| --color-primary | #2D9E95 | 主按钮、选中态、空闲状态、金额强调 |
+| --color-primary-deep | #23807A | 主按钮按压态 |
+| --color-primary-tint | rgba(45,158,149,0.08) | 浅青背景块(替代 #f7f7f7 中性灰块) |
+| --color-primary-tint-strong | rgba(45,158,149,0.14) | 选中 chip / 图标底 |
+| --color-warning | #FF9900 | 价格、收藏星标(保留) |
+| --color-error | #F43636 | 故障、失败(保留现状值) |
+| --color-success | #34A46C | 充电完成、退款成功 |
+| --text-1 | #1C2B29(青调近黑) | 标题 |
+| --text-2 | #5C6B69(青调灰) | 正文次级(替代 #666) |
+| --text-3 | #8C9997 | 辅助(替代 #999 / rgba(0,0,0,0.4~0.5)) |
+| --divider | rgba(28,43,41,0.06) | 分隔线(替代 rgba(0,0,0,0.1)) |
+| --bg-page | #F4F7F6(青调浅灰) | 页面底(替代 #F5F5F5 / #F6F7FA 混用) |
+| --bg-card | #FFFFFF | 卡片 |
+| --color-sec | #F2F6F5 | 浅色块(原 #f7f7f7 的替代) |
+
+清除游离色:#419D95、#44deba、#076370 → --color-primary 系;#347dff/rgba(52,125,255,0.1)、#ecf3ff、#e0ebff、#1aa4f2 等蓝色 → 青绿对应 tint;#ff6b35 橙色遗留 → 删除(价格用 --color-warning)。
+
+## Typography
+
+系统默认字体栈(小程序限制),仅用字号 + 字重构建层级。
+
+- 数字强调(余额/价格):32-48rpx,fw-600,主色或 --text-1
+- 页面标题:36-40rpx fw-600 / --text-1
+- 正文:26-28rpx / --text-2
+- 辅助说明:22-24rpx / --text-3
+- 层级比例 ≥1.25:22 → 28 → 36 → 48
+
+## Radius(统一刻度)
+
+- 卡片:20rpx
+- 小块/标签:12rpx(替代 4/6/8/10rpx 混用)
+- 底部弹层:24rpx 顶部圆角
+- 按钮/chips/胶囊:全圆角 pill
+- 头像/状态点:circle
+
+## Elevation(扁平化关键)
+
+- 列表卡片:无阴影、无边框,靠白卡 + 页面青调灰底对比;可选极淡投影 `0 2rpx 8rpx rgba(28,43,41,0.04)`
+- 浮层(底部面板、悬浮球、重定位按钮):`0 8rpx 24rpx rgba(28,43,41,0.12)` 单层柔和投影
+- 遮罩:rgba(12,24,22,0.45)
+- 禁止:双层描边+投影叠加、0.2+ 黑色重投影
+
+## Spacing
+
+- 页面水平留白:30rpx;卡片内边距:30rpx;区块间距:24rpx
+- 列表项内边距:上下 28rpx,节奏感通过分组留白(32rpx)而非统一 20rpx
+
+## Motion
+
+- 曲线:`--ease-out: cubic-bezier(0.22, 1, 0.36, 1)`;时长 fast 150ms / base 220ms / slow 280ms
+- 按压反馈:所有可点卡片/行/chip 按下 `scale(0.98)` + 150ms;主按钮按下加深为 --color-primary-deep
+- 弹层:底部弹层滑入 280ms ease-out + 遮罩淡入;关闭反向
+- 页面区块入场:列表卡片 fade-up(translateY(24rpx)→0, opacity 0→1)220ms,可按 index 递进 40ms(≤3 级)
+- 充电进行中:外环旋转(保留)+ 内圈呼吸 scale 1→1.04 交替 1.6s;结束时切换为成功态单次 pop(scale 0.92→1)
+- 数值变化(电量/费用):不做逐帧滚动,保持简单
+- 尊重系统 reduce-motion:纯装饰动画(呼吸/入场)可整体禁用
+
+## Components
+
+- **style-button**:primary 青绿实底 pill / warning 橙 / default 白底描边;按压 150ms 加深
+- **charge-station 卡片**:白底无描边;价格区用 --color-primary-tint 圆角块;状态 tag 统一 12rpx 圆角浅底;"导航" 主色 pill;按压 scale 反馈
+- **底部弹层**(style-bottom-view):白底、顶部 24rpx 圆角、单层柔投影、顶部拖拽指示条(可选)
+- **tabs**:选中项主色 + 下划线滑动过渡
+- **空状态**:icon + 单行文案,居中,不做插画堆砌
+- **搜索框(地图页)**:真实胶囊控件(白底/浅青底 + icon + 占位文案),替换背景图贴片

+ 38 - 0
PRODUCT.md

@@ -0,0 +1,38 @@
+# Product
+
+## Register
+
+product
+
+## Users
+
+新能源 EV 车主,在微信小程序内完成"找桩 → 到站 → 扫码充电 → 支付/开票"闭环。使用场景多为户外/车内单手操作,光线多变(白天强光、夜间车内),用户核心诉求是快速看到"哪里有空桩、多少钱、充到什么进度"。用户年龄段宽,对操作效率敏感、对视觉噪音容忍度低。
+
+## Product Purpose
+
+充电桩运营小程序(charge-front):地图找站与导航、站点详情与空闲桩查询、扫码/编码充电、充电实时状态、订单与费用明细、钱包充值/退款、发票、卡券活动。成功标准:车主 30 秒内找到合适桩位并开始充电,充电过程中对状态与费用一目了然。
+
+## Brand Personality
+
+清新、可信、轻盈。三个关键词:**清爽(teal 青绿、大量留白)、高效(信息层级直接、少装饰)、平稳(动效克制、状态清晰)**。品牌主色为青绿 #2D9E95,传递"绿色能源、环保出行"的联想。
+
+## Anti-references
+
+- 不要重投影 + 描边 + 渐变叠加的"厚重卡片风"(当前旧版遗留),显得笨重过时。
+- 不要满屏渐变背景与玻璃拟态,工具型产品应干净利落。
+- 不要混入与品牌无关的杂色(遗留的蓝色 #347dff 系、橙色 #ff6b35 系已造成色彩噪音)。
+- 不要 SaaS 仪表盘式的英雄数字模板与同质卡片网格。
+
+## Design Principles
+
+1. **状态即视觉**:空闲/充电/故障等状态用色彩与图标直接表达,用户扫一眼即可决策。
+2. **扁平轻量**:少阴影、少描边,用青绿浅色底(tint)与留白区分层级;投影仅用于浮层(底部面板、悬浮按钮)。
+3. **动效传达状态**:只动"有意义"的地方(按压反馈、弹层进出场、充电进行中的呼吸/旋转),150-250ms ease-out,不做弹跳与装饰动画。
+4. **色调纪律**:全局仅青绿主色 + 中性色(向青绿微调)+ 橙色警示/价格一个辅助色;清除一切游离色相。
+5. **单手可达**:核心操作(导航、开始充电、停止充电)位于拇指热区,按钮足够大、反馈足够明确。
+
+## Accessibility & Inclusion
+
+- 文字对比度 ≥ WCAG AA(正文 4.5:1);浅青背景上避免浅灰小字。
+- 动效尊重系统"减少动态效果"偏好,纯装饰动画可关闭。
+- 触控目标 ≥ 88rpx(约 44px);状态不单靠颜色区分(色弱用户需辅以文字/图标,现有 tag 已满足,需保持)。

+ 100 - 10
charge-front/src/App.vue

@@ -35,9 +35,20 @@ export default <any>{
 
 view {
   box-sizing: border-box;
+  /* 品牌色板:青绿主色 + 中性色向青绿微调(详见根目录 DESIGN.md) */
   --color-primary: #2d9e95;
+  --color-primary-deep: #23807a;
+  --color-primary-tint: rgba(45, 158, 149, 0.08);
+  --color-primary-tint-strong: rgba(45, 158, 149, 0.14);
   --color-warning: #ff9900;
-  --color-sec: #f7f7f7;
+  --color-error: #f43636;
+  --color-success: #34a46c;
+  --color-sec: #f2f6f5;
+  --text-1: #1c2b29;
+  --text-2: #5c6b69;
+  --text-3: #8c9997;
+  --divider: rgba(28, 43, 41, 0.06);
+  --bg-page: #f4f7f6;
 }
 
 .box-content {
@@ -62,27 +73,27 @@ image {
 }
 
 .color-000-5 {
-  color: rgba(0, 0, 0, 0.5);
+  color: #5c6b69;
 }
 
 .color-000-6 {
-  color: rgba(0, 0, 0, 0.6);
+  color: #4d5d5a;
 }
 
 .color-000-08 {
-  color: rgba(0, 0, 0, 0.08);
+  color: rgba(28, 43, 41, 0.08);
 }
 
 .color-333 {
-  color: #333;
+  color: #1c2b29;
 }
 
 .color-666 {
-  color: #666;
+  color: #5c6b69;
 }
 
 .color-999 {
-  color: #999;
+  color: #8c9997;
 }
 
 .color-primary {
@@ -102,13 +113,17 @@ image {
 }
 
 .bg-000-08 {
-  background-color: rgba(0, 0, 0, 0.08);
+  background-color: rgba(28, 43, 41, 0.06);
 }
 
 .bg-primary {
   background-color: var(--color-primary);
 }
 
+.bg-primary-tint {
+  background-color: var(--color-primary-tint);
+}
+
 .full-percent {
   height: 100%;
   width: 100%;
@@ -136,12 +151,87 @@ image {
 }
 
 .transition {
-  transition: all 0.3s;
+  transition: all 0.22s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+/* 按压反馈:元素加 .pressable,hover-class="pressed" */
+.pressable {
+  transition: transform 0.15s cubic-bezier(0.22, 1, 0.36, 1),
+    opacity 0.15s cubic-bezier(0.22, 1, 0.36, 1);
+}
+
+.pressed {
+  transform: scale(0.98);
+  opacity: 0.88;
 }
 
+/* 兼容旧用法:作为 hover-class 直接缩放 */
 .hover-scale {
-  transition: all 0.3s;
   transform: scale(0.98);
+  opacity: 0.88;
+}
+
+/* 入场动效:淡入上移 */
+.anim-fade-up {
+  animation: fade-up 0.22s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+@keyframes fade-up {
+  from {
+    opacity: 0;
+    transform: translateY(24rpx);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 入场动效:淡入 */
+.anim-fade-in {
+  animation: fade-in 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+@keyframes fade-in {
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
+}
+
+/* 弹层滑入 */
+.anim-slide-up {
+  animation: slide-up 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+@keyframes slide-up {
+  from {
+    transform: translateY(100%);
+  }
+
+  to {
+    transform: translateY(0);
+  }
+}
+
+/* 呼吸动效:进行中状态(如充电中) */
+.anim-breathe {
+  animation: breathe 1.6s ease-in-out infinite;
+}
+
+@keyframes breathe {
+  0%,
+  100% {
+    transform: scale(1);
+  }
+
+  50% {
+    transform: scale(1.04);
+  }
 }
 
 .animation-loading {

+ 2 - 2
charge-front/src/components/charge-icon/charge-icon.vue

@@ -35,10 +35,10 @@ export default {
 }
 
 .charge-icon-fast {
-  background: linear-gradient(154.59deg, #ffe767 11.86%, #f2751a 87.4%);
+  background: #f2751a;
 }
 
 .charge-icon-slow {
-  background: linear-gradient(154.59deg, #5ff19a 11.86%, #1aa4f2 87.4%);
+  background: var(--color-primary);
 }
 </style>

+ 1 - 1
charge-front/src/components/charge-station/charge-station.vue

@@ -295,7 +295,7 @@ export default {
     right: 26rpx;
     padding: 4rpx 10rpx 4rpx 4rpx;
     background: #ffffff;
-    border: 1rpx solid #44deba;
+    border: 1rpx solid var(--color-primary);
     border-radius: 20rpx;
   }
 

+ 2 - 5
charge-front/src/components/shadow-card/shadow-card.vue

@@ -54,8 +54,7 @@ export default {
 <style lang="scss">
 .shadow-card {
   background: #ffffff;
-  border: 1rpx solid rgba(0, 0, 0, 0.1);
-  box-shadow: 0px 4rpx 20rpx rgba(0, 0, 0, 0.1);
+  box-shadow: 0 4rpx 16rpx rgba(28, 43, 41, 0.06);
   border-radius: 20rpx;
   padding: 40rpx;
 
@@ -79,9 +78,7 @@ export default {
 
 .copy-btn {
   margin-left: 10rpx;
-  color: #1aa4f2;
-  /*  padding: 6rpx;
-    background: #1aa4f2;*/
+  color: var(--color-primary);
   font-size: 20rpx;
 }
 </style>

+ 3 - 2
charge-front/src/components/style-bottom-view/style-bottom-view.vue

@@ -38,7 +38,8 @@ export default {
   width: 100%;
   left: 0;
   bottom: 0;
-  transition: all 0.3s linear;
+  border-radius: 24rpx 24rpx 0 0;
+  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
   box-sizing: content-box;
   padding-bottom: constant(safe-area-inset-bottom);
   padding-bottom: env(safe-area-inset-bottom);
@@ -51,7 +52,7 @@ export default {
 }
 
 .fixed-bottom-view-shadow {
-  box-shadow: 0px 0px 40rpx 0px rgba(157, 147, 142, 0.36);
+  box-shadow: 0px 0px 32rpx 0px rgba(28, 43, 41, 0.08);
 }
 
 .fixed-bottom-view-hidden {

+ 65 - 30
charge-front/src/components/style-button/style-button.vue

@@ -1,15 +1,14 @@
 <template>
   <button
     class="button ext-class"
-    hover-class="none"
+    :class="[`type-${type}${border ? '-border' : ''}`]"
+    :hover-class="'button-press'"
+    hover-stay-time="80"
     :openType="openType"
     :style="{
       display: `var(--display-${size})`,
       width: `var(--width-${size})`,
       height: `${height ? height + 'rpx' : 'var(--height-' + size + ')'}`,
-      'background-color': `var(--bg-${type}${border ? '-border' : ''})`,
-      color: `var(--color-${type}${border ? '-border' : ''})`,
-      'border-color': `var(--border-${type}${border ? '-border' : ''})`,
       'font-size': `var(--fs-${size})`,
       'border-radius': `var(--height-${size})`,
       'font-weight': 500,
@@ -50,32 +49,6 @@ button::after {
 }
 
 .button {
-  --bg-default: #ffffff;
-  --bg-primary: #2d9e95;
-  --bg-warning: #ff9900;
-  --bg-error: red;
-  --color-default: #666666;
-  --color-primary: #ffffff;
-  --color-warning: #ffffff;
-  --color-error: #ffffff;
-  --border-default: #999999;
-  --border-primary: #2d9e95;
-  --border-warning: #ff9900;
-  --border-error: red;
-
-  --bg-default-border: #ffffff;
-  --bg-primary-border: #ffffff;
-  --bg-warning-border: #ffffff;
-  --bg-error-border: #ffffff;
-  --color-default-border: #666666;
-  --color-primary-border: #2d9e95;
-  --color-warning-border: #ff9900;
-  --color-error-border: red;
-  --border-default-border: #666666;
-  --border-primary-border: #2d9e95;
-  --border-warning-border: #ff9900;
-  --border-error-border: red;
-
   --display-medium: flex;
   --display-small: inline-flex;
   --height-medium: 96rpx;
@@ -96,5 +69,67 @@ button::after {
   box-sizing: border-box;
   border-width: 1px;
   border-style: solid;
+  transition: background-color 0.15s cubic-bezier(0.22, 1, 0.36, 1),
+    opacity 0.15s cubic-bezier(0.22, 1, 0.36, 1);
+
+  /* 实底类型 */
+  &.type-default {
+    background-color: #ffffff;
+    color: #5c6b69;
+    border-color: #dfe7e5;
+  }
+
+  &.type-primary {
+    background-color: var(--color-primary);
+    color: #ffffff;
+    border-color: var(--color-primary);
+  }
+
+  &.type-warning {
+    background-color: var(--color-warning);
+    color: #ffffff;
+    border-color: var(--color-warning);
+  }
+
+  &.type-error {
+    background-color: var(--color-error);
+    color: #ffffff;
+    border-color: var(--color-error);
+  }
+
+  /* 描边类型(border=true) */
+  &.type-default-border {
+    background-color: #ffffff;
+    color: #5c6b69;
+    border-color: #5c6b69;
+  }
+
+  &.type-primary-border {
+    background-color: #ffffff;
+    color: var(--color-primary);
+    border-color: var(--color-primary);
+  }
+
+  &.type-warning-border {
+    background-color: #ffffff;
+    color: var(--color-warning);
+    border-color: var(--color-warning);
+  }
+
+  &.type-error-border {
+    background-color: #ffffff;
+    color: var(--color-error);
+    border-color: var(--color-error);
+  }
+
+  /* 按压态 */
+  &.button-press {
+    opacity: 0.85;
+  }
+
+  &.type-primary.button-press {
+    background-color: var(--color-primary-deep);
+    opacity: 1;
+  }
 }
 </style>

+ 1 - 1
charge-front/src/pages-charge/machines/machines.vue

@@ -400,7 +400,7 @@ page {
     width: 120rpx;
     height: 48rpx;
     border-radius: 40rpx;
-    background: rgba(52, 125, 255, 0.1);
+    background: rgba(45, 158, 149, 0.1);
 
     image {
       width: 36rpx;

+ 2 - 2
charge-front/src/pages-charge/machines/price-desc/price-desc.vue

@@ -34,7 +34,7 @@
               'border-top': `1rpx solid ${
                 index === 0 ? 'transparent' : '#E5E5E5'
               }`,
-              'background':`${item.isCurrentTimePeriod?'rgba(52, 125, 255, 0.10)':'transparent'}`
+              'background':`${item.isCurrentTimePeriod?'rgba(45, 158, 149, 0.10)':'transparent'}`
             }"
           >
             <view class="td flex-center">
@@ -72,7 +72,7 @@ export default defineComponent({
       iconText: ["谷", "平", "峰", "尖", "统"],
       iconBgColor: [
         "rgba(0, 218, 179, 0.20)",
-        "rgba(52, 125, 255, 0.20)",
+        "rgba(100, 116, 139, 0.25)",
         "rgba(255, 153, 0, 0.20)",
         "rgba(255, 46, 0, 0.20)",
         "rgba(0, 218, 179, 0.20)"

+ 17 - 17
charge-front/src/pages-charge/order/order.vue

@@ -19,7 +19,7 @@
       <!-- 充电站点 -->
       <view class="info-item flex-align-center pb-32 border-b border-eee">
         <view class="info-icon flex-center w-56 h-56 bg-theme-light br-10 mr-20">
-          <uni-icons type="location" size="26" color="#419D95"></uni-icons>
+          <uni-icons type="location" size="26" color="#2d9e95"></uni-icons>
         </view>
         <view class="flex-grow">
           <view class="fs-24 color-999 mb-8">充电站点</view>
@@ -59,7 +59,7 @@
             <view 
               class="fs-26" 
               :class="{ 'color-theme': item.color === '#F43636', 'color-333': !item.color }"
-              :style="{ color: item.color ? '#419D95' : '' }"
+              :style="{ color: item.color ? 'var(--color-primary)' : '' }"
             >
               {{ item.value }}
               <uni-icons 
@@ -97,7 +97,7 @@
   
   <!-- 加载状态 -->
   <view class="loading-state flex-center" v-else>
-    <uni-icons type="spinner" size="40" color="#419D95" class="loading-icon"></uni-icons>
+    <uni-icons type="spinner" size="40" color="#2d9e95" class="loading-icon"></uni-icons>
     <view class="fs-28 color-999 ml-16">加载中...</view>
   </view>
 </template>
@@ -238,12 +238,12 @@ onLoad((options: any) => {
 
 /* 金额卡片 */
 .amount-card {
-  background: linear-gradient(135deg, #419D95 0%, #368a84 100%);
+  background: linear-gradient(135deg, var(--color-primary) 0%, #26847d 100%);
   transition: all 0.3s ease;
   
   &:hover {
     transform: translateY(-4rpx);
-    box-shadow: 0 8rpx 24rpx rgba(65, 157, 149, 0.3);
+    box-shadow: 0 8rpx 24rpx rgba(45, 158, 149, 0.3);
   }
 }
 
@@ -275,13 +275,13 @@ onLoad((options: any) => {
 
 /* 操作按钮 */
 .btn-theme {
-  background: linear-gradient(135deg, #419D95 0%, #368a84 100%);
+  background: linear-gradient(135deg, var(--color-primary) 0%, #26847d 100%);
   transition: all 0.3s ease;
-  box-shadow: 0 4rpx 12rpx rgba(65, 157, 149, 0.3);
+  box-shadow: 0 4rpx 12rpx rgba(45, 158, 149, 0.3);
   
   &:hover {
     transform: translateY(-2rpx);
-    box-shadow: 0 6rpx 16rpx rgba(65, 157, 149, 0.4);
+    box-shadow: 0 6rpx 16rpx rgba(45, 158, 149, 0.4);
   }
   
   &:active {
@@ -317,27 +317,27 @@ onLoad((options: any) => {
 }
 
 .bg-primary {
-  background-color: #ff6b35;
+  background-color: var(--color-primary);
 }
 
 .bg-primary-light {
-  background-color: rgba(255, 107, 53, 0.1);
+  background-color: var(--color-primary-tint);
 }
 
 .bg-success {
-  background-color: #4cd964;
+  background-color: var(--color-success);
 }
 
 .bg-success-light {
-  background-color: rgba(76, 217, 100, 0.1);
+  background-color: rgba(52, 164, 108, 0.1);
 }
 
 .bg-theme {
-  background-color: #419D95;
+  background-color: var(--color-primary);
 }
 
 .bg-theme-light {
-  background-color: rgba(65, 157, 149, 0.1);
+  background-color: rgba(45, 158, 149, 0.1);
 }
 
 .br-12 {
@@ -499,15 +499,15 @@ onLoad((options: any) => {
 }
 
 .color-primary {
-  color: #ff6b35;
+  color: var(--color-primary);
 }
 
 .color-success {
-  color: #4cd964;
+  color: var(--color-success);
 }
 
 .color-theme {
-  color: #419D95;
+  color: var(--color-primary);
 }
 
 .fs-24 {

+ 1 - 1
charge-front/src/pages-charge/ordering/ordering.vue

@@ -683,7 +683,7 @@ onShow(() => {
         left: 50%;
         top: 50%;
         transform: translate(-50%, -50%);
-        background: linear-gradient(180deg, #ffffff 0%, #ecf3ff 100%);
+        background: linear-gradient(180deg, #ffffff 0%, #e7f3f1 100%);
         box-shadow: 0px 18rpx 30rpx rgba(0, 0, 0, 0.1);
         border-radius: 50%;
         .icon {

+ 16 - 16
charge-front/src/pages-charge/orders/orders.vue

@@ -344,18 +344,18 @@ onReachBottom(() => {
   text-align: center;
   
   &.status-invoiced {
-    background-color: rgba(65, 157, 149, 0.1);
-    color: #419D95;
+    background-color: var(--color-primary-tint);
+    color: var(--color-primary);
   }
-  
+
   &.status-cancelled {
     background-color: #ffebee;
-    color: #f44336;
+    color: #f43636;
   }
-  
+
   &.status-processing {
-    background-color: rgba(65, 157, 149, 0.1);
-    color: #419D95;
+    background-color: var(--color-primary-tint);
+    color: var(--color-primary);
   }
 }
 
@@ -369,7 +369,7 @@ onReachBottom(() => {
 }
 
 .order-amount {
-  color: #419D95;
+  color: var(--color-primary);
   font-weight: 600;
   display: flex;
   align-items: center;
@@ -514,11 +514,11 @@ onReachBottom(() => {
 }
 
 .color-primary {
-  color: #ff6b35;
+  color: var(--color-primary);
 }
 
 .color-theme {
-  color: #419D95;
+  color: var(--color-primary);
 }
 
 .color-fff {
@@ -526,26 +526,26 @@ onReachBottom(() => {
 }
 
 .bg-primary {
-  background-color: #ff6b35;
+  background-color: var(--color-primary);
 }
 
 .bg-theme {
-  background-color: #419D95;
+  background-color: var(--color-primary);
 }
 
 .cancel-btn {
   transition: all 0.3s ease;
-  border: 2rpx solid #419D95;
+  border: 2rpx solid var(--color-primary);
   background-color: transparent;
   
   &:hover {
-    background-color: rgba(65, 157, 149, 0.05);
+    background-color: rgba(45, 158, 149, 0.05);
     transform: translateY(-2rpx);
-    box-shadow: 0 2rpx 8rpx rgba(65, 157, 149, 0.2);
+    box-shadow: 0 2rpx 8rpx rgba(45, 158, 149, 0.2);
   }
   
   &:active {
-    background-color: rgba(65, 157, 149, 0.1);
+    background-color: rgba(45, 158, 149, 0.1);
     transform: translateY(0);
   }
 }

+ 1 - 1
charge-front/src/pages-common/faq/faq.vue

@@ -123,7 +123,7 @@ onLoad((options) => {
     }
     .body {
       box-sizing: border-box;
-      background-color: rgba(52, 125, 255, 0.06);
+      background-color: rgba(45, 158, 149, 0.06);
       transition: all 0.3s;
       padding: 0rpx 24rpx;
     }

+ 10 - 10
charge-front/src/pages-common/invoice/invoice-form.vue

@@ -287,8 +287,8 @@ const submit = () => {
 .flex-between { justify-content: space-between; }
 
 .import-btn {
-  border: 2rpx solid #419D95;
-  background: rgba(65, 157, 149, 0.06);
+  border: 2rpx solid var(--color-primary);
+  background: rgba(45, 158, 149, 0.06);
 }
 
 .type-selector {
@@ -298,9 +298,9 @@ const submit = () => {
     transition: all 0.2s;
 
     &.active {
-      border-color: #419D95;
-      background: rgba(65, 157, 149, 0.08);
-      color: #419D95;
+      border-color: var(--color-primary);
+      background: rgba(45, 158, 149, 0.08);
+      color: var(--color-primary);
     }
   }
 }
@@ -317,8 +317,8 @@ const submit = () => {
     flex-shrink: 0;
 
     &.active {
-      border-color: #419D95;
-      background: rgba(65, 157, 149, 0.06);
+      border-color: var(--color-primary);
+      background: rgba(45, 158, 149, 0.06);
     }
   }
 }
@@ -337,7 +337,7 @@ const submit = () => {
   transition: background 0.2s;
 
   &.on {
-    background: #419D95;
+    background: var(--color-primary);
   }
 }
 
@@ -406,10 +406,10 @@ const submit = () => {
 .color-666 { color: #666; }
 .color-999 { color: #999; }
 .color-primary { color: #e74c3c; }
-.color-theme { color: #419D95; }
+.color-theme { color: var(--color-primary); }
 .color-fff { color: #fff; }
 .bg-fff { background-color: #fff; }
-.bg-theme { background-color: #419D95; }
+.bg-theme { background-color: var(--color-primary); }
 .flex { display: flex; }
 .flex-center { display: flex; align-items: center; justify-content: center; }
 .flex-align-center { display: flex; align-items: center; }

+ 11 - 11
charge-front/src/pages-user/invoice-title.vue

@@ -309,7 +309,7 @@ onShow(() => { loadList(); });
   background: #fff;
 
   &.default {
-    background: linear-gradient(135deg, rgba(65, 157, 149, 0.03) 0%, rgba(65, 157, 149, 0.01) 100%);
+    background: linear-gradient(135deg, rgba(45, 158, 149, 0.03) 0%, rgba(45, 158, 149, 0.01) 100%);
   }
 }
 
@@ -338,7 +338,7 @@ onShow(() => { loadList(); });
   color: #fff;
 }
 
-.edit-btn { background: #419D95; }
+.edit-btn { background: var(--color-primary); }
 .delete-btn { background: #e74c3c; }
 
 // === Item content ===
@@ -347,15 +347,15 @@ onShow(() => { loadList(); });
 .title-name { font-size: 30rpx; font-weight: 600; color: #1a1a1a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
 
 .type-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; margin-left: 12rpx; flex-shrink: 0;
-  &.tag-org { background: rgba(65, 157, 149, 0.1); color: #419D95; }
+  &.tag-org { background: rgba(45, 158, 149, 0.1); color: var(--color-primary); }
   &.tag-personal { background: rgba(255, 153, 0, 0.1); color: #cc7a00; }
 }
 
-.default-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; margin-left: 8rpx; background: rgba(65, 157, 149, 0.12); color: #419D95; flex-shrink: 0; }
+.default-tag { font-size: 20rpx; padding: 4rpx 12rpx; border-radius: 6rpx; margin-left: 8rpx; background: rgba(45, 158, 149, 0.12); color: var(--color-primary); flex-shrink: 0; }
 .item-detail { font-size: 24rpx; color: #999; margin-top: 10rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
 .item-footer { margin-top: 16rpx; }
 
-.set-default-btn { display: inline-block; font-size: 22rpx; color: #419D95; padding: 6rpx 20rpx; border: 1rpx solid rgba(65, 157, 149, 0.4); border-radius: 20rpx; }
+.set-default-btn { display: inline-block; font-size: 22rpx; color: var(--color-primary); padding: 6rpx 20rpx; border: 1rpx solid rgba(45, 158, 149, 0.4); border-radius: 20rpx; }
 
 // === Empty ===
 .empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding-top: 240rpx; }
@@ -364,7 +364,7 @@ onShow(() => { loadList(); });
 
 // === Add button ===
 .add-row { position: fixed; bottom: 0; left: 0; right: 0; padding: 16rpx 0; padding-bottom: calc(16rpx + env(safe-area-inset-bottom)); display: flex; justify-content: center; }
-.add-btn { display: flex; align-items: center; justify-content: center; width: 400rpx; height: 80rpx; background: #419D95; color: #fff; font-size: 32rpx; font-weight: 500; border-radius: 40rpx; }
+.add-btn { display: flex; align-items: center; justify-content: center; width: 400rpx; height: 80rpx; background: var(--color-primary); color: #fff; font-size: 32rpx; font-weight: 500; border-radius: 40rpx; }
 
 // === Modal ===
 .modal-mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0); z-index: 1000; display: flex; align-items: flex-end; transition: background 0.25s ease-out; &.visible { background: rgba(0,0,0,0.45); } }
@@ -376,14 +376,14 @@ onShow(() => { loadList(); });
 .modal-header { display: flex; align-items: center; justify-content: center; padding: 8rpx 30rpx 20rpx; position: relative; border-bottom: 1rpx solid rgba(0,0,0,0.05); }
 .modal-title { font-size: 32rpx; font-weight: 600; color: #1a1a1a; }
 .modal-header-right { position: absolute; right: 30rpx; top: 50%; transform: translateY(-50%); display: flex; align-items: center; }
-.import-title-btn { font-size: 24rpx; color: #419D95; padding: 8rpx 16rpx; border: 1rpx solid rgba(65, 157, 149, 0.4); border-radius: 16rpx; margin-right: 16rpx; }
+.import-title-btn { font-size: 24rpx; color: var(--color-primary); padding: 8rpx 16rpx; border: 1rpx solid rgba(45, 158, 149, 0.4); border-radius: 16rpx; margin-right: 16rpx; }
 .modal-close { padding: 12rpx; }
 
 .modal-body { padding: 8rpx 30rpx 0; overflow-y: auto; overflow-x: hidden; box-sizing: border-box; }
 
 .modal-footer { display: flex; padding: 20rpx 30rpx; padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); gap: 20rpx; border-top: 1rpx solid rgba(0,0,0,0.05); }
-.btn-cancel { width: 160rpx; height: 80rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; color: #419D95; background: rgba(65, 157, 149, 0.08); border-radius: 40rpx; flex-shrink: 0; }
-.btn-save { flex: 1; height: 80rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 500; color: #fff; background: #419D95; border-radius: 40rpx; &.loading { opacity: 0.7; } }
+.btn-cancel { width: 160rpx; height: 80rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; color: var(--color-primary); background: rgba(45, 158, 149, 0.08); border-radius: 40rpx; flex-shrink: 0; }
+.btn-save { flex: 1; height: 80rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 500; color: #fff; background: var(--color-primary); border-radius: 40rpx; &.loading { opacity: 0.7; } }
 
 // === Forms ===
 .form-section-label { font-size: 22rpx; color: #999; padding: 16rpx 0 8rpx; margin-bottom: 4rpx; }
@@ -395,8 +395,8 @@ onShow(() => { loadList(); });
 .form-input { flex: 1; height: 80rpx; padding: 0 20rpx; margin: 0; background: #f6f7fa; border: 1rpx solid #eee; border-radius: 12rpx; font-size: 28rpx; color: #1a1a1a; box-sizing: border-box; }
 .input-placeholder { color: #bbb; }
 .type-options { display: flex; }
-.type-opt { display: flex; align-items: center; justify-content: center; font-size: 26rpx; color: #888; padding: 10rpx 28rpx; border: 1rpx solid #e0e0e0; border-radius: 8rpx; margin-right: 16rpx; transition: all 0.15s; &.active { border-color: #419D95; background: rgba(65, 157, 149, 0.06); color: #419D95; } }
+.type-opt { display: flex; align-items: center; justify-content: center; font-size: 26rpx; color: #888; padding: 10rpx 28rpx; border: 1rpx solid #e0e0e0; border-radius: 8rpx; margin-right: 16rpx; transition: all 0.15s; &.active { border-color: var(--color-primary); background: rgba(45, 158, 149, 0.06); color: var(--color-primary); } }
 .form-switch { display: flex; align-items: center; justify-content: space-between; .form-label { margin-bottom: 0; } }
-.switch { width: 72rpx; height: 40rpx; background: #d0d0d0; border-radius: 24rpx; position: relative; transition: background 0.2s; &.on { background: #419D95; } }
+.switch { width: 72rpx; height: 40rpx; background: #d0d0d0; border-radius: 24rpx; position: relative; transition: background 0.2s; &.on { background: var(--color-primary); } }
 .switch-dot { width: 32rpx; height: 32rpx; background: #fff; border-radius: 50%; position: absolute; top: 4rpx; left: 4rpx; transition: transform 0.2s; .switch.on & { transform: translateX(32rpx); } }
 </style>

+ 1 - 1
charge-front/src/pages-user/wallet-refund/wallet-refund.vue

@@ -175,7 +175,7 @@ const close = () => {
   .reason-active {
     color: var(--color-primary);
     border: 1px solid var(--color-primary);
-    background: rgba(52, 125, 255, 0.1);
+    background: rgba(45, 158, 149, 0.1);
   }
   .reason-text {
     height: 224rpx;

+ 2 - 2
charge-front/src/pages-user/wallet/wallet.vue

@@ -293,7 +293,7 @@ const detail = (index: number) => {
   width: 100vw;
   background: linear-gradient(
           180deg,
-          #e0ebff 0%,
+          #d9efec 0%,
           rgba(255, 255, 255, 0) 60.13%
   );
 
@@ -323,7 +323,7 @@ const detail = (index: number) => {
           height: 64rpx;
           border-radius: 40rpx;
           background: rgba(255, 255, 255, 0.3);
-          color: #076370;
+          color: var(--color-primary-deep);
         }
       }
     }

+ 1 - 1
charge-front/src/styles/dialog.scss

@@ -6,6 +6,6 @@
   right: 0;
   width: 100%;
   height: 100%;
-  background-color: rgba(0, 0, 0, 0.6);
+  background-color: rgba(12, 24, 22, 0.45);
   z-index: 9999;
 }

+ 14 - 14
charge-front/src/uni.scss

@@ -14,27 +14,27 @@
 
 /* 颜色变量 */
 
-/* 行为相关颜色 */
-$uni-color-primary: #007aff;
-$uni-color-success: #4cd964;
-$uni-color-warning: #f0ad4e;
-$uni-color-error: #dd524d;
+/* 行为相关颜色(与品牌青绿对齐,详见根目录 DESIGN.md) */
+$uni-color-primary: #2d9e95;
+$uni-color-success: #34a46c;
+$uni-color-warning: #ff9900;
+$uni-color-error: #f43636;
 
-/* 文字基本颜色 */
-$uni-text-color: #333; // 基本色
+/* 文字基本颜色(青调中性色) */
+$uni-text-color: #1c2b29; // 基本色
 $uni-text-color-inverse: #fff; // 反色
-$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
-$uni-text-color-placeholder: #808080;
-$uni-text-color-disable: #c0c0c0;
+$uni-text-color-grey: #8c9997; // 辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #8c9997;
+$uni-text-color-disable: #c4cfcd;
 
 /* 背景颜色 */
 $uni-bg-color: #fff;
-$uni-bg-color-grey: #f8f8f8;
-$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
-$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
+$uni-bg-color-grey: #f4f7f6;
+$uni-bg-color-hover: #e8efed; // 点击状态颜色
+$uni-bg-color-mask: rgba(12, 24, 22, 0.45); // 遮罩颜色
 
 /* 边框颜色 */
-$uni-border-color: #c8c7cc;
+$uni-border-color: #dfe7e5;
 
 /* 尺寸变量 */