Sync: refine ui design notes
This commit is contained in:
@@ -15,21 +15,21 @@
|
||||
- 1.3 用户角色与权限差异
|
||||
2. [页面设计规范](#2-页面设计规范)
|
||||
- 2.1 客源列表主页(私客视图)
|
||||
3. [弹窗/抽屉设计规范](#3-弹窗抽屉设计规范)
|
||||
- 3.1 改等级弹窗
|
||||
- 3.2 改状态弹窗
|
||||
- 3.3 转公客弹窗
|
||||
- 3.4 转成交弹窗
|
||||
- 3.5 转无效弹窗
|
||||
- 3.6 收藏夹选择弹窗
|
||||
4. [交互状态规范](#4-交互状态规范)
|
||||
- 4.1 客源状态机
|
||||
- 4.2 权限控制矩阵
|
||||
- 4.3 HTMX 请求规范
|
||||
5. [关键数据字段说明](#5-关键数据字段说明)
|
||||
6. [竞品截图对应关系](#6-竞品截图对应关系)
|
||||
7. [实现优先级与工期估算](#7-实现优先级与工期估算)
|
||||
8. [开放问题(待决策)](#8-开放问题待决策)
|
||||
3. [Data Table 规范](#3-data-table-规范)
|
||||
- 3.1 列定义
|
||||
- 3.2 列状态变体
|
||||
- 3.3 操作列
|
||||
- 3.4 表格交互状态
|
||||
4. [弹窗设计规范(列表页)](#4-弹窗设计规范列表页)
|
||||
- 4.1 自定义列弹窗
|
||||
5. [交互状态规范](#5-交互状态规范)
|
||||
- 5.1 客源状态机
|
||||
- 5.2 权限控制矩阵
|
||||
- 5.3 HTMX 请求规范
|
||||
6. [关键数据字段说明](#6-关键数据字段说明)
|
||||
7. [竞品截图对应关系](#7-竞品截图对应关系)
|
||||
8. [实现优先级与工期估算](#8-实现优先级与工期估算)
|
||||
9. [开放问题(待决策)](#9-开放问题待决策)
|
||||
|
||||
---
|
||||
|
||||
@@ -664,7 +664,7 @@ HTMX 行为:所有筛选变更统一通过 `hx-get="/clients/private/" hx-trig
|
||||
| Tab Navigation | §10 Tab Navigation | 一级/二级 Tab 切换 | 一级用 underline 样式,二级用 pill 样式 |
|
||||
| Date Range Picker | §9 Date Range Picker | 「录入时间」「委托日期」「跟进时间」筛选 | 集成 Flatpickr,range 模式 |
|
||||
| Multi-select Tag Input | §17 Multi-select Tag Input | 位置(多选区)、等级(多选)筛选 | 无需 Tag Input 样式,直接用按钮多选组 |
|
||||
| Modal Dialog | §7 Modal Dialog | 改等级/改状态/转公客/转成交/转无效弹窗 | 见第3章各弹窗规范 |
|
||||
| Modal Dialog | §7 Modal Dialog | 自定义列弹窗 | 见§4.1 自定义列弹窗规范 |
|
||||
|
||||
#### 2.1.5 空状态设计
|
||||
|
||||
@@ -726,343 +726,215 @@ HTMX loading 触发:在 `<div id="client-list-container">` 添加 `hx-indicato
|
||||
|
||||
---
|
||||
|
||||
## 3. 弹窗/抽屉设计规范
|
||||
## 3. Data Table 规范
|
||||
|
||||
### 3.1 改等级弹窗(P0 🔴)
|
||||
> 引用基础规范:`组件规范设计.md` §1 Data Table
|
||||
> 本章描述客源列表页 Data Table 的**具体实例化配置**,包含列定义、单元格渲染、排序、选中、空状态和操作列。
|
||||
|
||||
#### 3.1.1 触发方式
|
||||
### 3.1 列定义(全部私客 / 求购视图)
|
||||
|
||||
- **触发位置**:客源详情页右侧信息概览面板「改等级」快捷按钮(本文档中列表页行内操作暂无此入口,详情页触发)
|
||||
- **组件类型**:Modal Dialog(选择理由:操作简单,2个字段,Drawer 过重)
|
||||
- **尺寸**:`max-w-sm`(384px)
|
||||
- **竞品截图**:竞品中改等级为小弹窗形式,与 Modal sm 对应
|
||||
表格容器:`<table class="min-w-full divide-y divide-neutral-200">`
|
||||
表头行:`<thead class="bg-neutral-50">`,列头单元格统一样式:`px-4 py-3 text-left text-xs font-semibold text-neutral-500 uppercase tracking-wide whitespace-nowrap`
|
||||
数据行:`<tr class="hover:bg-neutral-50 transition-colors" style="height:56px">`
|
||||
|
||||
#### 3.1.2 表单字段规范
|
||||
| # | 列名 | 数据字段 | 列宽 | 对齐 | 可排序 | 特殊渲染说明 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | (复选框) | — | `w-10`(40px)`px-4` | 居中 | 否 | 全选:表头 `<input type="checkbox" id="select-all">`;单选:行内 `<input type="checkbox" x-model="selected" :value="client.id">` |
|
||||
| 2 | 姓名 | `contact_name` + `grade_display` + 活跃度标签 | `min-w-[160px] max-w-[200px]` | 左对齐 | 否 | 蓝色链接 `text-info-600 hover:underline`;下方渲染 Grade Badge + 活跃度 Tag(见 §3.2) |
|
||||
| 3 | 状态 | `status_display` | `w-20`(80px) | 左对齐 | 否 | Status Badge(见 §3.2) |
|
||||
| 4 | 需求类型 | `requirement_type_display` | `w-20`(80px) | 左对齐 | 否 | 纯文字:二手 / 新房 / 租房 |
|
||||
| 5 | 需求/解读 | `budget_area_display` | `min-w-[180px]` | 左对齐 | 否 | 截断 `truncate`;Tooltip 展示完整内容(`title` 属性) |
|
||||
| 6 | 智能配房 | `match_count` | `w-24`(96px) | 左对齐 | 否 | `N套` + Heroicon `information-circle`(`w-4 h-4 text-neutral-400 ml-1 cursor-pointer`);点击弹出配房预览 Popover |
|
||||
| 7 | 意向商圈/小区 | `intent_location_display` | `min-w-[120px]` | 左对齐 | 否 | 多值逗号分隔;`-` 表示未填;截断 `truncate max-w-[160px]` |
|
||||
| 8 | 归属人 | `owner_display` | `min-w-[140px]` | 左对齐 | 否 | 格式:`姓名-门店组`;`text-sm text-neutral-700` |
|
||||
| 9 | 带看进度 | `viewing_progress_display` | `w-20`(80px) | 左对齐 | 否 | 「未带看」灰色文字;「一看」`bg-warning-50 text-warning-600 px-2 py-0.5 rounded-full text-xs`;「二看」`bg-info-50 text-info-600`;「复看」`bg-success-50 text-success-600` |
|
||||
| 10 | 带看次数 | `viewing_count` | `w-[72px]` | 左对齐 | 是 | `N次`;点击列头触发 HTMX 排序 |
|
||||
| 11 | 委托日期 | `commission_date` | `w-24`(96px) | 左对齐 | 是 | `YYYY-MM-DD`;未填显示 `-` |
|
||||
| 12 | 最近时间 | `last_follow_display` / `last_contact_display` | `w-24`(96px) | 左对齐 | 是(默认降序) | `N天前` / `今天`;超过 30 天字色 `text-danger-600` |
|
||||
| 13 | 操作 | — | `w-16`(64px) | 居中 | 否 | 见 §3.3 |
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值/预填值 |
|
||||
|---|---|---|---|---|
|
||||
| 原等级(只读) | 只读文本展示 | — | — | 当前等级值,如「C(一般)」 |
|
||||
| 新等级 | Select 下拉 | 是 | 必选 | 无默认值 |
|
||||
> **自定义列**(P1 🟡):用户通过「自定义列表」弹窗(§4.1)选择显示字段后,后端将用户配置存入 `UserColumnPreference`,Django 模板根据配置动态渲染列头和列单元格。可选字段见截图 `客源列表-自定义字段.png`:录入日期、最近通话日期、用途、来源、客源编号、首录人、成交人等。
|
||||
|
||||
新等级选项:A急迫 / A / B较强 / C一般 / D较弱 / E暂不关注
|
||||
---
|
||||
|
||||
#### 3.1.3 提交行为
|
||||
### 3.2 列状态变体
|
||||
|
||||
- **提交方式**:HTMX `hx-post="/clients/private/{id}/grade/"`
|
||||
- **成功响应**:关闭弹窗 + Toast「等级已更新」+ HTMX 局部刷新客源信息概览面板(`hx-target="#client-info-panel" hx-swap="innerHTML"`)
|
||||
- **失败响应(422)**:在「新等级」下方显示行内错误文字 `text-danger-600 text-xs`
|
||||
- **HTMX 属性**:
|
||||
**活跃度标签(姓名列下方,行内渲染,多个并排)**
|
||||
|
||||
| 标签值 | 显示文字 | Tailwind 样式 |
|
||||
|---|---|---|
|
||||
| `new_matched` | 新配房 | `bg-info-50 text-info-600` |
|
||||
| `active_7d` | 7日活跃 | `bg-success-50 text-success-600` |
|
||||
| `active_30d` | 30日活跃 | `bg-green-50 text-green-500` |
|
||||
| `expiring` | 即将过期 | `bg-warning-50 text-warning-600` |
|
||||
| `frozen` | 暂缓 | `bg-neutral-100 text-neutral-500` |
|
||||
| `invalid` | 无效 | `bg-danger-50 text-danger-600` |
|
||||
| 来源为营销 | 营销客 | `bg-purple-50 text-purple-600` |
|
||||
| 来源为销售 | 销售客 | `bg-orange-50 text-orange-600` |
|
||||
| 来源为访客 | 访客 | `bg-neutral-100 text-neutral-500` |
|
||||
|
||||
标签 HTML:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/grade/"
|
||||
hx-target="#client-info-panel"
|
||||
<span class="text-[11px] px-1.5 py-0.5 rounded-full font-medium bg-info-50 text-info-600">
|
||||
新配房
|
||||
</span>
|
||||
```
|
||||
|
||||
**状态 Badge(状态列)**
|
||||
|
||||
| `status` 值 | 显示文字 | 样式 |
|
||||
|---|---|---|
|
||||
| `buying` | 求购 | `bg-primary-50 text-primary-700 text-xs px-2 py-0.5 rounded-full` |
|
||||
| `renting` | 求租 | `bg-info-50 text-info-600 text-xs px-2 py-0.5 rounded-full` |
|
||||
| `buy_or_rent` | 租购 | `bg-warning-50 text-warning-600 text-xs px-2 py-0.5 rounded-full` |
|
||||
| `suspended` | 暂缓 | `bg-neutral-100 text-neutral-500 text-xs px-2 py-0.5 rounded-full` |
|
||||
|
||||
**排序列头**(带看次数 / 委托日期 / 最近时间):
|
||||
```html
|
||||
<th class="px-4 py-3 text-left text-xs font-semibold text-neutral-500 uppercase tracking-wide
|
||||
cursor-pointer hover:bg-neutral-100 select-none whitespace-nowrap"
|
||||
hx-get="/clients/private/"
|
||||
:hx-vals="JSON.stringify({sort: 'viewing_count', order: currentOrder})"
|
||||
hx-target="#client-list-container"
|
||||
hx-swap="innerHTML"
|
||||
hx-include="closest form">
|
||||
带看次数
|
||||
<!-- 未排序:双箭头图标 -->
|
||||
<svg class="inline w-4 h-4 text-neutral-300 ml-0.5"><!-- chevron-up-down --></svg>
|
||||
<!-- 升序激活:向上箭头 text-primary-600 -->
|
||||
<!-- 降序激活:向下箭头 text-primary-600 -->
|
||||
</th>
|
||||
```
|
||||
|
||||
**行选中态**:
|
||||
```html
|
||||
<tr class="hover:bg-neutral-50 transition-colors h-14"
|
||||
:class="selected.includes(client.id) ? 'bg-primary-50 hover:bg-primary-100' : ''">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 操作列
|
||||
|
||||
操作列宽 `w-16`(64px),居中对齐,固定在表格最右侧。
|
||||
|
||||
MVP 阶段操作列仅包含一个「拨号」图标按钮:
|
||||
|
||||
```html
|
||||
<td class="px-3 py-2 text-center">
|
||||
<button class="inline-flex items-center justify-center w-8 h-8 rounded-md
|
||||
text-primary-600 hover:bg-primary-50 hover:text-primary-700
|
||||
transition-colors"
|
||||
title="拨号"
|
||||
@click="$dispatch('open-dial-modal', { clientId: '{{ client.id }}', phone: '{{ client.contact_phone_masked }}' })">
|
||||
<svg class="w-5 h-5"><!-- heroicon: phone --></svg>
|
||||
</button>
|
||||
</td>
|
||||
```
|
||||
|
||||
> 后续迭代可在操作列增加「更多操作」下拉菜单(`...` 图标),包含跟进记录、收藏、转无效等快捷操作,但 MVP 阶段不实现,避免列表行交互过重。
|
||||
|
||||
---
|
||||
|
||||
### 3.4 表格交互状态
|
||||
|
||||
| 状态 | 触发场景 | 视觉表现 |
|
||||
|---|---|---|
|
||||
| 默认(无选中) | 页面加载完毕 | 所有行 `bg-white`,hover 时 `bg-neutral-50` |
|
||||
| 行选中 | 勾选复选框 | `bg-primary-50 hover:bg-primary-100`;工具栏批量操作按钮激活 |
|
||||
| 全选 | 点击表头复选框 | 当前页所有行选中;表头 checkbox `indeterminate` 或 `checked` |
|
||||
| Loading(HTMX 请求中) | 筛选/分页/排序触发 | 骨架屏覆盖 `#client-list-container`(见 §2.1.6) |
|
||||
| 空状态(无数据) | 筛选无结果 / 首次进入 | 见 §2.1.5 空状态设计 |
|
||||
| 置顶行 | `is_pinned = true` | 行头部显示 `⬆` 或 `bg-warning-50/30` 浅黄底色(产品待确认)|
|
||||
|
||||
---
|
||||
|
||||
## 4. 弹窗设计规范(列表页)
|
||||
|
||||
> **范围说明**:本章仅包含从**客源列表页直接触发**的弹窗。改等级、改状态、转公客、转成交、转无效、收藏夹等操作弹窗从**客源详情页**触发,应记录于详情页 UI 设计文档。
|
||||
|
||||
### 4.1 自定义列弹窗(P1 🟡)
|
||||
|
||||
#### 4.1.1 触发方式
|
||||
|
||||
- **触发位置**:工具栏右侧「自定义列表」按钮(Heroicon `adjustments-horizontal` + 文字)
|
||||
- **组件类型**:Modal Dialog(`组件规范设计.md` §7)
|
||||
- **尺寸**:`max-w-2xl`(640px)
|
||||
- **竞品参考截图**:`Project/fonrey/screenshots/客源/客源列表-自定义字段.png`
|
||||
|
||||
#### 4.1.2 弹窗布局
|
||||
|
||||
弹窗分为左右两栏:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 标题:自定义信息 [×] │
|
||||
├────────────────────────┬────────────────────────────┤
|
||||
│ 未选信息 │ 已选信息 │
|
||||
│ (可勾选字段列表) │ (已选字段,拖拽排序) │
|
||||
│ │ ┌─────────────────────┐ │
|
||||
│ □ 录入日期 │ │ ⋮⋮ 姓名 [删] │ │
|
||||
│ □ 最近通话日期 │ │ ⋮⋮ 状态 [删] │ │
|
||||
│ □ 用途 │ │ ⋮⋮ 需求类型 [删] │ │
|
||||
│ □ 来源 │ │ ⋮⋮ 需求/解读 [删] │ │
|
||||
│ □ 客源编号 │ │ ... │ │
|
||||
│ □ 首录人 │ └─────────────────────┘ │
|
||||
│ □ 成交人 │ 提示:拖拽可调整展示顺序 │
|
||||
├────────────────────────┴────────────────────────────┤
|
||||
│ [恢复默认] [取消] [确定] │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 4.1.3 字段说明
|
||||
|
||||
**未选信息区(左栏)**:
|
||||
- 显示所有可用但当前未选中的字段
|
||||
- 每项为 Checkbox + 字段名,点击勾选后字段移至右栏「已选信息」
|
||||
- 可用字段(参考截图):录入日期、最近通话日期、用途、来源、客源编号、首录人、成交人
|
||||
|
||||
**已选信息区(右栏)**:
|
||||
- 显示当前已选中的字段列表,带序号/排序手柄(`⋮⋮` Heroicon `bars-2`)
|
||||
- 拖拽排序(SortableJS 或原生 HTML5 drag-and-drop)
|
||||
- 每行末尾「删除」图标(Heroicon `x-mark`,`text-neutral-400 hover:text-danger-600`)点击将字段移回左栏
|
||||
- 固定字段(如「姓名」)不可删除(无删除图标,显示锁形图标 `lock-closed`)
|
||||
|
||||
#### 4.1.4 底部操作
|
||||
|
||||
| 按钮 | 位置 | 行为 |
|
||||
|---|---|---|
|
||||
| 恢复默认 | 底部左侧 | 重置为系统默认列配置;Alpine.js 本地状态重置,不立即提交 |
|
||||
| 取消 | 底部右侧次按钮 | 关闭弹窗,不保存 |
|
||||
| 确定 | 底部右侧主按钮 | `hx-post="/clients/column-preferences/"` 保存配置 → 关闭弹窗 → HTMX 刷新 `#client-list-container` 以重新渲染列 |
|
||||
|
||||
#### 4.1.5 提交行为
|
||||
|
||||
```html
|
||||
<form hx-post="/clients/column-preferences/"
|
||||
hx-target="#client-list-container"
|
||||
hx-swap="innerHTML"
|
||||
hx-on::after-request="if(event.detail.successful) { $dispatch('close-modal'); $dispatch('show-toast', {message: '等级已更新', type: 'success'}); }">
|
||||
hx-on::after-request="if(event.detail.successful){ $dispatch('close-modal'); }">
|
||||
<!-- 隐藏域:序列化已选字段顺序 -->
|
||||
<input type="hidden" name="columns" :value="JSON.stringify(selectedColumns)">
|
||||
...
|
||||
<button type="submit" :disabled="!newGrade"
|
||||
:class="newGrade ? 'bg-primary-600 hover:bg-primary-700' : 'bg-neutral-200 cursor-not-allowed'"
|
||||
class="px-4 py-2 text-white text-sm font-medium rounded-lg">
|
||||
<button type="submit"
|
||||
class="px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white
|
||||
text-sm font-medium rounded-lg transition-colors">
|
||||
确定
|
||||
</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
#### 3.1.4 使用的特殊组件
|
||||
#### 4.1.6 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器,`max-w-sm` |
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器,`max-w-2xl` |
|
||||
|
||||
Alpine.js 管理:弹窗开关(`open`),`newGrade` 绑定,确定按钮 disabled 状态。
|
||||
Alpine.js 管理:`selectedColumns`(有序数组)、`availableColumns`(剩余可选)、`dragging` 状态;拖拽排序通过 Alpine.js + SortableJS CDN 实现。
|
||||
|
||||
---
|
||||
## 5. 交互状态规范
|
||||
|
||||
### 3.2 改状态弹窗(P0 🔴)
|
||||
|
||||
#### 3.2.1 触发方式
|
||||
|
||||
- **触发位置**:客源详情页信息概览面板「改状态」按钮
|
||||
- **组件类型**:Modal Dialog
|
||||
- **尺寸**:`max-w-sm`(384px)
|
||||
|
||||
#### 3.2.2 表单字段规范
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值/预填值 |
|
||||
|---|---|---|---|---|
|
||||
| 原状态(只读) | 只读文本 | — | — | 当前状态,如「求购」 |
|
||||
| 新状态 | Select | 是 | 必选;不能与原状态相同 | 无默认值 |
|
||||
| 等级 | Select | 否 | — | 当前等级值(可修改) |
|
||||
| 更改理由 | Textarea | 是 | 最少 1 字,最多 200 字 | 空 |
|
||||
|
||||
新状态选项:求购 / 求租 / 租购
|
||||
|
||||
#### 3.2.3 提交行为
|
||||
|
||||
- **提交方式**:`hx-post="/clients/private/{id}/status/"`
|
||||
- **成功响应**:关闭弹窗 + Toast「状态已更新」+ 刷新客源信息概览面板
|
||||
- **失败响应(422)**:字段级红字提示(Textarea 下方显示「请填写更改理由」)
|
||||
- **HTMX 属性**:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/status/"
|
||||
hx-target="#client-info-panel"
|
||||
hx-swap="innerHTML"
|
||||
hx-on::after-request="if(event.detail.successful) closeModalAndToast('状态已更新')">
|
||||
```
|
||||
|
||||
「确定」按钮:`newStatus` 未选或 `reason` 为空时 disabled。
|
||||
|
||||
#### 3.2.4 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器 |
|
||||
|
||||
---
|
||||
|
||||
### 3.3 转公客弹窗(P0 🔴)
|
||||
|
||||
#### 3.3.1 触发方式
|
||||
|
||||
- **触发位置**:客源详情页信息概览面板「转公客」按钮
|
||||
- **组件类型**:Modal Dialog(操作不可逆,需明确确认)
|
||||
- **尺寸**:`max-w-sm`
|
||||
|
||||
#### 3.3.2 表单字段规范
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值/预填值 |
|
||||
|---|---|---|---|---|
|
||||
| 状态 | Select | 是 | 必选 | 当前状态值 |
|
||||
| 等级 | Select | 是 | 必选 | 当前等级值 |
|
||||
|
||||
弹窗标题区下方显示橙色警告提示:
|
||||
```html
|
||||
<div class="bg-warning-50 border border-warning-200 rounded-md px-3 py-2 text-sm text-warning-600 mb-4">
|
||||
转为公客后将无法撤销,该客源将进入公共客源池,全员可见可跟进。
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 3.3.3 提交行为
|
||||
|
||||
- **提交方式**:`hx-post="/clients/private/{id}/to-public/"`
|
||||
- **成功响应**:关闭弹窗 + Toast「已转为公客」+ 跳转至私客列表页(`window.location.href = '/clients/private/'`)
|
||||
- **HTMX 属性**:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/to-public/"
|
||||
hx-on::after-request="if(event.detail.successful){ showToast('已转为公客'); window.location.href='/clients/private/'; }">
|
||||
```
|
||||
|
||||
#### 3.3.4 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器,含不可逆警告 |
|
||||
|
||||
---
|
||||
|
||||
### 3.4 转成交弹窗(P0 🔴)
|
||||
|
||||
#### 3.4.1 触发方式
|
||||
|
||||
- **触发位置**:客源详情页信息概览面板「转成交」按钮
|
||||
- **组件类型**:Modal Dialog(需录入成交信息,字段较多)
|
||||
- **尺寸**:`max-w-lg`(512px)
|
||||
|
||||
#### 3.4.2 表单字段规范
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值/预填值 |
|
||||
|---|---|---|---|---|
|
||||
| 状态 | Radio(我购 / 我租) | 是 | — | 我购 |
|
||||
| 房源类型 | Radio(二手 / 新房) | 是 | — | 二手 |
|
||||
| 成交房源 | 房源选择器(链接按钮 → 弹出选择浮层) | 是 | 必选1套 | 空 |
|
||||
| 成交日期 | Date Picker | 是 | 不能晚于今日 | 当日 |
|
||||
| 成交价格 | Number Input(单位:万元) | 是 | > 0 | 空 |
|
||||
| 成交方 | 人员选择器 | 是 | — | 当前登录用户所属门店 |
|
||||
|
||||
**成交房源选择器**:点击「+ 选择成交房源」按钮,弹出独立 Modal(`max-w-4xl`),包含:
|
||||
- 搜索框(房源编号/楼盘地址/业主姓名/电话)
|
||||
- 筛选栏(区域/状态/相关方/部门)
|
||||
- 表格(房源名称、交易类型、状态、用途、城区商圈、房型、楼层、面积)
|
||||
- 单选(Radio per row)
|
||||
- 分页(50条/页,共89704条)
|
||||
- 底部「已选(0)」+ 「确定」按钮
|
||||
|
||||
#### 3.4.3 提交行为
|
||||
|
||||
- **提交方式**:`hx-post="/clients/private/{id}/to-transacted/"`
|
||||
- **成功响应**:关闭弹窗 + Toast「已标记为成交」+ 跳转详情页刷新状态
|
||||
- **失败响应(422)**:字段级错误提示
|
||||
- **HTMX 属性**:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/to-transacted/"
|
||||
hx-target="body"
|
||||
hx-swap="none"
|
||||
hx-on::after-request="handleTransactedResponse(event)">
|
||||
```
|
||||
|
||||
#### 3.4.4 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 主弹窗容器(`max-w-lg`) |
|
||||
| Modal Dialog(嵌套) | §7 Modal Dialog | 成交房源选择浮层(`max-w-4xl`) |
|
||||
| Date Range Picker | §9 Date Range Picker | 成交日期单选(single mode) |
|
||||
| Data Table | §1 Data Table | 房源选择列表 |
|
||||
| Pagination | §2 Pagination | 房源选择分页 |
|
||||
|
||||
---
|
||||
|
||||
### 3.5 转无效弹窗(P0 🔴)
|
||||
|
||||
#### 3.5.1 触发方式
|
||||
|
||||
- **触发位置**:客源详情页信息概览面板「转无效」按钮
|
||||
- **组件类型**:Modal Dialog(操作相对不可逆)
|
||||
- **尺寸**:`max-w-sm`
|
||||
|
||||
#### 3.5.2 表单字段规范
|
||||
|
||||
弹窗顶部蓝色信息提示框:
|
||||
```html
|
||||
<div class="bg-info-50 border border-info-200 rounded-md px-3 py-2 text-sm text-info-600 mb-4">
|
||||
该功能为整体客转无效,将把所有电话标记无效
|
||||
</div>
|
||||
```
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值/预填值 |
|
||||
|---|---|---|---|---|
|
||||
| 无效原因 | Radio List(单选) | 是 | 必选1项 | 号码无效(第一项) |
|
||||
|
||||
Radio 选项:
|
||||
- ⦿ 号码无效(默认)
|
||||
- ○ 同行中介
|
||||
- ○ 广告推销
|
||||
- ○ 客户无意向
|
||||
- ○ 其他
|
||||
|
||||
Radio HTML:
|
||||
```html
|
||||
<fieldset class="space-y-2">
|
||||
{% for reason in invalid_reasons %}
|
||||
<label class="flex items-center gap-3 p-3 border border-neutral-200 rounded-lg
|
||||
cursor-pointer hover:bg-neutral-50"
|
||||
:class="selectedReason === '{{ reason.value }}' ? 'border-primary-400 bg-primary-50' : ''">
|
||||
<input type="radio" name="invalid_reason" value="{{ reason.value }}"
|
||||
x-model="selectedReason"
|
||||
class="w-4 h-4 accent-primary-600">
|
||||
<span class="text-sm text-neutral-700">{{ reason.label }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
#### 3.5.3 提交行为
|
||||
|
||||
- **提交方式**:`hx-post="/clients/private/{id}/invalidate/"`
|
||||
- **成功响应**:关闭弹窗 + Toast「已标记为无效」+ 从私客列表移除该行(列表局部刷新)
|
||||
- **HTMX 属性**:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/invalidate/"
|
||||
hx-target="#client-list-container"
|
||||
hx-swap="innerHTML"
|
||||
hx-on::after-request="if(event.detail.successful) closeModal()">
|
||||
```
|
||||
|
||||
#### 3.5.4 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器,含信息提示 |
|
||||
|
||||
---
|
||||
|
||||
### 3.6 收藏夹选择弹窗(P1 🟡)
|
||||
|
||||
#### 3.6.1 触发方式
|
||||
|
||||
- **触发位置**:客源详情页信息概览面板「☆ 收藏」按钮
|
||||
- **组件类型**:Modal Dialog(轻量操作,非抽屉)
|
||||
- **尺寸**:`max-w-sm`
|
||||
|
||||
#### 3.6.2 表单字段规范
|
||||
|
||||
弹窗标题:「选择私客收藏夹」
|
||||
副标题:`text-neutral-400 text-xs`「可在私客列表筛选收藏的客户」
|
||||
|
||||
| 字段名 | 组件类型 | 必填 | 校验规则 | 默认值 |
|
||||
|---|---|---|---|---|
|
||||
| 选择收藏夹 | Radio List | 是 | 必选 | 默认收藏夹 |
|
||||
| 新建收藏夹名称(内联出现) | Text Input | — | 最多10字 | 空 |
|
||||
|
||||
收藏夹列表:
|
||||
```html
|
||||
<div class="space-y-1 max-h-48 overflow-y-auto">
|
||||
{% for folder in folders %}
|
||||
<label class="flex items-center gap-3 px-3 py-2 rounded-md cursor-pointer
|
||||
hover:bg-neutral-50">
|
||||
<input type="radio" name="folder_id" value="{{ folder.id }}"
|
||||
x-model="selectedFolder"
|
||||
class="w-4 h-4 accent-primary-600">
|
||||
<span class="text-sm text-neutral-700">{{ folder.name }}</span>
|
||||
{% if folder.is_default %}
|
||||
<span class="text-xs text-neutral-400">默认</span>
|
||||
{% endif %}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- 新建收藏夹(内联交互) -->
|
||||
<div class="mt-3 pt-3 border-t border-neutral-100">
|
||||
<template x-if="!creatingFolder">
|
||||
<button @click="creatingFolder = true"
|
||||
class="text-sm text-info-600 hover:underline">
|
||||
+ 创建收藏夹
|
||||
</button>
|
||||
</template>
|
||||
<template x-if="creatingFolder">
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="text" x-model="newFolderName" maxlength="10"
|
||||
placeholder="请输入名称最多10个字"
|
||||
class="flex-1 px-3 py-1.5 text-sm border border-neutral-300
|
||||
rounded-md focus-visible:ring-2 focus-visible:ring-primary-600/40">
|
||||
<button :disabled="!newFolderName || newFolderName.length > 10"
|
||||
:class="newFolderName && newFolderName.length <= 10
|
||||
? 'bg-primary-600 text-white' : 'bg-neutral-200 text-neutral-400'"
|
||||
class="px-3 py-1.5 text-sm rounded-md"
|
||||
hx-post="/clients/folders/create/"
|
||||
hx-target="#folder-list"
|
||||
hx-swap="innerHTML"
|
||||
hx-vals="js:{name: newFolderName}"
|
||||
hx-on::after-request="creatingFolder = false; newFolderName = ''">
|
||||
创建
|
||||
</button>
|
||||
<button @click="creatingFolder = false" class="text-sm text-neutral-500">取消</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 3.6.3 提交行为
|
||||
|
||||
- **提交方式**:`hx-post="/clients/private/{id}/favorite/"`
|
||||
- **成功响应**:关闭弹窗 + 信息面板「收藏」图标变为实心星 ★(`text-warning-600`)
|
||||
- **HTMX 属性**:
|
||||
```html
|
||||
<form hx-post="/clients/private/{{ client.id }}/favorite/"
|
||||
hx-target="#favorite-icon"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="if(event.detail.successful) closeModal()">
|
||||
```
|
||||
|
||||
#### 3.6.4 使用的特殊组件
|
||||
|
||||
| 组件名 | 来源 | 用途 |
|
||||
|---|---|---|
|
||||
| Modal Dialog | §7 Modal Dialog | 弹窗容器 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 交互状态规范
|
||||
|
||||
### 4.1 全局状态机
|
||||
### 5.1 全局状态机
|
||||
|
||||
**客源状态流转**(适用于列表页行内操作和详情页操作):
|
||||
|
||||
@@ -1077,7 +949,7 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
|
||||
视觉呈现:在列表状态列、详情页标题区用 Badge 展示;状态变更后相关 Badge 实时 HTMX 局部刷新。
|
||||
|
||||
### 4.2 权限控制矩阵
|
||||
### 5.2 权限控制矩阵
|
||||
|
||||
| 操作 | 经纪人(自己的客源) | 店长 | 管理员 |
|
||||
|---|---|---|---|
|
||||
@@ -1096,7 +968,7 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
|
||||
权限控制实现:Django 视图层通过 `request.user` 的 role 和 org_unit 过滤 QuerySet;前端通过 Django 模板 `{% if user.role == 'manager' %}` 条件渲染隐藏不可用按钮(双重防护)。
|
||||
|
||||
### 4.3 HTMX 请求规范
|
||||
### 5.3 HTMX 请求规范
|
||||
|
||||
| 操作 | hx-trigger | hx-method + URL | hx-target | hx-swap | Loading 行为 |
|
||||
|---|---|---|---|---|---|
|
||||
@@ -1106,16 +978,10 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
| 分页跳转 | `click` | `GET /clients/private/?page=N` | `#client-list-container` | `innerHTML` | 骨架屏 |
|
||||
| 每页条数变更 | `change` | `GET /clients/private/?page_size=N` | `#client-list-container` | `innerHTML` | 骨架屏 |
|
||||
| 列排序 | `click`(表头) | `GET /clients/private/?sort=field&order=asc\|desc` | `#client-list-container` | `innerHTML` | 骨架屏 |
|
||||
| 改等级提交 | `submit` | `POST /clients/private/{id}/grade/` | `#client-info-panel` | `innerHTML` | 按钮 loading spinner |
|
||||
| 改状态提交 | `submit` | `POST /clients/private/{id}/status/` | `#client-info-panel` | `innerHTML` | 按钮 loading spinner |
|
||||
| 转公客提交 | `submit` | `POST /clients/private/{id}/to-public/` | `body` | `none` | 按钮 loading spinner |
|
||||
| 转成交提交 | `submit` | `POST /clients/private/{id}/to-transacted/` | `body` | `none` | 按钮 loading spinner |
|
||||
| 转无效提交 | `submit` | `POST /clients/private/{id}/invalidate/` | `#client-list-container` | `innerHTML` | 按钮 loading spinner |
|
||||
| 收藏/取消收藏 | `submit` | `POST /clients/private/{id}/favorite/` | `#favorite-icon` | `outerHTML` | 图标 spinning |
|
||||
| 导出 | `click` | `POST /clients/private/export/` | `body` | `none` | Toast 提示「正在生成,完成后下载」 |
|
||||
| 创建收藏夹 | `click` | `POST /clients/folders/create/` | `#folder-list` | `innerHTML` | 按钮 loading |
|
||||
| 批量删除 | `click` | `DELETE /clients/private/batch/` | `#client-list-container` | `innerHTML` | 按钮 loading |
|
||||
| 批量修改相关方 | `submit`(Modal内) | `PATCH /clients/private/batch/related/` | `#client-list-container` | `innerHTML` | 按钮 loading |
|
||||
| 保存自定义列 | `submit`(§4.1 弹窗内) | `POST /clients/column-preferences/` | `#client-list-container` | `innerHTML` | 按钮 loading spinner |
|
||||
|
||||
**按钮 Loading 实现**(用于提交按钮):
|
||||
```html
|
||||
@@ -1133,7 +999,7 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键数据字段说明
|
||||
## 6. 关键数据字段说明
|
||||
|
||||
以下字段为客源列表页后端 API 需返回的完整字段集:
|
||||
|
||||
@@ -1183,7 +1049,7 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
|
||||
---
|
||||
|
||||
## 6. 竞品截图对应关系
|
||||
## 7. 竞品截图对应关系
|
||||
|
||||
| 截图路径 | 对应功能 | 对应文档章节 | 采纳的设计要点 |
|
||||
|---|---|---|---|
|
||||
@@ -1199,7 +1065,7 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
|
||||
---
|
||||
|
||||
## 7. 实现优先级与工期估算
|
||||
## 8. 实现优先级与工期估算
|
||||
|
||||
| 页面/功能 | 优先级 | 特殊组件复杂度 | 工期估算(前端) |
|
||||
|---|---|---|---|
|
||||
@@ -1207,27 +1073,21 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
| 搜索框 + 已存搜索 | P0 🔴 | 中(下拉交互) | 0.5 天 |
|
||||
| 快捷筛选行 + 分组筛选条(含展开/收起) | P0 🔴 | 中(Alpine.js 管理展开状态 + HTMX) | 1.5 天 |
|
||||
| 价格区间筛选(预设+自定义) | P0 🔴 | 低 | 0.5 天 |
|
||||
| 工具栏(批量操作 + 总条数 + 导出 + 自定义列) | P0 🔴 | 中(Column Visibility Panel §3) | 1 天 |
|
||||
| 数据表格主体(12列 + 活跃度标签渲染) | P0 🔴 | 高(Data Table §1,多行单元格) | 2 天 |
|
||||
| 工具栏(批量操作 + 总条数 + 导出) | P0 🔴 | 低(Toolbar §4) | 0.5 天 |
|
||||
| Data Table 主体(列定义 + 活跃度标签渲染) | P0 🔴 | 高(§3 Data Table,多行单元格) | 2 天 |
|
||||
| 分页栏(含跳页) | P0 🔴 | 低(Pagination §2) | 0.5 天 |
|
||||
| 重复检测提示区 | P0 🔴 | 低 | 0.25 天 |
|
||||
| 空状态设计 | P0 🔴 | 低 | 0.25 天 |
|
||||
| 骨架屏 Loading | P0 🔴 | 低 | 0.25 天 |
|
||||
| 改等级弹窗 | P0 🔴 | 低(Modal §7) | 0.5 天 |
|
||||
| 改状态弹窗 | P0 🔴 | 低(Modal §7) | 0.5 天 |
|
||||
| 转公客弹窗 | P0 🔴 | 低(Modal §7) | 0.5 天 |
|
||||
| 转成交弹窗(含房源选择器) | P0 🔴 | 高(嵌套 Modal + 房源搜索列表) | 2 天 |
|
||||
| 转无效弹窗 | P0 🔴 | 低(Modal §7) | 0.5 天 |
|
||||
| 已存搜索保存与调用 | P1 🟡 | 中 | 1 天 |
|
||||
| 导出 Excel(Celery 异步) | P1 🟡 | 中(后端为主) | 0.5 天前端 |
|
||||
| 自定义列表字段(Column Visibility) | P1 🟡 | 中(§3 Column Visibility) | 1 天 |
|
||||
| 收藏夹选择弹窗(含创建收藏夹) | P1 🟡 | 中(Modal + 内联交互) | 1 天 |
|
||||
| **合计 P0** | | | **约 10.75 天** |
|
||||
| **合计 P1** | | | **约 3.5 天** |
|
||||
| 自定义列弹窗(§4.1 Column Visibility) | P1 🟡 | 中(Modal + 拖拽排序) | 1.5 天 |
|
||||
| **合计 P0** | | | **约 6.25 天** |
|
||||
| **合计 P1** | | | **约 3 天** |
|
||||
|
||||
---
|
||||
|
||||
## 8. 开放问题(待决策)
|
||||
## 9. 开放问题(待决策)
|
||||
|
||||
| # | 问题 | 影响范围 | 待确认方 |
|
||||
|---|---|---|---|
|
||||
@@ -1239,5 +1099,5 @@ buy_or_rent(租购)→ public(公客)[不可逆]
|
||||
| 6 | 表格「最近时间」列:PRD 写的是「最近时间」(最近跟进或带看的距今天数),截图中显示「N天前」+ 日期(如`2026-04-19`)两行,是否需要双行展示? | 表格列定义 §2.1.3 | 产品经理(截图已有双行,建议对齐截图) |
|
||||
| 7 | 导出功能:Celery 异步生成后如何通知用户下载?WebSocket Push / 轮询 / 下载中心页?MVP 阶段建议使用轮询+下载链接 Toast | 导出按钮 §2.1.3 | 后端 + 产品 |
|
||||
| 8 | 批量合并客源:需要独立的合并规则弹窗(选择主记录 + 字段合并规则),复杂度高,是否降级到 P2? | 工具栏批量操作 | 产品经理 |
|
||||
| 9 | 转成交弹窗中「成交方」人员选择器:默认带入当前用户所属门店,支持修改的范围是全司还是当前用户权限内? | 转成交弹窗 §3.4 | 产品 + 后端 |
|
||||
| 9 | 转成交弹窗中「成交方」人员选择器:默认带入当前用户所属门店,支持修改的范围是全司还是当前用户权限内? | 详情页转成交弹窗(待详情页文档) | 产品 + 后端 |
|
||||
| 10 | 活跃度标签「营销客」「销售客」「访客」的触发条件(截图可见但 DATA_MODEL_CLIENT.md 中的 `activity_level` 枚举不含这三项):这些是 `source` 字段衍生的展示标签,还是独立的 `activity_level` 值?需后端澄清 | 活跃度标签渲染 §2.1.3 | 后端 |
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
- [Overview](overview.md) — living synthesis
|
||||
|
||||
## Sources
|
||||
- [2026-04-25] [Data Consolidation Agent](sources/data-consolidation-agent.md)
|
||||
- [2026-04-25] [Supply Chain Strategist Agent](sources/supply-chain-strategist.md)
|
||||
- [2026-04-25] [ZK Steward Agent](sources/zk-steward.md)
|
||||
- [2026-04-25] [Korean Business Navigator](sources/specialized-korean-business-navigator.md)
|
||||
@@ -411,7 +412,6 @@
|
||||
- [2026-04-20] [product-feedback-synthesizer](sources/product-feedback-synthesizer.md) — (expected: wiki/sources/product-feedback-synthesizer.md — source missing)
|
||||
- [2026-04-20] [specialized-developer-advocate](sources/specialized-developer-advocate.md) — (expected: wiki/sources/specialized-developer-advocate.md — source missing)
|
||||
- [2026-04-20] [report-distribution-agent](sources/report-distribution-agent.md) — (expected: wiki/sources/report-distribution-agent.md — source missing)
|
||||
- [2026-04-20] [Data Consolidation Agent](sources/data-consolidation-agent.md) — AI Agent 将分散的销售提取数据整合为实时报告仪表盘,含地区/代表/管道多维度业绩视图
|
||||
- [2026-04-20] [automation-governance-architect](sources/automation-governance-architect.md) — (expected: wiki/sources/automation-governance-architect.md — source missing)
|
||||
- [2026-04-20] [llm-wiki](sources/llm-wiki.md) — (expected: wiki/sources/llm-wiki.md — source missing)
|
||||
- [2026-04-20] [baoyu-skills](sources/baoyu-skills.md) — (expected: wiki/sources/baoyu-skills.md — source missing)
|
||||
|
||||
@@ -715,6 +715,8 @@ Key concepts: [[Django ORM]], [[Django REST Framework]], [[Django Admin 定制]]
|
||||
|
||||
**[[supply-chain-strategist]]**(Supply Chain Strategist):中国制造业供应链管理与战略采购专家 Agent——The Agency Specialized 部门的供应链全链路专家,基于中国制造业生态,帮助企业建立高效、有韧性、可持续的供应链体系。核心能力:供应商开发与分级管理(ABC 分类 + 战略合作伙伴升级)、Kraljic 矩阵采购类别策略、QCD 绩效评分体系(全季度评分年度淘汰)、TCO 全成本分析(直接/间接/隐性/全生命周期成本)、库存优化模型(EOQ/ROP/安全库存/VMI/JIT)、供应链数字化成熟度评估(L1 手动 → L5 自主智能)。采购渠道覆盖 1688/阿里巴巴、中国制造网、广交会、企查查企业核验等全渠道。合规能力:RBA 行为准则、SA8000 社会责任审计、碳足迹追踪、冲突矿产合规(CMRT)、ISO 14001/REACH/RoHS。关键原则:**关键物料禁止单一来源**;**TCO 是采购决策依据而非单价**;**质量问题必须追溯根本原因**。典型成就:紧固件品类年采购成本通过整合采购降低 12%,节省 ¥870,000。与 [[specialized-french-consulting-market]] 同属 Specialized 部门垂直领域 Agent,分别覆盖供应链管理和法国市场咨询两个不同专业方向。
|
||||
|
||||
**[[data-consolidation-agent]]**(Data Consolidation Agent):销售数据整合专家 Agent——The Agency Specialized 部门的战略数据整合专家,将分散的销售提取数据聚合为实时仪表盘。核心理念:**将原始销售指标转化为可操作的实时决策视图**。核心能力:并行多维度查询(地区/代表/管道/时间维度)、实时达成率计算(revenue / quota * 100,处理除零错误)、MTD/YTD/Year End 多时间视图、< 1 秒仪表盘加载 + 60 秒自动刷新。交付物:Dashboard Report(地区业绩摘要 + 代表排名 + 管道快照 + 6 个月趋势 + Top 5 业绩者)和 Territory Report(地区级深度分析,含所有代表指标及最近 50 条历史记录)。关键原则:**始终使用最新数据**(按 type 取最新 metric_date);**零数据不一致**(明细与汇总视图完全一致)。与 [[sales-data-extraction-agent]](上游数据提取)和 [[report-distribution-agent]](下游分发)构成销售数据管道;与 [[sales-pipeline-analyst]] 共享数据源但职责互补(整合 vs 分析);与 [[sales-coach-agent]] 协同提供 Top 5 业绩者洞察。属 [[Multi-Agent-System-Reliability]] 的数据层实践,为多 Agent 销售系统提供统一数据视图。
|
||||
|
||||
## Conflict Areas
|
||||
|
||||
1. **Kanban vs Event Sourcing**: Kanban emphasizes visual team collaboration; Event Sourcing emphasizes auto-tracking and context preservation. **[[Project State Management]]**(事件驱动看板替代方案)vs 传统 PM 工具。核心差异:手动拖拽 vs 自然语言输入;静态快照 vs 全历史保留;无上下文 vs 完整决策链。**[[Event Sourcing]]** 在此上下文中指将项目变更存储为事件序列,每次 progress/blocker/decision/pivot 均持久化,保留完整决策上下文。
|
||||
|
||||
Reference in New Issue
Block a user