App.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <template v-if="slides.length">
  3. <Screen v-if="screening" />
  4. <Student v-else-if="viewMode === 'student'" :courseid="urlParams.courseid" :type="urlParams.type" />
  5. <Editor v-else-if="_isPC" />
  6. <Mobile v-else />
  7. </template>
  8. <FullscreenSpin tip="数据初始化中,请稍等 ..." v-else loading :mask="false" />
  9. </template>
  10. <script lang="ts" setup>
  11. import { onMounted, ref, provide } from 'vue'
  12. import { storeToRefs } from 'pinia'
  13. import { useScreenStore, useMainStore, useSnapshotStore, useSlidesStore } from '@/store'
  14. import { LOCALSTORAGE_KEY_DISCARDED_DB } from '@/configs/storage'
  15. import { deleteDiscardedDB } from '@/utils/database'
  16. import { isPC } from '@/utils/common'
  17. import api from '@/services'
  18. import Editor from './views/Editor/index.vue'
  19. import Screen from './views/Screen/index.vue'
  20. import Mobile from './views/Mobile/index.vue'
  21. import Student from './views/Student/index.vue'
  22. import FullscreenSpin from '@/components/FullscreenSpin.vue'
  23. const _isPC = isPC()
  24. const mainStore = useMainStore()
  25. const slidesStore = useSlidesStore()
  26. const snapshotStore = useSnapshotStore()
  27. const { databaseId } = storeToRefs(mainStore)
  28. const { slides } = storeToRefs(slidesStore)
  29. const { screening } = storeToRefs(useScreenStore())
  30. // 视图模式:'editor', 'student', 'screen'
  31. // 支持通过URL参数直接访问学生模式
  32. const getInitialViewMode = () => {
  33. // 检查URL参数
  34. const urlParams = new URLSearchParams(window.location.search)
  35. const modeFromUrl = urlParams.get('mode')
  36. if (modeFromUrl === 'student') {
  37. return 'student'
  38. }
  39. // 检查localStorage
  40. const modeFromStorage = localStorage.getItem('viewMode')
  41. if (modeFromStorage) {
  42. return modeFromStorage
  43. }
  44. // 默认返回编辑模式
  45. return 'editor'
  46. }
  47. // 获取URL参数中的courseid和type
  48. const getUrlParams = () => {
  49. const urlParams = new URLSearchParams(window.location.search)
  50. return {
  51. courseid: urlParams.get('courseid'),
  52. type: urlParams.get('type')
  53. }
  54. }
  55. const urlParams = getUrlParams()
  56. const viewMode = ref(getInitialViewMode())
  57. // 全局切换视图模式的函数
  58. const switchViewMode = (mode: string) => {
  59. viewMode.value = mode
  60. localStorage.setItem('viewMode', mode)
  61. // 更新URL参数
  62. const url = new URL(window.location.href)
  63. if (mode === 'student') {
  64. url.searchParams.set('mode', 'student')
  65. }
  66. else {
  67. url.searchParams.delete('mode')
  68. }
  69. // 使用 history.pushState 更新URL,不刷新页面
  70. window.history.pushState({}, '', url.toString())
  71. }
  72. // 使用provide提供切换函数,供子组件调用
  73. provide('switchViewMode', switchViewMode)
  74. if (import.meta.env.MODE !== 'development') {
  75. window.onbeforeunload = () => false
  76. }
  77. onMounted(async () => {
  78. const slides = await api.getFileData('slides')
  79. slidesStore.setSlides(slides)
  80. await deleteDiscardedDB()
  81. snapshotStore.initSnapshotDatabase()
  82. // 监听视图模式切换事件
  83. window.addEventListener('viewModeChanged', (event: any) => {
  84. if (event.detail) {
  85. switchViewMode(event.detail)
  86. }
  87. })
  88. })
  89. // 应用注销时向 localStorage 中记录下本次 indexedDB 的数据库ID,用于之后清除数据库
  90. window.addEventListener('beforeunload', () => {
  91. const discardedDB = localStorage.getItem(LOCALSTORAGE_KEY_DISCARDED_DB)
  92. const discardedDBList: string[] = discardedDB ? JSON.parse(discardedDB) : []
  93. discardedDBList.push(databaseId.value)
  94. const newDiscardedDB = JSON.stringify(discardedDBList)
  95. localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB)
  96. })
  97. </script>
  98. <style lang="scss">
  99. #app {
  100. height: 100%;
  101. }
  102. </style>