|
@@ -4,11 +4,11 @@
|
|
|
<!-- 添加抽屉 -->
|
|
<!-- 添加抽屉 -->
|
|
|
<div class="drawer-box">
|
|
<div class="drawer-box">
|
|
|
<el-button
|
|
<el-button
|
|
|
- v-if="!drawerVisible"
|
|
|
|
|
- type="primary"
|
|
|
|
|
- @click="drawerVisible = true"
|
|
|
|
|
- @closed="buttonVisible = false"
|
|
|
|
|
- class="toggle-button"
|
|
|
|
|
|
|
+ v-if="!drawerVisible"
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ @click="drawerVisible = true"
|
|
|
|
|
+ @closed="buttonVisible = false"
|
|
|
|
|
+ class="toggle-button"
|
|
|
>
|
|
>
|
|
|
课程小节
|
|
课程小节
|
|
|
</el-button>
|
|
</el-button>
|
|
@@ -26,8 +26,8 @@
|
|
|
>
|
|
>
|
|
|
<template v-for="item in menuItems" :key="item.index">
|
|
<template v-for="item in menuItems" :key="item.index">
|
|
|
<el-menu-item v-if="!item.children" :index="item.index">{{
|
|
<el-menu-item v-if="!item.children" :index="item.index">{{
|
|
|
- item.title
|
|
|
|
|
- }}</el-menu-item>
|
|
|
|
|
|
|
+ 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>
|
|
@@ -35,8 +35,8 @@
|
|
|
<el-menu-item-group v-if="item.children">
|
|
<el-menu-item-group v-if="item.children">
|
|
|
<template v-for="child in item.children" :key="child.index">
|
|
<template 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>
|
|
@@ -57,9 +57,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>
|
|
@@ -95,6 +95,94 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <!-- 添加试题弹框 -->
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-show="questionDialogVisible"
|
|
|
|
|
+ class="child-dialog-wrapper"
|
|
|
|
|
+ @click.self="handleCloseQuestionDialog"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="child-dialog">
|
|
|
|
|
+ <div class="question-title">
|
|
|
|
|
+ <span class="question-icon">?</span>
|
|
|
|
|
+ {{ currentQuestion.title }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 选项区域 -->
|
|
|
|
|
+ <div v-if="currentQuestion.options && currentQuestion.options.length > 0" class="options-container">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(option, index) in currentQuestion.options"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="question-option"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-radio v-model="selectedOption" :label="index" :value="option" v-cloak="selectedOption = option">
|
|
|
|
|
+ <span>{{ option }}</span>
|
|
|
|
|
+ </el-radio>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-else class="no-options">
|
|
|
|
|
+ 暂无选项
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 底部按钮 -->
|
|
|
|
|
+ <div class="dialog-footer">
|
|
|
|
|
+ <el-button class="child-button cancel" @click="questionDialogVisible = false; showAIDialog = false">取消</el-button>
|
|
|
|
|
+ <el-button class="child-button confirm" @click="handleSubmitAnswer">确定</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 右侧小图标 -->
|
|
|
|
|
+ <div class="ai-icon-container" @click="handleAIClick">
|
|
|
|
|
+ <img src="@/assets/images/luxun.png" alt="AI对话" class="ai-icon" />
|
|
|
|
|
+ <span class="ai-text">AI助手</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- AI对话弹框 -->
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-show="showAIDialog"
|
|
|
|
|
+ class="ai-dialog-wrapper"
|
|
|
|
|
+ @click.self="showAIDialog = false"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="ai-dialog">
|
|
|
|
|
+ <div class="ai-dialog-header">
|
|
|
|
|
+ <h3>与AI对话</h3>
|
|
|
|
|
+ <el-button @click="showAIDialog = false" class="close-btn">×</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="ai-dialog-content">
|
|
|
|
|
+ <div class="ai-message-history">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(message, index) in messageHistory"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ :class="['message', message.type]"
|
|
|
|
|
+ >
|
|
|
|
|
+ <img
|
|
|
|
|
+ v-if="message.type === 'user'"
|
|
|
|
|
+ src="@/assets/images/libai.png"
|
|
|
|
|
+ alt="头像"
|
|
|
|
|
+ class="avatar"
|
|
|
|
|
+ />
|
|
|
|
|
+ <img
|
|
|
|
|
+ v-else
|
|
|
|
|
+ src="@/assets/images/luxun.png"
|
|
|
|
|
+ alt="头像"
|
|
|
|
|
+ class="avatar"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="message-content">
|
|
|
|
|
+ {{ message.content }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="userMessage"
|
|
|
|
|
+ placeholder="输入问题..."
|
|
|
|
|
+ class="user-input"
|
|
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #append class="flex flex-wrap items-center mb-4">
|
|
|
|
|
+<!-- <el-button @click="sendMessage" class="child-button confirm">发送</el-button>-->
|
|
|
|
|
+ <el-button @click="sendMessage" size="large" round>发送</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -241,8 +329,6 @@ const flattenMenuItems = () => {
|
|
|
return indices
|
|
return indices
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 记录已经暂停过的时间点索引
|
|
|
|
|
-let pausedIndices = ref([])
|
|
|
|
|
// 自动播放下一个视频
|
|
// 自动播放下一个视频
|
|
|
const playNextVideo = () => {
|
|
const playNextVideo = () => {
|
|
|
const allIndices = flattenMenuItems()
|
|
const allIndices = flattenMenuItems()
|
|
@@ -251,7 +337,11 @@ const playNextVideo = () => {
|
|
|
const nextIndex = allIndices[currentIndexInList + 1]
|
|
const nextIndex = allIndices[currentIndexInList + 1]
|
|
|
handleSelect(nextIndex)
|
|
handleSelect(nextIndex)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ //重置
|
|
|
pausedIndices = ref([])
|
|
pausedIndices = ref([])
|
|
|
|
|
+ userMessage = ref('')
|
|
|
|
|
+ messageHistory = ref([])
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 切换视频
|
|
// 切换视频
|
|
@@ -266,38 +356,188 @@ const playPreviousVideo = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 视频 ref
|
|
// 视频 ref
|
|
|
-const videoRef = ref(null)
|
|
|
|
|
-// 定义每个视频对应的暂停时间
|
|
|
|
|
|
|
+const videoRef = ref(null)
|
|
|
|
|
+// 记录已经暂停过的时间点索引
|
|
|
|
|
+let pausedIndices = ref([])
|
|
|
|
|
+// 试题弹框显示状态
|
|
|
|
|
+const questionDialogVisible = ref(false)
|
|
|
|
|
+// 当前显示的试题
|
|
|
|
|
+const currentQuestion = ref({ title: '', options: [] })
|
|
|
|
|
+// 用户选择的选项
|
|
|
|
|
+const selectedOption = ref(null)
|
|
|
|
|
+
|
|
|
|
|
+// AI对话弹出框显示状态
|
|
|
|
|
+let showAIDialog = ref(false)
|
|
|
|
|
+// 用户输入的消息
|
|
|
|
|
+let userMessage = ref('')
|
|
|
|
|
+// 消息历史记录
|
|
|
|
|
+let messageHistory = ref([])
|
|
|
|
|
+
|
|
|
|
|
+// 定义每个视频对应的暂停时间和问题
|
|
|
const videoPauseTimes = {
|
|
const videoPauseTimes = {
|
|
|
- [video4]: [1],
|
|
|
|
|
- [video6]: [3],
|
|
|
|
|
- [video9]: [2],
|
|
|
|
|
- [video12]: [1]
|
|
|
|
|
|
|
+ [video1]: {
|
|
|
|
|
+ pauseTimes: [1],
|
|
|
|
|
+ questions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '这是视频 1 的问题 1',
|
|
|
|
|
+ options: ['选项 1', '选项 2', '选项 3'],
|
|
|
|
|
+ aiQuestion: '请详细解释视频 1 问题 1 的正确答案',
|
|
|
|
|
+ aiAnswer: '视频 1 问题 1 的正确答案是...具体解释内容'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ [video4]: {
|
|
|
|
|
+ pauseTimes: [1],
|
|
|
|
|
+ questions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '这是视频 4 的问题 1222',
|
|
|
|
|
+ options: ['选项 1', '选项 2', '选项 3'],
|
|
|
|
|
+ aiQuestion: '关于视频 4 问题 1222,能给些提示吗',
|
|
|
|
|
+ aiAnswer: '视频 4 问题 1222 的提示信息...'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ [video6]: {
|
|
|
|
|
+ pauseTimes: [3],
|
|
|
|
|
+ questions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '这是视频 6 的问题 1',
|
|
|
|
|
+ options: ['选项 A', '选项 B', '选项 C'],
|
|
|
|
|
+ aiQuestion: '分析下视频 6 问题 1 各个选项',
|
|
|
|
|
+ aiAnswer: '视频 6 问题 1 选项 A...选项 B...选项 C...'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ [video9]: {
|
|
|
|
|
+ pauseTimes: [2],
|
|
|
|
|
+ questions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '这是视频 9 的问题 1',
|
|
|
|
|
+ options: ['答案一', '答案二', '答案三'],
|
|
|
|
|
+ aiQuestion: '视频 9 问题 1 的正确答案是哪个',
|
|
|
|
|
+ aiAnswer: '视频 9 问题 1 正确答案是...'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ [video12]: {
|
|
|
|
|
+ pauseTimes: [1],
|
|
|
|
|
+ questions: [
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '这是视频 12 的问题 1',
|
|
|
|
|
+ options: ['选项Ⅰ', '选项Ⅱ', '选项Ⅲ'],
|
|
|
|
|
+ aiQuestion: '解释下视频 12 问题 1 的选项Ⅰ',
|
|
|
|
|
+ aiAnswer: '视频 12 问题 1 选项Ⅰ的解释...'
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
// 处理视频时间更新事件
|
|
// 处理视频时间更新事件
|
|
|
const handleTimeUpdate = () => {
|
|
const handleTimeUpdate = () => {
|
|
|
if (!videoRef.value) return
|
|
if (!videoRef.value) return
|
|
|
|
|
+
|
|
|
const currentTime = videoRef.value.currentTime
|
|
const currentTime = videoRef.value.currentTime
|
|
|
const currentPauseTimes = videoPauseTimes[videoSrc.value]
|
|
const currentPauseTimes = videoPauseTimes[videoSrc.value]
|
|
|
if (currentPauseTimes) {
|
|
if (currentPauseTimes) {
|
|
|
- currentPauseTimes.forEach((time, index) => {
|
|
|
|
|
|
|
+ currentPauseTimes.pauseTimes.forEach((time, index) => {
|
|
|
// 检查是否到达时间点且还未暂停过
|
|
// 检查是否到达时间点且还未暂停过
|
|
|
if (currentTime >= time && !pausedIndices.value.includes(index)) {
|
|
if (currentTime >= time && !pausedIndices.value.includes(index)) {
|
|
|
videoRef.value.pause()
|
|
videoRef.value.pause()
|
|
|
pausedIndices.value.push(index)
|
|
pausedIndices.value.push(index)
|
|
|
|
|
+ // 显示对应的问题
|
|
|
|
|
+ if (currentPauseTimes.questions[index]) {
|
|
|
|
|
+ currentQuestion.value = currentPauseTimes.questions[index]
|
|
|
|
|
+ questionDialogVisible.value = true
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+// 关闭试题弹框
|
|
|
|
|
+const handleCloseQuestionDialog = () => {
|
|
|
|
|
+ questionDialogVisible.value = false
|
|
|
|
|
+ // 继续播放视频
|
|
|
|
|
+ videoRef.value.play()
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-</script>
|
|
|
|
|
|
|
+// 提交答案
|
|
|
|
|
+const handleSubmitAnswer = () => {
|
|
|
|
|
+ // 这里可以添加答案验证逻辑
|
|
|
|
|
+ console.log('用户选择的答案是:', selectedOption.value)
|
|
|
|
|
+ questionDialogVisible.value = false
|
|
|
|
|
+ // 继续播放视频
|
|
|
|
|
+ videoRef.value.play()
|
|
|
|
|
+ selectedOption.value = null
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+// 发送消息
|
|
|
|
|
+const sendMessage = async () => {
|
|
|
|
|
+ if (userMessage.value.trim()) {
|
|
|
|
|
+ // 添加用户消息到历史记录
|
|
|
|
|
+ messageHistory.value.push({
|
|
|
|
|
+ type: 'user',
|
|
|
|
|
+ content: userMessage.value
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 模拟 AI 回复
|
|
|
|
|
+ const aiResponse = await simulateAIResponse(userMessage.value)
|
|
|
|
|
+ messageHistory.value.push({
|
|
|
|
|
+ type: 'ai',
|
|
|
|
|
+ content: aiResponse
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 清空输入框
|
|
|
|
|
+ userMessage.value = ''
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理 AI 助手点击事件
|
|
|
|
|
+const handleAIClick = () => {
|
|
|
|
|
+ if (currentQuestion.value.aiQuestion) {
|
|
|
|
|
+ userMessage.value = currentQuestion.value.aiQuestion
|
|
|
|
|
+ sendMessage()
|
|
|
|
|
+ }
|
|
|
|
|
+ showAIDialog.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 模拟 AI 回复
|
|
|
|
|
+const simulateAIResponse = (question) => {
|
|
|
|
|
+ return new Promise((resolve) => {
|
|
|
|
|
+ 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
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 若未匹配到自定义回复,给出默认回复
|
|
|
|
|
+ resolve(`您的问题是:${question},这是 AI 的回复示例。`)
|
|
|
|
|
+ }, 1000)
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 关闭AI对话弹出框
|
|
|
|
|
+const handleCloseAIDialog = () => {
|
|
|
|
|
+ showAIDialog.value = false
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
|
@use 'sass:math';
|
|
@use 'sass:math';
|
|
|
// 定义rpx转换函数
|
|
// 定义rpx转换函数
|
|
|
@function rpx($px) {
|
|
@function rpx($px) {
|
|
|
@return math.div($px, 750) * 100vw;
|
|
@return math.div($px, 750) * 100vw;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// 定义儿童风格的蓝紫色调
|
|
|
|
|
+$primary-color: rgba(106, 90, 205, 0.52); // 主色调:蓝紫色
|
|
|
|
|
+$secondary-color: rgba(147, 112, 219, 0.66); // 辅助色:亮蓝紫色
|
|
|
|
|
+$accent-color: rgb(133, 89, 220); // 强调色:暗蓝紫色
|
|
|
|
|
+$light-color: #e6e6fa; // 浅色背景:淡紫色
|
|
|
|
|
+$text-color: #483d8b; // 文本颜色:靛蓝色
|
|
|
|
|
+
|
|
|
.home-container {
|
|
.home-container {
|
|
|
position: fixed;
|
|
position: fixed;
|
|
|
top: 0;
|
|
top: 0;
|
|
@@ -331,9 +571,9 @@ const handleTimeUpdate = () => {
|
|
|
.el-menu ::v-deep(.el-sub-menu__title:focus),
|
|
.el-menu ::v-deep(.el-sub-menu__title:focus),
|
|
|
.el-menu ::v-deep(.el-sub-menu__title:active) {
|
|
.el-menu ::v-deep(.el-sub-menu__title:active) {
|
|
|
background: linear-gradient(
|
|
background: linear-gradient(
|
|
|
- to bottom,
|
|
|
|
|
- #fee78a,
|
|
|
|
|
- #ffce1b
|
|
|
|
|
|
|
+ to bottom,
|
|
|
|
|
+ #fee78a,
|
|
|
|
|
+ #ffce1b
|
|
|
); /* 设置悬停、聚焦、点击状态下的背景色 */
|
|
); /* 设置悬停、聚焦、点击状态下的背景色 */
|
|
|
background-color: transparent;
|
|
background-color: transparent;
|
|
|
}
|
|
}
|
|
@@ -358,9 +598,9 @@ const handleTimeUpdate = () => {
|
|
|
.el-menu ::v-deep(.el-menu-item:focus),
|
|
.el-menu ::v-deep(.el-menu-item:focus),
|
|
|
.el-menu ::v-deep(.el-menu-item:active) {
|
|
.el-menu ::v-deep(.el-menu-item:active) {
|
|
|
background: linear-gradient(
|
|
background: linear-gradient(
|
|
|
- to bottom,
|
|
|
|
|
- #fee78a,
|
|
|
|
|
- #ffce1b
|
|
|
|
|
|
|
+ to bottom,
|
|
|
|
|
+ #fee78a,
|
|
|
|
|
+ #ffce1b
|
|
|
); /* 设置悬停、聚焦、点击状态下的背景色 */
|
|
); /* 设置悬停、聚焦、点击状态下的背景色 */
|
|
|
}
|
|
}
|
|
|
.drawer-box {
|
|
.drawer-box {
|
|
@@ -540,4 +780,501 @@ const handleTimeUpdate = () => {
|
|
|
font-size: rpx(20);
|
|
font-size: rpx(20);
|
|
|
color: white;
|
|
color: white;
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 儿童风格试题弹框样式
|
|
|
|
|
+.child-dialog {
|
|
|
|
|
+ .el-dialog__header {
|
|
|
|
|
+ display: none; // 隐藏原有的标题栏
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__body {
|
|
|
|
|
+ padding: rpx(20);
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__footer {
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+ padding: rpx(10) rpx(20);
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__wrapper {
|
|
|
|
|
+ // 修改半透明背景色
|
|
|
|
|
+ background-color: rgba(0, 0, 0, 0.6);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: rpx(20);
|
|
|
|
|
+ background: linear-gradient(135deg, $light-color, #d8bfd8); // 柔和的蓝紫色渐变
|
|
|
|
|
+ // 添加边框边晕效果
|
|
|
|
|
+ box-shadow: 0 0 20px 5px rgba($primary-color, 0.6), 0 0 40px 10px rgba($primary-color, 0.4), 0 0 60px 15px rgba($primary-color, 0.2);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+
|
|
|
|
|
+ // 添加装饰元素
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ content: "";
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: rpx(10);
|
|
|
|
|
+ background: linear-gradient(90deg, $primary-color, $secondary-color, $accent-color);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// AI对话弹出框样式
|
|
|
|
|
+.ai-dialog {
|
|
|
|
|
+ .el-dialog__header {
|
|
|
|
|
+ background: linear-gradient(90deg, $primary-color, $secondary-color);
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ padding: rpx(10) rpx(20);
|
|
|
|
|
+ border-radius: rpx(10) rpx(10) 0 0;
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__title {
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__body {
|
|
|
|
|
+ padding: rpx(15);
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__footer {
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+ padding: rpx(10) rpx(20);
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog {
|
|
|
|
|
+ border-radius: rpx(10);
|
|
|
|
|
+ // 修改半透明背景色
|
|
|
|
|
+ background-color: rgba(255, 255, 255, 0.95);
|
|
|
|
|
+ // 添加边框边晕效果
|
|
|
|
|
+ box-shadow: 0 0 20px 5px rgba($primary-color, 0.6), 0 0 40px 10px rgba($primary-color, 0.4), 0 0 60px 15px rgba($primary-color, 0.2);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 问题标题样式
|
|
|
|
|
+.question-title {
|
|
|
|
|
+ background: linear-gradient(90deg, rgba($primary-color, 0.2), rgba($secondary-color, 0.2));
|
|
|
|
|
+ padding: rpx(15);
|
|
|
|
|
+ border-radius: rpx(12);
|
|
|
|
|
+ margin-bottom: rpx(20);
|
|
|
|
|
+ color: $accent-color;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ font-size: rpx(14);
|
|
|
|
|
+ box-shadow: 0 rpx(3) rpx(10) rgba($primary-color, 0.1);
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .question-icon {
|
|
|
|
|
+ background-color: $accent-color;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ width: rpx(24);
|
|
|
|
|
+ height: rpx(24);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ margin-right: rpx(10);
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ box-shadow: 0 rpx(2) rpx(5) rgba($accent-color, 0.3);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 选项容器样式
|
|
|
|
|
+.options-container {
|
|
|
|
|
+ margin-bottom: rpx(20);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 问题选项样式
|
|
|
|
|
+.question-option {
|
|
|
|
|
+ margin: rpx(8) 0;
|
|
|
|
|
+ padding: rpx(10) rpx(15);
|
|
|
|
|
+ border-radius: rpx(12);
|
|
|
|
|
+ border: rpx(1) solid rgba($primary-color, 0.3);
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ box-shadow: 0 rpx(2) rpx(5) rgba($primary-color, 0.05);
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-radio__label) {
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ margin-left: rpx(8);
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ text-align: left;
|
|
|
|
|
+ // 增大字体大小
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 选中时的样式变化
|
|
|
|
|
+ .el-radio__input.is-checked + .el-radio__label {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: $accent-color;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: rgba($primary-color, 0.05);
|
|
|
|
|
+ border-color: rgba($primary-color, 0.5);
|
|
|
|
|
+ transform: translateY(-rpx(1));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 暂无选项样式
|
|
|
|
|
+.no-options {
|
|
|
|
|
+ color: rgba($text-color, 0.7);
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: rpx(20);
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 底部按钮样式
|
|
|
|
|
+.child-button {
|
|
|
|
|
+ min-width: rpx(80);
|
|
|
|
|
+ height: rpx(30);
|
|
|
|
|
+ border-radius: rpx(15);
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ box-shadow: 0 rpx(2) rpx(8) rgba(0, 0, 0, 0.1);
|
|
|
|
|
+
|
|
|
|
|
+ &.confirm {
|
|
|
|
|
+ background: linear-gradient(to right, $primary-color, $secondary-color);
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-right: 15px;;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: linear-gradient(to right, darken($primary-color, 5%), darken($secondary-color, 5%));
|
|
|
|
|
+ box-shadow: 0 rpx(3) rpx(10) rgba($primary-color, 0.4);
|
|
|
|
|
+ transform: translateY(-rpx(1));
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.cancel {
|
|
|
|
|
+ background: white;
|
|
|
|
|
+ border: rpx(1) solid rgba($primary-color, 0.3);
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: rgba($primary-color, 0.05);
|
|
|
|
|
+ border-color: rgba($primary-color, 0.5);
|
|
|
|
|
+ transform: translateY(-rpx(1));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// AI对话图标样式
|
|
|
|
|
+.ai-icon-container {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: rpx(20);
|
|
|
|
|
+ right: rpx(20);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ transform: translateY(-rpx(2));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .ai-icon {
|
|
|
|
|
+ width: rpx(30);
|
|
|
|
|
+ height: rpx(30);
|
|
|
|
|
+ margin-bottom: rpx(5);
|
|
|
|
|
+ filter: drop-shadow(0 rpx(2) rpx(4) rgba($primary-color, 0.3));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .ai-text {
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ font-size: rpx(8);
|
|
|
|
|
+ background-color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
+ padding: rpx(2) rpx(5);
|
|
|
|
|
+ border-radius: rpx(5);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// AI对话弹出框样式
|
|
|
|
|
+.ai-dialog {
|
|
|
|
|
+ .el-dialog__header {
|
|
|
|
|
+ background: linear-gradient(90deg, $primary-color, $secondary-color);
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ padding: rpx(10) rpx(20);
|
|
|
|
|
+ border-radius: rpx(10) rpx(10) 0 0;
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__title {
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__body {
|
|
|
|
|
+ padding: rpx(15);
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog__footer {
|
|
|
|
|
+ border-top: none;
|
|
|
|
|
+ padding: rpx(10) rpx(20);
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .el-dialog {
|
|
|
|
|
+ border-radius: rpx(10);
|
|
|
|
|
+ box-shadow: 0 rpx(10) rpx(30) rgba(0, 0, 0, 0.15);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// AI消息样式
|
|
|
|
|
+.ai-message {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ margin-bottom: rpx(15);
|
|
|
|
|
+
|
|
|
|
|
+ .ai-avatar {
|
|
|
|
|
+ width: rpx(30);
|
|
|
|
|
+ height: rpx(30);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin-right: rpx(10);
|
|
|
|
|
+ background-color: $primary-color;
|
|
|
|
|
+ padding: rpx(5);
|
|
|
|
|
+ box-shadow: 0 rpx(2) rpx(5) rgba($primary-color, 0.2);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .ai-text-content {
|
|
|
|
|
+ background-color: $light-color;
|
|
|
|
|
+ padding: rpx(8) rpx(12);
|
|
|
|
|
+ border-radius: rpx(10);
|
|
|
|
|
+ font-size: rpx(10);
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ max-width: 80%;
|
|
|
|
|
+ box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 用户输入框样式
|
|
|
|
|
+.user-input {
|
|
|
|
|
+ ::v-deep(.el-input__wrapper) {
|
|
|
|
|
+ border-radius: rpx(15);
|
|
|
|
|
+ border-color: rgba($primary-color, 0.3);
|
|
|
|
|
+ margin-right: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ &:focus-within {
|
|
|
|
|
+ box-shadow: 0 0 0 rpx(1) rgba($primary-color, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-input__inner) {
|
|
|
|
|
+ font-size: rpx(10);
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ text-indent: 1em;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+// 自定义试题弹框背景
|
|
|
|
|
+.child-dialog-wrapper {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ background-color: rgba(0, 0, 0, 0.6); // 半透明背景
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ z-index: 1000;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.child-dialog {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: rpx(20);
|
|
|
|
|
+ background: linear-gradient(135deg, $light-color, #d8bfd8); // 柔和的蓝紫色渐变
|
|
|
|
|
+ box-shadow: 0 0 20px 5px rgba($primary-color, 0.6), 0 0 40px 10px rgba($primary-color, 0.4), 0 0 60px 15px rgba($primary-color, 0.2);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ padding: rpx(20);
|
|
|
|
|
+ width: 60%;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ // 添加装饰元素
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ content: "";
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: rpx(10);
|
|
|
|
|
+ background: linear-gradient(90deg, $primary-color, $secondary-color, $accent-color);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// AI对话弹框样式
|
|
|
|
|
+.ai-dialog-wrapper {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ z-index: 1001;
|
|
|
|
|
+ pointer-events: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.ai-dialog {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: rpx(20);
|
|
|
|
|
+ background: linear-gradient(135deg, $light-color, #d8bfd8);
|
|
|
|
|
+ box-shadow: 0 0 20px 5px rgba($primary-color, 0.6), 0 0 40px 10px rgba($primary-color, 0.4), 0 0 60px 15px rgba($primary-color, 0.2);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ padding: rpx(20);
|
|
|
|
|
+ width: 30%;
|
|
|
|
|
+ // 增加高度
|
|
|
|
|
+ height: 80%;
|
|
|
|
|
+ margin-right: rpx(50);
|
|
|
|
|
+ pointer-events: auto;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+
|
|
|
|
|
+ &::before {
|
|
|
|
|
+ content: "";
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: rpx(10);
|
|
|
|
|
+ background: linear-gradient(90deg, $primary-color, $secondary-color, $accent-color);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.ai-dialog-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: rpx(15);
|
|
|
|
|
+
|
|
|
|
|
+ h3 {
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ font-size: rpx(12);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .close-btn {
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ width: rpx(20);
|
|
|
|
|
+ height: rpx(20);
|
|
|
|
|
+ font-size: rpx(16);
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.ai-dialog-content {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.ai-message-history {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ // 当内容超出容器高度时,显示垂直滚动条
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ margin-bottom: rpx(15);
|
|
|
|
|
+ // 可以根据实际情况调整最大高度
|
|
|
|
|
+ max-height: 50vh;
|
|
|
|
|
+ padding: 5px 10px;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ .message {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ margin-bottom: rpx(10);
|
|
|
|
|
+
|
|
|
|
|
+ &.user {
|
|
|
|
|
+ flex-direction: row-reverse;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .avatar {
|
|
|
|
|
+ width: rpx(30);
|
|
|
|
|
+ height: rpx(30);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin: 0 rpx(10);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .message-content {
|
|
|
|
|
+ background-color: $light-color;
|
|
|
|
|
+ padding: rpx(8) rpx(12);
|
|
|
|
|
+ border-radius: rpx(10);
|
|
|
|
|
+ font-size: rpx(10);
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ max-width: 80%;
|
|
|
|
|
+ box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 滚动条整体样式
|
|
|
|
|
+ &::-webkit-scrollbar {
|
|
|
|
|
+ width: rpx(4); // 滚动条宽度
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滚动条滑块样式
|
|
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
|
|
+ background-color: $primary-color; // 滑块颜色
|
|
|
|
|
+ border-radius: rpx(4); // 滑块圆角
|
|
|
|
|
+ transition: background-color 0.3s ease; // 颜色过渡效果
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background-color: darken($primary-color, 10%); // 悬停时滑块颜色加深
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滚动条轨道样式
|
|
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
|
|
+ background-color: rgba($primary-color, 0.2); // 轨道颜色
|
|
|
|
|
+ border-radius: rpx(4); // 轨道圆角
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .message {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ margin-bottom: rpx(10);
|
|
|
|
|
+
|
|
|
|
|
+ &.user {
|
|
|
|
|
+ flex-direction: row-reverse;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .avatar {
|
|
|
|
|
+ width: rpx(30);
|
|
|
|
|
+ height: rpx(30);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin: 0 rpx(10);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .message-content {
|
|
|
|
|
+ background-color: $light-color;
|
|
|
|
|
+ padding: rpx(8) rpx(12);
|
|
|
|
|
+ border-radius: rpx(10);
|
|
|
|
|
+ font-size: rpx(10);
|
|
|
|
|
+ color: $text-color;
|
|
|
|
|
+ max-width: 80%;
|
|
|
|
|
+ box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 优化发送按钮样式
|
|
|
|
|
+.send-button {
|
|
|
|
|
+ //background: linear-gradient(90deg, $primary-color, $secondary-color);
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ //background: linear-gradient(90deg, darken($primary-color, 5%), darken($secondary-color, 5%));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|