# Fonrey UI System 设计规范 **版本**:v1.2 **最后更新**:2026-04-25 **维护者**:UI/UX 架构组 **适用技术栈**:Tailwind CSS + HTMX + Alpine.js + Django 模板 **目标分辨率**:桌面 Web,≥ 1280px(v1 不做移动端适配) > **For developers**: 本文是开发还原 UI 的唯一权威。所有组件以 HTML + Tailwind class 描述,不输出 JSX。新增页面须先到此处查找可复用组件与模板;如需新模式,先补本文再落地。 > **关联文档**: > - `Project/fonrey/TECH_STACK/TECH_STACK.md`(技术总纲) > - `Project/fonrey/UI_SYSTEM/组件清单.md`(组件可行性分析) > - `Project/fonrey/PRD/*`(业务需求) --- ## 0. 设计语言定调(Design Language Overview) 参考 Linear 的克制、Notion 的信息密度、Salesforce Lightning 的企业严谨,结合竞品(链家/贝壳式房产工具)的操作效率要求,Fonrey 的设计语言定位为: - **专业、克制、高密度**:表格为王,单屏尽可能多展示数据;色彩只为信息服务,不用于装饰。 - **主色靛青(Teal)**:低饱和、冷静,与状态色(绿/黄/红)形成强区分;与房产行业"稳健/可靠"意象吻合,同时避免与 success 绿产生语义歧义。 - **中等圆角(8px)**:既不像消费端(12px+)过于柔软,也不像传统企业端(0-2px)过于呆板。 - **紧凑密度**:表格默认行高 56px(含 40×40 封面缩略图),表单字段间距 12px,信息密度优先于呼吸感。 --- ## 1. 设计原则(Design Principles) 1. **效率优先(Efficiency First)** 减少视觉噪音,让用户聚焦在数据和操作上。表格为核心场景,一屏可见行数 ≥ 15。 2. **状态可见(Visible State)** 任何异步请求必须有反馈(骨架屏 / Spinner / Toast);任何数据变更必须给出成功或失败的即时提示。HTMX 的"静默成功"是 Bug。 3. **复用先于新建(Reuse Over Reinvent)** 每个组件在本文中有唯一标准实现;新需求须先尝试组合既有组件,再提案新组件。 4. **键盘友好(Keyboard First)** 高频操作(搜索、翻页、新增、保存)须支持键盘;表格、表单、弹窗均支持 Tab / Enter / ESC。 5. **一致性高于美观(Consistency Over Cleverness)** 相同的动作在全产品使用相同的图标、色彩、位置。经纪人的肌肉记忆比单页的视觉惊喜更重要。 --- ## 2. 设计 Token(Design Tokens) 所有 Token 均映射到 `tailwind.config.js` 的 `theme.extend`,禁止在模板中使用任意十六进制色值。 ### 2.1 颜色系统 #### 2.1.1 品牌色(Primary — Teal) | Token | Hex | Tailwind 类 | 使用场景 | | ------------- | --------- | ---------------- | ------------------------- | | `primary-50` | `#F0FDFA` | `bg-primary-50` | 页面强调区微底色、Tag 极淡底 | | `primary-100` | `#CCFBF1` | `bg-primary-100` | 选中背景、标签底色 | | `primary-200` | `#99F6E4` | `bg-primary-200` | Hover 标签底色 | | `primary-500` | `#14B8A6` | `bg-primary-500` | 辅助主色(图标、强调文字) | | `primary-600` | `#0F766E` | `bg-primary-600` | **主按钮、激活态、Tab 下划线(基准主色)** | | `primary-700` | `#115E59` | `bg-primary-700` | 主按钮 Hover | | `primary-800` | `#134E4A` | `bg-primary-800` | 主按钮 Active / 深色文字 | #### 2.1.2 中性色(Neutral — Slate 系,偏冷灰) | Token | Hex | 使用场景 | |---|---|---| | `neutral-50` | `#F8FAFC` | 页面背景 | | `neutral-100` | `#F1F5F9` | Hover 底色、表头底色、禁用输入框底色 | | `neutral-200` | `#E2E8F0` | 分隔线、默认边框 | | `neutral-300` | `#CBD5E1` | 输入框边框、次级按钮边框 | | `neutral-400` | `#94A3B8` | 占位符、禁用文字、辅助图标 | | `neutral-500` | `#64748B` | 辅助文字、副标题 | | `neutral-600` | `#475569` | 次级正文 | | `neutral-700` | `#334155` | 正文 | | `neutral-800` | `#1E293B` | 标题 | | `neutral-900` | `#0F172A` | 强调标题 | #### 2.1.3 语义色(Semantic) | Token | Hex | 使用场景 | |---|---|---| | `success-600` | `#16A34A` | 操作成功 Toast、在售/激活状态 | | `success-50` | `#F0FDF4` | Success Tag 底色 | | `warning-600` | `#D97706` | 待确认/临期提醒 | | `warning-50` | `#FFFBEB` | Warning Tag 底色 | | `danger-600` | `#DC2626` | 删除/错误/逾期 | | `danger-50` | `#FEF2F2` | Danger Tag 底色 | | `info-600` | `#2563EB` | 信息提示、Link、已成交状态 | | `info-50` | `#EFF6FF` | Info Tag 底色 | > **语义色与主色分离**:主色是 Teal,success 是独立绿,避免"主操作按钮看起来像成功提示"。 #### 2.1.4 背景层级 | 层级 | Tailwind 类 | 使用场景 | |---|---|---| | L0 页面背景 | `bg-neutral-50` | 整体页面底色 | | L1 卡片/面板 | `bg-white` | 内容区块 | | L2 表头/次级区块 | `bg-neutral-100` | 表头、工具栏底色、代码块 | | L3 悬浮层 | `bg-white shadow-lg border border-neutral-200` | 弹窗、下拉、抽屉 | | L4 遮罩 | `bg-neutral-900/40` | Modal / Drawer 遮罩 | ### 2.2 字体系统 基础字体栈(Tailwind 默认即可): ``` font-sans: "Inter", "PingFang SC", "Microsoft YaHei", -apple-system, sans-serif; font-mono: "JetBrains Mono", "SFMono-Regular", Menlo, monospace; ``` | 层级 | 字号 | 字重 | 行高 | Tailwind 类 | 使用场景 | |---|---|---|---|---|---| | H1 页面标题 | 20px | 600 | 28px | `text-xl font-semibold text-neutral-800` | 页面 H1(紧凑型,避免占太多垂直空间) | | H2 区块标题 | 16px | 600 | 24px | `text-base font-semibold text-neutral-800` | 卡片/面板标题 | | H3 次级标题 | 14px | 600 | 20px | `text-sm font-semibold text-neutral-700` | 表单分组、Section 内标题 | | Body 正文 | 14px | 400 | 20px | `text-sm text-neutral-700` | 表单标签、描述、表格数据(默认) | | Data 数据强调 | 14px | 500 | 20px | `text-sm font-medium text-neutral-900` | 表格关键列(房源标题、价格) | | Number 数值 | 20px | 600 | 28px | `text-xl font-semibold tabular-nums` | Stat Card 数值、价格展示 | | Caption 辅助 | 12px | 400 | 16px | `text-xs text-neutral-500` | 提示、占位符、时间戳 | | Mono 代码/ID | 12px | 400 | 16px | `text-xs font-mono text-neutral-600` | 房源编号、系统 ID | > **关键约定**:表格与表单中**所有数字列**必须加 `tabular-nums`(等宽数字),保证纵向对齐。 ### 2.3 间距系统 4px 基础栅格,映射到 Tailwind 默认间距 Token。 | 场景 | Token | 值 | |---|---|---| | 原子间距(图标与文字) | `gap-1` / `gap-1.5` | 4 / 6 px | | 组件内边距(密集) | `p-2` | 8 px(如 Tag 内) | | 组件内边距(标准) | `px-3 py-2` | 12/8 px(输入框、按钮 md) | | 卡片内边距 | `p-4` 或 `p-6` | 16 / 24 px | | 表单字段纵向间距 | `space-y-3` | 12 px | | 区块纵向间距 | `space-y-6` | 24 px | | 页面两侧边距 | `px-6` | 24 px | | 列表页内容区边距 | `px-6 py-4` | — | ### 2.4 阴影与圆角 | Token | 值 | 使用场景 | |---|---|---| | `rounded` | 4px | 紧凑 Tag、小 Badge | | `rounded-md` | 6px | 按钮、输入框、下拉选项 | | `rounded-lg` | 8px | **卡片、面板、表格容器(基准)** | | `rounded-xl` | 12px | Modal / Drawer | | `rounded-full` | 圆 | 头像、开关滑块、圆点 | | 阴影 | 使用场景 | |---|---| | `shadow-xs`(自定义 `0 1px 2px rgba(15,23,42,0.04)`) | 卡片静态 | | `shadow-sm` | 卡片 Hover、次级浮层(如 Tooltip) | | `shadow-md` | Dropdown、Popover | | `shadow-lg` | Modal、Drawer、Toast | ### 2.5 圆角圆点与边框 - 默认边框:`border border-neutral-200` - 强调边框(Focus/激活):`ring-2 ring-primary-600/30 border-primary-600` - 错误边框:`border-danger-600 ring-2 ring-danger-600/20` ### 2.6 Z-index 层级 | 层级 | 值 | 场景 | |---|---|---| | `z-20` | 20 | 侧边栏、顶部导航 | | `z-30` | 30 | 页面内 Sticky 工具栏 | | `z-40` | 40 | Dropdown / Popover | | `z-50` | 50 | Modal / Drawer 遮罩 | | `z-60` | 60 | Modal / Drawer 面板 | | `z-70` | 70 | Toast 容器(始终最顶层) | ### 2.7 Tailwind 配置示例(节选) ```js // tailwind.config.js module.exports = { content: ['./apps/**/templates/**/*.html', './templates/**/*.html'], theme: { extend: { colors: { primary: { 50: '#F0FDFA', 100: '#CCFBF1', 200: '#99F6E4', 500: '#14B8A6', 600: '#0F766E', 700: '#115E59', 800: '#134E4A', }, 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'], }, }, }, plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')], } ``` --- ## 3. 基础组件规范(Base Components) ### 3.1 按钮(Button) #### 3.1.1 变体 | 变体 | 用途 | Tailwind 类 | |---|---|---| | Primary | 主操作(每个区域唯一) | `bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800` | | Secondary | 次级操作 | `bg-white border border-neutral-300 text-neutral-700 hover:bg-neutral-50 hover:border-neutral-400` | | Danger | 删除、不可逆操作 | `bg-danger-600 text-white hover:bg-danger-600/90` | | Ghost | 工具栏、表格行操作 | `text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900` | | Link | 内联跳转 | `text-primary-600 hover:text-primary-700 hover:underline underline-offset-2` | | Icon | 仅图标的工具按钮 | `text-neutral-500 hover:bg-neutral-100 hover:text-neutral-700 rounded-md p-1.5` | #### 3.1.2 尺寸 | 尺寸 | 场景 | Tailwind 类 | |---|---|---| | sm | 表格操作、Tag 内 | `px-2.5 py-1 text-xs rounded` | | md(默认) | 表单提交、工具栏 | `px-3 py-1.5 text-sm rounded-md` | | lg | 页面主操作(新增按钮) | `px-4 py-2 text-sm rounded-md` | #### 3.1.3 状态 - **Focus**:`focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40` - **Loading**:禁用 + 内嵌 Spinner + 文案改为进行时("保存中…") - **Disabled**:`disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-current`(即 hover 无效果) #### 3.1.4 标准 HTML 片段 ```html ``` #### 3.1.5 禁忌 - ❌ 同一视觉区域不得出现两个 Primary 按钮 - ❌ Danger 按钮必须二次确认(Modal),不得直接触发删除 - ❌ 不得用颜色以外的方式(如加粗)表达"危险" - ❌ Ghost 按钮不允许填充背景色做变体(容易与 Secondary 混淆) --- ### 3.2 输入框(Input) #### 3.2.1 状态 | 状态 | Tailwind 类 | |---|---| | 默认 | `border-neutral-300` | | Hover | `hover:border-neutral-400` | | Focus | `focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20` | | 错误 | `border-danger-600 focus:border-danger-600 focus:ring-danger-600/20` | | 禁用 | `bg-neutral-100 text-neutral-400 cursor-not-allowed` | | 只读 | `bg-neutral-50 text-neutral-700` | #### 3.2.2 标准结构 ```html

标题不能为空

不超过 50 字,将用于客户端展示

``` #### 3.2.3 变体 - **Textarea**:同上,`rows="3"` 起步,右下角 `resize-y`;需字数统计时右下角显示 `x-text="val.length + '/200'"` - **带前缀/后缀**:用 `relative` 包裹,前缀/后缀绝对定位 `absolute left-3 / right-3` - **带单位**:右侧灰色文字(如"万元"),用 `pr-14` 留白 - **数字输入**:`type="number"` + `tabular-nums` + 取消浏览器 spinner(用 `appearance-none`) - **密码输入**:默认 `type="password"`,右侧眼睛图标按钮(Alpine.js 切换 type) --- ### 3.3 下拉选择(Select / Dropdown) #### 3.3.1 三种实现路径 | 场景 | 实现 | |---|---| | 单选、选项 ≤ 10、不需搜索 | **原生 ` ``` #### 3.3.3 Alpine.js 自定义下拉(带搜索) ```html
``` #### 3.3.4 Tree Select(树形选择器) 适用组织架构、员工选择、部门选择等。 - 数据:后端一次性返回完整 JSON 树(组织树通常 < 500 节点,无压力) - 交互:节点左侧 `▶` 图标控制子树展开/折叠,叶节点可点击选中 - 搜索:输入时过滤,**命中子节点的父节点强制展开** - 底部固定操作行:`隐藏离职员工` 开关 实现要点见 `组件清单.md` Tree Select 章节。 #### 3.3.5 Multi-select Tag Input(多选标签输入) 适用于多个平级标签(房源状态、客源需求类型)。见 3.7 状态标签组件的 Tag 样式。 ```html
出售
``` --- ### 3.4 表格(Table) Fonrey 的核心场景,规范必须严格执行。 #### 3.4.1 结构规范 | 区域 | 说明 | Tailwind 类 | |---|---|---| | 外壳 | 圆角卡片容器 | `bg-white rounded-lg border border-neutral-200 overflow-hidden` | | 表头 `` | 粘性、小字、中性色底 | `bg-neutral-50 text-xs font-medium text-neutral-500 uppercase tracking-wider sticky top-0 z-10` | | 表头 `` | 高 36px;排序箭头右对齐 | `px-4 py-2 text-left` | | 数据行 `` | 密度可切换;Hover 高亮 | `hover:bg-neutral-50` | | 数据单元 `` | 正文字号;垂直居中 | `px-3 py-3 text-sm text-neutral-700 align-middle whitespace-nowrap` | | 选中行 | 浅主色高亮 | `bg-primary-50/40` | | 操作列 | 固定右侧;Ghost 图标按钮,Hover 显形 | `sticky right-0 bg-white opacity-0 group-hover:opacity-100` | | 表格底部(分页栏) | | `px-4 py-3 border-t border-neutral-200 bg-white flex items-center justify-between` | - **斑马纹**:B2B 高密度场景**不启用**(视觉噪音)。Hover 行高亮已足够区分。 - **封面缩略图**:房源/楼盘等含图业务表格,第一数据列(通常为"标题"列)内嵌缩略图(`` 或占位 `
`),尺寸随密度档联动(见下表)。缩略图统一 `rounded` (4px),对象填充 `object-cover`,加载失败占位为 `bg-neutral-100` + 图片占位图标。 - **三档密度**:工具栏右侧"密度"图标按钮切换,Alpine.js + `localStorage`(key: `fonrey:table:{module}:density`)持久化,默认 `standard`。 | 档位 | Key | 行高 | 缩略图尺寸 | 单元内边距 | 使用场景 | |---|---|---|---|---|---| | 紧凑 Compact | `compact` | 40px | 无(图片列隐藏) | `px-3 py-2` | 数据核对、大批量浏览、导出前预览 | | 标准 Standard(默认) | `standard` | 56px | 40×40 | `px-3 py-3` | 日常工作,"一眼认房" | | 舒适 Comfortable | `comfortable` | 72px | 56×56 | `px-3 py-4` | 含更多副信息(楼层/朝向/装修标签换行展示) | > **实现提示**:密度切换仅改 `` 上的 class(如 `table-density-standard`),通过父级 class + 子选择器统一控制行高、内边距、图片显隐,避免逐行改 class。 > **无图业务**(客源、跟进记录、权限等)表格固定使用 `compact` 40px 行高,不提供密度切换。 #### 3.4.2 标准片段 ```html
房源编号 状态 操作
共 3,629 条
跳至
``` #### 3.4.3 HTMX 局部刷新约定 - 所有筛选、排序、翻页触发 `hx-get`,目标容器为 `` 或 `#table-wrapper` - **加载态**:`htmx:beforeRequest` 给 `` 叠加骨架屏(`animate-pulse` 的 5 行占位) - **错误态**:`htmx:responseError` 保留原内容 + 触发 Error Toast #### 3.4.4 自定义列(Column Visibility) 右上角"自定义列表"按钮,弹出 Checkbox 面板,选择状态持久化到 `localStorage`(Key: `fonrey:table:{module}:cols`)。隐藏的列通过 Alpine.js `:class="{'hidden': !col.visible}"` 控制。 #### 3.4.5 空状态 见 6.3 空状态设计。表格空状态占整个 ``,不使用 `colspan` 占所有列的骚操作,改用覆盖层(`absolute inset-0 flex items-center justify-center`)。 --- ### 3.5 分页(Pagination) ```html ``` - **当前页**:`bg-primary-600 text-white` - **省略号**:Django 后端生成(前 3 后 3 + 当前 ±1) - **同页多表格独立分页**:每个分页器 `hx-target` 指向各自的表格容器 id(见 `组件清单.md`) --- ### 3.6 弹窗(Modal)与抽屉(Drawer) #### 3.6.1 选择原则 | 类型 | 场景 | 宽度 | 关闭行为 | |---|---|---|---| | Confirm Modal | 删除确认、不可逆操作 | `max-w-sm`(400px) | 点击遮罩**不关闭**(防误触),ESC 关闭 | | Form Modal | 新增/编辑(字段 ≤ 6) | `max-w-lg`(560px) | 点击遮罩关闭,ESC 关闭 | | Right Drawer | 查看详情、新增/编辑(字段多)、参考主页面 | `w-[640px]` 或 `w-[480px]` | 点击遮罩关闭,ESC 关闭 | | Full Modal | 复杂配置(权限矩阵) | `w-[80vw] max-w-6xl` | 点击遮罩**不关闭**,顶部关闭按钮 | #### 3.6.2 Modal 标准结构 ```html

新增房源

``` #### 3.6.3 Drawer 标准结构 ```html
``` #### 3.6.4 Confirm Modal 用于删除、下架、离职等不可逆操作。固定使用 Danger 风格: ```html

确认删除该房源?

删除后将进入回收站,30 天内可恢复。

``` --- ### 3.7 状态标签(Badge / Tag) 用于状态展示,不可点击,不可编辑(编辑用 Multi-select Tag Input)。 | 样式类型 | 场景 | Tailwind 类 | |---|---|---| | Subtle(默认,底色+文字) | 高频状态展示 | `bg-{color}-50 text-{color}-700` | | Solid | 极少数强调(如"紧急") | `bg-{color}-600 text-white` | | Outline | 低密度场景 | `border border-{color}-600 text-{color}-700` | #### 3.7.1 业务状态色板 | 状态 | 色系 | 示例 | |---|---|---| | 在售 / 激活 / 在职 | success | `bg-success-50 text-success-600` | | 出租 | info | `bg-info-50 text-info-600` | | 跟进中 / 待确认 | warning | `bg-warning-50 text-warning-600` | | 已成交 / 完成 | primary | `bg-primary-50 text-primary-700` | | 已下架 / 停用 / 离职 | neutral | `bg-neutral-100 text-neutral-500` | | 逾期 / 紧急 / 冻结 | danger | `bg-danger-50 text-danger-600` | | 暂缓 | 浅灰 + 斜体 | `bg-neutral-100 text-neutral-600 italic` | #### 3.7.2 交易类型标签色板 交易类型标签(买卖 / 租赁 / 租售)属于**分类标签**,不表达状态语义,禁止使用语义色(danger / info solid)。 **视觉层级要求**:交易类型标签须比同行副标签(满五、独家等)**更大、更醒目**: - 交易类型标签:`text-xs`(12px)+ `px-2 py-0.5` + `font-semibold` + 较深底色 - 副标签(房源属性 Tag):`text-[10px]` + `px-1.5 py-0.5` + `font-medium` + 极淡底色 | 交易类型 | 色系 | Tailwind 类 | 设计理由 | |---|---|---|---| | 买卖 | primary(Teal) | `bg-primary-200 text-primary-800` | 核心出售业务,用品牌主色强调 | | 租赁 | warning(Amber) | `bg-warning-200 text-warning-800` | 与买卖形成色相区分,暖色低调 | | 租售 | neutral | `bg-neutral-300 text-neutral-800` | 兼含两种类型,中性色避免歧义 | > **禁止**对交易类型标签使用 Solid 样式(`bg-{color}-600 text-white`),该样式仅用于极少数强调性状态(如"紧急")。 #### 3.7.2 标准片段 ```html 在售 ``` --- ### 3.8 Toast 通知 - 统一出现在**右下角**(`fixed bottom-6 right-6 z-70`) - 多条堆叠,新消息**追加在底部**,超出视窗则顶部旧消息自动移除 - 固定宽度 `w-80` | 类型 | 图标色 | 停留 | 手动关闭 | |---|---|---|---| | Success | `text-success-600` | 3s | 否 | | Error | `text-danger-600` | 5s | 是 | | Warning | `text-warning-600` | 5s | 是 | | Info | `text-info-600` | 3s | 否 | ```html

保存成功

房源已更新

``` **HTMX 触发规范**:后端响应 `HX-Trigger` header: ``` HX-Trigger: {"fonrey:toast": {"type": "success", "message": "保存成功", "detail": "房源已更新"}} ``` 前端全局监听 `document.addEventListener('fonrey:toast', ...)` 插入 Toast 节点。 --- ### 3.9 加载状态(Loading States) | 场景 | 实现方式 | |---|---| | HTMX 局部请求 | 目标区域叠加 Skeleton(`animate-pulse` 灰条占位),`htmx:beforeRequest` 添加,`htmx:afterSettle` 移除 | | 按钮提交中 | 禁用按钮 + 内嵌 Spinner + 文案改为进行时("保存中…") | | 页面首次加载 | 内容区骨架屏(与最终结构同骨架) | | 长耗时任务(导出) | Celery 异步,Info Toast 提示"任务已提交,完成后通知";结果通过站内消息推送 | #### 3.9.1 Skeleton 标准 ```html
``` #### 3.9.2 Spinner ```html ``` --- ### 3.10 Tab 导航(Tabs) 用于详情页内容区切换、筛选维度切换。 ```html
``` - **激活指示**:底部 2px 主色下划线 + 主色文字 - **计数 Badge**:中性色小圆角标 - **懒加载**:切换到 Tab 时用 HTMX `hx-get` 拉取,首次加载后缓存 --- ### 3.11 折叠面板(Accordion / Collapsible) 引入 Alpine 官方插件 `@alpinejs/collapse`(1KB)处理高度过渡。 ```html
``` --- ### 3.12 Toggle 开关(Switch) ```html ``` --- ### 3.13 日期与日期范围 - **单日期**:原生 `` + `@tailwindcss/forms` 样式 - **日期范围(核心)**:引入 **Flatpickr**(16KB,无框架依赖)。参考 `组件清单.md` 推荐。 ```html ``` Flatpickr 自定义样式覆盖见附录 10.3。 --- ### 3.14 文件上传 - **单/少量图片(头像、实勘主图)**:原生 `` + Alpine 预览 - **多图批量上传(相册管理)**:引入 **Filepond**,支持拖拽、预览、进度、队列 - **拖拽排序**:引入 **SortableJS**(3KB) 统一上传目标 Cloudflare R2,后端接收后转存并返回 URL。上传进度条使用 Filepond 内置样式,颜色 override 为 `primary-600`。 --- ### 3.15 图片预览(Lightbox) 引入 **Viewer.js**(5KB,无依赖)。覆盖缩放、旋转、全屏、翻页、缩略图条全部需求。样式用 Tailwind 覆盖。 --- ## 4. 业务组件规范(Business Components) ### 4.1 房源卡片(Property Card) 用于"卡片视图"模式(列表页允许用户切换表格/卡片两种视图)。 ``` ┌──────────────────────────────────────┐ │ ┌─────┐ 房源标题(2行截断) ⋯ │ │ │封面 │ 浦东 · 张江高科 │ │ │ 图 │ 89㎡ · 2室1厅 · 高层 │ │ └─────┘ ¥580 万 [在售] │ │ ──────────────────────────────── │ │ 👤 张三 · 2 小时前更新 │ └──────────────────────────────────────┘ ``` - 宽度:响应式栅格 `grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4` - 封面图:`w-32 h-24 rounded object-cover`,固定比例 4:3 - 点击整卡:进入详情页 - 右上角 `⋯`:触发 Action Menu(见 4.4) ### 4.2 筛选栏(Filter Bar) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 区域: [浦东新区▾] 价格: [¥300万-¥800万▾] 户型:[▾] 状态:[在售▾] │ │ [+ 高级筛选 (3)] [清空] [搜索] │ ├─────────────────────────────────────────────────────────────────┤ │ 已选: [浦东新区 ×] [¥300-800万 ×] [2室1厅 ×] [清空所有] │ └─────────────────────────────────────────────────────────────────┘ ``` - 常驻筛选横向排列,用 Select / Multi-select / Date Range - 高级筛选按钮(带数字 Badge 表示已填的高级条件数量),点击展开折叠区 - **筛选变化触发 `hx-get`**,`hx-trigger="change delay:200ms"`,结果刷新列表 `hx-target` - 已选条件 Tag 可单独删除(`×`)或一键清空 ### 4.3 数据统计卡片(Stat Card) ```html
在售房源
1,289 12.5%
较上月
``` ### 4.4 操作菜单(Action Menu) 三点按钮 `⋯` 触发下拉,危险操作(删除)永远在底部且有分隔线。 ```html
``` ### 4.5 跟进时间线(Follow-up Timeline) 用于房源/客源详情页的跟进记录展示。 ```html
  1. 张三 修改跟进 ·
    业主同意降价 20 万,挂牌价调整为 580 万,已通知重点客户。
``` ### 4.6 相册管理(Photo Gallery Manager) 参考 `组件清单.md`。核心组件: - 可横向滚动分类 Tab + 溢出 `⋯` - 多选图片网格(`grid-cols-6 gap-2`,每格 `aspect-[4/3]`) - 批量工具栏(依赖选中状态启用) - 上传 Modal(Filepond) - 排序模式(SortableJS) ### 4.7 字段填写要求配置表(Dynamic Form Table) 用于 `系统设置 → 房源设置 → 字段标签设置`。一张可增删行 + 拖拽排序 + Toggle 切换的表格,结合 SortableJS + Alpine.js。区分系统预置行(不可删)与用户自定义行。详见 `组件清单.md` §Sortable Table with Drag Handle。 ### 4.8 权限矩阵(Permission Matrix) 纵向:功能模块(房源、客源、楼盘 …);横向:权限动作(查看、新增、编辑、删除、审核)。交叉单元格为 Toggle 或三态(继承 / 开 / 关)。宽度超屏时 **左列固定** + 横向滚动: ```html
功能模块 查看 新增
``` ### 4.9 业主/客源联系人卡片(Contact Card) 头像 + 姓名 + 电话(敏感脱敏 `138****1234`) + 角色标签 + 操作菜单。手机号悬浮显示"查看完整"按钮(触发权限校验 + 审计日志)。 --- ## 5. 页面布局模板(Page Layout Templates) ### 5.1 整体框架 ``` ┌──────────────────────────────────────────────────────────────────────┐ │ Topbar(56px,sticky top-0 z-20) │ │ [Logo 150px] [主导航: 主页 房源 客源 营销 交易 数据 人事 系统] │ │ [消息🔔] [帮助?] [头像▾] │ ├─────────────────┬────────────────────────────────────────────────────┤ │ Sidebar │ 内容区(Content Area) │ │ 展开 240px │ 面包屑 > 房源管理 > 二手 & 租赁 [次操作] [主操作] │ │ 折叠 64px │ ───────────────────────────────────────────────── │ │ │ 页面标题 H1 │ │ [当前主分类 │ ───────────────────────────────────────────────── │ │ 的子菜单] │ 筛选 / 工具栏(Sticky,top-14) │ │ │ ───────────────────────────────────────────────── │ │ ← 折叠按钮 │ 内容主体(表格 / 卡片 / 表单) │ │ │ │ │ │ 分页栏 │ └─────────────────┴────────────────────────────────────────────────────┘ ``` **尺寸约定** | 区域 | 规格 | |---|---| | Topbar 高度 | 56px(`h-14`);`sticky top-0 z-20` | | Sidebar 展开宽度 | 240px(`w-60`);`fixed left-0 top-14 h-[calc(100vh-56px)] z-20` | | Sidebar 折叠宽度 | 64px(`w-16`) | | 内容区偏移 | 展开态 `ml-60`,折叠态 `ml-16`;`transition-[margin] duration-200` | | 内容区内边距 | `px-6 py-4` | | 工具栏 Sticky 偏移 | `sticky top-14 z-30`(Topbar 下方紧贴) | --- ### 5.2 顶部导航栏(Topbar) #### 5.2.1 结构规范 Topbar 分三区:左区(Logo)、中区(主导航 + 搜索)、右区(工具区)。 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ [🏢 Fonrey ▾] 主页 房源 客源 营销 [搜索框] [🔔] [⚙] [WS 王顺] │ └─────────────────────────────────────────────────────────────────────┘ ``` | 区域 | 内容 | 样式 | |---|---|---| | 左区(`w-60 shrink-0`) | Logo 图标 + 产品名"Fonrey" | `flex items-center gap-2 px-4 text-base font-semibold text-white` | | 中区(`flex-1`) | 主分类导航 + 全局搜索框 | `flex items-center gap-4 flex-1 px-2` | | 右区(`shrink-0`) | 消息通知 / 设置 / 头像+姓名 | `flex items-center gap-1 px-4 shrink-0` | > **配色**:Topbar 背景使用 `bg-primary-800`(`#134E4A`,深青绿),与下方白色 Sidebar 和 `bg-neutral-50` 内容区形成明确层次区分,同时保持品牌色系一致性。 #### 5.2.2 主导航 Tab 主分类(8项):**主页 / 房源 / 客源 / 营销 / 交易 / 数据 / 人事 / 系统** - 每项:`px-3 py-1.5 text-sm rounded-md` - 默认态:`text-primary-100 hover:bg-primary-700 hover:text-white` - 激活态:`bg-primary-600 text-white font-medium` - 点击切换主分类 → Sidebar 同步切换为该分类的子菜单 #### 5.2.3 全局搜索框 位于主导航右侧,宽度 `max-w-xs`。 - 默认态:`bg-primary-700/60 border-transparent text-white placeholder:text-primary-300` - Hover:`hover:bg-primary-700` - Focus:`focus:bg-white focus:text-neutral-700 focus:border-primary-600 focus:ring-2 focus:ring-primary-600/20` #### 5.2.4 右区工具 | 元素 | 图标 | 样式 | |---|---|---| | 消息通知 | `BellIcon` 20px + 红点 Badge | `p-1.5 text-primary-200 hover:bg-primary-700 hover:text-white rounded-md` | | 设置 | `Cog6ToothIcon` 20px | 同上 | | 头像菜单 | `w-7 h-7 rounded-full bg-primary-600` + 姓名 | 头像缩写 + `text-sm font-medium text-primary-100`,左侧 `border-l border-primary-700` 分隔 | #### 5.2.5 Topbar HTML 片段 ```html
F
Fonrey
WS
王顺
``` ┌─────────────────────────────────────────────────────────────────────┐ │ [🏢 Fonrey ▾] 主页 房源 客源 营销 交易 数据 人事 系统 │ │ [🔍] [🔔2] [?] [WS 王顺▾] │ └─────────────────────────────────────────────────────────────────────┘ ``` | 区域 | 内容 | 样式 | |---|---|---| | 左区(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` | #### 5.2.2 主导航 Tab 主分类(8项):**主页 / 房源 / 客源 / 营销 / 交易 / 数据 / 人事 / 系统** - 每项:`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 右区工具 | 元素 | 图标 | 说明 | |---|---|---| | 全局搜索 | `MagnifyingGlassIcon` 20px | 点击展开全局搜索 Popover(`max-w-lg`) | | 消息通知 | `BellIcon` 20px + 红点 Badge | 未读数 ≤ 99,超出显示"99+";点击打开通知 Drawer | | 帮助 | `QuestionMarkCircleIcon` 20px | 链接到帮助中心或触发 Tour | | 头像菜单 | 头像(`w-8 h-8 rounded-full`)+ 姓名缩写 | 下拉菜单:个人设置 / 切换角色 / 退出 | > **配色说明**:Topbar 背景使用 `bg-primary-800`(`#134E4A`,深青绿),与下方白色 Sidebar 和 `bg-neutral-50` 内容区形成明确层次区分,同时保持品牌色系一致性。 #### 5.2.4 Topbar HTML 片段 ```html
F
Fonrey
``` --- ### 5.3 侧边栏(Sidebar) #### 5.3.1 结构与折叠规范 ``` 展开态(240px) 折叠态(64px) ┌─────────────────────────┐ ┌──────┐ │ ▾ 房源管理 │ │ 🏘️ │ ← 一级图标,Hover Tooltip │ 全部房源 ● │ │──────│ │ 二手 & 租赁 │ │ 👤 │ │ 商铺 / 写字楼 │ │ 🏢 │ │─────────────────────────│ │ ⚙️ │ │ 客源管理 │ └──────┘ │ 私客管理 ● │ │ 公客池 │ │─────────────────────────│ │ [← 折叠] │ ← 折叠按钮(固定在 Sidebar 底部) └─────────────────────────┘ ``` - **Sidebar 定位**:`fixed left-0 top-14 h-[calc(100vh-56px)] z-20 overflow-y-auto` - **展开宽度**:`w-60`(240px);折叠宽度:`w-16`(64px) - **Alpine.js 状态**:`x-data="{ collapsed: $persist(false).as('fonrey:sidebar:collapsed') }"`(使用 `@alpinejs/persist` 持久化) - **内容区联动**:`
` #### 5.3.2 菜单层级 Sidebar 展示**当前主分类的子菜单**,分为一级菜单和二级菜单(可选)。 | 层级 | 样式 | 激活态 | |---|---|---| | 一级菜单(有子项) | `flex items-center gap-3 px-3 py-2 text-sm font-medium text-neutral-700 rounded-md hover:bg-neutral-100 cursor-pointer` | `text-neutral-900 bg-neutral-100` | | 一级菜单(无子项,直链) | 同上 | `bg-primary-50 text-primary-700 font-semibold border-l-2 border-primary-600 rounded-l-none` | | 二级菜单 | `ml-8 flex items-center gap-2 px-3 py-1.5 text-sm text-neutral-600 rounded-md hover:bg-neutral-100` | `bg-primary-50 text-primary-700 font-medium border-l-2 border-primary-600 rounded-l-none` | | 分组标题(可选) | `px-3 pt-4 pb-1 text-xs font-semibold text-neutral-400 uppercase tracking-wider` | — | #### 5.3.3 折叠态行为 - 仅显示一级菜单图标(`w-5 h-5`),居中 `justify-center` - 文字、箭头、二级菜单全部隐藏(`x-show="!collapsed"`) - Hover 图标时,右侧弹出 Tooltip:菜单名称(`absolute left-16 ml-1 px-2 py-1 text-xs bg-neutral-900 text-white rounded whitespace-nowrap z-40`) - 折叠按钮变为展开图标(`ChevronRightIcon`),固定在底部 #### 5.3.4 Sidebar HTML 片段 ```html
{% block content %}{% endblock %}
``` --- ### 5.4 列表页模板 适用:房源列表、客源列表、楼盘列表、权限人员列表、组织人员列表等。 ``` 面包屑 > 房源管理 > 二手 & 租赁 [导出▾] [+ 新增房源] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [Tab: 全部 (3629) | 在售 | 跟进中 | 已成交 | 已下架] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [筛选栏:区域 / 价格 / 户型 / 状态 / 经纪人 | 高级筛选(3) | 搜索] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [批量工具栏(选中时出现):已选 N 条 | 分享 | 收藏 | 下架 | 删除] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [视图切换: 表格 | 卡片] [密度: 紧凑] [自定义列▾] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 表格主体(HTMX 局部刷新) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 分页栏(共 3629 条 · 1 2 3 … · 20/页 · 跳至) ``` ### 5.5 详情页模板 适用:房源详情、客源详情、楼盘详情、员工详情。 ``` 面包屑 > 房源 > 浦东张江花园 89㎡ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [房源标题] [在售] [钥匙房] [收藏] [分享] [⋯ 更多] 浦东新区 · 张江高科路 · 89㎡ · 2室1厅 · ¥580 万 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [Tab: 基本信息 | 跟进记录(12) | 相册(8) | 附件(3) | 操作日志] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 主内容(Tab 内容,HTMX 懒加载) ┌───────────────────────┐ ┌────────────────────┐ │ 房源信息(含编辑链接)│ │ 维护完成度 69% │ │ │ │ [Accordion 进度] │ │ 产证信息(折叠) │ │ │ │ 房屋介绍 │ │ 相关员工(折叠) │ └───────────────────────┘ └────────────────────┘ ``` - 详情页头部 Sticky(便于长页面滚动时保持操作按钮可见) - Tab 计数 Badge 实时更新 - 右侧栏(`w-80`)用于维护度、相关员工等辅助信息;主区 `flex-1` - **编辑入口 = 详情字段旁的"编辑"链接 → 右侧 Drawer 滑入**(遵循"保留上下文"原则) ### 5.6 设置页模板 适用:系统设置、权限管理、个人设置。 ``` 面包屑 > 系统设置 > 房源设置 > 字段标签设置 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ┌──────────────────┬────────────────────────────┐ │ 左侧分组导航 │ 右侧内容区 │ │ (240px) │ │ │ │ [搜索设置项…] [编辑] │ │ ▾ 房源设置 │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │ 新增编辑查看 │ 员工信息设置 │ │ 字段标签设置 ● │ ┃ 个人信息 │ │ 相关方设置 │ ┃ 工龄计算方式: [...] │ │ ▾ 客源设置 │ ┃ 自动工号: [Toggle] │ │ ▾ 人事OA设置 │ │ │ │ [保存变更](Sticky 底部) │ └──────────────────┴────────────────────────────┘ ``` - **Read/Edit 模式切换**:右上角"编辑"按钮 → 全页切换到编辑态(Alpine.js 全局 `editing` 状态 + 数据快照以便"取消"还原) - 左侧导航支持二级折叠,激活项左侧 2px 主色竖条 - 底部保存按钮 Sticky(编辑态) ### 5.7 登录/认证页 独立布局,不使用 Sidebar。居中卡片 `max-w-md`,品牌色背景装饰(左侧 logo + slogan,右侧表单),参考 Salesforce Lightning 登录页密度。 ### 5.8 空状态页(Empty Page) 见 6.3。 ### 5.9 错误页(403/404/500) 三视图共享同一模板,仅图案与文案不同。`max-w-md mx-auto text-center` + SVG 插图 + 主按钮"返回首页"+ 次按钮"联系管理员"。 --- ## 6. 交互状态规范(Interaction States) ### 6.1 HTMX 请求生命周期 | 阶段 | 事件 | 视觉反馈 | |---|---|---| | 发送前 | `htmx:beforeRequest` | 目标区域 Skeleton / 按钮进入 Loading 态 / 触发元素禁用 | | 进行中 | `htmx:beforeOnLoad` | 保持 Loading | | 成功 | `htmx:afterSettle` | 移除骨架;如响应头含 `HX-Trigger: fonrey:toast` 则显示 Toast | | 422(校验失败) | 返回 Form Partial | 字段级红色提示 | | 其他失败 | `htmx:responseError` | 保留原内容 + 全局 Error Toast | | 网络超时 | `htmx:timeout` | 保留原内容 + "网络异常,请重试" Toast | ### 6.2 表单校验反馈 - **实时校验(Alpine.js)**:`blur` 时触发,不阻断提交 - **提交时校验(后端)**:后端返回 HTTP 422 + 包含错误 Partial;字段下方红色小字提示 - **错误提示位置**:字段下方,不使用顶部汇总(经纪人字段多,滚动回找浪费时间) - **提交成功**:Toast + 可选页面跳转(如新增后跳详情) ### 6.3 空状态设计 | 场景 | 标题 | 描述 | 引导操作 | |---|---|---|---| | 列表无数据 | 暂无房源 | 可以录入首条房源开始管理 | `+ 新增房源`(Primary) | | 搜索无结果 | 未找到匹配结果 | 请尝试调整筛选条件 | `清除筛选条件`(Link) | | 权限不足 | 暂无访问权限 | 请联系管理员申请权限 | `联系管理员`(Secondary) | | 功能关闭 | 功能未启用 | 请前往系统设置开启 | `前往设置`(Link,含权限判断) | 结构: ```html

暂无房源

可以录入首条房源开始管理

``` ### 6.4 键盘快捷键基线 | 快捷键 | 动作 | |---|---| | `Ctrl/Cmd + K` | 打开全局搜索 | | `Esc` | 关闭当前 Modal / Drawer | | `Enter` | 提交当前表单 / 确认 Modal(非 Textarea 场景) | | `Tab / Shift+Tab` | 表单字段间跳转 | | `/` | 聚焦当前页面主搜索框 | | `N`(列表页) | 打开"新增"入口 | --- ## 7. 图标规范(Icon Guidelines) ### 7.1 图标库 **Heroicons v2**(Tailwind 官方出品) - **Outline 24px**:默认选择(工具栏、导航、行内) - **Solid 20px**:用于状态指示、已选中态、强调 - **Mini 16px(solid)**:极密场景(表格行内、Tag 内) - 所有图标**继承文字颜色**(`currentColor`),不单独设置 `fill` 引入方式:Django 模板内联 SVG(通过自定义 templatetag `{% heroicon 'plus' %}`),避免远程请求,可利用 CDN 缓存。 ### 7.2 尺寸规范 | 尺寸 | 场景 | Tailwind | |---|---|---| | 24px | 侧边栏一级菜单 | `w-6 h-6` | | 20px | 顶部栏、Stat Card、Toast | `w-5 h-5` | | 16px | 按钮内、Tab、行内图标 | `w-4 h-4` | | 12px | Tag 内、状态点 | `w-3 h-3` | ### 7.3 核心图标映射 | 业务动作 | Heroicon | |---|---| | 新增 | `plus` | | 编辑 | `pencil-square` | | 删除 | `trash` | | 搜索 | `magnifying-glass` | | 筛选 | `funnel` | | 排序 | `chevron-up-down` | | 导出 | `arrow-down-tray` | | 导入 | `arrow-up-tray` | | 更多 | `ellipsis-horizontal` | | 关闭 | `x-mark` | | 返回 | `arrow-left` | | 刷新 | `arrow-path` | | 收藏 | `star`(solid = 已收藏) | | 分享 | `share` | | 通知 | `bell` | | 帮助 | `question-mark-circle` | | 用户 | `user` | | 组织 | `users` | | 房源 | `home`(首页为 `squares-2x2`) | | 客源 | `user-group` | | 楼盘 | `building-office-2` | | 权限 | `lock-closed` | | 设置 | `cog-6-tooth` | | 日历 | `calendar` | | 电话 | `phone` | | 钥匙 | `key` | | 附件 | `paper-clip` | | 图片 | `photo` | | 视频 | `video-camera` | | 下载 | `arrow-down-tray` | | 成功 | `check-circle` | | 警告 | `exclamation-triangle` | | 错误 | `x-circle` | | 信息 | `information-circle` | **一致性铁律**:同一业务动作在全产品使用**完全相同**的图标。新增业务动作需登记本映射表。 --- ## 8. 可访问性基线(Accessibility Baseline) - 所有表单字段必须关联 `