增加了配置查询功能,解决websocket推送问题。
This commit is contained in:
parent
b8974dce59
commit
622fff10fe
@ -1,3 +1,6 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Query
|
from fastapi import APIRouter, Query
|
||||||
|
|
||||||
from app.core.response import success_response
|
from app.core.response import success_response
|
||||||
@ -8,6 +11,20 @@ router = APIRouter(prefix="/alarm", tags=["alarm"])
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/list")
|
@router.get("/list")
|
||||||
def list_alarms(page: int = Query(default=1, ge=1), size: int = Query(default=20, ge=1, le=100)) -> dict:
|
def list_alarms(
|
||||||
data = platform_service.list_alarms(page=page, size=size)
|
page: int = Query(default=1, ge=1),
|
||||||
|
size: int = Query(default=20, ge=1, le=100),
|
||||||
|
no: Optional[str] = Query(default=None),
|
||||||
|
type: Optional[str] = Query(default=None),
|
||||||
|
start_time: Optional[datetime] = Query(default=None),
|
||||||
|
end_time: Optional[datetime] = Query(default=None),
|
||||||
|
) -> dict:
|
||||||
|
data = platform_service.list_alarms(
|
||||||
|
page=page,
|
||||||
|
size=size,
|
||||||
|
no=no,
|
||||||
|
alarm_type=type,
|
||||||
|
start_time=start_time,
|
||||||
|
end_time=end_time,
|
||||||
|
)
|
||||||
return success_response(data, msg="获取报警历史成功")
|
return success_response(data, msg="获取报警历史成功")
|
||||||
|
|||||||
@ -11,26 +11,51 @@ from app.services.platform_service import platform_service
|
|||||||
router = APIRouter(prefix="/config", tags=["config"])
|
router = APIRouter(prefix="/config", tags=["config"])
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/device", dependencies=[Depends(verify_api_token)])
|
||||||
|
def get_device_config() -> Dict[str, Any]:
|
||||||
|
return success_response(platform_service.get_device_config(), msg="获取设备配置成功")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/device", dependencies=[Depends(verify_api_token)])
|
@router.post("/device", dependencies=[Depends(verify_api_token)])
|
||||||
def save_device_config(payload: DeviceConfigIn) -> Dict[str, Any]:
|
def save_device_config(payload: DeviceConfigIn) -> Dict[str, Any]:
|
||||||
return success_response(platform_service.save_device_config(payload))
|
return success_response(platform_service.save_device_config(payload))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/channel", dependencies=[Depends(verify_api_token)])
|
||||||
|
def get_channel_config() -> Dict[str, Any]:
|
||||||
|
return success_response(platform_service.get_channel_config(), msg="获取通道配置成功")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/channel", dependencies=[Depends(verify_api_token)])
|
@router.post("/channel", dependencies=[Depends(verify_api_token)])
|
||||||
def save_channel_config(payload: ChannelConfigIn) -> Dict[str, Any]:
|
def save_channel_config(payload: ChannelConfigIn) -> Dict[str, Any]:
|
||||||
return success_response(platform_service.save_channel_config(payload))
|
return success_response(platform_service.save_channel_config(payload))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/line_alarm_setting", dependencies=[Depends(verify_api_token)])
|
||||||
|
def get_line_alarm_setting() -> Dict[str, Any]:
|
||||||
|
return success_response(platform_service.get_line_alarm_setting(), msg="获取线路报警设置成功")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/line_alarm_setting", dependencies=[Depends(verify_api_token)])
|
@router.post("/line_alarm_setting", dependencies=[Depends(verify_api_token)])
|
||||||
def save_line_alarm_setting(payload: LineAlarmSettingIn) -> Dict[str, Any]:
|
def save_line_alarm_setting(payload: LineAlarmSettingIn) -> Dict[str, Any]:
|
||||||
return success_response(platform_service.save_line_alarm_setting(payload))
|
return success_response(platform_service.save_line_alarm_setting(payload))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/ai_alarm_setting", dependencies=[Depends(verify_api_token)])
|
||||||
|
def get_ai_alarm_setting() -> Dict[str, Any]:
|
||||||
|
return success_response(platform_service.get_ai_alarm_setting(), msg="获取AI报警设置成功")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/ai_alarm_setting", dependencies=[Depends(verify_api_token)])
|
@router.post("/ai_alarm_setting", dependencies=[Depends(verify_api_token)])
|
||||||
def save_ai_alarm_setting(payload: List[AiAlarmSettingIn]) -> Dict[str, Any]:
|
def save_ai_alarm_setting(payload: List[AiAlarmSettingIn]) -> Dict[str, Any]:
|
||||||
return success_response(platform_service.save_ai_alarm_setting(payload))
|
return success_response(platform_service.save_ai_alarm_setting(payload))
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/system", dependencies=[Depends(verify_api_token)])
|
||||||
|
def get_system_config() -> Dict[str, Any]:
|
||||||
|
return success_response(platform_service.get_system_config(), msg="获取系统设置成功")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/system", dependencies=[Depends(verify_api_token)])
|
@router.post("/system", dependencies=[Depends(verify_api_token)])
|
||||||
def save_system_config(payload: SystemConfigIn) -> Dict[str, Any]:
|
def save_system_config(payload: SystemConfigIn) -> Dict[str, Any]:
|
||||||
return success_response(platform_service.save_system_config(payload))
|
return success_response(platform_service.save_system_config(payload))
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Dict, List
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from app.db.sqlite import get_connection
|
from app.db.sqlite import get_connection
|
||||||
from app.schemas.platform import AlarmEvent
|
from app.schemas.platform import AlarmEvent
|
||||||
@ -26,16 +27,45 @@ class AlarmRepository:
|
|||||||
connection.commit()
|
connection.commit()
|
||||||
return int(cursor.lastrowid)
|
return int(cursor.lastrowid)
|
||||||
|
|
||||||
def list_alarms(self, page: int = 1, size: int = 20) -> List[Dict[str, Any]]:
|
def list_alarms(
|
||||||
|
self,
|
||||||
|
page: int = 1,
|
||||||
|
size: int = 20,
|
||||||
|
no: str = "",
|
||||||
|
alarm_type: str = "",
|
||||||
|
start_time: Optional[datetime] = None,
|
||||||
|
end_time: Optional[datetime] = None,
|
||||||
|
) -> List[Dict[str, Any]]:
|
||||||
offset = (page - 1) * size
|
offset = (page - 1) * size
|
||||||
|
conditions = []
|
||||||
|
params: List[Any] = []
|
||||||
|
|
||||||
|
if no:
|
||||||
|
conditions.append("no = ?")
|
||||||
|
params.append(no)
|
||||||
|
if alarm_type:
|
||||||
|
conditions.append("type = ?")
|
||||||
|
params.append(alarm_type)
|
||||||
|
if start_time is not None:
|
||||||
|
conditions.append("time >= ?")
|
||||||
|
params.append(start_time.isoformat(sep=" ", timespec="seconds"))
|
||||||
|
if end_time is not None:
|
||||||
|
conditions.append("time <= ?")
|
||||||
|
params.append(end_time.isoformat(sep=" ", timespec="seconds"))
|
||||||
|
|
||||||
|
where_clause = ""
|
||||||
|
if conditions:
|
||||||
|
where_clause = "WHERE " + " AND ".join(conditions)
|
||||||
|
|
||||||
with get_connection() as connection:
|
with get_connection() as connection:
|
||||||
cursor = connection.execute(
|
cursor = connection.execute(
|
||||||
"""
|
f"""
|
||||||
SELECT id, alarm_type, time, no, type, content, level
|
SELECT id, alarm_type, time, no, type, content, level
|
||||||
FROM alarm_event
|
FROM alarm_event
|
||||||
|
{where_clause}
|
||||||
ORDER BY id DESC
|
ORDER BY id DESC
|
||||||
LIMIT ? OFFSET ?
|
LIMIT ? OFFSET ?
|
||||||
""",
|
""",
|
||||||
(size, offset),
|
tuple(params + [size, offset]),
|
||||||
)
|
)
|
||||||
return [dict(row) for row in cursor.fetchall()]
|
return [dict(row) for row in cursor.fetchall()]
|
||||||
|
|||||||
@ -31,6 +31,21 @@ class JsonConfigRepository:
|
|||||||
def write_setting_config(self, payload: Dict[str, Any]) -> Path:
|
def write_setting_config(self, payload: Dict[str, Any]) -> Path:
|
||||||
return self._write_json("setting.json", payload)
|
return self._write_json("setting.json", payload)
|
||||||
|
|
||||||
|
def read_device_config(self) -> Dict[str, Any]:
|
||||||
|
data = self.read_json("device.json")
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
|
||||||
|
def read_channel_config(self) -> Dict[str, Any]:
|
||||||
|
data = self.read_json("channel.json")
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
|
||||||
|
def read_setting_config(self) -> Dict[str, Any]:
|
||||||
|
data = self.read_json("setting.json")
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
|
||||||
|
def read_setting_section(self, section: str) -> Any:
|
||||||
|
return self.read_setting_config().get(section)
|
||||||
|
|
||||||
def read_json(self, filename: str) -> Union[Dict[str, Any], List[Any]]:
|
def read_json(self, filename: str) -> Union[Dict[str, Any], List[Any]]:
|
||||||
path = self.config_dir / filename
|
path = self.config_dir / filename
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any, Dict, List
|
from datetime import datetime
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from app.adapters.device_client import CDeviceClient, MockDeviceClient
|
from app.adapters.device_client import CDeviceClient, MockDeviceClient
|
||||||
from app.cache.memory_store import memory_store
|
from app.cache.memory_store import memory_store
|
||||||
@ -50,11 +51,48 @@ class PlatformService:
|
|||||||
device_result = self.device_client.send_device_config(payload)
|
device_result = self.device_client.send_device_config(payload)
|
||||||
return {"save_path": f"/config/{path.name}", **device_result}
|
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 = {
|
||||||
|
"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"},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
data.update(current)
|
||||||
|
# 不返回已保存的哈希密码,避免前端把哈希串直接显示到设置界面
|
||||||
|
data["password"] = ""
|
||||||
|
return data
|
||||||
|
|
||||||
def save_channel_config(self, payload: ChannelConfigIn) -> Dict[str, Any]:
|
def save_channel_config(self, payload: ChannelConfigIn) -> Dict[str, Any]:
|
||||||
path = self.config_repo.write_channel_config(payload.model_dump())
|
path = self.config_repo.write_channel_config(payload.model_dump())
|
||||||
device_result = self.device_client.send_channel_config(payload)
|
device_result = self.device_client.send_channel_config(payload)
|
||||||
return {"save_path": f"/config/{path.name}", **device_result}
|
return {"save_path": f"/config/{path.name}", **device_result}
|
||||||
|
|
||||||
|
def get_channel_config(self) -> Dict[str, Any]:
|
||||||
|
current = self.config_repo.read_channel_config()
|
||||||
|
data = {
|
||||||
|
"ai_channel": [{"ch": 1, "singal_type": "4-20mA", "line_no": 1, "type": "UA", "limit_low": 0, "limit_high": 20}],
|
||||||
|
"ao_channel": [{"ch": 1, "singal_type": "1-5v", "line_no": 2, "type": "UA", "limit_low": 0, "limit_high": 20}],
|
||||||
|
}
|
||||||
|
data.update(current)
|
||||||
|
return data
|
||||||
|
|
||||||
def save_line_alarm_setting(self, payload: LineAlarmSettingIn) -> Dict[str, Any]:
|
def save_line_alarm_setting(self, payload: LineAlarmSettingIn) -> Dict[str, Any]:
|
||||||
current = self.config_repo.read_json("setting.json")
|
current = self.config_repo.read_json("setting.json")
|
||||||
if not isinstance(current, dict):
|
if not isinstance(current, dict):
|
||||||
@ -64,6 +102,21 @@ class PlatformService:
|
|||||||
device_result = self.device_client.send_line_alarm_setting(payload)
|
device_result = self.device_client.send_line_alarm_setting(payload)
|
||||||
return {"save_path": f"/config/{path.name}", **device_result}
|
return {"save_path": f"/config/{path.name}", **device_result}
|
||||||
|
|
||||||
|
def get_line_alarm_setting(self) -> Dict[str, Any]:
|
||||||
|
current = self.config_repo.read_setting_section("line_alarm_setting")
|
||||||
|
if isinstance(current, dict):
|
||||||
|
return current
|
||||||
|
return {
|
||||||
|
"line_no": 1,
|
||||||
|
"over_limit_alarm": [
|
||||||
|
{"category": "电压", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True},
|
||||||
|
{"category": "电流", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True},
|
||||||
|
{"category": "差流", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": False},
|
||||||
|
{"category": "频率", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": False},
|
||||||
|
],
|
||||||
|
"fault_alarm": [{"category": "PT断线", "delay": 180, "output_node": "开出1", "enabled": True}],
|
||||||
|
}
|
||||||
|
|
||||||
def save_ai_alarm_setting(self, payload: List[AiAlarmSettingIn]) -> Dict[str, Any]:
|
def save_ai_alarm_setting(self, payload: List[AiAlarmSettingIn]) -> Dict[str, Any]:
|
||||||
current = self.config_repo.read_json("setting.json")
|
current = self.config_repo.read_json("setting.json")
|
||||||
if not isinstance(current, dict):
|
if not isinstance(current, dict):
|
||||||
@ -73,6 +126,22 @@ class PlatformService:
|
|||||||
device_result = self.device_client.send_ai_alarm_setting(current["ai_alarm_setting"])
|
device_result = self.device_client.send_ai_alarm_setting(current["ai_alarm_setting"])
|
||||||
return {"save_path": f"/config/{path.name}", **device_result}
|
return {"save_path": f"/config/{path.name}", **device_result}
|
||||||
|
|
||||||
|
def get_ai_alarm_setting(self) -> List[Dict[str, Any]]:
|
||||||
|
current = self.config_repo.read_setting_section("ai_alarm_setting")
|
||||||
|
if isinstance(current, list):
|
||||||
|
return current
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"channel_no": 1,
|
||||||
|
"singal_type": "4-20mA",
|
||||||
|
"limit_low": 0,
|
||||||
|
"limit_high": 20,
|
||||||
|
"delay": 180,
|
||||||
|
"output_node": "开出1",
|
||||||
|
"enabled": True,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
def save_system_config(self, payload: SystemConfigIn) -> Dict[str, Any]:
|
def save_system_config(self, payload: SystemConfigIn) -> Dict[str, Any]:
|
||||||
current = self.config_repo.read_json("setting.json")
|
current = self.config_repo.read_json("setting.json")
|
||||||
if not isinstance(current, dict):
|
if not isinstance(current, dict):
|
||||||
@ -81,8 +150,30 @@ class PlatformService:
|
|||||||
self.config_repo.write_setting_config(current)
|
self.config_repo.write_setting_config(current)
|
||||||
return self.device_client.send_system_config(payload)
|
return self.device_client.send_system_config(payload)
|
||||||
|
|
||||||
def list_alarms(self, page: int, size: int) -> List[Dict[str, Any]]:
|
def get_system_config(self) -> Dict[str, Any]:
|
||||||
return self.alarm_repo.list_alarms(page=page, size=size)
|
current = self.config_repo.read_setting_section("system_config")
|
||||||
|
data = SystemConfigIn().model_dump()
|
||||||
|
if isinstance(current, dict):
|
||||||
|
data.update(current)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def list_alarms(
|
||||||
|
self,
|
||||||
|
page: int,
|
||||||
|
size: int,
|
||||||
|
no: str = "",
|
||||||
|
alarm_type: str = "",
|
||||||
|
start_time: Optional[datetime] = None,
|
||||||
|
end_time: Optional[datetime] = None,
|
||||||
|
) -> List[Dict[str, Any]]:
|
||||||
|
return self.alarm_repo.list_alarms(
|
||||||
|
page=page,
|
||||||
|
size=size,
|
||||||
|
no=no,
|
||||||
|
alarm_type=alarm_type,
|
||||||
|
start_time=start_time,
|
||||||
|
end_time=end_time,
|
||||||
|
)
|
||||||
|
|
||||||
def switch_control(self, payload: SwitchControlIn) -> Dict[str, Any]:
|
def switch_control(self, payload: SwitchControlIn) -> Dict[str, Any]:
|
||||||
return self.device_client.send_switch_control(payload)
|
return self.device_client.send_switch_control(payload)
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.db.sqlite import get_connection, init_db
|
||||||
from app.main import app
|
from app.main import app
|
||||||
|
from app.repositories.alarm_repo import AlarmRepository
|
||||||
|
from app.repositories.json_config_repo import JsonConfigRepository
|
||||||
|
from app.schemas.platform import AlarmEvent
|
||||||
|
from app.services.platform_service import platform_service
|
||||||
|
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
@ -18,3 +26,117 @@ def test_realtime_endpoint() -> None:
|
|||||||
payload = response.json()
|
payload = response.json()
|
||||||
assert payload["code"] == 200
|
assert payload["code"] == 200
|
||||||
assert "line_list" in payload["data"]
|
assert "line_list" in payload["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_alarm_list_filters(tmp_path) -> None:
|
||||||
|
settings.alarm_db_path = tmp_path / "alarm.db"
|
||||||
|
init_db()
|
||||||
|
|
||||||
|
with get_connection() as connection:
|
||||||
|
connection.execute("DELETE FROM alarm_event")
|
||||||
|
connection.commit()
|
||||||
|
|
||||||
|
repo = AlarmRepository()
|
||||||
|
repo.save_alarm(
|
||||||
|
AlarmEvent(
|
||||||
|
alarm_type="保护报警",
|
||||||
|
time=datetime(2026, 5, 16, 10, 0, 0),
|
||||||
|
no="L1",
|
||||||
|
type="voltage",
|
||||||
|
content="A 相过压",
|
||||||
|
level="严重",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
repo.save_alarm(
|
||||||
|
AlarmEvent(
|
||||||
|
alarm_type="状态报警",
|
||||||
|
time=datetime(2026, 5, 16, 11, 0, 0),
|
||||||
|
no="L2",
|
||||||
|
type="current",
|
||||||
|
content="B 相过流",
|
||||||
|
level="一般",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.get(
|
||||||
|
"/api/alarm/list",
|
||||||
|
params={
|
||||||
|
"page": 1,
|
||||||
|
"size": 20,
|
||||||
|
"no": "L2",
|
||||||
|
"type": "current",
|
||||||
|
"start_time": "2026-05-16T10:30:00",
|
||||||
|
"end_time": "2026-05-16T11:30:00",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
payload = response.json()
|
||||||
|
assert payload["code"] == 200
|
||||||
|
assert len(payload["data"]) == 1
|
||||||
|
assert payload["data"][0]["no"] == "L2"
|
||||||
|
assert payload["data"][0]["type"] == "current"
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_query_endpoints(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.002",
|
||||||
|
"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"}
|
||||||
|
],
|
||||||
|
"uart": [
|
||||||
|
{"port": "COM1", "baud": 9600, "parity": "NONE", "data_bits": 8, "stop_bits": 1, "protocol": "Modbus RTU"}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
platform_service.config_repo.write_channel_config(
|
||||||
|
{
|
||||||
|
"ai_channel": [{"ch": 1, "singal_type": "4-20mA", "line_no": 1, "type": "UA", "limit_low": 0, "limit_high": 20}],
|
||||||
|
"ao_channel": [{"ch": 1, "singal_type": "1-5v", "line_no": 2, "type": "UA", "limit_low": 0, "limit_high": 20}],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
platform_service.config_repo.write_setting_config(
|
||||||
|
{
|
||||||
|
"line_alarm_setting": {"line_no": 1, "over_limit_alarm": [{"category": "电压", "limit": 180, "delay": 180, "output_node": "开出1", "enabled": True}], "fault_alarm": []},
|
||||||
|
"ai_alarm_setting": [{"channel_no": 1, "singal_type": "4-20mA", "limit_low": 0, "limit_high": 20, "delay": 180, "output_node": "开出1", "enabled": True}],
|
||||||
|
"system_config": {"time_sync": "manual", "brightness": 83, "screen_saver": 60},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
headers = {"X-API-Token": settings.auth_password}
|
||||||
|
|
||||||
|
device_response = client.get("/api/config/device", headers=headers)
|
||||||
|
channel_response = client.get("/api/config/channel", headers=headers)
|
||||||
|
line_alarm_response = client.get("/api/config/line_alarm_setting", headers=headers)
|
||||||
|
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 channel_response.status_code == 200
|
||||||
|
assert line_alarm_response.status_code == 200
|
||||||
|
assert ai_alarm_response.status_code == 200
|
||||||
|
assert system_response.status_code == 200
|
||||||
|
|
||||||
|
assert device_response.json()["data"]["password"] == ""
|
||||||
|
assert device_response.json()["data"]["net"][0]["ip"] == "192.168.1.10"
|
||||||
|
assert channel_response.json()["data"]["ai_channel"][0]["singal_type"] == "4-20mA"
|
||||||
|
assert line_alarm_response.json()["data"]["line_no"] == 1
|
||||||
|
assert ai_alarm_response.json()["data"][0]["channel_no"] == 1
|
||||||
|
assert system_response.json()["data"]["brightness"] == 83
|
||||||
|
finally:
|
||||||
|
platform_service.config_repo = old_repo
|
||||||
|
|||||||
@ -34,6 +34,9 @@
|
|||||||
3. **系统管理配置**
|
3. **系统管理配置**
|
||||||
- 对时设置:参数实时下发嵌入式程序
|
- 对时设置:参数实时下发嵌入式程序
|
||||||
- 灯光设置:屏幕亮度、屏保时间,参数实时下发嵌入式程序
|
- 灯光设置:屏幕亮度、屏保时间,参数实时下发嵌入式程序
|
||||||
|
4. **配置回显要求**
|
||||||
|
- 设备网络配置、通道配置、报警设置、系统设置页面在打开时需先读取已保存参数
|
||||||
|
- 已保存配置从本地JSON文件读取,并通过HTTP查询接口返回给Web界面显示
|
||||||
|
|
||||||
#### 2.2.2 实时数据动态显示功能
|
#### 2.2.2 实时数据动态显示功能
|
||||||
1. **数据读取周期**:间隔**0.5秒**从C语言控制系统读取实时数据
|
1. **数据读取周期**:间隔**0.5秒**从C语言控制系统读取实时数据
|
||||||
@ -126,6 +129,8 @@ Python FastAPI服务层(RESTful接口 + WebSocket推送 + 数据处理)
|
|||||||
Web界面 → HTTP POST → Python → JSON存储 + 下发C程序
|
Web界面 → HTTP POST → Python → JSON存储 + 下发C程序
|
||||||
3. **状态/查询流向**
|
3. **状态/查询流向**
|
||||||
Web界面 → HTTP GET → Python → 返回数据展示
|
Web界面 → HTTP GET → Python → 返回数据展示
|
||||||
|
4. **配置回显流向**
|
||||||
|
Web界面进入设置页 → HTTP GET配置查询接口 → Python读取JSON配置 → 返回当前配置数据 → Web界面显示
|
||||||
|
|
||||||
## 四、接口详细设计(RESTful + WebSocket)
|
## 四、接口详细设计(RESTful + WebSocket)
|
||||||
### 4.1 RESTful API 接口详情(完整参数+返回值)
|
### 4.1 RESTful API 接口详情(完整参数+返回值)
|
||||||
@ -288,7 +293,48 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 3. POST /api/config/device
|
#### 3. GET /api/config/device
|
||||||
|
**作用**:读取设备基础配置,用于设备/网络配置界面打开时回显当前参数
|
||||||
|
**参数**:无
|
||||||
|
**返回data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uart": [
|
||||||
|
{
|
||||||
|
"port": "COM1",
|
||||||
|
"baud": 9600,
|
||||||
|
"parity": "NONE",
|
||||||
|
"data_bits": 8,
|
||||||
|
"stop_bits": 1,
|
||||||
|
"protocol": "Modbus RTU"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4. POST /api/config/device
|
||||||
**作用**:提交设备基础配置(版本、通讯、密码)
|
**作用**:提交设备基础配置(版本、通讯、密码)
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
```json
|
```json
|
||||||
@ -344,7 +390,20 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 4. POST /api/config/channel
|
#### 5. GET /api/config/channel
|
||||||
|
**作用**:读取通道配置,用于通道配置界面打开时回显当前参数
|
||||||
|
**参数**:无
|
||||||
|
**返回data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ai_channel": [{"ch":1,"singal_type":"4-20mA","line_no":1,"type":"UA","limit_low":0,"limit_high":20}],
|
||||||
|
"ao_channel": [{"ch":1,"singal_type":"1-5v","line_no":2,"type":"UA","limit_low":0,"limit_high":20}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6. POST /api/config/channel
|
||||||
**作用**:提交AI/AO通道配置(AI:12通道,AO:12通道)
|
**作用**:提交AI/AO通道配置(AI:12通道,AO:12通道)
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
|
|
||||||
@ -358,13 +417,42 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 5. POST /api/config/line_alarm_setting
|
#### 7. GET /api/config/line_alarm_setting
|
||||||
|
**作用**:读取线路报警设置,用于报警设置界面打开时回显当前线路参数
|
||||||
|
**参数**:无
|
||||||
|
**返回data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"line_no": 1,
|
||||||
|
"over_limit_alarm": [
|
||||||
|
{
|
||||||
|
"category": "电压",
|
||||||
|
"limit": 180,
|
||||||
|
"delay": 180,
|
||||||
|
"output_node": "开出1",
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fault_alarm": [
|
||||||
|
{
|
||||||
|
"category": "PT断线",
|
||||||
|
"delay": 180,
|
||||||
|
"output_node": "开出1",
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 8. POST /api/config/line_alarm_setting
|
||||||
**作用**:提交定值报警阈值配置
|
**作用**:提交定值报警阈值配置
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
[
|
||||||
"line_no": 1,
|
{"line_no": 1,
|
||||||
"over_limit_alarm": [
|
"over_limit_alarm": [
|
||||||
{
|
{
|
||||||
"category": "电压",
|
"category": "电压",
|
||||||
@ -417,12 +505,33 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
]
|
||||||
```
|
```
|
||||||
**返回data**:`{"save_path":"/config/setting.json","send_status":"成功"}`
|
**返回data**:`{"save_path":"/config/setting.json","send_status":"成功"}`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 5. POST /api/config/ai_alarm_setting
|
#### 9. GET /api/config/ai_alarm_setting
|
||||||
|
**作用**:读取AI报警设置,用于报警设置界面打开时回显当前AI报警参数
|
||||||
|
**参数**:无
|
||||||
|
**返回data**:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"channel_no": 1,
|
||||||
|
"singal_type": "4-20mA",
|
||||||
|
"limit_low": 0,
|
||||||
|
"limit_high": 20,
|
||||||
|
"delay": 180,
|
||||||
|
"output_node": "开出1",
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 10. POST /api/config/ai_alarm_setting
|
||||||
|
|
||||||
**作用**:提交AI报警设置
|
**作用**:提交AI报警设置
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
@ -452,7 +561,21 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
**返回data**:`{"save_path":"/config/setting.json","send_status":"成功"}`
|
**返回data**:`{"save_path":"/config/setting.json","send_status":"成功"}`
|
||||||
|
|
||||||
#### 6. POST /api/config/system
|
#### 11. GET /api/config/system
|
||||||
|
**作用**:读取系统设置,用于系统设置界面打开时回显当前参数
|
||||||
|
**参数**:无
|
||||||
|
**返回data**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"time_sync": "auto",
|
||||||
|
"brightness": 80,
|
||||||
|
"screen_saver": 60
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 12. POST /api/config/system
|
||||||
|
|
||||||
**作用**:提交系统对时、灯光配置
|
**作用**:提交系统对时、灯光配置
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
@ -467,9 +590,26 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 7. GET /api/alarm/list
|
#### 13. GET /api/alarm/list
|
||||||
**作用**:分页查询历史报警
|
**作用**:分页查询历史报警
|
||||||
**参数**:`page=1&size=20`
|
**参数**:
|
||||||
|
- `page=1`:页码,从 `1` 开始
|
||||||
|
- `size=20`:每页条数,最大 `100`
|
||||||
|
- `no=L1`:按线路号/通道号精确筛选
|
||||||
|
- `type=current`:按报警类型字段精确筛选
|
||||||
|
- `start_time=2026-05-16T10:30:00`:按报警开始时间筛选
|
||||||
|
- `end_time=2026-05-16T11:30:00`:按报警结束时间筛选
|
||||||
|
|
||||||
|
**示例请求**:
|
||||||
|
```text
|
||||||
|
GET /api/alarm/list?page=1&size=20&no=L1&type=current&start_time=2026-05-16T10:30:00&end_time=2026-05-16T11:30:00
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
- 所有筛选条件均为可选
|
||||||
|
- 未传筛选条件时,默认按分页查询全部历史报警
|
||||||
|
- `start_time` 和 `end_time` 使用日期时间格式
|
||||||
|
|
||||||
**返回data**:
|
**返回data**:
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
@ -487,7 +627,7 @@ Web界面 → HTTP GET → Python → 返回数据展示
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 8. POST /api/control/switch
|
#### 14. POST /api/control/switch
|
||||||
**作用**:下发开关量控制指令
|
**作用**:下发开关量控制指令
|
||||||
**请求body参数**:
|
**请求body参数**:
|
||||||
```json
|
```json
|
||||||
|
|||||||
@ -21,6 +21,31 @@ export async function fetchDeviceStatus(): Promise<DeviceStatus> {
|
|||||||
return response.data.data
|
return response.data.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchDeviceConfig(): Promise<DeviceConfigPayload> {
|
||||||
|
const response = await http.get<ApiResponse<DeviceConfigPayload>>('/config/device')
|
||||||
|
return response.data.data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchChannelConfig(): Promise<ChannelConfigPayload> {
|
||||||
|
const response = await http.get<ApiResponse<ChannelConfigPayload>>('/config/channel')
|
||||||
|
return response.data.data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchLineAlarmSetting(): Promise<LineAlarmSettingPayload> {
|
||||||
|
const response = await http.get<ApiResponse<LineAlarmSettingPayload>>('/config/line_alarm_setting')
|
||||||
|
return response.data.data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAiAlarmSetting(): Promise<AiAlarmSettingItem[]> {
|
||||||
|
const response = await http.get<ApiResponse<AiAlarmSettingItem[]>>('/config/ai_alarm_setting')
|
||||||
|
return response.data.data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchSystemConfig(): Promise<SystemConfigPayload> {
|
||||||
|
const response = await http.get<ApiResponse<SystemConfigPayload>>('/config/system')
|
||||||
|
return response.data.data
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchAlarmHistory(page = 1, size = 20): Promise<AlarmEvent[]> {
|
export async function fetchAlarmHistory(page = 1, size = 20): Promise<AlarmEvent[]> {
|
||||||
const response = await http.get<ApiResponse<AlarmEvent[]>>(`/alarm/list?page=${page}&size=${size}`)
|
const response = await http.get<ApiResponse<AlarmEvent[]>>(`/alarm/list?page=${page}&size=${size}`)
|
||||||
return response.data.data
|
return response.data.data
|
||||||
|
|||||||
@ -38,6 +38,8 @@ const state = reactive<PlatformState>({
|
|||||||
let realtimeSocket: WebSocket | null = null
|
let realtimeSocket: WebSocket | null = null
|
||||||
let alarmSocket: WebSocket | null = null
|
let alarmSocket: WebSocket | null = null
|
||||||
let realtimePollTimer: number | null = null
|
let realtimePollTimer: number | null = null
|
||||||
|
let realtimeReconnectTimer: number | null = null
|
||||||
|
let realtimeReconnectAttempts = 0
|
||||||
|
|
||||||
function markRealtime(data: RealtimeData, source: string) {
|
function markRealtime(data: RealtimeData, source: string) {
|
||||||
state.realtime = data
|
state.realtime = data
|
||||||
@ -50,6 +52,57 @@ async function syncRealtimeByHttp(source = 'http-poll') {
|
|||||||
markRealtime(realtime, source)
|
markRealtime(realtime, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearRealtimeReconnectTimer() {
|
||||||
|
if (realtimeReconnectTimer !== null) {
|
||||||
|
window.clearTimeout(realtimeReconnectTimer)
|
||||||
|
realtimeReconnectTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleRealtimeReconnect() {
|
||||||
|
if (realtimeReconnectTimer !== null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const delay = Math.min(5000, 1000 * Math.max(1, realtimeReconnectAttempts + 1))
|
||||||
|
realtimeReconnectTimer = window.setTimeout(() => {
|
||||||
|
realtimeReconnectTimer = null
|
||||||
|
realtimeReconnectAttempts += 1
|
||||||
|
startRealtimeSocket()
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
function startRealtimeSocket() {
|
||||||
|
if (realtimeSocket && [WebSocket.CONNECTING, WebSocket.OPEN].includes(realtimeSocket.readyState)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const socket = connectRealtimeWithLifecycle(
|
||||||
|
(data) => {
|
||||||
|
state.realtimeConnected = true
|
||||||
|
markRealtime(data, 'websocket')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
onOpen: () => {
|
||||||
|
state.realtimeConnected = true
|
||||||
|
realtimeReconnectAttempts = 0
|
||||||
|
clearRealtimeReconnectTimer()
|
||||||
|
},
|
||||||
|
onClose: () => {
|
||||||
|
state.realtimeConnected = false
|
||||||
|
if (realtimeSocket === socket) {
|
||||||
|
realtimeSocket = null
|
||||||
|
}
|
||||||
|
scheduleRealtimeReconnect()
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
state.realtimeConnected = false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
realtimeSocket = socket
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshStatus() {
|
async function refreshStatus() {
|
||||||
state.statusLoading = true
|
state.statusLoading = true
|
||||||
try {
|
try {
|
||||||
@ -93,23 +146,7 @@ async function bootstrap() {
|
|||||||
await refreshAlarms(1)
|
await refreshAlarms(1)
|
||||||
|
|
||||||
if (!realtimeSocket) {
|
if (!realtimeSocket) {
|
||||||
realtimeSocket = connectRealtimeWithLifecycle(
|
startRealtimeSocket()
|
||||||
(data) => {
|
|
||||||
state.realtimeConnected = true
|
|
||||||
markRealtime(data, 'websocket')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onOpen: () => {
|
|
||||||
state.realtimeConnected = true
|
|
||||||
},
|
|
||||||
onClose: () => {
|
|
||||||
state.realtimeConnected = false
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
state.realtimeConnected = false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alarmSocket) {
|
if (!alarmSocket) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{ store: any; actions: any }>()
|
defineProps<{ store: any; actions: any }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { saveAiAlarmSetting, saveLineAlarmSetting } from '../api/platform'
|
import { fetchAiAlarmSetting, fetchLineAlarmSetting, saveAiAlarmSetting, saveLineAlarmSetting } from '../api/platform'
|
||||||
import type { AiAlarmSettingItem, LineAlarmSettingPayload } from '../types/platform'
|
import type { AiAlarmSettingItem, LineAlarmSettingPayload } from '../types/platform'
|
||||||
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
||||||
|
|
||||||
@ -32,6 +32,37 @@ const aiAlarm = reactive<AiAlarmSettingItem[]>([
|
|||||||
const result = ref('未保存')
|
const result = ref('未保存')
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const [lineData, aiData] = await Promise.all([fetchLineAlarmSetting(), fetchAiAlarmSetting()])
|
||||||
|
lineAlarm.line_no = lineData.line_no
|
||||||
|
lineData.over_limit_alarm.forEach((item, index) => {
|
||||||
|
if (lineAlarm.over_limit_alarm[index]) {
|
||||||
|
Object.assign(lineAlarm.over_limit_alarm[index], item)
|
||||||
|
} else {
|
||||||
|
lineAlarm.over_limit_alarm.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
lineData.fault_alarm.forEach((item, index) => {
|
||||||
|
if (lineAlarm.fault_alarm[index]) {
|
||||||
|
Object.assign(lineAlarm.fault_alarm[index], item)
|
||||||
|
} else {
|
||||||
|
lineAlarm.fault_alarm.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
aiData.forEach((item, index) => {
|
||||||
|
if (aiAlarm[index]) {
|
||||||
|
Object.assign(aiAlarm[index], item)
|
||||||
|
} else {
|
||||||
|
aiAlarm.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
result.value = '已加载当前报警设置'
|
||||||
|
} catch (error) {
|
||||||
|
result.value = error instanceof Error ? error.message : '加载报警设置失败'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { saveChannelConfig } from '../api/platform'
|
import { fetchChannelConfig, saveChannelConfig } from '../api/platform'
|
||||||
import type { ChannelConfigPayload } from '../types/platform'
|
import type { ChannelConfigPayload } from '../types/platform'
|
||||||
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
||||||
|
|
||||||
@ -14,6 +14,29 @@ const form = reactive<ChannelConfigPayload>({
|
|||||||
const result = ref('未保存')
|
const result = ref('未保存')
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const data = await fetchChannelConfig()
|
||||||
|
data.ai_channel.forEach((item, index) => {
|
||||||
|
if (form.ai_channel[index]) {
|
||||||
|
Object.assign(form.ai_channel[index], item)
|
||||||
|
} else {
|
||||||
|
form.ai_channel.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data.ao_channel.forEach((item, index) => {
|
||||||
|
if (form.ao_channel[index]) {
|
||||||
|
Object.assign(form.ao_channel[index], item)
|
||||||
|
} else {
|
||||||
|
form.ao_channel.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
result.value = '已加载当前通道配置'
|
||||||
|
} catch (error) {
|
||||||
|
result.value = error instanceof Error ? error.message : '加载通道配置失败'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
import { controlSwitch } from "../api/platform"
|
import { controlSwitch } from "../api/platform"
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from 'vue'
|
import { onMounted, reactive, ref } from 'vue'
|
||||||
import { saveDeviceConfig } from '../api/platform'
|
import { fetchDeviceConfig, saveDeviceConfig } from '../api/platform'
|
||||||
import type { DeviceConfigPayload } from '../types/platform'
|
import type { DeviceConfigPayload } from '../types/platform'
|
||||||
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
import { ensureSaveAuthorized } from '../utils/saveGuard'
|
||||||
|
|
||||||
@ -31,6 +31,32 @@ const form = reactive<DeviceConfigPayload>({
|
|||||||
const result = ref('未保存')
|
const result = ref('未保存')
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const data = await fetchDeviceConfig()
|
||||||
|
form.password = data.password
|
||||||
|
Object.assign(form.hardware_version, data.hardware_version)
|
||||||
|
Object.assign(form.software_version, data.software_version)
|
||||||
|
data.net.forEach((item, index) => {
|
||||||
|
if (form.net[index]) {
|
||||||
|
Object.assign(form.net[index], item)
|
||||||
|
} else {
|
||||||
|
form.net.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
data.uart.forEach((item, index) => {
|
||||||
|
if (form.uart[index]) {
|
||||||
|
Object.assign(form.uart[index], item)
|
||||||
|
} else {
|
||||||
|
form.uart.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
result.value = '已加载当前设备配置'
|
||||||
|
} catch (error) {
|
||||||
|
result.value = error instanceof Error ? error.message : '加载设备配置失败'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{ store: any; actions: any }>()
|
defineProps<{ store: any; actions: any }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref } from "vue"
|
import { onMounted, reactive, ref } from "vue"
|
||||||
import { saveSystemConfig } from "../api/platform"
|
import { fetchSystemConfig, saveSystemConfig } from "../api/platform"
|
||||||
import { ensureSaveAuthorized } from "../utils/saveGuard"
|
import { ensureSaveAuthorized } from "../utils/saveGuard"
|
||||||
|
|
||||||
defineProps<{ store: any; actions: any }>()
|
defineProps<{ store: any; actions: any }>()
|
||||||
@ -12,6 +12,16 @@ const form = reactive({
|
|||||||
})
|
})
|
||||||
const result = ref("未保存")
|
const result = ref("未保存")
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const data = await fetchSystemConfig()
|
||||||
|
Object.assign(form, data)
|
||||||
|
result.value = "已加载当前系统设置"
|
||||||
|
} catch (error) {
|
||||||
|
result.value = error instanceof Error ? error.message : "加载系统设置失败"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
const guard = await ensureSaveAuthorized()
|
const guard = await ensureSaveAuthorized()
|
||||||
if (!guard.ok) {
|
if (!guard.ok) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user