feat: 新增智电改造线路台账功能(ICC拉取同步)

- 数据库:新增迁移脚本20261011_icc_line_ledger.sql(electric_line/line_room/icc_sync_log三表、菜单61、role_menu(1,61)、定时任务icc_line_sync),同步db_seed.sql
- 后端:新增ElectricLine/IccSyncLog实体、查询DTO、线路台账服务与ICC拉取同步服务、/api/electric-lines控制器,接入RBAC(device:list)与定时任务
- 前端:新增智电改造线路台账页面及路由,API封装electricLineApi
- ICC同步采用本系统主动拉取模式,失败仅记日志不抛错,接口统一code/message/data格式兼容APP
This commit is contained in:
wk committed 2026-10-12 15:57:02 +08:00
1 parent f72644c24f
commit 41765cdf44
21 files changed
+1363 -6

No files matched your search

@@ -0,0 +1,14 @@
# Checklist
- [x] electric_line / line_room / icc_sync_log 表存在(生产库 + db_seed.sql 一致,幂等)
- [x] ElectricLine / IccSyncLog 实体与 DTO 实现,ElectricLine 仅 created_at(timestamps:false)
- [x] 列表查询使用参数绑定(Op.like/Op.in),无字符串拼接 SQL
- [x] GET /api/electric-lines:无 token 401、有 device:list 权限 200 返回 code/message/data 结构
- [x] POST /api/electric-lines/sync:JWT+RBAC 鉴权;定时任务服务内直调
- [x] IccLineSyncService 读 ICC_BASE_URL/ICC_TOKEN 占位配置,按 line_code upsert + 写 icc_sync_log;ICC 拉取失败记录 error 不抛业务错
- [x] icc_line_sync 定时任务已注册(@midwayjs/cron)
- [x] RBAC 映射含 /api/electric-lines → device:list
- [x] 前端 /device/line 页面渲染(搜索/同步按钮/表格/分页/状态 tag),无 v-html
- [x] 菜单 id=61 挂设备监控(4) 且 role_menu 绑定,db_seed.sql 与生产库一致
- [x] 后端 tsc --noEmit、前端 vue-tsc -b 均通过
- [x] 浏览器端登录后菜单可见、页面可用、同步按钮可用
+45
View File
@@ -0,0 +1,45 @@
# 智电改造线路台帐(设备监控)Spec
## Why
设备监控模块缺少"智电改造线路"台账。线路数据由 ICC 平台同步到本系统,运营侧需按客户/设备/建筑查看线路及状态。需在既有设备模块最小套路基础上新增后端接口(含鉴权与防注入)与前端页面,并兼容 APP。
## What Changes
- **新增** `electric_line` 表后端实体/DTO/Service/Controller(查询接口 `GET /api/electric-lines` 列表 + 详情,手动同步 `POST /api/electric-lines/sync`)
- **新增** ICC 拉取同步:`IccLineSyncService` 从 `.env`(`ICC_BASE_URL`/`ICC_TOKEN`)读取占位配置,请求 ICC 线路列表接口(路径与字段映射集中定义),幂等 upsert 写入 `electric_line`,记录 `icc_sync_log`
- **新增** 定时任务:注册 `icc_line_sync.task`(@midwayjs/cron,周期默认 10 分钟,可配置),服务内直调拉取
- **新增** RBAC 映射:`/api/electric-lines → device:list`
- **新增** 前端"智电改造线路台账"页面(`views/device/line/index.vue`),路由 `/device/line`,含"同步线路"手动按钮;菜单挂设备监控目录(parent=4,新 id=61)
- **同步** db_seed.sql 与迁移文件(建表 + 菜单 + role_menu),保持幂等一致
- **安全**:全部 SQL 走 Sequelize 参数绑定;前端不用 v-html(防 XSS);接口返回统一 `code/message/data`(兼容 APP)
## Impact
- Affected specs: 设备监控(设备台账、智电设备型号)、ICC 数据同步、RBAC 权限
- Affected code: server/src(entity/dto/service/controller/middleware)、client/src(api/router/views)、database(db_seed.sql、migrations/)
## ADDED Requirements
### Requirement: 线路台账查询(JWT+RBAC)
系统 SHALL 提供线路台账列表与详情查询,仅登录且有 `device:list` 权限的用户可访问;查询支持按 customer_id/equip_id/building_id/status/关键词(line_name/line_code)过滤分页;非 ADMIN 业务员按客户归属自动限定数据范围。
#### Scenario: 成功查询
- **WHEN** 已登录用户 GET `/api/electric-lines?page=1&pageSize=10&customerId=1`
- **THEN** 返回 `code=0,data{list,total}`,含线路编码/名称/所属设备/客户/建筑/楼层/位置/状态/同步时间;无 token 返回 401,无权限返回 403
### Requirement: ICC 拉取同步(占位配置 + 定时 + 手动)
系统 SHALL 提供 ICC 线路拉取同步能力:`IccLineSyncService` 读取 `.env` 的 `ICC_BASE_URL`/`ICC_TOKEN`(占位,字段映射集中在 `icc_line_mapper`),向 ICC 拉取线路列表,按 `line_code` upsert(幂等)写入 `electric_line`,更新 `synced_at`,写 `icc_sync_log`(status/record_count/error_message)。同步入口:① 定时任务(@midwayjs/cron,默认每 10 分钟,服务内直调);② 手动 `POST /api/electric-lines/sync`(JWT+RBAC `device:list`)。
#### Scenario: 定时/手动拉取成功
- **WHEN** 定时任务触发或运营点击"同步线路"
- **THEN** 拉取 ICC 数据并 upsert 对应线路行,`icc_sync_log` 记录成功;返回 `code=0,data{syncedCount,updatedCount}`
#### Scenario: 手动同步鉴权失败
- **WHEN** 未登录或无 `device:list` 权限调用 `/api/electric-lines/sync`
- **THEN** 返回 401/403,不触发拉取
#### Scenario: ICC 拉取失败
- **WHEN** ICC 地址不可达或返回异常
- **THEN** 同步日志记录失败状态与错误信息,业务接口不报错
### Requirement: 前端线路台账页
系统 SHALL 提供 `/device/line` 页面:搜索栏(线路名称/编码、客户、状态)、"同步线路"按钮(调 `/api/electric-lines/sync`,成功后刷新)、表格(编码/名称/客户/设备/建筑/楼层/位置/状态 tag/同步时间)、分页;样式与设备台账一致,全部文本经 Vue 插值转义。
#### Scenario: 打开页面
- **WHEN** 有 `device:list` 权限的用户访问设备监控→智电改造线路台账
- **THEN** 渲染列表并展示分页与筛选
## MODIFIED Requirements
(无既有功能被修改)
+26
View File
@@ -0,0 +1,26 @@
# Tasks
- [ ] Task 1: 数据库层:新建 migration 建 `electric_line`(按 db_design.html:575-589 字段)、`line_room`、`icc_sync_log`(若不存在),并把建表语句同步进 db_seed.sql;幂等(IF NOT EXISTS / 增量)
- [ ] SubTask 1.1: 核对生产库是否已有 electric_line/line_room/icc_sync_log,避免重复
- [ ] SubTask 1.2: 写 migration(migrations/20261011_icc_line_ledger.sql)并执行到远程生产库
- [ ] Task 2: 后端实体+DTO:新增 `ElectricLine` entity(timestamps:false,仅 created_at)、`IccSyncLog` entity;`electric_line.dto.ts` 定义查询/同步入参(line_code 必填、字段校验、长度限制)
- [ ] Task 3: 后端 Service:
- [ ] SubTask 3.1: `ElectricLineService.list(page, filter)`(Op.like/Op.in 参数绑定,非 ADMIN 限定 customer_id)
- [ ] SubTask 3.2: `IccLineSyncService.syncFromIcc()`:读 `.env` 的 ICC_BASE_URL/ICC_TOKEN 占位配置,请求 ICC 线路列表(路径与字段映射集中在 `icc_line_mapper`),按 line_code 批量 upsert + 写 icc_sync_log + 失败捕获不抛业务错误
- [ ] Task 4: 后端 Controller + RBAC:
- [ ] SubTask 4.1: `electric_line.controller.ts`:GET /api/electric-lines(列表/详情)、POST /api/electric-lines/sync(调 IccLineSyncService)
- [ ] SubTask 4.2: rbac.middleware.ts 追加 `/api/electric-lines → device:list`
- [ ] SubTask 4.3: `.env` 增加 ICC_BASE_URL、ICC_TOKEN(占位);定时任务注册 `icc_line_sync.task`(@midwayjs/cron,默认每 10 分钟)
- [ ] Task 5: 前端 API:`client/src/api/device.ts`(或新 `line.ts`)新增 `electricLineApi.list/get/sync`
- [ ] Task 6: 前端页面:`views/device/line/index.vue`(搜索+同步按钮+表格+分页+状态 tag),路由 `/device/line`(permission device:list),菜单 id=61 挂设备监控(4) + role_menu(1,61),同步 db_seed.sql
- [ ] Task 7: 验证:
- [ ] SubTask 7.1: 后端 `tsc --noEmit`、前端 `vue-tsc -b` 类型检查
- [ ] SubTask 7.2: 启动后端/前端,接口实测(无 token 401、有权限 200、无权限 403、sync 接口鉴权、ICC 拉取失败不报错)
- [ ] SubTask 7.3: 浏览器验证菜单出现、页面渲染、筛选/分页/同步按钮可用
# Task Dependencies
- Task 2/5 依赖 Task 1(表存在)
- Task 3 依赖 Task 2
- Task 4 依赖 Task 3
- Task 6 依赖 Task 5
- Task 7 依赖全部