2026-07-02 11:01:56 +08:00

1189 lines
40 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function () {
var EXCHANGE_RATE = 80000;
var WITHDRAW_MIN_AMOUNT = 50;
var params = new URLSearchParams(window.location.search);
var isMock = params.get('mock') === '1';
var currentMode = normalizeMode(params.get('mode')) || 'transfer';
var identity = String(params.get('identity') || '').trim();
var salaryAssetType = String(
params.get('salaryType') || params.get('asset_type') || ''
).trim();
var state = {
balance: 0,
paymentInfo: null,
selectedPayee: null,
isSearching: false,
isSaving: false,
isEditingAddress: false,
isSavingContact: false,
isSubmitting: false,
contactInfo: '',
historyItems: [],
transferRateTiers: [],
};
var lastSearchTriggerAt = 0;
var autoSearchTimer = 0;
var mockBalances = {
HOST_SALARY_USD: 30650.75,
AGENCY_SALARY_USD: 30650.75,
BD_SALARY_USD: 48620.8,
ADMIN_SALARY_USD: 168250.5,
};
var mock = {
balance: mockBalances[salaryAssetType] || 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: historyTitleKey(),
title: historyTitle(),
amount: 18400.25,
balance: mockBalances[salaryAssetType] || 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 normalizeIdentity(value) {
value = String(value || '')
.trim()
.toUpperCase()
.replace(/-/g, '_');
if (value === 'ADMIN') return 'BD_LEADER';
if (['HOST', 'AGENCY', 'BD', 'BD_LEADER'].indexOf(value) >= 0)
return value;
if (salaryAssetType === 'AGENCY_SALARY_USD') return 'AGENCY';
if (salaryAssetType === 'BD_SALARY_USD') return 'BD';
if (salaryAssetType === 'ADMIN_SALARY_USD') return 'BD_LEADER';
return 'HOST';
}
function api() {
if (window.HyAppAPI && window.HyAppAPI.salaryWallet)
return window.HyAppAPI.salaryWallet;
return window.HyApp && window.HyApp.api
? window.HyApp.api.salaryWallet
: null;
}
function userApi() {
if (window.HyAppAPI && window.HyAppAPI.user)
return window.HyAppAPI.user;
return window.HyApp && window.HyApp.api ? window.HyApp.api.user : null;
}
function commandId(prefix) {
return (
prefix +
'-' +
Date.now() +
'-' +
Math.random().toString(16).slice(2)
);
}
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 amountText(value) {
return moneyInput(value);
}
function usdMinorToNumber(value) {
return Number(value || 0) / 100;
}
function salaryBalanceAfterToNumber(value) {
if (value && typeof value === 'object') {
return usdMinorToNumber(value.available_amount);
}
return usdMinorToNumber(value);
}
function findTransferRate(value) {
var minor = Math.round(Number(value || 0) * 100);
return (state.transferRateTiers || []).find(function (tier) {
return (
String(tier.status || 'active') === 'active' &&
minor >= Number(tier.min_usd_minor || 0) &&
minor <= Number(tier.max_usd_minor || 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 historyTitleKey() {
if (salaryAssetType === 'BD_SALARY_USD')
return 'withdraw_exchange.history_bd_salary';
if (salaryAssetType === 'ADMIN_SALARY_USD')
return 'withdraw_exchange.history_admin_salary';
if (salaryAssetType === 'AGENCY_SALARY_USD')
return 'withdraw_exchange.history_agency_salary';
return 'withdraw_exchange.history_host_salary';
}
function historyTitle() {
if (salaryAssetType === 'BD_SALARY_USD') return 'BD salary';
if (salaryAssetType === 'ADMIN_SALARY_USD') return 'Admin salary';
if (salaryAssetType === 'AGENCY_SALARY_USD') return 'Agency salary';
return 'Host salary';
}
function firstValue(source, keys) {
if (!source) return '';
for (var i = 0; i < keys.length; i += 1) {
var value = source[keys[i]];
if (value !== undefined && value !== null && value !== '')
return value;
}
return '';
}
function contactFrom(value) {
if (!value || typeof value !== 'object') return '';
var source = value.profile || value.user || value;
return String(
firstValue(source, [
'contact_info',
'contactInfo',
'whatsapp_phone',
'whatsappPhone',
'contact',
]) || ''
).trim();
}
function withdrawAddressFrom(value) {
if (typeof value === 'string') return value.trim();
if (!value || typeof value !== 'object') return '';
if (typeof value.withdraw_address === 'string')
return value.withdraw_address.trim();
var source =
value.withdraw_address || value.user || value.profile || value;
return String(
firstValue(source, [
'cardNo',
'withdraw_usdt_trc20_address',
'withdrawUsdtTrc20Address',
'usdt_trc20_address',
'usdtTrc20Address',
'payment_address',
'paymentAddress',
'address',
]) || ''
).trim();
}
function paymentInfoFrom(value) {
var address = withdrawAddressFrom(value);
if (!address) return null;
return {
id: 'usdt_trc20',
cardNo: address,
};
}
function timeLabelFromMS(value) {
var number = Number(value || 0);
if (!Number.isFinite(number) || number <= 0) return '';
var date = new Date(number);
if (Number.isNaN(date.getTime())) return '';
return (
date.getFullYear() +
'-' +
String(date.getMonth() + 1).padStart(2, '0') +
'-' +
String(date.getDate()).padStart(2, '0') +
' ' +
String(date.getHours()).padStart(2, '0') +
':' +
String(date.getMinutes()).padStart(2, '0')
);
}
function historyLabelForBizType(bizType, delta) {
if (bizType === 'salary_exchange_to_coin') {
return {
key: 'withdraw_exchange.history_exchange_to_golds',
title: 'Exchange to golds',
};
}
if (bizType === 'salary_transfer_to_coin_seller') {
return {
key: 'withdraw_exchange.transfer',
title: 'Transfer',
};
}
if (bizType === 'host_salary_settlement' || delta >= 0) {
return {
key: historyTitleKey(),
title: historyTitle(),
};
}
return {
key: 'withdraw_exchange.withdraw',
title: 'Withdraw',
};
}
function normalizeHistoryItem(item, index) {
var delta = Number(
firstValue(item, ['available_delta', 'availableDelta'])
);
if (!Number.isFinite(delta)) delta = 0;
var balance = Number(
firstValue(item, ['available_after', 'availableAfter'])
);
if (!Number.isFinite(balance)) balance = 0;
var label = historyLabelForBizType(
String(firstValue(item, ['biz_type', 'bizType']) || ''),
delta
);
return {
id:
firstValue(item, ['transaction_id', 'transactionId']) ||
String(firstValue(item, ['entry_id', 'entryId']) || index),
key: label.key,
title: label.title,
amount: Math.abs(usdMinorToNumber(delta)),
balance: usdMinorToNumber(balance),
type: delta < 0 ? 1 : 0,
date: timeLabelFromMS(
firstValue(item, ['created_at_ms', 'createdAtMs'])
),
};
}
function normalizeHistoryItems(payload) {
var source = payload || {};
if (source.identity) identity = normalizeIdentity(source.identity);
if (source.salary_asset_type) {
salaryAssetType = source.salary_asset_type;
}
var items = Array.isArray(source.items)
? source.items
: Array.isArray(source.transactions)
? source.transactions
: Array.isArray(source)
? source
: [];
return items.map(function (item, index) {
return normalizeHistoryItem(item || {}, index);
});
}
function isValidTrc20(value) {
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || '').trim());
}
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;
var hasPayment = Boolean(payment);
$('emptyAddressState').hidden = hasPayment || state.isEditingAddress;
$('addressForm').hidden = hasPayment && !state.isEditingAddress;
$('boundAddressCard').hidden = !hasPayment || state.isEditingAddress;
if (payment) $('boundAddress').textContent = 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';
if (payee.avatar) {
var avatarImage = document.createElement('img');
avatarImage.src = payee.avatar;
avatarImage.alt = '';
avatar.appendChild(avatarImage);
} else {
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 transferRateMissing =
currentMode === 'transfer' && value > 0 && !findTransferRate(value);
var disabled =
value <= 0 ||
value > state.balance ||
(currentMode === 'withdraw' &&
(!state.paymentInfo || value < WITHDRAW_MIN_AMOUNT)) ||
(currentMode === 'transfer' &&
(!state.selectedPayee || transferRateMissing));
button.textContent = activeSubmitLabel();
button.disabled = disabled;
}
function needsContactForSubmit() {
return currentMode === 'exchange' || currentMode === 'transfer';
}
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...'
);
var historyRequest = isMock
? mockRequest('history')
: api() && api().history
? api().history(identity, 30).then(normalizeHistoryItems)
: Promise.resolve([]);
historyRequest
.then(function (items) {
state.historyItems = items || [];
renderHistory();
})
.catch(function (err) {
state.historyItems = [];
renderHistory();
toast(
err && err.message
? err.message
: t(
'withdraw_exchange.load_failed',
'Load failed. Try again later.'
)
);
});
}
function closeHistory() {
$('salaryHistoryModal').hidden = true;
document.body.classList.remove('modal-open');
}
function setContactStatus(message) {
var node = $('contactStatus');
node.textContent = message || '';
node.hidden = !message;
}
function setContactSaving(saving) {
state.isSavingContact = saving;
$('saveContactButton').disabled = saving;
$('saveContactButton').textContent = saving
? t('contact_card.saving', 'Saving...')
: t('contact_card.save', 'Save');
}
function openContactModal() {
$('contactInput').value = state.contactInfo || '';
setContactStatus('');
$('contactModal').hidden = false;
$('contactModal').setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
window.setTimeout(function () {
$('contactInput').focus();
}, 0);
}
function closeContactModal() {
$('contactModal').hidden = true;
$('contactModal').setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
}
function saveContact(event) {
if (event) event.preventDefault();
var contact = String($('contactInput').value || '').trim();
if (!contact) {
setContactStatus(
t('contact_card.required', 'Enter WhatsApp contact.')
);
return;
}
var apiClient = userApi();
if (!apiClient || !apiClient.updateContact) {
setContactStatus(
t('contact_card.api_unavailable', 'Contact API unavailable.')
);
return;
}
// Exchange/Transfer 需要运营联系方式用于后台跟进;联系方式是用户主资料,保存成功后才允许继续提交工资兑换或转账请求。
setContactSaving(true);
setContactStatus('');
apiClient
.updateContact({ contact_info: contact })
.then(function (response) {
state.contactInfo = contactFrom(response) || contact;
closeContactModal();
updateSubmit();
toast(t('contact_card.saved', 'Saved.'));
})
.catch(function () {
setContactStatus(t('contact_card.save_failed', 'Save failed.'));
})
.finally(function () {
setContactSaving(false);
});
}
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...'
);
var saveRequest = isMock
? mockRequest('saveAddress', { cardNo: address })
: api() && api().saveWithdrawAddress
? api()
.saveWithdrawAddress({
payment_address: address,
})
.then(paymentInfoFrom)
: Promise.reject(
new Error(
t('withdraw_exchange.submit_failed', 'Submit failed.')
)
);
saveRequest
.then(function (payment) {
state.paymentInfo = payment || {
id: 'usdt_trc20',
cardNo: address,
};
state.isEditingAddress = false;
$('trc20Address').value = '';
renderPaymentInfo();
toast(t('withdraw_exchange.address_saved', 'Address saved'));
})
.catch(function (err) {
toast(
err && err.message
? err.message
: t('withdraw_exchange.submit_failed', 'Submit failed.')
);
})
.finally(function () {
state.isSaving = false;
$('saveAddressButton').disabled = false;
$('saveAddressButton').textContent = t(
'withdraw_exchange.save_address',
'Save address'
);
});
}
function editAddress() {
if (!state.paymentInfo) return;
state.isEditingAddress = true;
$('trc20Address').value = state.paymentInfo.cardNo || '';
renderPaymentInfo();
window.setTimeout(function () {
$('trc20Address').focus();
}, 0);
}
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();
if (!isMock && !api()) {
toast(
t(
'withdraw_exchange.search_failed',
'Search failed. Try again later.'
)
);
return;
}
state.isSearching = true;
$('searchPayeeButton').disabled = true;
$('searchPayeeButton').textContent = t(
'withdraw_exchange.searching',
'Searching...'
);
var request = isMock
? mockRequest('searchPayee', { account: account })
: api()
.searchCoinSeller(account, identity)
.then(function (data) {
var seller = data && data.seller;
if (!seller) return null;
return {
id: seller.user_id || seller.userId,
name:
seller.username ||
seller.display_user_id ||
account,
account: seller.display_user_id || account,
avatar: seller.avatar || '',
};
});
request
.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();
})
.catch(function (err) {
state.isSearching = false;
$('searchPayeeButton').disabled = false;
$('searchPayeeButton').textContent = t(
'withdraw_exchange.search',
'Search'
);
toast(
err && err.message
? err.message
: t(
'withdraw_exchange.payee_not_found',
'User not found'
)
);
});
}
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'
);
if (currentMode === 'transfer' && !findTransferRate(value))
return t(
'withdraw_exchange.rate_not_configured',
'Exchange rate not configured.'
);
return '';
}
function submit() {
var error = validateSubmit();
if (error) {
toast(error);
return;
}
if (needsContactForSubmit() && !state.contactInfo) {
openContactModal();
return;
}
state.isSubmitting = true;
updateSubmit();
submitRequest()
.then(function (result) {
var input = inputs[currentMode];
if (input) input.value = '';
if (currentMode === 'transfer') {
state.selectedPayee = null;
$('transferAccount').value = '';
renderPayee();
}
if (isMock) {
state.balance = mock.balance;
} else if (currentMode === 'withdraw') {
state.balance = salaryBalanceAfterToNumber(
result.salary_balance_after
);
} else if (currentMode === 'exchange') {
state.balance = salaryBalanceAfterToNumber(
result.salary_balance_after
);
} else if (currentMode === 'transfer') {
state.balance = usdMinorToNumber(
result.source_salary_balance_after
);
}
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'));
})
.catch(function (err) {
state.isSubmitting = false;
updateSubmit();
toast(
err && err.message
? err.message
: t('withdraw_exchange.submit_failed', 'Submit failed.')
);
});
}
function submitRequest() {
var value = amount();
if (isMock) {
return mockRequest('submit', {
mode: currentMode,
amount: value,
payee: state.selectedPayee,
paymentInfo: state.paymentInfo,
});
}
if (!api()) {
return Promise.reject(
new Error(
t('withdraw_exchange.submit_failed', 'Submit failed.')
)
);
}
if (currentMode === 'exchange') {
return api().exchange({
command_id: commandId('salary-exchange'),
identity: identity,
amount_usd: amountText(value),
reason: 'salary exchange',
});
}
if (currentMode === 'withdraw') {
return api().withdraw({
command_id: commandId('salary-withdraw'),
identity: identity,
amount_usd: amountText(value),
payment_address: state.paymentInfo && state.paymentInfo.cardNo,
});
}
return api().transferToCoinSeller({
command_id: commandId('salary-transfer'),
identity: identity,
target_display_user_id: state.selectedPayee.account,
amount_usd: amountText(value),
reason: 'salary transfer',
});
}
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();
var centerPath = '../host-center/index.html';
if (identity === 'BD') centerPath = '../bd-center/index.html';
if (identity === 'BD_LEADER')
centerPath = '../superadmin-center/index.html';
if (identity === 'AGENCY') centerPath = '../agency-center/index.html';
window.location.href = centerPath + (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) {
if (event) event.preventDefault();
return;
}
last = now;
// 只能在 click 阶段变更弹窗状态WebView 里 pointerdown 先打开遮罩后,同一次触摸生成的 click 会落到新遮罩上,导致详情弹窗刚打开又被关闭。
if (event) event.preventDefault();
handler(event);
}
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('editAddressButton', editAddress);
bindTap('submitButton', submit);
bindTap('salaryHistoryButton', openHistory);
bindTap('salaryHistoryBackdrop', closeHistory);
bindTap('salaryHistoryCloseButton', closeHistory);
bindTap('contactBackdrop', closeContactModal);
bindTap('contactCloseButton', closeContactModal);
$('contactForm').addEventListener('submit', saveContact);
}
function renderStaticDynamicText() {
$('exchangeRateText').textContent = t(
'withdraw_exchange.exchange_rate_value',
'1$ = {amount} golds'
).replace('{amount}', EXCHANGE_RATE.toLocaleString('en-US'));
if (!$('salaryHistoryModal').hidden) renderHistory();
if (!$('contactModal').hidden && !state.isSavingContact) {
$('saveContactButton').textContent = t('contact_card.save', 'Save');
}
updateSubmit();
renderPayee();
}
function init() {
identity = normalizeIdentity(identity);
bindEvents();
setMode(currentMode);
renderStaticDynamicText();
loadOverview();
loadPaymentInfo();
loadContactInfo();
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'withdraw-exchange',
mock: isMock,
});
}
}
function loadOverview() {
if (isMock) {
mockRequest('balance').then(function (balance) {
state.balance = balance;
state.transferRateTiers = [
{
min_usd_minor: 100,
max_usd_minor: 1000,
coin_per_usd: 90000,
status: 'active',
},
{
min_usd_minor: 1100,
max_usd_minor: 5000,
coin_per_usd: 92000,
status: 'active',
},
];
renderBalance();
updateSubmit();
});
return;
}
if (!api()) {
toast(
t(
'withdraw_exchange.load_failed',
'Load failed. Try again later.'
)
);
return;
}
api()
.overview(identity)
.then(function (data) {
identity = normalizeIdentity(data.identity || identity);
salaryAssetType = data.salary_asset_type || salaryAssetType;
EXCHANGE_RATE = Number(data.exchange_rate || EXCHANGE_RATE);
var payment = paymentInfoFrom(data);
if (payment) state.paymentInfo = payment;
state.balance = usdMinorToNumber(
data.salary && data.salary.available_amount
);
state.transferRateTiers = data.transfer_rate_tiers || [];
renderStaticDynamicText();
renderBalance();
renderPaymentInfo();
updateSubmit();
})
.catch(function (err) {
toast(
err && err.message
? err.message
: t(
'withdraw_exchange.load_failed',
'Load failed. Try again later.'
)
);
});
}
function loadPaymentInfo() {
if (isMock) {
mockRequest('payment').then(function (payment) {
state.paymentInfo = payment;
renderPaymentInfo();
});
return;
}
state.paymentInfo = null;
state.isEditingAddress = false;
renderPaymentInfo();
if (!api() || !api().getWithdrawAddress) return;
api()
.getWithdrawAddress()
.then(function (data) {
state.paymentInfo = paymentInfoFrom(data);
renderPaymentInfo();
})
.catch(function () {
renderPaymentInfo();
});
}
function loadContactInfo() {
if (isMock) {
state.contactInfo = String(params.get('contact') || '').trim();
updateSubmit();
return;
}
var apiClient = userApi();
if (!apiClient || !apiClient.me) {
state.contactInfo = '';
updateSubmit();
return;
}
apiClient
.me()
.then(function (profile) {
state.contactInfo = contactFrom(profile);
updateSubmit();
})
.catch(function () {
state.contactInfo = '';
updateSubmit();
});
}
document.addEventListener('DOMContentLoaded', init);
window.addEventListener('hyapp:i18n-ready', renderStaticDynamicText);
})();