feat: 双主题系统 — 编辑风 + 极简亮色
前端: - 新增 Pinia theme store,localStorage 持久化,data-theme 切换 - App.vue: :root 新增 --font-*/--sidebar-* CSS 变量;新增 :root[data-theme=light] 完整配色(极简黑白金 + Noto Sans SC) - DesktopLayout: 侧边栏 15 个变量化 + 顶栏主题切换按钮 - MobileLayout: 装饰色变量化 - Settings: 新增「界面主题」卡片 - 21 个组件 font-family 统一替换为 var(--font-*) - 新增 utils/managerColor.ts — 12 色调色板 + 自适应文字色 + 后端自定义色优先 - WorkPlans/MiniBusiness/KeyVisits/CustomerManage: 客户经理标签色统一走共享工具 - UserManage: 编辑弹窗新增颜色选择器(仅 manager) - LightBoard: 去标题星标图标 - ManagerWorkspace/WorkPlans/MiniBusiness/KeyVisits: 删除按钮改为实心红底白字 后端: - User 模型新增 color 列 + lifespan 自动迁移 - users API 支持 color 字段读写 - UserOut schema 新增 color Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -111,12 +111,7 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
<div class="page-head">
|
||||
<div class="page-head-row">
|
||||
<div>
|
||||
<h2 class="page-title">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" style="margin-right:8px; color: var(--gold); vertical-align: -4px;">
|
||||
<path d="M12 2l2.4 7.2h7.6l-6 4.8 2.4 7.2-6.4-4.8-6.4 4.8 2.4-7.2-6-4.8h7.6z"/>
|
||||
</svg>
|
||||
客户拜访亮灯表
|
||||
</h2>
|
||||
<h2 class="page-title">客户拜访亮灯表</h2>
|
||||
<div class="month-nav">
|
||||
<button class="month-nav-btn" @click="changeMonth(-1)">◀</button>
|
||||
<span class="month-label">{{ referenceMonth }}</span>
|
||||
@@ -277,12 +272,12 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
/* ═══ Page Header ═══ */
|
||||
.page-head { margin-bottom: 20px; }
|
||||
.page-head-row { display: flex; justify-content: space-between; align-items: flex-start; }
|
||||
.page-title { margin: 0; font-family: 'ZCOOL XiaoWei', STSong, serif; font-size: 22px; font-weight: 400; color: var(--ink); letter-spacing: 0.06em; }
|
||||
.page-title { margin: 0; font-family: var(--font-heading); font-size: 22px; font-weight: 400; color: var(--ink); letter-spacing: 0.06em; }
|
||||
.month-nav { display: flex; align-items: center; gap: 8px; margin: 4px 0 6px; }
|
||||
.month-nav-btn { background: var(--surface); border: 1px solid var(--warm-border); padding: 3px 8px; cursor: pointer; color: var(--warm-gray); font-size: 12px; }
|
||||
.month-nav-btn:hover:not(:disabled) { color: var(--ink); border-color: var(--ink); }
|
||||
.month-nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
.month-label { font-family: 'JetBrains Mono', monospace; font-size: 14px; color: var(--ink); letter-spacing: 0.04em; }
|
||||
.month-label { font-family: var(--font-mono); font-size: 14px; color: var(--ink); letter-spacing: 0.04em; }
|
||||
.month-nav-reset { background: none; border: 1px solid var(--gold); color: var(--gold); padding: 3px 8px; cursor: pointer; font-size: 12px; }
|
||||
.month-nav-reset:hover { background: var(--gold); color: #fff; }
|
||||
.page-rule { width: 32px; height: 3px; background: var(--gold); margin-top: 12px; }
|
||||
@@ -291,8 +286,8 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
.team-bar { display: flex; gap: 0; background: var(--surface); border: 1px solid var(--warm-border); margin-bottom: 20px; }
|
||||
.team-stat { flex: 1; text-align: center; padding: 16px 8px; border-right: 1px solid var(--warm-border); display: flex; flex-direction: column; gap: 4px; }
|
||||
.team-stat:last-child { border-right: none; }
|
||||
.team-stat-num { font-family: 'ZCOOL XiaoWei', STSong, serif; font-size: 26px; color: var(--ink); line-height: 1.1; }
|
||||
.team-stat-label { font-family: 'Noto Serif SC', STSong, serif; font-size: 11px; color: var(--warm-gray); letter-spacing: 0.04em; }
|
||||
.team-stat-num { font-family: var(--font-heading); font-size: 26px; color: var(--ink); line-height: 1.1; }
|
||||
.team-stat-label { font-family: var(--font-body); font-size: 11px; color: var(--warm-gray); letter-spacing: 0.04em; }
|
||||
.team-stat--green .team-stat-num { color: var(--sage); }
|
||||
.team-stat--yellow .team-stat-num { color: var(--gold); }
|
||||
.team-stat--red .team-stat-num { color: var(--vermilion); }
|
||||
@@ -306,18 +301,18 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
.manager-summary:hover { background: rgba(196,147,74,0.03); }
|
||||
.manager-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
|
||||
.manager-expand { font-size: 10px; color: var(--warm-gray); width: 14px; flex-shrink: 0; }
|
||||
.manager-name { font-family: 'ZCOOL XiaoWei', STSong, serif; font-size: 15px; color: var(--ink); letter-spacing: 0.04em; cursor: pointer; }
|
||||
.manager-name { font-family: var(--font-heading); font-size: 15px; color: var(--ink); letter-spacing: 0.04em; cursor: pointer; }
|
||||
.manager-name:hover { color: var(--gold); }
|
||||
.manager-count { font-family: 'Noto Serif SC', STSong, serif; font-size: 12px; color: var(--warm-gray); }
|
||||
.manager-count { font-family: var(--font-body); font-size: 12px; color: var(--warm-gray); }
|
||||
.manager-lights { display: flex; gap: 6px; }
|
||||
.light-dot { display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 26px; border-radius: 4px; font-family: 'JetBrains Mono', monospace; font-size: 12px; font-weight: 600; cursor: help; }
|
||||
.light-dot { display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 26px; border-radius: 4px; font-family: var(--font-mono); font-size: 12px; font-weight: 600; cursor: help; }
|
||||
.light-dot--green { background: #EDF2EC; color: var(--sage); }
|
||||
.light-dot--yellow { background: #FBF6EE; color: var(--gold); }
|
||||
.light-dot--red { background: #FBF1EE; color: var(--vermilion); }
|
||||
.manager-coverage { display: flex; align-items: center; gap: 10px; width: 180px; flex-shrink: 0; }
|
||||
.coverage-bar { flex: 1; height: 6px; background: var(--paper-dark); border-radius: 3px; overflow: hidden; }
|
||||
.coverage-fill { height: 100%; border-radius: 3px; transition: width 0.5s ease; }
|
||||
.coverage-pct { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 600; width: 40px; text-align: right; }
|
||||
.coverage-pct { font-family: var(--font-mono); font-size: 13px; font-weight: 600; width: 40px; text-align: right; }
|
||||
|
||||
/* ═══ Customer Grid ═══ */
|
||||
.customer-grid { display: flex; flex-wrap: wrap; gap: 10px; padding: 0 18px 16px; border-top: 1px solid var(--warm-border); padding-top: 14px; }
|
||||
@@ -340,22 +335,22 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
.status-circle--yellow { background: conic-gradient(var(--gold) 50%, transparent 50%); box-shadow: inset 0 0 0 1.5px var(--gold); }
|
||||
.status-circle--red { background: transparent; border: 2px solid var(--vermilion); box-shadow: 0 0 0 2px rgba(184,71,46,0.08); }
|
||||
.status-circle--gray { background: transparent; border: 1.5px dashed var(--warm-gray); }
|
||||
.card-name { font-family: 'ZCOOL XiaoWei', STSong, serif; font-size: 13px; color: var(--ink); letter-spacing: 0.03em; line-height: 1.4; word-break: break-all; }
|
||||
.card-name { font-family: var(--font-heading); font-size: 13px; color: var(--ink); letter-spacing: 0.03em; line-height: 1.4; word-break: break-all; }
|
||||
.card-meta { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 6px; }
|
||||
.card-industry,.card-services { font-family: 'Noto Serif SC', STSong, serif; font-size: 10px; color: var(--warm-gray); }
|
||||
.card-industry,.card-services { font-family: var(--font-body); font-size: 10px; color: var(--warm-gray); }
|
||||
.card-visit-info { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
|
||||
.card-last-visit { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--warm-gray); }
|
||||
.card-last-visit { font-family: var(--font-mono); font-size: 10px; color: var(--warm-gray); }
|
||||
.card-last-visit--never { color: var(--vermilion); }
|
||||
.card-method { font-family: 'Noto Serif SC', STSong, serif; font-size: 10px; padding: 1px 6px; border: 1px solid var(--warm-border); color: var(--warm-gray); }
|
||||
.card-method { font-family: var(--font-body); font-size: 10px; padding: 1px 6px; border: 1px solid var(--warm-border); color: var(--warm-gray); }
|
||||
.card-plans { display: flex; gap: 4px; flex-wrap: wrap; }
|
||||
.plan-badge { font-family: 'JetBrains Mono', monospace; font-size: 9px; padding: 2px 6px; border-radius: 8px; background: #EDF2EC; color: var(--sage); }
|
||||
.plan-badge { font-family: var(--font-mono); font-size: 9px; padding: 2px 6px; border-radius: 8px; background: #EDF2EC; color: var(--sage); }
|
||||
.plan-badge.plan-overdue { background: #FBF1EE; color: var(--vermilion); animation: pulse-warn 2s ease-in-out infinite; }
|
||||
.card-warning { margin-top: 6px; font-family: 'Noto Serif SC', STSong, serif; font-size: 10px; color: var(--vermilion); }
|
||||
.card-warning { margin-top: 6px; font-family: var(--font-body); font-size: 10px; color: var(--vermilion); }
|
||||
.unassigned-section { border-style: dashed; border-color: var(--warm-gray); }
|
||||
.unassigned-summary { cursor: pointer; }
|
||||
.empty-state { text-align: center; padding: 48px 0; }
|
||||
.empty-text { font-family: 'Noto Serif SC', STSong, serif; font-size: 15px; color: var(--warm-gray); }
|
||||
.empty { text-align: center; padding: 20px; color: var(--c-text-muted); font-family: 'Noto Serif SC', STSong, serif; }
|
||||
.empty-text { font-family: var(--font-body); font-size: 15px; color: var(--warm-gray); }
|
||||
.empty { text-align: center; padding: 20px; color: var(--c-text-muted); font-family: var(--font-body); }
|
||||
|
||||
/* ═══ Dialog ═══ */
|
||||
.dlg-status { padding: 8px 12px; border-radius: 6px; font-size: 13px; font-weight: 600; margin-bottom: 12px; }
|
||||
@@ -369,7 +364,7 @@ const statusLabel: Record<string, string> = { green: '近30天已拜访', yellow
|
||||
.dlg-section { border-top: 1px solid var(--warm-border); padding-top: 10px; margin-top: 10px; }
|
||||
.dlg-section-title { margin: 0 0 8px; font-size: 13px; color: var(--ink); }
|
||||
.dlg-visit-item { display: flex; gap: 8px; padding: 4px 0; font-size: 12px; }
|
||||
.dlg-vdate { font-family: 'JetBrains Mono', monospace; color: var(--warm-gray); white-space: nowrap; }
|
||||
.dlg-vdate { font-family: var(--font-mono); color: var(--warm-gray); white-space: nowrap; }
|
||||
.dlg-vmethod { color: var(--sage); white-space: nowrap; }
|
||||
.dlg-vcontent { color: var(--c-text-muted); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dlg-plan-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12px; }
|
||||
|
||||
Reference in New Issue
Block a user