diff --git a/src/features/profile/ProfilePage.tsx b/src/features/profile/ProfilePage.tsx index 9a06565..e443091 100644 --- a/src/features/profile/ProfilePage.tsx +++ b/src/features/profile/ProfilePage.tsx @@ -1,7 +1,10 @@ import { CameraOutlined, + CheckOutlined, CheckCircleFilled, + CloseOutlined, DeleteOutlined, + EditOutlined, LockOutlined, MailOutlined, MobileOutlined, @@ -135,6 +138,48 @@ function mapAssetToSavedItem(asset: Awaited> }; } +function formatProfileDate(value: string | null | undefined): string { + if (!value) return "刚刚"; + const date = new Date(value); + if (Number.isNaN(date.getTime())) return value; + + return new Intl.DateTimeFormat("zh-CN", { + month: "numeric", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }).format(date); +} + +function formatTaskType(type: WebGenerationPreviewTask["type"]): string { + const labels: Record = { + image: "图像", + video: "视频", + agent: "智能体", + "digital-human": "数字人", + "character-mix": "角色融合", + }; + return labels[type] || type; +} + +function formatTaskStatus(status: WebGenerationPreviewTask["status"]): string { + const labels: Record = { + queued: "排队中", + running: "生成中", + completed: "已完成", + failed: "失败", + }; + return labels[status] || status; +} + +function formatAssetStatus(status: string | undefined): string { + const normalized = String(status || "").toLowerCase(); + if (normalized === "completed" || normalized === "ready" || normalized === "success") return "可用"; + if (normalized === "running" || normalized === "processing") return "处理中"; + if (normalized === "failed" || normalized === "error") return "失败"; + return status || "资产"; +} + function ProfilePage({ session, usage, @@ -182,6 +227,9 @@ function ProfilePage({ const [profileNotice, setProfileNotice] = useState(null); const [localAvatarUrl, setLocalAvatarUrl] = useState(() => session?.user.avatarUrl || readLocalProfileValue(userId, "avatar")); const [profileBio, setProfileBio] = useState(() => session?.user.bio || readLocalProfileValue(userId, "bio")); + const [isBioEditing, setIsBioEditing] = useState(false); + const [bioEditBackup, setBioEditBackup] = useState(""); + const [bioStatusNotice, setBioStatusNotice] = useState(null); const [bannerUrl, setBannerUrl] = useState(() => session?.user.backgroundUrl || readLocalProfileValue(userId, "background")); const completedTasks = tasks.filter((task) => task.status === "completed"); @@ -497,8 +545,29 @@ function ProfilePage({ void syncProfilePatch({ bio: nextBio || null }); }; + const startBioEdit = () => { + setBioEditBackup(profileBio); + setBioStatusNotice(null); + setIsBioEditing(true); + }; + + const confirmBioEdit = () => { + handleBioBlur(); + setIsBioEditing(false); + setBioStatusNotice("个性签名已保存"); + }; + + const cancelBioEdit = () => { + setProfileBio(bioEditBackup); + setIsBioEditing(false); + setBioStatusNotice(null); + }; + const renderEmptyState = (text: string, actionLabel: string, action: () => void) => (
+

{text}

{displayName} -