import { useQuery } from '@tanstack/react-query' import { Award, Briefcase, CheckCircle2, FileText, GraduationCap, MapPin, Shield, Star, Tag, User, Wrench, XCircle, } from 'lucide-react' import { fetchUserDetail, fetchUserInfo, fetchUserServices } from '@/api/modules/users' import { fetchExcProvider } from '@/api/modules/exc' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from '@/components/ui/sheet' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' interface UserDetailSheetProps { uid: string | null onClose: () => void onAssignRoles?: () => void } export function UserDetailSheet({ uid, onClose, onAssignRoles }: UserDetailSheetProps) { // 1. Basic user account query (GET /api/admin/v1/users/{uid}) const userQuery = useQuery({ queryKey: ['users', uid], queryFn: () => (uid ? fetchUserDetail(uid) : null), enabled: uid !== null, }) // 2. Full user profile, careers, educations, honors, addresses (GET /api/admin/v1/users/{uid}/info) const userInfoQuery = useQuery({ queryKey: ['user-info', uid], queryFn: async () => { if (!uid) return null try { const res = await fetchUserInfo(uid) return res.data } catch { return null } }, enabled: uid !== null, }) // 3. User provided services (GET /api/admin/v1/users/{uid}/services) const userServicesQuery = useQuery({ queryKey: ['user-services', uid], queryFn: async () => { if (!uid) return null try { const res = await fetchUserServices(uid) return res.data } catch { return null } }, enabled: uid !== null, }) // 4. Provider profile query (GET /api/admin/v1/exc/providers/{uid}) const providerQuery = useQuery({ queryKey: ['exc-provider', uid], queryFn: async () => { if (!uid) return null try { const res = await fetchExcProvider(uid) return res.data } catch { return null } }, enabled: uid !== null, retry: false, }) const user = userQuery.data?.data const userInfo = userInfoQuery.data const userServices = userServicesQuery.data?.expertises ?? [] const provider = providerQuery.data return ( !open && onClose()}>
{(user?.display_name ?? user?.username ?? 'U').slice(0, 1).toUpperCase()}
{userInfo?.profile?.computed_fullname ?? user?.display_name ?? user?.username ?? '用户详情'} {userInfo?.profile?.gender && ( {userInfo.profile.gender} )} {user?.uid}
{userQuery.isPending ? (
加载中…
) : !user ? (
未找到用户信息
) : ( 账号基础 个人资料 服务事项 ({userServices.length}) {/* TAB 1: ACCOUNT BASIC */} {/* Status overview */}
{user.status ? '正常启用' : '已禁用'} {user.is_robot ? ( 机器人账号 ) : ( 真人账号 )} {user.sid_display && ( SID: {user.sid_display} )}
{/* Account Basic Info */}

账号基础属性

用户名
{user.username ?? '—'}
显示名称
{user.display_name ?? '—'}
SID
{user.sid ?? '—'}
专业领域
{user.expertise ?? '—'}
{/* Contact & Verification */}

联系方式与验证

邮箱
{user.email ?? '—'}
{user.email && ( {user.email_verified_at ? ( <> 已验证 ) : ( <> 未验证 )} )}
手机号
{user.phone ?? '—'}
{user.phone && ( {user.phone_verified_at ? ( <> 已验证 ) : ( <> 未验证 )} )}
{/* Roles */}

已分配角色

{onAssignRoles && ( )}
{user.roles && user.roles.length > 0 ? ( user.roles.map((role) => ( {role} )) ) : ( 未分配任何角色 )}
{/* Timestamps */}
注册时间: {new Date(user.created_at).toLocaleString('zh-CN')}
{user.updated_at && (
更新时间: {new Date(user.updated_at).toLocaleString('zh-CN')}
)}
{/* TAB 2: DETAILED INFO */} {userInfoQuery.isPending ? (
加载个人资料中…
) : ( <> {/* Profile Headline & Bio */}

个人名片与简介

{userInfo?.profile?.computed_fullname ?? user.display_name ?? '—'} {userInfo?.profile?.gender && ( {userInfo.profile.gender} )}
{userInfo?.profile?.headline && (
{userInfo.profile.headline}
)} {userInfo?.profile?.bio ? (
{userInfo.profile.bio}
) : (
暂无个人简介
)}
{/* Region & Timezone */}

地区与语言偏好

国家/地区
{user.country_code ?? '—'}
城市
{user.city ?? '—'}
时区
{user.timezone ?? '—'}
语言偏好
{user.locale ?? '—'}
{/* Careers / Work Experience */}

工作经历 ({(userInfo?.careers ?? []).length})

{userInfo?.careers && userInfo.careers.length > 0 ? (
{userInfo.careers.map((career, idx) => (
{career.company_name ?? '未知公司'} {career.is_current && 在职}
{career.position} {career.department ? `· ${career.department}` : ''}
{(career.start_date || career.end_date) && (
{career.start_date ?? '—'} ~ {career.is_current ? '至今' : career.end_date ?? '—'}
)} {career.description && (
{career.description}
)}
))}
) : (
暂无工作经历记录
)}
{/* Education */}

教育经历 ({(userInfo?.educations ?? []).length})

{userInfo?.educations && userInfo.educations.length > 0 ? (
{userInfo.educations.map((edu, idx) => (
{edu.school_name ?? '学校'} {edu.degree && {edu.degree}}
{edu.major &&
{edu.major}
} {(edu.start_date || edu.end_date) && (
{edu.start_date ?? '—'} ~ {edu.is_current ? '至今' : edu.end_date ?? '—'}
)}
))}
) : (
暂无教育经历记录
)}
{/* Honors */}

荣誉与奖项 ({(userInfo?.honors ?? []).length})

{userInfo?.honors && userInfo.honors.length > 0 ? (
{userInfo.honors.map((honor, idx) => (
{honor.title ?? '荣誉奖项'} {honor.date && {honor.date}}
{honor.issuer &&
颁发单位:{honor.issuer}
} {honor.description &&
{honor.description}
}
))}
) : (
暂无荣誉与奖项记录
)}
{/* Addresses */}

常用服务地址 ({(userInfo?.addresses ?? []).length})

{userInfo?.addresses && userInfo.addresses.length > 0 ? (
{userInfo.addresses.map((addr, idx) => (
{addr.contact_name ?? '联系人'} {addr.contact_phone_number && ( {addr.contact_phone_number} )}
{[addr.province, addr.city, addr.district, addr.address_line] .filter(Boolean) .join(' ')}
))}
) : (
暂无保存的服务地址
)}
)}
{/* TAB 3: SERVICES */} {userServicesQuery.isPending ? (
加载服务事项中…
) : userServices.length > 0 ? (

专长项目与服务变体 ({userServices.length})

{userServices.map((exp) => (
{exp.name}
{exp.tags && exp.tags.length > 0 && (
{exp.tags.map((tag) => ( {tag} ))}
)}
{exp.description && (

{exp.description}

)}
{/* Service Variants */} {exp.services && exp.services.length > 0 && (
包含的服务变体
{exp.services.map((svc) => (
{svc.service_type === 'onsite' ? '上门服务' : svc.service_type === 'online' ? '在线服务' : svc.service_type === 'remote' ? '远程协助' : svc.service_type ?? '服务'} {svc.charge_type === 'time' ? '按时计费' : svc.charge_type === 'fixed' ? '固定价格' : svc.charge_type === 'quote' ? '按需报价' : svc.charge_type}
{svc.duration && (
预估服务时长: {svc.duration} 分钟
)}
{svc.price != null ? `${svc.currency_code ?? '¥'} ${(svc.price / 100).toFixed(2)}` : '按需报价'}
{svc.enabled ? '已上架' : '已下架'}
))}
)}
))}
) : provider ? ( /* Fallback to provider overview if userServices is empty */

专长服务商资格

在线状态
{provider.status === 'online' ? '在线' : provider.status === 'busy' ? '忙碌' : provider.status === 'offline' ? '离线' : provider.status}
实名认证
{provider.is_verified ? '已认证' : '未认证'}
评分
{provider.rating ? provider.rating.toFixed(1) : '暂无评分'}
已完结订单
{provider.completed_jobs ?? 0} 单
) : (

暂无服务事项

该用户尚未创建或发布任何专长项目与服务变体。

)} {/* Provider Profile Settings if available */} {provider && (

专长服务商抢单与派单参数

自动抢单模式
{provider.dispatch_setting?.auto_grab_enabled ? '已开启' : '已关闭'}
今日接单量
{provider.dispatch_setting?.accepted_today ?? 0} /{' '} {provider.dispatch_setting?.daily_accept_cap ?? '无限制'}
{provider.dispatch_setting?.min_price != null && (
最低接单起价
¥{provider.dispatch_setting.min_price}
)} {provider.dispatch_setting?.max_radius_meters != null && (
服务接单半径
{(provider.dispatch_setting.max_radius_meters / 1000).toFixed(1)} km
)}
)}
)}
) }