submitAudio.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <template>
  2. <view class="task-form-item form-item-media">
  3. <view class="form-lable">
  4. <text><text class="form-must" v-if="rule && rule.required">* </text>录音:</text>
  5. <view :class="['form-lable-content' , soundRecording.length > 0 ? 'lable-content-right' : '']"
  6. v-if="!soundRecording || soundRecording.length < num">
  7. <nb-voice-record v-if="!checkPage" @startRecord="start" @endRecord="end" @cancelRecord="cancel">
  8. <view class="lable-content-btn" @click.stop="onRecording()">
  9. <text class="iconfont_yige">&#xe6a0;</text>
  10. <text>长按录音</text>
  11. </view>
  12. </nb-voice-record>
  13. </view>
  14. <text class="form-media-num">({{soundRecording.length}}/{{num}})</text>
  15. </view>
  16. <view class="form-img-video">
  17. <view class="audio-item" :key="index" v-for="(item,index) in soundRecording"
  18. @click.stop="onPlayAudio(item , index)">
  19. <view :class="['audio-item-val' , play_index === index ? 'play-audio' : '']"><text
  20. class="iconfont_yige">&#xe6a5;</text>
  21. <text class="audio-time">{{item.duration}}</text> <text
  22. class="iconfont_yige">&#xe6a6;</text>
  23. </view>
  24. <view class="del-img-video iconfont_yige" @click.stop="delAudio(index)" v-if="!checkPage">&#xe867;
  25. </view>
  26. </view>
  27. </view>
  28. </view>
  29. </template>
  30. <script>
  31. import {
  32. SingleFileUpload
  33. } from "@/utils/tool.js"
  34. let innerAudioContext = uni.createInnerAudioContext();
  35. export default {
  36. name: 'submitAudio',
  37. model: {
  38. prop: ['soundRecording'],
  39. event: ['onChange']
  40. },
  41. props: {
  42. checkPage: {
  43. type: Boolean,
  44. default: false
  45. },
  46. num: {
  47. type: Number,
  48. default: 3
  49. },
  50. rule: {
  51. type: Object,
  52. default: null
  53. },
  54. soundRecording: {
  55. type: Array,
  56. default: () => [],
  57. require: true
  58. },
  59. },
  60. data() {
  61. return {
  62. play_index: -1,
  63. audio_s: 0,
  64. audioInterval: null,
  65. }
  66. },
  67. methods: {
  68. start() {
  69. // 开始录音
  70. try {
  71. clearInterval(this.audioInterval)
  72. } catch (e) {}
  73. this.audioInterval = null;
  74. this.audio_s = 0;
  75. this.audioInterval = setInterval(() => {
  76. this.audio_s += 1;
  77. }, 1000)
  78. },
  79. end(event) {
  80. try {
  81. clearInterval(this.audioInterval)
  82. } catch (e) {}
  83. this.audioInterval = null;
  84. const file_ = event ? event.tempFilePath : ''
  85. SingleFileUpload(file_, true).then(res => {
  86. this.soundRecording.push({
  87. filePath: res.url,
  88. duration: this.audio_s
  89. })
  90. })
  91. // 结束录音并处理得到的录音文件
  92. // event中,app端仅有tempFilePath字段,微信小程序还有duration和fileSize两个字段
  93. },
  94. cancel() {
  95. // 用户取消录音
  96. },
  97. delAudio(index) {
  98. if (this.play_index === index) {
  99. // 当前存在播放,先关闭播放
  100. try {
  101. innerAudioContext.pause();
  102. innerAudioContext.destroy()
  103. innerAudioContext = null
  104. } catch (e) {
  105. //TODO handle the exception
  106. }
  107. }
  108. this.soundRecording.splice(index, 1);
  109. },
  110. onPlayAudio(item, index) {
  111. console.log('item ==1111= ', innerAudioContext)
  112. if (innerAudioContext) {
  113. try {
  114. innerAudioContext.pause();
  115. innerAudioContext.destroy()
  116. innerAudioContext = null
  117. } catch (e) {
  118. //TODO handle the exception
  119. }
  120. }
  121. // 点击同一个播放的时候,阻止继续播放
  122. if (this.play_index === index) {
  123. this.play_index = -1;
  124. return
  125. }
  126. if (item) {
  127. try {
  128. innerAudioContext = uni.createInnerAudioContext();
  129. innerAudioContext.src = item.filePath;
  130. innerAudioContext.play();
  131. innerAudioContext.onPlay(() => {
  132. this.play_index = index;
  133. console.log('开始播放');
  134. });
  135. innerAudioContext.onError((res) => {
  136. this.play_index = -1;
  137. innerAudioContext.destroy()
  138. innerAudioContext = null
  139. // uni.showToast({
  140. // title: '播放失败',
  141. // icon: 'none'
  142. // })
  143. });
  144. innerAudioContext.onEnded((res) => {
  145. this.play_index = -1;
  146. innerAudioContext.destroy()
  147. innerAudioContext = null
  148. // uni.showToast({
  149. // title: '播放结束事件',
  150. // icon: 'none'
  151. // })
  152. });
  153. innerAudioContext.onPause((res) => {
  154. this.play_index = -1;
  155. innerAudioContext.destroy()
  156. innerAudioContext = null
  157. // uni.showToast({
  158. // title: '播放暂停事件',
  159. // icon: 'none'
  160. // })
  161. });
  162. } catch (e) {
  163. //TODO handle the exception
  164. console.log('play = Audio = ', e)
  165. }
  166. }
  167. },
  168. onRecording() {
  169. }
  170. }
  171. }
  172. </script>
  173. <style lang="scss" scoped>
  174. @import '~./submint.scss';
  175. .form-img-video {
  176. flex-direction: column !important;
  177. }
  178. .audio-item {
  179. width: 100%;
  180. display: flex;
  181. flex-direction: row;
  182. justify-content: space-between;
  183. align-items: center;
  184. margin-bottom: 20rpx;
  185. &:last-child {
  186. margin-bottom: 0rpx;
  187. }
  188. .audio-item-val {
  189. flex: 1;
  190. margin-right: 20rpx;
  191. height: 70rpx;
  192. background-color: #E6E6E6;
  193. border-radius: 14rpx;
  194. display: flex;
  195. align-items: center;
  196. padding: 0 20rpx;
  197. .audio-time {
  198. padding-left: 20rpx;
  199. }
  200. .iconfont_yige {
  201. font-size: 40rpx;
  202. }
  203. }
  204. }
  205. .play-audio {
  206. overflow: hidden;
  207. /* 超出部分隐藏起来 */
  208. animation: changecolor 1.5s linear infinite;
  209. /* 定义动画效果 */
  210. }
  211. @keyframes changecolor {
  212. 0% {
  213. background-color: rgba(60, 183, 210, 0.4);
  214. }
  215. 35% {
  216. background-color: rgba(60, 183, 210, 0.6);
  217. }
  218. 75% {
  219. background-color: rgba(60, 183, 210, 0.8);
  220. }
  221. 100% {
  222. background-color: rgba(60, 183, 210, 1);
  223. }
  224. }
  225. </style>