|
@@ -0,0 +1,1738 @@
|
|
|
+<template>
|
|
|
+ <div class="chatArea" v-loading="loading">
|
|
|
+ <div class="m-operation">
|
|
|
+ <div>实时转录</div>
|
|
|
+ <div>2023-11-11 11:11:24</div>
|
|
|
+ </div>
|
|
|
+ <div class="titBar">
|
|
|
+ <div class="titBarLeft">
|
|
|
+ <div
|
|
|
+ @click="cutBar(index)"
|
|
|
+ :class="pageStatus == index ? 'titBarBorder' : ''"
|
|
|
+ v-for="(i, index) in titBarList"
|
|
|
+ :key="index + 'a'"
|
|
|
+ >
|
|
|
+ <img :src="pageStatus == index ? i.ico : i.ico1" alt="" />{{
|
|
|
+ i.title
|
|
|
+ }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="titBarRig">
|
|
|
+ <!-- <img src="@/assets/icon/classroomObservation/put.png" alt="" />
|
|
|
+ <div style="cursor: pointer">收起</div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-top">
|
|
|
+ <!-- 开始页面 -->
|
|
|
+ <startPage
|
|
|
+ v-show="showIndexPage"
|
|
|
+ @startTape="recordedStart"
|
|
|
+ @uploadTape="uploadRecording"
|
|
|
+ />
|
|
|
+ <!-- 原文速递 -->
|
|
|
+ <transcription
|
|
|
+ v-show="pageStatus == 1 && !showIndexPage"
|
|
|
+ :data="transcriptionData"
|
|
|
+ />
|
|
|
+ <!-- ai对话 -->
|
|
|
+ <tape
|
|
|
+ ref="tapeRef"
|
|
|
+ :aiNameList="roleList"
|
|
|
+ :chatData="chatList"
|
|
|
+ v-show="pageStatus == 0 && !showIndexPage"
|
|
|
+ />
|
|
|
+ <!-- <div class="t-t-m-Item" v-show="cardStatus==1"> -->
|
|
|
+ <iframe
|
|
|
+ ref="viframe"
|
|
|
+ v-if="pageStatus == 2 && !showIndexPage"
|
|
|
+ style="width: 100%; height: 100%; border: none"
|
|
|
+ :src="
|
|
|
+ 'https://view.officeapps.live.com/op/view.aspx?src=' +
|
|
|
+ encodeURIComponent(fileUrl)
|
|
|
+ "
|
|
|
+ ></iframe>
|
|
|
+ <!-- </div> -->
|
|
|
+ </div>
|
|
|
+ <div class="ca-bottom">
|
|
|
+ <div class="ca-b-operation">
|
|
|
+ <div class="ca-b-o-header">
|
|
|
+ <div class="ca-b-o-h-left">
|
|
|
+ <!-- <div class="ca-b-o-h-l-select" @click.stop="changeAnalysis()">
|
|
|
+ <span class="ca-b-o-h-l-s-icon el-icon-collection"></span>
|
|
|
+ <div class="ca-b-o-h-s-l-text">课堂观察</div>
|
|
|
+ <span class="ca-b-o-h-s-l-icon2 el-icon-caret-top"></span>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div class="ca-b-o-h-l-select" style="color: #3681fc">
|
|
|
+ <div
|
|
|
+ style="cursor: pointer"
|
|
|
+ class="ca-b-o-h-s-l-text"
|
|
|
+ @click.stop="languageShow = !languageShow"
|
|
|
+ >
|
|
|
+ {{ languageList.find((i) => i.label == languageRadio).lang }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="languageList"
|
|
|
+ v-click-outside="handleBlur"
|
|
|
+ v-if="languageShow"
|
|
|
+ >
|
|
|
+ <el-radio
|
|
|
+ v-for="(i, index) in languageList"
|
|
|
+ :key="index + 'lag'"
|
|
|
+ :class="i.label == languageRadio ? 'radioBg' : ''"
|
|
|
+ v-model.number="languageRadio"
|
|
|
+ :label.Num="i.label"
|
|
|
+ >{{ i.lang }}</el-radio
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- <span class="ca-b-o-h-s-l-icon2 el-icon-caret-top"></span> -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="ca-b-o-h-l-btn" @click.stop="uploadRecording()">
|
|
|
+ <div class="ca-b-o-h-b-l-text">上传录音</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-h-right">
|
|
|
+ <div class="ca-b-o-h-r-radio">
|
|
|
+ <div
|
|
|
+ :class="
|
|
|
+ (index == 0 && showIndexPage) ||
|
|
|
+ (index == 1 && !showIndexPage)
|
|
|
+ ? 'TapeCss'
|
|
|
+ : ''
|
|
|
+ "
|
|
|
+ class="tapeSty"
|
|
|
+ @click="cutTape(index)"
|
|
|
+ v-for="(i, index) in tapeList"
|
|
|
+ :key="index + 'b'"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ :src="
|
|
|
+ (index == 0 && showIndexPage) ||
|
|
|
+ (index == 1 && !showIndexPage)
|
|
|
+ ? i.ico
|
|
|
+ : i.ico1
|
|
|
+ "
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- <span @click.stop="changeContinuousDialogue(!continuousDialogue)"
|
|
|
+ >连续对话</span
|
|
|
+ >
|
|
|
+ <el-switch
|
|
|
+ v-model="continuousDialogue"
|
|
|
+ active-color="#3681FC"
|
|
|
+ inactive-color="#b2bfc3"
|
|
|
+ >
|
|
|
+ </el-switch> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-main">
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-tape"
|
|
|
+ v-show="controlsStatus == 0"
|
|
|
+ @click.stop="recordedStart()"
|
|
|
+ >
|
|
|
+ <span class="el-icon-microphone"></span>
|
|
|
+ <div class="ca-b-o-m-t-text">点击开始录音</div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-tapeTwo" v-show="controlsStatus == 2">
|
|
|
+ <mini-audio
|
|
|
+ v-if="audioUrl"
|
|
|
+ :audio-source="audioUrl"
|
|
|
+ class="audio_class"
|
|
|
+ ></mini-audio>
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ margin-left: 20px;
|
|
|
+ cursor: pointer;
|
|
|
+ background-color: #3681fc;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ "
|
|
|
+ @click="recordedStart()"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ style="width: 10px; height: 16px"
|
|
|
+ src="../../../../assets/icon/classroomObservation/blueMai.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="ca-b-o-m-inputAre"
|
|
|
+ v-show="controlsStatus == 3"
|
|
|
+ v-loading="textareaLoading"
|
|
|
+ >
|
|
|
+ <div class="ca-b-o-m-left">
|
|
|
+ <textarea
|
|
|
+ id="myTextarea"
|
|
|
+ ref="textareaRef"
|
|
|
+ min-rows="1"
|
|
|
+ max-rows="5"
|
|
|
+ v-model="textareaValue"
|
|
|
+ placeholder="在此输入您想了解的内容"
|
|
|
+ autosize="none"
|
|
|
+ @input="textareaChange"
|
|
|
+ @change="textareaChange"
|
|
|
+ @keydown="textareaKeydown"
|
|
|
+ ></textarea>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-right">
|
|
|
+ <!-- <span @click.stop="tapeSubmit()"></span> -->
|
|
|
+ <!-- <div :class="sendBtnDsiable ? 'ca-b-o-m-r-dsiableBtn' : ''">
|
|
|
+ 发送
|
|
|
+ </div> -->
|
|
|
+ <el-button
|
|
|
+ :disabled="textareaValue.trim().length == 0"
|
|
|
+ type="primary"
|
|
|
+ size="mini"
|
|
|
+ @click="send()"
|
|
|
+ >发送</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ ref="roleListRef"
|
|
|
+ v-click-outside="noShowRoleList"
|
|
|
+ class="ca_b_o_m_roleList"
|
|
|
+ v-if="showRoleList && choseRoleList.length != 0"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ 'ca_b_o_m_rl_item',
|
|
|
+ roleListIndex == index ? 'ca_b_o_m_rl_itemActive' : '',
|
|
|
+ ]"
|
|
|
+ v-for="(item, index) in choseRoleList"
|
|
|
+ :key="item.assistant_id"
|
|
|
+ @click="choseRole(item)"
|
|
|
+ @mouseover="() => (roleListIndex = index)"
|
|
|
+ >
|
|
|
+ <div class="ca_b-o_m_rl_i_top">
|
|
|
+ <el-avatar
|
|
|
+ size="medium"
|
|
|
+ :src="
|
|
|
+ item.headUrl
|
|
|
+ ? item.headUrl
|
|
|
+ : require('@/assets/icon/classroomObservation/aiAvatar.png')
|
|
|
+ "
|
|
|
+ ></el-avatar>
|
|
|
+ <div>
|
|
|
+ <div>{{ item.assistantName }}</div>
|
|
|
+ <span v-if="item.username">作者:{{ item.username }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca_b-o_m_rl_i_bottom">
|
|
|
+ <span>{{ item.description }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-TapeArea" v-show="controlsStatus == 1">
|
|
|
+ <div class="ca-b-o-m-i-left">
|
|
|
+ <img
|
|
|
+ style="height: 120%"
|
|
|
+ src="@/assets/icon/classroomObservation/isTape.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <div>
|
|
|
+ <div v-if="recordedForm.status == 1" style="color: #ee3e3e">
|
|
|
+ 录音中...
|
|
|
+ </div>
|
|
|
+ <div v-if="recordedForm.status == 2" style="color: #6b798e">
|
|
|
+ 已暂停...
|
|
|
+ </div>
|
|
|
+ <span>{{ recordedForm.time }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <img
|
|
|
+ style="height: 120%"
|
|
|
+ src="@/assets/icon/classroomObservation/tapetime.png"
|
|
|
+ alt=""
|
|
|
+ /> -->
|
|
|
+ <div
|
|
|
+ style="
|
|
|
+ width: 100px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <div class="lyStart" @click="stopRecorded()">
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/lyStart.png"
|
|
|
+ alt=""
|
|
|
+ v-if="recordedForm.status == 1"
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/start.png"
|
|
|
+ alt=""
|
|
|
+ v-if="recordedForm.status == 2"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="lyStart" @click="finishRecorded()">
|
|
|
+ <img
|
|
|
+ style="width: 12px; height: 12px"
|
|
|
+ src="@/assets/icon/classroomObservation/lyStop.png"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="ca-b-o-m-left">
|
|
|
+ <textarea :value="textareaValue" autosize="none"></textarea>
|
|
|
+ </div>
|
|
|
+ <div class="ca-b-o-m-right">
|
|
|
+ <span @click.stop="tapeSubmit()"></span>
|
|
|
+ <div :class="sendBtnDsiable ? 'ca-b-o-m-r-dsiableBtn' : ''">
|
|
|
+ 发送
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 录音转文字 -->
|
|
|
+ <iframe
|
|
|
+ allow="camera *; microphone *;display-capture;midi;encrypted-media;"
|
|
|
+ src="https://beta.cloud.cocorobo.cn/browser/public/index.html"
|
|
|
+ ref="iiframe"
|
|
|
+ v-show="false"
|
|
|
+ ></iframe>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import startPage from "./startPage.vue";
|
|
|
+import transcription from "./transcription.vue";
|
|
|
+import tape from "./tape.vue";
|
|
|
+import { v4 as uuidv4 } from "uuid";
|
|
|
+import Recorder from "js-audio-recorder";
|
|
|
+import MarkdownIt from "markdown-it";
|
|
|
+const lamejs = require("lamejs");
|
|
|
+
|
|
|
+const recorder = new Recorder({
|
|
|
+ sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
|
|
|
+ sampleRate: 48000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
|
|
|
+ numChannels: 1, // 声道,支持 1 或 2, 默认是1
|
|
|
+ // compiling: false,(0.x版本中生效,1.x增加中) // 是否边录边转换,默认是false
|
|
|
+});
|
|
|
+
|
|
|
+// 绑定事件-打印的是当前录音数据
|
|
|
+// recorder.onprogress = function (params) {
|
|
|
+// console.log('--------------START---------------')
|
|
|
+// console.log('录音时长(秒)', params.duration);
|
|
|
+// console.log('录音大小(字节)', params.fileSize);
|
|
|
+// console.log('录音音量百分比(%)', params.vol);
|
|
|
+// console.log('当前录音的总数据([DataView, DataView...])', params.data);
|
|
|
+// console.log('--------------END---------------')
|
|
|
+// };
|
|
|
+
|
|
|
+// 自定义指令,用于处理点击外部区域的事件
|
|
|
+const clickOutside = {
|
|
|
+ bind(el, binding) {
|
|
|
+ // 在元素上绑定一个点击事件监听器
|
|
|
+ el.clickOutsideEvent = function (event) {
|
|
|
+ // 检查点击事件是否发生在元素的内部
|
|
|
+ if (!(el === event.target || el.contains(event.target))) {
|
|
|
+ // 如果点击事件发生在元素的外部,则触发指令绑定的方法,将点击的event数据传过去
|
|
|
+ binding.value(event);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 在文档上添加点击事件监听器
|
|
|
+ document.addEventListener("click", el.clickOutsideEvent);
|
|
|
+ },
|
|
|
+ unbind(el) {
|
|
|
+ // 在元素上解除点击事件监听器
|
|
|
+ document.removeEventListener("click", el.clickOutsideEvent);
|
|
|
+ },
|
|
|
+};
|
|
|
+export default {
|
|
|
+ emits: ["updateFileId", "changeAudioUrl"],
|
|
|
+ props: {
|
|
|
+ tid: {
|
|
|
+ type: String,
|
|
|
+ require: true,
|
|
|
+ },
|
|
|
+ fileId: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ fileIdId: {
|
|
|
+ type: String,
|
|
|
+ default: "",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ components: {
|
|
|
+ startPage,
|
|
|
+ transcription,
|
|
|
+ tape,
|
|
|
+ },
|
|
|
+ directives: {
|
|
|
+ "click-outside": clickOutside, // 注册自定义指令
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // continuousDialogue: true,
|
|
|
+ controlsStatus: 3, //0--点击开始录音 1--录音中 2--录音完毕预览 3--文字输入
|
|
|
+ pageStatus: 0, //0--ai对话 1--原文文稿 2--转录文稿
|
|
|
+ showIndexPage: false, //是否显示初始页面
|
|
|
+ languageRadio: 1, //设置选择语言
|
|
|
+ languageShow: false, //控制显示
|
|
|
+ loading: false,
|
|
|
+ textareaValue: "",
|
|
|
+ textareaLoading: false,
|
|
|
+ showRoleList: false,
|
|
|
+ roleListIndex: 0,
|
|
|
+ recordedForm: {
|
|
|
+ time: "00:00:00", //时间
|
|
|
+ status: 0, //0--未录音 1--正在录音 2--暂停 3--录音结束
|
|
|
+ },
|
|
|
+ roleList: [],
|
|
|
+ publicRoleList: [],
|
|
|
+ audioUrl: "",
|
|
|
+ fileUrl:
|
|
|
+ "https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/%E8%BD%AC%E5%BD%95%E6%96%87%E7%A8%BF1713172600896.xlsx",
|
|
|
+ // 设置list
|
|
|
+ languageList: [
|
|
|
+ { label: 1, lang: "普通话" },
|
|
|
+ { label: 2, lang: "广东话" },
|
|
|
+ { label: 3, lang: "英语" },
|
|
|
+ ],
|
|
|
+ // 语音文字list
|
|
|
+ tapeList: [
|
|
|
+ {
|
|
|
+ ico: require("@/assets/icon/classroomObservation/mai1.png"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/mai2.png"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ ico: require("@/assets/icon/classroomObservation/wen1.png"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/wen2.png"),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ titBarList: [
|
|
|
+ {
|
|
|
+ title: "Al对话",
|
|
|
+ ico: require("@/assets/icon/classroomObservation/Group9101.png"),
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/Group9102.png"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "原文速览",
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/Vector.png"),
|
|
|
+ ico: require("@/assets/icon/classroomObservation/Vector2.png"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "转录文稿",
|
|
|
+ ico1: require("@/assets/icon/classroomObservation/zhuanlu.png"),
|
|
|
+ ico: require("@/assets/icon/classroomObservation/zhuanlu2.png"),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ transcriptionData: {
|
|
|
+// time: "2024-01-13 15:58:00",
|
|
|
+// content: `对爱整洁,有精神、不拖拉,多思考。老师你好,同学们好。
|
|
|
+// 请坐。前几天白老师关注到一则新闻,我们大鹏新区政府提出要将2024年作为旅游高质量发展年,为了吸引更多的游客来到咱们大鹏,你认为最重要的是什么来?第一小组。
|
|
|
+// 我认为最重要的是要先把环境、绿水青山环境弄好,这样才能吸引更多的人来,大鹏是的。
|
|
|
+// 大家同意他的想法吗?保护大棚环境人人有责,上周咱们班的两位环境调查员就去到葵冲进行了实地调查,我们来看看他们发现了什么。
|
|
|
+// 大家好,我们是人大附中深圳学校五1班的张龙溪,何瑞一为了响应区政府的号召,今天我们作为环境调查员,准备实地调查一下葵冲的环境情况,走跟随我们的镜头一起去看一看我们调查到的情况有什么样,这样的。
|
|
|
+// 应该是这样的,就是这样的,像这样的。
|
|
|
+// 像这种情况。
|
|
|
+// 像这种情况。
|
|
|
+// 像这样的。
|
|
|
+// 我们调查到的情况不是很好,同学们你们。
|
|
|
+// 谁知谁知。
|
|
|
+// 刚刚视频有一些小小的不同步,但不影响我们去观察里面的内容。
|
|
|
+// 好,来,同学们,通过刚才的视频,你看到了哪些环境问题?第五小组。
|
|
|
+// 我看到了菜市场上到处是垃圾,到处是那些烂掉的瓜果皮,是的。
|
|
|
+// 其他小组呢?来第八小组我。
|
|
|
+// 看我看到了路上还有很多漂移的垃圾就路上了。
|
|
|
+// 你观察得很认真,是的,在咱们生活的这片区域确实存在很多的垃圾问题,这些垃圾主要是家庭里面产生的生活垃圾。
|
|
|
+// 根据调查,一个家庭一天产生的垃圾大约是三千克,咱们班一共有45位同学,所有同学的家庭一天产生的生活垃圾总质量是多少?老师还调查到一些数据。我校小学部一共有1556人,整个大鹏新区共有55,224户家庭,整个深圳市有6,424,556户家庭,他们一天分别产生多少垃圾呢?现在请小组长从材料框当中拿出实验记录单,我们用计算器来速算一下,将结果记录下来。
|
|
|
+// 好,可以开始计算。二十五六场这样做的之前工作。
|
|
|
+// 还差一些,这样更准确一点。
|
|
|
+// 用计算器这样更准确算完了没有?
|
|
|
+// 你们。
|
|
|
+// 算完了吗老师?
|
|
|
+// 拍一下照片。
|
|
|
+// 大家算完了吗?
|
|
|
+// 好,算完的小组面向老师坐,好好表扬第八小组。好,第五、第四、第三。
|
|
|
+// 好,这是第四小组的数据,我们来看跟大家的一样吗?一样,在刚刚大家记录数据的时候,你发现了什么?在你刚刚写下这些数据,有什么发现?第三小组。
|
|
|
+// 我发现每天生产的垃圾会非常多。
|
|
|
+// 垃圾很多多,到什么程度?我们来看。多到全班同学一天产生的垃圾,相当于一头成年公羊这么重,多到全校小学部家庭的垃圾,一天有一头非洲大象这么重。大鹏新区所有家庭一天产生的垃圾量相当于32头,非洲大象这么重,整个深圳市一天产生的垃圾高达3800头,非洲大象这么重。
|
|
|
+// 老师看到很多同学发出来很惊讶的表情,整个深圳市就产生这么多的垃圾,整个广东省全国23个省加起来,放眼全球,全世界一年产生的垃圾是多少?我们来看这个统计图,把各个地区的垃圾量加起来,全球一年产生垃圾量高达20.17亿吨。这么多的垃圾如果填埋高度是一米的话,它可以埋掉三个深圳或者一个广州的面积。
|
|
|
+// 面对这组数据,你有什么样的感受跟大家分享一下。来,第一小组,垃圾好多。
|
|
|
+// 垃圾很多。
|
|
|
+// 其他小组有什么样的感受?第八小组。
|
|
|
+// 如果我们一直都以填埋的方式去处理垃圾的话,可能全球的土地都用于填埋垃圾了。
|
|
|
+// 你还告诉了大家处理垃圾的一种方式是的,这么多的垃圾如果没有得到及时的处理,他们会侵占大量的土地包围我们的城市家园,我们就会陷入到一种垃圾围城的现状,面对这么庞大的垃圾量,我们该怎么办?
|
|
|
+// 第七小组。
|
|
|
+// 我觉得我们可以按照垃圾的种类来进行分类,比如说回收垃圾,它可以是回收,然后再利用的或者就是有害垃圾,比如说电池会污染,将会人们将会对它处以专业的处理。
|
|
|
+// 你想到了垃圾分类,其他小组。
|
|
|
+// 第五小组。
|
|
|
+// 并且像很多我们要应该少用一次性的垃圾,比如说你买菜的时候要少用一次性的塑料袋,尽量用布袋,这样子的话可以节省既节省资源,又节省了垃圾的。
|
|
|
+// 生产量,你说的是一个非常实用的方法,大家刚刚都说出来了,实际的行动是的。今天就让我们一起行动起来,一起共同想办法来解决垃圾问题。
|
|
|
+// 面对垃圾问题。
|
|
|
+// 正如第八小组刚刚说的,咱们国家早期的处理方式是直接填埋和焚烧发电,这两种方法在一定程度上减少了垃圾,但也存在着很严重的弊端。现在我们就一起来说一说这两种方法的好处和弊端。第一小组。
|
|
|
+// 直接填埋这种方法会占用大量土地,而且还会污染土地,焚烧发电这种方法会会污_
|
|
|
+// `,
|
|
|
+ },
|
|
|
+ chatList: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 选择可以@的角色
|
|
|
+ choseRoleList() {
|
|
|
+ let result = [...this.roleList, ...this.publicRoleList];
|
|
|
+ const _index = this.textareaValue.lastIndexOf("@");
|
|
|
+ if (_index !== -1) {
|
|
|
+ let roleName = this.textareaValue.substring(_index + 1);
|
|
|
+ result = result.filter((i) => i.assistantName.indexOf(roleName) != -1);
|
|
|
+ } else {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ choseRoleList() {
|
|
|
+ this.roleListIndex = 0;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleBlur(event) {
|
|
|
+ // console.log("点击其它区域啦", event);
|
|
|
+ this.languageShow = !this.languageShow;
|
|
|
+ },
|
|
|
+ // 上传录音
|
|
|
+ uploadRecording() {
|
|
|
+ let input = document.createElement("input");
|
|
|
+ input.type = "file";
|
|
|
+ input.accept = ".wav";
|
|
|
+ // input.accept = "audio/*, .txt, .pdf, .xlsx";
|
|
|
+ input.click();
|
|
|
+ input.onchange = () => {
|
|
|
+ this.loading = true;
|
|
|
+ let file = input.files[0];
|
|
|
+ this.uploadWavFileAndGetText(file)
|
|
|
+ return;
|
|
|
+ var credentials = {
|
|
|
+ accessKeyId: "AKIATLPEDU37QV5CHLMH",
|
|
|
+ secretAccessKey: "Q2SQw37HfolS7yeaR1Ndpy9Jl4E2YZKUuuy2muZR",
|
|
|
+ }; //秘钥形式的登录上传
|
|
|
+ window.AWS.config.update(credentials);
|
|
|
+ window.AWS.config.region = "cn-northwest-1"; //设置区域
|
|
|
+
|
|
|
+ var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
|
|
|
+ var _this = this;
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ var params = {
|
|
|
+ Key:
|
|
|
+ file.name.split(".")[0] +
|
|
|
+ new Date().getTime() +
|
|
|
+ "." +
|
|
|
+ file.name.split(".")[file.name.split(".").length - 1],
|
|
|
+ ContentType: file.type,
|
|
|
+ Body: file,
|
|
|
+ "Access-Control-Allow-Credentials": "*",
|
|
|
+ ACL: "public-read",
|
|
|
+ }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
|
|
|
+ var options = {
|
|
|
+ partSize: 2048 * 1024 * 1024,
|
|
|
+ queueSize: 2,
|
|
|
+ leavePartsOnError: true,
|
|
|
+ };
|
|
|
+ bucket
|
|
|
+ .upload(params, options)
|
|
|
+ .on("httpUploadProgress", function (evt) {
|
|
|
+ //这里可以写进度条
|
|
|
+ // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
|
|
|
+ })
|
|
|
+ .send(function (err, data) {
|
|
|
+ if (err) {
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ _this.loading = false;
|
|
|
+ } else {
|
|
|
+ // 判断是不是音频文件
|
|
|
+ const audioRegex = /\.(mp3|wav|ogg|flac|m4a)$/i;
|
|
|
+ if (audioRegex.test(data.Location)) {
|
|
|
+ _this.controlsStatus = 2;
|
|
|
+ _this.showIndexPage = false;
|
|
|
+ _this.pageStatus = 1;
|
|
|
+ // _this.audioUrl = data.Location;
|
|
|
+ _this.$emit("changeAudioUrl", data);
|
|
|
+ _this.loading = false;
|
|
|
+ } else {
|
|
|
+ _this.ajax
|
|
|
+ .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
|
|
|
+ url: data.Location,
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse;
|
|
|
+ if (_data.result && _data.result.id) {
|
|
|
+ _this.$emit("updateFileId", _data.result.id);
|
|
|
+ let pram2 = {
|
|
|
+ id: _this.fileIdId,
|
|
|
+ json_data: JSON.stringify({
|
|
|
+ file_ids: _data.result.id,
|
|
|
+ }),
|
|
|
+ // json_data: JSON.stringify({file_ids:'file-r5phg4I2oFqly4WpW7oOOTnA'}),
|
|
|
+ };
|
|
|
+ _this.ajax.post(
|
|
|
+ "https://gpt4.cocorobo.cn/update_classroom_observation",
|
|
|
+ pram2
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ }
|
|
|
+ _this.loading = false;
|
|
|
+ // this.$emit("updateFileId", data.Location)
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ _this.loading = false;
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // console.log(data.Location)
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // this.mainBtnStatus = 1;
|
|
|
+ // this.barNum = 4;
|
|
|
+ },
|
|
|
+ cutBar(val) {
|
|
|
+ this.pageStatus = val;
|
|
|
+ if (this.pageStatus == 0) {
|
|
|
+ //ai对话
|
|
|
+ this.controlsStatus = 3;
|
|
|
+ } else if (this.pageStatus == 1 || this.pageStatus == 2) {
|
|
|
+ // 原文速览&&转录文稿
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ }
|
|
|
+ this.showIndexPage = false;
|
|
|
+ },
|
|
|
+ cutTape(val) {
|
|
|
+ if (val == 0) {
|
|
|
+ this.showIndexPage = true;
|
|
|
+ this.controlsStatus = 0;
|
|
|
+ } else if (val == 1) {
|
|
|
+ if (this.pageStatus == 0) {
|
|
|
+ //ai对话
|
|
|
+ this.controlsStatus = 3;
|
|
|
+ } else if (this.pageStatus == 1 || this.pageStatus == 2) {
|
|
|
+ // 原文速览&&转录文稿
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ }
|
|
|
+ this.showIndexPage = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ recordedStart() {
|
|
|
+ // 开始录音
|
|
|
+ if (this.audioUrl) {
|
|
|
+ this.$confirm("再次录音会顶替掉原先的录音,您确定吗", "提醒", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning",
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+ this.recordedForm.status = 0;
|
|
|
+ this.audioUrl = "";
|
|
|
+ recorder.initRecorder(); //初始化录音
|
|
|
+ recorder.destroy(); // 销毁录音
|
|
|
+ this.recordedStart();
|
|
|
+ })
|
|
|
+ .catch((_) => {
|
|
|
+ console.log("不顶替");
|
|
|
+ });
|
|
|
+ } else if (this.controlsStatus != 1 && this.recordedForm.status == 0) {
|
|
|
+ recorder.initRecorder(); //初始化录音
|
|
|
+ recorder.destroy(); // 销毁录音
|
|
|
+ // 开始录音
|
|
|
+ recorder.start().then(
|
|
|
+ () => {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ this.recordedForm.status = 1;
|
|
|
+ recorder.onprogress = this.updateRecordedTime;
|
|
|
+ this.$message.success("录音已开始");
|
|
|
+ },
|
|
|
+ (error) => {
|
|
|
+ this.controlsStatus = 0;
|
|
|
+ this.recordedForm.status = 0;
|
|
|
+ // _this.$message.error(`${error.name} : ${error.message}`);
|
|
|
+ this.$message.error(
|
|
|
+ `没有找到可使用的麦克风,或者您没有允许此网页使用麦克风`
|
|
|
+ );
|
|
|
+ // 出错了
|
|
|
+ console.log(`${error.name} : ${error.message}`);
|
|
|
+ // if (_this.calcTimer) {
|
|
|
+ // clearInterval(_this.calcTimer)
|
|
|
+ // _this.calcTimer = null;
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } else if ([1, 2].includes(this.recordedForm.status)) {
|
|
|
+ this.controlsStatus = 1;
|
|
|
+ this.$message.info("还在录音中");
|
|
|
+ }
|
|
|
+ // this.controlsStatus = 1;
|
|
|
+ },
|
|
|
+ updateRecordedTime({ duration }) {
|
|
|
+ // 更新currentTime,将秒数转换为时分秒格式
|
|
|
+ let hours = Math.floor(duration / 3600);
|
|
|
+ let minutes = Math.floor((duration % 3600) / 60);
|
|
|
+ let seconds = Math.floor(duration % 60);
|
|
|
+ this.recordedForm.time = `${hours.toString().padStart(2, "0")}:${minutes
|
|
|
+ .toString()
|
|
|
+ .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
|
+ },
|
|
|
+ //切换观察
|
|
|
+ // changeAnalysis() {
|
|
|
+ // this.$message.info("切换观察");
|
|
|
+ // },
|
|
|
+ // 切换连续对话
|
|
|
+ changeContinuousDialogue(newValue) {
|
|
|
+ this.continuousDialogue = newValue;
|
|
|
+ },
|
|
|
+ // 点击发送旁的录音
|
|
|
+ // tapeSubmit() {
|
|
|
+ // this.$message.info("发送旁的录音");
|
|
|
+ // this.mainBtnStatus = 0;
|
|
|
+ // this.pageStatus = 1;
|
|
|
+ // this.TapeNum = 0;
|
|
|
+ // },
|
|
|
+ async finishRecorded() {
|
|
|
+ this.loading = true;
|
|
|
+ recorder.stop();
|
|
|
+ this.$message.success("已结束录音");
|
|
|
+
|
|
|
+
|
|
|
+ let file = this.convertToMp3(recorder.getWAV());
|
|
|
+ const mp3Blob = recorder.getWAVBlob();
|
|
|
+ let audioFile = this.dataURLtoAudio(mp3Blob, "wav");
|
|
|
+ this.uploadWavFileAndGetText(audioFile)
|
|
|
+ return;
|
|
|
+ file.lastModifiedDate = new Date();
|
|
|
+ file.name = "recordedFile.mp3";
|
|
|
+ var credentials = {
|
|
|
+ accessKeyId: "AKIATLPEDU37QV5CHLMH",
|
|
|
+ secretAccessKey: "Q2SQw37HfolS7yeaR1Ndpy9Jl4E2YZKUuuy2muZR",
|
|
|
+ }; //秘钥形式的登录上传
|
|
|
+ window.AWS.config.update(credentials);
|
|
|
+ window.AWS.config.region = "cn-northwest-1"; //设置区域
|
|
|
+
|
|
|
+ var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
|
|
|
+ var _this = this;
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ var params = {
|
|
|
+ Key:
|
|
|
+ file.name.split(".")[0] +
|
|
|
+ new Date().getTime() +
|
|
|
+ "." +
|
|
|
+ file.name.split(".")[file.name.split(".").length - 1],
|
|
|
+ ContentType: file.type,
|
|
|
+ Body: file,
|
|
|
+ "Access-Control-Allow-Credentials": "*",
|
|
|
+ ACL: "public-read",
|
|
|
+ }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
|
|
|
+ var options = {
|
|
|
+ partSize: 2048 * 1024 * 1024,
|
|
|
+ queueSize: 2,
|
|
|
+ leavePartsOnError: true,
|
|
|
+ };
|
|
|
+ bucket
|
|
|
+ .upload(params, options)
|
|
|
+ .on("httpUploadProgress", function (evt) {
|
|
|
+ //这里可以写进度条
|
|
|
+ // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
|
|
|
+ })
|
|
|
+ .send(function (err, data) {
|
|
|
+ if (err) {
|
|
|
+ _this.$message.error("上传失败");
|
|
|
+ _this.loading = false;
|
|
|
+ } else {
|
|
|
+ // 判断是不是音频文件
|
|
|
+ // 更改录音文件
|
|
|
+ _this.$emit("changeAudioUrl", data);
|
|
|
+ _this.controlsStatus = 2;
|
|
|
+ _this.pageStatus = 1;
|
|
|
+ _this.recordedForm.status = 3;
|
|
|
+ _this.showIndexPage = false;
|
|
|
+ _this.loading = false;
|
|
|
+ // const audioRegex = /\.(mp3|wav|ogg|flac|m4a)$/i;
|
|
|
+ // if (audioRegex.test(data.Location)) {
|
|
|
+ // _this.controlsStatus = 2;
|
|
|
+ // _this.showIndexPage = false;
|
|
|
+ // _this.pageStatus = 1;
|
|
|
+ // _this.audioUrl = data.Location;
|
|
|
+ // _this.loading = false;
|
|
|
+ // } else {
|
|
|
+ // _this.ajax
|
|
|
+ // .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
|
|
|
+ // url: data.Location,
|
|
|
+ // })
|
|
|
+ // .then((res) => {
|
|
|
+ // let _data = res.data.FunctionResponse;
|
|
|
+ // if (_data.result && _data.result.id) {
|
|
|
+ // _this.$emit("updateFileId", _data.result.id);
|
|
|
+ // let pram2 = {
|
|
|
+ // id: _this.fileIdid,
|
|
|
+ // json_data: JSON.stringify({
|
|
|
+ // file_ids: _data.result.id,
|
|
|
+ // }),
|
|
|
+ // // json_data: JSON.stringify({file_ids:'file-r5phg4I2oFqly4WpW7oOOTnA'}),
|
|
|
+ // };
|
|
|
+ // _this.ajax.post(
|
|
|
+ // "https://gpt4.cocorobo.cn/update_classroom_observation",
|
|
|
+ // pram2
|
|
|
+ // );
|
|
|
+ // } else {
|
|
|
+ // _this.$message.error("上传失败");
|
|
|
+ // }
|
|
|
+ // _this.loading = false;
|
|
|
+ // // this.$emit("updateFileId", data.Location)
|
|
|
+ // })
|
|
|
+ // .catch((e) => {
|
|
|
+ // _this.loading = false;
|
|
|
+ // _this.$message.error("上传失败");
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+
|
|
|
+ // console.log(data.Location)
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // recorder.download(mp3Blob, "recorder", "mp3");
|
|
|
+ // let wavBlob = await recorder.getWAVBlob()
|
|
|
+ // const reader = new FileReader();
|
|
|
+ //将blob转未ArrayBuffer
|
|
|
+ // reader.onload = () => {
|
|
|
+ // const audioData = reader.result; // 获取 WAV blob 数据
|
|
|
+ // const samples = new Int16Array(audioData); // 转换为 Int16Array
|
|
|
+ // // 创建一个mp3编码器
|
|
|
+ // const mp3Encoder = new lamejs.Mp3Encoder(1, 44100, 128);
|
|
|
+ // // 将录音数据编码为MP3
|
|
|
+ // const mp3Data = mp3Encoder.encodeBuffer(samples);
|
|
|
+ // // 创建一个Blob包含MP3数据
|
|
|
+ // const mp3Blob = new Blob([mp3Data], { type: "audio/mp3" });
|
|
|
+ // console.log(`MP3文件:${mp3Blob}`);
|
|
|
+ // this.loading = false;
|
|
|
+ // recorder.initRecorder(); // 初始化录音
|
|
|
+ // recorder.destroy(); // 销毁录音
|
|
|
+ // };
|
|
|
+ // reader.readAsArrayBuffer(blob);
|
|
|
+ },
|
|
|
+ stopRecorded() {
|
|
|
+ if (!recorder.ispause) {
|
|
|
+ recorder.pause();
|
|
|
+ this.recordedForm.status = 2;
|
|
|
+ this.$message.warning("已暂停录音");
|
|
|
+ } else {
|
|
|
+ recorder.resume();
|
|
|
+ this.recordedForm.status = 1;
|
|
|
+ this.$message.success("已继续录音");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeAudioUrl(newValue) {
|
|
|
+ if (!newValue) return;
|
|
|
+ this.audioUrl = newValue;
|
|
|
+ this.pageStatus = 1;
|
|
|
+ this.controlsStatus = 2;
|
|
|
+ this.showIndexPage = false;
|
|
|
+ },
|
|
|
+ // 发送消息
|
|
|
+ send(_text = this.textareaValue) {
|
|
|
+ this.textareaValue = "";
|
|
|
+ // 判断输入的文本是否为空
|
|
|
+ if (!_text.trim()) return;
|
|
|
+ // 这里处理@的角色
|
|
|
+ let _atRoleList = [];
|
|
|
+ let _roleList = [...this.roleList, ...this.publicRoleList];
|
|
|
+ _roleList.forEach((i) => {
|
|
|
+ if (_text.indexOf(`@${i.assistantName}`) != -1) {
|
|
|
+ _atRoleList.push(i);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (_atRoleList.length > 0) {
|
|
|
+ //有@角色
|
|
|
+ let _replaceText = _text;
|
|
|
+ let _htmlText = _text;
|
|
|
+ _atRoleList.forEach((_i) => {
|
|
|
+ _replaceText = _replaceText.replaceAll(`@${_i.assistantName}`, ``);
|
|
|
+ _htmlText = _htmlText.replaceAll(
|
|
|
+ `@${_i.assistantName}`,
|
|
|
+ `<span class='aite-name'>@${_i.assistantName}</span>`
|
|
|
+ );
|
|
|
+ });
|
|
|
+ _atRoleList.forEach((_item, _index) => {
|
|
|
+ const _uid = uuidv4();
|
|
|
+ if (_index == 0) {
|
|
|
+ this.chatList.push({
|
|
|
+ loading: true,
|
|
|
+ role: "user",
|
|
|
+ content: _htmlText,
|
|
|
+ uid: _uid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _item.file_names,
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _item.assistantName,
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.chatList.push({
|
|
|
+ loading: true,
|
|
|
+ role: "user",
|
|
|
+ content: "",
|
|
|
+ uid: _uid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _item.file_names,
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _item.assistantName,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.scrollBottom();
|
|
|
+ let params = {
|
|
|
+ assistant_id: _item.assistant_id,
|
|
|
+ userId: "602def61-005d-11ee-91d8-005056b86db5",
|
|
|
+ message: _replaceText,
|
|
|
+ session_name: "",
|
|
|
+ uid: _uid,
|
|
|
+ file_ids: this.fileId ? [this.fileId] : [],
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/ai_agent_park_chat_new", params)
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.$message.warning(response.data.FunctionResponse.result);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ });
|
|
|
+ this.getAtAuContent(
|
|
|
+ _uid,
|
|
|
+ _htmlText,
|
|
|
+ _item.headUrl,
|
|
|
+ _item.assistantName
|
|
|
+ );
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ //未@角色
|
|
|
+
|
|
|
+ let _uuid = uuidv4();
|
|
|
+ this.chatList.push({
|
|
|
+ role: "user",
|
|
|
+ content: `${_text}`,
|
|
|
+ uid: _uuid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: "",
|
|
|
+ index: this.chatList.length,
|
|
|
+ is_mind_map: false,
|
|
|
+ loading: true,
|
|
|
+ });
|
|
|
+ this.scrollBottom();
|
|
|
+ // 连续对话设置
|
|
|
+ let _historyMessage = [];
|
|
|
+ // this.chatList.forEach(i=>{
|
|
|
+
|
|
|
+ // })
|
|
|
+ _historyMessage.push({ role: "user", content: _text });
|
|
|
+ let params = JSON.stringify({
|
|
|
+ model: "gpt-3.5-turbo",
|
|
|
+ temperature: 0,
|
|
|
+ max_tokens: 4096,
|
|
|
+ top_p: 1,
|
|
|
+ frequency_penalty: 0,
|
|
|
+ presence_penalty: 0,
|
|
|
+ messages: _historyMessage,
|
|
|
+ uid: _uuid,
|
|
|
+ mind_map_question: "",
|
|
|
+ });
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.$message.warning(response.data.FunctionResponse.result);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ console.log(e);
|
|
|
+ });
|
|
|
+ this.getAiContent(_uuid);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getAiContent(_uid) {
|
|
|
+ let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
+ let _allText = "";
|
|
|
+ let _mdText = "";
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ _source.onmessage = (_e) => {
|
|
|
+ if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
+ //对话已经完成
|
|
|
+ _mdText = _mdText.replace("_", "");
|
|
|
+ _source.close();
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isalltext = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isShowSynchronization = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ // 保存对话👇 #TODO保存对话
|
|
|
+
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ //对话还在继续
|
|
|
+ let _text = "";
|
|
|
+ _text = _e.data.replaceAll("'", "");
|
|
|
+ if (_allText == "") {
|
|
|
+ _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
+ } else {
|
|
|
+ _allText += _text;
|
|
|
+ }
|
|
|
+ _mdText = _allText + "_";
|
|
|
+ _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
+ _mdText = _mdText.replace(/\\/g, "");
|
|
|
+ if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
+ //转化返回的回复流数据
|
|
|
+ _mdText = md.render(_mdText);
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ // 处理流数据
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ getAtAuContent(_uid, _text, _headUrl, _assistantName) {
|
|
|
+ let _source = new EventSource(
|
|
|
+ `https://gpt4.cocorobo.cn/question/${_uid}`
|
|
|
+ ); //http://gpt4.cocorobo.cn:8011/question/ https://gpt4.cocorobo.cn/question/
|
|
|
+ let _allText = "";
|
|
|
+ let _mdText = "";
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ _source.onmessage = (_e) => {
|
|
|
+ let _eData = JSON.parse(_e.data);
|
|
|
+ if (_eData.content.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
+ let _result = [];
|
|
|
+ if ("result" in _eData) {
|
|
|
+ _result = _eData.result;
|
|
|
+ for (let i = 0; i < _result.length; i++) {
|
|
|
+ _mdText = _mdText.replace(_result[i].text, _result[i].fileName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _mdText = _mdText.replace("_", "");
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isalltext = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isShowSynchronization = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ //#TODO 这里保存对话
|
|
|
+ } else {
|
|
|
+ let _text = _eData.content.replace("'", "").replace("'", "");
|
|
|
+ if (_allText == "") {
|
|
|
+ _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
+ } else {
|
|
|
+ _allText += _text;
|
|
|
+ }
|
|
|
+ _mdText = _allText + "_";
|
|
|
+ _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
+ _mdText = _mdText.replace(/\\/g, "");
|
|
|
+ if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
+ //转化返回的回复流数据
|
|
|
+ _mdText = md.render(_mdText);
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ // 处理流数据
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ textareaChange() {
|
|
|
+ if (this.textareaValue.at(-1) == "@") {
|
|
|
+ this.showRoleList = true;
|
|
|
+ }
|
|
|
+ this.$refs.textareaRef.style.height = "50px";
|
|
|
+ this.$refs.textareaRef.style.height =
|
|
|
+ this.$refs.textareaRef.scrollHeight + "px";
|
|
|
+ if (this.$refs.roleListRef) {
|
|
|
+ let roleListHeight =
|
|
|
+ this.$refs.textareaRef.scrollHeight >= 500
|
|
|
+ ? 520
|
|
|
+ : this.$refs.textareaRef.scrollHeight + 20;
|
|
|
+ this.$refs.roleListRef.style["margin-bottom"] = "70px";
|
|
|
+ this.$refs.roleListRef.style["margin-bottom"] = roleListHeight + "px";
|
|
|
+ this.$refs.roleListRef.style["max-height"] = `calc(100vh - ${
|
|
|
+ roleListHeight + 160
|
|
|
+ }px)`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 滚动条触底
|
|
|
+ scrollBottom() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.textareaChange();
|
|
|
+ this.$refs.tapeRef.$el.querySelector(".t-chartArea").scrollTop =
|
|
|
+ this.$refs.tapeRef.$el.querySelector(".t-chartArea").scrollHeight;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 点击了其他地方然后关闭角色列表
|
|
|
+ noShowRoleList() {
|
|
|
+ this.showRoleList = false;
|
|
|
+ },
|
|
|
+ convertToMp3(wavDataView) {
|
|
|
+ // 获取wav头信息
|
|
|
+ const wav = lamejs.WavHeader.readHeader(wavDataView); // 此处其实可以不用去读wav头信息,毕竟有对应的config配置
|
|
|
+ const { channels, sampleRate } = wav;
|
|
|
+ const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
|
|
|
+ // 获取左右通道数据
|
|
|
+ const result = recorder.getChannelData();
|
|
|
+ const buffer = [];
|
|
|
+ const leftData =
|
|
|
+ result.left &&
|
|
|
+ new Int16Array(result.left.buffer, 0, result.left.byteLength / 2);
|
|
|
+ const rightData =
|
|
|
+ result.right &&
|
|
|
+ new Int16Array(result.right.buffer, 0, result.right.byteLength / 2);
|
|
|
+ const remaining = leftData.length + (rightData ? rightData.length : 0);
|
|
|
+ const maxSamples = 1152;
|
|
|
+ for (let i = 0; i < remaining; i += maxSamples) {
|
|
|
+ const left = leftData.subarray(i, i + maxSamples);
|
|
|
+ let right = null;
|
|
|
+ let mp3buf = null;
|
|
|
+ if (channels === 2) {
|
|
|
+ right = rightData.subarray(i, i + maxSamples);
|
|
|
+ mp3buf = mp3enc.encodeBuffer(left, right);
|
|
|
+ } else {
|
|
|
+ mp3buf = mp3enc.encodeBuffer(left);
|
|
|
+ }
|
|
|
+ if (mp3buf.length > 0) {
|
|
|
+ buffer.push(mp3buf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const enc = mp3enc.flush();
|
|
|
+ if (enc.length > 0) {
|
|
|
+ buffer.push(enc);
|
|
|
+ }
|
|
|
+ return new Blob(buffer, { type: "audio/mp3" });
|
|
|
+ },
|
|
|
+ uploadWavFileAndGetText(audioFile) {
|
|
|
+ let iiframe = this.$refs["iiframe"];
|
|
|
+ let _this = this;
|
|
|
+ iiframe.contentWindow.onRecognizedResult = function (e) {
|
|
|
+ console.log("onRecognizedResult", e);
|
|
|
+ let privText = e.privText;
|
|
|
+ console.log(privText)
|
|
|
+ _this.transcriptionData.content = privText;
|
|
|
+ };
|
|
|
+ iiframe.contentWindow.doContinuousPronunciationAssessment("", {
|
|
|
+ files: [audioFile],
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 录音转wav
|
|
|
+ dataURLtoAudio(blob, filename) {
|
|
|
+ return new File([blob], filename, { type: "audio/wav" });
|
|
|
+ },
|
|
|
+ getRoleList() {
|
|
|
+ this.roleList = [];
|
|
|
+ let params = {
|
|
|
+ userId: "602def61-005d-11ee-91d8-005056b86db5",
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/get_ai_agent_assistant_list", params)
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse.result;
|
|
|
+ if (_data) {
|
|
|
+ this.roleList = JSON.parse(_data);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.$message.error("获取角色列表失败");
|
|
|
+ this.roleList = [];
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getPublicRoleList() {
|
|
|
+ this.publicRoleList = [];
|
|
|
+ let params = {
|
|
|
+ userId: "602def61-005d-11ee-91d8-005056b86db5",
|
|
|
+ organizeid: "45facc0a-1211-11ec-80ad-005056b86db5",
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post(
|
|
|
+ "https://gpt4.cocorobo.cn/get_ai_agent_assistant_share_list",
|
|
|
+ params
|
|
|
+ )
|
|
|
+ .then((res) => {
|
|
|
+ let _data = res.data.FunctionResponse.result;
|
|
|
+ if (_data) {
|
|
|
+ this.publicRoleList = JSON.parse(_data);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.publicRoleList = [];
|
|
|
+ console.log("获取公共角色失败", e);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 选择了@的角色
|
|
|
+ choseRole(_data) {
|
|
|
+ let _lastAtIndex = this.textareaValue.lastIndexOf("@");
|
|
|
+ this.textareaValue = `${this.textareaValue.slice(0, _lastAtIndex)}@${
|
|
|
+ _data.assistantName
|
|
|
+ } `;
|
|
|
+ this.$refs.textareaRef.focus();
|
|
|
+ this.showRoleList = false;
|
|
|
+ },
|
|
|
+ // 输入框键盘按下监听
|
|
|
+ textareaKeydown(_e) {
|
|
|
+ if (this.showRoleList && this.choseRoleList.length > 0) {
|
|
|
+ switch (_e.keyCode) {
|
|
|
+ case 38: //小键盘上
|
|
|
+ _e.preventDefault();
|
|
|
+ if (this.roleListIndex == 0) return;
|
|
|
+ this.roleListIndex--;
|
|
|
+ // 修改滚动条高度
|
|
|
+ this.$refs.roleListRef.scrollTop = this.roleListIndex * 105;
|
|
|
+ break;
|
|
|
+ case 40: //小键盘下
|
|
|
+ _e.preventDefault();
|
|
|
+ if (this.roleListIndex == this.choseRoleList.length - 1) return;
|
|
|
+ this.roleListIndex++;
|
|
|
+ this.$refs.roleListRef.scrollTop = this.roleListIndex * 105;
|
|
|
+ break;
|
|
|
+ case 13: //回车
|
|
|
+ _e.preventDefault();
|
|
|
+ this.choseRole(this.choseRoleList[this.roleListIndex]);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getData() {
|
|
|
+ this.getRoleList();
|
|
|
+ this.getPublicRoleList();
|
|
|
+ },
|
|
|
+ //保存消息
|
|
|
+ insertChat(answer, problem, type, alltext, assistant_id, headUrl, file_id) {
|
|
|
+ let params = {};
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.getData();
|
|
|
+ this.scrollBottom();
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.chatArea {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ /* align-items: center; */
|
|
|
+ /* justify-content: center; */
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+.audio_class {
|
|
|
+ /* width: 100% !important; */
|
|
|
+ /* height: 100% !important; */
|
|
|
+ background: #ccc !important;
|
|
|
+ margin: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.audio_class >>> .slider .process {
|
|
|
+ background: #000;
|
|
|
+}
|
|
|
+.tapeSty {
|
|
|
+ cursor: pointer;
|
|
|
+ width: 40px;
|
|
|
+ height: 25px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ /* padding: 10px 15px; */
|
|
|
+ border-radius: 20px;
|
|
|
+}
|
|
|
+.TapeCss {
|
|
|
+ background-color: #1467ee;
|
|
|
+}
|
|
|
+.titBar {
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ display: flex;
|
|
|
+ /* align-items: center; */
|
|
|
+ border-bottom: 1px #ccc solid;
|
|
|
+ z-index: 99;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft {
|
|
|
+ width: 40%;
|
|
|
+ min-width: 400px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ cursor: pointer;
|
|
|
+ justify-content: flex-start;
|
|
|
+}
|
|
|
+.titBar > .titBarRig {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: center;
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.titBar > .titBarRig > img {
|
|
|
+ margin-right: 5px;
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.titBarBorder {
|
|
|
+ font-weight: 600;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-bottom: 2px #1467ee solid;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft > div {
|
|
|
+ height: 100%;
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 16px;
|
|
|
+ min-width: 75px;
|
|
|
+ margin-right: 30px;
|
|
|
+ text-align: left;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.titBar > .titBarLeft > div > img {
|
|
|
+ margin-right: 5px;
|
|
|
+}
|
|
|
+.m-operation {
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-right: 30px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ align-items: baseline;
|
|
|
+}
|
|
|
+.m-operation :first-child {
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 26px;
|
|
|
+ text-align: left;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+.m-operation :nth-child(2) {
|
|
|
+ font-family: PingFang SC;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+.ca-top {
|
|
|
+ width: 100%;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.ca-bottom {
|
|
|
+ width: 100%;
|
|
|
+ height: 120px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-operation {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: flex-end;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+.ca-b-o-header {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-left {
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-l-select {
|
|
|
+ width: auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ position: relative;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+ border-radius: 15px;
|
|
|
+ cursor: pointer;
|
|
|
+ background-color: white;
|
|
|
+}
|
|
|
+
|
|
|
+/* .ca-b-o-h-l-select:hover .languageBlock{
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+.languageBlock {
|
|
|
+ display: none;
|
|
|
+} */
|
|
|
+
|
|
|
+.languageList {
|
|
|
+ position: absolute;
|
|
|
+ background-color: #fff;
|
|
|
+ top: calc(-100% - 100px);
|
|
|
+ left: 0%;
|
|
|
+ width: 120px;
|
|
|
+ /* padding: 0 10px; */
|
|
|
+ /* box-sizing: border-box; */
|
|
|
+ padding: 10px 0;
|
|
|
+ border-radius: 5px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ height: 100px;
|
|
|
+}
|
|
|
+
|
|
|
+.languageList >>> .el-radio {
|
|
|
+ width: 70%;
|
|
|
+ /* margin-bottom: 10px; */
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin: 0;
|
|
|
+ border-radius: 5px;
|
|
|
+}
|
|
|
+.radioBg {
|
|
|
+ background: rgba(243, 247, 253, 1);
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-l-s-icon {
|
|
|
+ margin-right: 2px;
|
|
|
+ font-size: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-s-l-icon2 {
|
|
|
+ margin-left: 5px;
|
|
|
+ font-size: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-l-btn {
|
|
|
+ width: auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 5px 10px;
|
|
|
+ margin-right: 20px;
|
|
|
+ border-radius: 15px;
|
|
|
+ background-color: white;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-right {
|
|
|
+ width: auto;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-h-r-radio {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: #e7e7e7;
|
|
|
+ border-radius: 20px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.ca-b-o-h-r-radio > span {
|
|
|
+ margin-right: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-main {
|
|
|
+ width: 100%;
|
|
|
+ /* flex: 1; */
|
|
|
+ height: 64px;
|
|
|
+
|
|
|
+ margin-top: 5px;
|
|
|
+ border-radius: 16px;
|
|
|
+ transition: 0.3s;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-main:hover {
|
|
|
+ box-shadow: 0 5px 10px 10px #e1e8eb;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-tape {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 20px;
|
|
|
+ color: #3681fc;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+}
|
|
|
+.ca-b-o-m-tapeTwo {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 20px;
|
|
|
+ color: #3681fc;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 20px;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+}
|
|
|
+.ca-b-o-m-tapeTwo >>> .vueAudioBetter {
|
|
|
+ width: 90%;
|
|
|
+}
|
|
|
+.ca-b-o-m-tape > span {
|
|
|
+ margin-right: 10px;
|
|
|
+ font-size: 22px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-tape:hover {
|
|
|
+ color: #1467ee;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-inputAre {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-TapeArea {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ border-radius: 16px;
|
|
|
+ background-color: #f0f2f5;
|
|
|
+ box-shadow: 0 5px 10px 10px #e6eaeb;
|
|
|
+ transition: 0.3s;
|
|
|
+ align-items: center;
|
|
|
+ padding-right: 20px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-i-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-i-left > div > div {
|
|
|
+ color: #ee3e3e;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-i-left > div > span {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-i-left > img {
|
|
|
+ margin-left: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-left {
|
|
|
+ flex: 1;
|
|
|
+ height: auto;
|
|
|
+ min-height: 64px;
|
|
|
+ display: flex;
|
|
|
+ /* justify-content: center; */
|
|
|
+ align-items: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding-left: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-left > textarea {
|
|
|
+ resize: none;
|
|
|
+ min-height: 50px;
|
|
|
+ margin: 7px 0;
|
|
|
+ max-height: 500px;
|
|
|
+ width: 100%;
|
|
|
+ font-size: 18px;
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ resize: none;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+.ca-b-o-m-right {
|
|
|
+ width: 100px;
|
|
|
+ min-width: 80px;
|
|
|
+ height: 64px;
|
|
|
+ max-height: 64px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+#myTextarea::-webkit-input-placeholder {
|
|
|
+ /* Chrome, Opera, Safari */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+}
|
|
|
+
|
|
|
+#myTextarea:-moz-placeholder {
|
|
|
+ /* Firefox 18- */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+ opacity: 1; /* 修复Firefox的透明度问题 */
|
|
|
+}
|
|
|
+
|
|
|
+#myTextarea::-moz-placeholder {
|
|
|
+ /* Firefox 19+ */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+ opacity: 1; /* 修复Firefox的透明度问题 */
|
|
|
+}
|
|
|
+
|
|
|
+#myTextarea:-ms-input-placeholder {
|
|
|
+ /* Internet Explorer 10-11 */
|
|
|
+ font-size: 14px; /* 修改placeholder字体大小 */
|
|
|
+ color: grey; /* 修改placeholder文字颜色 */
|
|
|
+}
|
|
|
+.ca-b-o-m-right > span {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ background: url("../../../../assets/icon/classroomObservation/tapeIng.png")
|
|
|
+ no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-right > div {
|
|
|
+ width: 52px;
|
|
|
+ height: 30px;
|
|
|
+
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: white;
|
|
|
+ font-size: 14px;
|
|
|
+ border-radius: 5px;
|
|
|
+ background-color: #1467ee;
|
|
|
+ margin-right: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.ca-b-o-m-r-dsiableBtn {
|
|
|
+ /* 禁止手势 */
|
|
|
+ cursor: not-allowed !important;
|
|
|
+ background-color: #aeccfe !important;
|
|
|
+}
|
|
|
+.lyStart {
|
|
|
+ width: 38px;
|
|
|
+ height: 32px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.ca_b_o_m_roleList {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ max-height: calc(100vh - 230px);
|
|
|
+ margin-bottom: 70px;
|
|
|
+ overflow: auto;
|
|
|
+ background-color: white;
|
|
|
+ border-radius: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b_o_m_rl_item {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ background-color: #f3f7fd;
|
|
|
+ border-radius: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: 0.3s;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b_o_m_rl_itemActive {
|
|
|
+ background-color: #c3ddfa;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b_o_m_rl_i_left {
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_top {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+.ca_b-o_m_rl_i_top > div {
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_top > div > span {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 5px;
|
|
|
+ color: #6b798e;
|
|
|
+}
|
|
|
+
|
|
|
+.ca_b-o_m_rl_i_bottom {
|
|
|
+ margin-top: 10px;
|
|
|
+ width: 90%;
|
|
|
+ overflow: hidden;
|
|
|
+ display: block;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+</style>
|