topfans/frontend/utils/api.js
2026-06-15 16:28:35 +08:00

1021 lines
26 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.

// API 基础配置 — 通过 Vite 注入的环境变量区分开发/生产环境
// .env.development → VITE_API_BASE_URL开发
// .env.production → VITE_API_BASE_URL生产
// HBuilderX「运行」= dev「发行」= prod自动加载对应 .env
// CLIvite --mode development|production
const API_BASE_URL = String(
import.meta.env.VITE_API_BASE_URL
).replace(/\/+$/, '')
const USE_MOCK_API = String(import.meta.env.VITE_USE_MOCK_API || 'false').toLowerCase() === 'true'
// 导出供 composable / 其他模块按需走 mock 短路(避免再读一次 env
export const IS_MOCK_API = USE_MOCK_API
const baseURL = API_BASE_URL
/**
* WebSocket 基础地址
* 优先读取 VITE_WS_BASE_URL独立部署 WS 时使用),未配置则按 API 地址自动推导 http→ws / https→wss
*/
const WS_BASE_URL = (() => {
const configured = import.meta.env.VITE_WS_BASE_URL
if (configured && String(configured).trim()) {
return String(configured).replace(/\/+$/, '')
}
return baseURL.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:')
})()
console.log('[API] env:', 'baseURL:', baseURL, 'ws:', WS_BASE_URL, 'mock:', USE_MOCK_API)
/** 获取 WebSocket 基础地址(环境变量 VITE_WS_BASE_URL未配置时由 API 地址自动推导) */
export async function getWebSocketBaseUrl() {
return WS_BASE_URL
}
/** 抠图专用 Gateway业务走团队库segment 走本机;如需分离可再加 VITE_SEGMENT_BASE_URL */
export function getSegmentApiBaseUrl() {
return baseURL
}
/** 镭射专用 GatewayAI 生成 + compositor 走本地,其他业务走远程;如需分离可再加 VITE_LASER_BASE_URL */
export function getLaserApiBaseUrl() {
return baseURL
}
// 模拟网络延迟
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 — transport error,网关层真鉴权失败)
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 === 0) {
resolve(res.data)
} else if (res.data.code === 16 || res.data.code === 7) {
// 业务状态码 401(token 失效) / 403(账号被封)→ 清缓存 + 跳登录页
// 注:400 是业务校验错误(密码错、参数错、verify_token 错),不登出,reject 让调用方 toast
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: 0,
message: '账号注销成功',
data: null
}
}
// 注销账号接口
export function deleteAccountApi() {
if (USE_MOCK_API) {
return mockDeleteAccountApi()
}
return request({
url: '/api/user/delete-account',
method: 'POST'
})
}
// 修改密码接口(Plan A: 需带 verify_token,scene=password 下发的一次性 token)
export function updatePasswordApi(oldPassword, newPassword, verifyToken) {
return request({
url: '/api/v1/account/password',
method: 'POST',
data: {
old_password: oldPassword,
new_password: newPassword,
verify_token: verifyToken
}
})
}
// 搜索用户
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 策略将本地临时文件直传 OSSApp / 小程序等)
* @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 !== 0 || !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 !== 0) {
throw new Error(body.message || '抠图失败')
}
return body
}
// #ifdef H5
function isH5SpecialImagePath(path) {
return /^blob:/i.test(path) || /^data:image\//i.test(path)
}
/**
* H5blob/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)
}
// #endif
/**
* 人像抠图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 })
}
// ==================== 铸爱工艺配置 ====================
// 鉴权:由 gateway AuthMiddleware 强制 JWT
// 响应:{ categories: [{ id, name, type_key, sort_order, crafts: [{ id, name, image_url, route_path, route_params, sort_order }] }], version }
// 缓存:后端 5s 进程内缓存,运营改完最长 5s 端上生效
export function getCastloveConfigApi() {
return request({
url: '/api/v1/castlove/config',
method: 'GET'
})
}
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 }),
}