/** * 应援活动主题配置模块 * 支持生日、演唱会、巴士三种活动类型 * 支持从后端动态获取配置 */ import { getActivityListApi, getActivityDetailApi, getActivityItemsApi, getActivityProgressApi, purchaseActivityItemApi } from './api.js' // 活动类型常量 export const ACTIVITY_TYPES = { BIRTHDAY: 'birthday', CONCERT: 'concert', BUS: 'bus', } // 阶段常量(内部使用) const STAGE_TYPES = { EARLY: 'early', // 0-25% MID: 'mid', // 26-50% LATE: 'late', // 51-75% COMPLETED: 'completed' // 76-100% } // 默认气泡文本(当后端未返回时使用) const DEFAULT_BUBBLE_TEXTS = ['加油!', '一起努力!', '继续前进!'] // ==================== API 调用函数 ==================== /** * 获取活动列表 * @param {number} starId - 明星ID * @param {string} status - 活动状态(可选) * @param {number} page - 页码 * @param {number} pageSize - 每页数量 * @returns {Promise} 活动列表 */ export async function fetchActivityList(starId, page = 1, pageSize = 10) { try { const response = await getActivityListApi(starId, page, pageSize) if (response.code === 200 && response.data) { return { activities: response.data.activities || [], page: response.data.page || page, pageSize: response.data.page_size || pageSize, total: response.data.total || 0 } } throw new Error(response.message || '获取活动列表失败') } catch (error) { console.error('fetchActivityList error:', error) throw error } } /** * 获取活动详情 * @param {number} activityId - 活动ID * @returns {Promise} 活动详情 */ export async function fetchActivityDetail(activityId) { try { const response = await getActivityDetailApi(activityId) if (response.code === 200 && response.data) { return enrichActivityData(response.data) } throw new Error(response.message || '获取活动详情失败') } catch (error) { console.error('fetchActivityDetail error:', error) throw error } } /** * 获取活动道具列表 * @param {number} activityId - 活动ID * @returns {Promise} 道具列表 */ export async function fetchActivityItems(activityId) { try { const response = await getActivityItemsApi(activityId) if (response.code === 200 && response.data) { return response.data.items || [] } throw new Error(response.message || '获取道具列表失败') } catch (error) { console.error('fetchActivityItems error:', error) throw error } } /** * 获取活动进度 * @param {number} activityId - 活动ID * @returns {Promise} 进度信息 */ export async function fetchActivityProgress(activityId) { try { const response = await getActivityProgressApi(activityId) if (response.code === 200 && response.data) { return response.data } throw new Error(response.message || '获取活动进度失败') } catch (error) { console.error('fetchActivityProgress error:', error) throw error } } /** * 购买活动道具 * @param {number} activityId - 活动ID * @param {string} itemType - 道具类型 * @param {number} quantity - 购买数量 * @returns {Promise} 购买结果 */ export async function purchaseItem(activityId, itemType, quantity = 1) { try { const response = await purchaseActivityItemApi(activityId, itemType, quantity) // 检查活动状态,只有 active 才能购买 if (response.code === 200 && response.data) { if (response.data.activity_status && response.data.activity_status !== 'active') { return { success: false, message: response.data.message || '活动不在进行中,无法购买' } } return { success: true, totalCrystalSpent: response.data.total_crystal_spent, totalContribution: response.data.total_contribution, currentProgress: response.data.current_progress, remainingBalance: response.data.remaining_balance } } return { success: false, message: response.message || '购买道具失败' } } catch (error) { console.error('purchaseItem error:', error) return { success: false, message: error.message || '购买道具失败' } } } // ==================== 数据处理函数 ==================== /** * 丰富活动数据(添加默认配置) * @param {Object} activity - 后端返回的活动数据 * @returns {Object} 丰富后的活动数据 */ function enrichActivityData(activity) { const currentStage = activity.current_stage || calculateStage(activity.current_progress, activity.target_progress) // 使用后端返回的数据,如果没有则使用默认值 const bubbleTexts = activity.bubble_texts || DEFAULT_BUBBLE_TEXTS return { ...activity, current_stage: currentStage, bubble_texts: bubbleTexts, // 转换道具数据格式 items: (activity.items || []).map(item => ({ id: item.id, type: item.item_type, label: item.item_name, icon: item.icon_url, cost: item.crystal_cost, contributionPoints: item.contribution_points })) } } /** * 根据进度计算当前阶段 * @param {number} current - 当前进度 * @param {number} target - 目标进度 * @returns {string} 阶段名称 */ function calculateStage(current, target) { if (current >= target) { return STAGE_TYPES.COMPLETED } const progress = (current / target) * 100 if (progress <= 25) { return STAGE_TYPES.EARLY } else if (progress <= 50) { return STAGE_TYPES.MID } else if (progress <= 75) { return STAGE_TYPES.LATE } else { return STAGE_TYPES.COMPLETED } } /** * 获取活动的时间状态描述 * @param {number} startTime - 开始时间 (秒级时间戳) * @param {number} endTime - 结束时间 (秒级时间戳) * @returns {Object} 状态信息 */ export function getActivityTimeStatus(startTime, endTime) { // 后端返回的是秒级时间戳,需要转换为毫秒 const startTimeMs = startTime * 1000 const endTimeMs = endTime * 1000 const now = Date.now() if (now < startTimeMs) { // 未开始 const diff = startTimeMs - now const days = Math.floor(diff / (1000 * 60 * 60 * 24)) const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) if (days > 0) { return { status: 'pending', text: `距开始还有 ${days} 天 ${hours} 小时` } } else { const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) return { status: 'pending', text: `距开始还有 ${minutes} 分钟` } } } else if (now > endTimeMs) { // 已结束 return { status: 'expired', text: '活动已结束' } } else { // 进行中 const diff = endTimeMs - now const days = Math.floor(diff / (1000 * 60 * 60 * 24)) const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)) if (days > 0) { return { status: 'active', text: `还剩 ${days} 天 ${hours} 小时` } } else { const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) return { status: 'active', text: `还剩 ${minutes} 分钟` } } } }