新增笔记
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -76,6 +76,10 @@
|
||||
11. `UI_DESIGN/` 下已审阅的静态页面(`.html`/`.md`)属于**强约束输入**:必须以其为实现基线,禁止擅自重做页面信息架构、主布局、字段顺序与关键交互。
|
||||
12. 若实现与 UI 静态页存在冲突:先按 UI 静态页落地,并在交付中列出冲突点;不得在未确认前自行改版 UI。
|
||||
|
||||
### 3.1) 可复用模板(建议直接引用)
|
||||
|
||||
- API 契约冲突提报模板:`Project/fonrey/prompt/提示词模板/API_CONTRACT_冲突提报模板_v1.md`
|
||||
|
||||
## 4) 通用执行模板(复制后替换 US 内容)
|
||||
|
||||
```text
|
||||
@@ -114,6 +118,12 @@
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 关键实现说明
|
||||
- 测试结果
|
||||
@@ -273,6 +283,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -341,6 +358,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -409,6 +433,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -477,6 +508,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -545,6 +583,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -613,6 +658,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -681,6 +733,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -749,6 +808,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -817,6 +883,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -885,6 +958,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -953,6 +1033,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1025,6 +1112,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1097,6 +1191,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1168,6 +1269,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1242,6 +1350,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1311,6 +1426,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1379,6 +1501,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1448,6 +1577,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1517,6 +1653,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1586,6 +1729,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1654,6 +1804,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1722,6 +1879,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1790,6 +1954,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1858,6 +2029,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1926,6 +2104,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -1995,6 +2180,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2064,6 +2256,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2133,6 +2332,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2202,6 +2408,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2271,6 +2484,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2340,6 +2560,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2409,6 +2636,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2478,6 +2712,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2547,6 +2788,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2616,6 +2864,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2685,6 +2940,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2754,6 +3016,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2823,6 +3092,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2892,6 +3168,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -2961,6 +3244,13 @@
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -3029,6 +3319,13 @@ Celery Beat 定时任务每日凌晨执行;超过运营配置天数(如30天
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
@@ -3097,6 +3394,13 @@ Celery Beat 定时任务每日凌晨执行;超过运营配置天数(如30天
|
||||
|
||||
【交付格式】
|
||||
- 变更文件列表
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
- UI 一致性核对清单(逐条对应 UI 静态页:已对齐/偏差项)
|
||||
- 核心实现说明(与验收标准逐条对应)
|
||||
- 测试命令与结果
|
||||
|
||||
421
Project/fonrey/REVIEW/REVIEW_全局_2026-04-28.md
Normal file
421
Project/fonrey/REVIEW/REVIEW_全局_2026-04-28.md
Normal file
@@ -0,0 +1,421 @@
|
||||
# Fonrey 全局系统设计 Review 报告
|
||||
|
||||
> **Review 类型**:全量 Review(PRD + DATA_MODEL + TECH_STACK + UI/UX + TASK 交叉验证)
|
||||
> **Review 模式**:增量对比 `REVIEW_全局_2026-04-26.md`,逐条核对 4 Blocker + 12 Major 状态,识别新增风险
|
||||
> **Review 日期**:2026-04-28
|
||||
> **Reviewer**:首席系统设计 Reviewer(AI 辅助,6 路并行 explore agent 取证)
|
||||
> **当前阶段**:需求 ~90% / 数据模型 ~80% / UI 设计 ~35%(HTML 原型推进中)/ TECH 横切规范 ~70%
|
||||
> **覆盖文档**:9 份 PRD + 10 份 TECH_STACK + 9 份 DATA_MODEL(含新增 ENUMS.md v2.2)+ 3 份 UI_SYSTEM + 11 份 UI_DESIGN + TASK 总表
|
||||
> **问题分级**:🔴 Blocker(阻塞开发) / 🟠 Major(必须修复但不阻塞) / 🟡 Minor(建议优化)
|
||||
> **状态标记**:✅ 已修复 / ⚠️ 部分修复 / ❌ 未修复 / 🆕 新增
|
||||
|
||||
---
|
||||
|
||||
## 〇、执行摘要(Executive Summary)
|
||||
|
||||
### 整体评价
|
||||
|
||||
相较 2026-04-26 版本,本期文档体系出现 **5 项实质性进展**,是历次 Review 以来修复力度最大的一次:
|
||||
|
||||
1. **🟢 B-01 系统配置 PRD 落地**:`PRD/系统配置/系统配置模块PRD.md`(273 行)+ `系统配置参数数据.md`(1100 行)+ `系统配置数据模型设计说明_for_Atlas.md`(275 行)三件套已完整产出,含 US-SETTING-001-A/B/C 三条 P0 Story 与完整验收标准。MVP 范围被显式约束(明确 ❌ 标签/带看/通知/发布平台等推迟到 P1/P2),**降低实施风险**。
|
||||
2. **🟢 B-02 枚举三方不一致根除**:`DATA_MODEL/ENUMS.md` v2.2(780 行,2026-04-28)作为**唯一权威源**已建立,全量统一为 `lower_snake_case`,历史大写值(`SUCCESS`/`A_urgent`/`A_app`)的迁移规则已写明,并要求 DB CHECK / `enum_labels` / 前端三方同步。
|
||||
3. **🟢 B-03 权限档位冲突收敛**:权限 PRD §3 已显式表述"五档基线 + 各权限项可选子集(含三档场景)";DATA_MODEL_PERMISSION 的 `staff_data_scopes` 表(已建 DDL,含 3 条索引)实现"跨层级并集"模型,PRD ↔ Data ↔ Code 三方对齐。
|
||||
4. **🟢 B-04 Keyset 分页规范化**:`API_CONTRACT.md` §4 已写入 `{"mode":"keyset","cursor":"...","limit":20}` 标准合约 + 不透明游标禁令;客源/房源/楼盘/组织 4 个模块技术方案均已采用此契约。
|
||||
5. **🟢 M-01 测试规范多租户化**:`TECH_STACK.md:208` + `测试规范.md:69,146` 三处明确"必须使用 `TenantClient`,禁止 Django 原生 `Client()`",4 个模块技术方案同步引用。
|
||||
|
||||
但本期 Review 也确认 **3 类系统性债务未动**,且因其他模块详化反而更显突出:
|
||||
|
||||
- **❌ 主表乐观锁 `version` 字段** —— 全量 DATA_MODEL 0 命中,89k 房源并发编辑场景(PRD 明确双经纪人同时改房)将出现"后写覆盖前写"。
|
||||
- **❌ 高写入表 `PARTITION BY` DDL** —— `follow_logs` / `property_photos` / `permission_change_logs` / `login_attempts` / `platform_audit_logs` 全量 0 命中分区子句,仅文字"建议月度分区"。**200 万跟进日志 + 2 年保留期** 的查询性能未保障。
|
||||
- **❌ KMS / 密钥轮换 SOP** —— 仅见"`R2_ADMIN_KEY` 通过 Docker Secret 注入",无主密钥轮换流程、无应急吊销、无加密字段重新封装。
|
||||
|
||||
### 核心问题摘录(Top 10)
|
||||
|
||||
| # | 等级 | 编号 | 问题 | 维度 | 状态 |
|
||||
|---|------|------|------|------|------|
|
||||
| 1 | 🔴 | **B-05** | 主表乐观锁 `version` 字段全量 0 实现:`properties` / `clients` / `complexes` 在 PRD 多人协作场景中是核心,DDL 无并发控制 | Data↔PRD | 🆕 升 Blocker(持续 3 次未修) |
|
||||
| 2 | 🔴 | **B-06** | 高写入表分区 DDL 仍未落地(M-03 持续 3 次未修):5 张高频表无 `PARTITION BY RANGE` 子句,仅注释"建议月度分区",无法在迁移期补加分区 | Data | 🆕 升 Blocker |
|
||||
| 3 | 🟠 | **M-11** | KMS / 密钥轮换 SOP 仍未补:`core/encryption.py` 已声明,但主密钥轮换、密钥版本号、加密字段重新封装、应急吊销四类流程在 TECH_STACK 与系统管理 PRD 中均无对应章节 | 安全 | ❌ 持续未修 |
|
||||
| 4 | 🟠 | **M-12** | Celery 任务 schema 切换缺统一封装:多模块技术方案声明 `tenant_schema_name` 入参,但无 `with_tenant_context` 装饰器或基类抽象,开发期容易漏写导致跨租户脏读 | TECH/多租户 | ⚠️ 部分修复 |
|
||||
| 5 | 🟠 | **M-13** | R2 路径前缀全局规范不一致:系统管理已规范 `backups/{tenant_schema}/...` `exports/{tenant_schema}/...`,但客源/房源/楼盘模块 R2 路径仍写"`property_photos/...`"无 tenant 前缀模板 | TECH/多租户 | ⚠️ 部分修复 |
|
||||
| 6 | 🟠 | **M-06** | 客户端发布无签名校验/防降级:`/api/client/updates/latest/` 与 `download_url` 对外公开,仅 SHA256 完整性校验,可被 MITM 投递降级版本(昨日 M-06 未修) | 安全 | ❌ 持续未修 |
|
||||
| 7 | 🟠 | **M-14** | ORM Manager / QuerySet 数据范围统一封装规范缺失:`DATA_MODEL_PERMISSION.md:143-145` 的 `ScopeQueryBuilder` 只是 helper,未规定"所有业务 QuerySet 必须经过 Scope 包装"的强制约束,开发期容易漏权限校验 | 安全/Data | 🆕 新增 |
|
||||
| 8 | 🟠 | **M-05** | 89k 数据 < 2 秒列表查询 NFR 仍无 p95/EXPLAIN/性能基准测试任务(昨日 M-05 未修) | NFR↔TECH↔测试 | ❌ 持续未修 |
|
||||
| 9 | 🟠 | **M-09** | UI_SYSTEM 复杂组件(虚拟滚动列表、批量操作面板、抽屉表单嵌套规则、文件上传批量、富权限树)规范深度不足;UI_DESIGN 11 份原型仅覆盖客源 + 房源列表,**楼盘/权限/系统配置/组织人事/发布管理 5 大模块全部缺原型** | UI | ⚠️ 部分修复 |
|
||||
| 10 | 🟡 | **N-01** | ENUMS.md v2.2 已统一,但 PRD 文本中仍混用中文枚举(如客源 PRD 仍写"求购/求租"),需要一次全文档"中文枚举 → ENUMS 锚点链接"替换 | PRD↔Data | 🆕 新增 |
|
||||
|
||||
### 风险等级分布
|
||||
|
||||
| 等级 | 本次(2026-04-28) | 上次(2026-04-26) | 净变化 |
|
||||
|------|---|---|---|
|
||||
| 🔴 Blocker | **2** | 4 | -2(B-01/B-02/B-03/B-04 全部清零;B-05/B-06 由历史 Major 升级) |
|
||||
| 🟠 Major | **9** | 12 | -3(M-01 已修复关闭;M-02→B-05、M-03→B-06 升级) |
|
||||
| 🟡 Minor | **3** | 6 | -3(聚焦 Top 风险) |
|
||||
| 合计 | **14** | 22 | -8 |
|
||||
|
||||
### 增量对比一览(昨日 Blocker / Major → 今日状态)
|
||||
|
||||
| 上次编号 | 简述 | 状态 | 今日处置 |
|
||||
|----------|------|------|----------|
|
||||
| **B-01** | 系统配置 PRD 空骨架 | ✅ **已修复**(273+1100+275 行三件套) | 关闭 |
|
||||
| **B-02** | 枚举三方不一致 | ✅ **已修复**(ENUMS.md v2.2 权威源) | 关闭,遗留 N-01(PRD 文本回写) |
|
||||
| **B-03** | 权限三档/五档冲突 | ✅ **已修复**(五档基线 + 子集子句) | 关闭,遗留 M-14(ORM 强制约束) |
|
||||
| **B-04** | Keyset 分页缺失 | ✅ **已修复**(API_CONTRACT §4 + 4 模块) | 关闭 |
|
||||
| M-01 | 测试规范多租户化 | ✅ 已修复(TenantClient 强制) | 关闭 |
|
||||
| M-02 | 主表乐观锁 / 楼盘锁 | ❌ 持续未修 | **升 B-05** |
|
||||
| M-03 | 高写入表分区 | ❌ 持续未修 | **升 B-06** |
|
||||
| M-04 | Celery/R2/索引规范 | ⚠️ 部分修复(拆分) | 拆分为 M-12 / M-13 / 残留索引矩阵 |
|
||||
| M-05 | 89k 数据 < 2s NFR 测试 | ❌ 持续未修 | M-05 |
|
||||
| M-06 | 客户端发布签名 | ❌ 持续未修 | M-06 |
|
||||
| M-07~M-08 | 价格走势 / 楼盘市场报盘 | ⚠️ 降级 | 转 N-02(Minor) |
|
||||
| M-09 | UI 组件 + Wireframe | ⚠️ 部分修复 | M-09 |
|
||||
| M-10 | Redis Key tenant 前缀 | ✅ 已修复(系统设置技术方案 §6.4) | 关闭 |
|
||||
| M-11 | 加密密钥管理 | ❌ 持续未修 | M-11 |
|
||||
| M-12 | 数据保留与归档 | ⚠️ 部分修复 | 转 N-03 |
|
||||
|
||||
---
|
||||
|
||||
## 一、PRD 一致性审查(PRD ↔ PRD ↔ TASK)
|
||||
|
||||
### ✅ 历史 B-01(系统配置 PRD 空骨架)已修复
|
||||
|
||||
**证据**:
|
||||
- `PRD/系统配置/系统配置模块PRD.md`(273 行,v0.1,2026-04-27):含目标度量、非目标范围、3 条 P0 User Story(US-SETTING-001-A/B/C)与完整 Given-When-Then 验收标准。
|
||||
- `PRD/系统配置/系统配置参数数据.md`(1100 行):实际参数清单。
|
||||
- `PRD/系统配置/系统配置数据模型设计说明_for_Atlas.md`(275 行):与 DATA_MODEL_SETTING.md 对齐。
|
||||
|
||||
**剩余风险(降级为 Minor N-04)**:US-SETTING-001 的"配置变更生效时效 ≤ 5 分钟(Redis 缓存 TTL)"与 `DATA_MODEL_SETTING.md` 的 Redis Key TTL = 300s 一致,但**无 Cache Invalidation 主动失效路径**(仅靠 TTL 过期),管理员保存后 5 分钟内一线经纪人仍看不到新选项 —— PRD AC-2 "刷新后立即可见" 与实现存在间隙。
|
||||
|
||||
---
|
||||
|
||||
### ✅ 历史 B-02(核心枚举三方不一致)已修复
|
||||
|
||||
**证据**:
|
||||
- `DATA_MODEL/ENUMS.md` v2.2(780 行,2026-04-28):作为唯一权威源,覆盖 Public(tenant 生命周期、平台管理员、备份导出、升级发布)+ Tenant(客源/房源/楼盘/权限/组织/系统设置)所有枚举域。
|
||||
- 命名规范统一为 `lower_snake_case`,历史大写值(`SUCCESS`/`FAILED`/`A_urgent`/`A_app`/`B_schema`/`C_feature`/`REPLACE`/`RESTRICT`/`GRANT`)的迁移路径已书面化。
|
||||
|
||||
**剩余风险(N-01 Minor)**:PRD 文本与 TASK AC 中仍存在大量中文/旧值混用(如客源 PRD 仍写"求购/求租")。需要一次性回写:
|
||||
- 在每份 PRD 顶部加 `> 枚举值参见 DATA_MODEL/ENUMS.md` 锚点
|
||||
- 在 ENUMS.md 中给每个枚举值附"中文展示标签"列(部分已有)
|
||||
- TASK.md 排一条 P0 任务:PRD 中文枚举 → 英文锚点引用
|
||||
|
||||
---
|
||||
|
||||
### ✅ 历史 B-03(权限档位三档/五档冲突)已修复
|
||||
|
||||
**证据**:
|
||||
- `PRD/权限管理/权限管理模块PRD.md:46`:明文"采用**五档模型**:本人 / 本组 / 本门店 / 本区域 / 全公司。注意:并非所有权限项均开放五档,各项的实际可选范围以权限编辑页的下拉配置为准(例如某些权限项仅提供「本人 / 本门店 / 全公司」三个选项)"
|
||||
- `:499`:复述同一约定,闭环。
|
||||
- `DATA_MODEL_PERMISSION.md:24,31,254-275,967-987`:`staff_data_scopes` 表 DDL 完整,索引 3 条到位,"员工数据范围 = 所有 staff_data_scopes 对应 org_units.path 子树并集"实现"跨层级叠加"。
|
||||
|
||||
**剩余风险(M-14 Major)见 §五**:DATA_MODEL_PERMISSION 的 `ScopeQueryBuilder` 只是 helper class,未在 TECH_STACK 中强制规定"所有业务 QuerySet 必须经过 Scope 包装",开发期容易漏写导致越权读取。
|
||||
|
||||
---
|
||||
|
||||
### 🟡 N-01 PRD 文本回写 ENUMS 锚点(来自 B-02 残留)
|
||||
|
||||
详见上文。**责任**:PM 在 Phase 1 编码启动前完成全量 PRD 文本扫描替换。
|
||||
|
||||
---
|
||||
|
||||
## 二、TECH_STACK / API / 测试规范审查
|
||||
|
||||
### ✅ 历史 B-04(Keyset 分页缺失)已修复
|
||||
|
||||
**证据**:
|
||||
- `API_CONTRACT.md:143,154,157,182`:标准请求/响应契约 `{"mode":"keyset","cursor":"opaque_cursor","limit":20}` + `next_cursor`
|
||||
- `API_CONTRACT.md:165`:`cursor` MUST 为不透明字符串,**禁止暴露内部排序字段组合** ✅ 与 OWASP 推荐一致
|
||||
- `API_CONTRACT.md:378`:drf-spectacular `OpenApiParameter("cursor", ...)` 注解
|
||||
- 客源 / 房源 / 楼盘 / 组织 4 个模块技术方案均同步采用
|
||||
|
||||
**剩余 Minor**:尚无 Keyset SQL 模板(含 `WHERE (sort_key, id) < (?, ?)` 的复合键模板)。建议在 `TECH_STACK.md` 新增 §"分页 SQL 模板"章节,给出含 `tenant_schema` schema-search-path 切换 + 复合键的标准实现。
|
||||
|
||||
---
|
||||
|
||||
### ✅ 历史 M-01(测试规范多租户化)已修复
|
||||
|
||||
**证据**:
|
||||
- `TECH_STACK.md:203,208,211`:明确 TenantClient 强制 + R2/Redis/邮件 Mock
|
||||
- `测试规范.md:55,69,146,230`:`TenantClient` 在测试金字塔图、约束章节、请求路径、Mock 策略 4 处统一表述
|
||||
- 4 个模块技术方案均引用
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-12 Celery 多租户 schema 切换无统一封装(M-04 拆分)
|
||||
|
||||
**文档**:`TECH_STACK/客源管理技术方案.md` / `房源管理技术方案.md` / `楼盘管理技术方案.md` / `组织人事技术方案.md`(均声明 `tenant_schema_name` 入参)vs `TECH_STACK.md`(无统一规范)
|
||||
|
||||
**事实**:
|
||||
- 模块技术方案约定 Celery 任务签名带 `tenant_schema_name: str` 形参,但**无 `with_tenant_context(schema)` 装饰器或基类**。
|
||||
- 系统设置技术方案虽给出 schema 切换示例(`:28-31`),但未提取为通用规范。
|
||||
- `core/cache.py` 已规范带前缀,但 ORM 查询的 schema 切换由开发者手写 `connection.set_schema(...)`,**漏写不报错**。
|
||||
|
||||
**影响**:
|
||||
- Celery worker 在多租户调度下,相邻任务可能因 search_path 残留导致跨租户脏读/脏写。
|
||||
- 单元测试若忘记设置 schema,测试通过但生产出错。
|
||||
|
||||
**改进方向**:
|
||||
- 在 `TECH_STACK.md` 新增 §"Celery 多租户规范":
|
||||
- 强制所有业务 task 用 `@tenant_task(schema_arg="tenant_schema_name")` 装饰器
|
||||
- 装饰器职责:进入时 `set_schema_to(schema)`,退出/异常时 `set_schema_to_public()`,记录 task_id 与 schema 到结构化日志
|
||||
- 测试规范补:"Celery 任务测试必须显式 mock schema 切换断言"
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-13 R2 路径前缀全局规范不一致(M-04 拆分)
|
||||
|
||||
**文档**:`TECH_STACK/系统管理技术文档.md:521-525`(已规范)vs 客源/房源/楼盘技术方案(未规范)
|
||||
|
||||
**事实**:
|
||||
- 系统管理已统一:`backups/{tenant_schema}/{record_id}.tar.gz` / `exports/{tenant_schema}/{task_id}.zip` / `releases/system/{version}/...`(无 tenant 前缀,公共资源)✅
|
||||
- 房源 / 客源模块的图片 / 跟进附件 R2 路径**未在文档中给出 key 模板**,仅写"预签名上传"。
|
||||
- 公开发布包路径无 tenant 前缀(合理:客户端尚未登录),但**生产环境 bucket policy 需明示**:哪些 prefix 是 public-read,哪些需要 signed URL。
|
||||
|
||||
**影响**:
|
||||
- 跨租户文件越权访问风险(房源图片如果误用全局 prefix,A 租户能猜到 B 租户对象 key)。
|
||||
- 生命周期策略(如客源跟进附件 90 天清理)无 prefix 难以配置。
|
||||
|
||||
**改进方向**:
|
||||
- 在 `TECH_STACK.md` 新增"R2 路径规范"统一表:
|
||||
```
|
||||
公共资源 → releases/system/{version}/... public-read
|
||||
租户 backup → backups/{tenant_schema}/{rid}.tar.gz signed only
|
||||
租户 export → exports/{tenant_schema}/{tid}.zip signed-24h
|
||||
房源图片 → media/{tenant_schema}/property/{pid}/{photo_id}.{ext}
|
||||
跟进附件 → media/{tenant_schema}/follow/{log_id}/{idx}.{ext}
|
||||
审计归档 → exports/audit/{task_id}.csv signed only
|
||||
```
|
||||
- 路径中**禁止出现 tenant_id(UUID)**,统一用 `tenant_schema_name`,便于跨环境迁移。
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-05 89k 数据 < 2 秒列表查询 NFR 仍无性能基准(持续未修)
|
||||
|
||||
**文档**:`PRD/客源管理/客源管理模块PRD.md` US-CLIENT-002 / `PRD/房源管理/房源管理模块PRD.md` US-PROPERTY-002 NFR:列表查询 p95 < 2s(89k 数据)
|
||||
|
||||
**事实**:
|
||||
- 测试规范未含 p95 / EXPLAIN ANALYZE / pg_stat_statements 集成。
|
||||
- 无 89k 量级 seed factory(仅有单条 fixture)。
|
||||
- 无 CI 性能回归任务(如 pgTAP / pytest-benchmark)。
|
||||
- AC 中"< 2 秒"实质不可测。
|
||||
|
||||
**改进方向**:
|
||||
- 在 `测试规范.md` 增补 §"性能测试":
|
||||
- seed: `make seed-perf` 灌入 89k 房源 + 200k 客源 + 200 万 follow_logs
|
||||
- 工具: `pytest-benchmark` + `EXPLAIN (ANALYZE, BUFFERS)` 输出归档
|
||||
- 阈值: 列表 p95 < 2s / 详情 p95 < 500ms / 写入 p95 < 1s
|
||||
- CI: nightly 跑一次,回归 > 20% 标 fail
|
||||
- 优先 instrument 客源/房源列表 API(含 keyset 翻第 100 页场景)
|
||||
|
||||
---
|
||||
|
||||
## 三、DATA_MODEL 审查
|
||||
|
||||
### 🔴 B-05 主表乐观锁 `version` 字段全量未实现(M-02 升级,连续 3 次未修)
|
||||
|
||||
**文档**:`DATA_MODEL/DATA_MODEL_PROPERTY.md` / `DATA_MODEL_CLIENT.md` / `DATA_MODEL_COMPLEX.md`
|
||||
|
||||
**事实**:grep `version|乐观锁|optimistic` 在 properties / clients / complexes 主表 DDL 中 **0 命中**(`version` 仅出现在 ENUMS.md 文档版本号、`SystemVersion` 表名、Permission 缓存 key `:perm:version` 等不相关上下文中)。
|
||||
|
||||
**业务场景**(PRD 多处):
|
||||
- 房源 PRD:双经纪人同时编辑同一房源(一人改价、一人改状态)
|
||||
- 客源 PRD:录入员 + 跟进经纪人同时编辑客源等级
|
||||
- 楼盘 PRD:4 类锁字段(lock_building/lock_room/lock_info/lock_standard_room)已建,但**无 `lock_version` 触发 update conflict**
|
||||
|
||||
**影响**:后写覆盖前写、数据丢失,**89k 房源体量下必然出现**。
|
||||
|
||||
**改进方向**:
|
||||
- DDL 增加:
|
||||
```sql
|
||||
ALTER TABLE properties ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE clients ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE complexes ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
|
||||
```
|
||||
- 应用层:`Model.objects.filter(id=x, version=v_old).update(..., version=F('version')+1)`,受影响行 0 → 抛 `ConflictError`,前端展示"已被他人修改,请刷新后重试"。
|
||||
- API_CONTRACT.md 增补 `If-Match: <version>` Header 规范(PUT/PATCH 必传)。
|
||||
|
||||
---
|
||||
|
||||
### 🔴 B-06 高写入表分区 DDL 仍未落地(M-03 升级,连续 3 次未修)
|
||||
|
||||
**文档**:`DATA_MODEL/DATA_MODEL_CLIENT.md`(follow_logs)/ `DATA_MODEL_PROPERTY.md`(property_photos)/ `DATA_MODEL_PERMISSION.md`(permission_change_logs)/ `DATA_MODEL_LOGIN.md`(login_attempts)/ `DATA_MODEL_PUBLIC.md`(platform_audit_logs)
|
||||
|
||||
**事实**:grep `PARTITION BY|分区表|partition` 在 DATA_MODEL 全量 0 命中。仅文字"建议月度分区"。
|
||||
|
||||
**业务体量**(PRD 与 NFR):
|
||||
- `follow_logs`:200 万 / 2 年保留期
|
||||
- `property_photos`:89k 房源 × 平均 8 张 ≈ 70 万行
|
||||
- `login_attempts`:所有登录失败/成功审计
|
||||
- `platform_audit_logs`:跨租户全平台审计
|
||||
|
||||
**影响**:单表过大导致索引膨胀、VACUUM 阻塞、按时间窗口归档不可分区操作。**编码后再切分区将停机迁移**,是必须前置的设计决策。
|
||||
|
||||
**改进方向**:
|
||||
- DDL 改为:
|
||||
```sql
|
||||
CREATE TABLE follow_logs (
|
||||
id BIGSERIAL,
|
||||
created_at TIMESTAMPTZ NOT NULL,
|
||||
...
|
||||
PRIMARY KEY (id, created_at) -- 分区键必须含 created_at
|
||||
) PARTITION BY RANGE (created_at);
|
||||
|
||||
CREATE TABLE follow_logs_2026_04 PARTITION OF follow_logs
|
||||
FOR VALUES FROM ('2026-04-01') TO ('2026-05-01');
|
||||
```
|
||||
- 增补 Celery 周期任务 `partition_maintenance_task`(每月最后一天):自动建下月分区 + drop 超出保留期分区。
|
||||
- DATA_MODEL.md 增 §"分区策略"统一表(保留期 / 分区粒度 / 维护任务)。
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-14 ORM 数据范围统一封装规范缺失(B-03 残留)
|
||||
|
||||
**文档**:`DATA_MODEL/DATA_MODEL_PERMISSION.md:143-145, 414-455`
|
||||
|
||||
**事实**:
|
||||
- `ScopeQueryBuilder` 已实现(含 `is_protected` 二次 AND 规则)。
|
||||
- 但**未在 TECH_STACK 中强制要求"所有业务 QuerySet 必须经过 ScopeQueryBuilder"**。
|
||||
- 模块技术方案 view 层示例代码直接 `Property.objects.filter(...)`,可绕过权限控制。
|
||||
|
||||
**影响**:开发新功能时漏接 ScopeQueryBuilder → 越权读取,且测试不易发现。
|
||||
|
||||
**改进方向**:
|
||||
- TECH_STACK 增补"ORM 数据范围强制规范":
|
||||
- 业务 Model 不暴露默认 `objects` Manager,统一暴露 `scoped(staff)` 入口
|
||||
- 写一个 lint rule(pylint plugin / pre-commit):禁止业务模块直接调用 `<Model>.objects.<query>`
|
||||
- 测试规范补"权限边界测试矩阵":每个 Model 至少 3 case(own / department / cross_department denied)
|
||||
|
||||
---
|
||||
|
||||
### 🟡 N-02 楼盘价格走势 / 市场报盘(M-07/M-08 降级)
|
||||
|
||||
历史 M-07/M-08 已写明"P2 不做",本期降为 Minor。
|
||||
|
||||
---
|
||||
|
||||
### 🟡 N-03 数据保留与归档策略(M-12 降级)
|
||||
|
||||
`platform_audit_logs` / `follow_logs` 在 PRD 中提到"2 年保留",但 DATA_MODEL 无对应 Celery 归档任务定义。建议在 B-06 分区落地后顺带补全 archive job。
|
||||
|
||||
---
|
||||
|
||||
## 四、安全审查(含多租户 / 权限 / 审计)
|
||||
|
||||
### 🟠 M-06 客户端发布无签名校验 / 防降级(持续未修)
|
||||
|
||||
**文档**:`PRD/发布管理/客户端发布管理模块PRD.md:165,198,284,347` / `TECH_STACK.md:119`
|
||||
|
||||
**事实**:
|
||||
- 端点 `GET /api/client/updates/latest/` 公开(合理)。
|
||||
- `download_url` 走 R2 / CDN 公开(合理)。
|
||||
- 完整性校验仅 SHA256(仅防偶然篡改,不防 MITM 主动替换)。
|
||||
- **无代码签名(Authenticode / OS-level codesign)**、**无服务端响应签名**、**无版本号单调递增校验(防降级)**。
|
||||
|
||||
**改进方向**:
|
||||
- 升级响应 JSON 增加 `signature` 字段(HMAC-SHA256,密钥服务端持有),客户端校验签名后再 fetch download_url。
|
||||
- `electron-updater` 配合 `publisherName`(Windows Authenticode),在 CI 用代码签名证书签 EXE。
|
||||
- 客户端本地存"已安装版本 N",若服务端返回版本 < N,**拒绝降级**(除非配置允许 force_downgrade=true 由后端控制)。
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-11 加密密钥管理 / 轮换 SOP 仍未补(持续未修)
|
||||
|
||||
**文档**:`TECH_STACK/系统管理技术文档.md:877`(仅"密钥通过 Docker Secret 注入"一句)
|
||||
|
||||
**事实**:
|
||||
- `core/encryption.py` 中央加密 helper 已声明(散见模块技术方案)。
|
||||
- **缺**:主密钥(KEK)轮换流程、字段加密密钥(DEK)版本号设计、密钥泄露应急吊销 + 全量字段重新封装、生产-staging 密钥隔离。
|
||||
|
||||
**改进方向**:
|
||||
- 在 `TECH_STACK.md` 新增 §"密钥管理 SOP":
|
||||
- 三层结构:环境主密钥(KMS / sops + age) → 应用 KEK(启动时加载) → 字段 DEK(per-row 或 per-column)
|
||||
- DDL 加密字段必须含 `key_version SMALLINT NOT NULL`
|
||||
- 季度轮换 + 异常吊销 runbook
|
||||
- 短期(无 KMS)方案:`age` + `sops` 加密 secrets 文件,运维流程文档化。
|
||||
|
||||
---
|
||||
|
||||
### 🟠 M-14 ORM 数据范围(详见 §三)
|
||||
|
||||
---
|
||||
|
||||
## 五、UI/UX 审查
|
||||
|
||||
### 🟠 M-09 UI 设计覆盖率与复杂组件深度(部分修复)
|
||||
|
||||
**文档**:`UI_DESIGN/`(11 份 markdown + 11 份 HTML 原型 + `UI_设计任务总表.md`)/ `UI_SYSTEM/`(3 份)
|
||||
|
||||
**事实**:
|
||||
- ✅ 已覆盖:客源列表 / 客源详情 / 客源新增 / 客源编辑 / 房源列表 5 类原型(HTML + Markdown 双版本)。
|
||||
- ❌ 仍缺:
|
||||
- 楼盘管理(详情 / 新增 / 锁字段交互)
|
||||
- 权限管理(权限树 / 数据范围编辑器 / 五档下拉子集)
|
||||
- 系统配置(lookup_items 编辑抽屉 / 必填规则配置)
|
||||
- 组织人事(org tree / 员工卡)
|
||||
- 发布管理(升级表单 / 灰度名单 / 进度面板)
|
||||
- ❌ UI_SYSTEM 复杂组件规范深度仍不足:虚拟滚动列表(89k 房源必需)、批量操作面板、抽屉表单嵌套规则、文件上传批量、富权限树。
|
||||
|
||||
**改进方向**:
|
||||
- 把 UI_DESIGN 11 份 task 按 PRD 优先级排进 Phase 1:客源(已齐)→ 房源详情 → 楼盘 → 权限 → 系统配置;
|
||||
- UI_SYSTEM 增补"复杂组件清单"5 项,每项给出 Alpine.js + HTMX 实现范本;
|
||||
- 89k 房源列表必须用虚拟滚动或固定窗口(如 PageDown 分页),HTMX 按 keyset cursor 局部刷新。
|
||||
|
||||
---
|
||||
|
||||
## 六、TASK ↔ 文档交叉验证
|
||||
|
||||
### 🟡 N-04 系统配置 Cache Invalidation(B-01 残留)
|
||||
|
||||
详见 §一。
|
||||
|
||||
---
|
||||
|
||||
## 七、汇总 Action Items
|
||||
|
||||
| # | 等级 | 编号 | Action | 责任 | 建议完成时间 | 编码门禁 |
|
||||
|---|------|------|--------|------|--------------|----------|
|
||||
| 1 | 🔴 | B-05 | 主表 `version` 字段 + `If-Match` API 规范 | 架构师 + 后端 Lead | T+3 天 | **Phase 1 启动前** |
|
||||
| 2 | 🔴 | B-06 | 5 张高写入表 `PARTITION BY RANGE` DDL + 分区维护 Celery 任务 | 架构师 + DBA | T+5 天 | **Phase 1 启动前** |
|
||||
| 3 | 🟠 | M-05 | 性能基准测试方案(seed 89k + pytest-benchmark + p95 阈值) | 测试 Lead | T+7 天 | Phase 1 内 |
|
||||
| 4 | 🟠 | M-06 | 客户端发布签名 + 防降级(HMAC + Authenticode) | 安全 + 发布运维 | T+10 天 | 客户端发布 GA 前 |
|
||||
| 5 | 🟠 | M-09 | 楼盘 / 权限 / 系统配置 / 组织人事 / 发布 5 模块原型 + 5 复杂组件规范 | UX + 前端 Lead | T+14 天 | 各模块编码前 |
|
||||
| 6 | 🟠 | M-11 | 密钥管理 SOP(KEK/DEK/版本/轮换/吊销) | 安全 + 运维 | T+10 天 | 加密字段上线前 |
|
||||
| 7 | 🟠 | M-12 | `@tenant_task` 装饰器 + Celery 多租户规范文档 | 架构师 | T+5 天 | Celery 任务编码前 |
|
||||
| 8 | 🟠 | M-13 | R2 路径前缀统一规范表 + bucket policy | 架构师 + 运维 | T+5 天 | R2 上传任务编码前 |
|
||||
| 9 | 🟠 | M-14 | ORM 数据范围强制 lint + `scoped(staff)` 入口 | 架构师 + 后端 Lead | T+7 天 | Phase 1 内 |
|
||||
| 10 | 🟡 | N-01 | PRD 文本中文枚举 → ENUMS 锚点全量替换 | PM | T+3 天 | 编码前清零 |
|
||||
| 11 | 🟡 | N-04 | 系统配置 Cache Invalidation 主动失效路径补充 | 后端 Lead | T+5 天 | US-SETTING-001 编码前 |
|
||||
| 12 | 🟡 | N-02/N-03 | 楼盘走势/数据归档策略 | PM + DBA | Phase 2 | 非阻塞 |
|
||||
|
||||
---
|
||||
|
||||
## 八、Review 结论
|
||||
|
||||
### 编码门禁(Phase 1 启动前必清零)
|
||||
|
||||
**🔴 Blocker(2 项必修)**:
|
||||
1. **B-05** 主表 `version` 乐观锁字段 —— 涉及 properties / clients / complexes DDL + API_CONTRACT 增补 `If-Match` Header
|
||||
2. **B-06** 5 张高写入表分区 DDL + 分区维护任务 —— 后期切分需停机,必须前置
|
||||
|
||||
### 整体判断
|
||||
|
||||
- **本期是历次 Review 进展最大的一次**:4 个 Blocker 全部清零,1 个 Major(M-01)已修复,文档体系(特别是 PRD ↔ ENUMS ↔ DATA_MODEL)建立了真正的"权威源"。
|
||||
- **剩余 Blocker 集中在 DATA_MODEL 物理设计层面**(并发控制 + 分区),属于"知道但没动"的债务,**修复成本可估、风险可控**,建议本周内打磨完毕。
|
||||
- **Phase 1 编码可在 B-05 / B-06 修复后立即启动**,其余 9 个 Major 可与编码并行推进,但需在对应模块进入开发前清零(参见上表"编码门禁"列)。
|
||||
- **下一次 Review 焦点**:B-05 / B-06 修复后,应重点审查 M-09(UI 覆盖率)+ M-05(性能基准),以及编码启动后第一波集成测试反馈。
|
||||
|
||||
### 文档健康度趋势
|
||||
|
||||
| 维度 | 04-25 | 04-26 | 04-28 | 趋势 |
|
||||
|------|-------|-------|-------|------|
|
||||
| PRD 完整性 | 60% | 75% | **90%** | ↑↑ |
|
||||
| DATA_MODEL 严谨性 | 50% | 65% | **80%** | ↑↑ |
|
||||
| TECH_STACK 横切规范 | 30% | 50% | **70%** | ↑ |
|
||||
| 测试规范多租户化 | 20% | 40% | **85%** | ↑↑↑ |
|
||||
| UI/UX 覆盖率 | 5% | 30% | **35%** | ↑(最弱环节) |
|
||||
| 安全设计 | 40% | 45% | **55%** | ↑(M-06/M-11 持续债务) |
|
||||
|
||||
---
|
||||
|
||||
> **Reviewer 签字**:首席系统设计 Reviewer(AI 辅助)
|
||||
> **下次 Review 建议触发条件**:B-05 + B-06 完成 PR 合并后,或 Phase 1 编码启动后第 1 个 Sprint 结束。
|
||||
@@ -28,17 +28,17 @@
|
||||
|
||||
## 3) P0 缺口任务(按优先级执行)
|
||||
|
||||
| 序号 | 优先级 | 模块 | 覆盖 US | UI.md 目标文件 | HTML 目标文件 | 当前状态 | 下一步 |
|
||||
| --- | ---- | ----------- | --------------------- | ----------------------------- | ------------------------ | ---- | --------------------------- |
|
||||
| 01 | P0-A | 登录管理 | US-ACCOUNT-001~003 | `UI_DESIGN/登录管理/登录_UI.md` | `UI_DESIGN/登录_UI.html` | 待评审 | 你评审登录 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 02 | P0-A | 房源管理(新增) | US-PROPERTY-001 | `UI_DESIGN/房源管理/新增房源_UI.md` | `UI_DESIGN/新增房源_UI.html` | 已完成 | 已完成评审迭代(壳层/按钮/结构一致化),进入任务03 |
|
||||
| 03 | P0-A | 房源管理(详情) | US-PROPERTY-003~008 | `UI_DESIGN/房源管理/房源详情_UI.md` | `UI_DESIGN/房源详情_UI.html` | 待评审 | 你评审房源详情 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 04 | P0-B | 楼盘管理(列表) | US-COMPLEX-002 | `UI_DESIGN/楼盘管理/楼盘列表_UI.md` | `UI_DESIGN/楼盘列表_UI.html` | 待评审 | 你评审楼盘列表 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 05 | P0-B | 楼盘管理(详情/维护) | US-COMPLEX-001 | `UI_DESIGN/楼盘管理/楼盘详情_UI.md` | `UI_DESIGN/楼盘详情_UI.html` | 待设计 | 完成任务04后开始 |
|
||||
| 06 | P0-B | 楼盘管理(区域) | US-COMPLEX-003 | `UI_DESIGN/楼盘管理/区域管理_UI.md` | `UI_DESIGN/区域管理_UI.html` | 待设计 | 完成任务05后开始 |
|
||||
| 07 | P0-C | 组织人事 | US-ORG-001~003 | `UI_DESIGN/组织人事管理/组织人事_UI.md` | `UI_DESIGN/组织人事_UI.html` | 待设计 | 完成任务06后开始 |
|
||||
| 08 | P0-C | 权限管理 | US-PERMISSION-001~005 | `UI_DESIGN/权限管理/权限管理_UI.md` | `UI_DESIGN/权限管理_UI.html` | 待设计 | 完成任务07后开始 |
|
||||
| 09 | P0-C | 系统配置 | US-SETTING-001-A/B/C | `UI_DESIGN/系统配置/系统配置_UI.md` | `UI_DESIGN/系统配置_UI.html` | 待设计 | 完成任务08后开始 |
|
||||
| 序号 | 优先级 | 模块 | 覆盖 US | UI.md 目标文件 | 竞品截图参考 | HTML 目标文件 | 当前状态 | 下一步 |
|
||||
| --- | ---- | ----------- | --------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------ | ---- | ---------------------------- |
|
||||
| 01 | P0-A | 登录管理 | US-ACCOUNT-001~003 | `UI_DESIGN/登录管理/登录_UI.md` | | `UI_DESIGN/登录_UI.html` | 待评审 | 你评审登录 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 02 | P0-A | 房源管理(新增) | US-PROPERTY-001 | `UI_DESIGN/房源管理/新增房源_UI.md` | | `UI_DESIGN/新增房源_UI.html` | 已完成 | 已完成评审迭代(壳层/按钮/结构一致化),进入任务03 |
|
||||
| 03 | P0-A | 房源管理(详情) | US-PROPERTY-003~008 | `UI_DESIGN/房源管理/房源详情_UI.md` | | `UI_DESIGN/房源详情_UI.html` | 待评审 | 你评审房源详情 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 04 | P0-B | 楼盘管理(列表) | US-COMPLEX-002 | `UI_DESIGN/楼盘管理/楼盘列表_UI.md` | | `UI_DESIGN/楼盘列表_UI.html` | 待评审 | 你评审楼盘列表 UI.md + 静态页,给我反馈我再迭代 |
|
||||
| 05 | P0-B | 楼盘管理(详情/维护) | US-COMPLEX-001 | `UI_DESIGN/楼盘管理/楼盘详情_UI.md` | `Project/fonrey/screenshots/楼盘管理/楼盘管理.png`<br>`Project/fonrey/screenshots/楼盘管理/楼栋管理.png`<br> | `UI_DESIGN/楼盘详情_UI.html` | 待评审 | 进入任务06(楼盘管理-区域管理) |
|
||||
| 06 | P0-B | 楼盘管理(区域) | US-COMPLEX-003 | `UI_DESIGN/楼盘管理/区域管理_UI.md` | `Project/fonrey/screenshots/楼盘管理/区域管理.png` | `UI_DESIGN/区域管理_UI.html` | 待设计 | 完成任务05后开始 |
|
||||
| 07 | P0-C | 组织人事 | US-ORG-001~003 | `UI_DESIGN/组织人事管理/组织人事_UI.md` | `Project/fonrey/screenshots/组织人事/组织结构/公司组织结构.png` | `UI_DESIGN/组织人事_UI.html` | 待设计 | 完成任务06后开始 |
|
||||
| 08 | P0-C | 权限管理 | US-PERMISSION-001~005 | `UI_DESIGN/权限管理/权限管理_UI.md`<br>`Project/fonrey/PRD/权限管理/房源-二手租赁.md`<br>`Project/fonrey/PRD/权限管理/客源.md` | `Project/fonrey/screenshots/权限管理/权限-客源-客源.png`<br>``<br>`Project/fonrey/screenshots/权限管理/权限-房源-二手租赁.jpg`<br>`` | `UI_DESIGN/权限管理_UI.html` | 待设计 | 完成任务07后开始 |
|
||||
| 09 | P0-C | 系统配置 | US-SETTING-001-A/B/C | `UI_DESIGN/系统配置/系统配置_UI.md` | | `UI_DESIGN/系统配置_UI.html` | 待设计 | 完成任务08后开始 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
181
Project/fonrey/UI_DESIGN/楼盘管理/区域管理_UI.md
Normal file
181
Project/fonrey/UI_DESIGN/楼盘管理/区域管理_UI.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# 区域管理 UI 设计文档
|
||||
|
||||
> **任务编号**:06(P0-B)
|
||||
> **覆盖范围**:`US-COMPLEX-003`(管理员维护区域管理:城区/商圈)
|
||||
> **输出文件**:`UI_DESIGN/区域管理_UI.html`
|
||||
> **设计基线**:`UI_SYSTEM/UI_SYSTEM.md`(列表页模板、Top Bar + Sidebar 壳层、表格/分页规范)
|
||||
> **竞品截图参考**:
|
||||
> - `Project/fonrey/screenshots/楼盘管理/区域管理.png`
|
||||
> - `Project/fonrey/screenshots/楼盘管理/商圈管理.png`
|
||||
> - `Project/fonrey/screenshots/楼盘管理/编辑商圈.png`
|
||||
> - `Project/fonrey/screenshots/楼盘管理/查看关联.png`
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
### 1.1 页面目标
|
||||
|
||||
区域管理页用于运营/数据管理员统一维护“城区-商圈”两级地理字典,并支撑楼盘、房源、客源模块的区域筛选与统计。
|
||||
|
||||
核心目标:
|
||||
|
||||
1. 在同一业务页面支持“城区管理 / 商圈管理”双子模块切换
|
||||
2. 支持关键词检索、区域过滤、有无坐标过滤
|
||||
3. 支持批量操作(合并城区、合并商圈、转移商圈)
|
||||
4. 支持新增/修改商圈弹窗维护
|
||||
5. 支持查看商圈关联关系(标准区域映射)
|
||||
|
||||
### 1.2 本任务边界
|
||||
|
||||
- ✅ 包含:壳层、模块 Tab、子 Tab、筛选区、批量区、表格、分页、弹窗校验、关联关系弹窗
|
||||
- ✅ 包含:竞品截图中的关键文案与字段结构(城区/商圈/关联关系)
|
||||
- ⛔ 不包含:真实后端 CRUD、真实关联跳转、真实地图 API、真实权限鉴权
|
||||
|
||||
---
|
||||
|
||||
## 2. 信息架构
|
||||
|
||||
### 2.1 壳层结构(统一后台模板)
|
||||
|
||||
- **Top Bar(固定 56px)**:品牌 + 一级导航 + 用户区
|
||||
- **Sidebar(固定 240px)**:房源管理二级导航
|
||||
- **Main Content(`ml-60 pt-[72px]`)**:
|
||||
1. 面包屑 + 页面标题
|
||||
2. 模块 Tab(楼盘 / 区域管理 / 学校管理 / 应用标准数据)
|
||||
3. 区域管理子 Tab(城区管理 / 商圈管理)
|
||||
4. 筛选区 + 批量区 + 列表区 + 分页区
|
||||
|
||||
### 2.2 区域管理子模块
|
||||
|
||||
#### A. 城区管理
|
||||
- 筛选:城区名称关键词 + 有无坐标(不限/有坐标/无坐标)
|
||||
- 列表字段:城区名称 / 商圈数量 / 楼盘数量 / 坐标 / 操作
|
||||
- 操作:修改、设置坐标、合并城区、新增城区
|
||||
|
||||
#### B. 商圈管理
|
||||
- 筛选:商圈名称关键词 + 区域过滤(标签)+ 有无坐标
|
||||
- 列表字段:城区名称 / 商圈名称(含“标准”标签)/ 楼盘数量 / 坐标 / 操作
|
||||
- 操作:修改、查看关联关系、设置坐标、合并商圈、转移商圈、新增商圈
|
||||
|
||||
### 2.3 关联关系视图(弹窗承载)
|
||||
|
||||
- 触发:商圈列表行内「查看关联关系」
|
||||
- 筛选:标准区域(下拉)、本地区域(下拉)
|
||||
- 列表字段:标准城市 / 标准城区 / 标准商圈 / 关联本地商圈 / 本地商圈所属城区 / 操作(变更)
|
||||
- 支持批量修改按钮(勾选后启用)
|
||||
|
||||
---
|
||||
|
||||
## 3. 关键交互设计
|
||||
|
||||
### 3.1 子 Tab 切换
|
||||
|
||||
- 点击「城区管理 / 商圈管理」切换内容区
|
||||
- 切换后保留当前模块壳层和分页区风格一致
|
||||
|
||||
### 3.2 筛选与重置
|
||||
|
||||
- 点击「查询」执行前端过滤
|
||||
- 点击「重置」清空关键词与标签筛选,恢复默认列表
|
||||
- 坐标筛选支持:不限 / 有坐标 / 无坐标
|
||||
|
||||
### 3.3 批量操作启用规则
|
||||
|
||||
- 未勾选时:批量按钮禁用态
|
||||
- 勾选 1 条及以上:批量按钮启用
|
||||
- 提示区实时显示:`已选本页 N 条`
|
||||
|
||||
### 3.4 新增/编辑弹窗
|
||||
|
||||
#### 城区弹窗
|
||||
- 标题:新增城区 / 修改城区
|
||||
- 字段:
|
||||
- 城区名称(必填)
|
||||
- 城区简称(选填)
|
||||
- 校验:城区名称为空时提示“请输入城区名称”
|
||||
|
||||
#### 商圈弹窗
|
||||
- 标题:新增商圈 / 修改商圈
|
||||
- 字段:
|
||||
- 所属城区(必填,下拉)
|
||||
- 商圈名称(必填,文本)
|
||||
- 校验:
|
||||
- 未选城区:`请选择所属城区`
|
||||
- 未填商圈名称:`请输入商圈名称`
|
||||
|
||||
### 3.5 设置坐标弹窗
|
||||
|
||||
- 支持城区/商圈两种来源
|
||||
- 字段:纬度、经度
|
||||
- 校验:任一为空时提示“请完整填写经纬度”
|
||||
|
||||
### 3.6 查看关联关系弹窗
|
||||
|
||||
- 保持“查看关联情况”核心信息结构
|
||||
- 支持顶部筛选 + 列表 + 批量修改占位
|
||||
- 点击「变更」仅触发原型提示(无真实提交)
|
||||
|
||||
---
|
||||
|
||||
## 4. 状态矩阵
|
||||
|
||||
| 状态 | 触发 | 页面反馈 |
|
||||
|---|---|---|
|
||||
| 默认态 | 首次进入页面 | 默认显示“城区管理”,加载城区列表 |
|
||||
| 子模块切换 | 点击子 Tab | 切换到对应列表和筛选区 |
|
||||
| 查询态 | 输入关键词并查询 | 列表按条件过滤 |
|
||||
| 空结果态 | 条件过严 | 表格显示“暂无匹配数据” |
|
||||
| 勾选态 | 勾选行/全选 | 批量按钮启用,显示已选条数 |
|
||||
| 弹窗校验失败 | 必填缺失提交 | 字段下方红字错误,弹窗保持打开 |
|
||||
| 保存成功(原型) | 校验通过提交 | 关闭弹窗 + Toast 成功提示 |
|
||||
| 主题策略 | 统一后台视觉 | 页面内不包含 Light/Dark/System 切换控件 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 字段与数据模型映射(DATA_MODEL_COMPLEX)
|
||||
|
||||
| UI 字段 | 数据模型字段 |
|
||||
|---|---|
|
||||
| 城区名称 | `districts.name` |
|
||||
| 城区简称 | `districts.short_name` |
|
||||
| 所属城市 | `districts.city` |
|
||||
| 商圈名称 | `business_areas.name` |
|
||||
| 所属城区 | `business_areas.district_id -> districts.id` |
|
||||
| 商圈坐标 | `business_areas.latitude` / `business_areas.longitude` |
|
||||
| 城区坐标(原型占位) | `districts` 扩展坐标字段(PRD层业务占位) |
|
||||
| 商圈数量 | `COUNT(business_areas.id)`(按城区聚合) |
|
||||
| 楼盘数量 | `COUNT(complexes.id)`(按城区/商圈聚合) |
|
||||
| 关联本地商圈 | `business_areas.name`(映射结果) |
|
||||
| 标准城市/城区/商圈 | 标准区域字典(独立映射域,原型以 mock 展示) |
|
||||
|
||||
---
|
||||
|
||||
## 6. 可访问性与规范
|
||||
|
||||
- 表格列头使用 `<th scope="col">`
|
||||
- 纯图标按钮补充 `aria-label`
|
||||
- 弹窗支持 `Esc` 关闭
|
||||
- 错误提示采用“字段下方红字文本”,不只依赖颜色
|
||||
- 焦点样式统一 `focus-visible:ring-2 focus-visible:ring-primary-600/40`
|
||||
- 页面保持浅色后台主题,不引入主题切换控件
|
||||
|
||||
---
|
||||
|
||||
## 7. 验收清单
|
||||
|
||||
- [x] 壳层结构:Top Bar + Sidebar + Main
|
||||
- [x] 模块 Tab 与子 Tab 结构完整
|
||||
- [x] 城区管理筛选/列表/批量/分页完整
|
||||
- [x] 商圈管理筛选/列表/批量/分页完整
|
||||
- [x] 商圈编辑弹窗字段与校验符合 PRD Story 10
|
||||
- [x] 关联关系视图字段与交互符合 PRD Story 11
|
||||
- [x] 页面内不包含 Light/Dark/System 主题切换控件
|
||||
- [ ] 控制台 0 报错(待本地预览验证)
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续衔接
|
||||
|
||||
- 本页评审通过后,进入任务07:组织人事(`US-ORG-001~003`)
|
||||
- 区域字典(城区/商圈)将作为房源/客源筛选条件来源,需保持命名与状态一致
|
||||
176
Project/fonrey/UI_DESIGN/楼盘管理/楼盘详情_UI.md
Normal file
176
Project/fonrey/UI_DESIGN/楼盘管理/楼盘详情_UI.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# 楼盘详情 UI 设计文档
|
||||
|
||||
> **任务编号**:05(P0-B)
|
||||
> **覆盖范围**:`US-COMPLEX-001`(管理员录入与维护楼盘基础信息)
|
||||
> **关联需求参考**:`PRD/房源管理/楼盘管理模块PRD.md` Story 2~8(楼盘详情分区信息架构)
|
||||
> **输出文件**:`UI_DESIGN/楼盘详情_UI.html`
|
||||
> **设计基线**:`UI_SYSTEM/UI_SYSTEM.md`(Top Bar + Sidebar 壳层、详情页模板、表单与校验规范)
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
### 1.1 页面目标
|
||||
|
||||
楼盘详情页用于运营/数据管理员在单个楼盘维度完成“查看 + 维护”闭环:
|
||||
|
||||
1. 查看楼盘基础档案(基本信息、对口学校、其他信息)
|
||||
2. 管理楼栋与结构(楼层/房号)
|
||||
3. 查看与维护楼盘图片、附件
|
||||
4. 查看价格走势与周边配套信息
|
||||
|
||||
### 1.2 本任务边界
|
||||
|
||||
本任务交付“楼盘详情静态高保真原型”,重点完成信息架构与关键交互演示。
|
||||
|
||||
- ✅ 包含:壳层、详情头部、分区 Tab、编辑抽屉、必填校验、批量操作占位、分页占位
|
||||
- ✅ 包含:底部固定操作区(编辑态)且按钮右对齐
|
||||
- ⛔ 不包含:真实接口联动、地图 API、图表库渲染、上传存储、权限后端判定
|
||||
|
||||
---
|
||||
|
||||
## 2. 信息架构
|
||||
|
||||
### 2.1 壳层结构(统一后台模板)
|
||||
|
||||
- **Top Bar(固定 56px)**:品牌 + 一级导航 + 用户区
|
||||
- **Sidebar(固定 240px)**:房源管理二级导航
|
||||
- **Main Content(`ml-60 pt-[72px]`)**:
|
||||
1. 面包屑 + 楼盘标题 + 锁定标签 + 顶部动作按钮
|
||||
2. 楼盘详情分区 Tab(8 个)
|
||||
3. Tab 内容区域
|
||||
|
||||
### 2.2 楼盘详情分区 Tab(页面级)
|
||||
|
||||
1. 楼盘信息(默认)
|
||||
2. 楼栋管理
|
||||
3. 结构管理
|
||||
4. 楼盘照片
|
||||
5. 楼盘附件
|
||||
6. 周边配套
|
||||
7. 楼盘价格走势
|
||||
8. 销控盘
|
||||
|
||||
### 2.3 楼盘信息分区结构(默认 Tab)
|
||||
|
||||
- **基本信息**:城区商圈、地址、建筑类型、楼栋结构、别名、竣工年限、坐标等
|
||||
- **对口学校**:学校名称/类型/性质/等级表格
|
||||
- **其他信息**:面积、容积率、绿化率、物业信息、车位信息、供水供电、备注
|
||||
- **右侧辅助面板**:维护完成度、锁定状态、相关员工、快捷操作
|
||||
|
||||
---
|
||||
|
||||
## 3. 关键交互设计
|
||||
|
||||
### 3.1 页面级交互
|
||||
|
||||
1. 点击分区 Tab 切换对应内容(单页切换)
|
||||
2. 顶部「解锁楼盘」按钮触发提示(原型态)
|
||||
3. 顶部「编辑楼盘信息」打开右侧编辑抽屉
|
||||
|
||||
### 3.2 编辑抽屉(楼盘信息维护)
|
||||
|
||||
- 抽屉分为:基本信息 / 学校信息 / 其他信息 三段
|
||||
- 必填字段校验:
|
||||
- 物业类型(必填)
|
||||
- 楼栋结构(必填)
|
||||
- 小区名称、小区地址为只读灰底展示
|
||||
- 底部固定操作区:
|
||||
- `取消`(次按钮)
|
||||
- `保存`(主按钮)
|
||||
- 底部操作区始终固定,按钮右对齐
|
||||
|
||||
### 3.3 楼栋管理交互
|
||||
|
||||
- 关键词搜索单元名
|
||||
- 行勾选 + 表头全选
|
||||
- 批量按钮(批量设置/合并/移动)随选中状态启用
|
||||
- 每行操作:编辑 / 结构管理
|
||||
|
||||
### 3.4 结构管理交互
|
||||
|
||||
- 左侧单元列表(可切换当前单元)
|
||||
- 右侧楼层-房号矩阵
|
||||
- 房号勾选后启用“批量编辑房号/合并房号”
|
||||
- 提示区显示“已选 N 条”与异常结构入口占位
|
||||
|
||||
### 3.5 其他分区交互(原型演示)
|
||||
|
||||
- 楼盘照片:分类切换(楼盘图片/户型图/楼盘VR)+ 户型过滤占位
|
||||
- 楼盘附件:上传入口占位 + 附件列表
|
||||
- 周边配套:分类切换(交通/教育/医疗/购物/生活/娱乐)+ 地图占位
|
||||
- 价格走势:司内/市场子 Tab 切换 + 图表占位 + 明细表
|
||||
|
||||
---
|
||||
|
||||
## 4. 状态矩阵
|
||||
|
||||
| 状态 | 触发 | 页面反馈 |
|
||||
|---|---|---|
|
||||
| 默认态 | 首次进入页面 | 默认激活“楼盘信息”Tab,展示详情概览 |
|
||||
| Tab 切换 | 点击分区 Tab | 内容区域切换,对应 Tab 高亮 |
|
||||
| 打开编辑 | 点击“编辑楼盘信息” | 右侧抽屉滑入,加载当前字段值 |
|
||||
| 校验失败 | 抽屉内点击保存且必填缺失 | 字段下方显示错误文本 + 保持抽屉打开 |
|
||||
| 保存成功(原型) | 抽屉内点击保存且校验通过 | 抽屉关闭 + Toast“楼盘信息已保存(原型)” |
|
||||
| 楼栋批量态 | 勾选楼栋行 | 批量按钮启用,显示已选条数 |
|
||||
| 结构批量态 | 勾选房号 | 矩阵批量按钮启用,显示已选条数 |
|
||||
| 空数据态 | 学校/附件/成交明细为空 | 使用“暂无数据”占位与引导文案 |
|
||||
| 主题策略 | 全局后台视觉 | 页面内不提供 Light/Dark/System 切换控件 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 字段与数据模型映射(DATA_MODEL_COMPLEX)
|
||||
|
||||
| UI 字段 | 数据模型字段 |
|
||||
|---|---|
|
||||
| 楼盘名称(只读) | `complexes.name` |
|
||||
| 城区商圈 | `complexes.district_id` + `complex_business_areas` |
|
||||
| 小区地址(只读) | `complexes.address` |
|
||||
| 概要地址 | `complexes.address_summary` |
|
||||
| 物业类型(多选) | `complexes.property_usage_types` |
|
||||
| 楼栋结构 | `complexes.building_structure` |
|
||||
| 建筑类型 | `complexes.building_type` |
|
||||
| 土地使用年限 | `complexes.land_use_years` |
|
||||
| 竣工年限 | `complexes.built_years` |
|
||||
| 权属类别 | `complexes.ownership_category` |
|
||||
| 单元总数/总户数 | `complexes.total_units` / `complexes.total_households` |
|
||||
| 经纬度坐标 | `complexes.latitude` / `complexes.longitude` |
|
||||
| 对口学校 | `complex_schools` + `schools` |
|
||||
| 楼栋列表 | `buildings` |
|
||||
| 楼层房号矩阵 | `room_units` |
|
||||
| 图片资源 | `complex_photos` |
|
||||
| 附件 | `complex_attachments` |
|
||||
| 价格走势 | `complex_price_trends` |
|
||||
| 锁定标签 | `lock_building` / `lock_room` / `lock_info` / `lock_standard_room` |
|
||||
|
||||
---
|
||||
|
||||
## 6. 可访问性与规范
|
||||
|
||||
- 表格列头使用语义化 `<th scope="col">`
|
||||
- 抽屉与弹层支持 `Esc` 关闭
|
||||
- 纯图标按钮均带 `aria-label`
|
||||
- 表单错误提示为“字段下方红字 + 文本说明”,不只靠颜色
|
||||
- 所有可交互控件支持 `focus-visible:ring-2`
|
||||
- 页面采用统一浅色后台主题,不包含主题切换控件
|
||||
|
||||
---
|
||||
|
||||
## 7. 验收清单
|
||||
|
||||
- [x] 壳层结构:Top Bar + Sidebar + Main
|
||||
- [x] 楼盘详情头部信息与锁定标签完整
|
||||
- [x] 8 个分区 Tab(楼盘信息/楼栋/结构/照片/附件/配套/价格/销控盘)完整
|
||||
- [x] 楼盘信息包含“基本信息/对口学校/其他信息”三段
|
||||
- [x] 编辑抽屉具备必填校验(物业类型、楼栋结构)
|
||||
- [x] 编辑态底部按钮固定且右对齐
|
||||
- [x] 楼栋管理与结构管理具备勾选 + 批量操作演示
|
||||
- [x] 页面内不包含主题切换控件
|
||||
- [ ] 控制台 0 报错(待本地预览验证)
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续衔接
|
||||
|
||||
- 本页评审通过后,继续任务06:区域管理(`US-COMPLEX-003`)
|
||||
- 区域管理将与本页“城区商圈”字段形成前后联动(字典数据来源一致)
|
||||
874
Project/fonrey/UI_DESIGN/楼盘详情_UI.html
Normal file
874
Project/fonrey/UI_DESIGN/楼盘详情_UI.html
Normal file
@@ -0,0 +1,874 @@
|
||||
<!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)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--bg-page: #F8FAFC;
|
||||
--bg-card: #FFFFFF;
|
||||
--bg-subtle: #F1F5F9;
|
||||
--text-primary: #0F172A;
|
||||
--text-secondary: #64748B;
|
||||
--border: #E2E8F0;
|
||||
}
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
body {
|
||||
background: var(--bg-page);
|
||||
color: var(--text-primary);
|
||||
font-family: Inter, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
[x-cloak] { display: none !important; }
|
||||
.tabular-nums { font-variant-numeric: tabular-nums; }
|
||||
.bg-surface { background: var(--bg-card); }
|
||||
.bg-subtle { background: var(--bg-subtle); }
|
||||
.border-surface { border-color: var(--border); }
|
||||
.text-surface { color: var(--text-primary); }
|
||||
.text-muted { color: var(--text-secondary); }
|
||||
|
||||
.tab-btn {
|
||||
color: #64748B;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
.tab-btn.active {
|
||||
color: #0F766E;
|
||||
border-bottom-color: #0F766E;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-lock {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
padding: 4px 8px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #FECACA;
|
||||
color: #B91C1C;
|
||||
background: #FEF2F2;
|
||||
}
|
||||
|
||||
.subtab-pill {
|
||||
border: 1px solid #E2E8F0;
|
||||
background: #FFFFFF;
|
||||
color: #64748B;
|
||||
}
|
||||
.subtab-pill.active {
|
||||
border-color: #0F766E;
|
||||
color: #0F766E;
|
||||
background: #F0FDFA;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.left-item {
|
||||
border: 1px solid #E2E8F0;
|
||||
background: #FFFFFF;
|
||||
color: #334155;
|
||||
}
|
||||
.left-item.active {
|
||||
border-color: #0F766E;
|
||||
background: #F0FDFA;
|
||||
color: #0F766E;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||||
::-webkit-scrollbar-thumb { background: #CBD5E1; border-radius: 4px; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #94A3B8; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-sm antialiased" x-data="complexDetailPage()" x-init="init()">
|
||||
<!-- Top Bar -->
|
||||
<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 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>
|
||||
<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>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="fixed left-0 top-14 h-[calc(100vh-56px)] w-60 z-20 border-r border-surface bg-surface overflow-y-auto">
|
||||
<nav class="p-3 space-y-0.5">
|
||||
<div class="px-2 pt-2 pb-1 text-xs font-medium text-muted 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">楼盘管理</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>
|
||||
<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 -->
|
||||
<main class="ml-60 pt-[72px] min-h-screen px-6 py-5">
|
||||
<div class="mx-auto max-w-[1680px] space-y-4">
|
||||
<!-- Header Card -->
|
||||
<section class="bg-surface border border-surface rounded-lg p-4 space-y-3">
|
||||
<nav class="flex items-center gap-1 text-xs text-muted" aria-label="面包屑">
|
||||
<a href="#" class="hover:text-neutral-700">房源</a>
|
||||
<span>/</span>
|
||||
<a href="#" class="hover:text-neutral-700">小区</a>
|
||||
<span>/</span>
|
||||
<a href="#" class="hover:text-neutral-700">楼盘管理系统-楼盘管理</a>
|
||||
<span>/</span>
|
||||
<span class="text-surface">楼盘详情</span>
|
||||
</nav>
|
||||
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="space-y-2">
|
||||
<h1 class="text-xl font-semibold text-surface">阳光威尼斯四期(别墅)</h1>
|
||||
<p class="text-xs text-muted">恒盛提香湾 / 璟聚人生 / 祁连山南路2727弄 / 金鼎路1600弄</p>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<span class="badge-lock">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-3 0h15a1.5 1.5 0 0 1 1.5 1.5v7.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 19.5V12a1.5 1.5 0 0 1 1.5-1.5Z"/></svg>
|
||||
楼栋锁
|
||||
</span>
|
||||
<span class="badge-lock"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-3 0h15a1.5 1.5 0 0 1 1.5 1.5v7.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 19.5V12a1.5 1.5 0 0 1 1.5-1.5Z"/></svg>房号</span>
|
||||
<span class="badge-lock"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-3 0h15a1.5 1.5 0 0 1 1.5 1.5v7.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 19.5V12a1.5 1.5 0 0 1 1.5-1.5Z"/></svg>信息</span>
|
||||
<span class="badge-lock"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-3 0h15a1.5 1.5 0 0 1 1.5 1.5v7.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 19.5V12a1.5 1.5 0 0 1 1.5-1.5Z"/></svg>标准房号</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="px-3 py-1.5 rounded-md border border-neutral-300 text-neutral-700 hover:bg-neutral-50" @click="notify('已触发楼盘解锁流程(原型)')">解锁楼盘</button>
|
||||
<button class="px-3 py-1.5 rounded-md bg-primary-600 text-white hover:bg-primary-700" @click="openEditDrawer()">编辑楼盘信息</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tabs -->
|
||||
<section class="bg-surface border border-surface rounded-lg px-4">
|
||||
<nav class="flex items-center gap-6 overflow-x-auto" aria-label="楼盘详情分区导航">
|
||||
<template x-for="item in tabs" :key="item.key">
|
||||
<button class="tab-btn py-3 whitespace-nowrap" :class="{ 'active': activeTab === item.key }" @click="activeTab = item.key" x-text="item.label"></button>
|
||||
</template>
|
||||
</nav>
|
||||
</section>
|
||||
|
||||
<!-- 楼盘信息 -->
|
||||
<section x-show="activeTab === 'info'" x-cloak class="grid grid-cols-12 gap-6 items-start">
|
||||
<div class="col-span-8 space-y-4">
|
||||
<article class="bg-surface border border-surface rounded-lg p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-base font-semibold">基本信息</h2>
|
||||
<p class="text-xs text-info-600">楼盘地址有误?点此【纠错】</p>
|
||||
</div>
|
||||
<dl class="grid grid-cols-2 gap-x-8 gap-y-3 text-sm">
|
||||
<div><dt class="text-xs text-muted">城区商圈</dt><dd class="mt-0.5">普陀-真光</dd></div>
|
||||
<div><dt class="text-xs text-muted">小区地址</dt><dd class="mt-0.5">上海普陀金鼎路1600弄,祁连山南路2727弄</dd></div>
|
||||
<div><dt class="text-xs text-muted">楼栋结构</dt><dd class="mt-0.5">单元-房号</dd></div>
|
||||
<div><dt class="text-xs text-muted">概要地址</dt><dd class="mt-0.5">金鼎路1600弄,祁连山南路2727弄</dd></div>
|
||||
<div><dt class="text-xs text-muted">小区别名</dt><dd class="mt-0.5">恒盛提香湾,璟聚人生,阳光建华城</dd></div>
|
||||
<div><dt class="text-xs text-muted">建筑类型</dt><dd class="mt-0.5">板塔结合</dd></div>
|
||||
<div><dt class="text-xs text-muted">物业类型</dt><dd class="mt-0.5">别墅</dd></div>
|
||||
<div><dt class="text-xs text-muted">土地使用年限</dt><dd class="mt-0.5">70年</dd></div>
|
||||
<div><dt class="text-xs text-muted">竣工年限</dt><dd class="mt-0.5">2009</dd></div>
|
||||
<div><dt class="text-xs text-muted">权属类别</dt><dd class="mt-0.5">商品房住宅</dd></div>
|
||||
<div><dt class="text-xs text-muted">单元总数</dt><dd class="mt-0.5">96栋</dd></div>
|
||||
<div><dt class="text-xs text-muted">总户数</dt><dd class="mt-0.5">96户</dd></div>
|
||||
<div class="col-span-2"><dt class="text-xs text-muted">小区坐标</dt><dd class="mt-0.5 tabular-nums">31.264564,121.376238</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
|
||||
<article class="bg-surface border border-surface rounded-lg p-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h2 class="text-base font-semibold">对口学校</h2>
|
||||
<button class="px-3 py-1.5 rounded-md border border-neutral-300 hover:bg-neutral-50" @click="notify('打开学校关联弹窗(原型)')">+ 添加学校</button>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full text-sm">
|
||||
<thead class="bg-subtle border-y border-surface">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2 text-left">学校名称</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">学校类型</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">学校性质</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">学校等级</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-if="schools.length === 0">
|
||||
<tr><td colspan="5" class="px-3 py-8 text-center text-muted">暂无数据</td></tr>
|
||||
</template>
|
||||
<template x-for="row in schools" :key="row.name">
|
||||
<tr class="border-b border-surface">
|
||||
<td class="px-3 py-2" x-text="row.name"></td>
|
||||
<td class="px-3 py-2" x-text="row.type"></td>
|
||||
<td class="px-3 py-2" x-text="row.nature"></td>
|
||||
<td class="px-3 py-2" x-text="row.level"></td>
|
||||
<td class="px-3 py-2"><button class="text-danger-600 hover:underline" @click="notify('删除学校关联(原型)')">删除</button></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="bg-surface border border-surface rounded-lg p-4">
|
||||
<h2 class="text-base font-semibold mb-3">其他信息</h2>
|
||||
<dl class="grid grid-cols-2 gap-x-8 gap-y-3 text-sm">
|
||||
<div><dt class="text-xs text-muted">小区总建筑面积</dt><dd class="mt-0.5 tabular-nums">80000㎡</dd></div>
|
||||
<div><dt class="text-xs text-muted">小区占地面积</dt><dd class="mt-0.5 tabular-nums">50000㎡</dd></div>
|
||||
<div><dt class="text-xs text-muted">容积率</dt><dd class="mt-0.5 tabular-nums">1.60</dd></div>
|
||||
<div><dt class="text-xs text-muted">绿化率</dt><dd class="mt-0.5 tabular-nums">45%</dd></div>
|
||||
<div><dt class="text-xs text-muted">物业公司</dt><dd class="mt-0.5">阳光物业有限公司</dd></div>
|
||||
<div><dt class="text-xs text-muted">物业费</dt><dd class="mt-0.5 tabular-nums">1.45 元/㎡/月</dd></div>
|
||||
<div><dt class="text-xs text-muted">物业电话</dt><dd class="mt-0.5">-</dd></div>
|
||||
<div><dt class="text-xs text-muted">开发商</dt><dd class="mt-0.5">上海意景房产开发有限公司</dd></div>
|
||||
<div><dt class="text-xs text-muted">车位数(总)</dt><dd class="mt-0.5 tabular-nums">800 个</dd></div>
|
||||
<div><dt class="text-xs text-muted">车位数(地下)</dt><dd class="mt-0.5">-</dd></div>
|
||||
<div><dt class="text-xs text-muted">停车位配比</dt><dd class="mt-0.5">100:63</dd></div>
|
||||
<div><dt class="text-xs text-muted">供水 / 供电</dt><dd class="mt-0.5">民水 / 民电</dd></div>
|
||||
<div><dt class="text-xs text-muted">统一供暖</dt><dd class="mt-0.5">无</dd></div>
|
||||
<div><dt class="text-xs text-muted">有无燃气</dt><dd class="mt-0.5">有</dd></div>
|
||||
<div class="col-span-2"><dt class="text-xs text-muted">备注</dt><dd class="mt-0.5">本楼盘别墅区产品为主,房号结构基本标准化。</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<aside class="col-span-4 space-y-4 sticky top-[88px]">
|
||||
<article class="bg-surface border border-surface rounded-lg p-4">
|
||||
<h3 class="text-sm font-semibold mb-3">维护完成度</h3>
|
||||
<div class="w-full h-2 rounded-full bg-neutral-200 overflow-hidden">
|
||||
<div class="h-full bg-primary-600" style="width: 72%"></div>
|
||||
</div>
|
||||
<p class="text-xs text-muted mt-2">当前维护度 72%,建议补全学校和附件信息。</p>
|
||||
</article>
|
||||
|
||||
<article class="bg-surface border border-surface rounded-lg p-4">
|
||||
<h3 class="text-sm font-semibold mb-3">相关员工</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li class="flex items-center justify-between"><span class="text-muted">首录人</span><span>李晨(普陀真光)</span></li>
|
||||
<li class="flex items-center justify-between"><span class="text-muted">归属人</span><span>杜利强(运营)</span></li>
|
||||
<li class="flex items-center justify-between"><span class="text-muted">最近更新</span><span class="tabular-nums">2026-04-28 15:20</span></li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="bg-surface border border-surface rounded-lg p-4 space-y-2">
|
||||
<button class="w-full px-3 py-2 rounded-md bg-primary-600 text-white hover:bg-primary-700" @click="openEditDrawer()">编辑楼盘信息</button>
|
||||
<button class="w-full px-3 py-2 rounded-md border border-surface hover:bg-neutral-50" @click="notify('打开楼盘附件上传(原型)')">上传附件</button>
|
||||
<button class="w-full px-3 py-2 rounded-md border border-surface hover:bg-neutral-50" @click="notify('查看楼盘操作日志(原型)')">查看操作日志</button>
|
||||
</article>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<!-- 楼栋管理 -->
|
||||
<section x-show="activeTab === 'buildings'" x-cloak class="bg-surface border border-surface rounded-lg p-4 space-y-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<input x-model.trim="buildingKeyword" type="text" placeholder="单元" class="w-56 px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" />
|
||||
<button class="px-3 py-2 rounded-md bg-primary-600 text-white hover:bg-primary-700" @click="applyBuildingFilter()">搜索</button>
|
||||
</div>
|
||||
<p class="text-xs text-muted">本楼盘还有 <span class="text-danger-600 font-medium">0</span> 个非标准结构,<button class="text-primary-600 hover:underline" @click="notify('查看非标明细(原型)')">查看明细</button></p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface" :disabled="selectedBuildingCount===0" :class="selectedBuildingCount===0 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-neutral-50'">批量设置单元信息</button>
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface" :disabled="selectedBuildingCount===0" :class="selectedBuildingCount===0 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-neutral-50'">合并单元</button>
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface" :disabled="selectedBuildingCount===0" :class="selectedBuildingCount===0 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-neutral-50'">移动单元</button>
|
||||
<span class="text-xs text-muted" x-text="selectedBuildingCount > 0 ? '已选 ' + selectedBuildingCount + ' 条' : '未选中单元'"></span>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto border border-surface rounded-lg">
|
||||
<table class="min-w-full text-sm">
|
||||
<thead class="bg-subtle border-b border-surface">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2 w-10"><input type="checkbox" aria-label="全选单元" class="rounded border-surface" :checked="allBuildingsOnPage" @click.prevent="toggleBuildingSelectPage(!allBuildingsOnPage)" /></th>
|
||||
<th scope="col" class="px-3 py-2 text-left">单元名</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">物业类型</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">竣工年限</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">总层数</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">土地使用年限</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">电梯</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">关联学校</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="row in filteredBuildings" :key="row.id">
|
||||
<tr class="border-b border-surface hover:bg-neutral-50/70">
|
||||
<td class="px-3 py-2">
|
||||
<input type="checkbox" class="rounded border-surface" :checked="selectedBuildingIds.includes(row.id)" @change="toggleBuildingSelect(row.id, $event.target.checked)" />
|
||||
</td>
|
||||
<td class="px-3 py-2">
|
||||
<button class="text-primary-600 hover:underline" @click="notify('进入单元详情(原型)')" x-text="row.name"></button>
|
||||
<span class="ml-2 inline-flex px-1.5 py-0.5 rounded text-xs bg-info-50 text-info-600 border border-info-600/20">标准</span>
|
||||
</td>
|
||||
<td class="px-3 py-2" x-text="row.usage"></td>
|
||||
<td class="px-3 py-2 tabular-nums" x-text="row.year"></td>
|
||||
<td class="px-3 py-2" x-text="row.floors"></td>
|
||||
<td class="px-3 py-2" x-text="row.landYears"></td>
|
||||
<td class="px-3 py-2" x-text="row.elevator"></td>
|
||||
<td class="px-3 py-2" x-text="row.school"></td>
|
||||
<td class="px-3 py-2">
|
||||
<button class="text-primary-600 hover:underline mr-3" @click="notify('编辑楼栋(原型)')">编辑</button>
|
||||
<button class="text-primary-600 hover:underline" @click="switchToStructure(row.name)">结构管理</button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs text-muted px-1">
|
||||
<span>共 <span x-text="filteredBuildings.length"></span> 条</span>
|
||||
<span>每页 20 条(原型占位)</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 结构管理 -->
|
||||
<section x-show="activeTab === 'structure'" x-cloak class="bg-surface border border-surface rounded-lg p-4">
|
||||
<div class="grid grid-cols-12 gap-4 min-h-[520px]">
|
||||
<aside class="col-span-4 border border-surface rounded-lg p-3 flex flex-col">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<select class="px-2.5 py-2 rounded-md border border-surface bg-white text-sm">
|
||||
<option>单元</option>
|
||||
</select>
|
||||
<button class="px-3 py-2 rounded-md border border-surface hover:bg-neutral-50 text-sm">设置单元信息</button>
|
||||
</div>
|
||||
<div class="space-y-1.5 overflow-y-auto pr-1">
|
||||
<template x-for="item in units" :key="item.id">
|
||||
<button class="left-item w-full text-left px-3 py-2 rounded-md text-sm" :class="{ 'active': currentUnitId === item.id }" @click="currentUnitId = item.id">
|
||||
<span x-text="item.name"></span>
|
||||
<span class="ml-2 inline-flex px-1.5 py-0.5 rounded text-xs bg-info-50 text-info-600 border border-info-600/20">标准</span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="col-span-8 border border-surface rounded-lg p-3 flex flex-col">
|
||||
<div class="flex items-center justify-between gap-3 mb-3">
|
||||
<h3 class="text-sm font-semibold" x-text="currentUnitName"></h3>
|
||||
<p class="text-xs text-muted">本楼盘还有 0 个房号无法关联结构,<button class="text-primary-600 hover:underline" @click="notify('查看无法关联明细(原型)')">查看明细</button></p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface" :disabled="selectedRoomCount===0" :class="selectedRoomCount===0 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-neutral-50'">批量编辑房号</button>
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface" :disabled="selectedRoomCount===0" :class="selectedRoomCount===0 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-neutral-50'">合并房号</button>
|
||||
<span class="text-xs text-muted" x-text="'已选 ' + selectedRoomCount + ' 条'">已选 0 条</span>
|
||||
<span class="text-xs text-muted">找不到房号?<button class="text-primary-600 hover:underline" @click="notify('申请新增房号(原型)')">点此申请新增</button></span>
|
||||
</div>
|
||||
|
||||
<div class="overflow-auto border border-surface rounded-lg flex-1">
|
||||
<table class="min-w-full text-sm">
|
||||
<thead class="bg-subtle border-b border-surface">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2 w-10"><input type="checkbox" class="rounded border-surface" :checked="allRoomsSelected" @click.prevent="toggleAllRooms(!allRoomsSelected)" /></th>
|
||||
<th scope="col" class="px-3 py-2 text-left">楼层名(实际层)</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">房号</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="room in currentRooms" :key="room.id">
|
||||
<tr class="border-b border-surface hover:bg-neutral-50/70">
|
||||
<td class="px-3 py-2"><input type="checkbox" class="rounded border-surface" :checked="selectedRoomIds.includes(room.id)" @change="toggleRoom(room.id, $event.target.checked)" /></td>
|
||||
<td class="px-3 py-2" x-text="room.floorName"></td>
|
||||
<td class="px-3 py-2">
|
||||
<span x-text="room.roomNo"></span>
|
||||
<span class="ml-2 inline-flex px-1.5 py-0.5 rounded text-xs bg-info-50 text-info-600 border border-info-600/20">标准</span>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 楼盘照片 -->
|
||||
<section x-show="activeTab === 'photos'" x-cloak class="bg-surface border border-surface rounded-lg p-4 space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="subtab-pill px-3 py-1.5 rounded-md" :class="{ 'active': photoType === 'complex' }" @click="photoType='complex'">楼盘图片(12)</button>
|
||||
<button class="subtab-pill px-3 py-1.5 rounded-md" :class="{ 'active': photoType === 'layout' }" @click="photoType='layout'">户型图(8)</button>
|
||||
<button class="subtab-pill px-3 py-1.5 rounded-md" :class="{ 'active': photoType === 'vr' }" @click="photoType='vr'">楼盘VR(2)</button>
|
||||
</div>
|
||||
<button class="px-3 py-2 rounded-md bg-primary-600 text-white hover:bg-primary-700" @click="notify('上传图片(原型)')">上传图片</button>
|
||||
</div>
|
||||
|
||||
<div x-show="photoType === 'layout'" class="flex items-center gap-2">
|
||||
<span class="text-xs text-muted">户型:</span>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs active">全部</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">1室</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">2室</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">3室</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">4室+</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-6 gap-3">
|
||||
<template x-for="card in 12" :key="card">
|
||||
<div class="border border-surface rounded-lg overflow-hidden bg-white">
|
||||
<div class="aspect-[4/3] bg-neutral-200 flex items-center justify-center text-neutral-500 text-xs">图片占位</div>
|
||||
<div class="px-2 py-1.5 text-xs text-neutral-600">1室2厅1卫 · 朝南</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 楼盘附件 -->
|
||||
<section x-show="activeTab === 'attachments'" x-cloak class="bg-surface border border-surface rounded-lg p-4 space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-base font-semibold">楼盘附件</h2>
|
||||
<button class="px-3 py-2 rounded-md bg-primary-600 text-white hover:bg-primary-700" @click="notify('上传附件(原型)')">上传附件</button>
|
||||
</div>
|
||||
<div class="overflow-x-auto border border-surface rounded-lg">
|
||||
<table class="min-w-full text-sm">
|
||||
<thead class="bg-subtle border-b border-surface">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2 text-left">附件名称</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">类型</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">大小</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">上传人</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">上传时间</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-surface"><td class="px-3 py-2">小区总平图.pdf</td><td class="px-3 py-2">PDF</td><td class="px-3 py-2">1.2MB</td><td class="px-3 py-2">杜利强</td><td class="px-3 py-2 tabular-nums">2026-04-25 11:20</td><td class="px-3 py-2"><button class="text-primary-600 hover:underline">下载</button></td></tr>
|
||||
<tr><td class="px-3 py-2">物业合同扫描件.zip</td><td class="px-3 py-2">ZIP</td><td class="px-3 py-2">3.8MB</td><td class="px-3 py-2">杜利强</td><td class="px-3 py-2 tabular-nums">2026-04-26 09:30</td><td class="px-3 py-2"><button class="text-primary-600 hover:underline">下载</button></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 周边配套 -->
|
||||
<section x-show="activeTab === 'facility'" x-cloak class="bg-surface border border-surface rounded-lg p-4">
|
||||
<div class="grid grid-cols-12 gap-4">
|
||||
<div class="col-span-8 border border-surface rounded-lg overflow-hidden">
|
||||
<div class="h-[420px] bg-neutral-200 flex items-center justify-center text-neutral-500">地图区域占位(楼盘点位 + 周边 POI)</div>
|
||||
</div>
|
||||
<aside class="col-span-4 border border-surface rounded-lg p-3 space-y-3">
|
||||
<div class="flex items-center gap-1 flex-wrap">
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs active">交通</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">教育</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">医疗</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">购物</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">生活</button>
|
||||
<button class="subtab-pill px-2 py-1 rounded-full text-xs">娱乐</button>
|
||||
</div>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li class="border border-surface rounded-md p-2"><p class="font-medium">地铁13号线 · 金运路站</p><p class="text-xs text-muted mt-0.5">距楼盘 1227 米</p></li>
|
||||
<li class="border border-surface rounded-md p-2"><p class="font-medium">公交站 · 祁连山南路金鼎路</p><p class="text-xs text-muted mt-0.5">距楼盘 356 米</p></li>
|
||||
<li class="border border-surface rounded-md p-2"><p class="font-medium">公交站 · 金鼎路定边路</p><p class="text-xs text-muted mt-0.5">距楼盘 412 米</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 价格走势 -->
|
||||
<section x-show="activeTab === 'price'" x-cloak class="bg-surface border border-surface rounded-lg p-4 space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="subtab-pill px-3 py-1.5 rounded-md" :class="{ 'active': priceView === 'internal' }" @click="priceView='internal'">司内数据</button>
|
||||
<button class="subtab-pill px-3 py-1.5 rounded-md" :class="{ 'active': priceView === 'market' }" @click="priceView='market'">市场数据</button>
|
||||
</div>
|
||||
<p class="text-xs text-muted">以下数据按照 T+1 更新,市场与网签数据仅供参考</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-3">
|
||||
<div class="border border-surface rounded-lg p-3"><p class="text-xs text-muted">本周挂牌均价</p><p class="text-xl font-semibold tabular-nums mt-1">57,800 元/㎡</p></div>
|
||||
<div class="border border-surface rounded-lg p-3"><p class="text-xs text-muted">近一年成交均价</p><p class="text-xl font-semibold tabular-nums mt-1">55,200 元/㎡</p></div>
|
||||
<div class="border border-surface rounded-lg p-3"><p class="text-xs text-muted">挂牌套数</p><p class="text-xl font-semibold tabular-nums mt-1">38 套</p></div>
|
||||
<div class="border border-surface rounded-lg p-3"><p class="text-xs text-muted">近一年成交套数</p><p class="text-xl font-semibold tabular-nums mt-1">26 套</p></div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="border border-surface rounded-lg p-3">
|
||||
<div class="flex items-center justify-between mb-2"><h3 class="font-medium">挂牌均价趋势</h3><div class="flex gap-1"><button class="subtab-pill px-2 py-0.5 rounded text-xs active">按周</button><button class="subtab-pill px-2 py-0.5 rounded text-xs">按月</button></div></div>
|
||||
<div class="h-56 bg-neutral-100 rounded-md flex items-center justify-center text-neutral-500">折线图占位</div>
|
||||
</div>
|
||||
<div class="border border-surface rounded-lg p-3">
|
||||
<h3 class="font-medium mb-2">成交均价趋势</h3>
|
||||
<div class="h-56 bg-neutral-100 rounded-md flex items-center justify-center text-neutral-500">折线图占位</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-surface rounded-lg overflow-hidden">
|
||||
<div class="px-3 py-2 bg-subtle border-b border-surface text-sm font-medium">本小区成交数据明细(近一年)</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full text-xs">
|
||||
<thead class="bg-subtle/60 border-b border-surface">
|
||||
<tr>
|
||||
<th scope="col" class="px-3 py-2 text-left">房源编号</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">挂牌价格(万)</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">成交价格(万)</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">成交单价(元/㎡)</th>
|
||||
<th scope="col" class="px-3 py-2 text-left">成交日期</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-surface"><td class="px-3 py-2">01DS016848</td><td class="px-3 py-2 tabular-nums">678</td><td class="px-3 py-2 tabular-nums">650</td><td class="px-3 py-2 tabular-nums">59215</td><td class="px-3 py-2 tabular-nums">2026-03-18</td></tr>
|
||||
<tr><td class="px-3 py-2">01DS015902</td><td class="px-3 py-2 tabular-nums">620</td><td class="px-3 py-2 tabular-nums">598</td><td class="px-3 py-2 tabular-nums">56612</td><td class="px-3 py-2 tabular-nums">2026-02-03</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 销控盘 -->
|
||||
<section x-show="activeTab === 'sales'" x-cloak class="bg-surface border border-surface rounded-lg p-8 text-center">
|
||||
<h2 class="text-lg font-semibold text-surface">销控盘(后续版本)</h2>
|
||||
<p class="text-sm text-muted mt-2">本模块用于新房/一手楼盘销控,当前在 P0 阶段保留占位。</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Edit Drawer -->
|
||||
<div x-cloak x-show="editDrawerOpen" class="fixed inset-0 z-40">
|
||||
<div class="absolute inset-0 bg-neutral-900/30" @click="closeEditDrawer()" aria-hidden="true"></div>
|
||||
<aside class="absolute right-0 top-0 h-full w-[560px] bg-white border-l border-surface shadow-xl flex flex-col">
|
||||
<header class="px-4 py-3 border-b border-surface flex items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-base font-semibold">编辑楼盘信息</h3>
|
||||
<p class="text-xs text-muted mt-0.5">部分信息修改会影响房源,请确认后保存</p>
|
||||
</div>
|
||||
<button class="p-1.5 rounded-md hover:bg-neutral-100" aria-label="关闭编辑抽屉" @click="closeEditDrawer()">
|
||||
<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="M6 18 18 6M6 6l12 12"/></svg>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="flex-1 overflow-y-auto p-4 space-y-5">
|
||||
<section class="space-y-3">
|
||||
<h4 class="text-sm font-semibold">基本信息</h4>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">小区名称 <span class="text-danger-600">*</span></label>
|
||||
<input type="text" class="w-full px-3 py-2 rounded-md border border-surface bg-neutral-100 text-neutral-500" x-model="editForm.name" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">小区地址 <span class="text-danger-600">*</span></label>
|
||||
<input type="text" class="w-full px-3 py-2 rounded-md border border-surface bg-neutral-100 text-neutral-500" x-model="editForm.address" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">物业类型 <span class="text-danger-600">*</span></label>
|
||||
<select x-model="editForm.propertyUsage" class="w-full px-3 py-2 rounded-md border bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" :class="editErrors.propertyUsage ? 'border-danger-600' : 'border-surface'">
|
||||
<option value="">请选择物业类型</option>
|
||||
<option value="residential">住宅</option>
|
||||
<option value="villa">别墅</option>
|
||||
<option value="commercial_residential">商住</option>
|
||||
<option value="commercial">商业</option>
|
||||
<option value="office">写字楼</option>
|
||||
</select>
|
||||
<p class="text-xs text-danger-600 mt-1" x-show="editErrors.propertyUsage" x-text="editErrors.propertyUsage"></p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">楼栋结构 <span class="text-danger-600">*</span></label>
|
||||
<select x-model="editForm.buildingStructure" class="w-full px-3 py-2 rounded-md border bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" :class="editErrors.buildingStructure ? 'border-danger-600' : 'border-surface'">
|
||||
<option value="">请选择楼栋结构</option>
|
||||
<option value="unit_room">单元-房号</option>
|
||||
<option value="other">其他</option>
|
||||
</select>
|
||||
<p class="text-xs text-danger-600 mt-1" x-show="editErrors.buildingStructure" x-text="editErrors.buildingStructure"></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="space-y-2">
|
||||
<h4 class="text-sm font-semibold">学校信息</h4>
|
||||
<p class="text-xs text-warning-600">删除学校,所有房源下关联该学校将会被删除(原型说明)</p>
|
||||
<div class="flex items-center justify-between border border-surface rounded-md px-3 py-2">
|
||||
<span>真光小学(公立 · 重点)</span>
|
||||
<button class="text-danger-600 hover:underline" @click="notify('删除学校(原型)')">删除</button>
|
||||
</div>
|
||||
<button class="px-3 py-1.5 rounded-md border border-surface hover:bg-neutral-50" @click="notify('新增学校(原型)')">+ 添加</button>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3 pb-24">
|
||||
<h4 class="text-sm font-semibold">其他信息</h4>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">容积率</label>
|
||||
<input type="number" step="0.01" x-model="editForm.plotRatio" class="w-full px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">绿化率(%)</label>
|
||||
<input type="number" step="0.01" x-model="editForm.greenRate" class="w-full px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">物业费(元/㎡/月)</label>
|
||||
<input type="number" step="0.01" x-model="editForm.propertyFee" class="w-full px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">停车位配比</label>
|
||||
<input type="text" x-model="editForm.parkingRatio" class="w-full px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-neutral-700 mb-1">备注</label>
|
||||
<textarea rows="3" x-model="editForm.remarks" class="w-full px-3 py-2 rounded-md border border-surface bg-white focus:outline-none focus:ring-2 focus:ring-primary-600/40"></textarea>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Fixed Footer: right aligned -->
|
||||
<footer class="absolute bottom-0 left-0 right-0 border-t border-surface bg-white px-4 py-3">
|
||||
<div class="flex items-center justify-end gap-3">
|
||||
<button class="inline-flex items-center px-5 py-2 text-sm font-medium rounded-md border border-neutral-300 text-neutral-700 hover:bg-neutral-50" @click="closeEditDrawer()">取消</button>
|
||||
<button class="inline-flex items-center gap-1.5 px-6 py-2 text-sm font-medium rounded-md bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-600/40 disabled:opacity-70 disabled:cursor-wait" :disabled="editSubmitting" @click="saveEdit()">
|
||||
<svg x-show="editSubmitting" class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8v4a4 4 0 0 0-4 4H4z"></path></svg>
|
||||
<span x-text="editSubmitting ? '保存中...' : '保存'"></span>
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<!-- Toast -->
|
||||
<div x-cloak x-show="toast.show" class="fixed bottom-6 right-6 z-50" x-transition>
|
||||
<div class="bg-surface border border-surface shadow-lg rounded-lg px-4 py-3 min-w-[260px]">
|
||||
<p class="text-sm font-medium" x-text="toast.title"></p>
|
||||
<p class="text-xs text-muted mt-1" x-text="toast.message"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function complexDetailPage() {
|
||||
return {
|
||||
activeTab: 'info',
|
||||
tabs: [
|
||||
{ key: 'info', label: '楼盘信息' },
|
||||
{ key: 'buildings', label: '楼栋管理' },
|
||||
{ key: 'structure', label: '结构管理' },
|
||||
{ key: 'photos', label: '楼盘照片' },
|
||||
{ key: 'attachments', label: '楼盘附件' },
|
||||
{ key: 'facility', label: '周边配套' },
|
||||
{ key: 'price', label: '楼盘价格走势' },
|
||||
{ key: 'sales', label: '销控盘' }
|
||||
],
|
||||
|
||||
schools: [
|
||||
{ name: '真光小学', type: '小学', nature: '公立', level: '重点' },
|
||||
{ name: '真光中学', type: '中学', nature: '公立', level: '区重点' }
|
||||
],
|
||||
|
||||
buildingKeyword: '',
|
||||
buildings: [
|
||||
{ id: 'b1', name: '祁连山南路2727弄101单元', usage: '别墅', year: 2009, floors: '1层', landYears: '70年', elevator: '无', school: '-' },
|
||||
{ id: 'b2', name: '祁连山南路2727弄57单元', usage: '别墅', year: 2009, floors: '1层', landYears: '70年', elevator: '无', school: '-' },
|
||||
{ id: 'b3', name: '祁连山南路2727弄59单元', usage: '别墅', year: 2009, floors: '1层', landYears: '70年', elevator: '无', school: '-' },
|
||||
{ id: 'b4', name: '祁连山南路2727弄61单元', usage: '别墅', year: 2009, floors: '1层', landYears: '70年', elevator: '无', school: '-' },
|
||||
{ id: 'b5', name: '祁连山南路2727弄63单元', usage: '别墅', year: 2009, floors: '1层', landYears: '70年', elevator: '无', school: '-' }
|
||||
],
|
||||
filteredBuildings: [],
|
||||
selectedBuildingIds: [],
|
||||
|
||||
units: [
|
||||
{ id: 'u1', name: '祁连山南路2727弄101单元' },
|
||||
{ id: 'u2', name: '祁连山南路2727弄57单元' },
|
||||
{ id: 'u3', name: '祁连山南路2727弄59单元' },
|
||||
{ id: 'u4', name: '祁连山南路2727弄61单元' }
|
||||
],
|
||||
currentUnitId: 'u2',
|
||||
roomMap: {
|
||||
u1: [
|
||||
{ id: 'r1', floorName: '1(1层)', roomNo: '101' },
|
||||
{ id: 'r2', floorName: '1(1层)', roomNo: '102' }
|
||||
],
|
||||
u2: [
|
||||
{ id: 'r3', floorName: '1(1层)', roomNo: '57-1' },
|
||||
{ id: 'r4', floorName: '1(1层)', roomNo: '57-2' }
|
||||
],
|
||||
u3: [
|
||||
{ id: 'r5', floorName: '1(1层)', roomNo: '59-1' }
|
||||
],
|
||||
u4: [
|
||||
{ id: 'r6', floorName: '1(1层)', roomNo: '61-1' }
|
||||
]
|
||||
},
|
||||
selectedRoomIds: [],
|
||||
|
||||
photoType: 'complex',
|
||||
priceView: 'internal',
|
||||
|
||||
editDrawerOpen: false,
|
||||
editSubmitting: false,
|
||||
editErrors: {},
|
||||
editForm: {
|
||||
name: '阳光威尼斯四期(别墅)',
|
||||
address: '上海普陀金鼎路1600弄,祁连山南路2727弄',
|
||||
propertyUsage: 'villa',
|
||||
buildingStructure: 'unit_room',
|
||||
plotRatio: '1.60',
|
||||
greenRate: '45',
|
||||
propertyFee: '1.45',
|
||||
parkingRatio: '100:63',
|
||||
remarks: '别墅区结构完整,建议补全学校关系。'
|
||||
},
|
||||
|
||||
toast: {
|
||||
show: false,
|
||||
title: '',
|
||||
message: ''
|
||||
},
|
||||
|
||||
init() {
|
||||
this.filteredBuildings = [...this.buildings];
|
||||
},
|
||||
|
||||
get selectedBuildingCount() {
|
||||
return this.selectedBuildingIds.length;
|
||||
},
|
||||
|
||||
get allBuildingsOnPage() {
|
||||
return this.filteredBuildings.length > 0 && this.filteredBuildings.every(row => this.selectedBuildingIds.includes(row.id));
|
||||
},
|
||||
|
||||
toggleBuildingSelect(id, checked) {
|
||||
if (checked) {
|
||||
if (!this.selectedBuildingIds.includes(id)) this.selectedBuildingIds.push(id);
|
||||
} else {
|
||||
this.selectedBuildingIds = this.selectedBuildingIds.filter(x => x !== id);
|
||||
}
|
||||
},
|
||||
|
||||
toggleBuildingSelectPage(checked) {
|
||||
const ids = this.filteredBuildings.map(r => r.id);
|
||||
if (checked) {
|
||||
this.selectedBuildingIds = Array.from(new Set([...this.selectedBuildingIds, ...ids]));
|
||||
} else {
|
||||
this.selectedBuildingIds = this.selectedBuildingIds.filter(id => !ids.includes(id));
|
||||
}
|
||||
},
|
||||
|
||||
applyBuildingFilter() {
|
||||
const kw = this.buildingKeyword.toLowerCase();
|
||||
this.filteredBuildings = this.buildings.filter(row => !kw || row.name.toLowerCase().includes(kw));
|
||||
this.selectedBuildingIds = this.selectedBuildingIds.filter(id => this.filteredBuildings.some(r => r.id === id));
|
||||
},
|
||||
|
||||
switchToStructure(unitName) {
|
||||
const target = this.units.find(u => u.name === unitName);
|
||||
if (target) this.currentUnitId = target.id;
|
||||
this.activeTab = 'structure';
|
||||
this.notify('已切换到结构管理分区');
|
||||
},
|
||||
|
||||
get currentUnitName() {
|
||||
const row = this.units.find(u => u.id === this.currentUnitId);
|
||||
return row ? row.name : '-';
|
||||
},
|
||||
|
||||
get currentRooms() {
|
||||
return this.roomMap[this.currentUnitId] || [];
|
||||
},
|
||||
|
||||
get selectedRoomCount() {
|
||||
return this.selectedRoomIds.length;
|
||||
},
|
||||
|
||||
get allRoomsSelected() {
|
||||
return this.currentRooms.length > 0 && this.currentRooms.every(r => this.selectedRoomIds.includes(r.id));
|
||||
},
|
||||
|
||||
toggleRoom(id, checked) {
|
||||
if (checked) {
|
||||
if (!this.selectedRoomIds.includes(id)) this.selectedRoomIds.push(id);
|
||||
} else {
|
||||
this.selectedRoomIds = this.selectedRoomIds.filter(x => x !== id);
|
||||
}
|
||||
},
|
||||
|
||||
toggleAllRooms(checked) {
|
||||
const ids = this.currentRooms.map(r => r.id);
|
||||
if (checked) {
|
||||
this.selectedRoomIds = Array.from(new Set([...this.selectedRoomIds, ...ids]));
|
||||
} else {
|
||||
this.selectedRoomIds = this.selectedRoomIds.filter(id => !ids.includes(id));
|
||||
}
|
||||
},
|
||||
|
||||
openEditDrawer() {
|
||||
this.editDrawerOpen = true;
|
||||
this.editErrors = {};
|
||||
},
|
||||
|
||||
closeEditDrawer() {
|
||||
this.editDrawerOpen = false;
|
||||
this.editErrors = {};
|
||||
this.editSubmitting = false;
|
||||
},
|
||||
|
||||
saveEdit() {
|
||||
this.editErrors = {};
|
||||
if (!this.editForm.propertyUsage) this.editErrors.propertyUsage = '请选择物业类型';
|
||||
if (!this.editForm.buildingStructure) this.editErrors.buildingStructure = '请选择楼栋结构';
|
||||
if (Object.keys(this.editErrors).length > 0) return;
|
||||
|
||||
this.editSubmitting = true;
|
||||
setTimeout(() => {
|
||||
this.editSubmitting = false;
|
||||
this.editDrawerOpen = false;
|
||||
this.notify('楼盘信息已保存(原型)');
|
||||
}, 550);
|
||||
},
|
||||
|
||||
notify(message) {
|
||||
this.toast.title = '操作反馈';
|
||||
this.toast.message = message;
|
||||
this.toast.show = true;
|
||||
clearTimeout(this.__toastTimer);
|
||||
this.__toastTimer = setTimeout(() => (this.toast.show = false), 1800);
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,7 +6,7 @@
|
||||
你的核心方法论:**以终为始**——从用户需求出发,验证每一层设计决策是否正确传导,找出断层、矛盾和遗漏。
|
||||
你的 Review 不是挑错,而是帮助团队在编码前发现最高代价的问题。
|
||||
|
||||
**工作目录**:`~/Workspace/nexus`
|
||||
**工作目录**:`/mnt/d/Workspace/nexus`
|
||||
|
||||
**你的职责边界**:
|
||||
- ✅ 负责:跨文档一致性检查、设计风险识别、遗漏场景挖掘、改进建议输出
|
||||
@@ -29,54 +29,80 @@
|
||||
请读取以下文档,作为本次 Review 的全部输入:
|
||||
|
||||
**产品文档(PRD)**:
|
||||
- PRD_MVP: `Project/fonrey/PRD/PRD_MVP.md`
|
||||
- 房源管理PRD: `Project/fonrey/PRD/房源管理/房源管理模块PRD.md`
|
||||
- 楼盘管理PRD: `Project/fonrey/PRD/房源管理/楼盘管理模块PRD.md`
|
||||
- 客源管理PRD: `Project/fonrey/PRD/客源管理/客源管理模块PRD.md`
|
||||
- 权限管理PRD: `Project/fonrey/PRD/权限管理/权限管理模块PRD.md`
|
||||
- 组织人事管理PRD: `Project/fonrey/PRD/组织人事管理/组织人事管理模块PRD.md`
|
||||
- 系统管理PRD: `Project/fonrey/PRD/系统管理/系统管理模块PRD`
|
||||
- 系统管理PRD: `Project/fonrey/PRD/系统管理/系统管理模块PRD.md`
|
||||
- 登录管理PRD: `Project/fonrey/PRD/登录管理/用户登录管理模块PRD.md`
|
||||
- 发布管理PRD: `Project/fonrey/PRD/发布管理/客户端发布管理模块PRD.md`
|
||||
|
||||
**技术文档**:
|
||||
- TECH_STACK:`Project/fonrey/TECH_STACK/TECH_STACK.md`
|
||||
- 项目总TECH_STACK:`Project/fonrey/TECH_STACK/TECH_STACK.md`
|
||||
- 登录管理技术方案:`Project/fonrey/TECH_STACK/登录管理技术方案.md`
|
||||
- 权限管理技术方案:`Project/fonrey/TECH_STACK/登录管理技术方案.md`
|
||||
- 测试规范:`Project/fonrey/TECH_STACK/测试规范`
|
||||
- 房源管理技术方案:`Project/fonrey/TECH_STACK/房源管理技术方案.md`
|
||||
- 楼盘管理技术方案:`Project/fonrey/TECH_STACK/楼盘管理技术方案.md`
|
||||
- 客源管理技术方案:`Project/fonrey/TECH_STACK/客源管理技术方案.md`
|
||||
- 系统管理技术方案: `Project/fonrey/TECH_STACK/系统管理技术文档.md`
|
||||
- 系统设置技术方案:`Project/fonrey/TECH_STACK/系统设置技术方案.md`
|
||||
- API契约规范:`Project/fonrey/TECH_STACK/API_CONTRACT.md`
|
||||
- 测试规范:`Project/fonrey/TECH_STACK/测试规范.md`
|
||||
|
||||
**数据模型**
|
||||
- DATA_MODEL:`Project/fonrey/DATA_MODEL/DATA_MODEL.md`
|
||||
- 项目总DATA_MODEL:`Project/fonrey/DATA_MODEL/DATA_MODEL.md`
|
||||
- 登录DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN`
|
||||
- 房源 DATA_MODDL: `Project/fonrey/DATA_MODEL/DATA_MODEL_PROPERTY.md`
|
||||
- 客源 DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_CLIENT.md`
|
||||
- 楼盘 DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md`
|
||||
- 组织人事DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_ORG.md`
|
||||
- 权限DATA_MODEL:`Project/fonrey/DATA_MODEL/DATA_MODEL_PERMISSION.md`
|
||||
- 系统管理DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_PUBLIC.md`
|
||||
- 系统设置DATA_MODEL: `Project/fonrey/DATA_MODEL/DATA_MODEL_SETTING`
|
||||
- 统一枚举字典:`Project/fonrey/DATA_MODEL/ENUMS.md`
|
||||
|
||||
**UI 设计文档**:
|
||||
- UI SYSTEM:`Project/fonrey/UI_SYSTEM/UI_SYSTEM.md`
|
||||
- 组件清单:`Project/fonrey/UI_SYSTEM/组件清单.md`
|
||||
- 组件设计规范:`Project/fonrey/UI_SYSTEM/组件规范设计.md`
|
||||
- 模块UI Design:
|
||||
- `Project/fonrey/UI_DESIGN/客源列表_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/客源详情_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/新增客源_UI`
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/编辑客源_UI`
|
||||
- `Project/fonrey/UI_DESIGN/房源管理/房源列表_UI`
|
||||
- `Project/fonrey/UI_DESIGN/登录管理/登录_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/房源管理/房源列表_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/房源管理/房源详情_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/房源管理/新增房源_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/编辑客源_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/客源列表_U.mdI
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/客源详情_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/客源管理/新增客源_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/楼盘管理/楼盘列表_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/楼盘管理/楼盘详情_UI.md`
|
||||
- `Project/fonrey/UI_DESIGN/UI_设计任务总表.md`
|
||||
|
||||
**UI 原型页面**:
|
||||
- UI SYSTEM: `Project/fonrey/UI_DESIGN/preview.html`
|
||||
- 总体页面预览: `Project/fonrey/UI_DESIGN/preview.html`
|
||||
- Tenant登录:`Project/fonrey/UI_DESIGN/登录_UI.html`
|
||||
- 经纪人登录:`Project/fonrey/UI_DESIGN/登录_账号密码_UI.html`
|
||||
- 客源列表:`Project/fonrey/UI_DESIGN/客源列表_UI.html`
|
||||
- 客源详情:`Project/fonrey/UI_DESIGN/客源详情_UI.html`
|
||||
- 编辑客源:`Project/fonrey/UI_DESIGN/编辑客源_UI.html`
|
||||
- 新增客源:`Project/fonrey/UI_DESIGN/新增客源_UI.html`
|
||||
- 房源列表:`Project/fonrey/UI_DESIGN/房源列表_UI.html`
|
||||
- 房源详情:`Project/fonrey/UI_DESIGN/房源详情_UI.html`
|
||||
- 楼盘列表:`Project/fonrey/UI_DESIGN/楼盘列表_UI.html`
|
||||
- 楼盘详情:`Project/fonrey/UI_DESIGN/楼盘详情_UI.html`
|
||||
|
||||
**任务汇总**
|
||||
- TASK:`Project/fonrey/PRD/TASK.md`
|
||||
- 任务总表(优化提示词):`Project/fonrey/PRD/TASK_AGENT_READY.md`
|
||||
- P0任务总表(优化提示词):`Project/fonrey/PRD/TASK_AGENT_READY_P0.md`
|
||||
|
||||
|
||||
**其他参考文档**:
|
||||
|
||||
- 历史Review报告:
|
||||
- `Project/fonrey/REVIEW/REVIEW_全局_2026-04-25.md`
|
||||
- `Project/fonrey/REVIEW/REVIEW_全局_2026-04-26.md`
|
||||
|
||||
---
|
||||
|
||||
|
||||
78
Project/fonrey/prompt/提示词模板/API_CONTRACT_冲突提报模板_v1.md
Normal file
78
Project/fonrey/prompt/提示词模板/API_CONTRACT_冲突提报模板_v1.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# API_CONTRACT 冲突提报模板(可复用)
|
||||
|
||||
> 版本:v1.0(2026-04-28)
|
||||
> 适用范围:`PRD/TASK_AGENT_READY*.md`、模块级 Agent 执行提示词、代码交付回执
|
||||
|
||||
---
|
||||
|
||||
## 1) 目的
|
||||
|
||||
当实现与 `Project/fonrey/TECH_STACK/API_CONTRACT.md` 存在差异时,统一使用本模板提报,确保:
|
||||
|
||||
- 冲突可审计(知道“哪里不一致”)
|
||||
- 影响可评估(前端/后端/测试/数据)
|
||||
- 处置可回滚(不阻断主干稳定性)
|
||||
|
||||
> 约束:**不得擅自修改 API_CONTRACT**。先按契约实现;若确需调整,必须先提报并待确认。
|
||||
|
||||
---
|
||||
|
||||
## 2) 可直接粘贴到任务提示词的交付片段
|
||||
|
||||
将以下段落放入每条任务的 `【交付格式】`:
|
||||
|
||||
```md
|
||||
- API 契约核对清单(逐条对应 API_CONTRACT:已对齐/偏差项)
|
||||
- API 契约冲突说明(如无冲突写“无”)
|
||||
- 冲突接口(Method + Path)
|
||||
- 当前契约要求(来自 API_CONTRACT)
|
||||
- 实现差异 / 建议改动
|
||||
- 影响面(前端/后端/测试/存量数据)
|
||||
- 回滚方案
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3) API 契约冲突提报单(标准格式)
|
||||
|
||||
> 若“无冲突”,填写:`API 契约冲突说明:无`
|
||||
|
||||
```md
|
||||
### API 契约冲突提报单
|
||||
- 任务ID:<US-XXX>
|
||||
- 关联模块:<登录/楼盘/房源/客源/...>
|
||||
- 冲突接口(Method + Path):
|
||||
- <GET|POST|PUT|PATCH|DELETE> <path>
|
||||
|
||||
- 当前契约要求(来自 API_CONTRACT):
|
||||
- 请求参数:<必填/可选/类型/约束>
|
||||
- 响应结构:<字段、类型、是否可空>
|
||||
- 错误码:<code + 含义>
|
||||
|
||||
- 实现差异 / 建议改动:
|
||||
- 差异点1:<描述>
|
||||
- 差异点2:<描述>
|
||||
- 建议:<保持契约 / 调整契约(需审批)>
|
||||
|
||||
- 影响面:
|
||||
- 前端:<页面/组件/调用方>
|
||||
- 后端:<视图/序列化器/服务层>
|
||||
- 测试:<需新增/需修正的用例>
|
||||
- 存量数据:<是否需要迁移/回填>
|
||||
|
||||
- 风险等级:<低/中/高>
|
||||
- 临时兜底方案:<可选>
|
||||
- 回滚方案:<可执行步骤>
|
||||
- 需要确认人:<产品/后端负责人/前端负责人>
|
||||
- 期望确认时限:<YYYY-MM-DD HH:mm>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4) 最小核对清单(提交前自检)
|
||||
|
||||
- [ ] 已逐条对照 API_CONTRACT 的路径/方法/参数/响应/错误码
|
||||
- [ ] 已明确“无冲突”或填写完整冲突提报单
|
||||
- [ ] 已写明影响面(前端/后端/测试/数据)
|
||||
- [ ] 已给出可执行回滚方案
|
||||
- [ ] 未直接修改 API_CONTRACT 文档内容
|
||||
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
10
Project/fonrey/广告词.md
Normal file
10
Project/fonrey/广告词.md
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
## 面向中小型房产经纪中介公司的信息管理系统
|
||||
|
||||
## 近乎零成本的房产经纪管理系统
|
||||
|
||||
## AI技术让你和大公司平台拉平信息差
|
||||
|
||||
## 小成本拉平信息差
|
||||
|
||||
Reference in New Issue
Block a user