feat(subscription): add expiry recovery flow

This commit is contained in:
chengma
2026-07-23 16:03:08 +08:00
parent b05c370250
commit c02866e610
7 changed files with 276 additions and 17 deletions
+55 -2
View File
@@ -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):