删除多个完成报告文件,优化项目结构以提升可维护性。
This commit is contained in:
@@ -107,7 +107,7 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
|
||||
<span className="text-sm">退出登录</span>
|
||||
</button>
|
||||
<Link
|
||||
href="/"
|
||||
href="/view"
|
||||
className="flex items-center gap-3 px-4 py-3 text-gray-400 hover:text-white rounded-lg hover:bg-gray-700/50 transition-colors"
|
||||
>
|
||||
<span className="text-sm">返回前台</span>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Metadata } from "next"
|
||||
import { Geist, Geist_Mono } from "next/font/google"
|
||||
import { Analytics } from "@vercel/analytics/next"
|
||||
import "./globals.css"
|
||||
import { LayoutWrapper } from "@/components/layout-wrapper"
|
||||
import { LayoutWrapper } from "@/components/view/layout/layout-wrapper"
|
||||
|
||||
const _geist = Geist({ subsets: ["latin"] })
|
||||
const _geistMono = Geist_Mono({ subsets: ["latin"] })
|
||||
|
||||
225
app/page.tsx
225
app/page.tsx
@@ -1,223 +1,6 @@
|
||||
/**
|
||||
* 一场SOUL的创业实验 - 首页
|
||||
* 开发: 卡若
|
||||
* 技术支持: 存客宝
|
||||
*/
|
||||
"use client"
|
||||
import { redirect } from "next/navigation"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Search, ChevronRight, BookOpen } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { bookData, getTotalSectionCount } from "@/lib/book-data"
|
||||
import { SearchModal } from "@/components/search-modal"
|
||||
import { BottomNav } from "@/components/bottom-nav"
|
||||
|
||||
export default function HomePage() {
|
||||
const router = useRouter()
|
||||
const { user } = useStore()
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
|
||||
// 计算数据(必须在所有 hooks 之后)
|
||||
const totalSections = getTotalSectionCount()
|
||||
const hasFullBook = user?.hasFullBook || false
|
||||
const purchasedCount = hasFullBook ? totalSections : user?.purchasedSections?.length || 0
|
||||
|
||||
// 推荐章节
|
||||
const featuredSections = [
|
||||
{ id: "1.1", title: "荷包:电动车出租的被动收入模式", tag: "免费", part: "真实的人" },
|
||||
{ id: "3.1", title: "3000万流水如何跑出来", tag: "热门", part: "真实的行业" },
|
||||
{ id: "8.1", title: "流量杠杆:抖音、Soul、飞书", tag: "推荐", part: "真实的赚钱" },
|
||||
]
|
||||
|
||||
// 最新更新
|
||||
const latestSection = {
|
||||
id: "9.14",
|
||||
title: "大健康私域:一个月150万的70后",
|
||||
part: "真实的赚钱",
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!mounted) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-black text-white pb-24">
|
||||
{/* 顶部区域 */}
|
||||
<header className="px-4 pt-6 pb-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
|
||||
<span className="text-white font-bold text-lg">S</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-bold text-white">Soul<span className="text-[#00CED1]">创业实验</span></h1>
|
||||
<p className="text-xs text-gray-500">来自派对房的真实故事</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded-full">{totalSections}章</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 搜索栏 */}
|
||||
<div
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer hover:border-[#00CED1]/30 transition-colors"
|
||||
>
|
||||
<Search className="w-4 h-4 text-gray-500" />
|
||||
<span className="text-gray-500 text-sm">搜索章节...</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 搜索弹窗 */}
|
||||
<SearchModal open={searchOpen} onOpenChange={setSearchOpen} />
|
||||
|
||||
<main className="px-4 space-y-5">
|
||||
{/* Banner卡片 - 最新章节 */}
|
||||
<div
|
||||
onClick={() => router.push(`/read/${latestSection.id}`)}
|
||||
className="relative p-5 rounded-2xl overflow-hidden cursor-pointer"
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #0d3331 0%, #1a1a2e 50%, #16213e 100%)",
|
||||
}}
|
||||
>
|
||||
<div className="absolute top-0 right-0 w-32 h-32 opacity-20">
|
||||
<div className="w-full h-full bg-[#00CED1] rounded-full blur-3xl" />
|
||||
</div>
|
||||
<span className="inline-block px-2 py-1 rounded text-xs bg-[#00CED1] text-black font-medium mb-3">
|
||||
最新更新
|
||||
</span>
|
||||
<h2 className="text-lg font-bold text-white mb-2 pr-8">{latestSection.title}</h2>
|
||||
<p className="text-sm text-gray-400 mb-3">{latestSection.part}</p>
|
||||
<div className="flex items-center gap-2 text-[#00CED1] text-sm font-medium">
|
||||
开始阅读
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 阅读进度卡 */}
|
||||
<div className="p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-medium text-white">我的阅读</h3>
|
||||
<span className="text-xs text-gray-500">
|
||||
{purchasedCount}/{totalSections}章
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-[#2c2c2e] rounded-full overflow-hidden mb-3">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-[#00CED1] to-[#20B2AA] rounded-full transition-all"
|
||||
style={{ width: `${(purchasedCount / totalSections) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-lg font-bold">{purchasedCount}</p>
|
||||
<p className="text-gray-500 text-xs">已读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">{totalSections - purchasedCount}</p>
|
||||
<p className="text-gray-500 text-xs">待读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">5</p>
|
||||
<p className="text-gray-500 text-xs">篇章</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">11</p>
|
||||
<p className="text-gray-500 text-xs">章节</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 精选推荐 */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-base font-semibold text-white">精选推荐</h3>
|
||||
<button onClick={() => router.push("/chapters")} className="text-xs text-[#00CED1] flex items-center gap-1">
|
||||
查看全部
|
||||
<ChevronRight className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{featuredSections.map((section) => (
|
||||
<div
|
||||
key={section.id}
|
||||
onClick={() => router.push(`/read/${section.id}`)}
|
||||
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-[#00CED1] text-xs font-medium">{section.id}</span>
|
||||
<span
|
||||
className={`text-xs px-2 py-0.5 rounded ${
|
||||
section.tag === "免费"
|
||||
? "bg-[#00CED1]/10 text-[#00CED1]"
|
||||
: section.tag === "热门"
|
||||
? "bg-pink-500/10 text-pink-400"
|
||||
: "bg-purple-500/10 text-purple-400"
|
||||
}`}
|
||||
>
|
||||
{section.tag}
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-white font-medium text-sm mb-1">{section.title}</h4>
|
||||
<p className="text-gray-500 text-xs">{section.part}</p>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-gray-600 mt-1" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-white mb-3">内容概览</h3>
|
||||
<div className="space-y-3">
|
||||
{bookData.map((part) => (
|
||||
<div
|
||||
key={part.id}
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-[#00CED1]/20 to-[#20B2AA]/10 flex items-center justify-center shrink-0">
|
||||
<span className="text-[#00CED1] font-bold text-sm">{part.number}</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-white font-medium text-sm mb-0.5">{part.title}</h4>
|
||||
<p className="text-gray-500 text-xs truncate">{part.subtitle}</p>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-gray-600 shrink-0" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 序言入口 */}
|
||||
<div
|
||||
onClick={() => router.push("/read/preface")}
|
||||
className="p-4 rounded-xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20 cursor-pointer"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-white font-medium text-sm mb-1">序言</h4>
|
||||
<p className="text-gray-400 text-xs">为什么我每天早上6点在Soul开播?</p>
|
||||
</div>
|
||||
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded">免费</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 使用统一的底部导航组件 */}
|
||||
<BottomNav />
|
||||
</div>
|
||||
)
|
||||
/** 根路径重定向到移动端首页 */
|
||||
export default function RootPage() {
|
||||
redirect("/view")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { ChevronRight, Lock, Unlock, Book, BookOpen, Sparkles, Zap, Crown, Searc
|
||||
import { useStore } from "@/lib/store"
|
||||
import { bookData, getTotalSectionCount, specialSections, getPremiumBookPrice, getExtraSectionsCount, BASE_SECTIONS_COUNT } from "@/lib/book-data"
|
||||
import { SearchModal } from "@/components/search-modal"
|
||||
import { BottomNav } from "@/components/bottom-nav"
|
||||
|
||||
export default function ChaptersPage() {
|
||||
const router = useRouter()
|
||||
@@ -22,7 +21,7 @@ export default function ChaptersPage() {
|
||||
const extraSections = getExtraSectionsCount()
|
||||
|
||||
const handleSectionClick = (sectionId: string) => {
|
||||
router.push(`/read/${sectionId}`)
|
||||
router.push(`/view/read/${sectionId}`)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -210,7 +209,6 @@ export default function ChaptersPage() {
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<BottomNav />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -8,7 +8,7 @@ export default function DocsPage() {
|
||||
<main className="min-h-screen bg-[#0a1628] text-white pb-20">
|
||||
<div className="sticky top-0 z-10 bg-[#0a1628]/95 backdrop-blur-md border-b border-gray-700/50">
|
||||
<div className="max-w-2xl mx-auto flex items-center gap-4 p-4">
|
||||
<Link href="/" className="p-2 -ml-2">
|
||||
<Link href="/view" className="p-2 -ml-2">
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
</Link>
|
||||
<h1 className="text-lg font-semibold">开发者文档</h1>
|
||||
@@ -46,7 +46,7 @@ export default function ForgotPasswordPage() {
|
||||
|
||||
if (data.success) {
|
||||
setSuccess(true)
|
||||
setTimeout(() => router.push("/login"), 2000)
|
||||
setTimeout(() => router.push("/view/login"), 2000)
|
||||
} else {
|
||||
setError(data.error || "重置失败")
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export default function ForgotPasswordPage() {
|
||||
<div className="min-h-screen bg-black text-white flex flex-col">
|
||||
<header className="flex items-center px-4 py-3">
|
||||
<Link
|
||||
href="/login"
|
||||
href="/view/login"
|
||||
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5 text-gray-400" />
|
||||
@@ -50,7 +50,7 @@ export default function LoginPage() {
|
||||
}
|
||||
const success = await login(phone, code)
|
||||
if (success) {
|
||||
router.push("/")
|
||||
router.push("/view")
|
||||
} else {
|
||||
setError("密码错误或用户不存在")
|
||||
}
|
||||
@@ -69,7 +69,7 @@ export default function LoginPage() {
|
||||
}
|
||||
const success = await register(phone, nickname, code, referralCode || undefined)
|
||||
if (success) {
|
||||
router.push("/")
|
||||
router.push("/view")
|
||||
} else {
|
||||
setError("该手机号已注册")
|
||||
}
|
||||
@@ -167,7 +167,7 @@ export default function LoginPage() {
|
||||
<div className="text-center space-y-2">
|
||||
{mode === "login" && (
|
||||
<div>
|
||||
<Link href="/login/forgot" className="text-[#30d158] text-sm">
|
||||
<Link href="/view/login/forgot" className="text-[#30d158] text-sm">
|
||||
忘记密码?
|
||||
</Link>
|
||||
</div>
|
||||
@@ -4,7 +4,6 @@ import { useState, useEffect } from "react"
|
||||
import { motion, AnimatePresence } from "framer-motion"
|
||||
import { Users, X, CheckCircle, Loader2, Lock, Zap } from "lucide-react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { BottomNav } from "@/components/bottom-nav"
|
||||
import { useStore } from "@/lib/store"
|
||||
|
||||
interface MatchUser {
|
||||
@@ -367,7 +366,7 @@ export default function MatchPage() {
|
||||
</span>
|
||||
{matchesRemaining <= 0 && !user?.hasFullBook && (
|
||||
<button
|
||||
onClick={() => router.push('/chapters')}
|
||||
onClick={() => router.push('/view/chapters')}
|
||||
className="px-3 py-1.5 rounded-full bg-[#FFD700]/20 text-[#FFD700] text-xs font-medium"
|
||||
>
|
||||
购买小节+1次
|
||||
@@ -495,7 +494,7 @@ export default function MatchPage() {
|
||||
<p className="text-gray-400 text-sm mt-1">仅需9.9元,每天3次免费匹配</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push('/chapters')}
|
||||
onClick={() => router.push('/view/chapters')}
|
||||
className="px-4 py-2 rounded-lg bg-[#00E5FF] text-black text-sm font-medium"
|
||||
>
|
||||
去购买
|
||||
@@ -706,7 +705,7 @@ export default function MatchPage() {
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowUnlockModal(false)
|
||||
router.push('/chapters')
|
||||
router.push('/view/chapters')
|
||||
}}
|
||||
className="w-full py-3 rounded-xl bg-[#FFD700] text-black font-medium"
|
||||
>
|
||||
@@ -845,7 +844,6 @@ export default function MatchPage() {
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<BottomNav />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { useStore } from "@/lib/store"
|
||||
export default function EditAddressPage() {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
const id = params.id as string
|
||||
const id = params?.id as string
|
||||
const { user } = useStore()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [fetching, setFetching] = useState(true)
|
||||
@@ -21,7 +21,7 @@ export default function EditAddressPage() {
|
||||
const [isDefault, setIsDefault] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) {
|
||||
if (!id || !user?.id) {
|
||||
setFetching(false)
|
||||
return
|
||||
}
|
||||
@@ -29,19 +29,18 @@ export default function EditAddressPage() {
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.success && data.item) {
|
||||
const item = data.item
|
||||
setName(item.name)
|
||||
setPhone(item.phone)
|
||||
setProvince(item.province)
|
||||
setCity(item.city)
|
||||
setDistrict(item.district)
|
||||
setDetail(item.detail)
|
||||
setIsDefault(item.isDefault)
|
||||
const a = data.item
|
||||
setName(a.name || "")
|
||||
setPhone(a.phone || "")
|
||||
setProvince(a.province || "")
|
||||
setCity(a.city || "")
|
||||
setDistrict(a.district || "")
|
||||
setDetail(a.detail || "")
|
||||
setIsDefault(!!a.isDefault)
|
||||
}
|
||||
setFetching(false)
|
||||
})
|
||||
.catch(() => setFetching(false))
|
||||
}, [id])
|
||||
.finally(() => setFetching(false))
|
||||
}, [id, user?.id])
|
||||
|
||||
if (!user?.id) {
|
||||
return (
|
||||
@@ -61,7 +60,6 @@ export default function EditAddressPage() {
|
||||
alert("请输入正确的手机号")
|
||||
return
|
||||
}
|
||||
// 省/市/区为选填
|
||||
if (!detail.trim()) {
|
||||
alert("请输入详细地址")
|
||||
return
|
||||
@@ -83,7 +81,7 @@ export default function EditAddressPage() {
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.success) {
|
||||
router.push("/my/addresses")
|
||||
router.push("/view/my/addresses")
|
||||
} else {
|
||||
alert(data.message || "保存失败")
|
||||
}
|
||||
@@ -97,7 +95,7 @@ export default function EditAddressPage() {
|
||||
if (fetching) {
|
||||
return (
|
||||
<div className="min-h-screen bg-black text-white flex items-center justify-center">
|
||||
<div className="text-white/40 text-sm">加载中...</div>
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#00CED1]" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -140,54 +138,21 @@ export default function EditAddressPage() {
|
||||
<div className="flex items-center justify-between p-4 border-b border-white/5">
|
||||
<label className="text-white text-sm w-24">省市区(选填)</label>
|
||||
<div className="flex-1 flex gap-2 justify-end">
|
||||
<input
|
||||
type="text"
|
||||
value={province}
|
||||
onChange={(e) => setProvince(e.target.value)}
|
||||
placeholder="省"
|
||||
className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={city}
|
||||
onChange={(e) => setCity(e.target.value)}
|
||||
placeholder="市"
|
||||
className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={district}
|
||||
onChange={(e) => setDistrict(e.target.value)}
|
||||
placeholder="区"
|
||||
className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none"
|
||||
/>
|
||||
<input type="text" value={province} onChange={(e) => setProvince(e.target.value)} placeholder="省" className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none" />
|
||||
<input type="text" value={city} onChange={(e) => setCity(e.target.value)} placeholder="市" className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none" />
|
||||
<input type="text" value={district} onChange={(e) => setDistrict(e.target.value)} placeholder="区" className="flex-1 max-w-24 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start justify-between p-4">
|
||||
<label className="text-white text-sm w-24 pt-2">详细地址</label>
|
||||
<textarea
|
||||
value={detail}
|
||||
onChange={(e) => setDetail(e.target.value)}
|
||||
placeholder="街道、楼栋、门牌号等"
|
||||
rows={3}
|
||||
className="flex-1 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none resize-none"
|
||||
/>
|
||||
<textarea value={detail} onChange={(e) => setDetail(e.target.value)} placeholder="街道、楼栋、门牌号等" rows={3} className="flex-1 bg-transparent text-white text-sm text-right placeholder-white/30 outline-none resize-none" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-4 border-t border-white/5">
|
||||
<span className="text-white text-sm">设为默认地址</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isDefault}
|
||||
onChange={(e) => setIsDefault(e.target.checked)}
|
||||
className="w-5 h-5 rounded accent-[#00CED1]"
|
||||
/>
|
||||
<input type="checkbox" checked={isDefault} onChange={(e) => setIsDefault(e.target.checked)} className="w-5 h-5 rounded accent-[#00CED1]" />
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full py-3 rounded-xl bg-[#00CED1] text-black font-medium disabled:opacity-50"
|
||||
>
|
||||
<button type="submit" disabled={loading} className="w-full py-3 rounded-xl bg-[#00CED1] text-black font-medium disabled:opacity-50">
|
||||
{loading ? "保存中..." : "保存"}
|
||||
</button>
|
||||
</form>
|
||||
@@ -58,7 +58,7 @@ export default function NewAddressPage() {
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.success) {
|
||||
router.push("/my/addresses")
|
||||
router.push("/view/my/addresses")
|
||||
} else {
|
||||
alert(data.message || "添加失败")
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export default function AddressesPage() {
|
||||
<div className="text-center">
|
||||
<p className="text-white/60 mb-4">请先登录</p>
|
||||
<button
|
||||
onClick={() => router.push("/my")}
|
||||
onClick={() => router.push("/view/my")}
|
||||
className="px-4 py-2 rounded-xl bg-[#00CED1] text-black font-medium"
|
||||
>
|
||||
去登录
|
||||
@@ -112,7 +112,7 @@ export default function AddressesPage() {
|
||||
<p className="text-white/60 text-sm leading-relaxed">{item.fullAddress}</p>
|
||||
<div className="flex justify-end gap-4 mt-3 pt-3 border-t border-white/5">
|
||||
<button
|
||||
onClick={() => router.push(`/my/addresses/${item.id}`)}
|
||||
onClick={() => router.push(`/view/my/addresses/${item.id}`)}
|
||||
className="flex items-center gap-1 text-[#00CED1] text-sm"
|
||||
>
|
||||
<Pencil className="w-4 h-4" /> 编辑
|
||||
@@ -130,7 +130,7 @@ export default function AddressesPage() {
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => router.push("/my/addresses/new")}
|
||||
onClick={() => router.push("/view/my/addresses/new")}
|
||||
className="mt-6 w-full py-3 rounded-xl bg-[#00CED1] text-black font-medium flex items-center justify-center gap-2"
|
||||
>
|
||||
<Plus className="w-5 h-5" /> 新增收货地址
|
||||
@@ -5,7 +5,6 @@ import { useRouter } from "next/navigation"
|
||||
import { User, Users, ChevronRight, Gift, Star, Info, Wallet, Footprints, Eye, BookOpen, Clock, ArrowUpRight, Phone, MessageCircle, CreditCard, X, Check, Loader2, Settings } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { AuthModal } from "@/components/modules/auth/auth-modal"
|
||||
import { BottomNav } from "@/components/bottom-nav"
|
||||
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
|
||||
|
||||
export default function MyPage() {
|
||||
@@ -190,7 +189,7 @@ export default function MyPage() {
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
onClick={() => router.push("/view/about")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -203,7 +202,6 @@ export default function MyPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BottomNav />
|
||||
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
|
||||
</main>
|
||||
)
|
||||
@@ -275,7 +273,7 @@ export default function MyPage() {
|
||||
<span className="text-white font-medium">我的收益</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
onClick={() => router.push("/view/my/referral")}
|
||||
className="text-[#00CED1] text-xs flex items-center gap-1"
|
||||
>
|
||||
推广中心
|
||||
@@ -299,7 +297,7 @@ export default function MyPage() {
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
onClick={() => router.push("/view/my/referral")}
|
||||
className="w-full py-2.5 rounded-xl bg-gradient-to-r from-[#FFD700]/80 to-[#FFA500]/80 text-black text-sm font-bold flex items-center justify-center gap-2"
|
||||
>
|
||||
<Gift className="w-4 h-4" />
|
||||
@@ -338,7 +336,7 @@ export default function MyPage() {
|
||||
{/* 菜单列表 */}
|
||||
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
|
||||
<button
|
||||
onClick={() => router.push("/my/purchases")}
|
||||
onClick={() => router.push("/view/my/purchases")}
|
||||
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -351,7 +349,7 @@ export default function MyPage() {
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
onClick={() => router.push("/view/my/referral")}
|
||||
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -366,7 +364,7 @@ export default function MyPage() {
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
onClick={() => router.push("/view/about")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -378,7 +376,7 @@ export default function MyPage() {
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/settings")}
|
||||
onClick={() => router.push("/view/my/settings")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -438,7 +436,7 @@ export default function MyPage() {
|
||||
<span className="text-white text-sm">章节 {sectionId}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push(`/read/${sectionId}`)}
|
||||
onClick={() => router.push(`/view/read/${sectionId}`)}
|
||||
className="text-[#00CED1] text-xs"
|
||||
>
|
||||
继续阅读
|
||||
@@ -451,7 +449,7 @@ export default function MyPage() {
|
||||
<BookOpen className="w-8 h-8 mx-auto mb-2 opacity-50" />
|
||||
<p className="text-sm">暂无阅读记录</p>
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
onClick={() => router.push("/view/chapters")}
|
||||
className="mt-2 text-[#00CED1] text-sm"
|
||||
>
|
||||
去阅读 →
|
||||
@@ -471,7 +469,7 @@ export default function MyPage() {
|
||||
<Users className="w-8 h-8 mx-auto mb-2 opacity-50" />
|
||||
<p className="text-sm">暂无匹配记录</p>
|
||||
<button
|
||||
onClick={() => router.push("/match")}
|
||||
onClick={() => router.push("/view/match")}
|
||||
className="mt-2 text-[#00CED1] text-sm"
|
||||
>
|
||||
去匹配 →
|
||||
@@ -483,7 +481,6 @@ export default function MyPage() {
|
||||
</>
|
||||
)}
|
||||
|
||||
<BottomNav />
|
||||
|
||||
{/* 绑定弹窗 */}
|
||||
{showBindModal && (
|
||||
@@ -13,7 +13,7 @@ export default function MyPurchasesPage() {
|
||||
<div className="min-h-screen bg-[#0a1628] text-white flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<p className="text-gray-400 mb-4">请先登录</p>
|
||||
<Link href="/" className="text-[#38bdac] hover:underline">
|
||||
<Link href="/view" className="text-[#38bdac] hover:underline">
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
@@ -29,7 +29,7 @@ export default function MyPurchasesPage() {
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 bg-[#0a1628]/90 backdrop-blur-md border-b border-gray-800">
|
||||
<div className="max-w-4xl mx-auto px-4 py-4 flex items-center">
|
||||
<Link href="/" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
|
||||
<Link href="/view" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
<span>返回</span>
|
||||
</Link>
|
||||
@@ -66,7 +66,7 @@ export default function MyPurchasesPage() {
|
||||
<div className="text-center py-12">
|
||||
<BookOpen className="w-16 h-16 text-gray-600 mx-auto mb-4" />
|
||||
<p className="text-gray-400 mb-4">您还没有购买任何章节</p>
|
||||
<Link href="/chapters" className="text-[#38bdac] hover:underline">
|
||||
<Link href="/view/chapters" className="text-[#38bdac] hover:underline">
|
||||
去浏览章节
|
||||
</Link>
|
||||
</div>
|
||||
@@ -89,7 +89,7 @@ export default function MyPurchasesPage() {
|
||||
{purchasedInPart.map((section) => (
|
||||
<Link
|
||||
key={section.id}
|
||||
href={`/read/${section.id}`}
|
||||
href={`/view/read/${section.id}`}
|
||||
className="flex items-center gap-3 px-4 py-3 hover:bg-[#0f2137]/40 transition-colors"
|
||||
>
|
||||
<CheckCircle className="w-4 h-4 text-[#38bdac]" />
|
||||
@@ -132,7 +132,7 @@ export default function ReferralPage() {
|
||||
<div className="min-h-screen bg-black text-white flex items-center justify-center pb-20">
|
||||
<div className="text-center glass-card p-8">
|
||||
<p className="text-[var(--app-text-secondary)] mb-4">请先登录</p>
|
||||
<Link href="/" className="btn-ios inline-block">
|
||||
<Link href="/view" className="btn-ios inline-block">
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
@@ -211,7 +211,7 @@ export default function ReferralPage() {
|
||||
{/* Header - iOS风格 */}
|
||||
<header className="sticky top-0 z-50 glass-nav safe-top">
|
||||
<div className="max-w-md mx-auto px-4 py-3 flex items-center">
|
||||
<Link href="/my" className="w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center touch-feedback">
|
||||
<Link href="/view/my" className="w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center touch-feedback">
|
||||
<ChevronLeft className="w-5 h-5 text-[var(--app-text-secondary)]" />
|
||||
</Link>
|
||||
<h1 className="flex-1 text-center font-semibold">分销中心</h1>
|
||||
@@ -176,7 +176,7 @@ export default function SettingsPage() {
|
||||
|
||||
{/* 收货地址 */}
|
||||
<button
|
||||
onClick={() => router.push("/my/addresses")}
|
||||
onClick={() => router.push("/view/my/addresses")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -205,7 +205,7 @@ export default function SettingsPage() {
|
||||
<button
|
||||
onClick={() => {
|
||||
logout()
|
||||
router.push("/")
|
||||
router.push("/view")
|
||||
}}
|
||||
className="w-full py-3 rounded-xl bg-[#1c1c1e] text-red-400 font-medium border border-red-400/30"
|
||||
>
|
||||
221
app/view/page.tsx
Normal file
221
app/view/page.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* 一场SOUL的创业实验 - 首页
|
||||
* 开发: 卡若
|
||||
* 技术支持: 存客宝
|
||||
*/
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Search, ChevronRight, BookOpen } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { bookData, getTotalSectionCount } from "@/lib/book-data"
|
||||
import { SearchModal } from "@/components/search-modal"
|
||||
|
||||
export default function HomePage() {
|
||||
const router = useRouter()
|
||||
const { user } = useStore()
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
|
||||
// 计算数据(必须在所有 hooks 之后)
|
||||
const totalSections = getTotalSectionCount()
|
||||
const hasFullBook = user?.hasFullBook || false
|
||||
const purchasedCount = hasFullBook ? totalSections : user?.purchasedSections?.length || 0
|
||||
|
||||
// 推荐章节
|
||||
const featuredSections = [
|
||||
{ id: "1.1", title: "荷包:电动车出租的被动收入模式", tag: "免费", part: "真实的人" },
|
||||
{ id: "3.1", title: "3000万流水如何跑出来", tag: "热门", part: "真实的行业" },
|
||||
{ id: "8.1", title: "流量杠杆:抖音、Soul、飞书", tag: "推荐", part: "真实的赚钱" },
|
||||
]
|
||||
|
||||
// 最新更新
|
||||
const latestSection = {
|
||||
id: "9.14",
|
||||
title: "大健康私域:一个月150万的70后",
|
||||
part: "真实的赚钱",
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!mounted) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-black text-white pb-24">
|
||||
{/* 顶部区域 */}
|
||||
<header className="px-4 pt-6 pb-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
|
||||
<span className="text-white font-bold text-lg">S</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg font-bold text-white">Soul<span className="text-[#00CED1]">创业实验</span></h1>
|
||||
<p className="text-xs text-gray-500">来自派对房的真实故事</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded-full">{totalSections}章</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 搜索栏 */}
|
||||
<div
|
||||
onClick={() => setSearchOpen(true)}
|
||||
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer hover:border-[#00CED1]/30 transition-colors"
|
||||
>
|
||||
<Search className="w-4 h-4 text-gray-500" />
|
||||
<span className="text-gray-500 text-sm">搜索章节...</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 搜索弹窗 */}
|
||||
<SearchModal open={searchOpen} onOpenChange={setSearchOpen} />
|
||||
|
||||
<main className="px-4 space-y-5">
|
||||
{/* Banner卡片 - 最新章节 */}
|
||||
<div
|
||||
onClick={() => router.push(`/view/read/${latestSection.id}`)}
|
||||
className="relative p-5 rounded-2xl overflow-hidden cursor-pointer"
|
||||
style={{
|
||||
background: "linear-gradient(135deg, #0d3331 0%, #1a1a2e 50%, #16213e 100%)",
|
||||
}}
|
||||
>
|
||||
<div className="absolute top-0 right-0 w-32 h-32 opacity-20">
|
||||
<div className="w-full h-full bg-[#00CED1] rounded-full blur-3xl" />
|
||||
</div>
|
||||
<span className="inline-block px-2 py-1 rounded text-xs bg-[#00CED1] text-black font-medium mb-3">
|
||||
最新更新
|
||||
</span>
|
||||
<h2 className="text-lg font-bold text-white mb-2 pr-8">{latestSection.title}</h2>
|
||||
<p className="text-sm text-gray-400 mb-3">{latestSection.part}</p>
|
||||
<div className="flex items-center gap-2 text-[#00CED1] text-sm font-medium">
|
||||
开始阅读
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 阅读进度卡 */}
|
||||
<div className="p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-medium text-white">我的阅读</h3>
|
||||
<span className="text-xs text-gray-500">
|
||||
{purchasedCount}/{totalSections}章
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-[#2c2c2e] rounded-full overflow-hidden mb-3">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-[#00CED1] to-[#20B2AA] rounded-full transition-all"
|
||||
style={{ width: `${(purchasedCount / totalSections) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-lg font-bold">{purchasedCount}</p>
|
||||
<p className="text-gray-500 text-xs">已读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">{totalSections - purchasedCount}</p>
|
||||
<p className="text-gray-500 text-xs">待读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">5</p>
|
||||
<p className="text-gray-500 text-xs">篇章</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white text-lg font-bold">11</p>
|
||||
<p className="text-gray-500 text-xs">章节</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 精选推荐 */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-base font-semibold text-white">精选推荐</h3>
|
||||
<button onClick={() => router.push("/view/chapters")} className="text-xs text-[#00CED1] flex items-center gap-1">
|
||||
查看全部
|
||||
<ChevronRight className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{featuredSections.map((section) => (
|
||||
<div
|
||||
key={section.id}
|
||||
onClick={() => router.push(`/view/read/${section.id}`)}
|
||||
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-[#00CED1] text-xs font-medium">{section.id}</span>
|
||||
<span
|
||||
className={`text-xs px-2 py-0.5 rounded ${
|
||||
section.tag === "免费"
|
||||
? "bg-[#00CED1]/10 text-[#00CED1]"
|
||||
: section.tag === "热门"
|
||||
? "bg-pink-500/10 text-pink-400"
|
||||
: "bg-purple-500/10 text-purple-400"
|
||||
}`}
|
||||
>
|
||||
{section.tag}
|
||||
</span>
|
||||
</div>
|
||||
<h4 className="text-white font-medium text-sm mb-1">{section.title}</h4>
|
||||
<p className="text-gray-500 text-xs">{section.part}</p>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-gray-600 mt-1" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-white mb-3">内容概览</h3>
|
||||
<div className="space-y-3">
|
||||
{bookData.map((part) => (
|
||||
<div
|
||||
key={part.id}
|
||||
onClick={() => router.push("/view/chapters")}
|
||||
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-[#00CED1]/20 to-[#20B2AA]/10 flex items-center justify-center shrink-0">
|
||||
<span className="text-[#00CED1] font-bold text-sm">{part.number}</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-white font-medium text-sm mb-0.5">{part.title}</h4>
|
||||
<p className="text-gray-500 text-xs truncate">{part.subtitle}</p>
|
||||
</div>
|
||||
<ChevronRight className="w-4 h-4 text-gray-600 shrink-0" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 序言入口 */}
|
||||
<div
|
||||
onClick={() => router.push("/view/read/preface")}
|
||||
className="p-4 rounded-xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20 cursor-pointer"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="text-white font-medium text-sm mb-1">序言</h4>
|
||||
<p className="text-gray-400 text-xs">为什么我每天早上6点在Soul开播?</p>
|
||||
</div>
|
||||
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded">免费</span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 使用统一的底部导航组件 */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export default async function HomePage() {
|
||||
|
||||
{/* 立即阅读按钮 */}
|
||||
<div className="px-6 mb-6">
|
||||
<Link href="/read/preface" className="btn-ios w-full py-4 text-lg shadow-[0_0_20px_rgba(48,209,88,0.2)]">
|
||||
<Link href="/view/read/preface" className="btn-ios w-full py-4 text-lg shadow-[0_0_20px_rgba(48,209,88,0.2)]">
|
||||
<div className="flex items-center gap-2">
|
||||
<Home className="w-5 h-5" />
|
||||
<span>立即阅读</span>
|
||||
@@ -126,15 +126,15 @@ export default async function HomePage() {
|
||||
|
||||
{/* 底部导航 */}
|
||||
<nav className="fixed bottom-0 left-0 right-0 h-20 bg-black/80 backdrop-blur-xl border-t border-white/5 flex items-center justify-around px-6 z-50">
|
||||
<Link href="/" className="flex flex-col items-center gap-1 text-[#30D158]">
|
||||
<Link href="/view" className="flex flex-col items-center gap-1 text-[#30D158]">
|
||||
<Home className="w-6 h-6" />
|
||||
<span className="text-[10px] font-medium">首页</span>
|
||||
</Link>
|
||||
<Link href="/match" className="flex flex-col items-center gap-1 text-white/40">
|
||||
<Link href="/view/match" className="flex flex-col items-center gap-1 text-white/40">
|
||||
<Sparkles className="w-6 h-6" />
|
||||
<span className="text-[10px] font-medium">匹配书友</span>
|
||||
</Link>
|
||||
<Link href="/my" className="flex flex-col items-center gap-1 text-white/40">
|
||||
<Link href="/view/my" className="flex flex-col items-center gap-1 text-white/40">
|
||||
<User className="w-6 h-6" />
|
||||
<span className="text-[10px] font-medium">我的</span>
|
||||
</Link>
|
||||
Reference in New Issue
Block a user