"""运行配置管理:config.json 的加载 / 保存 / 默认值。 配置文件位置: - 打包后(exe):与可执行文件同目录 - 源码运行:app/ 目录下 首次运行不存在时自动生成默认配置。 """ import json import os import sys DEFAULTS = { "local": {"ip": "127.0.0.1", "port": 7000}, # 本机监听地址 "c1": {"ip": "192.168.1.154", "port": 6000}, # 高压配电板(C1) "c2": {"ip": "192.168.1.158", "port": 6000}, # 仪表配电板(C2) "host": {"ip": "127.0.0.1", "port": 5001}, # 上位机(信息主机) "db_path": "test.db", "refresh_ms": 1000, "sim": {"interval": 1.0}, } def default_config_dir(): """返回配置文件所在目录(打包后为 exe 目录,源码为 app/ 目录)。""" if getattr(sys, "frozen", False): return os.path.dirname(sys.executable) return os.path.dirname(os.path.abspath(__file__)) class Config: def __init__(self, path=None): self.path = path or os.path.join(default_config_dir(), "config.json") self.data = self._load() def _load(self): if os.path.exists(self.path): try: with open(self.path, "r", encoding="utf-8") as f: loaded = json.load(f) merged = {} for key, value in DEFAULTS.items(): if isinstance(value, dict): merged[key] = {**value, **loaded.get(key, {})} else: merged[key] = loaded.get(key, value) return merged except (json.JSONDecodeError, OSError): pass return json.loads(json.dumps(DEFAULTS)) def save(self): with open(self.path, "w", encoding="utf-8") as f: json.dump(self.data, f, ensure_ascii=False, indent=2) # ---- 便捷访问 ------------------------------------------------- @property def local_ip(self): return self.data["local"]["ip"] @local_ip.setter def local_ip(self, v): self.data["local"]["ip"] = v @property def local_port(self): return int(self.data["local"]["port"]) @local_port.setter def local_port(self, v): self.data["local"]["port"] = int(v) @property def c1_ip(self): return self.data["c1"]["ip"] @property def c1_port(self): return int(self.data["c1"]["port"]) @property def c2_ip(self): return self.data["c2"]["ip"] @property def c2_port(self): return int(self.data["c2"]["port"]) @property def host_ip(self): return self.data["host"]["ip"] @property def host_port(self): return int(self.data["host"]["port"]) @property def refresh_ms(self): return int(self.data["refresh_ms"]) @property def db_path(self): p = self.data["db_path"] if os.path.isabs(p): return p return os.path.join(default_config_dir(), p) @db_path.setter def db_path(self, v): self.data["db_path"] = v @property def sim_interval(self): return float(self.data["sim"]["interval"]) @sim_interval.setter def sim_interval(self, v): self.data["sim"]["interval"] = float(v) # ---- 批量设置(供配置弹窗使用) -------------------------------- def set_endpoints(self, local_ip, local_port, c1_ip, c1_port, c2_ip, c2_port, host_ip, host_port): self.data["local"] = {"ip": local_ip, "port": int(local_port)} self.data["c1"] = {"ip": c1_ip, "port": int(c1_port)} self.data["c2"] = {"ip": c2_ip, "port": int(c2_port)} self.data["host"] = {"ip": host_ip, "port": int(host_port)}