import { Message } from "@arco-design/web-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { createCharacter } from "@/api/api"; import AvatarCropModal from "@/components/AvatarCropModal"; import { useCopyText } from "@/hooks/useCopyText"; import "./index.scss"; import { ROUTES } from "@/constants"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; const AGREEMENT_CHECKBOX_OFF_ICON = new URL("/src/assets/images/ic_checkbox_agreement_off.png", import.meta.url).href; const AGREEMENT_CHECKBOX_ON_ICON = new URL("/src/assets/images/ic_checkbox_agreement_on.png", import.meta.url).href; type CreateRoleModalProps = { visible: boolean; taskList: any[]; initialTaskId?: string | null; onClose: () => void; onCreated?: (taskId: string) => void; }; function formatCreateDate(task: any): string { const raw = task?.createTime; if (raw == null || raw === "") return ""; const numeric = Number(raw); const millis = Number.isFinite(numeric) ? (String(raw).length === 10 ? numeric * 1000 : numeric) : Number.NaN; const date = Number.isFinite(millis) ? new Date(millis) : new Date(String(raw)); if (Number.isNaN(date.getTime())) return ""; const year = date.getFullYear(); const month = `${date.getMonth() + 1}`.padStart(2, "0"); const day = `${date.getDate()}`.padStart(2, "0"); const hour = `${date.getHours()}`.padStart(2, "0"); const minute = `${date.getMinutes()}`.padStart(2, "0"); return `${year}-${month}-${day} ${hour}:${minute}`; } export default function CreateRoleModal({ visible, taskList, initialTaskId, onClose, onCreated }: CreateRoleModalProps) { const { t } = useTranslation(); const navigate = useNavigate(); const [activeTaskItem, setActiveTaskItem] = useState(null); const [avatar, setAvatar] = useState(activeTaskItem?.resultList?.[0]?.images?.[0] ?? ""); const [avatarOriginImage, setAvatarOriginImage] = useState(activeTaskItem?.resultList?.[0]?.images?.[0] ?? ""); const [cropModalImage, setCropModalImage] = useState(""); const [characterName, setCharacterName] = useState(""); const [description, setDescription] = useState(""); const [isPublic, setIsPublic] = useState(false); const [agreementChecked, setAgreementChecked] = useState(false); const [creating, setCreating] = useState(false); const thumbListRef = useRef(null); const copyText = useCopyText(); const userCreatedCharacter = activeTaskItem?.userCreatedCharacter; const hasCreatedCharacter = Number(userCreatedCharacter?.id) > 0; useEffect(() => { if (visible) return; setActiveTaskItem(null); setAvatar(""); setAvatarOriginImage(""); setCropModalImage(""); setCharacterName(""); setDescription(""); setIsPublic(false); setAgreementChecked(false); setCreating(false); }, [visible]); useEffect(() => { if (!visible) return; if (initialTaskId) { const selectedTask = taskList.find((task) => String(task.id) === String(initialTaskId)); if (selectedTask) { setActiveTaskItem(selectedTask); return; } } setActiveTaskItem(taskList[0] ?? null); }, [visible, initialTaskId, taskList]); useEffect(() => { if (!visible) return; if (!activeTaskItem) return; const existed = taskList.some((task) => String(task.id) === String(activeTaskItem.id)); if (!existed) { setActiveTaskItem(taskList[0] ?? null); return; } const nextTask = taskList.find((task) => String(task.id) === String(activeTaskItem.id)); if (nextTask && nextTask !== activeTaskItem) { setActiveTaskItem(nextTask); } }, [visible, taskList, activeTaskItem]); useEffect(() => { const nextOriginImage = hasCreatedCharacter ? (userCreatedCharacter?.avatar ?? "") : (activeTaskItem?.resultList?.[0]?.images?.[0] ?? ""); setCropModalImage(""); setAvatarOriginImage(nextOriginImage); setAvatar(nextOriginImage); setCharacterName(hasCreatedCharacter ? (userCreatedCharacter?.characterName ?? "") : ""); setDescription(hasCreatedCharacter ? (userCreatedCharacter?.description ?? "") : ""); }, [activeTaskItem, hasCreatedCharacter, userCreatedCharacter?.avatar, userCreatedCharacter?.characterName, userCreatedCharacter?.description]); const openCropModal = useCallback(() => { if (!avatarOriginImage) return; const rawAvatarOriginImage = avatarOriginImage.split("#")[0]; setCropModalImage(`${rawAvatarOriginImage}#crop=${Date.now()}`); }, [avatarOriginImage]); const handleCreateCharacter = useCallback(async () => { if (hasCreatedCharacter) { Message.warning(t("pages.charactersCreate.createRoleModal.alreadyCreated")); return; } if (!avatar) { Message.warning(t("pages.charactersCreate.createRoleModal.uploadAvatarFirst")); return; } if (!characterName.trim()) { Message.warning(t("pages.charactersCreate.createRoleModal.inputName")); return; } if (!description.trim()) { Message.warning(t("pages.charactersCreate.createRoleModal.inputDescription")); return; } if (!agreementChecked) { Message.warning(t("pages.charactersCreate.createRoleModal.agreementRequired")); return; } if (!activeTaskItem?.id) { Message.warning(t("pages.charactersCreate.createRoleModal.taskNotFound")); return; } setCreating(true); try { await createCharacter({ taskId: activeTaskItem.id, avatar, characterName, description, isPublic, }); Message.success(t("pages.charactersCreate.createRoleModal.createSuccess")); onCreated?.(String(activeTaskItem.id)); onClose(); navigate(ROUTES.CHARACTERS); } catch { Message.error(t("pages.charactersCreate.createRoleModal.createFailed")); } finally { setCreating(false); } }, [activeTaskItem?.id, agreementChecked, avatar, characterName, description, hasCreatedCharacter, isPublic, navigate, onClose, onCreated, t]); if (!visible) return null; const handleScrollThumbList = (direction: "left" | "right") => { const container = thumbListRef.current; if (!container) return; const offset = direction === "left" ? -121 : 121; container.scrollBy({ left: offset, behavior: "smooth" }); }; return (
{activeTaskItem?.resultList?.[0]?.images?.[0] ? : null}
{taskList.map((task, index) => { const taskId = String(task.id ?? index); const thumbSrc = task.resultList[0]?.images?.[0] ?? ""; const isActive = String(task.id) === String(activeTaskItem?.id); return ( ); })}
{ avatar ? : }
setCharacterName(event.target.value)} placeholder={t("pages.charactersCreate.createRoleModal.required")} disabled={hasCreatedCharacter} />