139 lines
5.4 KiB
GDScript
139 lines
5.4 KiB
GDScript
class_name PayPanel
|
||
extends PanelModule
|
||
|
||
# 充值/充值入口面板:
|
||
# - 负责充值、金豆购买等配置展示和模拟购买流程。
|
||
# - 海外 H5 首版不接真实支付 SDK,本面板只保留 UI 和后端接口入口。
|
||
# - 商品卡片不保存全局状态,支付结果通过 callbacks 更新玩家资源。
|
||
const NumberFormatterScript := preload("res://scripts/core/number_formatter.gd")
|
||
|
||
var _pay_api
|
||
var _tab_index := 0
|
||
var _content: Control
|
||
|
||
|
||
func setup(options: Dictionary) -> void:
|
||
super.setup(options)
|
||
_pay_api = options.get("pay_api")
|
||
|
||
|
||
func open() -> void:
|
||
_close_modal(false)
|
||
_tab_index = 0
|
||
var common_path: String = _texture_provider.atlas_path("common")
|
||
var panel: Control = _ui.create_common_panel_shell("PayPanel", Vector2(600.0, 790.0), "panel_icon_pay", common_path, "panel_title_pay", common_path)
|
||
_ui.add_content_panel_background(panel, "PayInner", Vector2(78.0, 238.0), Vector2(484.0, 550.0))
|
||
_create_tab_bar(panel, "PayTabs", ["金豆充值"], Vector2(93.0, 189.0), _tab_index, Callable(self, "_on_tab_pressed"))
|
||
_content = Control.new()
|
||
_content.name = "PayContent"
|
||
_content.position = Vector2(83.0, 242.0)
|
||
_content.size = Vector2(476.0, 540.0)
|
||
panel.add_child(_content)
|
||
_open_modal(panel)
|
||
render()
|
||
|
||
|
||
func _on_tab_pressed(index: int) -> void:
|
||
_tab_index = 0
|
||
var panel := _content.get_parent() as Control if _content != null else null
|
||
var tabs := panel.get_node_or_null("PayTabs") as Control if panel != null else null
|
||
_update_tab_bar(tabs, _tab_index)
|
||
render()
|
||
|
||
|
||
func render() -> void:
|
||
if _content == null:
|
||
return
|
||
_clear_children(_content)
|
||
var rows := _filter_rows(_tab_index)
|
||
if rows.is_empty():
|
||
_ui.add_panel_label(_content, "Empty", "暂无充值配置", Vector2(6.0, 196.0), Vector2(464.0, 52.0), 26, Color.html("#753f24"), 0, Color.TRANSPARENT)
|
||
return
|
||
for index in range(mini(rows.size(), 6)):
|
||
var row := rows[index]
|
||
var col := index % 3
|
||
var row_index := index / 3
|
||
var card_position := Vector2(10.0 + float(col) * 145.0, 10.0 + float(row_index) * 262.0)
|
||
_add_card(_content, row, index, card_position)
|
||
|
||
|
||
func _filter_rows(tab_index: int) -> Array[Dictionary]:
|
||
var result: Array[Dictionary] = []
|
||
for raw_row in _game_config.get_pay_config_list():
|
||
if not raw_row is Dictionary:
|
||
continue
|
||
var row: Dictionary = raw_row.duplicate(true)
|
||
var id := int(row.get("id", 0))
|
||
var is_gold := int(row.get("gold", 0)) > 0 or id > 6
|
||
if is_gold:
|
||
result.append(row)
|
||
result.sort_custom(func(left: Dictionary, right: Dictionary) -> bool:
|
||
return int(left.get("id", 0)) < int(right.get("id", 0))
|
||
)
|
||
return result
|
||
|
||
|
||
func _add_card(parent: Control, row: Dictionary, index: int, position: Vector2) -> void:
|
||
var holder := Control.new()
|
||
holder.name = "PayItem%s" % index
|
||
holder.position = position
|
||
holder.size = Vector2(134.0, 255.0)
|
||
holder.pivot_offset = holder.size * 0.5
|
||
holder.mouse_filter = Control.MOUSE_FILTER_STOP
|
||
parent.add_child(holder)
|
||
|
||
_ui.add_texture(holder, "Bg", _texture_provider.standalone("res://assets/egret/assets/game/pay/pay_item_bg.png"), Vector2.ZERO, Vector2(134.0, 224.0), TextureRect.STRETCH_SCALE)
|
||
var icon_prefix := "pay_g"
|
||
var icon_path := "res://assets/egret/assets/game/pay/%s%s.png" % [icon_prefix, index + 1]
|
||
_ui.add_texture(holder, "PayIcon", _texture_provider.standalone(icon_path, _texture_provider.standalone("res://assets/egret/assets/game/pay/pay_d1.png")), Vector2(25.0, 31.0), Vector2(85.0, 75.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
|
||
_ui.add_texture(holder, "ValueBar", _texture_provider.standalone("res://assets/egret/assets/game/pay/pay_bar.png"), Vector2(0.0, 126.0), Vector2(134.0, 36.0), TextureRect.STRETCH_SCALE)
|
||
var currency_icon: Texture2D = _texture_provider.common("sicon_gold")
|
||
_ui.add_texture(holder, "Currency", currency_icon, Vector2(12.0, 132.0), Vector2(32.0, 31.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
|
||
_ui.add_panel_label(holder, "Value", NumberFormatterScript.compact(_pay_value(row)), Vector2(43.0, 133.0), Vector2(88.0, 31.0), 22, Color.html("#f7b607"), 2, Color.html("#7d4b21"), HORIZONTAL_ALIGNMENT_LEFT)
|
||
_ui.add_texture_button(holder, "Buy", _texture_provider.common("c_btn2"), Vector2(26.0, 179.0), Vector2(88.0, 44.0), "购买", Callable(self, "_buy_item").bind(row.duplicate(true)), 22)
|
||
_ui.add_panel_label(holder, "Price", "¥%s" % int(row.get("rmb", 0)), Vector2(3.0, 228.0), Vector2(132.0, 27.0), 22, Color.html("#ff9b73"), 2, Color.WHITE)
|
||
|
||
|
||
func _pay_value(row: Dictionary) -> int:
|
||
return int(row.get("gold", 0))
|
||
|
||
|
||
func _buy_item(row: Dictionary) -> void:
|
||
if _is_busy():
|
||
return
|
||
var token := _token()
|
||
var pay_id := int(row.get("id", 0))
|
||
if token.is_empty() or pay_id <= 0:
|
||
_show_toast("登录信息失效")
|
||
return
|
||
_set_busy(true)
|
||
var result: Dictionary = await _pay_api.buy(token, pay_id)
|
||
_set_busy(false)
|
||
if not result.get("ok", false):
|
||
_show_toast(_response_status_text(result, "充值下单失败"))
|
||
return
|
||
var url := _payment_url(result)
|
||
if url.is_empty():
|
||
_show_toast("充值下单成功")
|
||
return
|
||
_show_toast("正在打开支付")
|
||
_open_payment_url(url)
|
||
|
||
|
||
func _payment_url(result: Dictionary) -> String:
|
||
var data = _response_data(result, {})
|
||
if data is Dictionary:
|
||
return str(data.get("url", data.get("pay_url", "")))
|
||
return ""
|
||
|
||
|
||
func _open_payment_url(url: String) -> void:
|
||
if url.strip_edges().is_empty():
|
||
return
|
||
if Engine.has_singleton("JavaScriptBridge"):
|
||
var bridge := Engine.get_singleton("JavaScriptBridge")
|
||
if bridge != null:
|
||
bridge.call("eval", "window.location.href = %s;" % JSON.stringify(url), true)
|
||
return
|
||
OS.shell_open(url)
|