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