11
This commit is contained in:
119
src/components/voice/BatchTextSynthesizeDialog.vue
Normal file
119
src/components/voice/BatchTextSynthesizeDialog.vue
Normal file
@@ -0,0 +1,119 @@
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const visible = defineModel("visible", { type: Boolean, default: false });
|
||||
const emit = defineEmits(["submit"]);
|
||||
|
||||
const lines = ref([{ text: "" }]);
|
||||
const pasteVisible = ref(false);
|
||||
const pasteRaw = ref("");
|
||||
|
||||
function addLine() {
|
||||
lines.value.push({ text: "" });
|
||||
}
|
||||
|
||||
function removeLine(index) {
|
||||
lines.value.splice(index, 1);
|
||||
}
|
||||
|
||||
function openPaste() {
|
||||
pasteRaw.value = "";
|
||||
pasteVisible.value = true;
|
||||
}
|
||||
|
||||
function confirmPaste() {
|
||||
const items = pasteRaw.value
|
||||
.split("\n")
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
if (items.length) {
|
||||
lines.value = items.map((text) => ({ text }));
|
||||
}
|
||||
pasteVisible.value = false;
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
const payload = lines.value.map((l) => ({ text: String(l.text || "").trim() }));
|
||||
if (!payload.length || payload.some((l) => !l.text)) {
|
||||
window.alert("所有内容不能为空");
|
||||
return;
|
||||
}
|
||||
emit("submit", payload);
|
||||
visible.value = false;
|
||||
lines.value = [{ text: "" }];
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog
|
||||
v-model:visible="visible"
|
||||
modal
|
||||
header="批量文本合成"
|
||||
:style="{ width: '80vw', maxWidth: '960px' }"
|
||||
:draggable="false"
|
||||
>
|
||||
<div class="mb-3 flex flex-wrap items-center gap-2">
|
||||
<Button label="添加一条" size="small" icon="pi pi-plus" @click="addLine" />
|
||||
<Button
|
||||
label="批量粘贴"
|
||||
size="small"
|
||||
icon="pi pi-clone"
|
||||
severity="secondary"
|
||||
outlined
|
||||
@click="openPaste"
|
||||
/>
|
||||
<span class="text-sm text-slate-500">共 {{ lines.length }} 条</span>
|
||||
</div>
|
||||
|
||||
<div v-if="!lines.length" class="py-12 text-center text-sm text-slate-500">
|
||||
暂无内容
|
||||
</div>
|
||||
<div v-else class="max-h-[50vh] space-y-2 overflow-y-auto pr-1">
|
||||
<div
|
||||
v-for="(line, index) in lines"
|
||||
:key="index"
|
||||
class="flex gap-2 rounded-lg border border-white/10 bg-white/5 p-3"
|
||||
>
|
||||
<Textarea
|
||||
v-model="line.text"
|
||||
rows="2"
|
||||
auto-resize
|
||||
class="flex-1"
|
||||
placeholder="输入内容"
|
||||
:maxlength="1000"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-trash"
|
||||
size="small"
|
||||
severity="danger"
|
||||
text
|
||||
aria-label="删除"
|
||||
@click="removeLine(index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<Button label="取消" severity="secondary" text @click="visible = false" />
|
||||
<Button label="提交合成" @click="onSubmit" />
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<Dialog
|
||||
v-model:visible="pasteVisible"
|
||||
modal
|
||||
header="批量粘贴,每行一条"
|
||||
:style="{ width: '70vw', maxWidth: '720px' }"
|
||||
>
|
||||
<Textarea
|
||||
v-model="pasteRaw"
|
||||
rows="12"
|
||||
class="w-full"
|
||||
placeholder="批量粘贴,每行一个"
|
||||
/>
|
||||
<template #footer>
|
||||
<Button label="确定" @click="confirmPaste" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -13,8 +13,44 @@ import {
|
||||
import { previewVoice } from "../../services/voicePreview.js";
|
||||
import VoiceCloneEditDialog from "./VoiceCloneEditDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
/** 声音页等独立场景:由父组件控制显隐与选中音色 */
|
||||
standalone: { type: Boolean, default: false },
|
||||
visible: { type: Boolean, default: false },
|
||||
selectedVoiceId: { type: String, default: "sys_Cherry" },
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "update:selectedVoiceId", "select"]);
|
||||
|
||||
const workflow = useWorkflowStore();
|
||||
const { voiceManageModalVisible, selectedVoiceId } = storeToRefs(workflow);
|
||||
const { voiceManageModalVisible, selectedVoiceId: workflowVoiceId } =
|
||||
storeToRefs(workflow);
|
||||
|
||||
const dialogVisible = computed({
|
||||
get() {
|
||||
return props.standalone ? props.visible : voiceManageModalVisible.value;
|
||||
},
|
||||
set(v) {
|
||||
if (props.standalone) {
|
||||
emit("update:visible", v);
|
||||
} else {
|
||||
voiceManageModalVisible.value = v;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const currentVoiceId = computed({
|
||||
get() {
|
||||
return props.standalone ? props.selectedVoiceId : workflowVoiceId.value;
|
||||
},
|
||||
set(v) {
|
||||
if (props.standalone) {
|
||||
emit("update:selectedVoiceId", v);
|
||||
} else {
|
||||
workflowVoiceId.value = v;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const activeTab = ref("system");
|
||||
const voiceCategory = ref("putonghua");
|
||||
@@ -41,7 +77,7 @@ function loadCloneVoices() {
|
||||
}
|
||||
}
|
||||
|
||||
watch(voiceManageModalVisible, (open) => {
|
||||
watch(dialogVisible, (open) => {
|
||||
if (open) {
|
||||
activeTab.value = "system";
|
||||
voiceCategory.value = "putonghua";
|
||||
@@ -63,11 +99,21 @@ function stopPreview() {
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
workflow.closeVoiceManageDialog();
|
||||
if (props.standalone) {
|
||||
dialogVisible.value = false;
|
||||
} else {
|
||||
workflow.closeVoiceManageDialog();
|
||||
}
|
||||
}
|
||||
|
||||
function onSelectVoice(voiceId) {
|
||||
workflow.selectVoice(voiceId);
|
||||
if (props.standalone) {
|
||||
currentVoiceId.value = voiceId;
|
||||
emit("select", voiceId);
|
||||
dialogVisible.value = false;
|
||||
} else {
|
||||
workflow.selectVoice(voiceId);
|
||||
}
|
||||
}
|
||||
|
||||
function onAddClone() {
|
||||
@@ -81,8 +127,12 @@ function onEditClone(record) {
|
||||
function onDeleteClone(record) {
|
||||
if (!window.confirm(`确认删除音色「${record.title}」?`)) return;
|
||||
deleteCloneVoice(record.id);
|
||||
if (selectedVoiceId.value === record.id) {
|
||||
workflow.selectVoice("sys_Cherry");
|
||||
if (currentVoiceId.value === record.id) {
|
||||
if (props.standalone) {
|
||||
currentVoiceId.value = "sys_Cherry";
|
||||
} else {
|
||||
workflow.selectVoice("sys_Cherry");
|
||||
}
|
||||
}
|
||||
if (previewPanelKey.value === record.id) {
|
||||
stopPreview();
|
||||
@@ -144,7 +194,7 @@ function showPreviewPlayer(key) {
|
||||
|
||||
<template>
|
||||
<Dialog
|
||||
v-model:visible="voiceManageModalVisible"
|
||||
v-model:visible="dialogVisible"
|
||||
modal
|
||||
header="音色管理"
|
||||
:style="{ width: '900px' }"
|
||||
|
||||
Reference in New Issue
Block a user