// API 基础配置 // 自动检测后端环境:探测开发服务器是否可用,能连通则用开发地址,否则用生产地址 // 团队开发机(Gateway + 团队数据库;注册/登录/余额/铸造) // const DEV_BASE = 'http://192.168.110.60:8080' const DEV_BASE = 'http://localhost:8081' const SEGMENT_BASE = 'http://localhost:8081' const LASER_BASE = 'http://localhost:8081' // 镭射 AI 生成 + compositor 走本地 Gateway const PROD_BASE = 'http://101.132.250.62:8080' // 生产环境 const HEALTH_URL = DEV_BASE + '/health' // 默认生产;H5 本地开发先走 DEV,避免 health 探测完成前请求打到生产(生产暂无 /segment) // 是否使用模拟数据(开发调试时设为 true,后端API准备好后改为 false) const USE_MOCK_API = true // 环境检测状态:0=检测中, 1=开发环境, 2=生产环境 let envStatus = 0 let baseURL = PROD_BASE // #ifdef H5 if (import.meta.env.DEV) { baseURL = DEV_BASE console.log('[API] H5 开发模式,默认地址:', DEV_BASE) } // #endif // 环境检测 Promise,确保 getApiBaseUrl / getWebSocketBaseUrl 等待检测完成 const envReadyPromise = new Promise((resolve) => { uni.request({ url: HEALTH_URL, method: 'GET', timeout: 2000, success: (res) => { if (res.statusCode === 200) { baseURL = DEV_BASE envStatus = 1 console.log('[API] 使用开发环境地址:', DEV_BASE) } else { envStatus = 2 console.log('[API] 开发环境返回非200,使用生产环境地址:', PROD_BASE) } resolve(envStatus) }, fail: () => { envStatus = 2 console.log('[API] 开发环境不可用,使用生产环境地址:', PROD_BASE) resolve(envStatus) } }) }) /** 等待环境检测完成(返回 'dev' | 'prod') */ export async function waitForEnvReady() { await envReadyPromise return envStatus === 1 ? 'dev' : 'prod' } /** 网关根地址(供 uni.uploadFile 等无法走 request 封装的场景拼接完整 URL) */ export async function getApiBaseUrl() { await envReadyPromise return String(baseURL).replace(/\/+$/, '') } /** 获取 WebSocket 基础地址(将 http:// 替换为 ws://) */ export async function getWebSocketBaseUrl() { await envReadyPromise const httpUrl = String(baseURL).replace(/\/+$/, '') return httpUrl.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:') } // 兼容旧代码:同步版本在环境检测完成前返回默认值(生产地址) export function getApiBaseUrlSync() { return String(baseURL).replace(/\/+$/, '') } /** 抠图专用 Gateway(可与 DEV_BASE 不同:业务走团队库,segment 走本机) */ export function getSegmentApiBaseUrl() { return String(SEGMENT_BASE).replace(/\/+$/, '') } /** 镭射专用 Gateway(AI 生成 + compositor 走本地,其他业务走远程) */ export function getLaserApiBaseUrl() { return String(LASER_BASE).replace(/\/+$/, '') } // 模拟网络延迟 function mockDelay(ms = 800) { return new Promise(resolve => setTimeout(resolve, ms)) } // 请求封装 export function request(options) { return new Promise((resolve, reject) => { // 构建请求头 const headers = { 'Content-Type': 'application/json', ...options.header } // 判断是否为登录或注册接口 const isAuthRequest = options.url.includes('/api/v1/auth/login') || options.url.includes( '/api/v1/auth/register') || options.url.includes('/api/v1/auth/send-code') || options.url.includes('/api/v1/auth/verify-code') // 如果不是登录/注册接口,则自动添加JWT token if (!isAuthRequest) { const token = uni.getStorageSync('access_token') if (token) { headers['Authorization'] = `Bearer ${token}` } } uni.request({ url: baseURL + options.url, method: options.method || 'GET', data: options.data || {}, header: headers, timeout: 60000, success: (res) => { // 处理token过期(HTTP 401未授权) if (res.statusCode === 401) { // 清除本地存储的token和用户信息 uni.removeStorageSync('access_token') uni.removeStorageSync('user') // 跳转到登录页 uni.reLaunch({ url: '/pages/login/login' }) reject(new Error('登录已过期,请重新登录')) return } // 可以在这里统一处理响应 if (res.statusCode === 200 || res.statusCode === 202) { // 检查业务状态码 if (res.data && res.data.code !== undefined) { if (res.data.code === 200) { resolve(res.data) } else if (res.data.code === 401 || res.data.code === 400 || res.data .code === 403) { // 业务状态码401/400/403(未授权/冻结/封号),清除缓存并跳转到登录页 uni.removeStorageSync('access_token') uni.removeStorageSync('user') // 保留错误消息用于显示 const errorMsg = res.data.message || '登录已过期,请重新登录' uni.reLaunch({ url: '/pages/login/login?error=' + encodeURIComponent( errorMsg) }) reject(new Error(errorMsg)) return } else { // 其他业务错误,返回包含 message 的错误 reject(new Error(res.data.message || '请求失败')) } } else { resolve(res.data) } } else { // HTTP 错误,尝试从响应中获取 message const errorMessage = res.data?.message || `请求失败 (${res.statusCode})` reject(new Error(errorMessage)) } }, fail: (err) => { reject(err) } }) }) } // 登录接口 export function loginApi(mobile, password) { return request({ url: '/api/v1/auth/login', method: 'POST', data: { mobile, password } }) } // 检查昵称是否已被注册 export function checkNicknameApi(nickname) { return request({ url: '/api/v1/auth/check-nickname', method: 'POST', data: { nickname } }) } // 检查手机号是否已被注册 export function checkmobileApi(mobile) { return request({ url: '/api/v1/auth/check-mobile', method: 'POST', data: { mobile } }) } // 注册接口 export function registerApi(mobile, password, star_id, nickname, verify_token = '', avatar_url = '') { return request({ url: '/api/v1/auth/register', method: 'POST', data: { mobile, password, star_id, nickname, verify_token, avatar_url } }) } // 发送验证码 export function sendCodeApi(mobile, scene = 'register') { return request({ url: '/api/v1/auth/send-code', method: 'POST', data: { mobile, scene } }); } // 验证验证码 export function verifyCodeApi(mobile, code, scene = 'register') { return request({ url: '/api/v1/auth/verify-code', method: 'POST', data: { mobile, code, scene } }); } // 更新用户信息接口 export function updateUserInfoApi(nickname) { return request({ url: '/api/user/update', method: 'POST', data: { nickname } }) } // 获取随机用户列表(广场页面使用) export function getRandomUsersApi(page = 1, pageSize) { return request({ url: `/api/v1/social/users?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 好友列表接口 export function friendListApi(page = 1, pageSize = 10) { return request({ url: `/api/v1/social/friends?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取用户信息接口(从缓存或API) export function getUserProfileApi() { return request({ url: '/api/v1/auth/me', method: 'GET' }) } // 修改昵称接口 export function updateNicknameApi(nickname) { return request({ url: '/api/v1/me/nickname', method: 'PUT', data: { nickname } }) } // 模拟注销账号接口 async function mockDeleteAccountApi() { await mockDelay(600) // 模拟网络延迟 return { code: 200, message: '账号注销成功', data: null } } // 注销账号接口 export function deleteAccountApi() { if (USE_MOCK_API) { return mockDeleteAccountApi() } return request({ url: '/api/user/delete-account', method: 'POST' }) } // 修改密码接口 export function updatePasswordApi(oldPassword, newPassword) { return request({ url: '/api/v1/account/password', method: 'POST', data: { old_password: oldPassword, new_password: newPassword } }) } // 搜索用户 export function searchUserApi(friendUserId) { return request({ url: `/api/v1/social/search-user?friend_fan_profile_id=${friendUserId}`, method: 'GET' }) } // 获取已发送的好友请求 export function getSentFriendRequestsApi(page = 1, pageSize = 10) { return request({ url: `/api/v1/social/friend-requests?type=sent&status=pending&page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 发送好友请求(添加好友) export function sendFriendRequestApi(friendUserId) { return request({ url: '/api/v1/social/friend-requests', method: 'POST', data: { friend_user_id: friendUserId } }) } // 获取收到的好友请求 export function getReceivedFriendRequestsApi(page = 1, pageSize = 10) { return request({ url: `/api/v1/social/friend-requests?type=received&status=pending&page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 处理好友请求(接受/拒绝) export function handleFriendRequestApi(requestId, action) { return request({ url: '/api/v1/social/friend-requests/handle', method: 'POST', data: { request_id: requestId, action: action } }) } // 删除好友 export function deleteFriendApi(friendUserId) { return request({ url: '/api/v1/social/friends', method: 'DELETE', data: { friend_user_id: friendUserId } }) } // 获取可选的粉丝身份列表 export function getFanIdentitiesApi() { return request({ url: '/api/v1/fan-identities', method: 'GET' }) } // 添加新的粉丝身份 export function addFanIdentityApi(starId, nickname) { return request({ url: '/api/v1/my/fan-identities', method: 'POST', data: { star_id: starId, nickname: nickname } }) } // 获取用户当前拥有的所有粉丝身份 export function getMyFanIdentitiesApi() { return request({ url: '/api/v1/my/fan-identities', method: 'GET' }) } // 切换粉丝身份 export function switchFanIdentityApi(newStarId) { return request({ url: '/api/v1/my/fan-identities/switch', method: 'POST', data: { new_star_id: newStarId } }) } // 获取用户藏品列表 export function getMyAssetsApi(page = 1, pageSize = 20) { return request({ url: `/api/v1/assets/me/items?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取藏品详情 export function getAssetDetailApi(assetId) { return request({ url: `/api/v1/assets/${assetId}`, method: 'GET' }) } // 点赞藏品 export function likeAssetApi(assetId) { return request({ url: `/api/v1/social/assets/${assetId}/like`, method: 'POST' }) } // 取消点赞藏品 export function unlikeAssetApi(assetId) { return request({ url: `/api/v1/social/assets/${assetId}/like`, method: 'DELETE' }) } // 获取资产点赞用户列表 export function getAssetLikersApi(assetId, pageSize = 6, cursor = 0) { return request({ url: `/api/v1/social/assets/${assetId}/likers?page_size=${pageSize}&cursor=${cursor}`, method: 'GET' }) } // 获取我的展馆槽位信息 export function getMyGalleriesApi() { return request({ url: '/api/v1/mygalleries', method: 'GET' }) } // 获取指定用户的展馆槽位信息 export function getUserGalleriesApi(targetUid) { return request({ url: `/api/v1/galleries/${targetUid}`, method: 'GET' }) } // 获取随机用户的展馆槽位信息 export function getRandomGalleryApi() { return request({ url: '/api/v1/galleries/random', method: 'GET' }) } // 放置藏品到展馆 export function placeAssetToGalleryApi(assetId, galleryOwnerId, slotId) { return request({ url: '/api/v1/galleries/place', method: 'POST', data: { asset_id: assetId, gallery_owner_id: galleryOwnerId, slot_id: slotId } }) } // 下架藏品 export function removeAssetFromGalleryApi(slotId) { return request({ url: `/api/v1/galleries/slots/${slotId}/asset`, method: 'DELETE' }) } /** * 获取 OSS 浏览器直传凭证(PostObject 表单字段) * 对应网关:GET /api/v1/assets/oss/upload-signature(与 /oss/signature 同一处理逻辑,此处走阶段一推荐路径) * @param {'avatar'|'asset'} [type='asset'] 上传目录类型 * @param {string} [orderId] 可选;传入则与后续 POST /api/v1/assets/mints 使用同一 order_id(后端 InitMintOrder) */ export function getOssSignatureApi(type = 'asset', orderId = '') { let url = `/api/v1/assets/oss/upload-signature?type=${encodeURIComponent(type)}` if (orderId) { url += `&order_id=${encodeURIComponent(orderId)}` } return request({ url, method: 'GET' }) } /** 兼容旧调用名:与 getOssSignatureApi 相同 */ export const getOssUploadSignatureApi = getOssSignatureApi /** * 获取公开 OSS 上传签名(注册等未登录场景用) * 对应网关:GET /api/v1/public/oss/upload-signature * @param {string} scene 场景,目前固定为 'register' * @param {string} key 命名空间,注册场景下传 mobile(用于服务端限定上传目录) */ export function getPublicOssSignatureApi(scene, key) { return request({ url: `/api/v1/public/oss/upload-signature?scene=${encodeURIComponent(scene)}&key=${encodeURIComponent(key)}`, method: 'GET' }) } /** * 获取 OSS 预签名 GET URL(私有桶读图) * 对应网关:GET /api/v1/assets/oss/presigned-url */ export function getOssPresignedUrlApi(fileName, expires = 3600, type = 'avatar') { return request({ url: `/api/v1/assets/oss/presigned-url?file_name=${encodeURIComponent(fileName)}&expires=${expires}&type=${type}`, method: 'GET' }) } /** * 批量预签名读 URL * 对应网关:GET /api/v1/assets/oss/batch-presigned-urls */ export function getBatchOssPresignedUrlsApi(files, expires = 3600, type = 'asset') { return request({ url: `/api/v1/assets/oss/batch-presigned-urls?files=${encodeURIComponent(JSON.stringify(files))}&expires=${expires}&type=${type}`, method: 'GET' }) } /** * 使用网关下发的 Post 策略将本地临时文件直传 OSS(App / 小程序等) * @param {string} filePath uni.chooseImage 等返回的 tempFilePaths 项 * @param {{ type?: 'avatar'|'asset', orderId?: string, fileName?: string }} [options] * @returns {Promise<{ imageUrl: string, orderId?: string, data: object }>} */ export function uploadLocalFileToOss(filePath, options = {}) { const { type = 'asset', orderId = '', fileName } = options const objectName = fileName || `${Date.now()}.jpg` return new Promise((resolve, reject) => { getOssSignatureApi(type, orderId) .then((signRes) => { if (!signRes || signRes.code !== 200 || !signRes.data) { reject(new Error((signRes && signRes.message) || '获取 OSS 签名失败')) return } const d = signRes.data const host = d.host const dir = d.dir || '' if (!host) { reject(new Error('签名数据缺少 host')) return } uni.uploadFile({ url: host, filePath, name: 'file', formData: { key: dir + objectName, policy: d.policy, success_action_status: '200', 'x-oss-credential': d.x_oss_credential, 'x-oss-date': d.x_oss_date, 'x-oss-security-token': d.security_token, 'x-oss-signature': d.signature, 'x-oss-signature-version': d.x_oss_signature_version }, success: (uploadRes) => { const ok = uploadRes.statusCode === 200 || uploadRes.statusCode === 204 if (!ok) { reject(new Error(`OSS 上传失败 HTTP ${uploadRes.statusCode}`)) return } const imageUrl = `${host.replace(/\/+$/, '')}/${dir}${objectName}` resolve({ imageUrl, orderId: d.order_id, data: d }) }, fail: (e) => { reject(new Error(e.errMsg || 'OSS 上传失败')) } }) }) .catch(reject) }) } // 更新用户头像 export function updateAvatarApi(avatarUrl) { return request({ url: '/api/v1/me/avatar', method: 'PUT', data: { avatar_url: avatarUrl } }) } // 创建铸造订单 export function createMintOrderApi(orderData) { return request({ url: '/api/v1/assets/mints', method: 'POST', data: orderData }) } // 删除铸造订单 export function deleteMintOrderApi(orderId) { return request({ url: `/api/v1/assets/mints/${orderId}`, method: 'DELETE' }) } // 获取铸造订单详情 export function getMintOrderDetailApi(orderId) { return request({ url: `/api/v1/assets/mints/${orderId}`, method: 'GET' }) } // 估算铸造费用(显示消耗和余额) export function estimateMintCostApi() { return request({ url: '/api/v1/assets/mints/cost-estimate', method: 'POST' }) } // 上传素材(返回 material_id) export function uploadMaterialApi(data) { return request({ url: '/api/v1/assets/materials/upload', method: 'POST', data }) } // 绑定资产素材关联 export function bindAssetMaterialsApi(assetId, materials) { return request({ url: `/api/v1/assets/${assetId}/materials`, method: 'POST', data: { materials } }) } // 获取资产素材列表 export function getAssetMaterialsApi(assetId) { return request({ url: `/api/v1/assets/${assetId}/materials`, method: 'GET' }) } /** * 解析抠图接口 JSON 响应 */ function parseSegmentPortraitResponse(statusCode, rawBody) { let body = rawBody try { body = typeof body === 'string' ? JSON.parse(body) : body } catch (e) { if (statusCode === 404) { throw new Error( '抠图接口 404:团队 Gateway 暂无 /segment,请在本机执行 start-all.ps1 并确认 SEGMENT_BASE 指向 8081' ) } throw new Error('抠图接口返回非 JSON') } if (statusCode === 401) { throw new Error('登录已过期') } if (statusCode < 200 || statusCode >= 300) { const msg = body?.message || `抠图失败 HTTP ${statusCode}` throw new Error(msg) } if (body?.code !== undefined && body.code !== 200) { throw new Error(body.message || '抠图失败') } return body } function isH5SpecialImagePath(path) { return /^blob:/i.test(path) || /^data:image\//i.test(path) } /** * H5:blob/data URL 无法用 uni.uploadFile,改 fetch + FormData * @param {string} filePath * @param {string} [imageBase64] */ async function segmentPortraitApiH5(filePath, imageBase64) { const token = uni.getStorageSync('access_token') const source = (imageBase64 && String(imageBase64).startsWith('data:')) ? String(imageBase64) : filePath const res = await fetch(source) const blob = await res.blob() const fd = new FormData() const ext = (blob.type || '').includes('png') ? 'png' : 'jpg' fd.append('image', blob, `upload.${ext}`) fd.append('scene', 'portrait') const headers = {} if (token) { headers.Authorization = `Bearer ${token}` } const uploadRes = await fetch(`${getSegmentApiBaseUrl()}/api/v1/segment`, { method: 'POST', headers, body: fd, }) const text = await uploadRes.text() return parseSegmentPortraitResponse(uploadRes.status, text) } /** * 人像抠图(multipart)— POST /api/v1/segment?scene=portrait * @param {string} filePath 本地图片路径 * @param {{ imageBase64?: string }} [options] H5 可传 data URL 作兜底 * @returns {Promise<{ code: number, data: { success: boolean, cutout_oss_key?: string, cutout_url_signed?: string, error_code?: string, message?: string } }>} */ export function segmentPortraitApi(filePath, options = {}) { const path = String(filePath || '').trim() const imageBase64 = options.imageBase64 || '' // #ifdef H5 if (isH5SpecialImagePath(path) || (imageBase64 && imageBase64.startsWith('data:'))) { return segmentPortraitApiH5(path, imageBase64) } // #endif return new Promise((resolve, reject) => { const token = uni.getStorageSync('access_token') uni.uploadFile({ url: `${getSegmentApiBaseUrl()}/api/v1/segment`, filePath: path, name: 'image', formData: { scene: 'portrait' }, timeout: 120000, header: token ? { Authorization: `Bearer ${token}` } : {}, success: (res) => { try { resolve(parseSegmentPortraitResponse(res.statusCode, res.data)) } catch (e) { reject(e) } }, fail: (err) => reject(new Error(err?.errMsg || '抠图请求失败')), }) }) } // 图生图 export function imageGenerationApi(params) { return request({ url: '/api/v1/assets/mints/image/generation', method: 'POST', data: params }) } // 获取热度排行榜 export function getHotRankingApi(dimension = 'total', starId = null, page = 1, pageSize = 10) { let url = `/api/v1/rankings/hot?dimension=${dimension}&page=${page}&page_size=${pageSize}` if (starId) { url += `&star_id=${starId}` } return request({ url: url, method: 'GET' }) } // 获取自制排行榜 export function getOriginalRankingApi(dimension = 'total', starId = null, page = 1, pageSize = 10) { let url = `/api/v1/rankings/original?dimension=${dimension}&page=${page}&page_size=${pageSize}` if (starId) { url += `&star_id=${starId}` } return request({ url: url, method: 'GET' }) } // ==================== 活动相关接口 ==================== // 获取活动列表 export function getActivityListApi(starId, page = 1, pageSize = 10) { let url = `/api/v1/activities?star_id=${starId}&page=${page}&page_size=${pageSize}` // if (status) { // url += `&status=${status}` // } return request({ url: url, method: 'GET' }) } // 获取活动详情 export function getActivityDetailApi(activityId) { return request({ url: `/api/v1/activities/${activityId}`, method: 'GET' }) } // 获取活动道具列表 export function getActivityItemsApi(activityId) { return request({ url: `/api/v1/activities/${activityId}/items`, method: 'GET' }) } // 获取活动进度 export function getActivityProgressApi(activityId) { return request({ url: `/api/v1/activities/${activityId}/progress`, method: 'GET' }) } // 购买活动道具 export function purchaseActivityItemApi(activityId, itemType, quantity = 1) { return request({ url: `/api/v1/activities/${activityId}/purchase`, method: 'POST', data: { item_type: itemType, quantity: quantity } }) } // 批量购买活动道具 export function batchPurchaseActivityItemsApi(activityId, items) { return request({ url: `/api/v1/activities/${activityId}/batch-purchase`, method: 'POST', data: { items: items } }) } // 获取活动最新贡献记录(实时轮询用) export function getActivityContributionsLatestApi(activityId, sinceTimestamp = 0, sinceId = 0, limit = 5) { return request({ url: `/api/v1/activities/${activityId}/contributions/latest?since_timestamp=${sinceTimestamp}&since_id=${sinceId}&limit=${limit}`, method: 'GET' }) } // 获取活动贡献点排名 export function getActivityRankingApi(activityId, starId = null, page = 1, pageSize = 10) { let url = `/api/v1/activities/${activityId}/ranking?page=${page}&page_size=${pageSize}` if (starId) { url += `&star_id=${starId}` } return request({ url: url, method: 'GET' }) } // ==================== 星册相关接口 ==================== // 获取星册首页数据 export function getStarbookHomeApi() { return request({ url: '/api/v1/starbook/home', method: 'GET' }) } // 获取星册藏品列表(分页) export function getStarbookItemsApi(type, category, grade = null, page = 1, pageSize = 20) { let url = `/api/v1/starbook/items?type=${type}&category=${category}&page=${page}&page_size=${pageSize}` if (grade !== null) { url += `&grade=${grade}` } return request({ url: url, method: 'GET' }) } // ==================== 他人作品统计接口 ==================== // 获取他人点赞的作品列表 export function getUserLikedAssetsApi(userId, page = 1, pageSize = 20) { return request({ url: `/api/v1/users/${userId}/liked-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取他人展出的作品列表 export function getUserExhibitedAssetsApi(userId, page = 1, pageSize = 20) { return request({ url: `/api/v1/users/${userId}/exhibited-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // ==================== 我的作品统计接口 ==================== // 获取我展出的作品列表 export function getMyExhibitedAssetsApi(page = 1, pageSize = 20) { return request({ url: `/api/v1/me/exhibited-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取我点赞的作品列表 export function getMyLikedAssetsApi(page = 1, pageSize = 20) { return request({ url: `/api/v1/me/liked-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取我今日点赞的作品列表 export function getMyTodayLikedAssetsApi(page = 1, pageSize = 20) { return request({ url: `/api/v1/me/today-liked-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // 获取我本周点赞的作品列表 export function getMyWeekLikedAssetsApi(page = 1, pageSize = 20) { return request({ url: `/api/v1/me/week-liked-assets?page=${page}&page_size=${pageSize}`, method: 'GET' }) } // ==================== 灵感瀑布相关接口 ==================== // 获取灵感瀑布藏品列表 export function getInspirationFlowApi(params) { return request({ url: '/api/v1/inspiration-flow', method: 'GET', data: params }) } // ==================== 铸造活动相关接口(运营banner)==================== // 获取铸造活动列表 export function getMintingActivitiesApi(starId = null, page = 1, pageSize = 10) { let url = `/api/v1/minting-activities?page=${page}&page_size=${pageSize}` if (starId) { url += `&star_id=${starId}` } return request({ url: url, method: 'GET' }) } // 获取收益汇总接口 export function getEarningsSummaryApi() { return request({ url: '/api/v1/assets/me/earnings-summary', method: 'GET' }) } // ==================== 数据看板 ==================== import { mockRouter } from './mock/dashboard' const DASHBOARD_PREFIX = '/api/v1/dashboard' // mock 触发器:当 USE_MOCK_API 为 true 时短路返回 mock 数据 // 后端就绪后将 USE_MOCK_API 改为 false 即可 async function dashboardRequest(endpoint, params = {}) { if (USE_MOCK_API) { const factory = mockRouter[`${DASHBOARD_PREFIX}${endpoint}`] if (factory) return factory(params) } return request({ url: `${DASHBOARD_PREFIX}${endpoint}`, method: 'GET', data: params }) } export const dashboardApi = { getTodayOverview: (starId) => dashboardRequest('/today-overview', { star_id: starId }), get7DayIncomeCurve: (starId) => dashboardRequest('/income-curve', { star_id: starId }), getExhibitionSummary: (starId) => dashboardRequest('/exhibition-summary', { star_id: starId }), getLikeIncomeByLevel: (starId) => dashboardRequest('/like-income-by-level', { star_id: starId }), getTopAssets: (starId) => dashboardRequest('/top-assets', { star_id: starId }), getLevelDistribution: (starId) => dashboardRequest('/level-distribution', { star_id: starId }), getUpgradeProgress: (starId) => dashboardRequest('/upgrade-progress', { star_id: starId }), }