跳转至

UI 改进方案 — 真实代码 Audit

状态:草稿待评审 · 日期:2026-05-06 · 范围studio-website-monorepo/apps/web 真实生产前端

⚠️ 本方案基于真实代码扫描(543 个 .vue 组件 + 16 个 theme + 6 对新旧路由)。之前基于 prototype HTML 的版本已作废。


一、量化诊断

维度 真实值 评价
Vue 组件数 543
Inline style="..." 88 处(其中 11 含 hex) ✅ 健康(多为动态 width / chart tooltip)
独立 hex 颜色(非 token) 55 种 🟡 业务组件大量 hardcode
Tailwind 颜色 class hardcode 数百处 bg-blue-100bg-emerald-50 🔴 绕过 CSS token
Theme 数量 8 套 × light/dark = 16 个 🔴 全部失效,见问题 #4
卡片实现方式 shadcn Card 72 处 vs 自定义 rounded+border 104 处 🔴 自定义比标准还多
新旧版本并存路由 6 对(v3 / -old / 旧版同时注册) 🔴 最大根源

整体判断:技术栈是行业一线(Tailwind 4 + shadcn-vue + lucide + OKLCH),但执行上累积了大量不一致——主要源于"重构未完成 + theme 系统未上线 + hardcode 颜色泛滥"。


二、用户感受到的问题(症状)

工程问题不是用户最先感知到的——用户感受到的是视觉和情绪层面的不适。下面是基于你给出的反馈整理的 7 类用户痛点(如果还有别的,告诉我补上):

# 用户感受 你怎么形容它的
1 🎨 没有品牌识别度 "没有一个品牌色调"——打开 app 看不出这是 retaintive 还是某个 SaaS 模板
2 🌀 视觉调性混乱 "没有统一的调性"——不同页面风格突变(旧 /calls 是蓝 shadow 卡片,新 /calls-v3 是 border 列表,像两个产品)
3 🔤 字体大小不统一 "字体大小没有统一"——同一种信息(如标题、metadata)在不同页面用不同字号
4 🔘 按钮样式不统一 "按钮的样式没有统一"——主要按钮 / 次要按钮 / 危险按钮看起来同等重要,不知道点哪个
5 📦 卡片界限不清 "卡片界限不清, 背景色是白色, 很多卡片还用了淡黄色, 卡片的边框也是淡黄色或者灰色"——眼睛找不到模块边界
6 👁️ 对眼睛不友好 "对眼睛不友好"——hardcode 多色 + 同时多种卡片底色(emerald-50 / blue-50 / amber-50 同屏混用),疲劳感
7 缺失美感 "缺失美感"——比对 Linear / Notion / Stripe 这种"完成度高"的产品有明显差距
8 🎯 缺失选中态反馈 点击列表行打开右侧详情后,列表里"我刚点的那条"没有任何视觉标识(无 highlight、无 border-left、无底色变化)——眼睛要在右侧详情和左侧列表间来回扫才知道在看哪条
9 🤔 不知道哪里能点 "有些图标可以点击, 有些不是按钮, 不能点击, 我区分不出"——icon 没有 button 的 affordance(无边框 / 无 hover bg / 无 cursor 提示),用户要靠试错才知道哪些可交互
10 图标看不懂含义 "有些图标我看不出来是什么东西, 就像这个学士帽, 完全不知道是什么"——纯 icon button 没有 label / tooltip / 文字辅助;lucide 库 800+ icon 里很多语义是抽象的,业务功能(Coaching? Training? Notes?)用户猜不出
11 🏷️ 不知道标签能不能点 "因为它用的这个淡黄色, 我都没有看出来这是个可以点击的标签"——chip / badge / tag 视觉上 readonly(status badge)和 interactive(filter chip)没区分,都是淡色底 + 圆角,用户不知道点了会发生什么

症状 → 根因映射

用户感受 根因(见下章节工程问题)
U1 没有品牌色调 → #4 themes 全部失效(实际只跑 zinc 中性灰,没有品牌色)
U2 视觉调性混乱 → #1 新旧路由并存 + #2 自定义卡片混乱
U3 字体大小不统一 → 缺设计规范约束(不是字号阶不够,是没有人指定"标题用哪个字号、metadata 用哪个")
U4 按钮样式不统一 → 同上(shadcn Button 已有 variant 但被绕过)
U5 卡片界限不清 → #2 自定义卡片 104 > shadcn Card 72 + #3 hardcode 多种底色(emerald-50 / blue-50)
U6 对眼睛不友好 → #3 业务组件 hardcode 12 种颜色 + #5 ECharts hardcode
U7 缺失美感 → 以上所有问题叠加导致
U8 缺失选中态反馈 → #6 列表交互态(selected / hover / active)规范缺失,组件未绑定 selected state 到视觉 class
U9 不知道哪里能点 → #7 Icon button 缺规范(无 affordance:无 border / 无 hover bg / 无 cursor 视觉提示)
U10 图标看不懂 → #7 Icon button 缺规范(无 aria-label / 无 tooltip / 纯 icon 业务语义不明)
U11 不知道标签能不能点 → #8 Chip/Badge/Tag 缺 readonly vs interactive 区分(视觉一致 → 用户分不清装饰 vs 按钮)

关键:U1(缺品牌色)和 U2(视觉混乱)是 100% 物理可解的——分别对应工程问题 #4 和 #1,修起来都是 0.5-2 天的事。U3-U7 是衍生问题,根因修了它们大部分跟着改善。U8 是独立 UX 问题——和样式系统无关,是组件层面缺 selection state 绑定。


三、8 个工程根因(按严重度排)

🔴 #1 新旧版本路由并存(最大根源)

vue-router/auto-routespages/ 下所有目录全部注册成路由。6 对旧/新版本同时活着,用户能访问到两套完全不同的 UI:

旧版 新版 视觉差异
/calls /calls-v3 旧:table + 蓝 shadow 卡片;新:list + border 无 shadow
/contacts /contacts-v3 圆角不同:rounded-lg vs rounded-xl
/leads /leads-v3 同上
/conversations /conversations-v3 同上
/lead-tracker /lead-tracker-old 旧版还在被引用
/activity-timeline /activity-timeline-old 同上

证据pages/calls/components/call-card.vue:186-192rounded-lg bg-card shadow-sm shadow-blue-200/50pages/calls-v3/index.vue:162-163rounded-xl border hover:bg-accent/50——两套并存。

🔴 #2 自定义卡片 (104) > shadcn Card (72)

pages/leads-v3/components/lead-funnel.vue 单文件混用 3 种卡片风格:

rounded-lg ring-1 ring-inset ring-border          ← neutral
rounded-lg bg-emerald-50 ring-emerald-200          ← 绿
rounded-lg bg-blue-50 ring-blue-200                ← 蓝

应该用 <Card variant="..."> 统一,每种 variant 内部走 token。

🔴 #3 业务组件大量 hardcode 颜色(绕过 token)

pages/calls/components/call-card.vue:113-146 一个组件用了 12 种 hardcode tailwind 颜色:

text-blue-600 bg-blue-100      text-purple-600 bg-purple-100
text-green-600 bg-green-100    text-red-600 bg-red-100
text-amber-600 bg-amber-100    text-gray-600 bg-gray-100

每种还要单独写 dark: —— 任何 theme 切换对这些颜色完全无效

pages/contacts-v3/index.vue:232-233 头像也是写死的 bg-green-500 / bg-purple-500 / bg-blue-500

🔴 #4 致命:16 个 theme 全部死代码

assets/themes.css 定义了 8 套 theme × light/dark = 16 个 .theme-xxx class,stores/theme.ts 也有 setTheme()

main.ts:14 注释 // Note: themes.css removed for dynamic loading,整个 src 里没有任何代码把 theme-xxx class 写到 <html> / <body>

状态 现实
themes.css 加载
useThemeStore.setTheme() 可调用
Class 写到 DOM 从未发生
实际生效的 theme 只有 zinc 默认(:root 里),其他 7 套 + 全部 dark mode 都是死代码

这是 ROI 最高的修复点——一行代码(document.documentElement.className = 'theme-' + activeTheme)就能让 16 个 theme 全部活过来。

🟡 #5 ECharts 不响应 dark mode

components/dashboard/RevenueWaterfallSankey.vue:199 color: '#333' 写死黑色,dark mode 下几乎看不见。Chart palette 第 207-215 行用 hsl(220, 100%, 60%) 等 HSL 裸值。

🔴 #6 列表 selection state 视觉反馈缺失(master-detail 模式)

典型场景:Calls / Contacts / Leads 等列表页都是 master-detail 布局——左侧列表 + 右侧详情。点击列表某行 → 右侧打开对应详情。

问题:左侧列表的"被选中那行"没有视觉标识: - 无 background highlight - 无 border-left accent - 无 chevron / arrow 指向右侧 - 不区分于其他普通 row 的 hover

结果:用户失去上下文。要回头数行号、对照名字才能确认"右侧详情对应的是哪一行"。在长列表(如 100 条 calls)里这是严重影响效率的问题。

根因:组件层面缺 selection state 绑定。data 层可能有 selectedCallId 但 template 里没把它绑定到 row 的 conditional class(如 :class="{ 'bg-accent border-l-4 border-l-primary': call.id === selectedCallId }")。

影响范围:所有 master-detail 列表页(calls / calls-v3 / contacts-v3 / leads-v3 / lead-tracker / messages 等)。

🟡 #7 Icon button 缺规范(affordance + 语义)

典型场景(截图证据 — calls 详情面板顶部):

[💬 Transcript]   [▦]   [🎓]
   带边框 button   ?     ?

💬 Transcript 一看就是 button(圆角 + 边框 + 文字),但右侧两个图标(网格学士帽)没有 button 视觉特征——用户既看不出是按钮,又看不出是什么功能(学士帽 = Coaching? Training? Knowledge base?)。

两类问题分别

类型 现状 修复方向
Affordance 缺失 icon 没有 border / hover bg / cursor 提示 统一用 shadcn <Button variant="ghost" size="icon"> 包装,hover 时浅底高亮
语义识别失败 纯 icon 不带文字辅助;lucide 800+ icon 多数是抽象图形 所有 icon button 必须加 aria-label + <Tooltip>;高频功能可考虑 icon + 极简文字 label

应用层面规则建议: - icon-only button 必须 配 tooltip - 业务核心动作(如 Coaching / Save / Edit)应优先 icon + 文字而非纯 icon - 装饰图标(不可点击的 icon)必须视觉上明显不同于 icon button(不要边框、不要 hover)

影响范围:整个应用所有 icon button——sidebar / table 行操作 / 详情面板工具栏 / dashboard widget header 等。

🟡 #8 Chip / Badge / Tag 缺 readonly vs interactive 区分

典型场景:calls 列表里 "Revenue" / "Intro Booking" / "Voicemail" / "Live Call" 都是 chip 形式(淡色底 + 圆角),但同时存在两种用途: - Readonly status badge:显示当前状态(如 "Voicemail" 是 call 的 state,纯展示) - Interactive filter chip:点击后筛选/编辑(如 Category 列的 chip 可能可点击切换分类)

问题:两类视觉一致——都是淡色底 + 圆角 + 文字。用户: - 看到淡黄底的 chip 不知道是不是按钮 - 不知道点了会发生什么(filter? edit? noop?) - 必须靠 hover 试探,但 hover 反馈也常常不存在

修复方向: | 类型 | 视觉规则 | |---|---| | Readonly badge(纯展示)| 实底 / 浅底,无 hover 变化,无 cursor pointer | | Interactive chip(可点击)| 边框 + hover 加深 + cursor pointer;最好带一个小 icon(× 删除 / ▾ 下拉 / ✓ 选中)暗示可操作 |

额外考虑:避免淡黄色 chip 单独使用——视觉上和 disabled state 太像;用 token 里的 --warning 而非 hardcode bg-amber-100

影响范围:所有列表页(calls / contacts / leads / lead-tracker)+ task page + dashboard 上的 status 显示。


四、视觉最差的 5 个页面/组件

  1. pages/calls/components/call-card.vue — 12 种 hardcode + rounded-[5px] 异形圆角 + shadow-blue-200/50 硬 shadow
  2. pages/leads-v3/components/lead-funnel.vue — 单文件 3 种 ring 卡片风格混用
  3. pages/contacts-v3/index.vue — 头像 hardcode + 容器圆角与 calls-v3 不一致(rounded-lg vs rounded-xl
  4. components/dashboard/RevenueWaterfallSankey.vue#333 写死 + HSL 裸值 palette
  5. pages/calls/index.vuepages/calls-v3/index.vue 同时活——同一路由层级两套交互范式

五、调性方向(必须先定)

当前所有 theme 失效 → 实际跑的是 zinc(中性灰)默认。修复 theme 系统时同时决定走哪个方向:

方向 参考 当前 themes.css 是否已存在 适合理由
A 极简专业 Linear / Stripe theme-neutral / theme-zinc 数据驱动 SaaS 主流;现在已是默认;最稳
B 温暖人性(推荐) Notion / Airtable theme-orange / theme-yellow 健身行业不冷冰冰;和 Mindbody/Glofox 老旧表格风差异化
C 科技深色 Vercel / Sentry ✅ 所有 theme 都有 dark mode 定义 "AI 感"强;Manager 长盯不友好

好消息:themes.css 已经把 8 个 theme + dark 全部预定义好了(包括 chart palette)—— 只要修好 theme apply 逻辑,立刻可以试用任何方向


六、改进优先级

优先级 范围 内容 工作量 见效
P0 问题 #4 — 修 theme apply App.vuemain.ts 里把 useThemeStore 的 active theme apply 到 <html> class;同时定默认走方向 A/B/C 0.5 天 立即——所有用了 token 的组件统一变化
P0 问题 #1 — 删旧路由 选定 v3 / 新版作为 SoT,删 pages/calls/pages/contacts/pages/leads/pages/conversations/-old 目录 1-2 天(含回归测试) 立即——视觉风格统一一半
P1 问题 #3 — 业务组件颜色 hardcode 替换 call-card.vue 12 种 hardcode → text-info-foreground bg-info 等 token;contacts 头像同;lead-funnel 同 1-2 天 立即——theme 切换全店生效
P1 问题 #2 — 自定义卡片 → shadcn Card 104 处 rounded+border 重写为 <Card>;自定义需求加到 Card 的 variant prop 2 天 卡片节奏感统一
P1 问题 #6 — 列表 selection state 所有 master-detail 列表(calls / contacts-v3 / leads-v3 / lead-tracker)的 row 加 selected 视觉绑定(bg-accent + border-l-4 border-l-primary);同时统一 hover/active 规范 0.5-1 天 立即——长列表场景效率明显改善
P1 问题 #7 — Icon button 规范化 全应用 icon-only button 替换为 <Button variant="ghost" size="icon"> + <Tooltip>;装饰 icon 移除 button 样式;业务核心动作改 icon + 文字 1-2 天 立即——用户能识别哪些可点 + 看懂含义
P1 问题 #8 — Chip/Badge 区分规范 <Badge> 拆 readonly / interactive 两种 variant;interactive 加 hover + cursor + 暗示性小 icon;废止淡黄色单独 chip 1 天 用户立刻看懂"哪些标签能点"
P2 问题 #5 — ECharts dark mode 适配 chart 配置读 CSS variable;用 --foreground --chart-1..5 替代 hex 1 天 dark mode 可用

总计 7.5-11 天 全部修完。

最大杠杆是 P0 #4 —— 一行代码修好 theme apply,所有走 token 的组件立刻统一到品牌色调;这一步做完再决定方向。


七、待确认

  1. 方向:A / B / C(默认 B,等你确认)
  2. 新旧路由怎么删:v3 替换原版?还是 v3 直接合并回原路径(/calls-v3/calls)?
  3. 是否给用户开放 theme 切换 UI:还是固定一套?
  4. 执行节奏:P0 #4 + P0 #1 先做(约 1.5-2.5 天),review 看效果,再决定 P1/P2?

八、说明

  • 本方案 5 个问题 + 5 个最差页面全部基于真实代码引用(543 vue 组件全扫)
  • 之前基于 prototype HTML 的 26 项 audit 不再适用
  • 具体 token 替换映射、删除哪些文件、修改哪些行 —— 属于实施阶段,方向定了再写