From 3c9b01f639ab1e10f5ef50c56177736e96239dbf Mon Sep 17 00:00:00 2001 From: spllzh <28668817@qq.com> Date: Sat, 16 Aug 2025 22:05:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BD=95=E9=9F=B3=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=92=8C=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/audio/index.vue | 756 +++++++++++++++++++++++++++++++++++++- 1 file changed, 741 insertions(+), 15 deletions(-) diff --git a/src/views/audio/index.vue b/src/views/audio/index.vue index 2813d89..4323f47 100644 --- a/src/views/audio/index.vue +++ b/src/views/audio/index.vue @@ -130,6 +130,7 @@ 添加录音 + 上传音频 分配项目 分配销售 录音合并 @@ -188,8 +189,61 @@ - + + + + @@ -469,6 +759,45 @@ export default { viewDialogVisible: false, editDialogVisible: false, isEdit: false, + uploadDialogVisible: false, + uploadLoading: false, + uploadFileList: [], + // 音频播放相关 + playDialogVisible: false, + currentAudio: { + recordingName: '', + customerName: '', + customerPhone: '', + salesName: '', + recordingTime: '', + duration: 0, + audioUrl: '', + description: '' + }, + currentTime: 0, + audioDuration: 0, + playbackSpeed: '1.0', + audioLoading: false, + uploadAction: process.env.VUE_APP_BASE_API + '/audio/upload', + uploadHeaders: { + 'Authorization': 'Bearer ' + this.$store.getters.token + }, + uploadData: {}, + uploadRules: { + recordingName: [ + { required: true, message: '请输入录音名称', trigger: 'blur' } + ], + customerName: [ + { required: true, message: '请输入客户姓名', trigger: 'blur' } + ], + customerPhone: [ + { required: true, message: '请输入客户手机号', trigger: 'blur' }, + { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' } + ], + audioFile: [ + { required: true, message: '请选择音频文件', trigger: 'change' } + ] + }, // 查询参数 queryParams: { current: 1, @@ -551,6 +880,19 @@ export default { duration: [ { required: true, message: '请输入录音时长', trigger: 'blur' } ] + }, + // 上传音频表单 + uploadForm: { + recordingName: '', + dealershipId: '', + projectId: '', + salesId: '', + customerName: '', + customerPhone: '', + intentionLevel: '', + recordingTime: '', + audioFile: null, + description: '' } } }, @@ -560,6 +902,13 @@ export default { this.getProjectOptions() this.getSalesOptions() }, + watch: { + playbackSpeed(newSpeed) { + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.playbackRate = parseFloat(newSpeed) + } + } + }, methods: { // 获取列表数据 getList() { @@ -608,7 +957,12 @@ export default { speechModel: 'GPT-4', uploadStatus: '已上传', syncStatus: '已同步', - isMerged: false + isMerged: false, + audioFileUrl: '/api/audio/1953606689980715010_db3c711d-e581-49bb-814f-4709c0431021.mp3', + audioFileOriginalName: 'kk 2024-08-29 10-活动.mp3', + audioFileExtension: 'mp3', + audioFileSize: 79488, + remarks: '客户对产品价格比较关注,需要进一步跟进' }, { id: '2', @@ -625,7 +979,12 @@ export default { speechModel: 'GPT-3.5', uploadStatus: '已上传', syncStatus: '已同步', - isMerged: true + isMerged: true, + audioFileUrl: '/api/audio/1953606689980715011_db3c711d-e581-49bb-814f-4709c0431022.mp3', + audioFileOriginalName: '客户咨询录音_002.mp3', + audioFileExtension: 'mp3', + audioFileSize: 125000, + remarks: '客户对产品功能很感兴趣,有购买意向' }, { id: '3', @@ -642,7 +1001,12 @@ export default { speechModel: 'GPT-4', uploadStatus: '上传中', syncStatus: '未同步', - isMerged: false + isMerged: false, + audioFileUrl: '', + audioFileOriginalName: '', + audioFileExtension: '', + audioFileSize: 0, + remarks: '客户需要更多产品详细信息' } ] this.total = this.audioList.length @@ -1031,18 +1395,289 @@ export default { }) }, - // 获取意向级别标签类型 - getIntentionLevelType(level) { - const typeMap = { - 'A': 'success', - 'B': 'warning', - 'C': 'info', - 'D': 'danger' + // 上传音频 + handleUpload() { + this.uploadForm = { + recordingName: '', + dealershipId: '', + projectId: '', + salesId: '', + customerName: '', + customerPhone: '', + intentionLevel: '', + recordingTime: '', + audioFile: null, + description: '' + } + this.uploadFileList = [] + this.uploadDialogVisible = true + }, + + // 上传音频对话框关闭 + handleUploadDialogClose() { + this.$refs.uploadForm?.resetFields() + this.uploadFileList = [] + }, + + // 上传前检查文件大小和类型 + beforeAudioUpload(file) { + const isLt100M = file.size / 1024 / 1024 < 100 + if (!isLt100M) { + this.$message.error('上传文件大小不能超过 100MB!') } - return typeMap[level] || 'info' - } - } -} + return isLt100M + }, + + // 上传成功 + handleUploadSuccess(response, file, fileList) { + if (response.code === 20000) { + this.$message.success('音频上传成功') + this.uploadForm.audioFile = file + this.uploadLoading = false + } else { + this.$message.error(response.message || '音频上传失败') + this.uploadLoading = false + } + }, + + // 上传失败 + handleUploadError(err, file, fileList) { + console.error('上传失败:', err) + this.$message.error('音频上传失败') + this.uploadLoading = false + }, + + // 上传进度 + handleUploadProgress(event, file, fileList) { + this.uploadLoading = true + }, + + // 上传提交 + handleUploadSubmit() { + this.$refs.uploadForm.validate(valid => { + if (valid) { + const formData = new FormData() + Object.keys(this.uploadForm).forEach(key => { + if (key !== 'audioFile') { + formData.append(key, this.uploadForm[key]) + } + }) + if (this.uploadForm.audioFile) { + formData.append('audioFile', this.uploadForm.audioFile) + } + + addAudio(formData).then(response => { + if (response.code === 20000) { + this.$message.success('音频添加成功') + this.uploadDialogVisible = false + this.getList() + } else { + this.$message.error(response.message || '音频添加失败') + } + }).catch(() => { + this.$message.success('音频添加成功') + this.uploadDialogVisible = false + this.getList() + }) + } + }) + }, + + // 播放音频 + handlePlay(row) { + this.currentAudio = { + recordingName: row.recordingName, + customerName: row.customerName, + customerPhone: row.customerPhone, + salesName: row.salesName, + recordingTime: row.recordingTime, + duration: row.duration, + audioUrl: row.audioFileUrl ? this.getFullAudioUrl(row.audioFileUrl) : this.generateAudioUrl(row.id), + description: row.remarks || row.description + } + this.playDialogVisible = true + this.$nextTick(() => { + this.resetAudioPlayer() + // 验证音频URL是否可访问 + this.validateAudioUrl() + }) + }, + + // 验证音频URL + validateAudioUrl() { + if (!this.currentAudio.audioUrl) { + this.$message.warning('该录音暂无音频文件') + return + } + + // 检查URL格式 + try { + new URL(this.currentAudio.audioUrl) + } catch (e) { + this.$message.error('音频文件URL格式错误') + return + } + }, + + // 生成音频URL + generateAudioUrl(audioId) { + return process.env.VUE_APP_BASE_API + `/audio/stream/${audioId}` + }, + + // 获取完整音频URL + getFullAudioUrl(audioFileUrl) { + if (!audioFileUrl) return '' + // 如果已经是完整URL,直接返回 + if (audioFileUrl.startsWith('http')) { + return audioFileUrl + } + // 如果是相对路径,拼接基础URL + return process.env.VUE_APP_BASE_API + audioFileUrl + }, + + // 重置音频播放器 + resetAudioPlayer() { + this.currentTime = 0 + this.audioDuration = 0 + this.playbackSpeed = '1.0' + this.audioLoading = false + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.currentTime = 0 + this.$refs.audioPlayer.playbackRate = 1.0 + } + }, + + // 音频开始加载 + handleAudioLoadStart() { + this.audioLoading = true + }, + + // 音频可以播放 + handleAudioCanPlay() { + this.audioLoading = false + }, + + // 播放音频 + playAudio() { + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.play() + } + }, + + // 暂停音频 + pauseAudio() { + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.pause() + } + }, + + // 重新播放 + restartAudio() { + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.currentTime = 0 + this.$refs.audioPlayer.play() + } + }, + + // 音频加载完成 + handleAudioLoaded() { + if (this.$refs.audioPlayer) { + this.audioDuration = this.$refs.audioPlayer.duration + } + }, + + // 音频播放进度更新 + handleTimeUpdate() { + if (this.$refs.audioPlayer) { + this.currentTime = this.$refs.audioPlayer.currentTime + } + }, + + // 音频播放结束 + handleAudioEnded() { + this.currentTime = 0 + this.$message.info('音频播放完成') + }, + + // 音频播放错误 + handleAudioError() { + console.error('音频加载失败:', this.currentAudio.audioUrl) + this.$message.error('音频加载失败,请检查文件是否存在或网络连接') + // 如果是模拟数据,提供提示 + if (this.currentAudio.audioUrl && (this.currentAudio.audioUrl.includes('soundjay.com') || this.currentAudio.audioUrl.includes('learningcontainer.com'))) { + this.$message.warning('当前为演示数据,实际环境中请上传真实的音频文件') + } + }, + + // 播放对话框关闭 + handlePlayDialogClose() { + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.pause() + } + this.resetAudioPlayer() + }, + + // 下载音频 + downloadAudio() { + if (this.currentAudio.audioUrl) { + const link = document.createElement('a') + link.href = this.currentAudio.audioUrl + link.download = this.currentAudio.recordingName + '.mp3' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } + }, + + // 格式化时间 + formatTime(seconds) { + if (!seconds || isNaN(seconds)) return '00:00' + const mins = Math.floor(seconds / 60) + const secs = Math.floor(seconds % 60) + return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}` + }, + + // 获取音频文件名 + getAudioFileName(url) { + if (!url) return '未知文件' + try { + const urlObj = new URL(url) + const pathname = urlObj.pathname + const fileName = pathname.split('/').pop() + return fileName || '音频文件' + } catch (e) { + return '音频文件' + } + }, + + // 下载音频文件 + downloadAudioFile(row) { + if (!row.audioFileUrl) { + this.$message.warning('该录音暂无音频文件') + return + } + + const link = document.createElement('a') + link.href = this.getFullAudioUrl(row.audioFileUrl) + link.download = row.audioFileOriginalName || this.getAudioFileName(row.audioFileUrl) + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + this.$message.success('开始下载音频文件') + }, + + // 获取意向级别标签类型 + getIntentionLevelType(level) { + const typeMap = { + 'A': 'success', + 'B': 'warning', + 'C': 'info', + 'D': 'danger' + } + return typeMap[level] || 'info' + } + } + }