submitAudio.vue 6.5 KB

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