438 lines
15 KiB
JavaScript
438 lines
15 KiB
JavaScript
(function () {
|
||
'use strict';
|
||
|
||
var state = {
|
||
range: null,
|
||
data: null,
|
||
tab: 'agency',
|
||
loading: false,
|
||
mutating: false,
|
||
removingHost: null,
|
||
};
|
||
|
||
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);
|
||
}
|
||
|
||
function count(value) {
|
||
if (value === null || value === undefined || !Number.isFinite(value)) {
|
||
return '—';
|
||
}
|
||
return Number(value).toLocaleString(undefined, {
|
||
maximumFractionDigits: 0,
|
||
});
|
||
}
|
||
|
||
function duration(value) {
|
||
if (!Number.isFinite(value)) return '—';
|
||
var minutes = Math.max(0, Math.floor(Number(value) / 60000));
|
||
var hours = Math.floor(minutes / 60);
|
||
var rest = minutes % 60;
|
||
if (!hours) return rest + t('fami_unit.minute_short', 'm');
|
||
return (
|
||
hours +
|
||
t('fami_unit.hour_short', 'h') +
|
||
(rest ? ' ' + rest + t('fami_unit.minute_short', 'm') : '')
|
||
);
|
||
}
|
||
|
||
function dateTime(value) {
|
||
if (!Number(value)) return '—';
|
||
return new Date(Number(value)).toLocaleString(undefined, {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
});
|
||
}
|
||
|
||
function renderIdentity() {
|
||
if (!state.data) return;
|
||
var agency = state.data.agency || {};
|
||
$('agencyName').textContent = agency.name || '—';
|
||
$('agencyID').textContent =
|
||
t('fami_agency.id_prefix', 'Agency ID:') +
|
||
' ' +
|
||
(agency.shortId || agency.id || '—');
|
||
$('createdAt').textContent =
|
||
t('fami_agency.created_prefix', 'Created:') +
|
||
' ' +
|
||
dateTime(agency.createdAtMS);
|
||
$('agencyInitial').textContent = String(agency.name || 'A')
|
||
.trim()
|
||
.charAt(0)
|
||
.toUpperCase();
|
||
$('agencyAvatar').hidden = !agency.avatar;
|
||
$('agencyInitial').hidden = !!agency.avatar;
|
||
if (agency.avatar) $('agencyAvatar').src = agency.avatar;
|
||
$('contactValue').textContent = state.data.contact || '—';
|
||
$('diamondBalance').textContent = count(state.data.pointBalance);
|
||
}
|
||
|
||
function renderSummary() {
|
||
var summary =
|
||
state.data && state.data.stats
|
||
? state.data.stats.summary || {}
|
||
: {};
|
||
$('totalEarnings').textContent = count(summary.total_earnings);
|
||
$('giftIncome').textContent = count(summary.gift_income);
|
||
$('shareIncome').textContent = count(summary.share_income);
|
||
$('totalHosts').textContent = count(summary.total_hosts);
|
||
$('giftedHosts').textContent = count(summary.gifted_host_count);
|
||
var statsError = state.data && state.data.errors.stats;
|
||
$('statsStatus').hidden = !statsError;
|
||
if (statsError) {
|
||
$('statsStatus').textContent = t(
|
||
'fami_common.stats_unavailable',
|
||
'Statistics are temporarily unavailable.'
|
||
);
|
||
}
|
||
}
|
||
|
||
function hostAvatar(host) {
|
||
var shell = document.createElement('span');
|
||
shell.className = 'host-avatar';
|
||
if (host.avatar) {
|
||
var image = document.createElement('img');
|
||
image.src = host.avatar;
|
||
image.alt = '';
|
||
shell.appendChild(image);
|
||
} else {
|
||
shell.textContent = String(host.name || 'H')
|
||
.charAt(0)
|
||
.toUpperCase();
|
||
}
|
||
return shell;
|
||
}
|
||
|
||
function textCell(row, value) {
|
||
var cell = document.createElement('td');
|
||
cell.textContent = value;
|
||
row.appendChild(cell);
|
||
}
|
||
|
||
function renderHosts() {
|
||
var hosts =
|
||
state.data && state.data.stats ? state.data.stats.hosts || [] : [];
|
||
var body = $('hostTableBody');
|
||
body.textContent = '';
|
||
hosts.forEach(function (host) {
|
||
var row = document.createElement('tr');
|
||
var identityCell = document.createElement('td');
|
||
var identity = document.createElement('div');
|
||
identity.className = 'host-identity';
|
||
identity.appendChild(hostAvatar(host));
|
||
var copy = document.createElement('span');
|
||
copy.className = 'host-copy';
|
||
var name = document.createElement('strong');
|
||
name.textContent = host.name || '—';
|
||
var id = document.createElement('span');
|
||
id.textContent =
|
||
t('fami_common.uid_prefix', 'UID:') +
|
||
' ' +
|
||
(host.displayUserId || host.userId || '—');
|
||
copy.appendChild(name);
|
||
copy.appendChild(id);
|
||
identity.appendChild(copy);
|
||
identityCell.appendChild(identity);
|
||
row.appendChild(identityCell);
|
||
textCell(row, count(host.diamondEarnings));
|
||
textCell(row, count(host.diamondExchanged));
|
||
textCell(row, count(host.giftSenders));
|
||
textCell(row, duration(host.onlineDurationMS));
|
||
textCell(row, duration(host.validMicDurationMS));
|
||
textCell(row, count(host.validMicDays));
|
||
textCell(row, dateTime(host.joinedAtMS));
|
||
var actionCell = document.createElement('td');
|
||
var remove = document.createElement('button');
|
||
remove.type = 'button';
|
||
remove.className = 'remove-button';
|
||
if (host.removable) {
|
||
remove.setAttribute('data-remove-host', host.userId);
|
||
remove.textContent = t('fami_agency.remove', 'Remove');
|
||
} else {
|
||
remove.disabled = true;
|
||
remove.textContent = t('fami_agency.owner', 'Owner');
|
||
}
|
||
actionCell.appendChild(remove);
|
||
row.appendChild(actionCell);
|
||
body.appendChild(row);
|
||
});
|
||
$('hostEmpty').hidden = hosts.length > 0;
|
||
$('hostCountLabel').textContent = t(
|
||
'fami_agency.host_count',
|
||
'{count} hosts'
|
||
).replace('{count}', count(hosts.length));
|
||
}
|
||
|
||
function renderRange() {
|
||
document.querySelectorAll('[data-range]').forEach(function (button) {
|
||
button.setAttribute(
|
||
'aria-pressed',
|
||
button.getAttribute('data-range') === state.range.preset
|
||
? 'true'
|
||
: 'false'
|
||
);
|
||
button.disabled = state.loading;
|
||
});
|
||
$('rangeCaption').textContent =
|
||
state.range.startDate === state.range.endDate
|
||
? state.range.startDate
|
||
: state.range.startDate + ' – ' + state.range.endDate;
|
||
}
|
||
|
||
function renderTabs() {
|
||
document.querySelectorAll('[data-tab]').forEach(function (button) {
|
||
button.setAttribute(
|
||
'aria-selected',
|
||
button.getAttribute('data-tab') === state.tab ? 'true' : 'false'
|
||
);
|
||
});
|
||
$('agencyPanel').hidden = state.tab !== 'agency';
|
||
$('hostsPanel').hidden = state.tab !== 'hosts';
|
||
$('dataTitle').textContent =
|
||
state.tab === 'agency'
|
||
? t('fami_agency.tab_agency', 'Agency data')
|
||
: t('fami_agency.tab_hosts', 'Host data');
|
||
}
|
||
|
||
function renderAll() {
|
||
renderIdentity();
|
||
renderSummary();
|
||
renderHosts();
|
||
renderRange();
|
||
renderTabs();
|
||
}
|
||
|
||
function setLoading(value) {
|
||
state.loading = value;
|
||
document.body.classList.toggle('is-loading', value);
|
||
renderRange();
|
||
}
|
||
|
||
function setMutating(value) {
|
||
state.mutating = value;
|
||
document.body.classList.toggle('is-mutating', value);
|
||
}
|
||
|
||
function load() {
|
||
setLoading(true);
|
||
return window.HyGuild.agencyCenter
|
||
.load(state.range)
|
||
.then(function (data) {
|
||
state.data = data;
|
||
renderAll();
|
||
})
|
||
.catch(function () {
|
||
toast(
|
||
t(
|
||
'fami_agency.load_failed',
|
||
'Unable to load Agency Center.'
|
||
)
|
||
);
|
||
$('statsStatus').hidden = false;
|
||
$('statsStatus').textContent = t(
|
||
'fami_agency.load_failed',
|
||
'Unable to load Agency Center.'
|
||
);
|
||
})
|
||
.finally(function () {
|
||
setLoading(false);
|
||
});
|
||
}
|
||
|
||
function selectRange(preset) {
|
||
if (preset === 'custom') {
|
||
$('rangeStart').value = state.range.startDate;
|
||
$('rangeEnd').value = state.range.endDate;
|
||
$('rangeDialog').showModal();
|
||
return;
|
||
}
|
||
state.range = window.HyGuild.dateRange.create(preset);
|
||
renderRange();
|
||
load();
|
||
}
|
||
|
||
function applyCustomRange(event) {
|
||
event.preventDefault();
|
||
try {
|
||
state.range = window.HyGuild.dateRange.create('custom', {
|
||
start: $('rangeStart').value,
|
||
end: $('rangeEnd').value,
|
||
});
|
||
} catch (_) {
|
||
toast(t('fami_range.invalid', 'Choose a valid date range.'));
|
||
return;
|
||
}
|
||
$('rangeDialog').close();
|
||
load();
|
||
}
|
||
|
||
function saveContact(event) {
|
||
event.preventDefault();
|
||
if (state.mutating) return;
|
||
var value = String($('contactInput').value || '').trim();
|
||
if (!value) {
|
||
toast(t('fami_agency.contact_required', 'Enter a contact number.'));
|
||
return;
|
||
}
|
||
setMutating(true);
|
||
window.HyGuild.agencyCenter
|
||
.saveContact(value)
|
||
.then(function () {
|
||
state.data.contact = value;
|
||
$('contactDialog').close();
|
||
renderIdentity();
|
||
toast(t('fami_agency.contact_saved', 'Contact saved.'));
|
||
})
|
||
.catch(function () {
|
||
toast(
|
||
t(
|
||
'fami_agency.contact_save_failed',
|
||
'Unable to save contact.'
|
||
)
|
||
);
|
||
})
|
||
.finally(function () {
|
||
setMutating(false);
|
||
});
|
||
}
|
||
|
||
function inviteHost(event) {
|
||
event.preventDefault();
|
||
if (state.mutating) return;
|
||
var displayID = String($('inviteHostID').value || '').trim();
|
||
if (!displayID) return;
|
||
setMutating(true);
|
||
window.HyGuild.agencyCenter
|
||
.inviteHost(displayID)
|
||
.then(function () {
|
||
$('inviteDialog').close();
|
||
toast(
|
||
t(
|
||
'fami_agency.invite_sent',
|
||
'Invitation sent. The host must accept it.'
|
||
)
|
||
);
|
||
})
|
||
.catch(function () {
|
||
toast(t('fami_agency.invite_failed', 'Unable to invite host.'));
|
||
})
|
||
.finally(function () {
|
||
setMutating(false);
|
||
});
|
||
}
|
||
|
||
function openRemove(hostUserID) {
|
||
var hosts = state.data.stats.hosts || [];
|
||
state.removingHost = hosts.find(function (host) {
|
||
return host.userId === hostUserID;
|
||
});
|
||
if (!state.removingHost) return;
|
||
$('removeMessage').textContent = t(
|
||
'fami_agency.remove_confirm',
|
||
'Remove {name} from this agency? Historical earnings will remain unchanged.'
|
||
).replace('{name}', state.removingHost.name || hostUserID);
|
||
$('removeDialog').showModal();
|
||
}
|
||
|
||
function removeHost(event) {
|
||
event.preventDefault();
|
||
if (state.mutating || !state.removingHost) return;
|
||
var target = state.removingHost;
|
||
setMutating(true);
|
||
window.HyGuild.agencyCenter
|
||
.removeHost(target.userId)
|
||
.then(function () {
|
||
// 成员关系由后端原子结束;成功后重拉统计,不能只在本地删行伪造 total_hosts。
|
||
$('removeDialog').close();
|
||
state.removingHost = null;
|
||
toast(t('fami_agency.host_removed', 'Host removed.'));
|
||
return load();
|
||
})
|
||
.catch(function () {
|
||
toast(t('fami_agency.remove_failed', 'Unable to remove host.'));
|
||
})
|
||
.finally(function () {
|
||
setMutating(false);
|
||
});
|
||
}
|
||
|
||
function bind() {
|
||
$('backButton').addEventListener('click', function () {
|
||
if (window.history.length > 1) window.history.back();
|
||
else if (window.HyAppBridge) window.HyAppBridge.back();
|
||
});
|
||
$('withdrawButton').addEventListener('click', function () {
|
||
window.location.href =
|
||
window.HyGuild.product.buildURL('../wallet/');
|
||
});
|
||
$('editContactButton').addEventListener('click', function () {
|
||
$('contactInput').value = (state.data && state.data.contact) || '';
|
||
$('contactDialog').showModal();
|
||
});
|
||
$('cancelContactButton').addEventListener('click', function () {
|
||
$('contactDialog').close();
|
||
});
|
||
$('contactForm').addEventListener('submit', saveContact);
|
||
document
|
||
.querySelector('.data-tabs')
|
||
.addEventListener('click', function (event) {
|
||
var button = event.target.closest('[data-tab]');
|
||
if (!button) return;
|
||
state.tab = button.getAttribute('data-tab');
|
||
renderTabs();
|
||
});
|
||
$('rangeFilters').addEventListener('click', function (event) {
|
||
var button = event.target.closest('[data-range]');
|
||
if (button && !state.loading)
|
||
selectRange(button.getAttribute('data-range'));
|
||
});
|
||
$('cancelRangeButton').addEventListener('click', function () {
|
||
$('rangeDialog').close();
|
||
});
|
||
$('rangeForm').addEventListener('submit', applyCustomRange);
|
||
$('addHostButton').addEventListener('click', function () {
|
||
$('inviteHostID').value = '';
|
||
$('inviteDialog').showModal();
|
||
});
|
||
$('cancelInviteButton').addEventListener('click', function () {
|
||
$('inviteDialog').close();
|
||
});
|
||
$('inviteForm').addEventListener('submit', inviteHost);
|
||
$('hostTableBody').addEventListener('click', function (event) {
|
||
var button = event.target.closest('[data-remove-host]');
|
||
if (button) openRemove(button.getAttribute('data-remove-host'));
|
||
});
|
||
$('cancelRemoveButton').addEventListener('click', function () {
|
||
$('removeDialog').close();
|
||
});
|
||
$('removeForm').addEventListener('submit', removeHost);
|
||
window.addEventListener('hyapp:i18n-ready', renderAll);
|
||
}
|
||
|
||
function init() {
|
||
state.range = window.HyGuild.dateRange.create('today');
|
||
bind();
|
||
renderRange();
|
||
load();
|
||
}
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
} else {
|
||
init();
|
||
}
|
||
})();
|