From f85e8631440a6fe22fea7c7b6dc058671a22714a Mon Sep 17 00:00:00 2001 From: zhuoqinglian <1035449612@qq.com> Date: Thu, 23 Apr 2026 17:50:57 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E8=AF=8D=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/apis/api.js | 4 +- .../src/apis/module/correctWord.js | 131 +++ main/manager-web/src/components/HeaderBar.vue | 95 +-- .../src/components/ReplacementWordDialog.vue | 494 ++++++++++++ .../src/components/TtsAdvancedSettings.vue | 119 ++- main/manager-web/src/i18n/de.js | 53 +- main/manager-web/src/i18n/en.js | 53 +- main/manager-web/src/i18n/pt_BR.js | 53 +- main/manager-web/src/i18n/vi.js | 53 +- main/manager-web/src/i18n/zh_CN.js | 51 +- main/manager-web/src/i18n/zh_TW.js | 53 +- main/manager-web/src/router/index.js | 12 + .../src/views/ReplacementWordManagement.vue | 763 ++++++++++++++++++ main/manager-web/src/views/roleConfig.vue | 17 +- 14 files changed, 1876 insertions(+), 75 deletions(-) create mode 100644 main/manager-web/src/apis/module/correctWord.js create mode 100644 main/manager-web/src/components/ReplacementWordDialog.vue create mode 100644 main/manager-web/src/views/ReplacementWordManagement.vue diff --git a/main/manager-web/src/apis/api.js b/main/manager-web/src/apis/api.js index 45a810c7..1ec27302 100755 --- a/main/manager-web/src/apis/api.js +++ b/main/manager-web/src/apis/api.js @@ -10,6 +10,7 @@ import user from './module/user.js' import voiceClone from './module/voiceClone.js' import voiceResource from './module/voiceResource.js' import knowledgeBase from './module/knowledgeBase.js' +import correctWord from './module/correctWord.js' @@ -41,5 +42,6 @@ export default { dict, voiceResource, voiceClone, - knowledgeBase + knowledgeBase, + correctWord } diff --git a/main/manager-web/src/apis/module/correctWord.js b/main/manager-web/src/apis/module/correctWord.js new file mode 100644 index 00000000..89171ae3 --- /dev/null +++ b/main/manager-web/src/apis/module/correctWord.js @@ -0,0 +1,131 @@ +import { getServiceUrl } from '../api'; +import RequestService from '../httpRequest'; + + +export default { + // 获取替换词文件列表 + getFileList(params, callback) { + const queryParams = new URLSearchParams({ + page: params.page, + pageSize: params.pageSize + }).toString(); + + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/list?${queryParams}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + console.error('获取替换词文件列表失败:', err) + RequestService.reAjaxFun(() => { + this.getFileList(params, callback) + }) + }).send() + }, + + // 获取所有替换词文件(不分页) + selectAll(callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/select`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + console.error('获取所有替换词文件失败:', err) + RequestService.reAjaxFun(() => { + this.selectAll(callback) + }) + }).send() + }, + + // 下载替换词文件 + downloadFile(id, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/download/${id}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + RequestService.clearRequestTime() + callback(err) + }).send() + }, + + // 新增替换词文件 + addFile(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file`) + .method('POST') + .data(data) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .fail((err) => { + RequestService.clearRequestTime() + callback(err) + }).send() + }, + + // 更新替换词文件 + updateFile(data, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/${data.id}`) + .method('PUT') + .data({ + fileName: data.fileName, + content: data.content + }) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + console.error('更新替换词文件失败:', err) + RequestService.reAjaxFun(() => { + this.updateFile(data, callback) + }) + }).send() + }, + + // 删除替换词文件 + deleteFile(id, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/${id}`) + .method('DELETE') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + console.error('删除替换词文件失败:', err) + RequestService.reAjaxFun(() => { + this.deleteFile(id, callback) + }) + }).send() + }, + + // 批量删除替换词文件 + batchDeleteFile(ids, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/correct-word/file/batch-delete`) + .method('POST') + .data(ids) + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + console.error('批量删除替换词文件失败:', err) + RequestService.reAjaxFun(() => { + this.batchDeleteFile(ids, callback) + }) + }).send() + } +} diff --git a/main/manager-web/src/components/HeaderBar.vue b/main/manager-web/src/components/HeaderBar.vue index 6e3196d8..80139f2a 100644 --- a/main/manager-web/src/components/HeaderBar.vue +++ b/main/manager-web/src/components/HeaderBar.vue @@ -2,7 +2,7 @@
-
+
@@ -14,7 +14,7 @@ $route.path === '/home' || $route.path === '/role-config' || $route.path === '/device-management', - }" @click="goHome"> + }" @click="handleRouter('home')"> + :class="{ 'active-tab': $route.path === '/voice-clone-management' }" @click="handleRouter('voiceCloneManagement')"> - + {{ $t("header.voiceCloneManagement") }} - + {{ $t("header.voiceResourceManagement") }}
+ @click="handleRouter('modelConfig')"> + @click="handleRouter('knowledgeBaseManagement')"> - + {{ $t("header.paramManagement") }} - + {{ $t("header.userManagement") }} - + {{ $t("header.otaManagement") }} - + {{ $t("header.dictManagement") }} - + {{ $t("header.providerManagement") }} - + {{ $t("header.agentTemplate") }} - + + {{ $t("header.replacementWordManagement") }} + + {{ $t("header.serverSideManagement") }} - + {{ $t("header.featureManagement") }} @@ -220,6 +223,23 @@ export default { label: "label", children: "children", }, + // 跳转页面配置 + routerPaths: { + home: "/home", + modelConfig: "/model-config", + knowledgeBaseManagement: "/knowledge-base-management", + voiceCloneManagement: "/voice-clone-management", + voiceResourceManagement: "/voice-resource-management", + paramManagement: "/params-management", + userManagement: "/user-management", + otaManagement: "/ota-management", + dictManagement: "/dict-management", + providerManagement: "/provider-management", + agentTemplate: "/agent-template-management", + replacementWordManagement: "/replacement-word-management", + serverSideManagement: "/server-side-management", + featureManagement: "/feature-management", + } }; }, computed: { @@ -331,49 +351,8 @@ export default { window.removeEventListener("resize", this.checkScreenSize); }, methods: { - goHome() { - // 跳转到首页 - this.$router.push("/home"); - }, - goUserManagement() { - this.$router.push("/user-management"); - }, - goModelConfig() { - this.$router.push("/model-config"); - }, - goKnowledgeBaseManagement() { - this.$router.push("/knowledge-base-management"); - }, - goVoiceCloneManagement() { - this.$router.push("/voice-clone-management"); - }, - goParamManagement() { - this.$router.push("/params-management"); - }, - goOtaManagement() { - this.$router.push("/ota-management"); - }, - goDictManagement() { - this.$router.push("/dict-management"); - }, - goProviderManagement() { - this.$router.push("/provider-management"); - }, - goServerSideManagement() { - this.$router.push("/server-side-management"); - }, - - // 跳转到音色资源管理 - goVoiceResourceManagement() { - this.$router.push("/voice-resource-management"); - }, - // 添加默认角色模板管理导航方法 - goAgentTemplateManagement() { - this.$router.push("/agent-template-management"); - }, - // 跳转到功能管理 - goFeatureManagement() { - this.$router.push("/feature-management"); + handleRouter(type) { + this.$router.push(this.routerPaths[type]); }, // 加载功能状态 async loadFeatureStatus() { diff --git a/main/manager-web/src/components/ReplacementWordDialog.vue b/main/manager-web/src/components/ReplacementWordDialog.vue new file mode 100644 index 00000000..0d61e124 --- /dev/null +++ b/main/manager-web/src/components/ReplacementWordDialog.vue @@ -0,0 +1,494 @@ + + + + + + + diff --git a/main/manager-web/src/components/TtsAdvancedSettings.vue b/main/manager-web/src/components/TtsAdvancedSettings.vue index fe11b0ac..f24cc59d 100644 --- a/main/manager-web/src/components/TtsAdvancedSettings.vue +++ b/main/manager-web/src/components/TtsAdvancedSettings.vue @@ -57,9 +57,32 @@ class="tts-slider" /> {{ $t('roleConfig.pitchHint') }} -
+
+ + +
+

+ {{ $t('roleConfig.replacementWordLabel') }} + + + +

+ + + +
- {{ wordCount }}{{ $t('replacementDialog.wordCountUnit') }} + + {{ wordCountText }}{{ $t('replacementDialog.wordCountUnit') }} + @@ -88,12 +90,22 @@ export default { } }, data() { + const MAX_WORD_COUNT = 4000; + const validateContent = (rule, value, callback) => { if (!value || !value.trim()) { callback(new Error(this.$t('replacementDialog.requiredContent'))); return; } + const lines = this.getValidLines(value); + const lineCount = lines.length; + + if (lineCount > MAX_WORD_COUNT) { + callback(new Error(this.$t('replacementDialog.maxWordCountExceeded', { max: MAX_WORD_COUNT }))); + return; + } + for (let i = 0; i < lines.length; i++) { const pipeCount = (lines[i].match(/\|/g) || []).length; if (pipeCount !== 1) { @@ -130,6 +142,7 @@ export default { fileName: '', content: '' }, + maxWordCount: MAX_WORD_COUNT, rules: { fileName: [ { required: true, message: this.$t('replacementDialog.requiredFileName'), trigger: "blur" } @@ -143,14 +156,22 @@ export default { computed: { wordCount() { if (!this.localForm.content) return 0; - const contentStr = Array.isArray(this.localForm.content) - ? this.localForm.content.join('\n') + const contentStr = Array.isArray(this.localForm.content) + ? this.localForm.content.join('\n') : this.localForm.content; if (!contentStr.trim()) { return 0; } const lines = this.getValidLines(); return lines.filter(line => line.includes('|')).length; + }, + + isOverLimit() { + return this.wordCount > this.maxWordCount; + }, + + wordCountText() { + return `${this.wordCount} / ${this.maxWordCount}`; } }, methods: { @@ -170,7 +191,7 @@ export default { handleFileChange(file) { if (!file) return; - + const rawFile = file.raw; if (!rawFile) return; @@ -178,6 +199,14 @@ export default { reader.onload = (e) => { const content = e.target.result; this.localForm.content = content; + + const lines = this.getValidLines(content); + if (lines.length > this.maxWordCount) { + this.$message.warning( + this.$t('replacementDialog.maxWordCountExceeded', { max: this.maxWordCount }) + ); + } + this.$nextTick(() => { if (this.$refs.form) { this.$refs.form.clearValidate('content'); @@ -193,6 +222,13 @@ export default { submit() { this.$refs.form.validate((valid) => { if (valid) { + if (this.isOverLimit) { + this.$message.error( + this.$t('replacementDialog.maxWordCountExceeded', { max: this.maxWordCount }) + ); + return; + } + const submitData = { id: this.localForm.id, fileName: this.localForm.fileName, @@ -428,6 +464,12 @@ export default { font-size: 13px; color: #64748b; font-weight: 500; + transition: color 0.3s ease; + + &.over-limit { + color: #ef4444; + font-weight: 600; + } } } diff --git a/main/manager-web/src/i18n/de.js b/main/manager-web/src/i18n/de.js index f0fe47b3..926133e1 100644 --- a/main/manager-web/src/i18n/de.js +++ b/main/manager-web/src/i18n/de.js @@ -385,6 +385,7 @@ export default { 'replacementDialog.invalidOriginalChar': 'Zeile {line} Originalwort enthält Sonderzeichen', 'replacementDialog.invalidReplacementChar': 'Zeile {line} Ersetzungswort enthält Sonderzeichen', 'replacementDialog.readFileError': 'Datei konnte nicht gelesen werden', + 'replacementDialog.maxWordCountExceeded': 'Die Anzahl der Ersetzungswörter darf {max} nicht überschreiten', // Ersetzungswortverwaltung Seite Text 'replacementWordManagement.getListFailed': 'Liste konnte nicht abgerufen werden', diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 59a3e8e8..19efceda 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -385,6 +385,7 @@ export default { 'replacementDialog.invalidOriginalChar': 'Line {line} original word contains special characters', 'replacementDialog.invalidReplacementChar': 'Line {line} replacement word contains special characters', 'replacementDialog.readFileError': 'Failed to read file', + 'replacementDialog.maxWordCountExceeded': 'Replacement word count cannot exceed {max}', // Replacement Word Management page text 'replacementWordManagement.getListFailed': 'Failed to get list', diff --git a/main/manager-web/src/i18n/pt_BR.js b/main/manager-web/src/i18n/pt_BR.js index bbdfc7aa..5f34d651 100644 --- a/main/manager-web/src/i18n/pt_BR.js +++ b/main/manager-web/src/i18n/pt_BR.js @@ -385,6 +385,7 @@ export default { 'replacementDialog.invalidOriginalChar': 'Linha {line} palavra original contém caracteres especiais', 'replacementDialog.invalidReplacementChar': 'Linha {line} palavra de substituição contém caracteres especiais', 'replacementDialog.readFileError': 'Falha ao ler arquivo', + 'replacementDialog.maxWordCountExceeded': 'A quantidade de palavras de substituição não pode exceder {max}', // Página de gerenciamento de palavras de substituição 'replacementWordManagement.getListFailed': 'Falha ao obter lista', diff --git a/main/manager-web/src/i18n/vi.js b/main/manager-web/src/i18n/vi.js index c16dbe0d..b553cfc4 100644 --- a/main/manager-web/src/i18n/vi.js +++ b/main/manager-web/src/i18n/vi.js @@ -385,6 +385,7 @@ export default { 'replacementDialog.invalidOriginalChar': 'Dòng {line} từ gốc chứa ký tự đặc biệt', 'replacementDialog.invalidReplacementChar': 'Dòng {line} từ thay thế chứa ký tự đặc biệt', 'replacementDialog.readFileError': 'Không thể đọc tệp', + 'replacementDialog.maxWordCountExceeded': 'Số lượng từ thay thế không thể vượt quá {max}', // Trang quản lý từ thay thế 'replacementWordManagement.getListFailed': 'Không thể lấy danh sách', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index ac9da9c7..91e109c2 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -383,6 +383,7 @@ export default { 'replacementDialog.invalidOriginalChar': '第{line}行待替换词包含特殊符号', 'replacementDialog.invalidReplacementChar': '第{line}行替换词包含特殊符号', 'replacementDialog.readFileError': '读取文件失败', + 'replacementDialog.maxWordCountExceeded': '替换词数量不能超过 {max} 个', // 替换词管理页面提示文本 'replacementWordManagement.getListFailed': '获取列表失败', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index 7d2d511d..91c8e0c2 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -385,6 +385,7 @@ export default { 'replacementDialog.invalidOriginalChar': '第{line}行待替換詞包含特殊符號', 'replacementDialog.invalidReplacementChar': '第{line}行替換詞包含特殊符號', 'replacementDialog.readFileError': '讀取檔案失敗', + 'replacementDialog.maxWordCountExceeded': '替換詞數量不能超過 {max} 個', // 替換詞管理頁面提示文本 'replacementWordManagement.getListFailed': '獲取列表失敗',