主题色

This commit is contained in:
zhx 2026-06-24 14:26:39 +08:00
parent f88ace4673
commit 0d0d2c42c6
6 changed files with 628 additions and 118 deletions

View File

@ -130,7 +130,9 @@ var default_api = 'https://api.global-interaction.com/';
if (!api) return '';
if (env === 'local' && api.local) return normalizeBaseURL(api.local);
if (env === 'test' && api.test) return normalizeBaseURL(api.test);
return api.prod || api.default ? normalizeBaseURL(api.prod || api.default) : '';
return api.prod || api.default
? normalizeBaseURL(api.prod || api.default)
: '';
}
function buildURL(path, query) {
@ -191,17 +193,51 @@ var default_api = 'https://api.global-interaction.com/';
return storedToken;
}
function themeAppCode(appCode) {
appCode = String(appCode || 'lalu')
.trim()
.toLowerCase();
return appCode === 'yumi' || appCode === 'aslan' ? appCode : 'lalu';
}
function applyAppTheme(appCode) {
if (!window.document || !window.document.documentElement) return;
window.document.documentElement.setAttribute(
'data-hy-app-code',
themeAppCode(appCode)
);
}
function peekAppCode() {
var queryAppCode =
readQuery('app') || readQuery('app_code') || readQuery('appCode');
if (queryAppCode) return queryAppCode;
if (memoryAppCode) return memoryAppCode;
if (!shouldPersist()) return 'lalu';
return window.localStorage.getItem(APP_CODE_KEY) || 'lalu';
}
function getAppCode() {
var queryAppCode = readQuery('app') || readQuery('app_code') || readQuery('appCode');
var queryAppCode =
readQuery('app') || readQuery('app_code') || readQuery('appCode');
if (queryAppCode) {
memoryAppCode = queryAppCode;
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, queryAppCode);
applyAppTheme(queryAppCode);
return queryAppCode;
}
if (memoryAppCode) return memoryAppCode;
if (!shouldPersist()) return 'lalu';
return window.localStorage.getItem(APP_CODE_KEY) || 'lalu';
if (memoryAppCode) {
applyAppTheme(memoryAppCode);
return memoryAppCode;
}
if (!shouldPersist()) {
applyAppTheme('lalu');
return 'lalu';
}
var storedAppCode = window.localStorage.getItem(APP_CODE_KEY) || 'lalu';
applyAppTheme(storedAppCode);
return storedAppCode;
}
function setAccessToken(token) {
@ -218,6 +254,7 @@ var default_api = 'https://api.global-interaction.com/';
function setAppCode(appCode) {
memoryAppCode = appCode || '';
applyAppTheme(appCode || 'lalu');
if (appCode) {
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, appCode);
@ -226,6 +263,8 @@ var default_api = 'https://api.global-interaction.com/';
if (shouldPersist()) window.localStorage.removeItem(APP_CODE_KEY);
}
applyAppTheme(peekAppCode());
function setAppConfig(config) {
activeAppConfig = config || null;
if (activeAppConfig && activeAppConfig.app) {
@ -239,17 +278,27 @@ var default_api = 'https://api.global-interaction.com/';
}
function loadAppConfig(scope) {
var appCode = String(getAppCode() || 'lalu').trim().toLowerCase();
var appCode = String(getAppCode() || 'lalu')
.trim()
.toLowerCase();
if (!appCode || appCode === 'lalu') {
activeAppConfig = null;
return Promise.resolve(null);
}
var scopePath = String(scope || '').replace(/^\/+|\/+$/g, '');
var configPath =
(scopePath ? '/' + scopePath : '.') + '/config/' + appCode + '.json';
var configURL = new URL(configPath, window.location.origin + window.location.pathname);
(scopePath ? '/' + scopePath : '.') +
'/config/' +
appCode +
'.json';
var configURL = new URL(
configPath,
window.location.origin + window.location.pathname
);
return window
.fetch(configURL.toString(), { cache: shouldPersist() ? 'default' : 'no-store' })
.fetch(configURL.toString(), {
cache: shouldPersist() ? 'default' : 'no-store',
})
.then(function (response) {
if (!response.ok) return null;
return response.json();
@ -322,7 +371,7 @@ var default_api = 'https://api.global-interaction.com/';
: payload &&
Object.prototype.hasOwnProperty.call(payload, 'body')
? payload.body
: payload;
: payload;
});
}
@ -494,7 +543,8 @@ var default_api = 'https://api.global-interaction.com/';
).toUpperCase();
var candidates = countries.filter(function (country) {
return (
String(country.country_code || '').toUpperCase() === countryCode ||
String(country.country_code || '').toUpperCase() ===
countryCode ||
String(country.country_code || '').toUpperCase() === 'GLOBAL'
);
});
@ -616,9 +666,15 @@ var default_api = 'https://api.global-interaction.com/';
return {
id: item.id || '',
pay_country_id:
item.payCountryId || item.pay_country_id || item.id || '',
item.payCountryId ||
item.pay_country_id ||
item.id ||
'',
payCountryId:
item.payCountryId || item.pay_country_id || item.id || '',
item.payCountryId ||
item.pay_country_id ||
item.id ||
'',
country_id: item.countryId || item.country_id || '',
currency_code: item.currency || item.currency_code || '',
currencyCode: item.currency || item.currency_code || '',
@ -640,8 +696,12 @@ var default_api = 'https://api.global-interaction.com/';
var products = (options.commodity || options.products || []).map(
function (item) {
var content = Number(item.content || 0);
var awardContent = Number(item.awardContent || item.award_content || 0);
var amountUsd = normalizeAmountUsd(item.amountUsd || item.amount_usd);
var awardContent = Number(
item.awardContent || item.award_content || 0
);
var amountUsd = normalizeAmountUsd(
item.amountUsd || item.amount_usd
);
return {
product_id: item.id,
productId: item.id,
@ -707,7 +767,8 @@ var default_api = 'https://api.global-interaction.com/';
}
function yumiPaymentMethods(options) {
var channels = (options.raw && options.raw.channels) || options.channels || [];
var channels =
(options.raw && options.raw.channels) || options.channels || [];
var supported = {};
channels.forEach(function (item) {
var channel = item.channel || {};
@ -740,7 +801,8 @@ var default_api = 'https://api.global-interaction.com/';
trade_no: order.tradeNo || order.trade_no || '',
provider_code: factoryCode === 'MIFA_PAY' ? 'mifapay' : factoryCode,
factory_code: factoryCode,
pay_url: order.requestUrl || order.request_url || order.pay_url || '',
pay_url:
order.requestUrl || order.request_url || order.pay_url || '',
currency_code: order.currency || order.currency_code || '',
country_code: order.countryCode || order.country_code || '',
provider_amount_minor: decimalToMinor(order.amount),
@ -777,16 +839,22 @@ var default_api = 'https://api.global-interaction.com/';
var rechargeAPI = {
context: function (displayUserID) {
if (isAslanWebPay()) {
return request(appEndpoint('context', '/order/web/pay/h5/context'), {
method: 'GET',
query: aslanUserQuery(displayUserID),
});
return request(
appEndpoint('context', '/order/web/pay/h5/context'),
{
method: 'GET',
query: aslanUserQuery(displayUserID),
}
);
}
if (isYumiWebPay()) {
return request(appEndpoint('context', '/order/web/pay/user-profile'), {
method: 'GET',
query: configuredWebPayUserQuery(displayUserID),
}).then(mapYumiContext);
return request(
appEndpoint('context', '/order/web/pay/user-profile'),
{
method: 'GET',
query: configuredWebPayUserQuery(displayUserID),
}
).then(mapYumiContext);
}
return request('/api/v1/recharge/h5/context', {
method: 'GET',
@ -803,10 +871,13 @@ var default_api = 'https://api.global-interaction.com/';
regionId: extra && (extra.region_id || extra.regionId),
userId: extra && (extra.user_id || extra.userId),
});
return request(appEndpoint('options', '/order/web/pay/h5/options'), {
method: 'GET',
query: query,
}).then(function (options) {
return request(
appEndpoint('options', '/order/web/pay/h5/options'),
{
method: 'GET',
query: query,
}
).then(function (options) {
options = options || {};
if (isYumiWebPay()) {
return mapYumiOptions(
@ -828,37 +899,45 @@ var default_api = 'https://api.global-interaction.com/';
},
createOrder: function (payload) {
if (isAslanWebPay()) {
return request(appEndpoint('orders', '/order/web/pay/h5/orders'), {
method: 'POST',
body: {
applicationId: activeAppConfig.application_id,
goodsId: payload && payload.product_id,
payCountryId: payload && payload.pay_country_id,
userId: payload && payload.user_id,
providerCode: payload && payload.provider_code,
payWay: payload && payload.pay_way,
payType: payload && payload.pay_type,
channelCode: payload && payload.channel_code,
returnUrl: payload && payload.return_url,
commandId: payload && payload.command_id,
type: (activeAppConfig && activeAppConfig.type) || 'GOLD',
language: readLanguageQuery() || 'en',
},
});
return request(
appEndpoint('orders', '/order/web/pay/h5/orders'),
{
method: 'POST',
body: {
applicationId: activeAppConfig.application_id,
goodsId: payload && payload.product_id,
payCountryId: payload && payload.pay_country_id,
userId: payload && payload.user_id,
providerCode: payload && payload.provider_code,
payWay: payload && payload.pay_way,
payType: payload && payload.pay_type,
channelCode: payload && payload.channel_code,
returnUrl: payload && payload.return_url,
commandId: payload && payload.command_id,
type:
(activeAppConfig && activeAppConfig.type) ||
'GOLD',
language: readLanguageQuery() || 'en',
},
}
);
}
if (isYumiWebPay()) {
return request(appEndpoint('orders', '/order/web/pay/recharge'), {
method: 'POST',
body: {
applicationId: activeAppConfig.application_id,
goodsId: payload && payload.product_id,
payCountryId: payload && payload.pay_country_id,
userId: payload && payload.user_id,
channelCode: payload && payload.channel_code,
newVersion: true,
appVersion: 'h5',
},
}).then(mapYumiOrder);
return request(
appEndpoint('orders', '/order/web/pay/recharge'),
{
method: 'POST',
body: {
applicationId: activeAppConfig.application_id,
goodsId: payload && payload.product_id,
payCountryId: payload && payload.pay_country_id,
userId: payload && payload.user_id,
channelCode: payload && payload.channel_code,
newVersion: true,
appVersion: 'h5',
},
}
).then(mapYumiOrder);
}
return request('/api/v1/recharge/h5/orders', {
method: 'POST',
@ -880,21 +959,24 @@ var default_api = 'https://api.global-interaction.com/';
getOrder: function (orderID, displayUserID) {
if (isAslanWebPay()) {
return request(
appEndpoint('order', '/order/web/pay/h5/orders/{orderId}').replace(
'{orderId}',
encodeURIComponent(orderID || '')
),
appEndpoint(
'order',
'/order/web/pay/h5/orders/{orderId}'
).replace('{orderId}', encodeURIComponent(orderID || '')),
{ method: 'GET' }
);
}
if (isYumiWebPay()) {
return request(appEndpoint('order', '/order/web/pay/order-status'), {
method: 'GET',
query: {
orderId: orderID || '',
userId: displayUserID || '',
},
}).then(mapYumiOrderStatus);
return request(
appEndpoint('order', '/order/web/pay/order-status'),
{
method: 'GET',
query: {
orderId: orderID || '',
userId: displayUserID || '',
},
}
).then(mapYumiOrderStatus);
}
return request(
'/api/v1/recharge/h5/orders/' +
@ -1107,15 +1189,21 @@ var default_api = 'https://api.global-interaction.com/';
method: 'GET',
});
},
searchUsers: function (keyword, pageSize) {
searchUsers: function (keyword, pageSize, scope) {
return request('/api/v1/manager-center/users/search', {
method: 'GET',
query: {
keyword: keyword,
page_size: pageSize || 20,
scope: scope,
},
});
},
listCountries: function () {
return request('/api/v1/countries', {
method: 'GET',
});
},
listResources: function (resourceType, pageSize) {
return request('/api/v1/manager-center/resource-grants/resources', {
method: 'GET',
@ -1175,6 +1263,12 @@ var default_api = 'https://api.global-interaction.com/';
body: payload || {},
});
},
transferUserCountry: function (payload) {
return request('/api/v1/manager-center/users/country', {
method: 'POST',
body: payload || {},
});
},
};
var superadminCenterAPI = bdLeaderCenterAPI;

View File

@ -18,6 +18,19 @@
--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-focus-ring: rgba(197, 166, 246, 0.18);
--hy-theme-role-shadow: 0 6px 16px rgba(91, 62, 142, 0.08);
--hy-theme-modal-shadow: 0 22px 54px rgba(40, 25, 72, 0.26);
--hy-theme-checkout-shadow: 0 -10px 28px rgba(40, 25, 72, 0.12);
--hy-theme-radius-tiny: 3px;
--hy-theme-radius-icon: 11px;
--hy-theme-radius-small: 12px;
--hy-theme-radius-control: 14px;
--hy-theme-radius-card: 16px;
--hy-theme-radius-language: 17px;
--hy-theme-radius-modal: 22px;
--hy-theme-radius-pill: 999px;
--hy-theme-radius-circle: 50%;
--hy-theme-hero: linear-gradient(
151deg,
#f0e6ff 0%,
@ -25,3 +38,65 @@
rgba(251, 248, 255, 0.88) 100%
);
}
:root[data-hy-app-code='yumi'] {
--hy-theme-bg: #f6fff8;
--hy-theme-surface: rgba(255, 255, 255, 0.97);
--hy-theme-surface-soft: #fbfffc;
--hy-theme-line: #d7efdf;
--hy-theme-primary: #bceccc;
--hy-theme-primary-strong: #6fd58f;
--hy-theme-primary-deep: #148846;
--hy-theme-primary-soft: #e8f8ee;
--hy-theme-accent: #8de0a8;
--hy-theme-success: #20b977;
--hy-theme-shadow: 0 10px 24px rgba(20, 136, 70, 0.075);
--hy-theme-button: #148846;
--hy-theme-button-disabled: #ccefd8;
--hy-theme-button-disabled-text: #6c9378;
--hy-theme-button-shadow: 0 8px 18px rgba(20, 136, 70, 0.18);
--hy-theme-focus-ring: rgba(20, 136, 70, 0.16);
--hy-theme-role-shadow: 0 6px 16px rgba(20, 136, 70, 0.08);
--hy-theme-modal-shadow: 0 22px 54px rgba(20, 84, 42, 0.22);
--hy-theme-checkout-shadow: 0 -10px 28px rgba(20, 84, 42, 0.1);
--hy-theme-radius-tiny: 50%;
--hy-theme-radius-icon: 50%;
--hy-theme-radius-small: 50%;
--hy-theme-radius-control: 50%;
--hy-theme-radius-card: 50%;
--hy-theme-radius-language: 50%;
--hy-theme-radius-modal: 50%;
--hy-theme-radius-pill: 50%;
--hy-theme-radius-circle: 50%;
}
:root[data-hy-app-code='aslan'] {
--hy-theme-bg: #fffdf3;
--hy-theme-surface: rgba(255, 255, 255, 0.98);
--hy-theme-surface-soft: #fffbf0;
--hy-theme-line: #efdc9f;
--hy-theme-primary: #ffe071;
--hy-theme-primary-strong: #f1bd2d;
--hy-theme-primary-deep: #8a5a00;
--hy-theme-primary-soft: #fff2bd;
--hy-theme-accent: #f6c43c;
--hy-theme-success: #2aa875;
--hy-theme-shadow: 0 10px 24px rgba(138, 90, 0, 0.08);
--hy-theme-button: #9b6500;
--hy-theme-button-disabled: #f0dfa9;
--hy-theme-button-disabled-text: #8f7b4c;
--hy-theme-button-shadow: 0 8px 18px rgba(138, 90, 0, 0.18);
--hy-theme-focus-ring: rgba(155, 101, 0, 0.18);
--hy-theme-role-shadow: 0 6px 16px rgba(138, 90, 0, 0.08);
--hy-theme-modal-shadow: 0 22px 54px rgba(92, 60, 0, 0.22);
--hy-theme-checkout-shadow: 0 -10px 28px rgba(92, 60, 0, 0.1);
--hy-theme-radius-tiny: 0;
--hy-theme-radius-icon: 0;
--hy-theme-radius-small: 0;
--hy-theme-radius-control: 0;
--hy-theme-radius-card: 0;
--hy-theme-radius-language: 0;
--hy-theme-radius-modal: 0;
--hy-theme-radius-pill: 0;
--hy-theme-radius-circle: 0;
}

View File

@ -107,6 +107,31 @@
>
</button>
<button
class="manager-tile"
type="button"
data-action="send-badge"
>
<span
class="tile-icon badge-icon"
aria-hidden="true"
>
<svg viewBox="0 0 48 48">
<path
d="M24 7 37 13v10c0 9-5.2 15-13 18-7.8-3-13-9-13-18V13Z"
/>
<path
d="m24 16 2.5 5.1 5.6.8-4.1 4 .9 5.7-4.9-2.7-4.9 2.7.9-5.7-4.1-4 5.6-.8Z"
/>
</svg>
</span>
<span
class="tile-title"
data-i18n="manager_center.send_badge"
>Send Badge</span
>
</button>
<button
class="manager-tile"
type="button"
@ -237,6 +262,30 @@
>
</button>
<button
class="manager-tile manager-tile-wide"
type="button"
data-action="transfer-user-country"
>
<span
class="tile-icon country-icon"
aria-hidden="true"
>
<svg viewBox="0 0 48 48">
<path
d="M24 42c8-8 13-15 13-23A13 13 0 1 0 11 19c0 8 5 15 13 23Z"
/>
<path d="M18 19h12" />
<path d="M24 13v12" />
</svg>
</span>
<span
class="tile-title"
data-i18n="manager_center.transfer_user_country"
>Transfer User Country</span
>
</button>
<button
class="manager-tile manager-tile-wide"
type="button"
@ -470,10 +519,10 @@
</div>
<script src="../../common/toast.js"></script>
<script src="../../common/api.js?v=20260612-manager-bd-leader"></script>
<script src="../../common/api.js?v=20260624-manager-badge-country"></script>
<script src="../../common/params.js?v=20260608-manager-real"></script>
<script src="../../common/jsbridge.js"></script>
<script src="../../common/i18n.js?v=20260608"></script>
<script src="./script.js?v=20260618-manager-permissions"></script>
<script src="./script.js?v=20260624-manager-badge-country"></script>
</body>
</html>

View File

@ -3,26 +3,31 @@
'block-user': 'Block User',
'send-frame': 'Send Frame',
'send-car': 'Send Car',
'send-badge': 'Send Badge',
'send-vip': 'Send VIP',
'update-user-level': 'Update User Level',
'add-bd-leader': 'Add BD Leader',
'add-admin': 'Add Admin',
'add-superadmin': 'Add Superadmin',
'transfer-user-country': 'Transfer User Country',
};
var DAY_MS = 24 * 60 * 60 * 1000;
var PERMANENT_BLOCK_MS = 10 * 365 * DAY_MS;
var RESOURCE_TYPES = {
'send-frame': 'avatar_frame',
'send-car': 'vehicle',
'send-badge': 'badge',
};
var ACTION_PERMISSION_KEYS = {
'send-frame': 'canGrantAvatarFrame',
'send-car': 'canGrantVehicle',
'send-badge': 'canGrantBadge',
'update-user-level': 'canUpdateUserLevel',
'add-bd-leader': 'canAddBdLeader',
'add-admin': 'canAddAdmin',
'add-superadmin': 'canAddSuperadmin',
'block-user': 'canBlockUser',
'transfer-user-country': 'canTransferUserCountry',
};
var RESOURCE_GRANT_DURATIONS = [
{ label: '7 days', ms: 7 * DAY_MS },
@ -43,6 +48,7 @@
overview: null,
permissions: {},
resourcesByType: {},
countries: [],
};
var blockState = {
searchedUser: null,
@ -73,6 +79,11 @@
searchedUser: null,
submitting: false,
};
var countryState = {
searchedUser: null,
selectedCountryCode: '',
submitting: false,
};
function $(id) {
return document.getElementById(id);
@ -235,6 +246,12 @@
: raw.can_grant_vehicle !== undefined
? Boolean(raw.can_grant_vehicle)
: true,
canGrantBadge:
raw.canGrantBadge !== undefined
? Boolean(raw.canGrantBadge)
: raw.can_grant_badge !== undefined
? Boolean(raw.can_grant_badge)
: true,
canUpdateUserLevel:
raw.canUpdateUserLevel !== undefined
? Boolean(raw.canUpdateUserLevel)
@ -265,6 +282,12 @@
: raw.can_block_user !== undefined
? Boolean(raw.can_block_user)
: true,
canTransferUserCountry:
raw.canTransferUserCountry !== undefined
? Boolean(raw.canTransferUserCountry)
: raw.can_transfer_user_country !== undefined
? Boolean(raw.can_transfer_user_country)
: true,
};
}
@ -287,11 +310,11 @@
return false;
}
function apiSearchUser(keyword) {
function apiSearchUser(keyword, scope) {
if (!api || !api.searchUsers) {
return Promise.reject(new Error('API not available.'));
}
return api.searchUsers(keyword, 20).then(function (data) {
return api.searchUsers(keyword, 20, scope).then(function (data) {
var items = (data && data.items) || [];
return items.map(normalizeUser);
});
@ -313,7 +336,9 @@
);
renderActionPermissions();
setDenied(false);
return canUseAction('block-user') ? refreshBlocks() : Promise.resolve();
return canUseAction('block-user')
? refreshBlocks()
: Promise.resolve();
})
.catch(function (error) {
setDenied(true);
@ -1095,6 +1120,239 @@
});
}
function normalizeCountry(item) {
item = item || {};
var code = String(
item.country_code ||
item.countryCode ||
item.code ||
item.alphaTwo ||
item.alpha_two ||
''
)
.trim()
.toUpperCase();
return {
code: code,
name:
item.country_display_name ||
item.countryDisplayName ||
item.country_name ||
item.countryName ||
item.name ||
code,
};
}
function countryLabel(country) {
if (!country) return '';
return country.name && country.name !== country.code
? country.name + ' · ' + country.code
: country.code;
}
function selectedCountry() {
for (var i = 0; i < pageState.countries.length; i += 1) {
if (
pageState.countries[i].code === countryState.selectedCountryCode
) {
return pageState.countries[i];
}
}
return null;
}
function loadCountries() {
if (pageState.countries.length) {
renderCountryOptions();
return Promise.resolve(pageState.countries);
}
if (!api || !api.listCountries) {
return Promise.reject(new Error('API not available.'));
}
return api
.listCountries()
.then(function (data) {
var list = (data && (data.countries || data.items)) || [];
pageState.countries = list
.map(normalizeCountry)
.filter(function (country) {
return !!country.code;
});
renderCountryOptions();
return pageState.countries;
})
.catch(showError);
}
function ensureCountryModal() {
if ($('countryModal')) return;
var modal = createNode('div', 'block-modal country-modal');
modal.id = 'countryModal';
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
modal.innerHTML =
'<button class="block-backdrop" id="countryBackdrop" type="button" aria-label="Close"></button>' +
'<section class="block-dialog" role="dialog" aria-modal="true" aria-labelledby="countryDialogTitle">' +
'<div class="block-dialog-header"><h2 id="countryDialogTitle">Transfer User Country</h2>' +
'<button class="block-close" id="countryCloseButton" type="button" aria-label="Close"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button></div>' +
'<div class="block-dialog-body"><div class="block-field"><label for="countrySearchInput">User ID</label>' +
'<div class="block-search-row"><input id="countrySearchInput" type="text" inputmode="numeric" autocomplete="off" placeholder="Enter user ID"/><button id="countrySearchButton" type="button">Search</button></div></div>' +
'<div class="block-search-result" id="countrySearchResult" aria-live="polite"></div>' +
'<div class="level-panel" id="countryPanel" hidden><div class="block-section-title">Select country</div><div class="grant-option-grid" id="countryOptionGrid"></div><button class="confirm-level-button" id="confirmCountryButton" type="button" disabled>Confirm Transfer</button></div></div></section>';
document.querySelector('.manager-center').appendChild(modal);
$('countryBackdrop').addEventListener('click', closeCountryModal);
$('countryCloseButton').addEventListener('click', closeCountryModal);
$('countrySearchButton').addEventListener('click', searchCountryUser);
$('countrySearchInput').addEventListener('keydown', function (event) {
if (event.key === 'Enter') searchCountryUser();
});
$('confirmCountryButton').addEventListener(
'click',
confirmCountryTransfer
);
}
function openCountryModal() {
if (pageState.denied) {
toast('Permission denied.');
return;
}
if (!ensureActionAllowed('transfer-user-country')) return;
ensureCountryModal();
countryState.searchedUser = null;
countryState.selectedCountryCode = '';
countryState.submitting = false;
$('countrySearchInput').value = '';
$('countrySearchResult').innerHTML = '';
$('countryPanel').hidden = true;
$('countryModal').hidden = false;
$('countryModal').setAttribute('aria-hidden', 'false');
loadCountries();
renderCountryActions();
setTimeout(function () {
$('countrySearchInput').focus();
}, 30);
}
function closeCountryModal() {
var modal = $('countryModal');
if (!modal) return;
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
}
function searchCountryUser() {
var value = $('countrySearchInput').value.trim();
if (!value) {
toast('Enter user ID.');
return;
}
apiSearchUser(value, 'all')
.then(function (items) {
if (!items.length) {
countryState.searchedUser = null;
$('countrySearchResult').innerHTML = '';
$('countryPanel').hidden = true;
renderCountryActions();
toast('No user found.');
return;
}
countryState.searchedUser = items[0];
var container = $('countrySearchResult');
container.innerHTML = '';
container.appendChild(
renderUserRow(
countryState.searchedUser,
'Select',
function () {
$('countryPanel').hidden = false;
renderCountryActions();
}
)
);
$('countryPanel').hidden = false;
renderCountryActions();
})
.catch(showError);
}
function renderCountryOptions() {
var grid = $('countryOptionGrid');
if (!grid) return;
grid.innerHTML = '';
if (!pageState.countries.length) {
grid.appendChild(
createNode('div', 'blocked-empty', 'No country available.')
);
renderCountryActions();
return;
}
pageState.countries.forEach(function (country) {
var button = createNode('button', 'country-option');
button.type = 'button';
button.classList.toggle(
'is-selected',
countryState.selectedCountryCode === country.code
);
button.appendChild(createNode('span', '', countryLabel(country)));
button.addEventListener('click', function () {
countryState.selectedCountryCode = country.code;
renderCountryOptions();
renderCountryActions();
});
grid.appendChild(button);
});
renderCountryActions();
}
function renderCountryActions() {
var confirm = $('confirmCountryButton');
if (!confirm) return;
var currentCountry = String(
(countryState.searchedUser && countryState.searchedUser.country) ||
''
).toUpperCase();
confirm.disabled =
!countryState.searchedUser ||
!countryState.selectedCountryCode ||
countryState.selectedCountryCode === currentCountry ||
countryState.submitting;
var country = selectedCountry();
confirm.textContent = country
? 'Transfer to ' + countryLabel(country)
: 'Confirm Transfer';
}
function confirmCountryTransfer() {
if (!countryState.searchedUser) {
toast('Search a user first.');
return;
}
if (!countryState.selectedCountryCode) {
toast('Select a country.');
return;
}
if (countryState.submitting) return;
countryState.submitting = true;
renderCountryActions();
api.transferUserCountry({
command_id: commandId('manager-country'),
target_user_id: userId(countryState.searchedUser),
country: countryState.selectedCountryCode,
reason: 'manager_center_country_transfer',
})
.then(function () {
toast('User country transferred.');
closeCountryModal();
})
.catch(showError)
.finally(function () {
countryState.submitting = false;
renderCountryActions();
});
}
function bindEvents() {
var backButton = $('backButton');
if (backButton) backButton.addEventListener('click', goBack);
@ -1112,6 +1370,10 @@
openLevelModal();
return;
}
if (action === 'transfer-user-country') {
openCountryModal();
return;
}
if (
action === 'add-bd-leader' ||
action === 'add-admin' ||

View File

@ -162,6 +162,11 @@
background: #eef4ff;
}
.badge-icon {
color: #3c8a6b;
background: #eaf8f1;
}
.vip-icon {
color: #d5a032;
background: #fff7dc;
@ -187,6 +192,11 @@
background: #fff2e6;
}
.country-icon {
color: #4e78d7;
background: #eef4ff;
}
.block-modal[hidden] {
display: none;
}
@ -486,6 +496,19 @@
white-space: nowrap;
}
.country-option {
display: grid;
min-height: 44px;
align-content: center;
line-height: 1.15;
}
.country-option span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.confirm-block-button,
.confirm-level-button {
height: 46px;

View File

@ -28,6 +28,19 @@
body {
overflow-x: hidden;
--recharge-focus-ring: var(--hy-theme-focus-ring);
--recharge-role-shadow: var(--hy-theme-role-shadow);
--recharge-modal-shadow: var(--hy-theme-modal-shadow);
--recharge-checkout-shadow: var(--hy-theme-checkout-shadow);
--recharge-radius-tiny: var(--hy-theme-radius-tiny);
--recharge-radius-icon: var(--hy-theme-radius-icon);
--recharge-radius-small: var(--hy-theme-radius-small);
--recharge-radius-control: var(--hy-theme-radius-control);
--recharge-radius-card: var(--hy-theme-radius-card);
--recharge-radius-language: var(--hy-theme-radius-language);
--recharge-radius-modal: var(--hy-theme-radius-modal);
--recharge-radius-pill: var(--hy-theme-radius-pill);
--recharge-radius-circle: var(--hy-theme-radius-circle);
}
button,
@ -90,7 +103,7 @@
height: 34px;
padding: 0 12px;
border: 1px solid var(--hy-theme-line);
border-radius: 17px;
border-radius: var(--recharge-radius-language);
background: var(--hy-theme-surface);
color: var(--hy-theme-text);
font-weight: 800;
@ -104,7 +117,7 @@
width: 128px;
padding: 6px;
border: 1px solid var(--hy-theme-line);
border-radius: 16px;
border-radius: var(--recharge-radius-card);
background: var(--hy-theme-surface);
box-shadow: var(--hy-theme-shadow);
}
@ -112,7 +125,7 @@
.language-menu button {
width: 100%;
min-height: 34px;
border-radius: 12px;
border-radius: var(--recharge-radius-small);
background: transparent;
color: var(--hy-theme-text);
text-align: left;
@ -132,7 +145,7 @@
margin-top: 10px;
padding: 14px;
border: 1px solid var(--hy-theme-line);
border-radius: 16px;
border-radius: var(--recharge-radius-card);
background: var(--hy-theme-surface);
box-shadow: var(--hy-theme-shadow);
}
@ -176,7 +189,7 @@
height: 46px;
padding: 0 14px;
border: 1px solid var(--hy-theme-line);
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-surface-soft);
color: var(--hy-theme-text);
outline: none;
@ -184,7 +197,7 @@
.input:focus {
border-color: var(--hy-theme-primary-strong);
box-shadow: 0 0 0 3px rgba(197, 166, 246, 0.18);
box-shadow: 0 0 0 3px var(--recharge-focus-ring);
}
.primary-button,
@ -194,7 +207,7 @@
align-items: center;
justify-content: center;
padding: 0 16px;
border-radius: 14px;
border-radius: var(--recharge-radius-control);
font-weight: 850;
letter-spacing: 0;
}
@ -224,7 +237,7 @@
align-items: center;
gap: 10px;
padding: 10px;
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-primary-soft);
}
@ -237,7 +250,7 @@
height: 44px;
flex: 0 0 auto;
overflow: hidden;
border-radius: 16px;
border-radius: var(--recharge-radius-card);
background: var(--hy-theme-primary);
}
@ -292,12 +305,12 @@
flex: 0 0 auto;
max-width: 112px;
padding: 4px 8px;
border-radius: 999px;
border-radius: var(--recharge-radius-pill);
border: 1px solid rgba(255, 255, 255, 0.62);
background: rgba(255, 255, 255, 0.48);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.58),
0 6px 16px rgba(91, 62, 142, 0.08);
var(--recharge-role-shadow);
color: var(--hy-theme-primary-deep);
font-size: 11px;
font-weight: 850;
@ -314,7 +327,7 @@
min-width: 58px;
min-height: 34px;
padding: 0 10px;
border-radius: 999px;
border-radius: var(--recharge-radius-pill);
font-size: 12px;
}
@ -329,7 +342,7 @@
min-height: 72px;
padding: 12px;
border: 1px solid var(--hy-theme-line);
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-surface-soft);
color: var(--hy-theme-text);
text-align: left;
@ -371,7 +384,7 @@
gap: 8px;
padding: 9px;
border: 1px solid var(--hy-theme-line);
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-surface-soft);
color: var(--hy-theme-text);
text-align: left;
@ -389,7 +402,7 @@
flex: 0 0 auto;
place-items: center;
overflow: hidden;
border-radius: 11px;
border-radius: var(--recharge-radius-icon);
background: var(--hy-theme-surface);
color: var(--hy-theme-primary-deep);
font-size: 11px;
@ -464,7 +477,7 @@
min-width: 38px;
min-height: 38px;
padding: 0;
border-radius: 50%;
border-radius: var(--recharge-radius-circle);
font-size: 0;
line-height: 1;
}
@ -475,7 +488,7 @@
position: absolute;
width: 16px;
height: 2px;
border-radius: 999px;
border-radius: var(--recharge-radius-pill);
background: currentColor;
}
@ -501,7 +514,7 @@
gap: 4px;
padding: 9px 10px;
border: 1px solid var(--hy-theme-line);
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-surface-soft);
}
@ -539,7 +552,7 @@
min-height: 30px;
padding: 0;
border: 1px solid var(--hy-theme-line);
border-radius: 10px;
border-radius: var(--recharge-radius-icon);
background: var(--hy-theme-surface);
color: var(--hy-theme-primary-deep);
}
@ -551,7 +564,7 @@
width: 12px;
height: 14px;
border: 2px solid currentColor;
border-radius: 3px;
border-radius: var(--recharge-radius-tiny);
}
.copy-icon-button::before {
@ -582,7 +595,7 @@
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
border-radius: var(--recharge-radius-circle);
background: var(--hy-theme-primary-deep);
box-shadow: 0 0 0 4px var(--hy-theme-primary-soft);
}
@ -591,7 +604,7 @@
display: grid;
gap: 8px;
padding: 12px;
border-radius: 14px;
border-radius: var(--recharge-radius-control);
background: var(--hy-theme-primary-soft);
}
@ -616,7 +629,7 @@
.copy-address-button {
min-height: 34px;
padding: 0 12px;
border-radius: 12px;
border-radius: var(--recharge-radius-small);
background: var(--hy-theme-surface);
font-size: 12px;
}
@ -652,9 +665,9 @@
margin: 0 auto;
overflow: auto;
border: 1px solid var(--hy-theme-line);
border-radius: 22px;
border-radius: var(--recharge-radius-modal);
background: var(--hy-theme-surface);
box-shadow: 0 22px 54px rgba(40, 25, 72, 0.26);
box-shadow: var(--recharge-modal-shadow);
}
.modal-header {
@ -711,7 +724,7 @@
padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
border-top: 1px solid var(--hy-theme-line);
background: rgba(255, 255, 255, 0.94);
box-shadow: 0 -10px 28px rgba(40, 25, 72, 0.12);
box-shadow: var(--recharge-checkout-shadow);
backdrop-filter: blur(12px);
}
@ -868,9 +881,7 @@
<div class="account-name" id="account-name">
-
</div>
<div class="role-pill" id="account-role">
-
</div>
<div class="role-pill" id="account-role">-</div>
</div>
<div class="account-meta" id="account-meta">-</div>
</div>
@ -1161,8 +1172,7 @@
.then(function (config) {
state.appConfig =
config ||
(window.HyAppAPI &&
window.HyAppAPI.getAppConfig
(window.HyAppAPI && window.HyAppAPI.getAppConfig
? window.HyAppAPI.getAppConfig()
: null);
})
@ -1592,8 +1602,7 @@
.join(' · '),
logoURL: method.logo_url || '',
amount: convertedAmount(product, method),
providerCode:
method.provider_code || 'mifapay',
providerCode: method.provider_code || 'mifapay',
methodID: method.method_id,
payCountryID:
method.pay_country_id ||
@ -1653,8 +1662,7 @@
pay_type: method.payType || '',
channel_code: method.channelCode || '',
country_code:
method.countryCode ||
state.selectedCountryCode,
method.countryCode || state.selectedCountryCode,
currency_code:
method.currencyCode ||
state.selectedCurrencyCode,
@ -1670,9 +1678,7 @@
return;
}
startPolling();
if (
isRedirectPaymentOrder(state.order)
) {
if (isRedirectPaymentOrder(state.order)) {
savePendingExternalOrder(state.order);
window.location.href = state.order.pay_url;
}
@ -2127,9 +2133,7 @@
var usdtMethod = methods.find(function (method) {
return method.key === 'usdt_trc20';
});
state.selectedMethodKey = (
usdtMethod || methods[0]
).key;
state.selectedMethodKey = (usdtMethod || methods[0]).key;
}
// token 模式不回传 display_user_id防止前端把 token 用户和输入账号混用。
@ -2290,7 +2294,8 @@
}
var countries =
(context && (context.country_list || context.countryList)) ||
(context &&
(context.country_list || context.countryList)) ||
[];
var selected = countries[0] || {};
state.selectedPayCountryID =
@ -2499,7 +2504,9 @@
var minor = Number(value || 0);
if (!Number.isFinite(minor) || minor <= 0) return '-';
return (
(minor / 100).toFixed(currencyFractionDigits(currency)) +
(minor / 100).toFixed(
currencyFractionDigits(currency)
) +
' ' +
currency
);