优化阅读页跳转逻辑,优先传递章节中间ID(mid),以提升分享功能的一致性。更新相关页面以支持新逻辑,确保用户体验流畅。增加退款功能的相关处理,支持订单退款及退款原因的记录,增强订单管理的灵活性。
This commit is contained in:
@@ -117,8 +117,10 @@ export function AdminLayout() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto bg-[#0a1628]">
|
||||
<Outlet />
|
||||
<div className="flex-1 overflow-auto bg-[#0a1628] min-w-0">
|
||||
<div className="w-full min-w-[1024px] min-h-full">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Link2 } from 'lucide-react'
|
||||
|
||||
export function ApiDocPage() {
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex items-center gap-2 mb-8">
|
||||
<Link2 className="w-8 h-8 text-[#38bdac]" />
|
||||
<h1 className="text-2xl font-bold text-white">API 接口文档</h1>
|
||||
|
||||
@@ -117,7 +117,7 @@ export function ChaptersPage() {
|
||||
<div className="min-h-screen bg-black text-white">
|
||||
{/* 导航栏 */}
|
||||
<div className="sticky top-0 bg-black/90 backdrop-blur border-b border-white/10 z-50">
|
||||
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
|
||||
<div className="w-full min-w-[1024px] px-4 py-4 flex items-center justify-between">
|
||||
<h1 className="text-xl font-bold">章节管理</h1>
|
||||
<div className="flex items-center gap-4">
|
||||
<button
|
||||
@@ -146,7 +146,7 @@ export function ChaptersPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto px-4 py-8">
|
||||
<div className="w-full min-w-[1024px] px-4 py-8">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
|
||||
@@ -364,7 +364,7 @@ export function ContentPage() {
|
||||
const chaptersForPart = currentPart?.chapters ?? []
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-6xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">内容管理</h2>
|
||||
|
||||
@@ -66,7 +66,7 @@ export function DashboardPage() {
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<h1 className="text-2xl font-bold mb-8 text-white">数据概览</h1>
|
||||
<div className="flex flex-col items-center justify-center py-24">
|
||||
<RefreshCw className="w-12 h-12 text-[#38bdac] animate-spin mb-4" />
|
||||
@@ -150,7 +150,7 @@ export function DashboardPage() {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<h1 className="text-2xl font-bold mb-8 text-white">数据概览</h1>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||
|
||||
@@ -12,12 +12,20 @@ import {
|
||||
DollarSign,
|
||||
Link2,
|
||||
Eye,
|
||||
Undo2,
|
||||
} from 'lucide-react'
|
||||
import { Pagination } from '@/components/ui/Pagination'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { get, put } from '@/api/client'
|
||||
|
||||
interface DistributionOverview {
|
||||
@@ -97,6 +105,8 @@ interface Order {
|
||||
referrerNickname?: string | null
|
||||
referrerCode?: string | null
|
||||
referralCode?: string | null
|
||||
orderSn?: string
|
||||
refundReason?: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
@@ -117,6 +127,9 @@ export function DistributionPage() {
|
||||
const [pageSize, setPageSize] = useState(10)
|
||||
const [total, setTotal] = useState(0)
|
||||
const [loadedTabs, setLoadedTabs] = useState<Set<string>>(new Set())
|
||||
const [refundOrder, setRefundOrder] = useState<Order | null>(null)
|
||||
const [refundReason, setRefundReason] = useState('')
|
||||
const [refundLoading, setRefundLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
loadInitialData()
|
||||
@@ -313,6 +326,30 @@ export function DistributionPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRefund() {
|
||||
if (!refundOrder?.orderSn && !refundOrder?.id) return
|
||||
setRefundLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const res = await put<{ success?: boolean; error?: string }>('/api/admin/orders/refund', {
|
||||
orderSn: refundOrder.orderSn || refundOrder.id,
|
||||
reason: refundReason || undefined,
|
||||
})
|
||||
if (res?.success) {
|
||||
setRefundOrder(null)
|
||||
setRefundReason('')
|
||||
await loadTabData('orders', true)
|
||||
} else {
|
||||
setError(res?.error || '退款失败')
|
||||
}
|
||||
} catch (e) {
|
||||
const err = e as Error & { data?: { error?: string } }
|
||||
setError(err?.data?.error || '退款失败,请检查网络后重试')
|
||||
} finally {
|
||||
setRefundLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusBadge(status: string) {
|
||||
const styles: Record<string, string> = {
|
||||
active: 'bg-green-500/20 text-green-400',
|
||||
@@ -364,7 +401,7 @@ export function DistributionPage() {
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
@@ -647,6 +684,7 @@ export function DistributionPage() {
|
||||
<option value="completed">已完成</option>
|
||||
<option value="pending">待支付</option>
|
||||
<option value="failed">已失败</option>
|
||||
<option value="refunded">已退款</option>
|
||||
</select>
|
||||
</div>
|
||||
<Card className="bg-[#0f2137] border-gray-700/50">
|
||||
@@ -664,9 +702,11 @@ export function DistributionPage() {
|
||||
<th className="p-4 text-left font-medium">金额</th>
|
||||
<th className="p-4 text-left font-medium">支付方式</th>
|
||||
<th className="p-4 text-left font-medium">状态</th>
|
||||
<th className="p-4 text-left font-medium">退款原因</th>
|
||||
<th className="p-4 text-left font-medium">推荐人/邀请码</th>
|
||||
<th className="p-4 text-left font-medium">分销佣金</th>
|
||||
<th className="p-4 text-left font-medium">下单时间</th>
|
||||
<th className="p-4 text-left font-medium">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-700/50">
|
||||
@@ -713,7 +753,11 @@ export function DistributionPage() {
|
||||
: order.paymentMethod || '微信支付'}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
{order.status === 'completed' || order.status === 'paid' ? (
|
||||
{order.status === 'refunded' ? (
|
||||
<Badge className="bg-gray-500/20 text-gray-400 border-0">
|
||||
已退款
|
||||
</Badge>
|
||||
) : order.status === 'completed' || order.status === 'paid' ? (
|
||||
<Badge className="bg-green-500/20 text-green-400 border-0">
|
||||
已完成
|
||||
</Badge>
|
||||
@@ -727,6 +771,9 @@ export function DistributionPage() {
|
||||
</Badge>
|
||||
)}
|
||||
</td>
|
||||
<td className="p-4 text-gray-400 text-sm max-w-[120px]" title={order.refundReason}>
|
||||
{order.status === 'refunded' && order.refundReason ? order.refundReason : '-'}
|
||||
</td>
|
||||
<td className="p-4 text-gray-300 text-sm">
|
||||
{order.referrerId || order.referralCode ? (
|
||||
<span
|
||||
@@ -758,6 +805,22 @@ export function DistributionPage() {
|
||||
? new Date(order.createdAt).toLocaleString('zh-CN')
|
||||
: '-'}
|
||||
</td>
|
||||
<td className="p-4">
|
||||
{(order.status === 'paid' || order.status === 'completed') && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-orange-500/50 text-orange-400 hover:bg-orange-500/20"
|
||||
onClick={() => {
|
||||
setRefundOrder(order)
|
||||
setRefundReason('')
|
||||
}}
|
||||
>
|
||||
<Undo2 className="w-3 h-3 mr-1" />
|
||||
退款
|
||||
</Button>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -1025,6 +1088,55 @@ export function DistributionPage() {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Dialog open={!!refundOrder} onOpenChange={(open) => !open && setRefundOrder(null)}>
|
||||
<DialogContent className="bg-[#0f2137] border-gray-700 text-white max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-white">订单退款</DialogTitle>
|
||||
</DialogHeader>
|
||||
{refundOrder && (
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-400 text-sm">
|
||||
订单号:{refundOrder.orderSn || refundOrder.id}
|
||||
</p>
|
||||
<p className="text-gray-400 text-sm">
|
||||
退款金额:¥{typeof refundOrder.amount === 'number' ? refundOrder.amount.toFixed(2) : parseFloat(String(refundOrder.amount || '0')).toFixed(2)}
|
||||
</p>
|
||||
<div>
|
||||
<label className="text-sm text-gray-400 block mb-2">退款原因(选填)</label>
|
||||
<div className="form-input">
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white placeholder:text-gray-500"
|
||||
placeholder="如:用户申请退款"
|
||||
value={refundReason}
|
||||
onChange={(e) => setRefundReason(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-orange-400/80 text-xs">
|
||||
退款将原路退回至用户微信,且无法撤销,请确认后再操作。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="border-gray-600 text-gray-300"
|
||||
onClick={() => setRefundOrder(null)}
|
||||
disabled={refundLoading}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-orange-500 hover:bg-orange-600 text-white"
|
||||
onClick={handleRefund}
|
||||
disabled={refundLoading}
|
||||
>
|
||||
{refundLoading ? '退款中...' : '确认退款'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export function MatchRecordsPage() {
|
||||
const totalPages = Math.ceil(total / pageSize) || 1
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
|
||||
@@ -239,7 +239,7 @@ export function MatchPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-6xl mx-auto space-y-6">
|
||||
<div className="p-8 w-full space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white flex items-center gap-2">
|
||||
|
||||
@@ -11,10 +11,17 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Search, RefreshCw, Download, Filter } from 'lucide-react'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Search, RefreshCw, Download, Filter, Undo2 } from 'lucide-react'
|
||||
import { useDebounce } from '@/hooks/useDebounce'
|
||||
import { Pagination } from '@/components/ui/Pagination'
|
||||
import { get } from '@/api/client'
|
||||
import { get, put } from '@/api/client'
|
||||
|
||||
interface Purchase {
|
||||
id: string
|
||||
@@ -24,7 +31,7 @@ interface Purchase {
|
||||
sectionTitle?: string
|
||||
productId?: string
|
||||
amount: number
|
||||
status: 'pending' | 'completed' | 'failed' | 'paid' | 'created'
|
||||
status: 'pending' | 'completed' | 'failed' | 'paid' | 'created' | 'refunded'
|
||||
paymentMethod?: string
|
||||
referrerEarnings?: number
|
||||
createdAt: string
|
||||
@@ -32,6 +39,7 @@ interface Purchase {
|
||||
userNickname?: string
|
||||
productType?: string
|
||||
description?: string
|
||||
refundReason?: string
|
||||
}
|
||||
|
||||
interface UsersItem {
|
||||
@@ -53,6 +61,9 @@ export function OrdersPage() {
|
||||
const [statusFilter, setStatusFilter] = useState<string>('all')
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [refundOrder, setRefundOrder] = useState<Purchase | null>(null)
|
||||
const [refundReason, setRefundReason] = useState('')
|
||||
const [refundLoading, setRefundLoading] = useState(false)
|
||||
|
||||
async function loadOrders() {
|
||||
setIsLoading(true)
|
||||
@@ -130,12 +141,36 @@ export function OrdersPage() {
|
||||
|
||||
const totalPages = Math.ceil(total / pageSize) || 1
|
||||
|
||||
async function handleRefund() {
|
||||
if (!refundOrder?.orderSn && !refundOrder?.id) return
|
||||
setRefundLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const res = await put<{ success?: boolean; error?: string }>('/api/admin/orders/refund', {
|
||||
orderSn: refundOrder.orderSn || refundOrder.id,
|
||||
reason: refundReason || undefined,
|
||||
})
|
||||
if (res?.success) {
|
||||
setRefundOrder(null)
|
||||
setRefundReason('')
|
||||
loadOrders()
|
||||
} else {
|
||||
setError(res?.error || '退款失败')
|
||||
}
|
||||
} catch (e) {
|
||||
const err = e as Error & { data?: { error?: string } }
|
||||
setError(err?.data?.error || '退款失败,请检查网络后重试')
|
||||
} finally {
|
||||
setRefundLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
if (purchases.length === 0) {
|
||||
alert('暂无数据可导出')
|
||||
return
|
||||
}
|
||||
const headers = ['订单号', '用户', '手机号', '商品', '金额', '支付方式', '状态', '分销佣金', '下单时间']
|
||||
const headers = ['订单号', '用户', '手机号', '商品', '金额', '支付方式', '状态', '退款原因', '分销佣金', '下单时间']
|
||||
const rows = purchases.map((p) => {
|
||||
const product = formatProduct(p)
|
||||
return [
|
||||
@@ -145,7 +180,8 @@ export function OrdersPage() {
|
||||
product.name,
|
||||
Number(p.amount || 0).toFixed(2),
|
||||
p.paymentMethod === 'wechat' ? '微信支付' : p.paymentMethod === 'alipay' ? '支付宝' : p.paymentMethod || '微信支付',
|
||||
p.status === 'paid' || p.status === 'completed' ? '已完成' : p.status === 'pending' || p.status === 'created' ? '待支付' : '已失败',
|
||||
p.status === 'refunded' ? '已退款' : p.status === 'paid' || p.status === 'completed' ? '已完成' : p.status === 'pending' || p.status === 'created' ? '待支付' : '已失败',
|
||||
p.status === 'refunded' && p.refundReason ? p.refundReason : '-',
|
||||
p.referrerEarnings ? Number(p.referrerEarnings).toFixed(2) : '-',
|
||||
p.createdAt ? new Date(p.createdAt).toLocaleString('zh-CN') : '',
|
||||
].join(',')
|
||||
@@ -161,7 +197,7 @@ export function OrdersPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
@@ -218,6 +254,7 @@ export function OrdersPage() {
|
||||
<option value="pending">待支付</option>
|
||||
<option value="created">已创建</option>
|
||||
<option value="failed">已失败</option>
|
||||
<option value="refunded">已退款</option>
|
||||
</select>
|
||||
</div>
|
||||
<Button
|
||||
@@ -249,8 +286,10 @@ export function OrdersPage() {
|
||||
<TableHead className="text-gray-400">金额</TableHead>
|
||||
<TableHead className="text-gray-400">支付方式</TableHead>
|
||||
<TableHead className="text-gray-400">状态</TableHead>
|
||||
<TableHead className="text-gray-400">退款原因</TableHead>
|
||||
<TableHead className="text-gray-400">分销佣金</TableHead>
|
||||
<TableHead className="text-gray-400">下单时间</TableHead>
|
||||
<TableHead className="text-gray-400">操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -291,7 +330,11 @@ export function OrdersPage() {
|
||||
: purchase.paymentMethod || '微信支付'}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{purchase.status === 'paid' || purchase.status === 'completed' ? (
|
||||
{purchase.status === 'refunded' ? (
|
||||
<Badge className="bg-gray-500/20 text-gray-400 hover:bg-gray-500/20 border-0">
|
||||
已退款
|
||||
</Badge>
|
||||
) : purchase.status === 'paid' || purchase.status === 'completed' ? (
|
||||
<Badge className="bg-green-500/20 text-green-400 hover:bg-green-500/20 border-0">
|
||||
已完成
|
||||
</Badge>
|
||||
@@ -305,6 +348,9 @@ export function OrdersPage() {
|
||||
</Badge>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-gray-400 text-sm max-w-[120px] truncate" title={purchase.refundReason}>
|
||||
{purchase.status === 'refunded' && purchase.refundReason ? purchase.refundReason : '-'}
|
||||
</TableCell>
|
||||
<TableCell className="text-[#FFD700]">
|
||||
{purchase.referrerEarnings
|
||||
? `¥${Number(purchase.referrerEarnings).toFixed(2)}`
|
||||
@@ -313,12 +359,28 @@ export function OrdersPage() {
|
||||
<TableCell className="text-gray-400 text-sm">
|
||||
{new Date(purchase.createdAt).toLocaleString('zh-CN')}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{(purchase.status === 'paid' || purchase.status === 'completed') && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-orange-500/50 text-orange-400 hover:bg-orange-500/20"
|
||||
onClick={() => {
|
||||
setRefundOrder(purchase)
|
||||
setRefundReason('')
|
||||
}}
|
||||
>
|
||||
<Undo2 className="w-3 h-3 mr-1" />
|
||||
退款
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
})}
|
||||
{purchases.length === 0 && (
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} className="text-center py-12 text-gray-500">
|
||||
<TableCell colSpan={10} className="text-center py-12 text-gray-500">
|
||||
暂无订单数据
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -340,6 +402,55 @@ export function OrdersPage() {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Dialog open={!!refundOrder} onOpenChange={(open) => !open && setRefundOrder(null)}>
|
||||
<DialogContent className="bg-[#0f2137] border-gray-700 text-white max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-white">订单退款</DialogTitle>
|
||||
</DialogHeader>
|
||||
{refundOrder && (
|
||||
<div className="space-y-4">
|
||||
<p className="text-gray-400 text-sm">
|
||||
订单号:{refundOrder.orderSn || refundOrder.id}
|
||||
</p>
|
||||
<p className="text-gray-400 text-sm">
|
||||
退款金额:¥{Number(refundOrder.amount || 0).toFixed(2)}
|
||||
</p>
|
||||
<div>
|
||||
<label className="text-sm text-gray-400 block mb-2">退款原因(选填)</label>
|
||||
<div className="form-input">
|
||||
<Input
|
||||
className="bg-[#0a1628] border-gray-700 text-white placeholder:text-gray-500"
|
||||
placeholder="如:用户申请退款"
|
||||
value={refundReason}
|
||||
onChange={(e) => setRefundReason(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-orange-400/80 text-xs">
|
||||
退款将原路退回至用户微信,且无法撤销,请确认后再操作。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="border-gray-600 text-gray-300"
|
||||
onClick={() => setRefundOrder(null)}
|
||||
disabled={refundLoading}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-orange-500 hover:bg-orange-600 text-white"
|
||||
onClick={handleRefund}
|
||||
disabled={refundLoading}
|
||||
>
|
||||
{refundLoading ? '退款中...' : '确认退款'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function PaymentPage() {
|
||||
const p = localSettings.paypal as Record<string, unknown>
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-5xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold mb-2 text-white">支付配置</h1>
|
||||
|
||||
@@ -103,7 +103,7 @@ export function QRCodesPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-5xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="mb-8">
|
||||
<h2 className="text-2xl font-bold text-white">微信群活码管理</h2>
|
||||
<p className="text-gray-400 mt-1">配置微信群跳转链接,用户支付后自动跳转加群</p>
|
||||
|
||||
@@ -92,7 +92,7 @@ export function ReferralSettingsPage() {
|
||||
if (loading) return <div className="p-8 text-gray-500">加载中...</div>
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white flex items-center gap-2">
|
||||
|
||||
@@ -236,7 +236,7 @@ export function SettingsPage() {
|
||||
if (loading) return <div className="p-8 text-gray-500">加载中...</div>
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">系统设置</h2>
|
||||
|
||||
@@ -107,7 +107,7 @@ export function SitePage() {
|
||||
const page = localSettings.pageConfig
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">网站配置</h2>
|
||||
|
||||
@@ -280,7 +280,7 @@ export function UsersPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-7xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
|
||||
@@ -120,7 +120,7 @@ export function VipRolesPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-4xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white flex items-center gap-2">
|
||||
|
||||
@@ -198,7 +198,7 @@ export function WithdrawalsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-6xl mx-auto">
|
||||
<div className="p-8 w-full">
|
||||
{error && (
|
||||
<div className="mb-4 px-4 py-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-400 text-sm flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
|
||||
Reference in New Issue
Block a user