voice-check-modal.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <template>
  2. <view class="modal" v-if="visible">
  3. <view class="modal-content">
  4. <view class="modal-title">麦克风检测</view>
  5. <view class="modal-text">请朗读下面的文字</view>
  6. <!-- 语音波形动画 -->
  7. <view class="wave-container" v-if="isRecording">
  8. <view class="wave-bar" v-for="(item, index) in waveData" :key="index"
  9. :style="{ height: item + 'rpx' }"></view>
  10. </view>
  11. <!-- 待朗读文字 -->
  12. <view class="read-text">成为奇才,就是现在,我们开始吧。</view>
  13. <!-- 按钮 -->
  14. <button class="confirm-btn" @tap="handleConfirm">
  15. {{ isRecording ? '读完了' : '开始' }}
  16. </button>
  17. </view>
  18. </view>
  19. </template>
  20. <script>
  21. const recorderManager = uni.getRecorderManager();
  22. export default {
  23. name: 'VoiceCheckModal',
  24. props: {
  25. visible: {
  26. type: Boolean,
  27. default: false
  28. }
  29. },
  30. data() {
  31. return {
  32. isRecording: false,
  33. waveData: Array(20).fill(20), // 初始波形数据
  34. waveTimer: null
  35. }
  36. },
  37. methods: {
  38. // 开始录音
  39. startRecording() {
  40. this.isRecording = true;
  41. recorderManager.start({
  42. duration: 10000,
  43. sampleRate: 16000,
  44. numberOfChannels: 1,
  45. encodeBitRate: 48000,
  46. format: 'wav'
  47. });
  48. // 模拟波形动画
  49. this.waveTimer = setInterval(() => {
  50. this.waveData = this.waveData.map(() => Math.random() * 40 + 20);
  51. }, 100);
  52. },
  53. // 停止录音
  54. stopRecording() {
  55. this.isRecording = false;
  56. recorderManager.stop();
  57. clearInterval(this.waveTimer);
  58. this.waveData = Array(20).fill(20);
  59. },
  60. // 处理确认按钮点击
  61. handleConfirm() {
  62. if (!this.isRecording) {
  63. this.startRecording();
  64. } else {
  65. this.stopRecording();
  66. this.$emit('complete');
  67. }
  68. }
  69. },
  70. beforeDestroy() {
  71. clearInterval(this.waveTimer);
  72. }
  73. }
  74. </script>
  75. <style scoped>
  76. .modal {
  77. position: fixed;
  78. top: 0;
  79. left: 0;
  80. right: 0;
  81. bottom: 0;
  82. background: rgba(0, 0, 0, 0.6);
  83. display: flex;
  84. align-items: center;
  85. justify-content: center;
  86. z-index: 999;
  87. }
  88. .modal-content {
  89. width: 80%;
  90. background: #fff;
  91. border-radius: 20rpx;
  92. padding: 40rpx;
  93. text-align: center;
  94. }
  95. .modal-title {
  96. font-size: 32rpx;
  97. font-weight: bold;
  98. margin-bottom: 20rpx;
  99. }
  100. .modal-text {
  101. font-size: 28rpx;
  102. color: #666;
  103. margin-bottom: 30rpx;
  104. }
  105. .wave-container {
  106. height: 160rpx;
  107. display: flex;
  108. align-items: center;
  109. justify-content: center;
  110. gap: 6rpx;
  111. margin: 30rpx 0;
  112. }
  113. .wave-bar {
  114. width: 8rpx;
  115. background: #0039b3;
  116. border-radius: 4rpx;
  117. transition: height 0.1s ease;
  118. }
  119. .read-text {
  120. background: #f5f5f5;
  121. padding: 30rpx;
  122. border-radius: 10rpx;
  123. font-size: 30rpx;
  124. margin: 30rpx 0;
  125. }
  126. .confirm-btn {
  127. width: 80%;
  128. height: 80rpx;
  129. line-height: 80rpx;
  130. background: #0039b3;
  131. color: #fff;
  132. border-radius: 40rpx;
  133. margin-top: 30rpx;
  134. }
  135. </style>