公会系统
This commit is contained in:
parent
dcc1938e63
commit
b5fbc1add9
119
common/api.js
119
common/api.js
@ -85,6 +85,16 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
}
|
||||
|
||||
function getAccessToken() {
|
||||
var queryToken =
|
||||
readQuery('token') ||
|
||||
readQuery('access_token') ||
|
||||
readQuery('accessToken');
|
||||
if (queryToken) {
|
||||
memoryAccessToken = queryToken;
|
||||
if (shouldPersist())
|
||||
window.localStorage.setItem(ACCESS_TOKEN_KEY, queryToken);
|
||||
return queryToken;
|
||||
}
|
||||
if (memoryAccessToken) return memoryAccessToken;
|
||||
if (!shouldPersist()) return '';
|
||||
return window.localStorage.getItem(ACCESS_TOKEN_KEY) || '';
|
||||
@ -235,6 +245,15 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
resolveDisplayUserID: function (displayUserID) {
|
||||
return request(
|
||||
'/api/v1/users/by-display-user-id/' +
|
||||
encodeURIComponent(displayUserID || ''),
|
||||
{
|
||||
method: 'GET',
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
var walletAPI = {
|
||||
@ -247,6 +266,48 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
query: { asset_type: value },
|
||||
});
|
||||
},
|
||||
transactions: function (params) {
|
||||
return request('/api/v1/wallet/transactions', {
|
||||
method: 'GET',
|
||||
query: params || {},
|
||||
});
|
||||
},
|
||||
transferCoinFromSeller: function (payload) {
|
||||
return request('/api/v1/wallet/coin-seller/transfer', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var salaryWalletAPI = {
|
||||
overview: function (identity) {
|
||||
return request('/api/v1/salary-wallet/overview', {
|
||||
method: 'GET',
|
||||
query: { identity: identity },
|
||||
});
|
||||
},
|
||||
searchCoinSeller: function (displayUserID, identity) {
|
||||
return request('/api/v1/salary-wallet/coin-sellers/search', {
|
||||
method: 'GET',
|
||||
query: {
|
||||
display_user_id: displayUserID,
|
||||
identity: identity,
|
||||
},
|
||||
});
|
||||
},
|
||||
exchange: function (payload) {
|
||||
return request('/api/v1/salary-wallet/exchange', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
transferToCoinSeller: function (payload) {
|
||||
return request('/api/v1/salary-wallet/transfer-to-coin-seller', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var hostAPI = {
|
||||
@ -318,6 +379,60 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
},
|
||||
};
|
||||
|
||||
var bdLeaderCenterAPI = {
|
||||
overview: function () {
|
||||
return request('/api/v1/bd-leader-center/overview', {
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
bds: function (pageSize) {
|
||||
return request('/api/v1/bd-leader-center/bds', {
|
||||
method: 'GET',
|
||||
query: { page_size: pageSize || 20 },
|
||||
});
|
||||
},
|
||||
agencies: function (pageSize) {
|
||||
return request('/api/v1/bd-leader-center/agencies', {
|
||||
method: 'GET',
|
||||
query: { page_size: pageSize || 20 },
|
||||
});
|
||||
},
|
||||
inviteBD: function (payload) {
|
||||
return request('/api/v1/bd-leader/invitations/bd', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
inviteAgency: function (payload) {
|
||||
return request('/api/v1/bd-leader/invitations/agency', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var bdCenterAPI = {
|
||||
overview: function () {
|
||||
return request('/api/v1/bd-center/overview', {
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
agencies: function (pageSize) {
|
||||
return request('/api/v1/bd-center/agencies', {
|
||||
method: 'GET',
|
||||
query: { page_size: pageSize || 20 },
|
||||
});
|
||||
},
|
||||
inviteAgency: function (payload) {
|
||||
return request('/api/v1/bd/invitations/agency', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var superadminCenterAPI = bdLeaderCenterAPI;
|
||||
|
||||
var levelAPI = {
|
||||
overview: function () {
|
||||
return request('/api/v1/levels/me/overview', { method: 'GET' });
|
||||
@ -364,9 +479,13 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
vip: vipAPI,
|
||||
user: userAPI,
|
||||
wallet: walletAPI,
|
||||
salaryWallet: salaryWalletAPI,
|
||||
host: hostAPI,
|
||||
hostCenter: hostCenterAPI,
|
||||
agencyCenter: agencyCenterAPI,
|
||||
bdCenter: bdCenterAPI,
|
||||
bdLeaderCenter: bdLeaderCenterAPI,
|
||||
superadminCenter: superadminCenterAPI,
|
||||
level: levelAPI,
|
||||
};
|
||||
clearLocalDevCache();
|
||||
|
||||
@ -101,6 +101,9 @@
|
||||
"withdraw_exchange.no_salary_history": "لا يوجد سجل راتب",
|
||||
"withdraw_exchange.balance": "الرصيد",
|
||||
"withdraw_exchange.history_host_salary": "راتب المضيف",
|
||||
"withdraw_exchange.history_agency_salary": "راتب الوكالة",
|
||||
"withdraw_exchange.history_bd_salary": "راتب BD",
|
||||
"withdraw_exchange.history_admin_salary": "راتب المسؤول",
|
||||
"withdraw_exchange.history_exchange_to_golds": "تبديل إلى عملات",
|
||||
"withdraw_exchange.history_gift_reward": "مكافأة الهدايا",
|
||||
"withdraw_exchange.mock_user_name": "المستخدم {account}",
|
||||
@ -146,7 +149,7 @@
|
||||
"bd_center.change_language": "تغيير اللغة",
|
||||
"bd_center.role": "BD",
|
||||
"bd_center.salary": "الراتب",
|
||||
"bd_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_center.withdraw_exchange": "سحب/تبديل",
|
||||
"bd_center.invite_agent": "دعوة وكيل",
|
||||
"bd_center.agency_list": "قائمة الوكالات",
|
||||
"bd_center.agency_statistics": "إحصائيات الوكالات",
|
||||
@ -169,6 +172,38 @@
|
||||
"bd_center.close": "إغلاق",
|
||||
"bd_center.mock_navigation": "انتقال تجريبي: {label}",
|
||||
"bd_center.mock_bill_loaded": "تم تحميل فاتورة تجريبية.",
|
||||
"bd_center.load_failed": "فشل التحميل. حاول مرة أخرى لاحقًا.",
|
||||
"bd_center.api_not_ready": "وحدة API غير جاهزة.",
|
||||
"bd_center.searching": "جارٍ البحث...",
|
||||
"bd_center.search_failed": "فشل البحث. حاول مرة أخرى لاحقًا.",
|
||||
"bd_center.invite_failed": "فشلت الدعوة. حاول مرة أخرى لاحقًا.",
|
||||
"bd_center.agency_added": "تمت إضافة الوكالة.",
|
||||
"bd_center.tools": "أدوات BD",
|
||||
"bd_leader_center.back": "رجوع",
|
||||
"bd_leader_center.title": "مركز BD Leader",
|
||||
"bd_leader_center.change_language": "تغيير اللغة",
|
||||
"bd_leader_center.role": "BD Leader",
|
||||
"bd_leader_center.salary": "الراتب",
|
||||
"bd_leader_center.withdraw_exchange": "سحب/تبديل",
|
||||
"bd_leader_center.salary_history": "سجل الراتب",
|
||||
"bd_leader_center.invite_bd": "دعوة BD",
|
||||
"bd_leader_center.bd_list": "قائمة BD",
|
||||
"bd_leader_center.close": "إغلاق",
|
||||
"bd_leader_center.enter_user_id": "أدخل معرف المستخدم",
|
||||
"bd_leader_center.search": "بحث",
|
||||
"bd_leader_center.no_users_found": "لم يتم العثور على مستخدمين",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "عدد BD",
|
||||
"bd_leader_center.agencies": "الوكالات",
|
||||
"bd_leader_center.agency_number": "عدد الوكالات",
|
||||
"bd_leader_center.team_salary": "راتب الفريق",
|
||||
"bd_leader_center.team_recharge": "شحن الفريق",
|
||||
"bd_leader_center.total_income": "إجمالي الدخل",
|
||||
"bd_leader_center.previous_income": "دخل الفترة السابقة",
|
||||
"bd_leader_center.in_progress": "قيد التنفيذ",
|
||||
"bd_leader_center.invite": "دعوة",
|
||||
"bd_leader_center.invite_success": "تم إرسال الدعوة.",
|
||||
"bd_leader_center.tools": "أدوات BD Leader",
|
||||
"agency_center.title": "مركز الوكالة",
|
||||
"agency_center.back": "رجوع",
|
||||
"agency_center.change_language": "تغيير اللغة",
|
||||
@ -212,5 +247,54 @@
|
||||
"agency_center.invite_step_1": "ادع المستخدمين لتنزيل التطبيق.",
|
||||
"agency_center.invite_step_2": "يجب على المستخدمين المدعوين تسجيل الدخول إلى التطبيق.",
|
||||
"agency_center.invite_step_3": "Me > Host Center > Apply to join the team.",
|
||||
"agency_center.invite_step_4": "أدخل معرف الفريق ثم اضغط إرسال."
|
||||
"agency_center.invite_step_4": "أدخل معرف الفريق ثم اضغط إرسال.",
|
||||
"coinseller_center.title": "مركز بائع العملات",
|
||||
"coinseller_center.back": "رجوع",
|
||||
"coinseller_center.change_language": "تغيير اللغة",
|
||||
"coinseller_center.role": "بائع عملات",
|
||||
"coinseller_center.coins": "العملات",
|
||||
"coinseller_center.coins_lower": "عملات",
|
||||
"coinseller_center.available_stock": "الرصيد المتاح",
|
||||
"coinseller_center.history": "السجل",
|
||||
"coinseller_center.help": "مساعدة",
|
||||
"coinseller_center.recharge_user": "شحن المستخدم",
|
||||
"coinseller_center.search_by_user_id": "البحث بمعرف المستخدم",
|
||||
"coinseller_center.enter_user_id": "أدخل معرف المستخدم",
|
||||
"coinseller_center.search": "بحث",
|
||||
"coinseller_center.target_user": "المستخدم الهدف",
|
||||
"coinseller_center.change": "تغيير",
|
||||
"coinseller_center.recharge_coins": "شحن العملات",
|
||||
"coinseller_center.enter_coin_amount": "أدخل كمية العملات",
|
||||
"coinseller_center.coin_amount_placeholder": "أدخل كمية العملات",
|
||||
"coinseller_center.recharge_now": "اشحن الآن",
|
||||
"coinseller_center.recent_records": "السجلات الأخيرة",
|
||||
"coinseller_center.today_activity": "نشاط اليوم",
|
||||
"coinseller_center.view_all": "عرض الكل",
|
||||
"coinseller_center.close": "إغلاق",
|
||||
"coinseller_center.transaction_records": "سجلات المعاملات",
|
||||
"coinseller_center.cancel": "إلغاء",
|
||||
"coinseller_center.income": "الدخل",
|
||||
"coinseller_center.expenditure": "المصروفات",
|
||||
"coinseller_center.load_more": "تحميل المزيد",
|
||||
"coinseller_center.faq_title": "الأسئلة الشائعة",
|
||||
"coinseller_center.faq_question_1": "كيف أشحن؟",
|
||||
"coinseller_center.faq_answer_1": "ابحث عن المستخدم، أدخل كمية العملات، ثم أكد الشحن.",
|
||||
"coinseller_center.faq_question_2": "كيف أتحقق من السجلات؟",
|
||||
"coinseller_center.faq_answer_2": "افتح السجل وبدل بين الدخل والمصروفات.",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "المنطقة: {region}",
|
||||
"coinseller_center.user_name_template": "المستخدم {id}",
|
||||
"coinseller_center.stock_transfer": "تحويل المخزون",
|
||||
"coinseller_center.transfer_out": "تحويل للخارج",
|
||||
"coinseller_center.system": "النظام",
|
||||
"coinseller_center.no_transaction_records": "لا توجد سجلات معاملات",
|
||||
"coinseller_center.select_user_first": "اختر مستخدما أولا.",
|
||||
"coinseller_center.valid_amount_required": "أدخل مبلغا صالحا.",
|
||||
"coinseller_center.amount_exceeds_stock": "المبلغ يتجاوز الرصيد.",
|
||||
"coinseller_center.recharge_success": "تم الشحن بنجاح.",
|
||||
"coinseller_center.user_not_found": "لم يتم العثور على المستخدم.",
|
||||
"coinseller_center.user_selected": "تم اختيار المستخدم.",
|
||||
"coinseller_center.loading": "جار التحميل...",
|
||||
"coinseller_center.load_failed": "فشل التحميل. حاول مرة أخرى لاحقا.",
|
||||
"coinseller_center.transfer_failed": "فشل التحويل."
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
"withdraw_exchange.exchange_amount": "Exchange amount",
|
||||
"withdraw_exchange.transfer_to": "Transfer to",
|
||||
"withdraw_exchange.transfer_amount": "Transfer amount",
|
||||
"withdraw_exchange.estimated_coins": "Estimated coins",
|
||||
"withdraw_exchange.search": "Search",
|
||||
"withdraw_exchange.searching": "Searching...",
|
||||
"withdraw_exchange.minimum": "Minimum 50 USD",
|
||||
@ -101,6 +102,9 @@
|
||||
"withdraw_exchange.no_salary_history": "No salary history",
|
||||
"withdraw_exchange.balance": "Balance",
|
||||
"withdraw_exchange.history_host_salary": "Host salary",
|
||||
"withdraw_exchange.history_agency_salary": "Agency salary",
|
||||
"withdraw_exchange.history_bd_salary": "BD salary",
|
||||
"withdraw_exchange.history_admin_salary": "Admin salary",
|
||||
"withdraw_exchange.history_exchange_to_golds": "Exchange to golds",
|
||||
"withdraw_exchange.history_gift_reward": "Gift reward",
|
||||
"withdraw_exchange.mock_user_name": "User {account}",
|
||||
@ -115,6 +119,11 @@
|
||||
"withdraw_exchange.withdraw_success": "Withdrawal submitted",
|
||||
"withdraw_exchange.exchange_success": "Exchange success",
|
||||
"withdraw_exchange.transfer_success": "Transfer success",
|
||||
"withdraw_exchange.rate_not_configured": "Exchange rate not configured.",
|
||||
"withdraw_exchange.withdraw_not_available": "Withdraw is not available yet.",
|
||||
"withdraw_exchange.submit_failed": "Submit failed.",
|
||||
"withdraw_exchange.load_failed": "Load failed. Try again later.",
|
||||
"withdraw_exchange.search_failed": "Search failed. Try again later.",
|
||||
"superadmin_center.back": "Back",
|
||||
"superadmin_center.title": "Super Admin Center",
|
||||
"superadmin_center.change_language": "Change language",
|
||||
@ -169,6 +178,38 @@
|
||||
"bd_center.close": "Close",
|
||||
"bd_center.mock_navigation": "Mock navigation: {label}",
|
||||
"bd_center.mock_bill_loaded": "Mock bill loaded.",
|
||||
"bd_center.load_failed": "Load failed. Try again later.",
|
||||
"bd_center.api_not_ready": "API module is not ready.",
|
||||
"bd_center.searching": "Searching...",
|
||||
"bd_center.search_failed": "Search failed. Try again later.",
|
||||
"bd_center.invite_failed": "Invite failed. Try again later.",
|
||||
"bd_center.agency_added": "Agency added.",
|
||||
"bd_center.tools": "BD tools",
|
||||
"bd_leader_center.back": "Back",
|
||||
"bd_leader_center.title": "BD Leader Center",
|
||||
"bd_leader_center.change_language": "Change language",
|
||||
"bd_leader_center.role": "BD Leader",
|
||||
"bd_leader_center.salary": "Salary",
|
||||
"bd_leader_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_leader_center.salary_history": "Salary History",
|
||||
"bd_leader_center.invite_bd": "Invite BD",
|
||||
"bd_leader_center.bd_list": "BD List",
|
||||
"bd_leader_center.close": "Close",
|
||||
"bd_leader_center.enter_user_id": "Enter User ID",
|
||||
"bd_leader_center.search": "Search",
|
||||
"bd_leader_center.no_users_found": "No users found",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "BD number",
|
||||
"bd_leader_center.agencies": "Agencies",
|
||||
"bd_leader_center.agency_number": "Agency number",
|
||||
"bd_leader_center.team_salary": "Team salary",
|
||||
"bd_leader_center.team_recharge": "Team recharge",
|
||||
"bd_leader_center.total_income": "Total income",
|
||||
"bd_leader_center.previous_income": "Previous income",
|
||||
"bd_leader_center.in_progress": "In progress",
|
||||
"bd_leader_center.invite": "Invite",
|
||||
"bd_leader_center.invite_success": "Invitation submitted.",
|
||||
"bd_leader_center.tools": "BD Leader tools",
|
||||
"agency_center.title": "Agency Center",
|
||||
"agency_center.back": "Back",
|
||||
"agency_center.change_language": "Change language",
|
||||
@ -212,5 +253,54 @@
|
||||
"agency_center.invite_step_1": "Invite users to download APP.",
|
||||
"agency_center.invite_step_2": "Invited users need to log in to the APP.",
|
||||
"agency_center.invite_step_3": "Me > Host Center > Apply to join the team.",
|
||||
"agency_center.invite_step_4": "Enter the team ID, click send to join."
|
||||
"agency_center.invite_step_4": "Enter the team ID, click send to join.",
|
||||
"coinseller_center.title": "Coin Seller Center",
|
||||
"coinseller_center.back": "Back",
|
||||
"coinseller_center.change_language": "Change language",
|
||||
"coinseller_center.role": "Coin Seller",
|
||||
"coinseller_center.coins": "Coins",
|
||||
"coinseller_center.coins_lower": "coins",
|
||||
"coinseller_center.available_stock": "Available stock",
|
||||
"coinseller_center.history": "History",
|
||||
"coinseller_center.help": "Help",
|
||||
"coinseller_center.recharge_user": "Recharge user",
|
||||
"coinseller_center.search_by_user_id": "Search by user ID",
|
||||
"coinseller_center.enter_user_id": "Enter user ID",
|
||||
"coinseller_center.search": "Search",
|
||||
"coinseller_center.target_user": "Target user",
|
||||
"coinseller_center.change": "Change",
|
||||
"coinseller_center.recharge_coins": "Recharge coins",
|
||||
"coinseller_center.enter_coin_amount": "Enter coins amount",
|
||||
"coinseller_center.coin_amount_placeholder": "Enter coins amount",
|
||||
"coinseller_center.recharge_now": "Recharge now",
|
||||
"coinseller_center.recent_records": "Recent records",
|
||||
"coinseller_center.today_activity": "Today's activity",
|
||||
"coinseller_center.view_all": "View all",
|
||||
"coinseller_center.close": "Close",
|
||||
"coinseller_center.transaction_records": "Transaction records",
|
||||
"coinseller_center.cancel": "Cancel",
|
||||
"coinseller_center.income": "Income",
|
||||
"coinseller_center.expenditure": "Expenditure",
|
||||
"coinseller_center.load_more": "Load more",
|
||||
"coinseller_center.faq_title": "FAQ",
|
||||
"coinseller_center.faq_question_1": "How to recharge?",
|
||||
"coinseller_center.faq_answer_1": "Search a user, enter the coin amount, then confirm recharge.",
|
||||
"coinseller_center.faq_question_2": "How to check records?",
|
||||
"coinseller_center.faq_answer_2": "Open history and switch between income and expenditure.",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "Region: {region}",
|
||||
"coinseller_center.user_name_template": "User {id}",
|
||||
"coinseller_center.stock_transfer": "Stock transfer",
|
||||
"coinseller_center.transfer_out": "Transfer out",
|
||||
"coinseller_center.system": "System",
|
||||
"coinseller_center.no_transaction_records": "No transaction records",
|
||||
"coinseller_center.select_user_first": "Select a user first.",
|
||||
"coinseller_center.valid_amount_required": "Please enter a valid amount.",
|
||||
"coinseller_center.amount_exceeds_stock": "Amount exceeds stock.",
|
||||
"coinseller_center.recharge_success": "Recharge success.",
|
||||
"coinseller_center.user_not_found": "User not found.",
|
||||
"coinseller_center.user_selected": "User selected.",
|
||||
"coinseller_center.loading": "Loading...",
|
||||
"coinseller_center.load_failed": "Load failed. Try again later.",
|
||||
"coinseller_center.transfer_failed": "Transfer failed."
|
||||
}
|
||||
|
||||
@ -101,6 +101,9 @@
|
||||
"withdraw_exchange.no_salary_history": "No hay historial salarial",
|
||||
"withdraw_exchange.balance": "Saldo",
|
||||
"withdraw_exchange.history_host_salary": "Salario de host",
|
||||
"withdraw_exchange.history_agency_salary": "Salario de agencia",
|
||||
"withdraw_exchange.history_bd_salary": "Salario BD",
|
||||
"withdraw_exchange.history_admin_salary": "Salario admin",
|
||||
"withdraw_exchange.history_exchange_to_golds": "Intercambio a monedas",
|
||||
"withdraw_exchange.history_gift_reward": "Recompensa de regalos",
|
||||
"withdraw_exchange.mock_user_name": "Usuario {account}",
|
||||
@ -146,7 +149,7 @@
|
||||
"bd_center.change_language": "Cambiar idioma",
|
||||
"bd_center.role": "BD",
|
||||
"bd_center.salary": "Salario",
|
||||
"bd_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_center.withdraw_exchange": "Retirar/Canjear",
|
||||
"bd_center.invite_agent": "Invitar agente",
|
||||
"bd_center.agency_list": "Lista de agencias",
|
||||
"bd_center.agency_statistics": "Estadísticas de agencias",
|
||||
@ -169,6 +172,38 @@
|
||||
"bd_center.close": "Cerrar",
|
||||
"bd_center.mock_navigation": "Navegación mock: {label}",
|
||||
"bd_center.mock_bill_loaded": "Factura mock cargada.",
|
||||
"bd_center.load_failed": "Error al cargar. Inténtalo de nuevo más tarde.",
|
||||
"bd_center.api_not_ready": "El módulo API no está listo.",
|
||||
"bd_center.searching": "Buscando...",
|
||||
"bd_center.search_failed": "Error de búsqueda. Inténtalo de nuevo más tarde.",
|
||||
"bd_center.invite_failed": "Error al invitar. Inténtalo de nuevo más tarde.",
|
||||
"bd_center.agency_added": "Agencia agregada.",
|
||||
"bd_center.tools": "Herramientas BD",
|
||||
"bd_leader_center.back": "Volver",
|
||||
"bd_leader_center.title": "Centro de líder BD",
|
||||
"bd_leader_center.change_language": "Cambiar idioma",
|
||||
"bd_leader_center.role": "Líder BD",
|
||||
"bd_leader_center.salary": "Salario",
|
||||
"bd_leader_center.withdraw_exchange": "Retirar/Canjear",
|
||||
"bd_leader_center.salary_history": "Historial salarial",
|
||||
"bd_leader_center.invite_bd": "Invitar BD",
|
||||
"bd_leader_center.bd_list": "Lista BD",
|
||||
"bd_leader_center.close": "Cerrar",
|
||||
"bd_leader_center.enter_user_id": "Ingresa el ID de usuario",
|
||||
"bd_leader_center.search": "Buscar",
|
||||
"bd_leader_center.no_users_found": "No se encontraron usuarios",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "Número de BD",
|
||||
"bd_leader_center.agencies": "Agencias",
|
||||
"bd_leader_center.agency_number": "Número de agencias",
|
||||
"bd_leader_center.team_salary": "Salario del equipo",
|
||||
"bd_leader_center.team_recharge": "Recarga del equipo",
|
||||
"bd_leader_center.total_income": "Ingreso total",
|
||||
"bd_leader_center.previous_income": "Ingreso anterior",
|
||||
"bd_leader_center.in_progress": "En progreso",
|
||||
"bd_leader_center.invite": "Invitar",
|
||||
"bd_leader_center.invite_success": "Invitación enviada.",
|
||||
"bd_leader_center.tools": "Herramientas de líder BD",
|
||||
"agency_center.title": "Centro de agencia",
|
||||
"agency_center.back": "Volver",
|
||||
"agency_center.change_language": "Cambiar idioma",
|
||||
@ -212,5 +247,54 @@
|
||||
"agency_center.invite_step_1": "Invita usuarios a descargar la APP.",
|
||||
"agency_center.invite_step_2": "Los usuarios invitados deben iniciar sesión en la APP.",
|
||||
"agency_center.invite_step_3": "Me > Host Center > Solicitar unirse al equipo.",
|
||||
"agency_center.invite_step_4": "Ingresa el ID del equipo y toca enviar."
|
||||
"agency_center.invite_step_4": "Ingresa el ID del equipo y toca enviar.",
|
||||
"coinseller_center.title": "Centro de vendedor de monedas",
|
||||
"coinseller_center.back": "Volver",
|
||||
"coinseller_center.change_language": "Cambiar idioma",
|
||||
"coinseller_center.role": "Vendedor de monedas",
|
||||
"coinseller_center.coins": "Monedas",
|
||||
"coinseller_center.coins_lower": "monedas",
|
||||
"coinseller_center.available_stock": "Stock disponible",
|
||||
"coinseller_center.history": "Historial",
|
||||
"coinseller_center.help": "Ayuda",
|
||||
"coinseller_center.recharge_user": "Recargar usuario",
|
||||
"coinseller_center.search_by_user_id": "Buscar por ID de usuario",
|
||||
"coinseller_center.enter_user_id": "Ingresa el ID de usuario",
|
||||
"coinseller_center.search": "Buscar",
|
||||
"coinseller_center.target_user": "Usuario objetivo",
|
||||
"coinseller_center.change": "Cambiar",
|
||||
"coinseller_center.recharge_coins": "Recargar monedas",
|
||||
"coinseller_center.enter_coin_amount": "Ingresa la cantidad de monedas",
|
||||
"coinseller_center.coin_amount_placeholder": "Ingresa la cantidad de monedas",
|
||||
"coinseller_center.recharge_now": "Recargar ahora",
|
||||
"coinseller_center.recent_records": "Registros recientes",
|
||||
"coinseller_center.today_activity": "Actividad de hoy",
|
||||
"coinseller_center.view_all": "Ver todo",
|
||||
"coinseller_center.close": "Cerrar",
|
||||
"coinseller_center.transaction_records": "Registros de transacciones",
|
||||
"coinseller_center.cancel": "Cancelar",
|
||||
"coinseller_center.income": "Ingreso",
|
||||
"coinseller_center.expenditure": "Gasto",
|
||||
"coinseller_center.load_more": "Cargar más",
|
||||
"coinseller_center.faq_title": "FAQ",
|
||||
"coinseller_center.faq_question_1": "¿Cómo recargar?",
|
||||
"coinseller_center.faq_answer_1": "Busca un usuario, ingresa la cantidad de monedas y confirma la recarga.",
|
||||
"coinseller_center.faq_question_2": "¿Cómo revisar los registros?",
|
||||
"coinseller_center.faq_answer_2": "Abre el historial y cambia entre ingresos y gastos.",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "Región: {region}",
|
||||
"coinseller_center.user_name_template": "Usuario {id}",
|
||||
"coinseller_center.stock_transfer": "Transferencia de stock",
|
||||
"coinseller_center.transfer_out": "Transferencia saliente",
|
||||
"coinseller_center.system": "Sistema",
|
||||
"coinseller_center.no_transaction_records": "No hay registros de transacciones",
|
||||
"coinseller_center.select_user_first": "Selecciona un usuario primero.",
|
||||
"coinseller_center.valid_amount_required": "Ingresa una cantidad válida.",
|
||||
"coinseller_center.amount_exceeds_stock": "La cantidad supera el stock.",
|
||||
"coinseller_center.recharge_success": "Recarga exitosa.",
|
||||
"coinseller_center.user_not_found": "Usuario no encontrado.",
|
||||
"coinseller_center.user_selected": "Usuario seleccionado.",
|
||||
"coinseller_center.loading": "Cargando...",
|
||||
"coinseller_center.load_failed": "Error al cargar. Inténtalo de nuevo más tarde.",
|
||||
"coinseller_center.transfer_failed": "Transferencia fallida."
|
||||
}
|
||||
|
||||
@ -101,6 +101,9 @@
|
||||
"withdraw_exchange.no_salary_history": "Belum ada riwayat gaji",
|
||||
"withdraw_exchange.balance": "Saldo",
|
||||
"withdraw_exchange.history_host_salary": "Gaji host",
|
||||
"withdraw_exchange.history_agency_salary": "Gaji agency",
|
||||
"withdraw_exchange.history_bd_salary": "Gaji BD",
|
||||
"withdraw_exchange.history_admin_salary": "Gaji admin",
|
||||
"withdraw_exchange.history_exchange_to_golds": "Tukar ke koin",
|
||||
"withdraw_exchange.history_gift_reward": "Reward hadiah",
|
||||
"withdraw_exchange.mock_user_name": "Pengguna {account}",
|
||||
@ -146,8 +149,8 @@
|
||||
"bd_center.change_language": "Ganti bahasa",
|
||||
"bd_center.role": "BD",
|
||||
"bd_center.salary": "Gaji",
|
||||
"bd_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_center.invite_agent": "Invite Agent",
|
||||
"bd_center.withdraw_exchange": "Tarik/Tukar",
|
||||
"bd_center.invite_agent": "Undang Agent",
|
||||
"bd_center.agency_list": "Daftar agency",
|
||||
"bd_center.agency_statistics": "Statistik agency",
|
||||
"bd_center.month": "Bulan",
|
||||
@ -169,6 +172,38 @@
|
||||
"bd_center.close": "Tutup",
|
||||
"bd_center.mock_navigation": "Navigasi mock: {label}",
|
||||
"bd_center.mock_bill_loaded": "Tagihan mock dimuat.",
|
||||
"bd_center.load_failed": "Gagal memuat. Coba lagi nanti.",
|
||||
"bd_center.api_not_ready": "Modul API belum siap.",
|
||||
"bd_center.searching": "Mencari...",
|
||||
"bd_center.search_failed": "Pencarian gagal. Coba lagi nanti.",
|
||||
"bd_center.invite_failed": "Undangan gagal. Coba lagi nanti.",
|
||||
"bd_center.agency_added": "Agency ditambahkan.",
|
||||
"bd_center.tools": "Alat BD",
|
||||
"bd_leader_center.back": "Kembali",
|
||||
"bd_leader_center.title": "Pusat BD Leader",
|
||||
"bd_leader_center.change_language": "Ganti bahasa",
|
||||
"bd_leader_center.role": "BD Leader",
|
||||
"bd_leader_center.salary": "Gaji",
|
||||
"bd_leader_center.withdraw_exchange": "Tarik/Tukar",
|
||||
"bd_leader_center.salary_history": "Riwayat gaji",
|
||||
"bd_leader_center.invite_bd": "Undang BD",
|
||||
"bd_leader_center.bd_list": "Daftar BD",
|
||||
"bd_leader_center.close": "Tutup",
|
||||
"bd_leader_center.enter_user_id": "Masukkan ID Pengguna",
|
||||
"bd_leader_center.search": "Cari",
|
||||
"bd_leader_center.no_users_found": "Pengguna tidak ditemukan",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "Jumlah BD",
|
||||
"bd_leader_center.agencies": "Agency",
|
||||
"bd_leader_center.agency_number": "Jumlah agency",
|
||||
"bd_leader_center.team_salary": "Gaji tim",
|
||||
"bd_leader_center.team_recharge": "Recharge tim",
|
||||
"bd_leader_center.total_income": "Total pendapatan",
|
||||
"bd_leader_center.previous_income": "Pendapatan sebelumnya",
|
||||
"bd_leader_center.in_progress": "Sedang berjalan",
|
||||
"bd_leader_center.invite": "Undang",
|
||||
"bd_leader_center.invite_success": "Undangan terkirim.",
|
||||
"bd_leader_center.tools": "Alat BD Leader",
|
||||
"agency_center.title": "Pusat Agency",
|
||||
"agency_center.back": "Kembali",
|
||||
"agency_center.change_language": "Ganti bahasa",
|
||||
@ -212,5 +247,54 @@
|
||||
"agency_center.invite_step_1": "Undang pengguna untuk mengunduh APP.",
|
||||
"agency_center.invite_step_2": "Pengguna yang diundang harus login ke APP.",
|
||||
"agency_center.invite_step_3": "Me > Host Center > Ajukan bergabung ke tim.",
|
||||
"agency_center.invite_step_4": "Masukkan ID tim lalu ketuk kirim."
|
||||
"agency_center.invite_step_4": "Masukkan ID tim lalu ketuk kirim.",
|
||||
"coinseller_center.title": "Pusat Penjual Koin",
|
||||
"coinseller_center.back": "Kembali",
|
||||
"coinseller_center.change_language": "Ganti bahasa",
|
||||
"coinseller_center.role": "Penjual Koin",
|
||||
"coinseller_center.coins": "Koin",
|
||||
"coinseller_center.coins_lower": "koin",
|
||||
"coinseller_center.available_stock": "Stok tersedia",
|
||||
"coinseller_center.history": "Riwayat",
|
||||
"coinseller_center.help": "Bantuan",
|
||||
"coinseller_center.recharge_user": "Isi ulang pengguna",
|
||||
"coinseller_center.search_by_user_id": "Cari dengan ID pengguna",
|
||||
"coinseller_center.enter_user_id": "Masukkan ID pengguna",
|
||||
"coinseller_center.search": "Cari",
|
||||
"coinseller_center.target_user": "Pengguna tujuan",
|
||||
"coinseller_center.change": "Ganti",
|
||||
"coinseller_center.recharge_coins": "Isi ulang koin",
|
||||
"coinseller_center.enter_coin_amount": "Masukkan jumlah koin",
|
||||
"coinseller_center.coin_amount_placeholder": "Masukkan jumlah koin",
|
||||
"coinseller_center.recharge_now": "Isi ulang sekarang",
|
||||
"coinseller_center.recent_records": "Riwayat terbaru",
|
||||
"coinseller_center.today_activity": "Aktivitas hari ini",
|
||||
"coinseller_center.view_all": "Lihat semua",
|
||||
"coinseller_center.close": "Tutup",
|
||||
"coinseller_center.transaction_records": "Riwayat transaksi",
|
||||
"coinseller_center.cancel": "Batal",
|
||||
"coinseller_center.income": "Pemasukan",
|
||||
"coinseller_center.expenditure": "Pengeluaran",
|
||||
"coinseller_center.load_more": "Muat lagi",
|
||||
"coinseller_center.faq_title": "FAQ",
|
||||
"coinseller_center.faq_question_1": "Bagaimana cara isi ulang?",
|
||||
"coinseller_center.faq_answer_1": "Cari pengguna, masukkan jumlah koin, lalu konfirmasi isi ulang.",
|
||||
"coinseller_center.faq_question_2": "Bagaimana melihat riwayat?",
|
||||
"coinseller_center.faq_answer_2": "Buka riwayat dan ganti antara pemasukan dan pengeluaran.",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "Wilayah: {region}",
|
||||
"coinseller_center.user_name_template": "Pengguna {id}",
|
||||
"coinseller_center.stock_transfer": "Transfer stok",
|
||||
"coinseller_center.transfer_out": "Transfer keluar",
|
||||
"coinseller_center.system": "Sistem",
|
||||
"coinseller_center.no_transaction_records": "Tidak ada riwayat transaksi",
|
||||
"coinseller_center.select_user_first": "Pilih pengguna terlebih dahulu.",
|
||||
"coinseller_center.valid_amount_required": "Masukkan jumlah yang valid.",
|
||||
"coinseller_center.amount_exceeds_stock": "Jumlah melebihi stok.",
|
||||
"coinseller_center.recharge_success": "Isi ulang berhasil.",
|
||||
"coinseller_center.user_not_found": "Pengguna tidak ditemukan.",
|
||||
"coinseller_center.user_selected": "Pengguna dipilih.",
|
||||
"coinseller_center.loading": "Memuat...",
|
||||
"coinseller_center.load_failed": "Gagal memuat. Coba lagi nanti.",
|
||||
"coinseller_center.transfer_failed": "Transfer gagal."
|
||||
}
|
||||
|
||||
@ -101,6 +101,9 @@
|
||||
"withdraw_exchange.no_salary_history": "Maaş geçmişi yok",
|
||||
"withdraw_exchange.balance": "Bakiye",
|
||||
"withdraw_exchange.history_host_salary": "Host maaşı",
|
||||
"withdraw_exchange.history_agency_salary": "Ajans maaşı",
|
||||
"withdraw_exchange.history_bd_salary": "BD maaşı",
|
||||
"withdraw_exchange.history_admin_salary": "Admin maaşı",
|
||||
"withdraw_exchange.history_exchange_to_golds": "Altına değişim",
|
||||
"withdraw_exchange.history_gift_reward": "Hediye ödülü",
|
||||
"withdraw_exchange.mock_user_name": "Kullanıcı {account}",
|
||||
@ -146,7 +149,7 @@
|
||||
"bd_center.change_language": "Dili değiştir",
|
||||
"bd_center.role": "BD",
|
||||
"bd_center.salary": "Maaş",
|
||||
"bd_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_center.withdraw_exchange": "Çek/Değiştir",
|
||||
"bd_center.invite_agent": "Ajans Davet Et",
|
||||
"bd_center.agency_list": "Ajans listesi",
|
||||
"bd_center.agency_statistics": "Ajans istatistikleri",
|
||||
@ -169,6 +172,38 @@
|
||||
"bd_center.close": "Kapat",
|
||||
"bd_center.mock_navigation": "Mock yönlendirme: {label}",
|
||||
"bd_center.mock_bill_loaded": "Mock fatura yüklendi.",
|
||||
"bd_center.load_failed": "Yüklenemedi. Daha sonra tekrar deneyin.",
|
||||
"bd_center.api_not_ready": "API modülü hazır değil.",
|
||||
"bd_center.searching": "Aranıyor...",
|
||||
"bd_center.search_failed": "Arama başarısız. Daha sonra tekrar deneyin.",
|
||||
"bd_center.invite_failed": "Davet başarısız. Daha sonra tekrar deneyin.",
|
||||
"bd_center.agency_added": "Ajans eklendi.",
|
||||
"bd_center.tools": "BD araçları",
|
||||
"bd_leader_center.back": "Geri",
|
||||
"bd_leader_center.title": "BD Lider Merkezi",
|
||||
"bd_leader_center.change_language": "Dili değiştir",
|
||||
"bd_leader_center.role": "BD Lider",
|
||||
"bd_leader_center.salary": "Maaş",
|
||||
"bd_leader_center.withdraw_exchange": "Çek/Değiştir",
|
||||
"bd_leader_center.salary_history": "Maaş geçmişi",
|
||||
"bd_leader_center.invite_bd": "BD davet et",
|
||||
"bd_leader_center.bd_list": "BD listesi",
|
||||
"bd_leader_center.close": "Kapat",
|
||||
"bd_leader_center.enter_user_id": "Kullanıcı ID gir",
|
||||
"bd_leader_center.search": "Ara",
|
||||
"bd_leader_center.no_users_found": "Kullanıcı bulunamadı",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "BD sayısı",
|
||||
"bd_leader_center.agencies": "Ajanslar",
|
||||
"bd_leader_center.agency_number": "Ajans sayısı",
|
||||
"bd_leader_center.team_salary": "Takım maaşı",
|
||||
"bd_leader_center.team_recharge": "Takım yüklemesi",
|
||||
"bd_leader_center.total_income": "Toplam gelir",
|
||||
"bd_leader_center.previous_income": "Önceki gelir",
|
||||
"bd_leader_center.in_progress": "Devam ediyor",
|
||||
"bd_leader_center.invite": "Davet et",
|
||||
"bd_leader_center.invite_success": "Davet gönderildi.",
|
||||
"bd_leader_center.tools": "BD Lider araçları",
|
||||
"agency_center.title": "Ajans Merkezi",
|
||||
"agency_center.back": "Geri",
|
||||
"agency_center.change_language": "Dili değiştir",
|
||||
@ -212,5 +247,54 @@
|
||||
"agency_center.invite_step_1": "Kullanıcıları APP indirmeye davet et.",
|
||||
"agency_center.invite_step_2": "Davet edilen kullanıcıların APP'e giriş yapması gerekir.",
|
||||
"agency_center.invite_step_3": "Ben > Host Center > Ekibe katılmak için başvur.",
|
||||
"agency_center.invite_step_4": "Takım ID'sini girin ve göndere dokunun."
|
||||
"agency_center.invite_step_4": "Takım ID'sini girin ve göndere dokunun.",
|
||||
"coinseller_center.title": "Coin Seller Merkezi",
|
||||
"coinseller_center.back": "Geri",
|
||||
"coinseller_center.change_language": "Dili değiştir",
|
||||
"coinseller_center.role": "Coin Seller",
|
||||
"coinseller_center.coins": "Coinler",
|
||||
"coinseller_center.coins_lower": "coin",
|
||||
"coinseller_center.available_stock": "Mevcut stok",
|
||||
"coinseller_center.history": "Geçmiş",
|
||||
"coinseller_center.help": "Yardım",
|
||||
"coinseller_center.recharge_user": "Kullanıcıya yükle",
|
||||
"coinseller_center.search_by_user_id": "Kullanıcı ID ile ara",
|
||||
"coinseller_center.enter_user_id": "Kullanıcı ID girin",
|
||||
"coinseller_center.search": "Ara",
|
||||
"coinseller_center.target_user": "Hedef kullanıcı",
|
||||
"coinseller_center.change": "Değiştir",
|
||||
"coinseller_center.recharge_coins": "Coin yükle",
|
||||
"coinseller_center.enter_coin_amount": "Coin miktarını girin",
|
||||
"coinseller_center.coin_amount_placeholder": "Coin miktarını girin",
|
||||
"coinseller_center.recharge_now": "Şimdi yükle",
|
||||
"coinseller_center.recent_records": "Son kayıtlar",
|
||||
"coinseller_center.today_activity": "Bugünkü etkinlik",
|
||||
"coinseller_center.view_all": "Tümünü gör",
|
||||
"coinseller_center.close": "Kapat",
|
||||
"coinseller_center.transaction_records": "İşlem kayıtları",
|
||||
"coinseller_center.cancel": "İptal",
|
||||
"coinseller_center.income": "Gelir",
|
||||
"coinseller_center.expenditure": "Gider",
|
||||
"coinseller_center.load_more": "Daha fazla yükle",
|
||||
"coinseller_center.faq_title": "SSS",
|
||||
"coinseller_center.faq_question_1": "Nasıl yükleme yapılır?",
|
||||
"coinseller_center.faq_answer_1": "Kullanıcıyı arayın, coin miktarını girin ve yüklemeyi onaylayın.",
|
||||
"coinseller_center.faq_question_2": "Kayıtlar nasıl kontrol edilir?",
|
||||
"coinseller_center.faq_answer_2": "Geçmişi açın ve gelir ile gider arasında geçiş yapın.",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "Bölge: {region}",
|
||||
"coinseller_center.user_name_template": "Kullanıcı {id}",
|
||||
"coinseller_center.stock_transfer": "Stok transferi",
|
||||
"coinseller_center.transfer_out": "Dışa transfer",
|
||||
"coinseller_center.system": "Sistem",
|
||||
"coinseller_center.no_transaction_records": "İşlem kaydı yok",
|
||||
"coinseller_center.select_user_first": "Önce bir kullanıcı seçin.",
|
||||
"coinseller_center.valid_amount_required": "Geçerli bir miktar girin.",
|
||||
"coinseller_center.amount_exceeds_stock": "Miktar stoktan fazla.",
|
||||
"coinseller_center.recharge_success": "Yükleme başarılı.",
|
||||
"coinseller_center.user_not_found": "Kullanıcı bulunamadı.",
|
||||
"coinseller_center.user_selected": "Kullanıcı seçildi.",
|
||||
"coinseller_center.loading": "Yükleniyor...",
|
||||
"coinseller_center.load_failed": "Yükleme başarısız. Daha sonra tekrar deneyin.",
|
||||
"coinseller_center.transfer_failed": "Transfer başarısız."
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
"withdraw_exchange.exchange_amount": "兑换金额",
|
||||
"withdraw_exchange.transfer_to": "转账给",
|
||||
"withdraw_exchange.transfer_amount": "转账金额",
|
||||
"withdraw_exchange.estimated_coins": "预计金币",
|
||||
"withdraw_exchange.search": "搜索",
|
||||
"withdraw_exchange.searching": "搜索中...",
|
||||
"withdraw_exchange.minimum": "最低 50 USD",
|
||||
@ -101,6 +102,9 @@
|
||||
"withdraw_exchange.no_salary_history": "暂无薪资历史",
|
||||
"withdraw_exchange.balance": "余额",
|
||||
"withdraw_exchange.history_host_salary": "主播薪资",
|
||||
"withdraw_exchange.history_agency_salary": "Agency 薪资",
|
||||
"withdraw_exchange.history_bd_salary": "BD 薪资",
|
||||
"withdraw_exchange.history_admin_salary": "Admin 薪资",
|
||||
"withdraw_exchange.history_exchange_to_golds": "兑换金币",
|
||||
"withdraw_exchange.history_gift_reward": "礼物奖励",
|
||||
"withdraw_exchange.mock_user_name": "用户 {account}",
|
||||
@ -115,6 +119,11 @@
|
||||
"withdraw_exchange.withdraw_success": "提现申请已提交",
|
||||
"withdraw_exchange.exchange_success": "兑换成功",
|
||||
"withdraw_exchange.transfer_success": "转账成功",
|
||||
"withdraw_exchange.rate_not_configured": "未配置兑换比例。",
|
||||
"withdraw_exchange.withdraw_not_available": "提现暂未开放。",
|
||||
"withdraw_exchange.submit_failed": "提交失败。",
|
||||
"withdraw_exchange.load_failed": "加载失败,请稍后重试。",
|
||||
"withdraw_exchange.search_failed": "搜索失败,请稍后重试。",
|
||||
"superadmin_center.back": "返回",
|
||||
"superadmin_center.title": "超管中心",
|
||||
"superadmin_center.change_language": "切换语言",
|
||||
@ -142,13 +151,13 @@
|
||||
"superadmin_center.invite": "邀请",
|
||||
"superadmin_center.invite_success": "邀请已提交。",
|
||||
"bd_center.back": "返回",
|
||||
"bd_center.title": "BD Center",
|
||||
"bd_center.title": "BD 中心",
|
||||
"bd_center.change_language": "切换语言",
|
||||
"bd_center.role": "BD",
|
||||
"bd_center.salary": "薪资",
|
||||
"bd_center.withdraw_exchange": "Withdraw/Exchange",
|
||||
"bd_center.withdraw_exchange": "提现/兑换",
|
||||
"bd_center.invite_agent": "邀请代理",
|
||||
"bd_center.agency_list": "Agency List",
|
||||
"bd_center.agency_list": "Agency 列表",
|
||||
"bd_center.agency_statistics": "代理统计",
|
||||
"bd_center.month": "月份",
|
||||
"bd_center.agency_number": "代理数量",
|
||||
@ -169,6 +178,38 @@
|
||||
"bd_center.close": "关闭",
|
||||
"bd_center.mock_navigation": "Mock 跳转:{label}",
|
||||
"bd_center.mock_bill_loaded": "Mock 账单已加载。",
|
||||
"bd_center.load_failed": "加载失败,请稍后重试。",
|
||||
"bd_center.api_not_ready": "API 模块未就绪。",
|
||||
"bd_center.searching": "搜索中...",
|
||||
"bd_center.search_failed": "搜索失败,请稍后重试。",
|
||||
"bd_center.invite_failed": "邀请失败,请稍后重试。",
|
||||
"bd_center.agency_added": "Agency 已添加。",
|
||||
"bd_center.tools": "BD 工具",
|
||||
"bd_leader_center.back": "返回",
|
||||
"bd_leader_center.title": "BD Leader 中心",
|
||||
"bd_leader_center.change_language": "切换语言",
|
||||
"bd_leader_center.role": "BD Leader",
|
||||
"bd_leader_center.salary": "薪资",
|
||||
"bd_leader_center.withdraw_exchange": "提现/兑换",
|
||||
"bd_leader_center.salary_history": "薪资记录",
|
||||
"bd_leader_center.invite_bd": "邀请 BD",
|
||||
"bd_leader_center.bd_list": "BD 列表",
|
||||
"bd_leader_center.close": "关闭",
|
||||
"bd_leader_center.enter_user_id": "输入用户 ID",
|
||||
"bd_leader_center.search": "搜索",
|
||||
"bd_leader_center.no_users_found": "未找到用户",
|
||||
"bd_leader_center.uid_prefix": "UID: {uid}",
|
||||
"bd_leader_center.bd_number": "BD 数量",
|
||||
"bd_leader_center.agencies": "Agency",
|
||||
"bd_leader_center.agency_number": "Agency 数量",
|
||||
"bd_leader_center.team_salary": "团队薪资",
|
||||
"bd_leader_center.team_recharge": "团队充值",
|
||||
"bd_leader_center.total_income": "总收入",
|
||||
"bd_leader_center.previous_income": "上期收入",
|
||||
"bd_leader_center.in_progress": "进行中",
|
||||
"bd_leader_center.invite": "邀请",
|
||||
"bd_leader_center.invite_success": "邀请已提交。",
|
||||
"bd_leader_center.tools": "BD Leader 工具",
|
||||
"agency_center.title": "Agency Center",
|
||||
"agency_center.back": "返回",
|
||||
"agency_center.change_language": "切换语言",
|
||||
@ -212,5 +253,54 @@
|
||||
"agency_center.invite_step_1": "Invite users to download APP.",
|
||||
"agency_center.invite_step_2": "Invited users need to log in to the APP.",
|
||||
"agency_center.invite_step_3": "Me > Host Center > Apply to join the team.",
|
||||
"agency_center.invite_step_4": "Enter the team ID, click send to join."
|
||||
"agency_center.invite_step_4": "Enter the team ID, click send to join.",
|
||||
"coinseller_center.title": "币商中心",
|
||||
"coinseller_center.back": "返回",
|
||||
"coinseller_center.change_language": "切换语言",
|
||||
"coinseller_center.role": "币商",
|
||||
"coinseller_center.coins": "金币",
|
||||
"coinseller_center.coins_lower": "金币",
|
||||
"coinseller_center.available_stock": "可用库存",
|
||||
"coinseller_center.history": "记录",
|
||||
"coinseller_center.help": "帮助",
|
||||
"coinseller_center.recharge_user": "充值用户",
|
||||
"coinseller_center.search_by_user_id": "按用户 ID 搜索",
|
||||
"coinseller_center.enter_user_id": "输入用户 ID",
|
||||
"coinseller_center.search": "搜索",
|
||||
"coinseller_center.target_user": "目标用户",
|
||||
"coinseller_center.change": "更换",
|
||||
"coinseller_center.recharge_coins": "充值金币",
|
||||
"coinseller_center.enter_coin_amount": "输入金币数量",
|
||||
"coinseller_center.coin_amount_placeholder": "输入金币数量",
|
||||
"coinseller_center.recharge_now": "立即充值",
|
||||
"coinseller_center.recent_records": "最近记录",
|
||||
"coinseller_center.today_activity": "今日动态",
|
||||
"coinseller_center.view_all": "查看全部",
|
||||
"coinseller_center.close": "关闭",
|
||||
"coinseller_center.transaction_records": "交易记录",
|
||||
"coinseller_center.cancel": "取消",
|
||||
"coinseller_center.income": "收入",
|
||||
"coinseller_center.expenditure": "支出",
|
||||
"coinseller_center.load_more": "加载更多",
|
||||
"coinseller_center.faq_title": "常见问题",
|
||||
"coinseller_center.faq_question_1": "如何充值?",
|
||||
"coinseller_center.faq_answer_1": "搜索用户,输入金币数量,然后确认充值。",
|
||||
"coinseller_center.faq_question_2": "如何查看记录?",
|
||||
"coinseller_center.faq_answer_2": "打开记录,并在收入和支出之间切换。",
|
||||
"coinseller_center.uid_prefix": "UID: {id}",
|
||||
"coinseller_center.stock_region": "地区:{region}",
|
||||
"coinseller_center.user_name_template": "用户 {id}",
|
||||
"coinseller_center.stock_transfer": "库存入账",
|
||||
"coinseller_center.transfer_out": "转出",
|
||||
"coinseller_center.system": "系统",
|
||||
"coinseller_center.no_transaction_records": "暂无交易记录",
|
||||
"coinseller_center.select_user_first": "请先选择用户。",
|
||||
"coinseller_center.valid_amount_required": "请输入有效金额。",
|
||||
"coinseller_center.amount_exceeds_stock": "金额超过库存。",
|
||||
"coinseller_center.recharge_success": "充值成功。",
|
||||
"coinseller_center.user_not_found": "未找到用户。",
|
||||
"coinseller_center.user_selected": "已选择用户。",
|
||||
"coinseller_center.loading": "加载中...",
|
||||
"coinseller_center.load_failed": "加载失败,请稍后重试。",
|
||||
"coinseller_center.transfer_failed": "转账失败。"
|
||||
}
|
||||
|
||||
@ -46,6 +46,8 @@
|
||||
<button type="button" data-lang-option="ar">AR</button>
|
||||
<button type="button" data-lang-option="tr">TR</button>
|
||||
<button type="button" data-lang-option="es">ES</button>
|
||||
<button type="button" data-lang-option="zh">ZH</button>
|
||||
<button type="button" data-lang-option="id">ID</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@ -90,7 +92,11 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card menu-card" aria-label="BD tools">
|
||||
<section
|
||||
class="card menu-card"
|
||||
aria-label="BD tools"
|
||||
data-i18n-aria="bd_center.tools"
|
||||
>
|
||||
<button
|
||||
class="menu-row"
|
||||
id="inviteAgentButton"
|
||||
@ -285,6 +291,7 @@
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="../../common/jsbridge.js"></script>
|
||||
<script src="../../common/i18n.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
<script src="../../common/api.js?v=20260604-bd-center"></script>
|
||||
<script src="./script.js?v=20260604-bd-center-api"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
(function () {
|
||||
var FIRST_BILL_MONTH = '2026-06';
|
||||
var BD_SALARY_ASSET = 'BD_SALARY_USD';
|
||||
var query = new URLSearchParams(window.location.search);
|
||||
var mock = {
|
||||
profile: {
|
||||
name: 'BD_Jasmine',
|
||||
@ -42,36 +44,17 @@
|
||||
},
|
||||
],
|
||||
},
|
||||
inviteRecords: [
|
||||
{
|
||||
id: 'inv-001',
|
||||
status: 'pending',
|
||||
profile: {
|
||||
id: '3187001',
|
||||
name: 'Agent_Lina',
|
||||
account: '168801',
|
||||
avatar: avatarData('L', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'inv-002',
|
||||
status: 'success',
|
||||
profile: {
|
||||
id: '3187002',
|
||||
name: 'Agent_Omar',
|
||||
account: '168802',
|
||||
avatar: avatarData('O', '#f4ebff', '#7d57c7'),
|
||||
},
|
||||
},
|
||||
],
|
||||
inviteRecords: [],
|
||||
searchPool: [
|
||||
{
|
||||
userId: '3187099',
|
||||
id: '3187099',
|
||||
name: 'Agent_River',
|
||||
account: '168899',
|
||||
avatar: avatarData('R', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
{
|
||||
userId: '3187100',
|
||||
id: '3187100',
|
||||
name: 'Agent_Sara',
|
||||
account: '168900',
|
||||
@ -80,6 +63,14 @@
|
||||
],
|
||||
};
|
||||
|
||||
var data = {
|
||||
profile: mock.profile,
|
||||
balance: mock.balance,
|
||||
billMonth: mock.billMonth,
|
||||
agencyBill: mock.agencyBill,
|
||||
inviteRecords: mock.inviteRecords,
|
||||
};
|
||||
|
||||
var state = {
|
||||
billMonth: normalizeBillMonth(mock.billMonth),
|
||||
inviteQuery: '',
|
||||
@ -87,12 +78,22 @@
|
||||
inviteStatus: '',
|
||||
inviteStatusType: '',
|
||||
searched: [],
|
||||
inviting: {},
|
||||
isMock: query.get('mock') === '1',
|
||||
};
|
||||
|
||||
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)
|
||||
@ -100,7 +101,11 @@
|
||||
}
|
||||
|
||||
function avatarData(text, background, foreground) {
|
||||
var letter = encodeURIComponent(String(text || 'B').charAt(0));
|
||||
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="' +
|
||||
@ -195,6 +200,47 @@
|
||||
.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, ['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);
|
||||
@ -232,12 +278,87 @@
|
||||
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) || {};
|
||||
var name =
|
||||
firstValue(agency, ['name']) ||
|
||||
displayName(owner, 'Agency ' + displayID(owner, displayID(agency)));
|
||||
var account =
|
||||
firstValue(agency, ['agency_id', 'agencyId']) ||
|
||||
displayID(owner, displayID(agency));
|
||||
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');
|
||||
$('profileName').textContent = mock.profile.name;
|
||||
$('profileUID').textContent = 'UID: ' + mock.profile.uid;
|
||||
fallback.textContent = initial(mock.profile.name) || 'B';
|
||||
var profile = data.profile || mock.profile;
|
||||
$('profileName').textContent = profile.name || '-';
|
||||
$('profileUID').textContent = 'UID: ' + (profile.uid || '-');
|
||||
fallback.textContent = initial(profile.name) || 'B';
|
||||
image.onload = function () {
|
||||
image.hidden = false;
|
||||
fallback.hidden = true;
|
||||
@ -246,11 +367,15 @@
|
||||
image.hidden = true;
|
||||
fallback.hidden = false;
|
||||
};
|
||||
image.src = mock.profile.avatar;
|
||||
image.src = profile.avatar || '';
|
||||
if (!profile.avatar) {
|
||||
image.hidden = true;
|
||||
fallback.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
function renderBalance() {
|
||||
$('availableBalance').textContent = money(mock.balance.available);
|
||||
$('availableBalance').textContent = money(data.balance && data.balance.available);
|
||||
}
|
||||
|
||||
function summaryCell(label, value) {
|
||||
@ -278,8 +403,8 @@
|
||||
meta.className = 'member-meta';
|
||||
side.className = 'member-side';
|
||||
renderImageAvatar(avatar, item.avatar, item.name);
|
||||
name.textContent = item.name;
|
||||
meta.textContent = 'UID: ' + item.account;
|
||||
name.textContent = item.name || '-';
|
||||
meta.textContent = 'UID: ' + (item.account || '-');
|
||||
[
|
||||
t('bd_center.team_salary', 'Team salary') +
|
||||
': $' +
|
||||
@ -302,7 +427,7 @@
|
||||
}
|
||||
|
||||
function renderTeamList() {
|
||||
var bill = mock.agencyBill;
|
||||
var bill = data.agencyBill || mock.agencyBill;
|
||||
$('billMonthText').textContent = monthLabel(state.billMonth);
|
||||
$('billRange').textContent = state.billMonth.replace('-', '.');
|
||||
|
||||
@ -317,7 +442,7 @@
|
||||
),
|
||||
]);
|
||||
|
||||
var rows = bill.memberBillList.map(memberRow);
|
||||
var rows = (bill.memberBillList || []).map(memberRow);
|
||||
if (!rows.length) {
|
||||
var empty = document.createElement('div');
|
||||
empty.className = 'empty-state';
|
||||
@ -377,7 +502,9 @@
|
||||
state.billMonth = nextMonth;
|
||||
closeMonthSheet();
|
||||
renderTeamList();
|
||||
toast(t('bd_center.mock_bill_loaded', 'Mock bill loaded.'));
|
||||
if (state.isMock) {
|
||||
toast(t('bd_center.mock_bill_loaded', 'Mock bill loaded.'));
|
||||
}
|
||||
}
|
||||
|
||||
function inviteProfile(item) {
|
||||
@ -385,13 +512,25 @@
|
||||
}
|
||||
|
||||
function statusLabel(status) {
|
||||
if (status === 'success') return t('bd_center.success', 'Success');
|
||||
if (status === 'pending') return t('bd_center.pending', 'Pending');
|
||||
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 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');
|
||||
@ -410,56 +549,29 @@
|
||||
profile.name,
|
||||
'invite-avatar-fallback'
|
||||
);
|
||||
name.textContent = profile.name;
|
||||
meta.textContent = 'UID: ' + profile.account;
|
||||
name.textContent = profile.name || '-';
|
||||
meta.textContent = 'UID: ' + (profile.account || '-');
|
||||
main.appendChild(name);
|
||||
main.appendChild(meta);
|
||||
|
||||
if (item.status === 'pending' || item.status === 'success') {
|
||||
if (status) {
|
||||
var badge = document.createElement('span');
|
||||
badge.className = 'invite-badge ' + item.status;
|
||||
badge.textContent = statusLabel(item.status);
|
||||
badge.className =
|
||||
'invite-badge ' +
|
||||
(status === 'pending' || status === 'Pending' ? 'pending' : 'success');
|
||||
badge.textContent = statusLabel(status);
|
||||
side.appendChild(badge);
|
||||
if (item.status === 'pending') {
|
||||
var cancel = document.createElement('button');
|
||||
cancel.className = 'invite-cancel';
|
||||
cancel.type = 'button';
|
||||
cancel.textContent = t('bd_center.cancel', 'Cancel');
|
||||
cancel.addEventListener('click', function () {
|
||||
mock.inviteRecords = mock.inviteRecords.filter(
|
||||
function (record) {
|
||||
return record.id !== item.id;
|
||||
}
|
||||
);
|
||||
toast(
|
||||
t(
|
||||
'bd_center.application_cancelled',
|
||||
'Application cancelled'
|
||||
)
|
||||
);
|
||||
renderInviteModal();
|
||||
});
|
||||
side.appendChild(cancel);
|
||||
}
|
||||
} else {
|
||||
var targetUserID = String(profile.userId || profile.id || '');
|
||||
var invite = document.createElement('button');
|
||||
invite.className = 'invite-action';
|
||||
invite.type = 'button';
|
||||
invite.textContent = t('bd_center.invite', 'Invite');
|
||||
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 () {
|
||||
mock.inviteRecords.unshift({
|
||||
id: 'inv-' + Date.now(),
|
||||
status: 'pending',
|
||||
profile: profile,
|
||||
});
|
||||
state.inviteQuery = '';
|
||||
state.inviteMode = 'records';
|
||||
state.searched = [];
|
||||
$('inviteSearchInput').value = '';
|
||||
toast(
|
||||
t('bd_center.invitation_submitted', 'Invitation submitted')
|
||||
);
|
||||
renderInviteModal();
|
||||
submitInvite(profile);
|
||||
});
|
||||
side.appendChild(invite);
|
||||
}
|
||||
@ -482,7 +594,7 @@
|
||||
var rows =
|
||||
state.inviteMode === 'search'
|
||||
? state.searched.map(inviteCard)
|
||||
: mock.inviteRecords.map(inviteCard);
|
||||
: data.inviteRecords.map(inviteCard);
|
||||
setInviteStatus(state.inviteStatus, state.inviteStatusType);
|
||||
replaceChildren($('inviteList'), rows);
|
||||
$('inviteEmpty').hidden =
|
||||
@ -495,6 +607,7 @@
|
||||
state.inviteMode = 'records';
|
||||
state.searched = [];
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
$('inviteSearchInput').value = '';
|
||||
$('inviteModal').hidden = false;
|
||||
$('inviteModal').setAttribute('aria-hidden', 'false');
|
||||
@ -511,43 +624,166 @@
|
||||
document.body.classList.remove('modal-open');
|
||||
}
|
||||
|
||||
function searchMockInvite(queryValue) {
|
||||
var queryLower = queryValue.toLowerCase();
|
||||
return mock.searchPool.filter(function (profile) {
|
||||
return (
|
||||
profile.name.toLowerCase().indexOf(queryLower) >= 0 ||
|
||||
profile.account.indexOf(queryLower) >= 0 ||
|
||||
profile.id.indexOf(queryLower) >= 0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function searchInvite(event) {
|
||||
event.preventDefault();
|
||||
var query = state.inviteQuery.trim().toLowerCase();
|
||||
var queryValue = state.inviteQuery.trim();
|
||||
state.inviteMode = 'search';
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
state.searched = mock.searchPool.filter(function (profile) {
|
||||
return (
|
||||
profile.name.toLowerCase().indexOf(query) >= 0 ||
|
||||
profile.account.indexOf(query) >= 0 ||
|
||||
profile.id.indexOf(query) >= 0
|
||||
);
|
||||
});
|
||||
if (!state.searched.length) {
|
||||
state.inviteStatus = t(
|
||||
'bd_center.no_users_found',
|
||||
'No users found'
|
||||
);
|
||||
state.searched = [];
|
||||
if (!queryValue) {
|
||||
renderInviteModal();
|
||||
return;
|
||||
}
|
||||
if (state.isMock) {
|
||||
state.searched = searchMockInvite(queryValue);
|
||||
if (!state.searched.length) {
|
||||
state.inviteStatus = t(
|
||||
'bd_center.no_users_found',
|
||||
'No users found'
|
||||
);
|
||||
}
|
||||
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...');
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
function submitInvite(profile) {
|
||||
var targetUserID = String(profile.userId || profile.id || '');
|
||||
if (!targetUserID) return;
|
||||
if (state.isMock) {
|
||||
data.inviteRecords.unshift({
|
||||
id: 'inv-' + Date.now(),
|
||||
status: 'success',
|
||||
profile: profile,
|
||||
});
|
||||
state.inviteMode = 'records';
|
||||
state.searched = [];
|
||||
state.inviteStatus = t('bd_center.agency_added', 'Agency added.');
|
||||
state.inviteStatusType = 'success';
|
||||
renderInviteModal();
|
||||
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.agency_added', 'Agency added.');
|
||||
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 loadRealData() {
|
||||
var service = centerAPI();
|
||||
if (state.isMock || !service) return Promise.resolve(false);
|
||||
return Promise.all([
|
||||
service.overview(),
|
||||
service.agencies(50),
|
||||
]).then(function (results) {
|
||||
applyOverview(results[0] || {});
|
||||
applyAgencies(results[1] || {});
|
||||
render();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
$('backButton').addEventListener('click', function () {
|
||||
if (window.HyAppBridge) window.HyAppBridge.back();
|
||||
});
|
||||
$('withdrawExchangeButton').addEventListener('click', function () {
|
||||
toast(
|
||||
t(
|
||||
'bd_center.mock_navigation',
|
||||
'Mock navigation: {label}'
|
||||
).replace(
|
||||
'{label}',
|
||||
t('bd_center.withdraw_exchange', 'Withdraw/Exchange')
|
||||
)
|
||||
);
|
||||
if (window.HyAppBridge) {
|
||||
window.HyAppBridge.back();
|
||||
return;
|
||||
}
|
||||
if (window.history.length > 1) window.history.back();
|
||||
});
|
||||
$('withdrawExchangeButton').addEventListener(
|
||||
'click',
|
||||
navigateToWithdrawExchange
|
||||
);
|
||||
$('inviteAgentButton').addEventListener('click', openInviteModal);
|
||||
$('inviteBackdrop').addEventListener('click', closeInviteModal);
|
||||
$('inviteCloseButton').addEventListener('click', closeInviteModal);
|
||||
@ -557,6 +793,7 @@
|
||||
state.inviteMode = 'records';
|
||||
state.searched = [];
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
}
|
||||
renderInviteModal();
|
||||
});
|
||||
@ -581,8 +818,17 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
render();
|
||||
bindEvents();
|
||||
loadRealData().catch(function (error) {
|
||||
toast(
|
||||
(error && error.message) ||
|
||||
t('bd_center.load_failed', 'Load failed. Try again later.')
|
||||
);
|
||||
});
|
||||
if (window.HyAppBridge) {
|
||||
window.HyAppBridge.ready({ page: 'bd-center', mock: true });
|
||||
window.HyAppBridge.ready({
|
||||
page: 'bd-center',
|
||||
mock: state.isMock,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
327
gonghui/bd-leader/index.html
Normal file
327
gonghui/bd-leader/index.html
Normal file
@ -0,0 +1,327 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<title>BD Leader Center</title>
|
||||
<link rel="stylesheet" href="../../common/theme.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="../common/center.css?v=20260604-bd-leader"
|
||||
/>
|
||||
<link rel="stylesheet" href="./style.css?v=20260604-bd-only" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="bd-leader-center" aria-label="BD Leader Center">
|
||||
<div class="hero-bg" aria-hidden="true"></div>
|
||||
|
||||
<nav class="title-bar">
|
||||
<button
|
||||
class="back-button"
|
||||
id="backButton"
|
||||
type="button"
|
||||
aria-label="Back"
|
||||
data-i18n-aria="bd_leader_center.back"
|
||||
>
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true">
|
||||
<path d="M20 8 12 16l8 8" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 data-i18n="bd_leader_center.title">BD Leader Center</h1>
|
||||
<div class="language-switcher">
|
||||
<button
|
||||
class="language-button"
|
||||
type="button"
|
||||
aria-label="Change language"
|
||||
aria-expanded="false"
|
||||
data-language-toggle
|
||||
data-current-lang
|
||||
data-i18n-aria="bd_leader_center.change_language"
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
<div class="language-menu" data-language-menu hidden>
|
||||
<button type="button" data-lang-option="en">EN</button>
|
||||
<button type="button" data-lang-option="ar">AR</button>
|
||||
<button type="button" data-lang-option="tr">TR</button>
|
||||
<button type="button" data-lang-option="es">ES</button>
|
||||
<button type="button" data-lang-option="zh">ZH</button>
|
||||
<button type="button" data-lang-option="id">ID</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
<section class="card profile-card">
|
||||
<div class="avatar-shell">
|
||||
<img class="avatar-image" id="profileAvatar" alt="" />
|
||||
<div
|
||||
class="avatar-fallback"
|
||||
id="profileAvatarFallback"
|
||||
aria-hidden="true"
|
||||
hidden
|
||||
>
|
||||
S
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-copy">
|
||||
<div
|
||||
class="role-pill"
|
||||
data-i18n="bd_leader_center.role"
|
||||
>
|
||||
BD Leader
|
||||
</div>
|
||||
<div class="name" id="profileName">-</div>
|
||||
<div class="meta" id="profileUID">UID: -</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card salary-card">
|
||||
<div class="salary-head">
|
||||
<h2 data-i18n="bd_leader_center.salary">Salary</h2>
|
||||
<button
|
||||
class="text-link"
|
||||
id="withdrawExchangeButton"
|
||||
type="button"
|
||||
data-i18n="bd_leader_center.withdraw_exchange"
|
||||
>
|
||||
Withdraw/Exchange
|
||||
</button>
|
||||
</div>
|
||||
<div class="salary-value">
|
||||
<span class="coin-icon" aria-hidden="true">$</span>
|
||||
<strong id="availableBalance">0.00</strong>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
class="card menu-card"
|
||||
aria-label="BD Leader tools"
|
||||
data-i18n-aria="bd_leader_center.tools"
|
||||
>
|
||||
<button
|
||||
class="menu-row"
|
||||
type="button"
|
||||
data-action="history"
|
||||
>
|
||||
<span class="menu-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M12 4a8 8 0 1 1-7.2 4.5" />
|
||||
<path d="M5 4v5h5" />
|
||||
<path d="M12 8v5l3 2" />
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="menu-label"
|
||||
data-i18n="bd_leader_center.salary_history"
|
||||
>Salary History</span
|
||||
>
|
||||
<span class="chevron" aria-hidden="true">›</span>
|
||||
</button>
|
||||
<button
|
||||
class="menu-row"
|
||||
type="button"
|
||||
data-action="invite-bd"
|
||||
>
|
||||
<span class="menu-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M10 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" />
|
||||
<path
|
||||
d="M3 21c.9-4.7 3.2-7 7-7 2 0 3.7.7 5 2"
|
||||
/>
|
||||
<path d="M19 9v8" />
|
||||
<path d="M15 13h8" />
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="menu-label"
|
||||
data-i18n="bd_leader_center.invite_bd"
|
||||
>Invite BD</span
|
||||
>
|
||||
<span class="chevron" aria-hidden="true">›</span>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="card team-card">
|
||||
<div class="team-head">
|
||||
<h2 data-i18n="bd_leader_center.bd_list">BD List</h2>
|
||||
</div>
|
||||
<div class="team-summary" id="teamSummary"></div>
|
||||
<div class="team-list" id="teamList"></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div class="home-indicator" aria-hidden="true"></div>
|
||||
|
||||
<div
|
||||
class="sheet-modal"
|
||||
id="historyModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="historyModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="bottom-sheet history-sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="historyTitle"
|
||||
>
|
||||
<div class="sheet-head">
|
||||
<h2
|
||||
id="historyTitle"
|
||||
data-i18n="bd_leader_center.salary_history"
|
||||
>
|
||||
Salary History
|
||||
</h2>
|
||||
<button
|
||||
class="sheet-close"
|
||||
type="button"
|
||||
data-close-modal="historyModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="history-summary" id="historySummary"></div>
|
||||
<div class="history-list" id="historyList"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="sheet-modal"
|
||||
id="detailsModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="detailsModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="bottom-sheet history-sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="detailsTitle"
|
||||
>
|
||||
<div class="sheet-head">
|
||||
<h2 id="detailsTitle">-</h2>
|
||||
<button
|
||||
class="sheet-close"
|
||||
type="button"
|
||||
data-close-modal="detailsModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="history-summary compact"
|
||||
id="detailsSummary"
|
||||
></div>
|
||||
<div class="history-list" id="detailsList"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="invite-modal"
|
||||
id="inviteModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="inviteModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="invite-dialog"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="inviteModalTitle"
|
||||
>
|
||||
<div class="invite-head">
|
||||
<h2
|
||||
id="inviteModalTitle"
|
||||
data-i18n="bd_leader_center.invite_bd"
|
||||
>
|
||||
Invite BD
|
||||
</h2>
|
||||
<button
|
||||
class="invite-close"
|
||||
type="button"
|
||||
data-close-modal="inviteModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="bd_leader_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="invite-body">
|
||||
<form class="invite-search-form" id="inviteSearchForm">
|
||||
<label class="invite-field">
|
||||
<span
|
||||
data-i18n="bd_leader_center.enter_user_id"
|
||||
>Enter User ID</span
|
||||
>
|
||||
<div class="invite-search-control">
|
||||
<input
|
||||
id="inviteSearchInput"
|
||||
type="text"
|
||||
inputmode="text"
|
||||
autocomplete="off"
|
||||
placeholder="Enter User ID"
|
||||
data-i18n-placeholder="bd_leader_center.enter_user_id"
|
||||
/>
|
||||
<button
|
||||
id="inviteSearchButton"
|
||||
type="submit"
|
||||
data-i18n="bd_leader_center.search"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
</form>
|
||||
<div
|
||||
class="invite-status"
|
||||
id="inviteStatus"
|
||||
role="status"
|
||||
hidden
|
||||
></div>
|
||||
<div class="invite-list" id="inviteList"></div>
|
||||
<div
|
||||
class="invite-empty"
|
||||
id="inviteEmpty"
|
||||
data-i18n="bd_leader_center.no_users_found"
|
||||
>
|
||||
No users found
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="../../common/jsbridge.js"></script>
|
||||
<script src="../../common/api.js?v=20260604-bd-leader-api"></script>
|
||||
<script src="../../common/i18n.js?v=20260604"></script>
|
||||
<script src="./script.js?v=20260604-bd-only"></script>
|
||||
</body>
|
||||
</html>
|
||||
876
gonghui/bd-leader/script.js
Normal file
876
gonghui/bd-leader/script.js
Normal file
@ -0,0 +1,876 @@
|
||||
(function () {
|
||||
var query = new URLSearchParams(window.location.search);
|
||||
var state = {
|
||||
inviteQuery: '',
|
||||
inviteStatus: '',
|
||||
inviteStatusType: '',
|
||||
inviteSearchResults: [],
|
||||
inviteSubmitting: {},
|
||||
selectedDetails: null,
|
||||
isMock: query.get('mock') === '1',
|
||||
};
|
||||
|
||||
var mock = {
|
||||
profile: {
|
||||
name: 'Leader Sophia',
|
||||
uid: 'BL-100001',
|
||||
avatar: avatarData('L', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
balance: {
|
||||
available: 168250.5,
|
||||
},
|
||||
overview: {
|
||||
totalBD: 8,
|
||||
totalAgency: 36,
|
||||
totalHosts: 428,
|
||||
teamSalary: 586420.8,
|
||||
teamRecharge: 1268800,
|
||||
},
|
||||
bdList: [
|
||||
{
|
||||
id: '880001',
|
||||
userId: '3200901',
|
||||
name: 'Mila BD',
|
||||
avatar: avatarData('M', '#dbc8ff', '#7d57c7'),
|
||||
agencies: 12,
|
||||
hosts: 126,
|
||||
salary: 128450.35,
|
||||
recharge: 356900,
|
||||
},
|
||||
{
|
||||
id: '880018',
|
||||
userId: '3200918',
|
||||
name: 'Jasmine BD',
|
||||
avatar: avatarData('J', '#f4ebff', '#7d57c7'),
|
||||
agencies: 9,
|
||||
hosts: 104,
|
||||
salary: 106280.4,
|
||||
recharge: 298520,
|
||||
},
|
||||
{
|
||||
id: '880026',
|
||||
userId: '3200926',
|
||||
name: 'Omar BD',
|
||||
avatar: avatarData('O', '#efe4ff', '#7d57c7'),
|
||||
agencies: 7,
|
||||
hosts: 82,
|
||||
salary: 86140,
|
||||
recharge: 214330,
|
||||
},
|
||||
],
|
||||
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: 'Success',
|
||||
profile: {
|
||||
userId: '3200901',
|
||||
id: '3200901',
|
||||
name: 'BD_River',
|
||||
account: '880099',
|
||||
avatar: avatarData('R', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
searchPool: {
|
||||
bd: [
|
||||
{
|
||||
userId: '3200902',
|
||||
id: '3200902',
|
||||
name: 'BD_Kai',
|
||||
account: '880102',
|
||||
avatar: avatarData('K', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
{
|
||||
userId: '3200903',
|
||||
id: '3200903',
|
||||
name: 'BD_Ayla',
|
||||
account: '880103',
|
||||
avatar: avatarData('A', '#efe4ff', '#7d57c7'),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
var data = {
|
||||
profile: mock.profile,
|
||||
balance: mock.balance,
|
||||
overview: mock.overview,
|
||||
bdList: mock.bdList,
|
||||
history: mock.history,
|
||||
inviteRecords: mock.inviteRecords,
|
||||
};
|
||||
|
||||
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 displayName(user, fallback) {
|
||||
return (
|
||||
(user && (user.username || user.name || user.display_user_id)) ||
|
||||
fallback ||
|
||||
'-'
|
||||
);
|
||||
}
|
||||
|
||||
function displayID(user) {
|
||||
return (
|
||||
(user && (user.display_user_id || user.displayUserID)) ||
|
||||
(user && (user.user_id || user.userId)) ||
|
||||
'-'
|
||||
);
|
||||
}
|
||||
|
||||
function displayAmount(salary) {
|
||||
if (!salary) return 0;
|
||||
if (salary.display_amount !== undefined) return salary.display_amount;
|
||||
if (salary.displayAmount !== undefined) return salary.displayAmount;
|
||||
return Number(salary.available_amount || salary.availableAmount || 0) / 100;
|
||||
}
|
||||
|
||||
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 applyMockData() {
|
||||
data.profile = mock.profile;
|
||||
data.balance = mock.balance;
|
||||
data.overview = mock.overview;
|
||||
data.bdList = mock.bdList;
|
||||
data.history = mock.history;
|
||||
data.inviteRecords = mock.inviteRecords;
|
||||
}
|
||||
|
||||
function applyEmptyData() {
|
||||
data.profile = { name: '-', uid: '-', avatar: '' };
|
||||
data.balance = { available: 0 };
|
||||
data.overview = {
|
||||
totalBD: 0,
|
||||
totalAgency: 0,
|
||||
totalHosts: 0,
|
||||
teamSalary: 0,
|
||||
teamRecharge: 0,
|
||||
};
|
||||
data.bdList = [];
|
||||
data.history = [];
|
||||
data.inviteRecords = { bd: [] };
|
||||
}
|
||||
|
||||
function normalizeOverview(payload) {
|
||||
var overview = payload && payload.overview ? payload.overview : {};
|
||||
return {
|
||||
totalBD: overview.total_bd || overview.totalBD || 0,
|
||||
totalAgency: overview.total_agency || overview.totalAgency || 0,
|
||||
totalHosts: overview.total_hosts || overview.totalHosts || 0,
|
||||
teamSalary: overview.team_salary || overview.teamSalary || 0,
|
||||
teamRecharge: overview.team_recharge || overview.teamRecharge || 0,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeBDItem(item) {
|
||||
var name = displayName(item, 'BD ' + displayID(item));
|
||||
return {
|
||||
id: displayID(item),
|
||||
userId: item.user_id || item.userId || '',
|
||||
name: name,
|
||||
avatar: item.avatar || '',
|
||||
agencies: item.agency_count || item.agencies || 0,
|
||||
hosts: item.host_count || item.hosts || 0,
|
||||
salary: item.salary === undefined ? null : item.salary,
|
||||
recharge: item.recharge === undefined ? null : item.recharge,
|
||||
sideValue:
|
||||
count(item.agency_count || item.agencies || 0) +
|
||||
' ' +
|
||||
t('bd_leader_center.agencies', 'Agencies'),
|
||||
sideSub: '',
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeInviteProfile(payload) {
|
||||
var user = payload && (payload.user || payload.profile || payload);
|
||||
if (!user || !(user.user_id || user.userId)) return null;
|
||||
var id = displayID(user);
|
||||
return {
|
||||
userId: user.user_id || user.userId,
|
||||
id: user.user_id || user.userId,
|
||||
name: displayName(user, 'User ' + id),
|
||||
account: id,
|
||||
avatar: user.avatar || '',
|
||||
};
|
||||
}
|
||||
|
||||
function commandID(prefix, targetUserID) {
|
||||
return [
|
||||
prefix,
|
||||
targetUserID,
|
||||
Date.now(),
|
||||
Math.random().toString(16).slice(2),
|
||||
].join('-');
|
||||
}
|
||||
|
||||
function api() {
|
||||
return window.HyAppAPI || {};
|
||||
}
|
||||
|
||||
function loadRealData() {
|
||||
var centerAPI = api().bdLeaderCenter;
|
||||
if (!centerAPI) {
|
||||
toast('API module is not ready.');
|
||||
return Promise.reject(new Error('api_not_ready'));
|
||||
}
|
||||
return Promise.all([
|
||||
centerAPI.overview(),
|
||||
centerAPI.bds(50),
|
||||
])
|
||||
.then(function (results) {
|
||||
var overviewPayload = results[0] || {};
|
||||
var bdPayload = results[1] || {};
|
||||
var profile = overviewPayload.profile || {};
|
||||
var overview = normalizeOverview(overviewPayload);
|
||||
var bds = (bdPayload.items || []).map(normalizeBDItem);
|
||||
overview.teamSalary = displayAmount(overviewPayload.salary);
|
||||
data.profile = {
|
||||
name: displayName(profile, 'BD Leader'),
|
||||
uid: displayID(profile),
|
||||
avatar: profile.avatar || '',
|
||||
};
|
||||
data.balance = {
|
||||
available: displayAmount(overviewPayload.salary),
|
||||
};
|
||||
data.overview = overview;
|
||||
data.bdList = bds;
|
||||
data.history = [
|
||||
{
|
||||
month: new Date().toISOString().slice(0, 7),
|
||||
status: 'In progress',
|
||||
bdCount: overview.totalBD,
|
||||
agencyCount: overview.totalAgency,
|
||||
totalSalary: overview.teamSalary,
|
||||
totalRecharge: overview.teamRecharge,
|
||||
},
|
||||
];
|
||||
data.inviteRecords = { bd: [] };
|
||||
render();
|
||||
})
|
||||
.catch(function (error) {
|
||||
toast(error.message || 'Load failed.');
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function renderProfile() {
|
||||
$('profileName').textContent = data.profile.name;
|
||||
$('profileUID').textContent = t(
|
||||
'bd_leader_center.uid_prefix',
|
||||
'UID: {id}'
|
||||
).replace('{id}', data.profile.uid);
|
||||
setImage(
|
||||
$('profileAvatar'),
|
||||
$('profileAvatarFallback'),
|
||||
data.profile.avatar,
|
||||
data.profile.name
|
||||
);
|
||||
}
|
||||
|
||||
function renderBalance() {
|
||||
$('availableBalance').textContent = money(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 renderTeamSummary() {
|
||||
$('teamSummary').classList.add('is-two');
|
||||
var cells = [
|
||||
summaryCell(
|
||||
t('bd_leader_center.bd_number', 'BD number'),
|
||||
count(data.overview.totalBD)
|
||||
),
|
||||
summaryCell(
|
||||
t('bd_leader_center.agencies', 'Agencies'),
|
||||
count(data.overview.totalAgency)
|
||||
),
|
||||
];
|
||||
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');
|
||||
var sideValue =
|
||||
item.sideValue ||
|
||||
(item.salary === null || item.salary === undefined
|
||||
? ''
|
||||
: '$' + money(item.salary));
|
||||
var subText =
|
||||
item.sideSub !== undefined
|
||||
? item.sideSub
|
||||
: count(item.agencies) +
|
||||
' ' +
|
||||
t('bd_leader_center.agencies', 'Agencies');
|
||||
|
||||
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 = 'ID: ' + item.id;
|
||||
salary.textContent = sideValue || subText;
|
||||
sub.textContent = sideValue ? subText : '';
|
||||
|
||||
main.appendChild(name);
|
||||
main.appendChild(meta);
|
||||
side.appendChild(salary);
|
||||
if (sub.textContent) 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() {
|
||||
renderTeamSummary();
|
||||
replaceChildren(
|
||||
$('teamList'),
|
||||
data.bdList.map(function (item) {
|
||||
return createMemberRow(item);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function renderHistory() {
|
||||
var previous = data.history[1] || { totalSalary: 0 };
|
||||
replaceChildren($('historySummary'), [
|
||||
summaryCell(
|
||||
t('bd_leader_center.total_income', 'Total income'),
|
||||
'$' + money(data.overview.teamSalary)
|
||||
),
|
||||
summaryCell(
|
||||
t('bd_leader_center.previous_income', 'Previous income'),
|
||||
'$' + money(previous.totalSalary)
|
||||
),
|
||||
]);
|
||||
replaceChildren(
|
||||
$('historyList'),
|
||||
data.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('bd_leader_center.bd_number', 'BD number'),
|
||||
count(item.bdCount)
|
||||
)
|
||||
);
|
||||
grid.appendChild(
|
||||
summaryCell(
|
||||
t('bd_leader_center.agency_number', 'Agency number'),
|
||||
count(item.agencyCount)
|
||||
)
|
||||
);
|
||||
grid.appendChild(
|
||||
summaryCell(
|
||||
t('bd_leader_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;
|
||||
var summaryRows;
|
||||
if (!item) return;
|
||||
$('detailsTitle').textContent = item.name;
|
||||
summaryRows = [summaryCell('ID', item.id)];
|
||||
if (item.salary !== null && item.salary !== undefined) {
|
||||
summaryRows.push(
|
||||
summaryCell(
|
||||
t('bd_leader_center.team_salary', 'Team salary'),
|
||||
'$' + money(item.salary)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (item.recharge !== null && item.recharge !== undefined) {
|
||||
summaryRows.push(
|
||||
summaryCell(
|
||||
t('bd_leader_center.team_recharge', 'Team recharge'),
|
||||
'$' + money(item.recharge)
|
||||
)
|
||||
);
|
||||
}
|
||||
replaceChildren($('detailsSummary'), summaryRows);
|
||||
replaceChildren($('detailsList'), [
|
||||
createReadonlyLine(
|
||||
t('bd_leader_center.agencies', 'Agencies'),
|
||||
count(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 t('bd_leader_center.invite_bd', 'Invite BD');
|
||||
}
|
||||
|
||||
function inviteRecords() {
|
||||
if (!state.inviteQuery) return data.inviteRecords.bd || [];
|
||||
if (!state.isMock) return state.inviteSearchResults;
|
||||
var keyword = state.inviteQuery.toLowerCase();
|
||||
return mock.searchPool.bd.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');
|
||||
var records = inviteRecords();
|
||||
status.hidden = !state.inviteStatus;
|
||||
status.textContent = state.inviteStatus;
|
||||
status.className =
|
||||
'invite-status' +
|
||||
(state.inviteStatusType ? ' ' + state.inviteStatusType : '');
|
||||
|
||||
$('inviteEmpty').hidden = records.length > 0 || !!state.inviteStatus;
|
||||
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');
|
||||
var submitting = !!state.inviteSubmitting[profile.userId];
|
||||
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 ||
|
||||
(submitting
|
||||
? t('bd_leader_center.in_progress', 'In progress')
|
||||
: t('bd_leader_center.invite', 'Invite'));
|
||||
action.disabled = !!record.status || submitting;
|
||||
action.addEventListener('click', function () {
|
||||
submitInvite(record, profile);
|
||||
});
|
||||
main.appendChild(name);
|
||||
main.appendChild(meta);
|
||||
card.appendChild(makeAvatar(profile));
|
||||
card.appendChild(main);
|
||||
card.appendChild(action);
|
||||
return card;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function searchInviteProfile(queryValue) {
|
||||
if (state.isMock) {
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
if (!api().user || !api().user.resolveDisplayUserID) {
|
||||
state.inviteStatus = 'API module is not ready.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
state.inviteSearchResults = [];
|
||||
state.inviteStatus = t('bd_leader_center.in_progress', 'In progress');
|
||||
state.inviteStatusType = '';
|
||||
renderInvite();
|
||||
api()
|
||||
.user.resolveDisplayUserID(queryValue)
|
||||
.then(function (payload) {
|
||||
var profile = normalizeInviteProfile(payload);
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
state.inviteSearchResults = profile ? [profile] : [];
|
||||
renderInvite();
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.inviteSearchResults = [];
|
||||
state.inviteStatus =
|
||||
error.message ||
|
||||
t('bd_leader_center.no_users_found', 'No users found');
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
});
|
||||
}
|
||||
|
||||
function submitInvite(record, profile) {
|
||||
var targetUserID = String(profile.userId || profile.id || '');
|
||||
var centerAPI = api().bdLeaderCenter;
|
||||
if (!targetUserID) return;
|
||||
if (state.isMock) {
|
||||
record.status = 'Success';
|
||||
state.inviteStatus = t(
|
||||
'bd_leader_center.invite_success',
|
||||
'Invitation submitted.'
|
||||
);
|
||||
state.inviteStatusType = 'success';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
if (!centerAPI) {
|
||||
state.inviteStatus = 'API module is not ready.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
state.inviteSubmitting[targetUserID] = true;
|
||||
renderInvite();
|
||||
var payload = {
|
||||
command_id: commandID('bd', targetUserID),
|
||||
target_user_id: targetUserID,
|
||||
};
|
||||
centerAPI
|
||||
.inviteBD(payload)
|
||||
.then(function () {
|
||||
record.status = 'Success';
|
||||
state.inviteStatus = t(
|
||||
'bd_leader_center.invite_success',
|
||||
'Invitation submitted.'
|
||||
);
|
||||
state.inviteStatusType = 'success';
|
||||
loadRealData().catch(function () {});
|
||||
renderInvite();
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.inviteStatus = error.message || 'Invite failed.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
})
|
||||
.finally(function () {
|
||||
delete state.inviteSubmitting[targetUserID];
|
||||
renderInvite();
|
||||
});
|
||||
}
|
||||
|
||||
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', 'BD_LEADER');
|
||||
params.set('salaryType', 'ADMIN_SALARY_USD');
|
||||
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') {
|
||||
state.inviteQuery = '';
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
state.inviteSearchResults = [];
|
||||
$('inviteSearchInput').value = '';
|
||||
renderInvite();
|
||||
openModal('inviteModal');
|
||||
}
|
||||
});
|
||||
});
|
||||
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('bd_leader_center.enter_user_id', 'Enter User ID');
|
||||
state.inviteStatusType = state.inviteQuery ? '' : 'warning';
|
||||
state.inviteSearchResults = [];
|
||||
if (state.inviteQuery) {
|
||||
searchInviteProfile(state.inviteQuery);
|
||||
} else {
|
||||
renderInvite();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key !== 'Escape') return;
|
||||
closeModal('historyModal');
|
||||
closeModal('detailsModal');
|
||||
closeModal('inviteModal');
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
renderProfile();
|
||||
renderBalance();
|
||||
renderTeamList();
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (state.isMock) {
|
||||
applyMockData();
|
||||
} else {
|
||||
applyEmptyData();
|
||||
}
|
||||
render();
|
||||
bindEvents();
|
||||
if (!state.isMock) {
|
||||
loadRealData().catch(function () {});
|
||||
}
|
||||
if (window.HyAppBridge) {
|
||||
window.HyAppBridge.ready({
|
||||
page: 'bd-leader-center',
|
||||
mock: state.isMock,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
})();
|
||||
521
gonghui/bd-leader/style.css
Normal file
521
gonghui/bd-leader/style.css
Normal file
@ -0,0 +1,521 @@
|
||||
.role-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--hy-theme-primary-soft, #f4ebff);
|
||||
color: var(--primary-deep);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.bd-leader-center .name {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.salary-card,
|
||||
.team-card {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.salary-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.salary-head h2 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: 18px;
|
||||
font-weight: 950;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.salary-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
color: #23272d;
|
||||
font-size: 34px;
|
||||
font-weight: 950;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.coin-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(145deg, #ffe179 0%, #ffb62d 52%, #f49b20 100%);
|
||||
color: #fff;
|
||||
font-size: 19px;
|
||||
font-weight: 950;
|
||||
box-shadow:
|
||||
inset 0 1px 2px rgba(255, 255, 255, 0.7),
|
||||
0 1px 2px rgba(195, 117, 12, 0.24);
|
||||
}
|
||||
|
||||
.salary-value strong {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.menu-card {
|
||||
display: grid;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.menu-row {
|
||||
display: grid;
|
||||
grid-template-columns: 38px minmax(0, 1fr) 24px;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
min-height: 64px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.menu-row:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
}
|
||||
|
||||
.menu-icon svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.menu-icon path {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #464951;
|
||||
font-size: 16px;
|
||||
font-weight: 850;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.team-card {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.team-head h2 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: 18px;
|
||||
font-weight: 950;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.team-summary,
|
||||
.history-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.team-summary.is-two {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.history-summary.compact {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.team-summary > div,
|
||||
.history-summary > div {
|
||||
min-width: 0;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
background: var(--hy-theme-primary-soft, #f4ebff);
|
||||
}
|
||||
|
||||
.team-summary span,
|
||||
.history-summary span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
font-weight: 850;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.team-summary strong,
|
||||
.history-summary strong {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
overflow-wrap: anywhere;
|
||||
color: var(--text);
|
||||
font-size: 15px;
|
||||
font-weight: 950;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.team-list,
|
||||
.history-list,
|
||||
.invite-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.team-list {
|
||||
max-height: 360px;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.member-row,
|
||||
.invite-card {
|
||||
display: grid;
|
||||
grid-template-columns: 44px minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.member-avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
.member-avatar img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.member-fallback {
|
||||
color: var(--primary-deep);
|
||||
font-size: 18px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.member-main,
|
||||
.invite-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.member-name,
|
||||
.invite-name {
|
||||
overflow: hidden;
|
||||
color: var(--text);
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-meta,
|
||||
.invite-meta {
|
||||
margin-top: 4px;
|
||||
overflow: hidden;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-side {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
color: #555b64;
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
line-height: 1.2;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.member-side strong {
|
||||
color: var(--primary-deep);
|
||||
font-size: 14px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.history-sheet {
|
||||
max-height: 82vh;
|
||||
max-height: 82dvh;
|
||||
}
|
||||
|
||||
.history-summary,
|
||||
.history-list {
|
||||
padding: 0 18px 14px;
|
||||
}
|
||||
|
||||
.history-row {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
}
|
||||
|
||||
.history-title {
|
||||
color: var(--text);
|
||||
font-size: 16px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
justify-self: flex-start;
|
||||
padding: 5px 9px;
|
||||
border-radius: 999px;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.history-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.readonly-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 48px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.readonly-line strong {
|
||||
color: var(--text);
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.invite-modal {
|
||||
position: fixed;
|
||||
z-index: 24;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.invite-dialog {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(394px, 100%);
|
||||
max-height: 80vh;
|
||||
max-height: 80dvh;
|
||||
overflow: hidden;
|
||||
border-radius: 14px;
|
||||
background: #fff;
|
||||
box-shadow: 0 18px 44px rgba(23, 31, 42, 0.2);
|
||||
}
|
||||
|
||||
.invite-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 18px 18px 12px;
|
||||
}
|
||||
|
||||
.invite-head h2 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: 20px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.invite-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
flex: 0 0 34px;
|
||||
border-radius: 50%;
|
||||
background: #f1f4f4;
|
||||
color: #5d6570;
|
||||
font-size: 25px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.invite-body {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 0 18px 18px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.invite-field {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.invite-field > span {
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.invite-search-control {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 96px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.invite-search-control input {
|
||||
min-width: 0;
|
||||
height: 44px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.invite-search-control button,
|
||||
.invite-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 44px;
|
||||
border-radius: 8px;
|
||||
background: var(--button);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.invite-action {
|
||||
min-width: 82px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.invite-action:disabled {
|
||||
background: var(--hy-theme-button-disabled, #eadffc);
|
||||
color: var(--hy-theme-button-disabled-text, #9a8faa);
|
||||
}
|
||||
|
||||
.invite-status,
|
||||
.invite-empty {
|
||||
min-height: 42px;
|
||||
padding: 11px 12px;
|
||||
border-radius: 8px;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.invite-status.warning {
|
||||
background: #fff5e8;
|
||||
color: #ba791c;
|
||||
}
|
||||
|
||||
.invite-status.success {
|
||||
background: #ecfbef;
|
||||
color: #219251;
|
||||
}
|
||||
|
||||
.invite-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
body.modal-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[dir='rtl'] .menu-row,
|
||||
[dir='rtl'] .member-row,
|
||||
[dir='rtl'] .invite-card {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir='rtl'] .member-side {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
[dir='rtl'] .chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.salary-card,
|
||||
.team-card {
|
||||
padding-right: 14px;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.team-summary,
|
||||
.history-summary,
|
||||
.history-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.member-row,
|
||||
.invite-card {
|
||||
grid-template-columns: 40px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.member-side,
|
||||
.invite-action {
|
||||
grid-column: 2;
|
||||
justify-self: start;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
439
gonghui/coinseller-center/index.html
Normal file
439
gonghui/coinseller-center/index.html
Normal file
@ -0,0 +1,439 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<title>Coin Seller Center</title>
|
||||
<link rel="stylesheet" href="../../common/theme.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="../common/center.css?v=20260604-coinseller"
|
||||
/>
|
||||
<link rel="stylesheet" href="./style.css?v=20260604" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="coinseller-center" aria-label="Coin Seller Center">
|
||||
<div class="hero-bg" aria-hidden="true"></div>
|
||||
|
||||
<nav class="title-bar">
|
||||
<button
|
||||
class="back-button"
|
||||
id="backButton"
|
||||
type="button"
|
||||
aria-label="Back"
|
||||
data-i18n-aria="coinseller_center.back"
|
||||
>
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true">
|
||||
<path d="M20 8 12 16l8 8" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 data-i18n="coinseller_center.title">Coin Seller Center</h1>
|
||||
<div class="language-switcher">
|
||||
<button
|
||||
class="language-button"
|
||||
type="button"
|
||||
aria-label="Change language"
|
||||
aria-expanded="false"
|
||||
data-language-toggle
|
||||
data-current-lang
|
||||
data-i18n-aria="coinseller_center.change_language"
|
||||
>
|
||||
EN
|
||||
</button>
|
||||
<div class="language-menu" data-language-menu hidden>
|
||||
<button type="button" data-lang-option="en">EN</button>
|
||||
<button type="button" data-lang-option="ar">AR</button>
|
||||
<button type="button" data-lang-option="tr">TR</button>
|
||||
<button type="button" data-lang-option="es">ES</button>
|
||||
<button type="button" data-lang-option="zh">ZH</button>
|
||||
<button type="button" data-lang-option="id">ID</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
<section class="card profile-card">
|
||||
<div class="avatar-shell">
|
||||
<img class="avatar-image" id="profileAvatar" alt="" />
|
||||
<div
|
||||
class="avatar-fallback"
|
||||
id="profileAvatarFallback"
|
||||
aria-hidden="true"
|
||||
hidden
|
||||
>
|
||||
C
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-copy">
|
||||
<div class="name" id="profileName">-</div>
|
||||
<div class="meta" id="profileUID">UID: -</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card balance-card">
|
||||
<div class="balance-head">
|
||||
<div>
|
||||
<div
|
||||
class="balance-label"
|
||||
data-i18n="coinseller_center.coins"
|
||||
>
|
||||
Coins
|
||||
</div>
|
||||
<div
|
||||
class="balance-subtitle"
|
||||
data-i18n="coinseller_center.available_stock"
|
||||
>
|
||||
Available stock
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="round-action"
|
||||
id="historyButton"
|
||||
type="button"
|
||||
aria-label="History"
|
||||
data-i18n-aria="coinseller_center.history"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M12 8v5l3 2" />
|
||||
<path d="M3.5 12a8.5 8.5 0 1 0 2.2-5.7" />
|
||||
<path d="M3.5 4.5v5h5" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="balance-value">
|
||||
<span class="coin-icon" aria-hidden="true">$</span>
|
||||
<strong id="coinBalance">0</strong>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card search-card">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 data-i18n="coinseller_center.recharge_user">
|
||||
Recharge user
|
||||
</h2>
|
||||
<p data-i18n="coinseller_center.search_by_user_id">
|
||||
Search by user ID
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="round-action small"
|
||||
id="helpButton"
|
||||
type="button"
|
||||
aria-label="Help"
|
||||
data-i18n-aria="coinseller_center.help"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="9" />
|
||||
<path d="M9.5 9a2.7 2.7 0 0 1 5.2.9c0 1.9-2.7 2.2-2.7 4.1" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<form class="search-form" id="searchForm">
|
||||
<input
|
||||
id="userSearchInput"
|
||||
type="text"
|
||||
inputmode="text"
|
||||
autocomplete="off"
|
||||
placeholder="Enter user ID"
|
||||
data-i18n-placeholder="coinseller_center.enter_user_id"
|
||||
/>
|
||||
<button
|
||||
id="searchButton"
|
||||
type="submit"
|
||||
data-i18n="coinseller_center.search"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
</form>
|
||||
<div class="form-status" id="searchStatus" hidden></div>
|
||||
|
||||
<div class="target-card" id="targetCard" hidden>
|
||||
<div class="target-avatar" id="targetAvatar"></div>
|
||||
<div class="target-main">
|
||||
<div
|
||||
class="role-pill"
|
||||
data-i18n="coinseller_center.target_user"
|
||||
>
|
||||
Target user
|
||||
</div>
|
||||
<div class="target-name" id="targetName">-</div>
|
||||
<div class="target-meta" id="targetUID">UID: -</div>
|
||||
</div>
|
||||
<button
|
||||
class="target-coin-action"
|
||||
id="openRechargeButton"
|
||||
type="button"
|
||||
aria-label="Recharge coins"
|
||||
data-i18n-aria="coinseller_center.recharge_coins"
|
||||
>
|
||||
<span class="coin-icon" aria-hidden="true">$</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card recent-card">
|
||||
<div class="section-head">
|
||||
<div>
|
||||
<h2 data-i18n="coinseller_center.recent_records">
|
||||
Recent records
|
||||
</h2>
|
||||
<p data-i18n="coinseller_center.today_activity">
|
||||
Today's activity
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="text-link"
|
||||
id="viewAllHistoryButton"
|
||||
type="button"
|
||||
data-i18n="coinseller_center.view_all"
|
||||
>
|
||||
View all
|
||||
</button>
|
||||
</div>
|
||||
<div class="record-list" id="recentList"></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div class="home-indicator" aria-hidden="true"></div>
|
||||
|
||||
<div
|
||||
class="sheet-modal"
|
||||
id="historyModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="historyModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="bottom-sheet history-sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="historyTitle"
|
||||
>
|
||||
<div class="sheet-head">
|
||||
<h2
|
||||
id="historyTitle"
|
||||
data-i18n="coinseller_center.transaction_records"
|
||||
>
|
||||
Transaction records
|
||||
</h2>
|
||||
<button
|
||||
class="sheet-close"
|
||||
type="button"
|
||||
data-close-modal="historyModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="history-body">
|
||||
<form class="history-search-form" id="historySearchForm">
|
||||
<input
|
||||
id="historySearchInput"
|
||||
type="text"
|
||||
inputmode="text"
|
||||
placeholder="Enter user ID"
|
||||
data-i18n-placeholder="coinseller_center.enter_user_id"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
data-i18n="coinseller_center.search"
|
||||
>
|
||||
Search
|
||||
</button>
|
||||
<button
|
||||
class="history-clear-button"
|
||||
id="historyClearButton"
|
||||
type="button"
|
||||
data-i18n="coinseller_center.cancel"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
class="history-tabs"
|
||||
role="tablist"
|
||||
aria-label="Transaction type"
|
||||
>
|
||||
<button
|
||||
class="history-tab is-active"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="true"
|
||||
data-history-tab="income"
|
||||
data-i18n="coinseller_center.income"
|
||||
>
|
||||
Income
|
||||
</button>
|
||||
<button
|
||||
class="history-tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected="false"
|
||||
data-history-tab="expenditure"
|
||||
data-i18n="coinseller_center.expenditure"
|
||||
>
|
||||
Expenditure
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-status" id="historyStatus" hidden></div>
|
||||
<div class="record-list history-records" id="historyList"></div>
|
||||
<button
|
||||
class="load-more"
|
||||
id="loadMoreButton"
|
||||
type="button"
|
||||
data-i18n="coinseller_center.load_more"
|
||||
>
|
||||
Load more
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="sheet-modal"
|
||||
id="rechargeModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="rechargeModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="bottom-sheet recharge-sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="rechargeTitle"
|
||||
>
|
||||
<div class="sheet-head">
|
||||
<h2
|
||||
id="rechargeTitle"
|
||||
data-i18n="coinseller_center.recharge_coins"
|
||||
>
|
||||
Recharge coins
|
||||
</h2>
|
||||
<button
|
||||
class="sheet-close"
|
||||
type="button"
|
||||
data-close-modal="rechargeModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="recharge-sheet-body">
|
||||
<div class="recharge-target" id="rechargeTargetName">
|
||||
-
|
||||
</div>
|
||||
<p data-i18n="coinseller_center.enter_coin_amount">
|
||||
Enter coins amount
|
||||
</p>
|
||||
<div class="quick-amounts" id="quickAmounts"></div>
|
||||
<form class="recharge-form" id="rechargeForm">
|
||||
<label class="coin-input-shell">
|
||||
<span class="input-coin" aria-hidden="true"
|
||||
>$</span
|
||||
>
|
||||
<input
|
||||
id="coinAmountInput"
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
autocomplete="off"
|
||||
placeholder="Enter coins amount"
|
||||
data-i18n-placeholder="coinseller_center.coin_amount_placeholder"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
id="rechargeButton"
|
||||
type="submit"
|
||||
disabled
|
||||
data-i18n="coinseller_center.recharge_now"
|
||||
>
|
||||
Recharge now
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
class="form-status"
|
||||
id="rechargeStatus"
|
||||
hidden
|
||||
></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="sheet-modal"
|
||||
id="helpModal"
|
||||
hidden
|
||||
aria-hidden="true"
|
||||
>
|
||||
<button
|
||||
class="modal-backdrop"
|
||||
type="button"
|
||||
data-close-modal="helpModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
></button>
|
||||
<section
|
||||
class="bottom-sheet help-sheet"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="helpTitle"
|
||||
>
|
||||
<div class="sheet-head">
|
||||
<h2 id="helpTitle" data-i18n="coinseller_center.help">
|
||||
Help
|
||||
</h2>
|
||||
<button
|
||||
class="sheet-close"
|
||||
type="button"
|
||||
data-close-modal="helpModal"
|
||||
aria-label="Close"
|
||||
data-i18n-aria="coinseller_center.close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="help-content">
|
||||
<h3 data-i18n="coinseller_center.faq_title">FAQ</h3>
|
||||
<p data-i18n="coinseller_center.faq_question_1">
|
||||
How to recharge?
|
||||
</p>
|
||||
<span data-i18n="coinseller_center.faq_answer_1">
|
||||
Search a user, enter the coin amount, then confirm recharge.
|
||||
</span>
|
||||
<p data-i18n="coinseller_center.faq_question_2">
|
||||
How to check records?
|
||||
</p>
|
||||
<span data-i18n="coinseller_center.faq_answer_2">
|
||||
Open history and switch between income and expenditure.
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="../../common/jsbridge.js"></script>
|
||||
<script src="../../common/api.js?v=20260604-coinseller-records"></script>
|
||||
<script src="../../common/i18n.js?v=20260604-coinseller"></script>
|
||||
<script src="./script.js?v=20260604-record-user-profile"></script>
|
||||
</body>
|
||||
</html>
|
||||
1121
gonghui/coinseller-center/script.js
Normal file
1121
gonghui/coinseller-center/script.js
Normal file
File diff suppressed because it is too large
Load Diff
550
gonghui/coinseller-center/style.css
Normal file
550
gonghui/coinseller-center/style.css
Normal file
@ -0,0 +1,550 @@
|
||||
.coinseller-center {
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
.role-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.balance-card,
|
||||
.search-card,
|
||||
.recent-card {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.balance-head,
|
||||
.section-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.balance-label,
|
||||
.section-head h2 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: 18px;
|
||||
font-weight: 950;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.balance-subtitle,
|
||||
.section-head p {
|
||||
margin: 6px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.round-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
flex: 0 0 44px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
}
|
||||
|
||||
.round-action.small {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
flex-basis: 36px;
|
||||
}
|
||||
|
||||
.round-action svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.round-action.small svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.round-action path,
|
||||
.round-action circle {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.balance-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
color: #23272d;
|
||||
font-size: 34px;
|
||||
font-weight: 950;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.balance-value strong {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.coin-icon,
|
||||
.input-coin {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(145deg, #ffe179 0%, #ffb62d 52%, #f49b20 100%);
|
||||
color: #fff;
|
||||
font-size: 19px;
|
||||
font-weight: 950;
|
||||
box-shadow:
|
||||
inset 0 1px 2px rgba(255, 255, 255, 0.7),
|
||||
0 1px 2px rgba(195, 117, 12, 0.24);
|
||||
}
|
||||
|
||||
.search-card,
|
||||
.recent-card {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.search-form,
|
||||
.history-search-form {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 102px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.search-form input,
|
||||
.history-search-form input,
|
||||
.coin-input-shell {
|
||||
min-width: 0;
|
||||
height: 52px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: rgba(251, 249, 255, 0.9);
|
||||
}
|
||||
|
||||
.search-form input,
|
||||
.history-search-form input {
|
||||
width: 100%;
|
||||
padding: 0 14px;
|
||||
color: var(--text);
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.search-form input::placeholder,
|
||||
.history-search-form input::placeholder,
|
||||
.coin-input-shell input::placeholder {
|
||||
color: #b5b0bd;
|
||||
}
|
||||
|
||||
.search-form button,
|
||||
.history-search-form button,
|
||||
.recharge-form button,
|
||||
.load-more {
|
||||
min-height: 52px;
|
||||
border-radius: 8px;
|
||||
background: var(--button);
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.history-clear-button {
|
||||
background: var(--primary-soft) !important;
|
||||
color: var(--primary-deep) !important;
|
||||
}
|
||||
|
||||
.form-status {
|
||||
min-height: 42px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 8px;
|
||||
background: rgba(249, 241, 255, 0.72);
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.form-status.success {
|
||||
background: rgba(49, 198, 168, 0.12);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.form-status.warning {
|
||||
background: rgba(217, 93, 114, 0.1);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.target-card {
|
||||
display: grid;
|
||||
grid-template-columns: 52px minmax(0, 1fr) 52px;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.target-card[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.target-avatar,
|
||||
.record-avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
color: var(--primary-deep);
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.target-avatar {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
font-size: 21px;
|
||||
}
|
||||
|
||||
.target-avatar img,
|
||||
.record-avatar img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.target-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.target-name {
|
||||
margin-top: 6px;
|
||||
overflow: hidden;
|
||||
color: var(--text);
|
||||
font-size: 17px;
|
||||
font-weight: 950;
|
||||
line-height: 1.15;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.target-meta {
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.target-coin-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
}
|
||||
|
||||
.target-coin-action .coin-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-basis: 32px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.quick-amounts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.quick-amount {
|
||||
min-height: 40px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.quick-amount.is-active {
|
||||
border-color: var(--primary-deep);
|
||||
background: var(--primary-deep);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.recharge-form {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.recharge-sheet {
|
||||
max-height: 78vh;
|
||||
max-height: 78dvh;
|
||||
}
|
||||
|
||||
.recharge-sheet-body {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
padding: 16px 18px calc(18px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.recharge-target {
|
||||
overflow: hidden;
|
||||
color: var(--text);
|
||||
font-size: 16px;
|
||||
font-weight: 950;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.recharge-sheet-body p {
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
font-weight: 850;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.coin-input-shell {
|
||||
display: grid;
|
||||
grid-template-columns: 42px minmax(0, 1fr);
|
||||
align-items: center;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.input-coin {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
flex-basis: 26px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.coin-input-shell input {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 20px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.recharge-form button {
|
||||
width: 100%;
|
||||
min-height: 56px;
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
.recharge-form button:disabled {
|
||||
background: var(--button-disabled);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.text-link {
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.record-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.record-row {
|
||||
display: grid;
|
||||
grid-template-columns: 42px minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fbfcfc;
|
||||
}
|
||||
|
||||
.record-avatar {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.record-main {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.record-title {
|
||||
overflow: hidden;
|
||||
color: var(--text);
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.record-meta {
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.record-side {
|
||||
display: grid;
|
||||
justify-items: end;
|
||||
gap: 4px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.record-side strong {
|
||||
color: var(--primary-deep);
|
||||
font-size: 15px;
|
||||
font-weight: 950;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.record-side.is-income strong {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.history-sheet {
|
||||
max-height: 86vh;
|
||||
max-height: 86dvh;
|
||||
}
|
||||
|
||||
.history-body {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 14px 16px 18px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.history-search-form {
|
||||
grid-template-columns: minmax(0, 1fr) 86px 76px;
|
||||
}
|
||||
|
||||
.history-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
padding: 6px;
|
||||
border-radius: 8px;
|
||||
background: var(--primary-soft);
|
||||
}
|
||||
|
||||
.history-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 42px;
|
||||
border-radius: 7px;
|
||||
color: var(--muted);
|
||||
font-size: 15px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.history-tab.is-active {
|
||||
background: #fff;
|
||||
color: var(--text);
|
||||
box-shadow: 0 8px 18px rgba(98, 72, 155, 0.08);
|
||||
}
|
||||
|
||||
.history-records {
|
||||
max-height: 360px;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
background: var(--primary-soft);
|
||||
color: var(--primary-deep);
|
||||
}
|
||||
|
||||
.help-content {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 16px 18px 22px;
|
||||
}
|
||||
|
||||
.help-content h3,
|
||||
.help-content p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.help-content h3 {
|
||||
color: var(--text);
|
||||
font-size: 17px;
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.help-content p {
|
||||
margin-top: 8px;
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.help-content span {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
font-weight: 750;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
body.modal-open .coinseller-center {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[dir='rtl'] .record-side {
|
||||
justify-items: start;
|
||||
}
|
||||
|
||||
[dir='rtl'] .history-search-form {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.balance-value {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
grid-template-columns: minmax(0, 1fr) 88px;
|
||||
}
|
||||
|
||||
.history-search-form {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
@ -75,7 +75,8 @@ input:focus-visible {
|
||||
.host-center,
|
||||
.bd-center,
|
||||
.agency-center,
|
||||
.superadmin-center {
|
||||
.superadmin-center,
|
||||
.coinseller-center {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 430px;
|
||||
@ -278,6 +279,111 @@ input:focus-visible {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.skeleton-line,
|
||||
.avatar-skeleton,
|
||||
.skeleton-coin,
|
||||
.skeleton-fill,
|
||||
.policy-skeleton-block {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
color: transparent !important;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
#f2eafb 0%,
|
||||
#eadcff 38%,
|
||||
#f8f3ff 62%,
|
||||
#f2eafb 100%
|
||||
) !important;
|
||||
background-size: 220% 100% !important;
|
||||
box-shadow: none !important;
|
||||
animation: centerSkeleton 1.15s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.name.skeleton-line {
|
||||
width: min(260px, 78%);
|
||||
height: 30px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.meta.skeleton-line {
|
||||
width: 135px;
|
||||
height: 18px;
|
||||
margin-top: 9px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.profile-badge.skeleton-line {
|
||||
width: 190px;
|
||||
height: 28px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.avatar-skeleton {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.income-value .skeleton-line,
|
||||
.balance-value .skeleton-line {
|
||||
width: 160px;
|
||||
height: 38px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.income-foot.skeleton-line {
|
||||
width: 190px;
|
||||
height: 18px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.task-pill.skeleton-line {
|
||||
width: 108px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.task-item strong.skeleton-line {
|
||||
width: 126px;
|
||||
height: 23px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.skeleton-fill {
|
||||
width: 38% !important;
|
||||
}
|
||||
|
||||
.policy-summary .skeleton-line {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.policy-summary strong.skeleton-line {
|
||||
width: 220px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.policy-summary span.skeleton-line {
|
||||
width: 260px;
|
||||
max-width: 100%;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.policy-skeleton-block {
|
||||
height: 132px;
|
||||
margin-top: 14px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes centerSkeleton {
|
||||
0% {
|
||||
background-position: 120% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -120% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-link,
|
||||
.salary-link {
|
||||
display: inline-flex;
|
||||
|
||||
@ -168,110 +168,6 @@
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
.skeleton-line,
|
||||
.avatar-skeleton,
|
||||
.skeleton-coin,
|
||||
.skeleton-fill,
|
||||
.policy-skeleton-block {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
color: transparent !important;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
#f2eafb 0%,
|
||||
#eadcff 38%,
|
||||
#f8f3ff 62%,
|
||||
#f2eafb 100%
|
||||
) !important;
|
||||
background-size: 220% 100% !important;
|
||||
box-shadow: none !important;
|
||||
animation: hostSkeleton 1.15s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.name.skeleton-line {
|
||||
width: min(260px, 78%);
|
||||
height: 30px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.meta.skeleton-line {
|
||||
width: 135px;
|
||||
height: 18px;
|
||||
margin-top: 9px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.profile-badge.skeleton-line {
|
||||
width: 190px;
|
||||
height: 28px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.avatar-skeleton {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.income-value .skeleton-line {
|
||||
width: 160px;
|
||||
height: 38px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.income-foot.skeleton-line {
|
||||
width: 190px;
|
||||
height: 18px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.task-pill.skeleton-line {
|
||||
width: 108px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.task-item strong.skeleton-line {
|
||||
width: 126px;
|
||||
height: 23px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.skeleton-fill {
|
||||
width: 38% !important;
|
||||
}
|
||||
|
||||
.policy-summary .skeleton-line {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.policy-summary strong.skeleton-line {
|
||||
width: 220px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.policy-summary span.skeleton-line {
|
||||
width: 260px;
|
||||
max-width: 100%;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.policy-skeleton-block {
|
||||
height: 132px;
|
||||
margin-top: 14px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes hostSkeleton {
|
||||
0% {
|
||||
background-position: 120% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -120% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.policy-sheet-body {
|
||||
min-height: 180px;
|
||||
overflow-y: auto;
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
rel="stylesheet"
|
||||
href="../common/center.css?v=20260604-superadmin"
|
||||
/>
|
||||
<link rel="stylesheet" href="./style.css?v=20260604" />
|
||||
<link rel="stylesheet" href="./style.css?v=20260604-summary" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -356,7 +356,8 @@
|
||||
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="../../common/jsbridge.js"></script>
|
||||
<script src="../../common/api.js?v=20260604-superadmin-api"></script>
|
||||
<script src="../../common/i18n.js?v=20260604"></script>
|
||||
<script src="./script.js?v=20260604"></script>
|
||||
<script src="./script.js?v=20260604-api"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
(function () {
|
||||
var query = new URLSearchParams(window.location.search);
|
||||
var state = {
|
||||
activeTab: 'bd',
|
||||
inviteMode: 'bd',
|
||||
inviteQuery: '',
|
||||
inviteStatus: '',
|
||||
inviteStatusType: '',
|
||||
inviteSearchResults: [],
|
||||
inviteSubmitting: {},
|
||||
selectedDetails: null,
|
||||
isMock: query.get('mock') === '1',
|
||||
};
|
||||
|
||||
var mock = {
|
||||
@ -27,6 +31,7 @@
|
||||
bdList: [
|
||||
{
|
||||
id: '880001',
|
||||
userId: '3200901',
|
||||
name: 'Mila BD',
|
||||
avatar: avatarData('M', '#dbc8ff', '#7d57c7'),
|
||||
agencies: 12,
|
||||
@ -36,6 +41,7 @@
|
||||
},
|
||||
{
|
||||
id: '880018',
|
||||
userId: '3200918',
|
||||
name: 'Jasmine BD',
|
||||
avatar: avatarData('J', '#f4ebff', '#7d57c7'),
|
||||
agencies: 9,
|
||||
@ -45,6 +51,7 @@
|
||||
},
|
||||
{
|
||||
id: '880026',
|
||||
userId: '3200926',
|
||||
name: 'Omar BD',
|
||||
avatar: avatarData('O', '#efe4ff', '#7d57c7'),
|
||||
agencies: 7,
|
||||
@ -56,6 +63,7 @@
|
||||
agencyList: [
|
||||
{
|
||||
id: '163003',
|
||||
userId: '3200801',
|
||||
name: 'Yumi Star Agency',
|
||||
avatar: avatarData('Y', '#dbc8ff', '#7d57c7'),
|
||||
bdId: '880001',
|
||||
@ -65,6 +73,7 @@
|
||||
},
|
||||
{
|
||||
id: '163086',
|
||||
userId: '3200802',
|
||||
name: 'Moon Live Agency',
|
||||
avatar: avatarData('M', '#f4ebff', '#7d57c7'),
|
||||
bdId: '880018',
|
||||
@ -74,6 +83,7 @@
|
||||
},
|
||||
{
|
||||
id: '163221',
|
||||
userId: '3200803',
|
||||
name: 'Nova Host Guild',
|
||||
avatar: avatarData('N', '#efe4ff', '#7d57c7'),
|
||||
bdId: '880026',
|
||||
@ -112,8 +122,9 @@
|
||||
bd: [
|
||||
{
|
||||
id: 'bd-inv-01',
|
||||
status: 'Pending',
|
||||
status: 'Success',
|
||||
profile: {
|
||||
userId: '3200901',
|
||||
id: '3200901',
|
||||
name: 'BD_River',
|
||||
account: '880099',
|
||||
@ -126,6 +137,7 @@
|
||||
id: 'agent-inv-01',
|
||||
status: 'Success',
|
||||
profile: {
|
||||
userId: '3200801',
|
||||
id: '3200801',
|
||||
name: 'Agent_Lina',
|
||||
account: '168801',
|
||||
@ -137,12 +149,14 @@
|
||||
searchPool: {
|
||||
bd: [
|
||||
{
|
||||
userId: '3200902',
|
||||
id: '3200902',
|
||||
name: 'BD_Kai',
|
||||
account: '880102',
|
||||
avatar: avatarData('K', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
{
|
||||
userId: '3200903',
|
||||
id: '3200903',
|
||||
name: 'BD_Ayla',
|
||||
account: '880103',
|
||||
@ -151,12 +165,14 @@
|
||||
],
|
||||
agent: [
|
||||
{
|
||||
userId: '3200802',
|
||||
id: '3200802',
|
||||
name: 'Agent_Omar',
|
||||
account: '168802',
|
||||
avatar: avatarData('O', '#dbc8ff', '#7d57c7'),
|
||||
},
|
||||
{
|
||||
userId: '3200803',
|
||||
id: '3200803',
|
||||
name: 'Agent_Sara',
|
||||
account: '168803',
|
||||
@ -166,6 +182,16 @@
|
||||
},
|
||||
};
|
||||
|
||||
var data = {
|
||||
profile: mock.profile,
|
||||
balance: mock.balance,
|
||||
overview: mock.overview,
|
||||
bdList: mock.bdList,
|
||||
agencyList: mock.agencyList,
|
||||
history: mock.history,
|
||||
inviteRecords: mock.inviteRecords,
|
||||
};
|
||||
|
||||
function $(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
@ -238,6 +264,29 @@
|
||||
.toUpperCase();
|
||||
}
|
||||
|
||||
function displayName(user, fallback) {
|
||||
return (
|
||||
(user && (user.username || user.name || user.display_user_id)) ||
|
||||
fallback ||
|
||||
'-'
|
||||
);
|
||||
}
|
||||
|
||||
function displayID(user) {
|
||||
return (
|
||||
(user && (user.display_user_id || user.displayUserID)) ||
|
||||
(user && (user.user_id || user.userId)) ||
|
||||
'-'
|
||||
);
|
||||
}
|
||||
|
||||
function displayAmount(salary) {
|
||||
if (!salary) return 0;
|
||||
if (salary.display_amount !== undefined) return salary.display_amount;
|
||||
if (salary.displayAmount !== undefined) return salary.displayAmount;
|
||||
return Number(salary.available_amount || salary.availableAmount || 0) / 100;
|
||||
}
|
||||
|
||||
function toast(message) {
|
||||
if (!message) return;
|
||||
if (window.HyAppToast && window.HyAppToast.show) {
|
||||
@ -296,22 +345,193 @@
|
||||
});
|
||||
}
|
||||
|
||||
function applyMockData() {
|
||||
data.profile = mock.profile;
|
||||
data.balance = mock.balance;
|
||||
data.overview = mock.overview;
|
||||
data.bdList = mock.bdList;
|
||||
data.agencyList = mock.agencyList;
|
||||
data.history = mock.history;
|
||||
data.inviteRecords = mock.inviteRecords;
|
||||
}
|
||||
|
||||
function applyEmptyData() {
|
||||
data.profile = { name: '-', uid: '-', avatar: '' };
|
||||
data.balance = { available: 0 };
|
||||
data.overview = {
|
||||
totalBD: 0,
|
||||
totalAgency: 0,
|
||||
totalHosts: 0,
|
||||
teamSalary: 0,
|
||||
teamRecharge: 0,
|
||||
};
|
||||
data.bdList = [];
|
||||
data.agencyList = [];
|
||||
data.history = [];
|
||||
data.inviteRecords = { bd: [], agent: [] };
|
||||
}
|
||||
|
||||
function normalizeOverview(payload) {
|
||||
var overview = payload && payload.overview ? payload.overview : {};
|
||||
return {
|
||||
totalBD: overview.total_bd || overview.totalBD || 0,
|
||||
totalAgency: overview.total_agency || overview.totalAgency || 0,
|
||||
totalHosts: overview.total_hosts || overview.totalHosts || 0,
|
||||
teamSalary: overview.team_salary || overview.teamSalary || 0,
|
||||
teamRecharge: overview.team_recharge || overview.teamRecharge || 0,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeBDItem(item) {
|
||||
var name = displayName(item, 'BD ' + displayID(item));
|
||||
return {
|
||||
id: displayID(item),
|
||||
userId: item.user_id || item.userId || '',
|
||||
name: name,
|
||||
avatar: item.avatar || '',
|
||||
agencies: item.agency_count || item.agencies || 0,
|
||||
hosts: item.host_count || item.hosts || 0,
|
||||
salary: item.salary === undefined ? null : item.salary,
|
||||
recharge: item.recharge === undefined ? null : item.recharge,
|
||||
sideValue:
|
||||
count(item.agency_count || item.agencies || 0) +
|
||||
' ' +
|
||||
t('superadmin_center.agencies', 'Agencies'),
|
||||
sideSub: '',
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeAgencyItem(item) {
|
||||
var agency = (item && item.agency) || item || {};
|
||||
var owner = (item && item.owner) || {};
|
||||
var parentBD = (item && item.parent_bd) || {};
|
||||
var parentBDID =
|
||||
parentBD.display_user_id ||
|
||||
parentBD.displayUserID ||
|
||||
parentBD.user_id ||
|
||||
parentBD.userId ||
|
||||
agency.parent_bd_user_id ||
|
||||
agency.parentBdUserId ||
|
||||
'';
|
||||
var name =
|
||||
agency.name ||
|
||||
displayName(owner, 'Agency ' + (agency.agency_id || agency.id || '-'));
|
||||
return {
|
||||
id: agency.agency_id || agency.id || '-',
|
||||
userId: owner.user_id || owner.userId || agency.owner_user_id || '',
|
||||
name: name,
|
||||
avatar: owner.avatar || '',
|
||||
bdId: parentBDID || '-',
|
||||
hosts: item.host_count || agency.active_host_count || 0,
|
||||
salary: item.salary === undefined ? null : item.salary,
|
||||
recharge: item.recharge === undefined ? null : item.recharge,
|
||||
sideValue:
|
||||
count(item.host_count || agency.active_host_count || 0) +
|
||||
' ' +
|
||||
t('superadmin_center.hosts', 'Hosts'),
|
||||
sideSub: parentBDID ? 'BD: ' + parentBDID : '',
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeInviteProfile(payload) {
|
||||
var user = payload && (payload.user || payload.profile || payload);
|
||||
if (!user || !(user.user_id || user.userId)) return null;
|
||||
var id = displayID(user);
|
||||
return {
|
||||
userId: user.user_id || user.userId,
|
||||
id: user.user_id || user.userId,
|
||||
name: displayName(user, 'User ' + id),
|
||||
account: id,
|
||||
avatar: user.avatar || '',
|
||||
};
|
||||
}
|
||||
|
||||
function commandID(prefix, targetUserID) {
|
||||
return [
|
||||
prefix,
|
||||
targetUserID,
|
||||
Date.now(),
|
||||
Math.random().toString(16).slice(2),
|
||||
].join('-');
|
||||
}
|
||||
|
||||
function api() {
|
||||
return window.HyAppAPI || {};
|
||||
}
|
||||
|
||||
function loadRealData() {
|
||||
var centerAPI = api().superadminCenter;
|
||||
if (!centerAPI) {
|
||||
toast('API module is not ready.');
|
||||
return Promise.reject(new Error('api_not_ready'));
|
||||
}
|
||||
return Promise.all([
|
||||
centerAPI.overview(),
|
||||
centerAPI.bds(50),
|
||||
centerAPI.agencies(50),
|
||||
])
|
||||
.then(function (results) {
|
||||
var overviewPayload = results[0] || {};
|
||||
var bdPayload = results[1] || {};
|
||||
var agencyPayload = results[2] || {};
|
||||
var profile = overviewPayload.profile || {};
|
||||
var overview = normalizeOverview(overviewPayload);
|
||||
var agencies = (agencyPayload.items || []).map(
|
||||
normalizeAgencyItem
|
||||
);
|
||||
var bds = (bdPayload.items || []).map(normalizeBDItem);
|
||||
if (!overview.totalHosts) {
|
||||
overview.totalHosts = agencies.reduce(function (sum, item) {
|
||||
return sum + Number(item.hosts || 0);
|
||||
}, 0);
|
||||
}
|
||||
overview.teamSalary = displayAmount(overviewPayload.salary);
|
||||
data.profile = {
|
||||
name: displayName(profile, 'Super Admin'),
|
||||
uid: displayID(profile),
|
||||
avatar: profile.avatar || '',
|
||||
};
|
||||
data.balance = {
|
||||
available: displayAmount(overviewPayload.salary),
|
||||
};
|
||||
data.overview = overview;
|
||||
data.bdList = bds;
|
||||
data.agencyList = agencies;
|
||||
data.history = [
|
||||
{
|
||||
month: new Date().toISOString().slice(0, 7),
|
||||
status: 'In progress',
|
||||
bdCount: overview.totalBD,
|
||||
agencyCount: overview.totalAgency,
|
||||
totalSalary: overview.teamSalary,
|
||||
totalRecharge: overview.teamRecharge,
|
||||
},
|
||||
];
|
||||
data.inviteRecords = { bd: [], agent: [] };
|
||||
render();
|
||||
})
|
||||
.catch(function (error) {
|
||||
toast(error.message || 'Load failed.');
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
function renderProfile() {
|
||||
$('profileName').textContent = mock.profile.name;
|
||||
$('profileName').textContent = data.profile.name;
|
||||
$('profileUID').textContent = t(
|
||||
'superadmin_center.uid_prefix',
|
||||
'UID: {id}'
|
||||
).replace('{id}', mock.profile.uid);
|
||||
).replace('{id}', data.profile.uid);
|
||||
setImage(
|
||||
$('profileAvatar'),
|
||||
$('profileAvatarFallback'),
|
||||
mock.profile.avatar,
|
||||
mock.profile.name
|
||||
data.profile.avatar,
|
||||
data.profile.name
|
||||
);
|
||||
}
|
||||
|
||||
function renderBalance() {
|
||||
$('availableBalance').textContent = money(mock.balance.available);
|
||||
$('availableBalance').textContent = money(data.balance.available);
|
||||
}
|
||||
|
||||
function summaryCell(label, value) {
|
||||
@ -326,38 +546,38 @@
|
||||
}
|
||||
|
||||
function activeItems() {
|
||||
return state.activeTab === 'agency' ? mock.agencyList : mock.bdList;
|
||||
return state.activeTab === 'agency' ? data.agencyList : data.bdList;
|
||||
}
|
||||
|
||||
function renderTeamSummary() {
|
||||
$('teamSummary').classList.toggle(
|
||||
'is-two',
|
||||
state.activeTab !== 'agency'
|
||||
);
|
||||
var cells =
|
||||
state.activeTab === 'agency'
|
||||
? [
|
||||
summaryCell(
|
||||
t('superadmin_center.agency_number', 'Agency number'),
|
||||
count(mock.overview.totalAgency)
|
||||
count(data.overview.totalAgency)
|
||||
),
|
||||
summaryCell(
|
||||
t('superadmin_center.hosts', 'Hosts'),
|
||||
count(mock.overview.totalHosts)
|
||||
count(data.overview.totalHosts)
|
||||
),
|
||||
summaryCell(
|
||||
t('superadmin_center.team_salary', 'Team salary'),
|
||||
'$' + compactMoney(mock.overview.teamSalary)
|
||||
'$' + compactMoney(data.overview.teamSalary)
|
||||
),
|
||||
]
|
||||
: [
|
||||
summaryCell(
|
||||
t('superadmin_center.bd_number', 'BD number'),
|
||||
count(mock.overview.totalBD)
|
||||
count(data.overview.totalBD)
|
||||
),
|
||||
summaryCell(
|
||||
t('superadmin_center.agencies', 'Agencies'),
|
||||
count(mock.overview.totalAgency)
|
||||
),
|
||||
summaryCell(
|
||||
t('superadmin_center.team_recharge', 'Team recharge'),
|
||||
'$' + compactMoney(mock.overview.teamRecharge)
|
||||
count(data.overview.totalAgency)
|
||||
),
|
||||
];
|
||||
replaceChildren($('teamSummary'), cells);
|
||||
@ -371,6 +591,21 @@
|
||||
var side = document.createElement('div');
|
||||
var salary = document.createElement('strong');
|
||||
var sub = document.createElement('span');
|
||||
var sideValue =
|
||||
item.sideValue ||
|
||||
(item.salary === null || item.salary === undefined
|
||||
? ''
|
||||
: '$' + money(item.salary));
|
||||
var subText =
|
||||
item.sideSub !== undefined
|
||||
? item.sideSub
|
||||
: state.activeTab === 'agency'
|
||||
? count(item.hosts) +
|
||||
' ' +
|
||||
t('superadmin_center.hosts', 'Hosts')
|
||||
: count(item.agencies) +
|
||||
' ' +
|
||||
t('superadmin_center.agencies', 'Agencies');
|
||||
|
||||
row.className = 'member-row';
|
||||
main.className = 'member-main';
|
||||
@ -383,20 +618,13 @@
|
||||
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');
|
||||
salary.textContent = sideValue || subText;
|
||||
sub.textContent = sideValue ? subText : '';
|
||||
|
||||
main.appendChild(name);
|
||||
main.appendChild(meta);
|
||||
side.appendChild(salary);
|
||||
side.appendChild(sub);
|
||||
if (sub.textContent) side.appendChild(sub);
|
||||
row.appendChild(makeAvatar(item));
|
||||
row.appendChild(main);
|
||||
row.appendChild(side);
|
||||
@ -425,19 +653,20 @@
|
||||
}
|
||||
|
||||
function renderHistory() {
|
||||
var previous = data.history[1] || { totalSalary: 0 };
|
||||
replaceChildren($('historySummary'), [
|
||||
summaryCell(
|
||||
t('superadmin_center.total_income', 'Total income'),
|
||||
'$' + money(mock.overview.teamSalary)
|
||||
'$' + money(data.overview.teamSalary)
|
||||
),
|
||||
summaryCell(
|
||||
t('superadmin_center.previous_income', 'Previous income'),
|
||||
'$' + money(mock.history[1].totalSalary)
|
||||
'$' + money(previous.totalSalary)
|
||||
),
|
||||
]);
|
||||
replaceChildren(
|
||||
$('historyList'),
|
||||
mock.history.map(function (item) {
|
||||
data.history.map(function (item) {
|
||||
var row = document.createElement('article');
|
||||
var title = document.createElement('div');
|
||||
var status = document.createElement('span');
|
||||
@ -476,19 +705,27 @@
|
||||
|
||||
function renderDetails() {
|
||||
var item = state.selectedDetails;
|
||||
var summaryRows;
|
||||
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)
|
||||
),
|
||||
]);
|
||||
summaryRows = [summaryCell('ID', item.id)];
|
||||
if (item.salary !== null && item.salary !== undefined) {
|
||||
summaryRows.push(
|
||||
summaryCell(
|
||||
t('superadmin_center.team_salary', 'Team salary'),
|
||||
'$' + money(item.salary)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (item.recharge !== null && item.recharge !== undefined) {
|
||||
summaryRows.push(
|
||||
summaryCell(
|
||||
t('superadmin_center.team_recharge', 'Team recharge'),
|
||||
'$' + money(item.recharge)
|
||||
)
|
||||
);
|
||||
}
|
||||
replaceChildren($('detailsSummary'), summaryRows);
|
||||
replaceChildren($('detailsList'), [
|
||||
createReadonlyLine(
|
||||
state.activeTab === 'agency'
|
||||
@ -518,7 +755,8 @@
|
||||
}
|
||||
|
||||
function inviteRecords() {
|
||||
if (!state.inviteQuery) return mock.inviteRecords[state.inviteMode];
|
||||
if (!state.inviteQuery) return data.inviteRecords[state.inviteMode] || [];
|
||||
if (!state.isMock) return state.inviteSearchResults;
|
||||
var keyword = state.inviteQuery.toLowerCase();
|
||||
return mock.searchPool[state.inviteMode].filter(function (item) {
|
||||
return (
|
||||
@ -532,14 +770,14 @@
|
||||
function renderInvite() {
|
||||
$('inviteModalTitle').textContent = inviteTitle();
|
||||
var status = $('inviteStatus');
|
||||
var records = inviteRecords();
|
||||
status.hidden = !state.inviteStatus;
|
||||
status.textContent = state.inviteStatus;
|
||||
status.className =
|
||||
'invite-status' +
|
||||
(state.inviteStatusType ? ' ' + state.inviteStatusType : '');
|
||||
|
||||
var records = inviteRecords();
|
||||
$('inviteEmpty').hidden = records.length > 0;
|
||||
$('inviteEmpty').hidden = records.length > 0 || !!state.inviteStatus;
|
||||
replaceChildren(
|
||||
$('inviteList'),
|
||||
records.map(function (record) {
|
||||
@ -549,6 +787,7 @@
|
||||
var name = document.createElement('div');
|
||||
var meta = document.createElement('div');
|
||||
var action = document.createElement('button');
|
||||
var submitting = !!state.inviteSubmitting[profile.userId];
|
||||
card.className = 'invite-card';
|
||||
main.className = 'invite-main';
|
||||
name.className = 'invite-name';
|
||||
@ -558,15 +797,13 @@
|
||||
name.textContent = profile.name;
|
||||
meta.textContent = 'ID: ' + profile.account;
|
||||
action.textContent =
|
||||
record.status || t('superadmin_center.invite', 'Invite');
|
||||
action.disabled = !!record.status;
|
||||
record.status ||
|
||||
(submitting
|
||||
? t('superadmin_center.in_progress', 'In progress')
|
||||
: t('superadmin_center.invite', 'Invite'));
|
||||
action.disabled = !!record.status || submitting;
|
||||
action.addEventListener('click', function () {
|
||||
state.inviteStatus = t(
|
||||
'superadmin_center.invite_success',
|
||||
'Invitation submitted.'
|
||||
);
|
||||
state.inviteStatusType = 'success';
|
||||
renderInvite();
|
||||
submitInvite(record, profile);
|
||||
});
|
||||
main.appendChild(name);
|
||||
main.appendChild(meta);
|
||||
@ -578,6 +815,96 @@
|
||||
);
|
||||
}
|
||||
|
||||
function searchInviteProfile(queryValue) {
|
||||
if (state.isMock) {
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
if (!api().user || !api().user.resolveDisplayUserID) {
|
||||
state.inviteStatus = 'API module is not ready.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
state.inviteSearchResults = [];
|
||||
state.inviteStatus = t('superadmin_center.in_progress', 'In progress');
|
||||
state.inviteStatusType = '';
|
||||
renderInvite();
|
||||
api()
|
||||
.user.resolveDisplayUserID(queryValue)
|
||||
.then(function (payload) {
|
||||
var profile = normalizeInviteProfile(payload);
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
state.inviteSearchResults = profile ? [profile] : [];
|
||||
renderInvite();
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.inviteSearchResults = [];
|
||||
state.inviteStatus =
|
||||
error.message ||
|
||||
t('superadmin_center.no_users_found', 'No users found');
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
});
|
||||
}
|
||||
|
||||
function submitInvite(record, profile) {
|
||||
var targetUserID = String(profile.userId || profile.id || '');
|
||||
var centerAPI = api().superadminCenter;
|
||||
if (!targetUserID) return;
|
||||
if (state.isMock) {
|
||||
record.status = 'Success';
|
||||
state.inviteStatus = t(
|
||||
'superadmin_center.invite_success',
|
||||
'Invitation submitted.'
|
||||
);
|
||||
state.inviteStatusType = 'success';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
if (!centerAPI) {
|
||||
state.inviteStatus = 'API module is not ready.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
return;
|
||||
}
|
||||
state.inviteSubmitting[targetUserID] = true;
|
||||
renderInvite();
|
||||
var payload = {
|
||||
command_id: commandID(state.inviteMode, targetUserID),
|
||||
target_user_id: targetUserID,
|
||||
};
|
||||
var request =
|
||||
state.inviteMode === 'agent'
|
||||
? centerAPI.inviteAgency(
|
||||
Object.assign({}, payload, {
|
||||
agency_name: profile.name,
|
||||
})
|
||||
)
|
||||
: centerAPI.inviteBD(payload);
|
||||
request
|
||||
.then(function () {
|
||||
record.status = 'Success';
|
||||
state.inviteStatus = t(
|
||||
'superadmin_center.invite_success',
|
||||
'Invitation submitted.'
|
||||
);
|
||||
state.inviteStatusType = 'success';
|
||||
loadRealData().catch(function () {});
|
||||
renderInvite();
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.inviteStatus = error.message || 'Invite failed.';
|
||||
state.inviteStatusType = 'warning';
|
||||
renderInvite();
|
||||
})
|
||||
.finally(function () {
|
||||
delete state.inviteSubmitting[targetUserID];
|
||||
renderInvite();
|
||||
});
|
||||
}
|
||||
|
||||
function openModal(id) {
|
||||
var modal = $(id);
|
||||
if (!modal) return;
|
||||
@ -631,6 +958,7 @@
|
||||
state.inviteQuery = '';
|
||||
state.inviteStatus = '';
|
||||
state.inviteStatusType = '';
|
||||
state.inviteSearchResults = [];
|
||||
$('inviteSearchInput').value = '';
|
||||
renderInvite();
|
||||
openModal('inviteModal');
|
||||
@ -657,7 +985,12 @@
|
||||
? ''
|
||||
: t('superadmin_center.enter_user_id', 'Enter User ID');
|
||||
state.inviteStatusType = state.inviteQuery ? '' : 'warning';
|
||||
renderInvite();
|
||||
state.inviteSearchResults = [];
|
||||
if (state.inviteQuery) {
|
||||
searchInviteProfile(state.inviteQuery);
|
||||
} else {
|
||||
renderInvite();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key !== 'Escape') return;
|
||||
@ -674,10 +1007,21 @@
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (state.isMock) {
|
||||
applyMockData();
|
||||
} else {
|
||||
applyEmptyData();
|
||||
}
|
||||
render();
|
||||
bindEvents();
|
||||
if (!state.isMock) {
|
||||
loadRealData().catch(function () {});
|
||||
}
|
||||
if (window.HyAppBridge) {
|
||||
window.HyAppBridge.ready({ page: 'superadmin-center', mock: true });
|
||||
window.HyAppBridge.ready({
|
||||
page: 'superadmin-center',
|
||||
mock: state.isMock,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -159,6 +159,10 @@
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.team-summary.is-two {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.history-summary.compact {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
@ -224,6 +224,16 @@
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
<div
|
||||
class="exchange-preview transfer-preview"
|
||||
id="transferPreview"
|
||||
hidden
|
||||
>
|
||||
<span data-i18n="withdraw_exchange.estimated_coins"
|
||||
>Estimated coins</span
|
||||
>
|
||||
<strong id="transferPreviewText"></strong>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -374,6 +384,8 @@
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="../../common/jsbridge.js"></script>
|
||||
<script src="../../common/i18n.js?v=20260602"></script>
|
||||
<script src="./script.js?v=20260602"></script>
|
||||
<script src="../../common/params.js?v=20260604"></script>
|
||||
<script src="../../common/api.js?v=20260604-salary-wallet"></script>
|
||||
<script src="./script.js?v=20260604-bd-wallet"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -2,7 +2,12 @@
|
||||
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,
|
||||
@ -11,12 +16,20 @@
|
||||
isSaving: false,
|
||||
isSubmitting: false,
|
||||
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: 30650.75,
|
||||
balance: mockBalances[salaryAssetType] || 30650.75,
|
||||
paymentInfo: null,
|
||||
payees: {
|
||||
163003: {
|
||||
@ -34,10 +47,10 @@
|
||||
},
|
||||
history: [
|
||||
{
|
||||
key: 'withdraw_exchange.history_host_salary',
|
||||
title: 'Host salary',
|
||||
key: historyTitleKey(),
|
||||
title: historyTitle(),
|
||||
amount: 18400.25,
|
||||
balance: 30650.75,
|
||||
balance: mockBalances[salaryAssetType] || 30650.75,
|
||||
type: 0,
|
||||
date: '2026-06-01 12:10',
|
||||
},
|
||||
@ -91,6 +104,26 @@
|
||||
: '';
|
||||
}
|
||||
|
||||
function normalizeIdentity(value) {
|
||||
value = String(value || '').trim().toUpperCase().replace(/-/g, '_');
|
||||
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() {
|
||||
return window.HyApp && window.HyApp.api
|
||||
? window.HyApp.api.salaryWallet
|
||||
: 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', {
|
||||
@ -109,6 +142,31 @@
|
||||
return Number(input && input.value ? input.value : 0) || 0;
|
||||
}
|
||||
|
||||
function amountText(value) {
|
||||
return moneyInput(value);
|
||||
}
|
||||
|
||||
function usdMinorToNumber(value) {
|
||||
return Number(value || 0) / 100;
|
||||
}
|
||||
|
||||
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 estimatedTransferCoins(value) {
|
||||
var rate = findTransferRate(value);
|
||||
if (!rate) return 0;
|
||||
return Math.round(Number(value || 0) * Number(rate.coin_per_usd || 0));
|
||||
}
|
||||
|
||||
function delay(value) {
|
||||
return new Promise(function (resolve) {
|
||||
window.setTimeout(function () {
|
||||
@ -164,6 +222,23 @@
|
||||
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 isValidTrc20(value) {
|
||||
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || '').trim());
|
||||
}
|
||||
@ -239,9 +314,16 @@
|
||||
copy.className = 'payee-copy';
|
||||
name.className = 'payee-name';
|
||||
id.className = 'payee-id';
|
||||
avatar.textContent = String(payeeName || 'U')
|
||||
.charAt(0)
|
||||
.toUpperCase();
|
||||
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;
|
||||
@ -253,6 +335,17 @@
|
||||
updateSubmit();
|
||||
}
|
||||
|
||||
function renderTransferPreview() {
|
||||
var preview = $('transferPreview');
|
||||
if (!preview) return;
|
||||
var value = inputs.transfer ? Number(inputs.transfer.value || 0) : 0;
|
||||
var coins = estimatedTransferCoins(value);
|
||||
preview.hidden = !(currentMode === 'transfer' && value > 0 && coins > 0);
|
||||
if (!preview.hidden) {
|
||||
$('transferPreviewText').textContent = coins.toLocaleString('en-US');
|
||||
}
|
||||
}
|
||||
|
||||
function renderHistory() {
|
||||
$('salaryHistoryTotal').textContent = '$' + money(state.balance);
|
||||
var list = $('salaryHistoryList');
|
||||
@ -309,14 +402,18 @@
|
||||
}
|
||||
|
||||
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);
|
||||
(currentMode === 'transfer' &&
|
||||
(!state.selectedPayee || transferRateMissing));
|
||||
button.textContent = activeSubmitLabel();
|
||||
button.disabled = disabled;
|
||||
renderTransferPreview();
|
||||
}
|
||||
|
||||
function normalizeAmount(event) {
|
||||
@ -344,7 +441,10 @@
|
||||
'withdraw_exchange.loading',
|
||||
'Loading...'
|
||||
);
|
||||
mockRequest('history').then(function (items) {
|
||||
var historyRequest = isMock
|
||||
? mockRequest('history')
|
||||
: Promise.resolve([]);
|
||||
historyRequest.then(function (items) {
|
||||
state.historyItems = items || [];
|
||||
renderHistory();
|
||||
});
|
||||
@ -404,26 +504,52 @@
|
||||
}
|
||||
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...'
|
||||
);
|
||||
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();
|
||||
});
|
||||
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() {
|
||||
@ -453,6 +579,11 @@
|
||||
'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 '';
|
||||
}
|
||||
|
||||
@ -462,32 +593,82 @@
|
||||
toast(error);
|
||||
return;
|
||||
}
|
||||
if (!isMock && currentMode === 'withdraw') {
|
||||
toast(
|
||||
t(
|
||||
'withdraw_exchange.withdraw_not_available',
|
||||
'Withdraw is not available yet.'
|
||||
)
|
||||
);
|
||||
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'));
|
||||
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 === 'exchange') {
|
||||
state.balance = usdMinorToNumber(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',
|
||||
});
|
||||
}
|
||||
return api().transferToCoinSeller({
|
||||
command_id: commandId('salary-transfer'),
|
||||
identity: identity,
|
||||
target_display_user_id: state.selectedPayee.account,
|
||||
amount_usd: amountText(value),
|
||||
reason: 'salary transfer',
|
||||
});
|
||||
}
|
||||
|
||||
@ -499,8 +680,11 @@
|
||||
var nextParams = new URLSearchParams(window.location.search);
|
||||
nextParams.delete('mode');
|
||||
var query = nextParams.toString();
|
||||
window.location.href =
|
||||
'../host-center/index.html' + (query ? '?' + query : '');
|
||||
var centerPath = '../host-center/index.html';
|
||||
if (identity === 'BD') centerPath = '../bd-center/index.html';
|
||||
if (identity === 'BD_LEADER') centerPath = '../bd-leader/index.html';
|
||||
if (identity === 'AGENCY') centerPath = '../agency-center/index.html';
|
||||
window.location.href = centerPath + (query ? '?' + query : '');
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
@ -564,26 +748,78 @@
|
||||
}
|
||||
|
||||
function init() {
|
||||
identity = normalizeIdentity(identity);
|
||||
bindEvents();
|
||||
setMode(currentMode);
|
||||
renderStaticDynamicText();
|
||||
mockRequest('balance').then(function (balance) {
|
||||
state.balance = balance;
|
||||
renderBalance();
|
||||
updateSubmit();
|
||||
});
|
||||
mockRequest('payment').then(function (payment) {
|
||||
state.paymentInfo = payment;
|
||||
renderPaymentInfo();
|
||||
});
|
||||
loadOverview();
|
||||
loadPaymentInfo();
|
||||
if (window.HyAppBridge) {
|
||||
window.HyAppBridge.ready({
|
||||
page: 'withdraw-exchange',
|
||||
mock: true,
|
||||
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);
|
||||
state.balance = usdMinorToNumber(
|
||||
data.salary && data.salary.available_amount
|
||||
);
|
||||
state.transferRateTiers = data.transfer_rate_tiers || [];
|
||||
renderStaticDynamicText();
|
||||
renderBalance();
|
||||
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;
|
||||
renderPaymentInfo();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
window.addEventListener('hyapp:i18n-ready', renderStaticDynamicText);
|
||||
})();
|
||||
|
||||
@ -379,7 +379,7 @@ input {
|
||||
|
||||
.transfer-search {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(82px, 108px);
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
@ -392,7 +392,7 @@ input {
|
||||
}
|
||||
|
||||
.search-payee-button {
|
||||
min-width: 82px;
|
||||
min-width: 0;
|
||||
min-height: 52px;
|
||||
padding: 0 14px;
|
||||
border-radius: 8px;
|
||||
@ -402,6 +402,10 @@ input {
|
||||
font-weight: 950;
|
||||
}
|
||||
|
||||
.transfer-preview {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.search-payee-button:disabled {
|
||||
background: var(--button-disabled);
|
||||
color: var(--button-disabled-text);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user