"use client" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { applyCurrentUserVerification, getCurrentUserForLogin, listCurrentUserVerifications, uploadFile, } from "@/lib/api" import { toApiError } from "@/lib/errors" import { notifyInfo, notifySuccess } from "@/lib/toast" import type { UserRole } from "@/lib/types" import { useAuthStore } from "@/store/auth" import { CheckCircle, Clock, ShieldCheck, Upload } from "lucide-react" import { useEffect, useState } from "react" type MaterialKey = "idCardFront" | "idCardBack" | "gameScreenshot" function MaterialUpload({ label, value, uploading, onSelect, }: { label: string value: string uploading: boolean onSelect: (file: File) => Promise }) { return ( ) } export default function VerifyPage() { const [verifyRole, setVerifyRole] = useState("") const [idCardFront, setIdCardFront] = useState("") const [idCardBack, setIdCardBack] = useState("") const [gameScreenshot, setGameScreenshot] = useState("") const [uploading, setUploading] = useState(null) const [submitting, setSubmitting] = useState(false) const [verificationRecords, setVerificationRecords] = useState< Awaited> >([]) const verificationStatus = useAuthStore((state) => state.verificationStatus) const verificationReasons = useAuthStore((state) => state.verificationReasons) const verifiedRoles = useAuthStore((state) => state.verifiedRoles) const login = useAuthStore((state) => state.login) useEffect(() => { let cancelled = false void listCurrentUserVerifications() .then((records) => { if (!cancelled) setVerificationRecords(records) }) .catch((error) => { if (!cancelled) notifyInfo(toApiError(error).msg) }) return () => { cancelled = true } }, []) const uploadMaterial = async (key: MaterialKey, file: File) => { setUploading(key) try { const url = await uploadFile(file, "verification") if (key === "idCardFront") setIdCardFront(url) if (key === "idCardBack") setIdCardBack(url) if (key === "gameScreenshot") setGameScreenshot(url) notifySuccess("材料已上传") } catch (error) { notifyInfo(toApiError(error).msg) } finally { setUploading(null) } } const submitVerification = async (role: UserRole) => { if (!idCardFront || !idCardBack) { notifyInfo("请先上传身份证正反面") return } setSubmitting(true) try { await applyCurrentUserVerification({ role, materials: { idCardFront, idCardBack, gameScreenshots: gameScreenshot ? [gameScreenshot] : undefined, }, }) const [records, updated] = await Promise.all([ listCurrentUserVerifications(), getCurrentUserForLogin(), ]) setVerificationRecords(records) login(updated, updated.verifiedRoles ?? [updated.role]) notifySuccess("认证申请已提交") } catch (error) { notifyInfo(toApiError(error).msg) } finally { setSubmitting(false) } } const roleMeta = [ { role: "player", label: "打手认证" }, { role: "owner", label: "店主认证" }, ] as const const statusFor = (role: UserRole) => { const record = verificationRecords.find((item) => item.role === role) return record?.status ?? verificationStatus[role] } const reasonFor = (role: UserRole) => { const record = verificationRecords.find((item) => item.role === role) return record?.rejectReason ?? verificationReasons[role] } return (

身份认证

认证说明
通过身份认证后,你可以成为打手或店主,开始接单或经营店铺
认证信息仅用于平台审核,不会对外展示
认证状态 {roleMeta.map((item) => { const status = statusFor(item.role) const reason = reasonFor(item.role) return (
{item.label} {status === "approved" || verifiedRoles.includes(item.role) ? ( 已通过 ) : status === "pending" ? ( 审核中 ) : status === "rejected" ? ( 未通过 ) : ( 未申请 )}
{status === "rejected" && (

驳回原因:{reason}

)} {status === "rejected" && ( )}
) })}
申请认证
uploadMaterial("idCardFront", file)} /> uploadMaterial("idCardBack", file)} /> uploadMaterial("gameScreenshot", file)} />

身份证正反面为必填,游戏截图可用于打手认证

) }