diff --git a/src/components/AppShell.tsx b/src/components/AppShell.tsx index 700938b..72e1776 100644 --- a/src/components/AppShell.tsx +++ b/src/components/AppShell.tsx @@ -90,7 +90,7 @@ function AppShell({ "avatarConsole", "characterMix", ] as WebViewKey[]; - const showPageScrollActions = showFloatingNav && !toolSurfaceViews.includes(activeView); + const showPageScrollActions = false; const visibleNavItems = useMemo( () => { diff --git a/src/features/ecommerce/EcommercePage.tsx b/src/features/ecommerce/EcommercePage.tsx index 9b574c3..c3b6416 100644 --- a/src/features/ecommerce/EcommercePage.tsx +++ b/src/features/ecommerce/EcommercePage.tsx @@ -2062,6 +2062,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) { 上传商品图,AI 即刻生成 符合多电商平台规范 的高转化率商品素材。 +
+ {selectedCloneOutput.label} + {platform} + {market} + {language} + {formatRatioDisplayValue(ratio)} +
{status === "done" ? ( diff --git a/src/features/profile/ProfilePage.tsx b/src/features/profile/ProfilePage.tsx index 1916f3d..1c92533 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, @@ -134,6 +137,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, @@ -187,6 +232,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"); @@ -195,6 +243,9 @@ function ProfilePage({ const packageLabel = session?.user.activePackages?.[0]?.name || "按量积分"; const avatarUrl = session?.user.avatarUrl || localAvatarUrl || null; const displayedBio = profileBio.trim() || "这个人还没有填写个性签名"; + const emailLooksValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim()); + const phoneLooksValid = /^1[3-9]\d{9}$/.test(phone.trim()); + const passwordLooksReady = password.length >= (mode === "register" ? 6 : 1); useEffect(() => { setLocalAvatarUrl(session?.user.avatarUrl || readLocalProfileValue(userId, "avatar")); @@ -525,8 +576,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} -