Sync: add design ux architecture notes

This commit is contained in:
2026-04-24 21:19:59 +08:00
parent 4b6b2f970c
commit 31d316b096
5 changed files with 168 additions and 50 deletions

View File

@@ -2,8 +2,8 @@
**状态**: Draft
**作者**: 产品经理
**最后更新**: 2026-04-24v1.1 验证码方式由图形字符验证码更新为滑块拼图行为验证码
**版本**: 1.1
**最后更新**: 2026-04-24v1.3 明确账号创建权限层级Tenant Admin 可自定义用户名/密码;普通员工账号由 Tenant Admin 在新增员工时创建,用户名为手机号,初始密码固定,首次登录强制修改
**版本**: 1.3
**所属系统**: Fonrey 房产经纪管理系统
**关联模块**: 组织人事管理、权限管理、系统管理
@@ -246,7 +246,7 @@ POST /api/auth/wechat/callback/ # 微信扫码确认后回调,换取系
| Logo | Fonrey 产品 Logo居中显示 |
| 标题 | 「欢迎使用 Fonrey 房睿」 |
| 副标题 | 「请输入您公司的专属识别码以继续」 |
| Tenant ID 输入框 | 单行文本,最大长度 64 字符,支持粘贴 |
| Tenant ID 输入框 | 单行数字输入,固定 12 位,支持粘贴;非数字字符自动过滤,超出 12 位截断 |
| 输入框 Label | 「公司识别码Tenant ID」 |
| 确认按钮 | 主色调按钮,文字「确认」 |
| 错误提示 | 输入框下方红色文字,固定区域占位(不影响布局抖动) |
@@ -254,10 +254,11 @@ POST /api/auth/wechat/callback/ # 微信扫码确认后回调,换取系
#### 5.1.3 Tenant ID 格式规范
- Tenant ID 由系统管理模块生成(每个租户在开通时由平台运营分配)
- 格式建议:`tenant_<slug>`,如 `tenant_fonrey_demo`,仅包含字母、数字、下划线,不区分大小写
- 长度6 ~ 64 字符
- 客户端存储位置Electron `app.getPath('userData')` 目录下的配置文件(加密存储,防止明文读取)
- **格式**:固定 **12 位纯数字**,如 `202500010001`
- **生成规则**(建议):由平台运营在系统管理后台开通租户时自动生成,不允许手动指定,确保全局唯一性;可采用时间戳前缀 + 随机后缀的方式生成(如 `YYYYMM` + 6 位随机数)
- **前端校验**:输入框仅接受数字字符(非数字自动过滤),输入满 12 位后自动触发格式完成状态;少于 12 位时点击「确认」弹出提示「识别码须为 12 位数字」
- **唯一性**:全局唯一(公共 Schema 层面),同一 Tenant ID 不可分配给多个租户
- **客户端存储**Electron `app.getPath('userData')` 目录下的配置文件(加密存储,防止明文读取)
#### 5.1.4 服务端 Tenant 验证接口规范
@@ -266,7 +267,7 @@ POST /api/auth/tenant/verify/
Request Body:
{
"tenant_id": "tenant_fonrey_demo"
"tenant_id": "202500010001"
}
Response 200 (成功):
@@ -346,29 +347,67 @@ Response 200 (失败):
#### 5.3.1 绑定原则
- 每个系统登录账号username必须与「组织人事管理」模块中的一条**员工档案Staff**绑定
- 员工档案包含:姓名、工号、手机号(可选,未来用于手机登录)、邮箱(用于找回密码)、所属门店/组别
- 每个系统登录账号必须与「组织人事管理」模块中的一条**员工档案Staff**绑定
- 账号与员工是 **1:1 关系**,一个员工对应一个账号,一个账号只能绑定一个员工
- 账号创建流程:**由系统管理员在「组织人事管理 → 员工列表」中为员工开通账号**,不支持用户自行注册
- 账号禁用:员工离职或被停用时,对应账号自动禁用;禁用账号无法登录,但历史操作记录保留
- **不支持用户自行注册**,所有账号均由有权限的管理角色创建
#### 5.3.2 账号字段规范
#### 5.3.2 账号创建权限分层
| 字段 | 规格 | 说明 |
|------|------|------|
| 用户名username | 英文字母开头,仅包含字母/数字/下划线6~30 字符,同租户内唯一 | 登录 ID不可更改 |
| 密码password | 8~32 位,含字母+数字,建议含特殊字符 | 使用 `PBKDF2+SHA256` 哈希存储 |
| 邮箱email | 标准邮箱格式,同租户内唯一(可选,但若空则无法自助找回密码) | 用于找回账号/密码 |
| 手机号phone | 中国大陆 11 位手机号,加密存储,同租户内唯一(可选) | 预留v2 用于手机登录 |
| 员工档案关联staff_id | 外键关联 `org.Staff` 模型 | 实名绑定 |
| 账号状态status | `active` / `disabled` / `locked` | locked 为密码错误锁定30 分钟自动恢复 |
| 初始密码 | 由管理员创建账号时设置或系统随机生成 | 建议首次登录强制修改密码 |
系统内共有两类账号创建场景,权限和规则各不相同:
#### 5.3.3 首次登录强制修改密码
**① Tenant Admin 账号(每个租户唯一的超级管理账号)**
- 管理员新建账号或重置密码后,账号处于「初始密码」状态
- 持有「初始密码」的账号登录成功后,系统自动弹出「请修改初始密码」强制页面,**不可跳过**
- 修改成功后,账号状态更新为正常,进入系统首页
| 项目 | 规格 |
|------|------|
| 创建时机 | 平台运营在系统管理后台开通租户时,同步创建第一个 Tenant Admin 账号 |
| 用户名 | **由平台运营自定义设置**,格式:英文字母开头,仅含字母/数字/下划线6~30 字符,同租户内唯一 |
| 初始密码 | **由平台运营自定义设置**须符合密码复杂度规则8~32 位,含字母+数字) |
| 首次登录 | 强制修改初始密码,不可跳过 |
| 权限范围 | 拥有该租户内最高权限,可管理员工账号、角色、系统设置等 |
| 数量限制 | 每个租户仅限 1 个 Tenant Admin 账号后续可扩展为多管理员v2 规划) |
**② 普通员工账号(经纪人、店长、行政等)**
| 项目 | 规格 |
|------|------|
| 创建时机 | Tenant Admin 在「组织人事管理 → 新增员工」时,系统自动为该员工创建登录账号 |
| 用户名 | **固定为该员工的手机号**11 位数字),同租户内唯一,创建后不可更改 |
| 初始密码 | **系统统一固定初始密码**(由平台在部署配置中设定,如 `Fonrey@2025`),所有新员工账号均使用同一初始密码 |
| 首次登录 | 强制修改初始密码,**不可跳过**(详见 5.3.4 |
| 密码重置 | Tenant Admin 可在员工管理界面对任意员工账号执行「重置密码」,重置后恢复为固定初始密码,触发首次登录强制修改流程 |
| 账号禁用 | 员工离职或被停用时,对应账号自动禁用;禁用账号无法登录,历史操作记录保留 |
#### 5.3.3 账号字段规范
| 字段 | 类型 | Tenant Admin | 普通员工账号 | 说明 |
|------|------|-------------|-------------|------|
| 用户名username | CharField(30) | 平台运营自定义,字母开头,含字母/数字/下划线6~30 字符 | **固定为员工手机号**11 位数字) | 登录 ID创建后不可更改 |
| 密码password | CharField | 平台运营自定义初始密码 | **系统统一固定初始密码** | PBKDF2+SHA256 哈希存储 |
| 手机号phone | CharField(11) | 选填,加密存储 | **必填,同时作为用户名**,加密存储,同租户内唯一 | 当前阶段为登录 IDv2 启用手机验证码登录后复用此字段 |
| 邮箱email | EmailField | 选填,同租户唯一 | 选填,同租户唯一 | 用于找回密码;若为空则无法自助找回 |
| 员工档案关联staff_id | OneToOneField → `org.Staff` | 可选关联(平台运营账号) | 必须关联 | 实名绑定 |
| 账号状态status | CharField | `active` / `disabled` / `locked` | `active` / `disabled` / `locked` | locked 为密码错误锁定30 分钟自动恢复 |
| 初始密码标记is_initial_password | BooleanField | True首次登录前 | True首次登录前 | True 时登录成功后强制跳转修改密码页 |
| 创建人created_by | ForeignKey → self | 平台运营(系统管理后台) | Tenant Admin | 审计追溯 |
#### 5.3.4 首次登录强制修改密码
- 新员工账号创建后,`is_initial_password = True`,账号处于「初始密码」状态
- 员工使用手机号(用户名)+ 固定初始密码登录成功后,系统**立即跳转**至「修改初始密码」强制页面,**不可关闭、不可跳过**,任何其他系统功能页面均不可访问
- Tenant Admin 对员工账号执行「重置密码」后,`is_initial_password` 重置为 True该员工下次登录时再次触发强制修改流程
- 修改成功后,`is_initial_password` 更新为 False原 Session 保持有效,直接进入系统首页
**强制修改密码页面规范**
| 元素 | 规格 |
|------|------|
| 页面标题 | 「欢迎使用 Fonrey请先设置您的登录密码」 |
| 提示文案 | 「您当前使用的是初始密码,为保障账号安全,请立即设置新密码后开始使用」 |
| 新密码输入框 | 密文显示,右侧「显示/隐藏」切换 |
| 确认新密码输入框 | 密文显示,与新密码一致性实时校验 |
| 密码强度提示 | 逐条实时显示规则达标状态(✓/✗):长度 ≥ 8 位 / 包含字母 / 包含数字 |
| 提交按钮 | 「确认并进入系统」 |
| 不可操作项 | 无「跳过」按钮;顶部导航栏、侧边菜单、关闭按钮均禁用 |
---
@@ -376,21 +415,30 @@ Response 200 (失败):
#### 5.4.1 找回用户名流程
> **说明**:由于普通员工的用户名即为其**手机号**,通常无需「找回用户名」功能。登录界面的「忘记用户名」入口保留,但仅对 Tenant Admin 账号有意义(其用户名为自定义字符串)。
```
用户点击「忘记用户名」
├─ 输入邮箱地址
│ 服务端查询该邮箱是否绑定账号(不向前端返回查询结果,防止枚举)
│ │
│ 统一响应「如该邮箱已绑定账号,您将收到邮件」
│ │
│ 后台:若邮箱存在 → 发送邮件(包含用户名)
│ 若邮箱不存在 → 静默处理,不发送
├─ 普通员工:提示「您的登录账号为您的手机号,请直接使用手机号登录」
提供「返回登录」按钮
└─ 用户查收邮件,获取用户名 → 返回登录
└─ Tenant Admin用户名非手机号格式
├─ 输入绑定邮箱
│ │
│ 服务端查询(不向前端返回查询结果,防止枚举)
│ │
│ 统一响应「如该邮箱已绑定账号,您将收到邮件」
│ │
│ 后台:邮箱存在 → 发送邮件(包含用户名)
│ 邮箱不存在 → 静默处理
└─ 用户查收邮件,获取用户名 → 返回登录
```
> **前端识别逻辑**:用户在「忘记用户名」页面输入邮箱提交后,服务端根据是否匹配到 Tenant Admin 账号决定处理路径,前端无需区分,统一展示「如该邮箱已绑定账号,您将收到邮件」。
**邮件模板(找回用户名)**
```
@@ -413,13 +461,16 @@ Response 200 (失败):
```
用户点击「忘记密码」
步骤1输入用户名 + 邮箱
步骤1身份验证
├─ 服务端校验(用户名 + 邮箱匹配)
├─ 输入手机号(即用户名+ 绑定邮箱
Tenant Admin 则输入自定义用户名 + 绑定邮箱)
│ │
统一响应「如信息匹配,重置链接将发送至您的邮箱」
服务端校验用户名与邮箱是否匹配
│ │
后台:匹配成功 → 生成加密 Token含过期时间 30min→ 发送邮件
统一响应「如信息匹配,重置链接将发送至您的邮箱」(防止枚举)
│ │
│ 后台:匹配成功 → 生成加密 Token有效期 30min→ 异步发送邮件
│ 不匹配 → 静默处理
步骤2用户点击邮件中的重置链接
@@ -428,16 +479,20 @@ Response 200 (失败):
│ │
│ 有效 → 展示「重置密码」表单
│ │
│ 无效/过期 → 提示「链接已过期,请重新申请」
│ 无效/过期 → 提示「链接已过期,请重新申请」,提供「重新申请」按钮
步骤3用户输入并提交新密码
├─ 密码复杂度校验
├─ 与历史密码对比校验(最近 3 次)
├─ 密码复杂度校验(≥ 8 位,含字母+数字)
├─ 与历史密码对比校验(最近 3 次,含固定初始密码
└─ 校验通过 → 更新密码 → 清除所有 Session → 跳转登录界面
└─ 校验通过 → 更新密码is_initial_password = False
→ 清除该账号所有有效 Session强制重新登录
→ 跳转登录界面,提示「密码已重置,请重新登录」
```
> **注意**:找回密码流程依赖员工账号绑定了邮箱。若员工未绑定邮箱,无法自助找回,需联系 Tenant Admin 在管理界面执行「重置密码」操作,将密码恢复为固定初始密码。
**邮件模板(重置密码)**
```
@@ -482,16 +537,17 @@ apps/
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | BigAutoField | 主键 |
| `username` | CharField(30) | 登录名,同租户唯一,不可变更 |
| `username` | CharField(30) | 登录名,同租户唯一,不可变更普通员工账号固定为手机号11位数字Tenant Admin 为自定义字符串 |
| `password` | CharField | PBKDF2+SHA256 哈希,使用 Django `make_password` |
| `email` | EmailField | 绑定邮箱,同租户唯一,选填 |
| `phone` | CharField(11) | 绑定手机号,加密存储(`core.encryption`选填 |
| `staff` | OneToOneField → `org.Staff` | 员工档案绑定,必须 |
| `email` | EmailField | 绑定邮箱,同租户唯一,选填;为空时无法自助找回密码 |
| `phone` | CharField(11) | 绑定手机号,加密存储(`core.encryption`;普通员工必填(同时作为 username 来源Tenant Admin 选填 |
| `staff` | OneToOneField → `org.Staff` | 员工档案绑定普通员工必须Tenant Admin 可为空 |
| `is_tenant_admin` | BooleanField | 标记是否为该租户的 Tenant Admin 账号,默认 False |
| `status` | CharField | `active` / `disabled` / `locked` |
| `is_initial_password` | BooleanField | True 时登录后强制修改密码 |
| `is_initial_password` | BooleanField | True 时登录成功后强制跳转修改密码页,不可跳过 |
| `last_login` | DateTimeField | 最后登录时间 |
| `created_at` | DateTimeField | 账号创建时间 |
| `created_by` | ForeignKey → self | 创建人(管理员 |
| `created_by` | ForeignKey → self | 创建人(普通员工由 Tenant Admin 创建Tenant Admin 由平台运营创建 |
#### 5.5.3 `LoginAttempt` 登录尝试记录