jack 1 ay önce
ebeveyn
işleme
e934e93735

+ 117 - 94
src/App.vue

@@ -1,10 +1,27 @@
 <template>
   <template v-if="slides.length">
-    <Screen v-if="viewMode !== 'student'" v-show="screening"/>
-    <Editor v-if="viewMode === 'editor'" v-show="_isPC && !screening" :courseid="urlParams.courseid"/>
-    <Editor2 v-else-if="viewMode === 'editor2'" v-show="_isPC && !screening" :courseid="urlParams.courseid"/>
-    <Editor3 v-else-if="viewMode === 'editor3'" v-show="_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" />
+    <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" />
@@ -13,128 +30,132 @@
 
 
 <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())
+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'
+  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 === "editor2") {
+    return "editor2";
   }
 
-  if (modeFromUrl === 'editor3') {
-    return 'editor3'
+  if (modeFromUrl === "editor3") {
+    return "editor3";
   }
   // 检查localStorage
-  const modeFromStorage = localStorage.getItem('viewMode')
+  const modeFromStorage = localStorage.getItem("viewMode");
   if (modeFromStorage) {
-    return modeFromStorage
+    return modeFromStorage;
   }
-  
+
   // 默认返回编辑模式
-  return 'editor'
-}
+  return "editor";
+};
 
 // 获取URL参数中的courseid和type
 const getUrlParams = () => {
-  const urlParams = new URLSearchParams(window.location.search)
+  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')
-  }
-}
+    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 urlParams = getUrlParams();
 
-const viewMode = ref(getInitialViewMode())
+const viewMode = ref(getInitialViewMode());
 
 // 全局切换视图模式的函数
 const switchViewMode = (mode: string) => {
-  viewMode.value = mode
-  localStorage.setItem('viewMode', mode)
-  
+  viewMode.value = mode;
+  localStorage.setItem("viewMode", mode);
+
   // 更新URL参数
-  const url = new URL(window.location.href)
-  if (mode === 'student') {
-    url.searchParams.set('mode', 'student')
+  const url = new URL(window.location.href);
+  if (mode === "student") {
+    url.searchParams.set("mode", "student");
+  } else {
+    url.searchParams.delete("mode");
   }
-  else {
-    url.searchParams.delete('mode')
-  }
-  
+
   // 使用 history.pushState 更新URL,不刷新页面
-  window.history.pushState({}, '', url.toString())
-}
+  window.history.pushState({}, "", url.toString());
+};
 
 // 使用provide提供切换函数,供子组件调用
-provide('switchViewMode', switchViewMode)
+provide("switchViewMode", switchViewMode);
 
-if (import.meta.env.MODE !== 'development') {
-  window.onbeforeunload = () => false
+if (import.meta.env.MODE !== "development") {
+  window.onbeforeunload = () => false;
 }
 
 onMounted(async () => {
-  const slides = await api.getFileData('slides')
-  console.log(slides) 
-  slidesStore.setSlides(slides)
+  const slides = await api.getFileData("slides");
+  console.log(slides);
+  slidesStore.setSlides(slides);
   // 初始化快照数据库
   // await deleteDiscardedDB()
   // snapshotStore.initSnapshotDatabase()
-  
+
   // 监听视图模式切换事件
-  window.addEventListener('viewModeChanged', (event: any) => {
+  window.addEventListener("viewModeChanged", (event: any) => {
     if (event.detail) {
-      switchViewMode(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) : []
+window.addEventListener("beforeunload", () => {
+  const discardedDB = localStorage.getItem(LOCALSTORAGE_KEY_DISCARDED_DB);
+  const discardedDBList: string[] = discardedDB ? JSON.parse(discardedDB) : [];
 
-  discardedDBList.push(databaseId.value)
+  discardedDBList.push(databaseId.value);
 
-  const newDiscardedDB = JSON.stringify(discardedDBList)
-  localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB)
-})
+  const newDiscardedDB = JSON.stringify(discardedDBList);
+  localStorage.setItem(LOCALSTORAGE_KEY_DISCARDED_DB, newDiscardedDB);
+});
 </script>
 
 <style lang="scss">
@@ -145,7 +166,7 @@ window.addEventListener('beforeunload', () => {
 .image-preview {
   position: fixed;
   inset: 0;
-  background: rgba(0,0,0,.85);
+  background: rgba(0, 0, 0, 0.85);
   display: flex;
   flex-direction: column;
   z-index: 6000;
@@ -164,20 +185,20 @@ window.addEventListener('beforeunload', () => {
   color: #fff;
   border-radius: 10px;
   cursor: pointer;
-  transition: transform .15s ease, box-shadow .2s ease, background .2s ease;
-  box-shadow: 0 2px 8px rgba(47,128,237,.3);
+  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,.35);
+  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,.28);
+  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,.6);
+  outline: 2px solid rgba(47, 128, 237, 0.6);
   outline-offset: 2px;
 }
 .image-preview__stage {
@@ -187,12 +208,14 @@ window.addEventListener('beforeunload', () => {
   justify-content: center;
   cursor: grab;
 }
-.image-preview__stage:active { cursor: grabbing; }
+.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,.3);
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
   user-select: none;
   will-change: transform;
 }

+ 2 - 4
src/views/components/element/ShapeElement/BaseShapeElement.vue

@@ -30,9 +30,7 @@
           <defs>
             <PatternDefs
               v-if="elementInfo.pattern"
-              :width="elementInfo.width"
-              :height="elementInfo.height"
-              :id="`ebase-pattern-${elementInfo.id}`" 
+              :id="`base-pattern-${elementInfo.id}`" 
               :src="elementInfo.pattern"
             />
             <GradientDefs
@@ -88,7 +86,7 @@ const props = defineProps<{
 const { theme } = storeToRefs(useSlidesStore())
 
 const element = computed(() => props.elementInfo)
-const { fill } = useElementFill(element, 'ebase')
+const { fill } = useElementFill(element, 'base')
 
 const outline = computed(() => props.elementInfo.outline)
 const { outlineWidth, outlineColor, strokeDashArray } = useElementOutline(outline)