update:区分本地化部署和非本地化部署tts的配置字段

This commit is contained in:
hrz
2025-06-30 16:56:56 +08:00
parent 7619979046
commit c68384be69
2 changed files with 110 additions and 114 deletions
+106 -112
View File
@@ -1,88 +1,63 @@
<template> <template>
<el-dialog <el-dialog :visible.sync="localVisible" width="90%" @close="handleClose" :show-close="false" :append-to-body="true"
:visible.sync="localVisible" :close-on-click-modal="true">
width="85%"
@close="handleClose"
:show-close="false"
:append-to-body="true"
:close-on-click-modal="true">
<button class="custom-close-btn" @click="handleClose"> <button class="custom-close-btn" @click="handleClose">
× ×
</button> </button>
<div class="scroll-wrapper"> <div class="scroll-wrapper">
<div <div class="table-container" ref="tableContainer" @scroll="handleScroll">
class="table-container" <el-table v-loading="loading" :data="filteredTtsModels" style="width: 100%;" class="data-table"
ref="tableContainer" header-row-class-name="table-header" :fit="true" element-loading-text="拼命加载中"
@scroll="handleScroll"> element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)">
<el-table
v-loading="loading"
:data="filteredTtsModels"
style="width: 100%;"
class="data-table"
header-row-class-name="table-header"
:fit="true"
element-loading-text="拼命加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)">
<el-table-column label="选择" width="50" align="center"> <el-table-column label="选择" width="50" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-checkbox v-model="scope.row.selected"></el-checkbox> <el-checkbox v-model="scope.row.selected"></el-checkbox>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="音色编码" align="center" min-width="50"> <el-table-column label="音色编码" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-if="scope.row.editing" v-model="scope.row.voiceCode"></el-input> <el-input v-if="scope.row.editing" v-model="scope.row.voiceCode"></el-input>
<span v-else>{{ scope.row.voiceCode }}</span> <span v-else>{{ scope.row.voiceCode }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="音色名称" align="center" min-width="50"> <el-table-column label="音色名称" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-if="scope.row.editing" v-model="scope.row.voiceName"></el-input> <el-input v-if="scope.row.editing" v-model="scope.row.voiceName"></el-input>
<span v-else>{{ scope.row.voiceName }}</span> <span v-else>{{ scope.row.voiceName }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="语言类型" align="center" min-width="50"> <el-table-column label="语言类型" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-if="scope.row.editing" v-model="scope.row.languageType"></el-input> <el-input v-if="scope.row.editing" v-model="scope.row.languageType"></el-input>
<span v-else>{{ scope.row.languageType }}</span> <span v-else>{{ scope.row.languageType }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="试听" align="center" min-width="100px" class-name="audio-column"> <el-table-column v-if="!showReferenceColumns" label="试听" align="center" class-name="audio-column">
<template slot-scope="scope"> <template slot-scope="scope">
<div class="custom-audio-container"> <div class="custom-audio-container">
<el-input <el-input v-if="scope.row.editing" v-model="scope.row.voiceDemo" placeholder="请输入MP3地址"
v-if="scope.row.editing" class="audio-input">
v-model="scope.row.voiceDemo"
placeholder="请输入MP3地址"
size="mini"
class="audio-input">
</el-input> </el-input>
<AudioPlayer v-else-if="isValidAudioUrl(scope.row.voiceDemo)" :audioUrl="scope.row.voiceDemo"/> <AudioPlayer v-else-if="isValidAudioUrl(scope.row.voiceDemo)" :audioUrl="scope.row.voiceDemo" />
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="备注" align="center"> <el-table-column v-if="!showReferenceColumns" label="备注" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input <el-input v-if="scope.row.editing" type="textarea" :rows="1" autosize v-model="scope.row.remark"
v-if="scope.row.editing" placeholder="这里是备注" class="remark-input"></el-input>
type="textarea"
:rows="1"
autosize
v-model="scope.row.remark"
placeholder="这里是备注"
class="remark-input"></el-input>
<span v-else>{{ scope.row.remark }}</span> <span v-else>{{ scope.row.remark }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="音频路径" align="center"> <el-table-column v-if="showReferenceColumns" label="克隆音频路径" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-if="scope.row.editing" v-model="scope.row.referenceAudio" placeholder="这里是参考音频路径 (本地模型用)"></el-input> <el-input v-if="scope.row.editing" v-model="scope.row.referenceAudio" placeholder="这里是克隆音频路径"></el-input>
<span v-else>{{ scope.row.referenceAudio }}</span> <span v-else>{{ scope.row.referenceAudio }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="音频文本" align="center"> <el-table-column v-if="showReferenceColumns" label="克隆音频文本" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-if="scope.row.editing" v-model="scope.row.referenceText" placeholder="这里是参考音频文本 (本地模型用)"></el-input> <el-input v-if="scope.row.editing" v-model="scope.row.referenceText" placeholder="这里是克隆音频对应文本"></el-input>
<span v-else>{{ scope.row.referenceText }}</span> <span v-else>{{ scope.row.referenceText }}</span>
</template> </template>
</el-table-column> </el-table-column>
@@ -96,12 +71,7 @@
删除 删除
</el-button> </el-button>
</template> </template>
<el-button <el-button v-else type="success" size="mini" @click="saveEdit(scope.row)" class="save-Tts">保存
v-else
type="success"
size="mini"
@click="saveEdit(scope.row)"
class="save-Tts">保存
</el-button> </el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -122,21 +92,19 @@
<el-button type="primary" size="mini" @click="addNew" style="background: #5bc98c;border: None;"> <el-button type="primary" size="mini" @click="addNew" style="background: #5bc98c;border: None;">
新增 新增
</el-button> </el-button>
<el-button type="primary" <el-button type="primary" size="mini" @click="deleteRow(filteredTtsModels.filter(row => row.selected))"
size="mini" style="background: red;border:None">删除
@click="deleteRow(filteredTtsModels.filter(row => row.selected))"
style="background: red;border:None">删除
</el-button> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script> <script>
import AudioPlayer from './AudioPlayer.vue'
import Api from "@/apis/api"; import Api from "@/apis/api";
import AudioPlayer from './AudioPlayer.vue';
export default { export default {
components: {AudioPlayer}, components: { AudioPlayer },
props: { props: {
visible: { visible: {
type: Boolean, type: Boolean,
@@ -145,6 +113,10 @@ export default {
ttsModelId: { ttsModelId: {
type: String, type: String,
required: true required: true
},
modelConfig: {
type: Object,
default: null
} }
}, },
data() { data() {
@@ -163,6 +135,7 @@ export default {
selectAll: false, selectAll: false,
selectedRows: [], selectedRows: [],
loading: false, loading: false,
showReferenceColumns: false, // 控制是否显示参考列
}; };
}, },
watch: { watch: {
@@ -170,12 +143,19 @@ export default {
this.localVisible = newVal; this.localVisible = newVal;
if (newVal) { if (newVal) {
this.currentPage = 1; this.currentPage = 1;
this.updateShowReferenceColumns(); // 更新显示状态
this.loadData(); // 对话框显示时加载数据 this.loadData(); // 对话框显示时加载数据
this.$nextTick(() => { this.$nextTick(() => {
this.updateScrollbar(); this.updateScrollbar();
}); });
} }
}, },
modelConfig: {
handler(newVal) {
this.updateShowReferenceColumns();
},
immediate: true
},
filteredTtsModels() { filteredTtsModels() {
this.$nextTick(() => { this.$nextTick(() => {
this.updateScrollbar(); this.updateScrollbar();
@@ -185,7 +165,7 @@ export default {
computed: { computed: {
filteredTtsModels() { filteredTtsModels() {
return this.ttsModels.filter(model => return this.ttsModels.filter(model =>
model.voiceName.toLowerCase().includes(this.searchQuery.toLowerCase()) model.voiceName.toLowerCase().includes(this.searchQuery.toLowerCase())
); );
} }
}, },
@@ -201,6 +181,16 @@ export default {
window.removeEventListener('mousemove', this.handleDrag); window.removeEventListener('mousemove', this.handleDrag);
}, },
methods: { methods: {
// 更新是否显示参考列
updateShowReferenceColumns() {
if (this.modelConfig && this.modelConfig.configJson) {
const providerType = this.modelConfig.configJson.type;
this.showReferenceColumns = ['fishspeech', 'gpt_sovits_v2', 'gpt_sovits_v3'].includes(providerType);
} else {
this.showReferenceColumns = false;
}
},
loadData() { loadData() {
this.loading = true; this.loading = true;
const params = { const params = {
@@ -251,6 +241,7 @@ export default {
this.total = 0; this.total = 0;
this.selectAll = false; this.selectAll = false;
this.searchQuery = ''; this.searchQuery = '';
this.showReferenceColumns = false;
this.localVisible = false; this.localVisible = false;
this.$emit('update:visible', false); this.$emit('update:visible', false);
@@ -263,7 +254,7 @@ export default {
if (!container || !scrollbarThumb || !scrollbarTrack) return; if (!container || !scrollbarThumb || !scrollbarTrack) return;
const {scrollHeight, clientHeight} = container; const { scrollHeight, clientHeight } = container;
const trackHeight = scrollbarTrack.clientHeight; const trackHeight = scrollbarTrack.clientHeight;
const thumbHeight = Math.max((clientHeight / scrollHeight) * trackHeight, 20); const thumbHeight = Math.max((clientHeight / scrollHeight) * trackHeight, 20);
@@ -278,7 +269,7 @@ export default {
if (!container || !scrollbarThumb || !scrollbarTrack) return; if (!container || !scrollbarThumb || !scrollbarTrack) return;
const {scrollHeight, clientHeight, scrollTop} = container; const { scrollHeight, clientHeight, scrollTop } = container;
const trackHeight = scrollbarTrack.clientHeight; const trackHeight = scrollbarTrack.clientHeight;
const thumbHeight = scrollbarThumb.clientHeight; const thumbHeight = scrollbarThumb.clientHeight;
const maxTop = trackHeight - thumbHeight; const maxTop = trackHeight - thumbHeight;
@@ -346,7 +337,7 @@ export default {
startEdit(row) { startEdit(row) {
row.editing = true; row.editing = true;
this.$set(row, 'originalData', {...row}); this.$set(row, 'originalData', { ...row });
}, },
saveEdit(row) { saveEdit(row) {
@@ -365,13 +356,17 @@ export default {
voiceName: row.voiceName, voiceName: row.voiceName,
languageType: row.languageType, languageType: row.languageType,
remark: row.remark, remark: row.remark,
referenceAudio: row.referenceAudio,
referenceText: row.referenceText,
ttsModelId: this.ttsModelId, ttsModelId: this.ttsModelId,
voiceDemo: row.voiceDemo || '', voiceDemo: row.voiceDemo || '',
sort: row.sort sort: row.sort
}; };
// 只有在显示参考列的情况下才添加参考字段
if (this.showReferenceColumns) {
params.referenceAudio = row.referenceAudio;
params.referenceText = row.referenceText;
}
let res; let res;
if (row.id) { if (row.id) {
// 已有ID,执行更新操作 // 已有ID,执行更新操作
@@ -439,8 +434,8 @@ export default {
} }
const maxSort = this.ttsModels.length > 0 const maxSort = this.ttsModels.length > 0
? Math.max(...this.ttsModels.map(item => Number(item.sort) || 0)) ? Math.max(...this.ttsModels.map(item => Number(item.sort) || 0))
: 0; : 0;
const newRow = { const newRow = {
voiceCode: '', voiceCode: '',
@@ -459,56 +454,56 @@ export default {
}, },
deleteRow(row) { deleteRow(row) {
// 处理单个音色或音色数组 // 处理单个音色或音色数组
const voices = Array.isArray(row) ? row : [row]; const voices = Array.isArray(row) ? row : [row];
if (Array.isArray(row) && row.length === 0) { if (Array.isArray(row) && row.length === 0) {
this.$message.warning("请先选择需要删除的音色"); this.$message.warning("请先选择需要删除的音色");
return; return;
}
const voiceCount = voices.length;
this.$confirm(`确定要删除选中的${voiceCount}个音色吗?`, "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
distinguishCancelAndClose: true
}).then(() => {
const ids = voices.map(voice => voice.id);
if (ids.some(id => !id)) {
this.$message.error("存在无效的音色ID");
return;
} }
Api.timbre.deleteVoice(ids, ({ data }) => {
const voiceCount = voices.length; if (data.code === 0) {
this.$confirm(`确定要删除选中的${voiceCount}个音色吗?`, "警告", { this.$message.success({
confirmButtonText: "确定", message: `成功删除${voiceCount}个参数`,
cancelButtonText: "取消", showClose: true
type: "warning", });
distinguishCancelAndClose: true this.loadData(); // 刷新参数列表
}).then(() => { } else {
const ids = voices.map(voice => voice.id); this.$message.error({
if (ids.some(id => !id)) { message: data.msg || '删除失败,请重试',
this.$message.error("存在无效的音色ID"); showClose: true
return; });
} }
Api.timbre.deleteVoice(ids, ({data}) => {
if (data.code === 0) {
this.$message.success({
message: `成功删除${voiceCount}个参数`,
showClose: true
});
this.loadData(); // 刷新参数列表
} else {
this.$message.error({
message: data.msg || '删除失败,请重试',
showClose: true
});
}
}); });
}).catch(action => { }).catch(action => {
if (action === 'cancel') { if (action === 'cancel') {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消删除操作', message: '已取消删除操作',
duration: 1000 duration: 1000
}); });
} else { } else {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '操作已关闭', message: '操作已关闭',
duration: 1000 duration: 1000
}); });
} }
}); });
}, },
@@ -520,7 +515,6 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-dialog { ::v-deep .el-dialog {
border-radius: 8px !important; border-radius: 8px !important;
overflow: hidden; overflow: hidden;
@@ -713,6 +707,7 @@ export default {
white-space: pre-wrap !important; white-space: pre-wrap !important;
word-break: break-all !important; word-break: break-all !important;
} }
/* 按钮组定位调整 */ /* 按钮组定位调整 */
.action-buttons { .action-buttons {
position: static; position: static;
@@ -737,5 +732,4 @@ export default {
flex-shrink: 0; flex-shrink: 0;
margin: 2px !important; margin: 2px !important;
} }
</style> </style>
+4 -2
View File
@@ -128,7 +128,7 @@
<ModelEditDialog :modelType="activeTab" :visible.sync="editDialogVisible" :modelData="editModelData" <ModelEditDialog :modelType="activeTab" :visible.sync="editDialogVisible" :modelData="editModelData"
@save="handleModelSave" /> @save="handleModelSave" />
<TtsModel :visible.sync="ttsDialogVisible" :ttsModelId="selectedTtsModelId" /> <TtsModel :visible.sync="ttsDialogVisible" :ttsModelId="selectedTtsModelId" :modelConfig="selectedModelConfig" />
<AddModelDialog :modelType="activeTab" :visible.sync="addDialogVisible" @confirm="handleAddConfirm" /> <AddModelDialog :modelType="activeTab" :visible.sync="addDialogVisible" @confirm="handleAddConfirm" />
</div> </div>
<el-footer> <el-footer>
@@ -162,7 +162,8 @@ export default {
total: 0, total: 0,
selectedModels: [], selectedModels: [],
isAllSelected: false, isAllSelected: false,
loading: false loading: false,
selectedModelConfig: {}
}; };
}, },
@@ -211,6 +212,7 @@ export default {
}, },
openTtsDialog(row) { openTtsDialog(row) {
this.selectedTtsModelId = row.id; this.selectedTtsModelId = row.id;
this.selectedModelConfig = row;
this.ttsDialogVisible = true; this.ttsDialogVisible = true;
}, },
headerCellClassName({ column, columnIndex }) { headerCellClassName({ column, columnIndex }) {