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