# -*- coding: utf-8 -*- """ Mega Water - 离线授权发卡器 (开发者专用) 生成绑定特定机器码的 .lic 授权文件 """ import os import sys # 确保 src.auth 在 path 中 _current_dir = os.path.dirname(os.path.abspath(__file__)) _project_root = os.path.abspath(os.path.join(_current_dir, "..", "..")) if _project_root not in sys.path: sys.path.insert(0, _project_root) from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QFileDialog, QMessageBox, QApplication, QDateEdit, QCheckBox ) from PyQt5.QtCore import Qt, QDate from src.auth.license_manager import generate_license # 永久授权的标识日期 PERMANENT_EXPIRY = "2099-12-31" class LicenseKeygenWindow(QWidget): """授权发卡器主窗口""" def __init__(self): super().__init__() self.setWindowTitle("Mega Water - 离线授权发卡器 (开发者专用)") self.setMinimumSize(640, 360) self.move(400, 280) self._default_save_path = os.path.join(_project_root, "license.lic") self._setup_ui() def _setup_ui(self): # ── 全局字体:无衬线,清晰 ── font_family = "Microsoft YaHei" if sys.platform == "win32" else "Segoe UI" self.setStyleSheet(f""" * {{ font-family: {font_family}, 'Segoe UI', sans-serif; font-size: 11pt; }} QLabel#titleLabel {{ font-size: 16pt; font-weight: bold; color: #2c3e50; }} QLabel#tipLabel {{ font-size: 10pt; color: #95a5a6; }} """) main_layout = QVBoxLayout() main_layout.setContentsMargins(45, 40, 45, 40) main_layout.setSpacing(18) # ── 标题 ── title_label = QLabel("离线授权发卡器 (开发者专用)") title_label.setObjectName("titleLabel") title_label.setAlignment(Qt.AlignCenter) main_layout.addWidget(title_label) # ── 机器码输入行 ── mc_layout = QHBoxLayout() mc_layout.setSpacing(12) mc_label = QLabel("机器码:") mc_label.setFixedWidth(90) self.mc_input = QLineEdit() self.mc_input.setPlaceholderText("粘贴用户发来的 32 位机器码") self.mc_input.setMinimumHeight(36) self.mc_input.setMinimumWidth(400) mc_layout.addWidget(mc_label, 0) mc_layout.addWidget(self.mc_input, 1) main_layout.addLayout(mc_layout) # ── 到期时间选择行 ── exp_layout = QHBoxLayout() exp_layout.setSpacing(14) exp_label = QLabel("到期时间:") exp_label.setFixedWidth(90) self.exp_edit = QDateEdit() self.exp_edit.setCalendarPopup(True) self.exp_edit.setMinimumHeight(36) self.exp_edit.setMinimumWidth(160) self.exp_edit.setDate(QDate.currentDate().addYears(1)) self.perm_check = QCheckBox("永久授权 (不限时)") self.perm_check.setMinimumHeight(36) self.perm_check.stateChanged.connect(self._on_perm_changed) exp_layout.addWidget(exp_label, 0) exp_layout.addWidget(self.exp_edit, 0) exp_layout.addWidget(self.perm_check, 0) exp_layout.addStretch(1) main_layout.addLayout(exp_layout) # ── 保存路径行 ── path_layout = QHBoxLayout() path_layout.setSpacing(12) path_label = QLabel("保存路径:") path_label.setFixedWidth(90) self.path_input = QLineEdit() self.path_input.setReadOnly(True) self.path_input.setMinimumHeight(36) self.browse_btn = QPushButton("浏览...") self.browse_btn.setMinimumHeight(36) self.browse_btn.setFixedWidth(80) self.browse_btn.clicked.connect(self._on_browse) path_layout.addWidget(path_label, 0) path_layout.addWidget(self.path_input, 1) path_layout.addWidget(self.browse_btn, 0) main_layout.addLayout(path_layout) # ── 弹性空间 ── main_layout.addSpacing(10) # ── 生成按钮 ── self.gen_btn = QPushButton("生成授权文件 (.lic)") self.gen_btn.setMinimumHeight(48) self.gen_btn.setStyleSheet(""" QPushButton { background-color: #27ae60; color: white; font-size: 13pt; font-weight: bold; border: none; border-radius: 8px; } QPushButton:hover { background-color: #2ecc71; } QPushButton:pressed { background-color: #1e8449; } """) self.gen_btn.clicked.connect(self._on_generate) main_layout.addWidget(self.gen_btn) # ── 底部提示 ── tip_label = QLabel("生成后请将 license.lic 文件发给用户,放置到软件安装目录下即可。") tip_label.setObjectName("tipLabel") tip_label.setAlignment(Qt.AlignCenter) main_layout.addWidget(tip_label) self.setLayout(main_layout) def _on_perm_changed(self, state): """永久授权复选框状态变化时,联动日期选择器""" if state == Qt.Checked: self.exp_edit.setEnabled(False) else: self.exp_edit.setEnabled(True) def _on_browse(self): """打开文件对话框选择保存路径""" path, _ = QFileDialog.getSaveFileName( self, "选择授权文件保存位置", self._default_save_path, "授权文件 (*.lic)" ) if path: if not path.lower().endswith(".lic"): path += ".lic" self.path_input.setText(path) def _on_generate(self): """点击生成按钮,调用授权管理器""" machine_code = self.mc_input.text().strip() if not machine_code: QMessageBox.warning(self, "输入错误", "请输入机器码") return output_path = self.path_input.text().strip() if not output_path: QMessageBox.warning(self, "输入错误", "请设置保存路径") return # 根据是否勾选永久授权决定日期 if self.perm_check.isChecked(): expiry_date = PERMANENT_EXPIRY else: expiry_date = self.exp_edit.date().toString("yyyy-MM-dd") ok, msg = generate_license( machine_code=machine_code, output_path=output_path, expiry_date=expiry_date ) if ok: QMessageBox.information( self, "生成成功", f"✅ 授权文件已成功生成!\n\n保存路径:\n{output_path}\n\n请将此文件发给用户即可。", QMessageBox.Ok ) else: QMessageBox.critical( self, "生成失败", f"❌ {msg}", QMessageBox.Ok ) if __name__ == "__main__": # ── 高 DPI 自适应(必须放在 QApplication 实例化之前)── from PyQt5.QtCore import Qt QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) app = QApplication(sys.argv) app.setApplicationName("LicenseKeygen") window = LicenseKeygenWindow() window.show() sys.exit(app.exec_())