main.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. <!--
  2. - Copyright (C) 2018-2019
  3. - All rights reserved, Designed By www.joolun.com
  4. 【微信消息 - 语音】
  5. 非繁源码:
  6. ① bug 修复:
  7. 1)joolun 的做法:使用 mediaId 从微信公众号,下载对应的 mp4 素材,从而播放内容;
  8. 存在的问题:mediaId 有效期是 3 天,超过时间后无法播放
  9. 2)重构后的做法:后端接收到微信公众号的视频消息后,将视频消息的 media_id 的文件内容保存到文件服务器中,这样前端可以直接使用 URL 播放。
  10. ② 代码优化:将 props 中的 reply 调成为 data 中对应的属性,并补充相关注释
  11. -->
  12. <template>
  13. <div class="wx-voice-div" @click="playVoice">
  14. <el-icon>
  15. <Icon v-if="playing !== true" icon="ep:video-play" :size="32" />
  16. <Icon v-else icon="ep:video-pause" :size="32" />
  17. <span class="amr-duration" v-if="duration">{{ duration }} 秒</span>
  18. </el-icon>
  19. <div v-if="content">
  20. <el-tag type="success" size="small">语音识别</el-tag>
  21. {{ content }}
  22. </div>
  23. </div>
  24. </template>
  25. <script lang="ts" setup>
  26. // 因为微信语音是 amr 格式,所以需要用到 amr 解码器:https://www.npmjs.com/package/benz-amr-recorder
  27. import BenzAMRRecorder from 'benz-amr-recorder'
  28. defineOptions({ name: 'WxVoicePlayer' })
  29. const props = defineProps({
  30. url: {
  31. type: String, // 语音地址,例如说:https://www.iocoder.cn/xxx.amr
  32. required: true
  33. },
  34. content: {
  35. type: String, // 语音文本
  36. required: false
  37. }
  38. })
  39. const amr = ref()
  40. const playing = ref(false)
  41. const duration = ref()
  42. /** 处理点击,播放或暂停 */
  43. const playVoice = () => {
  44. // 情况一:未初始化,则创建 BenzAMRRecorder
  45. if (amr.value === undefined) {
  46. amrInit()
  47. return
  48. }
  49. // 情况二:已经初始化,则根据情况播放或暂时
  50. if (amr.value.isPlaying()) {
  51. amrStop()
  52. } else {
  53. amrPlay()
  54. }
  55. }
  56. /** 音频初始化 */
  57. const amrInit = () => {
  58. amr.value = new BenzAMRRecorder()
  59. // 设置播放
  60. amr.value.initWithUrl(props.url).then(function () {
  61. amrPlay()
  62. duration.value = amr.value.getDuration()
  63. })
  64. // 监听暂停
  65. amr.value.onEnded(function () {
  66. playing.value = false
  67. })
  68. }
  69. /** 音频播放 */
  70. const amrPlay = () => {
  71. playing.value = true
  72. amr.value.play()
  73. }
  74. /** 音频暂停 */
  75. const amrStop = () => {
  76. playing.value = false
  77. amr.value.stop()
  78. }
  79. // TODO 非繁人:下面样式有点问题
  80. </script>
  81. <style lang="scss" scoped>
  82. .wx-voice-div {
  83. display: flex;
  84. width: 120px;
  85. height: 50px;
  86. padding: 5px;
  87. background-color: #eaeaea;
  88. border-radius: 10px;
  89. justify-content: center;
  90. align-items: center;
  91. }
  92. .amr-duration {
  93. margin-left: 5px;
  94. font-size: 11px;
  95. }
  96. </style>