Files
jiapu/utils/ApiClient.js
T
2026-07-11 09:41:32 +08:00

380 lines
13 KiB
JavaScript

(function (root, factory) {
// PC 接口客户端同时支持浏览器页面和 Node 单元测试加载。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenealogyApi = factory(root);
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var DEFAULT_CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
var DEFAULT_TENANT_ID = '000000';
var DEFAULT_TOKEN_KEY = 'genealogy_auth_token';
var DEFAULT_TOKEN_HEADER_NAME = 'Authorization';
function loadNodeModule(path) {
if (typeof require !== 'function') return null;
try {
return require(path);
} catch (error) {
return null;
}
}
function getConfigApi() {
if (root.GenealogyConfig) return root.GenealogyConfig;
var configFactory = loadNodeModule('../config.js');
return configFactory ? configFactory(root) : null;
}
function getStorageUtil() {
return root.StorageUtil || loadNodeModule('./StorageUtil.js');
}
function getAxiosRequestUtil() {
return root.AxiosRequestUtil || loadNodeModule('./AxiosRequestUtil.js');
}
function getStorage(store) {
if (store) return store;
try {
return root.localStorage;
} catch (error) {
return null;
}
}
function getTokenFromResponse(data) {
// 登录响应兼容后端已声明的多种 token 字段。
if (!data) return '';
return data.token || data.accessToken || data.access_token || data.tokenValue || '';
}
function requireLoginToken(data) {
var token = getTokenFromResponse(data);
if (!token) throw new ApiError('登录响应缺少 token');
return token;
}
function ApiError(message, options) {
this.name = 'ApiError';
this.message = message || '接口请求失败';
this.status = options && options.status;
this.code = options && options.code;
this.data = options && options.data;
}
ApiError.prototype = Object.create(Error.prototype);
ApiError.prototype.constructor = ApiError;
function createUnavailableMethod(name) {
return function () {
var error = new Error('PC 接口文档未提供该业务接口:' + name);
error.code = 'PC_API_NOT_AVAILABLE';
throw error;
};
}
function createFormData(fileOrFormData) {
var FormDataCtor = root.FormData;
if (FormDataCtor && fileOrFormData instanceof FormDataCtor) return fileOrFormData;
if (!FormDataCtor) throw new ApiError('当前环境不支持文件上传');
var formData = new FormDataCtor();
formData.append('file', fileOrFormData);
return formData;
}
function createChunkFormData(body) {
var FormDataCtor = root.FormData;
var source = body || {};
if (FormDataCtor && body instanceof FormDataCtor) return body;
if (!FormDataCtor) throw new ApiError('当前环境不支持文件上传');
var formData = new FormDataCtor();
formData.append('uploadId', source.uploadId);
formData.append('chunkIndex', source.chunkIndex);
formData.append('chunkMd5', source.chunkMd5);
formData.append('file', source.file);
return formData;
}
function buildApiUrl(baseUrl, path, query) {
var url = String(baseUrl || '').replace(/\/+$/g, '') + '/' + String(path || '').replace(/^\/+/, '');
var params = new URLSearchParams();
Object.keys(query || {}).forEach(function (key) {
var value = query[key];
if (value !== undefined && value !== null && value !== '') params.append(key, value);
});
return params.toString() ? url + '?' + params.toString() : url;
}
function createClient(options) {
var settings = options || {};
var configApi = getConfigApi();
var config = configApi && configApi.getConfig ? configApi.getConfig() : {};
var storageUtil = getStorageUtil();
var axiosRequestUtil = getAxiosRequestUtil();
var store = getStorage(settings.tokenStore || settings.storage);
var clientId = settings.clientId || config.clientId || DEFAULT_CLIENT_ID;
var tenantId = settings.tenantId || config.tenantId || DEFAULT_TENANT_ID;
var tokenKey = settings.tokenKey || config.tokenKey || DEFAULT_TOKEN_KEY;
var tokenHeaderName = settings.tokenHeaderName || config.tokenHeaderName || DEFAULT_TOKEN_HEADER_NAME;
var baseUrl = settings.baseUrl || config.apiBaseUrl;
if (!axiosRequestUtil || !axiosRequestUtil.createRequester) {
throw new ApiError('缺少 AxiosRequestUtil.createRequester 公共请求工具');
}
if (!baseUrl) {
throw new ApiError('缺少接口基础地址,请检查根目录 config.js');
}
function getToken() {
return storageUtil && storageUtil.read ? storageUtil.read(store, tokenKey) || '' : '';
}
function setToken(token) {
if (token && storageUtil && storageUtil.write) storageUtil.write(store, tokenKey, token);
}
function clearToken() {
if (storageUtil && storageUtil.remove) storageUtil.remove(store, tokenKey);
}
var requester = axiosRequestUtil.createRequester({
baseUrl: baseUrl,
clientId: clientId,
tokenHeaderName: tokenHeaderName,
getToken: getToken,
axiosInstance: settings.axiosInstance || root.axios
});
function request(method, path, requestOptions) {
return requester(method, path, requestOptions || {});
}
function withTenant(body) {
return Object.assign({
tenantId: tenantId,
clientId: clientId
}, body || {});
}
async function login(body) {
var data = await request('POST', '/genealogy/pc/auth/login', {
auth: false,
body: Object.assign({ grantType: 'password' }, withTenant(body))
});
setToken(requireLoginToken(data));
return data;
}
async function register(body) {
var data = await request('POST', '/genealogy/pc/auth/register', {
auth: false,
body: Object.assign({ grantType: 'password', registerSource: 'PC' }, withTenant(body))
});
clearToken();
return data;
}
async function loginBySms(body) {
var data = await request('POST', '/genealogy/pc/auth/login/sms', {
auth: false,
body: Object.assign({ grantType: 'sms' }, withTenant(body))
});
setToken(requireLoginToken(data));
return data;
}
function sendSmsCode(body) {
return request('POST', '/genealogy/pc/auth/sms/code', {
auth: false,
body: Object.assign({ grantType: 'sms' }, withTenant(body))
});
}
function captchaRequire(body) {
var source = body || {};
return request('GET', '/captcha/require', {
auth: false,
query: {
tenantId: source.tenantId || tenantId,
clientId: source.clientId || clientId,
sceneCode: source.sceneCode,
subject: source.subject
}
});
}
var client = {
clientId: clientId,
tenantId: tenantId,
tokenKey: tokenKey,
getToken: getToken,
setToken: setToken,
clearToken: clearToken,
request: request,
buildApiUrl: function (path, query) {
return buildApiUrl(baseUrl, path, query);
},
get: function (path, query) {
return request('GET', path, { query: query });
},
post: function (path, body, requestOptions) {
return request('POST', path, Object.assign({}, requestOptions || {}, { body: body }));
},
put: function (path, body, requestOptions) {
return request('PUT', path, Object.assign({}, requestOptions || {}, { body: body }));
},
delete: function (path, requestOptions) {
return request('DELETE', path, requestOptions || {});
},
login: login,
register: register,
sendSmsCode: sendSmsCode,
loginBySms: loginBySms,
smsLogin: loginBySms,
getProfile: function () {
return request('GET', '/genealogy/pc/auth/profile');
},
currentProfile: function () {
return request('GET', '/genealogy/pc/auth/profile');
},
updateProfile: function (body) {
return request('PUT', '/genealogy/pc/auth/profile', { body: body });
},
changePassword: function (body) {
return request('PUT', '/genealogy/pc/auth/password', { body: body });
},
resetPassword: function (body) {
return request('PUT', '/genealogy/pc/auth/password/reset', {
auth: false,
body: Object.assign({ tenantId: tenantId }, body || {})
});
},
changePhone: function (body) {
return request('PUT', '/genealogy/pc/auth/phone', { body: body });
},
deactivateAccount: async function (body) {
var data = await request('POST', '/genealogy/pc/auth/account/deactivate', { body: body });
clearToken();
return data;
},
logout: async function () {
try {
return await request('DELETE', '/genealogy/pc/auth/logout');
} finally {
clearToken();
}
},
uploadFile: function (fileOrFormData) {
return request('POST', '/genealogy/pc/files/upload', { body: createFormData(fileOrFormData) });
},
initResumableUpload: function (body) {
return request('POST', '/genealogy/pc/files/resumable/init', { body: body });
},
uploadChunk: function (body) {
return request('POST', '/genealogy/pc/files/resumable/chunk', { body: createChunkFormData(body) });
},
uploadResumableChunk: function (body) {
return this.uploadChunk(body);
},
completeResumableUpload: function (body) {
return request('POST', '/genealogy/pc/files/resumable/complete', { body: body });
},
bindFileReference: function (body) {
return request('POST', '/genealogy/pc/files/reference', { body: body });
},
releaseFileReference: function (query) {
return request('DELETE', '/genealogy/pc/files/reference', { query: query });
},
getRegionChildren: function (parentCode) {
return request('GET', '/genealogy/region/children', { query: { parentCode: parentCode } });
},
regionChildren: function (parentCode) {
return this.getRegionChildren(parentCode);
},
getRegionPath: function (regionCode) {
return request('GET', '/genealogy/region/path/' + encodeURIComponent(regionCode));
},
regionPath: function (regionCode) {
return this.getRegionPath(regionCode);
},
searchRegions: function (query) {
return request('GET', '/genealogy/region/search', { query: query });
},
regionSearch: function (query) {
return this.searchRegions(query);
},
getRegion: function (regionCode) {
return request('GET', '/genealogy/region/' + encodeURIComponent(regionCode));
},
regionDetail: function (regionCode) {
return this.getRegion(regionCode);
},
captchaRequire: captchaRequire,
captchaRequirement: captchaRequire,
captchaChallenge: function (body) {
return request('POST', '/captcha/challenge', { auth: false, body: body });
},
captchaVerify: function (body) {
return request('POST', '/captcha/verify', { auth: false, body: body });
},
legacyCaptcha: function () {
return request('GET', '/auth/code', { auth: false });
}
};
[
'listGenealogies', 'createGenealogy', 'publicGenealogies', 'myGenealogies', 'genealogyDetail', 'genealogyOverview',
'applyJoinGenealogy', 'myJoinApplies', 'pendingJoinApplies', 'auditJoinApply', 'cancelJoinApply', 'genealogyMembers',
'genealogyMemberOptions', 'updateGenealogyMember', 'removeGenealogyMember', 'leaveGenealogy', 'transferGenealogyOwner',
'articleCategories', 'articles', 'articleDetail', 'createArticle', 'updateArticle', 'feeds', 'feedsPage', 'feedDetail',
'createFeed', 'updateFeed', 'likeFeed', 'unlikeFeed', 'feedComments', 'feedCommentsPage', 'createFeedComment',
'deleteFeedComment', 'albums', 'createAlbum', 'updateAlbum', 'albumPhotos', 'createAlbumPhoto', 'ceremonies',
'ceremonyDetail', 'createCeremony', 'updateCeremony', 'ceremonyGifts', 'createCeremonyGift', 'meritRecords',
'createMeritRecord', 'growthRecords', 'growthRecordDetail', 'createGrowthRecord', 'updateGrowthRecord', 'memos',
'memoDetail', 'createMemo', 'updateMemo', 'vipPackages', 'vipOrders', 'createVipOrder', 'generationPoems',
'createGenerationPoem', 'updateGenerationPoem', 'previewGenerationPoems', 'saveGenerationPoemsBatch', 'lineageTree',
'lineagePersons', 'lineagePersonsPage', 'lineagePersonOptions', 'lineagePersonDetail', 'createLineagePerson',
'updateLineagePerson', 'deleteLineagePerson', 'addLineageRelation', 'notifications', 'markNotificationRead',
'markAllNotificationsRead', 'helpArticles', 'helpArticleDetail', 'promotions', 'feedbackList', 'submitFeedback'
].forEach(function (name) {
client[name] = createUnavailableMethod(name);
});
return client;
}
function createDefaultClient() {
// Node 测试环境可无全局 Axios,浏览器页面在加载顺序正确时会创建默认客户端。
try {
return createClient();
} catch (error) {
return null;
}
}
return {
DEFAULT_CLIENT_ID: DEFAULT_CLIENT_ID,
DEFAULT_TENANT_ID: DEFAULT_TENANT_ID,
TOKEN_KEY: DEFAULT_TOKEN_KEY,
ApiError: ApiError,
createClient: createClient,
defaultClient: createDefaultClient()
};
});