crush-level-web/src/app/(main)/leaderboard/components/SmallRankCard.tsx

84 lines
2.9 KiB
TypeScript
Raw Normal View History

2025-11-28 06:31:36 +00:00
'use client'
2025-11-13 08:38:25 +00:00
2025-11-28 06:31:36 +00:00
import { formatNumberToKMB } from '@/lib/utils'
import Image from 'next/image'
import { AiChatRankOutput, AiHeartbeatRankOutput, AiGiftRankOutput } from '@/services/home/types'
import { RankType } from '@/types/global'
import Link from 'next/link'
2025-11-13 08:38:25 +00:00
interface SmallRankCardProps {
2025-11-28 06:31:36 +00:00
item: AiChatRankOutput | AiHeartbeatRankOutput | AiGiftRankOutput
rankType: RankType
rank?: number // 用于显示排名如果不传则使用item.rankNo
2025-11-13 08:38:25 +00:00
}
2025-11-28 06:31:36 +00:00
export default function SmallRankCard({ item, rankType, rank }: SmallRankCardProps) {
2025-11-13 08:38:25 +00:00
// 根据排行榜类型获取对应的数值显示
const getDisplayValue = () => {
switch (rankType) {
case RankType.CHAT:
2025-11-28 06:31:36 +00:00
return formatNumberToKMB((item as AiChatRankOutput).chatNum || 0)
2025-11-13 08:38:25 +00:00
case RankType.CRUSH:
2025-11-28 06:31:36 +00:00
return `${(item as AiHeartbeatRankOutput).heartbeatValTotal || 0}`
2025-11-13 08:38:25 +00:00
case RankType.GIFTS:
2025-11-28 06:31:36 +00:00
return formatNumberToKMB(Math.floor(((item as AiGiftRankOutput).giftCoinNum || 0) / 100))
2025-11-13 08:38:25 +00:00
default:
2025-11-28 06:31:36 +00:00
return '0'
2025-11-13 08:38:25 +00:00
}
2025-11-28 06:31:36 +00:00
}
2025-11-13 08:38:25 +00:00
// 根据排行榜类型获取对应的图标
const getIcon = () => {
switch (rankType) {
case RankType.CHAT:
2025-11-28 06:31:36 +00:00
return <i className="iconfont icon-Chat !text-[12px]" />
2025-11-13 08:38:25 +00:00
case RankType.CRUSH:
2025-11-28 06:31:36 +00:00
return <Image src="/icons/icon-crush.svg" alt="" width={12} height={12} />
2025-11-13 08:38:25 +00:00
case RankType.GIFTS:
2025-11-28 06:31:36 +00:00
return <Image src="/icons/diamond.svg" alt="" width={12} height={12} />
2025-11-13 08:38:25 +00:00
default:
2025-11-28 06:31:36 +00:00
return <i className="iconfont icon-Chat !text-[12px]" />
2025-11-13 08:38:25 +00:00
}
2025-11-28 06:31:36 +00:00
}
2025-11-13 08:38:25 +00:00
if (!item) {
2025-11-28 06:31:36 +00:00
return <div className="flex-1 py-12"></div>
2025-11-13 08:38:25 +00:00
}
2025-11-28 06:31:36 +00:00
const imageUrl = item.homeImageUrl || ''
const rankNo = rank || item.rankNo || 1
2025-11-13 08:38:25 +00:00
return (
2025-11-28 06:31:36 +00:00
<Link href={`/chat/${item.aiId}`} prefetch={false} key={item.aiId} className="flex-1">
2025-11-13 08:38:25 +00:00
<div className="flex-1 py-12">
2025-11-28 06:31:36 +00:00
<div className="relative aspect-[240/360] w-full overflow-hidden rounded-b-lg">
2025-11-13 08:38:25 +00:00
<div
className="absolute inset-0"
style={{
background: `url(${imageUrl}) #211a2b 50% / cover no-repeat`,
2025-11-28 06:31:36 +00:00
maskImage: 'linear-gradient(180deg, rgba(255, 255, 255, 0.00) 0%, #FFF 55%)',
2025-11-13 08:38:25 +00:00
}}
/>
2025-11-28 06:31:36 +00:00
<div className="absolute right-0 bottom-0 left-0 aspect-[240/112]">
<Image
src={`/images/leaderboard/${rankNo}-st.svg`}
alt=""
fill
className="object-cover"
/>
2025-11-13 08:38:25 +00:00
</div>
<div className="absolute inset-0">
2025-11-28 06:31:36 +00:00
<div className="absolute right-0 bottom-[44] left-0 flex items-center justify-center gap-1">
2025-11-13 08:38:25 +00:00
{getIcon()}
<div className="txt-numMonotype-s">{getDisplayValue()}</div>
</div>
2025-11-28 06:31:36 +00:00
<div className="txt-numDisplay-m absolute right-0 bottom-1 left-0 text-center">
{rankNo === 2 ? '2nd' : '3rd'}
</div>
2025-11-13 08:38:25 +00:00
</div>
</div>
</div>
</Link>
2025-11-28 06:31:36 +00:00
)
2025-11-24 03:47:20 +00:00
}