fix(canvas): 画布与素材同步 - 修复批量缩略图、远程资源回退与重命名同步
This commit is contained in:
@@ -15,12 +15,12 @@ import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import { ModelPicker } from "@/components/model-picker";
|
||||
import { CreditSymbol, requestCreditCost } from "@/constant/credits";
|
||||
import { modelCapabilityConfigFor, normalizeImageValue, normalizeVideoValue, videoDurationOptions } from "@/lib/model-capabilities";
|
||||
import { modelQuoteRequest } from "@/lib/model-pricing";
|
||||
import { modelQuoteDescription, modelQuoteRequest } from "@/lib/model-pricing";
|
||||
import { customShotTitle, formatShotOrdinal, normalizeDefaultShotTitle } from "@/lib/shot-label";
|
||||
import { modelCompatibilityError, resolveCompatibleModel, resolveModelVideoBooleanOptions, type ModelRequirements } from "@/lib/model-selection";
|
||||
import { formatVideoResolutionLabel } from "@/lib/video-generation-options";
|
||||
import { submitBackendGenerationTask } from "@/services/api/generation-task";
|
||||
import { quoteLogicalModel } from "@/services/api/logical-models";
|
||||
import { quoteModel, type LogicalModelQuote } from "@/services/api/logical-models";
|
||||
import { type GenerationTask } from "@/services/api/task-center";
|
||||
import {
|
||||
createUnitWorkflow,
|
||||
@@ -182,8 +182,8 @@ export default function WorkflowProductionWorkbench(props: Props) {
|
||||
});
|
||||
const quoteRequest = useMemo(() => modelQuoteRequest(generationConfig, routedModel, generationCapability, modelRequirements), [generationCapability, generationConfig, modelRequirements, routedModel]);
|
||||
const quoteRequestKey = JSON.stringify(quoteRequest || null);
|
||||
const [quotedCredits, setQuotedCredits] = useState<number | null>(null);
|
||||
const generationCredits = quotedCredits ?? configuredCredits;
|
||||
const [routeQuote, setRouteQuote] = useState<LogicalModelQuote | null>(null);
|
||||
const generationCredits = routeQuote ? routeQuote.amountMicrocredits / 1_000_000 : configuredCredits;
|
||||
const formattedGenerationCredits = generationCredits?.toLocaleString("zh-CN", { maximumFractionDigits: 6 });
|
||||
const modelSummary = routedModel ? modelDisplayName(effectiveConfig, routedModel) : "未选择模型";
|
||||
const durationSummary = `${Number(watchedDuration || Math.max(0.5, (selectedShot?.durationMs || 3000) / 1000))}s`;
|
||||
@@ -212,15 +212,15 @@ export default function WorkflowProductionWorkbench(props: Props) {
|
||||
|
||||
useEffect(() => {
|
||||
if (!creditsEnabled || !quoteRequest) {
|
||||
setQuotedCredits(null);
|
||||
setRouteQuote(null);
|
||||
return;
|
||||
}
|
||||
const controller = new AbortController();
|
||||
setQuotedCredits(null);
|
||||
quoteLogicalModel(quoteRequest.logicalModelID, quoteRequest.intent, controller.signal)
|
||||
.then(({ quote }) => setQuotedCredits(quote.amountMicrocredits / 1_000_000))
|
||||
setRouteQuote(null);
|
||||
quoteModel(quoteRequest, controller.signal)
|
||||
.then(({ quote }) => setRouteQuote(quote))
|
||||
.catch(() => {
|
||||
if (!controller.signal.aborted) setQuotedCredits(null);
|
||||
if (!controller.signal.aborted) setRouteQuote(null);
|
||||
});
|
||||
return () => controller.abort();
|
||||
// quoteRequestKey captures the normalized request without retriggering on object identity.
|
||||
@@ -545,7 +545,7 @@ export default function WorkflowProductionWorkbench(props: Props) {
|
||||
</div>
|
||||
<footer className="workflow-editor-actions">
|
||||
<div className="workflow-generation-cost" aria-live="polite">
|
||||
{creditsEnabled && formattedGenerationCredits ? <><CreditSymbol /><span>本次预计 {formattedGenerationCredits} 积分</span></> : creditsEnabled && routedModel ? <span>本次费用将在提交时按实际规格计算</span> : null}
|
||||
{creditsEnabled && formattedGenerationCredits ? <><CreditSymbol /><span title={routeQuote ? modelQuoteDescription(routeQuote) : undefined}>本次预计 {formattedGenerationCredits} 积分</span></> : creditsEnabled && routedModel ? <span>本次费用将在提交时按实际规格计算</span> : null}
|
||||
</div>
|
||||
<div className="flex items-center gap-2"><Button danger icon={<Trash2 className="size-4" />} loading={deleteShot.isPending} disabled={saveShot.isPending || selectedShotSubmitting || changeAssetBinding.isPending} onClick={requestDeleteShot}>删除镜头</Button><Button htmlType="submit" icon={<Save className="size-4" />} loading={saveShot.isPending} disabled={!editorDirty || deleteShot.isPending}>保存脚本</Button><Button type="primary" icon={<Play className="size-4" />} loading={selectedShotSubmitting || shotTask?.status === "queued" || shotTask?.status === "running"} disabled={deleteShot.isPending} onClick={() => void generateArtifact()}>{selectedShotSubmitting ? `${stageCopy.action}(正在提交)` : shotTask?.status === "queued" || shotTask?.status === "running" ? `${stageCopy.action}(已运行${shotTaskElapsed})` : shotTask?.status === "failed" ? `${stageCopy.action}(上次失败,可重试)` : shotTask?.status === "succeeded" && !newestArtifact ? `${stageCopy.action}(已完成,正在同步)` : newestArtifact ? `${stageCopy.action}(已生成)` : stageCopy.action}</Button></div>
|
||||
</footer>
|
||||
|
||||
@@ -184,7 +184,6 @@ export default function ProjectsPage() {
|
||||
const hasInitialError = query.isError && !query.data;
|
||||
return (
|
||||
<WorkspacePage className="library-page project-library-page" grid>
|
||||
<PageHeader title="短剧 Agent" description="你的故事、章节与镜头,都在这里。" meta={<span className="app-projects-header-meta">{totalProjectCount} 个项目</span>} />
|
||||
<details className="story-launcher-panel" aria-label="开始一部新短剧">
|
||||
<summary className="story-launcher-head">
|
||||
<div className="story-launcher-title">
|
||||
|
||||
Reference in New Issue
Block a user