-
+
@@ -171,12 +171,16 @@ const coverageColor = (rate: number): string => {
{{ cust.in_use_services }}
-
- {{ { green: '最近', yellow: '上月', red: '上次' }[cust.status] }}:{{ cust.last_visit_date }}
-
+ {{ { green: '最近', yellow: '上月', red: '上次' }[cust.status] }}:{{ cust.last_visit_date }}
从未拜访
{{ cust.last_visit_method }}
+
+
+
+ {{ p.plan_overdue ? '⚠ 过期' : '📅' }} {{ p.plan_date }}
+
+
⚠ 连续 {{ cust.consecutive_missed_months }} 个月未拜访
@@ -196,25 +200,12 @@ const coverageColor = (rate: number): string => {
-
+
-
-
- {{ cust.customer_name }}
-
-
- {{ cust.industry }}
- {{ cust.in_use_services }}
-
-
- 未分配客户经理
-
+
{{ cust.customer_name }}
+
{{ cust.industry }}
+
未分配客户经理
@@ -222,9 +213,63 @@ const coverageColor = (rate: number): string => {
-
+
+
+
+
+
+
+ {{ statusLabel[selectedCustomer.status] }}
+
+ (连续 {{ selectedCustomer.consecutive_missed_months }} 个月)
+
+
+
+
+
+
行业{{ selectedCustomer.industry }}
+
在用业务{{ selectedCustomer.in_use_services }}
+
月费{{ selectedCustomer.monthly_fee }}
+
上次拜访{{ selectedCustomer.last_visit_date || '从未' }} · {{ selectedCustomer.last_visit_method }}
+
+
+
+
+
最近拜访记录
+
+ {{ v.visit_date }}
+ {{ v.visit_method }}
+ {{ v.content }}
+
+
+
+
+
+
已有计划
+
+ 📅 {{ p.plan_date }}
+ {{ p.plan_content }}
+ 已过期
+
+
+
+
+
+
+
+
+
+ 🔗 查看该客户周报记录
+
+
+
@@ -232,252 +277,103 @@ const coverageColor = (rate: number): string => {
/* ═══ 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: 'ZCOOL XiaoWei', STSong, serif; 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', 'SF Mono', monospace; font-size: 14px; color: var(--ink); letter-spacing: 0.04em; }
+.month-label { font-family: 'JetBrains Mono', monospace; 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; }
-/* ═══ Team Summary Bar ═══ */
-.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 Bar ═══ */
+.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: '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--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); }
.team-stat--coverage .team-stat-num { color: var(--ink); }
/* ═══ Manager Rows ═══ */
-.manager-list {
- display: flex; flex-direction: column; gap: 8px;
-}
-.manager-row {
- background: var(--surface);
- border: 1px solid var(--warm-border);
- transition: border-color 0.2s;
-}
-.manager-row--expanded {
- border-color: var(--ink);
-}
-
-/* ═══ Manager Summary ═══ */
-.manager-summary {
- display: flex; align-items: center; gap: 16px;
- padding: 14px 18px;
- cursor: pointer;
- transition: background 0.2s;
- user-select: none;
-}
-.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-list { display: flex; flex-direction: column; gap: 8px; }
+.manager-row { background: var(--surface); border: 1px solid var(--warm-border); transition: border-color 0.2s; }
+.manager-row--expanded { border-color: var(--ink); }
+.manager-summary { display: flex; align-items: center; gap: 16px; padding: 14px 18px; cursor: pointer; transition: background 0.2s; user-select: none; }
+.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:hover { color: var(--gold); }
-.manager-count {
- font-family: 'Noto Serif SC', STSong, serif;
- font-size: 12px; color: var(--warm-gray); letter-spacing: 0.03em;
-}
-.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', 'SF Mono', monospace;
- font-size: 12px; font-weight: 600;
- cursor: help;
-}
-.light-dot--green { background: #EDF2EC; color: var(--sage); }
+.manager-count { font-family: 'Noto Serif SC', STSong, serif; 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--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', 'SF Mono', monospace;
- font-size: 13px; font-weight: 600;
- width: 40px; text-align: right;
-}
+.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; }
/* ═══ 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;
-}
+.customer-grid { display: flex; flex-wrap: wrap; gap: 10px; padding: 0 18px 16px; border-top: 1px solid var(--warm-border); padding-top: 14px; }
/* ═══ Customer Card ═══ */
-.customer-card {
- width: 220px;
- background: var(--paper);
- border: 1px solid var(--warm-border);
- cursor: pointer;
- transition: all 0.2s;
- display: flex;
- overflow: hidden;
- position: relative;
-}
-.customer-card:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(28,55,56,0.06);
-}
+.customer-card { width: 220px; background: var(--paper); border: 1px solid var(--warm-border); cursor: pointer; transition: all 0.2s; display: flex; overflow: hidden; position: relative; }
+.customer-card:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(28,55,56,0.06); }
.customer-card:active { transform: scale(0.99); }
-
-.card-status-stripe {
- width: 4px; flex-shrink: 0;
-}
-.customer-card--green .card-status-stripe { background: var(--sage); }
+.card-status-stripe { width: 4px; flex-shrink: 0; }
+.customer-card--green .card-status-stripe { background: var(--sage); }
.customer-card--yellow .card-status-stripe { background: var(--gold); }
-.customer-card--red .card-status-stripe { background: var(--vermilion); }
-.customer-card--gray .card-status-stripe { background: var(--warm-gray); }
-
-.customer-card--red {
- animation: pulse-warn 3s ease-in-out infinite;
-}
-@keyframes pulse-warn {
- 0%, 100% { border-color: var(--warm-border); }
- 50% { border-color: rgba(184,71,46,0.35); }
-}
-
-.card-body {
- padding: 12px 14px;
- flex: 1; min-width: 0;
-}
-.card-name-row {
- display: flex; align-items: flex-start; gap: 8px;
- margin-bottom: 6px;
-}
-
-/* ═══ Status Circle Icons (geometric, no text) ═══ */
-.status-circle {
- display: inline-block;
- width: 16px; height: 16px;
- border-radius: 50%;
- flex-shrink: 0;
- margin-top: 2px;
-}
-/* Visited this month — solid filled circle ● */
-.status-circle--green {
- background: var(--sage);
- box-shadow: 0 0 0 2px rgba(74,103,65,0.15);
-}
-/* Visited last month only — half-filled circle ◐ */
-.status-circle--yellow {
- background: conic-gradient(var(--gold) 50%, transparent 50%);
- box-shadow: inset 0 0 0 1.5px var(--gold);
-}
-/* Not visited 2+ months — empty circle ○ */
-.status-circle--red {
- background: transparent;
- border: 2px solid var(--vermilion);
- box-shadow: 0 0 0 2px rgba(184,71,46,0.08);
-}
-/* Unassigned — dash */
-.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-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);
- letter-spacing: 0.03em;
-}
-.card-visit-info {
- display: flex; align-items: center; gap: 8px;
-}
-.card-last-visit {
- font-family: 'JetBrains Mono', 'SF Mono', monospace;
- font-size: 10px; color: var(--warm-gray);
-}
+.customer-card--red .card-status-stripe { background: var(--vermilion); }
+.customer-card--gray .card-status-stripe { background: var(--warm-gray); }
+.customer-card--red { animation: pulse-warn 3s ease-in-out infinite; }
+@keyframes pulse-warn { 0%,100% { border-color: var(--warm-border); } 50% { border-color: rgba(184,71,46,0.35); } }
+.card-body { padding: 12px 14px; flex: 1; min-width: 0; }
+.card-name-row { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 6px; }
+.status-circle { display: inline-block; width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; margin-top: 2px; }
+.status-circle--green { background: var(--sage); box-shadow: 0 0 0 2px rgba(74,103,65,0.15); }
+.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-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-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--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-warning {
- margin-top: 6px;
- font-family: 'Noto Serif SC', STSong, serif;
- font-size: 10px; color: var(--vermilion);
- letter-spacing: 0.03em;
-}
-
-/* ═══ Unassigned Section ═══ */
-.unassigned-section {
- border-style: dashed;
- border-color: var(--warm-gray);
-}
-.unassigned-summary {
- cursor: pointer;
-}
-
-/* ═══ Empty ═══ */
+.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-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.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); }
+.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; }
+
+/* ═══ Dialog ═══ */
+.dlg-status { padding: 8px 12px; border-radius: 6px; font-size: 13px; font-weight: 600; margin-bottom: 12px; }
+.dlg-status--green { background: #EDF2EC; color: var(--sage); }
+.dlg-status--yellow { background: #FBF6EE; color: var(--gold); }
+.dlg-status--red { background: #FBF1EE; color: var(--vermilion); }
+.dlg-status--gray { background: #f0ede5; color: var(--warm-gray); }
+.dlg-info { background: var(--c-bg-light, #faf9f6); border-radius: 6px; padding: 12px 16px; margin-bottom: 12px; }
+.dlg-info-row { display: flex; gap: 16px; padding: 4px 0; font-size: 13px; }
+.dlg-label { color: var(--c-text-muted); min-width: 60px; }
+.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-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; }
+.dlg-plan-item.dlg-plan-overdue { background: #FBF1EE; margin: 2px -4px; padding: 4px; border-radius: 4px; }
+.dlg-plan-form { background: var(--c-bg-light, #faf9f6); padding: 10px 12px; border-radius: 6px; }
+.plan-form-row { display: flex; gap: 8px; align-items: center; }