Explorar o código

feat(学生视图): 添加题目和回答切换功能并优化界面

- 在选择题详情弹窗中添加题目和回答的切换按钮
- 替换激光笔图标为AI助手图标
- 优化App.vue组件切换性能,添加KeepAlive
- 更新多语言文件,添加题目和回答的翻译
- 移除部分冗余代码和注释
lsc hai 2 semanas
pai
achega
74b77fe54e

+ 29 - 23
src/App.vue

@@ -1,28 +1,34 @@
 <template>
 <template>
   <template v-if="slides.length">
   <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 />
+    <Screen v-if="viewMode !== 'student' && screening" key="screen" />
+    <KeepAlive>
+      <Editor
+        v-if="viewMode === 'editor' && _isPC && !screening"
+        :courseid="urlParams.courseid"
+        key="editor"
+      />
+      <Editor2
+        v-else-if="viewMode === 'editor2' && _isPC && !screening"
+        :courseid="urlParams.courseid"
+        key="editor2"
+      />
+      <Editor3
+        v-else-if="viewMode === 'editor3' && _isPC && !screening"
+        :courseid="urlParams.courseid"
+        key="editor3"
+      />
+      <Student
+        v-else-if="viewMode === 'student'"
+        :courseid="urlParams.courseid"
+        :type="urlParams.type"
+        :userid="urlParams.userid"
+        :oid="urlParams.oid"
+        :org="urlParams.org"
+        :cid="urlParams.cid"
+        key="student"
+      />
+      <Mobile v-else key="mobile" />
+    </KeepAlive>
   </template>
   </template>
   <FullscreenSpin :tip="lang.ssInitDataWait" v-else loading :mask="false" />
   <FullscreenSpin :tip="lang.ssInitDataWait" v-else loading :mask="false" />
 </template>
 </template>

+ 2 - 0
src/plugins/icon.ts

@@ -98,6 +98,7 @@ import {
   Power,
   Power,
   ListView,
   ListView,
   Magic,
   Magic,
+  Tips,
   HighLight,
   HighLight,
   Download,
   Download,
   IndentLeft,
   IndentLeft,
@@ -232,6 +233,7 @@ export const icons: Icons = {
   IconPower: Power,
   IconPower: Power,
   IconListView: ListView,
   IconListView: ListView,
   IconMagic: Magic,
   IconMagic: Magic,
+  IconTips: Tips,
   IconHighLight: HighLight,
   IconHighLight: HighLight,
   IconDownload: Download,
   IconDownload: Download,
   IconIndentLeft: IndentLeft,
   IconIndentLeft: IndentLeft,

+ 6 - 6
src/views/Student/components/choiceQuestionDetailDialog.vue

@@ -4,7 +4,7 @@
       width: slideWidth + 'px',
       width: slideWidth + 'px',
       height: slideHeight + 'px',
       height: slideHeight + 'px',
     }">
     }">
-      <span class="closeIcon" @click="closeSlideIndex()">
+      <span v-show="false" class="closeIcon" @click="closeSlideIndex()">
         <img src="../../../assets/img/close.png" />
         <img src="../../../assets/img/close.png" />
       </span>
       </span>
 
 
@@ -471,7 +471,7 @@ const setEchartsArea1 = () => {
           fontSize: 17,
           fontSize: 17,
           lineHeight: 20,
           lineHeight: 20,
           interval: 0,
           interval: 0,
-          formatter: function (value: any, idx: number) {
+          formatter: function(value: any, idx: number) {
             // 如果是字符串且格式为JSON(图片),则解析处理
             // 如果是字符串且格式为JSON(图片),则解析处理
             if (typeof value === 'string') {
             if (typeof value === 'string') {
               try {
               try {
@@ -606,8 +606,8 @@ const setEchartsArea1 = () => {
       const selectedOption = _work.choiceUser[idx]
       const selectedOption = _work.choiceUser[idx]
       if (selectedOption && selectUserDialogRef.value) {
       if (selectedOption && selectUserDialogRef.value) {
         // console.log(selectedOption)
         // console.log(selectedOption)
-        console.log("selectedOption",selectedOption)
-        selectUserDialogRef.value.open(`${lang.ssSelectUser.replace("{a}","<span>"+selectedOption.index+"</span>")}`,selectedOption)
+        console.log('selectedOption', selectedOption)
+        selectUserDialogRef.value.open(`${lang.ssSelectUser.replace('{a}', '<span>' + selectedOption.index + '</span>')}`, selectedOption)
       }
       }
     })
     })
   }
   }
@@ -719,9 +719,9 @@ watch(
 
 
 // 查看未提交学生
 // 查看未提交学生
 const viewUnsubmittedStudents = () => {
 const viewUnsubmittedStudents = () => {
-  selectUserDialogRef.value.open(lang.ssUnsubmittedStudents,{user:props.showData.unsubmittedStudents.map((item: any) => item.name)})
+  selectUserDialogRef.value.open(lang.ssUnsubmittedStudents, {user: props.showData.unsubmittedStudents.map((item: any) => item.name)})
   // if (props.unsubmittedStudents.length > 0) {
   // if (props.unsubmittedStudents.length > 0) {
-    // unsubmittedStudentsDialogRef.value.open(props.unsubmittedStudents)
+  // unsubmittedStudentsDialogRef.value.open(props.unsubmittedStudents)
   // }
   // }
 }
 }
 
 

+ 68 - 6
src/views/Student/index.vue

@@ -78,6 +78,16 @@
           left: isFullscreen ? '0' : `${(containerWidth - slideWidth * canvasScale) / 2}px`,
           left: isFullscreen ? '0' : `${(containerWidth - slideWidth * canvasScale) / 2}px`,
           top: isFullscreen ? '0' : `${(containerHeight - slideHeight * canvasScale) / 2}px`
           top: isFullscreen ? '0' : `${(containerHeight - slideHeight * canvasScale) / 2}px`
         }" @mousemove="handleLaserMove">
         }" @mousemove="handleLaserMove">
+          <div class="homework-check-box" v-if="currentSlideHasIframe && !currentSlideHasBilibiliVideo" v-show="currentSlideHasIframe" :style="{
+            top: isFullscreen ? '0' : `15px`
+          }">
+            <div class="homework-check-box-item" @click="openChoiceQuestionDetail2(slideIndex)" :class="{'active': !choiceQuestionDetailDialogOpenList.includes(slideIndex)}">
+              <div class="homework-check-box-item-title">{{ lang.ssQuestion }}</div>
+            </div>
+            <div class="homework-check-box-item" @click="openChoiceQuestionDetail3(slideIndex)" :class="{'active': choiceQuestionDetailDialogOpenList.includes(slideIndex)}">
+              <div class="homework-check-box-item-title">{{ lang.ssAnswer }}</div>
+            </div>
+          </div>
           <div class="viewport" v-if="false">
           <div class="viewport" v-if="false">
             <div class="background" :style="backgroundStyle"></div>
             <div class="background" :style="backgroundStyle"></div>
 
 
@@ -110,7 +120,8 @@
                 <IconLoading v-else-if="currentSlideHasIframe && !currentSlideHasBilibiliVideo" class="tool-btn loading" v-tooltip="lang.ssSubmitting"></IconLoading>
                 <IconLoading v-else-if="currentSlideHasIframe && !currentSlideHasBilibiliVideo" class="tool-btn loading" v-tooltip="lang.ssSubmitting"></IconLoading>
                 <IconStopwatchStart v-if="props.type == '1' && courseDetail.userid == props.userid && isFollowModeActive" class="tool-btn" v-tooltip="lang.ssTimer" @click="timerlVisible = !timerlVisible"  />
                 <IconStopwatchStart v-if="props.type == '1' && courseDetail.userid == props.userid && isFollowModeActive" class="tool-btn" v-tooltip="lang.ssTimer" @click="timerlVisible = !timerlVisible"  />
                 <IconWrite v-if="isFollowModeActive && props.type == '1' && courseDetail.userid == props.userid" class="tool-btn" v-tooltip="lang.ssPenTool" @click="writingBoardToolVisible = true"  />
                 <IconWrite v-if="isFollowModeActive && props.type == '1' && courseDetail.userid == props.userid" class="tool-btn" v-tooltip="lang.ssPenTool" @click="writingBoardToolVisible = true"  />
-                <IconMagic v-if="isFollowModeActive && props.type == '1' && courseDetail.userid == props.userid" class="tool-btn" v-tooltip="lang.ssLaserPen" :class="{ 'active': laserPen }" @click="toggleLaserPen"  />
+                <!-- <IconMagic v-if="isFollowModeActive && props.type == '1' && courseDetail.userid == props.userid" class="tool-btn" v-tooltip="lang.ssLaserPen" :class="{ 'active': laserPen }" @click="toggleLaserPen"  /> -->
+                <IconTips v-if="props.type == '1'" class="tool-btn" v-tooltip="lang.ssAiHelper" :class="{ 'active': !workPanelCollapsed }" @click="workPanelCollapsed = !workPanelCollapsed"  />
                 <IconFullScreenOne class="tool-btn" v-tooltip="lang.ssOpenFull" @click="enterFullscreen" />
                 <IconFullScreenOne class="tool-btn" v-tooltip="lang.ssOpenFull" @click="enterFullscreen" />
               </div>
               </div>
           </div>
           </div>
@@ -194,7 +205,7 @@
           </button>
           </button>
           <!-- 标签页切换按钮 -->
           <!-- 标签页切换按钮 -->
           <div v-show="!workPanelCollapsed" class="tab-switcher">
           <div v-show="!workPanelCollapsed" class="tab-switcher">
-            <button 
+            <!-- <button 
               v-if="currentSlideHasIframe && !currentSlideHasBilibiliVideo"
               v-if="currentSlideHasIframe && !currentSlideHasBilibiliVideo"
               v-show="currentSlideHasIframe"
               v-show="currentSlideHasIframe"
               class="tab-btn" 
               class="tab-btn" 
@@ -203,7 +214,7 @@
               :title="lang.ssAnswerRes"
               :title="lang.ssAnswerRes"
             >
             >
               {{ lang.ssAnswerRes }}
               {{ lang.ssAnswerRes }}
-            </button>
+            </button> -->
             <button 
             <button 
               class="tab-btn" 
               class="tab-btn" 
               :class="{ active: rightPanelMode === 'dialogue' }"
               :class="{ active: rightPanelMode === 'dialogue' }"
@@ -649,9 +660,9 @@ const autoSwitchToAvailablePanel = () => {
     rightPanelMode.value = 'dialogue'
     rightPanelMode.value = 'dialogue'
     console.log('自动切换到对话面板')
     console.log('自动切换到对话面板')
   }
   }
-  else if (currentSlideHasIframe.value && rightPanelMode.value !== 'homework' && !currentSlideHasBilibiliVideo.value) {
-    rightPanelMode.value = 'homework'
-  }
+  // else if (currentSlideHasIframe.value && rightPanelMode.value !== 'homework' && !currentSlideHasBilibiliVideo.value) {
+  //   rightPanelMode.value = 'homework'
+  // }
 }
 }
 
 
 // 移除定时器相关函数,改用socket监听
 // 移除定时器相关函数,改用socket监听
@@ -3216,6 +3227,24 @@ const openChoiceQuestionDetail = (index:number) => {
   }
   }
 }
 }
 
 
+// 打开作业查看详细
+const openChoiceQuestionDetail2 = (index:number) => {
+  if (!choiceQuestionDetailDialogOpenList.value.includes(index)) {
+  }
+  else {
+    choiceQuestionDetailDialogOpenList.value = choiceQuestionDetailDialogOpenList.value.filter(i => i !== index)
+  }
+}
+
+
+// 打开作业查看详细
+const openChoiceQuestionDetail3 = (index:number) => {
+  if (!choiceQuestionDetailDialogOpenList.value.includes(index)) {
+    choiceQuestionDetailDialogOpenList.value.push(index)
+  }
+}
+
+
 const handlePageUnload = () => {
 const handlePageUnload = () => {
   if (isCreator.value && timerIndicator.value.visible && props.type === '1') {
   if (isCreator.value && timerIndicator.value.visible && props.type === '1') {
     sendMessage({ type: 'timer_stop', courseid: props.courseid })
     sendMessage({ type: 'timer_stop', courseid: props.courseid })
@@ -5259,4 +5288,37 @@ const clearTimerState = () => {
     }
     }
   }
   }
 }
 }
+
+.homework-check-box {
+  position: absolute;
+  top: 15px;
+  left: 50%;
+  transform: translate(-50%, 0);
+  display: flex;
+  align-items: center;
+  box-shadow: 0px 3px 4px 3px #f2f2f2;
+  padding: 8px;
+  border-radius: 5px;
+  background: #fff;
+  z-index: 999;
+
+  .homework-check-box-item{
+    padding: 10px 18px;
+    border-radius: 5px;
+    font-weight: 600;
+    cursor: pointer;
+    transition: all 0.3s ease;
+
+    &.active{
+      background: #f6c82b;
+    }
+    
+    &:hover{
+      background: #fff;
+      color: #f6c82b;
+    }
+  }
+
+  .homework-check-box-item-title{}
+}
 </style>
 </style>

+ 2 - 0
src/views/lang/cn.json

@@ -721,6 +721,8 @@
   "ssCocoLinkTip":"请添加 Cocorobo 同域、亚马逊或可访问的 HTML 链接。",
   "ssCocoLinkTip":"请添加 Cocorobo 同域、亚马逊或可访问的 HTML 链接。",
   "ssChoiceQuestion":"选择题",
   "ssChoiceQuestion":"选择题",
   "ssAnswerCount":"回答人数",
   "ssAnswerCount":"回答人数",
+  "ssQuestion":"题目",
+  "ssAnswer":"回答",
   "ssViewUnsubmittedStudents":"点击查看未提交学生",
   "ssViewUnsubmittedStudents":"点击查看未提交学生",
   "ssSelectUser":"选择{a}的成员",
   "ssSelectUser":"选择{a}的成员",
   "ssUnsubmittedStudents":"未提交学生"
   "ssUnsubmittedStudents":"未提交学生"

+ 2 - 0
src/views/lang/en.json

@@ -721,6 +721,8 @@
   "ssCocoLinkTip":"Please add Cocorobo, Amazon, or accessible HTML link.",
   "ssCocoLinkTip":"Please add Cocorobo, Amazon, or accessible HTML link.",
   "ssChoiceQuestion":"Choice Question",
   "ssChoiceQuestion":"Choice Question",
   "ssAnswerCount":"Answer count",
   "ssAnswerCount":"Answer count",
+  "ssQuestion":"Question",
+  "ssAnswer":"Answer",
   "ssViewUnsubmittedStudents":"Click to view unsubmitted students",
   "ssViewUnsubmittedStudents":"Click to view unsubmitted students",
   "ssSelectUser":"Select members of {a}",
   "ssSelectUser":"Select members of {a}",
   "ssUnsubmittedStudents":"Unsubmitted students"
   "ssUnsubmittedStudents":"Unsubmitted students"

+ 2 - 0
src/views/lang/hk.json

@@ -721,6 +721,8 @@
   "ssCocoLinkTip":"請添加 Cocorobo 同域、亚马逊或可访问的 HTML 链接。",
   "ssCocoLinkTip":"請添加 Cocorobo 同域、亚马逊或可访问的 HTML 链接。",
   "ssChoiceQuestion":"選擇題",
   "ssChoiceQuestion":"選擇題",
   "ssAnswerCount":"回答人數",
   "ssAnswerCount":"回答人數",
+  "ssQuestion":"題目",
+  "ssAnswer":"回答",
   "ssViewUnsubmittedStudents":"點擊查看未提交學生",
   "ssViewUnsubmittedStudents":"點擊查看未提交學生",
   "ssSelectUser":"選擇{a}的成員",
   "ssSelectUser":"選擇{a}的成員",
   "ssUnsubmittedStudents":"未提交學生"
   "ssUnsubmittedStudents":"未提交學生"