Files
smart_grid_iot/.trae/documents/空间拓扑与用电架构-实现计划.md
T
andyesfly f72644c24f feat: 新增客户用电回路全链路功能
新增客户用电回路表及相关数据库迁移、后端服务、控制器、DTO、实体类和权限配置;新增前端API封装,同时调整路由名称以匹配新业务模块,复用现有菜单权限避免403错误。
2026-10-12 15:20:08 +08:00

122 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 空间拓扑与用电架构 · 实现计划
## 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 | <br /> |
| 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 | <br /> |
索引:`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. 回归:确认原有建筑/房间增删改仍可用(房间功能未被破坏)。