2026-06-24 16:31:13 +08:00

1607 lines
55 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var test_api = 'https://api-test.global-interaction.com/';
var local_api = 'http://127.0.0.1:13000/';
var default_api = 'https://api.global-interaction.com/';
(function () {
var API_ENV_KEY = 'hyapp_h5_env';
var ACCESS_TOKEN_KEY = 'hyapp_access_token';
var APP_CODE_KEY = 'hyapp_app_code';
var RENEWED_ACCESS_TOKEN_HEADER = 'X-Hyapp-Access-Token';
var LANGUAGE_QUERY_KEYS = [
'language',
'lang',
'locale',
'app_lang',
'appLanguage',
];
var memoryEnv = '';
var memoryAccessToken = '';
var memoryAppCode = '';
var activeAppConfig = null;
function currentQueryParams() {
var params = new URLSearchParams(window.location.search);
var hash = window.location.hash || '';
if (hash.indexOf('?') >= 0) {
new URLSearchParams(hash.split('?').slice(1).join('?')).forEach(
function (value, key) {
if (!params.has(key)) params.set(key, value);
}
);
}
return params;
}
function readQuery(name) {
return currentQueryParams().get(name);
}
function readLanguageQuery() {
var params = currentQueryParams();
for (var i = 0; i < LANGUAGE_QUERY_KEYS.length; i += 1) {
var value = params.get(LANGUAGE_QUERY_KEYS[i]);
if (value) return value;
}
return '';
}
function normalizeToken(value) {
var token = String(value || '').trim();
if (!token) return '';
if (/^Bearer\s+/i.test(token)) token = token.replace(/^Bearer\s+/i, '');
var match = token.match(
/[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/
);
return match ? match[0] : token;
}
function decodeBase64URLJSON(value) {
try {
var normalized = String(value || '')
.replace(/-/g, '+')
.replace(/_/g, '/');
while (normalized.length % 4) normalized += '=';
return JSON.parse(window.atob(normalized));
} catch (_) {
return null;
}
}
function isExpiredToken(token) {
var parts = String(token || '').split('.');
if (parts.length < 2) return false;
var payload = decodeBase64URLJSON(parts[1]);
if (!payload || !payload.exp) return false;
// JWT exp 是秒级时间戳;本地 H5 不能只凭 query 有 token 就进入 token 模式,过期 token 会被 gateway 当成未登录。
// 这里预留 5 秒偏移,避免页面发请求时刚好跨过过期点,导致 H5 隐藏账号输入但服务端收到空 display_user_id。
return Number(payload.exp) * 1000 <= Date.now() + 5000;
}
function normalizeBaseURL(value) {
return String(value || '').replace(/\/+$/, '') + '/';
}
function isLocalDevOrigin() {
var host = window.location.hostname;
return host === '127.0.0.1' || host === 'localhost' || host === '::1';
}
function shouldPersist() {
return !isLocalDevOrigin();
}
function clearLocalDevCache() {
if (shouldPersist()) return;
window.localStorage.removeItem(API_ENV_KEY);
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
window.localStorage.removeItem(APP_CODE_KEY);
}
function devProxyBase(path) {
return normalizeBaseURL(window.location.origin + path);
}
function resolveEnv() {
var env = readQuery('env');
if (env === 'test' || env === 'local') {
memoryEnv = env;
if (shouldPersist()) window.localStorage.setItem(API_ENV_KEY, env);
return env;
}
if (memoryEnv) return memoryEnv;
if (!shouldPersist()) return '';
return window.localStorage.getItem(API_ENV_KEY) || '';
}
function resolveBaseURL() {
var env = resolveEnv();
var configuredAPI = activeAppAPIBaseURL(env);
if (configuredAPI) return configuredAPI;
if (env === 'test')
return isLocalDevOrigin()
? devProxyBase('/__api_test__/')
: normalizeBaseURL(test_api);
if (env === 'local') return normalizeBaseURL(local_api);
return normalizeBaseURL(default_api);
}
function activeAppAPIBaseURL(env) {
var api = activeAppConfig && activeAppConfig.api;
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)
: '';
}
function buildURL(path, query) {
var url = new URL(path.replace(/^\/+/, ''), resolveBaseURL());
if (query) {
Object.keys(query).forEach(function (key) {
var value = query[key];
if (value === undefined || value === null || value === '')
return;
url.searchParams.set(key, value);
});
}
return url.toString();
}
function isSameOriginURL(url) {
try {
return (
new URL(url, window.location.href).origin ===
window.location.origin
);
} catch (_) {
return false;
}
}
function getAccessToken() {
if (memoryAccessToken && !isExpiredToken(memoryAccessToken))
return memoryAccessToken;
if (memoryAccessToken && isExpiredToken(memoryAccessToken)) {
memoryAccessToken = '';
if (shouldPersist())
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
}
var queryToken =
normalizeToken(readQuery('token')) ||
normalizeToken(readQuery('access_token')) ||
normalizeToken(readQuery('accessToken'));
if (queryToken) {
if (isExpiredToken(queryToken)) {
if (shouldPersist())
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
return '';
}
memoryAccessToken = queryToken;
if (shouldPersist())
window.localStorage.setItem(ACCESS_TOKEN_KEY, queryToken);
return queryToken;
}
if (!shouldPersist()) return '';
var storedToken = normalizeToken(
window.localStorage.getItem(ACCESS_TOKEN_KEY) || ''
);
if (storedToken && isExpiredToken(storedToken)) {
window.localStorage.removeItem(ACCESS_TOKEN_KEY);
return '';
}
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');
if (queryAppCode) {
memoryAppCode = queryAppCode;
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, queryAppCode);
applyAppTheme(queryAppCode);
return queryAppCode;
}
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) {
token = normalizeToken(token);
if (token && isExpiredToken(token)) token = '';
memoryAccessToken = token || '';
if (token) {
if (shouldPersist())
window.localStorage.setItem(ACCESS_TOKEN_KEY, token);
return;
}
if (shouldPersist()) window.localStorage.removeItem(ACCESS_TOKEN_KEY);
}
function setAppCode(appCode) {
memoryAppCode = appCode || '';
applyAppTheme(appCode || 'lalu');
if (appCode) {
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, appCode);
return;
}
if (shouldPersist()) window.localStorage.removeItem(APP_CODE_KEY);
}
applyAppTheme(peekAppCode());
function setAppConfig(config) {
activeAppConfig = config || null;
if (activeAppConfig && activeAppConfig.app) {
setAppCode(activeAppConfig.app);
}
return activeAppConfig;
}
function getAppConfig() {
return activeAppConfig;
}
function loadAppConfig(scope) {
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
);
return window
.fetch(configURL.toString(), {
cache: shouldPersist() ? 'default' : 'no-store',
})
.then(function (response) {
if (!response.ok) return null;
return response.json();
})
.then(function (config) {
return setAppConfig(config);
})
.catch(function () {
activeAppConfig = null;
return null;
});
}
function errorMessageForResponse(response, payload) {
if (response.status === 409) return 'Duplicate request.';
return payload.message || response.statusText || 'request_failed';
}
function notifyHTTPError(response, message) {
if (response.status !== 409 || !message) return;
if (window.HyAppToast && window.HyAppToast.show) {
window.HyAppToast.show(message);
return;
}
window.dispatchEvent(
new CustomEvent('hyapp:toast', {
detail: { message: message },
})
);
}
function parseResponse(response) {
return response.text().then(function (text) {
var payload = text ? JSON.parse(text) : {};
if (!response.ok) {
var message = errorMessageForResponse(response, payload);
notifyHTTPError(response, message);
var httpError = new Error(message);
httpError.status = response.status;
httpError.code = payload.code;
httpError.request_id = payload.request_id;
httpError.payload = payload;
throw httpError;
}
var code = payload && payload.code;
var errorCode = payload && payload.errorCode;
var isErrorCode =
(typeof code === 'number' && code !== 0) ||
(typeof code === 'string' && code !== '' && code !== 'OK') ||
(typeof errorCode === 'number' && errorCode !== 0) ||
(typeof errorCode === 'string' &&
errorCode !== '' &&
errorCode !== '0' &&
errorCode !== 'OK');
if (isErrorCode) {
var apiError = new Error(
payload.message ||
payload.errorMsg ||
payload.error ||
'api_request_failed'
);
apiError.code = payload.code || payload.errorCode;
apiError.request_id = payload.request_id;
apiError.payload = payload;
throw apiError;
}
return payload &&
Object.prototype.hasOwnProperty.call(payload, 'data')
? payload.data
: payload &&
Object.prototype.hasOwnProperty.call(payload, 'body')
? payload.body
: payload;
});
}
function persistRenewedAccessToken(response) {
var renewedToken =
response && response.headers
? response.headers.get(RENEWED_ACCESS_TOKEN_HEADER)
: '';
if (renewedToken) setAccessToken(renewedToken);
}
function request(path, options) {
var opts = options || {};
var headers = Object.assign(
{},
(activeAppConfig && activeAppConfig.headers) || {},
opts.headers || {}
);
var token = getAccessToken();
var appCode = getAppCode();
var url = buildURL(path, opts.query);
if (token) headers.Authorization = 'Bearer ' + token;
if (appCode) headers['X-App-Code'] = appCode;
if (!shouldPersist() && isSameOriginURL(url))
headers['Cache-Control'] = 'no-cache';
var body = opts.body;
if (body && typeof body === 'object' && !(body instanceof FormData)) {
headers['Content-Type'] =
headers['Content-Type'] || 'application/json';
body = JSON.stringify(body);
}
return window
.fetch(url, {
method: opts.method || 'GET',
headers: headers,
body: body,
cache: shouldPersist() ? 'default' : 'no-store',
credentials: opts.credentials || 'omit',
})
.then(function (response) {
persistRenewedAccessToken(response);
return parseResponse(response);
});
}
var vipAPI = {
me: function () {
return request('/api/v1/vip/me', { method: 'GET' });
},
packages: function () {
return request('/api/v1/vip/packages', { method: 'GET' });
},
purchase: function (payload) {
return request('/api/v1/vip/purchase', {
method: 'POST',
body: payload || {},
});
},
};
var userAPI = {
me: function () {
return request('/api/v1/users/me', { method: 'GET' });
},
overview: function () {
return request('/api/v1/users/me/overview', { method: 'GET' });
},
appearance: function () {
return request('/api/v1/users/me/appearance', { 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',
});
},
resolveDisplayUserID: function (displayUserID) {
return request(
'/api/v1/users/by-display-user-id/' +
encodeURIComponent(displayUserID || ''),
{
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 },
});
},
transactions: function (params) {
return request('/api/v1/wallet/transactions', {
method: 'GET',
query: params || {},
});
},
transferCoinFromSeller: function (payload) {
return request('/api/v1/wallet/coin-seller/transfer', {
method: 'POST',
body: payload || {},
});
},
};
// H5 充值 API 只做路径和参数名封装token、app_code、env、错误 envelope 仍由 request 统一处理。
// 金额、金币数、普通/币商钱包、MiFaPay 参数和 USDT 链上校验都以后端订单快照为准。
function isAslanWebPay() {
return activeAppConfig && activeAppConfig.adapter === 'aslan-web-pay';
}
function isYumiWebPay() {
return activeAppConfig && activeAppConfig.adapter === 'yumi-web-pay';
}
function isConfiguredWebPay() {
return isAslanWebPay() || isYumiWebPay();
}
function appEndpoint(name, fallback) {
return (
(activeAppConfig &&
activeAppConfig.endpoints &&
activeAppConfig.endpoints[name]) ||
fallback
);
}
function aslanUserQuery(displayUserID) {
var value = String(displayUserID || '').trim();
var query = {
applicationId: activeAppConfig.application_id,
type: activeAppConfig.type || 'GOLD',
sysOrigin: activeAppConfig.sys_origin || 'ATYOU',
};
if (value) {
query.account = value;
}
if (/^\d+$/.test(value)) {
query.userId = value;
}
return query;
}
function configuredWebPayUserQuery(displayUserID) {
return Object.assign(aslanUserQuery(displayUserID), {
sysOrigin: activeAppConfig.sys_origin || 'LIKEI',
});
}
function aslanPaymentMethods(options) {
var providers = (activeAppConfig && activeAppConfig.providers) || {};
var mifapay = providers.mifapay || {};
var countries = mifapay.countries || [];
var countryCode = String(
options.country_code || options.countryCode || ''
).toUpperCase();
var candidates = countries.filter(function (country) {
return (
String(country.country_code || '').toUpperCase() ===
countryCode ||
String(country.country_code || '').toUpperCase() === 'GLOBAL'
);
});
var methods = [];
candidates.forEach(function (country) {
(country.methods || []).forEach(function (method, index) {
methods.push(
Object.assign({}, method, {
method_id: [
mifapay.provider_code || 'mifapay',
country.country_code,
method.pay_way,
method.pay_type,
index,
].join(':'),
provider_code: mifapay.provider_code || 'mifapay',
provider_name: mifapay.provider_name || 'MiFaPay',
country_code: country.country_code,
country_name: country.country_name,
currency_code:
country.country_code === 'GLOBAL'
? options.currency_code || country.currency_code
: country.currency_code,
usd_to_currency_rate:
options.usd_to_currency_rate ||
options.usdToCurrencyRate ||
0,
pay_country_id:
options.pay_country_id ||
options.payCountryId ||
'',
status: mifapay.status || 'active',
})
);
});
});
return methods;
}
function firstValue(object, keys) {
object = object || {};
for (var i = 0; i < keys.length; i += 1) {
var value = object[keys[i]];
if (value !== undefined && value !== null && value !== '')
return value;
}
return '';
}
function normalizeCountryCode(value) {
return String(value || '')
.trim()
.toUpperCase();
}
function countryCodeFromCountry(country) {
country = country || {};
return normalizeCountryCode(
firstValue(country, [
'alphaTwo',
'alpha_two',
'countryCode',
'country_code',
'code',
])
);
}
function countryNameFromCountry(country) {
return firstValue(country, [
'aliasName',
'enName',
'countryName',
'country_name',
'name',
]);
}
function normalizeAmountUsd(value) {
var amount = Number(value || 0);
return Number.isFinite(amount) && amount > 0 ? amount : 0;
}
function decimalToMinor(value) {
return Math.round(normalizeAmountUsd(value) * 100);
}
function mapYumiContext(context) {
context = context || {};
var profile = context.userProfile || context.user_profile || {};
var countryList = context.countryList || context.country_list || [];
var selectedCountry = countryList[0] || {};
var country = selectedCountry.country || {};
var countryCode =
normalizeCountryCode(profile.countryCode || profile.country_code) ||
countryCodeFromCountry(country);
return {
auth_mode: 'display_user_id',
account: {
id: profile.id || '',
user_id: profile.id || '',
userId: profile.id || '',
display_user_id: profile.account || profile.id || '',
username: profile.userNickname || profile.user_nickname || '',
avatar: profile.userAvatar || profile.user_avatar || '',
country_code: countryCode,
countryCode: countryCode,
country_name:
profile.countryName ||
profile.country_name ||
countryNameFromCountry(country),
countryName:
profile.countryName ||
profile.country_name ||
countryNameFromCountry(country),
},
country_list: countryList.map(function (item) {
var itemCountry = item.country || {};
return {
id: item.id || '',
pay_country_id:
item.payCountryId ||
item.pay_country_id ||
item.id ||
'',
payCountryId:
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 || '',
country_code: countryCodeFromCountry(itemCountry),
countryCode: countryCodeFromCountry(itemCountry),
country_name: countryNameFromCountry(itemCountry),
countryName: countryNameFromCountry(itemCountry),
country: itemCountry,
};
}),
region_id: context.regionId || context.region_id || '',
regionId: context.regionId || context.region_id || '',
raw: context,
};
}
function mapYumiOptions(options) {
options = options || {};
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
);
return {
product_id: item.id,
productId: item.id,
pay_country_id:
item.payCountryId ||
item.pay_country_id ||
options.payCountryId ||
options.pay_country_id ||
'',
coin_amount:
(Number.isFinite(content) ? content : 0) +
(Number.isFinite(awardContent) ? awardContent : 0),
base_coin_amount: Number.isFinite(content) ? content : 0,
award_coin_amount: Number.isFinite(awardContent)
? awardContent
: 0,
amount_usdt: amountUsd,
amount_usdt_micro: Math.round(amountUsd * 1000000),
amount_minor: decimalToMinor(amountUsd),
currency_code: item.currency || item.currency_code || '',
raw: item,
};
}
);
var firstProduct = products[0] || {};
var countryCode = normalizeCountryCode(
options.country_code || options.countryCode || ''
);
var currencyCode =
options.currency_code ||
options.currencyCode ||
firstProduct.currency_code ||
'';
return {
products: products,
payment_methods: yumiPaymentMethods(
Object.assign({}, options, {
pay_country_id:
options.payCountryId ||
options.pay_country_id ||
firstProduct.pay_country_id ||
'',
country_code: countryCode,
currency_code: currencyCode,
usd_to_currency_rate:
options.usd_to_currency_rate ||
options.usdToCurrencyRate ||
0,
})
),
pay_country_id:
options.payCountryId ||
options.pay_country_id ||
firstProduct.pay_country_id ||
'',
country_code: countryCode,
currency_code: currencyCode,
usd_to_currency_rate:
options.usd_to_currency_rate || options.usdToCurrencyRate || 0,
usdt_trc20_enabled: false,
raw: options,
};
}
function yumiPaymentMethods(options) {
var channels =
(options.raw && options.raw.channels) || options.channels || [];
var supported = {};
channels.forEach(function (item) {
var channel = item.channel || {};
var details = item.details || {};
[
channel.channelCode,
channel.channel_code,
details.channelCode,
details.channel_code,
].forEach(function (code) {
if (code) supported[String(code)] = item;
});
});
return aslanPaymentMethods(options).filter(function (method) {
var channelCode =
method.channel_code ||
[method.pay_way, method.pay_type].filter(Boolean).join('_');
if (!Object.keys(supported).length) return true;
return !!supported[channelCode];
});
}
function mapYumiOrder(order) {
order = order || {};
var factoryCode = String(
order.factoryCode || order.factory_code || ''
).toUpperCase();
return {
order_id: order.orderId || order.order_id || '',
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 || '',
currency_code: order.currency || order.currency_code || '',
country_code: order.countryCode || order.country_code || '',
provider_amount_minor: decimalToMinor(order.amount),
status: 'pending',
raw: order,
};
}
function mapYumiOrderStatus(order) {
order = order || {};
var status = String(order.status || '').toUpperCase();
var normalized =
order.success === true || status === 'SUCCESS'
? 'credited'
: order.finished === true || status === 'FAIL'
? 'failed'
: 'pending';
var factoryCode = String(
order.factoryCode || order.factory_code || ''
).toUpperCase();
return {
order_id: order.orderId || order.order_id || '',
trade_no: order.tradeNo || order.trade_no || '',
provider_code: factoryCode === 'MIFA_PAY' ? 'mifapay' : factoryCode,
factory_code: factoryCode,
currency_code: order.currency || order.currency_code || '',
provider_amount_minor: decimalToMinor(order.amount),
status: normalized,
failure_reason: order.reason || '',
raw: order,
};
}
var rechargeAPI = {
context: function (displayUserID) {
if (isAslanWebPay()) {
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('/api/v1/recharge/h5/context', {
method: 'GET',
query: { display_user_id: displayUserID || '' },
});
},
options: function (displayUserID, extra) {
if (isConfiguredWebPay()) {
var query = Object.assign(aslanUserQuery(displayUserID), {
payCountryId:
extra && (extra.pay_country_id || extra.payCountryId),
countryCode:
extra && (extra.country_code || extra.countryCode),
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) {
options = options || {};
if (isYumiWebPay()) {
return mapYumiOptions(
Object.assign({}, options, {
pay_country_id:
query.payCountryId ||
options.pay_country_id ||
options.payCountryId ||
'',
country_code:
query.countryCode || options.country_code,
})
);
}
options.payment_methods = aslanPaymentMethods(options);
options.usdt_trc20_enabled = false;
return options;
});
}
return request('/api/v1/recharge/h5/options', {
method: 'GET',
query: { display_user_id: displayUserID || '' },
});
},
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',
},
}
);
}
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('/api/v1/recharge/h5/orders', {
method: 'POST',
query: { language: readLanguageQuery() },
body: payload || {},
});
},
submitTx: function (orderID, payload) {
return request(
'/api/v1/recharge/h5/orders/' +
encodeURIComponent(orderID || '') +
'/tx',
{
method: 'POST',
body: payload || {},
}
);
},
getOrder: function (orderID, displayUserID) {
if (isAslanWebPay()) {
return request(
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(
'/api/v1/recharge/h5/orders/' +
encodeURIComponent(orderID || ''),
{
method: 'GET',
query: { display_user_id: displayUserID || '' },
}
);
},
};
var salaryWalletAPI = {
overview: function (identity) {
return request('/api/v1/salary-wallet/overview', {
method: 'GET',
query: { identity: identity },
});
},
history: function (identity, limit) {
return request('/api/v1/salary-wallet/history', {
method: 'GET',
query: {
identity: identity,
page_size: limit || 30,
},
});
},
searchCoinSeller: function (displayUserID, identity) {
return request('/api/v1/salary-wallet/coin-sellers/search', {
method: 'GET',
query: {
display_user_id: displayUserID,
identity: identity,
},
});
},
exchange: function (payload) {
return request('/api/v1/salary-wallet/exchange', {
method: 'POST',
body: payload || {},
});
},
transferToCoinSeller: function (payload) {
return request('/api/v1/salary-wallet/transfer-to-coin-seller', {
method: 'POST',
body: payload || {},
});
},
};
var hostAPI = {
searchAgencies: function (shortId, pageSize) {
return request('/api/v1/host/agencies/search', {
method: 'GET',
query: { short_id: shortId, page_size: pageSize || 20 },
});
},
applyToAgency: function (payload) {
return request('/api/v1/host/agency-applications', {
method: 'POST',
body: payload || {},
});
},
};
var agencyCenterAPI = {
overview: function () {
return request('/api/v1/agency-center/overview', {
method: 'GET',
});
},
platformPolicy: function () {
return request('/api/v1/agency-center/platform-policy', {
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 || {},
}
);
},
inviteHost: function (payload) {
return request('/api/v1/agency-center/invitations/host', {
method: 'POST',
body: payload || {},
});
},
};
var hostCenterAPI = {
agency: function () {
return request('/api/v1/host-center/agency', {
method: 'GET',
});
},
platformPolicy: function () {
return request('/api/v1/host-center/platform-policy', {
method: 'GET',
});
},
};
var bdLeaderCenterAPI = {
overview: function () {
return request('/api/v1/bd-leader-center/overview', {
method: 'GET',
});
},
bds: function (pageSize) {
return request('/api/v1/bd-leader-center/bds', {
method: 'GET',
query: { page_size: pageSize || 20 },
});
},
agencies: function (pageSize) {
return request('/api/v1/bd-leader-center/agencies', {
method: 'GET',
query: { page_size: pageSize || 20 },
});
},
inviteBD: function (payload) {
return request('/api/v1/bd-leader/invitations/bd', {
method: 'POST',
body: payload || {},
});
},
inviteAgency: function (payload) {
return request('/api/v1/bd-leader/invitations/agency', {
method: 'POST',
body: payload || {},
});
},
};
var bdCenterAPI = {
overview: function () {
return request('/api/v1/bd-center/overview', {
method: 'GET',
});
},
agencies: function (pageSize) {
return request('/api/v1/bd-center/agencies', {
method: 'GET',
query: { page_size: pageSize || 20 },
});
},
inviteAgency: function (payload) {
return request('/api/v1/bd/invitations/agency', {
method: 'POST',
body: payload || {},
});
},
};
var roleInvitationAPI = {
list: function (status, pageSize) {
return request('/api/v1/role-invitations', {
method: 'GET',
query: {
status: status || 'pending',
page_size: pageSize || 50,
},
});
},
process: function (invitationID, payload) {
return request(
'/api/v1/role-invitations/' +
encodeURIComponent(invitationID || '') +
'/process',
{
method: 'POST',
body: payload || {},
}
);
},
};
var managerCenterAPI = {
overview: function () {
return request('/api/v1/manager-center/overview', {
method: 'GET',
});
},
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',
query: {
resource_type: resourceType,
page_size: pageSize || 20,
},
});
},
grantResource: function (payload) {
return request('/api/v1/manager-center/resource-grants', {
method: 'POST',
body: payload || {},
});
},
grantVip: function (payload) {
return request('/api/v1/manager-center/vip-grants', {
method: 'POST',
body: payload || {},
});
},
listBlocks: function (status, pageSize) {
return request('/api/v1/manager-center/blocks', {
method: 'GET',
query: {
status: status || 'active',
page_size: pageSize || 50,
},
});
},
blockUser: function (payload) {
return request('/api/v1/manager-center/blocks', {
method: 'POST',
body: payload || {},
});
},
unblockUser: function (blockId, payload) {
return request(
'/api/v1/manager-center/blocks/' +
encodeURIComponent(blockId || '') +
'/unblock',
{
method: 'POST',
body: payload || {},
}
);
},
updateLevel: function (payload) {
return request('/api/v1/manager-center/levels', {
method: 'POST',
body: payload || {},
});
},
createBDLeader: function (payload) {
return request('/api/v1/manager-center/bd-leaders', {
method: 'POST',
body: payload || {},
});
},
transferUserCountry: function (payload) {
return request('/api/v1/manager-center/users/country', {
method: 'POST',
body: payload || {},
});
},
};
var superadminCenterAPI = bdLeaderCenterAPI;
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 || {},
});
},
};
// 任务页 API 只封装 H5 需要的两个 App 合约登录态、app_code、env 和错误 envelope 仍由 request 统一处理。
// 领取奖励的 command_id 必须来自点击动作本身,页面脚本负责生成并在同一次重试中复用,避免重复点击造成多次发奖。
var taskAPI = {
tabs: function () {
return request('/api/v1/tasks/tabs', { method: 'GET' });
},
claim: function (payload) {
return request('/api/v1/tasks/claim', {
method: 'POST',
body: payload || {},
});
},
};
var weeklyStarAPI = {
current: function () {
return request('/api/v1/activities/weekly-star/current', {
method: 'GET',
});
},
leaderboard: function (params) {
return request('/api/v1/activities/weekly-star/leaderboard', {
method: 'GET',
query: params || {},
});
},
history: function (limit) {
return request('/api/v1/activities/weekly-star/history', {
method: 'GET',
query: { limit: limit || 10 },
});
},
};
var cpWeeklyRankAPI = {
status: function (params) {
return request('/api/v1/activities/cp-weekly-rank', {
method: 'GET',
query: params || {},
});
},
};
var cpSpaceAPI = {
relationships: function (params) {
return request('/api/v1/cp/relationships', {
method: 'GET',
query: params || {},
});
},
breakRelationship: function (relationshipID, payload) {
return request(
'/api/v1/cp/relationships/' +
encodeURIComponent(relationshipID || '') +
'/break',
{
method: 'POST',
body: payload || {},
}
);
},
};
// 转盘 H5 只通过 gateway 活动接口读配置、抽奖、查记录和跑马灯提示;页面不再内置 mock 奖品,避免后台资源组未配置时前端仍展示假奖池。
// 抽奖 command_id 由页面点击时生成并随请求提交,服务端用它做幂等,网络重试不会重复扣费或重复发奖。
var activityWheelAPI = {
config: function (wheelID) {
return request(
'/api/v1/activity/wheel/' +
encodeURIComponent(wheelID || 'classic') +
'/config',
{ method: 'GET' }
);
},
draw: function (wheelID, payload) {
return request(
'/api/v1/activity/wheel/' +
encodeURIComponent(wheelID || 'classic') +
'/draw',
{
method: 'POST',
body: payload || {},
}
);
},
history: function (wheelID, params) {
return request(
'/api/v1/activity/wheel/' +
encodeURIComponent(wheelID || 'classic') +
'/history',
{
method: 'POST',
query: params || {},
body: {},
}
);
},
hints: function (wheelID) {
return request(
'/api/v1/activity/wheel/' +
encodeURIComponent(wheelID || 'classic') +
'/hints',
{
method: 'POST',
body: {},
}
);
},
};
// 邀请活动 H5 只关心当前用户本月状态和领取动作;有效人数、累计充值和最高档差额都以后端聚合事实为准。
// 领取时页面必须传入本次点击生成的 command_id服务端按用户、周期、档位和 command_id 做幂等发奖。
var inviteActivityRewardAPI = {
status: function () {
return request('/api/v1/activities/invite-reward', {
method: 'GET',
});
},
leaderboard: function (params) {
return request('/api/v1/activities/invite-reward/leaderboard', {
method: 'GET',
query: params || {},
});
},
claim: function (payload) {
return request('/api/v1/activities/invite-reward/claim', {
method: 'POST',
body: payload || {},
});
},
};
var diceGameAPI = {
config: function (gameID) {
return request('/api/v1/games/dice/config', {
method: 'GET',
query: { game_id: gameID || 'dice' },
});
},
match: function (payload) {
return request('/api/v1/games/dice/match', {
method: 'POST',
body: payload || {},
});
},
getMatch: function (matchID) {
return request(
'/api/v1/games/dice/matches/' +
encodeURIComponent(matchID || ''),
{ method: 'GET' }
);
},
roll: function (matchID) {
return request(
'/api/v1/games/dice/matches/' +
encodeURIComponent(matchID || '') +
'/roll',
{ method: 'POST', body: {} }
);
},
cancel: function (matchID) {
return request(
'/api/v1/games/dice/matches/' +
encodeURIComponent(matchID || '') +
'/cancel',
{ method: 'POST', body: {} }
);
},
};
var rpsGameAPI = {
config: function (gameID) {
return request('/api/v1/games/rps/config', {
method: 'GET',
query: { game_id: gameID || 'rock' },
});
},
match: function (payload) {
return request('/api/v1/games/rps/match', {
method: 'POST',
body: payload || {},
});
},
create: function (payload) {
return request('/api/v1/games/rps/matches', {
method: 'POST',
body: payload || {},
});
},
join: function (matchID, payload) {
return request(
'/api/v1/games/rps/matches/' +
encodeURIComponent(matchID || '') +
'/join',
{ method: 'POST', body: payload || {} }
);
},
getMatch: function (matchID) {
return request(
'/api/v1/games/rps/matches/' +
encodeURIComponent(matchID || ''),
{ method: 'GET' }
);
},
roll: function (matchID, payload) {
return request(
'/api/v1/games/rps/matches/' +
encodeURIComponent(matchID || '') +
'/roll',
{ method: 'POST', body: payload || {} }
);
},
cancel: function (matchID) {
return request(
'/api/v1/games/rps/matches/' +
encodeURIComponent(matchID || '') +
'/cancel',
{ method: 'POST', body: {} }
);
},
};
function analyticsEventID(prefix) {
var random = '';
if (window.crypto && window.crypto.getRandomValues) {
var bytes = new Uint32Array(2);
window.crypto.getRandomValues(bytes);
random = bytes[0].toString(36) + bytes[1].toString(36);
} else {
random = Math.random().toString(36).slice(2);
}
return (
String(prefix || 'self_game') +
'_' +
Date.now().toString(36) +
'_' +
random
);
}
function reportSelfGameEvent(payload) {
var body = Object.assign({}, payload || {});
body.event_id = body.event_id || analyticsEventID(body.event_name);
body.occurred_at_ms = body.occurred_at_ms || Date.now();
return request('/api/v1/games/self/report-events', {
method: 'POST',
body: body,
});
}
var gameAPI = {
dice: diceGameAPI,
rps: rpsGameAPI,
reportEvent: reportSelfGameEvent,
};
window.HyAppAPI = {
baseURL: resolveBaseURL,
buildURL: buildURL,
getAccessToken: getAccessToken,
getAppCode: getAppCode,
setAccessToken: setAccessToken,
setAppCode: setAppCode,
setAppConfig: setAppConfig,
getAppConfig: getAppConfig,
loadAppConfig: loadAppConfig,
request: request,
get: function (path, query) {
return request(path, { method: 'GET', query: query });
},
post: function (path, body, query) {
return request(path, { method: 'POST', body: body, query: query });
},
put: function (path, body, query) {
return request(path, { method: 'PUT', body: body, query: query });
},
patch: function (path, body, query) {
return request(path, { method: 'PATCH', body: body, query: query });
},
delete: function (path, query) {
return request(path, { method: 'DELETE', query: query });
},
vip: vipAPI,
user: userAPI,
wallet: walletAPI,
recharge: rechargeAPI,
salaryWallet: salaryWalletAPI,
host: hostAPI,
hostCenter: hostCenterAPI,
agencyCenter: agencyCenterAPI,
bdCenter: bdCenterAPI,
bdLeaderCenter: bdLeaderCenterAPI,
roleInvitations: roleInvitationAPI,
managerCenter: managerCenterAPI,
superadminCenter: superadminCenterAPI,
activityWheel: activityWheelAPI,
level: levelAPI,
task: taskAPI,
weeklyStar: weeklyStarAPI,
cpWeeklyRank: cpWeeklyRankAPI,
cpSpace: cpSpaceAPI,
inviteActivityReward: inviteActivityRewardAPI,
game: gameAPI,
};
clearLocalDevCache();
})();