From 56352478fe985ede2307e5be6a15d7fe44dfe1f9 Mon Sep 17 00:00:00 2001
From: Ran_Chen <1908198662@qq.com>
Date: Wed, 9 Apr 2025 17:52:41 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=9F=B3=E8=89=B2=E2=80=9C?=
=?UTF-8?q?=E4=BF=AE=E6=94=B9=E2=80=9D=EF=BC=8C=E2=80=9C=E4=BF=9D=E5=AD=98?=
=?UTF-8?q?=E2=80=9D=E6=8E=A5=E5=8F=A3=E7=9A=84=E8=B0=83=E7=94=A8=EF=BC=8C?=
=?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8A=A5=E6=95=85=E9=9A=9C=EF=BC=8C=E9=9C=80?=
=?UTF-8?q?=E8=A6=81=E8=B0=83=E6=95=B4=E4=B8=80=E4=B8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
main/manager-web/src/apis/module/timbre.js | 118 +++++++--
main/manager-web/src/components/TtsModel.vue | 242 ++++++++++++++++---
2 files changed, 311 insertions(+), 49 deletions(-)
diff --git a/main/manager-web/src/apis/module/timbre.js b/main/manager-web/src/apis/module/timbre.js
index e00198a8..9b48e5c3 100644
--- a/main/manager-web/src/apis/module/timbre.js
+++ b/main/manager-web/src/apis/module/timbre.js
@@ -1,28 +1,102 @@
// timbre.js
-import { getServiceUrl } from '../api';
+import {getServiceUrl} from '../api';
import RequestService from '../httpRequest';
export default {
- getVoiceList(params, callback) {
- const queryParams = new URLSearchParams({
- ttsModelId: params.ttsModelId,
- page: params.page || 1,
- limit: params.limit || 10,
- name: params.name || ''
- }).toString();
+ /**
+ * 获取音色数据
+ */
+ getVoiceList(params, callback) {
+ const queryParams = new URLSearchParams({
+ ttsModelId: params.ttsModelId,
+ page: params.page || 1,
+ limit: params.limit || 10,
+ name: params.name || ''
+ }).toString();
- RequestService.sendRequest()
- .url(`${getServiceUrl()}/ttsVoice?${queryParams}`)
- .method('GET')
- .success((res) => {
- RequestService.clearRequestTime();
- callback(res.data || []);
- })
- .fail((err) => {
- console.error('获取音色列表失败:', err);
- RequestService.reAjaxFun(() => {
- this.getVoiceList(params, callback);
- });
- }).send();
- },
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res.data || []);
+ })
+ .fail((err) => {
+ console.error('获取音色列表失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.getVoiceList(params, callback);
+ });
+ }).send();
+ },
+ /**
+ * 音色保存
+ */
+ saveVoice(params, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice`)
+ .method('POST')
+ .data(JSON.stringify({
+ languages: params.languageType,
+ name: params.voiceName,
+ remark: params.remark,
+ sort: params.sort,
+ ttsModelId: params.ttsModelId,
+ ttsVoice: params.voiceCode,
+ voiceDemo: params.voiceDemo || ''
+ }))
+ .success((res) => {
+ callback(res.data);
+ })
+ .fail((err) => {
+ console.error('保存音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.saveVoice(params, callback);
+ });
+ }).send();
+ },
+ /**
+ * 音色删除
+ */
+ deleteVoice(id, callback) {
+ console.log('尝试删除音色,ID:', id);
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice`)
+ .method('DELETE')
+ .data({ ids: [id] })
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res);
+ })
+ .fail((err) => {
+ console.error('删除音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.deleteVoice(id, callback);
+ });
+ }).send();
+ },
+ /**
+ * 音色修改
+ */
+ updateVoice(params, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice/${params.id}`)
+ .method('PUT')
+ .data(JSON.stringify({
+ languages: params.languageType,
+ name: params.voiceName,
+ remark: params.remark,
+ ttsModelId: params.ttsModelId,
+ ttsVoice: params.voiceCode,
+ voiceDemo: params.voiceDemo || ''
+ }))
+ .success((res) => {
+ callback(res.data);
+ })
+ .fail((err) => {
+ console.error('修改音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.updateVoice(params, callback);
+ });
+ }).send();
+ }
}
\ No newline at end of file
diff --git a/main/manager-web/src/components/TtsModel.vue b/main/manager-web/src/components/TtsModel.vue
index 3ca93db0..e60bfbb0 100644
--- a/main/manager-web/src/components/TtsModel.vue
+++ b/main/manager-web/src/components/TtsModel.vue
@@ -48,8 +48,14 @@
@@ -99,7 +105,9 @@
{{ selectAll ? '取消全选' : '全选' }}
- 新增
+
+ 新增
+
删除
@@ -129,7 +137,7 @@ export default {
editVoiceData: {},
ttsModels: [],
currentPage: 1,
- pageSize: 100,
+ pageSize: 10000,
total: 0,
isDragging: false,
startY: 0,
@@ -182,28 +190,38 @@ export default {
limit: this.pageSize,
name: this.searchQuery
};
+
Api.timbre.getVoiceList(params, (data) => {
- console.log(data.data.list);
if (data.code === 0) {
- this.ttsModels = data.data.list.map(item => ({
- id: item.id || '',
- voiceCode: item.ttsVoice || '',
- voiceName: item.name || '未命名音色',
- languageType: item.languages || '',
- remark: item.remark || '',
- voiceDemo: item.voiceDemo || '',
- selected: false,
- editing: false
- }));
+ this.ttsModels = data.data.list
+ .map(item => ({
+ id: item.id || '',
+ voiceCode: item.ttsVoice || '',
+ voiceName: item.name || '未命名音色',
+ languageType: item.languages || '',
+ remark: item.remark || '',
+ voiceDemo: item.voiceDemo || '',
+ selected: false,
+ editing: false,
+ sort: Number(item.sort)
+ }))
+ .sort((a, b) => a.sort - b.sort);
this.total = data.total;
} else {
- this.$message.error(data.msg || '获取音色列表失败');
+ this.$message.error({
+ message: data.msg || '获取音色列表失败',
+ showClose: true
+ });
}
}, (err) => {
console.error('加载失败:', err);
- this.$message.error('加载音色数据失败');
+ this.$message.error({
+ message: '加载音色数据失败',
+ showClose: true
+ });
});
},
+
handleClose() {
// 重置状态
this.ttsModels = [];
@@ -215,6 +233,7 @@ export default {
this.localVisible = false;
this.$emit('update:visible', false);
},
+
updateScrollbar() {
const container = this.$refs.tableContainer;
const scrollbarThumb = this.$refs.scrollbarThumb;
@@ -229,6 +248,7 @@ export default {
scrollbarThumb.style.height = `${thumbHeight}px`;
this.updateThumbPosition();
},
+
updateThumbPosition() {
const container = this.$refs.tableContainer;
const scrollbarThumb = this.$refs.scrollbarThumb;
@@ -244,6 +264,7 @@ export default {
scrollbarThumb.style.top = `${Math.min(thumbTop, maxTop)}px`;
},
+
handleScroll() {
const container = this.$refs.tableContainer;
if (container.scrollTop + container.clientHeight >= container.scrollHeight - 50) {
@@ -254,15 +275,18 @@ export default {
}
this.updateThumbPosition();
},
+
startDrag(e) {
this.isDragging = true;
this.startY = e.clientY;
this.scrollTop = this.$refs.tableContainer.scrollTop;
e.preventDefault();
},
+
stopDrag() {
this.isDragging = false;
},
+
handleDrag(e) {
if (!this.isDragging) return;
@@ -277,6 +301,7 @@ export default {
const scrollRatio = (trackHeight - thumbHeight) / maxScrollTop;
container.scrollTop = this.scrollTop + deltaY / scrollRatio;
},
+
handleTrackClick(e) {
const container = this.$refs.tableContainer;
const scrollbarTrack = this.$refs.scrollbarTrack;
@@ -296,16 +321,75 @@ export default {
scrollbarThumb.style.top = `${newTop}px`;
container.scrollTop = (newTop / (trackHeight - thumbHeight)) * (container.scrollHeight - container.clientHeight);
},
- // 按钮组
+
startEdit(row) {
row.editing = true;
this.$set(row, 'originalData', {...row});
},
saveEdit(row) {
- row.editing = false;
- delete row.originalData;
- // 这里可以添加保存到服务器的逻辑
+ try {
+ const params = {
+ id: row.id,
+ voiceCode: row.voiceCode,
+ voiceName: row.voiceName,
+ languageType: row.languageType,
+ remark: row.remark,
+ ttsModelId: this.ttsModelId,
+ voiceDemo: row.voiceDemo || '',
+ sort: row.sort
+ };
+
+ let res;
+ if (row.id) {
+ // 已有ID,执行更新操作
+ Api.timbre.updateVoice(params, (response) => {
+ res = response;
+ this.handleResponse(res, row);
+ });
+ } else {
+ // 没有ID,执行新增操作
+ Api.timbre.saveVoice(params, (response) => {
+ res = response;
+ this.handleResponse(res, row);
+ });
+ }
+ } catch (error) {
+ console.error('操作失败:', error);
+ // 异常情况下也恢复原始数据
+ if (row.originalData) {
+ Object.assign(row, row.originalData);
+ row.editing = false;
+ delete row.originalData;
+ }
+ this.$message.error({
+ message: '操作失败,请重试',
+ showClose: true
+ });
+ }
+ },
+
+ handleResponse(res, row) {
+ if (res.code === 0) {
+ this.$message.success({
+ message: row.id ? '修改成功' : '保存成功',
+ showClose: true
+ });
+ row.editing = false;
+ delete row.originalData;
+ this.loadData(); // 刷新数据
+ } else {
+ // 保存失败时恢复原始数据
+ if (row.originalData) {
+ Object.assign(row, row.originalData);
+ row.editing = false;
+ delete row.originalData;
+ }
+ this.$message.error({
+ message: res.msg || (row.id ? '修改失败' : '保存失败'),
+ showClose: true
+ });
+ }
},
toggleSelectAll() {
@@ -316,24 +400,128 @@ export default {
},
addNew() {
+ const maxSort = this.ttsModels.length > 0
+ ? Math.max(...this.ttsModels.map(item => Number(item.sort) || 0))
+ : 0;
+
const newRow = {
- voiceCode: '新编码',
- voiceName: '新音色',
+ voiceCode: '',
+ voiceName: '',
languageType: '中文',
+ voiceDemo: '',
remark: '',
selected: false,
- editing: true
+ editing: true,
+ sort: maxSort + 1
};
+
this.ttsModels.unshift(newRow);
},
deleteRow(row) {
- const index = this.ttsModels.indexOf(row);
- this.ttsModels.splice(index, 1);
+ this.$confirm("确定要删除该音色吗?", "警告", {
+ confirmButtonText: "确定",
+ cancelButtonText: "取消",
+ type: "warning",
+ })
+ .then(() => {
+ Api.timbre.deleteVoice(row.id, (response) => {
+ if (response.code === 0) {
+ this.$message.success({
+ message: "删除成功",
+ showClose: true
+ });
+ this.loadData(); // 刷新数据
+ } else {
+ this.$message.error({
+ message: response.msg || "删除失败",
+ showClose: true
+ });
+ }
+ });
+ })
+ .catch(() => {
+ this.$message.info("已取消删除");
+ });
},
batchDelete() {
- this.ttsModels = this.ttsModels.filter(row => !row.selected);
+ const selectedRows = this.filteredTtsModels.filter(row => row.selected);
+ if (selectedRows.length === 0) {
+ this.$message.warning("请先选择需要删除的音色");
+ return;
+ }
+
+ this.$confirm(`确定要删除选中的${selectedRows.length}个音色吗?`, "警告", {
+ confirmButtonText: "确定",
+ cancelButtonText: "取消",
+ type: "warning",
+ })
+ .then(async () => {
+ const loading = this.$loading({
+ lock: true,
+ text: "正在删除中...",
+ spinner: "el-icon-loading",
+ background: "rgba(0, 0, 0, 0.7)",
+ });
+
+ try {
+ const results = await Promise.all(
+ selectedRows.map((row) => {
+ return new Promise((resolve) => {
+ Api.timbre.deleteVoice(row.id, (response) => {
+ if (response.code === 0) {
+ resolve({ success: true, id: row.id });
+ } else {
+ resolve({
+ success: false,
+ id: row.id,
+ msg: response.msg || '删除失败'
+ });
+ }
+ });
+ });
+ })
+ );
+
+ const successCount = results.filter(r => r.success).length;
+ const failCount = results.length - successCount;
+
+ if (failCount === 0) {
+ this.$message.success({
+ message: `成功删除${successCount}个音色`,
+ showClose: true
+ });
+ } else if (successCount === 0) {
+ this.$message.error({
+ message: '删除失败,请重试',
+ showClose: true
+ });
+ } else {
+ this.$message.warning({
+ message: `成功删除${successCount}个音色,${failCount}个删除失败`,
+ showClose: true
+ });
+ }
+
+ this.loadData(); // 刷新数据
+ } catch (error) {
+ console.error('批量删除出错:', error);
+ this.$message.error({
+ message: '删除过程中发生错误',
+ showClose: true
+ });
+ } finally {
+ loading.close();
+ }
+ })
+ .catch(() => {
+ this.$message.info("已取消删除");
+ });
+ },
+
+ isValidAudioUrl(url) {
+ return url && (url.endsWith('.mp3') || url.endsWith('.ogg') || url.endsWith('.wav'));
}
}
};