[F9/F10] 子系统管理 + 告警正交 5 态列表(UI 骨架 + mock)

两任务并行完成,因同动 router/iot.ts 与 locales/page.json 合并 commit。

F9 子系统管理 + 设备批量绑定:
- apps/web-antd/src/api/iot/subsystem/index.ts
- apps/web-antd/src/views/iot/subsystem/{list,form,devices}.vue
- apps/web-antd/src/views/iot/subsystem/__tests__/subsystem-utils.test.ts (18 用例)
- Known Pitfalls: 评审 A6 Redis stats 降级 / A7 403 拦截器 / 批量 100 台 / code regex snake_case
- 后端 B10/B11 API 契约: /iot/subsystem/{page,get,create,update,delete,simple-list,device-count}
  + /iot/device/{batchBindSubsystem,bindSubsystem} + /iot/device/page 加 subsystemId 过滤

F10 告警记录 (评审 C1 正交 5 态):
- apps/web-antd/src/views/iot/alarm/record/{list,detail}.vue
- apps/web-antd/src/views/iot/alarm/record/{alarm-state,api}.ts
- apps/web-antd/src/views/iot/alarm/record/components/{AlarmStateTag,AlarmOperations}.vue
- apps/web-antd/src/views/iot/alarm/record/__tests__/AlarmStateTag.spec.ts (12 用例)
- 5 态: 活跃·未确认(red) / 活跃·已确认(orange) / 已清除·未确认(gold醒目) / 已清除·已确认(green) / 已归档(default)
- Known Pitfalls: C1 5 态必展示 / archived 优先判断 / 30s 轮询 / 严重度颜色映射
- 后端 B12 API 契约: /iot/alarm-record/{page,get,ack,unack,clear,archive,batch-*,history,remark}

共同:
- apps/web-antd/src/router/routes/modules/iot.ts 追加 subsystem + alarm 路由
- locales/langs/{zh-CN,en-US}/page.json 追加 iot.subsystem.* + iot.alarm.*

note: 路由用顶级路径;项目采用动态菜单机制,菜单注册需后端 menu 表配置(运维侧工作),
      前端路由可通过 URL 直接访问。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-04-23 22:39:47 +08:00
parent 8613641d1d
commit ba459aa1d7
15 changed files with 2443 additions and 0 deletions

View File

@@ -41,6 +41,53 @@
}
},
"iot": {
"subsystem": {
"title": "Subsystem",
"listTitle": "Subsystem List",
"name": "Name",
"namePlaceholder": "Enter subsystem name",
"nameRequired": "Name is required",
"nameTooLong": "Name must not exceed 128 characters",
"code": "Code",
"codePlaceholder": "e.g. security, clean",
"codeRequired": "Code is required",
"codeTooLong": "Code must not exceed 64 characters",
"codeFormat": "Code must start with a lowercase letter and contain only lowercase letters, digits, or underscores",
"codeHelp": "Format: starts with a letter, allows digits and underscores, e.g. clean_01",
"status": "Status",
"statusEnabled": "Enabled",
"statusDisabled": "Disabled",
"statusPlaceholder": "Select status",
"icon": "Icon",
"iconPlaceholder": "Icon URL or iconify name",
"description": "Description",
"descriptionPlaceholder": "Enter description",
"deviceCount": "Devices",
"searchPlaceholder": "Search name / code",
"viewDevices": "View Devices",
"deleteDisabledTip": "Cannot delete: subsystem has {0} device(s)",
"deviceListTitle": "Subsystem Devices",
"deviceName": "Device Name",
"serialNumber": "Serial Number",
"deviceState": "Online State",
"deviceOnline": "Online",
"deviceOffline": "Offline",
"deviceSearchPlaceholder": "Search device name",
"statTotal": "Total Devices",
"statOnline": "Online",
"statAlarm": "Alarming",
"statsNotice": "Stats are provided by Redis cache and may have a short delay (⚠️ A6)",
"batchBind": "Batch Bind Devices",
"batchBindHint": "Max 100 devices per batch",
"bindSuccess": "{0} device(s) bound successfully",
"selectDeviceTip": "Please select devices first",
"unbind": "Remove",
"unbindConfirm": "Remove device \"{0}\" from this subsystem?",
"unbinding": "Removing device...",
"unbindSuccess": "Device removed",
"transferCandidate": "Candidate Devices",
"transferSelected": "Selected Devices"
},
"dag": {
"toolbar": {
"zoomIn": "Zoom In",
@@ -120,6 +167,86 @@
"desc": "Send notification (SMS/Email/Webhook)"
}
}
},
"alarm": {
"state": {
"archived": "Archived",
"activeUnacked": "Active·Unacked",
"activeAcked": "Active·Acked",
"clearedUnacked": "Cleared·Unacked",
"clearedAcked": "Cleared·Acked",
"unknown": "Unknown"
},
"severity": {
"critical": "Critical",
"major": "Major",
"minor": "Minor",
"warning": "Warning",
"info": "Info",
"unknown": "Unknown"
},
"list": {
"title": "Alarm Records"
},
"field": {
"alarmName": "Alarm Name",
"severity": "Severity",
"state": "State",
"deviceName": "Device",
"productName": "Product",
"triggerCount": "Trigger Count",
"startTs": "First Triggered",
"endTs": "Last Triggered",
"clearTs": "Cleared At",
"ackTs": "Acked At"
},
"filter": {
"all": "All",
"ackState": "Ack State",
"clearState": "Clear State",
"archived": "Archive",
"unacked": "Unacked",
"acked": "Acked",
"active": "Active",
"cleared": "Cleared",
"excludeArchived": "Exclude Archived",
"allRecords": "All Records",
"onlyArchived": "Archived Only"
},
"op": {
"ack": "Ack",
"unack": "Unack",
"clear": "Clear",
"archive": "Archive",
"noOps": "No Operations",
"confirmTitle": "Confirm",
"ackConfirm": "Acknowledge this alarm?",
"unackConfirm": "Unacknowledge this alarm?",
"clearConfirm": "Clear this alarm?",
"archiveConfirm": "Archive this alarm? No further operations after archiving.",
"batchAck": "Batch Ack",
"batchClear": "Batch Clear",
"batchArchive": "Batch Archive",
"batchAckConfirm": "Acknowledge {count} selected alarm(s)?",
"batchClearConfirm": "Clear {count} selected alarm(s)?",
"batchArchiveConfirm": "Archive {count} selected alarm(s)? No further operations after archiving.",
"selectFirst": "Please select records first",
"ackSuccess": "Acknowledged",
"unackSuccess": "Unacknowledged",
"clearSuccess": "Cleared",
"archiveSuccess": "Archived"
},
"detail": {
"title": "Alarm Detail",
"basicInfo": "Basic Info",
"propagationPath": "Propagation Path",
"details": "Alarm Details",
"remark": "Process Remark",
"remarkPlaceholder": "Enter remark",
"remarkSaved": "Remark saved",
"history": "History",
"noHistory": "No history records"
}
}
}
}