2026-06-04 19:29:48 +08:00

697 lines
23 KiB
JavaScript

(function () {
var state = {
activeTab: 'bd',
inviteMode: 'bd',
inviteQuery: '',
inviteStatus: '',
inviteStatusType: '',
selectedDetails: null,
};
var mock = {
profile: {
name: 'Admin Sophia',
uid: 'SA-100001',
avatar: avatarData('S', '#dbc8ff', '#7d57c7'),
},
balance: {
available: 168250.5,
},
overview: {
totalBD: 8,
totalAgency: 36,
totalHosts: 428,
teamSalary: 586420.8,
teamRecharge: 1268800,
},
bdList: [
{
id: '880001',
name: 'Mila BD',
avatar: avatarData('M', '#dbc8ff', '#7d57c7'),
agencies: 12,
hosts: 126,
salary: 128450.35,
recharge: 356900,
},
{
id: '880018',
name: 'Jasmine BD',
avatar: avatarData('J', '#f4ebff', '#7d57c7'),
agencies: 9,
hosts: 104,
salary: 106280.4,
recharge: 298520,
},
{
id: '880026',
name: 'Omar BD',
avatar: avatarData('O', '#efe4ff', '#7d57c7'),
agencies: 7,
hosts: 82,
salary: 86140,
recharge: 214330,
},
],
agencyList: [
{
id: '163003',
name: 'Yumi Star Agency',
avatar: avatarData('Y', '#dbc8ff', '#7d57c7'),
bdId: '880001',
hosts: 28,
salary: 38420.55,
recharge: 126880,
},
{
id: '163086',
name: 'Moon Live Agency',
avatar: avatarData('M', '#f4ebff', '#7d57c7'),
bdId: '880018',
hosts: 19,
salary: 29106.2,
recharge: 98540,
},
{
id: '163221',
name: 'Nova Host Guild',
avatar: avatarData('N', '#efe4ff', '#7d57c7'),
bdId: '880026',
hosts: 16,
salary: 22450,
recharge: 73150,
},
],
history: [
{
month: '2026-06',
status: 'In progress',
bdCount: 8,
agencyCount: 36,
totalSalary: 586420.8,
totalRecharge: 1268800,
},
{
month: '2026-05',
status: 'Completed',
bdCount: 7,
agencyCount: 31,
totalSalary: 520180.25,
totalRecharge: 1112900,
},
{
month: '2026-04',
status: 'Completed',
bdCount: 6,
agencyCount: 26,
totalSalary: 462300,
totalRecharge: 980400,
},
],
inviteRecords: {
bd: [
{
id: 'bd-inv-01',
status: 'Pending',
profile: {
id: '3200901',
name: 'BD_River',
account: '880099',
avatar: avatarData('R', '#dbc8ff', '#7d57c7'),
},
},
],
agent: [
{
id: 'agent-inv-01',
status: 'Success',
profile: {
id: '3200801',
name: 'Agent_Lina',
account: '168801',
avatar: avatarData('L', '#f4ebff', '#7d57c7'),
},
},
],
},
searchPool: {
bd: [
{
id: '3200902',
name: 'BD_Kai',
account: '880102',
avatar: avatarData('K', '#dbc8ff', '#7d57c7'),
},
{
id: '3200903',
name: 'BD_Ayla',
account: '880103',
avatar: avatarData('A', '#efe4ff', '#7d57c7'),
},
],
agent: [
{
id: '3200802',
name: 'Agent_Omar',
account: '168802',
avatar: avatarData('O', '#dbc8ff', '#7d57c7'),
},
{
id: '3200803',
name: 'Agent_Sara',
account: '168803',
avatar: avatarData('S', '#efe4ff', '#7d57c7'),
},
],
},
};
function $(id) {
return document.getElementById(id);
}
function avatarData(text, background, foreground) {
var value =
String(text || 'S')
.trim()
.charAt(0) || 'S';
var letter = value.replace(/[<>&"']/g, '');
var svg =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">' +
'<rect width="96" height="96" rx="48" fill="' +
background +
'"/>' +
'<text x="50%" y="54%" text-anchor="middle" dominant-baseline="middle" fill="' +
foreground +
'" font-family="Arial, sans-serif" font-size="38" font-weight="800">' +
letter +
'</text>' +
'</svg>';
return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function money(value) {
return Number(value || 0).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function compactMoney(value) {
var amount = Number(value || 0);
var abs = Math.abs(amount);
if (abs >= 1000000) {
return (
(amount / 1000000).toLocaleString('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
}) + 'M'
);
}
if (abs >= 1000) {
return (
(amount / 1000).toLocaleString('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
}) + 'K'
);
}
return money(amount);
}
function count(value) {
return Number(value || 0).toLocaleString('en-US', {
maximumFractionDigits: 0,
});
}
function initial(text) {
return String(text || '')
.trim()
.charAt(0)
.toUpperCase();
}
function toast(message) {
if (!message) return;
if (window.HyAppToast && window.HyAppToast.show) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function setImage(image, fallback, src, name) {
if (!image || !fallback) return;
fallback.textContent = initial(name) || 'S';
if (!src) {
image.hidden = true;
fallback.hidden = false;
return;
}
image.onload = function () {
image.hidden = false;
fallback.hidden = true;
};
image.onerror = function () {
image.hidden = true;
fallback.hidden = false;
};
image.src = src;
}
function makeAvatar(item) {
var avatar = document.createElement('div');
var fallback = document.createElement('span');
avatar.className = 'member-avatar';
fallback.className = 'member-fallback';
fallback.textContent = initial(item.name) || 'S';
avatar.appendChild(fallback);
if (item.avatar) {
var image = document.createElement('img');
image.src = item.avatar;
image.alt = '';
image.addEventListener('load', function () {
fallback.hidden = true;
});
image.addEventListener('error', function () {
image.remove();
fallback.hidden = false;
});
avatar.appendChild(image);
}
return avatar;
}
function replaceChildren(node, children) {
node.textContent = '';
children.forEach(function (child) {
node.appendChild(child);
});
}
function renderProfile() {
$('profileName').textContent = mock.profile.name;
$('profileUID').textContent = t(
'superadmin_center.uid_prefix',
'UID: {id}'
).replace('{id}', mock.profile.uid);
setImage(
$('profileAvatar'),
$('profileAvatarFallback'),
mock.profile.avatar,
mock.profile.name
);
}
function renderBalance() {
$('availableBalance').textContent = money(mock.balance.available);
}
function summaryCell(label, value) {
var cell = document.createElement('div');
var labelNode = document.createElement('span');
var valueNode = document.createElement('strong');
labelNode.textContent = label;
valueNode.textContent = value;
cell.appendChild(labelNode);
cell.appendChild(valueNode);
return cell;
}
function activeItems() {
return state.activeTab === 'agency' ? mock.agencyList : mock.bdList;
}
function renderTeamSummary() {
var cells =
state.activeTab === 'agency'
? [
summaryCell(
t('superadmin_center.agency_number', 'Agency number'),
count(mock.overview.totalAgency)
),
summaryCell(
t('superadmin_center.hosts', 'Hosts'),
count(mock.overview.totalHosts)
),
summaryCell(
t('superadmin_center.team_salary', 'Team salary'),
'$' + compactMoney(mock.overview.teamSalary)
),
]
: [
summaryCell(
t('superadmin_center.bd_number', 'BD number'),
count(mock.overview.totalBD)
),
summaryCell(
t('superadmin_center.agencies', 'Agencies'),
count(mock.overview.totalAgency)
),
summaryCell(
t('superadmin_center.team_recharge', 'Team recharge'),
'$' + compactMoney(mock.overview.teamRecharge)
),
];
replaceChildren($('teamSummary'), cells);
}
function createMemberRow(item) {
var row = document.createElement('article');
var main = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var side = document.createElement('div');
var salary = document.createElement('strong');
var sub = document.createElement('span');
row.className = 'member-row';
main.className = 'member-main';
name.className = 'member-name';
meta.className = 'member-meta';
side.className = 'member-side';
name.textContent = item.name;
meta.textContent =
state.activeTab === 'agency'
? 'ID: ' + item.id + ' · BD: ' + item.bdId
: 'ID: ' + item.id;
salary.textContent = '$' + money(item.salary);
sub.textContent =
state.activeTab === 'agency'
? count(item.hosts) +
' ' +
t('superadmin_center.hosts', 'Hosts')
: count(item.agencies) +
' ' +
t('superadmin_center.agencies', 'Agencies');
main.appendChild(name);
main.appendChild(meta);
side.appendChild(salary);
side.appendChild(sub);
row.appendChild(makeAvatar(item));
row.appendChild(main);
row.appendChild(side);
row.addEventListener('click', function () {
state.selectedDetails = item;
renderDetails();
openModal('detailsModal');
});
return row;
}
function renderTeamList() {
document.querySelectorAll('[data-team-tab]').forEach(function (button) {
var active =
button.getAttribute('data-team-tab') === state.activeTab;
button.classList.toggle('is-active', active);
button.setAttribute('aria-selected', String(active));
});
renderTeamSummary();
replaceChildren(
$('teamList'),
activeItems().map(function (item) {
return createMemberRow(item);
})
);
}
function renderHistory() {
replaceChildren($('historySummary'), [
summaryCell(
t('superadmin_center.total_income', 'Total income'),
'$' + money(mock.overview.teamSalary)
),
summaryCell(
t('superadmin_center.previous_income', 'Previous income'),
'$' + money(mock.history[1].totalSalary)
),
]);
replaceChildren(
$('historyList'),
mock.history.map(function (item) {
var row = document.createElement('article');
var title = document.createElement('div');
var status = document.createElement('span');
var grid = document.createElement('div');
row.className = 'history-row';
title.className = 'history-title';
status.className = 'status-tag';
grid.className = 'history-grid';
title.textContent = item.month;
status.textContent = item.status;
grid.appendChild(
summaryCell(
t('superadmin_center.bd_number', 'BD number'),
count(item.bdCount)
)
);
grid.appendChild(
summaryCell(
t('superadmin_center.agency_number', 'Agency number'),
count(item.agencyCount)
)
);
grid.appendChild(
summaryCell(
t('superadmin_center.team_salary', 'Team salary'),
'$' + compactMoney(item.totalSalary)
)
);
row.appendChild(status);
row.appendChild(title);
row.appendChild(grid);
return row;
})
);
}
function renderDetails() {
var item = state.selectedDetails;
if (!item) return;
$('detailsTitle').textContent = item.name;
replaceChildren($('detailsSummary'), [
summaryCell('ID', item.id),
summaryCell(
t('superadmin_center.team_salary', 'Team salary'),
'$' + money(item.salary)
),
summaryCell(
t('superadmin_center.team_recharge', 'Team recharge'),
'$' + money(item.recharge)
),
]);
replaceChildren($('detailsList'), [
createReadonlyLine(
state.activeTab === 'agency'
? t('superadmin_center.hosts', 'Hosts')
: t('superadmin_center.agencies', 'Agencies'),
count(state.activeTab === 'agency' ? item.hosts : item.agencies)
),
]);
}
function createReadonlyLine(label, value) {
var row = document.createElement('div');
var labelNode = document.createElement('span');
var valueNode = document.createElement('strong');
row.className = 'readonly-line';
labelNode.textContent = label;
valueNode.textContent = value;
row.appendChild(labelNode);
row.appendChild(valueNode);
return row;
}
function inviteTitle() {
return state.inviteMode === 'agent'
? t('superadmin_center.invite_agent', 'Invite Agent')
: t('superadmin_center.invite_bd', 'Invite BD');
}
function inviteRecords() {
if (!state.inviteQuery) return mock.inviteRecords[state.inviteMode];
var keyword = state.inviteQuery.toLowerCase();
return mock.searchPool[state.inviteMode].filter(function (item) {
return (
item.name.toLowerCase().indexOf(keyword) >= 0 ||
item.account.indexOf(keyword) >= 0 ||
item.id.indexOf(keyword) >= 0
);
});
}
function renderInvite() {
$('inviteModalTitle').textContent = inviteTitle();
var status = $('inviteStatus');
status.hidden = !state.inviteStatus;
status.textContent = state.inviteStatus;
status.className =
'invite-status' +
(state.inviteStatusType ? ' ' + state.inviteStatusType : '');
var records = inviteRecords();
$('inviteEmpty').hidden = records.length > 0;
replaceChildren(
$('inviteList'),
records.map(function (record) {
var profile = record.profile || record;
var card = document.createElement('article');
var main = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var action = document.createElement('button');
card.className = 'invite-card';
main.className = 'invite-main';
name.className = 'invite-name';
meta.className = 'invite-meta';
action.className = 'invite-action';
action.type = 'button';
name.textContent = profile.name;
meta.textContent = 'ID: ' + profile.account;
action.textContent =
record.status || t('superadmin_center.invite', 'Invite');
action.disabled = !!record.status;
action.addEventListener('click', function () {
state.inviteStatus = t(
'superadmin_center.invite_success',
'Invitation submitted.'
);
state.inviteStatusType = 'success';
renderInvite();
});
main.appendChild(name);
main.appendChild(meta);
card.appendChild(makeAvatar(profile));
card.appendChild(main);
card.appendChild(action);
return card;
})
);
}
function openModal(id) {
var modal = $(id);
if (!modal) return;
modal.hidden = false;
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
}
function closeModal(id) {
var modal = $(id);
if (!modal) return;
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
var hasOpen = Array.prototype.some.call(
document.querySelectorAll('.sheet-modal, .invite-modal'),
function (node) {
return !node.hidden;
}
);
document.body.classList.toggle('modal-open', hasOpen);
}
function navigateToWithdrawExchange() {
var params = new URLSearchParams(window.location.search);
params.set('identity', 'SUPER_ADMIN');
params.set('salaryType', 'SUPER_ADMIN_SALARY');
if (!params.has('mode')) params.set('mode', 'withdraw');
window.location.href =
'../withdraw-exchange/index.html?' + params.toString();
}
function bindEvents() {
$('backButton').addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
});
$('withdrawExchangeButton').addEventListener(
'click',
navigateToWithdrawExchange
);
document.querySelectorAll('.menu-row').forEach(function (button) {
button.addEventListener('click', function () {
var action = button.getAttribute('data-action');
if (action === 'history') {
renderHistory();
openModal('historyModal');
return;
}
if (action === 'invite-bd' || action === 'invite-agent') {
state.inviteMode =
action === 'invite-agent' ? 'agent' : 'bd';
state.inviteQuery = '';
state.inviteStatus = '';
state.inviteStatusType = '';
$('inviteSearchInput').value = '';
renderInvite();
openModal('inviteModal');
}
});
});
document.querySelectorAll('[data-team-tab]').forEach(function (button) {
button.addEventListener('click', function () {
state.activeTab = button.getAttribute('data-team-tab') || 'bd';
renderTeamList();
});
});
document
.querySelectorAll('[data-close-modal]')
.forEach(function (node) {
node.addEventListener('click', function () {
closeModal(node.getAttribute('data-close-modal'));
});
});
$('inviteSearchForm').addEventListener('submit', function (event) {
event.preventDefault();
state.inviteQuery = $('inviteSearchInput').value.trim();
state.inviteStatus = state.inviteQuery
? ''
: t('superadmin_center.enter_user_id', 'Enter User ID');
state.inviteStatusType = state.inviteQuery ? '' : 'warning';
renderInvite();
});
document.addEventListener('keydown', function (event) {
if (event.key !== 'Escape') return;
closeModal('historyModal');
closeModal('detailsModal');
closeModal('inviteModal');
});
}
function render() {
renderProfile();
renderBalance();
renderTeamList();
}
function init() {
render();
bindEvents();
if (window.HyAppBridge) {
window.HyAppBridge.ready({ page: 'superadmin-center', mock: true });
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('hyapp:i18n-ready', function () {
render();
if (!$('historyModal').hidden) renderHistory();
if (!$('inviteModal').hidden) renderInvite();
if (!$('detailsModal').hidden) renderDetails();
});
})();