import type { Artist, ArtistTag } from "@/types/artist"; const STAGE_NAMES: Array<[string, string, string]> = [ ["艺奈", "AURORA", "破晓极光"], ["路米", "LUMI", "暖光治愈"], ["星澪", "NEBULA", "星云吟唱"], ["凯", "KAI", "海岸少年"], ["回音", "ECHO", "声波女王"], ["薇尔", "VEIL", "薄雾低语"], ["艾莉雅", "ARIA", "咏叹之声"], ["怜", "REN", "莲华少女"], ["米拉", "MIRA", "镜面舞者"], ["诺娃", "NOVA", "超新星"], ["纪罗", "KIRO", "Rap 制造机"], ["瑞", "ZUI", "醉月夜"], ["阳", "SOL", "阳光少年"], ["凛", "LIN", "学院偶像"], ["律", "LYRA", "竖琴公主"], ["昕", "DAWN", "晨曦少女"], ["天", "SKY", "天空之翼"], ["语", "ARIE", "诗与远方"], ["翼", "WING", "飞翔之翼"], ["铃", "CHIME", "风铃声"], ["夜", "NYX", "暗夜女神"], ["晴", "SUNNY", "晴空万里"], ["月", "LUNA", "月光女神"], ["岚", "STORM", "暴风之子"], ["雷", "BOLT", "雷霆速度"], ["焰", "FLARE", "火焰之心"], ["雪", "FROST", "霜花少女"], ["林", "LEAF", "森林精灵"], ["渊", "ABYSS", "深渊之声"], ["瑶", "JADE", "翡翠少女"], ["晨", "AURIA", "金色晨光"], ["岩", "ROCK", "硬核摇滚"], ["翔", "SOAR", "翱翔天际"], ["茉", "MOLLY", "茉莉芬芳"], ["梓", "AZUR", "蓝调诗人"], ]; // 4 个新主标签均匀分布。每位艺人 1-2 个标签,便于筛选器命中。 const TAG_POOL: ArtistTag[][] = [ ["vocal"], ["dance"], ["all-rounder"], ["rap"], ["vocal", "all-rounder"], ["dance", "all-rounder"], ["rap", "all-rounder"], ["vocal"], ["dance"], ["all-rounder"], ["rap"], ["vocal", "dance"], ]; const THEME_COLORS = [ "#8b5cf6", "#ec4899", "#06b6d4", "#f59e0b", "#10b981", "#ef4444", "#a78bfa", "#f472b6", "#38bdf8", "#fbbf24", "#34d399", "#fb7185", ]; /** 生成确定性 35 位艺人 mock 数据 */ function buildArtists(): Artist[] { return STAGE_NAMES.map(([name, enName, slogan], idx) => { const no = String(idx + 1).padStart(3, "0"); const rank = idx + 1; // 票数采用反比例衰减(确定性 · 避免 SSR/CSR hydration 不一致) // 主曲线:125000/√rank · 用 idx 推导抖动量保持稳定分布 const jitter = ((idx * 1103) % 2999) - 1499; const votes = Math.round(125000 / Math.sqrt(rank) + jitter); return { id: no, no, name, enName, slogan, bio: `来自虚拟星域的偶像候选人 ${enName},从小热爱音乐与舞蹈。性格${ rank % 2 === 0 ? "温柔" : "活泼" },擅长${ idx % 3 === 0 ? "抒情曲" : idx % 3 === 1 ? "舞台表演" : "Rap 创作" }。曾获得多项虚拟偶像新人奖项,代表作品深受粉丝喜爱。立志成为 Top12 出道阵容的一员,用音乐传递梦想与力量。`, portrait: "", avatar: "", gallery: ["", "", "", "", ""], videoUrl: undefined, videoPoster: "", tags: TAG_POOL[idx % TAG_POOL.length]!, birthday: `${String(((idx * 7) % 12) + 1).padStart(2, "0")}-${String( ((idx * 13) % 28) + 1 ).padStart(2, "0")}`, height: 158 + (idx % 12), cv: idx < 12 ? `CV 配音 #${idx + 1}` : undefined, themeColor: THEME_COLORS[idx % THEME_COLORS.length]!, votes, rank, }; }); } export const ARTISTS: Artist[] = buildArtists(); export const TOP_12 = ARTISTS.slice(0, 12); export const CANDIDATES = ARTISTS.slice(12); /** 按当前排序方式获取艺人列表 */ export type SortKey = "votes" | "no" | "recent"; export function sortArtists(list: Artist[], key: SortKey = "votes"): Artist[] { const sorted = [...list]; if (key === "votes") sorted.sort((a, b) => b.votes - a.votes); else if (key === "no") sorted.sort((a, b) => a.no.localeCompare(b.no)); return sorted; } /** 按 ID 获取艺人 */ export function getArtist(id: string): Artist | undefined { return ARTISTS.find((a) => a.id === id); } /** 活动结束时间(mock:当前日期 + 12 天) */ export function getActivityEndTime(): Date { const end = new Date(); end.setDate(end.getDate() + 12); end.setHours(end.getHours() + 3); end.setMinutes(end.getMinutes() + 24); end.setSeconds(end.getSeconds() + 18); return end; }