express+vue在线im实现【四】

往期内容

express+vue在线im实现【一】
express+vue在线im实现【二】
express+vue在线im实现【三】

本期示例

在这里插入图片描述
在这里插入图片描述

本期总结

  • 支持了音频的录制和发送,如果觉得对你有用,还请点个免费的收藏与关注

下期安排

  • 在线语音

具体实现

<template>
    <kl-dialog width="300px" center :header="false" :footer="false" :dialogVisible.sync="visable">
        <div class="flex-column-wrap p-20 flex-center-wrap pr p-t-40" @click.stop="() => {}">
            <i
                class="f-20 f-600 c-555 cu el-icon-close p-a el-icon-close-1"
                @click.stop="close"
            ></i>
            <e-image
                :height="80"
                :lazy="false"
                src="http://139.9.210.43:5000/netdist/kl1718850348458vjab00h8x4d-1718850348280~1~.png"
            ></e-image>

            <!-- 录制时长 -->
            <div class="m-t-20">录制时长{{ getAudioTime() }}</div>

            <div class="flex-wrap m-t-20">
                <el-button size="small" type="info" @click.stop="reload">重新录制</el-button>
                <el-button size="small" type="warning" @click.stop="stop">停止</el-button>
                <el-button size="small" type="success" @click.stop="play">播放</el-button>
                <el-button :disabled="audioTime == 0" size="small" type="danger" @click.stop="send"
                    >发送</el-button
                >
            </div>
        </div>

        <!-- 语音播放 -->
        <audioPlay
            v-model="isShowAudio"
            :url="parseResourceUrl(filePath)"
            @ended="isShowAudio = false"
        ></audioPlay>
    </kl-dialog>
</template>

<script>
export default {
    components: {
        audioPlay: () => import('@/components/audioPlay/index.vue'),
    },
    props: {
        value: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            isShowAudio: false,
            filePath: '',
            file: null,
            mediaRecorder: null,
            isStart: false,
            audioTime: 0,
            timer: null,
        }
    },
    computed: {
        visable: {
            get() {
                return this.value
            },
            set() {
                return this.$emit('input', !this.value)
            },
        },
    },
    watch: {
        value(val) {
            if (val) {
                // 进入直接开始录音
                this.init()
                return
            }
        },
    },
    beforeDestroy() {
        this.clearTimer()
        this.audioTime = 0
    },
    methods: {
        close() {
            this.filePath = ''
            this.mediaRecorder = null
            this.file = null
            this.visable = false
            this.clearTimer()
            this.audioTime = 0
        },
        getAudioTime() {
            return (this.audioTime / 1000).toFixed(2) + 's'
        },
        reload() {
            this.filePath = ''
            this.mediaRecorder = null
            this.file = null
            this.init()
        },
        stop() {
            this.clearTimer()
            this.mediaRecorder.stop()
        },
        play() {
            if (!this.filePath) {
                this.stop()
            }

            this.isShowAudio = true
        },
        async send() {
            if (!this.filePath) {
                this.stop()

                await this.sleep()
            }

            this.commonUploadFile(this.file, 'im', 500)
                .then(({ url = '' }) => {
                    this.$emit('pushInfo', {
                        msg_type: '5',
                        content: url,
                        time: this.audioTime,
                    })
                    this.close()
                })
                .catch(() => {})
        },
        clearTimer() {
            clearInterval(this.timer)
            this.timer = null
        },
        init() {
            if (this.mediaRecorder) return

            this.clearTimer()
            this.audioTime = 0
            // 请求麦克风权限
            navigator.mediaDevices
                .getUserMedia({ audio: true })
                .then((stream) => {
                    // 创建MediaRecorder实例
                    const mediaRecorder = new MediaRecorder(stream)

                    // 处理录音数据
                    const recordedChunks = []
                    mediaRecorder.ondataavailable = (event) => {
                        if (event.data.size > 0) {
                            recordedChunks.push(event.data)
                        }
                    }

                    // 停止录音时的处理
                    mediaRecorder.onstop = () => {
                        // 将数据块转换为Blob对象
                        const blob = new Blob(recordedChunks, { type: 'audio/ogg; codecs=opus' })
                        const fileName = 'recordedAudio.ogg'

                        this.file = new File([blob], fileName, {
                            type: 'audio/ogg', // 这里不需要指定codecs,因为Blob已经包含了它
                        })
                        // TODO:还没做
                        this.filePath = this.getObjectURL(this.file)
                    }

                    // 开始录音
                    mediaRecorder.start()
                    this.mediaRecorder = mediaRecorder

                    // 计时器
                    this.timer = setInterval(() => {
                        // 最大60s
                        if (this.audioTime >= 60 * 1000) {
                            this.clearTimer()
                            return
                        }
                        this.audioTime += 50
                    }, 50)
                })
                .catch((err) => {
                    console.error('Error accessing the microphone:', err)
                })
        },
        // 获取视频的本地地址
        getObjectURL(file) {
            var url = null
            // 下面函数执行的效果是一样的,只是需要针对不同的浏览器执行不同的 js 函数而已
            if (window.createObjectURL !== undefined) {
                // basic
                url = window.createObjectURL(file)
            } else if (window.URL !== undefined) {
                // mozilla(firefox)
                url = window.URL.createObjectURL(file)
            } else if (window.webkitURL !== undefined) {
                // webkit or chrome
                url = window.webkitURL.createObjectURL(file)
            }
            return url
        },
    },
}
</script>

<style lang="scss" scoped>
.el-icon-close-1 {
    top: 5px;
    right: 5px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/728874.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【总结】ui自动化selenium知识点总结

1. 大致原理 首页安装第三方库selenium库&#xff0c; 其次要下载好浏览器驱动文件&#xff0c;比如谷歌的 chromedriver.exe&#xff0c;配置上环境变量。 使用selenium的webdriver类去创建一个浏览器驱动对象赋值叫driver&#xff0c;一个浏览器驱动对象就可以 实现 对浏…

【PHP项目实战训练】——使用thinkphp框架对数据进行增删改查功能

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

国内怎样使用GPT4 turbo

GPT是当前最为熟知的大模型&#xff0c;它优越的性能一直遥遥领先于其它一众厂商&#xff0c;然而如此优秀的AI在中国境内却是无法正常使用的。本文将告诉你4种使用gpt4的方法&#xff0c;让你突破限制顺利使用。 官方售价是20美元/月&#xff0c;40次提问/3小时&#xff0c;需…

嵌入式系统软件开发环境_2.一般架构

1.Eclipse框架 嵌入式系统软件开发环境是可帮助用户开发嵌入式软件的一组工具的集合&#xff0c;其架构的主要特征离不开“集成”问题&#xff0c;采用什么样的架构框架是决定开发环境优劣主要因素。Eclipse框架是当前嵌入式系统软件开发环境被普遍公认的一种基础环境框架。目…

vscode插件开发之 - TestController

TesController概要介绍 TestController 组件是用于实现自定义测试框架和集成测试结果的。它允许开发者定义自己的测试运行器&#xff0c;以支持在VSCode中运行和展示测试。以下是一些使用 TestController 组件的主要场景&#xff1a; 自定义测试框架&#xff1a;如果你正在开发…

深度学习算法informer(时序预测)(三)(Encoder)

一、EncoderLayer架构如图&#xff08;不改变输入形状&#xff09; 二、ConvLayer架构如图&#xff08;输入形状中特征维度减半&#xff09; 三、Encoder整体 包括三部分 1. 多层EncoderLayer 2. 多层ConvLayer 3. 层归一化 代码如下 class AttentionLayer(nn.Module):de…

世界奇观短视频制作,AI加持,新手也能月入上万

在这个数字化的时代&#xff0c;短视频已经成为了人们获取信息和娱乐的重要途径。特别是那些展示世界奇观的短视频&#xff0c;如极端的气候、危险的动物、美丽的自然景观等&#xff0c;这些主题具有很强的吸引力&#xff0c;能够引起观众的兴趣和好奇心。那么&#xff0c;如何…

运算放大器(运放)反相放大器电路

运算放大器(运放)反相放大器电路 设计目标 输入ViMin输入ViMax输出VoMin输出VoMax频率f电源Vcc电源Vee–7V7V–14V14V3kHz15V–15V 设计说明 该设计将输入信号 Vi 反相并应用 –2V/V 的信号增益。输入信号通常来自低阻抗源&#xff0c;因为该电路的输入阻抗由输入电阻器 R1…

深度学习神经网络协同过滤模型(NCF)与用户协同过滤(UCF)的区别

一、效果图 点我查看在线demo 二、启发式推荐系统 推荐系统的核心是根据用户的兴趣需求&#xff0c;给用户推荐喜欢的内容。常用的推荐算法有启发式推荐算法&#xff0c;可分为基于用户的 协同过滤&#xff0c;基于物品的协同过滤。 1、基于用户的协同过滤&#xff08;UCF…

【云岚到家】-day04-1-数据同步方案-Canal-MQ

【云岚到家】-day04-1-数据同步方案-Canal-MQ 1 服务搜索1.1 服务搜索技术方案1.1.1 需求分析1.1.2 技术方案1.1.2.1 使用Elasticsearch进行全文检索1.1.2.2 索引同步方案 1.1.3 CanalMQ1.1.3.1 MySQL主从数据同步1.1.3.2 Canal工作流程1.1.3.3 具体实现方案 1.2 MQ技术方案1.2…

Linux连接工具MobaXterm详细使用教程

目录 一、MobaXterm的下载 1、访问官网 2、下载便携版 3、启动MobaXterm 二、MobaXterm基本使用设置 1、新建会话 2、使用ssh连接第一个会话 3、设置主密码 4、主界面 5、sftp文件上传下载 6、文件拖拽的上传下载 7.右键粘贴 8、查看服务器监测信息​编辑 9、个…

文件扫描工具哪个好?便捷的文件扫描工具推荐

对于初入职场的大学毕业生&#xff0c;申请就业补贴是一项不可忽视的福利。 它不仅能够为新生活带来经济上的缓解&#xff0c;也有助于职业生涯的顺利起步。面对申请过程中需提交的文件&#xff0c;如纸质劳动合同&#xff0c;不必烦恼。市面上众多文件扫描软件能助你一臂之力…

Oracle最终还是杀死了MySQL

起因 大约15年前&#xff0c;Oracle收购了Sun公司&#xff0c;从而也拥有了MySQL&#xff0c;互联网上关于Oracle何时会“扼杀MySQL”的讨论此起彼伏。 当时流传着各种理论&#xff1a;从彻底扼杀 MySQL 以减少对 Oracle 专有数据库的竞争&#xff0c;到干掉 MySQL 开源项目&…

vcpkg安装opencv中的特殊问题记录(无法找到opencv_corexd.dll)

我是按照网上的vcpkg安装opencv方法进行的&#xff08;比如这篇&#xff1a;从0开始在visual studio上安装opencv&#xff08;超详细&#xff0c;针对小白&#xff09;&#xff09;&#xff0c;但是中间出现了一些别人没有遇到的问题&#xff0c;虽然原因没有找到&#xff0c;但…

离子污染测试仪有哪些检测方法?校准机构如何选择?

离子污染测试仪是许多生产企业会使用到的一种仪器&#xff0c;作为一种高精度的操作仪器&#xff0c;在长时间的使用下&#xff0c;仪器磨损和失准也是常见状况&#xff0c;因此企业都会进行定期校准来维护仪器&#xff0c;那么离子污染测试仪有哪些检测方法&#xff1f;校准机…

深度学习500问——Chapter11:迁移学习(3)

文章目录 11.3 迁移学习的常用方法 11.3.1 数据分布自适应 11.3.2 边缘分布自适应 11.3.3 条件分布自适应 11.3.4 联合分布自适应 11.3.5 概率分布自适应方法优劣性比较 11.3.6 特征选择 11.3.7 统计特征对齐方法 11.3 迁移学习的常用方法 11.3.1 数据分布自适应 数据分布自适…

阿里拍卖资产推荐算法 召回进展年中总结

阿里拍卖是阿里巴巴旗下拍卖平台&#xff0c;覆盖房产、机动车、土地、债权等类目。召回策略作为推荐场景的第一环&#xff0c;决定了整个推荐系统的上限&#xff0c;目前包含了包括向量召回、I2I、LBS2I、C2I等多路召回。召回的核心目标是尽可能的返回用户所有可能会感兴趣的商…

教你使用Python玩转MySQL数据库,大数据导入不再是难题!

数据分析离不开数据库&#xff0c;如何使用python连接MySQL数据库&#xff0c;并进行增删改查操作呢&#xff1f; 我们还会遇到需要将大批量数据导入数据库的情况&#xff0c;又该如何使用Python进行大数据的高效导入呢&#xff1f; 本文会一一讲解&#xff0c;并配合代码和实…

Spring Boot组件化与参数校验

Spring Boot组件化与参数校验 Spring Boot版本选择 2.3.x版本 2.6.x版本 Spring Boot核心思想 约定大于配置&#xff0c;简化繁琐的配置 Spring Boot自动配置原理 SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类&#xff0c;Spr…

Vue3学习日记(day5)

接下来我们继续探讨文档 event对象 在Vue.js中&#xff0c;$event变量或箭头函数中的event参数用于捕获原始的DOM事件对象。这个对象包含了所有与特定事件相关的信息&#xff0c;比如鼠标点击的位置、键盘按键的键码、触摸事件的触摸点等。 当你在事件处理器中需要做一些基于…