From 88ab0ca1ab219d3d90f270450069f58d883244b7 Mon Sep 17 00:00:00 2001
From: root <13910913995@163.com>
Date: Tue, 19 May 2026 09:26:51 +0800
Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/app/api/routes/config.py | 22 +++-
backend/app/services/platform_service.py | 119 ++++++++++++++++--
backend/config/channel.json | 2 +-
backend/config/device.json | 10 +-
backend/config/setting.json | 83 ++++++++----
backend/tests/test_api.py | 90 +++++++++++++
...气量测控平台系统需求分析及技术框架设计.md | 116 +++++++++++++++--
frontend/src/views/AlarmHistoryView.vue | 2 +-
frontend/src/views/AlarmSettingView.vue | 2 +-
frontend/src/views/ChannelConfigView.vue | 2 +-
frontend/src/views/ControlView.vue | 2 +-
frontend/src/views/DeviceConfigView.vue | 2 +-
frontend/src/views/StatusView.vue | 2 +-
13 files changed, 395 insertions(+), 59 deletions(-)
diff --git a/backend/app/api/routes/config.py b/backend/app/api/routes/config.py
index ca517ae..e9ecb99 100644
--- a/backend/app/api/routes/config.py
+++ b/backend/app/api/routes/config.py
@@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends, Query
from app.core.response import success_response
from app.core.security import verify_api_token
-from app.schemas.platform import AiAlarmSettingIn, ChannelConfigIn, DeviceConfigIn, LineAlarmSettingIn, SystemConfigIn
+from app.schemas.platform import AiAlarmSettingIn, ChannelConfigIn, DeviceConfigIn, LineAlarmSettingIn, NetConfigItem, SystemConfigIn, UartConfigItem
from app.services.platform_service import platform_service
@@ -21,6 +21,26 @@ def save_device_config(payload: DeviceConfigIn) -> Dict[str, Any]:
return success_response(platform_service.save_device_config(payload))
+@router.get("/device/net", dependencies=[Depends(verify_api_token)])
+def get_net_config(nic: str = Query(..., min_length=1)) -> Dict[str, Any]:
+ return success_response(platform_service.get_net_config(nic=nic), msg="获取网卡配置成功")
+
+
+@router.post("/device/net", dependencies=[Depends(verify_api_token)])
+def save_net_config(payload: NetConfigItem) -> Dict[str, Any]:
+ return success_response(platform_service.save_net_config(payload), msg="保存网卡配置成功")
+
+
+@router.get("/device/uart", dependencies=[Depends(verify_api_token)])
+def get_uart_config(port: str = Query(..., min_length=1)) -> Dict[str, Any]:
+ return success_response(platform_service.get_uart_config(port=port), msg="获取串口配置成功")
+
+
+@router.post("/device/uart", dependencies=[Depends(verify_api_token)])
+def save_uart_config(payload: UartConfigItem) -> Dict[str, Any]:
+ return success_response(platform_service.save_uart_config(payload), msg="保存串口配置成功")
+
+
@router.get("/channel", dependencies=[Depends(verify_api_token)])
def get_channel_config() -> Dict[str, Any]:
return success_response(platform_service.get_channel_config(), msg="获取通道配置成功")
diff --git a/backend/app/services/platform_service.py b/backend/app/services/platform_service.py
index 791dc14..3548393 100644
--- a/backend/app/services/platform_service.py
+++ b/backend/app/services/platform_service.py
@@ -15,9 +15,11 @@ from app.schemas.platform import (
DeviceConfigIn,
DeviceStatus,
LineAlarmSettingIn,
+ NetConfigItem,
RealtimeData,
SwitchControlIn,
SystemConfigIn,
+ UartConfigItem,
)
from app.ws.manager import ws_manager
@@ -44,16 +46,8 @@ class PlatformService:
memory_store.set_status(status)
return status
- def save_device_config(self, payload: DeviceConfigIn) -> Dict[str, Any]:
- data = payload.model_dump()
- data["password"] = hash_password(payload.password)
- path = self.config_repo.write_device_config(data)
- device_result = self.device_client.send_device_config(payload)
- return {"save_path": f"/config/{path.name}", **device_result}
-
- def get_device_config(self) -> Dict[str, Any]:
- current = self.config_repo.read_device_config()
- data = {
+ def _default_device_config(self) -> Dict[str, Any]:
+ return {
"password": "",
"hardware_version": {
"board_version": "B001.001.001",
@@ -74,11 +68,114 @@ class PlatformService:
{"port": "COM2", "baud": 115200, "parity": "NONE", "data_bits": 8, "stop_bits": 1, "protocol": "Modbus RTU"},
],
}
- data.update(current)
+
+ def _merge_keyed_items(self, defaults: List[Dict[str, Any]], current: Any, key_field: str) -> List[Dict[str, Any]]:
+ merged = [dict(item) for item in defaults]
+ if not isinstance(current, list):
+ return merged
+
+ index_map = {
+ item.get(key_field): index
+ for index, item in enumerate(merged)
+ if isinstance(item, dict) and item.get(key_field) is not None
+ }
+ for item in current:
+ if not isinstance(item, dict):
+ continue
+ key = item.get(key_field)
+ if key in index_map:
+ merged[index_map[key]].update(item)
+ else:
+ merged.append(dict(item))
+ return merged
+
+ def _upsert_keyed_item(self, items: List[Dict[str, Any]], payload: Dict[str, Any], key_field: str) -> List[Dict[str, Any]]:
+ key = payload.get(key_field)
+ updated = False
+ for index, item in enumerate(items):
+ if item.get(key_field) == key:
+ items[index] = payload
+ updated = True
+ break
+ if not updated:
+ items.append(payload)
+ return items
+
+ def _find_keyed_item(self, items: List[Dict[str, Any]], key_field: str, key_value: str) -> Optional[Dict[str, Any]]:
+ for item in items:
+ if item.get(key_field) == key_value:
+ return item
+ return None
+
+ def _load_device_config_with_defaults(self) -> Dict[str, Any]:
+ current = self.config_repo.read_device_config()
+ defaults = self._default_device_config()
+ data = {
+ "password": current.get("password", "") if isinstance(current, dict) else "",
+ "hardware_version": dict(defaults["hardware_version"]),
+ "software_version": dict(defaults["software_version"]),
+ "net": [],
+ "uart": [],
+ }
+
+ if isinstance(current, dict):
+ if isinstance(current.get("hardware_version"), dict):
+ data["hardware_version"].update(current["hardware_version"])
+ if isinstance(current.get("software_version"), dict):
+ data["software_version"].update(current["software_version"])
+ data["net"] = self._merge_keyed_items(defaults["net"], current.get("net"), "nic")
+ data["uart"] = self._merge_keyed_items(defaults["uart"], current.get("uart"), "port")
+ else:
+ data["net"] = self._merge_keyed_items(defaults["net"], None, "nic")
+ data["uart"] = self._merge_keyed_items(defaults["uart"], None, "port")
+
+ return data
+
+ def save_device_config(self, payload: DeviceConfigIn) -> Dict[str, Any]:
+ data = self._load_device_config_with_defaults()
+ payload_data = payload.model_dump()
+ data["hardware_version"] = payload_data["hardware_version"]
+ data["software_version"] = payload_data["software_version"]
+ data["net"] = self._merge_keyed_items(data["net"], payload_data["net"], "nic")
+ data["uart"] = self._merge_keyed_items(data["uart"], payload_data["uart"], "port")
+ if payload.password.strip():
+ data["password"] = hash_password(payload.password)
+ path = self.config_repo.write_device_config(data)
+ device_result = self.device_client.send_device_config(payload)
+ return {"save_path": f"/config/{path.name}", **device_result}
+
+ def get_device_config(self) -> Dict[str, Any]:
+ data = self._load_device_config_with_defaults()
# 不返回已保存的哈希密码,避免前端把哈希串直接显示到设置界面
data["password"] = ""
return data
+ def get_net_config(self, nic: str) -> Dict[str, Any]:
+ device_config = self._load_device_config_with_defaults()
+ item = self._find_keyed_item(device_config["net"], "nic", nic)
+ if item is not None:
+ return item
+ return {"nic": nic, "ip": "", "mask": "", "gateway": "", "protocol": ""}
+
+ def save_net_config(self, payload: NetConfigItem) -> Dict[str, Any]:
+ device_config = self._load_device_config_with_defaults()
+ device_config["net"] = self._upsert_keyed_item(device_config["net"], payload.model_dump(), "nic")
+ path = self.config_repo.write_device_config(device_config)
+ return {"save_path": f"/config/{path.name}", "target": "net", "nic": payload.nic, "send_status": "成功"}
+
+ def get_uart_config(self, port: str) -> Dict[str, Any]:
+ device_config = self._load_device_config_with_defaults()
+ item = self._find_keyed_item(device_config["uart"], "port", port)
+ if item is not None:
+ return item
+ return {"port": port, "baud": 9600, "parity": "NONE", "data_bits": 8, "stop_bits": 1, "protocol": ""}
+
+ def save_uart_config(self, payload: UartConfigItem) -> Dict[str, Any]:
+ device_config = self._load_device_config_with_defaults()
+ device_config["uart"] = self._upsert_keyed_item(device_config["uart"], payload.model_dump(), "port")
+ path = self.config_repo.write_device_config(device_config)
+ return {"save_path": f"/config/{path.name}", "target": "uart", "port": payload.port, "send_status": "成功"}
+
def save_channel_config(self, payload: ChannelConfigIn) -> Dict[str, Any]:
path = self.config_repo.write_channel_config(payload.model_dump())
device_result = self.device_client.send_channel_config(payload)
diff --git a/backend/config/channel.json b/backend/config/channel.json
index 2043af2..8b66336 100644
--- a/backend/config/channel.json
+++ b/backend/config/channel.json
@@ -3,7 +3,7 @@
{
"ch": 1,
"singal_type": "1-5v",
- "line_no": 2,
+ "line_no": 1,
"type": "UA",
"limit_low": 0.0,
"limit_high": 20.0
diff --git a/backend/config/device.json b/backend/config/device.json
index c501daf..add360f 100644
--- a/backend/config/device.json
+++ b/backend/config/device.json
@@ -1,7 +1,7 @@
{
- "password": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
+ "password": "ac9689e2272427085e35b9d3e3e8bed88cb3434828b43b86fc0596cad4c6e270",
"hardware_version": {
- "board_version": "B001.001.002",
+ "board_version": "B001.001.001",
"display_version": "S001.001.001",
"other_version": "Y001.001.001"
},
@@ -29,15 +29,15 @@
"uart": [
{
"port": "COM1",
- "baud": 9600,
+ "baud": 19200,
"parity": "NONE",
"data_bits": 8,
"stop_bits": 1,
- "protocol": ""
+ "protocol": "Modbus RTU"
},
{
"port": "COM2",
- "baud": 115200,
+ "baud": 19200,
"parity": "NONE",
"data_bits": 8,
"stop_bits": 1,
diff --git a/backend/config/setting.json b/backend/config/setting.json
index 8960fed..b093bd8 100644
--- a/backend/config/setting.json
+++ b/backend/config/setting.json
@@ -1,29 +1,62 @@
{
- "line_alarm_setting":
- [
+ "line_alarm_setting": [
{
- "line_no": 1,
- "over_limit_alarm": [
- {
- "category": "??",
- "limit": 180.0,
- "delay": 180,
- "output_node": "??1",
- "enabled": true
- }
- ],
- "fault_alarm": [
- {
- "category": "PT??",
- "limit": null,
- "delay": 180,
- "output_node": "??1",
- "enabled": true
- }
- ]
- }
- ]
- ,
+ "line_no": 1,
+ "over_limit_alarm": [
+ {
+ "category": "电压",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "开出1",
+ "enabled": true
+ },
+ {
+ "category": "电流",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "开出2",
+ "enabled": true
+ },
+ {
+ "category": "差流",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "",
+ "enabled": false
+ },
+ {
+ "category": "功率",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "",
+ "enabled": false
+ },
+ {
+ "category": "频率",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "",
+ "enabled": false
+ }
+ ],
+ "fault_alarm": [
+ {
+ "category": "PT断线",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "",
+ "enabled": false
+ },
+ {
+ "category": "CT断线",
+ "limit": 0.0,
+ "delay": 0,
+ "output_node": "",
+ "enabled": false
+ }
+ ]
+ }
+ ],
"ai_alarm_setting": [
{
"channel_no": 1,
@@ -135,7 +168,7 @@
}
],
"system_config": {
- "time_sync": "manual",
+ "time_sync": "2026-05-18 17:05:28",
"brightness": 83,
"screen_saver": 120
}
diff --git a/backend/tests/test_api.py b/backend/tests/test_api.py
index 8ccfb5e..79995d2 100644
--- a/backend/tests/test_api.py
+++ b/backend/tests/test_api.py
@@ -124,12 +124,16 @@ def test_config_query_endpoints(tmp_path) -> None:
headers = {"X-API-Token": settings.auth_password}
device_response = client.get("/api/config/device", headers=headers)
+ net_response = client.get("/api/config/device/net", headers=headers, params={"nic": "网卡一"})
+ uart_response = client.get("/api/config/device/uart", headers=headers, params={"port": "COM1"})
channel_response = client.get("/api/config/channel", headers=headers)
line_alarm_response = client.get("/api/config/line_alarm_setting", headers=headers, params={"line_no": 2})
ai_alarm_response = client.get("/api/config/ai_alarm_setting", headers=headers)
system_response = client.get("/api/config/system", headers=headers)
assert device_response.status_code == 200
+ assert net_response.status_code == 200
+ assert uart_response.status_code == 200
assert channel_response.status_code == 200
assert line_alarm_response.status_code == 200
assert ai_alarm_response.status_code == 200
@@ -137,6 +141,8 @@ def test_config_query_endpoints(tmp_path) -> None:
assert device_response.json()["data"]["password"] == ""
assert device_response.json()["data"]["net"][0]["ip"] == "192.168.1.10"
+ assert net_response.json()["data"]["nic"] == "网卡一"
+ assert uart_response.json()["data"]["port"] == "COM1"
assert channel_response.json()["data"]["ai_channel"][0]["singal_type"] == "4-20mA"
assert line_alarm_response.json()["data"]["line_no"] == 2
assert line_alarm_response.json()["data"]["over_limit_alarm"][0]["category"] == "电流"
@@ -169,3 +175,87 @@ def test_save_line_alarm_setting_stores_list(tmp_path) -> None:
assert saved["line_alarm_setting"][0]["line_no"] == 3
finally:
platform_service.config_repo = old_repo
+
+
+def test_save_device_net_and_uart_by_key(tmp_path) -> None:
+ old_repo = platform_service.config_repo
+ platform_service.config_repo = JsonConfigRepository(tmp_path)
+
+ try:
+ platform_service.config_repo.write_device_config(
+ {
+ "password": "hashed-password",
+ "hardware_version": {
+ "board_version": "B001.001.001",
+ "display_version": "S001.001.001",
+ "other_version": "Y001.001.001",
+ },
+ "software_version": {
+ "display_program": "001.001.001",
+ "communication_program": "001.001.001",
+ "measurement_program": "001.001.001",
+ },
+ "net": [
+ {"nic": "网卡一", "ip": "192.168.1.10", "mask": "255.255.255.0", "gateway": "192.168.1.1", "protocol": "Modbus TCP"},
+ {"nic": "网卡二", "ip": "192.168.1.56", "mask": "255.255.255.255", "gateway": "192.168.1.56", "protocol": "Modbus TCP"},
+ ],
+ "uart": [
+ {"port": "COM1", "baud": 9600, "parity": "NONE", "data_bits": 8, "stop_bits": 1, "protocol": ""},
+ {"port": "COM2", "baud": 115200, "parity": "NONE", "data_bits": 8, "stop_bits": 1, "protocol": "Modbus RTU"},
+ ],
+ }
+ )
+
+ headers = {"X-API-Token": settings.auth_password}
+
+ net_save = client.post(
+ "/api/config/device/net",
+ headers=headers,
+ json={"nic": "网卡二", "ip": "10.10.10.2", "mask": "255.255.255.0", "gateway": "10.10.10.1", "protocol": "IEC104"},
+ )
+ uart_save = client.post(
+ "/api/config/device/uart",
+ headers=headers,
+ json={"port": "COM2", "baud": 4800, "parity": "EVEN", "data_bits": 8, "stop_bits": 1, "protocol": "DLT645"},
+ )
+ full_save = client.post(
+ "/api/config/device",
+ headers=headers,
+ json={
+ "password": "",
+ "hardware_version": {
+ "board_version": "B001.001.003",
+ "display_version": "S001.001.001",
+ "other_version": "Y001.001.001",
+ },
+ "software_version": {
+ "display_program": "001.001.001",
+ "communication_program": "001.001.001",
+ "measurement_program": "001.001.001",
+ },
+ "net": [
+ {"nic": "网卡一", "ip": "172.16.1.10", "mask": "255.255.255.0", "gateway": "172.16.1.1", "protocol": "Modbus TCP"}
+ ],
+ "uart": [
+ {"port": "COM1", "baud": 19200, "parity": "ODD", "data_bits": 8, "stop_bits": 1, "protocol": "Modbus RTU"}
+ ],
+ },
+ )
+
+ assert net_save.status_code == 200
+ assert uart_save.status_code == 200
+ assert full_save.status_code == 200
+
+ saved = platform_service.config_repo.read_device_config()
+ net_map = {item["nic"]: item for item in saved["net"]}
+ uart_map = {item["port"]: item for item in saved["uart"]}
+
+ assert net_map["网卡一"]["ip"] == "172.16.1.10"
+ assert net_map["网卡二"]["ip"] == "10.10.10.2"
+ assert net_map["网卡二"]["protocol"] == "IEC104"
+ assert uart_map["COM1"]["baud"] == 19200
+ assert uart_map["COM2"]["baud"] == 4800
+ assert uart_map["COM2"]["protocol"] == "DLT645"
+ assert saved["password"] == "hashed-password"
+ finally:
+ platform_service.config_repo = old_repo
diff --git a/document/电气量测控平台系统需求分析及技术框架设计.md b/document/电气量测控平台系统需求分析及技术框架设计.md
index 1f03491..594541c 100644
--- a/document/电气量测控平台系统需求分析及技术框架设计.md
+++ b/document/电气量测控平台系统需求分析及技术框架设计.md
@@ -369,6 +369,11 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
}
```
+说明:
+- `net` 按 `nic` 标识各网卡配置
+- `uart` 按 `port` 标识各串口配置
+- 界面如需按单个网卡或单个串口精确读取,可调用后续独立查询接口
+
***
#### 4. POST /api/config/device
@@ -428,9 +433,100 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
**返回data**:`{"save_path":"/config/device.json","send_status":"成功"}`
+说明:
+- 设备整体保存时,网卡配置按 `nic` 合并更新
+- 串口配置按 `port` 合并更新
+- 未出现在本次提交中的其他网卡或串口配置会保留,不会因数组顺序变化被误覆盖
+
***
-#### 5. GET /api/config/channel
+#### 5. GET /api/config/device/net
+
+**作用**:按网卡标识读取单个网卡配置
+**参数**:
+- `nic=网卡一`:按 `nic` 查询对应网卡信息
+**返回data**:
+
+```json
+{
+ "nic": "网卡一",
+ "ip": "192.168.1.10",
+ "mask": "255.255.255.0",
+ "gateway": "192.168.1.1",
+ "protocol": "Modbus TCP"
+}
+```
+
+***
+
+#### 6. POST /api/config/device/net
+
+**作用**:按网卡标识保存单个网卡配置
+**请求body参数**:
+
+```json
+{
+ "nic": "网卡一",
+ "ip": "192.168.1.10",
+ "mask": "255.255.255.0",
+ "gateway": "192.168.1.1",
+ "protocol": "Modbus TCP"
+}
+```
+
+**返回data**:`{"save_path":"/config/device.json","target":"net","nic":"网卡一","send_status":"成功"}`
+
+说明:
+- 服务端会根据 `nic` 更新对应网卡对象
+- 若不存在相同 `nic`,则追加到 `net` 数组
+
+***
+
+#### 7. GET /api/config/device/uart
+
+**作用**:按串口标识读取单个串口配置
+**参数**:
+- `port=COM1`:按 `port` 查询对应串口信息
+**返回data**:
+
+```json
+{
+ "port": "COM1",
+ "baud": 9600,
+ "parity": "NONE",
+ "data_bits": 8,
+ "stop_bits": 1,
+ "protocol": "Modbus RTU"
+}
+```
+
+***
+
+#### 8. POST /api/config/device/uart
+
+**作用**:按串口标识保存单个串口配置
+**请求body参数**:
+
+```json
+{
+ "port": "COM1",
+ "baud": 9600,
+ "parity": "NONE",
+ "data_bits": 8,
+ "stop_bits": 1,
+ "protocol": "Modbus RTU"
+}
+```
+
+**返回data**:`{"save_path":"/config/device.json","target":"uart","port":"COM1","send_status":"成功"}`
+
+说明:
+- 服务端会根据 `port` 更新对应串口对象
+- 若不存在相同 `port`,则追加到 `uart` 数组
+
+***
+
+#### 9. GET /api/config/channel
**作用**:读取通道配置,用于通道配置界面打开时回显当前参数
**参数**:无
@@ -445,7 +541,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 6. POST /api/config/channel
+#### 10. POST /api/config/channel
**作用**:提交AI/AO通道配置(AI:12通道,AO:12通道)
**请求body参数**:
@@ -461,7 +557,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 7. GET /api/config/line\_alarm\_setting
+#### 11. GET /api/config/line\_alarm\_setting
**作用**:读取线路报警设置,用于报警设置界面打开时回显当前线路参数
**参数**:
@@ -493,7 +589,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 8. POST /api/config/line\_alarm\_setting
+#### 12. POST /api/config/line\_alarm\_setting
**作用**:提交定值报警阈值配置
**请求body参数**:
@@ -564,7 +660,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 9. GET /api/config/ai\_alarm\_setting
+#### 13. GET /api/config/ai\_alarm\_setting
**作用**:读取AI报警设置,用于报警设置界面打开时回显当前AI报警参数
**参数**:无
@@ -586,7 +682,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 10. POST /api/config/ai\_alarm\_setting
+#### 14. POST /api/config/ai\_alarm\_setting
**作用**:提交AI报警设置
**请求body参数**:
@@ -616,7 +712,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
**返回data**:`{"save_path":"/config/setting.json","send_status":"成功"}`
-#### 11. GET /api/config/system
+#### 15. GET /api/config/system
**作用**:读取系统设置,用于系统设置界面打开时回显当前参数
**参数**:无
@@ -632,7 +728,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 12. POST /api/config/system
+#### 16. POST /api/config/system
**作用**:提交系统对时、灯光配置
**请求body参数**:
@@ -649,7 +745,7 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
***
-#### 13. GET /api/alarm/list
+#### 17. GET /api/alarm/list
**作用**:分页查询历史报警
**参数**:
@@ -691,7 +787,7 @@ GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:3
***
-#### 14. POST /api/control/switch
+#### 18. POST /api/control/switch
**作用**:下发开关量控制指令
**请求body参数**:
diff --git a/frontend/src/views/AlarmHistoryView.vue b/frontend/src/views/AlarmHistoryView.vue
index a745dc2..288cb3a 100644
--- a/frontend/src/views/AlarmHistoryView.vue
+++ b/frontend/src/views/AlarmHistoryView.vue
@@ -1,4 +1,4 @@
-
diff --git a/frontend/src/views/AlarmSettingView.vue b/frontend/src/views/AlarmSettingView.vue
index c67aeea..c187513 100644
--- a/frontend/src/views/AlarmSettingView.vue
+++ b/frontend/src/views/AlarmSettingView.vue
@@ -1,4 +1,4 @@
-