fix fix fix
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,3 +17,4 @@ android/.idea/caches
|
|||||||
ios/build
|
ios/build
|
||||||
ios/Pods
|
ios/Pods
|
||||||
android/app/release
|
android/app/release
|
||||||
|
__pycache__
|
||||||
|
|||||||
1
requirements-gui.txt
Normal file
1
requirements-gui.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
PySide6>=6.6.0
|
||||||
Submodule servers/walletman updated: 7ee1c24dd2...f5519400a0
12
upi.html
12
upi.html
@@ -140,6 +140,10 @@
|
|||||||
background: linear-gradient(135deg, #00897b, #4db6ac);
|
background: linear-gradient(135deg, #00897b, #4db6ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c-gpay {
|
||||||
|
background: linear-gradient(135deg, #1a73e8, #34a853);
|
||||||
|
}
|
||||||
|
|
||||||
.c-upi {
|
.c-upi {
|
||||||
background: linear-gradient(135deg, #37474f, #78909c);
|
background: linear-gradient(135deg, #37474f, #78909c);
|
||||||
}
|
}
|
||||||
@@ -192,6 +196,7 @@
|
|||||||
<option value="paytm">Paytm</option>
|
<option value="paytm">Paytm</option>
|
||||||
<option value="phonepe">PhonePe (native p2p)</option>
|
<option value="phonepe">PhonePe (native p2p)</option>
|
||||||
<option value="phonepe_pay">PhonePe (pay)</option>
|
<option value="phonepe_pay">PhonePe (pay)</option>
|
||||||
|
<option value="gpay">Google Pay</option>
|
||||||
<option value="mobikwik">MobiKwik</option>
|
<option value="mobikwik">MobiKwik</option>
|
||||||
<option value="freecharge">Freecharge</option>
|
<option value="freecharge">Freecharge</option>
|
||||||
<option value="upi">Other UPI</option>
|
<option value="upi">Other UPI</option>
|
||||||
@@ -253,7 +258,7 @@
|
|||||||
bharatpe_biz: {
|
bharatpe_biz: {
|
||||||
label: 'BharatPe Business',
|
label: 'BharatPe Business',
|
||||||
pa: 'BHARATPE.8A0T1R2O5E77327@fbpe', pn: 'BharatPe Merchant',
|
pa: 'BHARATPE.8A0T1R2O5E77327@fbpe', pn: 'BharatPe Merchant',
|
||||||
extra: () => '&tn=Pay%20To%20BharatPe%20Merchant',
|
extra: () => '&tn=Pay+To+BharatPe+Merchant',
|
||||||
warn: null,
|
warn: null,
|
||||||
},
|
},
|
||||||
paytm_per: {
|
paytm_per: {
|
||||||
@@ -276,7 +281,7 @@
|
|||||||
},
|
},
|
||||||
freecharge_per: {
|
freecharge_per: {
|
||||||
label: 'Freecharge Personal',
|
label: 'Freecharge Personal',
|
||||||
pa: 'simple6812@freecharge', pn: 'Gurvir Singh',
|
pa: '9124307439@freecharge', pn: 'Niranjan Mishra',
|
||||||
extra: () => '',
|
extra: () => '',
|
||||||
warn: null,
|
warn: null,
|
||||||
},
|
},
|
||||||
@@ -310,6 +315,7 @@
|
|||||||
paytm: (pa, pn, am, extra) => `paytmmp://cash_wallet?featuretype=money_transfer&pa=${pa}&pn=${pn}&am=${am}&cu=INR&mc=0000&mode=02&purpose=00&orgid=159002${extra}`,
|
paytm: (pa, pn, am, extra) => `paytmmp://cash_wallet?featuretype=money_transfer&pa=${pa}&pn=${pn}&am=${am}&cu=INR&mc=0000&mode=02&purpose=00&orgid=159002${extra}`,
|
||||||
phonepe: (pa, pn, am) => phonepeNative(pa, pn, am, 'payment'),
|
phonepe: (pa, pn, am) => phonepeNative(pa, pn, am, 'payment'),
|
||||||
phonepe_pay: (pa, pn, am, extra) => `phonepe://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
phonepe_pay: (pa, pn, am, extra) => `phonepe://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
|
gpay: (pa, pn, am, extra) => `tez://upi/pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
mobikwik: (pa, pn, am, extra) => { const tn = (extra.match(/[?&]tn=([^&]*)/) || [])[1] || 'payment'; return `mobikwik://moneytransfer/upi/verifyVpa?vpa=${encodeURIComponent(pa)}&amount=${am}¬e=${tn}`; },
|
mobikwik: (pa, pn, am, extra) => { const tn = (extra.match(/[?&]tn=([^&]*)/) || [])[1] || 'payment'; return `mobikwik://moneytransfer/upi/verifyVpa?vpa=${encodeURIComponent(pa)}&amount=${am}¬e=${tn}`; },
|
||||||
freecharge: (pa, pn, am, extra) => `freechargeupi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
freecharge: (pa, pn, am, extra) => `freechargeupi://pay?pa=${pa}&pn=${pn}&am=${am}&cu=INR${extra}`,
|
||||||
// fallback 在 scheduleAutoClick 里处理
|
// fallback 在 scheduleAutoClick 里处理
|
||||||
@@ -318,7 +324,7 @@
|
|||||||
|
|
||||||
const APP_COLORS = {
|
const APP_COLORS = {
|
||||||
paytm: 'c-paytm', phonepe: 'c-phonepe', phonepe_pay: 'c-phonepe',
|
paytm: 'c-paytm', phonepe: 'c-phonepe', phonepe_pay: 'c-phonepe',
|
||||||
mobikwik: 'c-mobikwik', freecharge: 'c-freecharge', upi: 'c-upi',
|
gpay: 'c-gpay', mobikwik: 'c-mobikwik', freecharge: 'c-freecharge', upi: 'c-upi',
|
||||||
};
|
};
|
||||||
|
|
||||||
const PHONEPE_WALLETS = new Set(['phonepe_biz', 'phonepe_per']);
|
const PHONEPE_WALLETS = new Set(['phonepe_biz', 'phonepe_per']);
|
||||||
|
|||||||
423
walletsgui.py
Normal file
423
walletsgui.py
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""wallets.json 图形管理(PySide6)。默认同目录下 servers/walletman/cmd/wallets.json。"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from PySide6.QtGui import QAction, QCloseEvent, QKeySequence
|
||||||
|
from PySide6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QComboBox,
|
||||||
|
QDialog,
|
||||||
|
QDialogButtonBox,
|
||||||
|
QFileDialog,
|
||||||
|
QFormLayout,
|
||||||
|
QHBoxLayout,
|
||||||
|
QHeaderView,
|
||||||
|
QLabel,
|
||||||
|
QLineEdit,
|
||||||
|
QMainWindow,
|
||||||
|
QMessageBox,
|
||||||
|
QPushButton,
|
||||||
|
QTableWidget,
|
||||||
|
QTableWidgetItem,
|
||||||
|
QTextEdit,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 与 servers/walletman/cmd/tools/main.go 中 walletTypeMenu 一致
|
||||||
|
WALLET_TYPES = [
|
||||||
|
"paytm",
|
||||||
|
"phonepe",
|
||||||
|
"mobikwik",
|
||||||
|
"freecharge",
|
||||||
|
"bharatpe business",
|
||||||
|
"paytm business",
|
||||||
|
"phonepe business",
|
||||||
|
"googlepay business",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def default_wallets_path() -> Path:
|
||||||
|
root = Path(__file__).resolve().parent
|
||||||
|
for rel in (
|
||||||
|
root / "servers" / "walletman" / "cmd" / "wallets.json",
|
||||||
|
root / "wallets.json",
|
||||||
|
):
|
||||||
|
if rel.is_file():
|
||||||
|
return rel
|
||||||
|
return root / "servers" / "walletman" / "cmd" / "wallets.json"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_params(s: str) -> dict[str, Any]:
|
||||||
|
s = s.strip()
|
||||||
|
if not s:
|
||||||
|
raise ValueError("params 为空")
|
||||||
|
return json.loads(s)
|
||||||
|
|
||||||
|
|
||||||
|
def format_params_pretty(s: str) -> str:
|
||||||
|
s = s.strip()
|
||||||
|
if not s:
|
||||||
|
return ""
|
||||||
|
return json.dumps(json.loads(s), ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
def compact_params_json(s: str) -> str:
|
||||||
|
return json.dumps(json.loads(s), ensure_ascii=False, separators=(",", ":"))
|
||||||
|
|
||||||
|
|
||||||
|
def suggest_wallet_id(wallet_type: str, params: str) -> str:
|
||||||
|
try:
|
||||||
|
p = json.loads(params)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return ""
|
||||||
|
mob = p.get("mobile")
|
||||||
|
if isinstance(mob, str) and mob:
|
||||||
|
return f"{wallet_type}_{mob}"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class WalletEditDialog(QDialog):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent: QWidget | None,
|
||||||
|
title: str,
|
||||||
|
wallet_type: str,
|
||||||
|
wallet_id: str,
|
||||||
|
params: str,
|
||||||
|
allow_change_id: bool = True,
|
||||||
|
*,
|
||||||
|
is_add: bool = False,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setMinimumSize(640, 480)
|
||||||
|
self._is_add = is_add
|
||||||
|
self._id_locked = not allow_change_id and bool(wallet_id)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
form = QFormLayout()
|
||||||
|
self.edit_uid: QLineEdit | None = None
|
||||||
|
if is_add:
|
||||||
|
self.edit_uid = QLineEdit("10000")
|
||||||
|
self.edit_uid.setPlaceholderText("如 10000")
|
||||||
|
form.addRow("用户", self.edit_uid)
|
||||||
|
self.combo_type = QComboBox()
|
||||||
|
self.combo_type.setEditable(True)
|
||||||
|
for t in WALLET_TYPES:
|
||||||
|
self.combo_type.addItem(t)
|
||||||
|
idx = self.combo_type.findText(wallet_type, Qt.MatchFlag.MatchFixedString)
|
||||||
|
if idx >= 0:
|
||||||
|
self.combo_type.setCurrentIndex(idx)
|
||||||
|
else:
|
||||||
|
self.combo_type.setCurrentText(wallet_type)
|
||||||
|
self.edit_id = QLineEdit(wallet_id)
|
||||||
|
self.edit_id.setPlaceholderText("留空则根据 params 里 mobile 自动生成")
|
||||||
|
if self._id_locked:
|
||||||
|
self.edit_id.setReadOnly(True)
|
||||||
|
form.addRow("类型", self.combo_type)
|
||||||
|
form.addRow("钱包 key", self.edit_id)
|
||||||
|
layout.addLayout(form)
|
||||||
|
self.text_params = QTextEdit()
|
||||||
|
self.text_params.setFontFamily("Menlo" if sys.platform == "darwin" else "Consolas")
|
||||||
|
self.text_params.setPlainText(params)
|
||||||
|
layout.addWidget(QLabel("params (JSON)"))
|
||||||
|
layout.addWidget(self.text_params, 1)
|
||||||
|
box = QDialogButtonBox(
|
||||||
|
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||||
|
)
|
||||||
|
box.accepted.connect(self._accept)
|
||||||
|
box.rejected.connect(self.reject)
|
||||||
|
layout.addWidget(box)
|
||||||
|
|
||||||
|
def _accept(self) -> None:
|
||||||
|
ptxt = self.text_params.toPlainText().strip()
|
||||||
|
try:
|
||||||
|
parse_params(ptxt)
|
||||||
|
except (json.JSONDecodeError, ValueError) as e:
|
||||||
|
QMessageBox.warning(self, "JSON 无效", str(e))
|
||||||
|
return
|
||||||
|
self._ok = True
|
||||||
|
self.accept()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user_id(self) -> str:
|
||||||
|
if not self._is_add or self.edit_uid is None:
|
||||||
|
return "10000"
|
||||||
|
return self.edit_uid.text().strip() or "10000"
|
||||||
|
return self.combo_type.currentText().strip()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wallet_id(self) -> str:
|
||||||
|
return self.edit_id.text().strip()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def params_compact(self) -> str:
|
||||||
|
return compact_params_json(self.text_params.toPlainText())
|
||||||
|
|
||||||
|
|
||||||
|
class WalletsWindow(QMainWindow):
|
||||||
|
COL_USER, COL_ID, COL_TYPE, COL_PREVIEW = 0, 1, 2, 3
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Wallets 管理器")
|
||||||
|
self.resize(1100, 600)
|
||||||
|
self._path: Path = default_wallets_path()
|
||||||
|
self._data: dict[str, dict[str, dict[str, str]]] = {}
|
||||||
|
self._dirty = False
|
||||||
|
|
||||||
|
central = QWidget()
|
||||||
|
self.setCentralWidget(central)
|
||||||
|
v = QVBoxLayout(central)
|
||||||
|
path_row = QHBoxLayout()
|
||||||
|
self.label_path = QLabel()
|
||||||
|
path_row.addWidget(self.label_path)
|
||||||
|
btn_browse = QPushButton("打开…")
|
||||||
|
btn_browse.clicked.connect(self._open_file)
|
||||||
|
path_row.addWidget(btn_browse)
|
||||||
|
v.addLayout(path_row)
|
||||||
|
|
||||||
|
self.table = QTableWidget(0, 4)
|
||||||
|
self.table.setHorizontalHeaderLabels(["用户", "Wallet ID", "类型", "params 摘要"])
|
||||||
|
self.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
|
||||||
|
self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
||||||
|
self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
|
||||||
|
self.table.doubleClicked.connect(self._on_double_click)
|
||||||
|
v.addWidget(self.table)
|
||||||
|
|
||||||
|
row = QHBoxLayout()
|
||||||
|
for text, fn in [
|
||||||
|
("重新加载", self._reload),
|
||||||
|
("保存", self._save),
|
||||||
|
("添加", self._add),
|
||||||
|
("编辑", self._edit),
|
||||||
|
("删除", self._delete),
|
||||||
|
]:
|
||||||
|
b = QPushButton(text)
|
||||||
|
b.clicked.connect(fn)
|
||||||
|
row.addWidget(b)
|
||||||
|
v.addLayout(row)
|
||||||
|
self._update_path_label()
|
||||||
|
self._build_menu()
|
||||||
|
self.statusBar().showMessage("就绪")
|
||||||
|
self._load_file(self._path, quiet=True)
|
||||||
|
|
||||||
|
def _build_menu(self) -> None:
|
||||||
|
m = self.menuBar().addMenu("文件")
|
||||||
|
a_open = QAction("打开…", self)
|
||||||
|
a_open.setShortcut(QKeySequence.StandardKey.Open)
|
||||||
|
a_open.triggered.connect(self._open_file)
|
||||||
|
m.addAction(a_open)
|
||||||
|
a_save = QAction("保存", self)
|
||||||
|
a_save.setShortcut(QKeySequence.StandardKey.Save)
|
||||||
|
a_save.triggered.connect(self._save)
|
||||||
|
m.addAction(a_save)
|
||||||
|
m.addSeparator()
|
||||||
|
a_exit = QAction("退出", self)
|
||||||
|
a_exit.setShortcut(QKeySequence.StandardKey.Quit)
|
||||||
|
a_exit.triggered.connect(self.close)
|
||||||
|
m.addAction(a_exit)
|
||||||
|
|
||||||
|
def _update_path_label(self) -> None:
|
||||||
|
self.label_path.setText(f"文件: {self._path} " + ("● 未保存" if self._dirty else ""))
|
||||||
|
self.label_path.setTextInteractionFlags(
|
||||||
|
Qt.TextInteractionFlag.TextSelectableByMouse
|
||||||
|
)
|
||||||
|
|
||||||
|
def _set_dirty(self, d: bool) -> None:
|
||||||
|
self._dirty = d
|
||||||
|
self._update_path_label()
|
||||||
|
|
||||||
|
def _load_file(self, path: Path, quiet: bool = False) -> None:
|
||||||
|
if not path.is_file():
|
||||||
|
self._data = {}
|
||||||
|
self._rebuild_table()
|
||||||
|
self._set_dirty(False)
|
||||||
|
if not quiet:
|
||||||
|
QMessageBox.information(self, "提示", f"文件不存在,将使用空数据:\n{path}")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
raw = path.read_text(encoding="utf-8")
|
||||||
|
self._data = json.loads(raw)
|
||||||
|
except (OSError, json.JSONDecodeError) as e:
|
||||||
|
QMessageBox.critical(self, "读取失败", str(e))
|
||||||
|
return
|
||||||
|
self._path = path.resolve()
|
||||||
|
self._rebuild_table()
|
||||||
|
self._set_dirty(False)
|
||||||
|
self.setWindowTitle(f"Wallets 管理器 — {self._path.name}")
|
||||||
|
|
||||||
|
def _reload(self) -> None:
|
||||||
|
if self._dirty:
|
||||||
|
r = QMessageBox.question(
|
||||||
|
self, "未保存", "是否丢弃未保存的修改?",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
|
)
|
||||||
|
if r != QMessageBox.StandardButton.Yes:
|
||||||
|
return
|
||||||
|
self._load_file(self._path, quiet=True)
|
||||||
|
|
||||||
|
def _save(self) -> None:
|
||||||
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
try:
|
||||||
|
text = json.dumps(self._data, ensure_ascii=False, indent=2) + "\n"
|
||||||
|
self._path.write_text(text, encoding="utf-8")
|
||||||
|
except OSError as e:
|
||||||
|
QMessageBox.critical(self, "保存失败", str(e))
|
||||||
|
return
|
||||||
|
self._set_dirty(False)
|
||||||
|
QMessageBox.information(self, "已保存", str(self._path))
|
||||||
|
|
||||||
|
def _open_file(self) -> None:
|
||||||
|
if self._dirty:
|
||||||
|
r = QMessageBox.question(
|
||||||
|
self, "未保存", "是否先保存?",
|
||||||
|
QMessageBox.StandardButton.Save
|
||||||
|
| QMessageBox.StandardButton.Discard
|
||||||
|
| QMessageBox.StandardButton.Cancel,
|
||||||
|
)
|
||||||
|
if r == QMessageBox.StandardButton.Save:
|
||||||
|
self._save()
|
||||||
|
elif r == QMessageBox.StandardButton.Cancel:
|
||||||
|
return
|
||||||
|
path, _ = QFileDialog.getOpenFileName(
|
||||||
|
self, "选择 wallets.json", str(self._path.parent), "JSON (*.json);;*.*"
|
||||||
|
)
|
||||||
|
if path:
|
||||||
|
self._load_file(Path(path))
|
||||||
|
|
||||||
|
def _rebuild_table(self) -> None:
|
||||||
|
rows: list[tuple[str, str, str, str]] = []
|
||||||
|
for uid, wallets in self._data.items():
|
||||||
|
for wid, ent in wallets.items():
|
||||||
|
wt = ent.get("walletType", "")
|
||||||
|
p = ent.get("params", "")
|
||||||
|
prev = p[:80] + ("…" if len(p) > 80 else "")
|
||||||
|
rows.append((str(uid), wid, str(wt), prev))
|
||||||
|
rows.sort(key=lambda x: (x[0], x[1]))
|
||||||
|
self.table.setRowCount(len(rows))
|
||||||
|
for i, (uid, wid, wt, prev) in enumerate(rows):
|
||||||
|
self.table.setItem(i, self.COL_USER, QTableWidgetItem(uid))
|
||||||
|
self.table.setItem(i, self.COL_ID, QTableWidgetItem(wid))
|
||||||
|
self.table.setItem(i, self.COL_TYPE, QTableWidgetItem(wt))
|
||||||
|
self.table.setItem(i, self.COL_PREVIEW, QTableWidgetItem(prev))
|
||||||
|
|
||||||
|
def _selected_cell(self) -> tuple[int, int] | None:
|
||||||
|
idx = self.table.currentIndex()
|
||||||
|
if not idx.isValid():
|
||||||
|
return None
|
||||||
|
return idx.row(), idx.column()
|
||||||
|
|
||||||
|
def _row_to_keys(self, row: int) -> tuple[str, str] | None:
|
||||||
|
u = self.table.item(row, self.COL_USER)
|
||||||
|
w = self.table.item(row, self.COL_ID)
|
||||||
|
if not u or not w:
|
||||||
|
return None
|
||||||
|
return u.text(), w.text()
|
||||||
|
|
||||||
|
def _on_double_click(self) -> None:
|
||||||
|
self._edit()
|
||||||
|
|
||||||
|
def _add(self) -> None:
|
||||||
|
default_type = WALLET_TYPES[0]
|
||||||
|
dlg = WalletEditDialog(self, "添加钱包", default_type, "", "{}", allow_change_id=True, is_add=True)
|
||||||
|
if dlg.exec() != QDialog.DialogCode.Accepted:
|
||||||
|
return
|
||||||
|
uid = dlg.user_id
|
||||||
|
wt, pid, pcompact = dlg.wallet_type, dlg.wallet_id, dlg.params_compact
|
||||||
|
if not pid:
|
||||||
|
pid = suggest_wallet_id(wt, pcompact)
|
||||||
|
if not pid:
|
||||||
|
QMessageBox.warning(self, "错误", "无法生成 Wallet ID,请填写「钱包 key」或确保 params 含 mobile")
|
||||||
|
return
|
||||||
|
if uid not in self._data:
|
||||||
|
self._data[uid] = {}
|
||||||
|
existed = pid in self._data[uid]
|
||||||
|
self._data[uid][pid] = {"walletType": wt, "params": pcompact}
|
||||||
|
self._rebuild_table()
|
||||||
|
self._set_dirty(True)
|
||||||
|
if existed:
|
||||||
|
self.statusBar().showMessage(f"已更新(原记录已存在): {uid} / {pid}", 5000)
|
||||||
|
else:
|
||||||
|
self.statusBar().showMessage(f"已添加: {uid} / {pid}", 5000)
|
||||||
|
|
||||||
|
def _edit(self) -> None:
|
||||||
|
sel = self._selected_cell()
|
||||||
|
if not sel:
|
||||||
|
QMessageBox.information(self, "提示", "先选中一行")
|
||||||
|
return
|
||||||
|
row = sel[0]
|
||||||
|
keys = self._row_to_keys(row)
|
||||||
|
if not keys:
|
||||||
|
return
|
||||||
|
uid, wid = keys
|
||||||
|
ent = self._data.get(uid, {}).get(wid)
|
||||||
|
if not ent:
|
||||||
|
return
|
||||||
|
wt = ent["walletType"]
|
||||||
|
try:
|
||||||
|
pretty = format_params_pretty(ent["params"])
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
pretty = str(ent.get("params", ""))
|
||||||
|
dlg = WalletEditDialog(self, "编辑钱包", wt, wid, pretty, allow_change_id=False, is_add=False)
|
||||||
|
if dlg.exec() != QDialog.DialogCode.Accepted:
|
||||||
|
return
|
||||||
|
nwt, _, pcompact = dlg.wallet_type, dlg.wallet_id, dlg.params_compact
|
||||||
|
self._data[uid][wid] = {"walletType": nwt, "params": pcompact}
|
||||||
|
self._rebuild_table()
|
||||||
|
self._set_dirty(True)
|
||||||
|
|
||||||
|
def _delete(self) -> None:
|
||||||
|
sel = self._selected_cell()
|
||||||
|
if not sel:
|
||||||
|
return
|
||||||
|
keys = self._row_to_keys(sel[0])
|
||||||
|
if not keys:
|
||||||
|
return
|
||||||
|
uid, wid = keys
|
||||||
|
if (
|
||||||
|
QMessageBox.question(
|
||||||
|
self, "删除", f"确定删除 {uid} / {wid} ?",
|
||||||
|
)
|
||||||
|
!= QMessageBox.StandardButton.Yes
|
||||||
|
):
|
||||||
|
return
|
||||||
|
self._data.get(uid, {}).pop(wid, None)
|
||||||
|
if self._data.get(uid) == {}:
|
||||||
|
self._data.pop(uid, None)
|
||||||
|
self._rebuild_table()
|
||||||
|
self._set_dirty(True)
|
||||||
|
|
||||||
|
def closeEvent(self, event: QCloseEvent) -> None:
|
||||||
|
if self._dirty:
|
||||||
|
r = QMessageBox.question(
|
||||||
|
self, "未保存", "是否保存后退出?",
|
||||||
|
QMessageBox.StandardButton.Save
|
||||||
|
| QMessageBox.StandardButton.Discard
|
||||||
|
| QMessageBox.StandardButton.Cancel,
|
||||||
|
)
|
||||||
|
if r == QMessageBox.StandardButton.Save:
|
||||||
|
self._save()
|
||||||
|
elif r == QMessageBox.StandardButton.Cancel:
|
||||||
|
event.ignore()
|
||||||
|
return
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
w = WalletsWindow()
|
||||||
|
w.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user