feat: 电商工作台进度与生成记录健壮性优化
This commit is contained in:
+30
-46
@@ -1,4 +1,4 @@
|
||||
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
BugOutlined,
|
||||
CheckCircleFilled,
|
||||
@@ -20,9 +20,7 @@ import {
|
||||
import ErrorBoundary from "./components/ErrorBoundary";
|
||||
import ToastContainer from "./components/toast/ToastContainer";
|
||||
import { toast } from "./components/toast/toastStore";
|
||||
import EcommercePage from "./features/ecommerce/EcommercePage";
|
||||
import { flushPendingGenerationRecords } from "./api/generationRecordClient";
|
||||
import { ossAssets } from "./data/ossAssets";
|
||||
import { keyServerClient } from "./api/keyServerClient";
|
||||
import { setUserMaxConcurrency } from "./api/generationConcurrency";
|
||||
import {
|
||||
@@ -38,6 +36,8 @@ import { useAppStore, useSessionStore } from "./stores";
|
||||
import type { WebUserSession } from "./types";
|
||||
import "./styles/ecommerce-standalone.css";
|
||||
|
||||
const EcommercePage = lazy(() => import("./features/ecommerce/EcommercePage"));
|
||||
|
||||
type AuthMode = "login" | "register";
|
||||
type AuthMethod = "account" | "email" | "phone";
|
||||
|
||||
@@ -51,17 +51,6 @@ interface LocalProfilePageProps {
|
||||
onLogout: () => void;
|
||||
}
|
||||
|
||||
const profileWorks = [
|
||||
{ title: "主图套图生成", desc: "电商主图与场景图自动生成", image: ossAssets.ecommerce.templateCases[0], type: "图像", time: "6/9 18:13" },
|
||||
{ title: "A+详情页设计", desc: "产品卖点与长图详情版式", image: ossAssets.ecommerce.templateCases[1], type: "图像", time: "6/9 10:11" },
|
||||
{ title: "短视频广告", desc: "产品展示短视频脚本与画面", image: ossAssets.ecommerce.productSet.hosting, type: "视频", time: "6/9 10:05" },
|
||||
{ title: "模特图生成", desc: "服饰商品真人上身展示", image: ossAssets.ecommerce.tryOn.tryA, type: "图像", time: "6/9 10:03" },
|
||||
{ title: "商品场景图", desc: "按平台比例输出营销素材", image: ossAssets.ecommerce.detail.gridA, type: "图像", time: "6/9 10:01" },
|
||||
{ title: "高度复刻", desc: "参考图结构复刻与商品替换", image: ossAssets.ecommerce.detail.gridB, type: "图像", time: "6/9 09:39" },
|
||||
{ title: "详情模块", desc: "功能卖点、参数和包装模块", image: ossAssets.ecommerce.detail.gridC, type: "图像", time: "6/8 21:20" },
|
||||
{ title: "平台素材", desc: "淘宝/天猫投放图批量生成", image: ossAssets.ecommerce.detail.gridD, type: "图像", time: "6/8 18:26" },
|
||||
];
|
||||
|
||||
function LocalAvatar({ session, size = "md" }: { session: WebUserSession; size?: "sm" | "md" | "lg" }) {
|
||||
const displayName = session.user.displayName || session.user.username || "用户";
|
||||
const label = displayName.trim().slice(0, 1).toUpperCase() || "用";
|
||||
@@ -75,9 +64,9 @@ function LocalAvatar({ session, size = "md" }: { session: WebUserSession; size?:
|
||||
|
||||
function LocalProfilePage({ session, balance, imageCount, videoCount, onBack, onBugFeedback, onLogout }: LocalProfilePageProps) {
|
||||
const displayName = session.user.displayName || session.user.username || "用户";
|
||||
const workCount = Math.max(imageCount + videoCount, profileWorks.length);
|
||||
const projectCount = Math.max(1, Math.round(workCount / 18));
|
||||
const assetCount = Math.max(1, Math.round(workCount / 20));
|
||||
const workCount = Math.max(imageCount + videoCount, 0);
|
||||
const projectCount = 0;
|
||||
const assetCount = 0;
|
||||
|
||||
return (
|
||||
<section className="local-profile-page">
|
||||
@@ -142,22 +131,15 @@ function LocalProfilePage({ session, balance, imageCount, videoCount, onBack, on
|
||||
<header>
|
||||
<div>
|
||||
<strong>代表作</strong>
|
||||
<span>最近完成的高质量生成内容</span>
|
||||
<span>后续将展示接口返回的真实作品</span>
|
||||
</div>
|
||||
<em>{workCount} 项</em>
|
||||
</header>
|
||||
<div className="local-profile-work-grid">
|
||||
{profileWorks.map((work) => (
|
||||
<article key={`${work.title}-${work.time}`} className="local-profile-work-card">
|
||||
<img src={work.image} alt="" />
|
||||
<div>
|
||||
<span>{work.type}</span>
|
||||
<strong>{work.title}</strong>
|
||||
<p>{work.desc}</p>
|
||||
<em>已完成 · {work.time}</em>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
<div className="local-profile-work-grid local-profile-work-grid--empty">
|
||||
<div className="local-profile-empty">
|
||||
<strong>暂无代表作数据</strong>
|
||||
<span>作品接口接入后,这里会显示你的真实生成内容。</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
@@ -184,7 +166,6 @@ function App() {
|
||||
const [sessionNotice, setSessionNotice] = useState<string | null>(null);
|
||||
const [profileMenuOpen, setProfileMenuOpen] = useState(false);
|
||||
const [currentPage, setCurrentPage] = useState<"workspace" | "profile">("workspace");
|
||||
const [workspaceKey, setWorkspaceKey] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
void loadDarkGreenTheme();
|
||||
@@ -339,7 +320,7 @@ function App() {
|
||||
const balance = Math.max(usage.balanceCents, 0) / 100;
|
||||
const displayName = session?.user.displayName || session?.user.username || "用户";
|
||||
const actualWorkCount = Math.max(usage.imageUsed + usage.videoUsed, 0);
|
||||
const shownWorkCount = Math.max(actualWorkCount, profileWorks.length);
|
||||
const shownWorkCount = actualWorkCount;
|
||||
|
||||
const avatarMenuStats = useMemo(
|
||||
() => [
|
||||
@@ -360,7 +341,6 @@ function App() {
|
||||
const handleOpenWorkspace = () => {
|
||||
setProfileMenuOpen(false);
|
||||
setCurrentPage("workspace");
|
||||
setWorkspaceKey((k) => k + 1);
|
||||
};
|
||||
|
||||
const handleBugFeedback = () => {
|
||||
@@ -447,17 +427,22 @@ function App() {
|
||||
</header>
|
||||
|
||||
<main className="ecommerce-standalone__content">
|
||||
{currentPage === "profile" && session ? (
|
||||
<LocalProfilePage
|
||||
session={session}
|
||||
balance={balance}
|
||||
imageCount={usage.imageUsed}
|
||||
videoCount={usage.videoUsed}
|
||||
onBack={handleOpenWorkspace}
|
||||
onBugFeedback={handleBugFeedback}
|
||||
onLogout={handleLogout}
|
||||
/>
|
||||
) : (
|
||||
{session ? (
|
||||
<div className="ecommerce-standalone__page" hidden={currentPage !== "profile"}>
|
||||
<LocalProfilePage
|
||||
session={session}
|
||||
balance={balance}
|
||||
imageCount={usage.imageUsed}
|
||||
videoCount={usage.videoUsed}
|
||||
onBack={handleOpenWorkspace}
|
||||
onBugFeedback={handleBugFeedback}
|
||||
onLogout={handleLogout}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 工作台常驻挂载,仅用 hidden 切换。切到个人中心时不卸载,
|
||||
生成任务、进度动画、已上传图片等本地状态全部保留,切回即继续。 */}
|
||||
<div className="ecommerce-standalone__page" hidden={Boolean(session) && currentPage === "profile"}>
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
@@ -468,7 +453,6 @@ function App() {
|
||||
}
|
||||
>
|
||||
<EcommercePage
|
||||
key={workspaceKey}
|
||||
projects={[]}
|
||||
isAuthenticated={Boolean(session)}
|
||||
onStartCreate={() => undefined}
|
||||
@@ -482,7 +466,7 @@ function App() {
|
||||
/>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{authOpen ? (
|
||||
|
||||
Reference in New Issue
Block a user