import { YXG_API_BASE, YXG_ASSET_BASE } from './yxgConfig.js' import $http from './requestConfig.js' const TOKEN_KEY = 'token' const LEGACY_TOKEN_KEY = 'yxg_token' const DEVICE_KEY = 'yxg_device_key' export function getYxgToken() { return uni.getStorageSync(TOKEN_KEY) || uni.getStorageSync(LEGACY_TOKEN_KEY) || '' } export function setYxgToken(token) { if (token) { uni.setStorageSync(TOKEN_KEY, token) uni.removeStorageSync(LEGACY_TOKEN_KEY) } else { uni.removeStorageSync(TOKEN_KEY) uni.removeStorageSync(LEGACY_TOKEN_KEY) uni.removeStorageSync('userinfo') } } export function getDeviceKey() { return uni.getStorageSync(DEVICE_KEY) || '' } export function setDeviceKey(key) { if (key) uni.setStorageSync(DEVICE_KEY, key) } export function assetURL(path) { const p = String(path || '').trim() if (!p) return '' if (/^https?:\/\//i.test(p)) return p return YXG_ASSET_BASE + (p.startsWith('/') ? p : `/${p}`) } function joinURL(base, path) { if (/^https?:\/\//i.test(path)) return path return `${base.replace(/\/$/, '')}${path.startsWith('/') ? path : `/${path}`}` } function request(method, path, body, extra = {}) { return $http.request({ method, url: path, data: body === undefined ? {} : body, isPrompt: extra.isPrompt ?? false, load: extra.load ?? false, timeout: extra.timeout, }).catch((e) => { const raw = e instanceof Error ? e.message : (e && e.errMsg) || '请求失败' throw new Error(String(raw).replace(/^【request】/, '')) }) } export const yxgApi = { authRegister: (body) => request('POST', '/api/v1/auth/register', body), authLogin: (body) => request('POST', '/api/v1/auth/login', body), authLogout: () => request('POST', '/api/v1/auth/logout', {}), authMe: () => request('GET', '/api/v1/auth/me'), authUpdateMe: (body) => request('PATCH', '/api/v1/auth/me', body), authUploadAvatar(filePath) { return new Promise((resolve, reject) => { const header = {} const token = getYxgToken() const device = getDeviceKey() if (token) header.Authorization = `Bearer ${token}` if (device) header['X-Device-Key'] = device uni.uploadFile({ url: joinURL(YXG_API_BASE, '/api/v1/auth/me/avatar'), filePath, name: 'file', header, success(res) { let data = res.data if (typeof data === 'string') { try { data = JSON.parse(data) } catch { reject(new Error('上传失败')) return } } if (!data || data.code !== 0) { reject(new Error(data?.message || '上传失败')) return } resolve(data.data) }, fail(err) { reject(new Error(err.errMsg || '上传失败')) }, }) }) }, listProfiles: () => request('GET', '/api/v1/profiles'), createProfile: (body) => request('POST', '/api/v1/profiles', body), updateProfile: (id, body) => request('PATCH', `/api/v1/profiles/${id}`, body), deleteProfile: (id) => request('DELETE', `/api/v1/profiles/${id}`), createPortrait: (profile_id) => request('POST', '/api/v1/reports/portrait', { profile_id }), createStar: (profile_id) => request('POST', '/api/v1/reports/star', { profile_id }), createSynastry: (profile_id_a, profile_id_b, as_of) => request('POST', '/api/v1/reports/synastry', { profile_id_a, profile_id_b, ...(as_of ? { as_of } : {}), }), getLatestReport: (profile_id, type, peer_profile_id) => { let q = `profile_id=${encodeURIComponent(profile_id)}&type=${encodeURIComponent(type)}` if (peer_profile_id) q += `&peer_profile_id=${encodeURIComponent(peer_profile_id)}` return request('GET', `/api/v1/reports/latest?${q}`) }, listSynastryNearby: (lat, lng, radius_km = 50) => request('GET', `/api/v1/synastry/nearby?lat=${lat}&lng=${lng}&radius_km=${radius_km}`), createSynastryInvite: (profile_id) => request('POST', '/api/v1/synastry/invites', { profile_id }), getSynastryInvite: (token) => request('GET', `/api/v1/synastry/invites/${token}`), acceptSynastryInvite: (token, body) => request('POST', `/api/v1/synastry/invites/${token}/accept`, body), createRhythm: (profile_id) => request('POST', '/api/v1/reports/rhythm', { profile_id }), listImageCardScenes: () => request('GET', '/api/v1/image-cards/scenes'), getImageCardQuota: () => request('GET', '/api/v1/image-cards/quota'), drawImageCard: (body) => request('POST', '/api/v1/image-cards/draw', body), getSolarTermsToday: () => request('GET', '/api/v1/solar-terms/today'), saveMood: (body) => request('POST', '/api/v1/moods', body), getMoodToday: () => request('GET', '/api/v1/moods/today'), getMoodsRecent: () => request('GET', '/api/v1/moods/recent'), getExploreCatalog: () => request('GET', '/api/v1/explore/catalog'), getExploreCategory: (key) => request('GET', `/api/v1/explore/catalog/${key}`), listGrowthPlans: () => request('GET', '/api/v1/growth/plans'), createGrowthPlan: (body) => request('POST', '/api/v1/growth/plans', body), createGrowthCheckin: (planId, body) => request('POST', `/api/v1/growth/plans/${planId}/checkin`, body || {}), listGrowthCheckins: (planId) => request('GET', `/api/v1/growth/plans/${planId}/checkins`), listReports: () => request('GET', '/api/v1/reports'), getReport: (id) => request('GET', `/api/v1/reports/${id}`), getMembership: () => request('GET', '/api/v1/membership/me'), createOrder: (body) => request('POST', '/api/v1/orders', body), payMock: (orderId) => request('POST', `/api/v1/orders/${orderId}/pay-mock`, {}), createRelationInsight: (profile_a_id, profile_b_id) => request('POST', '/api/v1/relation/insight', { profile_a_id, profile_b_id }), listScales: () => request('GET', '/api/v1/scales'), getScaleBankCatalog: () => request('GET', '/api/v1/scale-bank/catalog'), getScaleBankCategory: (key) => request('GET', `/api/v1/scale-bank/categories/${key}`), getScale: (slug) => request('GET', `/api/v1/scales/${slug}`), getScaleResult: (slug) => request('GET', `/api/v1/scales/${slug}/result`), submitScale: (slug, profile_id, answers) => request('POST', `/api/v1/scales/${slug}/result`, { profile_id, answers }), getAskQuota: () => request('GET', '/api/v1/ask/quota'), createAskThread: (body) => request('POST', '/api/v1/ask/threads', body), clearAskThread: (threadId) => request('DELETE', `/api/v1/ask/threads/${threadId}`), listAskMessages: (threadId) => request('GET', `/api/v1/ask/threads/${threadId}/messages`), sendAskMessage: (threadId, content) => request('POST', `/api/v1/ask/threads/${threadId}/messages`, { content }, { timeout: 60000 }), getHomeTools: () => request('GET', '/api/v1/home/tools'), getHomeBanners: (placement = 'home') => request('GET', `/api/v1/home/banners?placement=${encodeURIComponent(placement)}`), getHomeFeedSlots: (placement = 'home') => request('GET', `/api/v1/home/feed-slots?placement=${encodeURIComponent(placement)}`), getHomeDailyTips: () => request('GET', '/api/v1/home/daily-tips'), }