96 lines
3.6 KiB
Python
96 lines
3.6 KiB
Python
"""采购工具固定双 Tab 原生窗口。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QTimer, Qt, Slot
|
|
from PySide6.QtGui import QCloseEvent
|
|
from PySide6.QtWidgets import QMainWindow, QTabWidget
|
|
|
|
from cmbuyer_client.localstate.models import ProfileSettings
|
|
from cmbuyer_client.polling.coordinator import PollingCoordinator, PollingState, RecoveryStatus
|
|
|
|
from .execution import ExecutionPage
|
|
from .records import PurchaseRecordProvider
|
|
from .settings import ProfileStore, SettingsPage
|
|
|
|
|
|
class PurchaseToolWindow(QMainWindow):
|
|
EXECUTION_PAGE_ID = "purchase-execution"
|
|
SETTINGS_PAGE_ID = "settings"
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
store: ProfileStore,
|
|
coordinator: PollingCoordinator,
|
|
profile_settings: ProfileSettings | None,
|
|
has_stored_device_token: bool,
|
|
record_provider: PurchaseRecordProvider | None = None,
|
|
parent=None,
|
|
) -> None:
|
|
super().__init__(parent)
|
|
self.setWindowTitle("采购工具")
|
|
self.setAccessibleName("采购工具")
|
|
self.setMinimumSize(720, 520)
|
|
self.resize(1180, 760)
|
|
self._coordinator = coordinator
|
|
self._close_pending = False
|
|
|
|
recovery = coordinator.recovery_status
|
|
frozen = recovery is None or recovery.has_pending_claim or recovery.has_active_claim
|
|
self.tabs = QTabWidget()
|
|
self.tabs.setObjectName("mainTabs")
|
|
self.tabs.setTabsClosable(False)
|
|
self.tabs.setMovable(False)
|
|
self.execution_page = ExecutionPage(coordinator, record_provider)
|
|
self.execution_page.setProperty("pageId", self.EXECUTION_PAGE_ID)
|
|
self.settings_page = SettingsPage(
|
|
store,
|
|
settings=profile_settings,
|
|
has_stored_device_token=has_stored_device_token,
|
|
identity_frozen=frozen,
|
|
)
|
|
self.settings_page.setProperty("pageId", self.SETTINGS_PAGE_ID)
|
|
self.tabs.addTab(self.execution_page, "采购执行")
|
|
self.tabs.addTab(self.settings_page, "配置")
|
|
self.tabs.setCurrentWidget(self.execution_page)
|
|
self.setCentralWidget(self.tabs)
|
|
|
|
self.settings_page.settings_saved.connect(
|
|
lambda settings, has_token: self._coordinator.update_profile_settings(settings)
|
|
)
|
|
coordinator.recovery_status_changed.connect(self._on_recovery_status)
|
|
coordinator.configuration_freeze_changed.connect(self.settings_page.set_identity_frozen)
|
|
coordinator.settled.connect(self._finish_pending_close)
|
|
|
|
@Slot(object)
|
|
def _on_recovery_status(self, raw: object) -> None:
|
|
if not isinstance(raw, RecoveryStatus):
|
|
self.settings_page.set_identity_frozen(True)
|
|
return
|
|
self.settings_page.set_identity_frozen(raw.has_pending_claim or raw.has_active_claim)
|
|
|
|
def closeEvent(self, event: QCloseEvent) -> None:
|
|
running = self._coordinator.state in (
|
|
PollingState.STARTING,
|
|
PollingState.RECOVERING,
|
|
PollingState.WAITING,
|
|
PollingState.CLAIMING,
|
|
PollingState.ACTIVE,
|
|
) or self._coordinator.operation_in_flight
|
|
if running:
|
|
# 不 terminate 飞行中的 QThread。先提升 stop latch,等待 HTTP 自身
|
|
# 超时和 DurableClientGateway 落库,再由 settled 重试关闭。
|
|
self._close_pending = True
|
|
self._coordinator.stop()
|
|
event.ignore()
|
|
return
|
|
event.accept()
|
|
|
|
@Slot()
|
|
def _finish_pending_close(self) -> None:
|
|
if not self._close_pending:
|
|
return
|
|
self._close_pending = False
|
|
QTimer.singleShot(0, self.close)
|