Просмотр исходного кода

feat(editor-en): 单页展示模式,只保留英语口语工具

jimmylee 1 день назад
Родитель
Сommit
97ca4824fa

+ 4 - 4
src/App.vue

@@ -19,10 +19,10 @@
         key="editor3"
         key="editor3"
       />
       />
       <EditorEn
       <EditorEn
-        v-else-if="viewMode === 'editorEn' && _isPC && !screening"
+        v-else-if="viewMode === 'editor-en' && _isPC && !screening"
         :courseid="urlParams.courseid"
         :courseid="urlParams.courseid"
         :userid="urlParams.userid"
         :userid="urlParams.userid"
-        key="editorEn"
+        key="editor-en"
       />
       />
       <Student
       <Student
         v-else-if="viewMode === 'student'"
         v-else-if="viewMode === 'student'"
@@ -94,8 +94,8 @@ const getInitialViewMode = () => {
     return 'editor3'
     return 'editor3'
   }
   }
   
   
-  if (modeFromUrl === 'editorEn') {
-    return 'editorEn'
+  if (modeFromUrl === 'editor-en') {
+    return 'editor-en'
   }
   }
 
 
   // 检查localStorage
   // 检查localStorage

+ 17 - 8
src/components/CollapsibleToolbar/index2.vue

@@ -2,7 +2,8 @@
   <div class="collapsible-toolbar" :class="{ collapsed: isCollapsed }">
   <div class="collapsible-toolbar" :class="{ collapsed: isCollapsed }">
     <div class="toolbar-content" v-show="!isCollapsed">
     <div class="toolbar-content" v-show="!isCollapsed">
       <div class="sidebar-content">
       <div class="sidebar-content">
-        <div class="sidebar-item feature-sidebar-item" :class="{ active: activeSubmenu === 'cocoai' }"
+        <div class="sidebar-item feature-sidebar-item" v-if="!onlyEnglish"
+          :class="{ active: activeSubmenu === 'cocoai' }"
           @click="toggleSubmenu('cocoai')">
           @click="toggleSubmenu('cocoai')">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <path d="M12 2L2 7l10 5 10-5-10-5z"></path>
             <path d="M12 2L2 7l10 5 10-5-10-5z"></path>
@@ -11,7 +12,8 @@
           </svg>
           </svg>
           <span class="item-label">Coco AI</span>
           <span class="item-label">Coco AI</span>
         </div>
         </div>
-        <div class="sidebar-item feature-sidebar-item" :class="{ active: activeSubmenu === 'uploadFile' }"
+        <div class="sidebar-item feature-sidebar-item" v-if="!onlyEnglish"
+          :class="{ active: activeSubmenu === 'uploadFile' }"
           @click="toggleSubmenu('uploadFile')">
           @click="toggleSubmenu('uploadFile')">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <path d="M12 16V4"></path>
             <path d="M12 16V4"></path>
@@ -21,7 +23,7 @@
           </svg>
           </svg>
           <span class="item-label">{{ lang.ssUploadFile }}</span>
           <span class="item-label">{{ lang.ssUploadFile }}</span>
         </div>
         </div>
-        <div class="sidebar-divider"></div>
+        <div class="sidebar-divider" v-if="!onlyEnglish"></div>
         <!-- <div class="sidebar-item" :class="{ active: activeSubmenu === 'page' }" @click="toggleSubmenu('page')">
         <!-- <div class="sidebar-item" :class="{ active: activeSubmenu === 'page' }" @click="toggleSubmenu('page')">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
             <g id="Component 1">
             <g id="Component 1">
@@ -33,7 +35,7 @@
           </svg>
           </svg>
           <span class="item-label">{{ lang.ssPage }}</span>
           <span class="item-label">{{ lang.ssPage }}</span>
         </div> -->
         </div> -->
-        <div class="sidebar-item" :class="{ active: activeSubmenu === 'interactive' }"
+        <div class="sidebar-item" v-if="!onlyEnglish" :class="{ active: activeSubmenu === 'interactive' }"
           @click="toggleSubmenu('interactive')">
           @click="toggleSubmenu('interactive')">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
             <g id="Frame">
             <g id="Frame">
@@ -47,7 +49,8 @@
           </svg>
           </svg>
           <span class="item-label">{{ lang.ssInteract }}</span>
           <span class="item-label">{{ lang.ssInteract }}</span>
         </div>
         </div>
-        <div class="sidebar-item" :class="{ active: activeSubmenu === 'aiapp' }" @click="toggleSubmenu('aiapp')">
+        <div class="sidebar-item" v-if="!onlyEnglish" :class="{ active: activeSubmenu === 'aiapp' }"
+          @click="toggleSubmenu('aiapp')">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <rect x="3" y="3" width="7" height="7" />
             <rect x="3" y="3" width="7" height="7" />
             <rect x="14" y="3" width="7" height="7" />
             <rect x="14" y="3" width="7" height="7" />
@@ -56,7 +59,8 @@
           </svg>
           </svg>
           <span class="item-label">{{ lang.ssAiApp }}</span>
           <span class="item-label">{{ lang.ssAiApp }}</span>
         </div>
         </div>
-        <div class="sidebar-item" :class="{ active: activeSubmenu === 'h5page' }" @click="toggleSubmenu('h5page')">
+        <div class="sidebar-item" v-if="!onlyEnglish" :class="{ active: activeSubmenu === 'h5page' }"
+          @click="toggleSubmenu('h5page')">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
           <svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <circle cx="12" cy="12" r="10" />
             <circle cx="12" cy="12" r="10" />
             <path d="M2 12h20" />
             <path d="M2 12h20" />
@@ -79,7 +83,7 @@
           </svg>
           </svg>
           <span class="item-label">{{ lang.ssCreative }}</span>
           <span class="item-label">{{ lang.ssCreative }}</span>
         </div> -->
         </div> -->
-        <div class="sidebar-item" :class="{ active: activeSubmenu === 'multimedia' }"
+        <div class="sidebar-item" v-if="!onlyEnglish" :class="{ active: activeSubmenu === 'multimedia' }"
           @click="toggleSubmenu('multimedia')">
           @click="toggleSubmenu('multimedia')">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
           <svg class="item-icon" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
             <g id="Component 1">
             <g id="Component 1">
@@ -745,10 +749,14 @@ const props = withDefaults(defineProps<{
   defaultCollapsed?: boolean
   defaultCollapsed?: boolean
   userid?: string | null
   userid?: string | null
   courseTitle?: string | null
   courseTitle?: string | null
+  // 只保留英语口语这一项工具,其余侧边栏入口全部隐藏(EditorEn 展示页用)。
+  // 默认 false,index3 等现役编辑器走默认分支,行为不变。
+  onlyEnglish?: boolean
 }>(), {
 }>(), {
   defaultCollapsed: false,
   defaultCollapsed: false,
   userid: null,
   userid: null,
   courseTitle: null,
   courseTitle: null,
+  onlyEnglish: false,
 })
 })
 
 
 
 
@@ -766,7 +774,8 @@ const emit = defineEmits<{
 }>()
 }>()
 
 
 const isCollapsed = ref(props.defaultCollapsed)
 const isCollapsed = ref(props.defaultCollapsed)
-const activeSubmenu = ref<string | null>(null)
+// onlyEnglish 时侧边栏只剩英语一项,收着让人先点一下没有意义,直接展开
+const activeSubmenu = ref<string | null>(props.onlyEnglish ? 'english' : null)
 const contentList = ref<ContentItem[]>([])
 const contentList = ref<ContentItem[]>([])
 const hoveredTool = ref<string | null>(null)
 const hoveredTool = ref<string | null>(null)
 const webpageUrl = ref('')
 const webpageUrl = ref('')

+ 10 - 0
src/hooks/useAddSlidesOrElements.ts

@@ -1,7 +1,9 @@
+import { inject } from 'vue'
 import { storeToRefs } from 'pinia'
 import { storeToRefs } from 'pinia'
 import { nanoid } from 'nanoid'
 import { nanoid } from 'nanoid'
 import { useSlidesStore, useMainStore } from '@/store'
 import { useSlidesStore, useMainStore } from '@/store'
 import type { PPTElement, Slide } from '@/types/slides'
 import type { PPTElement, Slide } from '@/types/slides'
+import { injectKeySingleSlideMode } from '@/types/injectKey'
 import { createSlideIdMap, createElementIdMap, getElementRange } from '@/utils/element'
 import { createSlideIdMap, createElementIdMap, getElementRange } from '@/utils/element'
 import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 
@@ -10,6 +12,9 @@ export default () => {
   const slidesStore = useSlidesStore()
   const slidesStore = useSlidesStore()
   const { currentSlide } = storeToRefs(slidesStore)
   const { currentSlide } = storeToRefs(slidesStore)
 
 
+  // 由 indexEn.vue provide;其余编辑器没有 provide,这里拿到 default false
+  const singleSlideMode = inject(injectKeySingleSlideMode, false)
+
   const { addHistorySnapshot } = useHistorySnapshot()
   const { addHistorySnapshot } = useHistorySnapshot()
 
 
   /**
   /**
@@ -64,6 +69,11 @@ export default () => {
    * @param slide 页面数据
    * @param slide 页面数据
    */
    */
   const addSlidesFromData = (slides: Slide[]) => {
   const addSlidesFromData = (slides: Slide[]) => {
+    // 单页模式下唯一还能加出第二页的入口:Ctrl+V 粘贴整页数据(Thumbnails 的右键
+    // 菜单已经随缩略图一起隐藏,但 usePasteEvent 仍然活着),以及 useAIPPT 的批量加页。
+    // 两条路都经过这里,一道守卫全封住。
+    if (singleSlideMode) return
+
     const slideIdMap = createSlideIdMap(slides)
     const slideIdMap = createSlideIdMap(slides)
     const newSlides = slides.map(slide => {
     const newSlides = slides.map(slide => {
       const { groupIdMap, elIdMap } = createElementIdMap(slide.elements)
       const { groupIdMap, elIdMap } = createElementIdMap(slide.elements)

+ 21 - 0
src/hooks/useSlideHandler.ts

@@ -91,6 +91,26 @@ export default () => {
     addHistorySnapshot()
     addHistorySnapshot()
   }
   }
 
 
+  // 用一页全新的空白页替换掉当前全部页面(单页模式下代替 createSlide 使用)
+  //
+  // 刻意做成一次赋值而不是「先 createSlide 再 deleteSlide 旧页」:
+  // 1. setSlides 是原子的,不存在「新页建好了但旧页没删掉」这种中间态;
+  // 2. 不在这里存快照,让后续 createElement 那一笔成为唯一的一笔,Ctrl+Z 一次回到原状;
+  // 3. 新页保证是空的,createFrameElement 里「当前页已有 frame 就拒绝插入」的守卫必定放行。
+  const replaceAllSlidesWithNew = () => {
+    const emptySlide: Slide = {
+      id: nanoid(10),
+      elements: [],
+      background: {
+        type: 'solid',
+        color: theme.value.backgroundColor,
+      },
+    }
+    mainStore.setActiveElementIdList([])
+    slidesStore.setSlides([emptySlide])
+    slidesStore.updateSlideIndex(0)
+  }
+
   // 根据模板创建新页面
   // 根据模板创建新页面
   const createSlideByTemplate = (slide: Slide) => {
   const createSlideByTemplate = (slide: Slide) => {
     const { groupIdMap, elIdMap } = createElementIdMap(slide.elements)
     const { groupIdMap, elIdMap } = createElementIdMap(slide.elements)
@@ -207,6 +227,7 @@ export default () => {
     copySlide,
     copySlide,
     pasteSlide,
     pasteSlide,
     createSlide,
     createSlide,
+    replaceAllSlidesWithNew,
     createSlideByTemplate,
     createSlideByTemplate,
     copyAndPasteSlide,
     copyAndPasteSlide,
     deleteSlide,
     deleteSlide,

+ 15 - 1
src/types/injectKey.ts

@@ -9,4 +9,18 @@ export type RadioGroupValue = {
 
 
 export const injectKeySlideScale: InjectionKey<SlideScale> = Symbol()
 export const injectKeySlideScale: InjectionKey<SlideScale> = Symbol()
 export const injectKeySlideId: InjectionKey<SlideId> = Symbol()
 export const injectKeySlideId: InjectionKey<SlideId> = Symbol()
-export const injectKeyRadioGroupValue: InjectionKey<RadioGroupValue> = Symbol()
+export const injectKeyRadioGroupValue: InjectionKey<RadioGroupValue> = Symbol()
+
+/**
+ * 单页模式。EditorEn(英语展示页)专用:整个编辑器只允许存在一页,
+ * 插入口语工具时用「替换当前全部页面」代替「新增一页」。
+ *
+ * provide:views/Editor/indexEn.vue
+ * inject :EnglishSpeaking/layers/Layer2Speaking.vue —— 建页分支
+ *          hooks/useAddSlidesOrElements.ts —— 挡住 Ctrl+V 贴页 / AIPPT 批量加页
+ *
+ * 其余编辑器(index / index2 / index3)不 provide,inject 一律拿到 default false,
+ * 行为与今天完全一致。因为是 provide 而不是全局 store,值随 EditorEn 一起消失,
+ * 不存在「切走之后旗标还留着」的问题。
+ */
+export const injectKeySingleSlideMode: InjectionKey<boolean> = Symbol()

+ 22 - 4
src/views/Editor/EnglishSpeaking/layers/Layer2Speaking.vue

@@ -74,11 +74,12 @@
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { ref, computed } from 'vue'
+import { ref, computed, inject } from 'vue'
 import { lang } from '@/main'
 import { lang } from '@/main'
 import type { CreationMode, SpeakingRecommendationTask, TopicDiscussionTask } from '@/types/englishSpeaking'
 import type { CreationMode, SpeakingRecommendationTask, TopicDiscussionTask } from '@/types/englishSpeaking'
 import type { ArticleReadingTask } from '@/types/articleReading'
 import type { ArticleReadingTask } from '@/types/articleReading'
 import { ARTICLE_READING_TOOL_TYPE, TOPIC_DISCUSSION_TOOL_TYPE } from '@/configs/englishSpeakingTools'
 import { ARTICLE_READING_TOOL_TYPE, TOPIC_DISCUSSION_TOOL_TYPE } from '@/configs/englishSpeakingTools'
+import { injectKeySingleSlideMode } from '@/types/injectKey'
 import { filterSpeakingTasks, type SpeakingTaskFilter } from '../preview/articleReadingModel'
 import { filterSpeakingTasks, type SpeakingTaskFilter } from '../preview/articleReadingModel'
 import { useSpeakingStore } from '@/store/speaking'
 import { useSpeakingStore } from '@/store/speaking'
 import { useArticleReadingStore } from '@/store/articleReading'
 import { useArticleReadingStore } from '@/store/articleReading'
@@ -143,15 +144,32 @@ const filteredTasks = computed(() => filterSpeakingTasks(unitTasks.value, select
 
 
 // 新交互:点卡片即新建一页 + 创建配置 + 插入画布元素;配置页改由"点击画布里的 77 型元素"唤起
 // 新交互:点卡片即新建一页 + 创建配置 + 插入画布元素;配置页改由"点击画布里的 77 型元素"唤起
 const { createFrameElement } = useCreateElement()
 const { createFrameElement } = useCreateElement()
-const { createSlide } = useSlideHandler()
+const { createSlide, replaceAllSlidesWithNew } = useSlideHandler()
 const inserting = ref(false)
 const inserting = ref(false)
 
 
+// 由 indexEn.vue provide;其余编辑器没有 provide,这里拿到 default false
+const singleSlideMode = inject(injectKeySingleSlideMode, false)
+
+// 腾出一页空白页来放新工具。
+//
+// 单页模式(英语展示页)下换成「替换掉全部页面」:那个编辑器藏了缩略图、只允许一页,
+// 再往后加页的话老师看不见也切不过去。两条路都保证新页是空的,因为 createFrameElement
+// 会拒绝插进已经有 frame 的页面。
+//
+// 已知问题(两种模式都有,单页模式下更频繁):被替换掉的那个工具,它的 config 已经
+// POST 到后端了,这里只是丢掉画布上引用它的 frame 元素,后端那条记录会变成孤儿。
+// 服务端目前没有删除 config 的接口,前端无法回收。
+const openSlideForNewTool = () => {
+  if (singleSlideMode) replaceAllSlidesWithNew()
+  else createSlide()
+}
+
 async function insertSpeakingToolToCanvas(source: 'select' | 'manual') {
 async function insertSpeakingToolToCanvas(source: 'select' | 'manual') {
   if (inserting.value) return
   if (inserting.value) return
   inserting.value = true
   inserting.value = true
   try {
   try {
     const { id } = await createSpeakingConfig(speakingStore.config)
     const { id } = await createSpeakingConfig(speakingStore.config)
-    createSlide()
+    openSlideForNewTool()
     createFrameElement(id, TOPIC_DISCUSSION_TOOL_TYPE)
     createFrameElement(id, TOPIC_DISCUSSION_TOOL_TYPE)
     // 创建后立即唤起左侧配置面板(与点击画布 77 型 frame 同款信号),使用户可直接编辑
     // 创建后立即唤起左侧配置面板(与点击画布 77 型 frame 同款信号),使用户可直接编辑
     speakingStore.openConfigPanel()
     speakingStore.openConfigPanel()
@@ -179,7 +197,7 @@ async function insertArticleToolToCanvas(source: 'select' | 'manual') {
   const pending = message.info(lang.ssArticleGeneratingDemo as string, { duration: 0 })
   const pending = message.info(lang.ssArticleGeneratingDemo as string, { duration: 0 })
   try {
   try {
     const { id } = await createArticleConfig(articleStore.config)
     const { id } = await createArticleConfig(articleStore.config)
-    createSlide()
+    openSlideForNewTool()
     createFrameElement(id, ARTICLE_READING_TOOL_TYPE)
     createFrameElement(id, ARTICLE_READING_TOOL_TYPE)
     articleStore.openConfigPanel(id)
     articleStore.openConfigPanel(id)
     message.success(source === 'select' ? lang.ssArticleTemplateCreated : lang.ssArticleManualCreated)
     message.success(source === 'select' ? lang.ssArticleTemplateCreated : lang.ssArticleManualCreated)

+ 16 - 7
src/views/Editor/indexEn.vue

@@ -162,10 +162,10 @@
     </div>
     </div>
     <!-- <EditorHeader class="layout-header" /> -->
     <!-- <EditorHeader class="layout-header" /> -->
     <div class="layout-content">
     <div class="layout-content">
-      <CollapsibleToolbar class="layout-sidebar" @toggle="handleToolbarToggle" :userid="props.userid" :courseTitle="courseTitle" />
+      <CollapsibleToolbar class="layout-sidebar" @toggle="handleToolbarToggle" :userid="props.userid" :courseTitle="courseTitle" :onlyEnglish="true" />
       <div class="layout-content-center">
       <div class="layout-content-center">
         <CanvasTool class="center-top"  :userid="props.userid"/>
         <CanvasTool class="center-top"  :userid="props.userid"/>
-        <Canvas class="center-body" :style="{ height: `calc(100% - ${remarkHeight + 60}px  - 120px)` }"
+        <Canvas class="center-body" :style="{ height: `calc(100% - ${remarkHeight + 60}px  - ${singleSlideMode ? 0 : 120}px)` }"
           :courseid="props.courseid" @course-loaded="handleCourseLoaded"  ref="canvas"/>
           :courseid="props.courseid" @course-loaded="handleCourseLoaded"  ref="canvas"/>
         <!-- <Remark
         <!-- <Remark
           class="center-bottom" 
           class="center-bottom" 
@@ -173,7 +173,8 @@
           :style="{ height: `${remarkHeight}px` }"
           :style="{ height: `${remarkHeight}px` }"
            v-show="false"
            v-show="false"
         /> -->
         /> -->
-        <Thumbnails class="layout-content-left" />
+        <!-- 单页模式下没有第二页可切,缩略图条只会占掉 120px 画布高度 -->
+        <Thumbnails class="layout-content-left" v-if="!singleSlideMode" />
       </div>
       </div>
       <Toolbar class="layout-content-right" v-show="false" />
       <Toolbar class="layout-content-right" v-show="false" />
     </div>
     </div>
@@ -200,7 +201,7 @@
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
+import { ref, computed, onMounted, onUnmounted, watch, provide } from 'vue'
 import { storeToRefs } from 'pinia'
 import { storeToRefs } from 'pinia'
 import { useMainStore, useSlidesStore } from '@/store'
 import { useMainStore, useSlidesStore } from '@/store'
 import useGlobalHotkey from '@/hooks/useGlobalHotkey'
 import useGlobalHotkey from '@/hooks/useGlobalHotkey'
@@ -221,6 +222,7 @@ import AIPPTDialog from './AIPPTDialog.vue'
 import Modal from '@/components/Modal.vue'
 import Modal from '@/components/Modal.vue'
 import CollapsibleToolbar from '@/components/CollapsibleToolbar/index2.vue'
 import CollapsibleToolbar from '@/components/CollapsibleToolbar/index2.vue'
 import CreateCourseDialog from '@/components/CreateCourseDialog.vue'
 import CreateCourseDialog from '@/components/CreateCourseDialog.vue'
+import { injectKeySingleSlideMode } from '@/types/injectKey'
 import api from '@/services/course'
 import api from '@/services/course'
 import { lang } from '@/main'
 import { lang } from '@/main'
 
 
@@ -247,6 +249,12 @@ const props = withDefaults(defineProps<Props>(), {
 })
 })
 
 
 
 
+// 英语展示页固定单页:不显示缩略图,插入口语工具时替换掉当前全部页面而不是新增一页。
+// 通过 provide 下发而不是写进 store,是为了让这个值随本组件一起消失 —— 切到别的
+// 编辑器时它拿到的是 inject 的 default false,不存在旗标残留的问题。
+const singleSlideMode: boolean = true
+provide(injectKeySingleSlideMode, singleSlideMode)
+
 const mainStore = useMainStore()
 const mainStore = useMainStore()
 const slidesStore = useSlidesStore()
 const slidesStore = useSlidesStore()
 const { dialogForExport, showSelectPanel, showSearchPanel, showNotesPanel, showMarkupPanel, showAIPPTDialog } = storeToRefs(mainStore)
 const { dialogForExport, showSelectPanel, showSearchPanel, showNotesPanel, showMarkupPanel, showAIPPTDialog } = storeToRefs(mainStore)
@@ -402,9 +410,10 @@ const setTitle2 = (newTitle: string) => {
 Object.assign(window, { getCourseDetail, setTitle })
 Object.assign(window, { getCourseDetail, setTitle })
 
 
 onMounted(() => {
 onMounted(() => {
-  if (!props.courseid) {
-    showCreateCourseDialog.value = true
-  }
+  // 展示页不弹「创建新课程」遮罩,直接进编辑页。
+  // 等价于在遮罩里点了「创建空白」—— CreateCourseDialog 的 blank 分支只 emit
+  // select + close,handleCreateCourseSelect 又只处理 'upload',所以那条路本来
+  // 就什么都没做,这里省掉遮罩不会漏掉任何初始化。
   ccourseid.value = props.courseid || ''
   ccourseid.value = props.courseid || ''
   mainStore.setUserid(props.userid || '')
   mainStore.setUserid(props.userid || '')
   // 添加点击外部关闭下拉菜单的事件监听
   // 添加点击外部关闭下拉菜单的事件监听