|
@@ -4,8 +4,8 @@
|
|
|
<!-- 展开收起侧边栏 -->
|
|
<!-- 展开收起侧边栏 -->
|
|
|
<div class="icon-expand">
|
|
<div class="icon-expand">
|
|
|
<el-icon
|
|
<el-icon
|
|
|
- @click="toggleDrawer"
|
|
|
|
|
- :style="{ color: drawerVisible ? 'white' : '#B6B0D8' }"
|
|
|
|
|
|
|
+ @click="toggleDrawer"
|
|
|
|
|
+ :style="{ color: drawerVisible ? 'white' : '#B6B0D8' }"
|
|
|
>
|
|
>
|
|
|
<component :is="drawerVisible ? Fold : Expand" />
|
|
<component :is="drawerVisible ? Fold : Expand" />
|
|
|
<!-- <Tickets /> -->
|
|
<!-- <Tickets /> -->
|
|
@@ -23,28 +23,28 @@
|
|
|
课程小节
|
|
课程小节
|
|
|
</h3>
|
|
</h3>
|
|
|
<el-menu
|
|
<el-menu
|
|
|
- :default-active="activeMenuIndex"
|
|
|
|
|
|
|
+ :default-active="course.key"
|
|
|
@open="handleOpen"
|
|
@open="handleOpen"
|
|
|
@close="handleClose"
|
|
@close="handleClose"
|
|
|
@select="handleSelect"
|
|
@select="handleSelect"
|
|
|
:default-openeds="['3']"
|
|
:default-openeds="['3']"
|
|
|
>
|
|
>
|
|
|
- <template v-for="item in menuItems" :key="item.index">
|
|
|
|
|
- <el-menu-item v-if="!item.children" :index="item.index">{{
|
|
|
|
|
- item.title
|
|
|
|
|
- }}</el-menu-item>
|
|
|
|
|
|
|
+ <template v-for="item in menuItems" :key="item.key">
|
|
|
|
|
+ <el-menu-item v-if="!item.children" :index="item.key">{{
|
|
|
|
|
+ item.title
|
|
|
|
|
+ }}</el-menu-item>
|
|
|
<el-sub-menu v-else :index="item.index">
|
|
<el-sub-menu v-else :index="item.index">
|
|
|
<template #title>
|
|
<template #title>
|
|
|
<span>{{ item.title }}</span>
|
|
<span>{{ item.title }}</span>
|
|
|
</template>
|
|
</template>
|
|
|
<el-menu-item-group v-if="item.children">
|
|
<el-menu-item-group v-if="item.children">
|
|
|
<template
|
|
<template
|
|
|
- v-for="child in item.children"
|
|
|
|
|
- :key="child.index"
|
|
|
|
|
|
|
+ v-for="child in item.children"
|
|
|
|
|
+ :key="child.index"
|
|
|
>
|
|
>
|
|
|
<el-menu-item :index="child.index">{{
|
|
<el-menu-item :index="child.index">{{
|
|
|
- child.title
|
|
|
|
|
- }}</el-menu-item>
|
|
|
|
|
|
|
+ child.title
|
|
|
|
|
+ }}</el-menu-item>
|
|
|
</template>
|
|
</template>
|
|
|
</el-menu-item-group>
|
|
</el-menu-item-group>
|
|
|
</el-sub-menu>
|
|
</el-sub-menu>
|
|
@@ -67,9 +67,9 @@
|
|
|
<div class="inner-box right-box">
|
|
<div class="inner-box right-box">
|
|
|
<div class="top-right-box">
|
|
<div class="top-right-box">
|
|
|
<el-input
|
|
<el-input
|
|
|
- v-model="SearchInput"
|
|
|
|
|
- class="search-input"
|
|
|
|
|
- placeholder="搜索"
|
|
|
|
|
|
|
+ v-model="SearchInput"
|
|
|
|
|
+ class="search-input"
|
|
|
|
|
+ placeholder="搜索"
|
|
|
>
|
|
>
|
|
|
<template #prefix>
|
|
<template #prefix>
|
|
|
<el-icon class="el-input__icon"><search /></el-icon>
|
|
<el-icon class="el-input__icon"><search /></el-icon>
|
|
@@ -79,23 +79,23 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
<div class="box-2">
|
|
<div class="box-2">
|
|
|
<!-- 课程标题 autoplay自动播放 @ended="playNextVideo"-->
|
|
<!-- 课程标题 autoplay自动播放 @ended="playNextVideo"-->
|
|
|
<div class="small-title">
|
|
<div class="small-title">
|
|
|
- <span>{{ smallTitle }}</span>
|
|
|
|
|
|
|
+ <span>{{ course.courseName }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="box-video">
|
|
<div class="box-video">
|
|
|
<video
|
|
<video
|
|
|
- class="full-box-video"
|
|
|
|
|
- :src="videoSrc"
|
|
|
|
|
- controlsList="nodownload"
|
|
|
|
|
- controls
|
|
|
|
|
- @timeupdate="handleTimeUpdate"
|
|
|
|
|
- @play="checkVideoPermission"
|
|
|
|
|
- ref="videoRef"
|
|
|
|
|
|
|
+ class="full-box-video"
|
|
|
|
|
+ :src="course.courseVideoPath"
|
|
|
|
|
+ controlsList="nodownload"
|
|
|
|
|
+ controls
|
|
|
|
|
+ @timeupdate="handleTimeUpdate"
|
|
|
|
|
+ @play="checkVideoPermission"
|
|
|
|
|
+ ref="videoRef"
|
|
|
>
|
|
>
|
|
|
- <source :src="videoSrc" type="video/mp4" />
|
|
|
|
|
|
|
+ <source :src="course.courseVideoPath" type="video/mp4" />
|
|
|
您的浏览器不支持视频播放。
|
|
您的浏览器不支持视频播放。
|
|
|
</video>
|
|
</video>
|
|
|
</div>
|
|
</div>
|
|
@@ -115,32 +115,32 @@
|
|
|
<!-- 添加试题弹框 -->
|
|
<!-- 添加试题弹框 -->
|
|
|
<transition name="fade-scale">
|
|
<transition name="fade-scale">
|
|
|
<div
|
|
<div
|
|
|
- v-show="questionDialogVisible"
|
|
|
|
|
- class="child-dialog-wrapper"
|
|
|
|
|
- @click.self="handleCloseQuestionDialog"
|
|
|
|
|
|
|
+ v-show="questionDialogVisible"
|
|
|
|
|
+ class="child-dialog-wrapper"
|
|
|
|
|
+ @click.self="handleCloseQuestionDialog"
|
|
|
>
|
|
>
|
|
|
<div class="child-dialog">
|
|
<div class="child-dialog">
|
|
|
<div class="question-title">
|
|
<div class="question-title">
|
|
|
<span class="question-icon">?</span>
|
|
<span class="question-icon">?</span>
|
|
|
- {{ currentQuestion.title }}
|
|
|
|
|
|
|
+ <span v-html="courseConfig.ccQuestContent"></span>
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 选项区域 -->
|
|
<!-- 选项区域 -->
|
|
|
<div
|
|
<div
|
|
|
- v-if="
|
|
|
|
|
- currentQuestion.options && currentQuestion.options.length > 0
|
|
|
|
|
|
|
+ v-if="
|
|
|
|
|
+ courseConfig.ccQuestOption && courseConfig.ccQuestOption.length > 0
|
|
|
"
|
|
"
|
|
|
- class="options-container"
|
|
|
|
|
|
|
+ class="options-container"
|
|
|
>
|
|
>
|
|
|
<div
|
|
<div
|
|
|
- v-for="(option, index) in currentQuestion.options"
|
|
|
|
|
- :key="index"
|
|
|
|
|
- class="question-option"
|
|
|
|
|
|
|
+ v-for="(option, index) in courseConfig.ccQuestOption"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="question-option"
|
|
|
>
|
|
>
|
|
|
<el-radio
|
|
<el-radio
|
|
|
- v-model="selectedOption"
|
|
|
|
|
- :label="index"
|
|
|
|
|
- :value="option"
|
|
|
|
|
- v-cloak="(selectedOption = option)"
|
|
|
|
|
|
|
+ v-model="selectedOption"
|
|
|
|
|
+ :label="index"
|
|
|
|
|
+ :value="option"
|
|
|
|
|
+ v-cloak="(selectedOption = option)"
|
|
|
>
|
|
>
|
|
|
<span>{{ option }}</span>
|
|
<span>{{ option }}</span>
|
|
|
</el-radio>
|
|
</el-radio>
|
|
@@ -153,17 +153,17 @@
|
|
|
<div class="dialog-footer">
|
|
<div class="dialog-footer">
|
|
|
<!-- <el-button class="child-button cancel" @click="questionDialogVisible = false; showAIDialog = false">取消</el-button>-->
|
|
<!-- <el-button class="child-button cancel" @click="questionDialogVisible = false; showAIDialog = false">取消</el-button>-->
|
|
|
<el-button
|
|
<el-button
|
|
|
- class="child-button confirm"
|
|
|
|
|
- @click="handleSubmitAnswer"
|
|
|
|
|
- >确定</el-button
|
|
|
|
|
|
|
+ class="child-button confirm"
|
|
|
|
|
+ @click="handleSubmitAnswer"
|
|
|
|
|
+ >确定</el-button
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
<!-- 右侧小图标 -->
|
|
<!-- 右侧小图标 -->
|
|
|
<div class="ai-icon-container" @click="handleAIClick">
|
|
<div class="ai-icon-container" @click="handleAIClick">
|
|
|
<img
|
|
<img
|
|
|
- src="@/assets/images/xiaozhi.png"
|
|
|
|
|
- alt="AI对话"
|
|
|
|
|
- class="ai-icon"
|
|
|
|
|
|
|
+ src="@/assets/images/xiaozhi.png"
|
|
|
|
|
+ alt="AI对话"
|
|
|
|
|
+ class="ai-icon"
|
|
|
/>
|
|
/>
|
|
|
<span class="ai-text">AI助手</span>
|
|
<span class="ai-text">AI助手</span>
|
|
|
</div>
|
|
</div>
|
|
@@ -172,52 +172,50 @@
|
|
|
</transition>
|
|
</transition>
|
|
|
<!-- AI对话弹框 -->
|
|
<!-- AI对话弹框 -->
|
|
|
<div
|
|
<div
|
|
|
- v-show="showAIDialog"
|
|
|
|
|
- class="ai-dialog-wrapper"
|
|
|
|
|
- @click.self="showAIDialog = false"
|
|
|
|
|
|
|
+ v-show="showAIDialog"
|
|
|
|
|
+ class="ai-dialog-wrapper"
|
|
|
|
|
+ @click.self="showAIDialog = false"
|
|
|
>
|
|
>
|
|
|
<div class="ai-dialog">
|
|
<div class="ai-dialog">
|
|
|
<div class="ai-dialog-header">
|
|
<div class="ai-dialog-header">
|
|
|
<h3>小智智能助手</h3>
|
|
<h3>小智智能助手</h3>
|
|
|
<el-button @click="showAIDialog = false" class="close-btn"
|
|
<el-button @click="showAIDialog = false" class="close-btn"
|
|
|
- >×</el-button
|
|
|
|
|
|
|
+ >×</el-button
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="ai-dialog-content">
|
|
<div class="ai-dialog-content">
|
|
|
<div class="ai-message-history">
|
|
<div class="ai-message-history">
|
|
|
<div
|
|
<div
|
|
|
- v-for="(message, index) in messageHistory"
|
|
|
|
|
- :key="index"
|
|
|
|
|
- :class="['message', message.type]"
|
|
|
|
|
|
|
+ v-for="(message, index) in messageHistory"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ :class="['message', message.type]"
|
|
|
>
|
|
>
|
|
|
<img
|
|
<img
|
|
|
- v-if="message.type === 'user'"
|
|
|
|
|
- src="@/assets/images/user.png"
|
|
|
|
|
- class="avatar user"
|
|
|
|
|
|
|
+ v-if="message.type === 'user'"
|
|
|
|
|
+ src="@/assets/images/user.png"
|
|
|
|
|
+ class="avatar user"
|
|
|
/>
|
|
/>
|
|
|
<img v-else src="@/assets/images/xiaozhi.png" class="avatar" />
|
|
<img v-else src="@/assets/images/xiaozhi.png" class="avatar" />
|
|
|
- <div class="message-content">
|
|
|
|
|
- {{ message.content }}
|
|
|
|
|
|
|
+ <div class="message-content" v-html="message.content">
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<el-input
|
|
<el-input
|
|
|
- v-model="userMessage"
|
|
|
|
|
- placeholder="输入问题..."
|
|
|
|
|
- class="user-input"
|
|
|
|
|
- @keyup.enter="sendMessage"
|
|
|
|
|
|
|
+ v-model="userMessage"
|
|
|
|
|
+ placeholder="输入问题..."
|
|
|
|
|
+ class="user-input"
|
|
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
>
|
|
>
|
|
|
<template #append class="flex flex-wrap items-center mb-4">
|
|
<template #append class="flex flex-wrap items-center mb-4">
|
|
|
<!-- <el-button @click="sendMessage" class="child-button confirm">发送</el-button>-->
|
|
<!-- <el-button @click="sendMessage" class="child-button confirm">发送</el-button>-->
|
|
|
- <el-button @click="sendMessage" size="large" round
|
|
|
|
|
- >发送</el-button
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <el-button @click="sendMessage" size="large" round>发送</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -225,46 +223,14 @@
|
|
|
import { ref, onMounted } from 'vue'
|
|
import { ref, onMounted } from 'vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
import { useRouter } from 'vue-router'
|
|
|
import {
|
|
import {
|
|
|
- ArrowDown,
|
|
|
|
|
- ArrowRightBold,
|
|
|
|
|
Expand,
|
|
Expand,
|
|
|
- Reading,
|
|
|
|
|
Fold,
|
|
Fold,
|
|
|
- Tickets,
|
|
|
|
|
Memo
|
|
Memo
|
|
|
} from '@element-plus/icons-vue'
|
|
} from '@element-plus/icons-vue'
|
|
|
-import {
|
|
|
|
|
- Document,
|
|
|
|
|
- Menu as IconMenu,
|
|
|
|
|
- Location,
|
|
|
|
|
- Setting
|
|
|
|
|
-} from '@element-plus/icons-vue'
|
|
|
|
|
import { Search, ArrowLeftBold } from '@element-plus/icons-vue'
|
|
import { Search, ArrowLeftBold } from '@element-plus/icons-vue'
|
|
|
-import {
|
|
|
|
|
- ElMessage,
|
|
|
|
|
- ElMessageBox,
|
|
|
|
|
- ElNotification,
|
|
|
|
|
- valueEquals
|
|
|
|
|
-} from 'element-plus'
|
|
|
|
|
-// 引入视频
|
|
|
|
|
-import video1 from '@/assets/02video/01video.mp4'
|
|
|
|
|
-import video2 from '@/assets/02video/02video.mp4'
|
|
|
|
|
-import video3 from '@/assets/02video/03video.mp4'
|
|
|
|
|
-import video4 from '@/assets/02video/04video.mp4'
|
|
|
|
|
-import video5 from '@/assets/02video/05video.mp4'
|
|
|
|
|
-import video6 from '@/assets/02video/06video.mp4'
|
|
|
|
|
-import video7 from '@/assets/02video/07video.mp4'
|
|
|
|
|
-import video8 from '@/assets/02video/08video.mp4'
|
|
|
|
|
-import video9 from '@/assets/02video/09video.mp4'
|
|
|
|
|
-import video10 from '@/assets/02video/10video.mp4'
|
|
|
|
|
-import video11 from '@/assets/02video/11video.mp4'
|
|
|
|
|
-import video12 from '@/assets/02video/12video.mp4'
|
|
|
|
|
-import video13 from '@/assets/02video/13video.mp4'
|
|
|
|
|
-import video14 from '@/assets/02video/14video.mp4'
|
|
|
|
|
-import video15 from '@/assets/02video/15video.mp4'
|
|
|
|
|
-
|
|
|
|
|
-import { ClassType } from '@/api/class.js'
|
|
|
|
|
-import { Message } from '@/utils/message/Message.js'
|
|
|
|
|
|
|
+
|
|
|
|
|
+import {ClassType} from "@/api/class.js";
|
|
|
|
|
+import {Message} from "@/utils/message/Message.js";
|
|
|
|
|
|
|
|
const router = useRouter() // 获取当前路由对象
|
|
const router = useRouter() // 获取当前路由对象
|
|
|
// 搜索框
|
|
// 搜索框
|
|
@@ -278,7 +244,6 @@ const toggleDrawer = () => {
|
|
|
drawerVisible.value = !drawerVisible.value
|
|
drawerVisible.value = !drawerVisible.value
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const activeMenuIndex = ref('1-1')
|
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
// 返回上一页
|
|
|
const goBack = () => {
|
|
const goBack = () => {
|
|
@@ -287,15 +252,24 @@ const goBack = () => {
|
|
|
|
|
|
|
|
// 渲染页面标题
|
|
// 渲染页面标题
|
|
|
const boxIconTitle = ref('')
|
|
const boxIconTitle = ref('')
|
|
|
-// 课程数据
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 课程集合数据
|
|
|
const courseList = ref([])
|
|
const courseList = ref([])
|
|
|
|
|
+//当前课程
|
|
|
|
|
+const course = ref({})
|
|
|
// 菜单数据
|
|
// 菜单数据
|
|
|
const menuItems = ref([])
|
|
const menuItems = ref([])
|
|
|
-
|
|
|
|
|
-// 定义视频源
|
|
|
|
|
-const videoSrc = ref('')
|
|
|
|
|
-// 新增视频路径映射
|
|
|
|
|
-const videoPathMap = ref({})
|
|
|
|
|
|
|
+// 课程集合数据
|
|
|
|
|
+const videoPathMap = ref({})
|
|
|
|
|
+
|
|
|
|
|
+//课程小节字典(需要新加接口调取字典)
|
|
|
|
|
+const menuDict = ref({
|
|
|
|
|
+ "1": "课前回顾",
|
|
|
|
|
+ "2": "课程引入",
|
|
|
|
|
+ "3": "知识讲解",
|
|
|
|
|
+ "4": "趣味实操",
|
|
|
|
|
+ "5": "课程总结",
|
|
|
|
|
+})
|
|
|
|
|
|
|
|
// 渲染 课程数据结构 以及 视频
|
|
// 渲染 课程数据结构 以及 视频
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
@@ -304,78 +278,41 @@ onMounted(async () => {
|
|
|
try {
|
|
try {
|
|
|
// 取接口课程数据
|
|
// 取接口课程数据
|
|
|
const res = await ClassType(typeId)
|
|
const res = await ClassType(typeId)
|
|
|
- console.log(res);
|
|
|
|
|
-
|
|
|
|
|
courseList.value = res.data
|
|
courseList.value = res.data
|
|
|
|
|
|
|
|
- // 初始化第一个视频源和标题
|
|
|
|
|
- if (courseList.value.length > 0 && courseList.value[0].courseVideoPath) {
|
|
|
|
|
- videoSrc.value = courseList.value[0].courseVideoPath
|
|
|
|
|
- currentIndex.value = '1-1'
|
|
|
|
|
- smallTitle.value = courseList.value[0].courseName
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 按 courseLabel 分组
|
|
|
|
|
- const groupedByLabel = {}
|
|
|
|
|
- courseList.value.forEach(item => {
|
|
|
|
|
- if (!groupedByLabel[item.courseLabel]) {
|
|
|
|
|
- groupedByLabel[item.courseLabel] = []
|
|
|
|
|
|
|
+ //课程数据
|
|
|
|
|
+ courseList.value.forEach((courseTemp,index) => {
|
|
|
|
|
+ let menuIndex = courseTemp.courseLabel + '-' + (index+1);
|
|
|
|
|
+ //填充大纲小节
|
|
|
|
|
+ let menu = menuItems.value.find(menu => courseTemp.courseLabel === menu.index);
|
|
|
|
|
+ if (menu){//小节
|
|
|
|
|
+ menu.children = menu.children || [];
|
|
|
|
|
+ menu.children.push({
|
|
|
|
|
+ key: menuIndex,
|
|
|
|
|
+ index: menuIndex,
|
|
|
|
|
+ title: courseTemp.courseName
|
|
|
|
|
+ })
|
|
|
|
|
+ }else {//大节
|
|
|
|
|
+ menuItems.value.push({
|
|
|
|
|
+ key: menuIndex,
|
|
|
|
|
+ index: courseTemp.courseLabel,
|
|
|
|
|
+ title: menuDict.value[courseTemp.courseLabel]
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
- groupedByLabel[item.courseLabel].push(item)
|
|
|
|
|
- })
|
|
|
|
|
|
|
|
|
|
- // 对每个组按 courseOrder 排序
|
|
|
|
|
- Object.keys(groupedByLabel).forEach(label => {
|
|
|
|
|
- groupedByLabel[label].sort((a, b) => a.courseOrder - b.courseOrder)
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ courseTemp["key"] = menuIndex;
|
|
|
|
|
+ videoPathMap.value[menuIndex] = courseTemp
|
|
|
|
|
|
|
|
- // 构建视频路径映射
|
|
|
|
|
- videoPathMap.value = {}
|
|
|
|
|
- let labelIndex = 0
|
|
|
|
|
- Object.keys(groupedByLabel).forEach(label => {
|
|
|
|
|
- const groupItems = groupedByLabel[label]
|
|
|
|
|
- groupItems.forEach((item, indexInGroup) => {
|
|
|
|
|
- const idx = `${labelIndex + 1}-${indexInGroup + 1}`
|
|
|
|
|
- if (item.courseVideoPath) {
|
|
|
|
|
- videoPathMap.value[idx] = item.courseVideoPath
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- labelIndex++
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- // 构建新的 menuItems 结构
|
|
|
|
|
- menuItems.value = []
|
|
|
|
|
- Object.keys(groupedByLabel).forEach((label, labelIndex) => {
|
|
|
|
|
- const groupItems = groupedByLabel[label]
|
|
|
|
|
- // 检查是否是知识分解组(图灵测试到大模型时代)
|
|
|
|
|
- const isKnowledgeGroup = groupItems.some(item =>
|
|
|
|
|
- ['图灵测试', '大模型时代'].includes(item.courseName)
|
|
|
|
|
- )
|
|
|
|
|
- if (isKnowledgeGroup) {
|
|
|
|
|
- // 构建知识分解组的树型结构
|
|
|
|
|
- menuItems.value.push({
|
|
|
|
|
- index: `${labelIndex + 1}`,
|
|
|
|
|
- title: '知识讲解',
|
|
|
|
|
- children: groupItems.map((item, index) => ({
|
|
|
|
|
- index: `${labelIndex + 1}-${index + 1}`,
|
|
|
|
|
- title: item.courseName
|
|
|
|
|
- }))
|
|
|
|
|
- })
|
|
|
|
|
- } else {
|
|
|
|
|
- // 普通组直接添加菜单项
|
|
|
|
|
- groupItems.forEach((item, index) => {
|
|
|
|
|
- const idx = `${labelIndex + 1}-${index + 1}`
|
|
|
|
|
- menuItems.value.push({
|
|
|
|
|
- index: idx,
|
|
|
|
|
- title: item.courseName
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ //确定默认课程
|
|
|
|
|
+ if (index === 0) {
|
|
|
|
|
+ course.value = courseTemp;
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('获取课程数据失败:', error)
|
|
console.error('获取课程数据失败:', error)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
const title = router.currentRoute.value.query.typeName
|
|
const title = router.currentRoute.value.query.typeName
|
|
|
if (title) {
|
|
if (title) {
|
|
|
boxIconTitle.value = String(title)
|
|
boxIconTitle.value = String(title)
|
|
@@ -386,12 +323,11 @@ onMounted(async () => {
|
|
|
const handleOpen = () => {}
|
|
const handleOpen = () => {}
|
|
|
const handleClose = () => {}
|
|
const handleClose = () => {}
|
|
|
|
|
|
|
|
-// 当前播放的索引
|
|
|
|
|
-const currentIndex = ref('1-1')
|
|
|
|
|
-
|
|
|
|
|
-// 渲染课程标题到视频上方
|
|
|
|
|
-const smallTitle = ref('课前回顾')
|
|
|
|
|
|
|
+// 菜单选择的处理函数
|
|
|
const handleSelect = index => {
|
|
const handleSelect = index => {
|
|
|
|
|
+ //测试账号禁用视频
|
|
|
|
|
+ if (disableVideo(index))return;
|
|
|
|
|
+
|
|
|
const findTitle = items => {
|
|
const findTitle = items => {
|
|
|
for (const item of items) {
|
|
for (const item of items) {
|
|
|
if (item.index === index) {
|
|
if (item.index === index) {
|
|
@@ -406,15 +342,14 @@ const handleSelect = index => {
|
|
|
}
|
|
}
|
|
|
return null
|
|
return null
|
|
|
}
|
|
}
|
|
|
- const title = findTitle(menuItems.value)
|
|
|
|
|
- if (title) {
|
|
|
|
|
- smallTitle.value = title
|
|
|
|
|
- }
|
|
|
|
|
// 根据索引切换视频,使用新的 videoPathMap
|
|
// 根据索引切换视频,使用新的 videoPathMap
|
|
|
if (videoPathMap.value[index]) {
|
|
if (videoPathMap.value[index]) {
|
|
|
- videoSrc.value = videoPathMap.value[index]
|
|
|
|
|
- currentIndex.value = index
|
|
|
|
|
|
|
+ course.value = videoPathMap.value[index]
|
|
|
|
|
+ }else {
|
|
|
|
|
+ //视频不存在
|
|
|
|
|
+ Message().notifyWarning('视频不存在!', true);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
//测试账号禁用视频
|
|
//测试账号禁用视频
|
|
|
if (disableVideo()) return
|
|
if (disableVideo()) return
|
|
|
}
|
|
}
|
|
@@ -425,7 +360,7 @@ const flattenMenuItems = () => {
|
|
|
const traverse = items => {
|
|
const traverse = items => {
|
|
|
for (const item of items) {
|
|
for (const item of items) {
|
|
|
if (!item.children) {
|
|
if (!item.children) {
|
|
|
- indices.push(item.index)
|
|
|
|
|
|
|
+ indices.push(item.key)
|
|
|
} else {
|
|
} else {
|
|
|
traverse(item.children)
|
|
traverse(item.children)
|
|
|
}
|
|
}
|
|
@@ -438,9 +373,10 @@ const flattenMenuItems = () => {
|
|
|
// 播放下一个视频
|
|
// 播放下一个视频
|
|
|
const playNextVideo = () => {
|
|
const playNextVideo = () => {
|
|
|
//测试账号禁用视频
|
|
//测试账号禁用视频
|
|
|
- if (disableVideo()) return
|
|
|
|
|
|
|
+ if (disableVideo())return;
|
|
|
|
|
+
|
|
|
const allIndices = flattenMenuItems()
|
|
const allIndices = flattenMenuItems()
|
|
|
- const currentIndexInList = allIndices.indexOf(currentIndex.value)
|
|
|
|
|
|
|
+ const currentIndexInList = allIndices.indexOf(course.value.key)
|
|
|
if (currentIndexInList !== -1 && currentIndexInList < allIndices.length - 1) {
|
|
if (currentIndexInList !== -1 && currentIndexInList < allIndices.length - 1) {
|
|
|
const nextIndex = allIndices[currentIndexInList + 1]
|
|
const nextIndex = allIndices[currentIndexInList + 1]
|
|
|
handleSelect(nextIndex)
|
|
handleSelect(nextIndex)
|
|
@@ -450,23 +386,21 @@ const playNextVideo = () => {
|
|
|
once: true
|
|
once: true
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
- // 更新侧边栏选中状态
|
|
|
|
|
- activeMenuIndex.value = nextIndex
|
|
|
|
|
}
|
|
}
|
|
|
// 重置
|
|
// 重置
|
|
|
- pausedIndices = ref([])
|
|
|
|
|
|
|
+ pausedIndices = ref({time: [], newTime: []})
|
|
|
userMessage = ref('')
|
|
userMessage = ref('')
|
|
|
messageHistory = ref([])
|
|
messageHistory = ref([])
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 切换视频
|
|
// 切换视频
|
|
|
// 播放上一个视频
|
|
// 播放上一个视频
|
|
|
const playPreviousVideo = () => {
|
|
const playPreviousVideo = () => {
|
|
|
//测试账号禁用视频
|
|
//测试账号禁用视频
|
|
|
- if (disableVideo()) return
|
|
|
|
|
|
|
+ if (disableVideo())return;
|
|
|
|
|
+
|
|
|
const allIndices = flattenMenuItems()
|
|
const allIndices = flattenMenuItems()
|
|
|
- const currentIndexInList = allIndices.indexOf(currentIndex.value)
|
|
|
|
|
|
|
+ const currentIndexInList = allIndices.indexOf(course.value.key)
|
|
|
if (currentIndexInList > 0) {
|
|
if (currentIndexInList > 0) {
|
|
|
const previousIndex = allIndices[currentIndexInList - 1]
|
|
const previousIndex = allIndices[currentIndexInList - 1]
|
|
|
handleSelect(previousIndex)
|
|
handleSelect(previousIndex)
|
|
@@ -476,16 +410,14 @@ const playPreviousVideo = () => {
|
|
|
once: true
|
|
once: true
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
- // 更新侧边栏选中状态
|
|
|
|
|
- activeMenuIndex.value = nextIndex
|
|
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 尝试播放视频,处理浏览器自动播放限制
|
|
// 尝试播放视频,处理浏览器自动播放限制
|
|
|
const tryPlayVideo = () => {
|
|
const tryPlayVideo = () => {
|
|
|
//测试账号禁用视频
|
|
//测试账号禁用视频
|
|
|
- if (disableVideo()) return
|
|
|
|
|
|
|
+ if (disableVideo())return;
|
|
|
|
|
+
|
|
|
const playPromise = videoRef.value.play()
|
|
const playPromise = videoRef.value.play()
|
|
|
if (playPromise !== undefined) {
|
|
if (playPromise !== undefined) {
|
|
|
playPromise.catch(error => {
|
|
playPromise.catch(error => {
|
|
@@ -493,78 +425,50 @@ const tryPlayVideo = () => {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
// 检查视频播放权限
|
|
// 检查视频播放权限
|
|
|
const checkVideoPermission = () => {
|
|
const checkVideoPermission = () => {
|
|
|
- if (disableVideo()) {
|
|
|
|
|
|
|
+ if (disableVideo() || questionDialogVisible.value) {
|
|
|
if (videoRef.value) {
|
|
if (videoRef.value) {
|
|
|
videoRef.value.pause()
|
|
videoRef.value.pause()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ //记录已暂停的内容
|
|
|
|
|
+ setVideoStop();
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
//禁用视频
|
|
//禁用视频
|
|
|
-const disableVideo = () => {
|
|
|
|
|
- let dis = [
|
|
|
|
|
- '3-4',
|
|
|
|
|
- '3-5',
|
|
|
|
|
- '3-6',
|
|
|
|
|
- '3-7',
|
|
|
|
|
- '3-8',
|
|
|
|
|
- '3-9',
|
|
|
|
|
- '3-10',
|
|
|
|
|
- '3-11',
|
|
|
|
|
- '4-1',
|
|
|
|
|
- '5-1'
|
|
|
|
|
- ]
|
|
|
|
|
- if (
|
|
|
|
|
- localStorage.getItem('userName') === 'aiTest' &&
|
|
|
|
|
- dis.indexOf(currentIndex.value) !== -1
|
|
|
|
|
- ) {
|
|
|
|
|
|
|
+const disableVideo = (index = course.value.key) => {
|
|
|
|
|
+ let dis = ["1-6","1-7","1-8","1-9","1-10","1-11","1-12","1-13","1-14","1-15"]
|
|
|
|
|
+
|
|
|
|
|
+ if (localStorage.getItem('userName') === "aiTest" &&
|
|
|
|
|
+ dis.indexOf(index) !== -1) {
|
|
|
|
|
+
|
|
|
if (videoRef.value) {
|
|
if (videoRef.value) {
|
|
|
|
|
+ // 记录当前播放时间
|
|
|
videoRef.value.pause()
|
|
videoRef.value.pause()
|
|
|
- // 禁用视频进度条拖拽功能
|
|
|
|
|
- const handleSeeking = () => {
|
|
|
|
|
- videoRef.value.pause()
|
|
|
|
|
- Message().notifyWarning(
|
|
|
|
|
- '您的账号并未开放此课程,禁止拖动进度条!',
|
|
|
|
|
- true
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- // 添加 seeking 事件监听器
|
|
|
|
|
- videoRef.value.addEventListener('seeking', handleSeeking)
|
|
|
|
|
- // 当视频源改变时,移除事件监听器,避免影响其他视频
|
|
|
|
|
- const removeListener = () => {
|
|
|
|
|
- videoRef.value.removeEventListener('seeking', handleSeeking)
|
|
|
|
|
- videoRef.value.removeEventListener('loadedmetadata', removeListener)
|
|
|
|
|
- }
|
|
|
|
|
- videoRef.value.addEventListener('loadedmetadata', removeListener)
|
|
|
|
|
|
|
+ // 阻止用户跳转到新的时间点,将播放时间重置为之前的时间
|
|
|
|
|
+ videoRef.value.currentTime = 0;
|
|
|
}
|
|
}
|
|
|
//提示禁用// 显示消息框
|
|
//提示禁用// 显示消息框
|
|
|
- Message().notifyWarning('您的账号并未开放此课程!', true)
|
|
|
|
|
- return true
|
|
|
|
|
- } else {
|
|
|
|
|
- // 若不符合禁用条件,移除事件监听器
|
|
|
|
|
- if (videoRef.value) {
|
|
|
|
|
- videoRef.value.removeEventListener('seeking', e => {
|
|
|
|
|
- e.preventDefault()
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- return false
|
|
|
|
|
|
|
+ Message().notifyWarning('您的账号并未开放此课程!', true);
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 视频 ref
|
|
// 视频 ref
|
|
|
const videoRef = ref(null)
|
|
const videoRef = ref(null)
|
|
|
// 记录已经暂停过的时间点索引
|
|
// 记录已经暂停过的时间点索引
|
|
|
-let pausedIndices = ref([])
|
|
|
|
|
|
|
+let pausedIndices = ref({time: [], newTime: []})
|
|
|
// 试题弹框显示状态
|
|
// 试题弹框显示状态
|
|
|
const questionDialogVisible = ref(false)
|
|
const questionDialogVisible = ref(false)
|
|
|
// 当前显示的试题
|
|
// 当前显示的试题
|
|
|
-const currentQuestion = ref({ title: '', options: [] })
|
|
|
|
|
|
|
+const courseConfig = ref({})
|
|
|
// 用户选择的选项
|
|
// 用户选择的选项
|
|
|
const selectedOption = ref(null)
|
|
const selectedOption = ref(null)
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// AI对话弹出框显示状态
|
|
// AI对话弹出框显示状态
|
|
|
let showAIDialog = ref(false)
|
|
let showAIDialog = ref(false)
|
|
|
// 用户输入的消息
|
|
// 用户输入的消息
|
|
@@ -572,155 +476,37 @@ let userMessage = ref('')
|
|
|
// 消息历史记录
|
|
// 消息历史记录
|
|
|
let messageHistory = ref([])
|
|
let messageHistory = ref([])
|
|
|
|
|
|
|
|
-// 定义每个视频对应的暂停时间和问题
|
|
|
|
|
-const videoPauseTimes = {
|
|
|
|
|
- [video2]: {
|
|
|
|
|
- pauseTimes: [30],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '视频当中发生了什么事情呢?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '视频当中发生了什么事情呢',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '让我来告诉你吧:泡泡怪篡改了Ai历史数据,导致Ai系统发生崩溃,所以要修正Ai历史抓到泡泡怪!'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video3]: {
|
|
|
|
|
- pauseTimes: [49],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '同学们,大家了解图灵测试了吗?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '视频当中发生了什么事情呢',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '让我来告诉你吧:泡泡怪篡改了Ai历史数据,导致Ai系统发生崩溃,所以要修正Ai历史抓到泡泡怪!'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video4]: {
|
|
|
|
|
- pauseTimes: [2],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '你觉得deepseek、豆包等大模型可以通过图灵测试吗?为什么?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '你觉得deepseek、豆包等大模型可以通过图灵测试吗?为什么?',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '大模型已缩短与图灵测试的标志距离,尤其在表面对话层面,但因缺乏深层次理解、逻辑一致性与真实认知,仍无法在严格测试中稳定通过。'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video5]: {
|
|
|
|
|
- pauseTimes: [49],
|
|
|
|
|
- questions: []
|
|
|
|
|
- },
|
|
|
|
|
- [video6]: {
|
|
|
|
|
- pauseTimes: [5]
|
|
|
|
|
- },
|
|
|
|
|
- [video7]: {
|
|
|
|
|
- pauseTimes: [64.5, 91],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '如果你是聊天机器人,你会怎么回答用户呢?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '',
|
|
|
|
|
- aiAnswer: ''
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- title:
|
|
|
|
|
- '当我们和聊天机器人对话的内容被人类所查看并回答时,隐私信息是否泄露?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion:
|
|
|
|
|
- '当我们和聊天机器人对话的内容被人类所查看并回答时,隐私信息是否泄露?',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '与聊天机器人的对话被人类查看时,隐私泄露风险客\n' +
|
|
|
|
|
- '观存在,尤其是人类介入或安全漏洞场景下。建议优先选择支持本地'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video8]: {
|
|
|
|
|
- pauseTimes: [72],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '如果你身体不舒服时找这样的专家检查,那么它开的药你敢喝吗?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion:
|
|
|
|
|
- '如果你身体不舒服时找这样的专家检查,那么它开的药你敢喝吗?',
|
|
|
|
|
- aiAnswer: '这题没给答案,你自己去查吧!'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video9]: {
|
|
|
|
|
- pauseTimes: [2],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '在生活中,有哪些正在使用的专家系统呢?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '在生活中,有哪些正在使用的专家系统呢?',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '在医疗健康领域有复杂疾病协同决策和Ai医生分身与诊断辅助;在水利交通领域的水利厅专家库系统用于项目验收和抢险督查'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video11]: {
|
|
|
|
|
- pauseTimes: [1, 90, 176],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '怎么会有爆炸声?泡泡怪在这里吗?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '',
|
|
|
|
|
- aiAnswer: ''
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- title: '同学们喜欢下围棋吗?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '',
|
|
|
|
|
- aiAnswer: ''
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- title: '为什么AlphaGo要在围棋上攻克真人冠军呢?',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '为什么AlphaGo要在围棋上攻克真人冠军呢?',
|
|
|
|
|
- aiAnswer:
|
|
|
|
|
- '围棋是人类智力游戏的巅峰,拥有天文数字级的可能性,每颗棋子价值由全局态势动态决定,所以当前一手可能百步之后才显现价值。AlphaGo战胜人类顶尖选手,它证明了Ai不仅能处理规则明确的事物,更能攻克依赖直觉、策略的“人类专属领域”'
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- },
|
|
|
|
|
- [video12]: {
|
|
|
|
|
- pauseTimes: [1]
|
|
|
|
|
- },
|
|
|
|
|
- [video13]: {
|
|
|
|
|
- pauseTimes: [62],
|
|
|
|
|
- questions: [
|
|
|
|
|
- {
|
|
|
|
|
- title: '我们一起来感受一下大模型吧!',
|
|
|
|
|
- options: [],
|
|
|
|
|
- aiQuestion: '',
|
|
|
|
|
- aiAnswer: ''
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// 处理视频时间更新事件
|
|
// 处理视频时间更新事件
|
|
|
const handleTimeUpdate = () => {
|
|
const handleTimeUpdate = () => {
|
|
|
|
|
+ //测试账号禁用视频
|
|
|
if (!videoRef.value) return
|
|
if (!videoRef.value) return
|
|
|
- const currentTime = videoRef.value.currentTime
|
|
|
|
|
- const currentPauseTimes = videoPauseTimes[videoSrc.value]
|
|
|
|
|
- if (currentPauseTimes) {
|
|
|
|
|
- currentPauseTimes.pauseTimes.forEach((time, index) => {
|
|
|
|
|
- // 检查是否到达时间点且还未暂停过
|
|
|
|
|
- if (currentTime >= time && !pausedIndices.value.includes(index)) {
|
|
|
|
|
- videoRef.value.pause()
|
|
|
|
|
- pausedIndices.value.push(index)
|
|
|
|
|
- // 显示对应的问题
|
|
|
|
|
- if (currentPauseTimes.questions[index]) {
|
|
|
|
|
- currentQuestion.value = currentPauseTimes.questions[index]
|
|
|
|
|
- questionDialogVisible.value = true
|
|
|
|
|
|
|
+
|
|
|
|
|
+ const currentTime = parseInt(videoRef.value.currentTime)
|
|
|
|
|
+
|
|
|
|
|
+ if (!course.value.courseConfigList) return
|
|
|
|
|
+ course.value.courseConfigList.forEach(courseCofig => {
|
|
|
|
|
+
|
|
|
|
|
+ //暂停时间
|
|
|
|
|
+ let time = courseCofig.ccTime
|
|
|
|
|
+ // 检查是否到达时间点且还未暂停过
|
|
|
|
|
+ let timeIndex = pausedIndices.value.time.indexOf(time);
|
|
|
|
|
+
|
|
|
|
|
+ if (currentTime === time && (timeIndex === -1 || Date.now() - pausedIndices.value.newTime[timeIndex] > 1000) ) {
|
|
|
|
|
+
|
|
|
|
|
+ videoRef.value.pause()
|
|
|
|
|
+
|
|
|
|
|
+ // 显示对应的问题
|
|
|
|
|
+ if (courseCofig.ccQuestContent) {
|
|
|
|
|
+ questionDialogVisible.value = true
|
|
|
|
|
+ courseConfig.value = courseCofig
|
|
|
|
|
+
|
|
|
|
|
+ //解析选项
|
|
|
|
|
+ if (courseCofig.ccQuestOption) {
|
|
|
|
|
+ courseConfig.courseQuestion = courseCofig.ccQuestOption.split(',')
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 关闭试题弹框
|
|
// 关闭试题弹框
|
|
@@ -728,6 +514,22 @@ const handleCloseQuestionDialog = () => {
|
|
|
questionDialogVisible.value = false
|
|
questionDialogVisible.value = false
|
|
|
// 继续播放视频
|
|
// 继续播放视频
|
|
|
videoRef.value.play()
|
|
videoRef.value.play()
|
|
|
|
|
+
|
|
|
|
|
+ //记录已暂停的内容
|
|
|
|
|
+ setVideoStop();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//记录已暂停的内容
|
|
|
|
|
+const setVideoStop = () => {
|
|
|
|
|
+ const currentTime = parseInt(videoRef.value.currentTime)
|
|
|
|
|
+ let timeIndex = pausedIndices.value.time.indexOf(currentTime);
|
|
|
|
|
+ if (timeIndex === -1) {
|
|
|
|
|
+ pausedIndices.value.time.push(currentTime)
|
|
|
|
|
+ pausedIndices.value.newTime.push(Date.now())
|
|
|
|
|
+ }else{
|
|
|
|
|
+ pausedIndices.value.time[timeIndex] = currentTime
|
|
|
|
|
+ pausedIndices.value.newTime[timeIndex] = Date.now()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 提交答案
|
|
// 提交答案
|
|
@@ -737,6 +539,9 @@ const handleSubmitAnswer = () => {
|
|
|
// 继续播放视频
|
|
// 继续播放视频
|
|
|
videoRef.value.play()
|
|
videoRef.value.play()
|
|
|
selectedOption.value = null
|
|
selectedOption.value = null
|
|
|
|
|
+
|
|
|
|
|
+ //记录已暂停的内容
|
|
|
|
|
+ setVideoStop();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 发送消息
|
|
// 发送消息
|
|
@@ -764,11 +569,12 @@ const sendMessage = async () => {
|
|
|
const handleAIClick = () => {
|
|
const handleAIClick = () => {
|
|
|
// 清空输入框
|
|
// 清空输入框
|
|
|
messageHistory = ref([])
|
|
messageHistory = ref([])
|
|
|
- if (currentQuestion.value.aiQuestion) {
|
|
|
|
|
- userMessage.value = currentQuestion.value.aiQuestion
|
|
|
|
|
|
|
+ if (courseConfig.value.ccQuestContent) {
|
|
|
|
|
+ userMessage.value = courseConfig.value.ccQuestContent
|
|
|
sendMessage()
|
|
sendMessage()
|
|
|
userMessage.value = ''
|
|
userMessage.value = ''
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
showAIDialog.value = true
|
|
showAIDialog.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -776,15 +582,9 @@ const handleAIClick = () => {
|
|
|
const simulateAIResponse = question => {
|
|
const simulateAIResponse = question => {
|
|
|
return new Promise(resolve => {
|
|
return new Promise(resolve => {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- const currentVideoInfo = videoPauseTimes[videoSrc.value]
|
|
|
|
|
- if (currentVideoInfo) {
|
|
|
|
|
- const currentQuestionObj = currentVideoInfo.questions.find(
|
|
|
|
|
- q => q.aiQuestion === question
|
|
|
|
|
- )
|
|
|
|
|
- if (currentQuestionObj && currentQuestionObj.aiAnswer) {
|
|
|
|
|
- resolve(currentQuestionObj.aiAnswer)
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (courseConfig.value.ccAiAnswer) {
|
|
|
|
|
+ resolve(courseConfig.value.ccAiAnswer)
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
// 若未匹配到自定义回复,给出默认回复
|
|
// 若未匹配到自定义回复,给出默认回复
|
|
|
resolve(`您的问题是:${question},这是 AI 的回复示例。`)
|
|
resolve(`您的问题是:${question},这是 AI 的回复示例。`)
|
|
@@ -796,6 +596,7 @@ const simulateAIResponse = question => {
|
|
|
const handleCloseAIDialog = () => {
|
|
const handleCloseAIDialog = () => {
|
|
|
showAIDialog.value = false
|
|
showAIDialog.value = false
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|