hyapp-h5/common/api.js
2026-06-11 01:01:40 +08:00

742 lines
24 KiB
JavaScript
Raw 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 memoryEnv = '';
var memoryAccessToken = '';
var memoryAppCode = '';
function readQuery(name) {
return new URLSearchParams(window.location.search).get(name);
}
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();
if (env === 'test')
return isLocalDevOrigin()
? devProxyBase('/__api_test__/')
: normalizeBaseURL(test_api);
if (env === 'local') return normalizeBaseURL(local_api);
return normalizeBaseURL(default_api);
}
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 getAppCode() {
var queryAppCode = readQuery('app_code') || readQuery('appCode');
if (queryAppCode) {
memoryAppCode = queryAppCode;
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, queryAppCode);
return queryAppCode;
}
if (memoryAppCode) return memoryAppCode;
if (!shouldPersist()) return 'lalu';
return window.localStorage.getItem(APP_CODE_KEY) || 'lalu';
}
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 || '';
if (appCode) {
if (shouldPersist())
window.localStorage.setItem(APP_CODE_KEY, appCode);
return;
}
if (shouldPersist()) window.localStorage.removeItem(APP_CODE_KEY);
}
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 isErrorCode =
(typeof code === 'number' && code !== 0) ||
(typeof code === 'string' && code !== '' && code !== 'OK');
if (isErrorCode) {
var apiError = new Error(
payload.message || 'api_request_failed'
);
apiError.code = payload.code;
apiError.request_id = payload.request_id;
apiError.payload = payload;
throw apiError;
}
return payload &&
Object.prototype.hasOwnProperty.call(payload, 'data')
? payload.data
: 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({}, 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 链上校验都以后端订单快照为准。
var rechargeAPI = {
context: function (displayUserID) {
return request('/api/v1/recharge/h5/context', {
method: 'GET',
query: { display_user_id: displayUserID || '' },
});
},
options: function (displayUserID) {
return request('/api/v1/recharge/h5/options', {
method: 'GET',
query: { display_user_id: displayUserID || '' },
});
},
createOrder: function (payload) {
return request('/api/v1/recharge/h5/orders', {
method: 'POST',
body: payload || {},
});
},
submitTx: function (orderID, payload) {
return request(
'/api/v1/recharge/h5/orders/' +
encodeURIComponent(orderID || '') +
'/tx',
{
method: 'POST',
body: payload || {},
}
);
},
getOrder: function (orderID, displayUserID) {
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 },
});
},
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 || {},
}
);
},
};
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 managerCenterAPI = {
overview: function () {
return request('/api/v1/manager-center/overview', {
method: 'GET',
});
},
searchUsers: function (keyword, pageSize) {
return request('/api/v1/manager-center/users/search', {
method: 'GET',
query: {
keyword: keyword,
page_size: pageSize || 20,
},
});
},
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 || {},
});
},
};
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 || {},
});
},
};
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 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 gameAPI = {
dice: diceGameAPI,
};
window.HyAppAPI = {
baseURL: resolveBaseURL,
buildURL: buildURL,
getAccessToken: getAccessToken,
getAppCode: getAppCode,
setAccessToken: setAccessToken,
setAppCode: setAppCode,
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,
managerCenter: managerCenterAPI,
superadminCenter: superadminCenterAPI,
level: levelAPI,
weeklyStar: weeklyStarAPI,
game: gameAPI,
};
clearLocalDevCache();
})();