""" 配置加载 从 scripts/data/config.json 读取用户配置,环境变量可覆盖系统 URL 与用户字段。 """ import json import os from pathlib import Path # 项目根 = src/config.py 的上上级(曾多写一层 parent,导致解析到项目之外、凭据恒为空) _CONFIG_PATH = Path(__file__).resolve().parent.parent / "scripts" / "data" / "config.json" # 会话级配置允许覆盖的用户相关字段白名单(含密码) # 前端安全的配置字段白名单(不含密码) SAFE_CONFIG_KEYS = frozenset( { "username", "default_name", "default_card_no", "default_person_id", } ) # 模块级配置缓存 _config_cache: dict[str, str | Path] | None = None def _read_config() -> dict[str, str | Path]: """读取并合并配置,缺失字段使用默认值""" raw = {} if _CONFIG_PATH.exists(): with open(_CONFIG_PATH, encoding="utf-8") as f: raw = json.load(f) project_root = _CONFIG_PATH.parent return { "sso_login_url": os.environ.get("SSO_LOGIN_URL", "https://tyrz.fynu.edu.cn/sso/login"), "portal_url": os.environ.get("PORTAL_URL", "https://tyrz.fynu.edu.cn/oshall"), "reimburse_url": os.environ.get("REIMBURSE_URL", "http://210.45.32.214:8081"), "reimburse_page": os.environ.get("REIMBURSE_PAGE", "/expen/common/common?v=4.0"), "travel_page": os.environ.get("TRAVEL_PAGE", "/expen/travel/travel?v=4.0"), "username": raw.get("username", ""), "password": raw.get("password", ""), "default_name": raw.get("default_name", ""), "default_card_no": raw.get("default_card_no", ""), "default_person_id": raw.get("default_person_id", ""), "upload_pin": os.environ.get("UPLOAD_PIN") or raw.get("upload_pin", ""), "attachment_dir": project_root / "attachments", } def load_config() -> dict[str, str | Path]: """加载并合并配置,使用模块级缓存避免重复读取文件""" global _config_cache if _config_cache is None: _config_cache = _read_config() return dict(_config_cache) def clear_config_cache() -> None: """清除配置缓存(测试或配置变更时调用)""" global _config_cache _config_cache = None