110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
'use client'
|
||
|
||
import { WxUserWithProgress } from '@/types'
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
DialogDescription,
|
||
} from '@/components/ui/dialog'
|
||
|
||
interface WxUserDetailDialogProps {
|
||
open: boolean
|
||
onOpenChange: (open: boolean) => void
|
||
user: WxUserWithProgress | null | undefined
|
||
}
|
||
|
||
export function WxUserDetailDialog({
|
||
open,
|
||
onOpenChange,
|
||
user,
|
||
}: WxUserDetailDialogProps) {
|
||
if (!user) return null
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>用户详情</DialogTitle>
|
||
<DialogDescription>
|
||
完整信息及关卡进度
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<div className="space-y-4">
|
||
<div className="flex items-center gap-4">
|
||
<div className="w-16 h-16 flex-shrink-0">
|
||
{user.avatarUrl ? (
|
||
<img
|
||
src={user.avatarUrl}
|
||
alt={user.nickname || 'User'}
|
||
className="w-16 h-16 rounded-full object-cover"
|
||
/>
|
||
) : (
|
||
<div className="w-16 h-16 rounded-full bg-gray-200 flex items-center justify-center text-xl font-medium text-gray-600">
|
||
{user.nickname?.[0]?.toUpperCase() || 'U'}
|
||
</div>
|
||
)}
|
||
</div>
|
||
<div>
|
||
<h2 className="text-xl font-semibold text-gray-900">
|
||
{user.nickname || '匿名用户'}
|
||
</h2>
|
||
<p className="text-sm text-gray-500 mt-1">
|
||
注册时间:{new Date(user.createdAt).toLocaleDateString('zh-CN')}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="bg-gray-50 rounded-lg p-4">
|
||
<p className="text-xs text-gray-500 uppercase tracking-wider mb-1">积分</p>
|
||
<p className="text-2xl font-bold text-orange-600">{user.points}</p>
|
||
</div>
|
||
<div className="bg-gray-50 rounded-lg p-4">
|
||
<p className="text-xs text-gray-500 uppercase tracking-wider mb-1">已通关关卡</p>
|
||
<p className="text-2xl font-bold text-green-600">{user.levelProgress.length}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<p className="text-xs text-gray-500 uppercase tracking-wider mb-2">OpenID</p>
|
||
<code className="block bg-gray-100 text-gray-800 text-xs p-3 rounded-lg break-all">
|
||
{user.openid}
|
||
</code>
|
||
</div>
|
||
|
||
{user.levelProgress.length > 0 && (
|
||
<div>
|
||
<p className="text-xs text-gray-500 uppercase tracking-wider mb-2">关卡进度</p>
|
||
<div className="space-y-2">
|
||
{user.levelProgress.map((progress) => (
|
||
<div
|
||
key={progress.id}
|
||
className="flex items-center justify-between bg-gray-50 rounded-lg px-3 py-2"
|
||
>
|
||
<div className="flex flex-col">
|
||
<span className="text-xs text-gray-400 font-mono">
|
||
{progress.levelId}
|
||
</span>
|
||
{progress.level && (
|
||
<span className="text-sm font-medium text-gray-900">
|
||
{progress.level.answer}
|
||
</span>
|
||
)}
|
||
</div>
|
||
<span className="text-xs text-gray-400">
|
||
{new Date(progress.completedAt).toLocaleDateString('zh-CN')}
|
||
</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
)
|
||
}
|