更新组件和API,新增语音转文本功能,优化音频消息组件,调整右键菜单逻辑

This commit is contained in:
Phoenix 2025-05-16 15:20:35 +08:00
parent 419bde4db2
commit 478336c2fe
6 changed files with 96 additions and 29 deletions

1
components.d.ts vendored
View File

@ -60,6 +60,7 @@ declare module 'vue' {
NoticeTab: typeof import('./src/components/group/manage/NoticeTab.vue')['default']
NotificationApi: typeof import('./src/components/common/NotificationApi.vue')['default']
NRadio: typeof import('naive-ui')['NRadio']
NSpin: typeof import('naive-ui')['NSpin']
NVirtualList: typeof import('naive-ui')['NVirtualList']
RevokeMessage: typeof import('./src/components/talk/message/RevokeMessage.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']

View File

@ -9,7 +9,10 @@ export const ServeGetTalkList = (data = {}) => {
export const ServeCreateTalkList = (data = {}) => {
return post('/api/v1/talk/create', data)
}
// 聊天列表创建服务接口
export const voiceToText = (data = {}) => {
return post('/api/v1/talk/message/voice-to-text', data)
}
// 删除聊天列表服务接口
export const ServeDeleteTalkList = (data = {}) => {
return post('/api/v1/talk/delete', data)

View File

@ -3,7 +3,7 @@ import { ref, reactive } from 'vue'
import { PlayOne, PauseOne } from '@icon-park/vue-next'
import { ITalkRecordExtraAudio, ITalkRecord } from '@/types/chat'
defineProps<{
const props = defineProps<{
extra: ITalkRecordExtraAudio
data: ITalkRecord
maxWidth?: Boolean
@ -18,7 +18,8 @@ const state = reactive({
progress: 0,
duration: 0,
currentTime: 0,
loading: true
loading: true,
showText: false
})
const onPlay = () => {
@ -40,6 +41,12 @@ const onCanplay = () => {
state.duration = audioRef.value.duration
durationDesc.value = formatTime(parseInt(audioRef.value.duration))
state.loading = false
if (props.data.is_convert_text === 1 && props.data.extra.content) {
setTimeout(() => {
state.showText = true
}, 300)
}
}
const onError = (e: any) => {
@ -61,17 +68,12 @@ const formatTime = (value: number = 0) => {
return '-'
}
const minutes = Math.floor(value / 60)
let seconds = value
if (minutes > 0) {
seconds = Math.floor(value - minutes * 60)
}
return `${minutes}'${seconds}"`
return `${Math.floor(value)}"`
}
</script>
<template>
<div class="im-message-audio">
<div class="pointer w-200px bg-#f5f5f5 rounded-10px px-11px">
<div class="im-message-audio h-44px">
<audio
ref="audioRef"
preload="auto"
@ -98,20 +100,27 @@ const formatTime = (value: number = 0) => {
</div>
<div class="time">{{ durationDesc }}</div>
</div>
<transition name="expand">
<div class="text-container py-12px border-t-2px border-t-solid border-t-#E0E0E4" v-if="data.is_convert_text===1">
<div class="flex justify-center items-center" v-if="data.is_convert_text===1&&!data.extra.content">
<n-spin :stroke-width="3" size="small" />
</div>
<transition name="fade">
<div class="text-content" v-if="data.extra.content">{{ data.extra.content }}</div>
</transition>
</div>
</transition>
</div>
</template>
<style lang="less" scoped>
.im-message-audio {
--audio-bg-color: #f5f5f5;
--audio-btn-bg-color: #ffffff;
width: 200px;
height: 45px;
border-radius: 10px;
display: flex;
align-items: center;
overflow: hidden;
background-color: var(--audio-bg-color);
> div {
display: flex;
align-items: center;
@ -132,6 +141,7 @@ const formatTime = (value: number = 0) => {
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
}
@ -230,6 +240,7 @@ const formatTime = (value: number = 0) => {
height: 70%;
width: 1px;
background-color: #9b9595;
transition: left 0.1s linear;
}
}
@ -241,6 +252,40 @@ const formatTime = (value: number = 0) => {
}
}
.expand-enter-active,
.expand-leave-active {
transition: all 0.5s ease;
overflow: hidden;
}
.expand-enter-from,
.expand-leave-to {
max-height: 0;
opacity: 0;
padding: 0;
border-top-width: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.text-container {
overflow: hidden;
transition: all 0.2s ease;
}
.text-content {
line-height: 1.5;
transition: all 0.2s ease;
}
html[theme-mode='dark'] {
.im-message-audio {
--audio-bg-color: #2c2c32;

View File

@ -47,7 +47,10 @@ export interface ITalkRecord {
extra: any
isCheck: boolean
send_status: number
float: string
float: string,
is_convert_text?:number//语音记录的 是否是在展示转文本状态 1是 0否,
erp_user_id:number
}
export interface ITalkRecordExtraText {

View File

@ -16,6 +16,7 @@ import { useInject, useTalkRecord, useUtil } from '@/hooks'
import { ExclamationCircleFilled } from '@ant-design/icons-vue';
import { useUserStore } from '@/store'
import RevokeMessage from '@/components/talk/message/RevokeMessage.vue'
import { voiceToText } from '@/api/chat.js'
const props = defineProps({
uid: {
type: Number,
@ -45,16 +46,8 @@ const userStore = useUserStore()
// const showUserInfoModal = (uid: number) => {
// userStore.getUserInfo(uid)
// }
watch(() => records, (newValue, oldValue) => {
console.log(newValue);
}, { deep: true, immediate: true })
//
const skipBottom = ref(false)
setTimeout(() => {
console.log(records.value, 'records.value');
}, 1000)
//
const isShowTalkTime = (index: number, datetime: string) => {
if (datetime == undefined) {
@ -243,6 +236,17 @@ const onContextMenu = (e: any, item: ITalkRecord) => {
e.preventDefault()
}
const onConvertText =async (data: ITalkRecord) => {
console.log('data',data)
data.is_convert_text = 1
const res = await voiceToText({msgId:data.msg_id,voiceUrl:data.extra.url})
if(res.code == 200){
data.extra.content = res.data.convText
}
}
const onloseConvertText=(data: ITalkRecord)=>{
data.is_convert_text = 0
}
const evnets = {
copy: onCopyText,
revoke: onRevokeTalk,
@ -250,7 +254,9 @@ const evnets = {
multiSelect: onMultiSelect,
download: onDownloadFile,
quote: onQuoteMessage,
collect: onCollectImage
collect: onCollectImage,
convertText: onConvertText,
closeConvertText:onloseConvertText
}
//

View File

@ -30,9 +30,17 @@ export function useMenu() {
})
const showDropdownMenu = (e: any, uid: number, item: any) => {
dropdown.item = Object.assign({}, item)
// dropdown.item = Object.assign({}, item)
dropdown.item = item
dropdown.options = []
if ([4].includes(item.msg_type)) {
if(item.is_convert_text === 1){
dropdown.options.push({ label: '关闭转文字', key: 'closeConvertText' })
}else{
dropdown.options.push({ label: '转文字', key: 'convertText' })
}
}
if ([1, 3].includes(item.msg_type)) {
dropdown.options.push({ label: '复制', key: 'copy' })
}
@ -54,6 +62,7 @@ export function useMenu() {
dropdown.options.push({ label: '收藏', key: 'collect' })
}
dropdown.x = e.clientX
dropdown.y = e.clientY
dropdown.show = true