6f96bf50ac
当从外部目录(如D:\ccc)拖入文件时,输出文件会错误地写入源目录。 根因是所有路径使用相对路径 + os.getcwd() 解析,CWD不同则路径错误。 修复方案: - ConfigManager.get_path() 改为使用 app_root (exe所在目录/脚本所在目录) - 将 22 处裸硬编码 "data/result"/"data/output" 替换为 config.get_path() - 添加 result_folder 到默认配置和 config.ini - 修复 error_utils.py 中的路径匹配字符串 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
131 lines
3.9 KiB
Python
131 lines
3.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""用户设置与最近文件管理模块"""
|
|
|
|
import os
|
|
import json
|
|
import re
|
|
import tkinter as tk
|
|
from typing import Dict, List, Any
|
|
|
|
from app.core.utils.log_utils import get_logger
|
|
from app.config.settings import ConfigManager
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
RECENT_LIST_WIDGET = None
|
|
|
|
|
|
def load_user_settings():
|
|
try:
|
|
path = os.path.abspath(os.path.join('data', 'user_settings.json'))
|
|
if os.path.exists(path):
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
return json.load(f)
|
|
except Exception as e:
|
|
logger.debug(f"加载用户设置失败: {e}")
|
|
return {}
|
|
|
|
|
|
def save_user_settings(settings: Dict[str, Any]):
|
|
try:
|
|
os.makedirs('data', exist_ok=True)
|
|
path = os.path.abspath(os.path.join('data', 'user_settings.json'))
|
|
with open(path, 'w', encoding='utf-8') as f:
|
|
json.dump(settings, f, ensure_ascii=False, indent=2)
|
|
except Exception as e:
|
|
logger.debug(f"保存用户设置失败: {e}")
|
|
|
|
|
|
def get_recent_files() -> List[str]:
|
|
s = load_user_settings()
|
|
items = s.get('recent_files', [])
|
|
if not isinstance(items, list):
|
|
return []
|
|
|
|
def _allowed(p: str) -> bool:
|
|
try:
|
|
if not isinstance(p, str) or not os.path.isfile(p):
|
|
return False
|
|
ext = os.path.splitext(p)[1].lower()
|
|
return ext in {'.xlsx', '.xls', '.jpg', '.jpeg', '.png', '.bmp'}
|
|
except Exception:
|
|
return False
|
|
|
|
kept = [p for p in items if _allowed(p)]
|
|
if not kept:
|
|
candidates = []
|
|
cfg = ConfigManager()
|
|
for d in [cfg.get_path('Paths', 'output_folder', fallback='data/output'), cfg.get_path('Paths', 'result_folder', fallback='data/result')]:
|
|
try:
|
|
if os.path.exists(d):
|
|
for name in os.listdir(d):
|
|
p = os.path.join(d, name)
|
|
if _allowed(p):
|
|
candidates.append(p)
|
|
except Exception:
|
|
pass
|
|
if candidates:
|
|
kept = candidates
|
|
try:
|
|
kept_sorted = sorted(kept, key=lambda p: os.path.getmtime(p), reverse=True)
|
|
except Exception:
|
|
kept_sorted = kept
|
|
if kept_sorted != items or len(kept_sorted) != len(items):
|
|
s['recent_files'] = kept_sorted[:20]
|
|
save_user_settings(s)
|
|
return kept_sorted[:10]
|
|
|
|
|
|
def refresh_recent_list_widget():
|
|
try:
|
|
global RECENT_LIST_WIDGET
|
|
if RECENT_LIST_WIDGET is None:
|
|
return
|
|
RECENT_LIST_WIDGET.delete(0, tk.END)
|
|
for i, p in enumerate(get_recent_files(), start=1):
|
|
RECENT_LIST_WIDGET.insert(tk.END, f"{i}. {p}")
|
|
except Exception as e:
|
|
logger.debug(f"刷新最近文件列表失败: {e}")
|
|
|
|
|
|
def _extract_path_from_recent_item(s: str) -> str:
|
|
try:
|
|
m = re.match(r'^(\d+)\.\s+(.*)$', s)
|
|
p = m.group(2) if m else s
|
|
return p.strip().strip('"')
|
|
except Exception:
|
|
return s.strip().strip('"')
|
|
|
|
|
|
def add_recent_file(path: str) -> None:
|
|
try:
|
|
if not path:
|
|
return
|
|
try:
|
|
if not os.path.isfile(path):
|
|
return
|
|
ext = os.path.splitext(path)[1].lower()
|
|
if ext not in {'.xlsx', '.xls', '.jpg', '.jpeg', '.png', '.bmp'}:
|
|
return
|
|
except Exception:
|
|
return
|
|
s = load_user_settings()
|
|
items = s.get('recent_files', [])
|
|
items = [p for p in items if p != path]
|
|
items.insert(0, path)
|
|
s['recent_files'] = items[:20]
|
|
save_user_settings(s)
|
|
refresh_recent_list_widget()
|
|
except Exception as e:
|
|
logger.debug(f"添加最近文件失败: {e}")
|
|
|
|
|
|
def clear_recent_files():
|
|
try:
|
|
s = load_user_settings()
|
|
s['recent_files'] = []
|
|
save_user_settings(s)
|
|
except Exception as e:
|
|
logger.debug(f"清空最近文件失败: {e}")
|