20 KiB
客源详情页 UI 设计文档
版本:v1.2 · 日期:2026-04-25
依赖规范:Project/fonrey/UI_SYSTEM/UI_SYSTEM.mdv1.2、Project/fonrey/UI_SYSTEM/组件规范设计.md
视觉参考:Project/fonrey/UI_SYSTEM/preview.html(页面骨架、卡片层级、工具栏密度)
PRD 来源:Project/fonrey/PRD/客源管理/客源管理模块PRD.md§5.7 私客详情页
静态原型:Project/fonrey/客源详情_静态原型.html(以此为视觉真相来源)
1. 模块概述
1.1 页面目标
- 在一个页面内完成私客详情查看、跟进、带看、状态流转、联系人管理、相关员工查看。
- 桌面优先(
>=1280px),不做移动端适配。 - 技术栈固定:Tailwind CSS + HTMX + Alpine.js + Django Template。
1.2 本版关键改动(相对 v1.1)
- 修正 Topbar 配色:
bg-white border-b→bg-primary-800,与 UI_SYSTEM v1.2 对齐。 - 修正主内容区 padding:
pt-14 py-4→pt-[72px] py-5。 - 修正 Section 锚点导航 sticky 位置:
top-20→top-16。 - 修正右侧面板 sticky:
top-20→top-16,并增加max-h-[calc(100vh-80px)] overflow-y-auto。 - 修正客源概览卡片顶部标识区:
bg-primary-600(非bg-primary-800)。 - 补充客源解读 Section 实际字段和数据展示规范。
- 补充 Alpine.js
clientDetailPage()状态机完整定义。
1.3 URL 与入口
- 详情页主路由:
/clients/<client_id>/ - 入口:客源列表点击姓名或详情操作。
- 所有左侧 Section 默认随页面 SSR 输出,首屏即可看到首个 Section,向下滚动查看其余 Section。
2. 设计基线(必须遵守)
2.1 视觉与 Token
- 主色:
primary-600,禁用硬编码 Hex。 - Topbar 背景:
bg-primary-800(深青绿,区别于内容区)。 - 页面底色:
bg-neutral-50,内容卡片:bg-white border border-neutral-200 rounded-lg。 - 正文字号:
text-sm;辅助:text-xs text-neutral-500;关键数字加tabular-nums。 - 圆角:卡片
rounded-lg,输入/按钮rounded-md,标签rounded或rounded-full。 - 焦点环统一:
focus-visible:ring-2 focus-visible:ring-primary-600/40。
2.2 组件与图标
- 图标库:Heroicons v2。
- 默认:Outline 24px(
w-5 h-5) - 高密:Mini 16px(
w-4 h-4)
- 默认:Outline 24px(
- 禁止独立 CSS 文件;样式全部使用 Tailwind utility class。
2.3 页面骨架
- Topbar:
fixed top-0 left-0 right-0 h-14 z-20 bg-primary-800 flex items-center justify-between - Sidebar:
fixed left-0 top-14 h-[calc(100vh-56px)] w-60 z-20 border-r border-neutral-200 bg-white - 主内容区:
ml-60 pt-[72px] min-h-screen bg-neutral-50 px-6 py-5 - 区块垂直节奏:
space-y-4(外层)、space-y-6(左侧 Section 间距)
3. 页面信息架构
3.1 整体结构
Topbar (h-14, bg-primary-800)
-> Sidebar (w-60, fixed left)
-> Content Area (ml-60, pt-[72px], bg-neutral-50, px-6 py-5)
-> Breadcrumb + Page Title
-> Main Grid (12 cols, gap-6)
- Left (col-span-8)
- Sticky Section Anchor Nav (top-16, z-30)
- Section 1: 需求信息
- Section 2: 跟进记录
- Section 3: 带看记录
- Section 4: 客源解读
- Section 5: 二手配房
- Right Sidebar (col-span-4, sticky top-16)
- 客源信息概览(含快捷操作)
- 联系人
- 相关员工
3.2 主体布局骨架
<main class="ml-60 pt-[72px] min-h-screen bg-neutral-50 px-6 py-5">
<div class="mx-auto max-w-[1600px] space-y-4">
<!-- 面包屑 + 页头 -->
<div class="flex items-start justify-between">
<div>
<nav class="flex items-center gap-1 text-xs text-neutral-500 mb-1" aria-label="面包屑">...</nav>
<h1 class="text-xl font-semibold text-neutral-800">客源详情</h1>
<p class="text-xs text-neutral-500 mt-0.5">按 Section 连续展示,点击导航锚点快速定位</p>
</div>
</div>
<div class="grid grid-cols-12 gap-6 items-start">
<section class="col-span-8 min-w-0 space-y-6">
<!-- Anchor Nav + All Sections -->
</section>
<aside class="col-span-4 min-w-0 space-y-3 sticky top-16 max-h-[calc(100vh-80px)] overflow-y-auto">
<!-- Right panels -->
</aside>
</div>
</div>
</main>
4. Topbar
结构同 UI_SYSTEM §5.2,客源详情页激活「客源」导航项。
<header class="fixed top-0 left-0 right-0 h-14 z-20 bg-primary-800 flex items-center justify-between">
<!-- 左区:Logo -->
<div class="flex items-center gap-2 px-4 w-60 shrink-0">
<div class="w-7 h-7 rounded-md bg-primary-500 flex items-center justify-center text-white text-sm font-semibold">F</div>
<span class="text-base font-semibold text-white">Fonrey</span>
</div>
<!-- 中区:主导航(nav flex-1,无搜索框) -->
<nav class="flex items-center gap-1 flex-1 px-2" aria-label="主导航">
<a class="px-3 py-1.5 text-sm rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">主页</a>
<a class="px-3 py-1.5 text-sm rounded-md bg-primary-600 text-white font-medium">客源</a><!-- 激活态 -->
<!-- …其余项 -->
</nav>
<!-- 右区 -->
<div class="flex items-center gap-1 px-4 shrink-0">
<button class="p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md" aria-label="消息"><!-- BellIcon --></button>
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-primary-700">
<div class="w-8 h-8 rounded-full bg-primary-600 text-white flex items-center justify-center text-sm font-semibold">魏</div>
<span class="text-sm font-medium text-primary-100">魏深</span>
</div>
</div>
</header>
注:详情页 Topbar 右区只有消息通知 + 头像姓名,省略设置按钮(与 preview.html 保持一致)。
5. 左侧主内容区(全量 Section + 锚点导航)
5.1 Section 导航(替代 Tab)
5.1.1 交互定义
- 导航仅用于锚点跳转,不切换内容,不销毁 DOM。
- 点击导航项:
scrollToSection(id)平滑滚动到目标 Section。 - 当前高亮:
IntersectionObserver(rootMargin-140px 0px -55% 0px,threshold0.01)驱动activeSection。 - 导航条 sticky:
sticky top-16 z-30,滚动时固定在左栏顶部。
5.1.2 导航样式
- 容器:
bg-white border border-neutral-200 rounded-lg px-3 py-2 sticky top-16 z-30 shadow-xs - 项默认:
px-3 py-1.5 text-sm rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-800 - 项激活:
bg-primary-50 text-primary-700 font-medium - 焦点:
focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40 aria-current="true"标注当前激活项
5.1.3 Alpine.js 数据结构
navItems: [
{ id: 'section-requirements', label: '需求信息' },
{ id: 'section-follow', label: '跟进记录' },
{ id: 'section-viewings', label: '带看记录' },
{ id: 'section-insights', label: '客源解读' },
{ id: 'section-matches', label: '二手配房' }
],
activeSection: 'section-requirements'
5.1.4 代码骨架
<div class="bg-white border border-neutral-200 rounded-lg px-3 py-2 sticky top-16 z-30 shadow-xs">
<nav class="flex items-center gap-1 overflow-x-auto whitespace-nowrap" aria-label="详情分区导航">
<template x-for="item in navItems" :key="item.id">
<a :href="'#' + item.id"
@click.prevent="scrollToSection(item.id)"
:aria-current="activeSection === item.id ? 'true' : 'false'"
:class="activeSection === item.id
? 'bg-primary-50 text-primary-700 font-medium'
: 'text-neutral-600 hover:bg-neutral-100 hover:text-neutral-800'"
class="px-3 py-1.5 text-sm rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40"
x-text="item.label"></a>
</template>
</nav>
</div>
5.2 Section 1:需求信息(P0)
- ID:
section-requirements,class 含section-anchor scroll-mt-24 - 容器:
bg-white rounded-lg border border-neutral-200 p-4 space-y-4 - Header:标题
text-base font-semibold text-neutral-800+ 右侧文字链「编辑」text-sm text-primary-600 hover:text-primary-700 hover:underline underline-offset-2 - 字段网格:
grid grid-cols-3 gap-x-6 gap-y-4 - 字段项:
<dt class="text-xs text-neutral-500">+<dd class="text-sm text-neutral-900">,数字型加tabular-nums - 备注字段:
col-span-3(跨满三列) - 空值:统一显示
-
字段列表:总价、面积、居室、装修、朝向、楼层、楼龄、意向商圈、意向小区、交通情况、备注(col-span-3)
5.3 Section 2:跟进记录(P0)
- ID:
section-follow,class 含section-anchor scroll-mt-24 - 容器:
bg-white rounded-lg border border-neutral-200 p-4 space-y-4 - Header 右侧:「写跟进」Primary 按钮,含铅笔图标
w-4 h-4,点击触发写跟进 Drawer(drawerOpen=true)
类型筛选条(flex items-center gap-2 flex-wrap):
- 激活项:
px-3 py-1 text-xs rounded-full bg-primary-600 text-white - 默认项:
px-3 py-1 text-xs rounded-full bg-neutral-100 text-neutral-600 hover:bg-neutral-200 - 选项:全部 / 写入跟进 / 敏感信息跟进 / 修改跟进 / 其他跟进
日期筛选栏:border border-neutral-200 rounded-md p-3 bg-neutral-50 flex items-center gap-3 flex-wrap text-xs,含开始/结束日期输入框、有录音/有图片 checkbox。
时间线:relative border-l-2 border-neutral-200 ml-3 space-y-4 pl-5
- 普通记录:圆点
bg-primary-600,卡片rounded-md border border-neutral-200 p-3 bg-white space-y-1 - 敏感记录:圆点
bg-warning-600,卡片rounded-md border border-warning-600/20 bg-warning-50 p-3 space-y-1 - 类型标签:
inline-flex items-center px-2 py-0.5 rounded-full bg-info-50 text-info-600 font-medium(电话),bg-warning-50 text-warning-600(敏感查看)
底部:「查看全部跟进」文字链,text-sm text-primary-600 hover:underline underline-offset-2。
5.4 Section 3:带看记录(P0)
- ID:
section-viewings,class 含section-anchor scroll-mt-24 - Header 右侧:两个 Secondary 按钮(
新增预约/新增带看) - 筛选栏:同跟进记录日期筛选样式,含「归属人带看」「其他人带看」checkbox
- 时间线结构同跟进记录,房源名称用
text-primary-600 hover:underline链接 - 带看次数标签:
inline-flex items-center px-2 py-0.5 rounded-full bg-primary-50 text-primary-700 font-medium(如「一看」)
5.5 Section 4:客源解读(P1)
- ID:
section-insights,class 含section-anchor scroll-mt-24 - Header 右侧:更新时间文字
text-xs text-neutral-500
行为指标行(grid grid-cols-3 gap-3):
- 卡片:
border border-neutral-200 rounded-md p-3 bg-white - 标签
text-xs text-neutral-500,值text-xl font-semibold text-neutral-900 tabular-nums - 字段:活跃行为 / 工作日活跃 / 周末活跃
偏好占比行(grid grid-cols-3 gap-3):
- 卡片:
border border-neutral-200 rounded-md p-3 text-center - 标签
text-xs text-neutral-500,占比值text-2xl font-semibold text-primary-600 tabular-nums - 字段:价格偏好 / 户型偏好 / 面积偏好
5.6 Section 5:二手配房(P1)
- ID:
section-matches,class 含section-anchor scroll-mt-24 - Header 右侧:「批量分享」Secondary 按钮
分组标题:text-sm font-semibold text-neutral-700(如「优质户型」)
房源卡片(border border-neutral-200 rounded-md p-3):
- 缩略图:
w-20 h-14 rounded bg-neutral-100(占位) - 房源名:
text-sm font-medium text-primary-600 hover:underline - 描述:
text-xs text-neutral-500(户型·面积·区域) - 标签行:
inline-flex items-center px-1.5 py-0.5 text-[11px] rounded,朝向bg-warning-50 text-warning-600,私盘bg-info-50 text-info-600 - 价格:
text-sm font-medium text-neutral-900 tabular-nums,降价说明text-xs font-normal text-neutral-500
6. 右侧信息面板
右侧 col-span-4,sticky top-16 max-h-[calc(100vh-80px)] overflow-y-auto space-y-3。
6.1 客源信息概览(P0)
容器:bg-white rounded-lg border border-neutral-200 overflow-hidden
顶部标识区:bg-primary-600 px-4 py-3
- 求购 Badge:
inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-white/20 text-white - 客户姓名:
text-sm font-semibold text-white truncate - 带看进度副文字:
text-xs text-white/80 mt-0.5
标签行(flex items-center gap-1.5 flex-wrap):
- 私客:
bg-neutral-100 text-neutral-600 - 带看进度(如「一看」):
bg-primary-50 text-primary-700 - 等级(如「C(一般)」):
bg-warning-50 text-warning-600 - 统一尺寸:
inline-flex items-center px-1.5 py-0.5 text-xs rounded - 右侧文字链「编辑」
text-sm text-primary-600 hover:text-primary-700 hover:underline underline-offset-2
字段列表(dl space-y-1.5):
- 每行:
grid grid-cols-[72px_1fr] gap-2 dt:text-xs text-neutral-500;dd:text-xs text-right text-neutral-800- 数字/日期加
tabular-nums,编号加font-mono - 字段:最近跟进 / 客户编号 / 委托日期 / 需求类型 / 房源用途 / 客户来源
6.2 快捷操作区(P0)
三主按钮(grid grid-cols-3 gap-2):
- 样式:
flex flex-col items-center gap-1 py-2 text-xs font-medium bg-primary-600 text-white rounded-md hover:bg-primary-700 - 按钮:打电话 / 写跟进(触发
drawerOpen=true)/ 报备/常看
操作网格(grid grid-cols-2 gap-1):
- 默认:
px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100 - 危险项(转无效):
text-danger-600 hover:bg-danger-50 - 按钮:收藏 / 不置顶 / 改等级(
modal='grade')/ 改状态(modal='status')/ 转公客 / 转成交(modal='deal')/ 转无效 / 编辑客源(modal='edit')
6.3 联系人面板(P0)
容器:bg-white rounded-lg border border-neutral-200 p-3
- Header 操作:
查看号码/新增联系人,text-xs text-primary-600 hover:underline space-x-2 - 姓名:
text-sm font-medium text-neutral-900 - 号码(脱敏):
text-xs text-neutral-600 tabular-nums - 拨打统计:
text-xs text-neutral-500
6.4 相关员工面板(P0)
容器:bg-white rounded-lg border border-neutral-200 p-3
- Header 操作:
编辑,text-xs text-primary-600 hover:underline - 每个员工块(
space-y-3):- 角色标签:
text-xs font-medium text-neutral-700(如「【首录人】」) - 姓名:
text-sm text-neutral-900 - 参与时间:
text-xs text-neutral-500 tabular-nums
- 角色标签:
7. 弹窗与抽屉
7.1 统一规范
- 遮罩:
fixed inset-0 z-50 bg-neutral-900/40,点击关闭 - 弹窗层:
z-60 fixed inset-0 flex items-center justify-center p-4 pointer-events-none - 弹窗体:
pointer-events-auto bg-white rounded-xl shadow-lg border border-neutral-200 flex flex-col - Header:
flex items-center justify-between px-5 py-4 border-b border-neutral-200,关闭按钮p-1 text-neutral-500 hover:bg-neutral-100 rounded-md - Footer:
flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50,取消 Secondary + 确认 Primary
7.2 弹窗清单
| 弹窗 | 触发 | 宽度 | 内容要点 |
|---|---|---|---|
| 改等级 | modal='grade' |
max-w-sm |
原等级展示 + 下拉选择新等级 |
| 改状态 | modal='status' |
max-w-md |
原状态展示 + 下拉新状态 + 理由 textarea |
| 转成交 | modal='deal' |
max-w-lg |
状态/房源类型下拉 + 选择成交房源按钮 |
| 编辑基础信息 | modal='edit' |
max-w-2xl max-h-[85vh] overflow-y-auto |
需求类型/来源/用途/付款方式/证件号码 |
7.3 写跟进 Drawer
- 触发:
drawerOpen=true - 宽度:
w-[480px],从右侧滑入(translate-x-full→translate-x-0) - 字段:跟进方式(select)/ 跟进内容(textarea,至少 6 字)/ 跟进时间(input)/ 附件(file)/ 是否开放给同事查看(checkbox,默认勾选)
8. Alpine.js 状态机
function clientDetailPage() {
return {
modal: null, // 'grade' | 'status' | 'deal' | 'edit' | null
drawerOpen: false,
navItems: [
{ id: 'section-requirements', label: '需求信息' },
{ id: 'section-follow', label: '跟进记录' },
{ id: 'section-viewings', label: '带看记录' },
{ id: 'section-insights', label: '客源解读' },
{ id: 'section-matches', label: '二手配房' }
],
activeSection: 'section-requirements',
observer: null,
scrollToSection(id) {
const el = document.getElementById(id)
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
},
init() {
const sections = Array.from(document.querySelectorAll('.section-anchor'))
this.observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) this.activeSection = entry.target.id
})
}, { root: null, rootMargin: '-140px 0px -55% 0px', threshold: 0.01 })
sections.forEach((s) => this.observer.observe(s))
}
}
}
9. HTMX 交互规范
9.1 原则
- 页面首次渲染直接 SSR 输出完整 5 个 Section。
- 每个 Section 内部筛选/分页独立请求,仅刷新本 Section 容器。
- 弹窗/Drawer 提交后定向刷新对应 Section 或右侧面板。
9.2 请求映射
| 操作 | URL | Target | Swap |
|---|---|---|---|
| 跟进类型筛选 | /clients/{id}/follow-logs/partial |
#follow-section-body |
innerHTML |
| 跟进加载更多 | /clients/{id}/follow-logs/partial?page=N |
#follow-timeline-list |
beforeend |
| 带看筛选 | /clients/{id}/viewings/partial |
#viewings-section-body |
innerHTML |
| 客源解读刷新 | /clients/{id}/insights/partial |
#insights-section-body |
innerHTML |
| 配房筛选/分页 | /clients/{id}/matches/partial |
#matches-section-body |
innerHTML |
| 查看号码 | /clients/{id}/contacts/{cid}/reveal-phone/ |
#phone-{cid} |
innerHTML |
10. 状态与可用性规范
10.1 Loading
- 每个 Section 内独立
htmx-indicator骨架。 - 按钮提交中显示 Spinner + 进行时文案(如
保存中...)。
10.2 Empty
- 跟进为空:
暂无跟进 - 带看为空:
暂无带看记录+新增带看按钮 - 配房为空:
暂无匹配房源
10.3 Error
htmx:responseError保留旧内容 + 右下角 Error Toast。
10.4 A11y
- 可点击项支持键盘 Tab 聚焦。
- 所有交互控件保留
focus-visible样式。 - 锚点导航当前项
aria-current="true"。 - Modal 打开时
role="dialog"+aria-modal="true"。
11. 工程落地清单
body挂载x-data="clientDetailPage()",包含完整状态机(见第 8 节)。- Topbar 使用
bg-primary-800,激活项bg-primary-600 text-white。 - 主内容区:
ml-60 pt-[72px] min-h-screen bg-neutral-50 px-6 py-5。 - Section 锚点导航 sticky
top-16 z-30;右侧面板 stickytop-16 max-h-[calc(100vh-80px)] overflow-y-auto。 - 所有 Section 添加 class
section-anchor scroll-mt-24,供 IntersectionObserver 监听。 - 右侧客源概览顶部标识区用
bg-primary-600(非bg-primary-800)。 - 每个 Section 设置独立 HTMX target,避免全页刷新。
- Modal 遮罩
z-50,弹窗体z-60;Drawer 遮罩z-50,Drawer 面板z-60。 - 全量检查 class 是否符合 token(颜色、圆角、焦点环、表格密度)。
12. 验收标准
- Topbar 为深青绿色
bg-primary-800,与内容区有明显层次区分。 - 左侧主区无 Tab 切换行为,所有内容可连续滚动查看。
- 点击 Section 导航仅发生锚点滚动,不触发内容隐藏/显示。
- 锚点导航随滚动自动高亮当前 Section。
- 页面视觉与
客源详情_静态原型.html一致:层级、卡片密度、按钮和输入风格一致。 - 颜色、字号、圆角、焦点环全部使用系统 token 与规范类名。
- 关键路径(写跟进、改状态、查看号码)可在单页完成并有明确反馈(loading/toast/error)。