2026-06-04 10:06:57 +08:00

590 lines
19 KiB
JavaScript

(function () {
var EXCHANGE_RATE = 80000;
var WITHDRAW_MIN_AMOUNT = 50;
var params = new URLSearchParams(window.location.search);
var currentMode = normalizeMode(params.get('mode')) || 'transfer';
var state = {
balance: 0,
paymentInfo: null,
selectedPayee: null,
isSearching: false,
isSaving: false,
isSubmitting: false,
historyItems: [],
};
var lastSearchTriggerAt = 0;
var autoSearchTimer = 0;
var mock = {
balance: 30650.75,
paymentInfo: null,
payees: {
163003: {
id: 'payee_163003',
name: 'Yumi Star Agency',
account: '163003',
avatar: '',
},
163000: {
id: 'payee_163000',
name: 'quick_1780052629537',
account: '163000',
avatar: '',
},
},
history: [
{
key: 'withdraw_exchange.history_host_salary',
title: 'Host salary',
amount: 18400.25,
balance: 30650.75,
type: 0,
date: '2026-06-01 12:10',
},
{
key: 'withdraw_exchange.history_exchange_to_golds',
title: 'Exchange to golds',
amount: 800,
balance: 12250.5,
type: 1,
date: '2026-05-30 20:42',
},
{
key: 'withdraw_exchange.history_gift_reward',
title: 'Gift reward',
amount: 8250.5,
balance: 13050.5,
type: 0,
date: '2026-05-28 18:30',
},
],
};
var inputs = {
withdraw: $('withdrawAmount'),
exchange: $('exchangeAmount'),
transfer: $('transferAmount'),
};
function $(id) {
return document.getElementById(id);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function toast(message) {
if (window.HyAppToast) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function normalizeMode(mode) {
var value = String(mode || '').trim();
return ['withdraw', 'exchange', 'transfer'].indexOf(value) >= 0
? value
: '';
}
function money(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function moneyInput(value) {
var number = Number(value || 0);
return Number.isFinite(number) ? number.toFixed(2) : '0.00';
}
function amount() {
var input = inputs[currentMode];
return Number(input && input.value ? input.value : 0) || 0;
}
function delay(value) {
return new Promise(function (resolve) {
window.setTimeout(function () {
resolve(value);
}, 260);
});
}
function mockRequest(action, payload) {
if (action === 'balance') return delay(mock.balance);
if (action === 'payment') return delay(mock.paymentInfo);
if (action === 'history') return delay(mock.history.slice());
if (action === 'saveAddress') {
mock.paymentInfo = {
id: 'usdt_mock_1',
cardNo: payload.cardNo,
};
return delay(mock.paymentInfo);
}
if (action === 'searchPayee') {
var account = String(payload.account || '').trim();
var payee = mock.payees[account];
if (!payee && account && account !== '000000') {
payee = {
id: 'payee_' + account,
name: 'User ' + account,
nameKey: 'withdraw_exchange.mock_user_name',
account: account,
avatar: '',
};
}
return delay(payee || null);
}
if (action === 'submit') {
mock.balance = Math.max(0, mock.balance - payload.amount);
mock.history.unshift({
title: titleForMode(payload.mode),
amount: payload.amount,
balance: mock.balance,
type: 1,
date: new Date().toISOString().replace('T', ' ').slice(0, 16),
});
return delay({ ok: true });
}
return delay(null);
}
function titleForMode(mode) {
if (mode === 'withdraw')
return t('withdraw_exchange.withdraw', 'Withdraw');
if (mode === 'exchange')
return t('withdraw_exchange.exchange', 'Exchange');
return t('withdraw_exchange.transfer', 'Transfer');
}
function isValidTrc20(value) {
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || '').trim());
}
function maskAddress(value) {
var text = String(value || '').trim();
if (text.length <= 12) return text || '-';
return text.slice(0, 6) + '...' + text.slice(-6);
}
function activeSubmitLabel() {
if (currentMode === 'withdraw')
return t('withdraw_exchange.withdraw_now', 'Withdraw now');
if (currentMode === 'exchange')
return t('withdraw_exchange.exchange_now', 'Exchange now');
return t('withdraw_exchange.transfer_now', 'Transfer now');
}
function renderBalance() {
$('balanceAmount').textContent = money(state.balance);
Object.keys(inputs).forEach(function (key) {
if (inputs[key]) inputs[key].max = moneyInput(state.balance);
});
}
function renderMode() {
document.querySelectorAll('.mode-tab').forEach(function (tab) {
var active = tab.getAttribute('data-mode') === currentMode;
tab.classList.toggle('active', active);
tab.setAttribute('aria-selected', String(active));
});
document.querySelectorAll('.mode-panel').forEach(function (panel) {
panel.classList.toggle(
'active',
panel.getAttribute('data-panel') === currentMode
);
});
$('paymentSection').hidden = currentMode !== 'withdraw';
updateSubmit();
}
function renderPaymentInfo() {
var payment = state.paymentInfo;
$('emptyAddressState').hidden = Boolean(payment);
$('addressForm').hidden = Boolean(payment);
$('boundAddressCard').hidden = !payment;
if (payment)
$('boundAddress').textContent = maskAddress(payment.cardNo);
updateSubmit();
}
function renderPayee() {
var result = $('payeeResult');
result.textContent = '';
if (!state.selectedPayee) {
result.hidden = true;
updateSubmit();
return;
}
var payee = state.selectedPayee;
var payeeName = payee.nameKey
? t(payee.nameKey, payee.name || 'User {account}').replace(
'{account}',
payee.account
)
: payee.name;
var avatar = document.createElement('div');
var copy = document.createElement('div');
var name = document.createElement('div');
var id = document.createElement('div');
avatar.className = 'payee-avatar';
copy.className = 'payee-copy';
name.className = 'payee-name';
id.className = 'payee-id';
avatar.textContent = String(payeeName || 'U')
.charAt(0)
.toUpperCase();
name.textContent = payeeName || '-';
id.textContent =
t('withdraw_exchange.uid_prefix', 'UID:') + ' ' + payee.account;
copy.appendChild(name);
copy.appendChild(id);
result.appendChild(avatar);
result.appendChild(copy);
result.hidden = false;
updateSubmit();
}
function renderHistory() {
$('salaryHistoryTotal').textContent = '$' + money(state.balance);
var list = $('salaryHistoryList');
list.textContent = '';
if (!state.historyItems.length) {
var empty = document.createElement('div');
empty.className = 'salary-history-empty';
empty.textContent = t(
'withdraw_exchange.no_salary_history',
'No salary history'
);
list.appendChild(empty);
return;
}
state.historyItems.forEach(function (item) {
var row = document.createElement('article');
var main = document.createElement('div');
var title = document.createElement('div');
var meta = document.createElement('div');
var value = document.createElement('div');
var isOut = Number(item.type) === 1;
row.className = 'salary-history-item';
main.className = 'salary-history-item-main';
title.className = 'salary-history-item-title';
meta.className = 'salary-history-item-meta';
value.className =
'salary-history-amount' + (isOut ? ' is-out' : '');
title.textContent = item.key ? t(item.key, item.title) : item.title;
meta.textContent =
item.date +
' ' +
t('withdraw_exchange.balance', 'Balance') +
': $' +
money(item.balance);
value.textContent = (isOut ? '-' : '+') + '$' + money(item.amount);
main.appendChild(title);
main.appendChild(meta);
row.appendChild(main);
row.appendChild(value);
list.appendChild(row);
});
}
function updateSubmit() {
var button = $('submitButton');
if (state.isSubmitting) {
button.textContent = t(
'withdraw_exchange.submitting',
'Submitting...'
);
button.disabled = true;
return;
}
var value = amount();
var disabled =
value <= 0 ||
value > state.balance ||
(currentMode === 'withdraw' &&
(!state.paymentInfo || value < WITHDRAW_MIN_AMOUNT)) ||
(currentMode === 'transfer' && !state.selectedPayee);
button.textContent = activeSubmitLabel();
button.disabled = disabled;
}
function normalizeAmount(event) {
var input = event.target;
var raw = String(input.value || '').replace(/[^\d.]/g, '');
var parts = raw.split('.');
var next =
parts.length > 2 ? parts[0] + '.' + parts.slice(1).join('') : raw;
var value = Number(next);
if (Number.isFinite(value) && value > state.balance)
next = moneyInput(state.balance);
input.value = next;
updateSubmit();
}
function setMode(mode) {
currentMode = normalizeMode(mode) || 'transfer';
renderMode();
}
function openHistory() {
$('salaryHistoryModal').hidden = false;
document.body.classList.add('modal-open');
$('salaryHistoryList').textContent = t(
'withdraw_exchange.loading',
'Loading...'
);
mockRequest('history').then(function (items) {
state.historyItems = items || [];
renderHistory();
});
}
function closeHistory() {
$('salaryHistoryModal').hidden = true;
document.body.classList.remove('modal-open');
}
function saveAddress() {
var address = String($('trc20Address').value || '').trim();
if (!isValidTrc20(address)) {
toast(
t(
'withdraw_exchange.invalid_address',
'Please enter a valid TRC20 USDT address'
)
);
return;
}
state.isSaving = true;
$('saveAddressButton').disabled = true;
$('saveAddressButton').textContent = t(
'withdraw_exchange.saving',
'Saving...'
);
mockRequest('saveAddress', { cardNo: address }).then(
function (payment) {
state.paymentInfo = payment;
state.isSaving = false;
$('saveAddressButton').disabled = false;
$('saveAddressButton').textContent = t(
'withdraw_exchange.save_address',
'Save address'
);
renderPaymentInfo();
toast(t('withdraw_exchange.address_saved', 'Address saved'));
}
);
}
function searchPayee() {
var now = Date.now();
if (now - lastSearchTriggerAt < 240) return;
lastSearchTriggerAt = now;
var account = String($('transferAccount').value || '').trim();
if (!account) {
toast(
t(
'withdraw_exchange.missing_payee',
'Please search and select a user'
)
);
return;
}
state.selectedPayee = null;
renderPayee();
state.isSearching = true;
$('searchPayeeButton').disabled = true;
$('searchPayeeButton').textContent = t(
'withdraw_exchange.searching',
'Searching...'
);
mockRequest('searchPayee', { account: account }).then(function (payee) {
state.isSearching = false;
$('searchPayeeButton').disabled = false;
$('searchPayeeButton').textContent = t(
'withdraw_exchange.search',
'Search'
);
if (!payee) {
toast(t('withdraw_exchange.payee_not_found', 'User not found'));
return;
}
state.selectedPayee = payee;
renderPayee();
});
}
function validateSubmit() {
var value = amount();
if (value <= 0)
return t(
'withdraw_exchange.invalid_amount',
'Please enter a valid amount'
);
if (value > state.balance)
return t(
'withdraw_exchange.amount_exceeds_balance',
'Amount exceeds salary'
);
if (currentMode === 'withdraw' && !state.paymentInfo)
return t(
'withdraw_exchange.missing_payment_info',
'Please add a TRC20 USDT address'
);
if (currentMode === 'withdraw' && value < WITHDRAW_MIN_AMOUNT)
return t(
'withdraw_exchange.amount_too_low',
'Minimum withdrawal amount is 50 USD'
);
if (currentMode === 'transfer' && !state.selectedPayee)
return t(
'withdraw_exchange.missing_payee',
'Please search and select a user'
);
return '';
}
function submit() {
var error = validateSubmit();
if (error) {
toast(error);
return;
}
state.isSubmitting = true;
updateSubmit();
mockRequest('submit', {
mode: currentMode,
amount: amount(),
payee: state.selectedPayee,
paymentInfo: state.paymentInfo,
}).then(function () {
var input = inputs[currentMode];
if (input) input.value = '';
if (currentMode === 'transfer') {
state.selectedPayee = null;
$('transferAccount').value = '';
renderPayee();
}
state.balance = mock.balance;
state.isSubmitting = false;
renderBalance();
updateSubmit();
var key =
currentMode === 'withdraw'
? 'withdraw_exchange.withdraw_success'
: currentMode === 'exchange'
? 'withdraw_exchange.exchange_success'
: 'withdraw_exchange.transfer_success';
toast(t(key, 'Submitted'));
});
}
function goBack() {
if (window.history.length > 1) {
window.history.back();
return;
}
var nextParams = new URLSearchParams(window.location.search);
nextParams.delete('mode');
var query = nextParams.toString();
window.location.href =
'../host-center/index.html' + (query ? '?' + query : '');
}
function bindEvents() {
function bindTap(id, handler) {
var node = $(id);
var last = 0;
function run(event) {
var now = Date.now();
if (now - last < 220) return;
last = now;
if (event && event.type === 'pointerdown') {
event.preventDefault();
}
handler(event);
}
node.addEventListener('pointerdown', run);
node.addEventListener('click', run);
}
bindTap('backButton', goBack);
document.querySelectorAll('.mode-tab').forEach(function (tab) {
tab.addEventListener('click', function () {
setMode(tab.getAttribute('data-mode'));
});
});
Object.keys(inputs).forEach(function (key) {
if (inputs[key])
inputs[key].addEventListener('input', normalizeAmount);
});
bindTap('allButton', function () {
inputs.withdraw.value = moneyInput(state.balance);
updateSubmit();
});
$('transferAccount').addEventListener('input', function () {
state.selectedPayee = null;
renderPayee();
window.clearTimeout(autoSearchTimer);
if (String($('transferAccount').value || '').trim().length >= 3) {
autoSearchTimer = window.setTimeout(searchPayee, 260);
}
});
$('transferAccount').addEventListener('keydown', function (event) {
if (event.key === 'Enter') searchPayee();
});
bindTap('searchPayeeButton', searchPayee);
bindTap('saveAddressButton', saveAddress);
bindTap('submitButton', submit);
bindTap('salaryHistoryButton', openHistory);
bindTap('salaryHistoryBackdrop', closeHistory);
bindTap('salaryHistoryCloseButton', closeHistory);
}
function renderStaticDynamicText() {
$('exchangeRateText').textContent = t(
'withdraw_exchange.exchange_rate_value',
'1$ = {amount} golds'
).replace('{amount}', EXCHANGE_RATE.toLocaleString('en-US'));
if (!$('salaryHistoryModal').hidden) renderHistory();
updateSubmit();
renderPayee();
}
function init() {
bindEvents();
setMode(currentMode);
renderStaticDynamicText();
mockRequest('balance').then(function (balance) {
state.balance = balance;
renderBalance();
updateSubmit();
});
mockRequest('payment').then(function (payment) {
state.paymentInfo = payment;
renderPaymentInfo();
});
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'withdraw-exchange',
mock: true,
});
}
}
document.addEventListener('DOMContentLoaded', init);
window.addEventListener('hyapp:i18n-ready', renderStaticDynamicText);
})();