| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- <template>
- <template v-if="slides.length">
- <Screen v-if="viewMode !== 'student' && screening" />
- <Editor
- v-if="viewMode === 'editor' && _isPC && !screening"
- :courseid="urlParams.courseid"
- />
- <Editor2
- v-else-if="viewMode === 'editor2' && _isPC && !screening"
- :courseid="urlParams.courseid"
- />
- <Editor3
- v-else-if="viewMode === 'editor3' && _isPC && !screening"
- :courseid="urlParams.courseid"
- />
- <Student
- v-else-if="viewMode === 'student'"
- :courseid="urlParams.courseid"
- :type="urlParams.type"
- :userid="urlParams.userid"
- :oid="urlParams.oid"
- :org="urlParams.org"
- :cid="urlParams.cid"
- />
- <Mobile v-else />
- </template>
- <FullscreenSpin :tip="lang.ssInitDataWait" v-else loading :mask="false" />
- </template>
- <script lang="ts" setup>
- import { onMounted, ref, provide } from "vue";
- import { storeToRefs } from "pinia";
- import {
- useScreenStore,
- useMainStore,
- useSnapshotStore,
- useSlidesStore,
- } from "@/store";
- import { lang } from "@/main";
- import { LOCALSTORAGE_KEY_DISCARDED_DB } from "@/configs/storage";
- import { deleteDiscardedDB } from "@/utils/database";
- import { isPC } from "@/utils/common";
- import api from "@/services";
- import Editor from "./views/Editor/index.vue";
- import Editor2 from "./views/Editor/index2.vue";
- import Editor3 from "./views/Editor/index3.vue";
- import Screen from "./views/Screen/index.vue";
- import Mobile from "./views/Mobile/index.vue";
- import Student from "./views/Student/index.vue";
- import FullscreenSpin from "@/components/FullscreenSpin.vue";
- const _isPC = isPC();
- const mainStore = useMainStore();
- const slidesStore = useSlidesStore();
- const snapshotStore = useSnapshotStore();
- const { databaseId } = storeToRefs(mainStore);
- const { slides } = storeToRefs(slidesStore);
- const { screening } = storeToRefs(useScreenStore());
- // 视图模式:'editor', 'student', 'screen'
- // 支持通过URL参数直接访问学生模式
- const getInitialViewMode = () => {
- // 检查URL参数
- const urlParams = new URLSearchParams(window.location.search);
- const modeFromUrl = urlParams.get("mode");
- console.log(modeFromUrl);
- if (modeFromUrl === "student") {
- return "student";
- }
- if (modeFromUrl === "editor2") {
- return "editor2";
- }
- if (modeFromUrl === "editor3") {
- return "editor3";
- }
- // 检查localStorage
- const modeFromStorage = localStorage.getItem("viewMode");
- if (modeFromStorage) {
- return modeFromStorage;
- }
- // 默认返回编辑模式
- return "editor";
- };
- // 获取URL参数中的courseid和type
- const getUrlParams = () => {
- const urlParams = new URLSearchParams(window.location.search);
- return {
- courseid: urlParams.get("courseid"),
- userid: urlParams.get("userid"),
- oid: urlParams.get("oid"),
- org: urlParams.get("org"),
- cid: urlParams.get("cid"),
- type: urlParams.get("type"),
- };
- };
- const urlParams = getUrlParams();
- const viewMode = ref(getInitialViewMode());
- // 全局切换视图模式的函数
- const switchViewMode = (mode: string) => {
- viewMode.value = mode;
- localStorage.setItem("viewMode", mode);
- // 更新URL参数
- const url = new URL(window.location.href);
- if (mode === "student") {
- url.searchParams.set("mode", "student");
- } else {
- url.searchParams.delete("mode");
- }
- // 使用 history.pushState 更新URL,不刷新页面
- window.history.pushState({}, "", url.toString());
- };
- // 使用provide提供切换函数,供子组件调用
- provide("switchViewMode", switchViewMode);
- if (import.meta.env.MODE !== "development") {
- window.onbeforeunload = () => false;
- }
- onMounted(async () => {
- const slides = await api.getFileData("slides");
- console.log(slides);
- slidesStore.setSlides(slides);
- // 初始化快照数据库
- // await deleteDiscardedDB()
- // snapshotStore.initSnapshotDatabase()
- // 监听视图模式切换事件
- window.addEventListener("viewModeChanged", (event: any) => {
- if (event.detail) {
- switchViewMode(event.detail);
- }
- });
- });
- // 应用注销时向 localStorage 中记录下本次 indexedDB 的数据库ID,用于之后清除数据库
- window.addEventListener("beforeunload", () => {
- const discardedDB = localStorage.getItem(LOCALSTORAGE_KEY_DISCARDED_DB);
- const discardedDBList: string[] = discardedDB ? JSON.parse(discardedDB) : [];
- discardedDBList.push(databaseId.value);
- const newDiscardedDB = JSON.stringify(discardedDBList);
- localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB);
- });
- </script>
- <style lang="scss">
- #app {
- height: 100%;
- }
- .image-preview {
- position: fixed;
- inset: 0;
- background: rgba(0, 0, 0, 0.85);
- display: flex;
- flex-direction: column;
- z-index: 6000;
- }
- .image-preview__toolbar {
- display: flex;
- gap: 8px;
- padding: 10px;
- justify-content: center;
- z-index: 9999;
- }
- .image-preview__toolbar button {
- padding: 8px 12px;
- border: none;
- background: linear-gradient(180deg, #3a8bff 0%, #2f80ed 100%);
- color: #fff;
- border-radius: 10px;
- cursor: pointer;
- transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease;
- box-shadow: 0 2px 8px rgba(47, 128, 237, 0.3);
- }
- .image-preview__toolbar button:hover {
- transform: translateY(-1px);
- box-shadow: 0 6px 16px rgba(47, 128, 237, 0.35);
- }
- .image-preview__toolbar button:active {
- transform: translateY(0);
- box-shadow: 0 2px 8px rgba(47, 128, 237, 0.28);
- background: linear-gradient(180deg, #2f80ed 0%, #1b6dde 100%);
- }
- .image-preview__toolbar button:focus-visible {
- outline: 2px solid rgba(47, 128, 237, 0.6);
- outline-offset: 2px;
- }
- .image-preview__stage {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: grab;
- }
- .image-preview__stage:active {
- cursor: grabbing;
- }
- .image-preview__img {
- max-width: 92vw;
- max-height: 92vh;
- border-radius: 8px;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
- user-select: none;
- will-change: transform;
- }
- </style>
|