Sync: add design and process improvement notes

This commit is contained in:
2026-04-25 19:38:47 +08:00
parent 2613a74c73
commit 8c909c9c08
21 changed files with 1553 additions and 107 deletions

View File

@@ -0,0 +1,316 @@
# 客源详情页 UI 设计文档
> **版本**v1.1 · **日期**2026-04-25
> **依赖规范**`Project/fonrey/UI_SYSTEM/UI_SYSTEM.md` v1.2、`Project/fonrey/UI_SYSTEM/组件规范设计.md`
> **视觉参考**`Project/fonrey/UI_SYSTEM/preview.html`(页面骨架、卡片层级、工具栏密度)
> **PRD 来源**`Project/fonrey/PRD/客源管理/客源管理模块PRD.md` §5.7 私客详情页
---
## 1. 模块概述
### 1.1 页面目标
- 在一个页面内完成私客详情查看、跟进、带看、状态流转、联系人管理、相关员工查看。
- 桌面优先(`>=1280px`),不做移动端适配。
- 技术栈固定Tailwind CSS + HTMX + Alpine.js + Django Template。
### 1.2 本版关键改动(相对 v1.0
- 左侧主内容区**取消 Tab 切换**,改为**全量 Section 连续展示**。
- 顶部 Section 导航仅用于锚点跳转(`#section-*`),不隐藏任何内容。
- 页面布局、间距、层级、色彩、焦点环严格对齐 `UI_SYSTEM.md``preview.html`
### 1.3 URL 与入口
- 详情页主路由:`/clients/<client_id>/`
- 入口:客源列表点击姓名或详情操作。
- 所有左侧 Section 默认随页面 SSR 输出,首屏即可看到首个 Section向下滚动查看其余 Section。
---
## 2. 设计基线(必须遵守)
### 2.1 视觉与 Token
- 主色:`primary-600`,禁用硬编码 Hex。
- 页面底色:`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`
- 焦点环统一:`focus-visible:ring-2 focus-visible:ring-primary-600/40`
### 2.2 组件与图标
- 图标库Heroicons v2。
- 默认Outline 24px`w-5 h-5`
- 强调Solid 20px`w-5 h-5`
- 高密Mini 16px`w-4 h-4`
- 禁止独立 CSS 文件;样式全部使用 Tailwind utility class。
### 2.3 页面骨架对齐 preview 模板
- Topbar`h-14 sticky top-0 z-20 bg-white border-b border-neutral-200`
- Sidebar展开 `w-60`,内容区偏移 `ml-60`
- 主内容区:`px-6 py-4`
- 区块垂直节奏:`space-y-6`
---
## 3. 页面信息架构
## 3.1 整体结构
```
Topbar (56)
-> Sidebar (240)
-> Content Area (bg-neutral-50)
-> Breadcrumb + Header Actions
-> Main Grid (12 cols)
- Left Content: 8 cols
- Sticky Section Anchor Nav (非 Tab)
- Section 1: 需求信息
- Section 2: 跟进记录
- Section 3: 带看记录
- Section 4: 客源解读P1
- Section 5: 二手配房P1
- Right Sidebar: 4 cols
- 客源信息概览
- 联系人
- 相关员工
- 其他操作
```
### 3.2 主体布局规范
```html
<main class="ml-60 min-h-[calc(100vh-56px)] bg-neutral-50 px-6 py-4">
<div class="mx-auto max-w-[1600px] space-y-4">
<!-- 面包屑 + 页头 -->
<div class="grid grid-cols-12 gap-6 items-start">
<section class="col-span-8 min-w-0 space-y-6" id="client-detail-main">
<!-- Anchor Nav -->
<!-- All sections rendered below -->
</section>
<aside class="col-span-4 min-w-0 space-y-3 sticky top-20" id="client-detail-side">
<!-- right panels -->
</aside>
</div>
</div>
</main>
```
---
## 4. 左侧主内容区(全量 Section + 锚点导航)
### 4.1 Section 导航(替代 Tab
### 4.1.1 交互定义
- 导航仅用于锚点跳转,不切换内容,不销毁 DOM。
- 点击导航项:`href="#section-xxx"`,平滑滚动到目标 Section。
- 当前高亮:通过 IntersectionObserver + Alpine 更新 `activeSection`
- 导航条 sticky滚动时固定在左栏顶部便于快速定位。
### 4.1.2 导航样式
- 容器:`bg-white border border-neutral-200 rounded-lg px-3 py-2 sticky top-20 z-30`
- 项默认:`text-sm text-neutral-600 hover:text-neutral-800 hover:bg-neutral-100 rounded-md`
- 项激活:`bg-primary-50 text-primary-700 font-medium`
### 4.1.3 代码骨架
```html
<div x-data="sectionNav()" class="bg-white border border-neutral-200 rounded-lg px-3 py-2 sticky top-20 z-30">
<nav class="flex items-center gap-1 overflow-x-auto whitespace-nowrap" aria-label="详情分区导航">
<a href="#section-requirements" @click="jump('section-requirements')"
:class="active==='section-requirements' ? '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">需求信息</a>
<a href="#section-follow" @click="jump('section-follow')" class="px-3 py-1.5 text-sm rounded-md">跟进记录</a>
<a href="#section-viewings" @click="jump('section-viewings')" class="px-3 py-1.5 text-sm rounded-md">带看记录</a>
<a href="#section-insights" @click="jump('section-insights')" class="px-3 py-1.5 text-sm rounded-md">客源解读</a>
<a href="#section-matches" @click="jump('section-matches')" class="px-3 py-1.5 text-sm rounded-md">二手配房</a>
</nav>
</div>
```
---
### 4.2 Section 1需求信息P0
- Section ID`section-requirements`
- 卡片结构:标题行(含编辑按钮)+ 三列字段网格 + 备注跨列。
- 容器:`bg-white rounded-lg border border-neutral-200 p-4 space-y-4`
字段:总价、面积、居室、装修、朝向、楼层、楼龄、意向商圈、意向小区、交通情况、备注。空值统一 `-`
```html
<section id="section-requirements" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">需求信息</h2>
<button class="text-sm text-primary-600 hover:text-primary-700 hover:underline underline-offset-2">编辑</button>
</header>
<dl class="grid grid-cols-3 gap-x-6 gap-y-4">
<!-- field items -->
</dl>
</section>
```
---
### 4.3 Section 2跟进记录P0
- Section ID`section-follow`
- 不再以 Tab 切页;在同一 Section 内使用筛选条 + 时间线。
- Header 右侧固定主操作:`写跟进`Primary
结构:
- 筛选工具栏(跟进类型、日期范围、有录音/有图片)
- 时间线列表(日期分组)
- 加载更多
样式要点:
- 条目卡片 `rounded-md border border-neutral-200 p-3`
- 敏感信息记录 `bg-warning-50 border-warning-600/20`
---
### 4.4 Section 3带看记录P0
- Section ID`section-viewings`
- Header 右侧操作:`新增带看`Secondary+ `新增预约`Secondary
- 筛选:日期范围、归属人带看、其他人带看。
- 内容:时间线卡片,显示带看情况、房源链接、带看次数标签、详情链接。
---
### 4.5 Section 4客源解读P1
- Section ID`section-insights`
- 默认展示占位/空态,接口就绪后替换数据。
- 布局2 列卡片 + 偏好摘要 + 图表占位(可先文本百分比)。
---
### 4.6 Section 5二手配房P1
- Section ID`section-matches`
- Header更新时间 + `批量分享`
- 内容:按分组展示房源卡片列表(优质户型/降价/热门/新上)。
- 卡片内操作:`分享房源``反馈`
---
## 5. 右侧信息面板
### 5.1 客源信息概览P0
- 顶部标识区使用主色:`bg-primary-600 text-white rounded-t-lg`
- 标签行:私客、带看进度、等级。
- 字段列表:最近跟进、客户编号、委托日期、需求类型、用途、来源、购房目的、付款方式、名下房产、贷款记录、证件信息、意向学校、入学时间。
- 展开收起:默认展示 8 行,点击 `展开全部` 展示完整。
### 5.2 快捷操作区P0
- 三主按钮:打电话、写跟进、报备/常看。
- 两列操作网格:收藏、置顶、改等级、改状态、转公客、转成交、转无效、编辑客源。
- 禁用态统一:`disabled:opacity-50 disabled:cursor-not-allowed`
### 5.3 联系人面板P0
- Header 操作:`查看号码``新增联系人`
- 手机号默认脱敏;点击查看明文需后端留痕并返回片段更新。
### 5.4 相关员工面板P0
- 展示首录人、归属人、参与时间。
- 店长/管理员显示 `编辑` 入口。
---
## 6. 弹窗与抽屉(与右侧操作对应)
### 6.1 统一规范
- Modal遵循 `UI_SYSTEM.md` §3.6,默认 `max-w-sm/max-w-md/max-w-lg`
- Drawer右侧 `w-[480px]`,用于写跟进等字段较多场景。
- Footer右对齐`取消` + `确认`
### 6.2 P0 弹窗清单
- 改等级Modal, `max-w-sm`
- 改状态Modal, `max-w-md`
- 转成交Modal, `max-w-lg`
- 选择成交房源Modal, `max-w-5xl`,内含表格+分页)
- 写跟进Drawer, `w-[480px]`
---
## 7. HTMX 交互规范(锚点版)
### 7.1 关键变化
- 删除「左侧 Tab 切换请求」。
- 详情页首次渲染直接返回完整 Sections。
- 每个 Section 内部独立筛选和分页请求,仅刷新本 Section 容器。
### 7.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?period=7d` | `#insights-section-body` | `innerHTML` |
| 配房筛选/分页 | `/clients/{id}/matches/partial` | `#matches-section-body` | `innerHTML` |
| 查看号码 | `/clients/{id}/contacts/{cid}/reveal-phone/` | `#phone-{cid}` | `innerHTML` |
---
## 8. 状态与可用性规范
### 8.1 Loading
- 每个 Section 内独立 `htmx-indicator` 骨架。
- 按钮提交中显示 Spinner + 进行时文案(如 `保存中...`)。
### 8.2 Empty
- 跟进为空:`暂无跟进`
- 带看为空:`暂无带看记录` + `新增带看`
- 配房为空:`暂无匹配房源`
### 8.3 Error
- `htmx:responseError` 保留旧内容 + 右下角 Error Toast。
### 8.4 A11y
- 可点击项支持键盘 Tab 聚焦。
- 所有交互控件保留 `focus-visible` 样式。
- 锚点导航项增加 `aria-current="true"`(当前 Section
---
## 9. 工程落地清单(给 AI Engineer
1.`UI_SYSTEM.md` 页面框架替换客源详情页现有容器尺寸Topbar/Sidebar/Content offset
2. 删除左侧 Tab 状态机(`activeTab`)及对应 `hx-get` Tab 切换逻辑。
3. 新增 `Section Anchor Nav`,实现锚点滚动与激活高亮。
4. 将需求信息、跟进记录、带看记录、客源解读、二手配房改为同页连续 Sections。
5. 每个 Section 设置独立 HTMX target避免全页刷新。
6. 右侧信息面板保持 sticky`top-20`)并拆分为 4 个卡片区块。
7. 弹窗/抽屉入口统一走 HTMX 拉取片段,提交后定向刷新对应 Section 或右侧卡片。
8. 全量检查 class 是否符合 token尤其颜色、圆角、焦点环、表格密度
---
## 10. 验收标准
- 左侧主区无 Tab 切换行为,所有内容可连续滚动查看。
- 点击 Section 导航仅发生锚点滚动,不触发内容隐藏/显示。
- 页面视觉与 `preview.html` 一致:层级、卡片密度、按钮和输入风格一致。
- 颜色、字号、圆角、焦点环全部使用系统 token 与规范类名。
- 关键路径写跟进、改状态、查看号码可在单页完成并有明确反馈loading/toast/error

View File

@@ -1012,7 +1012,7 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
| 区域 | 内容 | 样式 |
|---|---|---|
| 左区150px | Logo 图 + 产品名"Fonrey" | `flex items-center gap-2 px-4 text-base font-semibold text-neutral-900` |
| 左区150px | Logo 图 + 产品名"Fonrey" | `flex items-center gap-2 px-4 text-base font-semibold text-white` |
| 中区flex-1 | 主分类导航 Tab | 见 5.2.2 |
| 右区auto | 全局搜索图标 / 消息 / 帮助 / 头像菜单 | `flex items-center gap-1 px-4` |
@@ -1020,9 +1020,9 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
主分类8项**主页 / 房源 / 客源 / 营销 / 交易 / 数据 / 人事 / 系统**
- 每项:`px-3 py-1 text-sm font-medium rounded-md`
- 默认态:`text-neutral-600 hover:bg-neutral-100 hover:text-neutral-800`
- 激活态:`bg-primary-50 text-primary-700`
- 每项:`px-3 py-1.5 text-sm font-medium rounded-md`
- 默认态:`text-primary-100 hover:bg-primary-700 hover:text-white`
- 激活态:`bg-primary-600 text-white`
- 点击切换主分类 → Sidebar 同步切换为该分类的子菜单
#### 5.2.3 右区工具
@@ -1034,16 +1034,18 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
| 帮助 | `QuestionMarkCircleIcon` 20px | 链接到帮助中心或触发 Tour |
| 头像菜单 | 头像(`w-8 h-8 rounded-full`+ 姓名缩写 | 下拉菜单:个人设置 / 切换角色 / 退出 |
> **配色说明**Topbar 背景使用 `bg-primary-800``#134E4A`,深青绿),与下方白色 Sidebar 和 `bg-neutral-50` 内容区形成明确层次区分,同时保持品牌色系一致性。
#### 5.2.4 Topbar HTML 片段
```html
<header class="fixed top-0 left-0 right-0 h-14 z-20
bg-white border-b border-neutral-200
bg-primary-800
flex items-center justify-between">
<!-- 左区Logo -->
<div class="flex items-center gap-2 px-4 w-60 shrink-0">
<img src="/static/img/logo.svg" class="w-7 h-7" alt="Fonrey">
<span class="text-base font-semibold text-neutral-900">Fonrey</span>
<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>
<!-- 中区:主导航 -->
@@ -1051,8 +1053,8 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
{% for item in nav_items %}
<a href="{{ item.url }}"
class="px-3 py-1.5 text-sm font-medium rounded-md
{% if item.active %}bg-primary-50 text-primary-700
{% else %}text-neutral-600 hover:bg-neutral-100 hover:text-neutral-800{% endif %}">
{% if item.active %}bg-primary-600 text-white
{% else %}text-primary-100 hover:bg-primary-700 hover:text-white{% endif %}">
{{ item.label }}
</a>
{% endfor %}
@@ -1061,13 +1063,13 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
<!-- 右区:工具 -->
<div class="flex items-center gap-1 px-4 shrink-0">
<!-- 全局搜索 -->
<button class="p-1.5 text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700 rounded-md"
<button class="p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md"
aria-label="搜索">
<svg class="w-5 h-5"><!-- MagnifyingGlassIcon --></svg>
</button>
<!-- 消息通知 -->
<button class="relative p-1.5 text-neutral-500 hover:bg-neutral-100 rounded-md"
<button class="relative p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md"
aria-label="消息通知">
<svg class="w-5 h-5"><!-- BellIcon --></svg>
<span class="absolute top-1 right-1 min-w-[16px] h-4 px-1 text-[10px] font-bold
@@ -1076,20 +1078,20 @@ Topbar 分三区左区Logo、中区主导航、右区工具区
</button>
<!-- 帮助 -->
<button class="p-1.5 text-neutral-500 hover:bg-neutral-100 rounded-md" aria-label="帮助">
<button class="p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md" aria-label="帮助">
<svg class="w-5 h-5"><!-- QuestionMarkCircleIcon --></svg>
</button>
<!-- 头像菜单 -->
<div x-data="{ open: false }" @click.away="open=false" class="relative ml-1">
<div x-data="{ open: false }" @click.away="open=false" class="relative ml-1 pl-3 border-l border-primary-700">
<button @click="open=!open"
class="flex items-center gap-2 p-1 rounded-md hover:bg-neutral-100">
<span class="w-8 h-8 rounded-full bg-primary-100 text-primary-700
class="flex items-center gap-2 p-1 rounded-md hover:bg-primary-700">
<span class="w-8 h-8 rounded-full bg-primary-600 text-white
flex items-center justify-center text-sm font-semibold">
</span>
<span class="text-sm text-neutral-700 font-medium">王顺</span>
<svg class="w-4 h-4 text-neutral-400"><!-- ChevronDownIcon --></svg>
<span class="text-sm text-primary-100 font-medium">王顺</span>
<svg class="w-4 h-4 text-primary-300"><!-- ChevronDownIcon --></svg>
</button>
<div x-show="open" x-transition
class="absolute right-0 mt-1 w-44 bg-white rounded-md shadow-md

View File

@@ -48,43 +48,42 @@
<body class="bg-neutral-50 text-neutral-700 text-sm antialiased">
<!-- ============ 顶部导航 ============ -->
<header class="sticky top-0 z-20 bg-white border-b border-neutral-200">
<div class="flex items-center h-14 px-6 gap-6">
<!-- Logo -->
<div class="flex items-center gap-2">
<div class="w-7 h-7 rounded-md bg-primary-600 flex items-center justify-center text-white font-semibold">F</div>
<span class="font-semibold text-neutral-800 text-base">Fonrey · 房睿</span>
<header class="sticky top-0 z-20 bg-primary-800">
<div class="flex items-center h-14 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 font-semibold">F</div>
<span class="font-semibold text-white text-base">Fonrey · 房睿</span>
</div>
<!-- 主导航 -->
<nav class="flex items-center gap-1 text-sm">
<a class="px-3 py-1.5 rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900">工作台</a>
<a class="px-3 py-1.5 rounded-md bg-primary-50 text-primary-700 font-medium">房源</a>
<a class="px-3 py-1.5 rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900"></a>
<a class="px-3 py-1.5 rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900">楼盘</a>
<a class="px-3 py-1.5 rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900">组织人事</a>
<a class="px-3 py-1.5 rounded-md text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900">设置</a>
</nav>
<!-- 全局搜索 -->
<div class="flex-1 max-w-md relative">
<svg class="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-neutral-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-4.3-4.3M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z"/></svg>
<input type="text" placeholder="搜索房源 / 客户 / 楼盘 ⌘K"
class="w-full pl-9 pr-3 py-1.5 text-sm rounded-md bg-neutral-100 border border-transparent hover:bg-neutral-50 hover:border-neutral-300 focus:bg-white focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20 focus:outline-none placeholder:text-neutral-400">
<!-- 中区:主导航 + 搜索 -->
<div class="flex items-center gap-4 flex-1 px-2">
<nav class="flex items-center gap-1 text-sm">
<a class="px-3 py-1.5 rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">工作台</a>
<a class="px-3 py-1.5 rounded-md bg-primary-600 text-white font-medium"></a>
<a class="px-3 py-1.5 rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">客源</a>
<a class="px-3 py-1.5 rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">楼盘</a>
<a class="px-3 py-1.5 rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">组织人事</a>
<a class="px-3 py-1.5 rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">设置</a>
</nav>
<!-- 全局搜索 -->
<div class="max-w-xs w-full relative">
<svg class="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-primary-300" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-4.3-4.3M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z"/></svg>
<input type="text" placeholder="搜索房源 / 客户 / 楼盘 ⌘K"
class="w-full pl-9 pr-3 py-1.5 text-sm rounded-md bg-primary-700/60 border border-transparent text-white placeholder:text-primary-300 hover:bg-primary-700 focus:bg-white focus:text-neutral-700 focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20 focus:outline-none focus:placeholder:text-neutral-400">
</div>
</div>
<!--侧操作 -->
<div class="flex items-center gap-1">
<button class="relative p-1.5 text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700 rounded-md">
<!--区:工具 -->
<div class="flex items-center gap-1 px-4 shrink-0">
<button class="relative p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022 23.848 23.848 0 0 0 5.454 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0"/></svg>
<span class="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-danger-600"></span>
</button>
<button class="p-1.5 text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700 rounded-md">
<button class="p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>
</button>
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-neutral-200">
<div class="flex items-center gap-2 pl-3 ml-1 border-l border-primary-700">
<div class="w-7 h-7 rounded-full bg-primary-600 text-white flex items-center justify-center text-xs font-semibold">WS</div>
<div class="text-xs leading-tight">
<div class="font-medium text-neutral-800">魏深</div>
<div class="text-neutral-500">朝阳大区·大望路店</div>
</div>
<span class="text-sm font-medium text-primary-100">魏深</span>
</div>
</div>
</div>

View File

@@ -0,0 +1,488 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280">
<title>Fonrey 客源详情页 · 静态原型</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#F0FDFA',
100: '#CCFBF1',
200: '#99F6E4',
500: '#14B8A6',
600: '#0F766E',
700: '#115E59',
800: '#134E4A'
},
neutral: {
50: '#F8FAFC',
100: '#F1F5F9',
200: '#E2E8F0',
300: '#CBD5E1',
400: '#94A3B8',
500: '#64748B',
600: '#475569',
700: '#334155',
800: '#1E293B',
900: '#0F172A'
},
success: { 50: '#F0FDF4', 600: '#16A34A' },
warning: { 50: '#FFFBEB', 600: '#D97706' },
danger: { 50: '#FEF2F2', 600: '#DC2626' },
info: { 50: '#EFF6FF', 600: '#2563EB' }
},
boxShadow: {
xs: '0 1px 2px rgba(15,23,42,0.04)'
},
fontFamily: {
sans: ['Inter', 'PingFang SC', 'Microsoft YaHei', 'sans-serif'],
mono: ['JetBrains Mono', 'SFMono-Regular', 'Menlo', 'monospace']
}
}
}
}
</script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
html { scroll-behavior: smooth; }
.tabular-nums { font-variant-numeric: tabular-nums; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: #CBD5E1; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #94A3B8; }
</style>
</head>
<body class="bg-neutral-50 text-sm text-neutral-700 antialiased" x-data="clientDetailPage()">
<header class="fixed top-0 left-0 right-0 h-14 z-20 bg-primary-800 flex items-center justify-between">
<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 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 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>
<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 text-primary-100 hover:bg-primary-700 hover:text-white">交易</a>
<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 text-primary-100 hover:bg-primary-700 hover:text-white">人事</a>
<a class="px-3 py-1.5 text-sm rounded-md text-primary-100 hover:bg-primary-700 hover:text-white">系统</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="消息">
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022 23.848 23.848 0 0 0 5.454 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0"/></svg>
</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>
<aside class="fixed left-0 top-14 h-[calc(100vh-56px)] w-60 z-20 border-r border-neutral-200 bg-white">
<nav class="p-3 space-y-0.5">
<div class="px-2 pt-2 pb-1 text-xs font-medium text-neutral-500 uppercase tracking-wide">客源管理</div>
<a class="flex items-center gap-2 px-2 py-1.5 rounded-md bg-primary-50 text-primary-700 font-medium">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/></svg>
私客列表
</a>
<a class="flex items-center gap-2 px-2 py-1.5 rounded-md text-neutral-700 hover:bg-neutral-100">公客池</a>
<a class="flex items-center gap-2 px-2 py-1.5 rounded-md text-neutral-700 hover:bg-neutral-100">成交客</a>
<a class="flex items-center gap-2 px-2 py-1.5 rounded-md text-neutral-700 hover:bg-neutral-100">已删客源</a>
</nav>
</aside>
<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="面包屑">
<a class="hover:text-neutral-700">客源</a>
<svg class="w-3 h-3" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/></svg>
<a class="hover:text-neutral-700">私客管理</a>
<svg class="w-3 h-3" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"/></svg>
<span class="text-neutral-700">姚叔叔置换电梯两房(上门)</span>
</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">
<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>
<section id="section-requirements" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4 section-anchor">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">需求信息</h2>
<button class="text-sm text-primary-600 hover:text-primary-700 hover:underline underline-offset-2">编辑</button>
</header>
<dl class="grid grid-cols-3 gap-x-6 gap-y-4">
<div class="space-y-1"><dt class="text-xs text-neutral-500">总价</dt><dd class="text-sm text-neutral-900 tabular-nums">550-600万元</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">面积</dt><dd class="text-sm text-neutral-900 tabular-nums">100-110m2</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">居室</dt><dd class="text-sm text-neutral-900">2居</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">装修</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">朝向</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">楼层</dt><dd class="text-sm text-neutral-900">中楼层、低楼层</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">楼龄</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">意向商圈</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">意向小区</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1"><dt class="text-xs text-neutral-500">交通情况</dt><dd class="text-sm text-neutral-900">-</dd></div>
<div class="space-y-1 col-span-3"><dt class="text-xs text-neutral-500">备注</dt><dd class="text-sm text-neutral-900">-</dd></div>
</dl>
</section>
<section id="section-follow" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4 section-anchor">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">跟进记录</h2>
<button @click="drawerOpen=true" class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium bg-primary-600 text-white rounded-md hover:bg-primary-700 active:bg-primary-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Z"/></svg>
写跟进
</button>
</header>
<div class="flex items-center gap-2 flex-wrap">
<button class="px-3 py-1 text-xs rounded-full bg-primary-600 text-white">全部</button>
<button class="px-3 py-1 text-xs rounded-full bg-neutral-100 text-neutral-600 hover:bg-neutral-200">写入跟进</button>
<button class="px-3 py-1 text-xs rounded-full bg-neutral-100 text-neutral-600 hover:bg-neutral-200">敏感信息跟进</button>
<button class="px-3 py-1 text-xs rounded-full bg-neutral-100 text-neutral-600 hover:bg-neutral-200">修改跟进</button>
<button class="px-3 py-1 text-xs rounded-full bg-neutral-100 text-neutral-600 hover:bg-neutral-200">其他跟进</button>
</div>
<div class="border border-neutral-200 rounded-md p-3 bg-neutral-50 flex items-center gap-3 flex-wrap text-xs text-neutral-600">
<span class="text-neutral-500">筛选</span>
<input class="px-2 py-1 rounded border border-neutral-300 bg-white text-xs" placeholder="开始日期">
<span></span>
<input class="px-2 py-1 rounded border border-neutral-300 bg-white text-xs" placeholder="结束日期">
<label class="inline-flex items-center gap-1"><input type="checkbox" class="rounded border-neutral-300">有录音</label>
<label class="inline-flex items-center gap-1"><input type="checkbox" class="rounded border-neutral-300">有图片</label>
</div>
<ol class="relative border-l-2 border-neutral-200 ml-3 space-y-4 pl-5">
<li class="relative">
<span class="absolute -left-[27px] top-1 w-3 h-3 rounded-full bg-primary-600 ring-4 ring-white"></span>
<div class="rounded-md border border-neutral-200 p-3 bg-white space-y-1">
<div class="flex items-center gap-2 text-xs text-neutral-500">
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-info-50 text-info-600 font-medium">电话</span>
<time class="tabular-nums">11:25</time>
</div>
<p class="text-sm text-neutral-700">433弄5楼65.85平想置换丽晶苑2/3号楼楼层不要太高自己房子还没有挂牌。</p>
<p class="text-xs text-neutral-500">都市港湾店一组 雷威 · 2026-04-19</p>
</div>
</li>
<li class="relative">
<span class="absolute -left-[27px] top-1 w-3 h-3 rounded-full bg-warning-600 ring-4 ring-white"></span>
<div class="rounded-md border border-warning-600/20 bg-warning-50 p-3 space-y-1">
<div class="flex items-center gap-2 text-xs text-neutral-500">
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-warning-50 text-warning-600 font-medium">敏感查看</span>
<time class="tabular-nums">11:23</time>
</div>
<p class="text-sm text-neutral-700">查看联系人完整号码,系统自动留痕。</p>
<p class="text-xs text-neutral-500">系统记录 · 2026-04-19</p>
</div>
</li>
</ol>
<div class="text-center pt-1">
<button class="text-sm text-primary-600 hover:text-primary-700 hover:underline underline-offset-2">查看全部跟进</button>
</div>
</section>
<section id="section-viewings" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4 section-anchor">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">带看记录</h2>
<div class="flex items-center gap-2">
<button class="px-3 py-1.5 text-sm font-medium bg-white border border-neutral-300 text-neutral-700 rounded-md hover:bg-neutral-50 hover:border-neutral-400">新增预约</button>
<button class="px-3 py-1.5 text-sm font-medium bg-white border border-neutral-300 text-neutral-700 rounded-md hover:bg-neutral-50 hover:border-neutral-400">新增带看</button>
</div>
</header>
<div class="border border-neutral-200 rounded-md p-3 bg-neutral-50 flex items-center gap-3 flex-wrap text-xs text-neutral-600">
<label class="inline-flex items-center gap-1"><input type="checkbox" class="rounded border-neutral-300">归属人带看</label>
<label class="inline-flex items-center gap-1"><input type="checkbox" class="rounded border-neutral-300">其他人带看</label>
<input class="px-2 py-1 rounded border border-neutral-300 bg-white text-xs" placeholder="开始日期">
<span></span>
<input class="px-2 py-1 rounded border border-neutral-300 bg-white text-xs" placeholder="结束日期">
</div>
<ol class="relative border-l-2 border-neutral-200 ml-3 space-y-4 pl-5">
<li class="relative">
<span class="absolute -left-[27px] top-1 w-3 h-3 rounded-full bg-primary-600 ring-4 ring-white"></span>
<div class="rounded-md border border-neutral-200 p-3 bg-white space-y-1">
<p class="text-xs text-neutral-500 tabular-nums">2026-04-17 20:30</p>
<p class="text-sm text-neutral-700">带看情况:客户继续维护</p>
<p class="text-sm"><a class="text-primary-600 hover:underline" href="#">金沙丽晶苑一期-001-1201</a></p>
<p class="text-xs text-neutral-500"><span class="inline-flex items-center px-2 py-0.5 rounded-full bg-primary-50 text-primary-700 font-medium">一看</span> 带看:雷威 · <a class="text-primary-600 hover:underline" href="#">详情 ></a></p>
</div>
</li>
</ol>
</section>
<section id="section-insights" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4 section-anchor">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">客源解读</h2>
<span class="text-xs text-neutral-500">更新时间2026-04-25 09:12</span>
</header>
<div class="grid grid-cols-3 gap-3">
<div class="border border-neutral-200 rounded-md p-3 bg-white">
<p class="text-xs text-neutral-500">活跃行为</p>
<p class="mt-1 text-xl font-semibold text-neutral-900 tabular-nums">7 天内</p>
</div>
<div class="border border-neutral-200 rounded-md p-3 bg-white">
<p class="text-xs text-neutral-500">工作日活跃</p>
<p class="mt-1 text-xl font-semibold text-neutral-900 tabular-nums">-</p>
</div>
<div class="border border-neutral-200 rounded-md p-3 bg-white">
<p class="text-xs text-neutral-500">周末活跃</p>
<p class="mt-1 text-xl font-semibold text-neutral-900 tabular-nums">-</p>
</div>
</div>
<div class="grid grid-cols-3 gap-3">
<div class="border border-neutral-200 rounded-md p-3 text-center">
<p class="text-xs text-neutral-500">价格偏好</p>
<p class="mt-2 text-2xl font-semibold text-primary-600 tabular-nums">64%</p>
</div>
<div class="border border-neutral-200 rounded-md p-3 text-center">
<p class="text-xs text-neutral-500">户型偏好</p>
<p class="mt-2 text-2xl font-semibold text-primary-600 tabular-nums">22%</p>
</div>
<div class="border border-neutral-200 rounded-md p-3 text-center">
<p class="text-xs text-neutral-500">面积偏好</p>
<p class="mt-2 text-2xl font-semibold text-primary-600 tabular-nums">14%</p>
</div>
</div>
</section>
<section id="section-matches" class="scroll-mt-24 bg-white rounded-lg border border-neutral-200 p-4 space-y-4 section-anchor">
<header class="flex items-center justify-between">
<h2 class="text-base font-semibold text-neutral-800">二手配房</h2>
<button class="px-3 py-1.5 text-sm font-medium bg-white border border-neutral-300 text-neutral-700 rounded-md hover:bg-neutral-50 hover:border-neutral-400">批量分享</button>
</header>
<div class="space-y-3">
<h3 class="text-sm font-semibold text-neutral-700">优质户型</h3>
<article class="border border-neutral-200 rounded-md p-3">
<div class="flex gap-3">
<div class="w-20 h-14 rounded bg-neutral-100"></div>
<div class="min-w-0 flex-1">
<p class="text-sm font-medium text-primary-600 hover:underline cursor-pointer">都市港湾</p>
<p class="text-xs text-neutral-500">2/2/1 · 101.17m2 · 嘉定 丰庄</p>
<div class="mt-1 flex items-center gap-1">
<span class="inline-flex items-center px-1.5 py-0.5 text-[11px] rounded bg-warning-50 text-warning-600">朝南户型采光好</span>
<span class="inline-flex items-center px-1.5 py-0.5 text-[11px] rounded bg-info-50 text-info-600">私盘</span>
</div>
<p class="mt-1 text-sm font-medium text-neutral-900 tabular-nums">620万 <span class="text-xs font-normal text-neutral-500">已跌20万 · 61283元/m2</span></p>
</div>
</div>
</article>
</div>
</section>
</section>
<aside class="col-span-4 min-w-0 space-y-3 sticky top-16 max-h-[calc(100vh-80px)] overflow-y-auto">
<section class="bg-white rounded-lg border border-neutral-200 overflow-hidden">
<div class="bg-primary-600 px-4 py-3">
<div class="flex items-start gap-2">
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-white/20 text-white">求购</span>
<div class="min-w-0">
<h2 class="text-sm font-semibold text-white truncate">姚叔叔置换电梯两房(上门)先生</h2>
<p class="text-xs text-white/80 mt-0.5">带看进度:一看</p>
</div>
</div>
</div>
<div class="p-3 space-y-3">
<div class="flex items-center gap-1.5 flex-wrap">
<span class="inline-flex items-center px-1.5 py-0.5 text-xs rounded bg-neutral-100 text-neutral-600">私客</span>
<span class="inline-flex items-center px-1.5 py-0.5 text-xs rounded bg-primary-50 text-primary-700">一看</span>
<span class="inline-flex items-center px-1.5 py-0.5 text-xs rounded bg-warning-50 text-warning-600">C(一般)</span>
</div>
<dl class="space-y-1.5">
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">最近跟进</dt><dd class="text-xs text-right text-neutral-800 tabular-nums">2026-04-19</dd></div>
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">客户编号</dt><dd class="text-xs text-right text-neutral-800 font-mono">60419C03182A3</dd></div>
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">委托日期</dt><dd class="text-xs text-right text-neutral-800 tabular-nums">2026-04-19</dd></div>
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">需求类型</dt><dd class="text-xs text-right text-neutral-800">二手</dd></div>
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">房源用途</dt><dd class="text-xs text-right text-neutral-800">住宅</dd></div>
<div class="grid grid-cols-[72px_1fr] gap-2"><dt class="text-xs text-neutral-500">客户来源</dt><dd class="text-xs text-right text-neutral-800">线下丨门店接待</dd></div>
</dl>
<div class="grid grid-cols-3 gap-2">
<button class="flex flex-col items-center gap-1 py-2 text-xs font-medium bg-primary-600 text-white rounded-md hover:bg-primary-700">打电话</button>
<button @click="drawerOpen=true" class="flex flex-col items-center gap-1 py-2 text-xs font-medium bg-primary-600 text-white rounded-md hover:bg-primary-700">写跟进</button>
<button class="flex flex-col items-center gap-1 py-2 text-xs font-medium bg-primary-600 text-white rounded-md hover:bg-primary-700">报备/常看</button>
</div>
<div class="grid grid-cols-2 gap-1">
<button class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">收藏</button>
<button class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">不置顶</button>
<button @click="modal='grade'" class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">改等级</button>
<button @click="modal='status'" class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">改状态</button>
<button class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">转公客</button>
<button @click="modal='deal'" class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">转成交</button>
<button class="px-2 py-2 text-xs text-left rounded-md text-danger-600 hover:bg-danger-50">转无效</button>
<button @click="modal='edit'" class="px-2 py-2 text-xs text-left rounded-md text-neutral-600 hover:bg-neutral-100">编辑客源</button>
</div>
</div>
</section>
<section class="bg-white rounded-lg border border-neutral-200 p-3">
<header class="flex items-center justify-between mb-2">
<h3 class="text-sm font-semibold text-neutral-800">联系人</h3>
<div class="text-xs text-primary-600 space-x-2">
<button class="hover:underline">查看号码</button>
<button class="hover:underline">新增联系人</button>
</div>
</header>
<div class="space-y-1">
<p class="text-sm font-medium text-neutral-900">姚叔叔置换电梯两房(上门)先生</p>
<p class="text-xs text-neutral-600 tabular-nums">电话1+86 137****8888</p>
<p class="text-xs text-neutral-500">默认拨打 · 接通0次 · 拨打0次</p>
</div>
</section>
<section class="bg-white rounded-lg border border-neutral-200 p-3">
<header class="flex items-center justify-between mb-2">
<h3 class="text-sm font-semibold text-neutral-800">相关员工</h3>
<button class="text-xs text-primary-600 hover:underline">编辑</button>
</header>
<div class="space-y-3">
<div>
<p class="text-xs font-medium text-neutral-700">【首录人】</p>
<p class="text-sm text-neutral-900">都市港湾店一组 雷威</p>
<p class="text-xs text-neutral-500 tabular-nums">参与时间2026-04-17 19:21</p>
</div>
<div>
<p class="text-xs font-medium text-neutral-700">【归属人】</p>
<p class="text-sm text-neutral-900">都市港湾店一组 雷威</p>
<p class="text-xs text-neutral-500 tabular-nums">参与时间2026-04-17 19:21</p>
</div>
</div>
</section>
</aside>
</div>
</div>
</main>
<div x-show="modal" x-transition.opacity class="fixed inset-0 z-50 bg-neutral-900/40" @click="modal = null"></div>
<div x-show="modal === 'grade'" x-transition class="fixed inset-0 z-60 flex items-center justify-center p-4 pointer-events-none">
<div class="w-full max-w-sm bg-white rounded-xl shadow-lg border border-neutral-200 pointer-events-auto flex flex-col">
<div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200"><h2 class="text-base font-semibold text-neutral-800">改等级</h2><button @click="modal = null" class="p-1 text-neutral-500 hover:bg-neutral-100 rounded-md">x</button></div>
<div class="px-5 py-4 space-y-3"><p class="text-sm text-neutral-500">原等级C(一般)</p><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300 focus:outline-none focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20"><option>请选择新等级</option><option>A_urgent</option><option>A</option><option>B</option><option>C</option><option>D</option><option>E</option></select></div>
<div class="flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50"><button @click="modal = null" class="px-3 py-1.5 text-sm border border-neutral-300 rounded-md hover:bg-white">取消</button><button class="px-3 py-1.5 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700">保存</button></div>
</div>
</div>
<div x-show="modal === 'status'" x-transition class="fixed inset-0 z-60 flex items-center justify-center p-4 pointer-events-none">
<div class="w-full max-w-md bg-white rounded-xl shadow-lg border border-neutral-200 pointer-events-auto flex flex-col">
<div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200"><h2 class="text-base font-semibold text-neutral-800">改状态</h2><button @click="modal = null" class="p-1 text-neutral-500 hover:bg-neutral-100 rounded-md">x</button></div>
<div class="px-5 py-4 space-y-3">
<p class="text-sm text-neutral-500">原状态:求购</p>
<select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>请选择新状态</option><option>暂缓</option><option>转公</option><option>成交</option><option>无效</option></select>
<textarea rows="3" class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300" placeholder="请输入更改理由"></textarea>
</div>
<div class="flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50"><button @click="modal = null" class="px-3 py-1.5 text-sm border border-neutral-300 rounded-md hover:bg-white">取消</button><button class="px-3 py-1.5 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700">保存</button></div>
</div>
</div>
<div x-show="modal === 'deal'" x-transition class="fixed inset-0 z-60 flex items-center justify-center p-4 pointer-events-none">
<div class="w-full max-w-lg bg-white rounded-xl shadow-lg border border-neutral-200 pointer-events-auto flex flex-col">
<div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200"><h2 class="text-base font-semibold text-neutral-800">转成交</h2><button @click="modal = null" class="p-1 text-neutral-500 hover:bg-neutral-100 rounded-md">x</button></div>
<div class="px-5 py-4 space-y-3">
<div class="grid grid-cols-2 gap-3">
<div><label class="block text-xs text-neutral-500 mb-1">状态</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>我购</option><option>我租</option></select></div>
<div><label class="block text-xs text-neutral-500 mb-1">房源类型</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>二手</option><option>新房</option></select></div>
<div class="col-span-2"><label class="block text-xs text-neutral-500 mb-1">成交房源</label><button class="w-full px-3 py-2 text-sm border border-neutral-300 rounded-md text-left text-primary-600 hover:bg-neutral-50">+ 选择成交房源</button></div>
</div>
</div>
<div class="flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50"><button @click="modal = null" class="px-3 py-1.5 text-sm border border-neutral-300 rounded-md hover:bg-white">取消</button><button class="px-3 py-1.5 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700">确认转成交</button></div>
</div>
</div>
<div x-show="modal === 'edit'" x-transition class="fixed inset-0 z-60 flex items-center justify-center p-4 pointer-events-none">
<div class="w-full max-w-2xl bg-white rounded-xl shadow-lg border border-neutral-200 pointer-events-auto flex flex-col max-h-[85vh]">
<div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200"><h2 class="text-base font-semibold text-neutral-800">编辑基础信息</h2><button @click="modal = null" class="p-1 text-neutral-500 hover:bg-neutral-100 rounded-md">x</button></div>
<div class="flex-1 overflow-y-auto px-5 py-4">
<div class="grid grid-cols-2 gap-3">
<div><label class="block text-xs text-neutral-500 mb-1">需求类型</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>二手</option><option>新房</option></select></div>
<div><label class="block text-xs text-neutral-500 mb-1">来源</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>线下丨门店接待</option></select></div>
<div><label class="block text-xs text-neutral-500 mb-1">用途</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>住宅</option></select></div>
<div><label class="block text-xs text-neutral-500 mb-1">付款方式</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>请选择</option></select></div>
<div class="col-span-2"><label class="block text-xs text-neutral-500 mb-1">证件号码</label><input class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300" placeholder="请输入证件号码"></div>
</div>
</div>
<div class="flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50"><button @click="modal = null" class="px-3 py-1.5 text-sm border border-neutral-300 rounded-md hover:bg-white">取消</button><button class="px-3 py-1.5 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700">保存</button></div>
</div>
</div>
<div x-show="drawerOpen" x-transition.opacity class="fixed inset-0 z-50 bg-neutral-900/40" @click="drawerOpen = false"></div>
<aside x-show="drawerOpen" x-transition:enter="ease-out duration-200" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0" x-transition:leave="ease-in duration-150" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full" class="fixed right-0 top-0 h-full w-[480px] z-60 bg-white shadow-lg flex flex-col border-l border-neutral-200">
<div class="flex items-center justify-between px-5 py-4 border-b border-neutral-200"><h2 class="text-base font-semibold text-neutral-800">写入跟进</h2><button @click="drawerOpen=false" class="p-1 text-neutral-500 hover:bg-neutral-100 rounded-md">x</button></div>
<div class="flex-1 overflow-y-auto px-5 py-4 space-y-3">
<div><label class="block text-xs text-neutral-500 mb-1">跟进方式</label><select class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300"><option>电话</option><option>上门</option><option>微信</option><option>短信</option><option>其他</option></select></div>
<div><label class="block text-xs text-neutral-500 mb-1">跟进内容</label><textarea rows="4" class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300" placeholder="至少6字"></textarea></div>
<div><label class="block text-xs text-neutral-500 mb-1">跟进时间</label><input class="w-full px-3 py-2 text-sm rounded-md border border-neutral-300" value="2026-04-25 10:30"></div>
<div><label class="block text-xs text-neutral-500 mb-1">附件</label><input type="file" class="w-full text-sm"></div>
<label class="inline-flex items-center gap-2 text-sm text-neutral-700"><input type="checkbox" checked class="rounded border-neutral-300">是否开放给同事查看</label>
</div>
<div class="flex items-center justify-end gap-2 px-5 py-3 border-t border-neutral-200 bg-neutral-50"><button @click="drawerOpen=false" class="px-3 py-1.5 text-sm border border-neutral-300 rounded-md hover:bg-white">取消</button><button class="px-3 py-1.5 text-sm bg-primary-600 text-white rounded-md hover:bg-primary-700">提交</button></div>
</aside>
<script>
function clientDetailPage() {
return {
modal: 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((section) => this.observer.observe(section))
}
}
}
</script>
</body>
</html>