251 lines
6.8 KiB
JavaScript
251 lines
6.8 KiB
JavaScript
/**
|
|
* 应援活动主题配置模块
|
|
* 支持生日、演唱会、巴士三种活动类型
|
|
* 支持从后端动态获取配置
|
|
*/
|
|
|
|
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, status = '', page = 1, pageSize = 10) {
|
|
try {
|
|
const response = await getActivityListApi(starId, status, 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)
|
|
if (response.code === 200 && response.data) {
|
|
return {
|
|
totalCrystalSpent: response.data.total_crystal_spent,
|
|
totalContribution: response.data.total_contribution,
|
|
currentProgress: response.data.current_progress,
|
|
remainingBalance: response.data.remaining_balance
|
|
}
|
|
}
|
|
throw new Error(response.message || '购买道具失败')
|
|
} catch (error) {
|
|
console.error('purchaseItem error:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
// ==================== 数据处理函数 ====================
|
|
|
|
/**
|
|
* 丰富活动数据(添加默认配置)
|
|
* @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} 分钟`
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|