This commit is contained in:
fengchuanhn@gmail.com
2026-05-15 19:17:13 +08:00
parent 9d2c592127
commit 7b56c6cfa8
11 changed files with 601 additions and 445 deletions

View File

@@ -0,0 +1,137 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const {
ipMode,
videoType,
copyType,
industryPersona,
productBusiness,
sellingPrice,
otherRequirements,
targetWords,
recognizedContent,
} = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="IP深度学习" step="01">
<SelectButton
v-model="ipMode"
:options="workflow.ipModes"
option-label="label"
option-value="value"
class="mb-3 w-full"
size="small"
/>
<template v-if="ipMode === 'ipBrain'">
<Button label="添加IP大脑" class="w-full" size="small" />
<div class="mt-3">
<div class="dashboard-field-label">
已学习到的对标
<span class="dashboard-field-label--muted text-xs">(0/5)</span>
</div>
<p class="dashboard-muted py-2">暂无对标</p>
</div>
<div class="mt-3">
<div class="dashboard-field-label mb-2">选题库</div>
<p class="dashboard-muted py-2 text-center text-sm">请先选择一个对标</p>
</div>
</template>
<template v-else-if="ipMode === 'videoWrite'">
<Button label="打开视频链接" class="w-full" size="small" />
<div class="mt-3 space-y-1">
<div class="dashboard-field-label flex items-center gap-1">
<span>识别的原始内容</span>
<span class="text-xs font-normal text-slate-500">(使用视频仿写功能后显示)</span>
</div>
<Textarea
v-model="recognizedContent"
readonly
placeholder="使用【打开视频链接】功能后,识别的原始内容将显示在这里..."
class="dashboard-textarea-mono w-full"
rows="10"
/>
</div>
</template>
<template v-else>
<div class="space-y-2.5">
<div>
<div class="dashboard-field-label">
视频类型 <span class="text-xs text-red-400">*</span>
</div>
<Select v-model="videoType" :options="workflow.videoTypes" size="small" class="w-full" />
</div>
<div>
<div class="dashboard-field-label">
文案类型 <span class="text-xs text-red-400">*</span>
</div>
<Select v-model="copyType" :options="workflow.copyTypes" size="small" class="w-full" />
</div>
<div>
<div class="dashboard-field-label">
行业+人设 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="industryPersona"
placeholder="例如餐饮店我叫斌哥在上海有10年餐饮经验"
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
产品/业务 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="productBusiness"
placeholder="例如:纸巾,麻辣烫,房产,教培,财务..."
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
卖点+价格 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="sellingPrice"
placeholder="例如纸张柔软亲肤正常价99今天只要59元"
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
其他要求 <span class="text-xs text-slate-400">可选</span>
</div>
<Textarea
v-model="otherRequirements"
placeholder="例如风格幽默突出性价比适合30-50岁人群..."
rows="3"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">目标字数</div>
<div class="flex items-center gap-2">
<Slider v-model="targetWords" :min="50" :max="1500" class="flex-1" />
<InputNumber
v-model="targetWords"
:min="50"
:max="1500"
size="small"
class="w-24"
/>
</div>
</div>
<Button label="生成爆款文案" size="small" class="w-full" />
</div>
</template>
</DashboardCard>
</template>

View File

@@ -0,0 +1,76 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const { voiceEmotion, speechRate, voiceLanguage, avatarSelect } = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="音视频生成" step="02">
<div class="grid grid-cols-3 gap-2">
<div>
<div class="mb-1 text-xs text-slate-200">音色</div>
<Button label="选择音色" size="small" severity="secondary" outlined class="w-full" />
</div>
<div>
<div class="mb-1 text-xs text-slate-200">情绪</div>
<Select
v-model="voiceEmotion"
:options="workflow.voiceEmotions"
size="small"
class="w-full"
/>
</div>
<div>
<div class="mb-1 text-xs text-slate-200">语速</div>
<InputNumber
v-model="speechRate"
:min="0.5"
:max="2"
:step="0.1"
size="small"
class="w-full"
/>
</div>
</div>
<div class="mt-3 flex items-end gap-2">
<div class="min-w-0 flex-1">
<div class="mb-1 text-xs text-slate-200">语言</div>
<Select
v-model="voiceLanguage"
:options="workflow.languages"
size="small"
class="w-full"
/>
</div>
<Button label="生成语音" size="small" class="shrink-0" />
</div>
<div class="dashboard-preview-box mt-3">
<div class="mb-2 flex items-center justify-between gap-2">
<span class="text-xs text-slate-400">音频预览</span>
<Select placeholder="暂无历史记录" disabled size="small" class="w-40" />
</div>
<p class="py-4 text-center text-xs text-gray-500">暂无音频请生成或选择历史记录</p>
</div>
<div class="mt-3">
<div class="mb-2 text-xs text-slate-400">选择形象</div>
<Select
v-model="avatarSelect"
:options="workflow.avatarOptions"
option-label="label"
option-value="value"
placeholder="请选择形象"
size="small"
class="w-full"
/>
</div>
<Button label="生成口播视频" size="small" class="mt-3 w-full" />
<div class="mt-2">
<div class="mb-1 text-xs text-slate-200">视频预览</div>
<div class="dashboard-aspect-video">
<span class="text-xs text-gray-400">暂无视频预览</span>
</div>
</div>
</DashboardCard>
</template>

View File

@@ -0,0 +1,27 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const { pipInPicture, autoCutBreath, greenScreen } = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="视频编辑" step="03" :grow="true">
<div class="flex flex-col gap-2">
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="pipInPicture" binary />
画中画
</label>
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="autoCutBreath" binary />
自动剪气口
</label>
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="greenScreen" binary />
启动绿幕切换
</label>
<Button label="自动处理" size="small" class="w-full" disabled />
</div>
</DashboardCard>
</template>

View File

@@ -0,0 +1,96 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const {
titleGenerated,
tagsGenerated,
keywordTab,
keywordsFocus,
keywordsDescribe,
keywordsAction,
keywordsEmotion,
} = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="标题标签关键词" step="04">
<Button label="生成标题标签关键词" size="small" class="mb-3 w-full" />
<div class="mb-3">
<div class="dashboard-field-label mb-1">生成的标题可编辑</div>
<Textarea
v-model="titleGenerated"
placeholder="标题将显示在这里..."
rows="2"
class="w-full"
/>
</div>
<div class="mb-3">
<div class="dashboard-field-label mb-1">生成的标签可编辑</div>
<Textarea
v-model="tagsGenerated"
placeholder="标签将显示在这里,逗号分隔..."
rows="2"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label mb-2">生成的关键词</div>
<Tabs v-model:value="keywordTab">
<TabList>
<Tab value="0">重点词/成语词</Tab>
<Tab value="1">描述词</Tab>
<Tab value="2">行动词</Tab>
<Tab value="3">情感词</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<Textarea
v-model="keywordsFocus"
placeholder="请输入重点词/成语词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">
已添加 {{ workflow.keywordCountFocus }} 个关键词
</p>
</TabPanel>
<TabPanel value="1">
<Textarea
v-model="keywordsDescribe"
placeholder="请输入描述词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">
已添加 {{ workflow.keywordCountDescribe }} 个关键词
</p>
</TabPanel>
<TabPanel value="2">
<Textarea
v-model="keywordsAction"
placeholder="请输入行动词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">
已添加 {{ workflow.keywordCountAction }} 个关键词
</p>
</TabPanel>
<TabPanel value="3">
<Textarea
v-model="keywordsEmotion"
placeholder="请输入情感词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">
已添加 {{ workflow.keywordCountEmotion }} 个关键词
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</DashboardCard>
</template>

View File

@@ -0,0 +1,47 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const { autoSubtitle, smartSubtitle, bgmEnabled, bgmVolume } = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="字幕和音乐" step="05" :grow="true">
<label class="flex items-center gap-2 text-sm">
<Checkbox v-model="autoSubtitle" binary />
自动生成字幕
</label>
<label class="mt-2 flex items-center gap-2 text-sm">
<Checkbox v-model="smartSubtitle" binary />
启用智能字幕
</label>
<div class="mt-2 flex items-center gap-2">
<Button label="模板选择" size="small" outlined />
<span class="dashboard-muted truncate text-sm">已选模板: 未选择</span>
</div>
<label class="mt-3 flex items-center gap-2 text-sm">
<Checkbox v-model="bgmEnabled" binary />
添加背景音乐
</label>
<div class="mt-2 flex flex-wrap items-center gap-2">
<InputNumber
v-model="bgmVolume"
:min="0"
:max="100"
:disabled="!bgmEnabled"
size="small"
class="w-20"
/>
<span class="text-sm text-slate-400">%</span>
<Button label="选择音乐" size="small" severity="secondary" :disabled="!bgmEnabled" />
<Button label="试听" size="small" outlined :disabled="!bgmEnabled" />
</div>
<Button
label="自动生成字幕和BGM"
size="small"
class="mt-3 w-full"
:disabled="!autoSubtitle && !bgmEnabled"
/>
</DashboardCard>
</template>

View File

@@ -0,0 +1,15 @@
<script setup>
</script>
<template>
<DashboardCard title="封面制作" step="06">
<Button label="自动生成封面" size="small" class="w-full" />
<Button label="封面设置" size="small" severity="secondary" class="mt-2 w-full" />
<div class="mt-3">
<div class="dashboard-field-label mb-2">封面预览</div>
<div class="dashboard-aspect-video">
<span class="dashboard-muted text-sm">暂无封面预览</span>
</div>
</div>
</DashboardCard>
</template>

View File

@@ -0,0 +1,33 @@
<script setup>
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
</script>
<template>
<DashboardCard title="视频发布" step="07" :grow="true">
<div
v-for="(platform, index) in workflow.publishPlatforms"
:key="index"
class="dashboard-platform-row mb-2"
>
<label class="flex shrink-0 items-center gap-2 text-sm" style="min-width: 70px">
<Checkbox v-model="platform.checked" binary />
{{ platform.label }}
</label>
<Select
v-model="platform.account"
placeholder="选择账号"
size="small"
class="min-w-0 flex-1"
/>
</div>
<div class="mt-3 flex gap-2">
<Button label="发布" size="small" class="flex-1" />
<Button label="定时发布" size="small" class="flex-1" />
</div>
<p class="mt-2 text-center text-xs leading-relaxed text-gray-400 opacity-80">
首次发布请手动关闭浏览器内出现的任何弹窗提示说明等防止干扰脚本下次即可流畅运行
</p>
</DashboardCard>
</template>

View File

@@ -0,0 +1,41 @@
<script setup>
import { storeToRefs } from "pinia";
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
const { scriptContent, editLanguage, editWordCount } = storeToRefs(workflow);
</script>
<template>
<DashboardCard title="视频文案编辑" :grow="true">
<div class="space-y-2">
<div class="dashboard-field-label">文案内容</div>
<Textarea
v-model="scriptContent"
placeholder="文案内容将显示在这里..."
class="dashboard-textarea-mono w-full"
rows="12"
/>
<div class="flex flex-wrap items-center gap-2 pt-1">
<InputNumber
v-model="editWordCount"
:min="100"
:max="2000"
size="small"
class="w-28"
/>
<span class="text-xs text-slate-400"></span>
<Select
v-model="editLanguage"
:options="workflow.languages"
size="small"
class="w-36"
/>
</div>
<div class="flex gap-2 pt-1">
<Button label="撰写文案" size="small" />
<Button label="AI法务" size="small" severity="secondary" />
</div>
</div>
</DashboardCard>
</template>

View File

@@ -0,0 +1,20 @@
<script setup>
import { useWorkflowStore } from "../../stores/workflow.js";
const workflow = useWorkflowStore();
function onClearData() {
workflow.clearData();
}
</script>
<template>
<section class="dashboard-card p-3">
<button type="button" class="dashboard-one-click">开启一键自动</button>
<div class="mt-2 grid grid-cols-2 gap-2">
<Button label="停止任务" size="small" text severity="danger" />
<Button label="清除数据" size="small" text severity="danger" @click="onClearData" />
</div>
<Button label="智能体配置" size="small" outlined class="mt-2 w-full" />
</section>
</template>

91
src/stores/workflow.js Normal file
View File

@@ -0,0 +1,91 @@
import { defineStore } from "pinia";
const defaultPublishPlatforms = () => [
{ label: "*音", checked: false, account: null },
{ label: "*手", checked: false, account: null },
{ label: "*频号", checked: false, account: null },
{ label: "*红书", checked: false, account: null },
];
export const useWorkflowStore = defineStore("workflow", {
state: () => ({
// 01 IP 深度学习
ipMode: "ipBrain",
recognizedContent: "",
videoType: "口播文案",
copyType: "人设型",
industryPersona: "",
productBusiness: "",
sellingPrice: "",
otherRequirements: "",
targetWords: 300,
// 视频文案编辑
scriptContent: "",
editLanguage: "中文(普通话)",
editWordCount: 300,
// 02 音视频生成
voiceEmotion: "自然",
speechRate: 1,
voiceLanguage: "中文(普通话)",
avatarSelect: null,
// 03 视频编辑
pipInPicture: false,
autoCutBreath: false,
greenScreen: false,
// 04 标题标签关键词
titleGenerated: "",
tagsGenerated: "",
keywordTab: "0",
keywordsFocus: "",
keywordsDescribe: "",
keywordsAction: "",
keywordsEmotion: "",
// 05 字幕和音乐
autoSubtitle: false,
smartSubtitle: true,
bgmEnabled: false,
bgmVolume: 30,
subtitleTemplate: null,
// 07 视频发布
publishPlatforms: defaultPublishPlatforms(),
}),
getters: {
ipModes: () => [
{ label: "IP学习", value: "ipBrain" },
{ label: "视频学习", value: "videoWrite" },
{ label: "爆款文案", value: "customPrompt" },
],
videoTypes: () => ["口播文案", "剧情文案", "带货文案"],
copyTypes: () => ["人设型", "卖点型", "故事型"],
voiceEmotions: () => ["自然", "热情", "沉稳"],
languages: () => ["中文(普通话)", "中文(粤语)", "English"],
avatarOptions: () => [{ label: "请选择形象", value: null }],
keywordCountFocus: (state) => countLines(state.keywordsFocus),
keywordCountDescribe: (state) => countLines(state.keywordsDescribe),
keywordCountAction: (state) => countLines(state.keywordsAction),
keywordCountEmotion: (state) => countLines(state.keywordsEmotion),
},
actions: {
resetAll() {
this.$reset();
this.publishPlatforms = defaultPublishPlatforms();
},
clearData() {
this.resetAll();
},
},
});
function countLines(text) {
if (!text?.trim()) return 0;
return text.split("\n").filter((line) => line.trim()).length;
}

View File

@@ -1,464 +1,37 @@
<script setup> <script setup>
import { ref } from "vue"; import Step01IpLearning from "../components/workflow/Step01IpLearning.vue";
const ipMode = ref("ipBrain"); import StepScriptEditor from "../components/workflow/StepScriptEditor.vue";
const ipModes = [ import Step02AudioVideo from "../components/workflow/Step02AudioVideo.vue";
{ label: "IP学习", value: "ipBrain" }, import Step03VideoEdit from "../components/workflow/Step03VideoEdit.vue";
{ label: "视频学习", value: "videoWrite" }, import Step04TitleTags from "../components/workflow/Step04TitleTags.vue";
{ label: "爆款文案", value: "customPrompt" }, import Step05SubtitleMusic from "../components/workflow/Step05SubtitleMusic.vue";
]; import WorkflowQuickActions from "../components/workflow/WorkflowQuickActions.vue";
import Step06Cover from "../components/workflow/Step06Cover.vue";
const videoType = ref("口播文案"); import Step07Publish from "../components/workflow/Step07Publish.vue";
const videoTypes = ["口播文案", "剧情文案", "带货文案"];
const copyType = ref("人设型");
const copyTypes = ["人设型", "卖点型", "故事型"];
const scriptContent = ref("");
const industryPersona = ref("");
const productBusiness = ref("");
const sellingPrice = ref("");
const otherRequirements = ref("");
const targetWords = ref(300);
const voiceEmotion = ref("自然");
const voiceEmotions = ["自然", "热情", "沉稳"];
const speechRate = ref(1);
const voiceLanguage = ref("中文(普通话)");
const languages = ["中文(普通话)", "中文(粤语)", "English"];
const avatarSelect = ref(null);
const avatarOptions = [{ label: "请选择形象", value: null }];
const editLanguage = ref("中文(普通话)");
const editWordCount = ref(300);
const titleGenerated = ref("");
const tagsGenerated = ref("");
const keywordTab = ref("0");
const keywordsFocus = ref("");
const autoSubtitle = ref(false);
const smartSubtitle = ref(true);
const bgmEnabled = ref(false);
const bgmVolume = ref(30);
const pipInPicture = ref(false);
const autoCutBreath = ref(false);
const greenScreen = ref(false);
const publishPlatforms = ref([
{ label: "*音", checked: false, account: null },
{ label: "*手", checked: false, account: null },
{ label: "*频号", checked: false, account: null },
{ label: "*红书", checked: false, account: null },
]);
</script> </script>
<template> <template>
<div class="dashboard-page custom-scrollbar"> <div class="dashboard-page custom-scrollbar">
<div class="dashboard-grid"> <div class="dashboard-grid">
<!-- 1 -->
<div class="dashboard-col"> <div class="dashboard-col">
<DashboardCard title="IP深度学习" step="01"> <Step01IpLearning />
<SelectButton <StepScriptEditor />
v-model="ipMode"
:options="ipModes"
option-label="label"
option-value="value"
class="mb-3 w-full"
size="small"
/>
<template v-if="ipMode === 'ipBrain'">
<Button label="添加IP大脑" class="w-full" size="small" />
<div class="mt-3">
<div class="dashboard-field-label">
已学习到的对标
<span class="dashboard-field-label--muted text-xs">(0/5)</span>
</div>
<p class="dashboard-muted py-2">暂无对标</p>
</div>
<div class="mt-3">
<div class="dashboard-field-label mb-2">选题库</div>
<p class="dashboard-muted py-2 text-center text-sm">请先选择一个对标</p>
</div>
</template>
<template v-else-if="ipMode === 'videoWrite'">
<Button label="打开视频链接" class="w-full" size="small" />
<div class="mt-3 space-y-1">
<div class="dashboard-field-label flex items-center gap-1">
<span>识别的原始内容</span>
<span class="text-xs font-normal text-slate-500">(使用视频仿写功能后显示)</span>
</div>
<Textarea
readonly
placeholder="使用【打开视频链接】功能后,识别的原始内容将显示在这里..."
class="dashboard-textarea-mono w-full"
rows="10"
/>
</div>
</template>
<template v-else>
<div class="space-y-2.5">
<div>
<div class="dashboard-field-label">
视频类型 <span class="text-xs text-red-400">*</span>
</div>
<Select v-model="videoType" :options="videoTypes" size="small" class="w-full" />
</div>
<div>
<div class="dashboard-field-label">
文案类型 <span class="text-xs text-red-400">*</span>
</div>
<Select v-model="copyType" :options="copyTypes" size="small" class="w-full" />
</div>
<div>
<div class="dashboard-field-label">
行业+人设 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="industryPersona"
placeholder="例如餐饮店我叫斌哥在上海有10年餐饮经验"
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
产品/业务 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="productBusiness"
placeholder="例如:纸巾,麻辣烫,房产,教培,财务..."
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
卖点+价格 <span class="text-xs text-slate-400">可选</span>
</div>
<InputText
v-model="sellingPrice"
placeholder="例如纸张柔软亲肤正常价99今天只要59元"
size="small"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">
其他要求 <span class="text-xs text-slate-400">可选</span>
</div>
<Textarea
v-model="otherRequirements"
placeholder="例如风格幽默突出性价比适合30-50岁人群..."
rows="3"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label">目标字数</div>
<div class="flex items-center gap-2">
<Slider v-model="targetWords" :min="50" :max="1500" class="flex-1" />
<InputNumber
v-model="targetWords"
:min="50"
:max="1500"
size="small"
class="w-24"
/>
</div>
</div>
<Button label="生成爆款文案" size="small" class="w-full" />
</div>
</template>
</DashboardCard>
<DashboardCard title="视频文案编辑" :grow="true">
<div class="space-y-2">
<div class="dashboard-field-label">文案内容</div>
<Textarea
v-model="scriptContent"
placeholder="文案内容将显示在这里..."
class="dashboard-textarea-mono w-full"
rows="12"
/>
<div class="flex flex-wrap items-center gap-2 pt-1">
<InputNumber
v-model="editWordCount"
:min="100"
:max="2000"
size="small"
class="w-28"
/>
<span class="text-xs text-slate-400"></span>
<Select
v-model="editLanguage"
:options="languages"
size="small"
class="w-36"
/>
</div>
<div class="flex gap-2 pt-1">
<Button label="撰写文案" size="small" />
<Button label="AI法务" size="small" severity="secondary" />
</div>
</div>
</DashboardCard>
</div> </div>
<!-- 2 -->
<div class="dashboard-col"> <div class="dashboard-col">
<DashboardCard title="音视频生成" step="02"> <Step02AudioVideo />
<div class="grid grid-cols-3 gap-2"> <Step03VideoEdit />
<div>
<div class="mb-1 text-xs text-slate-200">音色</div>
<Button
label="选择音色"
size="small"
severity="secondary"
outlined
class="w-full"
/>
</div>
<div>
<div class="mb-1 text-xs text-slate-200">情绪</div>
<Select
v-model="voiceEmotion"
:options="voiceEmotions"
size="small"
class="w-full"
/>
</div>
<div>
<div class="mb-1 text-xs text-slate-200">语速</div>
<InputNumber
v-model="speechRate"
:min="0.5"
:max="2"
:step="0.1"
size="small"
class="w-full"
/>
</div>
</div>
<div class="mt-3 flex items-end gap-2">
<div class="min-w-0 flex-1">
<div class="mb-1 text-xs text-slate-200">语言</div>
<Select
v-model="voiceLanguage"
:options="languages"
size="small"
class="w-full"
/>
</div>
<Button label="生成语音" size="small" class="shrink-0" />
</div>
<div class="dashboard-preview-box mt-3">
<div class="mb-2 flex items-center justify-between gap-2">
<span class="text-xs text-slate-400">音频预览</span>
<Select placeholder="暂无历史记录" disabled size="small" class="w-40" />
</div>
<p class="py-4 text-center text-xs text-gray-500">
暂无音频请生成或选择历史记录
</p>
</div>
<div class="mt-3">
<div class="mb-2 text-xs text-slate-400">选择形象</div>
<Select
v-model="avatarSelect"
:options="avatarOptions"
option-label="label"
option-value="value"
placeholder="请选择形象"
size="small"
class="w-full"
/>
</div>
<Button label="生成口播视频" size="small" class="mt-3 w-full" />
<div class="mt-2">
<div class="mb-1 text-xs text-slate-200">视频预览</div>
<div class="dashboard-aspect-video">
<span class="text-xs text-gray-400">暂无视频预览</span>
</div>
</div>
</DashboardCard>
<DashboardCard title="视频编辑" step="03" :grow="true">
<div class="flex flex-col gap-2">
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="pipInPicture" binary />
画中画
</label>
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="autoCutBreath" binary />
自动剪气口
</label>
<label class="flex items-center gap-2 text-sm text-slate-200">
<Checkbox v-model="greenScreen" binary />
启动绿幕切换
</label>
<Button label="自动处理" size="small" class="w-full" disabled />
</div>
</DashboardCard>
</div> </div>
<!-- 3 -->
<div class="dashboard-col"> <div class="dashboard-col">
<DashboardCard title="标题标签关键词" step="04"> <Step04TitleTags />
<Button label="生成标题标签关键词" size="small" class="mb-3 w-full" /> <Step05SubtitleMusic />
<div class="mb-3">
<div class="dashboard-field-label mb-1">生成的标题可编辑</div>
<Textarea
v-model="titleGenerated"
placeholder="标题将显示在这里..."
rows="2"
class="w-full"
/>
</div>
<div class="mb-3">
<div class="dashboard-field-label mb-1">生成的标签可编辑</div>
<Textarea
v-model="tagsGenerated"
placeholder="标签将显示在这里,逗号分隔..."
rows="2"
class="w-full"
/>
</div>
<div>
<div class="dashboard-field-label mb-2">生成的关键词</div>
<Tabs v-model:value="keywordTab">
<TabList>
<Tab value="0">重点词/成语词</Tab>
<Tab value="1">描述词</Tab>
<Tab value="2">行动词</Tab>
<Tab value="3">情感词</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<Textarea
v-model="keywordsFocus"
placeholder="请输入重点词/成语词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">已添加 0 个关键词</p>
</TabPanel>
<TabPanel value="1">
<Textarea
placeholder="请输入描述词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">已添加 0 个关键词</p>
</TabPanel>
<TabPanel value="2">
<Textarea
placeholder="请输入行动词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">已添加 0 个关键词</p>
</TabPanel>
<TabPanel value="3">
<Textarea
placeholder="请输入情感词,每行一个..."
rows="8"
class="dashboard-textarea-mono w-full"
/>
<p class="dashboard-muted mt-2 text-sm">已添加 0 个关键词</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</DashboardCard>
<DashboardCard title="字幕和音乐" step="05" :grow="true">
<label class="flex items-center gap-2 text-sm">
<Checkbox v-model="autoSubtitle" binary />
自动生成字幕
</label>
<label class="mt-2 flex items-center gap-2 text-sm">
<Checkbox v-model="smartSubtitle" binary />
启用智能字幕
</label>
<div class="mt-2 flex items-center gap-2">
<Button label="模板选择" size="small" outlined />
<span class="dashboard-muted truncate text-sm">已选模板: 未选择</span>
</div>
<label class="mt-3 flex items-center gap-2 text-sm">
<Checkbox v-model="bgmEnabled" binary />
添加背景音乐
</label>
<div class="mt-2 flex flex-wrap items-center gap-2">
<InputNumber
v-model="bgmVolume"
:min="0"
:max="100"
:disabled="!bgmEnabled"
size="small"
class="w-20"
/>
<span class="text-sm text-slate-400">%</span>
<Button label="选择音乐" size="small" severity="secondary" :disabled="!bgmEnabled" />
<Button label="试听" size="small" outlined :disabled="!bgmEnabled" />
</div>
<Button
label="自动生成字幕和BGM"
size="small"
class="mt-3 w-full"
:disabled="!autoSubtitle && !bgmEnabled"
/>
</DashboardCard>
</div> </div>
<!-- 4 -->
<div class="dashboard-col"> <div class="dashboard-col">
<section class="dashboard-card p-3"> <WorkflowQuickActions />
<button type="button" class="dashboard-one-click">开启一键自动</button> <Step06Cover />
<div class="mt-2 grid grid-cols-2 gap-2"> <Step07Publish />
<Button label="停止任务" size="small" text severity="danger" />
<Button label="清除数据" size="small" text severity="danger" />
</div>
<Button label="智能体配置" size="small" outlined class="mt-2 w-full" />
</section>
<DashboardCard title="封面制作" step="06">
<Button label="自动生成封面" size="small" class="w-full" />
<Button label="封面设置" size="small" severity="secondary" class="mt-2 w-full" />
<div class="mt-3">
<div class="dashboard-field-label mb-2">封面预览</div>
<div class="dashboard-aspect-video">
<span class="dashboard-muted text-sm">暂无封面预览</span>
</div>
</div>
</DashboardCard>
<DashboardCard title="视频发布" step="07" :grow="true">
<div
v-for="(platform, index) in publishPlatforms"
:key="index"
class="dashboard-platform-row mb-2"
>
<label class="flex shrink-0 items-center gap-2 text-sm" style="min-width: 70px">
<Checkbox v-model="platform.checked" binary />
{{ platform.label }}
</label>
<Select
v-model="platform.account"
placeholder="选择账号"
size="small"
class="min-w-0 flex-1"
/>
</div>
<div class="mt-3 flex gap-2">
<Button label="发布" size="small" class="flex-1" />
<Button label="定时发布" size="small" class="flex-1" />
</div>
<p class="mt-2 text-center text-xs leading-relaxed text-gray-400 opacity-80">
首次发布请手动关闭浏览器内出现的任何弹窗提示说明等防止干扰脚本下次即可流畅运行
</p>
</DashboardCard>
</div> </div>
</div> </div>
</div> </div>