Przeglądaj źródła

Merge remote-tracking branch 'origin/develop' into develop

jiajunchen 19 godzin temu
rodzic
commit
a7421c9e3a
1 zmienionych plików z 260 dodań i 3 usunięć
  1. 260
    3
      src/view/safeCheck/safeCheck_edit/index.vue

+ 260
- 3
src/view/safeCheck/safeCheck_edit/index.vue Wyświetl plik

@@ -91,7 +91,17 @@
91 91
           maxlength="1000"
92 92
           show-word-limit
93 93
           rows="4"
94
-        />
94
+        >
95
+          <template #right-icon>
96
+            <van-icon 
97
+              name="volume-o" 
98
+              size="20" 
99
+              :color="isRecording ? '#ee0a24' : '#1989fa'"
100
+              @click="toggleVoiceInput"
101
+              style="margin-right: 8px; cursor: pointer;"
102
+            />
103
+          </template>
104
+        </van-field>
95 105
 
96 106
         <van-field
97 107
           border
@@ -145,10 +155,69 @@
145 155
 
146 156
   <van-dialog v-model:show="showDialogVisible" title="删除文件" show-cancel-button
147 157
               confirm-button-color="#ee0124" message="确定删除该文件吗?" @confirm="onDelete" />
158
+
159
+  <!-- 语音识别弹窗 -->
160
+  <van-dialog
161
+    v-model:show="showVoiceDialog"
162
+    title="语音输入"
163
+    :show-cancel-button="false"
164
+    :show-confirm-button="false"
165
+    :close-on-click-overlay="true"
166
+    width="90%"
167
+  >
168
+    <div style="padding: 20px; text-align: center;">
169
+      <van-icon 
170
+        name="volume-o" 
171
+        size="60" 
172
+        :color="isRecording ? '#ee0a24' : '#1989fa'"
173
+        :class="{ 'pulsing': isRecording }"
174
+      />
175
+      <div style="margin-top: 20px; font-size: 16px; color: #323233;">
176
+        {{ isRecording ? '正在录音,请说话...' : voiceErrorMessage || '点击开始录音' }}
177
+      </div>
178
+      <!-- 错误信息显示 -->
179
+      <div v-if="voiceErrorMessage && !isRecording" style="margin-top: 15px; padding: 10px; background: #fff7e6; border-radius: 4px; border-left: 3px solid #ff9800;">
180
+        <div style="font-size: 14px; color: #ff9800; text-align: left;">
181
+          {{ voiceErrorMessage }}
182
+        </div>
183
+      </div>
184
+      <!-- 识别结果显示 -->
185
+      <div v-if="recognizedText" style="margin-top: 15px; padding: 10px; background: #f7f8fa; border-radius: 4px; text-align: left; max-height: 150px; overflow-y: auto;">
186
+        <div style="font-size: 14px; color: #666; margin-bottom: 5px;">识别结果:</div>
187
+        <div style="font-size: 14px; color: #323233; word-break: break-all;">{{ recognizedText }}</div>
188
+      </div>
189
+      <div style="margin-top: 20px; display: flex; justify-content: center; gap: 10px;">
190
+        <van-button 
191
+          v-if="!isRecording" 
192
+          type="primary" 
193
+          size="small" 
194
+          @click="startRecognition"
195
+        >
196
+          开始录音
197
+        </van-button>
198
+        <van-button 
199
+          v-else 
200
+          type="danger" 
201
+          size="small" 
202
+          @click="stopRecognition"
203
+        >
204
+          停止录音
205
+        </van-button>
206
+        <van-button 
207
+          v-if="recognizedText" 
208
+          type="primary" 
209
+          size="small" 
210
+          @click="confirmVoiceText"
211
+        >
212
+          确认使用
213
+        </van-button>
214
+      </div>
215
+    </div>
216
+  </van-dialog>
148 217
 </template>
149 218
 
150 219
 <script setup>
151
-import { ref, reactive, onMounted, getCurrentInstance, nextTick } from 'vue';
220
+import { ref, reactive, onMounted, getCurrentInstance, nextTick, onUnmounted } from 'vue';
152 221
 import { closeToast, Dialog, showFailToast, showLoadingToast, showSuccessToast, showToast } from 'vant';
153 222
 
154 223
 const { proxy } = getCurrentInstance();
@@ -356,7 +425,180 @@ import AttachmentS3Image from '@/components/AttachmentS3Image.vue';
356 425
       }
357 426
     });
358 427
   };
359
-  
428
+
429
+  /***********************语音识别功能******************************/
430
+  // 语音识别相关状态
431
+  const isRecording = ref(false);
432
+  const showVoiceDialog = ref(false);
433
+  const recognizedText = ref('');
434
+  const voiceErrorMessage = ref('');
435
+  let recognition = null;
436
+
437
+  // 检查浏览器是否支持语音识别
438
+  function checkSpeechRecognitionSupport() {
439
+    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
440
+    if (!SpeechRecognition) {
441
+      showToast({
442
+        type: 'fail',
443
+        message: '您的浏览器不支持语音识别功能'
444
+      });
445
+      return false;
446
+    }
447
+    return true;
448
+  }
449
+
450
+  // 初始化语音识别
451
+  function initSpeechRecognition() {
452
+    if (!checkSpeechRecognitionSupport()) {
453
+      return;
454
+    }
455
+
456
+    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
457
+    recognition = new SpeechRecognition();
458
+    
459
+    // 设置语言为中文
460
+    recognition.lang = 'zh-CN';
461
+    // 连续识别
462
+    recognition.continuous = true;
463
+    // 返回临时结果
464
+    recognition.interimResults = true;
465
+
466
+    // 识别开始
467
+    recognition.onstart = () => {
468
+      isRecording.value = true;
469
+      recognizedText.value = '';
470
+      voiceErrorMessage.value = '';
471
+    };
472
+
473
+    // 识别结果
474
+    recognition.onresult = (event) => {
475
+      let interimTranscript = '';
476
+      let finalTranscript = '';
477
+
478
+      for (let i = event.resultIndex; i < event.results.length; i++) {
479
+        const transcript = event.results[i][0].transcript;
480
+        if (event.results[i].isFinal) {
481
+          finalTranscript += transcript;
482
+        } else {
483
+          interimTranscript += transcript;
484
+        }
485
+      }
486
+
487
+      recognizedText.value = finalTranscript || interimTranscript;
488
+    };
489
+
490
+    // 识别错误
491
+    recognition.onerror = (event) => {
492
+      console.error('语音识别错误:', event.error);
493
+      isRecording.value = false;
494
+      
495
+      let errorMessage = '语音识别出错';
496
+      switch (event.error) {
497
+        case 'no-speech':
498
+          errorMessage = '未检测到语音,请重试';
499
+          break;
500
+        case 'audio-capture':
501
+          errorMessage = '无法访问麦克风,请检查权限';
502
+          break;
503
+        case 'not-allowed':
504
+          errorMessage = '麦克风权限被拒绝,请在浏览器设置中允许';
505
+          break;
506
+        case 'network':
507
+          errorMessage = '网络错误,请检查网络连接';
508
+          break;
509
+        case 'aborted':
510
+          errorMessage = '语音识别已中断';
511
+          break;
512
+        case 'service-not-allowed':
513
+          errorMessage = '语音识别服务不可用';
514
+          break;
515
+        default:
516
+          errorMessage = `语音识别出错: ${event.error}`;
517
+      }
518
+      
519
+      voiceErrorMessage.value = errorMessage;
520
+      
521
+      showToast({
522
+        type: 'fail',
523
+        message: errorMessage
524
+      });
525
+    };
526
+
527
+    // 识别结束
528
+    recognition.onend = () => {
529
+      isRecording.value = false;
530
+    };
531
+  }
532
+
533
+  // 切换语音输入
534
+  function toggleVoiceInput() {
535
+    if (!checkSpeechRecognitionSupport()) {
536
+      return;
537
+    }
538
+
539
+    if (!recognition) {
540
+      initSpeechRecognition();
541
+    }
542
+
543
+    showVoiceDialog.value = true;
544
+    recognizedText.value = '';
545
+    voiceErrorMessage.value = '';
546
+  }
547
+
548
+  // 开始识别
549
+  function startRecognition() {
550
+    if (!recognition) {
551
+      initSpeechRecognition();
552
+    }
553
+
554
+    // 清除之前的错误信息
555
+    voiceErrorMessage.value = '';
556
+    recognizedText.value = '';
557
+
558
+    try {
559
+      recognition.start();
560
+    } catch (error) {
561
+      console.error('启动语音识别失败:', error);
562
+      voiceErrorMessage.value = '启动语音识别失败,请重试';
563
+      showToast({
564
+        type: 'fail',
565
+        message: '启动语音识别失败,请重试'
566
+      });
567
+    }
568
+  }
569
+
570
+  // 停止识别
571
+  function stopRecognition() {
572
+    if (recognition && isRecording.value) {
573
+      recognition.stop();
574
+    }
575
+  }
576
+
577
+  // 确认使用识别的文本
578
+  function confirmVoiceText() {
579
+    if (recognizedText.value) {
580
+      // 如果已有内容,追加;否则直接设置
581
+      if (form.value.checkResult) {
582
+        form.value.checkResult += recognizedText.value;
583
+      } else {
584
+        form.value.checkResult = recognizedText.value;
585
+      }
586
+      recognizedText.value = '';
587
+      voiceErrorMessage.value = '';
588
+      showVoiceDialog.value = false;
589
+      showToast({
590
+        type: 'success',
591
+        message: '已添加语音识别内容'
592
+      });
593
+    }
594
+  }
595
+
596
+  // 组件卸载时清理
597
+  onUnmounted(() => {
598
+    if (recognition && isRecording.value) {
599
+      recognition.stop();
600
+    }
601
+  });
360 602
 
361 603
 </script>
362 604
 
@@ -369,4 +611,19 @@ import AttachmentS3Image from '@/components/AttachmentS3Image.vue';
369 611
   padding: 10px;
370 612
 }
371 613
 
614
+.pulsing {
615
+  animation: pulse 1.5s ease-in-out infinite;
616
+}
617
+
618
+@keyframes pulse {
619
+  0%, 100% {
620
+    transform: scale(1);
621
+    opacity: 1;
622
+  }
623
+  50% {
624
+    transform: scale(1.2);
625
+    opacity: 0.7;
626
+  }
627
+}
628
+
372 629
 </style>

Ładowanie…
Anuluj
Zapisz