feat(subscription): add expiry recovery flow
This commit is contained in:
+55
-2
@@ -20,9 +20,9 @@ from .workers import SubscriptionCheckWorker
|
||||
PREFERRED_WINDOW_SIZE = (1180, 760)
|
||||
MIN_WINDOW_SIZE = (960, 640)
|
||||
WINDOW_SCREEN_MARGIN = 40
|
||||
# 观察期真实查询会员状态,但不在客户端限制存量用户工作流。
|
||||
# 当前开发版本启用真实查询和客户端强制门禁。
|
||||
SUBSCRIPTION_CHECK_ENABLED = True
|
||||
SUBSCRIPTION_ENFORCEMENT_ENABLED = False
|
||||
SUBSCRIPTION_ENFORCEMENT_ENABLED = True
|
||||
|
||||
|
||||
def _screen_available_geometry():
|
||||
@@ -121,6 +121,7 @@ class MainWindow(QMainWindow):
|
||||
self._subscription_thread = None
|
||||
self._subscription_request_token = 0
|
||||
self._subscription_closed = False
|
||||
self._expired_subscription_notice_shown = False
|
||||
self.tabs = QTabWidget()
|
||||
self.tabs.setObjectName("mainTabs")
|
||||
self.tabs.setStyleSheet(TAB_STYLE)
|
||||
@@ -130,6 +131,10 @@ class MainWindow(QMainWindow):
|
||||
settings_tab = self._settings_tab()
|
||||
if hasattr(settings_tab, "settingsSaved"):
|
||||
settings_tab.settingsSaved.connect(self._on_settings_saved)
|
||||
if hasattr(settings_tab, "subscriptionCheckRequested"):
|
||||
settings_tab.subscriptionCheckRequested.connect(
|
||||
self.begin_subscription_check
|
||||
)
|
||||
central = QWidget()
|
||||
central_layout = QVBoxLayout(central)
|
||||
central_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -229,6 +234,7 @@ class MainWindow(QMainWindow):
|
||||
self._set_membership_window_title()
|
||||
if not SUBSCRIPTION_CHECK_ENABLED:
|
||||
self._set_product_access(True)
|
||||
self._set_subscription_check_running(False)
|
||||
self.show_status("会员订阅检测已暂停", level="muted")
|
||||
return
|
||||
self._subscription_request_token += 1
|
||||
@@ -236,6 +242,7 @@ class MainWindow(QMainWindow):
|
||||
if self._subscription_worker is not None:
|
||||
self._subscription_worker.cancel()
|
||||
self._set_product_access(not SUBSCRIPTION_ENFORCEMENT_ENABLED)
|
||||
self._set_subscription_check_running(True)
|
||||
self.show_status("正在验证会员状态", level="info")
|
||||
worker = SubscriptionCheckWorker(
|
||||
config=self.config,
|
||||
@@ -287,9 +294,12 @@ class MainWindow(QMainWindow):
|
||||
if self._subscription_thread is thread:
|
||||
self._subscription_thread = None
|
||||
self._subscription_worker = None
|
||||
self._set_subscription_check_running(False)
|
||||
|
||||
def _apply_subscription_status(self, status):
|
||||
self._subscription_status = status
|
||||
if status.allows_product_workflows:
|
||||
self._expired_subscription_notice_shown = False
|
||||
if status.state == subscription.STATUS_ACTIVE:
|
||||
expiry = subscription.format_expiry(status.expires_at)
|
||||
self._set_membership_window_title(
|
||||
@@ -335,6 +345,8 @@ class MainWindow(QMainWindow):
|
||||
return
|
||||
self.open_settings_tab()
|
||||
self.show_status(status.user_message, level=self._subscription_level(status))
|
||||
if status.state == subscription.STATUS_EXPIRED:
|
||||
self._show_expired_subscription_notice_once(status)
|
||||
|
||||
@staticmethod
|
||||
def _subscription_level(status):
|
||||
@@ -362,6 +374,47 @@ class MainWindow(QMainWindow):
|
||||
for index, title in enumerate(TAB_TITLES):
|
||||
self.tabs.setTabEnabled(index, bool(enabled) or title == "设置")
|
||||
|
||||
def _set_subscription_check_running(self, running):
|
||||
settings_tab = self._settings_tab()
|
||||
if hasattr(settings_tab, "set_subscription_check_running"):
|
||||
settings_tab.set_subscription_check_running(running)
|
||||
|
||||
def _show_expired_subscription_notice_once(self, status):
|
||||
if self._expired_subscription_notice_shown:
|
||||
return
|
||||
self._expired_subscription_notice_shown = True
|
||||
|
||||
box = QMessageBox(self)
|
||||
box.setIcon(QMessageBox.Warning)
|
||||
box.setWindowTitle("会员套餐已过期")
|
||||
text = (
|
||||
"当前账号的蝦皮圈会员已到期,业务功能已暂停。"
|
||||
"请前往会员中心续费或更换套餐,完成后返回设置重新检测会员状态。"
|
||||
)
|
||||
manage_url = str(status.manage_url or "").strip()
|
||||
if not manage_url:
|
||||
text += "\n\n会员中心地址当前不可用,请检查默认网关配置或稍后重试。"
|
||||
box.setText(text)
|
||||
manage_button = box.addButton("前往会员中心", QMessageBox.ActionRole)
|
||||
exit_button = box.addButton("退出程序", QMessageBox.DestructiveRole)
|
||||
manage_button.setEnabled(bool(manage_url))
|
||||
if manage_url:
|
||||
box.setDefaultButton(manage_button)
|
||||
else:
|
||||
manage_button.setToolTip("会员中心地址当前不可用")
|
||||
box.exec()
|
||||
|
||||
clicked = box.clickedButton()
|
||||
if clicked is manage_button and manage_url:
|
||||
opened = QDesktopServices.openUrl(QUrl(manage_url))
|
||||
if opened is False:
|
||||
self.show_status(
|
||||
"无法打开会员中心,请检查系统默认浏览器后重试",
|
||||
level="warning",
|
||||
)
|
||||
elif clicked is exit_button:
|
||||
self.close()
|
||||
|
||||
def _show_subscription_notice_once(self, status):
|
||||
notice_id = str(status.notice_id or "").strip()
|
||||
if not notice_id or notice_id == appconfig.subscription_notice_id(self.config):
|
||||
|
||||
@@ -66,6 +66,7 @@ class SettingsTab(QWidget):
|
||||
"""Tab 5: AI model definitions stored in data/config/ai_models.json."""
|
||||
|
||||
settingsSaved = Signal(str)
|
||||
subscriptionCheckRequested = Signal()
|
||||
|
||||
BACKEND_ITEMS = [
|
||||
("默认网关", "cmhub"),
|
||||
@@ -279,6 +280,9 @@ class SettingsTab(QWidget):
|
||||
self.cdp_ready_timeout_spin.setObjectName("cdpReadyTimeoutSpin")
|
||||
self.cdp_ready_timeout_spin.setRange(1, 3600)
|
||||
self.save_config_button = QPushButton("保存设置")
|
||||
self.subscription_check_button = QPushButton("重新检测会员状态")
|
||||
self.subscription_check_button.setObjectName("subscriptionCheckButton")
|
||||
self.subscription_check_button.setToolTip("重新查询当前 cmhub 账号的会员套餐状态")
|
||||
self.unsaved_changes_label = QLabel("● 未保存更改")
|
||||
self.unsaved_changes_label.setObjectName("settingsUnsavedChangesLabel")
|
||||
self.unsaved_changes_label.setStyleSheet("color: #bc4c00; font-weight: 600;")
|
||||
@@ -455,6 +459,7 @@ class SettingsTab(QWidget):
|
||||
save_settings_layout.addWidget(self.save_config_button)
|
||||
save_settings_layout.addWidget(self.unsaved_changes_label)
|
||||
save_settings_layout.addStretch(1)
|
||||
save_settings_layout.addWidget(self.subscription_check_button)
|
||||
panel_layout.addLayout(save_settings_layout)
|
||||
panel_layout.addStretch(1)
|
||||
|
||||
@@ -490,6 +495,9 @@ class SettingsTab(QWidget):
|
||||
self.chrome_path_browse_button.clicked.connect(self.browse_chrome_path)
|
||||
self.chrome_path_detect_button.clicked.connect(self.detect_chrome_path)
|
||||
self.save_config_button.clicked.connect(self.save_app_settings)
|
||||
self.subscription_check_button.clicked.connect(
|
||||
self._request_subscription_check
|
||||
)
|
||||
self._connect_dirty_signals()
|
||||
|
||||
with self._dirty_tracking_suspended():
|
||||
@@ -548,6 +556,16 @@ class SettingsTab(QWidget):
|
||||
def _set_status(self, message, level=None):
|
||||
_emit_status(self.status_callback, message, level=level)
|
||||
|
||||
def _request_subscription_check(self, checked=False):
|
||||
self.subscriptionCheckRequested.emit()
|
||||
|
||||
def set_subscription_check_running(self, running):
|
||||
running = bool(running)
|
||||
self.subscription_check_button.setEnabled(not running)
|
||||
self.subscription_check_button.setText(
|
||||
"正在检测会员状态..." if running else "重新检测会员状态"
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
def _dirty_tracking_suspended(self):
|
||||
self._suspend_dirty += 1
|
||||
|
||||
Reference in New Issue
Block a user