feat: add admin site config page and optimize my page
Add "Site Configuration" page and refactor "My" page Expand store with site, menu, and page configurations. #VERCEL_SKIP Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import type React from "react"
|
||||
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { LayoutDashboard, FileText, Users, CreditCard, QrCode, Settings, LogOut, Wallet } from "lucide-react"
|
||||
import { LayoutDashboard, FileText, Users, CreditCard, QrCode, Settings, LogOut, Wallet, Globe } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useEffect } from "react"
|
||||
@@ -22,6 +22,7 @@ export default function AdminLayout({ children }: { children: React.ReactNode })
|
||||
|
||||
const menuItems = [
|
||||
{ icon: LayoutDashboard, label: "数据概览", href: "/admin" },
|
||||
{ icon: Globe, label: "网站配置", href: "/admin/site" },
|
||||
{ icon: FileText, label: "内容管理", href: "/admin/content" },
|
||||
{ icon: Users, label: "用户管理", href: "/admin/users" },
|
||||
{ icon: CreditCard, label: "支付配置", href: "/admin/payment" },
|
||||
|
||||
14
app/admin/site/loading.tsx
Normal file
14
app/admin/site/loading.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="animate-pulse">
|
||||
<div className="h-8 bg-gray-700 rounded w-1/4 mb-8" />
|
||||
<div className="space-y-6">
|
||||
<div className="h-64 bg-[#0f2137] rounded-xl" />
|
||||
<div className="h-48 bg-[#0f2137] rounded-xl" />
|
||||
<div className="h-64 bg-[#0f2137] rounded-xl" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
367
app/admin/site/page.tsx
Normal file
367
app/admin/site/page.tsx
Normal file
@@ -0,0 +1,367 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { Save, Globe, Menu, FileText, Palette } from "lucide-react"
|
||||
|
||||
export default function SiteConfigPage() {
|
||||
const { settings, updateSettings } = useStore()
|
||||
const [localSettings, setLocalSettings] = useState({
|
||||
siteConfig: settings.siteConfig || {
|
||||
siteName: "卡若日记",
|
||||
siteTitle: "一场SOUL的创业实验场",
|
||||
siteDescription: "来自Soul派对房的真实商业故事",
|
||||
logo: "/logo.png",
|
||||
favicon: "/favicon.ico",
|
||||
primaryColor: "#00CED1",
|
||||
},
|
||||
menuConfig: settings.menuConfig || {
|
||||
home: { enabled: true, label: "首页" },
|
||||
chapters: { enabled: true, label: "目录" },
|
||||
match: { enabled: true, label: "匹配" },
|
||||
my: { enabled: true, label: "我的" },
|
||||
},
|
||||
pageConfig: settings.pageConfig || {
|
||||
homeTitle: "一场SOUL的创业实验场",
|
||||
homeSubtitle: "来自Soul派对房的真实商业故事",
|
||||
chaptersTitle: "我要看",
|
||||
matchTitle: "语音匹配",
|
||||
myTitle: "我的",
|
||||
aboutTitle: "关于作者",
|
||||
},
|
||||
})
|
||||
const [saved, setSaved] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (settings.siteConfig) {
|
||||
setLocalSettings({
|
||||
siteConfig: settings.siteConfig,
|
||||
menuConfig: settings.menuConfig,
|
||||
pageConfig: settings.pageConfig,
|
||||
})
|
||||
}
|
||||
}, [settings])
|
||||
|
||||
const handleSave = () => {
|
||||
updateSettings(localSettings)
|
||||
setSaved(true)
|
||||
setTimeout(() => setSaved(false), 2000)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">网站配置</h2>
|
||||
<p className="text-gray-400 mt-1">配置网站名称、图标、菜单和页面标题</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
className={`${saved ? "bg-green-500" : "bg-[#00CED1]"} hover:bg-[#20B2AA] text-white transition-colors`}
|
||||
>
|
||||
<Save className="w-4 h-4 mr-2" />
|
||||
{saved ? "已保存" : "保存设置"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* 网站基础信息 */}
|
||||
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Globe className="w-5 h-5 text-[#00CED1]" />
|
||||
网站基础信息
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-400">配置网站名称、标题和描述</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="site-name" className="text-gray-300">
|
||||
网站名称
|
||||
</Label>
|
||||
<Input
|
||||
id="site-name"
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.siteConfig.siteName}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, siteName: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="site-title" className="text-gray-300">
|
||||
网站标题
|
||||
</Label>
|
||||
<Input
|
||||
id="site-title"
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.siteConfig.siteTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, siteTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="site-desc" className="text-gray-300">
|
||||
网站描述
|
||||
</Label>
|
||||
<Input
|
||||
id="site-desc"
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.siteConfig.siteDescription}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, siteDescription: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="logo" className="text-gray-300">
|
||||
Logo地址
|
||||
</Label>
|
||||
<Input
|
||||
id="logo"
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.siteConfig.logo}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, logo: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="favicon" className="text-gray-300">
|
||||
Favicon地址
|
||||
</Label>
|
||||
<Input
|
||||
id="favicon"
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.siteConfig.favicon}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, favicon: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 主题颜色 */}
|
||||
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Palette className="w-5 h-5 text-[#00CED1]" />
|
||||
主题颜色
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-400">配置网站主题色</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="space-y-2 flex-1">
|
||||
<Label htmlFor="primary-color" className="text-gray-300">
|
||||
主色调
|
||||
</Label>
|
||||
<div className="flex items-center gap-3">
|
||||
<Input
|
||||
id="primary-color"
|
||||
type="color"
|
||||
className="w-16 h-10 bg-[#0a1628] border-gray-700 cursor-pointer"
|
||||
value={localSettings.siteConfig.primaryColor}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, primaryColor: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white flex-1"
|
||||
value={localSettings.siteConfig.primaryColor}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
siteConfig: { ...prev.siteConfig, primaryColor: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="w-24 h-24 rounded-xl flex items-center justify-center text-white font-bold"
|
||||
style={{ backgroundColor: localSettings.siteConfig.primaryColor }}
|
||||
>
|
||||
预览
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 菜单配置 */}
|
||||
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<Menu className="w-5 h-5 text-[#00CED1]" />
|
||||
底部菜单配置
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-400">控制底部导航栏菜单的显示和名称</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{Object.entries(localSettings.menuConfig).map(([key, config]) => (
|
||||
<div key={key} className="flex items-center justify-between p-4 bg-[#0a1628] rounded-lg">
|
||||
<div className="flex items-center gap-4 flex-1">
|
||||
<Switch
|
||||
checked={config.enabled}
|
||||
onCheckedChange={(checked) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
menuConfig: {
|
||||
...prev.menuConfig,
|
||||
[key]: { ...config, enabled: checked },
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<span className="text-gray-300 w-16 capitalize">{key}</span>
|
||||
<Input
|
||||
className="bg-[#0f2137] border-gray-700 text-white max-w-[200px]"
|
||||
value={config.label}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
menuConfig: {
|
||||
...prev.menuConfig,
|
||||
[key]: { ...config, label: e.target.value },
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<span className={`text-sm ${config.enabled ? "text-green-400" : "text-gray-500"}`}>
|
||||
{config.enabled ? "显示" : "隐藏"}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 页面标题配置 */}
|
||||
<Card className="bg-[#0f2137] border-gray-700/50 shadow-xl">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center gap-2">
|
||||
<FileText className="w-5 h-5 text-[#00CED1]" />
|
||||
页面标题配置
|
||||
</CardTitle>
|
||||
<CardDescription className="text-gray-400">配置各个页面的标题和副标题</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">首页标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.homeTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, homeTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">首页副标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.homeSubtitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, homeSubtitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">目录页标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.chaptersTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, chaptersTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">匹配页标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.matchTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, matchTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">我的页标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.myTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, myTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-gray-300">关于作者标题</Label>
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white"
|
||||
value={localSettings.pageConfig.aboutTitle}
|
||||
onChange={(e) =>
|
||||
setLocalSettings((prev) => ({
|
||||
...prev,
|
||||
pageConfig: { ...prev.pageConfig, aboutTitle: e.target.value },
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
231
app/my/page.tsx
231
app/my/page.tsx
@@ -2,11 +2,21 @@
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { User, ChevronRight, Copy, Check, Home, List, Sparkles, Clock } from "lucide-react"
|
||||
import { User, ChevronRight, Copy, Check, Home, List, TrendingUp, Gift, Star, Info } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { AuthModal } from "@/components/modules/auth/auth-modal"
|
||||
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
|
||||
|
||||
function PlanetIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} 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>
|
||||
)
|
||||
}
|
||||
|
||||
export default function MyPage() {
|
||||
const router = useRouter()
|
||||
const { user, isLoggedIn, logout, getAllPurchases, settings } = useStore()
|
||||
@@ -60,10 +70,10 @@ export default function MyPage() {
|
||||
<List className="w-5 h-5 text-gray-500 mb-1" />
|
||||
<span className="text-gray-500 text-xs">目录</span>
|
||||
</button>
|
||||
{/* 匹配按钮 - 更大更突出 */}
|
||||
{/* 匹配按钮 - 小星球图标 */}
|
||||
<button onClick={() => router.push("/match")} 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">
|
||||
<Sparkles className="w-6 h-6 text-white" />
|
||||
<PlanetIcon className="w-7 h-7 text-white" />
|
||||
</div>
|
||||
<span className="text-gray-500 text-xs mt-1">匹配</span>
|
||||
</button>
|
||||
@@ -84,81 +94,62 @@ export default function MyPage() {
|
||||
<h1 className="text-lg font-medium text-[#00CED1]">我的</h1>
|
||||
</div>
|
||||
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-[#00CED1]/20">
|
||||
{/* 用户卡片 - 突出个性化 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-14 h-14 rounded-full border-2 border-[#00CED1]/50 flex items-center justify-center">
|
||||
<User className="w-7 h-7 text-white/30" />
|
||||
<div className="w-16 h-16 rounded-full border-2 border-dashed border-[#00CED1]/50 flex items-center justify-center bg-gradient-to-br from-[#00CED1]/10 to-transparent">
|
||||
<User className="w-8 h-8 text-white/30" />
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={() => setShowAuthModal(true)} className="text-[#00CED1] font-medium text-lg">
|
||||
<div className="flex-1">
|
||||
<button onClick={() => setShowAuthModal(true)} className="text-[#00CED1] font-semibold text-lg">
|
||||
点击登录
|
||||
</button>
|
||||
<p className="text-white/30 text-sm">ID: ---</p>
|
||||
<p className="text-white/30 text-sm">解锁专属权益</p>
|
||||
</div>
|
||||
<div className="px-3 py-1 rounded-full bg-[#00CED1]/20 border border-[#00CED1]/30">
|
||||
<span className="text-[#00CED1] text-xs">VIP</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
{/* 个性化数据 */}
|
||||
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">0</p>
|
||||
<p className="text-white/40 text-xs">已读章节</p>
|
||||
<p className="text-white/40 text-xs">已读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">0</p>
|
||||
<p className="text-white/40 text-xs">阅读时长(分)</p>
|
||||
<p className="text-white/40 text-xs">收藏</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">0</p>
|
||||
<p className="text-white/40 text-xs">书签</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 关于作者入口 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-xl font-bold text-white">
|
||||
{authorInfo.name.charAt(0)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-white font-semibold">{authorInfo.name}</h3>
|
||||
<p className="text-gray-400 text-sm">{authorInfo.description}</p>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<span className="flex items-center gap-1 text-[#00CED1] text-xs">
|
||||
<Clock className="w-3 h-3" />
|
||||
每日 {authorInfo.liveTime}
|
||||
</span>
|
||||
<span className="text-gray-500 text-xs">{authorInfo.platform}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="px-3 py-2 rounded-lg bg-[#00CED1] text-black text-sm font-medium"
|
||||
>
|
||||
详情
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 分销中心 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
{/* 收益中心 - 突出收益 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#FFD700]/10 via-[#1c1c1e] to-[#1c1c1e] border border-[#FFD700]/20">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">💰</span>
|
||||
<span className="text-white font-medium">分销中心</span>
|
||||
<div className="w-8 h-8 rounded-lg bg-[#FFD700]/20 flex items-center justify-center">
|
||||
<TrendingUp className="w-4 h-4 text-[#FFD700]" />
|
||||
</div>
|
||||
<span className="text-white font-medium">收益中心</span>
|
||||
</div>
|
||||
<span className="text-[#00CED1] text-sm bg-[#00CED1]/10 px-2 py-1 rounded">佣金比例: 90%</span>
|
||||
<span className="text-[#FFD700] text-sm bg-[#FFD700]/10 px-3 py-1 rounded-full">90%分成</span>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-2">累计收益</p>
|
||||
<div className="bg-gradient-to-r from-[#FFD700]/5 to-transparent rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-1">累计收益</p>
|
||||
<p className="text-[#FFD700] text-3xl font-bold text-center">¥0.00</p>
|
||||
<div className="grid grid-cols-2 gap-4 mt-4 pt-4 border-t border-white/10">
|
||||
<div className="flex justify-center gap-8 mt-3">
|
||||
<div className="text-center">
|
||||
<p className="text-white/50 text-xs">可提现</p>
|
||||
<p className="text-white/40 text-xs">可提现</p>
|
||||
<p className="text-white font-medium">¥0.00</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white/50 text-xs">已提现</p>
|
||||
<p className="text-white/40 text-xs">已提现</p>
|
||||
<p className="text-white font-medium">¥0.00</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -167,9 +158,10 @@ export default function MyPage() {
|
||||
<div className="grid grid-cols-2 gap-3 mb-4">
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
className="py-3 rounded-xl bg-[#00CED1] text-white font-medium"
|
||||
className="py-3 rounded-xl bg-gradient-to-r from-[#FFD700] to-[#FFA500] text-black font-medium flex items-center justify-center gap-2"
|
||||
>
|
||||
生成推广海报
|
||||
<Gift className="w-4 h-4" />
|
||||
生成海报
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
@@ -179,17 +171,17 @@ export default function MyPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">0</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">0</p>
|
||||
<p className="text-white/40 text-xs">推荐人数</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">0</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">0</p>
|
||||
<p className="text-white/40 text-xs">成交订单</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">90%</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">90%</p>
|
||||
<p className="text-white/40 text-xs">佣金率</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,7 +190,7 @@ export default function MyPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-white/50 text-xs">我的邀请码</p>
|
||||
<p className="text-[#00CED1] font-mono text-lg">- - -</p>
|
||||
<p className="text-[#FFD700] font-mono text-lg">- - -</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
@@ -224,7 +216,7 @@ export default function MyPage() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
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">
|
||||
<span className="text-xl">🏷️</span>
|
||||
@@ -232,6 +224,19 @@ export default function MyPage() {
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
{/* 关于作者 - 小图标入口 */}
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-6 h-6 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
|
||||
<Info className="w-3 h-3 text-white" />
|
||||
</div>
|
||||
<span className="text-white">关于作者</span>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BottomNavBar />
|
||||
@@ -250,79 +255,63 @@ export default function MyPage() {
|
||||
<h1 className="text-lg font-medium text-[#00CED1]">我的</h1>
|
||||
</div>
|
||||
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-[#00CED1]/20">
|
||||
{/* 用户卡片 - 突出个性化 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-14 h-14 rounded-full border-2 border-[#00CED1] flex items-center justify-center bg-gradient-to-br from-[#00CED1]/20 to-transparent">
|
||||
<User className="w-7 h-7 text-[#00CED1]" />
|
||||
<div className="w-16 h-16 rounded-full border-2 border-[#00CED1] flex items-center justify-center bg-gradient-to-br from-[#00CED1]/20 to-transparent">
|
||||
<span className="text-2xl font-bold text-[#00CED1]">{user?.nickname?.charAt(0) || "U"}</span>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-white font-medium text-lg">{user?.nickname || "用户"}</p>
|
||||
<div className="flex-1">
|
||||
<p className="text-white font-semibold text-lg">{user?.nickname || "用户"}</p>
|
||||
<p className="text-white/30 text-sm">ID: {user?.id?.slice(-8) || "---"}</p>
|
||||
</div>
|
||||
<div className="px-3 py-1 rounded-full bg-[#00CED1]/20 border border-[#00CED1]/30">
|
||||
<span className="text-[#00CED1] text-xs flex items-center gap-1">
|
||||
<Star className="w-3 h-3" />
|
||||
VIP
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
{/* 个性化数据 */}
|
||||
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">{purchasedCount}</p>
|
||||
<p className="text-white/40 text-xs">已读章节</p>
|
||||
<p className="text-white/40 text-xs">已读</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">{readingMinutes}</p>
|
||||
<p className="text-white/40 text-xs">阅读时长(分)</p>
|
||||
<p className="text-white/40 text-xs">时长(分)</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-center p-2 rounded-lg bg-white/5">
|
||||
<p className="text-[#00CED1] text-xl font-bold">{bookmarks}</p>
|
||||
<p className="text-white/40 text-xs">书签</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 关于作者入口 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-xl font-bold text-white">
|
||||
{authorInfo.name.charAt(0)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-white font-semibold">{authorInfo.name}</h3>
|
||||
<p className="text-gray-400 text-sm">{authorInfo.description}</p>
|
||||
<div className="flex items-center gap-3 mt-1">
|
||||
<span className="flex items-center gap-1 text-[#00CED1] text-xs">
|
||||
<Clock className="w-3 h-3" />
|
||||
每日 {authorInfo.liveTime}
|
||||
</span>
|
||||
<span className="text-gray-500 text-xs">{authorInfo.platform}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="px-3 py-2 rounded-lg bg-[#00CED1] text-black text-sm font-medium"
|
||||
>
|
||||
详情
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 分销中心 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
{/* 收益中心 - 突出收益 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#FFD700]/10 via-[#1c1c1e] to-[#1c1c1e] border border-[#FFD700]/20">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">💰</span>
|
||||
<span className="text-white font-medium">分销中心</span>
|
||||
<div className="w-8 h-8 rounded-lg bg-[#FFD700]/20 flex items-center justify-center">
|
||||
<TrendingUp className="w-4 h-4 text-[#FFD700]" />
|
||||
</div>
|
||||
<span className="text-white font-medium">收益中心</span>
|
||||
</div>
|
||||
<span className="text-[#00CED1] text-sm bg-[#00CED1]/10 px-2 py-1 rounded">佣金比例: 90%</span>
|
||||
<span className="text-[#FFD700] text-sm bg-[#FFD700]/10 px-3 py-1 rounded-full">90%分成</span>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-2">累计收益</p>
|
||||
<div className="bg-gradient-to-r from-[#FFD700]/5 to-transparent rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-1">累计收益</p>
|
||||
<p className="text-[#FFD700] text-3xl font-bold text-center">¥{(user?.earnings || 0).toFixed(2)}</p>
|
||||
<div className="grid grid-cols-2 gap-4 mt-4 pt-4 border-t border-white/10">
|
||||
<div className="flex justify-center gap-8 mt-3">
|
||||
<div className="text-center">
|
||||
<p className="text-white/50 text-xs">可提现</p>
|
||||
<p className="text-white/40 text-xs">可提现</p>
|
||||
<p className="text-white font-medium">¥{(user?.pendingEarnings || 0).toFixed(2)}</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-white/50 text-xs">已提现</p>
|
||||
<p className="text-white/40 text-xs">已提现</p>
|
||||
<p className="text-white font-medium">¥{(user?.withdrawnEarnings || 0).toFixed(2)}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -331,9 +320,10 @@ export default function MyPage() {
|
||||
<div className="grid grid-cols-2 gap-3 mb-4">
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
className="py-3 rounded-xl bg-[#00CED1] text-white font-medium"
|
||||
className="py-3 rounded-xl bg-gradient-to-r from-[#FFD700] to-[#FFA500] text-black font-medium flex items-center justify-center gap-2"
|
||||
>
|
||||
生成推广海报
|
||||
<Gift className="w-4 h-4" />
|
||||
生成海报
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
@@ -343,17 +333,17 @@ export default function MyPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">{user?.referralCount || 0}</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">{user?.referralCount || 0}</p>
|
||||
<p className="text-white/40 text-xs">推荐人数</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">{completedOrders}</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">{completedOrders}</p>
|
||||
<p className="text-white/40 text-xs">成交订单</p>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-[#00CED1] text-xl font-bold">90%</p>
|
||||
<p className="text-[#FFD700] text-xl font-bold">90%</p>
|
||||
<p className="text-white/40 text-xs">佣金率</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -362,7 +352,7 @@ export default function MyPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-white/50 text-xs">我的邀请码</p>
|
||||
<p className="text-[#00CED1] font-mono text-lg">{user?.referralCode || "---"}</p>
|
||||
<p className="text-[#FFD700] font-mono text-lg">{user?.referralCode || "---"}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleCopyCode}
|
||||
@@ -389,7 +379,7 @@ export default function MyPage() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/bookmarks")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
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">
|
||||
<span className="text-xl">🏷️</span>
|
||||
@@ -397,6 +387,19 @@ export default function MyPage() {
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
{/* 关于作者 - 小图标入口 */}
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="w-full flex items-center justify-between p-4 active:bg-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-6 h-6 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
|
||||
<Info className="w-3 h-3 text-white" />
|
||||
</div>
|
||||
<span className="text-white">关于作者</span>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="mx-4 mt-4">
|
||||
|
||||
57
lib/store.ts
57
lib/store.ts
@@ -112,6 +112,31 @@ export interface FeishuSyncConfig {
|
||||
syncInterval: number // 分钟
|
||||
}
|
||||
|
||||
export interface SiteConfig {
|
||||
siteName: string
|
||||
siteTitle: string
|
||||
siteDescription: string
|
||||
logo: string
|
||||
favicon: string
|
||||
primaryColor: string
|
||||
}
|
||||
|
||||
export interface MenuConfig {
|
||||
home: { enabled: boolean; label: string }
|
||||
chapters: { enabled: boolean; label: string }
|
||||
match: { enabled: boolean; label: string }
|
||||
my: { enabled: boolean; label: string }
|
||||
}
|
||||
|
||||
export interface PageConfig {
|
||||
homeTitle: string
|
||||
homeSubtitle: string
|
||||
chaptersTitle: string
|
||||
matchTitle: string
|
||||
myTitle: string
|
||||
aboutTitle: string
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
distributorShare: number
|
||||
authorShare: number
|
||||
@@ -128,6 +153,9 @@ export interface Settings {
|
||||
liveTime: string
|
||||
platform: string
|
||||
}
|
||||
siteConfig: SiteConfig
|
||||
menuConfig: MenuConfig
|
||||
pageConfig: PageConfig
|
||||
}
|
||||
|
||||
interface StoreState {
|
||||
@@ -171,7 +199,7 @@ const initialSettings: Settings = {
|
||||
partnerId: "2088511801157159",
|
||||
securityKey: "lz6ey1h3kl9zqkgtjz3avb5gk37wzbrp",
|
||||
mobilePayEnabled: true,
|
||||
paymentInterface: "official_instant", // 支付宝官方即时到账接口
|
||||
paymentInterface: "official_instant",
|
||||
},
|
||||
wechat: {
|
||||
enabled: true,
|
||||
@@ -184,7 +212,7 @@ const initialSettings: Settings = {
|
||||
mpVerifyCode: "SP8AfZJyAvprRORT",
|
||||
merchantId: "1318592501",
|
||||
apiKey: "wx3e31b068be59ddc131b068be59ddc2",
|
||||
groupQrCode: "", // 微信群二维码链接,管理员配置
|
||||
groupQrCode: "",
|
||||
},
|
||||
usdt: {
|
||||
enabled: true,
|
||||
@@ -234,6 +262,28 @@ const initialSettings: Settings = {
|
||||
liveTime: "06:00-09:00",
|
||||
platform: "Soul派对房",
|
||||
},
|
||||
siteConfig: {
|
||||
siteName: "卡若日记",
|
||||
siteTitle: "一场SOUL的创业实验场",
|
||||
siteDescription: "来自Soul派对房的真实商业故事",
|
||||
logo: "/logo.png",
|
||||
favicon: "/favicon.ico",
|
||||
primaryColor: "#00CED1",
|
||||
},
|
||||
menuConfig: {
|
||||
home: { enabled: true, label: "首页" },
|
||||
chapters: { enabled: true, label: "目录" },
|
||||
match: { enabled: true, label: "匹配" },
|
||||
my: { enabled: true, label: "我的" },
|
||||
},
|
||||
pageConfig: {
|
||||
homeTitle: "一场SOUL的创业实验场",
|
||||
homeSubtitle: "来自Soul派对房的真实商业故事",
|
||||
chaptersTitle: "我要看",
|
||||
matchTitle: "语音匹配",
|
||||
myTitle: "我的",
|
||||
aboutTitle: "关于作者",
|
||||
},
|
||||
}
|
||||
|
||||
export const useStore = create<StoreState>()(
|
||||
@@ -649,6 +699,9 @@ export const useStore = create<StoreState>()(
|
||||
const newSettings: Partial<Settings> = {
|
||||
paymentMethods: mergedPaymentMethods,
|
||||
authorInfo: { ...settings.authorInfo, ...data.authorInfo },
|
||||
siteConfig: { ...settings.siteConfig, ...data.siteConfig },
|
||||
menuConfig: { ...settings.menuConfig, ...data.menuConfig },
|
||||
pageConfig: { ...settings.pageConfig, ...data.pageConfig },
|
||||
}
|
||||
|
||||
set({ settings: { ...settings, ...newSettings } })
|
||||
|
||||
Reference in New Issue
Block a user