|
@@ -1,67 +1,178 @@
|
|
|
<template>
|
|
|
- <div class="message">
|
|
|
- <ul class="message-list">
|
|
|
- <li
|
|
|
- v-for="(item, i) in messageList"
|
|
|
- :key="i"
|
|
|
- :class="[
|
|
|
- 'message-list-item',
|
|
|
- { text: item.message_type === messageItem[0].message_type },
|
|
|
- { audio: item.message_type === messageItem[1].message_type },
|
|
|
- {
|
|
|
- video: item.message_type === messageItem[2].message_type
|
|
|
- }
|
|
|
- ]"
|
|
|
- >
|
|
|
- <template v-if="item.message_type === messageItem[0].message_type">
|
|
|
- <div class="text">{{ item.text }}</div>
|
|
|
- </template>
|
|
|
- <template v-else-if="item.message_type === messageItem[1].message_type">
|
|
|
- <div class="avatar">T</div>
|
|
|
- <AudioShow
|
|
|
- :file-id="item.file_id"
|
|
|
- :stop-play="stopPlay"
|
|
|
- @pauseOtherAudio="pauseOtherAudio"
|
|
|
- @changeStopPlay="changeStopPlay"
|
|
|
- />
|
|
|
- </template>
|
|
|
- <template v-else-if="item.message_type === messageItem[2].message_type">
|
|
|
- <div class="avatar">T</div>
|
|
|
- <VideoShow
|
|
|
- :file-id="item.file_id"
|
|
|
- :stop-play="stopPlay"
|
|
|
- @pauseOtherAudio="pauseOtherAudio"
|
|
|
- @changeStopPlay="changeStopPlay"
|
|
|
- />
|
|
|
- </template>
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
+ <div>
|
|
|
+ <div class="message-box">
|
|
|
+ <div v-if="messageList.length <= 0" class="message-box-none">暂无内容</div>
|
|
|
+ <template v-else>
|
|
|
+ <ul class="message-list">
|
|
|
+ <li
|
|
|
+ v-for="({ message_type, text, file_id, is_student_reply }, i) in messageList"
|
|
|
+ :key="i"
|
|
|
+ :class="[
|
|
|
+ 'message-list-item',
|
|
|
+ { reverser: is_student_reply === 'true' },
|
|
|
+ { text: message_type === messageItem[0].message_type },
|
|
|
+ { audio: message_type === messageItem[1].message_type },
|
|
|
+ {
|
|
|
+ video: message_type === messageItem[2].message_type
|
|
|
+ }
|
|
|
+ ]"
|
|
|
+ >
|
|
|
+ <template v-if="message_type === messageItem[0].message_type">
|
|
|
+ <div class="text">{{ text }}</div>
|
|
|
+ </template>
|
|
|
+ <template v-else-if="message_type === messageItem[1].message_type">
|
|
|
+ <div class="avatar">{{ is_student_reply === 'true' ? 'S' : 'T' }}</div>
|
|
|
+ <AudioShow
|
|
|
+ :file-id="file_id"
|
|
|
+ :stop-play="stopPlay"
|
|
|
+ @pauseOtherAudio="pauseOtherAudio"
|
|
|
+ @changeStopPlay="changeStopPlay"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="message_type === messageItem[2].message_type">
|
|
|
+ <div class="avatar">{{ is_student_reply === 'true' ? 'S' : 'T' }}</div>
|
|
|
+ <VideoShow
|
|
|
+ :file-id="file_id"
|
|
|
+ :stop-play="stopPlay"
|
|
|
+ @pauseOtherAudio="pauseOtherAudio"
|
|
|
+ @changeStopPlay="changeStopPlay"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <svg-icon
|
|
|
+ v-if="
|
|
|
+ (is_student_reply === 'true' && !isTeacher) || (is_student_reply === 'false' && isTeacher)
|
|
|
+ ? true
|
|
|
+ : false
|
|
|
+ "
|
|
|
+ class-name="delete"
|
|
|
+ class="display-none"
|
|
|
+ icon-class="delete-current"
|
|
|
+ @click="deleteMessageItem(i)"
|
|
|
+ />
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ v-model="textMsg"
|
|
|
+ type="textarea"
|
|
|
+ class="sound-input"
|
|
|
+ resize="none"
|
|
|
+ placeholder="输入"
|
|
|
+ @keyup.enter.ctrl.native="sendMessage"
|
|
|
+ />
|
|
|
+ <div class="recording-operation">
|
|
|
+ <div class="switch">
|
|
|
+ <span
|
|
|
+ v-for="{ type, name } in audioAndVideo"
|
|
|
+ :key="type"
|
|
|
+ :class="[type === curRecord ? 'active' : '']"
|
|
|
+ @click="selectRecord(type, isRecording, closeRecording)"
|
|
|
+ >
|
|
|
+ {{ name }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <template v-for="{ icon, buttonName, recordingButtonName, type } in audioAndVideo">
|
|
|
+ <div
|
|
|
+ v-if="curRecord === type"
|
|
|
+ :key="icon"
|
|
|
+ :class="['press-sound', icon]"
|
|
|
+ @mousedown="() => curRecord === audioAndVideo[0].type && startRecording()"
|
|
|
+ @click="() => (curRecord === audioAndVideo[1].type ? changVisible_video(true, { fn: getVideoData }) : '')"
|
|
|
+ @mouseup="() => curRecord === audioAndVideo[0].type && closeRecording()"
|
|
|
+ >
|
|
|
+ <svg-icon :icon-class="icon" class-name="button-icon" />
|
|
|
+ {{ isRecording ? recordingButtonName : buttonName }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { inject } from 'vue';
|
|
|
+import { watch, ref, inject } from 'vue';
|
|
|
import { messageItem } from '@/views/teacher/create_course/step_three/components/data/TaskData.js';
|
|
|
+import { soundRecording, useRecordingPageData, audioAndVideo } from '@/components/course/common/recording';
|
|
|
+import { fileUploadPrimordial } from '@/api/app.js';
|
|
|
|
|
|
import AudioShow from '@/components/course/common/AudioShow.vue';
|
|
|
import VideoShow from '@/components/course/common/VideoShow.vue';
|
|
|
|
|
|
-defineProps({
|
|
|
+const props = defineProps({
|
|
|
messageList: {
|
|
|
type: Array,
|
|
|
required: true
|
|
|
+ },
|
|
|
+ addMessageItem: {
|
|
|
+ type: Function,
|
|
|
+ default: () => {}
|
|
|
+ },
|
|
|
+ deleteMessageItem: {
|
|
|
+ type: Function,
|
|
|
+ default: () => {}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
const { stopPlay, changeStopPlay, pauseOtherAudio } = inject('stopPlay');
|
|
|
+const isTeacher = inject('isTeacher');
|
|
|
+
|
|
|
+// 文本
|
|
|
+let textMsg = ref('');
|
|
|
+function sendMessage() {
|
|
|
+ props.addMessageItem(
|
|
|
+ Object.assign({}, messageItem[0], {
|
|
|
+ text: textMsg.value,
|
|
|
+ is_student_reply: isTeacher ? 'false' : 'true'
|
|
|
+ })
|
|
|
+ );
|
|
|
+ textMsg.value = '';
|
|
|
+}
|
|
|
+
|
|
|
+let { curRecord, selectRecord } = useRecordingPageData();
|
|
|
+
|
|
|
+// 录音
|
|
|
+let { startRecording, closeRecording, isRecording, blob } = soundRecording();
|
|
|
+
|
|
|
+watch(blob, (newVal) => {
|
|
|
+ let formData = new FormData();
|
|
|
+ formData.append('录音.mp3', newVal, '录音.mp3');
|
|
|
+ fileUploadPrimordial('Mid', formData).then(({ file_info_list }) => {
|
|
|
+ if (file_info_list.length > 0) {
|
|
|
+ props.addMessageItem(
|
|
|
+ Object.assign({}, messageItem[1], {
|
|
|
+ file_id: file_info_list[0].file_id,
|
|
|
+ is_student_reply: isTeacher ? 'false' : 'true'
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+// 录影
|
|
|
+const { changVisible_video } = inject('visible_video');
|
|
|
+
|
|
|
+function getVideoData(data) {
|
|
|
+ props.addMessageItem({ ...data, is_student_reply: isTeacher ? 'false' : 'true' });
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
-.message {
|
|
|
+$tip-color: #999;
|
|
|
+
|
|
|
+// 消息框
|
|
|
+.message-box {
|
|
|
+ min-height: 230px;
|
|
|
padding: 16px 0;
|
|
|
background-color: #f4f4f4;
|
|
|
border: 1px solid $border-color;
|
|
|
|
|
|
+ &-none {
|
|
|
+ height: 100%;
|
|
|
+ line-height: 212px;
|
|
|
+ text-align: center;
|
|
|
+ vertical-align: middle;
|
|
|
+ }
|
|
|
+
|
|
|
.message-list {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
@@ -85,11 +196,30 @@ const { stopPlay, changeStopPlay, pauseOtherAudio } = inject('stopPlay');
|
|
|
width: 38px;
|
|
|
height: 38px;
|
|
|
line-height: 38px;
|
|
|
+ color: #2a76e8;
|
|
|
text-align: center;
|
|
|
background-color: #e3eeff;
|
|
|
border-radius: 50%;
|
|
|
}
|
|
|
|
|
|
+ &.reverser {
|
|
|
+ flex-direction: row-reverse;
|
|
|
+
|
|
|
+ .text {
|
|
|
+ margin-right: 54px;
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .avatar {
|
|
|
+ color: #fff;
|
|
|
+ background-color: #3dc45b;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep .audio-line {
|
|
|
+ background-color: #3dc45b;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
&.text:not(:first-child) {
|
|
|
margin-top: 8px;
|
|
|
}
|
|
@@ -100,6 +230,77 @@ const { stopPlay, changeStopPlay, pauseOtherAudio } = inject('stopPlay');
|
|
|
margin-top: 22px;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ &:hover .delete {
|
|
|
+ display: block;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 输入
|
|
|
+.sound-input {
|
|
|
+ :deep .el-textarea__inner {
|
|
|
+ height: 92px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ font-size: 16px;
|
|
|
+ border: 1px solid $border-color;
|
|
|
+ border-top-width: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 操作
|
|
|
+.recording-operation {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 8px 16px;
|
|
|
+ border: 1px solid $border-color;
|
|
|
+ border-top-width: 0;
|
|
|
+
|
|
|
+ .switch {
|
|
|
+ background-color: #e7e7e7;
|
|
|
+ border: 1px solid $border-color;
|
|
|
+ border-radius: 4px;
|
|
|
+
|
|
|
+ > span {
|
|
|
+ display: inline-block;
|
|
|
+ height: 28px;
|
|
|
+ padding: 2px 8px;
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 24px;
|
|
|
+ color: $tip-color;
|
|
|
+ cursor: pointer;
|
|
|
+ background-color: #e7e7e7;
|
|
|
+ border-radius: 3px;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ color: #000;
|
|
|
+ background-color: #fff;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 25%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .press-sound {
|
|
|
+ padding: 4px 8px;
|
|
|
+ line-height: 22px;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 40px;
|
|
|
+
|
|
|
+ &.microphone {
|
|
|
+ color: #fff;
|
|
|
+ background-color: #de4444;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.videocamera {
|
|
|
+ color: #de4444;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #de4444;
|
|
|
+ }
|
|
|
+
|
|
|
+ .button-icon {
|
|
|
+ margin-right: 4px;
|
|
|
}
|
|
|
}
|
|
|
}
|