AIDevelop.vue 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. <template>
  2. <!-- AI发展历程 -->
  3. <div class="home-container">
  4. <!-- 展开收起侧边栏 -->
  5. <div class="icon-expand">
  6. <el-icon
  7. @click="toggleDrawer"
  8. :style="{ color: drawerVisible ? 'white' : '#B6B0D8' }"
  9. >
  10. <component :is="drawerVisible ? Fold : Expand" />
  11. <!-- <Tickets /> -->
  12. </el-icon>
  13. </div>
  14. <transition name="drawer-slide">
  15. <div class="main-content" v-if="drawerVisible">
  16. <!-- 添加抽屉 -->
  17. <div class="drawer-box">
  18. <el-row class="tac">
  19. <el-col :span="12">
  20. <h3 class="mb-2">
  21. <el-icon><Memo /></el-icon>
  22. 课程小节
  23. </h3>
  24. <el-menu
  25. default-active="1-1"
  26. @open="handleOpen"
  27. @close="handleClose"
  28. @select="handleSelect"
  29. :default-openeds="['3']"
  30. >
  31. <template v-for="item in menuItems" :key="item.index">
  32. <el-menu-item v-if="!item.children" :index="item.index">{{
  33. item.title
  34. }}</el-menu-item>
  35. <el-sub-menu v-else :index="item.index">
  36. <template #title>
  37. <span>{{ item.title }}</span>
  38. </template>
  39. <el-menu-item-group v-if="item.children">
  40. <template
  41. v-for="child in item.children"
  42. :key="child.index"
  43. >
  44. <el-menu-item :index="child.index">{{
  45. child.title
  46. }}</el-menu-item>
  47. </template>
  48. </el-menu-item-group>
  49. </el-sub-menu>
  50. </template>
  51. </el-menu>
  52. </el-col>
  53. </el-row>
  54. </div>
  55. </div>
  56. </transition>
  57. <div class="content-box">
  58. <div class="box-1">
  59. <div class="inner-box left-box">
  60. <div class="box-icon" @click="goBack">
  61. <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
  62. {{ boxIconTitle }}
  63. </div>
  64. </div>
  65. <div class="inner-box right-box">
  66. <div class="top-right-box">
  67. <el-input
  68. v-model="SearchInput"
  69. class="search-input"
  70. placeholder="搜索"
  71. >
  72. <template #prefix>
  73. <el-icon class="el-input__icon"><search /></el-icon>
  74. </template>
  75. </el-input>
  76. </div>
  77. </div>
  78. </div>
  79. <div class="box-2">
  80. <!-- 课程标题 autoplay自动播放 @ended="playNextVideo"-->
  81. <div class="small-title">
  82. <span>{{ smallTitle }}</span>
  83. </div>
  84. <div class="box-video">
  85. <video
  86. class="full-box-video"
  87. :src="videoSrc"
  88. controlsList="nodownload"
  89. controls
  90. @timeupdate="handleTimeUpdate"
  91. @play="checkVideoPermission"
  92. ref="videoRef"
  93. >
  94. <source :src="videoSrc" type="video/mp4" />
  95. 您的浏览器不支持视频播放。
  96. </video>
  97. </div>
  98. <!-- 添加切换视频 -->
  99. <div class="video-switch">
  100. <!-- 上一个视频 -->
  101. <div class="caret-left" @click="playPreviousVideo">
  102. <el-button type="warning" round>上一节</el-button>
  103. </div>
  104. <!-- 下一个视频 -->
  105. <div class="caret-right" @click="playNextVideo">
  106. <el-button type="warning" round>下一节</el-button>
  107. </div>
  108. </div>
  109. </div>
  110. <!-- 添加试题弹框 -->
  111. <transition name="fade-scale">
  112. <div
  113. v-show="questionDialogVisible"
  114. class="child-dialog-wrapper"
  115. @click.self="handleCloseQuestionDialog"
  116. >
  117. <div class="child-dialog">
  118. <div class="question-title">
  119. <span class="question-icon">?</span>
  120. {{ currentQuestion.title }}
  121. </div>
  122. <!-- 选项区域 -->
  123. <div
  124. v-if="
  125. currentQuestion.options && currentQuestion.options.length > 0
  126. "
  127. class="options-container"
  128. >
  129. <div
  130. v-for="(option, index) in currentQuestion.options"
  131. :key="index"
  132. class="question-option"
  133. >
  134. <el-radio
  135. v-model="selectedOption"
  136. :label="index"
  137. :value="option"
  138. v-cloak="(selectedOption = option)"
  139. >
  140. <span>{{ option }}</span>
  141. </el-radio>
  142. </div>
  143. </div>
  144. <div v-else class="no-options">
  145. <!-- 暂无选项-->
  146. </div>
  147. <!-- 底部按钮 -->
  148. <div class="dialog-footer">
  149. <!-- <el-button class="child-button cancel" @click="questionDialogVisible = false; showAIDialog = false">取消</el-button>-->
  150. <el-button
  151. class="child-button confirm"
  152. @click="handleSubmitAnswer"
  153. >确定</el-button
  154. >
  155. </div>
  156. <!-- 右侧小图标 -->
  157. <div class="ai-icon-container" @click="handleAIClick">
  158. <img
  159. src="@/assets/images/xiaozhi.png"
  160. alt="AI对话"
  161. class="ai-icon"
  162. />
  163. <span class="ai-text">AI助手</span>
  164. </div>
  165. </div>
  166. </div>
  167. </transition>
  168. <!-- AI对话弹框 -->
  169. <div
  170. v-show="showAIDialog"
  171. class="ai-dialog-wrapper"
  172. @click.self="showAIDialog = false"
  173. >
  174. <div class="ai-dialog">
  175. <div class="ai-dialog-header">
  176. <h3>小智智能助手</h3>
  177. <el-button @click="showAIDialog = false" class="close-btn"
  178. >×</el-button
  179. >
  180. </div>
  181. <div class="ai-dialog-content">
  182. <div class="ai-message-history">
  183. <div
  184. v-for="(message, index) in messageHistory"
  185. :key="index"
  186. :class="['message', message.type]"
  187. >
  188. <img
  189. v-if="message.type === 'user'"
  190. src="@/assets/images/user.png"
  191. class="avatar user"
  192. />
  193. <img v-else src="@/assets/images/xiaozhi.png" class="avatar" />
  194. <div class="message-content">
  195. {{ message.content }}
  196. </div>
  197. </div>
  198. </div>
  199. <el-input
  200. v-model="userMessage"
  201. placeholder="输入问题..."
  202. class="user-input"
  203. @keyup.enter="sendMessage"
  204. >
  205. <template #append class="flex flex-wrap items-center mb-4">
  206. <!-- <el-button @click="sendMessage" class="child-button confirm">发送</el-button>-->
  207. <el-button @click="sendMessage" size="large" round
  208. >发送</el-button
  209. >
  210. </template>
  211. </el-input>
  212. </div>
  213. </div>
  214. </div>
  215. </div>
  216. </div>
  217. </template>
  218. <script setup>
  219. import { ref, onMounted } from 'vue'
  220. import { useRouter } from 'vue-router'
  221. import {
  222. ArrowDown,
  223. ArrowRightBold,
  224. Expand,
  225. Reading,
  226. Fold,
  227. Tickets,
  228. Memo
  229. } from '@element-plus/icons-vue'
  230. import {
  231. Document,
  232. Menu as IconMenu,
  233. Location,
  234. Setting
  235. } from '@element-plus/icons-vue'
  236. import { Search, ArrowLeftBold } from '@element-plus/icons-vue'
  237. import {
  238. ElMessage,
  239. ElMessageBox,
  240. ElNotification,
  241. valueEquals
  242. } from 'element-plus'
  243. // 引入视频
  244. import video1 from '@/assets/02video/01video.mp4'
  245. import video2 from '@/assets/02video/02video.mp4'
  246. import video3 from '@/assets/02video/03video.mp4'
  247. import video4 from '@/assets/02video/04video.mp4'
  248. import video5 from '@/assets/02video/05video.mp4'
  249. import video6 from '@/assets/02video/06video.mp4'
  250. import video7 from '@/assets/02video/07video.mp4'
  251. import video8 from '@/assets/02video/08video.mp4'
  252. import video9 from '@/assets/02video/09video.mp4'
  253. import video10 from '@/assets/02video/10video.mp4'
  254. import video11 from '@/assets/02video/11video.mp4'
  255. import video12 from '@/assets/02video/12video.mp4'
  256. import video13 from '@/assets/02video/13video.mp4'
  257. import video14 from '@/assets/02video/14video.mp4'
  258. import video15 from '@/assets/02video/15video.mp4'
  259. import { ClassType } from '@/api/class.js'
  260. import { Message } from '@/utils/message/Message.js'
  261. const router = useRouter() // 获取当前路由对象
  262. // 搜索框
  263. const SearchInput = ref('')
  264. // 添加按钮显示状态
  265. const buttonVisible = ref(false)
  266. // 添加抽屉显示状态
  267. const drawerVisible = ref(true)
  268. // 添加切换抽屉显示状态的函数
  269. const toggleDrawer = () => {
  270. drawerVisible.value = !drawerVisible.value
  271. }
  272. // 返回上一页
  273. const goBack = () => {
  274. router.go(-1)
  275. }
  276. // 渲染页面标题
  277. const boxIconTitle = ref('')
  278. // 课程数据
  279. const courseList = ref([])
  280. // 菜单数据
  281. const menuItems = ref([])
  282. // 定义视频源
  283. const videoSrc = ref('')
  284. // 新增视频路径映射
  285. const videoPathMap = ref({})
  286. // 渲染 课程数据结构 以及 视频
  287. onMounted(async () => {
  288. const typeId = router.currentRoute.value.query.typeId
  289. if (typeId) {
  290. try {
  291. // 取接口课程数据
  292. const res = await ClassType(typeId)
  293. console.log(res);
  294. courseList.value = res.data
  295. // 初始化第一个视频源和标题
  296. if (courseList.value.length > 0 && courseList.value[0].courseVideoPath) {
  297. videoSrc.value = courseList.value[0].courseVideoPath
  298. currentIndex.value = '1-1'
  299. smallTitle.value = courseList.value[0].courseName
  300. }
  301. // 按 courseLabel 分组
  302. const groupedByLabel = {}
  303. courseList.value.forEach(item => {
  304. if (!groupedByLabel[item.courseLabel]) {
  305. groupedByLabel[item.courseLabel] = []
  306. }
  307. groupedByLabel[item.courseLabel].push(item)
  308. })
  309. // 对每个组按 courseOrder 排序
  310. Object.keys(groupedByLabel).forEach(label => {
  311. groupedByLabel[label].sort((a, b) => a.courseOrder - b.courseOrder)
  312. })
  313. // 构建视频路径映射
  314. videoPathMap.value = {}
  315. let labelIndex = 0
  316. Object.keys(groupedByLabel).forEach(label => {
  317. const groupItems = groupedByLabel[label]
  318. groupItems.forEach((item, indexInGroup) => {
  319. const idx = `${labelIndex + 1}-${indexInGroup + 1}`
  320. if (item.courseVideoPath) {
  321. videoPathMap.value[idx] = item.courseVideoPath
  322. }
  323. })
  324. labelIndex++
  325. })
  326. // 构建新的 menuItems 结构
  327. menuItems.value = []
  328. Object.keys(groupedByLabel).forEach((label, labelIndex) => {
  329. const groupItems = groupedByLabel[label]
  330. // 检查是否是知识分解组(图灵测试到大模型时代)
  331. const isKnowledgeGroup = groupItems.some(item =>
  332. ['图灵测试', '大模型时代'].includes(item.courseName)
  333. )
  334. if (isKnowledgeGroup) {
  335. // 构建知识分解组的树型结构
  336. menuItems.value.push({
  337. index: `${labelIndex + 1}`,
  338. title: '知识讲解',
  339. children: groupItems.map((item, index) => ({
  340. index: `${labelIndex + 1}-${index + 1}`,
  341. title: item.courseName
  342. }))
  343. })
  344. } else {
  345. // 普通组直接添加菜单项
  346. groupItems.forEach((item, index) => {
  347. const idx = `${labelIndex + 1}-${index + 1}`
  348. menuItems.value.push({
  349. index: idx,
  350. title: item.courseName
  351. })
  352. })
  353. }
  354. })
  355. } catch (error) {
  356. console.error('获取课程数据失败:', error)
  357. }
  358. }
  359. const title = router.currentRoute.value.query.typeName
  360. if (title) {
  361. boxIconTitle.value = String(title)
  362. }
  363. })
  364. // 菜单打开和关闭的处理函数
  365. const handleOpen = () => {}
  366. const handleClose = () => {}
  367. // 当前播放的索引
  368. const currentIndex = ref('1-1')
  369. // 渲染课程标题到视频上方
  370. const smallTitle = ref('课前回顾')
  371. const handleSelect = index => {
  372. const findTitle = items => {
  373. for (const item of items) {
  374. if (item.index === index) {
  375. return item.title
  376. }
  377. if (item.children) {
  378. const result = findTitle(item.children)
  379. if (result) {
  380. return result
  381. }
  382. }
  383. }
  384. return null
  385. }
  386. const title = findTitle(menuItems.value)
  387. if (title) {
  388. smallTitle.value = title
  389. }
  390. // 根据索引切换视频,使用新的 videoPathMap
  391. if (videoPathMap.value[index]) {
  392. videoSrc.value = videoPathMap.value[index]
  393. currentIndex.value = index
  394. }
  395. //测试账号禁用视频
  396. if (disableVideo()) return
  397. }
  398. // 展平所有菜单项索引
  399. const flattenMenuItems = () => {
  400. const indices = []
  401. const traverse = items => {
  402. for (const item of items) {
  403. if (!item.children) {
  404. indices.push(item.index)
  405. } else {
  406. traverse(item.children)
  407. }
  408. }
  409. }
  410. traverse(menuItems.value)
  411. return indices
  412. }
  413. // 播放下一个视频
  414. const playNextVideo = () => {
  415. //测试账号禁用视频
  416. if (disableVideo()) return
  417. const allIndices = flattenMenuItems()
  418. const currentIndexInList = allIndices.indexOf(currentIndex.value)
  419. if (currentIndexInList !== -1 && currentIndexInList < allIndices.length - 1) {
  420. const nextIndex = allIndices[currentIndexInList + 1]
  421. handleSelect(nextIndex)
  422. // 切换视频后自动播放
  423. if (videoRef.value) {
  424. videoRef.value.addEventListener('loadedmetadata', tryPlayVideo, {
  425. once: true
  426. })
  427. }
  428. }
  429. // 重置
  430. pausedIndices = ref([])
  431. userMessage = ref('')
  432. messageHistory = ref([])
  433. }
  434. // 切换视频
  435. // 播放上一个视频
  436. const playPreviousVideo = () => {
  437. //测试账号禁用视频
  438. if (disableVideo()) return
  439. const allIndices = flattenMenuItems()
  440. const currentIndexInList = allIndices.indexOf(currentIndex.value)
  441. if (currentIndexInList > 0) {
  442. const previousIndex = allIndices[currentIndexInList - 1]
  443. handleSelect(previousIndex)
  444. // 切换视频后自动播放
  445. if (videoRef.value) {
  446. videoRef.value.addEventListener('loadedmetadata', tryPlayVideo, {
  447. once: true
  448. })
  449. }
  450. }
  451. }
  452. // 尝试播放视频,处理浏览器自动播放限制
  453. const tryPlayVideo = () => {
  454. //测试账号禁用视频
  455. if (disableVideo()) return
  456. const playPromise = videoRef.value.play()
  457. if (playPromise !== undefined) {
  458. playPromise.catch(error => {
  459. console.error('视频播放失败,可能是浏览器自动播放限制:', error)
  460. })
  461. }
  462. }
  463. // 检查视频播放权限
  464. const checkVideoPermission = () => {
  465. if (disableVideo()) {
  466. if (videoRef.value) {
  467. videoRef.value.pause()
  468. }
  469. }
  470. }
  471. //禁用视频
  472. const disableVideo = () => {
  473. let dis = [
  474. '3-4',
  475. '3-5',
  476. '3-6',
  477. '3-7',
  478. '3-8',
  479. '3-9',
  480. '3-10',
  481. '3-11',
  482. '4-1',
  483. '5-1'
  484. ]
  485. if (
  486. localStorage.getItem('userName') === 'aiTest' &&
  487. dis.indexOf(currentIndex.value) !== -1
  488. ) {
  489. if (videoRef.value) {
  490. videoRef.value.pause()
  491. // 禁用视频进度条拖拽功能
  492. const handleSeeking = () => {
  493. videoRef.value.pause()
  494. Message().notifyWarning(
  495. '您的账号并未开放此课程,禁止拖动进度条!',
  496. true
  497. )
  498. }
  499. // 添加 seeking 事件监听器
  500. videoRef.value.addEventListener('seeking', handleSeeking)
  501. // 当视频源改变时,移除事件监听器,避免影响其他视频
  502. const removeListener = () => {
  503. videoRef.value.removeEventListener('seeking', handleSeeking)
  504. videoRef.value.removeEventListener('loadedmetadata', removeListener)
  505. }
  506. videoRef.value.addEventListener('loadedmetadata', removeListener)
  507. }
  508. //提示禁用// 显示消息框
  509. Message().notifyWarning('您的账号并未开放此课程!', true)
  510. return true
  511. } else {
  512. // 若不符合禁用条件,移除事件监听器
  513. if (videoRef.value) {
  514. videoRef.value.removeEventListener('seeking', e => {
  515. e.preventDefault()
  516. })
  517. }
  518. return false
  519. }
  520. }
  521. // 视频 ref
  522. const videoRef = ref(null)
  523. // 记录已经暂停过的时间点索引
  524. let pausedIndices = ref([])
  525. // 试题弹框显示状态
  526. const questionDialogVisible = ref(false)
  527. // 当前显示的试题
  528. const currentQuestion = ref({ title: '', options: [] })
  529. // 用户选择的选项
  530. const selectedOption = ref(null)
  531. // AI对话弹出框显示状态
  532. let showAIDialog = ref(false)
  533. // 用户输入的消息
  534. let userMessage = ref('')
  535. // 消息历史记录
  536. let messageHistory = ref([])
  537. // 定义每个视频对应的暂停时间和问题
  538. const videoPauseTimes = {
  539. [video2]: {
  540. pauseTimes: [30],
  541. questions: [
  542. {
  543. title: '视频当中发生了什么事情呢?',
  544. options: [],
  545. aiQuestion: '视频当中发生了什么事情呢',
  546. aiAnswer:
  547. '让我来告诉你吧:泡泡怪篡改了Ai历史数据,导致Ai系统发生崩溃,所以要修正Ai历史抓到泡泡怪!'
  548. }
  549. ]
  550. },
  551. [video3]: {
  552. pauseTimes: [49],
  553. questions: [
  554. {
  555. title: '同学们,大家了解图灵测试了吗?',
  556. options: [],
  557. aiQuestion: '视频当中发生了什么事情呢',
  558. aiAnswer:
  559. '让我来告诉你吧:泡泡怪篡改了Ai历史数据,导致Ai系统发生崩溃,所以要修正Ai历史抓到泡泡怪!'
  560. }
  561. ]
  562. },
  563. [video4]: {
  564. pauseTimes: [2],
  565. questions: [
  566. {
  567. title: '你觉得deepseek、豆包等大模型可以通过图灵测试吗?为什么?',
  568. options: [],
  569. aiQuestion: '你觉得deepseek、豆包等大模型可以通过图灵测试吗?为什么?',
  570. aiAnswer:
  571. '大模型已缩短与图灵测试的标志距离,尤其在表面对话层面,但因缺乏深层次理解、逻辑一致性与真实认知,仍无法在严格测试中稳定通过。'
  572. }
  573. ]
  574. },
  575. [video5]: {
  576. pauseTimes: [49],
  577. questions: []
  578. },
  579. [video6]: {
  580. pauseTimes: [5]
  581. },
  582. [video7]: {
  583. pauseTimes: [64.5, 91],
  584. questions: [
  585. {
  586. title: '如果你是聊天机器人,你会怎么回答用户呢?',
  587. options: [],
  588. aiQuestion: '',
  589. aiAnswer: ''
  590. },
  591. {
  592. title:
  593. '当我们和聊天机器人对话的内容被人类所查看并回答时,隐私信息是否泄露?',
  594. options: [],
  595. aiQuestion:
  596. '当我们和聊天机器人对话的内容被人类所查看并回答时,隐私信息是否泄露?',
  597. aiAnswer:
  598. '与聊天机器人的对话被人类查看时,隐私泄露风险客\n' +
  599. '观存在,尤其是人类介入或安全漏洞场景下。建议优先选择支持本地'
  600. }
  601. ]
  602. },
  603. [video8]: {
  604. pauseTimes: [72],
  605. questions: [
  606. {
  607. title: '如果你身体不舒服时找这样的专家检查,那么它开的药你敢喝吗?',
  608. options: [],
  609. aiQuestion:
  610. '如果你身体不舒服时找这样的专家检查,那么它开的药你敢喝吗?',
  611. aiAnswer: '这题没给答案,你自己去查吧!'
  612. }
  613. ]
  614. },
  615. [video9]: {
  616. pauseTimes: [2],
  617. questions: [
  618. {
  619. title: '在生活中,有哪些正在使用的专家系统呢?',
  620. options: [],
  621. aiQuestion: '在生活中,有哪些正在使用的专家系统呢?',
  622. aiAnswer:
  623. '在医疗健康领域有复杂疾病协同决策和Ai医生分身与诊断辅助;在水利交通领域的水利厅专家库系统用于项目验收和抢险督查'
  624. }
  625. ]
  626. },
  627. [video11]: {
  628. pauseTimes: [1, 90, 176],
  629. questions: [
  630. {
  631. title: '怎么会有爆炸声?泡泡怪在这里吗?',
  632. options: [],
  633. aiQuestion: '',
  634. aiAnswer: ''
  635. },
  636. {
  637. title: '同学们喜欢下围棋吗?',
  638. options: [],
  639. aiQuestion: '',
  640. aiAnswer: ''
  641. },
  642. {
  643. title: '为什么AlphaGo要在围棋上攻克真人冠军呢?',
  644. options: [],
  645. aiQuestion: '为什么AlphaGo要在围棋上攻克真人冠军呢?',
  646. aiAnswer:
  647. '围棋是人类智力游戏的巅峰,拥有天文数字级的可能性,每颗棋子价值由全局态势动态决定,所以当前一手可能百步之后才显现价值。AlphaGo战胜人类顶尖选手,它证明了Ai不仅能处理规则明确的事物,更能攻克依赖直觉、策略的“人类专属领域”'
  648. }
  649. ]
  650. },
  651. [video12]: {
  652. pauseTimes: [1]
  653. },
  654. [video13]: {
  655. pauseTimes: [62],
  656. questions: [
  657. {
  658. title: '我们一起来感受一下大模型吧!',
  659. options: [],
  660. aiQuestion: '',
  661. aiAnswer: ''
  662. }
  663. ]
  664. }
  665. }
  666. // 处理视频时间更新事件
  667. const handleTimeUpdate = () => {
  668. if (!videoRef.value) return
  669. const currentTime = videoRef.value.currentTime
  670. const currentPauseTimes = videoPauseTimes[videoSrc.value]
  671. if (currentPauseTimes) {
  672. currentPauseTimes.pauseTimes.forEach((time, index) => {
  673. // 检查是否到达时间点且还未暂停过
  674. if (currentTime >= time && !pausedIndices.value.includes(index)) {
  675. videoRef.value.pause()
  676. pausedIndices.value.push(index)
  677. // 显示对应的问题
  678. if (currentPauseTimes.questions[index]) {
  679. currentQuestion.value = currentPauseTimes.questions[index]
  680. questionDialogVisible.value = true
  681. }
  682. }
  683. })
  684. }
  685. }
  686. // 关闭试题弹框
  687. const handleCloseQuestionDialog = () => {
  688. questionDialogVisible.value = false
  689. // 继续播放视频
  690. videoRef.value.play()
  691. }
  692. // 提交答案
  693. const handleSubmitAnswer = () => {
  694. // 这里可以添加答案验证逻辑
  695. questionDialogVisible.value = false
  696. // 继续播放视频
  697. videoRef.value.play()
  698. selectedOption.value = null
  699. }
  700. // 发送消息
  701. const sendMessage = async () => {
  702. if (userMessage.value.trim()) {
  703. // 添加用户消息到历史记录
  704. messageHistory.value.push({
  705. type: 'user',
  706. content: userMessage.value
  707. })
  708. // 模拟 AI 回复
  709. const aiResponse = await simulateAIResponse(userMessage.value)
  710. messageHistory.value.push({
  711. type: 'ai',
  712. content: aiResponse
  713. })
  714. // 清空输入框
  715. userMessage.value = ''
  716. }
  717. }
  718. // 处理 AI 助手点击事件
  719. const handleAIClick = () => {
  720. // 清空输入框
  721. messageHistory = ref([])
  722. if (currentQuestion.value.aiQuestion) {
  723. userMessage.value = currentQuestion.value.aiQuestion
  724. sendMessage()
  725. userMessage.value = ''
  726. }
  727. showAIDialog.value = true
  728. }
  729. // 模拟 AI 回复
  730. const simulateAIResponse = question => {
  731. return new Promise(resolve => {
  732. setTimeout(() => {
  733. const currentVideoInfo = videoPauseTimes[videoSrc.value]
  734. if (currentVideoInfo) {
  735. const currentQuestionObj = currentVideoInfo.questions.find(
  736. q => q.aiQuestion === question
  737. )
  738. if (currentQuestionObj && currentQuestionObj.aiAnswer) {
  739. resolve(currentQuestionObj.aiAnswer)
  740. return
  741. }
  742. }
  743. // 若未匹配到自定义回复,给出默认回复
  744. resolve(`您的问题是:${question},这是 AI 的回复示例。`)
  745. }, 1000)
  746. })
  747. }
  748. // 关闭AI对话弹出框
  749. const handleCloseAIDialog = () => {
  750. showAIDialog.value = false
  751. }
  752. </script>
  753. <style scoped lang="scss">
  754. @use 'sass:math';
  755. @use 'sass:color'; // 引入 color 模块
  756. // 定义rpx转换函数
  757. @function rpx($px) {
  758. @return math.div($px, 750) * 100vw;
  759. }
  760. // 定义儿童风格的蓝紫色调
  761. $primary-color: rgba(106, 90, 205, 0.52); // 主色调:蓝紫色
  762. $secondary-color: rgba(147, 112, 219, 0.66); // 辅助色:亮蓝紫色
  763. $accent-color: rgb(133, 89, 220); // 强调色:暗蓝紫色
  764. $light-color: #e6e6fa; // 浅色背景:淡紫色
  765. $text-color: #483d8b; // 文本颜色:靛蓝色
  766. /* 添加过渡样式 */
  767. .drawer-slide-enter-active,
  768. .drawer-slide-leave-active {
  769. transition: all 0.3s ease;
  770. }
  771. .drawer-slide-enter-from,
  772. .drawer-slide-leave-to {
  773. transform: translateX(-100%);
  774. opacity: 0;
  775. }
  776. .main-content {
  777. width: rpx(135);
  778. height: 100%;
  779. position: relative;
  780. background: linear-gradient(to bottom, #001169, #8a78d0);
  781. }
  782. .content-box {
  783. flex: 1;
  784. height: 100%;
  785. display: flex;
  786. flex-direction: column; /* 子元素上下排列 */
  787. background: linear-gradient(
  788. to bottom,
  789. #e2ddfc,
  790. #f1effd
  791. ); /* 设置悬停、聚焦、点击状态下的背景色 */
  792. }
  793. .icon-expand {
  794. width: rpx(135);
  795. height: rpx(30);
  796. // background: rgb(15, 28, 116, 0.4);
  797. z-index: 9999;
  798. position: absolute;
  799. cursor: pointer; // 添加鼠标指针样式
  800. }
  801. .icon-expand .el-icon {
  802. font-size: rpx(15);
  803. position: absolute;
  804. color: white;
  805. left: rpx(9);
  806. margin-top: rpx(17);
  807. }
  808. .icon-expand .el-icon:active {
  809. color: black;
  810. }
  811. .home-container {
  812. position: fixed;
  813. top: 0;
  814. left: 0;
  815. right: 0;
  816. bottom: 0;
  817. background: linear-gradient(to bottom, #001169, #b4a8e1);
  818. display: flex;
  819. flex-direction: row;
  820. gap: rpx(0);
  821. }
  822. .el-row {
  823. margin: auto;
  824. margin-top: rpx(40);
  825. margin-left: rpx(20);
  826. }
  827. .tac ::v-deep(.el-menu) {
  828. background-color: transparent;
  829. border: none;
  830. width: 100%;
  831. }
  832. /* 取消点击后的蓝色字体 el-sub-menu__title*/
  833. .tac ::v-deep(.el-menu-item.is-active),
  834. .tac ::v-deep(.el-sub-menu__title.is-active) {
  835. color: white;
  836. }
  837. // 取消鼠标悬浮颜色
  838. .tac ::v-deep(.el-sub-menu__title) {
  839. width: rpx(130);
  840. height: rpx(20);
  841. margin-bottom: rpx(5);
  842. border-radius: rpx(6);
  843. }
  844. .el-menu ::v-deep(.el-sub-menu__title:hover),
  845. .el-menu ::v-deep(.el-sub-menu__title:focus),
  846. .el-menu ::v-deep(.el-sub-menu__title:active) {
  847. background: linear-gradient(to bottom, #fee78a, #ffce1b);
  848. background-color: transparent;
  849. }
  850. .mb-2 {
  851. color: white;
  852. margin-top: rpx(1);
  853. }
  854. .mb-2 .el-icon {
  855. font-size: rpx(10);
  856. margin-left: rpx(5);
  857. }
  858. .el-menu-item {
  859. width: rpx(100);
  860. height: rpx(20);
  861. margin-bottom: rpx(5);
  862. border-radius: rpx(6);
  863. color: white;
  864. font-size: rpx(7);
  865. }
  866. .el-menu ::v-deep(.el-sub-menu__title) {
  867. color: white;
  868. width: rpx(100);
  869. height: rpx(20);
  870. margin-bottom: rpx(5);
  871. font-size: rpx(7);
  872. }
  873. .el-menu ::v-deep(.el-sub-menu__title:hover),
  874. .el-menu ::v-deep(.el-sub-menu__title:focus),
  875. .el-menu ::v-deep(.el-sub-menu__title:active) {
  876. background: linear-gradient(to bottom, #fee78a, #ffce1b);
  877. color: black;
  878. font-size: rpx(8);
  879. }
  880. .el-menu ::v-deep(.el-menu-item:hover),
  881. .el-menu ::v-deep(.el-menu-item:focus),
  882. .el-menu ::v-deep(.el-menu-item:active) {
  883. background: linear-gradient(to bottom, #fee78a, #ffce1b);
  884. color: black;
  885. font-size: rpx(8);
  886. box-shadow: 0 4px 8px rgba(3, 3, 3, 0.3);
  887. }
  888. .el-menu .el-menu-item.is-active {
  889. background: linear-gradient(to bottom, #fee78a, #ffce1b);
  890. color: black;
  891. font-size: rpx(8);
  892. box-shadow: 0 4px 8px rgba(3, 3, 3, 0.3);
  893. }
  894. .drawer-box {
  895. position: absolute;
  896. display: flex;
  897. align-items: center;
  898. height: 100%;
  899. width: 100%;
  900. overflow-y: auto; /* 添加垂直滚动条 */
  901. max-height: 100%; /* 设置最大高度 */
  902. /* 添加滚动条样式 */
  903. &::-webkit-scrollbar {
  904. width: rpx(1);
  905. }
  906. &::-webkit-scrollbar-thumb {
  907. background-color: #b4a8e1;
  908. border-radius: rpx(5);
  909. }
  910. &::-webkit-scrollbar-track {
  911. background-color: rgba(255, 255, 255, 0.2);
  912. border-radius: rpx(5);
  913. }
  914. }
  915. .drawer-box .toggle-button {
  916. width: rpx(10);
  917. height: rpx(50);
  918. font-size: rpx(7);
  919. background-color: rgba(17, 23, 29, 0.2);
  920. border: none;
  921. position: relative;
  922. writing-mode: vertical-lr; // 文字垂直排列,从左到右
  923. text-orientation: upright; // 文字保持正立
  924. }
  925. .toggle-button:hover {
  926. left: 0;
  927. }
  928. .toggle-button.is-active,
  929. .toggle-button:active,
  930. .toggle-button:focus {
  931. background-color: rgba(165, 209, 247, 0.8);
  932. color: white;
  933. border: none; // 移除点击时的边框
  934. outline: none; // 移除点击时的外边框
  935. }
  936. .box-1 {
  937. width: 100%;
  938. height: rpx(50);
  939. margin-top: rpx(10);
  940. display: flex;
  941. justify-content: center;
  942. align-items: center;
  943. box-sizing: border-box;
  944. font-size: rpx(15); // 默认字体大小
  945. }
  946. .inner-box {
  947. height: 100%;
  948. display: flex;
  949. justify-content: center;
  950. align-items: center;
  951. font-size: rpx(16); // 默认字体大小
  952. }
  953. .left-box {
  954. position: relative;
  955. justify-content: flex-start;
  956. align-items: flex-start;
  957. flex: 1; // 设置左侧盒子占比为 2
  958. cursor: pointer; // 添加鼠标指针样式
  959. }
  960. .box-icon {
  961. width: 100%;
  962. height: 100%;
  963. flex: 1;
  964. display: flex; // 添加 flex 布局
  965. align-items: center; // 垂直居中
  966. color: black; // 设置图标颜色为白色
  967. padding-left: rpx(15);
  968. font-size: rpx(10); // 设置图标大小,可按需调整
  969. z-index: 9999;
  970. }
  971. .box-icon .left-icon {
  972. margin-left: rpx(10);
  973. margin-right: rpx(5); // 设置图标和文字之间的间距 ;
  974. }
  975. .left-box span {
  976. position: absolute;
  977. font-size: rpx(11); // 默认字体大小
  978. color: black;
  979. }
  980. .right-box {
  981. flex: 1;
  982. position: relative; // 添加相对定位;
  983. }
  984. .top-right-box {
  985. position: absolute; // 添加绝对定位
  986. margin-top: rpx(9); // 调整上边距离
  987. margin-right: rpx(50); // 调整右边距离
  988. width: 100%; // 设置盒子宽度,可按需调整
  989. height: 60px; // 设置盒子高度,可按需调整
  990. display: flex;
  991. justify-content: flex-end;
  992. }
  993. .top-right-box {
  994. ::v-deep(.el-input__wrapper) {
  995. background-color: rgb(255, 255, 255, 0.5);
  996. border-radius: rpx(12);
  997. border: white 1px solid;
  998. color: #aaa5c5;
  999. }
  1000. ::v-deep(.el-input__icon) {
  1001. color: #aaa5c5; // 设置输入框图标颜色为白色
  1002. }
  1003. // 添加占位符样式
  1004. ::v-deep(.el-input__inner::placeholder) {
  1005. color: #aaa5c5;
  1006. }
  1007. // 添加输入框文字颜色样式
  1008. ::v-deep(.el-input__inner) {
  1009. color: black;
  1010. }
  1011. }
  1012. // 搜索框
  1013. .search-input {
  1014. width: rpx(100);
  1015. height: rpx(15);
  1016. font-size: rpx(7);
  1017. }
  1018. .box-2 {
  1019. width: 100%;
  1020. flex: 1;
  1021. box-shadow: 0 4px 8px rgba(202, 52, 52, 0.1);
  1022. box-sizing: border-box;
  1023. display: flex; // 确保子元素水平排列
  1024. flex-wrap: wrap; // 允许子元素换行;
  1025. align-content: center; // 顶部对齐;
  1026. cursor: pointer; // 添加鼠标指针样式
  1027. }
  1028. .box-video {
  1029. width: 100%;
  1030. height: rpx(300);
  1031. video.full-box-video {
  1032. // width: 100%;
  1033. height: rpx(280);
  1034. margin: 0 auto;
  1035. border-radius: rpx(12);
  1036. box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
  1037. object-fit: cover;
  1038. // object-fit: contain;
  1039. }
  1040. }
  1041. /* 隐藏 Chrome 视频控件的渐变背景等默认样式 */
  1042. video::-webkit-media-controls-panel {
  1043. background: transparent !important; /* 去掉背景渐变,设为透明 */
  1044. }
  1045. .small-title {
  1046. width: 100%;
  1047. margin-top: rpx(-20);
  1048. height: rpx(20);
  1049. color: black;
  1050. font-size: rpx(10);
  1051. justify-content: center; //使子元素水平居中
  1052. }
  1053. .video-switch {
  1054. width: 100%;
  1055. // height: rpx(50);
  1056. display: flex;
  1057. margin-top: rpx(-20);
  1058. // background-color: saddlebrown;
  1059. }
  1060. .caret-right,
  1061. .caret-left {
  1062. width: rpx(50);
  1063. margin: auto;
  1064. display: flex;
  1065. margin-top: rpx(5);
  1066. margin-bottom: rpx(15);
  1067. }
  1068. .caret-left ::v-deep(.el-button.is-round),
  1069. .caret-right ::v-deep(.el-button.is-round) {
  1070. width: rpx(50);
  1071. height: rpx(15);
  1072. color: #aaa5c5;
  1073. border-radius: none;
  1074. border: 1px white solid;
  1075. background-color: rgb(255, 255, 255, 0.5); // 进度条背景颜色,调浅为半透明白色
  1076. box-shadow: 0 4px 8px rgba(202, 52, 52, 0.1);
  1077. }
  1078. // 儿童风格试题弹框样式
  1079. .child-dialog {
  1080. .el-dialog__header {
  1081. display: none; // 隐藏原有的标题栏
  1082. }
  1083. .el-dialog__body {
  1084. padding: rpx(20);
  1085. position: relative;
  1086. }
  1087. .el-dialog__footer {
  1088. border-top: none;
  1089. padding: rpx(10) rpx(20);
  1090. text-align: center;
  1091. }
  1092. .el-dialog__wrapper {
  1093. // 修改半透明背景色
  1094. background-color: rgba(0, 0, 0, 0.6);
  1095. }
  1096. .el-dialog {
  1097. border: none;
  1098. border-radius: rpx(20);
  1099. background: linear-gradient(
  1100. 135deg,
  1101. $light-color,
  1102. #d8bfd8
  1103. ); // 柔和的蓝紫色渐变
  1104. // 添加边框边晕效果
  1105. box-shadow: 0 0 20px 5px rgba($primary-color, 0.6),
  1106. 0 0 40px 10px rgba($primary-color, 0.4),
  1107. 0 0 60px 15px rgba($primary-color, 0.2);
  1108. overflow: hidden;
  1109. // 添加装饰元素
  1110. &::before {
  1111. content: '';
  1112. position: absolute;
  1113. top: 0;
  1114. left: 0;
  1115. width: 100%;
  1116. height: rpx(10);
  1117. background: linear-gradient(
  1118. 90deg,
  1119. $primary-color,
  1120. $secondary-color,
  1121. $accent-color
  1122. );
  1123. }
  1124. }
  1125. }
  1126. // 问题标题样式
  1127. .question-title {
  1128. background: linear-gradient(
  1129. 90deg,
  1130. rgba($primary-color, 0.2),
  1131. rgba($secondary-color, 0.2)
  1132. );
  1133. padding: rpx(15);
  1134. border-radius: rpx(12);
  1135. margin-bottom: rpx(20);
  1136. color: $accent-color;
  1137. font-weight: bold;
  1138. font-size: rpx(14);
  1139. box-shadow: 0 rpx(3) rpx(10) rgba($primary-color, 0.1);
  1140. position: relative;
  1141. display: flex;
  1142. align-items: center;
  1143. .question-icon {
  1144. background-color: $accent-color;
  1145. color: white;
  1146. width: rpx(24);
  1147. height: rpx(24);
  1148. border-radius: 50%;
  1149. display: flex;
  1150. align-items: center;
  1151. justify-content: center;
  1152. margin-right: rpx(10);
  1153. font-weight: bold;
  1154. box-shadow: 0 rpx(2) rpx(5) rgba($accent-color, 0.3);
  1155. }
  1156. }
  1157. // 选项容器样式
  1158. .options-container {
  1159. margin-bottom: rpx(20);
  1160. }
  1161. // 问题选项样式
  1162. .question-option {
  1163. margin: rpx(8) 0;
  1164. padding: rpx(10) rpx(15);
  1165. border-radius: rpx(12);
  1166. border: rpx(1) solid rgba($primary-color, 0.3);
  1167. transition: all 0.3s ease;
  1168. display: flex;
  1169. align-items: center;
  1170. background-color: white;
  1171. box-shadow: 0 rpx(2) rpx(5) rgba($primary-color, 0.05);
  1172. ::v-deep(.el-radio__label) {
  1173. color: $text-color;
  1174. margin-left: rpx(8);
  1175. flex: 1;
  1176. text-align: left;
  1177. // 增大字体大小
  1178. font-size: rpx(12);
  1179. }
  1180. // 选中时的样式变化
  1181. .el-radio__input.is-checked + .el-radio__label {
  1182. font-weight: bold;
  1183. color: $accent-color;
  1184. }
  1185. &:hover {
  1186. background-color: rgba($primary-color, 0.05);
  1187. border-color: rgba($primary-color, 0.5);
  1188. transform: translateY(-rpx(1));
  1189. }
  1190. }
  1191. // 暂无选项样式
  1192. .no-options {
  1193. color: rgba($text-color, 0.7);
  1194. text-align: center;
  1195. padding: rpx(20);
  1196. font-size: rpx(12);
  1197. }
  1198. // 底部按钮样式
  1199. .child-button {
  1200. min-width: rpx(80);
  1201. height: rpx(30);
  1202. border-radius: rpx(15);
  1203. font-size: rpx(12);
  1204. font-weight: 500;
  1205. transition: all 0.3s ease;
  1206. box-shadow: 0 rpx(2) rpx(8) rgba(0, 0, 0, 0.1);
  1207. &.confirm {
  1208. background: linear-gradient(to right, $primary-color, $secondary-color);
  1209. border: none;
  1210. border-right: 15px;
  1211. color: white;
  1212. &:hover {
  1213. background: linear-gradient(
  1214. to right,
  1215. color.adjust($primary-color, $lightness: -5%),
  1216. color.adjust($secondary-color, $lightness: -5%)
  1217. );
  1218. box-shadow: 0 rpx(3) rpx(10) rgba($primary-color, 0.4);
  1219. transform: translateY(-rpx(1));
  1220. color: white;
  1221. }
  1222. }
  1223. &.cancel {
  1224. background: white;
  1225. border: rpx(1) solid rgba($primary-color, 0.3);
  1226. color: $text-color;
  1227. &:hover {
  1228. background: rgba($primary-color, 0.05);
  1229. border-color: rgba($primary-color, 0.5);
  1230. transform: translateY(-rpx(1));
  1231. }
  1232. }
  1233. }
  1234. // AI对话图标样式
  1235. .ai-icon-container {
  1236. position: absolute;
  1237. bottom: rpx(20);
  1238. right: rpx(20);
  1239. display: flex;
  1240. flex-direction: column;
  1241. align-items: center;
  1242. cursor: pointer;
  1243. transition: all 0.3s ease;
  1244. &:hover {
  1245. transform: translateY(-rpx(2));
  1246. }
  1247. .ai-icon {
  1248. width: rpx(30);
  1249. height: rpx(30);
  1250. margin-bottom: rpx(0);
  1251. filter: drop-shadow(0 rpx(2) rpx(4) rgba($primary-color, 0.3));
  1252. // 添加过渡动画
  1253. transition: transform 0.3s ease;
  1254. }
  1255. // 悬浮时放大效果
  1256. .ai-icon:hover {
  1257. transform: scale(1.5);
  1258. }
  1259. .ai-text {
  1260. color: $text-color;
  1261. font-size: rpx(8);
  1262. background-color: rgba(255, 255, 255, 0.7);
  1263. padding: rpx(2) rpx(5);
  1264. border-radius: rpx(5);
  1265. }
  1266. }
  1267. // AI消息样式
  1268. .ai-message {
  1269. display: flex;
  1270. align-items: flex-start;
  1271. margin-bottom: rpx(15);
  1272. .ai-avatar {
  1273. width: rpx(30);
  1274. height: rpx(30);
  1275. border-radius: 50%;
  1276. margin-right: rpx(10);
  1277. background-color: $primary-color;
  1278. padding: rpx(5);
  1279. box-shadow: 0 rpx(2) rpx(5) rgba($primary-color, 0.2);
  1280. }
  1281. .ai-text-content {
  1282. background-color: $light-color;
  1283. padding: rpx(8) rpx(12);
  1284. border-radius: rpx(10);
  1285. font-size: rpx(10);
  1286. color: $text-color;
  1287. max-width: 80%;
  1288. box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
  1289. }
  1290. }
  1291. // 用户输入框样式
  1292. .user-input {
  1293. ::v-deep(.el-input__wrapper) {
  1294. border-radius: rpx(15);
  1295. border-color: rgba($primary-color, 0.3);
  1296. margin-right: 10px;
  1297. &:focus-within {
  1298. box-shadow: 0 0 0 rpx(1) rgba($primary-color, 0.5);
  1299. }
  1300. }
  1301. ::v-deep(.el-input__inner) {
  1302. font-size: rpx(10);
  1303. color: $text-color;
  1304. text-indent: 1em;
  1305. }
  1306. }
  1307. /* 定义淡入和缩放动画 */
  1308. .fade-scale-enter-active,
  1309. .fade-scale-leave-active {
  1310. transition: all 0.5s ease;
  1311. }
  1312. .fade-scale-enter-from,
  1313. .fade-scale-leave-to {
  1314. opacity: 0.1;
  1315. transform: scale(0.9);
  1316. }
  1317. // 自定义试题弹框背景
  1318. .child-dialog-wrapper {
  1319. position: fixed;
  1320. top: 0;
  1321. left: 0;
  1322. right: 0;
  1323. bottom: 0;
  1324. background-color: rgba(0, 0, 0, 0.6); // 半透明背景
  1325. display: flex;
  1326. justify-content: center;
  1327. align-items: center;
  1328. z-index: 1000;
  1329. }
  1330. .child-dialog {
  1331. border: none;
  1332. border-radius: rpx(20);
  1333. background: linear-gradient(
  1334. 135deg,
  1335. $light-color,
  1336. #d8bfd8
  1337. ); // 柔和的蓝紫色渐变
  1338. box-shadow: 0 0 20px 5px rgba($primary-color, 0.6),
  1339. 0 0 40px 10px rgba($primary-color, 0.4),
  1340. 0 0 60px 15px rgba($primary-color, 0.2);
  1341. overflow: hidden;
  1342. padding: rpx(20);
  1343. width: 60%;
  1344. position: relative;
  1345. }
  1346. // AI对话弹框样式
  1347. .ai-dialog-wrapper {
  1348. position: fixed;
  1349. top: 0;
  1350. left: 0;
  1351. right: 0;
  1352. bottom: 0;
  1353. display: flex;
  1354. justify-content: flex-end;
  1355. align-items: center;
  1356. z-index: 1001;
  1357. pointer-events: none;
  1358. }
  1359. .ai-dialog {
  1360. border: none;
  1361. border-radius: rpx(20);
  1362. background: linear-gradient(135deg, $light-color, #d8bfd8);
  1363. box-shadow: 0 0 20px 5px rgba($primary-color, 0.6),
  1364. 0 0 40px 10px rgba($primary-color, 0.4),
  1365. 0 0 60px 15px rgba($primary-color, 0.2);
  1366. overflow: hidden;
  1367. padding: rpx(20);
  1368. width: 30%;
  1369. // 增加高度
  1370. height: 80%;
  1371. margin-right: rpx(50);
  1372. pointer-events: auto;
  1373. position: relative;
  1374. display: flex;
  1375. flex-direction: column;
  1376. &::before {
  1377. content: '';
  1378. position: absolute;
  1379. top: 0;
  1380. left: 0;
  1381. width: 100%;
  1382. height: rpx(10);
  1383. background: linear-gradient(
  1384. 90deg,
  1385. $primary-color,
  1386. $secondary-color,
  1387. $accent-color
  1388. );
  1389. }
  1390. }
  1391. .ai-dialog-header {
  1392. display: flex;
  1393. justify-content: space-between;
  1394. align-items: center;
  1395. margin-bottom: rpx(15);
  1396. h3 {
  1397. color: $text-color;
  1398. font-size: rpx(12);
  1399. }
  1400. .close-btn {
  1401. padding: 0;
  1402. width: rpx(20);
  1403. height: rpx(20);
  1404. font-size: rpx(16);
  1405. line-height: 1;
  1406. }
  1407. }
  1408. .ai-dialog-content {
  1409. flex: 1;
  1410. display: flex;
  1411. flex-direction: column;
  1412. }
  1413. .ai-message-history {
  1414. flex: 1;
  1415. // 当内容超出容器高度时,显示垂直滚动条
  1416. overflow-y: auto;
  1417. margin-bottom: rpx(15);
  1418. // 可以根据实际情况调整最大高度
  1419. max-height: 50vh;
  1420. padding: 5px 10px;
  1421. .message {
  1422. display: flex;
  1423. align-items: flex-start;
  1424. margin-bottom: rpx(10);
  1425. &.user {
  1426. flex-direction: row-reverse;
  1427. }
  1428. .avatar {
  1429. width: rpx(30);
  1430. height: rpx(30);
  1431. border-radius: 50%;
  1432. margin: 0 rpx(10);
  1433. }
  1434. .user {
  1435. width: 15px;
  1436. height: 15px;
  1437. }
  1438. .message-content {
  1439. background-color: $light-color;
  1440. padding: rpx(8) rpx(12);
  1441. border-radius: rpx(10);
  1442. font-size: rpx(10);
  1443. color: $text-color;
  1444. max-width: 80%;
  1445. box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
  1446. }
  1447. }
  1448. // 滚动条整体样式
  1449. &::-webkit-scrollbar {
  1450. width: rpx(4); // 滚动条宽度
  1451. }
  1452. // 滚动条滑块样式
  1453. &::-webkit-scrollbar-thumb {
  1454. background-color: $primary-color; // 滑块颜色
  1455. border-radius: rpx(4); // 滑块圆角
  1456. transition: background-color 0.3s ease; // 颜色过渡效果
  1457. &:hover {
  1458. //background-color: darken($primary-color, 10%); // 悬停时滑块颜色加深
  1459. }
  1460. }
  1461. // 滚动条轨道样式
  1462. &::-webkit-scrollbar-track {
  1463. background-color: rgba($primary-color, 0.2); // 轨道颜色
  1464. border-radius: rpx(4); // 轨道圆角
  1465. }
  1466. .message {
  1467. display: flex;
  1468. align-items: flex-start;
  1469. margin-bottom: rpx(10);
  1470. &.user {
  1471. flex-direction: row-reverse;
  1472. }
  1473. .avatar {
  1474. width: rpx(30);
  1475. height: rpx(30);
  1476. border-radius: 50%;
  1477. margin: 0 rpx(10);
  1478. }
  1479. .message-content {
  1480. background-color: $light-color;
  1481. padding: rpx(8) rpx(12);
  1482. border-radius: rpx(10);
  1483. font-size: rpx(10);
  1484. color: $text-color;
  1485. max-width: 80%;
  1486. box-shadow: 0 rpx(1) rpx(3) rgba(0, 0, 0, 0.05);
  1487. }
  1488. }
  1489. }
  1490. // 优化发送按钮样式
  1491. .send-button {
  1492. //background: linear-gradient(90deg, $primary-color, $secondary-color);
  1493. border: none;
  1494. color: white;
  1495. &:hover {
  1496. //background: linear-gradient(90deg, darken($primary-color, 5%), darken($secondary-color, 5%));
  1497. }
  1498. }
  1499. </style>