31cc1e02ce
- 新增 AffiliateProgram / AffiliateLink / AffiliateClick 规范化 Prisma 模型 取代原手写裸表 affiliate_stats / affiliate_clicks - 新增迁移 prisma/migrations/20260711000000_add_affiliate_models - 重构 affiliate.service.ts 改用 Prisma ORM,消除 $queryRawUnsafe SQL 注入 - 重构 affiliate.controller.ts 接口:programs / links(?skillId,?toolId) / stats / click - 前端 affiliate 页接入真实接口,移除硬编码 demo 数据 - 技能详情页新增「学此技能推荐使用的工具」联盟链接区块 - 新增 affiliate.service.spec.ts(4 用例通过)与幂等种子 seed-affiliate.ts - 更新 docs/progress/current.md,明确无 ICP 经营许可证下以联盟返佣为合规变现主路径 - 含此前工作区未提交改动(工具 slug 路由、支付/订单、SEO 等) Co-Authored-By: opencode <opencode@anthropic.com>
119 lines
6.3 KiB
TypeScript
Executable File
119 lines
6.3 KiB
TypeScript
Executable File
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import Link from 'next/link';
|
|
import { useT } from '@/i18n';
|
|
import { API_BASE } from '@/lib/config';
|
|
import Image from 'next/image';
|
|
|
|
interface BeianInfo {
|
|
icp: string
|
|
gongan: string
|
|
gonganLink: string
|
|
showGongan: boolean
|
|
}
|
|
|
|
function getBeianInfo(): BeianInfo {
|
|
if (typeof window === 'undefined') {
|
|
return { icp: '京ICP备2026007249号-1', gongan: '京公网安备11011502039545号', gonganLink: 'https://beian.mps.gov.cn/#/query/webSearch?code=11011502039545', showGongan: true }
|
|
}
|
|
const hostname = window.location.hostname
|
|
if (hostname === 'yuzhiran.com' || hostname === 'www.yuzhiran.com') {
|
|
return { icp: '京ICP备2026007249号-1', gongan: '京公网安备11011502039545号', gonganLink: 'https://beian.mps.gov.cn/#/query/webSearch?code=11011502039545', showGongan: true }
|
|
}
|
|
if (hostname === 'yuzhiran.com.cn' || hostname === 'www.yuzhiran.com.cn') {
|
|
return { icp: '京ICP备2026007249号-2', gongan: '京公网安备11011502039622号', gonganLink: 'https://beian.mps.gov.cn/#/query/webSearch?code=11011502039622', showGongan: true }
|
|
}
|
|
return { icp: '京ICP备2026007249号-1', gongan: '京公网安备11011502039545号', gonganLink: 'https://beian.mps.gov.cn/#/query/webSearch?code=11011502039545', showGongan: true }
|
|
}
|
|
|
|
const qrCodes = [
|
|
{ src: '/images/yzr/yuzhiran.jpg', alt: '微信公众号', label: '微信公众号' },
|
|
{ src: '/images/yzr/yuzhiran-tech.jpg', alt: '微信服务号', label: '微信服务号' },
|
|
{ src: '/images/yzr/yuzhiran-yhl.jpg', alt: '小程序', label: '小程序' },
|
|
{ src: '/images/yzr/kefu.png', alt: '微信客服', label: '微信客服' },
|
|
]
|
|
|
|
export function Footer() {
|
|
const t = useT();
|
|
const [config, setConfig] = useState<Record<string, string>>({});
|
|
const [beian, setBeian] = useState<BeianInfo>({ icp: '', gongan: '', gonganLink: '', showGongan: false });
|
|
|
|
useEffect(() => {
|
|
setBeian(getBeianInfo());
|
|
fetch(`${API_BASE}/public/config`)
|
|
.then(r => r.json()).then(data => setConfig(data || {}))
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
return (
|
|
<footer className="border-t border-border bg-muted/30">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
|
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-8">
|
|
<div className="col-span-2 md:col-span-2">
|
|
<h3 className="text-lg font-bold bg-gradient-to-r from-brand-600 to-brand-400 bg-clip-text text-transparent mb-4">宇之然 AI</h3>
|
|
<p className="text-sm text-muted-foreground mb-4">{t.footer.tagline}</p>
|
|
<div className="flex flex-wrap gap-3">
|
|
{qrCodes.map((qr) => (
|
|
<div key={qr.alt} className="text-center group">
|
|
<Image
|
|
src={qr.src}
|
|
alt={qr.alt}
|
|
width={72}
|
|
height={72}
|
|
className="rounded-lg bg-white transition-transform duration-200 group-hover:scale-150 group-hover:z-10 group-hover:shadow-xl cursor-pointer"
|
|
unoptimized
|
|
/>
|
|
<p className="text-xs text-muted-foreground mt-1">{qr.label}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-3">{t.footer.explore}</h4>
|
|
<ul className="space-y-2.5">
|
|
<li><Link href="/courses" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.nav.courses}</Link></li>
|
|
<li><Link href="/sandbox" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.nav.sandbox}</Link></li>
|
|
<li><Link href="/prompts" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.nav.prompts}</Link></li>
|
|
<li><Link href="/resources" className="text-sm text-muted-foreground hover:text-foreground transition-colors">云资源</Link></li>
|
|
<li><Link href="/tools" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.footer.aiTools}</Link></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-3">{t.footer.about}</h4>
|
|
<ul className="space-y-2.5">
|
|
<li><Link href="/about" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.footer.aboutUs}</Link></li>
|
|
<li><Link href="/privacy" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.footer.privacy}</Link></li>
|
|
<li><Link href="/terms" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.footer.terms}</Link></li>
|
|
<li><Link href="/ai-agreement" className="text-sm text-muted-foreground hover:text-foreground transition-colors">{t.footer.aiAgreement}</Link></li>
|
|
</ul>
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-semibold mb-3">{t.footer.contact}</h4>
|
|
<ul className="space-y-2.5">
|
|
<li className="text-sm text-muted-foreground">{config.contact_email ? `邮箱:${config.contact_email}` : '邮箱:contact@yuzhiran.com'}</li>
|
|
<li className="text-sm text-muted-foreground">北京宇之然科技中心</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div className="mt-10 pt-8 border-t border-border">
|
|
<div className="flex flex-col md:flex-row items-center justify-between gap-2 text-xs text-muted-foreground">
|
|
<p>{t.footer.copyright.replace('{year}', String(new Date().getFullYear()))}</p>
|
|
<div className="flex items-center gap-3">
|
|
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer" className="hover:text-foreground transition-colors">
|
|
{beian.icp}
|
|
</a>
|
|
{beian.showGongan && (
|
|
<a href={beian.gonganLink} target="_blank" rel="noreferrer" className="hover:text-foreground transition-colors inline-flex items-center gap-1">
|
|
<Image src="/images/beian/gongan-beian.png" alt="公安备案" width={16} height={16} unoptimized />
|
|
{beian.gongan}
|
|
</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
);
|
|
}
|