init: 初始化 AssetX 项目仓库

包含 webapp(Next.js 用户端)、webapp-back(Go 后端)、
antdesign(管理后台)、landingpage(营销落地页)、
数据库 SQL 和配置文件。
This commit is contained in:
2026-03-27 11:26:43 +00:00
commit 2ee4553b71
634 changed files with 988255 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
'use client';
import { motion } from 'framer-motion';
import { Card, CardBody, Avatar, AvatarGroup } from '@heroui/react';
import { useLanguage } from '@/contexts/LanguageContext';
import { useTheme } from '@/contexts/ThemeContext';
import { useCountUp } from '@/hooks/useCountUp';
// 格式化数字 - 确保始终显示正确的单位
function formatNumber(num: number, prefix: string = '', suffix: string = '', forceUnit: 'M' | 'K' | '' = '') {
if (forceUnit === 'M') {
return `${prefix}${Math.floor(num)}${suffix}`;
} else if (forceUnit === 'K') {
return `${prefix}${Math.floor(num)}${suffix}`;
} else if (num >= 1000000) {
return `${prefix}${Math.floor(num / 1000000)}M${suffix}`;
} else if (num >= 1000) {
return `${prefix}${Math.floor(num / 1000)}K${suffix}`;
}
return `${prefix}${num.toLocaleString()}${suffix}`;
}
export default function StatsSection() {
const { t } = useLanguage();
const { theme } = useTheme();
const tvl = useCountUp(485, 1500, 0.80);
const apy = useCountUp(515, 1500, 0.85);
const yield_ = useCountUp(45, 1500, 0.75);
const users = useCountUp(23928, 1800, 0.80);
const isDark = theme === 'dark';
return (
<section
className="w-full overflow-x-clip border-b transition-colors bg-bg-base border-border-normal flex-shrink-0 flex justify-center"
style={{ paddingLeft: 'clamp(16px, 4vw, 80px)', paddingRight: 'clamp(16px, 4vw, 80px)' }}
>
<div className="w-full max-w-[1440px] 2xl:max-w-[1760px] 3xl:max-w-[2200px] grid grid-cols-2 md:grid-cols-4">
{/* TVL */}
<Card
className="rounded-none border-r border-b md:border-b-0 transition-colors bg-bg-base border-border-normal"
shadow="none"
>
<CardBody className="flex flex-col gap-2 items-start justify-center py-4 md:py-0 md:h-[182px] px-4 md:px-0">
<p className="font-domine transition-colors text-text-secondary" style={{ fontSize: 'clamp(14px, 1vw, 20px)' }}>
{t('stats.tvl')}
</p>
<div
ref={tvl.elementRef}
className="font-extrabold font-domine transition-colors text-text-primary"
style={{ fontSize: 'clamp(20px, 2.5vw, 48px)', lineHeight: '110%', letterSpacing: '-0.01em' }}
>
{formatNumber(tvl.count, '$', 'M+', 'M')}
</div>
</CardBody>
</Card>
{/* APY */}
<Card
className={`rounded-none border-b md:border-b-0 md:border-r transition-colors ${
isDark ? 'bg-[#0a0a0a] border-[#27272a]' : 'bg-white border-[#e5e7eb]'
}`}
shadow="none"
>
<CardBody className="flex flex-col gap-2 items-start justify-center py-4 md:py-0 md:h-[182px] px-4 md:px-8">
<p className="font-domine transition-colors text-text-secondary" style={{ fontSize: 'clamp(14px, 1vw, 20px)' }}>
{t('stats.apy')}
</p>
<div
ref={apy.elementRef}
className="font-extrabold font-domine transition-colors"
style={{ fontSize: 'clamp(20px, 2.5vw, 48px)', lineHeight: '110%', letterSpacing: '-0.01em', color: '#059669' }}
>
{(apy.count / 100).toFixed(2)}%
</div>
</CardBody>
</Card>
{/* Yield */}
<Card
className={`rounded-none border-r transition-colors ${
isDark ? 'bg-[#0a0a0a] border-[#27272a]' : 'bg-white border-[#e5e7eb]'
}`}
shadow="none"
>
<CardBody className="flex flex-col gap-2 items-start justify-center py-4 md:py-0 md:h-[182px] px-4 md:px-8">
<p className="font-domine transition-colors text-text-secondary" style={{ fontSize: 'clamp(14px, 1vw, 20px)' }}>
{t('stats.yield')}
</p>
<div
ref={yield_.elementRef}
className="font-extrabold font-domine transition-colors text-text-primary"
style={{ fontSize: 'clamp(20px, 2.5vw, 48px)', lineHeight: '110%', letterSpacing: '-0.01em' }}
>
{formatNumber(yield_.count, '$', 'M', 'M')}
</div>
</CardBody>
</Card>
{/* Users */}
<Card
className="rounded-none transition-colors bg-bg-base overflow-hidden"
shadow="none"
>
<CardBody className="flex flex-col gap-2 items-start justify-center py-4 md:py-0 md:h-[182px] px-4 md:pl-8 overflow-hidden">
<p className="font-domine transition-colors text-text-secondary" style={{ fontSize: 'clamp(14px, 1vw, 20px)' }}>
{t('stats.users')}
</p>
<div className="flex flex-row items-center gap-4">
<div
ref={users.elementRef}
className="text-xl md:text-2xl xl:text-4xl font-extrabold font-domine transition-colors text-text-primary"
style={{ lineHeight: '110%', letterSpacing: '-0.01em' }}
>
{users.count.toLocaleString()}+
</div>
<motion.div
className="hidden lg:block"
initial={{ y: '3rem', opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.7, ease: 'easeOut', delay: 0.5 }}
>
<AvatarGroup max={4}>
<Avatar src="/image-230.png" size="sm" />
<Avatar src="/image-240.png" size="sm" />
<Avatar src="/image-250.png" size="sm" />
<Avatar src="/image-251.png" size="sm" />
</AvatarGroup>
</motion.div>
</div>
</CardBody>
</Card>
</div>
</section>
);
}