This commit is contained in:
949036910@qq.com
2026-06-03 15:27:24 +08:00
parent d4f28ba00d
commit 328ee75be5
21 changed files with 90 additions and 16 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 KiB

View File

@@ -127,7 +127,7 @@ function onThumbError(event) {
.template-thumbnail { .template-thumbnail {
width: 100%; width: 100%;
aspect-ratio: 9 / 16;
min-height: 200px; min-height: 200px;
max-height: min(46vh, 360px); max-height: min(46vh, 360px);
border-radius: 10px; border-radius: 10px;

View File

@@ -8,6 +8,8 @@ const props = defineProps({
step: { type: String, default: "" }, step: { type: String, default: "" },
defaultOpen: { type: Boolean, default: true }, defaultOpen: { type: Boolean, default: true },
grow: { type: Boolean, default: false }, grow: { type: Boolean, default: false },
/** 当前步骤正在执行异步任务时显示旋转边框 */
processing: { type: Boolean, default: false },
}); });
const open = ref(props.defaultOpen); const open = ref(props.defaultOpen);
@@ -20,7 +22,10 @@ function toggle() {
<template> <template>
<section <section
class="dashboard-card" class="dashboard-card"
:class="{ 'dashboard-card--grow': props.grow }" :class="{
'dashboard-card--grow': props.grow,
'section-processing': props.processing,
}"
> >
<header class="dashboard-card-header cursor-pointer" @click="toggle"> <header class="dashboard-card-header cursor-pointer" @click="toggle">
<div class="flex min-w-0 items-center gap-2"> <div class="flex min-w-0 items-center gap-2">

View File

@@ -25,6 +25,7 @@ const {
ipTopicRewriteProgress, ipTopicRewriteProgress,
rewrittenTopics, rewrittenTopics,
hitScriptGenerating, hitScriptGenerating,
step01Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const topicFeedback = ref({ severity: "", message: "" }); const topicFeedback = ref({ severity: "", message: "" });
@@ -88,7 +89,7 @@ function onHitScriptFeedback(result) {
</script> </script>
<template> <template>
<DashboardCard title="IP深度学习" step="01"> <DashboardCard title="IP深度学习" step="01" :processing="step01Processing">
<SelectButton <SelectButton
v-model="ipMode" v-model="ipMode"
:options="workflow.ipModes" :options="workflow.ipModes"

View File

@@ -23,6 +23,7 @@ const {
generatedVideoPath, generatedVideoPath,
currentVideoId, currentVideoId,
videoHistory, videoHistory,
step02Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -125,7 +126,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<DashboardCard title="音视频生成" step="02"> <DashboardCard title="音视频生成" step="02" :processing="step02Processing">
<div class="grid grid-cols-3 gap-2"> <div class="grid grid-cols-3 gap-2">
<div> <div>
<div class="mb-1 text-xs text-slate-200">音色</div> <div class="mb-1 text-xs text-slate-200">音色</div>

View File

@@ -15,6 +15,7 @@ const {
generatedVideoPath, generatedVideoPath,
processedVideoSrc, processedVideoSrc,
processedVideoPath, processedVideoPath,
step03Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -73,7 +74,7 @@ async function onOpenVideoInExplorer() {
</script> </script>
<template> <template>
<DashboardCard title="视频编辑" step="03" :grow="true"> <DashboardCard title="视频编辑" step="03" :grow="true" :processing="step03Processing">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<label class="flex items-center gap-2 text-sm text-slate-200"> <label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="pipInPicture" binary /> <Checkbox v-model="pipInPicture" binary />

View File

@@ -15,6 +15,7 @@ const {
titleTagsGenerating, titleTagsGenerating,
scriptContent, scriptContent,
titleTagPrompt, titleTagPrompt,
step04Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -45,7 +46,7 @@ async function onGenerateTitleTags() {
</script> </script>
<template> <template>
<DashboardCard title="标题标签关键词" step="04"> <DashboardCard title="标题标签关键词" step="04" :processing="step04Processing">
<Button <Button
label="生成标题标签关键词" label="生成标题标签关键词"
size="small" size="small"

View File

@@ -18,6 +18,7 @@ const {
subtitlePreviewVideoPath, subtitlePreviewVideoPath,
subtitlePreviewVideoSrc, subtitlePreviewVideoSrc,
bgmPreviewSrc, bgmPreviewSrc,
step05Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -84,7 +85,7 @@ async function onOpenVideoInExplorer() {
</script> </script>
<template> <template>
<DashboardCard title="字幕和音乐" step="05" :grow="true"> <DashboardCard title="字幕和音乐" step="05" :grow="true" :processing="step05Processing">
<label class="flex items-center gap-2 text-sm text-slate-200"> <label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="autoSubtitle" binary /> <Checkbox v-model="autoSubtitle" binary />
自动生成字幕 自动生成字幕

View File

@@ -12,6 +12,7 @@ const {
coverGenerating, coverGenerating,
coverImageSrc, coverImageSrc,
coverTemplateId, coverTemplateId,
step06Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -49,7 +50,7 @@ function onSettingsApplied() {
</script> </script>
<template> <template>
<DashboardCard title="封面制作" step="06"> <DashboardCard title="封面制作" step="06" :processing="step06Processing">
<Button <Button
label="自动生成封面" label="自动生成封面"
size="small" size="small"

View File

@@ -13,6 +13,7 @@ const {
generatedVideoPath, generatedVideoPath,
processedVideoPath, processedVideoPath,
publishScheduledAt, publishScheduledAt,
step07Processing,
} = storeToRefs(workflow); } = storeToRefs(workflow);
const feedback = ref({ severity: "", message: "" }); const feedback = ref({ severity: "", message: "" });
@@ -179,7 +180,7 @@ function formatUpdateTime(account) {
</script> </script>
<template> <template>
<DashboardCard title="视频发布" step="07" :grow="true"> <DashboardCard title="视频发布" step="07" :grow="true" :processing="step07Processing">
<div class="mb-2 flex justify-end"> <div class="mb-2 flex justify-end">
<Button <Button
label="账号管理" label="账号管理"

View File

@@ -81,12 +81,13 @@ function describeCoverPreset(tpl) {
*/ */
export function loadSystemCoverTemplates() { export function loadSystemCoverTemplates() {
const electron = loadElectronCoverTemplates(); const electron = loadElectronCoverTemplates();
const legacyQuick = COVER_TEMPLATES.map(systemTemplateFromPreset).map((t) => ({ return electron;
...t, // const legacyQuick = COVER_TEMPLATES.map(systemTemplateFromPreset).map((t) => ({
id: `cover_quick_${t.id}`, // ...t,
description: t.description || "ffmpeg/PIL 快速预设", // id: `cover_quick_${t.id}`,
})); // description: t.description || "ffmpeg/PIL 快速预设",
return [...electron, ...legacyQuick]; // }));
// return [...electron, ...legacyQuick];
} }
/** /**

View File

@@ -401,6 +401,28 @@ export const useWorkflowStore = defineStore("workflow", {
oneClickBusy: (state) => state.oneClickRunning, oneClickBusy: (state) => state.oneClickRunning,
step01Processing: (state) =>
state.ipBrainCollecting ||
state.ipTopicsRewriting ||
state.videoRewriting ||
state.scriptGenerating ||
state.hitScriptGenerating ||
state.legalChecking,
step02Processing: (state) =>
state.speechGenerating || state.videoGenerating,
step03Processing: (state) => state.videoProcessing,
step04Processing: (state) => state.titleTagsGenerating,
step05Processing: (state) => state.subtitleBgmGenerating,
step06Processing: (state) => state.coverGenerating,
step07Processing: (state) =>
state.publishing || Boolean(state.publishLoggingIn),
ipBenchmarkCount: (state) => state.ipBenchmarks.length, ipBenchmarkCount: (state) => state.ipBenchmarks.length,
selectedBenchmark: (state) => selectedBenchmark: (state) =>

View File

@@ -526,6 +526,44 @@ body {
box-shadow: 0 0 16px rgba(59, 130, 246, 0.06); box-shadow: 0 0 16px rgba(59, 130, 246, 0.06);
} }
@property --border-angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes spinning-border-rotate-485e84d5 {
to {
--border-angle: 360deg;
}
}
.dashboard-card.section-processing {
border: 2px solid transparent !important;
background-image:
linear-gradient(180deg, #14161efa, #0b0c12fa),
conic-gradient(
from var(--border-angle),
transparent 0%,
transparent 66%,
rgba(56, 189, 248, 0.92) 79%,
rgba(59, 130, 246, 1) 86%,
rgba(139, 92, 246, 0.92) 93%,
transparent 100%
) !important;
box-shadow:
0 0 0 1px #3b82f61f,
0 0 18px #3b82f61f,
0 0 32px #8b5cf614 !important;
animation: spinning-border-rotate-485e84d5 2.8s linear infinite !important;
background-origin: border-box !important;
background-clip: padding-box, border-box !important;
}
.dashboard-card.section-processing:hover {
border-color: transparent !important;
}
.dashboard-card--grow { .dashboard-card--grow {
flex: 1; flex: 1;
display: flex; display: flex;

View File

@@ -2,7 +2,7 @@
* Electron 封面模板导出格式适配cover-template-*.json / coverTemplate 单条导出) * Electron 封面模板导出格式适配cover-template-*.json / coverTemplate 单条导出)
*/ */
import { createDefaultCoverTemplateConfig } from "../config/coverTemplateDefaults.js"; import { createDefaultCoverTemplateConfig } from "../config/coverTemplateDefaults.js";
import { publicAssetUrl } from "../utils/publicAsset.js";
/** Electron 模板名 → 稳定 id */ /** Electron 模板名 → 稳定 id */
const ELECTRON_TEMPLATE_IDS = { const ELECTRON_TEMPLATE_IDS = {
人像居中: "cover_electron_portrait_center", 人像居中: "cover_electron_portrait_center",
@@ -96,6 +96,7 @@ export function electronCoverItemToTemplate(item, opts = {}) {
return { return {
id, id,
name, name,
thumbnailPath: publicAssetUrl(`cover-templates/${item.id}.png`),
description: "Electron 系统预设", description: "Electron 系统预设",
config: normalizeElectronCoverConfig(item?.config || {}, opts), config: normalizeElectronCoverConfig(item?.config || {}, opts),
isSystem: true, isSystem: true,