from __future__ import annotations import os from pathlib import Path from typing import Any import yaml class Config: """配置管理类""" _instance = None _config_data = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance def __init__(self): if self._config_data is None: self._load_config() def _load_config(self) -> None: """加载配置文件""" config_path = Path(__file__).parent / "config.yaml" # 默认配置 default_config = { "wechat": { "appid": "", "appsecret": "" }, "chrome": { "path": r"C:\Program Files\Google\Chrome\Application\chrome.exe" }, "step1": { "url": "https://feast.yidaima.cn/login", "username": "wangpeng", "password": "Feastcoding@123", "project_name": "【A167】基于Springboot + vue3实现的宿舍报修系统", "feast_button": "FeastCoding" }, "step2": { "url": "http://yidaima.cn:6005/" }, "database": { "host": "localhost", "port": 3306, "database": "test", "user": "root", "password": "123456" } } if config_path.exists(): try: with open(config_path, 'r', encoding='utf-8') as f: loaded_config = yaml.safe_load(f) or {} # 合并配置 self._config_data = self._merge_config(default_config, loaded_config) except Exception as e: print(f"[Config] 加载配置文件失败: {e},使用默认配置") self._config_data = default_config else: print("[Config] 配置文件不存在,使用默认配置") self._config_data = default_config # 环境变量覆盖 self._apply_env_overrides() def _merge_config(self, default: dict, loaded: dict) -> dict: """递归合并配置""" result = default.copy() for key, value in loaded.items(): if key in result and isinstance(result[key], dict) and isinstance(value, dict): result[key] = self._merge_config(result[key], value) else: result[key] = value return result def _apply_env_overrides(self) -> None: """应用环境变量覆盖""" # 微信配置 if os.environ.get("WECHAT_APPID"): self._config_data["wechat"]["appid"] = os.environ.get("WECHAT_APPID") if os.environ.get("WECHAT_APPSECRET"): self._config_data["wechat"]["appsecret"] = os.environ.get("WECHAT_APPSECRET") # Chrome 路径 if os.environ.get("CHROME_PATH"): self._config_data["chrome"]["path"] = os.environ.get("CHROME_PATH") # Step1 配置 if os.environ.get("FEAST_USERNAME"): self._config_data["step1"]["username"] = os.environ.get("FEAST_USERNAME") if os.environ.get("FEAST_PASSWORD"): self._config_data["step1"]["password"] = os.environ.get("FEAST_PASSWORD") # 数据库配置 if os.environ.get("DB_HOST"): self._config_data["database"]["host"] = os.environ.get("DB_HOST") if os.environ.get("DB_PORT"): self._config_data["database"]["port"] = int(os.environ.get("DB_PORT")) if os.environ.get("DB_NAME"): self._config_data["database"]["database"] = os.environ.get("DB_NAME") if os.environ.get("DB_USER"): self._config_data["database"]["user"] = os.environ.get("DB_USER") if os.environ.get("DB_PASSWORD"): self._config_data["database"]["password"] = os.environ.get("DB_PASSWORD") def get(self, key: str, default: Any = None) -> Any: """ 获取配置值,支持点号分隔的路径 例如: get("wechat.appid") 或 get("step1.url") """ keys = key.split('.') value = self._config_data for k in keys: if isinstance(value, dict) and k in value: value = value[k] else: return default return value @property def wechat_appid(self) -> str: return self.get("wechat.appid", "") @property def wechat_appsecret(self) -> str: return self.get("wechat.appsecret", "") @property def chrome_path(self) -> str: return self.get("chrome.path", r"C:\Program Files\Google\Chrome\Application\chrome.exe") @property def step1_config(self) -> dict: return self.get("step1", {}) @property def step2_config(self) -> dict: return self.get("step2", {}) @property def database_config(self) -> dict: return self.get("database", {}) # 全局配置实例 _config_instance = None def get_config() -> Config: """获取配置实例(单例模式)""" global _config_instance if _config_instance is None: _config_instance = Config() return _config_instance def reset_config(): """重置配置实例(用于重新加载)""" global _config_instance _config_instance = None if __name__ == "__main__": # 测试配置加载 config = get_config() print(f"WeChat AppID: {config.wechat_appid}") print(f"WeChat AppSecret: {'*' * len(config.wechat_appsecret) if config.wechat_appsecret else '(empty)'}") print(f"Chrome Path: {config.chrome_path}") print(f"Step1 URL: {config.get('step1.url')}") print(f"Step2 URL: {config.get('step2.url')}") print(f"Database Host: {config.get('database.host')}") print(f"Database Port: {config.get('database.port')}")