This commit is contained in:
zhx 2026-06-04 10:06:57 +08:00
parent df79b94ed9
commit 0d6d3feb1e
22 changed files with 7662 additions and 35 deletions

View File

@ -218,7 +218,38 @@ var default_api = 'https://api.global-interaction.com/';
},
};
var hostAPI = {
var userAPI = {
me: function () {
return request('/api/v1/users/me', { method: 'GET' });
},
overview: function () {
return request('/api/v1/users/me/overview', { method: 'GET' });
},
hostIdentity: function () {
return request('/api/v1/users/me/host-identity', {
method: 'GET',
});
},
roleSummary: function () {
return request('/api/v1/users/me/role-summary', {
method: 'GET',
});
},
};
var walletAPI = {
balances: function (assetTypes) {
var value = Array.isArray(assetTypes)
? assetTypes.join(',')
: assetTypes;
return request('/api/v1/wallet/me/balances', {
method: 'GET',
query: { asset_type: value },
});
},
};
var hostAPI = {
searchAgencies: function (shortId, pageSize) {
return request('/api/v1/host/agencies/search', {
method: 'GET',
@ -230,25 +261,69 @@ var default_api = 'https://api.global-interaction.com/';
method: 'POST',
body: payload || {},
});
},
};
},
};
var levelAPI = {
overview: function () {
return request("/api/v1/levels/me/overview", { method: "GET" });
},
track: function (track) {
return request("/api/v1/levels/tracks/" + encodeURIComponent(track || ""), {
method: "GET",
});
},
rewards: function (query) {
return request("/api/v1/levels/rewards", {
method: "GET",
query: query || {},
});
},
};
var agencyCenterAPI = {
overview: function () {
return request('/api/v1/agency-center/overview', {
method: 'GET',
});
},
hosts: function () {
return request('/api/v1/agency-center/hosts', {
method: 'GET',
});
},
applications: function (status) {
return request('/api/v1/agency-center/applications', {
method: 'GET',
query: { status: status || 'pending' },
});
},
reviewApplication: function (applicationId, payload) {
return request(
'/api/v1/agency-center/applications/' +
encodeURIComponent(applicationId || '') +
'/review',
{
method: 'POST',
body: payload || {},
}
);
},
removeHost: function (hostUserId, payload) {
return request(
'/api/v1/agency-center/hosts/' +
encodeURIComponent(hostUserId || '') +
'/remove',
{
method: 'POST',
body: payload || {},
}
);
},
};
var levelAPI = {
overview: function () {
return request('/api/v1/levels/me/overview', { method: 'GET' });
},
track: function (track) {
return request(
'/api/v1/levels/tracks/' + encodeURIComponent(track || ''),
{
method: 'GET',
}
);
},
rewards: function (query) {
return request('/api/v1/levels/rewards', {
method: 'GET',
query: query || {},
});
},
};
window.HyAppAPI = {
baseURL: resolveBaseURL,
@ -272,10 +347,13 @@ var default_api = 'https://api.global-interaction.com/';
},
delete: function (path, query) {
return request(path, { method: 'DELETE', query: query });
},
vip: vipAPI,
host: hostAPI,
level: levelAPI,
};
},
vip: vipAPI,
user: userAPI,
wallet: walletAPI,
host: hostAPI,
agencyCenter: agencyCenterAPI,
level: levelAPI,
};
clearLocalDevCache();
})();

View File

@ -1,7 +1,7 @@
(function () {
var STORAGE_KEY = 'hyapp_h5_lang';
var DEFAULT_LANG = 'en';
var SUPPORTED = ['en', 'ar', 'tr', 'es'];
var SUPPORTED = ['en', 'ar', 'tr', 'es', 'zh', 'id'];
var scriptURL =
document.currentScript && document.currentScript.src
? document.currentScript.src
@ -23,6 +23,8 @@
if (lang.indexOf('ar') === 0) return 'ar';
if (lang.indexOf('tr') === 0) return 'tr';
if (lang.indexOf('es') === 0) return 'es';
if (lang.indexOf('zh') === 0) return 'zh';
if (lang.indexOf('id') === 0) return 'id';
return SUPPORTED.indexOf(lang) >= 0 ? lang : '';
}
@ -165,8 +167,14 @@
supported: SUPPORTED.slice(),
};
document.addEventListener('DOMContentLoaded', function () {
function init() {
initLanguageMenu();
load(resolveLang());
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

View File

@ -18,6 +18,7 @@
"host_center.loading_agencies": "جار تحميل الوكالات...",
"host_center.no_agency": "لم يتم العثور على وكالة في بلدك.",
"host_center.search_failed": "فشل البحث. حاول لاحقا.",
"host_center.load_failed": "فشل التحميل. حاول لاحقا.",
"host_center.apply_failed": "فشل إرسال الطلب. حاول لاحقا.",
"host_center.apply_success": "تم إرسال الطلب.",
"host_center.applying": "جار الإرسال...",
@ -26,5 +27,161 @@
"host_center.join": "انضم",
"host_center.cancel": "إلغاء",
"host_center.join_confirm_title": "انضم إلى وكالة",
"host_center.join_confirm_message": "هل أنت متأكد أنك تريد الانضمام إلى {agency}؟"
"host_center.join_confirm_message": "هل أنت متأكد أنك تريد الانضمام إلى {agency}؟",
"host_center.verified_host": "مضيف موثق",
"host_center.agency_short_id": "رقم الوكالة: {id}",
"host_center.my_agency": "وكالتي",
"host_center.leave": "مغادرة",
"host_center.available_salary": "راتبي المتاح",
"host_center.salary_details": "تفاصيل الراتب",
"host_center.salary_month_note": "تسوية {month} · {currency}",
"host_center.todays_task": "مهمة اليوم",
"host_center.anchor_type": "نوع المضيف",
"host_center.minutes": "الدقائق",
"host_center.gift_task": "مهمة الهدايا",
"host_center.in_progress": "قيد التنفيذ",
"host_center.level_progress": "تقدم المستوى",
"host_center.current_level": "المستوى الحالي",
"host_center.next_level_need": "المطلوب للمستوى التالي",
"host_center.level_value": "المستوى {level}",
"host_center.platform_policy": "سياسة المنصة",
"host_center.exchange_coins": "تبديل العملات",
"host_center.withdraw_exchange": "السحب/التبديل",
"host_center.transfer": "تحويل",
"host_center.cash_withdraw": "سحب نقدي",
"host_center.bank_accounts": "الحسابات البنكية",
"host_center.leave_agency": "مغادرة الوكالة",
"host_center.leave_confirm_message": "هل أنت متأكد أنك تريد مغادرة وكالتك؟",
"host_center.confirm": "تأكيد",
"host_center.close": "إغلاق",
"host_center.leave_success_mock": "تم إرسال طلب مغادرة الوكالة.",
"host_center.mock_navigation": "انتقال تجريبي: {label}",
"host_center.live_salary": "راتب البث",
"host_center.gift_reward": "مكافأة الهدايا",
"host_center.bonus": "مكافأة",
"host_center.month_june": "يونيو",
"host_center.currency_coins": "عملات",
"withdraw_exchange.page_label": "السحب والتبديل",
"withdraw_exchange.back": "رجوع",
"withdraw_exchange.title": "السحب/التبديل",
"withdraw_exchange.change_language": "تغيير اللغة",
"withdraw_exchange.mode_tabs": "السحب أو التبديل أو التحويل",
"withdraw_exchange.salary": "الراتب",
"withdraw_exchange.salary_history": "سجل الراتب",
"withdraw_exchange.withdraw": "سحب",
"withdraw_exchange.exchange": "تبديل",
"withdraw_exchange.transfer": "تحويل",
"withdraw_exchange.withdraw_amount": "مبلغ السحب",
"withdraw_exchange.exchange_amount": "مبلغ التبديل",
"withdraw_exchange.transfer_to": "تحويل إلى",
"withdraw_exchange.transfer_amount": "مبلغ التحويل",
"withdraw_exchange.search": "بحث",
"withdraw_exchange.searching": "جار البحث...",
"withdraw_exchange.minimum": "الحد الأدنى 50 USD",
"withdraw_exchange.all": "الكل",
"withdraw_exchange.exchange_rate": "سعر التبديل",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} عملة",
"withdraw_exchange.payment_method": "عنوان USDT TRC20",
"withdraw_exchange.payment_method_subtitle": "يتم إرسال السحوبات إلى عنوان USDT TRC20 الخاص بك.",
"withdraw_exchange.no_payment_info": "لا يوجد عنوان USDT",
"withdraw_exchange.no_payment_info_copy": "أدخل عنوان USDT TRC20 قبل السحب.",
"withdraw_exchange.trc20_address": "عنوان TRC20",
"withdraw_exchange.save_address": "حفظ العنوان",
"withdraw_exchange.saving": "جار الحفظ...",
"withdraw_exchange.usdt_only": "USDT فقط",
"withdraw_exchange.withdraw_now": "اسحب الآن",
"withdraw_exchange.exchange_now": "بدّل الآن",
"withdraw_exchange.transfer_now": "حوّل الآن",
"withdraw_exchange.submitting": "جار الإرسال...",
"withdraw_exchange.payee": "المستلم",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "إغلاق",
"withdraw_exchange.loading": "جار التحميل...",
"withdraw_exchange.no_salary_history": "لا يوجد سجل راتب",
"withdraw_exchange.balance": "الرصيد",
"withdraw_exchange.history_host_salary": "راتب المضيف",
"withdraw_exchange.history_exchange_to_golds": "تبديل إلى عملات",
"withdraw_exchange.history_gift_reward": "مكافأة الهدايا",
"withdraw_exchange.mock_user_name": "المستخدم {account}",
"withdraw_exchange.missing_payment_info": "يرجى إضافة عنوان USDT TRC20",
"withdraw_exchange.invalid_address": "يرجى إدخال عنوان USDT TRC20 صالح",
"withdraw_exchange.invalid_amount": "يرجى إدخال مبلغ صالح",
"withdraw_exchange.amount_too_low": "الحد الأدنى لمبلغ السحب هو 50 USD",
"withdraw_exchange.amount_exceeds_balance": "المبلغ يتجاوز الراتب",
"withdraw_exchange.payee_not_found": "لم يتم العثور على المستخدم",
"withdraw_exchange.missing_payee": "يرجى البحث عن مستخدم واختياره",
"withdraw_exchange.address_saved": "تم حفظ العنوان",
"withdraw_exchange.withdraw_success": "تم إرسال طلب السحب",
"withdraw_exchange.exchange_success": "تم التبديل بنجاح",
"withdraw_exchange.transfer_success": "تم التحويل بنجاح",
"bd_center.back": "رجوع",
"bd_center.title": "مركز BD",
"bd_center.change_language": "تغيير اللغة",
"bd_center.role": "BD",
"bd_center.salary": "الراتب",
"bd_center.withdraw_exchange": "Withdraw/Exchange",
"bd_center.invite_agent": "دعوة وكيل",
"bd_center.agency_list": "قائمة الوكالات",
"bd_center.agency_statistics": "إحصائيات الوكالات",
"bd_center.month": "الشهر",
"bd_center.agency_number": "عدد الوكالات",
"bd_center.team_salary": "راتب الفريق",
"bd_center.team_recharge": "شحن الفريق",
"bd_center.recharge": "الشحن",
"bd_center.host": "مضيف",
"bd_center.no_data": "لا توجد بيانات",
"bd_center.enter_user_id": "أدخل معرف المستخدم",
"bd_center.search": "بحث",
"bd_center.no_users_found": "لم يتم العثور على مستخدمين",
"bd_center.success": "نجاح",
"bd_center.pending": "قيد الانتظار",
"bd_center.cancel": "إلغاء",
"bd_center.invite": "دعوة",
"bd_center.application_cancelled": "تم إلغاء الطلب",
"bd_center.invitation_submitted": "تم إرسال الدعوة",
"bd_center.close": "إغلاق",
"bd_center.mock_navigation": "انتقال تجريبي: {label}",
"bd_center.mock_bill_loaded": "تم تحميل فاتورة تجريبية.",
"agency_center.title": "مركز الوكالة",
"agency_center.back": "رجوع",
"agency_center.change_language": "تغيير اللغة",
"agency_center.open_messages": "فتح الرسائل",
"agency_center.work_time": "وقت العمل (دقيقة)",
"agency_center.work_time_short": "العمل",
"agency_center.target": "الهدف",
"agency_center.open_daily_data": "فتح البيانات اليومية",
"agency_center.salary": "الراتب",
"agency_center.withdraw_exchange": "سحب/استبدال",
"agency_center.open_withdraw_exchange": "فتح صفحة السحب والاستبدال",
"agency_center.host_list": "قائمة المضيفين",
"agency_center.salary_bills": "فواتير الراتب",
"agency_center.agency_policy": "سياسة الوكالة",
"agency_center.invite_host": "كيفية دعوة مضيف",
"agency_center.close": "إغلاق",
"agency_center.daily_data": "البيانات اليومية",
"agency_center.gift_points": "نقاط الهدايا",
"agency_center.online_minutes": "دقائق الاتصال",
"agency_center.enter_host_id": "أدخل معرف المضيف",
"agency_center.search": "بحث",
"agency_center.no_hosts": "لا يوجد مضيفون",
"agency_center.remove": "إزالة",
"agency_center.tips": "تنبيه",
"agency_center.cancel": "إلغاء",
"agency_center.confirm": "تأكيد",
"agency_center.remove_confirm_message": "هل تريد إزالة {name} من وكالتك؟",
"agency_center.host_removed": "تمت إزالة المضيف.",
"agency_center.host_salary": "راتب المضيف",
"agency_center.agency_salary": "راتب الوكالة",
"agency_center.total": "المجموع",
"agency_center.messages": "الرسائل",
"agency_center.no_messages": "لا توجد رسائل",
"agency_center.agree": "موافقة",
"agency_center.refuse": "رفض",
"agency_center.approved_application": "تمت الموافقة على طلب {name}.",
"agency_center.rejected_application": "تم رفض طلب {name}.",
"agency_center.mock_navigation": "انتقال تجريبي: {label}",
"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": "أدخل معرف الفريق ثم اضغط إرسال."
}

View File

@ -18,6 +18,7 @@
"host_center.loading_agencies": "Loading agencies...",
"host_center.no_agency": "No agency found in your country.",
"host_center.search_failed": "Search failed. Try again later.",
"host_center.load_failed": "Load failed. Try again later.",
"host_center.apply_failed": "Application failed. Try again later.",
"host_center.apply_success": "Application submitted.",
"host_center.applying": "Submitting...",
@ -26,5 +27,161 @@
"host_center.join": "Join",
"host_center.cancel": "Cancel",
"host_center.join_confirm_title": "Join Agency",
"host_center.join_confirm_message": "Are you sure you want to join {agency}?"
"host_center.join_confirm_message": "Are you sure you want to join {agency}?",
"host_center.verified_host": "Verified Host",
"host_center.agency_short_id": "Agency ID: {id}",
"host_center.my_agency": "My Agency",
"host_center.leave": "Leave",
"host_center.available_salary": "My available salary",
"host_center.salary_details": "Salary details",
"host_center.salary_month_note": "{month} settlement · {currency}",
"host_center.todays_task": "Today's task",
"host_center.anchor_type": "Anchor type",
"host_center.minutes": "Minutes",
"host_center.gift_task": "Gift Task",
"host_center.in_progress": "In progress",
"host_center.level_progress": "Level progress",
"host_center.current_level": "Current level",
"host_center.next_level_need": "Needed for next level",
"host_center.level_value": "Lv. {level}",
"host_center.platform_policy": "Platform policy",
"host_center.exchange_coins": "Exchange coins",
"host_center.withdraw_exchange": "Withdraw/Exchange",
"host_center.transfer": "Transfer",
"host_center.cash_withdraw": "Cash withdraw",
"host_center.bank_accounts": "Bank accounts",
"host_center.leave_agency": "Leave Agency",
"host_center.leave_confirm_message": "Are you sure you want to leave your agency?",
"host_center.confirm": "Confirm",
"host_center.close": "Close",
"host_center.leave_success_mock": "Agency leave submitted.",
"host_center.mock_navigation": "Mock navigation: {label}",
"host_center.live_salary": "Live salary",
"host_center.gift_reward": "Gift reward",
"host_center.bonus": "Bonus",
"host_center.month_june": "June",
"host_center.currency_coins": "Coins",
"withdraw_exchange.page_label": "Withdraw and exchange",
"withdraw_exchange.back": "Back",
"withdraw_exchange.title": "Withdraw/Exchange",
"withdraw_exchange.change_language": "Change language",
"withdraw_exchange.mode_tabs": "Withdraw, exchange, or transfer",
"withdraw_exchange.salary": "salary",
"withdraw_exchange.salary_history": "Salary history",
"withdraw_exchange.withdraw": "Withdraw",
"withdraw_exchange.exchange": "Exchange",
"withdraw_exchange.transfer": "Transfer",
"withdraw_exchange.withdraw_amount": "Withdraw amount",
"withdraw_exchange.exchange_amount": "Exchange amount",
"withdraw_exchange.transfer_to": "Transfer to",
"withdraw_exchange.transfer_amount": "Transfer amount",
"withdraw_exchange.search": "Search",
"withdraw_exchange.searching": "Searching...",
"withdraw_exchange.minimum": "Minimum 50 USD",
"withdraw_exchange.all": "All",
"withdraw_exchange.exchange_rate": "Exchange rate",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} golds",
"withdraw_exchange.payment_method": "USDT TRC20 address",
"withdraw_exchange.payment_method_subtitle": "Withdrawals are sent to your TRC20 USDT address.",
"withdraw_exchange.no_payment_info": "No USDT address",
"withdraw_exchange.no_payment_info_copy": "Fill in a TRC20 USDT address before withdrawing.",
"withdraw_exchange.trc20_address": "TRC20 address",
"withdraw_exchange.save_address": "Save address",
"withdraw_exchange.saving": "Saving...",
"withdraw_exchange.usdt_only": "USDT only",
"withdraw_exchange.withdraw_now": "Withdraw now",
"withdraw_exchange.exchange_now": "Exchange now",
"withdraw_exchange.transfer_now": "Transfer now",
"withdraw_exchange.submitting": "Submitting...",
"withdraw_exchange.payee": "Payee",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "Close",
"withdraw_exchange.loading": "Loading...",
"withdraw_exchange.no_salary_history": "No salary history",
"withdraw_exchange.balance": "Balance",
"withdraw_exchange.history_host_salary": "Host salary",
"withdraw_exchange.history_exchange_to_golds": "Exchange to golds",
"withdraw_exchange.history_gift_reward": "Gift reward",
"withdraw_exchange.mock_user_name": "User {account}",
"withdraw_exchange.missing_payment_info": "Please add a TRC20 USDT address",
"withdraw_exchange.invalid_address": "Please enter a valid TRC20 USDT address",
"withdraw_exchange.invalid_amount": "Please enter a valid amount",
"withdraw_exchange.amount_too_low": "Minimum withdrawal amount is 50 USD",
"withdraw_exchange.amount_exceeds_balance": "Amount exceeds salary",
"withdraw_exchange.payee_not_found": "User not found",
"withdraw_exchange.missing_payee": "Please search and select a user",
"withdraw_exchange.address_saved": "Address saved",
"withdraw_exchange.withdraw_success": "Withdrawal submitted",
"withdraw_exchange.exchange_success": "Exchange success",
"withdraw_exchange.transfer_success": "Transfer success",
"bd_center.back": "Back",
"bd_center.title": "BD Center",
"bd_center.change_language": "Change language",
"bd_center.role": "BD",
"bd_center.salary": "Salary",
"bd_center.withdraw_exchange": "Withdraw/Exchange",
"bd_center.invite_agent": "Invite Agent",
"bd_center.agency_list": "Agency List",
"bd_center.agency_statistics": "Agency Statistics",
"bd_center.month": "Month",
"bd_center.agency_number": "Agency number",
"bd_center.team_salary": "Team salary",
"bd_center.team_recharge": "Team recharge",
"bd_center.recharge": "Recharge",
"bd_center.host": "Host",
"bd_center.no_data": "No data",
"bd_center.enter_user_id": "Enter User ID",
"bd_center.search": "Search",
"bd_center.no_users_found": "No users found",
"bd_center.success": "Success",
"bd_center.pending": "Pending",
"bd_center.cancel": "Cancel",
"bd_center.invite": "Invite",
"bd_center.application_cancelled": "Application cancelled",
"bd_center.invitation_submitted": "Invitation submitted",
"bd_center.close": "Close",
"bd_center.mock_navigation": "Mock navigation: {label}",
"bd_center.mock_bill_loaded": "Mock bill loaded.",
"agency_center.title": "Agency Center",
"agency_center.back": "Back",
"agency_center.change_language": "Change language",
"agency_center.open_messages": "Open messages",
"agency_center.work_time": "Work Time (min)",
"agency_center.work_time_short": "Work",
"agency_center.target": "Target",
"agency_center.open_daily_data": "Open daily data",
"agency_center.salary": "Salary",
"agency_center.withdraw_exchange": "Withdraw/Exchange",
"agency_center.open_withdraw_exchange": "Open withdraw and exchange page",
"agency_center.host_list": "Host List",
"agency_center.salary_bills": "Salary Bills",
"agency_center.agency_policy": "Agency Policy",
"agency_center.invite_host": "How to invite host",
"agency_center.close": "Close",
"agency_center.daily_data": "Daily data",
"agency_center.gift_points": "Gift points",
"agency_center.online_minutes": "Online minutes",
"agency_center.enter_host_id": "Enter host ID",
"agency_center.search": "Search",
"agency_center.no_hosts": "No hosts",
"agency_center.remove": "Remove",
"agency_center.tips": "Tips",
"agency_center.cancel": "Cancel",
"agency_center.confirm": "Confirm",
"agency_center.remove_confirm_message": "Confirm remove {name} from your agency?",
"agency_center.host_removed": "Host removed.",
"agency_center.host_salary": "Host salary",
"agency_center.agency_salary": "Agency salary",
"agency_center.total": "Total",
"agency_center.messages": "Messages",
"agency_center.no_messages": "No messages",
"agency_center.agree": "Agree",
"agency_center.refuse": "Refuse",
"agency_center.approved_application": "Approved {name}'s application.",
"agency_center.rejected_application": "Rejected {name}'s application.",
"agency_center.mock_navigation": "Mock navigation: {label}",
"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."
}

View File

@ -18,6 +18,7 @@
"host_center.loading_agencies": "Cargando agencias...",
"host_center.no_agency": "No se encontró ninguna agencia en tu país.",
"host_center.search_failed": "La búsqueda falló. Inténtalo más tarde.",
"host_center.load_failed": "La carga falló. Inténtalo más tarde.",
"host_center.apply_failed": "La solicitud falló. Inténtalo más tarde.",
"host_center.apply_success": "Solicitud enviada.",
"host_center.applying": "Enviando...",
@ -26,5 +27,161 @@
"host_center.join": "Unirse",
"host_center.cancel": "Cancelar",
"host_center.join_confirm_title": "Unirse a una agencia",
"host_center.join_confirm_message": "¿Seguro que quieres unirte a {agency}?"
"host_center.join_confirm_message": "¿Seguro que quieres unirte a {agency}?",
"host_center.verified_host": "Host verificado",
"host_center.agency_short_id": "ID de agencia: {id}",
"host_center.my_agency": "Mi agencia",
"host_center.leave": "Salir",
"host_center.available_salary": "Mi salario disponible",
"host_center.salary_details": "Detalles del salario",
"host_center.salary_month_note": "Liquidación de {month} · {currency}",
"host_center.todays_task": "Tarea de hoy",
"host_center.anchor_type": "Tipo de host",
"host_center.minutes": "Minutos",
"host_center.gift_task": "Tarea de regalos",
"host_center.in_progress": "En progreso",
"host_center.level_progress": "Progreso de nivel",
"host_center.current_level": "Nivel actual",
"host_center.next_level_need": "Necesario para el siguiente nivel",
"host_center.level_value": "Nv. {level}",
"host_center.platform_policy": "Política de plataforma",
"host_center.exchange_coins": "Cambiar monedas",
"host_center.withdraw_exchange": "Retirar/Intercambiar",
"host_center.transfer": "Transferir",
"host_center.cash_withdraw": "Retiro de efectivo",
"host_center.bank_accounts": "Cuentas bancarias",
"host_center.leave_agency": "Salir de la agencia",
"host_center.leave_confirm_message": "¿Seguro que quieres salir de tu agencia?",
"host_center.confirm": "Confirmar",
"host_center.close": "Cerrar",
"host_center.leave_success_mock": "Solicitud de salida enviada.",
"host_center.mock_navigation": "Navegación mock: {label}",
"host_center.live_salary": "Salario en vivo",
"host_center.gift_reward": "Recompensa de regalos",
"host_center.bonus": "Bono",
"host_center.month_june": "Junio",
"host_center.currency_coins": "Monedas",
"withdraw_exchange.page_label": "Retiro e intercambio",
"withdraw_exchange.back": "Volver",
"withdraw_exchange.title": "Retirar/Intercambiar",
"withdraw_exchange.change_language": "Cambiar idioma",
"withdraw_exchange.mode_tabs": "Retirar, intercambiar o transferir",
"withdraw_exchange.salary": "salario",
"withdraw_exchange.salary_history": "Historial salarial",
"withdraw_exchange.withdraw": "Retirar",
"withdraw_exchange.exchange": "Intercambiar",
"withdraw_exchange.transfer": "Transferir",
"withdraw_exchange.withdraw_amount": "Monto a retirar",
"withdraw_exchange.exchange_amount": "Monto a intercambiar",
"withdraw_exchange.transfer_to": "Transferir a",
"withdraw_exchange.transfer_amount": "Monto a transferir",
"withdraw_exchange.search": "Buscar",
"withdraw_exchange.searching": "Buscando...",
"withdraw_exchange.minimum": "Mínimo 50 USD",
"withdraw_exchange.all": "Todo",
"withdraw_exchange.exchange_rate": "Tipo de cambio",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} monedas",
"withdraw_exchange.payment_method": "Dirección USDT TRC20",
"withdraw_exchange.payment_method_subtitle": "Los retiros se envían a tu dirección USDT TRC20.",
"withdraw_exchange.no_payment_info": "Sin dirección USDT",
"withdraw_exchange.no_payment_info_copy": "Agrega una dirección USDT TRC20 antes de retirar.",
"withdraw_exchange.trc20_address": "Dirección TRC20",
"withdraw_exchange.save_address": "Guardar dirección",
"withdraw_exchange.saving": "Guardando...",
"withdraw_exchange.usdt_only": "Solo USDT",
"withdraw_exchange.withdraw_now": "Retirar ahora",
"withdraw_exchange.exchange_now": "Intercambiar ahora",
"withdraw_exchange.transfer_now": "Transferir ahora",
"withdraw_exchange.submitting": "Enviando...",
"withdraw_exchange.payee": "Destinatario",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "Cerrar",
"withdraw_exchange.loading": "Cargando...",
"withdraw_exchange.no_salary_history": "No hay historial salarial",
"withdraw_exchange.balance": "Saldo",
"withdraw_exchange.history_host_salary": "Salario de host",
"withdraw_exchange.history_exchange_to_golds": "Intercambio a monedas",
"withdraw_exchange.history_gift_reward": "Recompensa de regalos",
"withdraw_exchange.mock_user_name": "Usuario {account}",
"withdraw_exchange.missing_payment_info": "Agrega una dirección USDT TRC20",
"withdraw_exchange.invalid_address": "Ingresa una dirección USDT TRC20 válida",
"withdraw_exchange.invalid_amount": "Ingresa un monto válido",
"withdraw_exchange.amount_too_low": "El monto mínimo de retiro es 50 USD",
"withdraw_exchange.amount_exceeds_balance": "El monto supera el salario",
"withdraw_exchange.payee_not_found": "Usuario no encontrado",
"withdraw_exchange.missing_payee": "Busca y selecciona un usuario",
"withdraw_exchange.address_saved": "Dirección guardada",
"withdraw_exchange.withdraw_success": "Retiro enviado",
"withdraw_exchange.exchange_success": "Intercambio exitoso",
"withdraw_exchange.transfer_success": "Transferencia exitosa",
"bd_center.back": "Volver",
"bd_center.title": "Centro BD",
"bd_center.change_language": "Cambiar idioma",
"bd_center.role": "BD",
"bd_center.salary": "Salario",
"bd_center.withdraw_exchange": "Withdraw/Exchange",
"bd_center.invite_agent": "Invitar agente",
"bd_center.agency_list": "Lista de agencias",
"bd_center.agency_statistics": "Estadísticas de agencias",
"bd_center.month": "Mes",
"bd_center.agency_number": "Número de agencias",
"bd_center.team_salary": "Salario del equipo",
"bd_center.team_recharge": "Recarga del equipo",
"bd_center.recharge": "Recarga",
"bd_center.host": "Host",
"bd_center.no_data": "Sin datos",
"bd_center.enter_user_id": "Ingresa el ID de usuario",
"bd_center.search": "Buscar",
"bd_center.no_users_found": "No se encontraron usuarios",
"bd_center.success": "Éxito",
"bd_center.pending": "Pendiente",
"bd_center.cancel": "Cancelar",
"bd_center.invite": "Invitar",
"bd_center.application_cancelled": "Solicitud cancelada",
"bd_center.invitation_submitted": "Invitación enviada",
"bd_center.close": "Cerrar",
"bd_center.mock_navigation": "Navegación mock: {label}",
"bd_center.mock_bill_loaded": "Factura mock cargada.",
"agency_center.title": "Centro de agencia",
"agency_center.back": "Volver",
"agency_center.change_language": "Cambiar idioma",
"agency_center.open_messages": "Abrir mensajes",
"agency_center.work_time": "Tiempo de trabajo (min)",
"agency_center.work_time_short": "Trabajo",
"agency_center.target": "Objetivo",
"agency_center.open_daily_data": "Abrir datos diarios",
"agency_center.salary": "Salario",
"agency_center.withdraw_exchange": "Retirar/Cambiar",
"agency_center.open_withdraw_exchange": "Abrir retiro y cambio",
"agency_center.host_list": "Lista de hosts",
"agency_center.salary_bills": "Facturas de salario",
"agency_center.agency_policy": "Política de agencia",
"agency_center.invite_host": "Cómo invitar host",
"agency_center.close": "Cerrar",
"agency_center.daily_data": "Datos diarios",
"agency_center.gift_points": "Puntos de regalo",
"agency_center.online_minutes": "Minutos online",
"agency_center.enter_host_id": "Ingresa ID de host",
"agency_center.search": "Buscar",
"agency_center.no_hosts": "No hay hosts",
"agency_center.remove": "Eliminar",
"agency_center.tips": "Aviso",
"agency_center.cancel": "Cancelar",
"agency_center.confirm": "Confirmar",
"agency_center.remove_confirm_message": "¿Confirmas eliminar a {name} de tu agencia?",
"agency_center.host_removed": "Host eliminado.",
"agency_center.host_salary": "Salario de host",
"agency_center.agency_salary": "Salario de agencia",
"agency_center.total": "Total",
"agency_center.messages": "Mensajes",
"agency_center.no_messages": "Sin mensajes",
"agency_center.agree": "Aceptar",
"agency_center.refuse": "Rechazar",
"agency_center.approved_application": "Solicitud de {name} aprobada.",
"agency_center.rejected_application": "Solicitud de {name} rechazada.",
"agency_center.mock_navigation": "Navegación mock: {label}",
"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."
}

View File

@ -18,6 +18,7 @@
"host_center.loading_agencies": "Memuat agency...",
"host_center.no_agency": "Agency tidak ditemukan di negara Anda.",
"host_center.search_failed": "Pencarian gagal. Coba lagi nanti.",
"host_center.load_failed": "Gagal memuat. Coba lagi nanti.",
"host_center.apply_failed": "Pengajuan gagal. Coba lagi nanti.",
"host_center.apply_success": "Pengajuan terkirim.",
"host_center.applying": "Mengirim...",
@ -26,5 +27,161 @@
"host_center.join": "Gabung",
"host_center.cancel": "Batal",
"host_center.join_confirm_title": "Gabung Agency",
"host_center.join_confirm_message": "Apakah Anda yakin ingin bergabung dengan {agency}?"
"host_center.join_confirm_message": "Apakah Anda yakin ingin bergabung dengan {agency}?",
"host_center.verified_host": "Host Terverifikasi",
"host_center.agency_short_id": "ID Agency: {id}",
"host_center.my_agency": "Agency Saya",
"host_center.leave": "Keluar",
"host_center.available_salary": "Gaji tersedia saya",
"host_center.salary_details": "Detail gaji",
"host_center.salary_month_note": "Penyelesaian {month} · {currency}",
"host_center.todays_task": "Tugas hari ini",
"host_center.anchor_type": "Tipe host",
"host_center.minutes": "Menit",
"host_center.gift_task": "Tugas hadiah",
"host_center.in_progress": "Berlangsung",
"host_center.level_progress": "Progress level",
"host_center.current_level": "Level saat ini",
"host_center.next_level_need": "Dibutuhkan ke level berikutnya",
"host_center.level_value": "Lv. {level}",
"host_center.platform_policy": "Kebijakan platform",
"host_center.exchange_coins": "Tukar coin",
"host_center.withdraw_exchange": "Tarik/Tukar",
"host_center.transfer": "Transfer",
"host_center.cash_withdraw": "Tarik tunai",
"host_center.bank_accounts": "Akun bank",
"host_center.leave_agency": "Keluar dari Agency",
"host_center.leave_confirm_message": "Apakah Anda yakin ingin keluar dari agency Anda?",
"host_center.confirm": "Konfirmasi",
"host_center.close": "Tutup",
"host_center.leave_success_mock": "Pengajuan keluar agency terkirim.",
"host_center.mock_navigation": "Navigasi mock: {label}",
"host_center.live_salary": "Gaji live",
"host_center.gift_reward": "Reward hadiah",
"host_center.bonus": "Bonus",
"host_center.month_june": "Juni",
"host_center.currency_coins": "Koin",
"withdraw_exchange.page_label": "Tarik dan tukar",
"withdraw_exchange.back": "Kembali",
"withdraw_exchange.title": "Tarik/Tukar",
"withdraw_exchange.change_language": "Ganti bahasa",
"withdraw_exchange.mode_tabs": "Tarik, tukar, atau transfer",
"withdraw_exchange.salary": "gaji",
"withdraw_exchange.salary_history": "Riwayat gaji",
"withdraw_exchange.withdraw": "Tarik",
"withdraw_exchange.exchange": "Tukar",
"withdraw_exchange.transfer": "Transfer",
"withdraw_exchange.withdraw_amount": "Jumlah penarikan",
"withdraw_exchange.exchange_amount": "Jumlah penukaran",
"withdraw_exchange.transfer_to": "Transfer ke",
"withdraw_exchange.transfer_amount": "Jumlah transfer",
"withdraw_exchange.search": "Cari",
"withdraw_exchange.searching": "Mencari...",
"withdraw_exchange.minimum": "Minimum 50 USD",
"withdraw_exchange.all": "Semua",
"withdraw_exchange.exchange_rate": "Kurs tukar",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} koin",
"withdraw_exchange.payment_method": "Alamat USDT TRC20",
"withdraw_exchange.payment_method_subtitle": "Penarikan dikirim ke alamat USDT TRC20 Anda.",
"withdraw_exchange.no_payment_info": "Belum ada alamat USDT",
"withdraw_exchange.no_payment_info_copy": "Isi alamat USDT TRC20 sebelum menarik.",
"withdraw_exchange.trc20_address": "Alamat TRC20",
"withdraw_exchange.save_address": "Simpan alamat",
"withdraw_exchange.saving": "Menyimpan...",
"withdraw_exchange.usdt_only": "Hanya USDT",
"withdraw_exchange.withdraw_now": "Tarik sekarang",
"withdraw_exchange.exchange_now": "Tukar sekarang",
"withdraw_exchange.transfer_now": "Transfer sekarang",
"withdraw_exchange.submitting": "Mengirim...",
"withdraw_exchange.payee": "Penerima",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "Tutup",
"withdraw_exchange.loading": "Memuat...",
"withdraw_exchange.no_salary_history": "Belum ada riwayat gaji",
"withdraw_exchange.balance": "Saldo",
"withdraw_exchange.history_host_salary": "Gaji host",
"withdraw_exchange.history_exchange_to_golds": "Tukar ke koin",
"withdraw_exchange.history_gift_reward": "Reward hadiah",
"withdraw_exchange.mock_user_name": "Pengguna {account}",
"withdraw_exchange.missing_payment_info": "Tambahkan alamat USDT TRC20",
"withdraw_exchange.invalid_address": "Masukkan alamat USDT TRC20 yang valid",
"withdraw_exchange.invalid_amount": "Masukkan jumlah yang valid",
"withdraw_exchange.amount_too_low": "Jumlah penarikan minimum 50 USD",
"withdraw_exchange.amount_exceeds_balance": "Jumlah melebihi gaji",
"withdraw_exchange.payee_not_found": "Pengguna tidak ditemukan",
"withdraw_exchange.missing_payee": "Cari dan pilih pengguna terlebih dahulu",
"withdraw_exchange.address_saved": "Alamat tersimpan",
"withdraw_exchange.withdraw_success": "Pengajuan penarikan terkirim",
"withdraw_exchange.exchange_success": "Penukaran berhasil",
"withdraw_exchange.transfer_success": "Transfer berhasil",
"bd_center.back": "Kembali",
"bd_center.title": "Pusat BD",
"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.agency_list": "Daftar agency",
"bd_center.agency_statistics": "Statistik agency",
"bd_center.month": "Bulan",
"bd_center.agency_number": "Jumlah agency",
"bd_center.team_salary": "Gaji tim",
"bd_center.team_recharge": "Recharge tim",
"bd_center.recharge": "Recharge",
"bd_center.host": "Host",
"bd_center.no_data": "Tidak ada data",
"bd_center.enter_user_id": "Masukkan ID Pengguna",
"bd_center.search": "Cari",
"bd_center.no_users_found": "Pengguna tidak ditemukan",
"bd_center.success": "Berhasil",
"bd_center.pending": "Menunggu",
"bd_center.cancel": "Batal",
"bd_center.invite": "Undang",
"bd_center.application_cancelled": "Pengajuan dibatalkan",
"bd_center.invitation_submitted": "Undangan terkirim",
"bd_center.close": "Tutup",
"bd_center.mock_navigation": "Navigasi mock: {label}",
"bd_center.mock_bill_loaded": "Tagihan mock dimuat.",
"agency_center.title": "Pusat Agency",
"agency_center.back": "Kembali",
"agency_center.change_language": "Ganti bahasa",
"agency_center.open_messages": "Buka pesan",
"agency_center.work_time": "Waktu Kerja (mnt)",
"agency_center.work_time_short": "Kerja",
"agency_center.target": "Target",
"agency_center.open_daily_data": "Buka data harian",
"agency_center.salary": "Gaji",
"agency_center.withdraw_exchange": "Tarik/Tukar",
"agency_center.open_withdraw_exchange": "Buka halaman tarik dan tukar",
"agency_center.host_list": "Daftar Host",
"agency_center.salary_bills": "Tagihan gaji",
"agency_center.agency_policy": "Kebijakan agency",
"agency_center.invite_host": "Cara mengundang host",
"agency_center.close": "Tutup",
"agency_center.daily_data": "Data harian",
"agency_center.gift_points": "Poin hadiah",
"agency_center.online_minutes": "Menit online",
"agency_center.enter_host_id": "Masukkan ID host",
"agency_center.search": "Cari",
"agency_center.no_hosts": "Tidak ada host",
"agency_center.remove": "Hapus",
"agency_center.tips": "Tips",
"agency_center.cancel": "Batal",
"agency_center.confirm": "Konfirmasi",
"agency_center.remove_confirm_message": "Konfirmasi hapus {name} dari agency Anda?",
"agency_center.host_removed": "Host dihapus.",
"agency_center.host_salary": "Gaji host",
"agency_center.agency_salary": "Gaji agency",
"agency_center.total": "Total",
"agency_center.messages": "Pesan",
"agency_center.no_messages": "Tidak ada pesan",
"agency_center.agree": "Setuju",
"agency_center.refuse": "Tolak",
"agency_center.approved_application": "Pengajuan {name} disetujui.",
"agency_center.rejected_application": "Pengajuan {name} ditolak.",
"agency_center.mock_navigation": "Navigasi mock: {label}",
"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."
}

View File

@ -1,5 +1,5 @@
{
"host_center.title": "Host Center",
"host_center.title": "Host Merkezi",
"host_center.back": "Geri",
"host_center.change_language": "Dili değiştir",
"host_center.profile_name": "Namenamename",
@ -18,6 +18,7 @@
"host_center.loading_agencies": "Ajanslar yükleniyor...",
"host_center.no_agency": "Ülkenizde ajans bulunamadı.",
"host_center.search_failed": "Arama başarısız. Daha sonra deneyin.",
"host_center.load_failed": "Yükleme başarısız. Daha sonra deneyin.",
"host_center.apply_failed": "Başvuru başarısız. Daha sonra deneyin.",
"host_center.apply_success": "Başvuru gönderildi.",
"host_center.applying": "Gönderiliyor...",
@ -26,5 +27,161 @@
"host_center.join": "Katıl",
"host_center.cancel": "İptal",
"host_center.join_confirm_title": "Ajansa Katıl",
"host_center.join_confirm_message": "{agency} için katılmak istediğinizden emin misiniz?"
"host_center.join_confirm_message": "{agency} için katılmak istediğinizden emin misiniz?",
"host_center.verified_host": "Doğrulanmış Host",
"host_center.agency_short_id": "Ajans ID: {id}",
"host_center.my_agency": "Ajansım",
"host_center.leave": "Ayrıl",
"host_center.available_salary": "Kullanılabilir maaşım",
"host_center.salary_details": "Maaş detayları",
"host_center.salary_month_note": "{month} ödemesi · {currency}",
"host_center.todays_task": "Bugünün görevi",
"host_center.anchor_type": "Host türü",
"host_center.minutes": "Dakika",
"host_center.gift_task": "Hediye görevi",
"host_center.in_progress": "Devam ediyor",
"host_center.level_progress": "Seviye ilerlemesi",
"host_center.current_level": "Mevcut seviye",
"host_center.next_level_need": "Sonraki seviye için gereken",
"host_center.level_value": "Sv. {level}",
"host_center.platform_policy": "Platform kuralları",
"host_center.exchange_coins": "Coin değiştir",
"host_center.withdraw_exchange": "Çekim/Değişim",
"host_center.transfer": "Transfer",
"host_center.cash_withdraw": "Nakit çekim",
"host_center.bank_accounts": "Banka hesapları",
"host_center.leave_agency": "Ajanstan ayrıl",
"host_center.leave_confirm_message": "Ajansınızdan ayrılmak istediğinizden emin misiniz?",
"host_center.confirm": "Onayla",
"host_center.close": "Kapat",
"host_center.leave_success_mock": "Ajanstan ayrılma isteği gönderildi.",
"host_center.mock_navigation": "Mock yönlendirme: {label}",
"host_center.live_salary": "Canlı maaşı",
"host_center.gift_reward": "Hediye ödülü",
"host_center.bonus": "Bonus",
"host_center.month_june": "Haziran",
"host_center.currency_coins": "Coin",
"withdraw_exchange.page_label": "Çekim ve değişim",
"withdraw_exchange.back": "Geri",
"withdraw_exchange.title": "Çekim/Değişim",
"withdraw_exchange.change_language": "Dili değiştir",
"withdraw_exchange.mode_tabs": "Çekim, değişim veya transfer",
"withdraw_exchange.salary": "Maaş",
"withdraw_exchange.salary_history": "Maaş geçmişi",
"withdraw_exchange.withdraw": "Çekim",
"withdraw_exchange.exchange": "Değişim",
"withdraw_exchange.transfer": "Transfer",
"withdraw_exchange.withdraw_amount": "Çekim tutarı",
"withdraw_exchange.exchange_amount": "Değişim tutarı",
"withdraw_exchange.transfer_to": "Transfer alıcısı",
"withdraw_exchange.transfer_amount": "Transfer tutarı",
"withdraw_exchange.search": "Ara",
"withdraw_exchange.searching": "Aranıyor...",
"withdraw_exchange.minimum": "Minimum 50 USD",
"withdraw_exchange.all": "Tümü",
"withdraw_exchange.exchange_rate": "Değişim kuru",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} altın",
"withdraw_exchange.payment_method": "USDT TRC20 adresi",
"withdraw_exchange.payment_method_subtitle": "Çekimler TRC20 USDT adresinize gönderilir.",
"withdraw_exchange.no_payment_info": "USDT adresi yok",
"withdraw_exchange.no_payment_info_copy": "Çekimden önce bir TRC20 USDT adresi girin.",
"withdraw_exchange.trc20_address": "TRC20 adresi",
"withdraw_exchange.save_address": "Adresi kaydet",
"withdraw_exchange.saving": "Kaydediliyor...",
"withdraw_exchange.usdt_only": "Sadece USDT",
"withdraw_exchange.withdraw_now": "Şimdi çek",
"withdraw_exchange.exchange_now": "Şimdi değiştir",
"withdraw_exchange.transfer_now": "Şimdi transfer et",
"withdraw_exchange.submitting": "Gönderiliyor...",
"withdraw_exchange.payee": "Alıcı",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "Kapat",
"withdraw_exchange.loading": "Yükleniyor...",
"withdraw_exchange.no_salary_history": "Maaş geçmişi yok",
"withdraw_exchange.balance": "Bakiye",
"withdraw_exchange.history_host_salary": "Host 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}",
"withdraw_exchange.missing_payment_info": "Lütfen bir TRC20 USDT adresi ekleyin",
"withdraw_exchange.invalid_address": "Lütfen geçerli bir TRC20 USDT adresi girin",
"withdraw_exchange.invalid_amount": "Lütfen geçerli bir tutar girin",
"withdraw_exchange.amount_too_low": "Minimum çekim tutarı 50 USD",
"withdraw_exchange.amount_exceeds_balance": "Tutar maaş bakiyesini aşıyor",
"withdraw_exchange.payee_not_found": "Kullanıcı bulunamadı",
"withdraw_exchange.missing_payee": "Lütfen bir kullanıcı arayın ve seçin",
"withdraw_exchange.address_saved": "Adres kaydedildi",
"withdraw_exchange.withdraw_success": "Çekim talebi gönderildi",
"withdraw_exchange.exchange_success": "Değişim başarılı",
"withdraw_exchange.transfer_success": "Transfer başarılı",
"bd_center.back": "Geri",
"bd_center.title": "BD Merkezi",
"bd_center.change_language": "Dili değiştir",
"bd_center.role": "BD",
"bd_center.salary": "Maaş",
"bd_center.withdraw_exchange": "Withdraw/Exchange",
"bd_center.invite_agent": "Ajans Davet Et",
"bd_center.agency_list": "Ajans listesi",
"bd_center.agency_statistics": "Ajans istatistikleri",
"bd_center.month": "Ay",
"bd_center.agency_number": "Ajans sayısı",
"bd_center.team_salary": "Takım maaşı",
"bd_center.team_recharge": "Takım yüklemesi",
"bd_center.recharge": "Yükleme",
"bd_center.host": "Host",
"bd_center.no_data": "Veri yok",
"bd_center.enter_user_id": "Kullanıcı ID gir",
"bd_center.search": "Ara",
"bd_center.no_users_found": "Kullanıcı bulunamadı",
"bd_center.success": "Başarılı",
"bd_center.pending": "Beklemede",
"bd_center.cancel": "İptal",
"bd_center.invite": "Davet et",
"bd_center.application_cancelled": "Başvuru iptal edildi",
"bd_center.invitation_submitted": "Davet gönderildi",
"bd_center.close": "Kapat",
"bd_center.mock_navigation": "Mock yönlendirme: {label}",
"bd_center.mock_bill_loaded": "Mock fatura yüklendi.",
"agency_center.title": "Ajans Merkezi",
"agency_center.back": "Geri",
"agency_center.change_language": "Dili değiştir",
"agency_center.open_messages": "Mesajları aç",
"agency_center.work_time": "Çalışma süresi (dk)",
"agency_center.work_time_short": "Çalışma",
"agency_center.target": "Hedef",
"agency_center.open_daily_data": "Günlük veriyi aç",
"agency_center.salary": "Maaş",
"agency_center.withdraw_exchange": "Çek/Değiştir",
"agency_center.open_withdraw_exchange": "Çekme ve değişim sayfasını aç",
"agency_center.host_list": "Host Listesi",
"agency_center.salary_bills": "Maaş faturaları",
"agency_center.agency_policy": "Ajans politikası",
"agency_center.invite_host": "Host nasıl davet edilir",
"agency_center.close": "Kapat",
"agency_center.daily_data": "Günlük veri",
"agency_center.gift_points": "Hediye puanı",
"agency_center.online_minutes": "Online dakika",
"agency_center.enter_host_id": "Host ID girin",
"agency_center.search": "Ara",
"agency_center.no_hosts": "Host yok",
"agency_center.remove": "Kaldır",
"agency_center.tips": "İpuçları",
"agency_center.cancel": "İptal",
"agency_center.confirm": "Onayla",
"agency_center.remove_confirm_message": "{name} ajansınızdan kaldırılsın mı?",
"agency_center.host_removed": "Host kaldırıldı.",
"agency_center.host_salary": "Host maaşı",
"agency_center.agency_salary": "Ajans maaşı",
"agency_center.total": "Toplam",
"agency_center.messages": "Mesajlar",
"agency_center.no_messages": "Mesaj yok",
"agency_center.agree": "Onayla",
"agency_center.refuse": "Reddet",
"agency_center.approved_application": "{name} başvurusu onaylandı.",
"agency_center.rejected_application": "{name} başvurusu reddedildi.",
"agency_center.mock_navigation": "Mock yönlendirme: {label}",
"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."
}

View File

@ -18,6 +18,7 @@
"host_center.loading_agencies": "公会加载中...",
"host_center.no_agency": "未找到同国家公会。",
"host_center.search_failed": "搜索失败,请稍后重试。",
"host_center.load_failed": "加载失败,请稍后重试。",
"host_center.apply_failed": "申请失败,请稍后重试。",
"host_center.apply_success": "申请已提交。",
"host_center.applying": "提交中...",
@ -26,5 +27,161 @@
"host_center.join": "加入",
"host_center.cancel": "取消",
"host_center.join_confirm_title": "加入公会",
"host_center.join_confirm_message": "确定要加入 {agency} 吗?"
"host_center.join_confirm_message": "确定要加入 {agency} 吗?",
"host_center.verified_host": "已认证主播",
"host_center.agency_short_id": "公会 ID: {id}",
"host_center.my_agency": "我的公会",
"host_center.leave": "退出",
"host_center.available_salary": "我的可用薪资",
"host_center.salary_details": "薪资明细",
"host_center.salary_month_note": "{month} 结算 · {currency}",
"host_center.todays_task": "今日任务",
"host_center.anchor_type": "主播类型",
"host_center.minutes": "时长",
"host_center.gift_task": "礼物任务",
"host_center.in_progress": "进行中",
"host_center.level_progress": "等级进度",
"host_center.current_level": "当前等级",
"host_center.next_level_need": "距离下一级需要",
"host_center.level_value": "Lv. {level}",
"host_center.platform_policy": "平台政策",
"host_center.exchange_coins": "兑换金币",
"host_center.withdraw_exchange": "提现/兑换",
"host_center.transfer": "转账",
"host_center.cash_withdraw": "提现",
"host_center.bank_accounts": "银行卡",
"host_center.leave_agency": "退出公会",
"host_center.leave_confirm_message": "确定要退出当前公会吗?",
"host_center.confirm": "确认",
"host_center.close": "关闭",
"host_center.leave_success_mock": "退出公会申请已提交。",
"host_center.mock_navigation": "Mock 跳转:{label}",
"host_center.live_salary": "直播薪资",
"host_center.gift_reward": "礼物奖励",
"host_center.bonus": "奖金",
"host_center.month_june": "6 月",
"host_center.currency_coins": "金币",
"withdraw_exchange.page_label": "提现和兑换",
"withdraw_exchange.back": "返回",
"withdraw_exchange.title": "提现/兑换",
"withdraw_exchange.change_language": "切换语言",
"withdraw_exchange.mode_tabs": "提现、兑换或转账",
"withdraw_exchange.salary": "薪资",
"withdraw_exchange.salary_history": "薪资历史",
"withdraw_exchange.withdraw": "提现",
"withdraw_exchange.exchange": "兑换",
"withdraw_exchange.transfer": "转账",
"withdraw_exchange.withdraw_amount": "提现金额",
"withdraw_exchange.exchange_amount": "兑换金额",
"withdraw_exchange.transfer_to": "转账给",
"withdraw_exchange.transfer_amount": "转账金额",
"withdraw_exchange.search": "搜索",
"withdraw_exchange.searching": "搜索中...",
"withdraw_exchange.minimum": "最低 50 USD",
"withdraw_exchange.all": "全部",
"withdraw_exchange.exchange_rate": "兑换比例",
"withdraw_exchange.exchange_rate_value": "1$ = {amount} 金币",
"withdraw_exchange.payment_method": "USDT TRC20 address",
"withdraw_exchange.payment_method_subtitle": "提现会发送到你的 TRC20 USDT 地址。",
"withdraw_exchange.no_payment_info": "暂无 USDT 地址",
"withdraw_exchange.no_payment_info_copy": "提现前请先填写 TRC20 USDT 地址。",
"withdraw_exchange.trc20_address": "TRC20 地址",
"withdraw_exchange.save_address": "保存地址",
"withdraw_exchange.saving": "保存中...",
"withdraw_exchange.usdt_only": "仅支持 USDT",
"withdraw_exchange.withdraw_now": "立即提现",
"withdraw_exchange.exchange_now": "立即兑换",
"withdraw_exchange.transfer_now": "立即转账",
"withdraw_exchange.submitting": "提交中...",
"withdraw_exchange.payee": "收款人",
"withdraw_exchange.uid_prefix": "UID:",
"withdraw_exchange.close": "关闭",
"withdraw_exchange.loading": "加载中...",
"withdraw_exchange.no_salary_history": "暂无薪资历史",
"withdraw_exchange.balance": "余额",
"withdraw_exchange.history_host_salary": "主播薪资",
"withdraw_exchange.history_exchange_to_golds": "兑换金币",
"withdraw_exchange.history_gift_reward": "礼物奖励",
"withdraw_exchange.mock_user_name": "用户 {account}",
"withdraw_exchange.missing_payment_info": "请先添加 TRC20 USDT 地址",
"withdraw_exchange.invalid_address": "请输入有效的 TRC20 USDT 地址",
"withdraw_exchange.invalid_amount": "请输入有效金额",
"withdraw_exchange.amount_too_low": "最低提现金额为 50 USD",
"withdraw_exchange.amount_exceeds_balance": "金额超过薪资余额",
"withdraw_exchange.payee_not_found": "未找到用户",
"withdraw_exchange.missing_payee": "请先搜索并选择用户",
"withdraw_exchange.address_saved": "地址已保存",
"withdraw_exchange.withdraw_success": "提现申请已提交",
"withdraw_exchange.exchange_success": "兑换成功",
"withdraw_exchange.transfer_success": "转账成功",
"bd_center.back": "返回",
"bd_center.title": "BD Center",
"bd_center.change_language": "切换语言",
"bd_center.role": "BD",
"bd_center.salary": "薪资",
"bd_center.withdraw_exchange": "Withdraw/Exchange",
"bd_center.invite_agent": "邀请代理",
"bd_center.agency_list": "Agency List",
"bd_center.agency_statistics": "代理统计",
"bd_center.month": "月份",
"bd_center.agency_number": "代理数量",
"bd_center.team_salary": "团队薪资",
"bd_center.team_recharge": "团队充值",
"bd_center.recharge": "充值",
"bd_center.host": "主播",
"bd_center.no_data": "暂无数据",
"bd_center.enter_user_id": "输入用户 ID",
"bd_center.search": "搜索",
"bd_center.no_users_found": "未找到用户",
"bd_center.success": "成功",
"bd_center.pending": "待处理",
"bd_center.cancel": "取消",
"bd_center.invite": "邀请",
"bd_center.application_cancelled": "申请已取消",
"bd_center.invitation_submitted": "邀请已提交",
"bd_center.close": "关闭",
"bd_center.mock_navigation": "Mock 跳转:{label}",
"bd_center.mock_bill_loaded": "Mock 账单已加载。",
"agency_center.title": "Agency Center",
"agency_center.back": "返回",
"agency_center.change_language": "切换语言",
"agency_center.open_messages": "打开消息",
"agency_center.work_time": "Work Time (min)",
"agency_center.work_time_short": "Work",
"agency_center.target": "Target",
"agency_center.open_daily_data": "打开每日数据",
"agency_center.salary": "Salary",
"agency_center.withdraw_exchange": "Withdraw/Exchange",
"agency_center.open_withdraw_exchange": "打开提现兑换页面",
"agency_center.host_list": "Host List",
"agency_center.salary_bills": "Salary Bills",
"agency_center.agency_policy": "Agency Policy",
"agency_center.invite_host": "How to invite host",
"agency_center.close": "关闭",
"agency_center.daily_data": "Daily data",
"agency_center.gift_points": "Gift points",
"agency_center.online_minutes": "Online minutes",
"agency_center.enter_host_id": "Enter host ID",
"agency_center.search": "Search",
"agency_center.no_hosts": "No hosts",
"agency_center.remove": "Remove",
"agency_center.tips": "Tips",
"agency_center.cancel": "Cancel",
"agency_center.confirm": "Confirm",
"agency_center.remove_confirm_message": "Confirm remove {name} from your agency?",
"agency_center.host_removed": "Host removed.",
"agency_center.host_salary": "Host salary",
"agency_center.agency_salary": "Agency salary",
"agency_center.total": "Total",
"agency_center.messages": "Messages",
"agency_center.no_messages": "No messages",
"agency_center.agree": "Agree",
"agency_center.refuse": "Refuse",
"agency_center.approved_application": "Approved {name}'s application.",
"agency_center.rejected_application": "Rejected {name}'s application.",
"agency_center.mock_navigation": "Mock navigation: {label}",
"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."
}

View File

@ -14,7 +14,8 @@
--hy-theme-danger: #d95d72;
--hy-theme-shadow: 0 10px 24px rgba(132, 90, 212, 0.075);
--hy-theme-button: #7d57c7;
--hy-theme-button-disabled: #c5a6f6;
--hy-theme-button-disabled: #eadffc;
--hy-theme-button-disabled-text: #9a8faa;
--hy-theme-button-shadow: 0 8px 18px rgba(125, 87, 199, 0.18);
--hy-theme-button-disabled-shadow: none;
--hy-theme-hero: linear-gradient(

View File

@ -0,0 +1,440 @@
<!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>Agency Center</title>
<link rel="stylesheet" href="../../common/theme.css" />
<link rel="stylesheet" href="../common/center.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="agency-center" aria-label="Agency 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="agency_center.back"
>
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="agency_center.title">Agency 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="agency_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>
</div>
</div>
</nav>
<main class="content">
<section class="card profile-card">
<div class="avatar-shell">
<img class="avatar-image" id="agencyAvatar" alt="" />
<div
class="avatar-fallback"
id="agencyAvatarFallback"
aria-hidden="true"
hidden
>
A
</div>
</div>
<div class="profile-copy">
<div class="name" id="agencyName">Yumi Star Agency</div>
<div class="meta" id="agencyUid">UID: 163003</div>
<div class="agency-line" id="bdName">BD: Mila</div>
</div>
<button
class="message-button"
id="messageButton"
type="button"
aria-label="Open messages"
data-i18n-aria="agency_center.open_messages"
>
<svg viewBox="0 0 28 28" aria-hidden="true">
<path
d="M5 8.5A3.5 3.5 0 0 1 8.5 5h11A3.5 3.5 0 0 1 23 8.5v7A3.5 3.5 0 0 1 19.5 19H12l-5 4v-4.5A3.5 3.5 0 0 1 5 15.3Z"
/>
<path d="M9 10h10M9 14h6" />
</svg>
<span
class="message-unread-dot"
id="messageUnreadDot"
hidden
></span>
</button>
</section>
<section class="card salary-card">
<div class="salary-head">
<div class="salary-title">
<span data-i18n="agency_center.salary">Salary</span>
<svg viewBox="0 0 20 20" aria-hidden="true">
<circle cx="10" cy="10" r="8" />
<path d="M10 9v5M10 6.3v.2" />
</svg>
</div>
<button
class="salary-link"
id="withdrawExchangeButton"
type="button"
data-i18n="agency_center.withdraw_exchange"
>
Withdraw/Exchange
</button>
</div>
<button
class="salary-value"
id="salaryValueButton"
type="button"
aria-label="Open withdraw and exchange page"
data-i18n-aria="agency_center.open_withdraw_exchange"
>
<span class="salary-currency" aria-hidden="true"
>$</span
>
<span id="currentSalary">0.00</span>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
</section>
<section class="card menu-card" aria-label="Agency tools">
<button
class="menu-row"
type="button"
data-action="host-list"
>
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" />
<path
d="M2.5 21c.8-4.3 3.3-6.4 6.5-6.4s5.7 2.1 6.5 6.4"
/>
<path d="M17.8 11.5a3.2 3.2 0 1 0-1.2-6" />
<path d="M17.8 15c2.3.5 3.8 2.1 4.4 5" />
</svg>
</span>
<span
class="menu-label"
data-i18n="agency_center.host_list"
>Host List</span
>
<span class="menu-count" id="hostCount">0</span>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
<button
class="menu-row"
type="button"
data-action="team-bill"
>
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M6 3h12v18H6Z" />
<path d="M9 8h6M9 12h5M9 16h6" />
</svg>
</span>
<span
class="menu-label"
data-i18n="agency_center.salary_bills"
>Salary Bills</span
>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-action="policy">
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M7 3h8l4 4v18H7Z" />
<path d="M15 3v6h5M10 13h7M10 17h5" />
</svg>
</span>
<span
class="menu-label"
data-i18n="agency_center.agency_policy"
>Agency Policy</span
>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-action="invite">
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M12 18v-6" />
<path d="M9 15h6" />
<path
d="M12 3a7 7 0 0 0-7 7c0 5 7 11 7 11s7-6 7-11a7 7 0 0 0-7-7Z"
/>
</svg>
</span>
<span
class="menu-label"
data-i18n="agency_center.invite_host"
>How to invite host</span
>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
</section>
</main>
<div class="home-indicator" aria-hidden="true"></div>
<div class="sheet-modal" id="hostSheet" hidden aria-hidden="true">
<button
class="modal-backdrop"
type="button"
data-close-sheet="hostSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
></button>
<section
class="bottom-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="hostListTitle"
>
<div class="sheet-head">
<h2
id="hostListTitle"
data-i18n="agency_center.host_list"
>
Host List
</h2>
<button
class="sheet-close"
type="button"
data-close-sheet="hostSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
>
&times;
</button>
</div>
<form class="host-search" id="hostSearchForm">
<input
id="hostSearchInput"
type="text"
inputmode="numeric"
autocomplete="off"
placeholder="Enter host ID"
data-i18n-placeholder="agency_center.enter_host_id"
/>
<button type="submit" data-i18n="agency_center.search">
Search
</button>
</form>
<div class="host-list" id="hostList"></div>
<div class="sheet-empty" id="hostListEmpty" hidden></div>
</section>
</div>
<div
class="confirm-modal"
id="removeConfirmModal"
hidden
aria-hidden="true"
>
<button
class="modal-backdrop"
type="button"
data-close-sheet="removeConfirmModal"
aria-label="Cancel"
data-i18n-aria="agency_center.cancel"
></button>
<section
class="confirm-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="removeConfirmTitle"
>
<h2 id="removeConfirmTitle" data-i18n="agency_center.tips">
Tips
</h2>
<p id="removeConfirmText"></p>
<div class="confirm-actions">
<button
class="confirm-cancel"
type="button"
data-close-sheet="removeConfirmModal"
data-i18n="agency_center.cancel"
>
Cancel
</button>
<button
class="confirm-submit"
id="confirmRemoveButton"
type="button"
data-i18n="agency_center.confirm"
>
Confirm
</button>
</div>
</section>
</div>
<div class="sheet-modal" id="billSheet" hidden aria-hidden="true">
<button
class="modal-backdrop"
type="button"
data-close-sheet="billSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
></button>
<section
class="bottom-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="billTitle"
>
<div class="sheet-head">
<h2
id="billTitle"
data-i18n="agency_center.salary_bills"
>
Salary Bills
</h2>
<button
class="sheet-close"
type="button"
data-close-sheet="billSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
>
&times;
</button>
</div>
<div class="bill-list" id="billList"></div>
</section>
</div>
<div class="sheet-modal" id="inviteSheet" hidden aria-hidden="true">
<button
class="modal-backdrop"
type="button"
data-close-sheet="inviteSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
></button>
<section
class="bottom-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="inviteTitle"
>
<div class="sheet-head">
<h2
id="inviteTitle"
data-i18n="agency_center.invite_host"
>
How to invite host
</h2>
<button
class="sheet-close"
type="button"
data-close-sheet="inviteSheet"
aria-label="Close"
data-i18n-aria="agency_center.close"
>
&times;
</button>
</div>
<div class="invite-steps">
<div class="invite-step">
<span>1</span>
<p data-i18n="agency_center.invite_step_1">
Invite users to download APP.
</p>
</div>
<div class="invite-step">
<span>2</span>
<p data-i18n="agency_center.invite_step_2">
Invited users need to log in to the APP.
</p>
</div>
<div class="invite-step">
<span>3</span>
<p data-i18n="agency_center.invite_step_3">
Me > Host Center > Apply to join the team.
</p>
</div>
<div class="invite-step">
<span>4</span>
<p data-i18n="agency_center.invite_step_4">
Enter the team ID, click send to join.
</p>
</div>
</div>
</section>
</div>
<div
class="message-modal"
id="messageModal"
hidden
aria-hidden="true"
>
<button
class="modal-backdrop"
type="button"
data-close-sheet="messageModal"
aria-label="Close"
data-i18n-aria="agency_center.close"
></button>
<section
class="message-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="messageTitle"
>
<div class="sheet-head">
<h2
id="messageTitle"
data-i18n="agency_center.messages"
>
Messages
</h2>
<button
class="sheet-close"
type="button"
data-close-sheet="messageModal"
aria-label="Close"
data-i18n-aria="agency_center.close"
>
&times;
</button>
</div>
<div class="message-list" id="messageList"></div>
<div class="sheet-empty" id="messageEmpty" hidden></div>
</section>
</div>
</div>
<script src="../../common/toast.js"></script>
<script src="../../common/api.js?v=20260603-agency-center"></script>
<script src="../../common/params.js?v=20260603-agency-center"></script>
<script src="../../common/jsbridge.js"></script>
<script src="../../common/i18n.js"></script>
<script src="./script.js"></script>
</body>
</html>

View File

@ -0,0 +1,727 @@
(function () {
var AGENCY_SALARY_USD = 'AGENCY_SALARY_USD';
var HOST_SALARY_USD = 'HOST_SALARY_USD';
var mock = {
profile: {
name: 'Yumi Star Agency',
uid: '163003',
avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
bd: 'Mila BD (880001)',
},
metrics: {
salary: 12880.75,
},
hosts: [
{
id: '163000',
name: 'quick_1780052629537',
avatar: avatarData('Q', '#dbc8ff', '#7d57c7'),
workTime: 86,
gift: 2450,
salary: 3050.25,
},
{
id: '163011',
name: 'Lina_voice',
avatar: avatarData('L', '#f4ebff', '#7d57c7'),
workTime: 124,
gift: 3760,
salary: 4280.5,
},
{
id: '163024',
name: 'Nora_live',
avatar: avatarData('N', '#efe4ff', '#7d57c7'),
workTime: 98,
gift: 2990,
salary: 2298,
},
],
bills: [
{
month: '2026-06',
hostSalary: 8420.2,
agencySalary: 3260.55,
total: 11680.75,
status: 'In progress',
},
{
month: '2026-05',
hostSalary: 13240,
agencySalary: 5140.8,
total: 18380.8,
status: 'Completed',
},
],
messages: [
{
id: 'apply-1001',
applicationId: '1001',
name: 'Mona_host',
account: '163088',
avatar: avatarData('M', '#dbc8ff', '#7d57c7'),
},
{
id: 'apply-1002',
applicationId: '1002',
name: 'Sara_room',
account: '163099',
avatar: avatarData('S', '#f4ebff', '#7d57c7'),
},
],
};
var state = {
hosts: mock.hosts.slice(),
messages: mock.messages.slice(),
hostSearch: '',
pendingRemoveHost: null,
profile: mock.profile,
salary: mock.metrics.salary,
loading: false,
isMock: shouldUseMock(),
};
function $(id) {
return document.getElementById(id);
}
function shouldUseMock() {
var params = new URLSearchParams(window.location.search);
return params.get('mock') === '1' || params.get('mock') === 'true';
}
function avatarData(text, background, foreground) {
var letter = encodeURIComponent(String(text || 'A').charAt(0));
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 toast(message) {
if (window.HyAppToast) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function formatMoney(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function formatCount(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
maximumFractionDigits: 2,
});
}
function toNumber(value) {
var number = Number(value || 0);
return Number.isFinite(number) ? number : 0;
}
function commandID(prefix) {
return (
prefix +
'-' +
Date.now().toString(36) +
'-' +
Math.random().toString(36).slice(2, 8)
);
}
function salaryDisplayAmount(salary, assetType) {
if (!salary) return 0;
if (salary.display_amount !== undefined && salary.display_amount !== null) {
return toNumber(salary.display_amount);
}
if (
assetType === AGENCY_SALARY_USD ||
assetType === HOST_SALARY_USD
) {
return toNumber(salary.available_amount) / 100;
}
return toNumber(salary.available_amount);
}
function initial(text) {
return String(text || '')
.trim()
.charAt(0)
.toUpperCase();
}
function setImage(image, fallback, src, name) {
if (!image || !fallback) return;
fallback.textContent = initial(name) || 'A';
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 = 'small-avatar';
fallback.textContent = initial(item.name) || 'A';
avatar.appendChild(fallback);
if (item.avatar) {
var image = document.createElement('img');
image.src = item.avatar;
image.alt = '';
image.addEventListener('error', function () {
image.remove();
});
avatar.appendChild(image);
}
return avatar;
}
function hasRealAPI() {
return (
!state.isMock &&
window.HyAppAPI &&
window.HyAppAPI.agencyCenter
);
}
function displayName(user, fallback) {
if (!user) return fallback || '-';
return (
user.username ||
user.display_user_id ||
user.user_id ||
fallback ||
'-'
);
}
function normalizeOverview(payload) {
var agency = payload && payload.agency ? payload.agency : {};
var bd = payload && payload.bd ? payload.bd : null;
state.profile = {
name: agency.name || mock.profile.name,
uid: agency.agency_id || mock.profile.uid,
avatar: agency.avatar || '',
bd: bd
? displayName(bd, '') +
(bd.display_user_id ? ' (' + bd.display_user_id + ')' : '')
: '',
};
state.salary = salaryDisplayAmount(
payload ? payload.salary : null,
AGENCY_SALARY_USD
);
}
function normalizeHost(item) {
var userId = String(item.host_user_id || item.user_id || item.id || '');
var displayId = String(item.display_user_id || userId);
return {
id: displayId,
userId: userId,
name: item.username || displayId || userId || '-',
avatar: item.avatar || '',
salary: salaryDisplayAmount(item.salary, HOST_SALARY_USD),
};
}
function normalizeMessage(item) {
var applicant = item.applicant || {};
var applicantUserId = String(
item.applicant_user_id || applicant.user_id || ''
);
return {
id: String(item.application_id || item.id || ''),
applicationId: String(item.application_id || item.id || ''),
name: displayName(applicant, applicantUserId),
account: applicant.display_user_id || applicantUserId,
avatar: applicant.avatar || '',
};
}
function applyAgencyCenterPayload(overview, hosts, applications) {
normalizeOverview(overview || {});
state.hosts = ((hosts && hosts.items) || []).map(normalizeHost);
state.messages = ((applications && applications.items) || []).map(
normalizeMessage
);
}
function loadAgencyCenter() {
if (!hasRealAPI()) return Promise.resolve();
if (window.HyAppParams && window.HyAppParams.parse) {
window.HyAppParams.parse();
}
state.loading = true;
return Promise.all([
window.HyAppAPI.agencyCenter.overview(),
window.HyAppAPI.agencyCenter.hosts(),
window.HyAppAPI.agencyCenter.applications('pending'),
])
.then(function (results) {
applyAgencyCenterPayload(results[0], results[1], results[2]);
render();
})
.catch(function () {
toast(
t(
'agency_center.load_failed',
'Load failed. Try again later.'
)
);
})
.finally(function () {
state.loading = false;
});
}
function renderProfile() {
var profile = state.profile || mock.profile;
$('agencyName').textContent = profile.name;
$('agencyUid').textContent = 'UID: ' + profile.uid;
$('bdName').textContent = profile.bd ? 'BD: ' + profile.bd : '';
setImage(
$('agencyAvatar'),
$('agencyAvatarFallback'),
profile.avatar,
profile.name
);
}
function renderSalary() {
$('currentSalary').textContent = formatMoney(state.salary);
}
function renderHostCount() {
$('hostCount').textContent = formatCount(state.hosts.length);
}
function renderUnread() {
var dot = $('messageUnreadDot');
if (dot) dot.hidden = state.messages.length <= 0;
}
function filteredHosts() {
var keyword = state.hostSearch.trim();
if (!keyword) return state.hosts;
return state.hosts.filter(function (host) {
return (
host.id.indexOf(keyword) >= 0 ||
String(host.userId || '').indexOf(keyword) >= 0 ||
host.name.toLowerCase().indexOf(keyword.toLowerCase()) >= 0
);
});
}
function renderHostList() {
var list = $('hostList');
var empty = $('hostListEmpty');
var hosts = filteredHosts();
list.textContent = '';
empty.hidden = hosts.length > 0;
empty.textContent = t('agency_center.no_hosts', 'No hosts');
hosts.forEach(function (host) {
var row = document.createElement('div');
var user = document.createElement('div');
var copy = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var remove = document.createElement('button');
row.className = 'host-row';
user.className = 'host-user';
copy.className = 'host-copy';
name.className = 'host-name';
meta.className = 'host-meta';
remove.className = 'remove-host-button';
remove.type = 'button';
name.textContent = host.name;
meta.textContent =
'UID: ' +
host.id +
' · ' +
t('agency_center.salary', 'Salary') +
': ' +
'$' +
formatMoney(host.salary);
remove.textContent = t('agency_center.remove', 'Remove');
remove.addEventListener('click', function () {
state.pendingRemoveHost = host;
renderRemoveConfirm();
openSheet('removeConfirmModal');
});
user.appendChild(makeAvatar(host));
copy.appendChild(name);
copy.appendChild(meta);
user.appendChild(copy);
row.appendChild(user);
row.appendChild(remove);
list.appendChild(row);
});
}
function renderRemoveConfirm() {
var host = state.pendingRemoveHost;
var text = $('removeConfirmText');
if (!text) return;
text.textContent = t(
'agency_center.remove_confirm_message',
'Confirm remove {name} from your agency?'
).replace('{name}', host ? host.name : '-');
}
function confirmRemoveHost() {
var host = state.pendingRemoveHost;
if (!host) return;
if (hasRealAPI()) {
window.HyAppAPI.agencyCenter
.removeHost(host.userId || host.id, {
command_id: commandID('agency-remove-host'),
reason: 'agency_center',
})
.then(function () {
state.pendingRemoveHost = null;
closeSheet('removeConfirmModal');
toast(t('agency_center.host_removed', 'Host removed.'));
return loadAgencyCenter();
})
.catch(function (error) {
if (error && error.status === 409) return;
toast(
t(
'agency_center.remove_failed',
'Remove failed. Try again later.'
)
);
});
return;
}
state.hosts = state.hosts.filter(function (item) {
return item.id !== host.id;
});
state.pendingRemoveHost = null;
closeSheet('removeConfirmModal');
renderHostCount();
renderHostList();
toast(t('agency_center.host_removed', 'Host removed.'));
}
function createBillCell(label, value) {
var cell = document.createElement('div');
var title = document.createElement('span');
var strong = document.createElement('strong');
cell.className = 'bill-cell';
title.textContent = label;
strong.textContent = value;
cell.appendChild(title);
cell.appendChild(strong);
return cell;
}
function renderBillList() {
var list = $('billList');
list.textContent = '';
mock.bills.forEach(function (bill) {
var row = document.createElement('div');
var month = document.createElement('div');
var values = document.createElement('div');
row.className = 'bill-row';
month.className = 'bill-month';
values.className = 'bill-values';
month.textContent = bill.month + ' · ' + bill.status;
values.appendChild(
createBillCell(
t('agency_center.host_salary', 'Host salary'),
formatMoney(bill.hostSalary)
)
);
values.appendChild(
createBillCell(
t('agency_center.agency_salary', 'Agency salary'),
formatMoney(bill.agencySalary)
)
);
values.appendChild(
createBillCell(
t('agency_center.total', 'Total'),
formatMoney(bill.total)
)
);
row.appendChild(month);
row.appendChild(values);
list.appendChild(row);
});
}
function renderMessages() {
var list = $('messageList');
var empty = $('messageEmpty');
list.textContent = '';
empty.hidden = state.messages.length > 0;
empty.textContent = t('agency_center.no_messages', 'No messages');
state.messages.forEach(function (message) {
var card = document.createElement('div');
var user = document.createElement('div');
var copy = document.createElement('div');
var name = document.createElement('div');
var id = document.createElement('div');
var actions = document.createElement('div');
var agree = document.createElement('button');
var refuse = document.createElement('button');
card.className = 'message-card';
user.className = 'message-user';
copy.className = 'message-copy';
name.className = 'message-name';
id.className = 'message-id';
actions.className = 'message-actions';
agree.className = 'message-action agree';
refuse.className = 'message-action refuse';
agree.type = 'button';
refuse.type = 'button';
name.textContent = message.name;
id.textContent = 'ID: ' + message.account;
agree.textContent = t('agency_center.agree', 'Agree');
refuse.textContent = t('agency_center.refuse', 'Refuse');
agree.addEventListener('click', function () {
processMessage(message, 'agree');
});
refuse.addEventListener('click', function () {
processMessage(message, 'refuse');
});
user.appendChild(makeAvatar(message));
copy.appendChild(name);
copy.appendChild(id);
user.appendChild(copy);
actions.appendChild(agree);
actions.appendChild(refuse);
card.appendChild(user);
card.appendChild(actions);
list.appendChild(card);
});
}
function processMessage(message, action) {
if (hasRealAPI()) {
var decision = action === 'agree' ? 'approve' : 'reject';
window.HyAppAPI.agencyCenter
.reviewApplication(message.applicationId || message.id, {
command_id: commandID('agency-review-application'),
decision: decision,
reason: 'agency_center',
})
.then(function () {
var key =
action === 'agree'
? 'agency_center.approved_application'
: 'agency_center.rejected_application';
var fallback =
action === 'agree'
? "Approved {name}'s application."
: "Rejected {name}'s application.";
toast(t(key, fallback).replace('{name}', message.name));
return loadAgencyCenter();
})
.catch(function (error) {
if (error && error.status === 409) return;
toast(
t(
'agency_center.review_failed',
'Review failed. Try again later.'
)
);
});
return;
}
state.messages = state.messages.filter(function (item) {
return item.id !== message.id;
});
renderUnread();
renderMessages();
var key =
action === 'agree'
? 'agency_center.approved_application'
: 'agency_center.rejected_application';
var fallback =
action === 'agree'
? "Approved {name}'s application."
: "Rejected {name}'s application.";
toast(t(key, fallback).replace('{name}', message.name));
}
function openSheet(id) {
var sheet = $(id);
if (!sheet) return;
sheet.hidden = false;
sheet.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
}
function closeSheet(id) {
var sheet = $(id);
if (!sheet) return;
sheet.hidden = true;
sheet.setAttribute('aria-hidden', 'true');
var hasOpen = Array.prototype.some.call(
document.querySelectorAll(
'.sheet-modal, .message-modal, .confirm-modal'
),
function (modal) {
return !modal.hidden;
}
);
document.body.classList.toggle('modal-open', hasOpen);
}
function closeAllSheets() {
document
.querySelectorAll('.sheet-modal, .message-modal, .confirm-modal')
.forEach(function (sheet) {
sheet.hidden = true;
sheet.setAttribute('aria-hidden', 'true');
});
state.pendingRemoveHost = null;
document.body.classList.remove('modal-open');
}
function navigateToWithdrawExchange() {
var params = new URLSearchParams(window.location.search);
if (!params.has('mode')) params.set('mode', 'transfer');
window.location.href =
'../withdraw-exchange/index.html?' + params.toString();
}
function bindEvents() {
$('backButton').addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
});
$('messageButton').addEventListener('click', function () {
renderMessages();
openSheet('messageModal');
});
$('withdrawExchangeButton').addEventListener(
'click',
navigateToWithdrawExchange
);
$('salaryValueButton').addEventListener(
'click',
navigateToWithdrawExchange
);
$('hostSearchForm').addEventListener('submit', function (event) {
event.preventDefault();
state.hostSearch = $('hostSearchInput').value || '';
renderHostList();
});
$('confirmRemoveButton').addEventListener('click', confirmRemoveHost);
document
.querySelectorAll('[data-close-sheet]')
.forEach(function (node) {
node.addEventListener('click', function () {
if (
node.getAttribute('data-close-sheet') ===
'removeConfirmModal'
) {
state.pendingRemoveHost = null;
}
closeSheet(node.getAttribute('data-close-sheet'));
});
});
document.querySelectorAll('.menu-row').forEach(function (button) {
button.addEventListener('click', function () {
var action = button.getAttribute('data-action');
if (action === 'host-list') {
state.hostSearch = '';
$('hostSearchInput').value = '';
renderHostList();
openSheet('hostSheet');
return;
}
if (action === 'team-bill') {
renderBillList();
openSheet('billSheet');
return;
}
if (action === 'invite') {
openSheet('inviteSheet');
return;
}
toast(
t(
'agency_center.mock_navigation',
'Mock navigation: {label}'
).replace(
'{label}',
t('agency_center.agency_policy', 'Agency Policy')
)
);
});
});
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape') closeAllSheets();
});
}
function render() {
renderProfile();
renderSalary();
renderHostCount();
renderUnread();
renderHostList();
renderBillList();
renderMessages();
}
function initPage() {
render();
bindEvents();
loadAgencyCenter();
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'agency-center',
mock: state.isMock,
});
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPage);
} else {
initPage();
}
window.addEventListener('hyapp:i18n-ready', function () {
render();
});
})();

View File

@ -0,0 +1,932 @@
:root {
--page-bg: var(--hy-theme-bg, #fbf8ff);
--card-bg: var(--hy-theme-surface, rgba(255, 255, 255, 0.96));
--text: var(--hy-theme-text, #282333);
--muted: var(--hy-theme-muted, #8d879a);
--line: var(--hy-theme-line, #f0e8fb);
--primary: var(--hy-theme-primary, #dbc8ff);
--primary-soft: var(--hy-theme-primary-soft, #f4ebff);
--primary-deep: var(--hy-theme-primary-deep, #7d57c7);
--button: var(--hy-theme-button, #7d57c7);
--danger: var(--hy-theme-danger, #d95d72);
--shadow: var(--hy-theme-shadow, 0 10px 24px rgba(132, 90, 212, 0.075));
}
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
body {
display: flex;
justify-content: center;
background: #111;
color: var(--text);
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif;
}
button,
input {
font: inherit;
}
button {
border: 0;
padding: 0;
background: transparent;
color: inherit;
}
button:focus,
input:focus {
outline: none;
}
button:focus-visible,
input:focus-visible {
outline: 2px solid rgba(125, 87, 199, 0.32);
outline-offset: 2px;
}
[hidden] {
display: none !important;
}
.agency-center {
position: relative;
width: 100%;
max-width: 430px;
min-height: 100vh;
min-height: 100dvh;
overflow: hidden;
background:
linear-gradient(
145deg,
rgba(255, 255, 255, 0.82),
rgba(250, 246, 255, 0) 42%
),
var(--page-bg);
}
.hero-bg {
position: absolute;
inset: 0 0 auto;
height: 215px;
background: var(
--hy-theme-hero,
linear-gradient(
151deg,
#f0e6ff 0%,
#fffbff 58%,
rgba(251, 248, 255, 0.88) 100%
)
);
clip-path: polygon(0 0, 100% 0, 100% 76%, 70% 47%, 40% 58%, 0 78%);
}
.title-bar,
.content,
.home-indicator {
position: relative;
z-index: 1;
}
.title-bar {
display: grid;
grid-template-columns: 52px 1fr 52px;
align-items: center;
z-index: 3;
height: 60px;
padding: 0 14px;
direction: ltr;
}
.title-bar h1 {
margin: 0;
color: var(--text);
font-size: 22px;
font-weight: 900;
line-height: 1;
text-align: center;
}
.back-button {
display: flex;
align-items: center;
justify-content: flex-start;
width: 44px;
height: 44px;
}
.back-button svg {
width: 28px;
height: 28px;
}
.back-button path {
fill: none;
stroke: var(--text);
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 3;
}
.language-switcher {
position: relative;
justify-self: end;
}
.language-button {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 30px;
border: 1px solid rgba(35, 40, 46, 0.12);
border-radius: 15px;
background: rgba(255, 255, 255, 0.68);
color: var(--text);
font-size: 13px;
font-weight: 900;
box-shadow: 0 4px 12px rgba(43, 118, 107, 0.08);
}
.language-menu {
position: absolute;
z-index: 20;
top: calc(100% + 7px);
right: 0;
display: grid;
gap: 2px;
min-width: 72px;
padding: 5px;
border: 1px solid rgba(35, 40, 46, 0.1);
border-radius: 8px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 10px 26px rgba(36, 46, 60, 0.14);
}
.language-menu button {
min-height: 34px;
border-radius: 6px;
color: var(--text);
font-size: 12px;
font-weight: 900;
}
.language-menu button.is-active {
background: var(--primary-soft);
color: var(--primary-deep);
}
.content {
display: flex;
flex-direction: column;
gap: 15px;
padding: 8px 14px 90px;
}
.card {
width: 100%;
border-radius: 8px;
background: var(--card-bg);
box-shadow: var(--shadow);
}
.profile-card {
display: flex;
align-items: center;
min-height: 103px;
padding: 16px 18px 16px 24px;
}
.avatar-shell {
position: relative;
width: 64px;
height: 64px;
flex: 0 0 64px;
}
.avatar-image,
.avatar-fallback {
width: 64px;
height: 64px;
border-radius: 50%;
}
.avatar-image {
display: block;
object-fit: cover;
}
.avatar-fallback {
display: flex;
align-items: center;
justify-content: center;
background: var(--primary);
color: var(--primary-deep);
font-size: 24px;
font-weight: 950;
}
.profile-copy {
min-width: 0;
margin-left: 20px;
}
.name {
overflow: hidden;
color: var(--text);
font-size: 20px;
font-weight: 900;
line-height: 1.1;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta,
.agency-line {
overflow: hidden;
color: var(--muted);
font-size: 13px;
font-weight: 750;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta {
margin-top: 6px;
}
.agency-line {
margin-top: 7px;
}
.message-button {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
flex: 0 0 42px;
margin-left: auto;
border-radius: 50%;
background: var(--primary-soft);
color: var(--primary-deep);
}
.message-button svg {
width: 25px;
height: 25px;
}
.message-button path {
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2.2;
}
.message-unread-dot {
position: absolute;
top: 7px;
right: 7px;
width: 9px;
height: 9px;
border: 2px solid #fff;
border-radius: 50%;
background: #ff3b30;
}
.salary-card {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 113px;
padding: 18px 24px;
}
.salary-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.salary-title {
display: flex;
align-items: center;
min-width: 0;
color: var(--text);
font-size: 17px;
font-weight: 900;
}
.salary-title svg {
width: 17px;
height: 17px;
margin-left: 7px;
}
.salary-title circle,
.salary-title path {
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-width: 2;
}
.salary-link {
flex: 0 0 auto;
color: var(--primary-deep);
font-size: 13px;
font-weight: 900;
white-space: nowrap;
}
.salary-value {
display: flex;
align-items: center;
max-width: 100%;
margin-top: 14px;
color: #23272d;
font-size: 34px;
font-weight: 950;
line-height: 1.05;
}
.salary-currency {
flex: 0 0 auto;
margin-right: 6px;
color: #f2ad2c;
font-size: 28px;
font-weight: 950;
line-height: 1;
}
.chevron {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 8px;
color: var(--muted);
font-size: 24px;
font-weight: 500;
line-height: 0.8;
}
.menu-card {
display: grid;
padding: 0 16px;
}
.menu-row {
display: grid;
grid-template-columns: 38px minmax(0, 1fr) auto 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;
}
.menu-count {
color: var(--muted);
font-size: 13px;
font-weight: 900;
white-space: nowrap;
}
.sheet-modal,
.message-modal,
.confirm-modal {
position: fixed;
z-index: 24;
inset: 0;
display: flex;
justify-content: center;
}
.sheet-modal {
align-items: flex-end;
padding: 0 0 env(safe-area-inset-bottom);
}
.message-modal,
.confirm-modal {
align-items: center;
padding: 18px;
}
.confirm-modal {
z-index: 30;
}
.modal-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 21, 28, 0.38);
}
.bottom-sheet {
position: relative;
display: flex;
flex-direction: column;
width: min(430px, 100%);
max-height: 80vh;
max-height: 80dvh;
overflow: hidden;
border-radius: 16px 16px 0 0;
background: #fff;
box-shadow: 0 -14px 34px rgba(23, 31, 42, 0.16);
}
.message-dialog,
.confirm-dialog {
position: relative;
overflow: hidden;
background: #fff;
box-shadow: 0 18px 44px rgba(23, 31, 42, 0.2);
}
.message-dialog {
display: flex;
flex-direction: column;
width: min(394px, 100%);
max-height: 78vh;
max-height: 78dvh;
border-radius: 14px;
}
.confirm-dialog {
display: grid;
gap: 14px;
width: min(342px, 100%);
padding: 20px 18px 18px;
border-radius: 14px;
}
.confirm-dialog h2,
.confirm-dialog p {
margin: 0;
text-align: center;
}
.confirm-dialog h2 {
color: var(--text);
font-size: 18px;
font-weight: 950;
line-height: 1.2;
}
.confirm-dialog p {
color: var(--muted);
font-size: 14px;
font-weight: 800;
line-height: 1.35;
}
.confirm-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 4px;
}
.confirm-cancel,
.confirm-submit {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 42px;
border-radius: 8px;
font-size: 14px;
font-weight: 900;
}
.confirm-cancel {
border: 1px solid var(--line);
background: #fff;
color: var(--text);
}
.confirm-submit {
background: var(--button);
color: #fff;
box-shadow: var(
--hy-theme-button-shadow,
0 8px 18px rgba(125, 87, 199, 0.18)
);
}
.sheet-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
min-height: 58px;
padding: 16px 18px 12px;
border-bottom: 1px solid var(--line);
}
.sheet-head h2 {
margin: 0;
color: var(--text);
font-size: 18px;
font-weight: 950;
line-height: 1.2;
}
.sheet-close {
display: flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: var(--primary-soft);
color: var(--primary-deep);
font-size: 25px;
font-weight: 500;
line-height: 1;
}
.host-list,
.bill-list,
.message-list,
.invite-steps {
display: grid;
gap: 10px;
min-height: 0;
overflow-y: auto;
padding: 14px 18px max(18px, env(safe-area-inset-bottom));
-webkit-overflow-scrolling: touch;
}
.host-row,
.bill-row,
.message-card,
.invite-step {
border: 1px solid var(--line);
border-radius: 8px;
background: #fbfcfc;
}
.bill-row {
display: grid;
gap: 10px;
padding: 12px;
}
.bill-month {
color: var(--text);
font-size: 15px;
font-weight: 950;
line-height: 1.2;
}
.bill-values {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.bill-cell span {
display: block;
overflow: hidden;
color: var(--muted);
font-size: 12px;
font-weight: 800;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.bill-cell strong {
display: block;
margin-top: 4px;
overflow-wrap: anywhere;
color: #292d33;
font-size: 16px;
font-weight: 950;
line-height: 1.2;
}
.host-search {
display: grid;
grid-template-columns: minmax(0, 1fr) 82px;
gap: 10px;
padding: 14px 18px 0;
}
.host-search input {
min-width: 0;
height: 42px;
border: 1px solid var(--line);
border-radius: 8px;
background: #fff;
color: var(--text);
padding: 0 12px;
font-size: 14px;
font-weight: 800;
}
.host-search input::placeholder {
color: #b7b3bf;
}
.host-search button,
.remove-host-button,
.message-action {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 34px;
border-radius: 8px;
font-size: 12px;
font-weight: 950;
white-space: nowrap;
}
.host-search button {
min-height: 42px;
background: var(--button);
color: #fff;
box-shadow: var(
--hy-theme-button-shadow,
0 8px 18px rgba(125, 87, 199, 0.18)
);
}
.host-row,
.message-card {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
padding: 12px;
}
.host-user,
.message-user {
display: flex;
align-items: center;
min-width: 0;
}
.small-avatar {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 46px;
height: 46px;
flex: 0 0 46px;
overflow: hidden;
border-radius: 50%;
background: var(--primary);
color: var(--primary-deep);
font-size: 18px;
font-weight: 950;
}
.small-avatar img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.host-copy,
.message-copy {
min-width: 0;
margin-left: 12px;
}
.host-name,
.message-name {
overflow: hidden;
color: var(--text);
font-size: 15px;
font-weight: 950;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.host-meta,
.message-id {
margin-top: 5px;
overflow: hidden;
color: var(--muted);
font-size: 12px;
font-weight: 800;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.remove-host-button {
min-width: 58px;
padding: 0 10px;
background: #fff;
border: 1px solid rgba(217, 93, 114, 0.28);
color: var(--danger);
}
.message-actions {
display: flex;
gap: 6px;
}
.message-action {
min-width: 54px;
padding: 0 10px;
}
.message-action.agree {
background: var(--button);
color: #fff;
}
.message-action.refuse {
background: #f1edf8;
color: var(--text);
}
.invite-step {
display: grid;
grid-template-columns: 30px minmax(0, 1fr);
gap: 12px;
align-items: start;
padding: 13px 12px;
color: #3d4148;
font-size: 14px;
font-weight: 800;
line-height: 1.42;
}
.invite-step span {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
border-radius: 50%;
background: var(--primary-soft);
color: var(--primary-deep);
font-size: 14px;
font-weight: 950;
line-height: 1;
}
.invite-step p {
margin: 0;
}
.sheet-empty {
display: flex;
align-items: center;
justify-content: center;
min-height: 112px;
margin: 14px 18px max(18px, env(safe-area-inset-bottom));
border: 1px dashed var(--line);
border-radius: 8px;
color: var(--muted);
font-size: 14px;
font-weight: 850;
text-align: center;
}
.modal-open {
overflow: hidden;
}
.home-indicator {
position: absolute;
left: 50%;
bottom: 8px;
width: 154px;
height: 5px;
border-radius: 999px;
background: #050506;
transform: translateX(-50%);
}
[dir='rtl'] .content,
[dir='rtl'] .bottom-sheet,
[dir='rtl'] .message-dialog,
[dir='rtl'] .confirm-dialog {
direction: rtl;
}
[dir='rtl'] .profile-copy {
margin-right: 20px;
margin-left: 0;
text-align: right;
}
[dir='rtl'] .message-button {
margin-right: auto;
margin-left: 0;
}
[dir='rtl'] .menu-row {
text-align: right;
}
[dir='rtl'] .chevron {
transform: rotate(180deg);
}
[dir='rtl'] .host-copy,
[dir='rtl'] .message-copy {
margin-right: 12px;
margin-left: 0;
text-align: right;
}
@media (max-width: 360px) {
.content {
padding-right: 12px;
padding-left: 12px;
}
.profile-card,
.salary-card {
padding-right: 18px;
padding-left: 18px;
}
.profile-copy {
margin-left: 14px;
}
.bill-values {
grid-template-columns: 1fr;
}
.salary-value {
font-size: 29px;
}
}

View File

@ -0,0 +1,290 @@
<!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 Center</title>
<link rel="stylesheet" href="../../common/theme.css" />
<link rel="stylesheet" href="../common/center.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="bd-center" aria-label="BD 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_center.back"
>
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="bd_center.title">BD 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_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>
</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
>
B
</div>
</div>
<div class="profile-copy">
<div class="role-pill" data-i18n="bd_center.role">
BD
</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_center.salary">Salary</h2>
<button
class="text-link"
id="withdrawExchangeButton"
type="button"
data-i18n="bd_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 tools">
<button
class="menu-row"
id="inviteAgentButton"
type="button"
data-action="invite-agent"
data-label="Invite Agent"
>
<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_center.invite_agent"
>Invite Agent</span
>
<span class="chevron" aria-hidden="true"></span>
</button>
</section>
<section class="card team-stats-card">
<div class="team-list-head">
<h2 data-i18n="bd_center.agency_statistics">
Agency Statistics
</h2>
</div>
<div class="team-list-period">
<label class="month-filter">
<span data-i18n="bd_center.month">Month</span>
<button
class="month-trigger"
id="billMonthButton"
type="button"
aria-label="Month"
data-i18n-aria="bd_center.month"
>
<span id="billMonthText">2026年06月</span>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M7 2v4M17 2v4" />
<path
d="M4 8h16M6 4h12a2 2 0 0 1 2 2v14H4V6a2 2 0 0 1 2-2Z"
/>
<path
d="M8 12h2M12 12h2M16 12h2M8 16h2M12 16h2"
/>
</svg>
</button>
</label>
<div class="bill-range" id="billRange"></div>
</div>
<div class="team-list-summary" id="teamListSummary"></div>
</section>
<section class="card team-users-card">
<div class="team-list-head">
<h2 data-i18n="bd_center.agency_list">Agency List</h2>
</div>
<div class="team-list-content" id="teamListContent"></div>
</section>
</main>
<div class="home-indicator" aria-hidden="true"></div>
<div
class="invite-modal"
id="inviteModal"
hidden
aria-hidden="true"
>
<button
class="modal-backdrop"
id="inviteBackdrop"
type="button"
aria-label="Close"
data-i18n-aria="bd_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_center.invite_agent"
>
Invite Agent
</h2>
<button
class="invite-close"
id="inviteCloseButton"
type="button"
aria-label="Close"
data-i18n-aria="bd_center.close"
>
×
</button>
</div>
<div class="invite-body">
<form class="invite-search-form" id="inviteSearchForm">
<label class="invite-field">
<span data-i18n="bd_center.enter_user_id"
>Enter User ID</span
>
<div class="invite-search-control">
<input
id="inviteSearchInput"
type="text"
inputmode="text"
placeholder="Enter User ID"
data-i18n-placeholder="bd_center.enter_user_id"
/>
<button
id="inviteSearchButton"
type="submit"
data-i18n="bd_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_center.no_users_found"
>
No users found
</div>
</div>
</section>
</div>
<div
class="sheet-modal month-sheet-modal"
id="monthSheet"
hidden
aria-hidden="true"
>
<button
class="modal-backdrop"
id="monthSheetBackdrop"
type="button"
aria-label="Close"
data-i18n-aria="bd_center.close"
></button>
<section
class="bottom-sheet month-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="monthSheetTitle"
>
<div class="sheet-head">
<h2 id="monthSheetTitle" data-i18n="bd_center.month">
Month
</h2>
<button
class="sheet-close"
id="monthSheetCloseButton"
type="button"
aria-label="Close"
data-i18n-aria="bd_center.close"
>
×
</button>
</div>
<div
class="month-option-list"
id="monthOptionList"
role="listbox"
aria-label="Month"
data-i18n-aria="bd_center.month"
></div>
</section>
</div>
</div>
<script src="../../common/toast.js"></script>
<script src="../../common/jsbridge.js"></script>
<script src="../../common/i18n.js"></script>
<script src="./script.js"></script>
</body>
</html>

592
gonghui/bd-center/script.js Normal file
View File

@ -0,0 +1,592 @@
(function () {
var FIRST_BILL_MONTH = '2026-06';
var mock = {
profile: {
name: 'BD_Jasmine',
uid: 'BD-163008',
avatar: avatarData('B', '#dbc8ff', '#7d57c7'),
},
balance: {
available: 48620.8,
},
billMonth: currentMonth(),
agencyBill: {
billTitle: '2026.06',
agencyNumber: 12,
totalSalary: 128450.35,
totalRecharge: 356900.0,
memberBillList: [
{
name: 'Yumi Star Agency',
account: '163003',
avatar: avatarData('Y', '#dbc8ff', '#7d57c7'),
teamSalaryAmount: 38420.55,
teamRechargeAmount: 126880,
teamMemberCount: 28,
},
{
name: 'Moon Live Agency',
account: '163086',
avatar: avatarData('M', '#f4ebff', '#7d57c7'),
teamSalaryAmount: 29106.2,
teamRechargeAmount: 98540,
teamMemberCount: 19,
},
{
name: 'Nova Host Guild',
account: '163221',
avatar: avatarData('N', '#dbc8ff', '#7d57c7'),
teamSalaryAmount: 22450,
teamRechargeAmount: 73150,
teamMemberCount: 16,
},
],
},
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'),
},
},
],
searchPool: [
{
id: '3187099',
name: 'Agent_River',
account: '168899',
avatar: avatarData('R', '#dbc8ff', '#7d57c7'),
},
{
id: '3187100',
name: 'Agent_Sara',
account: '168900',
avatar: avatarData('S', '#f4ebff', '#7d57c7'),
},
],
};
var state = {
billMonth: normalizeBillMonth(mock.billMonth),
inviteQuery: '',
inviteMode: 'records',
inviteStatus: '',
inviteStatusType: '',
searched: [],
};
function $(id) {
return document.getElementById(id);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function avatarData(text, background, foreground) {
var letter = encodeURIComponent(String(text || 'B').charAt(0));
var svg =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">' +
'<rect width="96" height="96" rx="48" fill="' +
background +
'"/>' +
'<text x="50%" y="54%" text-anchor="middle" dominant-baseline="middle" fill="' +
foreground +
'" font-family="Arial, sans-serif" font-size="38" font-weight="800">' +
letter +
'</text>' +
'</svg>';
return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
}
function currentMonth() {
var now = new Date();
return (
String(now.getFullYear()) +
'-' +
String(now.getMonth() + 1).padStart(2, '0')
);
}
function monthDate(value) {
var parts = String(value || currentMonth()).split('-');
var year = Number(parts[0]) || new Date().getFullYear();
var month = Number(parts[1]) || new Date().getMonth() + 1;
return new Date(year, month - 1, 1);
}
function monthValue(date) {
return (
String(date.getFullYear()) +
'-' +
String(date.getMonth() + 1).padStart(2, '0')
);
}
function monthTime(value) {
return monthDate(value).getTime();
}
function normalizeBillMonth(value) {
if (monthTime(value) < monthTime(FIRST_BILL_MONTH)) {
return FIRST_BILL_MONTH;
}
if (monthTime(value) > monthTime(currentMonth())) {
return currentMonth();
}
return monthValue(monthDate(value));
}
function monthLabel(value) {
var date = monthDate(value);
return (
String(date.getFullYear()) +
'年' +
String(date.getMonth() + 1).padStart(2, '0') +
'月'
);
}
function monthOptions() {
var options = [];
var cursor = monthDate(currentMonth());
var first = monthDate(FIRST_BILL_MONTH);
while (cursor.getTime() >= first.getTime()) {
options.push(new Date(cursor.getFullYear(), cursor.getMonth(), 1));
cursor = new Date(cursor.getFullYear(), cursor.getMonth() - 1, 1);
}
return options;
}
function money(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function count(value) {
return Number(value || 0).toLocaleString('en-US', {
maximumFractionDigits: 0,
});
}
function initial(text) {
return String(text || '')
.trim()
.charAt(0)
.toUpperCase();
}
function toast(message) {
if (window.HyAppToast) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function replaceChildren(node, children) {
node.textContent = '';
children.forEach(function (child) {
node.appendChild(child);
});
}
function renderImageAvatar(container, src, name, fallbackClass) {
container.textContent = '';
if (!src) {
var fallback = document.createElement('span');
fallback.className = fallbackClass || 'member-fallback';
fallback.textContent = initial(name) || 'B';
container.appendChild(fallback);
return;
}
var image = document.createElement('img');
image.src = src;
image.alt = '';
image.addEventListener('error', function () {
container.textContent = '';
var fallback = document.createElement('span');
fallback.className = fallbackClass || 'member-fallback';
fallback.textContent = initial(name) || 'B';
container.appendChild(fallback);
});
container.appendChild(image);
}
function 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';
image.onload = function () {
image.hidden = false;
fallback.hidden = true;
};
image.onerror = function () {
image.hidden = true;
fallback.hidden = false;
};
image.src = mock.profile.avatar;
}
function renderBalance() {
$('availableBalance').textContent = money(mock.balance.available);
}
function summaryCell(label, value) {
var cell = document.createElement('div');
var labelNode = document.createElement('span');
var valueNode = document.createElement('strong');
labelNode.textContent = label;
valueNode.textContent = value;
cell.appendChild(labelNode);
cell.appendChild(valueNode);
return cell;
}
function memberRow(item) {
var row = document.createElement('article');
var avatar = document.createElement('div');
var main = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var side = document.createElement('div');
row.className = 'member-row';
avatar.className = 'member-avatar';
main.className = 'member-main';
name.className = 'member-name';
meta.className = 'member-meta';
side.className = 'member-side';
renderImageAvatar(avatar, item.avatar, item.name);
name.textContent = item.name;
meta.textContent = 'UID: ' + item.account;
[
t('bd_center.team_salary', 'Team salary') +
': $' +
money(item.teamSalaryAmount),
t('bd_center.recharge', 'Recharge') +
': $' +
money(item.teamRechargeAmount),
t('bd_center.host', 'Host') + ': ' + count(item.teamMemberCount),
].forEach(function (line) {
var node = document.createElement('div');
node.textContent = line;
side.appendChild(node);
});
main.appendChild(name);
main.appendChild(meta);
row.appendChild(avatar);
row.appendChild(main);
row.appendChild(side);
return row;
}
function renderTeamList() {
var bill = mock.agencyBill;
$('billMonthText').textContent = monthLabel(state.billMonth);
$('billRange').textContent = state.billMonth.replace('-', '.');
replaceChildren($('teamListSummary'), [
summaryCell(
t('bd_center.agency_number', 'Agency number'),
count(bill.agencyNumber)
),
summaryCell(
t('bd_center.team_salary', 'Team salary'),
'$' + money(bill.totalSalary)
),
]);
var rows = bill.memberBillList.map(memberRow);
if (!rows.length) {
var empty = document.createElement('div');
empty.className = 'empty-state';
empty.textContent = t('bd_center.no_data', 'No data');
rows = [empty];
}
replaceChildren($('teamListContent'), rows);
}
function monthOption(date) {
var value = monthValue(date);
var option = document.createElement('button');
option.className = 'month-option';
option.type = 'button';
option.setAttribute('role', 'option');
option.setAttribute('data-month', value);
option.setAttribute('aria-selected', String(value === state.billMonth));
option.textContent = monthLabel(value);
if (value === state.billMonth) option.classList.add('is-selected');
return option;
}
function renderMonthSheet() {
replaceChildren(
$('monthOptionList'),
monthOptions().map(function (date) {
return monthOption(date);
})
);
}
function openMonthSheet() {
renderMonthSheet();
$('monthSheet').hidden = false;
$('monthSheet').setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
window.setTimeout(function () {
var selected = $('monthOptionList').querySelector('.is-selected');
if (selected && selected.scrollIntoView) {
selected.scrollIntoView({ block: 'center' });
}
}, 0);
}
function closeMonthSheet() {
$('monthSheet').hidden = true;
$('monthSheet').setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
}
function selectMonth(value) {
var nextMonth = normalizeBillMonth(value);
if (!nextMonth || nextMonth === state.billMonth) {
closeMonthSheet();
return;
}
state.billMonth = nextMonth;
closeMonthSheet();
renderTeamList();
toast(t('bd_center.mock_bill_loaded', 'Mock bill loaded.'));
}
function inviteProfile(item) {
return item.profile || item;
}
function statusLabel(status) {
if (status === 'success') return t('bd_center.success', 'Success');
if (status === 'pending') return t('bd_center.pending', 'Pending');
return '';
}
function inviteCard(item) {
var profile = inviteProfile(item);
var card = document.createElement('article');
var avatar = document.createElement('div');
var main = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var side = document.createElement('div');
card.className = 'invite-user-card';
avatar.className = 'invite-user-avatar';
main.className = 'invite-user-main';
name.className = 'invite-user-name';
meta.className = 'invite-user-meta';
side.className = 'invite-user-side';
renderImageAvatar(
avatar,
profile.avatar,
profile.name,
'invite-avatar-fallback'
);
name.textContent = profile.name;
meta.textContent = 'UID: ' + profile.account;
main.appendChild(name);
main.appendChild(meta);
if (item.status === 'pending' || item.status === 'success') {
var badge = document.createElement('span');
badge.className = 'invite-badge ' + item.status;
badge.textContent = statusLabel(item.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 invite = document.createElement('button');
invite.className = 'invite-action';
invite.type = 'button';
invite.textContent = 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();
});
side.appendChild(invite);
}
card.appendChild(avatar);
card.appendChild(main);
card.appendChild(side);
return card;
}
function setInviteStatus(text, type) {
var node = $('inviteStatus');
node.textContent = text || '';
node.hidden = !text;
node.classList.toggle('is-error', type === 'error');
node.classList.toggle('is-success', type === 'success');
}
function renderInviteModal() {
var rows =
state.inviteMode === 'search'
? state.searched.map(inviteCard)
: mock.inviteRecords.map(inviteCard);
setInviteStatus(state.inviteStatus, state.inviteStatusType);
replaceChildren($('inviteList'), rows);
$('inviteEmpty').hidden =
rows.length > 0 || Boolean(state.inviteStatus);
$('inviteSearchButton').disabled = !state.inviteQuery.trim();
}
function openInviteModal() {
state.inviteQuery = '';
state.inviteMode = 'records';
state.searched = [];
state.inviteStatus = '';
$('inviteSearchInput').value = '';
$('inviteModal').hidden = false;
$('inviteModal').setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
renderInviteModal();
window.setTimeout(function () {
$('inviteSearchInput').focus();
}, 80);
}
function closeInviteModal() {
$('inviteModal').hidden = true;
$('inviteModal').setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
}
function searchInvite(event) {
event.preventDefault();
var query = state.inviteQuery.trim().toLowerCase();
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'
);
}
renderInviteModal();
}
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')
)
);
});
$('inviteAgentButton').addEventListener('click', openInviteModal);
$('inviteBackdrop').addEventListener('click', closeInviteModal);
$('inviteCloseButton').addEventListener('click', closeInviteModal);
$('inviteSearchInput').addEventListener('input', function (event) {
state.inviteQuery = event.target.value;
if (!state.inviteQuery.trim()) {
state.inviteMode = 'records';
state.searched = [];
state.inviteStatus = '';
}
renderInviteModal();
});
$('inviteSearchForm').addEventListener('submit', searchInvite);
$('billMonthButton').addEventListener('click', openMonthSheet);
$('monthSheetBackdrop').addEventListener('click', closeMonthSheet);
$('monthSheetCloseButton').addEventListener('click', closeMonthSheet);
$('monthOptionList').addEventListener('click', function (event) {
var option = event.target.closest('[data-month]');
if (!option) return;
selectMonth(option.getAttribute('data-month'));
});
}
function render() {
renderProfile();
renderBalance();
renderTeamList();
renderInviteModal();
}
document.addEventListener('DOMContentLoaded', function () {
render();
bindEvents();
if (window.HyAppBridge) {
window.HyAppBridge.ready({ page: 'bd-center', mock: true });
}
});
window.addEventListener('hyapp:i18n-ready', function () {
render();
});
})();

535
gonghui/bd-center/style.css Normal file
View File

@ -0,0 +1,535 @@
.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-center .name {
margin-top: 7px;
}
.salary-card,
.team-stats-card,
.team-users-card {
padding: 16px;
}
.salary-head,
.team-list-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.salary-head h2,
.team-list-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;
}
.team-stats-card,
.team-users-card {
display: grid;
gap: 12px;
}
.team-list-period {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 10px;
}
.month-filter {
display: grid;
min-width: 0;
gap: 6px;
}
.month-filter span {
color: var(--muted);
font-size: 12px;
font-weight: 850;
line-height: 1.2;
}
.month-trigger {
display: grid;
grid-template-columns: minmax(0, 1fr) 22px;
align-items: center;
gap: 10px;
width: 100%;
min-width: 0;
height: 38px;
padding: 0 10px;
border: 1px solid var(--line);
border-radius: 8px;
background: #fbfcfc;
color: var(--text);
font-size: 13px;
font-weight: 900;
text-align: left;
}
.month-trigger span {
min-width: 0;
overflow: hidden;
color: var(--text);
font-size: 13px;
font-weight: 900;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.month-trigger svg {
width: 20px;
height: 20px;
}
.month-trigger path {
fill: none;
stroke: var(--text);
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.8;
}
.bill-range {
color: var(--muted);
font-size: 12px;
font-weight: 850;
line-height: 1.25;
text-align: right;
}
.team-list-summary {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.team-list-summary > div {
min-width: 0;
padding: 10px;
border-radius: 8px;
background: var(--hy-theme-primary-soft, #f4ebff);
}
.team-list-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-list-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-content {
display: grid;
gap: 10px;
max-height: 360px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.member-row,
.invite-user-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;
}
.member-avatar,
.invite-user-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
overflow: hidden;
border-radius: 50%;
background: var(--primary);
}
.member-avatar img,
.invite-user-avatar img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.member-fallback,
.invite-avatar-fallback {
color: var(--primary-deep);
font-size: 18px;
font-weight: 950;
}
.member-main,
.invite-user-main {
min-width: 0;
}
.member-name,
.invite-user-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-user-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;
}
.empty-state,
.invite-empty {
display: flex;
align-items: center;
justify-content: center;
min-height: 80px;
border: 1px dashed var(--line);
border-radius: 8px;
color: var(--muted);
font-size: 14px;
font-weight: 850;
text-align: center;
}
.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);
}
.month-sheet {
max-height: 62vh;
max-height: 62dvh;
}
.month-option-list {
display: grid;
gap: 8px;
min-height: 0;
overflow-y: auto;
padding: 12px 18px max(18px, env(safe-area-inset-bottom));
-webkit-overflow-scrolling: touch;
}
.month-option {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 44px;
padding: 0 14px;
border: 1px solid var(--line);
border-radius: 8px;
background: #fbfcfc;
color: var(--text);
font-size: 15px;
font-weight: 900;
text-align: left;
}
.month-option.is-selected {
border-color: transparent;
background: var(--button);
color: #fff;
box-shadow: var(
--hy-theme-button-shadow,
0 8px 18px rgba(125, 87, 199, 0.18)
);
}
.invite-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
min-height: 58px;
padding: 16px 18px 12px;
border-bottom: 1px solid var(--line);
}
.invite-head h2 {
min-width: 0;
margin: 0;
overflow: hidden;
color: var(--text);
font-size: 18px;
font-weight: 950;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.invite-close {
display: flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: var(--hy-theme-primary-soft, #f4ebff);
color: var(--primary-deep);
font-size: 25px;
font-weight: 500;
line-height: 1;
}
.invite-body {
display: flex;
min-height: 0;
flex: 1 1 auto;
flex-direction: column;
gap: 12px;
overflow-y: auto;
padding: 14px 18px max(18px, env(safe-area-inset-bottom));
-webkit-overflow-scrolling: touch;
}
.invite-search-form {
margin: 0;
}
.invite-field {
display: grid;
gap: 8px;
}
.invite-field > span {
color: #555b64;
font-size: 13px;
font-weight: 900;
line-height: 1.2;
}
.invite-search-control {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
}
.invite-search-control input {
width: 100%;
min-width: 0;
height: 42px;
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,
.invite-cancel {
min-height: 34px;
border-radius: 8px;
font-size: 12px;
font-weight: 950;
}
.invite-search-control button {
min-width: 76px;
height: 42px;
padding: 0 12px;
background: var(--button);
color: #fff;
box-shadow: var(
--hy-theme-button-shadow,
0 8px 18px rgba(125, 87, 199, 0.18)
);
}
.invite-search-control button:disabled {
background: var(--button-disabled);
box-shadow: var(--hy-theme-button-disabled-shadow, none);
}
.invite-status {
padding: 10px 12px;
border-radius: 8px;
background: var(--hy-theme-primary-soft, #f4ebff);
color: var(--primary-deep);
font-size: 12px;
font-weight: 850;
line-height: 1.35;
}
.invite-status.is-error {
background: #fff0f0;
color: #c43f3f;
}
.invite-status.is-success {
background: #ebfbf2;
color: #128946;
}
.invite-list {
display: grid;
gap: 10px;
}
.invite-user-side {
display: grid;
justify-items: end;
gap: 6px;
}
.invite-action {
min-width: 68px;
padding: 0 12px;
background: var(--button);
color: #fff;
}
.invite-cancel {
min-width: 68px;
padding: 0 12px;
border: 1px solid rgba(217, 93, 114, 0.24);
background: #fff2f2;
color: var(--danger);
}
.invite-badge {
min-width: 72px;
padding: 5px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 950;
line-height: 1;
text-align: center;
}
.invite-badge.pending {
background: #fff4dc;
color: #bd7a10;
}
.invite-badge.success {
background: #e9fbf1;
color: #15914f;
}
@media (max-width: 360px) {
.salary-card,
.team-stats-card,
.team-users-card {
padding-right: 18px;
padding-left: 18px;
}
.salary-value {
font-size: 29px;
}
.team-list-summary {
grid-template-columns: 1fr;
}
.member-row,
.invite-user-card {
grid-template-columns: 44px minmax(0, 1fr);
}
.member-side,
.invite-user-side {
grid-column: 2;
justify-items: start;
text-align: left;
}
}

484
gonghui/common/center.css Normal file
View File

@ -0,0 +1,484 @@
:root {
--page-bg: var(--hy-theme-bg, #f7f3ff);
--card-bg: var(--hy-theme-surface, rgba(255, 255, 255, 0.96));
--text: var(--hy-theme-text, #282333);
--muted: var(--hy-theme-muted, #8d879a);
--line: var(--hy-theme-line, #eee7f8);
--primary: var(--hy-theme-primary, #dbc8ff);
--primary-soft: var(--hy-theme-primary-soft, #f4ebff);
--primary-strong: var(--hy-theme-primary-strong, #c5a6f6);
--primary-deep: var(--hy-theme-primary-deep, #7d57c7);
--button: var(--hy-theme-button, #7d57c7);
--button-disabled: var(--hy-theme-button-disabled, #c5a6f6);
--shadow: var(--hy-theme-shadow, 0 10px 26px rgba(109, 69, 189, 0.1));
--danger: var(--hy-theme-danger, #d95d72);
--success: var(--hy-theme-success, #31c6a8);
}
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
body {
display: flex;
justify-content: center;
background: #111;
color: var(--text);
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif;
}
button,
input {
font: inherit;
}
button {
border: 0;
padding: 0;
background: transparent;
color: inherit;
}
button:focus,
input:focus {
outline: none;
}
button:focus-visible,
input:focus-visible {
outline: 2px solid rgba(125, 87, 199, 0.32);
outline-offset: 2px;
}
[hidden] {
display: none !important;
}
.host-center,
.bd-center,
.agency-center {
position: relative;
width: 100%;
max-width: 430px;
min-height: 100vh;
min-height: 100dvh;
overflow: hidden;
background:
linear-gradient(
145deg,
rgba(255, 255, 255, 0.82),
rgba(250, 246, 255, 0) 42%
),
var(--page-bg);
}
.hero-bg {
position: absolute;
inset: 0 0 auto;
height: 215px;
background: var(
--hy-theme-hero,
linear-gradient(
151deg,
#f0e6ff 0%,
#fffbff 58%,
rgba(250, 246, 255, 0.82) 100%
)
);
clip-path: polygon(0 0, 100% 0, 100% 76%, 70% 47%, 40% 58%, 0 78%);
}
.title-bar,
.content,
.home-indicator {
position: relative;
z-index: 1;
}
.title-bar {
display: grid;
grid-template-columns: 52px 1fr 52px;
align-items: center;
z-index: 3;
height: 60px;
padding: 0 14px;
direction: ltr;
}
.title-bar h1 {
margin: 0;
color: var(--text);
font-size: 22px;
font-weight: 900;
line-height: 1;
text-align: center;
}
.back-button {
display: flex;
align-items: center;
justify-content: flex-start;
width: 44px;
height: 44px;
}
.back-button svg {
width: 28px;
height: 28px;
}
.back-button path {
fill: none;
stroke: var(--text);
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 3;
}
.language-switcher {
position: relative;
justify-self: end;
}
.language-button {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 30px;
border: 1px solid rgba(35, 40, 46, 0.12);
border-radius: 15px;
background: rgba(255, 255, 255, 0.68);
color: var(--text);
font-size: 13px;
font-weight: 900;
box-shadow: 0 4px 12px rgba(43, 118, 107, 0.08);
}
.language-menu {
position: absolute;
z-index: 20;
top: calc(100% + 7px);
right: 0;
display: grid;
gap: 2px;
min-width: 72px;
padding: 5px;
border: 1px solid rgba(35, 40, 46, 0.1);
border-radius: 8px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 10px 26px rgba(36, 46, 60, 0.14);
}
.language-menu button {
min-height: 34px;
border-radius: 6px;
color: var(--text);
font-size: 12px;
font-weight: 900;
}
.language-menu button.is-active {
background: var(--primary-soft);
color: var(--primary-deep);
}
.content {
display: flex;
flex-direction: column;
gap: 15px;
padding: 8px 14px 90px;
}
.card {
width: 100%;
border-radius: 8px;
background: var(--card-bg);
box-shadow: var(--shadow);
}
.profile-card {
display: flex;
align-items: center;
min-height: 103px;
padding: 16px 24px;
}
.avatar-shell {
position: relative;
width: 64px;
height: 64px;
flex: 0 0 64px;
}
.avatar-image,
.avatar-fallback {
width: 64px;
height: 64px;
border-radius: 50%;
}
.avatar-image {
display: block;
object-fit: cover;
}
.avatar-fallback {
display: flex;
align-items: center;
justify-content: center;
background: var(--primary);
color: var(--primary-deep);
font-size: 24px;
font-weight: 950;
}
.profile-copy {
min-width: 0;
margin-left: 20px;
}
.name {
overflow: hidden;
color: var(--text);
font-size: 20px;
font-weight: 900;
line-height: 1.1;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta {
margin-top: 6px;
overflow: hidden;
color: var(--muted);
font-size: 13px;
font-weight: 750;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-link,
.salary-link {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
min-height: 34px;
color: var(--primary-deep);
font-size: 13px;
font-weight: 900;
white-space: nowrap;
}
.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;
}
.menu-count {
color: var(--muted);
font-size: 13px;
font-weight: 900;
white-space: nowrap;
}
.chevron {
color: var(--muted);
font-size: 24px;
font-weight: 500;
line-height: 1;
text-align: right;
}
.sheet-modal,
.message-modal,
.invite-modal {
position: fixed;
z-index: 24;
inset: 0;
display: flex;
justify-content: center;
}
.sheet-modal {
align-items: flex-end;
padding: 0 0 env(safe-area-inset-bottom);
}
.message-modal,
.invite-modal {
align-items: center;
padding: 18px;
}
.modal-backdrop {
position: absolute;
inset: 0;
background: rgba(15, 21, 28, 0.38);
}
.bottom-sheet {
position: relative;
display: flex;
flex-direction: column;
width: min(430px, 100%);
max-height: 80vh;
max-height: 80dvh;
overflow: hidden;
border-radius: 16px 16px 0 0;
background: #fff;
box-shadow: 0 -14px 34px rgba(23, 31, 42, 0.16);
}
.sheet-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
min-height: 58px;
padding: 16px 18px 12px;
border-bottom: 1px solid var(--line);
}
.sheet-head h2 {
margin: 0;
color: var(--text);
font-size: 18px;
font-weight: 950;
line-height: 1.2;
}
.sheet-close {
display: flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: var(--primary-soft);
color: var(--primary-deep);
font-size: 25px;
font-weight: 500;
line-height: 1;
}
.home-indicator {
position: absolute;
left: 50%;
bottom: 8px;
width: 154px;
height: 5px;
border-radius: 999px;
background: #050506;
transform: translateX(-50%);
}
.modal-open {
overflow: hidden;
}
[dir='rtl'] .content,
[dir='rtl'] .bottom-sheet,
[dir='rtl'] .message-dialog,
[dir='rtl'] .invite-dialog {
direction: rtl;
}
[dir='rtl'] .profile-copy {
margin-right: 20px;
margin-left: 0;
text-align: right;
}
[dir='rtl'] .menu-row {
text-align: right;
}
[dir='rtl'] .chevron {
transform: rotate(180deg);
}
@media (max-width: 360px) {
.content {
padding-right: 12px;
padding-left: 12px;
}
.profile-card {
padding-right: 18px;
padding-left: 18px;
}
.profile-copy {
margin-left: 14px;
}
}

View File

@ -0,0 +1,160 @@
<!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>Host Center</title>
<link rel="stylesheet" href="../../common/theme.css?v=20260602" />
<link rel="stylesheet" href="../common/center.css?v=20260602" />
<link rel="stylesheet" href="./style.css?v=20260602" />
</head>
<body>
<div class="host-center" aria-label="Host 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="host_center.back"
>
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="host_center.title">Host 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="host_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
>
Y
</div>
</div>
<div class="profile-copy">
<div class="name" id="profileName">Yumi_Host</div>
<div class="meta" id="profileUID">UID: 1688008</div>
<div class="profile-badge" id="profileBadge"></div>
</div>
</section>
<section class="card income-card">
<div class="income-head">
<h2 data-i18n="host_center.available_salary">
My available salary
</h2>
<button
class="text-link"
id="incomeWithdrawExchangeButton"
type="button"
data-i18n="host_center.withdraw_exchange"
>
Withdraw/Exchange
</button>
</div>
<div class="income-value">
<span class="coin-icon" aria-hidden="true">$</span>
<span id="availableSalary"></span>
</div>
<div class="income-foot" id="incomeFoot"></div>
</section>
<section class="card task-card" aria-labelledby="levelTitle">
<div class="section-head">
<h2
id="levelTitle"
data-i18n="host_center.level_progress"
>
Level progress
</h2>
<span class="task-pill" id="levelStatus"></span>
</div>
<div class="task-grid">
<div class="task-item">
<span data-i18n="host_center.current_level"
>Current level</span
>
<strong id="currentLevel"></strong>
</div>
<div class="task-item">
<span data-i18n="host_center.next_level_need"
>Needed for next level</span
>
<strong id="nextLevelNeed"></strong>
</div>
</div>
<div class="progress-track" aria-hidden="true">
<div class="progress-fill" id="levelProgress"></div>
</div>
</section>
<section class="card menu-card" aria-label="Host tools">
<button
class="menu-row"
type="button"
data-action="policy"
data-label="Platform policy"
>
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path
d="M12 3 5 6v5c0 4.5 3 7.8 7 10 4-2.2 7-5.5 7-10V6l-7-3Z"
/>
<path d="m9 12 2 2 4-5" />
</svg>
</span>
<span
class="menu-label"
data-i18n="host_center.platform_policy"
>Platform policy</span
>
<span class="chevron" aria-hidden="true"></span>
</button>
</section>
</main>
<div class="home-indicator" aria-hidden="true"></div>
</div>
<script src="../../common/api.js?v=20260602-api"></script>
<script src="../../common/toast.js"></script>
<script src="../../common/params.js?v=20260602-api"></script>
<script src="../../common/jsbridge.js"></script>
<script src="../../common/i18n.js?v=20260602-api"></script>
<script src="./script.js?v=20260602-api"></script>
</body>
</html>

View File

@ -0,0 +1,471 @@
(function () {
var HOST_SALARY_USD = 'HOST_SALARY_USD';
var HOST_LEVEL_TRACK = 'charm';
var mock = {
profile: {
name: 'quick_1780052629537',
uid: '163000',
avatar: avatarData('Y', '#dbc8ff', '#7d57c7'),
},
agency: {
shortId: '163003',
},
salary: {
available: 30650.75,
monthKey: 'host_center.month_june',
month: 'June',
currencyKey: 'host_center.currency_usd',
currency: 'USD',
useCurrentMonth: false,
},
level: {
current: 3,
currentRequired: 0,
currentValue: 2450,
nextValue: 4000,
},
};
var state = cloneHostState(mock);
function $(id) {
return document.getElementById(id);
}
function cloneHostState(value) {
return {
profile: Object.assign({}, value.profile),
agency: Object.assign({}, value.agency),
salary: Object.assign({}, value.salary),
level: Object.assign({}, value.level),
};
}
function avatarData(text, background, foreground) {
var value =
String(text || 'Y')
.trim()
.charAt(0) || 'Y';
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) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function initial(text) {
return String(text || '')
.trim()
.charAt(0)
.toUpperCase();
}
function queryValue(name) {
return new URLSearchParams(window.location.search).get(name);
}
function isMockMode() {
return queryValue('mock') === '1';
}
function hasAccessToken() {
return (
window.HyAppAPI &&
window.HyAppAPI.getAccessToken &&
!!window.HyAppAPI.getAccessToken()
);
}
function unwrapData(payload) {
if (!payload || typeof payload !== 'object') return payload;
return Object.prototype.hasOwnProperty.call(payload, 'data')
? payload.data
: payload;
}
function firstValue(source, keys) {
if (!source) return '';
for (var i = 0; i < keys.length; i += 1) {
var value = source[keys[i]];
if (value !== undefined && value !== null && value !== '') {
return value;
}
}
return '';
}
function toNumber(value) {
var number = Number(value);
return Number.isFinite(number) ? number : 0;
}
function safeRequest(factory) {
return factory().catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn('[host-center] api failed', error);
}
return null;
});
}
function currentLocale() {
var lang =
window.HyAppI18n && window.HyAppI18n.lang
? window.HyAppI18n.lang()
: 'en';
var map = {
en: 'en-US',
ar: 'ar',
tr: 'tr-TR',
es: 'es-ES',
zh: 'zh-CN',
id: 'id-ID',
};
return map[lang] || 'en-US';
}
function currentMonthName() {
try {
return new Date().toLocaleString(currentLocale(), {
month: 'long',
});
} catch (_) {
return 'June';
}
}
function salaryMonthLabel(salary) {
if (salary.monthKey) return t(salary.monthKey, salary.month);
if (salary.useCurrentMonth) return currentMonthName();
return salary.month || currentMonthName();
}
function salaryCurrencyLabel(salary) {
if (salary.currencyKey) return t(salary.currencyKey, salary.currency);
return salary.currency || t('host_center.currency_usd', 'USD');
}
function renderProfile() {
var image = $('profileAvatar');
var fallback = $('profileAvatarFallback');
var badge = $('profileBadge');
var profile = state.profile;
var agency = state.agency;
$('profileName').textContent = profile.name || 'User';
$('profileUID').textContent = 'UID: ' + (profile.uid || '-');
fallback.textContent = initial(profile.name || profile.uid) || 'Y';
if (agency.shortId) {
badge.hidden = false;
badge.textContent = t(
'host_center.agency_short_id',
'Agency ID: {id}'
).replace('{id}', agency.shortId);
} else {
badge.hidden = true;
badge.textContent = '';
}
if (!profile.avatar) {
image.hidden = true;
image.removeAttribute('src');
fallback.hidden = false;
return;
}
image.onload = function () {
image.hidden = false;
fallback.hidden = true;
};
image.onerror = function () {
image.hidden = true;
fallback.hidden = false;
};
image.src = profile.avatar;
}
function renderIncome() {
var salary = state.salary;
$('availableSalary').textContent = money(salary.available);
$('incomeFoot').textContent = t(
'host_center.salary_month_note',
'{month} settlement · {currency}'
)
.replace('{month}', salaryMonthLabel(salary))
.replace('{currency}', salaryCurrencyLabel(salary));
}
function renderLevel() {
var level = state.level;
var currentRequired = toNumber(level.currentRequired);
var currentValue = toNumber(level.currentValue);
var nextValue = toNumber(level.nextValue);
var need = Math.max(0, nextValue - currentValue);
var denominator = Math.max(1, nextValue - currentRequired);
var currentInLevel = Math.max(0, currentValue - currentRequired);
var percent =
nextValue > currentRequired
? Math.min(
100,
Math.round((currentInLevel / denominator) * 100)
)
: 100;
$('currentLevel').textContent = t(
'host_center.level_value',
'Lv. {level}'
).replace('{level}', String(level.current || 0));
$('nextLevelNeed').textContent = money(need);
$('levelProgress').style.width = percent + '%';
$('levelStatus').textContent = t(
'host_center.in_progress',
'In progress'
);
}
function render() {
renderProfile();
renderIncome();
renderLevel();
}
function applyProfile(payload) {
var profile = unwrapData(payload);
if (!profile) return;
var name = firstValue(profile, [
'username',
'nickname',
'name',
'display_name',
]);
var uid = firstValue(profile, [
'display_user_id',
'default_display_user_id',
'uid',
'user_id',
]);
var avatar = firstValue(profile, ['avatar', 'avatar_url', 'avatarUrl']);
state.profile = {
name: name || state.profile.name,
uid: uid || state.profile.uid,
avatar:
avatar ||
avatarData(
initial(name || uid || state.profile.name),
'#dbc8ff',
'#7d57c7'
),
};
}
function applyRoleSummary(payload) {
var summary = unwrapData(payload);
if (!summary) return;
var agencyId = firstValue(summary, [
'agency_id',
'agencyId',
'host_agency_id',
'hostAgencyId',
]);
state.agency = {
shortId: agencyId ? String(agencyId) : '',
};
}
function displayAmountForAsset(assetType, amount) {
if (assetType === HOST_SALARY_USD) return toNumber(amount) / 100;
return toNumber(amount);
}
function findBalance(payload, assetType) {
var data = unwrapData(payload);
var balances =
data && Array.isArray(data.balances) ? data.balances : [];
for (var i = 0; i < balances.length; i += 1) {
if (
balances[i].asset_type === assetType ||
balances[i].assetType === assetType
) {
return balances[i];
}
}
return null;
}
function applyWallet(payload) {
var balance = findBalance(payload, HOST_SALARY_USD);
if (!balance) return;
var amount = firstValue(balance, [
'available_amount',
'availableAmount',
]);
state.salary = Object.assign({}, state.salary, {
available: displayAmountForAsset(HOST_SALARY_USD, amount),
monthKey: '',
month: '',
currencyKey: 'host_center.currency_usd',
currency: 'USD',
useCurrentMonth: true,
});
}
function pickLevelTrack(payload) {
var data = unwrapData(payload);
var tracks = data && Array.isArray(data.tracks) ? data.tracks : [];
if (!tracks.length) return null;
for (var i = 0; i < tracks.length; i += 1) {
if (tracks[i].track === HOST_LEVEL_TRACK) return tracks[i];
}
return tracks[0];
}
function applyLevel(payload) {
var track = pickLevelTrack(payload);
if (!track) return;
state.level = {
current: toNumber(
firstValue(track, ['level', 'current_level', 'currentLevel'])
),
currentRequired: toNumber(
firstValue(track, [
'current_level_required_value',
'currentLevelRequiredValue',
])
),
currentValue: toNumber(
firstValue(track, ['total_value', 'totalValue'])
),
nextValue: toNumber(
firstValue(track, [
'next_level_required_value',
'nextLevelRequiredValue',
'total_value',
'totalValue',
])
),
};
}
function toast(message) {
if (!message) return;
if (window.HyAppToast && window.HyAppToast.show) {
window.HyAppToast.show(message);
}
}
function loadRealData() {
if (isMockMode() || !window.HyAppAPI) return Promise.resolve(false);
if (window.HyAppParams && window.HyAppParams.parse) {
window.HyAppParams.parse();
}
if (!hasAccessToken()) return Promise.resolve(false);
return Promise.all([
safeRequest(function () {
return window.HyAppAPI.user.me();
}),
safeRequest(function () {
return window.HyAppAPI.user.roleSummary();
}),
safeRequest(function () {
return window.HyAppAPI.wallet.balances([HOST_SALARY_USD]);
}),
safeRequest(function () {
return window.HyAppAPI.level.overview();
}),
]).then(function (results) {
applyProfile(results[0]);
applyRoleSummary(results[1]);
applyWallet(results[2]);
applyLevel(results[3]);
render();
var hasAnyData = results.some(function (item) {
return !!item;
});
if (!hasAnyData) {
toast(
t(
'host_center.load_failed',
'Load failed. Try again later.'
)
);
}
return hasAnyData;
});
}
function openWithdrawExchange() {
var params = new URLSearchParams(window.location.search);
params.set('mode', params.get('mode') || 'transfer');
window.location.href =
'../withdraw-exchange/index.html?' + params.toString();
}
function bindEvents() {
$('backButton').addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
});
$('incomeWithdrawExchangeButton').addEventListener(
'click',
openWithdrawExchange
);
}
var initialized = false;
function init() {
if (initialized) return;
initialized = true;
render();
bindEvents();
loadRealData().then(function (loaded) {
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'host-center',
mock: !loaded,
});
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('hyapp:i18n-ready', function () {
render();
});
})();

View File

@ -0,0 +1,151 @@
.profile-badge {
display: inline-flex;
align-items: center;
margin-top: 8px;
padding: 5px 9px;
border-radius: 999px;
background: var(--hy-theme-primary-soft, #f4ebff);
color: var(--primary-deep);
font-size: 13px;
font-weight: 750;
line-height: 1.2;
}
.income-card,
.task-card {
padding: 16px;
}
.section-head,
.income-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.section-head h2,
.income-head h2 {
min-width: 0;
margin: 0;
overflow: hidden;
color: var(--text);
font-size: 18px;
font-weight: 950;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.income-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);
}
.income-foot {
margin-top: 12px;
color: var(--muted);
font-size: 13px;
font-weight: 800;
line-height: 1.35;
}
.task-pill {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 28px;
padding: 0 10px;
border-radius: 999px;
background: var(--hy-theme-primary-soft, #f4ebff);
color: var(--primary-deep);
font-size: 12px;
font-weight: 900;
}
.task-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-top: 16px;
}
.task-item {
min-width: 0;
}
.task-item > span {
display: block;
overflow: hidden;
color: var(--muted);
font-size: 12px;
font-weight: 800;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.task-item strong {
display: block;
margin-top: 6px;
overflow-wrap: anywhere;
color: #292d33;
font-size: 17px;
font-weight: 950;
line-height: 1.2;
}
.progress-track {
height: 9px;
margin-top: 16px;
overflow: hidden;
border-radius: 999px;
background: var(--hy-theme-primary-soft, #f4ebff);
}
.progress-fill {
width: 0;
height: 100%;
border-radius: inherit;
background: var(--button);
transition: width 0.2s ease;
}
@media (max-width: 360px) {
.income-card,
.task-card {
padding-right: 18px;
padding-left: 18px;
}
.income-value {
font-size: 29px;
}
.task-grid {
grid-template-columns: 1fr;
}
}

View File

@ -0,0 +1,379 @@
<!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>Withdraw/Exchange</title>
<link rel="stylesheet" href="../../common/theme.css?v=20260602" />
<link rel="stylesheet" href="./style.css?v=20260602" />
</head>
<body>
<div
class="withdraw-exchange-page"
aria-label="Withdraw and exchange"
data-i18n-aria="withdraw_exchange.page_label"
>
<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="withdraw_exchange.back"
>
<svg viewBox="0 0 32 32" aria-hidden="true">
<path d="M20 8 12 16l8 8" />
</svg>
</button>
<h1 data-i18n="withdraw_exchange.title">Withdraw/Exchange</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="withdraw_exchange.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="balance-card">
<div class="balance-head">
<div
class="balance-label"
data-i18n="withdraw_exchange.salary"
>
salary
</div>
<button
class="balance-history-button"
id="salaryHistoryButton"
type="button"
aria-label="Salary history"
data-i18n-aria="withdraw_exchange.salary_history"
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="m9 5 7 7-7 7" />
</svg>
</button>
</div>
<div class="balance-value">
<span class="balance-currency" aria-hidden="true"
>$</span
>
<span id="balanceAmount">0.00</span>
</div>
</section>
<section class="mode-card">
<div
class="mode-tabs"
role="tablist"
aria-label="Withdraw, exchange, or transfer"
data-i18n-aria="withdraw_exchange.mode_tabs"
>
<button
class="mode-tab"
type="button"
role="tab"
aria-selected="false"
data-mode="withdraw"
data-i18n="withdraw_exchange.withdraw"
>
Withdraw
</button>
<button
class="mode-tab"
type="button"
role="tab"
aria-selected="false"
data-mode="exchange"
data-i18n="withdraw_exchange.exchange"
>
Exchange
</button>
<button
class="mode-tab"
type="button"
role="tab"
aria-selected="false"
data-mode="transfer"
data-i18n="withdraw_exchange.transfer"
>
Transfer
</button>
</div>
<div class="mode-panel" data-panel="withdraw">
<label class="field">
<span data-i18n="withdraw_exchange.withdraw_amount"
>Withdraw amount</span
>
<div class="field-control amount-control">
<span aria-hidden="true">$</span>
<input
id="withdrawAmount"
type="number"
inputmode="decimal"
min="50"
step="0.01"
aria-label="Withdraw amount"
data-i18n-aria="withdraw_exchange.withdraw_amount"
/>
</div>
</label>
<div class="hint-row">
<span data-i18n="withdraw_exchange.minimum"
>Minimum 50 USD</span
>
<button
class="text-action"
id="allButton"
type="button"
data-i18n="withdraw_exchange.all"
>
All
</button>
</div>
</div>
<div class="mode-panel" data-panel="exchange">
<label class="field">
<span data-i18n="withdraw_exchange.exchange_amount"
>Exchange amount</span
>
<div class="field-control amount-control">
<span aria-hidden="true">$</span>
<input
id="exchangeAmount"
type="number"
inputmode="decimal"
min="0"
step="0.01"
aria-label="Exchange amount"
data-i18n-aria="withdraw_exchange.exchange_amount"
/>
</div>
</label>
<div class="exchange-preview">
<span data-i18n="withdraw_exchange.exchange_rate"
>Exchange rate</span
>
<strong id="exchangeRateText"></strong>
</div>
</div>
<div class="mode-panel" data-panel="transfer">
<div class="field">
<span data-i18n="withdraw_exchange.transfer_to"
>Transfer to</span
>
<div class="transfer-search">
<input
id="transferAccount"
type="text"
inputmode="numeric"
autocomplete="off"
aria-label="Transfer to"
data-i18n-aria="withdraw_exchange.transfer_to"
/>
<button
class="search-payee-button"
id="searchPayeeButton"
type="button"
data-i18n="withdraw_exchange.search"
>
Search
</button>
</div>
</div>
<div class="payee-result" id="payeeResult" hidden></div>
<label class="field transfer-amount-field">
<span data-i18n="withdraw_exchange.transfer_amount"
>Transfer amount</span
>
<div class="field-control amount-control">
<span aria-hidden="true">$</span>
<input
id="transferAmount"
type="number"
inputmode="decimal"
min="0"
step="0.01"
aria-label="Transfer amount"
data-i18n-aria="withdraw_exchange.transfer_amount"
/>
</div>
</label>
</div>
</section>
<section
class="card-section payment-section"
id="paymentSection"
>
<div class="section-head">
<div>
<div
class="section-title"
data-i18n="withdraw_exchange.payment_method"
>
USDT TRC20 address
</div>
<div
class="section-subtitle"
data-i18n="withdraw_exchange.payment_method_subtitle"
>
Withdrawals are sent to your TRC20 USDT address.
</div>
</div>
</div>
<div class="empty-address-state" id="emptyAddressState">
<div class="empty-icon" aria-hidden="true">
<svg viewBox="0 0 32 32">
<path d="M9 16a5 5 0 0 1 5-5h3" />
<path d="M15 21h-3a5 5 0 0 1 0-10h3" />
<path d="M17 21h3a5 5 0 0 0 0-10h-3" />
<path d="M13 16h6" />
</svg>
</div>
<div>
<div
class="empty-title"
data-i18n="withdraw_exchange.no_payment_info"
>
No USDT address
</div>
<div
class="empty-copy"
data-i18n="withdraw_exchange.no_payment_info_copy"
>
Fill in a TRC20 USDT address before withdrawing.
</div>
</div>
</div>
<div class="address-form" id="addressForm">
<label class="field">
<span data-i18n="withdraw_exchange.trc20_address"
>TRC20 address</span
>
<input
id="trc20Address"
type="text"
autocomplete="off"
/>
</label>
<button
class="primary-button"
id="saveAddressButton"
type="button"
data-i18n="withdraw_exchange.save_address"
>
Save address
</button>
</div>
<div
class="bound-address-card"
id="boundAddressCard"
hidden
>
<div class="network-badge" aria-hidden="true">
TRC20
</div>
<div class="bound-copy">
<div class="bound-network">USDT TRC20</div>
<div class="bound-address" id="boundAddress">-</div>
<div
class="bound-meta"
data-i18n="withdraw_exchange.usdt_only"
>
USDT only
</div>
</div>
</div>
</section>
<button
class="submit-button"
id="submitButton"
type="button"
disabled
data-i18n="withdraw_exchange.transfer_now"
>
Transfer now
</button>
</main>
<div class="salary-history-modal" id="salaryHistoryModal" hidden>
<button
class="salary-history-backdrop"
id="salaryHistoryBackdrop"
type="button"
aria-label="Close"
data-i18n-aria="withdraw_exchange.close"
></button>
<section
class="salary-history-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="salaryHistoryTitle"
>
<div class="salary-history-head">
<h2
id="salaryHistoryTitle"
data-i18n="withdraw_exchange.salary_history"
>
Salary history
</h2>
<button
class="salary-history-close"
id="salaryHistoryCloseButton"
type="button"
aria-label="Close"
data-i18n-aria="withdraw_exchange.close"
>
×
</button>
</div>
<div class="salary-history-summary">
<span data-i18n="withdraw_exchange.salary">salary</span>
<strong id="salaryHistoryTotal">$0.00</strong>
</div>
<div
class="salary-history-list"
id="salaryHistoryList"
></div>
</section>
</div>
<div class="home-indicator" aria-hidden="true"></div>
</div>
<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>
</body>
</html>

View File

@ -0,0 +1,589 @@
(function () {
var EXCHANGE_RATE = 80000;
var WITHDRAW_MIN_AMOUNT = 50;
var params = new URLSearchParams(window.location.search);
var currentMode = normalizeMode(params.get('mode')) || 'transfer';
var state = {
balance: 0,
paymentInfo: null,
selectedPayee: null,
isSearching: false,
isSaving: false,
isSubmitting: false,
historyItems: [],
};
var lastSearchTriggerAt = 0;
var autoSearchTimer = 0;
var mock = {
balance: 30650.75,
paymentInfo: null,
payees: {
163003: {
id: 'payee_163003',
name: 'Yumi Star Agency',
account: '163003',
avatar: '',
},
163000: {
id: 'payee_163000',
name: 'quick_1780052629537',
account: '163000',
avatar: '',
},
},
history: [
{
key: 'withdraw_exchange.history_host_salary',
title: 'Host salary',
amount: 18400.25,
balance: 30650.75,
type: 0,
date: '2026-06-01 12:10',
},
{
key: 'withdraw_exchange.history_exchange_to_golds',
title: 'Exchange to golds',
amount: 800,
balance: 12250.5,
type: 1,
date: '2026-05-30 20:42',
},
{
key: 'withdraw_exchange.history_gift_reward',
title: 'Gift reward',
amount: 8250.5,
balance: 13050.5,
type: 0,
date: '2026-05-28 18:30',
},
],
};
var inputs = {
withdraw: $('withdrawAmount'),
exchange: $('exchangeAmount'),
transfer: $('transferAmount'),
};
function $(id) {
return document.getElementById(id);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function toast(message) {
if (window.HyAppToast) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function normalizeMode(mode) {
var value = String(mode || '').trim();
return ['withdraw', 'exchange', 'transfer'].indexOf(value) >= 0
? value
: '';
}
function money(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
}
function moneyInput(value) {
var number = Number(value || 0);
return Number.isFinite(number) ? number.toFixed(2) : '0.00';
}
function amount() {
var input = inputs[currentMode];
return Number(input && input.value ? input.value : 0) || 0;
}
function delay(value) {
return new Promise(function (resolve) {
window.setTimeout(function () {
resolve(value);
}, 260);
});
}
function mockRequest(action, payload) {
if (action === 'balance') return delay(mock.balance);
if (action === 'payment') return delay(mock.paymentInfo);
if (action === 'history') return delay(mock.history.slice());
if (action === 'saveAddress') {
mock.paymentInfo = {
id: 'usdt_mock_1',
cardNo: payload.cardNo,
};
return delay(mock.paymentInfo);
}
if (action === 'searchPayee') {
var account = String(payload.account || '').trim();
var payee = mock.payees[account];
if (!payee && account && account !== '000000') {
payee = {
id: 'payee_' + account,
name: 'User ' + account,
nameKey: 'withdraw_exchange.mock_user_name',
account: account,
avatar: '',
};
}
return delay(payee || null);
}
if (action === 'submit') {
mock.balance = Math.max(0, mock.balance - payload.amount);
mock.history.unshift({
title: titleForMode(payload.mode),
amount: payload.amount,
balance: mock.balance,
type: 1,
date: new Date().toISOString().replace('T', ' ').slice(0, 16),
});
return delay({ ok: true });
}
return delay(null);
}
function titleForMode(mode) {
if (mode === 'withdraw')
return t('withdraw_exchange.withdraw', 'Withdraw');
if (mode === 'exchange')
return t('withdraw_exchange.exchange', 'Exchange');
return t('withdraw_exchange.transfer', 'Transfer');
}
function isValidTrc20(value) {
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || '').trim());
}
function maskAddress(value) {
var text = String(value || '').trim();
if (text.length <= 12) return text || '-';
return text.slice(0, 6) + '...' + text.slice(-6);
}
function activeSubmitLabel() {
if (currentMode === 'withdraw')
return t('withdraw_exchange.withdraw_now', 'Withdraw now');
if (currentMode === 'exchange')
return t('withdraw_exchange.exchange_now', 'Exchange now');
return t('withdraw_exchange.transfer_now', 'Transfer now');
}
function renderBalance() {
$('balanceAmount').textContent = money(state.balance);
Object.keys(inputs).forEach(function (key) {
if (inputs[key]) inputs[key].max = moneyInput(state.balance);
});
}
function renderMode() {
document.querySelectorAll('.mode-tab').forEach(function (tab) {
var active = tab.getAttribute('data-mode') === currentMode;
tab.classList.toggle('active', active);
tab.setAttribute('aria-selected', String(active));
});
document.querySelectorAll('.mode-panel').forEach(function (panel) {
panel.classList.toggle(
'active',
panel.getAttribute('data-panel') === currentMode
);
});
$('paymentSection').hidden = currentMode !== 'withdraw';
updateSubmit();
}
function renderPaymentInfo() {
var payment = state.paymentInfo;
$('emptyAddressState').hidden = Boolean(payment);
$('addressForm').hidden = Boolean(payment);
$('boundAddressCard').hidden = !payment;
if (payment)
$('boundAddress').textContent = maskAddress(payment.cardNo);
updateSubmit();
}
function renderPayee() {
var result = $('payeeResult');
result.textContent = '';
if (!state.selectedPayee) {
result.hidden = true;
updateSubmit();
return;
}
var payee = state.selectedPayee;
var payeeName = payee.nameKey
? t(payee.nameKey, payee.name || 'User {account}').replace(
'{account}',
payee.account
)
: payee.name;
var avatar = document.createElement('div');
var copy = document.createElement('div');
var name = document.createElement('div');
var id = document.createElement('div');
avatar.className = 'payee-avatar';
copy.className = 'payee-copy';
name.className = 'payee-name';
id.className = 'payee-id';
avatar.textContent = String(payeeName || 'U')
.charAt(0)
.toUpperCase();
name.textContent = payeeName || '-';
id.textContent =
t('withdraw_exchange.uid_prefix', 'UID:') + ' ' + payee.account;
copy.appendChild(name);
copy.appendChild(id);
result.appendChild(avatar);
result.appendChild(copy);
result.hidden = false;
updateSubmit();
}
function renderHistory() {
$('salaryHistoryTotal').textContent = '$' + money(state.balance);
var list = $('salaryHistoryList');
list.textContent = '';
if (!state.historyItems.length) {
var empty = document.createElement('div');
empty.className = 'salary-history-empty';
empty.textContent = t(
'withdraw_exchange.no_salary_history',
'No salary history'
);
list.appendChild(empty);
return;
}
state.historyItems.forEach(function (item) {
var row = document.createElement('article');
var main = document.createElement('div');
var title = document.createElement('div');
var meta = document.createElement('div');
var value = document.createElement('div');
var isOut = Number(item.type) === 1;
row.className = 'salary-history-item';
main.className = 'salary-history-item-main';
title.className = 'salary-history-item-title';
meta.className = 'salary-history-item-meta';
value.className =
'salary-history-amount' + (isOut ? ' is-out' : '');
title.textContent = item.key ? t(item.key, item.title) : item.title;
meta.textContent =
item.date +
' ' +
t('withdraw_exchange.balance', 'Balance') +
': $' +
money(item.balance);
value.textContent = (isOut ? '-' : '+') + '$' + money(item.amount);
main.appendChild(title);
main.appendChild(meta);
row.appendChild(main);
row.appendChild(value);
list.appendChild(row);
});
}
function updateSubmit() {
var button = $('submitButton');
if (state.isSubmitting) {
button.textContent = t(
'withdraw_exchange.submitting',
'Submitting...'
);
button.disabled = true;
return;
}
var value = amount();
var disabled =
value <= 0 ||
value > state.balance ||
(currentMode === 'withdraw' &&
(!state.paymentInfo || value < WITHDRAW_MIN_AMOUNT)) ||
(currentMode === 'transfer' && !state.selectedPayee);
button.textContent = activeSubmitLabel();
button.disabled = disabled;
}
function normalizeAmount(event) {
var input = event.target;
var raw = String(input.value || '').replace(/[^\d.]/g, '');
var parts = raw.split('.');
var next =
parts.length > 2 ? parts[0] + '.' + parts.slice(1).join('') : raw;
var value = Number(next);
if (Number.isFinite(value) && value > state.balance)
next = moneyInput(state.balance);
input.value = next;
updateSubmit();
}
function setMode(mode) {
currentMode = normalizeMode(mode) || 'transfer';
renderMode();
}
function openHistory() {
$('salaryHistoryModal').hidden = false;
document.body.classList.add('modal-open');
$('salaryHistoryList').textContent = t(
'withdraw_exchange.loading',
'Loading...'
);
mockRequest('history').then(function (items) {
state.historyItems = items || [];
renderHistory();
});
}
function closeHistory() {
$('salaryHistoryModal').hidden = true;
document.body.classList.remove('modal-open');
}
function saveAddress() {
var address = String($('trc20Address').value || '').trim();
if (!isValidTrc20(address)) {
toast(
t(
'withdraw_exchange.invalid_address',
'Please enter a valid TRC20 USDT address'
)
);
return;
}
state.isSaving = true;
$('saveAddressButton').disabled = true;
$('saveAddressButton').textContent = t(
'withdraw_exchange.saving',
'Saving...'
);
mockRequest('saveAddress', { cardNo: address }).then(
function (payment) {
state.paymentInfo = payment;
state.isSaving = false;
$('saveAddressButton').disabled = false;
$('saveAddressButton').textContent = t(
'withdraw_exchange.save_address',
'Save address'
);
renderPaymentInfo();
toast(t('withdraw_exchange.address_saved', 'Address saved'));
}
);
}
function searchPayee() {
var now = Date.now();
if (now - lastSearchTriggerAt < 240) return;
lastSearchTriggerAt = now;
var account = String($('transferAccount').value || '').trim();
if (!account) {
toast(
t(
'withdraw_exchange.missing_payee',
'Please search and select a user'
)
);
return;
}
state.selectedPayee = null;
renderPayee();
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();
});
}
function validateSubmit() {
var value = amount();
if (value <= 0)
return t(
'withdraw_exchange.invalid_amount',
'Please enter a valid amount'
);
if (value > state.balance)
return t(
'withdraw_exchange.amount_exceeds_balance',
'Amount exceeds salary'
);
if (currentMode === 'withdraw' && !state.paymentInfo)
return t(
'withdraw_exchange.missing_payment_info',
'Please add a TRC20 USDT address'
);
if (currentMode === 'withdraw' && value < WITHDRAW_MIN_AMOUNT)
return t(
'withdraw_exchange.amount_too_low',
'Minimum withdrawal amount is 50 USD'
);
if (currentMode === 'transfer' && !state.selectedPayee)
return t(
'withdraw_exchange.missing_payee',
'Please search and select a user'
);
return '';
}
function submit() {
var error = validateSubmit();
if (error) {
toast(error);
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'));
});
}
function goBack() {
if (window.history.length > 1) {
window.history.back();
return;
}
var nextParams = new URLSearchParams(window.location.search);
nextParams.delete('mode');
var query = nextParams.toString();
window.location.href =
'../host-center/index.html' + (query ? '?' + query : '');
}
function bindEvents() {
function bindTap(id, handler) {
var node = $(id);
var last = 0;
function run(event) {
var now = Date.now();
if (now - last < 220) return;
last = now;
if (event && event.type === 'pointerdown') {
event.preventDefault();
}
handler(event);
}
node.addEventListener('pointerdown', run);
node.addEventListener('click', run);
}
bindTap('backButton', goBack);
document.querySelectorAll('.mode-tab').forEach(function (tab) {
tab.addEventListener('click', function () {
setMode(tab.getAttribute('data-mode'));
});
});
Object.keys(inputs).forEach(function (key) {
if (inputs[key])
inputs[key].addEventListener('input', normalizeAmount);
});
bindTap('allButton', function () {
inputs.withdraw.value = moneyInput(state.balance);
updateSubmit();
});
$('transferAccount').addEventListener('input', function () {
state.selectedPayee = null;
renderPayee();
window.clearTimeout(autoSearchTimer);
if (String($('transferAccount').value || '').trim().length >= 3) {
autoSearchTimer = window.setTimeout(searchPayee, 260);
}
});
$('transferAccount').addEventListener('keydown', function (event) {
if (event.key === 'Enter') searchPayee();
});
bindTap('searchPayeeButton', searchPayee);
bindTap('saveAddressButton', saveAddress);
bindTap('submitButton', submit);
bindTap('salaryHistoryButton', openHistory);
bindTap('salaryHistoryBackdrop', closeHistory);
bindTap('salaryHistoryCloseButton', closeHistory);
}
function renderStaticDynamicText() {
$('exchangeRateText').textContent = t(
'withdraw_exchange.exchange_rate_value',
'1$ = {amount} golds'
).replace('{amount}', EXCHANGE_RATE.toLocaleString('en-US'));
if (!$('salaryHistoryModal').hidden) renderHistory();
updateSubmit();
renderPayee();
}
function init() {
bindEvents();
setMode(currentMode);
renderStaticDynamicText();
mockRequest('balance').then(function (balance) {
state.balance = balance;
renderBalance();
updateSubmit();
});
mockRequest('payment').then(function (payment) {
state.paymentInfo = payment;
renderPaymentInfo();
});
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'withdraw-exchange',
mock: true,
});
}
}
document.addEventListener('DOMContentLoaded', init);
window.addEventListener('hyapp:i18n-ready', renderStaticDynamicText);
})();

View File

@ -0,0 +1,848 @@
:root {
--page-bg: var(--hy-theme-bg, #fbf8ff);
--card-bg: var(--hy-theme-surface, rgba(255, 255, 255, 0.96));
--text: var(--hy-theme-text, #282333);
--muted: var(--hy-theme-muted, #8d879a);
--soft: var(--hy-theme-primary-soft, #f4ebff);
--line: var(--hy-theme-line, #f0e8fb);
--primary: var(--hy-theme-primary, #dbc8ff);
--primary-strong: var(--hy-theme-primary-strong, #c5a6f6);
--primary-deep: var(--hy-theme-primary-deep, #7d57c7);
--gold: #e3b55b;
--shadow: var(--hy-theme-shadow, 0 10px 24px rgba(132, 90, 212, 0.075));
--button: var(--hy-theme-button, #7d57c7);
--button-disabled: var(--hy-theme-button-disabled, #eadffc);
--button-disabled-text: var(--hy-theme-button-disabled-text, #9a8faa);
}
* {
box-sizing: border-box;
}
html,
body {
width: 100%;
min-height: 100%;
margin: 0;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
body {
display: flex;
justify-content: center;
background: #111;
color: var(--text);
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif;
}
button,
input {
font: inherit;
}
button {
border: 0;
padding: 0;
background: transparent;
color: inherit;
}
button:focus {
outline: none;
}
button:focus-visible {
outline: 2px solid rgba(125, 87, 199, 0.28);
outline-offset: 2px;
}
input {
width: 100%;
border: 0;
outline: 0;
background: transparent;
color: var(--text);
}
[hidden] {
display: none !important;
}
.withdraw-exchange-page {
position: relative;
width: 100%;
max-width: 430px;
min-height: 100vh;
min-height: 100dvh;
overflow: hidden auto;
background: var(--page-bg);
}
.hero-bg {
position: absolute;
inset: 0 0 auto;
height: 215px;
background: var(
--hy-theme-hero,
linear-gradient(
151deg,
#f0e6ff 0%,
#fffbff 58%,
rgba(251, 248, 255, 0.88) 100%
)
);
clip-path: polygon(0 0, 100% 0, 100% 76%, 70% 47%, 40% 58%, 0 78%);
}
.title-bar,
.content,
.home-indicator {
position: relative;
z-index: 1;
}
.title-bar {
display: grid;
grid-template-columns: 52px 1fr 52px;
align-items: center;
z-index: 12;
height: 60px;
padding: 0 14px;
direction: ltr;
}
.title-bar h1 {
margin: 0;
color: #24282e;
font-size: 22px;
font-weight: 950;
line-height: 1;
text-align: center;
}
.back-button {
display: flex;
align-items: center;
justify-content: flex-start;
width: 44px;
height: 44px;
}
.back-button svg {
width: 28px;
height: 28px;
}
.back-button path {
fill: none;
stroke: #24282e;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 3;
}
.language-switcher {
position: relative;
justify-self: end;
}
.language-button {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 30px;
border: 1px solid rgba(35, 40, 46, 0.12);
border-radius: 15px;
background: rgba(255, 255, 255, 0.72);
color: #25282e;
font-size: 13px;
font-weight: 900;
box-shadow: 0 4px 12px rgba(132, 90, 212, 0.08);
}
.language-menu {
position: absolute;
z-index: 30;
top: calc(100% + 7px);
right: 0;
display: grid;
gap: 2px;
min-width: 72px;
padding: 5px;
border: 1px solid rgba(35, 40, 46, 0.1);
border-radius: 8px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 10px 26px rgba(36, 46, 60, 0.14);
}
.language-menu button {
min-height: 34px;
border-radius: 6px;
color: #25282e;
font-size: 12px;
font-weight: 900;
}
.language-menu button.is-active {
background: var(--soft);
color: var(--primary-deep);
}
.content {
display: flex;
flex-direction: column;
gap: 14px;
padding: 8px 14px 92px;
}
.balance-card,
.mode-card,
.card-section {
width: 100%;
border-radius: 8px;
background: var(--card-bg);
box-shadow: var(--shadow);
}
.balance-card {
padding: 20px 24px 19px;
}
.balance-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.balance-label {
color: var(--muted);
font-size: 15px;
font-weight: 850;
}
.balance-history-button {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
flex: 0 0 42px;
border-radius: 50%;
background: var(--soft);
color: var(--primary-deep);
}
.balance-history-button svg {
width: 26px;
height: 26px;
}
.balance-history-button path {
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2.8;
}
.balance-value {
display: flex;
align-items: center;
margin-top: 13px;
color: #23272d;
font-size: 38px;
font-weight: 950;
line-height: 1.05;
}
.balance-currency {
flex: 0 0 auto;
margin-right: 8px;
color: var(--gold);
font-size: 31px;
font-weight: 950;
line-height: 1;
}
.mode-card {
padding: 16px;
}
.mode-tabs {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
padding: 4px;
border-radius: 8px;
background: var(--soft);
}
.mode-tab {
min-height: 46px;
border-radius: 7px;
color: var(--muted);
font-size: 15px;
font-weight: 950;
}
.mode-tab.active {
background: #fff;
color: var(--text);
box-shadow: 0 5px 14px rgba(132, 90, 212, 0.1);
}
.mode-panel {
display: none;
margin-top: 18px;
}
.mode-panel.active {
display: block;
}
.field {
display: block;
}
.field > span {
display: block;
margin-bottom: 8px;
color: #4a4d53;
font-size: 15px;
font-weight: 850;
}
.field-control,
.field input {
min-height: 52px;
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.field input {
padding: 0 14px;
}
.amount-control {
display: flex;
align-items: center;
padding: 0 14px;
}
.amount-control span {
flex: 0 0 auto;
margin-right: 9px;
color: var(--gold);
font-size: 24px;
font-weight: 950;
}
.amount-control input {
min-height: 0;
padding: 0;
background: transparent;
font-size: 23px;
font-weight: 900;
}
.hint-row,
.exchange-preview {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
color: var(--muted);
font-size: 13px;
font-weight: 800;
}
.text-action {
color: var(--primary-deep);
font-weight: 950;
}
.exchange-preview strong {
color: #24282e;
}
.transfer-search {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
}
.transfer-search input {
min-height: 52px;
padding: 0 14px;
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.search-payee-button {
min-width: 82px;
min-height: 52px;
padding: 0 14px;
border-radius: 8px;
background: var(--button);
color: #fff;
font-size: 15px;
font-weight: 950;
}
.search-payee-button:disabled {
background: var(--button-disabled);
color: var(--button-disabled-text);
}
.payee-result {
display: flex;
align-items: center;
gap: 12px;
min-height: 68px;
margin-top: 12px;
padding: 12px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.payee-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
flex: 0 0 44px;
overflow: hidden;
border-radius: 50%;
background: var(--soft);
color: var(--primary-deep);
font-weight: 950;
}
.payee-avatar img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.payee-copy {
min-width: 0;
flex: 1;
}
.payee-name {
overflow: hidden;
color: #25282e;
font-size: 15px;
font-weight: 900;
text-overflow: ellipsis;
white-space: nowrap;
}
.payee-id {
margin-top: 4px;
overflow: hidden;
color: var(--muted);
font-size: 12px;
font-weight: 800;
text-overflow: ellipsis;
white-space: nowrap;
}
.transfer-amount-field {
margin-top: 14px;
}
.card-section {
padding: 18px 16px;
}
.section-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.section-title {
color: #24282e;
font-size: 17px;
font-weight: 900;
}
.section-subtitle {
margin-top: 4px;
color: var(--muted);
font-size: 13px;
font-weight: 750;
}
.empty-address-state {
display: flex;
align-items: center;
gap: 13px;
min-height: 76px;
margin-top: 16px;
padding: 13px;
border: 1px dashed var(--line);
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.empty-icon {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
flex: 0 0 42px;
border-radius: 50%;
background: var(--soft);
}
.empty-icon svg {
width: 24px;
height: 24px;
}
.empty-icon path {
fill: none;
stroke: var(--primary-deep);
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2.2;
}
.empty-title {
color: #292d33;
font-size: 15px;
font-weight: 900;
}
.empty-copy {
margin-top: 3px;
color: var(--muted);
font-size: 12px;
font-weight: 750;
line-height: 1.25;
}
.address-form {
display: flex;
flex-direction: column;
margin-top: 14px;
}
.address-form input {
min-height: 48px;
padding: 0 14px;
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.bound-address-card {
display: flex;
align-items: center;
gap: 14px;
min-height: 88px;
margin-top: 16px;
padding: 14px;
border-radius: 8px;
background: linear-gradient(135deg, #4a3378 0%, #7d57c7 100%);
color: #fff;
}
.network-badge {
display: flex;
align-items: center;
justify-content: center;
width: 56px;
height: 32px;
flex: 0 0 56px;
border-radius: 7px;
background: linear-gradient(135deg, #ffe58b 0%, #c8942e 100%);
color: #1f252c;
font-size: 12px;
font-weight: 950;
}
.bound-copy {
min-width: 0;
flex: 1 1 auto;
}
.bound-network {
font-size: 15px;
font-weight: 900;
}
.bound-address {
margin-top: 5px;
overflow-wrap: anywhere;
color: rgba(255, 255, 255, 0.82);
font-size: 14px;
font-weight: 850;
}
.bound-meta {
margin-top: 4px;
color: rgba(255, 255, 255, 0.62);
font-size: 12px;
font-weight: 750;
}
.primary-button,
.submit-button {
min-height: 50px;
border-radius: 25px;
font-size: 16px;
font-weight: 950;
}
.primary-button,
.submit-button {
background: var(--button);
color: #fff;
}
.primary-button {
width: 100%;
margin-top: 14px;
}
.submit-button {
width: 100%;
box-shadow: var(
--hy-theme-button-shadow,
0 8px 18px rgba(125, 87, 199, 0.18)
);
}
.primary-button:disabled,
.submit-button:disabled {
background: var(--button-disabled);
color: var(--button-disabled-text);
box-shadow: var(--hy-theme-button-disabled-shadow, none);
}
.salary-history-modal {
position: fixed;
inset: 0;
z-index: 60;
display: flex;
align-items: flex-end;
justify-content: center;
}
.salary-history-backdrop {
position: absolute;
inset: 0;
background: rgba(14, 19, 24, 0.44);
}
.salary-history-dialog {
position: relative;
z-index: 1;
display: flex;
width: min(100%, 430px);
max-height: 78vh;
max-height: 78dvh;
flex-direction: column;
overflow: hidden;
border-radius: 18px 18px 0 0;
background: #fff;
box-shadow: 0 -14px 36px rgba(26, 35, 44, 0.16);
}
.salary-history-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 18px 18px 12px;
}
.salary-history-head h2 {
min-width: 0;
margin: 0;
overflow: hidden;
color: #24282e;
font-size: 18px;
font-weight: 950;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.salary-history-close {
display: flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
flex: 0 0 34px;
border-radius: 50%;
background: #f3f5f5;
color: #676b72;
font-size: 28px;
line-height: 1;
}
.salary-history-summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin: 0 18px 12px;
padding: 14px;
border-radius: 8px;
background: var(--soft);
}
.salary-history-summary span {
color: var(--muted);
font-size: 13px;
font-weight: 850;
}
.salary-history-summary strong {
min-width: 0;
overflow-wrap: anywhere;
color: #24282e;
font-size: 20px;
font-weight: 950;
}
.salary-history-list {
display: grid;
gap: 10px;
overflow-y: auto;
padding: 0 18px calc(18px + env(safe-area-inset-bottom));
}
.salary-history-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px 12px;
padding: 14px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--hy-theme-surface-soft, #fdfaff);
}
.salary-history-item-main {
min-width: 0;
}
.salary-history-item-title {
overflow: hidden;
color: #25282e;
font-size: 14px;
font-weight: 900;
line-height: 1.25;
text-overflow: ellipsis;
white-space: nowrap;
}
.salary-history-item-meta {
display: flex;
flex-wrap: wrap;
gap: 6px 10px;
margin-top: 6px;
color: var(--muted);
font-size: 12px;
font-weight: 750;
line-height: 1.25;
}
.salary-history-amount {
color: var(--primary-deep);
font-size: 15px;
font-weight: 950;
line-height: 1.25;
white-space: nowrap;
}
.salary-history-amount.is-out {
color: var(--hy-theme-danger, #d95d72);
}
.salary-history-empty {
padding: 24px 12px 30px;
color: var(--muted);
font-size: 14px;
font-weight: 850;
text-align: center;
}
.modal-open {
overflow: hidden;
}
.home-indicator {
position: fixed;
left: 50%;
bottom: 8px;
width: 154px;
height: 5px;
border-radius: 999px;
background: #050506;
transform: translateX(-50%);
}
[dir='rtl'] .content {
direction: rtl;
}
[dir='rtl'] .balance-currency,
[dir='rtl'] .amount-control span {
margin-right: 0;
margin-left: 9px;
}
[dir='rtl'] .home-indicator {
direction: ltr;
}
@media (max-width: 360px) {
.content {
padding-right: 12px;
padding-left: 12px;
}
.balance-card {
padding-right: 18px;
padding-left: 18px;
}
.balance-value {
font-size: 31px;
}
.title-bar h1 {
font-size: 19px;
}
.mode-tab {
font-size: 13px;
}
.transfer-search {
grid-template-columns: 1fr;
}
}