2026-01-14 12:50:00 +08:00
|
|
|
|
"use client"
|
|
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
import { useState } from "react"
|
2026-01-14 12:50:00 +08:00
|
|
|
|
import { motion, AnimatePresence } from "framer-motion"
|
2026-01-14 07:46:30 +00:00
|
|
|
|
import { Mic, X } from "lucide-react"
|
2026-01-14 07:32:08 +00:00
|
|
|
|
import { Home, List, User } from "lucide-react"
|
|
|
|
|
|
import { useRouter } from "next/navigation"
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
|
|
|
|
|
interface MatchUser {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
nickname: string
|
|
|
|
|
|
avatar: string
|
|
|
|
|
|
tags: string[]
|
|
|
|
|
|
matchScore: number
|
|
|
|
|
|
concept: string
|
|
|
|
|
|
wechat: string
|
|
|
|
|
|
commonInterests: Array<{ icon: string; text: string }>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
const matchTypes = [
|
2026-01-14 07:46:30 +00:00
|
|
|
|
{ id: "team", label: "团队招募", icon: "🎮", color: "#4CAF50", scenario: "team" },
|
|
|
|
|
|
{ id: "resource", label: "资源对接", icon: "👥", color: "#7B61FF", scenario: "resource" },
|
|
|
|
|
|
{ id: "mentor", label: "导师顾问", icon: "❤️", color: "#E91E63", scenario: "mentor" },
|
2026-01-14 05:41:44 +00:00
|
|
|
|
]
|
|
|
|
|
|
|
2026-01-14 07:46:30 +00:00
|
|
|
|
interface JoinModalProps {
|
|
|
|
|
|
isOpen: boolean
|
|
|
|
|
|
onClose: () => void
|
|
|
|
|
|
type: (typeof matchTypes)[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function JoinModal({ isOpen, onClose, type }: JoinModalProps) {
|
|
|
|
|
|
const [phone, setPhone] = useState("")
|
|
|
|
|
|
const [name, setName] = useState("")
|
|
|
|
|
|
const [remark, setRemark] = useState("")
|
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
|
|
|
|
const [submitResult, setSubmitResult] = useState<{ success: boolean; message: string } | null>(null)
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
|
if (!phone) {
|
|
|
|
|
|
setSubmitResult({ success: false, message: "请输入手机号" })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 简单的手机号验证
|
|
|
|
|
|
if (!/^1[3-9]\d{9}$/.test(phone)) {
|
|
|
|
|
|
setSubmitResult({ success: false, message: "请输入正确的手机号" })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setIsSubmitting(true)
|
|
|
|
|
|
setSubmitResult(null)
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch("/api/cunkebao", {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
phone,
|
|
|
|
|
|
name,
|
|
|
|
|
|
scenario: type.scenario,
|
|
|
|
|
|
remark,
|
|
|
|
|
|
}),
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const result = await response.json()
|
|
|
|
|
|
setSubmitResult(result)
|
|
|
|
|
|
|
|
|
|
|
|
if (result.success) {
|
|
|
|
|
|
// 成功后清空表单
|
|
|
|
|
|
setPhone("")
|
|
|
|
|
|
setName("")
|
|
|
|
|
|
setRemark("")
|
|
|
|
|
|
// 3秒后关闭弹窗
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
onClose()
|
|
|
|
|
|
setSubmitResult(null)
|
|
|
|
|
|
}, 3000)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
setSubmitResult({ success: false, message: "网络错误,请稍后重试" })
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setIsSubmitting(false)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isOpen) return null
|
|
|
|
|
|
|
|
|
|
|
|
const getTitle = () => {
|
|
|
|
|
|
switch (type.id) {
|
|
|
|
|
|
case "team":
|
|
|
|
|
|
return "加入切片团队"
|
|
|
|
|
|
case "resource":
|
|
|
|
|
|
return "加入资源群"
|
|
|
|
|
|
case "mentor":
|
|
|
|
|
|
return "预约导师顾问"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "加入"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getDescription = () => {
|
|
|
|
|
|
switch (type.id) {
|
|
|
|
|
|
case "team":
|
|
|
|
|
|
return "加入切片团队,一起创造价值,共享收益"
|
|
|
|
|
|
case "resource":
|
|
|
|
|
|
return "加入资源对接群,链接优质商业资源"
|
|
|
|
|
|
case "mentor":
|
|
|
|
|
|
return "预约一对一导师咨询,获取专业指导"
|
|
|
|
|
|
default:
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<AnimatePresence>
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
|
exit={{ opacity: 0 }}
|
|
|
|
|
|
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4"
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
>
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ scale: 0.9, opacity: 0 }}
|
|
|
|
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
|
|
|
|
exit={{ scale: 0.9, opacity: 0 }}
|
|
|
|
|
|
className="bg-[#1c1c1e] rounded-2xl w-full max-w-sm overflow-hidden"
|
|
|
|
|
|
onClick={(e) => e.stopPropagation()}
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 头部 */}
|
|
|
|
|
|
<div className="relative p-6 pb-4">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="absolute right-4 top-4 w-8 h-8 rounded-full bg-white/10 flex items-center justify-center"
|
|
|
|
|
|
>
|
|
|
|
|
|
<X className="w-4 h-4 text-white/60" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div className="flex items-center gap-3 mb-2">
|
|
|
|
|
|
<span className="text-3xl">{type.icon}</span>
|
|
|
|
|
|
<h2 className="text-xl font-bold text-white">{getTitle()}</h2>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p className="text-white/50 text-sm">{getDescription()}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 表单 */}
|
|
|
|
|
|
<div className="px-6 pb-6 space-y-4">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-white/60 text-sm mb-2">手机号 *</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="tel"
|
|
|
|
|
|
value={phone}
|
|
|
|
|
|
onChange={(e) => setPhone(e.target.value)}
|
|
|
|
|
|
placeholder="请输入手机号"
|
|
|
|
|
|
className="w-full px-4 py-3 rounded-xl bg-black/30 border border-white/10 text-white placeholder-white/30 focus:border-[#00E5FF]/50 focus:outline-none transition-colors"
|
|
|
|
|
|
maxLength={11}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-white/60 text-sm mb-2">姓名(选填)</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={name}
|
|
|
|
|
|
onChange={(e) => setName(e.target.value)}
|
|
|
|
|
|
placeholder="请输入您的姓名"
|
|
|
|
|
|
className="w-full px-4 py-3 rounded-xl bg-black/30 border border-white/10 text-white placeholder-white/30 focus:border-[#00E5FF]/50 focus:outline-none transition-colors"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-white/60 text-sm mb-2">备注(选填)</label>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
value={remark}
|
|
|
|
|
|
onChange={(e) => setRemark(e.target.value)}
|
|
|
|
|
|
placeholder="简单介绍一下您自己"
|
|
|
|
|
|
rows={3}
|
|
|
|
|
|
className="w-full px-4 py-3 rounded-xl bg-black/30 border border-white/10 text-white placeholder-white/30 focus:border-[#00E5FF]/50 focus:outline-none transition-colors resize-none"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 提交结果提示 */}
|
|
|
|
|
|
{submitResult && (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ opacity: 0, y: -10 }}
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
|
className={`p-3 rounded-xl text-sm ${
|
|
|
|
|
|
submitResult.success ? "bg-green-500/20 text-green-400" : "bg-red-500/20 text-red-400"
|
|
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{submitResult.message}
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 提交按钮 */}
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={handleSubmit}
|
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
|
className="w-full py-4 rounded-xl bg-[#00E5FF] text-black font-medium disabled:opacity-50 disabled:cursor-not-allowed transition-opacity"
|
|
|
|
|
|
>
|
|
|
|
|
|
{isSubmitting ? "提交中..." : "立即加入"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<p className="text-white/30 text-xs text-center">提交后我们会尽快与您联系</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
</AnimatePresence>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-14 12:50:00 +08:00
|
|
|
|
export default function MatchPage() {
|
|
|
|
|
|
const [isMatching, setIsMatching] = useState(false)
|
|
|
|
|
|
const [currentMatch, setCurrentMatch] = useState<MatchUser | null>(null)
|
|
|
|
|
|
const [matchAttempts, setMatchAttempts] = useState(0)
|
2026-01-14 07:46:30 +00:00
|
|
|
|
const [selectedType, setSelectedType] = useState(matchTypes[0])
|
|
|
|
|
|
const [showJoinModal, setShowJoinModal] = useState(false)
|
|
|
|
|
|
const [joinType, setJoinType] = useState(matchTypes[0])
|
2026-01-14 07:32:08 +00:00
|
|
|
|
const router = useRouter()
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
|
|
|
|
|
const startMatch = () => {
|
|
|
|
|
|
setIsMatching(true)
|
|
|
|
|
|
setMatchAttempts(0)
|
|
|
|
|
|
setCurrentMatch(null)
|
|
|
|
|
|
|
|
|
|
|
|
const interval = setInterval(() => {
|
|
|
|
|
|
setMatchAttempts((prev) => prev + 1)
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
setTimeout(
|
|
|
|
|
|
() => {
|
|
|
|
|
|
clearInterval(interval)
|
|
|
|
|
|
setIsMatching(false)
|
|
|
|
|
|
setCurrentMatch(getMockMatch())
|
|
|
|
|
|
},
|
|
|
|
|
|
Math.random() * 3000 + 3000,
|
|
|
|
|
|
)
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getMockMatch = (): MatchUser => {
|
2026-01-14 05:41:44 +00:00
|
|
|
|
const nicknames = ["创业先锋", "资源整合者", "私域专家", "商业导师", "连续创业者"]
|
2026-01-14 12:50:00 +08:00
|
|
|
|
const randomIndex = Math.floor(Math.random() * nicknames.length)
|
|
|
|
|
|
const concepts = [
|
2026-01-14 05:41:44 +00:00
|
|
|
|
"专注私域流量运营5年,帮助100+品牌实现从0到1的增长。",
|
|
|
|
|
|
"连续创业者,擅长商业模式设计和资源整合。",
|
|
|
|
|
|
"在Soul分享真实创业故事,希望找到志同道合的合作伙伴。",
|
2026-01-14 12:50:00 +08:00
|
|
|
|
]
|
2026-01-14 05:41:44 +00:00
|
|
|
|
const wechats = ["soul_partner_1", "soul_business_2024", "soul_startup_fan"]
|
|
|
|
|
|
|
2026-01-14 12:50:00 +08:00
|
|
|
|
return {
|
|
|
|
|
|
id: `user_${Date.now()}`,
|
|
|
|
|
|
nickname: nicknames[randomIndex],
|
|
|
|
|
|
avatar: `https://picsum.photos/200/200?random=${randomIndex}`,
|
2026-01-14 07:46:30 +00:00
|
|
|
|
tags: ["创业者", "私域运营", selectedType.label],
|
2026-01-14 12:50:00 +08:00
|
|
|
|
matchScore: Math.floor(Math.random() * 20) + 80,
|
|
|
|
|
|
concept: concepts[randomIndex % concepts.length],
|
|
|
|
|
|
wechat: wechats[randomIndex % wechats.length],
|
|
|
|
|
|
commonInterests: [
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{ icon: "📚", text: "都在读《创业实验》" },
|
|
|
|
|
|
{ icon: "💼", text: "对私域运营感兴趣" },
|
|
|
|
|
|
{ icon: "🎯", text: "相似的创业方向" },
|
|
|
|
|
|
],
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const nextMatch = () => {
|
|
|
|
|
|
setCurrentMatch(null)
|
|
|
|
|
|
setTimeout(() => startMatch(), 500)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleAddWechat = () => {
|
|
|
|
|
|
if (!currentMatch) return
|
2026-01-14 05:41:44 +00:00
|
|
|
|
navigator.clipboard
|
|
|
|
|
|
.writeText(currentMatch.wechat)
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
alert(`微信号已复制:${currentMatch.wechat}\n\n请打开微信添加好友,备注"创业合作"即可。`)
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(() => {
|
|
|
|
|
|
alert(`微信号:${currentMatch.wechat}\n\n请手动复制并添加好友。`)
|
|
|
|
|
|
})
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-14 07:46:30 +00:00
|
|
|
|
const handleTypeClick = (type: (typeof matchTypes)[0]) => {
|
|
|
|
|
|
setJoinType(type)
|
|
|
|
|
|
setShowJoinModal(true)
|
|
|
|
|
|
}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
|
|
|
|
|
return (
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<div className="min-h-screen bg-black pb-24">
|
|
|
|
|
|
<div className="flex items-center justify-between px-6 pt-6 pb-4">
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<h1 className="text-2xl font-bold text-white">语音匹配</h1>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<button className="w-10 h-10 rounded-full bg-[#1c1c1e] flex items-center justify-center">
|
|
|
|
|
|
<svg className="w-5 h-5 text-white/60" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
|
<path
|
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
|
d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
</button>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<AnimatePresence mode="wait">
|
|
|
|
|
|
{!isMatching && !currentMatch && (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key="idle"
|
|
|
|
|
|
initial={{ opacity: 0, y: 20 }}
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
|
exit={{ opacity: 0, y: -20 }}
|
|
|
|
|
|
className="flex flex-col items-center px-6"
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 中央匹配圆环 */}
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
onClick={startMatch}
|
|
|
|
|
|
className="relative w-[280px] h-[280px] mb-8 cursor-pointer"
|
|
|
|
|
|
whileTap={{ scale: 0.95 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 外层光环 */}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
<motion.div
|
2026-01-14 05:41:44 +00:00
|
|
|
|
className="absolute inset-[-30px] rounded-full"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
background: "radial-gradient(circle, transparent 50%, rgba(0, 229, 255, 0.1) 70%, transparent 100%)",
|
|
|
|
|
|
}}
|
|
|
|
|
|
animate={{
|
|
|
|
|
|
scale: [1, 1.1, 1],
|
|
|
|
|
|
opacity: [0.5, 0.8, 0.5],
|
|
|
|
|
|
}}
|
|
|
|
|
|
transition={{
|
|
|
|
|
|
duration: 2,
|
|
|
|
|
|
repeat: Number.POSITIVE_INFINITY,
|
|
|
|
|
|
ease: "easeInOut",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 中间光环 */}
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
className="absolute inset-[-15px] rounded-full border-2 border-[#00E5FF]/30"
|
|
|
|
|
|
animate={{
|
|
|
|
|
|
scale: [1, 1.05, 1],
|
|
|
|
|
|
opacity: [0.3, 0.6, 0.3],
|
|
|
|
|
|
}}
|
|
|
|
|
|
transition={{
|
|
|
|
|
|
duration: 1.5,
|
|
|
|
|
|
repeat: Number.POSITIVE_INFINITY,
|
|
|
|
|
|
ease: "easeInOut",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 内层渐变球 */}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
<motion.div
|
2026-01-14 05:41:44 +00:00
|
|
|
|
className="absolute inset-0 rounded-full flex flex-col items-center justify-center overflow-hidden"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
background: "linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)",
|
|
|
|
|
|
boxShadow: "0 0 60px rgba(0, 229, 255, 0.3), inset 0 0 60px rgba(123, 97, 255, 0.2)",
|
|
|
|
|
|
}}
|
|
|
|
|
|
animate={{
|
|
|
|
|
|
y: [0, -5, 0],
|
|
|
|
|
|
}}
|
|
|
|
|
|
transition={{
|
|
|
|
|
|
duration: 3,
|
|
|
|
|
|
repeat: Number.POSITIVE_INFINITY,
|
|
|
|
|
|
ease: "easeInOut",
|
|
|
|
|
|
}}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 内部渐变光效 */}
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="absolute inset-0 rounded-full"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
background:
|
|
|
|
|
|
"radial-gradient(circle at 30% 30%, rgba(123, 97, 255, 0.4) 0%, transparent 50%), radial-gradient(circle at 70% 70%, rgba(233, 30, 99, 0.3) 0%, transparent 50%)",
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 中心图标 */}
|
|
|
|
|
|
<Mic className="w-12 h-12 text-white/90 mb-3 relative z-10" />
|
|
|
|
|
|
<div className="text-xl font-bold text-white mb-1 relative z-10">开始匹配</div>
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<div className="text-sm text-white/60 relative z-10">寻找{selectedType.label}</div>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</motion.div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 当前模式显示 */}
|
|
|
|
|
|
<p className="text-white/50 text-sm mb-8">
|
2026-01-14 07:46:30 +00:00
|
|
|
|
当前模式: <span className="text-[#00E5FF]">{selectedType.label}</span>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</p>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 分隔线 */}
|
|
|
|
|
|
<div className="w-full h-px bg-white/10 mb-6" />
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<p className="text-white/40 text-sm mb-4">选择匹配类型</p>
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<div className="grid grid-cols-3 gap-4 w-full">
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{matchTypes.map((type) => (
|
2026-01-14 12:50:00 +08:00
|
|
|
|
<button
|
2026-01-14 05:41:44 +00:00
|
|
|
|
key={type.id}
|
2026-01-14 07:46:30 +00:00
|
|
|
|
onClick={() => handleTypeClick(type)}
|
|
|
|
|
|
className="p-5 rounded-xl flex flex-col items-center gap-3 transition-all bg-[#1c1c1e] border border-white/10 hover:border-[#00E5FF]/50 hover:bg-[#00E5FF]/5 active:scale-95"
|
2026-01-14 12:50:00 +08:00
|
|
|
|
>
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<span className="text-3xl">{type.icon}</span>
|
|
|
|
|
|
<span className="text-sm text-white/80">{type.label}</span>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</button>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{isMatching && (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key="matching"
|
|
|
|
|
|
initial={{ opacity: 0, scale: 0.9 }}
|
|
|
|
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
|
|
|
|
exit={{ opacity: 0, scale: 0.9 }}
|
|
|
|
|
|
className="text-center px-6"
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 匹配动画 */}
|
|
|
|
|
|
<div className="relative w-[200px] h-[200px] mx-auto mb-8">
|
2026-01-14 12:50:00 +08:00
|
|
|
|
<motion.div
|
2026-01-14 05:41:44 +00:00
|
|
|
|
className="absolute inset-0 rounded-full bg-gradient-to-br from-[#00E5FF] via-[#7B61FF] to-[#E91E63]"
|
|
|
|
|
|
animate={{ rotate: 360 }}
|
|
|
|
|
|
transition={{ duration: 3, repeat: Number.POSITIVE_INFINITY, ease: "linear" }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="absolute inset-2 rounded-full bg-black flex items-center justify-center">
|
2026-01-14 12:50:00 +08:00
|
|
|
|
<motion.div
|
2026-01-14 05:41:44 +00:00
|
|
|
|
animate={{ scale: [1, 1.2, 1] }}
|
|
|
|
|
|
transition={{ duration: 1, repeat: Number.POSITIVE_INFINITY }}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<Mic className="w-12 h-12 text-[#00E5FF]" />
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</motion.div>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</div>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 扩散波纹 */}
|
|
|
|
|
|
{[1, 2, 3].map((ring) => (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key={ring}
|
|
|
|
|
|
className="absolute inset-0 rounded-full border-2 border-[#00E5FF]/30"
|
|
|
|
|
|
animate={{
|
|
|
|
|
|
scale: [1, 2],
|
|
|
|
|
|
opacity: [0.6, 0],
|
|
|
|
|
|
}}
|
|
|
|
|
|
transition={{
|
|
|
|
|
|
duration: 2,
|
|
|
|
|
|
repeat: Number.POSITIVE_INFINITY,
|
|
|
|
|
|
delay: ring * 0.5,
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<h2 className="text-xl font-semibold mb-2 text-white">正在寻找合作伙伴...</h2>
|
|
|
|
|
|
<p className="text-white/50 mb-8">已匹配 {matchAttempts} 次</p>
|
|
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => setIsMatching(false)}
|
|
|
|
|
|
className="px-8 py-3 rounded-full bg-[#1c1c1e] text-white border border-white/10"
|
|
|
|
|
|
>
|
|
|
|
|
|
取消匹配
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{currentMatch && !isMatching && (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key="matched"
|
|
|
|
|
|
initial={{ opacity: 0, y: 20 }}
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
|
exit={{ opacity: 0, y: -20 }}
|
|
|
|
|
|
className="px-6"
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 成功动画 */}
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
className="text-center mb-6"
|
|
|
|
|
|
initial={{ scale: 0 }}
|
|
|
|
|
|
animate={{ scale: 1 }}
|
|
|
|
|
|
transition={{ type: "spring", bounce: 0.5 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="text-6xl">✨</span>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 用户卡片 */}
|
|
|
|
|
|
<div className="bg-[#1c1c1e] rounded-2xl p-5 mb-4 border border-white/5">
|
|
|
|
|
|
<div className="flex items-center gap-4 mb-4">
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={currentMatch.avatar || "/placeholder.svg"}
|
|
|
|
|
|
alt={currentMatch.nickname}
|
|
|
|
|
|
className="w-16 h-16 rounded-full border-2 border-[#00E5FF]"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
|
<h3 className="text-lg font-semibold text-white mb-2">{currentMatch.nickname}</h3>
|
|
|
|
|
|
<div className="flex flex-wrap gap-1">
|
|
|
|
|
|
{currentMatch.tags.map((tag) => (
|
|
|
|
|
|
<span key={tag} className="px-2 py-0.5 rounded text-xs bg-[#00E5FF]/20 text-[#00E5FF]">
|
|
|
|
|
|
{tag}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
))}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
<div className="text-center">
|
|
|
|
|
|
<div className="text-2xl font-bold text-[#00E5FF]">{currentMatch.matchScore}%</div>
|
|
|
|
|
|
<div className="text-xs text-white/50">匹配度</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-01-14 05:41:44 +00:00
|
|
|
|
{/* 共同兴趣 */}
|
|
|
|
|
|
<div className="pt-4 border-t border-white/10 mb-4">
|
|
|
|
|
|
<h4 className="text-sm text-white/60 mb-2">共同兴趣</h4>
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
{currentMatch.commonInterests.map((interest, i) => (
|
|
|
|
|
|
<div key={i} className="flex items-center gap-2 text-sm text-white/80">
|
|
|
|
|
|
<span>{interest.icon}</span>
|
|
|
|
|
|
<span>{interest.text}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</div>
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 核心理念 */}
|
|
|
|
|
|
<div className="pt-4 border-t border-white/10">
|
|
|
|
|
|
<h4 className="text-sm text-white/60 mb-2">核心理念</h4>
|
|
|
|
|
|
<p className="text-sm text-white/70">{currentMatch.concept}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 操作按钮 */}
|
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
|
<button onClick={handleAddWechat} className="w-full py-4 rounded-xl bg-[#00E5FF] text-black font-medium">
|
2026-01-14 07:46:30 +00:00
|
|
|
|
一键加好友
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={nextMatch}
|
|
|
|
|
|
className="w-full py-4 rounded-xl bg-[#1c1c1e] text-white border border-white/10"
|
|
|
|
|
|
>
|
2026-01-14 07:46:30 +00:00
|
|
|
|
重新匹配
|
2026-01-14 05:41:44 +00:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</AnimatePresence>
|
2026-01-14 07:32:08 +00:00
|
|
|
|
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<JoinModal isOpen={showJoinModal} onClose={() => setShowJoinModal(false)} type={joinType} />
|
|
|
|
|
|
|
2026-01-14 07:32:08 +00:00
|
|
|
|
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
|
|
|
|
|
|
<div className="px-4 py-2">
|
|
|
|
|
|
<div className="flex items-center justify-around">
|
|
|
|
|
|
<button onClick={() => router.push("/")} className="flex flex-col items-center py-2 px-4">
|
|
|
|
|
|
<Home className="w-5 h-5 text-gray-500 mb-1" />
|
|
|
|
|
|
<span className="text-gray-500 text-xs">首页</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button onClick={() => router.push("/chapters")} className="flex flex-col items-center py-2 px-4">
|
|
|
|
|
|
<List className="w-5 h-5 text-gray-500 mb-1" />
|
|
|
|
|
|
<span className="text-gray-500 text-xs">目录</span>
|
|
|
|
|
|
</button>
|
2026-01-14 07:46:30 +00:00
|
|
|
|
{/* 匹配按钮 - 当前页面高亮,小星球图标 */}
|
2026-01-14 07:32:08 +00:00
|
|
|
|
<button className="flex flex-col items-center py-2 px-6 -mt-4">
|
|
|
|
|
|
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
|
2026-01-14 07:46:30 +00:00
|
|
|
|
<svg className="w-7 h-7 text-white" viewBox="0 0 24 24" fill="currentColor">
|
|
|
|
|
|
<circle cx="12" cy="12" r="8" fill="currentColor" opacity="0.9" />
|
|
|
|
|
|
<ellipse
|
|
|
|
|
|
cx="12"
|
|
|
|
|
|
cy="12"
|
|
|
|
|
|
rx="11"
|
|
|
|
|
|
ry="4"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
strokeWidth="1.5"
|
|
|
|
|
|
opacity="0.6"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<circle cx="9" cy="10" r="1.5" fill="white" opacity="0.4" />
|
|
|
|
|
|
</svg>
|
2026-01-14 07:32:08 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
<span className="text-[#00CED1] text-xs font-medium mt-1">匹配</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button onClick={() => router.push("/my")} className="flex flex-col items-center py-2 px-4">
|
|
|
|
|
|
<User className="w-5 h-5 text-gray-500 mb-1" />
|
|
|
|
|
|
<span className="text-gray-500 text-xs">我的</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</nav>
|
2026-01-14 12:50:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|