chore: migrate frontend assets to OSS and same-origin APIs
This commit is contained in:
@@ -16,10 +16,10 @@ import WorkspacePageShell from "../../components/WorkspacePageShell";
|
||||
import OptimizedImage from "../../components/OptimizedImage";
|
||||
import { EmptyState } from "../../components/EmptyState";
|
||||
import { cloneWorkflow, createBlankWorkflow } from "../../data/workflows";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
import type { WebCanvasWorkflow, WebProjectSummary } from "../../types";
|
||||
import { getCommunityCaseCover, getWorkflowFromCase, shouldShowInCanvasCommunity } from "./communityCaseUtils";
|
||||
import { ossThumb } from "../../utils/ossImageOptimize";
|
||||
const OSS_MUBAN = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban";
|
||||
|
||||
interface CommunityPageProps {
|
||||
projects: WebProjectSummary[];
|
||||
@@ -31,23 +31,12 @@ interface CommunityPageProps {
|
||||
onRequireLogin?: (action: string) => boolean | void;
|
||||
}
|
||||
|
||||
const communityCardImages = [
|
||||
`${OSS_MUBAN}/dianshang1.png`,
|
||||
`${OSS_MUBAN}/dianshang2.png`,
|
||||
`${OSS_MUBAN}/dianshang3.png`,
|
||||
`${OSS_MUBAN}/wechat-7.png`,
|
||||
`${OSS_MUBAN}/wechat-8.png`,
|
||||
`${OSS_MUBAN}/wechat-9.png`,
|
||||
];
|
||||
const communityCardImages = ossAssets.community.cardImages;
|
||||
|
||||
const SLIDE_INTERVAL = 3000;
|
||||
const CAROUSEL_VISIBLE_COUNT = 3;
|
||||
const MANUAL_PAUSE_DURATION = 2000;
|
||||
const COMMUNITY_CAROUSEL_VIDEOS = [
|
||||
"https://stringtest.oss-cn-hangzhou.aliyuncs.com/test3.mp4",
|
||||
"https://stringtest.oss-cn-hangzhou.aliyuncs.com/test4.mp4",
|
||||
"https://stringtest.oss-cn-hangzhou.aliyuncs.com/test6.mp4",
|
||||
];
|
||||
const COMMUNITY_CAROUSEL_VIDEOS = ossAssets.community.carouselVideos;
|
||||
|
||||
function buildWorkflowFromServerCase(item: ServerCommunityCase, fallback: WebCanvasWorkflow): WebCanvasWorkflow {
|
||||
const workflow = getWorkflowFromCase(item);
|
||||
|
||||
@@ -13,12 +13,8 @@ import {
|
||||
SkinOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useEffect, useRef, useState, type CSSProperties, type ChangeEvent, type DragEvent, type ReactNode } from "react";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
import { EcommerceProgressBar } from "./EcommerceProgressBar";
|
||||
|
||||
const OSS_MUBAN = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban";
|
||||
const ecommerceGenerated = `${OSS_MUBAN}/ecommerce-carousel-generated.png`;
|
||||
const ecommerceSlide4 = `${OSS_MUBAN}/slide-4.png`;
|
||||
const ecommerceSlide5 = `${OSS_MUBAN}/slide-5.png`;
|
||||
import ImageMentionMenu, { getImageMentionQuery, insertImageMentionValue, type MentionImageOption } from "./ImageMentionMenu";
|
||||
import EcommerceVideoWorkspace from "./EcommerceVideoWorkspace";
|
||||
import EcommerceVideoHistoryPanel from "./panels/EcommerceVideoHistoryPanel";
|
||||
@@ -72,6 +68,7 @@ interface CloneResult {
|
||||
id: string;
|
||||
src: string;
|
||||
label: string;
|
||||
type?: "image" | "video";
|
||||
}
|
||||
|
||||
interface CloneSavedSetting {
|
||||
@@ -597,15 +594,12 @@ const tryOnModelOptions = {
|
||||
ethnicity: ["欧美白人", "亚洲人", "拉美裔", "非洲裔"],
|
||||
body: ["标准", "高挑", "微胖", "运动"],
|
||||
};
|
||||
const sampleResults = [ecommerceSlide4, ecommerceGenerated, ecommerceSlide5];
|
||||
const productSetAssets = {
|
||||
main: "https://xiuxiu-pro.meitudata.com/poster/6e3eebacad8d5e47e1896ee7d54827bc.png?imageView2/2/w/800/format/webp/q/80/ignore-error/1",
|
||||
scene: "https://xiuxiu-pro.meitudata.com/poster/21225fc86b28d9e4d85636483c67408e.png?imageView2/2/w/400/format/webp/q/80/ignore-error/1",
|
||||
model: "https://xiuxiu-pro.meitudata.com/poster/4b8e6d1bd0996be52822dd1fac73cffd.png?imageView2/2/w/400/format/webp/q/80/ignore-error/1",
|
||||
detail: "https://xiuxiu-pro.meitudata.com/poster/29dd195a450ee5a7f7451ded6680e969.png?imageView2/2/w/400/format/webp/q/80/ignore-error/1",
|
||||
selling: "https://xiuxiu-pro.meitudata.com/poster/66bdef541b67588e8db2a03b39dc815b.jpg?imageView2/2/w/400/format/webp/q/80/ignore-error/1",
|
||||
hosting: "https://xiuxiu-pro-new.meitudata.com/poster/50c17a98c77fac4d0523c8cbdf0d33ca.jpg?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
};
|
||||
const sampleResults = [
|
||||
ossAssets.ecommerce.slides.slide4,
|
||||
ossAssets.ecommerce.generated,
|
||||
ossAssets.ecommerce.slides.slide5,
|
||||
];
|
||||
const productSetAssets = ossAssets.ecommerce.productSet;
|
||||
const productSetPreviewCards = [
|
||||
{ id: "main", label: "01 主图 (白底/合规)", src: productSetAssets.main },
|
||||
{ id: "scene", label: "02 场景展示", src: productSetAssets.scene },
|
||||
@@ -613,21 +607,7 @@ const productSetPreviewCards = [
|
||||
{ id: "detail", label: "04 细节说明", src: productSetAssets.detail },
|
||||
{ id: "selling", label: "05 卖点详解", src: productSetAssets.selling },
|
||||
];
|
||||
const tryOnAssets = {
|
||||
dressA: "https://xiuxiu-pro-new.meitudata.com/poster/133ca2d6c13bac6cfaa11fa29a155551.jpg?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
dressB: "https://xiuxiu-pro-new.meitudata.com/poster/a661006820e888d9df13023075096e94.jpg?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
modelWoman: "https://xiuxiu-pro-new.meitudata.com/poster/f806c6afaf6f38f634c156c5b6058201.png?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
modelMan: "https://xiuxiu-pro-new.meitudata.com/poster/8c26503c67dc695e25e420e48caf4cde.png?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
modelAsian: "https://xiuxiu-pro-new.meitudata.com/poster/0f2a7c92707312ec74647d66f15a6ef9.jpg?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
tryA: "https://xiuxiu-pro-new.meitudata.com/poster/7f77e0866f05ff723959e1f48830713c.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
tryB: "https://xiuxiu-pro-new.meitudata.com/poster/0b951004eabcdd7cae595dfdb4c7f8c3.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
jacket: "https://xiuxiu-pro-new.meitudata.com/poster/fdbf10b4c92af5b1986444cdd9affaa5.png?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
jacketResultA: "https://xiuxiu-pro-new.meitudata.com/poster/b1152bb292323b87696dd2f6e518e818.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
jacketResultB: "https://xiuxiu-pro-new.meitudata.com/poster/1c1e757702108fef92d85be0c2802c01.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
hat: "https://xiuxiu-pro-new.meitudata.com/poster/278af735b076ab812888802d3e3db0b8.jpg?imageView2/2/w/280/format/webp/q/80/ignore-error/1",
|
||||
hatResultA: "https://xiuxiu-pro-new.meitudata.com/poster/a3ba241b7aa6060869b096d3f10e5db4.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
hatResultB: "https://xiuxiu-pro-new.meitudata.com/poster/01ed1ae80a187c70c682bb6d0ec6fa68.jpg?imageView2/2/w/345/format/webp/q/80/ignore-error/1",
|
||||
};
|
||||
const tryOnAssets = ossAssets.ecommerce.tryOn;
|
||||
|
||||
const tryOnCards = [
|
||||
{
|
||||
@@ -672,18 +652,7 @@ const detailModules = [
|
||||
const defaultDetailModuleIds: string[] = [];
|
||||
const defaultCloneDetailModuleIds = ["hero", "selling", "usage", "angle", "scene", "detail"];
|
||||
const cloneDetailModules = detailModules;
|
||||
const detailAssets = {
|
||||
productA: "https://xiuxiu-pro.meitudata.com/poster/182676711565ee98e20cf92d766d1643.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
productB: "https://xiuxiu-pro.meitudata.com/poster/ba6312cbc3a32ceb8966f9ea20b9ee9c.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
productC: "https://xiuxiu-pro.meitudata.com/poster/7ee5753a3141fa12cda155126c8225d3.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
longPage: "https://xiuxiu-pro.meitudata.com/poster/19ef313484fc87c9bdd3cd52ce2a5947.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridA: "https://xiuxiu-pro.meitudata.com/poster/e74e8d920ac0f87020f90457d42a7153.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridB: "https://xiuxiu-pro.meitudata.com/poster/1652064f17c5c2b32ce287244b505c15.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridC: "https://xiuxiu-pro.meitudata.com/poster/dd8abace327edf61d8a8e2d7db42cfbe.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridD: "https://xiuxiu-pro.meitudata.com/poster/7dc397f1cb76a35f7f0ed3c3ce78ba81.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridE: "https://xiuxiu-pro.meitudata.com/poster/1199bd8b968a5162752e1ee2b093d315.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
gridF: "https://xiuxiu-pro.meitudata.com/poster/7a8cdb3693418df9915741960f8f5aa8.png?imageView2/2/format/webp/q/80/ignore-error/1",
|
||||
};
|
||||
const detailAssets = ossAssets.ecommerce.detail;
|
||||
const detailProductSamples = [detailAssets.productA, detailAssets.productB, detailAssets.productC];
|
||||
const detailGridSamples = [detailAssets.gridA, detailAssets.gridB, detailAssets.gridC, detailAssets.gridD, detailAssets.gridE, detailAssets.gridF];
|
||||
|
||||
@@ -866,13 +835,13 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
const cloneSetTotal = Object.values(cloneSetCounts).reduce((sum, value) => sum + value, 0);
|
||||
const canGenerateSet = setImages.length > 0 && productSetStatus !== "generating";
|
||||
const canGenerate = (cloneOutput === "video-outfit"
|
||||
? videoOutfitVideoFile && videoOutfitRefFile
|
||||
? Boolean(videoOutfitVideoFile && videoOutfitRefFile)
|
||||
: productImages.length > 0) && status !== "generating";
|
||||
const canGenerateTryOn = garmentImages.length > 0 && tryOnStatus !== "generating" && tryOnStatus !== "modeling";
|
||||
const canGenerateDetail = detailProductImages.length > 0 && detailStatus !== "generating";
|
||||
const cloneVideoDurationProgress =
|
||||
((cloneVideoDuration - cloneVideoDurationMin) / (cloneVideoDurationMax - cloneVideoDurationMin)) * 100;
|
||||
const cloneVideoDurationStyle = {
|
||||
const cloneVideoDurationStyle: CSSProperties = {
|
||||
"--clone-video-duration-progress": `${cloneVideoDurationProgress}%`,
|
||||
} as CSSProperties;
|
||||
|
||||
@@ -1487,7 +1456,7 @@ function ProductClonePage(_props: ProductClonePageProps = {}) {
|
||||
pMarket: string,
|
||||
tryOnOptions?: { gender?: string; age?: string; ethnicity?: string; body?: string; appearance?: string; scenes?: string[]; smartScene?: boolean },
|
||||
statusFn?: (status: "generating" | "done" | "idle" | "failed") => void,
|
||||
resultFn?: (results: CloneImageItem[]) => void,
|
||||
resultFn?: (results: CloneResult[]) => void,
|
||||
): Promise<void> => {
|
||||
statusFn?.("generating");
|
||||
try {
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
import ecommerceCarouselGenerated from "../../assets/ecommerce-carousel-generated.png";
|
||||
import moreTemplateSlide1 from "../../assets/more-template-carousel/slide-1.jpg";
|
||||
import moreTemplateSlide2 from "../../assets/more-template-carousel/slide-2.jpg";
|
||||
import moreTemplateSlide3 from "../../assets/more-template-carousel/slide-3.jpg";
|
||||
import moreTemplateSlide4 from "../../assets/more-template-carousel/slide-4.png";
|
||||
import moreTemplateSlide5 from "../../assets/more-template-carousel/slide-5.gif";
|
||||
import ecommerceHeroSlide1 from "../../assets/ecommerce-hero-carousel/slide-1.webp";
|
||||
import ecommerceHeroSlide2 from "../../assets/ecommerce-hero-carousel/slide-2.webp";
|
||||
import ecommerceHeroSlide3 from "../../assets/ecommerce-hero-carousel/slide-3.webp";
|
||||
import ecommerceHeroSlide4 from "../../assets/ecommerce-hero-carousel/slide-4.webp";
|
||||
import ecommerceHeroSlide5 from "../../assets/ecommerce-hero-carousel/slide-5.webp";
|
||||
import ecommerceCarouselImage1 from "../../../tu/微信图片_20260514125332_8_2.png";
|
||||
import ecommerceCarouselImage2 from "../../../tu/微信图片_20260514125332_9_2.png";
|
||||
import ecommerceCarouselImage3 from "../../../tu/微信图片_20260514125332_7_2.png";
|
||||
import ecommerceCarouselImage4 from "../../../tu/微信图片_20260514125332_12_2.png";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
|
||||
const [
|
||||
moreTemplateSlide1,
|
||||
moreTemplateSlide2,
|
||||
moreTemplateSlide3,
|
||||
moreTemplateSlide4,
|
||||
moreTemplateSlide5,
|
||||
] = ossAssets.ecommerce.templateSlides;
|
||||
const [
|
||||
ecommerceHeroSlide1,
|
||||
ecommerceHeroSlide2,
|
||||
ecommerceHeroSlide3,
|
||||
ecommerceHeroSlide4,
|
||||
ecommerceHeroSlide5,
|
||||
] = ossAssets.ecommerce.heroSlides;
|
||||
const [
|
||||
ecommerceCarouselImage1,
|
||||
ecommerceCarouselImage2,
|
||||
ecommerceCarouselImage3,
|
||||
ecommerceCarouselImage4,
|
||||
ecommerceCarouselImage5,
|
||||
ecommerceCarouselImage6,
|
||||
] = ossAssets.ecommerce.templateCases;
|
||||
const ecommerceCarouselGenerated = ossAssets.ecommerce.generated;
|
||||
|
||||
export interface TemplateCase {
|
||||
title: string;
|
||||
@@ -124,6 +134,6 @@ export const templateCases: TemplateCase[] = [
|
||||
title: "促销卖点组合图",
|
||||
category: "详情图",
|
||||
summary: "把成分、规格、卖点拆成清晰的详情页模块。",
|
||||
imageUrl: "https://picsum.photos/id/1080/900/620",
|
||||
imageUrl: ecommerceCarouselImage6,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -7,15 +7,18 @@ import {
|
||||
ReloadOutlined,
|
||||
SettingOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { ChangeEvent, DragEvent, MutableRefObject, RefObject } from "react";
|
||||
import type { CSSProperties, ChangeEvent, DragEvent, MutableRefObject, RefObject } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
type CloneOutputKey = string;
|
||||
type CloneSetCountKey = string;
|
||||
type ProductSetOutputKey = "set" | "detail" | "model" | "video";
|
||||
type CloneOutputKey = ProductSetOutputKey | "hot" | "video-outfit";
|
||||
type CloneSetCountKey = "selling" | "white" | "scene";
|
||||
type CloneModelPanelTab = "scene" | "model";
|
||||
type CloneReferenceMode = "upload" | "link";
|
||||
type CloneReplicateLevelKey = string;
|
||||
type CloneVideoQualityKey = string;
|
||||
type CloneReplicateLevelKey = "style" | "high";
|
||||
type CloneVideoQualityKey = "standard" | "high" | "ultra";
|
||||
type CloneBasicSelectKey = "platform" | "market" | "language" | "ratio";
|
||||
type CloneModelSelectKey = "gender" | "age" | "ethnicity" | "body";
|
||||
|
||||
interface CloneImageItem {
|
||||
id: string;
|
||||
@@ -24,7 +27,7 @@ interface CloneImageItem {
|
||||
}
|
||||
|
||||
interface CloneBasicSelectItem {
|
||||
key: string;
|
||||
key: CloneBasicSelectKey;
|
||||
label: string;
|
||||
value: string;
|
||||
options: string[];
|
||||
@@ -32,7 +35,7 @@ interface CloneBasicSelectItem {
|
||||
}
|
||||
|
||||
interface CloneModelSelectItem {
|
||||
key: string;
|
||||
key: CloneModelSelectKey;
|
||||
label: string;
|
||||
value: string;
|
||||
options: string[];
|
||||
@@ -76,7 +79,7 @@ interface EcommerceClonePanelProps {
|
||||
cloneOutput: CloneOutputKey;
|
||||
cloneOutputOptions: CloneOutputOption[];
|
||||
cloneBasicSelects: CloneBasicSelectItem[];
|
||||
openCloneBasicSelect: string | null;
|
||||
openCloneBasicSelect: CloneBasicSelectKey | null;
|
||||
cloneReferenceMode: CloneReferenceMode;
|
||||
cloneReferenceImages: CloneImageItem[];
|
||||
maxCloneReferenceImages: number;
|
||||
@@ -94,7 +97,7 @@ interface EcommerceClonePanelProps {
|
||||
selectedCloneModelScenes: string[];
|
||||
cloneModelCustomScene: string;
|
||||
cloneModelSelects: CloneModelSelectItem[];
|
||||
openCloneModelSelect: string | null;
|
||||
openCloneModelSelect: CloneModelSelectKey | null;
|
||||
cloneModelSelectDropUp: boolean;
|
||||
cloneModelAppearance: string;
|
||||
cloneVideoQuality: CloneVideoQualityKey;
|
||||
@@ -102,27 +105,27 @@ interface EcommerceClonePanelProps {
|
||||
cloneVideoDuration: number;
|
||||
cloneVideoDurationMin: number;
|
||||
cloneVideoDurationMax: number;
|
||||
cloneVideoDurationStyle: { [key: string]: number | string };
|
||||
cloneVideoDurationStyle: CSSProperties;
|
||||
cloneVideoSmart: boolean;
|
||||
canGenerate: boolean;
|
||||
status: string;
|
||||
lastFailedActionRef: MutableRefObject<(() => void) | null>;
|
||||
setIsProductUploadDragging: (value: boolean) => void;
|
||||
handleProductDrop: (event: DragEvent<HTMLElement>) => void;
|
||||
handleProductDrop: (event: DragEvent<HTMLDivElement>) => void;
|
||||
removeProductImage: (id: string) => void;
|
||||
handleProductUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
handleCloneOutputChange: (value: CloneOutputKey) => void;
|
||||
setOpenCloneBasicSelect: (value: string | null) => void;
|
||||
setOpenCloneBasicSelect: (value: CloneBasicSelectKey | null) => void;
|
||||
setCloneReferenceMode: (value: CloneReferenceMode) => void;
|
||||
handleCloneReferenceUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
setCloneReplicateLevel: (value: CloneReplicateLevelKey) => void;
|
||||
startCloneSetCountHold: (key: CloneSetCountKey, delta: number, disabled: boolean) => void;
|
||||
startCloneSetCountHold: (key: CloneSetCountKey, delta: -1 | 1, disabled: boolean) => void;
|
||||
clearCloneSetCountHold: () => void;
|
||||
toggleCloneDetailModule: (id: string) => void;
|
||||
setCloneModelPanelTab: (value: CloneModelPanelTab) => void;
|
||||
toggleCloneModelScene: (scene: string) => void;
|
||||
setCloneModelCustomScene: (value: string) => void;
|
||||
setOpenCloneModelSelect: (value: string | null) => void;
|
||||
setOpenCloneModelSelect: (value: CloneModelSelectKey | null) => void;
|
||||
setCloneModelSelectDropUp: (value: boolean) => void;
|
||||
setCloneModelAppearance: (value: string) => void;
|
||||
setCloneVideoQuality: (value: CloneVideoQualityKey) => void;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { CloudUploadOutlined, CloseOutlined, FileImageOutlined, SettingOutlined } from "@ant-design/icons";
|
||||
import type { ChangeEvent, DragEvent, RefObject } from "react";
|
||||
|
||||
type ProductSetOutputKey = "set" | "detail" | "model" | "video";
|
||||
|
||||
interface EcommerceSetPanelProps {
|
||||
setInputRef: RefObject<HTMLInputElement>;
|
||||
setImages: Array<{ id: string; src: string; name: string }>;
|
||||
isSetUploadDragging: boolean;
|
||||
productSetOutputOptions: Array<{ key: string; label: string }>;
|
||||
productSetOutput: string;
|
||||
productSetOutputOptions: Array<{ key: ProductSetOutputKey; label: string }>;
|
||||
productSetOutput: ProductSetOutputKey;
|
||||
platformOptions: string[];
|
||||
marketOptions: string[];
|
||||
productSetLanguageOptions: string[];
|
||||
@@ -16,10 +18,10 @@ interface EcommerceSetPanelProps {
|
||||
productSetLanguage: string;
|
||||
productSetRatio: string;
|
||||
setIsSetUploadDragging: (value: boolean) => void;
|
||||
handleSetDrop: (event: DragEvent<HTMLElement>) => void;
|
||||
handleSetDrop: (event: DragEvent<HTMLButtonElement>) => void;
|
||||
handleSetUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
removeSetImage: (id: string) => void;
|
||||
handleProductSetOutputChange: (value: string) => void;
|
||||
handleProductSetOutputChange: (value: ProductSetOutputKey) => void;
|
||||
handleProductSetPlatformChange: (value: string) => void;
|
||||
handleProductSetMarketChange: (value: string) => void;
|
||||
setProductSetLanguage: (value: string) => void;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { Fragment, useCallback, useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
|
||||
import type { WebViewKey, WebImageWorkbenchTool } from "../../types";
|
||||
import { useScrollEntrance } from "../../hooks/useScrollEntrance";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
import WelcomeSplash from "./WelcomeSplash";
|
||||
import ToolboxSection from "./ToolboxSection";
|
||||
import ScriptReviewShowcase from "./ScriptReviewShowcase";
|
||||
@@ -24,13 +25,12 @@ function ScrollEntrance({ children, className, ...rest }: { children: React.Reac
|
||||
);
|
||||
}
|
||||
|
||||
const OSS_MUBAN = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban";
|
||||
const heroImage1 = `${OSS_MUBAN}/hero-1.png`;
|
||||
const heroImage2 = `${OSS_MUBAN}/hero-2.png`;
|
||||
const heroImage3 = `${OSS_MUBAN}/hero-3.png`;
|
||||
const featureEcommerceImage = `${OSS_MUBAN}/feature-ecommerce.jpg`;
|
||||
const featureScriptImage = `${OSS_MUBAN}/feature-script.jpg`;
|
||||
const featureTokenImage = `${OSS_MUBAN}/feature-token.jpg`;
|
||||
const [heroImage1, heroImage2, heroImage3] = ossAssets.home.heroSlides;
|
||||
const {
|
||||
ecommerce: featureEcommerceImage,
|
||||
script: featureScriptImage,
|
||||
token: featureTokenImage,
|
||||
} = ossAssets.home.features;
|
||||
|
||||
interface HomePageProps {
|
||||
onOpenGenerate: () => void;
|
||||
@@ -42,7 +42,7 @@ interface HomePageProps {
|
||||
onOpenImageTool?: (tool: WebImageWorkbenchTool) => void;
|
||||
}
|
||||
|
||||
const HOME_BACKGROUND_VIDEO = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/muban/hero-bg.mp4";
|
||||
const HOME_BACKGROUND_VIDEO = ossAssets.home.backgroundVideo;
|
||||
|
||||
const HOME_CAROUSEL_IMAGES = [
|
||||
{ imageUrl: heroImage1, title: "灵感生成" },
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { ToolOutlined } from "@ant-design/icons";
|
||||
import type { WebViewKey, WebImageWorkbenchTool } from "../../types";
|
||||
import toolImageBefore from "../../assets/toolbox/牛仔.png";
|
||||
import toolImageAfter from "../../assets/toolbox/西装.png";
|
||||
import watermarkBefore from "../../assets/toolbox/去水印前.png";
|
||||
import watermarkAfter from "../../assets/toolbox/去水印后.png";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
|
||||
const {
|
||||
imageBefore: toolImageBefore,
|
||||
imageAfter: toolImageAfter,
|
||||
watermarkBefore,
|
||||
watermarkAfter,
|
||||
} = ossAssets.toolbox;
|
||||
|
||||
interface ToolboxSectionProps {
|
||||
onSelectView: (view: WebViewKey) => void;
|
||||
|
||||
@@ -20,6 +20,7 @@ import { assetClient } from "../../api/assetClient";
|
||||
import { communityClient, type ServerCommunityCase } from "../../api/communityClient";
|
||||
import { keyServerClient } from "../../api/keyServerClient";
|
||||
import { isServerRequestError } from "../../api/serverConnection";
|
||||
import { ossAssets } from "../../data/ossAssets";
|
||||
import type { WebAuthMode, WebGenerationPreviewTask, WebProjectSummary, WebUsageSummary, WebUserSession } from "../../types";
|
||||
import type { SavedAssetItem } from "../assets/localAssetStore";
|
||||
|
||||
@@ -44,8 +45,8 @@ type ProfilePanel = "works" | "projects" | "assets" | "community";
|
||||
type AccountPanel = "credits" | "tasks";
|
||||
|
||||
const PROFILE_LOCAL_STORAGE_PREFIX = "omniai-web-profile-ui";
|
||||
const AUTH_LOGO_URL = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/logo.png";
|
||||
const AUTH_SHOWCASE_VIDEO_URL = "https://stringtest.oss-cn-hangzhou.aliyuncs.com/test5.mp4";
|
||||
const AUTH_LOGO_URL = ossAssets.brand.logo;
|
||||
const AUTH_SHOWCASE_VIDEO_URL = ossAssets.auth.showcaseVideo;
|
||||
|
||||
function profileStorageKey(userId: string | number | undefined, field: "avatar" | "bio" | "background"): string {
|
||||
return `${PROFILE_LOCAL_STORAGE_PREFIX}:${userId ?? "guest"}:${field}`;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CheckCircleOutlined, FlagOutlined, MailOutlined, PhoneOutlined } from "@ant-design/icons";
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { useEffect, useState, type FormEvent } from "react";
|
||||
import { publicConfigClient, type WebPublicConfig } from "../../api/publicConfigClient";
|
||||
import { reportClient, type ReportInput } from "../../api/reportClient";
|
||||
|
||||
type SubmitState = "idle" | "loading" | "success" | "error";
|
||||
@@ -31,6 +32,7 @@ function ReportPage() {
|
||||
const [contactPhone, setContactPhone] = useState("");
|
||||
const [submitState, setSubmitState] = useState<SubmitState>("idle");
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
const [publicConfig, setPublicConfig] = useState<WebPublicConfig>({});
|
||||
|
||||
const canSubmit =
|
||||
submitState !== "loading" && reportType !== "" && title.trim() !== "" && description.trim() !== "";
|
||||
@@ -48,6 +50,22 @@ function ReportPage() {
|
||||
setErrorMsg("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
publicConfigClient
|
||||
.get()
|
||||
.then((config) => {
|
||||
if (!cancelled) setPublicConfig(config);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setPublicConfig({});
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (event: FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (!canSubmit) return;
|
||||
@@ -85,9 +103,9 @@ function ReportPage() {
|
||||
</header>
|
||||
|
||||
<div className="report-contact-strip">
|
||||
<span><MailOutlined /> {import.meta.env.VITE_REPORT_EMAIL || "support@omniai.com"}</span>
|
||||
<span><PhoneOutlined /> {import.meta.env.VITE_REPORT_PHONE || "请在环境变量配置客服电话"}</span>
|
||||
<span>{import.meta.env.VITE_ICP_RECORD || "ICP备案信息待配置"}</span>
|
||||
<span><MailOutlined /> {publicConfig.contactEmail || "由服务器配置"}</span>
|
||||
<span><PhoneOutlined /> {publicConfig.contactPhone || "由服务器配置"}</span>
|
||||
<span>{publicConfig.icpRecord || "由服务器配置"}</span>
|
||||
</div>
|
||||
|
||||
{submitState === "success" ? (
|
||||
|
||||
@@ -999,11 +999,6 @@ function WorkbenchPage({
|
||||
});
|
||||
removeKeepaliveTask(task.taskId);
|
||||
onRefreshUsage?.();
|
||||
if (status.status === "completed") {
|
||||
import("../../utils/generationNotifier").then((m) =>
|
||||
m.notifyTaskCompleted(task.mode === "video" ? "视频" : "图片", task.mode as "image" | "video"),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user