Browse Source

1。新增语音播报功能

hongrunxia 6 months ago
parent
commit
c7c900c780

+ 89 - 0
src/layouts/default/header/components/notify/speakVoice.ts

@@ -0,0 +1,89 @@
+// 定义 SpeakVoice 类并将其导出为默认导出
+export default class SpeakVoice {
+  synth: SpeechSynthesis;
+  instance: any;
+  voices: { name: string }[];
+  constructor() {
+    this.synth = window.speechSynthesis; // 启用文本
+    this.instance = new SpeechSynthesisUtterance();
+    this.voices = [];
+    this.initVoice();
+  }
+
+  // 初始化
+  initVoice() {
+    this.instance.volume = 1; // 声音音量:1,范围从0到1
+    this.instance.rate = 3; // 设置语速:1,范围从0到100
+    this.instance.lang = 'zh-CN'; // 使用的语言:中文
+    this.instance.pitch = 0; // 表示说话的音高,数值,范围从0(最小)到2(最大)。默认值为1
+    this.instance.voiceURI = 'Ting-Ting';
+    // this.instance.voiceURI = 'Google 普通话(中国大陆)';
+  }
+
+  // 语音开始
+  handleSpeak() {
+    this.synth.speak(this.instance as SpeechSynthesisUtterance); // 播放
+  }
+
+  // 语音队列重播
+  handleReply(text) {
+    this.instance.text = text;
+    this.handleCancel();
+    this.handleSpeak();
+  }
+
+  // 语音队列删除 , 删除队列中所有的语音.如果正在播放,则直接停止
+  handleCancel() {
+    this.synth.cancel();
+  }
+
+  // 语音暂停, 暂停语音该次语音播放
+  handleStop() {
+    this.synth.pause();
+  }
+
+  // 恢复暂停的语音
+  handleResume() {
+    this.synth.resume();
+  }
+
+  // 声音切换
+  setVoiceType(voiceName) {
+    const voice = this.voices.find((voice) => voice.name === voiceName);
+    if (voice) {
+      this.instance.voice = voice;
+    } else {
+      console.warn('指定的语音未找到:', voiceName);
+    }
+  }
+
+  // 获取可用的中文语音
+  async getSpeechCnVoices() {
+    try {
+      const voices = await this.getSpeechVoices();
+      const cnVoices = voices.filter((item) => item.lang.startsWith('zh-') && item.localService);
+      if (cnVoices.length === 0) {
+        throw new Error('没有可用的中文语音!');
+      }
+      this.voices = cnVoices;
+      return cnVoices;
+    } catch (error) {
+      console.error(error);
+      throw error;
+    }
+  }
+
+  // 异步获取所有可用的语音
+  async getSpeechVoices() {
+    // 返回一个新的 Promise
+    return new Promise((resolve) => {
+      // 如果当前没有可用的语音,等待 onvoiceschanged 事件触发
+      if (this.synth.getVoices().length === 0) {
+        this.synth.onvoiceschanged = () => resolve(this.synth.getVoices());
+      } else {
+        // 如果已经有可用的语音,立即解析 Promise
+        resolve(this.synth.getVoices());
+      }
+    });
+  }
+}

+ 119 - 0
src/views/vent/deviceManager/comment/FanLineModal .vue

@@ -0,0 +1,119 @@
+<template>
+  <div> </div>
+  <div class="vent-form">
+    <BasicForm @register="registerForm" />
+    <div class="j-box-bottom-button offset-20" style="margin-top: 30px">
+      <div class="j-box-bottom-button-float">
+        <a-button preIcon="ant-design:sync-outlined" @click="onReset">重置</a-button>
+        <a-button type="primary" preIcon="ant-design:save-filled" @click="handleSubmit">保存</a-button>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { inject, nextTick, watch, unref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  // 声明Emits
+  const emit = defineEmits(['saveOrUpdate']);
+  const testData = inject('formData') as any;
+  //表单配置
+  const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
+    schemas: [
+      {
+        label: 'R',
+        field: 'fr',
+        component: 'Input',
+        colProps: { span: 6 },
+      },
+      {
+        label: '角度',
+        field: 'strangle',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '频率',
+        field: 'fhz',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '最大风量',
+        field: 'fqmax',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '最小风量',
+        field: 'fqmin',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '系数a',
+        field: 'ha',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '系数b',
+        field: 'hb',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+      {
+        label: '系数c',
+        field: 'hc',
+        component: 'InputNumber',
+        colProps: { span: 6 },
+      },
+    ],
+    showActionButtonGroup: false,
+    layout: 'horizontal',
+    labelWidth: 80,
+  });
+
+  watch(
+    testData,
+    (newV) => {
+      nextTick(() => {
+        setFieldsValue({ ...newV });
+      });
+    },
+    { immediate: true }
+  );
+
+  // 重置表单
+  async function onReset() {
+    await resetFields();
+    await setFieldsValue({ ...testData });
+  }
+  //表单提交事件
+  async function handleSubmit(v) {
+    try {
+      let values = await validate();
+      emit('saveOrUpdate', values);
+    } finally {
+      // setModalProps({ confirmLoading: false });
+    }
+  }
+</script>
+<style lang="less" scoped>
+  @ventSpace: zxm;
+  .j-box-bottom-button-float {
+    border: none !important;
+    padding-bottom: 30px;
+    left: 0px !important;
+    right: 0px !important;
+    bottom: 0px !important;
+  }
+  .vent-form {
+    // width: 100%;
+    max-height: 700px;
+    overflow-y: auto;
+
+    .@{ventSpace}-select-selection-item {
+      color: rgba(255, 255, 255, 1) !important;
+    }
+  }
+</style>