modify: 台账更改插件
This commit is contained in:
@@ -11,7 +11,6 @@ from pathlib import Path
|
||||
|
||||
from PySide6.QtCore import QDate, QSettings, Qt
|
||||
from PySide6.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QButtonGroup,
|
||||
QCheckBox,
|
||||
QComboBox,
|
||||
@@ -19,10 +18,7 @@ from PySide6.QtWidgets import (
|
||||
QFileDialog,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QListWidget,
|
||||
QListWidgetItem,
|
||||
QPlainTextEdit,
|
||||
QPushButton,
|
||||
QRadioButton,
|
||||
QSpinBox,
|
||||
QStackedWidget,
|
||||
@@ -40,18 +36,21 @@ from chongming_license import (
|
||||
)
|
||||
|
||||
from .common import (
|
||||
FALLBACK_PLUGIN_TYPES,
|
||||
ask_overwrite,
|
||||
btn,
|
||||
copy_to_clipboard,
|
||||
discover_plugin_types,
|
||||
error,
|
||||
hint,
|
||||
hbox,
|
||||
info,
|
||||
make_mono_label,
|
||||
mono_font,
|
||||
section,
|
||||
set_status,
|
||||
warn,
|
||||
)
|
||||
from .keystore import SigningKey
|
||||
from .plugin_picker import PluginPicker
|
||||
|
||||
# 签发依据的三种方式(与 CLI 的 --request-code / --sources-json / --machine-code 对位)
|
||||
MODE_REQUEST_CODE = 0
|
||||
@@ -77,16 +76,20 @@ class IssueTab(QWidget):
|
||||
self._source_note: str = ""
|
||||
|
||||
root = QVBoxLayout(self)
|
||||
root.setContentsMargins(14, 14, 14, 14)
|
||||
root.setSpacing(12)
|
||||
|
||||
# ---------- 签名私钥 ----------
|
||||
key_box, key_form = section("签名私钥")
|
||||
self.key_status = QLabel("—")
|
||||
self.key_status.setWordWrap(True)
|
||||
# 指纹要逐字符核对,必须等宽
|
||||
self.key_fp = QLabel("—")
|
||||
self.key_fp.setFont(mono_font(11))
|
||||
self.key_fp.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
key_form.addRow("当前", self.key_status)
|
||||
key_form.addRow("公钥指纹", self.key_fp)
|
||||
key_form.addRow("", QLabel("在「密钥」页生成或加载私钥。签发前请核对公钥指纹与设备端一致。"))
|
||||
key_form.addRow("", hint("在「密钥」页生成或加载私钥。签发前请核对公钥指纹与设备端一致。"))
|
||||
root.addWidget(key_box)
|
||||
|
||||
# ---------- 签发依据 ----------
|
||||
@@ -109,9 +112,9 @@ class IssueTab(QWidget):
|
||||
)
|
||||
self.rc_edit.setMaximumHeight(76)
|
||||
rc_layout.addWidget(self.rc_edit)
|
||||
rc_btn = QPushButton("解析申请码")
|
||||
rc_btn.clicked.connect(self._parse_request_code)
|
||||
rc_layout.addWidget(rc_btn)
|
||||
rc_button = btn("解析申请码", icon_name="search")
|
||||
rc_button.clicked.connect(self._parse_request_code)
|
||||
rc_layout.addWidget(rc_button)
|
||||
self.stack.addWidget(page_rc)
|
||||
|
||||
# 页 1:来源 JSON 文件
|
||||
@@ -120,11 +123,9 @@ class IssueTab(QWidget):
|
||||
json_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.json_edit = QLineEdit()
|
||||
self.json_edit.setPlaceholderText("show --json 的导出文件(含 sources 字段,或就是来源字典)")
|
||||
json_browse = QPushButton("浏览…")
|
||||
json_browse.setFixedWidth(72)
|
||||
json_browse = btn("浏览…", icon_name="folder")
|
||||
json_browse.clicked.connect(self._pick_json)
|
||||
json_load = QPushButton("解析")
|
||||
json_load.setFixedWidth(72)
|
||||
json_load = btn("解析", icon_name="import_file")
|
||||
json_load.clicked.connect(self._parse_json_file)
|
||||
json_layout.addWidget(hbox(self.json_edit, json_browse, json_load))
|
||||
self.stack.addWidget(page_json)
|
||||
@@ -136,11 +137,11 @@ class IssueTab(QWidget):
|
||||
self.mc_edit = QLineEdit()
|
||||
self.mc_edit.setPlaceholderText("如 BC60-D20E-F863-7236-68E2-6A24")
|
||||
self.mc_edit.setFont(make_mono_label().font())
|
||||
mc_btn = QPushButton("使用该机器码")
|
||||
mc_btn.clicked.connect(self._use_machine_code)
|
||||
mc_layout.addWidget(hbox(self.mc_edit, mc_btn))
|
||||
mc_layout.addWidget(QLabel(
|
||||
"⚠ 仅按机器码精确匹配:换一块网卡就会失授权。建议改用申请码。"
|
||||
mc_button = btn("使用该机器码")
|
||||
mc_button.clicked.connect(self._use_machine_code)
|
||||
mc_layout.addWidget(hbox(self.mc_edit, mc_button))
|
||||
mc_layout.addWidget(hint(
|
||||
"⚠ 仅按机器码精确匹配:换一块网卡就会失授权。建议改用申请码。", role="warn"
|
||||
))
|
||||
self.stack.addWidget(page_mc)
|
||||
|
||||
@@ -161,36 +162,16 @@ class IssueTab(QWidget):
|
||||
root.addWidget(target_box)
|
||||
|
||||
# ---------- 授权插件 ----------
|
||||
# 勾选组件与台账「改插件」共用(plugin_picker):行直接加进本卡片,排版与
|
||||
# 抽出之前一致;下面几个属性名沿用旧名,既有代码与回归测试都在用
|
||||
plugin_box, plugin_form = section("授权插件")
|
||||
self.plugin_list = QListWidget()
|
||||
self.plugin_list.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||
self.plugin_list.setMaximumHeight(120)
|
||||
plugin_form.addRow("", self.plugin_list)
|
||||
|
||||
self.plugin_input = QLineEdit()
|
||||
self.plugin_input.setPlaceholderText("输入插件 type 后点「添加」")
|
||||
add_btn = QPushButton("添加")
|
||||
add_btn.setFixedWidth(72)
|
||||
add_btn.clicked.connect(self._add_plugin)
|
||||
remove_btn = QPushButton("移除选中")
|
||||
remove_btn.setFixedWidth(96)
|
||||
remove_btn.clicked.connect(self._remove_selected_plugins)
|
||||
all_btn = QPushButton("全选")
|
||||
all_btn.setFixedWidth(72)
|
||||
all_btn.clicked.connect(lambda: self._set_all_checked(True))
|
||||
none_btn = QPushButton("全不选")
|
||||
none_btn.setFixedWidth(72)
|
||||
none_btn.clicked.connect(lambda: self._set_all_checked(False))
|
||||
plugin_form.addRow(
|
||||
"", hbox(self.plugin_input, add_btn, remove_btn, all_btn, none_btn)
|
||||
self.plugin_picker = PluginPicker(
|
||||
plugin_form, settings, notify=lambda title, msg: warn(self, title, msg)
|
||||
)
|
||||
|
||||
self.root_edit = QLineEdit(str(settings.value("issue/root", str(Path.cwd()))))
|
||||
self.root_edit.setPlaceholderText("项目根目录(用于自动列出插件)")
|
||||
reload_btn = QPushButton("重新加载插件列表")
|
||||
reload_btn.setFixedWidth(140)
|
||||
reload_btn.clicked.connect(self._reload_plugins)
|
||||
plugin_form.addRow("项目根", hbox(self.root_edit, reload_btn))
|
||||
self.plugin_list = self.plugin_picker.list
|
||||
self.plugin_input = self.plugin_picker.input
|
||||
self.plugin_note = self.plugin_picker.note
|
||||
self.root_edit = self.plugin_picker.root_edit
|
||||
|
||||
root.addWidget(plugin_box)
|
||||
|
||||
@@ -247,16 +228,16 @@ class IssueTab(QWidget):
|
||||
self.preview.setPlaceholderText("载荷预览:点「刷新预览」")
|
||||
action_form.addRow("", self.preview)
|
||||
|
||||
refresh_btn = QPushButton("刷新预览")
|
||||
refresh_btn = btn("刷新预览", icon_name="refresh")
|
||||
refresh_btn.clicked.connect(self._refresh_preview)
|
||||
copy_btn = QPushButton("复制预览")
|
||||
copy_btn = btn("复制预览", icon_name="copy")
|
||||
copy_btn.clicked.connect(lambda: copy_to_clipboard(self.preview.toPlainText(), self))
|
||||
self.record_check = QCheckBox("签发后记入台账(便于日后续期与检索)")
|
||||
self.record_check.setChecked(True)
|
||||
self.record_check.setToolTip(
|
||||
"台账会连机器指纹一起存下来,续期时可直接复用,无需再向客户索取申请码"
|
||||
)
|
||||
self.issue_btn = QPushButton("签发并保存…")
|
||||
self.issue_btn = btn("签发并保存…", role="primary", icon_name="save")
|
||||
self.issue_btn.clicked.connect(self._issue)
|
||||
action_form.addRow("", hbox(refresh_btn, copy_btn, self.issue_btn))
|
||||
action_form.addRow("", self.record_check)
|
||||
@@ -280,60 +261,16 @@ class IssueTab(QWidget):
|
||||
self.key_fp.setText("—")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 插件列表
|
||||
# 插件列表(实现在 plugin_picker.PluginPicker,这里只为既有调用点留入口)
|
||||
# ------------------------------------------------------------------
|
||||
def _reload_plugins(self) -> None:
|
||||
root = self.root_edit.text().strip() or "."
|
||||
found = discover_plugin_types(root)
|
||||
note = ""
|
||||
if not found:
|
||||
found = list(FALLBACK_PLUGIN_TYPES)
|
||||
note = f"(未在 {root}/config/workers 找到插件,已用常见候选)"
|
||||
|
||||
# 保留用户已勾选的项,避免重新加载把选择清掉
|
||||
checked = self._checked_plugins()
|
||||
self.plugin_list.clear()
|
||||
for ptype in found:
|
||||
item = QListWidgetItem(ptype)
|
||||
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
||||
item.setCheckState(
|
||||
Qt.CheckState.Checked if ptype in checked else Qt.CheckState.Unchecked
|
||||
)
|
||||
self.plugin_list.addItem(item)
|
||||
if note:
|
||||
self.target_result.setText(self.target_result.text())
|
||||
self.settings.setValue("issue/root", root)
|
||||
self.plugin_picker.reload()
|
||||
|
||||
def _checked_plugins(self) -> list[str]:
|
||||
return [
|
||||
self.plugin_list.item(i).text()
|
||||
for i in range(self.plugin_list.count())
|
||||
if self.plugin_list.item(i).checkState() == Qt.CheckState.Checked
|
||||
]
|
||||
return self.plugin_picker.checked()
|
||||
|
||||
def _set_all_checked(self, checked: bool) -> None:
|
||||
state = Qt.CheckState.Checked if checked else Qt.CheckState.Unchecked
|
||||
for i in range(self.plugin_list.count()):
|
||||
self.plugin_list.item(i).setCheckState(state)
|
||||
|
||||
def _add_plugin(self) -> None:
|
||||
name = self.plugin_input.text().strip()
|
||||
if not name:
|
||||
return
|
||||
existing = {self.plugin_list.item(i).text() for i in range(self.plugin_list.count())}
|
||||
if name in existing:
|
||||
warn(self, "已存在", f"{name} 已在列表中。")
|
||||
self.plugin_input.clear()
|
||||
return
|
||||
item = QListWidgetItem(name)
|
||||
item.setFlags(item.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
||||
item.setCheckState(Qt.CheckState.Checked)
|
||||
self.plugin_list.addItem(item)
|
||||
self.plugin_input.clear()
|
||||
|
||||
def _remove_selected_plugins(self) -> None:
|
||||
for item in self.plugin_list.selectedItems():
|
||||
self.plugin_list.takeItem(self.plugin_list.row(item))
|
||||
self.plugin_picker.set_all(checked)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 签发依据解析
|
||||
@@ -346,7 +283,7 @@ class IssueTab(QWidget):
|
||||
self._sources = {}
|
||||
self._machine_code = ""
|
||||
self._source_note = ""
|
||||
self.target_result.setText("尚未解析签发对象")
|
||||
set_status(self.target_result, "尚未解析签发对象", "hint")
|
||||
self.sources_view.clear()
|
||||
self.preview.clear()
|
||||
|
||||
@@ -422,7 +359,9 @@ class IssueTab(QWidget):
|
||||
detail.append("⚠ 没有任何可信来源,判定将只依赖易重复的来源,安全性不足")
|
||||
else:
|
||||
detail.append("⚠ 无来源指纹:仅按机器码精确匹配,换硬件即失授权")
|
||||
self.target_result.setText("\n".join(detail))
|
||||
# 命中"⚠"时整块转警示色 —— 弱来源/无来源是签发前最该被看见的信息
|
||||
set_status(self.target_result, "\n".join(detail),
|
||||
"warn" if any("⚠" in line for line in detail) else "hint")
|
||||
|
||||
self.sources_view.setPlainText(
|
||||
"\n".join(f"{k} = {v}" for k, v in sorted(sources.items())) if sources else "(无)"
|
||||
|
||||
Reference in New Issue
Block a user