1127 lines
38 KiB
JavaScript
1127 lines
38 KiB
JavaScript
(function () {
|
||
var FIRST_BILL_MONTH = '2026-06';
|
||
var BD_SALARY_ASSET = 'BD_SALARY_USD';
|
||
|
||
var data = {
|
||
profile: null,
|
||
balance: { available: 0 },
|
||
billMonth: currentMonth(),
|
||
agencyBill: {
|
||
agencyNumber: 0,
|
||
totalSalary: 0,
|
||
totalRecharge: 0,
|
||
memberBillList: [],
|
||
},
|
||
inviteRecords: [],
|
||
};
|
||
|
||
var state = {
|
||
billMonth: normalizeBillMonth(data.billMonth),
|
||
inviteQuery: '',
|
||
inviteMode: 'records',
|
||
inviteStatus: '',
|
||
inviteStatusType: '',
|
||
searched: [],
|
||
inviting: {},
|
||
messages: [],
|
||
processingMessages: {},
|
||
searching: false,
|
||
loading: true,
|
||
};
|
||
|
||
function $(id) {
|
||
return document.getElementById(id);
|
||
}
|
||
|
||
function api() {
|
||
return window.HyAppAPI || {};
|
||
}
|
||
|
||
function centerAPI() {
|
||
return api().bdCenter || null;
|
||
}
|
||
|
||
function t(key, fallback) {
|
||
return window.HyAppI18n && window.HyAppI18n.t
|
||
? window.HyAppI18n.t(key, fallback)
|
||
: fallback || key;
|
||
}
|
||
|
||
function avatarData(text, background, foreground) {
|
||
var raw =
|
||
String(text || 'B')
|
||
.trim()
|
||
.charAt(0) || 'B';
|
||
var letter = raw.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 currentMonth() {
|
||
var now = new Date();
|
||
return (
|
||
String(now.getFullYear()) +
|
||
'-' +
|
||
String(now.getMonth() + 1).padStart(2, '0')
|
||
);
|
||
}
|
||
|
||
function monthDate(value) {
|
||
var parts = String(value || currentMonth()).split('-');
|
||
var year = Number(parts[0]) || new Date().getFullYear();
|
||
var month = Number(parts[1]) || new Date().getMonth() + 1;
|
||
return new Date(year, month - 1, 1);
|
||
}
|
||
|
||
function monthValue(date) {
|
||
return (
|
||
String(date.getFullYear()) +
|
||
'-' +
|
||
String(date.getMonth() + 1).padStart(2, '0')
|
||
);
|
||
}
|
||
|
||
function monthTime(value) {
|
||
return monthDate(value).getTime();
|
||
}
|
||
|
||
function normalizeBillMonth(value) {
|
||
if (monthTime(value) < monthTime(FIRST_BILL_MONTH)) {
|
||
return FIRST_BILL_MONTH;
|
||
}
|
||
if (monthTime(value) > monthTime(currentMonth())) {
|
||
return currentMonth();
|
||
}
|
||
return monthValue(monthDate(value));
|
||
}
|
||
|
||
function monthLabel(value) {
|
||
var date = monthDate(value);
|
||
return (
|
||
String(date.getFullYear()) +
|
||
'/' +
|
||
String(date.getMonth() + 1).padStart(2, '0') +
|
||
''
|
||
);
|
||
}
|
||
|
||
function monthOptions() {
|
||
var options = [];
|
||
var cursor = monthDate(currentMonth());
|
||
var first = monthDate(FIRST_BILL_MONTH);
|
||
while (cursor.getTime() >= first.getTime()) {
|
||
options.push(new Date(cursor.getFullYear(), cursor.getMonth(), 1));
|
||
cursor = new Date(cursor.getFullYear(), cursor.getMonth() - 1, 1);
|
||
}
|
||
return options;
|
||
}
|
||
|
||
function money(value) {
|
||
var number = Number(value || 0);
|
||
return number.toLocaleString('en-US', {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2,
|
||
});
|
||
}
|
||
|
||
function count(value) {
|
||
return Number(value || 0).toLocaleString('en-US', {
|
||
maximumFractionDigits: 0,
|
||
});
|
||
}
|
||
|
||
function initial(text) {
|
||
return String(text || '')
|
||
.trim()
|
||
.charAt(0)
|
||
.toUpperCase();
|
||
}
|
||
|
||
function firstValue(item, keys) {
|
||
if (!item) return '';
|
||
for (var i = 0; i < keys.length; i += 1) {
|
||
var value = item[keys[i]];
|
||
if (value !== undefined && value !== null && value !== '') {
|
||
return value;
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
function displayName(user, fallback) {
|
||
return (
|
||
firstValue(user, ['username', 'name', 'display_user_id']) ||
|
||
fallback ||
|
||
'-'
|
||
);
|
||
}
|
||
|
||
function displayID(user, fallback) {
|
||
return (
|
||
firstValue(user, [
|
||
'short_id',
|
||
'shortId',
|
||
'display_user_id',
|
||
'displayUserID',
|
||
]) ||
|
||
firstValue(user, ['user_id', 'userId', 'id']) ||
|
||
fallback ||
|
||
'-'
|
||
);
|
||
}
|
||
|
||
function salaryAmount(salary) {
|
||
if (!salary) return 0;
|
||
if (salary.display_amount !== undefined)
|
||
return Number(salary.display_amount);
|
||
if (salary.displayAmount !== undefined)
|
||
return Number(salary.displayAmount);
|
||
if (salary.available_amount !== undefined) {
|
||
return Number(salary.available_amount || 0) / 100;
|
||
}
|
||
if (salary.availableAmount !== undefined) {
|
||
return Number(salary.availableAmount || 0) / 100;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
function toast(message) {
|
||
if (window.HyAppToast) {
|
||
window.HyAppToast.show(message);
|
||
return;
|
||
}
|
||
window.alert(message);
|
||
}
|
||
|
||
function replaceChildren(node, children) {
|
||
node.textContent = '';
|
||
children.forEach(function (child) {
|
||
node.appendChild(child);
|
||
});
|
||
}
|
||
|
||
function setSkeleton(element, loading, text) {
|
||
if (!element) return;
|
||
element.classList.toggle('skeleton-line', Boolean(loading));
|
||
if (loading) {
|
||
element.textContent = '';
|
||
return;
|
||
}
|
||
element.textContent = text || '';
|
||
}
|
||
|
||
function renderImageAvatar(container, src, name, fallbackClass) {
|
||
container.textContent = '';
|
||
if (!src) {
|
||
var fallback = document.createElement('span');
|
||
fallback.className = fallbackClass || 'member-fallback';
|
||
fallback.textContent = initial(name) || 'B';
|
||
container.appendChild(fallback);
|
||
return;
|
||
}
|
||
var image = document.createElement('img');
|
||
image.src = src;
|
||
image.alt = '';
|
||
image.addEventListener('error', function () {
|
||
container.textContent = '';
|
||
var fallback = document.createElement('span');
|
||
fallback.className = fallbackClass || 'member-fallback';
|
||
fallback.textContent = initial(name) || 'B';
|
||
container.appendChild(fallback);
|
||
});
|
||
container.appendChild(image);
|
||
}
|
||
|
||
function normalizeProfile(payload) {
|
||
var profile =
|
||
payload && payload.profile ? payload.profile : payload || {};
|
||
var name = displayName(profile, 'BD');
|
||
return {
|
||
name: name,
|
||
uid: displayID(profile),
|
||
avatar:
|
||
firstValue(profile, ['avatar']) ||
|
||
avatarData(initial(name) || 'B', '#dbc8ff', '#7d57c7'),
|
||
};
|
||
}
|
||
|
||
function normalizeAgencyItem(item) {
|
||
var agency = (item && item.agency) || item || {};
|
||
var owner = (item && item.owner) || {};
|
||
// Agency 列表展示的是负责人维度;用户改昵称后应跟随 owner 最新资料,agency.name 只作为旧数据兜底。
|
||
var name =
|
||
displayName(owner, '') ||
|
||
firstValue(agency, ['name']) ||
|
||
'Agency ' + displayID(owner, displayID(agency));
|
||
var account =
|
||
displayID(owner, '') ||
|
||
firstValue(agency, [
|
||
'short_id',
|
||
'shortId',
|
||
'display_user_id',
|
||
'displayUserID',
|
||
'agency_id',
|
||
'agencyId',
|
||
]) ||
|
||
'-';
|
||
return {
|
||
name: name,
|
||
account: account,
|
||
avatar:
|
||
firstValue(agency, ['avatar']) ||
|
||
firstValue(owner, ['avatar']) ||
|
||
avatarData(initial(name) || 'A', '#dbc8ff', '#7d57c7'),
|
||
teamSalaryAmount: Number(
|
||
firstValue(item, ['team_salary', 'teamSalary']) || 0
|
||
),
|
||
teamRechargeAmount: Number(
|
||
firstValue(item, ['team_recharge', 'teamRecharge']) || 0
|
||
),
|
||
teamMemberCount: Number(
|
||
firstValue(item, ['host_count', 'hostCount']) ||
|
||
firstValue(agency, ['host_count', 'hostCount']) ||
|
||
0
|
||
),
|
||
};
|
||
}
|
||
|
||
function applyOverview(payload) {
|
||
var overview = payload && payload.overview ? payload.overview : {};
|
||
data.profile = normalizeProfile(payload || {});
|
||
data.balance = { available: salaryAmount(payload && payload.salary) };
|
||
data.agencyBill.agencyNumber = Number(
|
||
firstValue(overview, ['total_agency', 'totalAgency']) || 0
|
||
);
|
||
}
|
||
|
||
function applyAgencies(payload) {
|
||
var items =
|
||
payload && (payload.items || payload.agencies)
|
||
? payload.items || payload.agencies
|
||
: [];
|
||
var rows = items.map(normalizeAgencyItem);
|
||
data.agencyBill.memberBillList = rows;
|
||
data.agencyBill.agencyNumber = rows.length;
|
||
data.agencyBill.totalSalary = rows.reduce(function (sum, item) {
|
||
return sum + Number(item.teamSalaryAmount || 0);
|
||
}, 0);
|
||
data.agencyBill.totalRecharge = rows.reduce(function (sum, item) {
|
||
return sum + Number(item.teamRechargeAmount || 0);
|
||
}, 0);
|
||
}
|
||
|
||
function normalizeInviteProfile(payload, fallbackID) {
|
||
var user = payload && (payload.user || payload.profile || payload);
|
||
if (!user) return null;
|
||
var userID = firstValue(user, ['user_id', 'userId', 'id']);
|
||
if (!userID) return null;
|
||
var account = displayID(user, fallbackID);
|
||
var name = displayName(user, 'User ' + account);
|
||
return {
|
||
userId: String(userID),
|
||
id: String(userID),
|
||
name: name,
|
||
account: account,
|
||
avatar:
|
||
firstValue(user, ['avatar']) ||
|
||
avatarData(initial(name) || 'U', '#dbc8ff', '#7d57c7'),
|
||
};
|
||
}
|
||
|
||
function renderProfile() {
|
||
var image = $('profileAvatar');
|
||
var fallback = $('profileAvatarFallback');
|
||
var profile = data.profile || {};
|
||
var loading = Boolean(state.loading);
|
||
setSkeleton($('profileName'), loading, profile.name || '-');
|
||
setSkeleton($('profileUID'), loading, 'UID: ' + (profile.uid || '-'));
|
||
fallback.classList.toggle('avatar-skeleton', loading);
|
||
if (loading) {
|
||
image.hidden = true;
|
||
image.removeAttribute('src');
|
||
fallback.hidden = false;
|
||
fallback.textContent = '';
|
||
return;
|
||
}
|
||
fallback.textContent = initial(profile.name) || 'B';
|
||
image.onload = function () {
|
||
image.hidden = false;
|
||
fallback.hidden = true;
|
||
};
|
||
image.onerror = function () {
|
||
image.hidden = true;
|
||
fallback.hidden = false;
|
||
};
|
||
image.src = profile.avatar || '';
|
||
if (!profile.avatar) {
|
||
image.hidden = true;
|
||
fallback.hidden = false;
|
||
}
|
||
}
|
||
|
||
function renderBalance() {
|
||
var loading = Boolean(state.loading);
|
||
var coinIcon = document.querySelector('.salary-value .coin-icon');
|
||
if (coinIcon) coinIcon.classList.toggle('skeleton-coin', loading);
|
||
setSkeleton(
|
||
$('availableBalance'),
|
||
loading,
|
||
money(data.balance && data.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 summarySkeletonCell() {
|
||
var cell = document.createElement('div');
|
||
var labelNode = document.createElement('span');
|
||
var valueNode = document.createElement('strong');
|
||
labelNode.className = 'skeleton-line';
|
||
valueNode.className = 'skeleton-line';
|
||
cell.appendChild(labelNode);
|
||
cell.appendChild(valueNode);
|
||
return cell;
|
||
}
|
||
|
||
function skeletonMemberRow() {
|
||
var row = document.createElement('article');
|
||
var avatar = document.createElement('div');
|
||
var main = document.createElement('div');
|
||
var name = document.createElement('div');
|
||
var meta = document.createElement('div');
|
||
var side = document.createElement('div');
|
||
row.className = 'member-row is-skeleton';
|
||
avatar.className = 'member-avatar avatar-skeleton';
|
||
main.className = 'member-main';
|
||
name.className = 'member-name skeleton-line';
|
||
meta.className = 'member-meta skeleton-line';
|
||
side.className = 'member-side';
|
||
for (var i = 0; i < 3; i += 1) {
|
||
var line = document.createElement('div');
|
||
line.className = 'skeleton-line';
|
||
side.appendChild(line);
|
||
}
|
||
main.appendChild(name);
|
||
main.appendChild(meta);
|
||
row.appendChild(avatar);
|
||
row.appendChild(main);
|
||
row.appendChild(side);
|
||
return row;
|
||
}
|
||
|
||
function memberRow(item) {
|
||
var row = document.createElement('article');
|
||
var avatar = document.createElement('div');
|
||
var main = document.createElement('div');
|
||
var name = document.createElement('div');
|
||
var meta = document.createElement('div');
|
||
var side = document.createElement('div');
|
||
row.className = 'member-row';
|
||
avatar.className = 'member-avatar';
|
||
main.className = 'member-main';
|
||
name.className = 'member-name';
|
||
meta.className = 'member-meta';
|
||
side.className = 'member-side';
|
||
renderImageAvatar(avatar, item.avatar, item.name);
|
||
name.textContent = item.name || '-';
|
||
meta.textContent = 'UID: ' + (item.account || '-');
|
||
[
|
||
t('bd_center.team_salary', 'Team salary') +
|
||
': $' +
|
||
money(item.teamSalaryAmount),
|
||
t('bd_center.recharge', 'Recharge') +
|
||
': $' +
|
||
money(item.teamRechargeAmount),
|
||
t('bd_center.host', 'Host') + ': ' + count(item.teamMemberCount),
|
||
].forEach(function (line) {
|
||
var node = document.createElement('div');
|
||
node.textContent = line;
|
||
side.appendChild(node);
|
||
});
|
||
main.appendChild(name);
|
||
main.appendChild(meta);
|
||
row.appendChild(avatar);
|
||
row.appendChild(main);
|
||
row.appendChild(side);
|
||
return row;
|
||
}
|
||
|
||
function renderTeamList() {
|
||
var bill = data.agencyBill;
|
||
$('billMonthText').textContent = monthLabel(state.billMonth);
|
||
|
||
if (state.loading) {
|
||
replaceChildren($('teamListSummary'), [
|
||
summarySkeletonCell(),
|
||
summarySkeletonCell(),
|
||
]);
|
||
replaceChildren($('teamListContent'), [
|
||
skeletonMemberRow(),
|
||
skeletonMemberRow(),
|
||
skeletonMemberRow(),
|
||
]);
|
||
return;
|
||
}
|
||
|
||
replaceChildren($('teamListSummary'), [
|
||
summaryCell(
|
||
t('bd_center.agency_number', 'Agency number'),
|
||
count(bill.agencyNumber)
|
||
),
|
||
summaryCell(
|
||
t('bd_center.team_salary', 'Team salary'),
|
||
'$' + money(bill.totalSalary)
|
||
),
|
||
]);
|
||
|
||
var rows = (bill.memberBillList || []).map(memberRow);
|
||
if (!rows.length) {
|
||
var empty = document.createElement('div');
|
||
empty.className = 'empty-state';
|
||
empty.textContent = t('bd_center.no_data', 'No data');
|
||
rows = [empty];
|
||
}
|
||
replaceChildren($('teamListContent'), rows);
|
||
}
|
||
|
||
function monthOption(date) {
|
||
var value = monthValue(date);
|
||
var option = document.createElement('button');
|
||
option.className = 'month-option';
|
||
option.type = 'button';
|
||
option.setAttribute('role', 'option');
|
||
option.setAttribute('data-month', value);
|
||
option.setAttribute('aria-selected', String(value === state.billMonth));
|
||
option.textContent = monthLabel(value);
|
||
if (value === state.billMonth) option.classList.add('is-selected');
|
||
return option;
|
||
}
|
||
|
||
function renderMonthSheet() {
|
||
replaceChildren(
|
||
$('monthOptionList'),
|
||
monthOptions().map(function (date) {
|
||
return monthOption(date);
|
||
})
|
||
);
|
||
}
|
||
|
||
function openMonthSheet() {
|
||
renderMonthSheet();
|
||
$('monthSheet').hidden = false;
|
||
$('monthSheet').setAttribute('aria-hidden', 'false');
|
||
document.body.classList.add('modal-open');
|
||
window.setTimeout(function () {
|
||
var selected = $('monthOptionList').querySelector('.is-selected');
|
||
if (selected && selected.scrollIntoView) {
|
||
selected.scrollIntoView({ block: 'center' });
|
||
}
|
||
}, 0);
|
||
}
|
||
|
||
function closeMonthSheet() {
|
||
$('monthSheet').hidden = true;
|
||
$('monthSheet').setAttribute('aria-hidden', 'true');
|
||
document.body.classList.remove('modal-open');
|
||
}
|
||
|
||
function selectMonth(value) {
|
||
var nextMonth = normalizeBillMonth(value);
|
||
if (!nextMonth || nextMonth === state.billMonth) {
|
||
closeMonthSheet();
|
||
return;
|
||
}
|
||
state.billMonth = nextMonth;
|
||
closeMonthSheet();
|
||
renderTeamList();
|
||
}
|
||
|
||
function inviteProfile(item) {
|
||
return item.profile || item;
|
||
}
|
||
|
||
function statusLabel(status) {
|
||
if (
|
||
status === 'success' ||
|
||
status === 'Success' ||
|
||
status === 'accepted'
|
||
) {
|
||
return t('bd_center.success', 'Success');
|
||
}
|
||
if (status === 'pending' || status === 'Pending')
|
||
return t('bd_center.pending', 'Pending');
|
||
return '';
|
||
}
|
||
|
||
function commandID(prefix, targetUserID) {
|
||
return [
|
||
prefix,
|
||
targetUserID,
|
||
Date.now(),
|
||
Math.random().toString(16).slice(2),
|
||
].join('-');
|
||
}
|
||
|
||
function normalizeInvitationMessage(item) {
|
||
var invitation = (item && item.invitation) || item || {};
|
||
var inviter = (item && item.inviter) || {};
|
||
var id = String(
|
||
invitation.invitation_id || invitation.invitationId || ''
|
||
);
|
||
var type = firstValue(invitation, [
|
||
'invitation_type',
|
||
'invitationType',
|
||
]);
|
||
var agencyName = firstValue(invitation, ['agency_name', 'agencyName']);
|
||
var inviterName =
|
||
displayName(inviter, '') ||
|
||
firstValue(invitation, ['inviter_user_id', 'inviterUserId']) ||
|
||
t('bd_center.inviter', 'Inviter');
|
||
return {
|
||
id: id,
|
||
type: type,
|
||
name: inviterName,
|
||
account:
|
||
displayID(inviter, '') ||
|
||
firstValue(invitation, ['inviter_user_id', 'inviterUserId']),
|
||
avatar: firstValue(inviter, ['avatar']),
|
||
title: invitationMessageTitle(type, inviterName, agencyName),
|
||
};
|
||
}
|
||
|
||
function invitationMessageTitle(type, inviterName, agencyName) {
|
||
if (type === 'host') {
|
||
return t(
|
||
'bd_center.host_invitation',
|
||
'{name} invited you to join {agency}'
|
||
)
|
||
.replace('{name}', inviterName)
|
||
.replace(
|
||
'{agency}',
|
||
agencyName || t('bd_center.agency', 'Agency')
|
||
);
|
||
}
|
||
if (type === 'agency') {
|
||
return t(
|
||
'bd_center.agency_invitation',
|
||
'{name} invited you to create agency {agency}'
|
||
)
|
||
.replace('{name}', inviterName)
|
||
.replace(
|
||
'{agency}',
|
||
agencyName || t('bd_center.agency', 'Agency')
|
||
);
|
||
}
|
||
if (type === 'bd') {
|
||
return t(
|
||
'bd_center.bd_invitation',
|
||
'{name} invited you to become BD'
|
||
).replace('{name}', inviterName);
|
||
}
|
||
return t(
|
||
'bd_center.role_invitation',
|
||
'{name} sent you an invitation'
|
||
).replace('{name}', inviterName);
|
||
}
|
||
|
||
function inviteCard(item) {
|
||
var profile = inviteProfile(item);
|
||
var status = item.status || '';
|
||
var card = document.createElement('article');
|
||
var avatar = document.createElement('div');
|
||
var main = document.createElement('div');
|
||
var name = document.createElement('div');
|
||
var meta = document.createElement('div');
|
||
var side = document.createElement('div');
|
||
card.className = 'invite-user-card';
|
||
avatar.className = 'invite-user-avatar';
|
||
main.className = 'invite-user-main';
|
||
name.className = 'invite-user-name';
|
||
meta.className = 'invite-user-meta';
|
||
side.className = 'invite-user-side';
|
||
renderImageAvatar(
|
||
avatar,
|
||
profile.avatar,
|
||
profile.name,
|
||
'invite-avatar-fallback'
|
||
);
|
||
name.textContent = profile.name || '-';
|
||
meta.textContent = 'UID: ' + (profile.account || '-');
|
||
main.appendChild(name);
|
||
main.appendChild(meta);
|
||
|
||
if (status) {
|
||
var badge = document.createElement('span');
|
||
badge.className =
|
||
'invite-badge ' +
|
||
(status === 'pending' || status === 'Pending'
|
||
? 'pending'
|
||
: 'success');
|
||
badge.textContent = statusLabel(status);
|
||
side.appendChild(badge);
|
||
} else {
|
||
var targetUserID = String(profile.userId || profile.id || '');
|
||
var invite = document.createElement('button');
|
||
invite.className = 'invite-action';
|
||
invite.type = 'button';
|
||
invite.disabled = Boolean(state.inviting[targetUserID]);
|
||
invite.textContent = state.inviting[targetUserID]
|
||
? t('bd_center.pending', 'Pending')
|
||
: t('bd_center.invite', 'Invite');
|
||
invite.addEventListener('click', function () {
|
||
submitInvite(profile);
|
||
});
|
||
side.appendChild(invite);
|
||
}
|
||
|
||
card.appendChild(avatar);
|
||
card.appendChild(main);
|
||
card.appendChild(side);
|
||
return card;
|
||
}
|
||
|
||
function setInviteStatus(text, type) {
|
||
var node = $('inviteStatus');
|
||
node.textContent = text || '';
|
||
node.hidden = !text;
|
||
node.classList.toggle('is-error', type === 'error');
|
||
node.classList.toggle('is-success', type === 'success');
|
||
}
|
||
|
||
function renderInviteModal() {
|
||
var rows =
|
||
state.inviteMode === 'search'
|
||
? state.searched.map(inviteCard)
|
||
: data.inviteRecords.map(inviteCard);
|
||
setInviteStatus(state.inviteStatus, state.inviteStatusType);
|
||
replaceChildren($('inviteList'), rows);
|
||
$('inviteEmpty').hidden =
|
||
rows.length > 0 || Boolean(state.inviteStatus);
|
||
$('inviteSearchButton').disabled =
|
||
!state.inviteQuery.trim() || Boolean(state.searching);
|
||
}
|
||
|
||
function renderUnread() {
|
||
var dot = $('messageUnreadDot');
|
||
if (dot) dot.hidden = state.messages.length <= 0;
|
||
}
|
||
|
||
function renderMessages() {
|
||
var list = $('messageList');
|
||
var empty = $('messageEmpty');
|
||
if (!list || !empty) return;
|
||
list.textContent = '';
|
||
empty.hidden = state.messages.length > 0;
|
||
empty.textContent = t('bd_center.no_messages', 'No messages');
|
||
state.messages.forEach(function (message) {
|
||
var card = document.createElement('article');
|
||
var avatar = document.createElement('div');
|
||
var main = document.createElement('div');
|
||
var title = document.createElement('div');
|
||
var meta = document.createElement('div');
|
||
var side = document.createElement('div');
|
||
var agree = document.createElement('button');
|
||
var refuse = document.createElement('button');
|
||
card.className = 'message-card';
|
||
avatar.className = 'message-avatar';
|
||
main.className = 'message-main';
|
||
title.className = 'message-title';
|
||
meta.className = 'message-meta';
|
||
side.className = 'message-actions';
|
||
agree.className = 'message-action agree';
|
||
refuse.className = 'message-action refuse';
|
||
agree.type = 'button';
|
||
refuse.type = 'button';
|
||
agree.disabled = Boolean(state.processingMessages[message.id]);
|
||
refuse.disabled = Boolean(state.processingMessages[message.id]);
|
||
renderImageAvatar(
|
||
avatar,
|
||
message.avatar,
|
||
message.name,
|
||
'message-fallback'
|
||
);
|
||
title.textContent = message.title;
|
||
meta.textContent = message.account ? 'ID: ' + message.account : '';
|
||
agree.textContent = t('bd_center.agree', 'Agree');
|
||
refuse.textContent = t('bd_center.refuse', 'Refuse');
|
||
agree.addEventListener('click', function () {
|
||
processInvitationMessage(message, 'accept');
|
||
});
|
||
refuse.addEventListener('click', function () {
|
||
processInvitationMessage(message, 'reject');
|
||
});
|
||
main.appendChild(title);
|
||
main.appendChild(meta);
|
||
side.appendChild(agree);
|
||
side.appendChild(refuse);
|
||
card.appendChild(avatar);
|
||
card.appendChild(main);
|
||
card.appendChild(side);
|
||
list.appendChild(card);
|
||
});
|
||
renderUnread();
|
||
}
|
||
|
||
function openInviteModal() {
|
||
state.inviteQuery = '';
|
||
state.inviteMode = 'records';
|
||
state.searched = [];
|
||
state.inviteStatus = '';
|
||
state.inviteStatusType = '';
|
||
state.searching = false;
|
||
$('inviteSearchInput').value = '';
|
||
$('inviteModal').hidden = false;
|
||
$('inviteModal').setAttribute('aria-hidden', 'false');
|
||
document.body.classList.add('modal-open');
|
||
renderInviteModal();
|
||
window.setTimeout(function () {
|
||
$('inviteSearchInput').focus();
|
||
}, 80);
|
||
}
|
||
|
||
function closeInviteModal() {
|
||
$('inviteModal').hidden = true;
|
||
$('inviteModal').setAttribute('aria-hidden', 'true');
|
||
document.body.classList.remove('modal-open');
|
||
}
|
||
|
||
function searchInvite(event) {
|
||
event.preventDefault();
|
||
var queryValue = state.inviteQuery.trim();
|
||
state.inviteMode = 'search';
|
||
state.inviteStatus = '';
|
||
state.inviteStatusType = '';
|
||
state.searched = [];
|
||
if (!queryValue) {
|
||
renderInviteModal();
|
||
return;
|
||
}
|
||
if (!api().user || !api().user.resolveDisplayUserID) {
|
||
state.inviteStatus = t(
|
||
'bd_center.api_not_ready',
|
||
'API module is not ready.'
|
||
);
|
||
state.inviteStatusType = 'error';
|
||
renderInviteModal();
|
||
return;
|
||
}
|
||
state.inviteStatus = t('bd_center.searching', 'Searching...');
|
||
state.searching = true;
|
||
renderInviteModal();
|
||
api()
|
||
.user.resolveDisplayUserID(queryValue)
|
||
.then(function (payload) {
|
||
var profile = normalizeInviteProfile(payload, queryValue);
|
||
state.inviteStatus = profile
|
||
? ''
|
||
: t('bd_center.no_users_found', 'No users found');
|
||
state.inviteStatusType = '';
|
||
state.searched = profile ? [profile] : [];
|
||
renderInviteModal();
|
||
})
|
||
.catch(function (error) {
|
||
state.inviteStatus =
|
||
(error && error.message) ||
|
||
t(
|
||
'bd_center.search_failed',
|
||
'Search failed. Try again later.'
|
||
);
|
||
state.inviteStatusType = 'error';
|
||
state.searched = [];
|
||
renderInviteModal();
|
||
})
|
||
.finally(function () {
|
||
state.searching = false;
|
||
renderInviteModal();
|
||
});
|
||
}
|
||
|
||
function submitInvite(profile) {
|
||
var targetUserID = String(profile.userId || profile.id || '');
|
||
if (!targetUserID) return;
|
||
if (!centerAPI() || !centerAPI().inviteAgency) {
|
||
state.inviteStatus = t(
|
||
'bd_center.api_not_ready',
|
||
'API module is not ready.'
|
||
);
|
||
state.inviteStatusType = 'error';
|
||
renderInviteModal();
|
||
return;
|
||
}
|
||
state.inviting[targetUserID] = true;
|
||
renderInviteModal();
|
||
centerAPI()
|
||
.inviteAgency({
|
||
command_id: commandID('bd-agency', targetUserID),
|
||
target_user_id: targetUserID,
|
||
agency_name: profile.name,
|
||
})
|
||
.then(function () {
|
||
data.inviteRecords.unshift({
|
||
id: 'inv-' + Date.now(),
|
||
status: 'success',
|
||
profile: profile,
|
||
});
|
||
state.inviteMode = 'records';
|
||
state.searched = [];
|
||
state.inviteStatus = t(
|
||
'bd_center.invitation_submitted',
|
||
'Invitation submitted'
|
||
);
|
||
state.inviteStatusType = 'success';
|
||
loadRealData().catch(function () {});
|
||
renderInviteModal();
|
||
})
|
||
.catch(function (error) {
|
||
state.inviteStatus =
|
||
(error && error.message) ||
|
||
t(
|
||
'bd_center.invite_failed',
|
||
'Invite failed. Try again later.'
|
||
);
|
||
state.inviteStatusType = 'error';
|
||
renderInviteModal();
|
||
})
|
||
.finally(function () {
|
||
delete state.inviting[targetUserID];
|
||
renderInviteModal();
|
||
});
|
||
}
|
||
|
||
function navigateToWithdrawExchange() {
|
||
var params = new URLSearchParams(window.location.search);
|
||
params.set('identity', 'BD');
|
||
params.set('salaryType', BD_SALARY_ASSET);
|
||
params.set('asset_type', BD_SALARY_ASSET);
|
||
if (!params.has('mode')) params.set('mode', 'withdraw');
|
||
window.location.href =
|
||
'../withdraw-exchange/index.html?' + params.toString();
|
||
}
|
||
|
||
function loadRoleInvitations() {
|
||
if (!api().roleInvitations || !api().roleInvitations.list) {
|
||
state.messages = [];
|
||
renderMessages();
|
||
return Promise.resolve(false);
|
||
}
|
||
return api()
|
||
.roleInvitations.list('pending', 50)
|
||
.then(function (payload) {
|
||
var items =
|
||
(payload && (payload.items || payload.invitations)) || [];
|
||
state.messages = items
|
||
.map(normalizeInvitationMessage)
|
||
.filter(function (item) {
|
||
return !!item.id;
|
||
});
|
||
renderMessages();
|
||
return true;
|
||
})
|
||
.catch(function () {
|
||
state.messages = [];
|
||
renderMessages();
|
||
return false;
|
||
});
|
||
}
|
||
|
||
function processInvitationMessage(message, action) {
|
||
if (
|
||
!message ||
|
||
!message.id ||
|
||
!api().roleInvitations ||
|
||
!api().roleInvitations.process
|
||
) {
|
||
return;
|
||
}
|
||
state.processingMessages[message.id] = true;
|
||
renderMessages();
|
||
api()
|
||
.roleInvitations.process(message.id, {
|
||
command_id: commandID('role-invite-' + action, message.id),
|
||
action: action,
|
||
reason: 'h5_message_center',
|
||
})
|
||
.then(function () {
|
||
state.messages = state.messages.filter(function (item) {
|
||
return item.id !== message.id;
|
||
});
|
||
toast(
|
||
t(
|
||
action === 'accept'
|
||
? 'bd_center.invitation_accepted'
|
||
: 'bd_center.invitation_rejected',
|
||
action === 'accept'
|
||
? 'Invitation accepted.'
|
||
: 'Invitation rejected.'
|
||
)
|
||
);
|
||
renderMessages();
|
||
return loadRealData();
|
||
})
|
||
.catch(function (error) {
|
||
toast(
|
||
(error && error.message) ||
|
||
t(
|
||
'bd_center.process_failed',
|
||
'Process failed. Try again later.'
|
||
)
|
||
);
|
||
})
|
||
.finally(function () {
|
||
delete state.processingMessages[message.id];
|
||
renderMessages();
|
||
});
|
||
}
|
||
|
||
function openMessages() {
|
||
$('messageModal').hidden = false;
|
||
$('messageModal').setAttribute('aria-hidden', 'false');
|
||
document.body.classList.add('modal-open');
|
||
renderMessages();
|
||
}
|
||
|
||
function closeMessages() {
|
||
$('messageModal').hidden = true;
|
||
$('messageModal').setAttribute('aria-hidden', 'true');
|
||
document.body.classList.remove('modal-open');
|
||
}
|
||
|
||
function setLoading(loading) {
|
||
state.loading = Boolean(loading);
|
||
render();
|
||
}
|
||
|
||
function loadRealData() {
|
||
var service = centerAPI();
|
||
setLoading(true);
|
||
if (
|
||
!service ||
|
||
!service.overview ||
|
||
!service.agencies ||
|
||
!service.inviteAgency
|
||
) {
|
||
setLoading(false);
|
||
return Promise.reject(
|
||
new Error(
|
||
t('bd_center.api_not_ready', 'API module is not ready.')
|
||
)
|
||
);
|
||
}
|
||
return Promise.all([service.overview(), service.agencies(50)])
|
||
.then(function (results) {
|
||
applyOverview(results[0] || {});
|
||
applyAgencies(results[1] || {});
|
||
return true;
|
||
})
|
||
.catch(function (error) {
|
||
data.profile = null;
|
||
data.balance = { available: 0 };
|
||
data.agencyBill = {
|
||
agencyNumber: 0,
|
||
totalSalary: 0,
|
||
totalRecharge: 0,
|
||
memberBillList: [],
|
||
};
|
||
throw error;
|
||
})
|
||
.finally(function () {
|
||
setLoading(false);
|
||
});
|
||
}
|
||
|
||
function bindEvents() {
|
||
$('backButton').addEventListener('click', function () {
|
||
if (window.HyAppBridge) {
|
||
window.HyAppBridge.back();
|
||
return;
|
||
}
|
||
if (window.history.length > 1) window.history.back();
|
||
});
|
||
$('withdrawExchangeButton').addEventListener(
|
||
'click',
|
||
navigateToWithdrawExchange
|
||
);
|
||
$('messageButton').addEventListener('click', openMessages);
|
||
$('messageBackdrop').addEventListener('click', closeMessages);
|
||
$('messageCloseButton').addEventListener('click', closeMessages);
|
||
$('inviteAgentButton').addEventListener('click', openInviteModal);
|
||
$('inviteBackdrop').addEventListener('click', closeInviteModal);
|
||
$('inviteCloseButton').addEventListener('click', closeInviteModal);
|
||
$('inviteSearchInput').addEventListener('input', function (event) {
|
||
state.inviteQuery = event.target.value;
|
||
if (!state.inviteQuery.trim()) {
|
||
state.inviteMode = 'records';
|
||
state.searched = [];
|
||
state.inviteStatus = '';
|
||
state.inviteStatusType = '';
|
||
}
|
||
renderInviteModal();
|
||
});
|
||
$('inviteSearchForm').addEventListener('submit', searchInvite);
|
||
$('billMonthButton').addEventListener('click', openMonthSheet);
|
||
$('monthSheetBackdrop').addEventListener('click', closeMonthSheet);
|
||
$('monthSheetCloseButton').addEventListener('click', closeMonthSheet);
|
||
$('monthOptionList').addEventListener('click', function (event) {
|
||
var option = event.target.closest('[data-month]');
|
||
if (!option) return;
|
||
selectMonth(option.getAttribute('data-month'));
|
||
});
|
||
}
|
||
|
||
function render() {
|
||
renderProfile();
|
||
renderBalance();
|
||
renderTeamList();
|
||
renderInviteModal();
|
||
renderMessages();
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
render();
|
||
bindEvents();
|
||
loadRealData()
|
||
.catch(function (error) {
|
||
toast(
|
||
(error && error.message) ||
|
||
t(
|
||
'bd_center.load_failed',
|
||
'Load failed. Try again later.'
|
||
)
|
||
);
|
||
})
|
||
.finally(loadRoleInvitations);
|
||
if (window.HyAppBridge) {
|
||
window.HyAppBridge.ready({
|
||
page: 'bd-center',
|
||
});
|
||
}
|
||
});
|
||
|
||
window.addEventListener('hyapp:i18n-ready', function () {
|
||
render();
|
||
});
|
||
|
||
window.addEventListener('hyapp:role-invitation-processed', function () {
|
||
loadRealData().catch(function () {});
|
||
});
|
||
})();
|