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(); })();