feat: 2.3.2

This commit is contained in:
2026-05-19 17:30:29 +08:00
parent 7ca11c6534
commit 8430d1054e
39 changed files with 6581 additions and 738 deletions
+135 -3
View File
@@ -20,6 +20,9 @@ signal closed
@onready var ban_btn := %BanBtn as Button
@onready var unban_btn := %UnbanBtn as Button
@onready var delete_btn := %DeleteBtn as Button
@onready var history_btn := %HistoryBtn as Button
@onready var history_dialog := %HistoryDialog as AcceptDialog
@onready var history_text := %HistoryText as RichTextLabel
# Tab: Leaderboards
@onready var lb_tree := %LeaderboardTree as Tree
@@ -61,6 +64,11 @@ var _resolved_user_id: String = ""
var _mail_root: TreeItem
var _all_server_mails: Array = []
# Tab: Shop (Featured Banners)
@onready var slots_vbox := %SlotsVBox as VBoxContainer
@onready var load_banners_btn := %LoadBannersBtn as Button
@onready var save_banners_btn := %SaveBannersBtn as Button
const MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
# -- Data --
@@ -178,6 +186,7 @@ func _connect_signals() -> void:
ban_btn.pressed.connect(_on_ban)
unban_btn.pressed.connect(_on_unban)
delete_btn.pressed.connect(_on_delete)
history_btn.pressed.connect(_on_history_pressed)
user_tree.item_edited.connect(_on_user_tree_item_edited)
user_tree.button_clicked.connect(_on_user_tree_button_clicked)
@@ -204,6 +213,10 @@ func _connect_signals() -> void:
delete_mail_server_btn.pressed.connect(_on_delete_mail_server_pressed)
_update_mail_action_btns(null)
# Shop actions
load_banners_btn.pressed.connect(func(): await _load_featured_banners())
save_banners_btn.pressed.connect(func(): await _save_featured_banners())
# =============================================================================
# Core Panel Logic
# =============================================================================
@@ -228,6 +241,8 @@ func _on_tab_changed(tab_index: int) -> void:
await _load_daily_rewards_config()
elif tab_index == 4:
await _load_mail()
elif tab_index == 5:
await _load_featured_banners()
# =============================================================================
# RPC Helper
@@ -262,7 +277,8 @@ func _load_users() -> void:
_set_status("Failed: " + str(res.error), CLR_STATUS_ERR)
return
all_users = res.get("users", [])
var raw_users = res.get("users", [])
all_users = raw_users if typeof(raw_users) == TYPE_ARRAY else []
count_label.text = "%d users" % all_users.size()
for user in all_users:
@@ -464,6 +480,63 @@ func _on_unban() -> void:
_set_status("Unbanned %d/%d" % [ok, to_unban.size()], CLR_STATUS_OK)
await _load_users()
func _on_history_pressed() -> void:
var selected_data = _get_checked_user_data()
if selected_data.size() != 1:
_set_status("Please select exactly ONE user to view history.", CLR_STATUS_ERR)
return
var uid = selected_data[0].get("user_id", "")
_set_status("Fetching history for user...", CLR_STATUS_OK)
var res = await _rpc("admin_get_user_history", {"user_id": uid})
if res.has("error"):
_set_status("Failed to get history: " + str(res.error), CLR_STATUS_ERR)
return
_set_status("History loaded.", CLR_STATUS_OK)
var h = res.get("history", {})
var text = "[b]=== USER HISTORY ===[/b]\n"
text += "User ID: " + uid + "\n\n"
# Logins
text += "[b]-- Recent Logins --[/b]\n"
var logins = h.get("logins", [])
if logins.is_empty():
text += "No recent logins found.\n"
else:
for l in logins:
var time_str = Time.get_datetime_string_from_unix_time(int(l.get("time", 0)))
text += "- %s (IP: %s)\n" % [time_str, l.get("ip", "unknown")]
text += "\n"
# Wallet Ledger
text += "[b]-- Economy / Wallet Ledger --[/b]\n"
var ledger = h.get("wallet_ledger", [])
if ledger.is_empty():
text += "No transactions found.\n"
else:
for item in ledger:
var changeset = str(item.get("changeset", {}))
var c_time = item.get("create_time", "")
text += "- [%s] %s\n" % [c_time.left(19).replace("T", " "), changeset]
text += "\n"
# Matches
text += "[b]-- Matches --[/b]\n"
var matches = h.get("matches", [])
if matches.is_empty():
text += "No match history found.\n"
else:
for m in matches:
text += "- " + str(m) + "\n"
history_text.text = text
history_dialog.popup_centered()
func _on_delete() -> void:
var users := _get_checked_user_data()
if users.is_empty(): return
@@ -498,7 +571,8 @@ func _load_leaderboard() -> void:
_set_status("Failed to load scores", CLR_STATUS_ERR)
return
lb_data = res.get("leaderboard", [])
var raw_lb = res.get("leaderboard", [])
lb_data = raw_lb if typeof(raw_lb) == TYPE_ARRAY else []
count_label.text = "%d records" % lb_data.size()
lb_data.sort_custom(func(a, b): return a.get("high_score", 0) > b.get("high_score", 0))
@@ -824,7 +898,8 @@ func _load_mail() -> void:
_set_status("Failed: " + str(res.error), CLR_STATUS_ERR)
return
_all_server_mails = res.get("mails", [])
var raw_mails = res.get("mails", [])
_all_server_mails = raw_mails if typeof(raw_mails) == TYPE_ARRAY else []
count_label.text = "%d mails" % _all_server_mails.size()
var now_str = Time.get_datetime_string_from_system(true)
@@ -1065,3 +1140,60 @@ func _on_delete_mail_server_pressed() -> void:
await _load_mail()
confirm.queue_free()
)
# =============================================================================
# TAB 6: SHOP — FEATURED BANNERS
# =============================================================================
var _slot_nodes: Array = [] # cached references to the 3 slot HBoxContainers
func _get_slot_nodes() -> Array:
if _slot_nodes.is_empty():
for child in slots_vbox.get_children():
if child is HBoxContainer:
_slot_nodes.append(child)
return _slot_nodes
func _load_featured_banners() -> void:
_set_status("Loading banners...")
var res := await _rpc("admin_get_featured_banners", {})
if res.has("error"):
_set_status("Failed: " + str(res.error), CLR_STATUS_ERR)
return
var raw_banners = res.get("banners", [])
var banners: Array = raw_banners if typeof(raw_banners) == TYPE_ARRAY else []
var slots := _get_slot_nodes()
for i in range(slots.size()):
var slot: HBoxContainer = slots[i]
var id_edit: LineEdit = slot.get_node("ItemIdEdit") as LineEdit
var lbl_edit: LineEdit = slot.get_node("LabelEdit") as LineEdit
if i < banners.size():
var b: Dictionary = banners[i] if banners[i] is Dictionary else {}
id_edit.text = b.get("item_id", "")
lbl_edit.text = b.get("label", "")
else:
id_edit.text = ""
lbl_edit.text = ""
count_label.text = "%d banners configured" % banners.size()
_set_status("Banners loaded", CLR_STATUS_OK)
func _save_featured_banners() -> void:
var banners: Array = []
var slots := _get_slot_nodes()
for slot in slots:
var id_edit: LineEdit = slot.get_node("ItemIdEdit") as LineEdit
var lbl_edit: LineEdit = slot.get_node("LabelEdit") as LineEdit
var item_id: String = id_edit.text.strip_edges()
var label: String = lbl_edit.text.strip_edges()
if not item_id.is_empty():
banners.append({"item_id": item_id, "label": label})
_set_status("Saving banners...")
var res := await _rpc("admin_set_featured_banners", {"banners": banners})
if res.has("error"):
_set_status("Save failed: " + str(res.error), CLR_STATUS_ERR)
elif res.has("success"):
_set_status("Banners saved! (%d slots)" % banners.size(), CLR_STATUS_OK)