换位置

This commit is contained in:
lwt
2026-06-09 14:01:20 +08:00
parent 6d86678e11
commit 0b34f2e3d0
53 changed files with 1762 additions and 603 deletions
+70 -24
View File
@@ -14,6 +14,7 @@ class MainWindow(QMainWindow):
"""主窗口。支持“无项目”启动:先显示欢迎页,打开项目后加载并显示功能页。"""
CONSOLE_PANEL_HEIGHT = 345
AUTO_UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000
def __init__(self, config: Optional[Config] = None):
super().__init__()
@@ -21,6 +22,9 @@ class MainWindow(QMainWindow):
self._project_content_widget = None # 项目内容容器,首次打开项目时创建
self._cache_init_worker = None
self._startup_update_check_started = False
self._update_check_worker = None
self._update_prompt_active = False
self._last_prompted_update_version = ""
self.init_ui()
def init_ui(self):
@@ -255,6 +259,9 @@ class MainWindow(QMainWindow):
self._status_timer.timeout.connect(self._update_status_time)
self._status_timer.start(1000)
self._update_status_time()
self._auto_update_timer = QTimer(self)
self._auto_update_timer.setInterval(self.AUTO_UPDATE_CHECK_INTERVAL_MS)
self._auto_update_timer.timeout.connect(self._start_startup_update_check)
# 菜单栏:保证在窗口内可见(非系统原生菜单),便于看到“文件”“帮助”
menubar = self.menuBar()
@@ -306,49 +313,77 @@ class MainWindow(QMainWindow):
def showEvent(self, event):
super().showEvent(event)
# 首次打开后延迟检查远端版本清单,版本不一致则弹窗询问是否更新
# 首次打开后延迟检查一次,随后每 5 分钟在后台检查远端版本清单。
if not self._startup_update_check_started:
self._startup_update_check_started = True
self._auto_update_timer.start()
QTimer.singleShot(1500, self._start_startup_update_check)
def _start_startup_update_check(self):
"""启动时在后台检查远端版本清单(仅当配置了 update_url 时)"""
"""在后台检查远端版本清单(仅当配置了 update_url 时)"""
info = get_version_info()
update_url = (info.get("update_url") or "").strip()
if not update_url:
return
self._startup_check_worker = UpdateCheckWorker(update_url, self)
self._startup_check_worker.finished_signal.connect(self._on_startup_update_checked)
self._startup_check_worker.start()
if self._update_check_worker and self._update_check_worker.isRunning():
return
worker = UpdateCheckWorker(update_url, self)
self._update_check_worker = worker
worker.finished_signal.connect(self._on_startup_update_checked)
worker.finished.connect(lambda w=worker: self._clear_update_check_worker(w))
worker.finished.connect(worker.deleteLater)
worker.start()
def _clear_update_check_worker(self, worker):
if self._update_check_worker is worker:
self._update_check_worker = None
def _on_startup_update_checked(self, manifest):
"""启动检查结果:若本地版本与远端版本不一致则弹窗询问是否更新"""
"""后台检查结果:若远端版本更高则弹窗询问是否更新"""
if not manifest:
return
current = get_current_version()
remote_version = (manifest.get("version") or "").strip()
if not remote_version or remote_version == current:
if not remote_version or not version_less(current, remote_version):
if remote_version == current:
self._last_prompted_update_version = ""
return
if remote_version == self._last_prompted_update_version:
return
if self._update_prompt_active:
return
if hasattr(self, "_update_worker") and self._update_worker and self._update_worker.isRunning():
return
self._last_prompted_update_version = remote_version
self._update_prompt_active = True
release_notes = (manifest.get("release_notes") or "").strip()
msg = f"远程版本 {remote_version} 与当前版本 {current} 不一致"
msg = f"发现新版本 {remote_version}(当前 {current}"
if release_notes:
msg += f"\n\n{release_notes}"
msg += "\n\n是否立即更新?"
ret = QMessageBox.question(
self,
"检查更新",
msg,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.Yes,
)
try:
ret = QMessageBox.question(
self,
"检查更新",
msg,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.Yes,
)
finally:
self._update_prompt_active = False
if ret != QMessageBox.StandardButton.Yes:
return
delta = get_delta_for_current(manifest, current)
has_delta = delta and delta.get("patch_url") and delta.get("new_exe_sha256")
has_delta = bool(delta)
full_url = (manifest.get("full_installer_url") or manifest.get("download_url") or "").strip()
self._update_manifest = manifest # 保存 manifest,增量失败时可用来发起全量更新
if has_delta:
self._start_update_download(delta["patch_url"], use_delta=True, expected_sha256=delta.get("new_exe_sha256"))
self._start_update_download(
get_delta_download_url(delta),
use_delta=True,
expected_sha256=get_delta_expected_sha256(delta),
delta_kind=get_delta_kind(delta),
)
elif full_url:
self._start_update_download(full_url, use_delta=False)
else:
@@ -411,6 +446,7 @@ class MainWindow(QMainWindow):
def _on_close_project(self):
self.config.tool_dir = None
self.config.user_config_path = None
self.config.tool_config_path = None
self.config.config_error = "未打开项目"
self.config.data = _empty_config_data()
@@ -465,7 +501,7 @@ class MainWindow(QMainWindow):
release_notes = manifest.get("release_notes", "")
full_url = (manifest.get("full_installer_url") or manifest.get("download_url") or "").strip()
delta = get_delta_for_current(manifest, current)
has_delta = bool(delta and delta.get("patch_url") and delta.get("new_exe_sha256"))
has_delta = bool(delta)
if not full_url and not has_delta:
QMessageBox.warning(
self,
@@ -492,9 +528,10 @@ class MainWindow(QMainWindow):
self._update_manifest = manifest
if clicked == btn_delta and has_delta:
self._start_update_download(
delta["patch_url"],
get_delta_download_url(delta),
use_delta=True,
expected_sha256=delta.get("new_exe_sha256"),
expected_sha256=get_delta_expected_sha256(delta),
delta_kind=get_delta_kind(delta),
)
else:
self._start_update_download(full_url, use_delta=False)
@@ -504,12 +541,17 @@ class MainWindow(QMainWindow):
download_url: str,
use_delta: bool = False,
expected_sha256: Optional[str] = None,
delta_kind: str = "",
):
"""下载更新包(全量 exe 或增量 patch),完成后全量则启动安装,增量则 bsdiff 打补丁并替换"""
dest = Path(tempfile.gettempdir()) / "ServerManager_Update"
dest.mkdir(parents=True, exist_ok=True)
suffix = Path(download_url).suffix or (".patch" if use_delta else ".exe")
from urllib.parse import urlparse
suffix = Path(urlparse(download_url).path).suffix
if not suffix:
suffix = ".smdelta" if use_delta and delta_kind == "file_zip" else (".patch" if use_delta else ".exe")
dest_file = dest / ("ServerManager_patch" + suffix if use_delta else f"ServerManager_Setup{suffix}")
self._update_delta_kind = delta_kind
self._update_download_path = dest_file
self._update_progress = QProgressDialog("正在下载更新...", "取消", 0, 100, self)
self._update_progress.setWindowTitle("检查更新")
@@ -542,13 +584,17 @@ class MainWindow(QMainWindow):
if not path or not Path(path).exists():
QMessageBox.warning(self, "检查更新", "下载失败,请稍后重试或手动下载。")
return
if is_delta and expected_sha256:
if is_delta:
QMessageBox.information(
self,
"检查更新",
"增量包已下载,即将退出并重启以应用补丁"
"增量包已下载,即将退出并重启以应用更新"
)
ok, reason = apply_delta_patch(Path(path), expected_sha256)
delta_kind = getattr(self, "_update_delta_kind", "") or "bsdiff_exe"
if delta_kind == "file_zip":
ok, reason = apply_file_delta_package(Path(path), expected_sha256 or "")
else:
ok, reason = apply_delta_patch(Path(path), expected_sha256 or "")
if ok:
pass # 成功时进程会退出
else: