新增笔记
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user