11
BIN
public/cover-templates/1xwrrcvf7a5-mkdite6i.png
Normal file
|
After Width: | Height: | Size: 800 KiB |
BIN
public/cover-templates/43t1uykj8zg-mkdite6i.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
public/cover-templates/485183be-6eed-4eae-b74a-8591f08b69fa.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
public/cover-templates/6404718a-1b1c-4148-9807-ad3c57a53e0c.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
public/cover-templates/705fa010-5bf3-4041-b624-0fd364bea5ad.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/cover-templates/8f17c467-c69c-45b2-8011-94a6c3071d16.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
public/cover-templates/sb8mm7l4bjf-mkdite6i.png
Normal file
|
After Width: | Height: | Size: 944 KiB |
BIN
public/cover-templates/v08ezr6v3x-mkdite6i.png
Normal file
|
After Width: | Height: | Size: 726 KiB |
@@ -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;
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 />
|
||||||
自动生成字幕
|
自动生成字幕
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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="账号管理"
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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) =>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||