# 空间拓扑与用电架构 · 实现计划 ## Context(为什么做) 现有「空间拓扑与用电架构」页面(`client/src/views/customer/topology/index.vue`)只实现了「客户 → 建筑 → 房间」三层树 + 建筑/房间增删改,**"用电架构"部分完全缺失**:数据库与后端没有任何承载"用电回路"的表或接口,页面上也没有配电拓扑可视化。 设计稿 `系统设计/UI/空间拓扑与用电架构/code.html` 定义了三栏工业级布局(左空间树 / 中配电单线拓扑流 / 右节点属性面板)。本次目标:在新表 + 新后端接口的基础上,把该页面补齐为三栏结构,让"空间"与"用电回路"打通。 ## 已确认的边界(用户决策) | 项 | 结论 | | ------ | ---------------------------------------- | | 目标形态 | 按设计稿做完整三栏(左树 / 中单线图 / 右属性面板) | | 左树层级 | 客户 → 建筑 → **楼层** → 房间 → **回路**(不要"配电箱"层) | | 楼层 | 由房间/回路按 `floor_no` 分组生成的**虚拟层**,不建表 | | 中间图上层 | 进线柜 / 变压器:**只读展示**,不落库、不做 CRUD | | 中间图末端 | **回路卡片**(一个回路一张卡) | | 实时电气量 | 电压/电流/功率/温度等**一律占位**(显示 `—`),不造假数据、不接采集 | | ICC 映射 | **不做**(设计稿里的网关层、ICC 设备码、告警阈值联动均不实现) | | 覆盖端 | 仅 Web 管理端 `client/` | | 数据来源 | 新建表 + 后端 CRUD 接口 | ## 数据模型(新增 1 张表) `customer_circuit`(客户用电回路)—— 参照 `customer_room` 的建表风格(`database/db_init.sql#L364-L387`): | 字段 | 类型 | 说明 | | -------------- | --------------------- | ----------------------------------- | | id | BIGSERIAL PK |
| | customer\_id | BIGINT NOT NULL | → `customer(id)` | | building\_id | BIGINT NOT NULL | → `customer_building(id)` | | room\_id | BIGINT NULL | → `customer_room(id)`,允许挂建筑/楼层而不挂房间 | | floor\_no | VARCHAR(16) | 楼层(冗余,便于按楼层分组) | | circuit\_code | VARCHAR(64) NOT NULL | 回路编号,全局唯一 | | circuit\_name | VARCHAR(128) NOT NULL | 回路名称 | | loop\_spec | VARCHAR(128) | 回路规格(如 `三相380V / 铜芯4×25+1×16`) | | load\_type | VARCHAR(32) | 负荷类型(照明/动力/空调/插座…) | | rated\_voltage | VARCHAR(32) | 额定电压(配置值) | | rated\_current | VARCHAR(32) | 额定电流(配置值) | | rated\_power | NUMERIC(10,2) | 额定功率 kW(配置值) | | status | SMALLINT DEFAULT 1 | 1 正常 / 0 停用 | | remark | TEXT | 备注 | | sort\_order | INT DEFAULT 0 | 排序 | | created\_at | TIMESTAMP |
| 索引:`customer_id`、`building_id`、`room_id`、唯一键 `circuit_code`。 > 命名跟随现有习惯:表 `customer_circuit`、entity `CustomerCircuit`、路由 `/api/customer-circuits`、权限码 `customer:circuit`(与 `customer:building` / `customer:room` 同级)。 ## 后端改动(Midway.js + sequelize-typescript) 参照样板:`customer_room` 全链路。 1. **迁移**:`database/migrations/20261011_customer_circuit.sql`(幂等 `CREATE TABLE IF NOT EXISTS`),并在 `database/db_init.sql` 同步该表定义。 2. **Entity**:`server/src/entity/customer_circuit.entity.ts`(照抄 `customer_building.entity.ts` 的 `@Table/@Column/@BelongsTo/@CreatedAt` 写法)。 3. **DTO**:`server/src/dto/customer_circuit.dto.ts`(Query/Create/Update,class-validator 风格照抄 `customer_room.dto.ts`)。 4. **Service**:`server/src/service/customer_circuit.service.ts` * `list` / `detail` / `create` / `update` / `delete`(照抄 `customer_room.service.ts`,统一返回 `{ code, message, data }`)。 * `topology(customerId)`:**一次请求**返回整棵「建筑 → 楼层 → 房间 → 回路」结构,避免前端 N+1(现有页面是逐建筑拉房间)。返回形如: ```json { "buildings": [ { "id":1, "buildingName":"…", "floors":[ { "floorNo":"2", "rooms":[ { "id":9, "roomName":"…", "circuits":[…] } ], "circuits":[…] } ] } ] } ``` 5. **Controller**:`server/src/controller/customer_circuit.controller.ts`(`@Controller("/api/customer-circuits")`,含 `GET /topology`)。 6. **权限注册**:`server/src/middleware/rbac.middleware.ts` 的 `PERMISSION_MAP` 新增 `"/api/customer-circuits": "customer:circuit"`。 7. **菜单/权限种子**:在 `database/db_seed.sql` 复用现有「空间拓扑与用电架构」菜单(id=32, `/customer/topology`, 权限码 `customer:topology`),并**参照** **`customer:room`** **的登记方式**新增按钮级权限 `customer:circuit`。 ## 前端改动(Vue3 + Ant Design Vue) 1. **新增 API 封装** `client/src/api/customerCircuit.ts`:照抄 `customerRoom.ts` 风格(`getList/getDetail/create/update/delete/getTopology` + 类型定义 + 常量:负荷类型选项)。 2. **重写** `client/src/views/customer/topology/index.vue` 为三栏: * **顶部**:面包屑 + 客户切换器 + 指标条 + 「新增回路」按钮。指标只展示**可由现有数据算出**的项(已接入建筑数、监测用电回路数、空间建模覆盖率 = 有回路的房间数/房间总数);无数据源的项(变电所/配电室、ICC 边缘网关)**不展示**。 * **左栏(≈280px)**:`a-tree` 渲染「客户 → 建筑 → 楼层 → 房间 → 回路」;节点徽章显示回路数;节点悬停操作:建筑/房间沿用现有增删改(`customerBuildingApi` / `customerRoomApi`),回路可新增/编辑/删除。 * **中栏**:单线图。上层为**只读示意**(10kV 进线柜 → 变压器 → 低压母线,按客户/建筑信息填充文案)、下层为**回路卡片网格**(编号/名称/所属房间/规格/额定参数,点击选中;实时电气量显示 `—`)。用 div 网格 + 内联 SVG 母线渲染(与设计稿一致),**不引入新依赖**(echarts 已在依赖中但不必要)。 * **右栏(≈320px)**:选中节点的属性面板(回路基本信息可编辑并保存;房间/建筑节点展示只读属性)。 * 样式沿用页面既有基线:背景 `#eef3f8`、主色 `#0054cd`、卡片圆角 `12px`、等宽字体用 `Consolas/Menlo`。 3. **路由/权限**:沿用现有 `customer/topology` 路由与 `customer:topology` 菜单,**不新增页面路由**。 ## 不做(明确排除) * ICC 网关节点、ICC 设备码映射、告警阈值联动、下发同步 * 实时电气量采集与展示(一律 `—`) * 「从 ICC 同步拓扑」「CAD/BIM 导入」「导出高清拓扑图」按钮 → 先不实现(可留占位,若留则点击提示"暂未开放") * 「空间三维映射」视图切换 * 配电箱/配电柜层 * Flutter 管理端 ## 假设(如不认可请指出) 1. 中间图的上层(进线柜/变压器)**纯前端静态示意**,文案按所选客户/建筑动态填充,不落库。 2. `circuit_code` **全局唯一**(与设备台账 `equip_code` 一致);若你希望"客户内唯一",需改唯一约束。 3. 回路可以**不挂房间**(只挂建筑+楼层),以适应公共区域回路。 4. 顶部指标只做能算出来的 3 项,其余留白而非显示假数据。 ## 验证方式 1. 执行迁移:`database/migrations/20261011_customer_circuit.sql`(以及 db\_seed 的权限登记),确认表与权限数据落库。 2. 后端:启动 `server/`,用带 token 的请求验证 `GET /api/customer-circuits/topology?customerId=1`、以及 create/update/delete;无 token 应 401、无权限应 403。 3. 前端:`client/` 执行 `npm run check`(vue-tsc)通过;`npm run dev` 后进入「客户管理 → 空间拓扑与用电架构」: * 选客户 → 左树按「建筑 → 楼层 → 房间 → 回路」正确展开; * 新增/编辑/删除回路后树与中间卡片同步刷新; * 点击回路卡片 → 右栏属性正确回填、可保存; * 中间图上层的进线柜/变压器为只读示意。 4. 回归:确认原有建筑/房间增删改仍可用(房间功能未被破坏)。