lsc 2 주 전
부모
커밋
a18b45a2ac
3개의 변경된 파일185개의 추가작업 그리고 36개의 파일을 삭제
  1. 4 0
      src/assets/img/arrow.svg
  2. 2 0
      src/views/Student/components/DialoguePanel.vue
  3. 179 36
      src/views/Student/index.vue

+ 4 - 0
src/assets/img/arrow.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10 15L15 10L10 5" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M5 15L10 10L5 5" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 2 - 0
src/views/Student/components/DialoguePanel.vue

@@ -474,6 +474,8 @@ onMounted(() => {
 	display: flex;
 	flex-direction: column;
   position: relative;
+  padding: 0 8px;
+  box-sizing: border-box;
 	.dp_messageList {
 		width: 100%;
 		height: calc(100% - 60px - 40px - 10px); // 减去输入框和清空按钮的高度

+ 179 - 36
src/views/Student/index.vue

@@ -12,12 +12,16 @@
       <div class="thumbnails">
         <div class="viewer-header slide-header">
           <h3 v-show="!slidePanelCollapsed">课程大纲</h3>
-          <button class="collapse-btn" @click="slidePanelCollapsed = !slidePanelCollapsed" :title="slidePanelCollapsed ? '展开' : '收起'">
-            <span v-if="slidePanelCollapsed">›</span>
-            <span v-else>‹</span>
+          <button class="collapse-btn" @click="slidePanelCollapsed = !slidePanelCollapsed" :title="slidePanelCollapsed ? '展开' : '收起'" style="right: 8px;">
+            <span v-if="slidePanelCollapsed">
+              <img src="@/assets/img/arrow.svg">
+            </span>
+            <span v-else>
+              <img src="@/assets/img/arrow.svg" style="transform: rotate(180deg);">
+            </span>
           </button>
         </div>
-        <div v-show="!slidePanelCollapsed">
+        <div v-show="!slidePanelCollapsed" class="panel-content">
           <div class="thumbnail-list">
             <div v-for="(slide, index) in slides" :key="slide.id" class="thumbnail-item"
               :class="{ 'active': slideIndex === index }" @click="goToSlide(index)">
@@ -68,7 +72,7 @@
                     :manualExitFullscreen="() => { }" /> -->
 
         <!-- 不全屏时:使用编辑模式的显示比例和居中逻辑 -->
-        <div class="slide-list-wrap" :style="{
+        <div class="slide-list-wrap" :class="{'slide-list-wrap-n': !isFullscreen}" :style="{
           width: isFullscreen ? '100%' : (slideWidth * canvasScale) + 'px',
           height: isFullscreen ? '100%' : (slideHeight * canvasScale) + 'px',
           left: isFullscreen ? '0' : `${(containerWidth - slideWidth * canvasScale) / 2}px`,
@@ -82,8 +86,10 @@
               :manualExitFullscreen="() => { }" :is-visible="slideIndex === index" />
           </div>
 
-          <ScreenSlideList :slideWidth="slideWidth * canvasScale" :slideHeight="slideHeight * canvasScale"
+          <ScreenSlideList :style="{ width: isFullscreen ? '100%' : slideWidth2 * canvasScale + 'px', height: isFullscreen ? '100%' : slideHeight2 * canvasScale + 'px', margin: '0 auto' }" :slideWidth="isFullscreen ? slideWidth * canvasScale : slideWidth2 * canvasScale" :slideHeight="isFullscreen ? slideHeight * canvasScale : slideHeight2 * canvasScale"
             :animationIndex="0" :turnSlideToId="() => { }" :manualExitFullscreen="() => { }"  :slideIndex="slideIndex"/>
+
+          <div class="slide-bottom" v-if="!isFullscreen"></div>
         </div>
         <!-- 全屏时的左右下角工具按钮 -->
         <div v-if="isFullscreen && (!isFollowModeActive || props.type == '1')" class="tools-left">
@@ -135,18 +141,48 @@
     <div class="layout-content-right" v-show="type == '1'" :class="{ collapsed: workPanelCollapsed }">
       <div class="thumbnails">
         <div class="viewer-header right-panel-header">
-          <h3 v-show="!workPanelCollapsed">{{ 
-            rightPanelMode === 'homework' ? '作业区' : 
-            rightPanelMode === 'dialogue' ? '对话区' : rightPanelMode === 'choice' ? '统计' : ''
-          }}</h3>
-          <button class="collapse-btn" @click="workPanelCollapsed = !workPanelCollapsed" :title="workPanelCollapsed ? '展开' : '收起'" v-if="rightPanelMode != ''">
-            <span v-if="workPanelCollapsed">›</span>
-            <span v-else>‹</span>
+          <button class="collapse-btn" @click="workPanelCollapsed = !workPanelCollapsed" :title="workPanelCollapsed ? '展开' : '收起'" v-if="rightPanelMode != ''" style="left: 8px;">
+            <span v-if="workPanelCollapsed">
+              <img src="@/assets/img/arrow.svg" style="transform: rotate(180deg);">
+            </span>
+            <span v-else>
+              <img src="@/assets/img/arrow.svg">
+            </span>
           </button>
+          <!-- 标签页切换按钮 -->
+          <div v-show="!workPanelCollapsed" class="tab-switcher">
+            <button 
+              class="tab-btn" 
+              :class="{ active: rightPanelMode === 'homework' }"
+              @click="switchToHomework"
+              title="回答结果"
+            >
+              回答结果
+            </button>
+            <button 
+              class="tab-btn" 
+              :class="{ active: rightPanelMode === 'dialogue' }"
+              @click="switchToDialogue"
+              title="对话区"
+            >
+              对话区
+            </button>
+            <!-- <button 
+              v-if="isChoiceQuestion"
+              class="tab-btn" 
+              :class="{ active: rightPanelMode === 'choice' }"
+              @click="switchToChoice"
+              title="统计"
+            >
+              统计
+            </button> -->
+          </div>
+          
+
         </div>
         
         <!-- 侧边导航标签 - 无论展开还是收缩都显示在左侧 -->
-        <div class="side-nav-tabs">
+        <!-- <div class="side-nav-tabs">
           <button 
             v-if="currentSlideHasIframe"
             class="side-nav-btn" 
@@ -165,19 +201,19 @@
           >
             <img :src="rightPanelMode === 'choice' ? choiceActiveIcon : choiceIcon" alt="统计">
           </button>
-          <!-- <button 
+          <button 
             class="side-nav-btn" 
             :class="{ active: rightPanelMode === 'dialogue' }"
             @click="switchToDialogue"
             title="对话"
           >
             <img :src="rightPanelMode === 'dialogue' ? dialogueActiveIcon : dialogueIcon" alt="对话">
-          </button> -->
-        </div>
+          </button>
+        </div> -->
         
 
         
-        <!-- 作业区内容 -->
+        <!-- 回答结果内容 -->
         <div v-show="!workPanelCollapsed && rightPanelMode === 'homework'" class="panel-content">
           <div class="homework-title">已提交</div>
           <div v-if="workLoading" class="homework-loading">正在加载作业...</div>
@@ -307,6 +343,8 @@ const isSubmitting = ref(false)
 const showSlideList = ref(true)
 const slideWidth = ref(0)
 const slideHeight = ref(0)
+const slideWidth2 = ref(0)
+const slideHeight2 = ref(0)
 
 // 添加loading状态
 const isLoading = ref(false)
@@ -329,7 +367,7 @@ const visibleQA = ref(false)
 const visibleChoice = ref(false)
 const visibleAI = ref(false)
 
-// 作业区收缩状态
+// 回答结果收缩状态
 const workPanelCollapsed = ref(true)
 // 幻灯片导航收缩状态
 const slidePanelCollapsed = ref(true)
@@ -362,7 +400,7 @@ const providerSocket = ref<WebsocketProvider | null>(null)
 const mId = ref<string | null>(null)
 
 
-// 切换到作业区
+// 切换到回答结果
 const switchToHomework = () => {
   rightPanelMode.value = 'homework'
   if (workPanelCollapsed.value) {
@@ -388,7 +426,7 @@ const switchToChoice = () => {
 
 // 自动切换到可用的面板
 const autoSwitchToAvailablePanel = () => {
-  // 如果当前在作业区但没有iframe,自动切换到其他可用面板
+  // 如果当前在回答结果但没有iframe,自动切换到其他可用面板
   if (rightPanelMode.value === 'homework' && !currentSlideHasIframe.value) {
     if (isChoiceQuestion.value) {
       rightPanelMode.value = 'choice'
@@ -455,6 +493,9 @@ const calculateSlideSize = () => {
   const slideWrapRef = isFullscreen.value ? document.body : viewerCanvasRef.value
   const winWidth = slideWrapRef?.clientWidth || 0
   const winHeight = slideWrapRef?.clientHeight || 0
+  const winWidth2 = slideWrapRef && typeof slideWrapRef.clientWidth === 'number' ? slideWrapRef.clientWidth - 40 : 0
+  const winHeight2 = slideWrapRef && typeof slideWrapRef.clientHeight === 'number' ? slideWrapRef.clientHeight - 85 : 0
+
 
   // 根据视口比例计算最佳尺寸
   if (winHeight / winWidth === viewportRatio.value) {
@@ -470,7 +511,38 @@ const calculateSlideSize = () => {
     slideHeight.value = winHeight
   }
 
+  // 这里的逻辑存在一些问题和可以优化的地方:
+  // 1. winWidth2 或 winHeight2 可能为0,导致后续计算为NaN。
+  // 2. slideHeight.value - slideHeight2.value < 85 这个判断,slideHeight2.value 可能还未被合理赋值,导致判断不准确。
+  // 3. 反复赋值 slideHeight2/slideWidth2,可能导致宽高比被破坏。
+  // 4. 代码重复,可合并优化。
+
+  // 先按比例计算
+  let tempWidth = 0
+  let tempHeight = 0
+  if (winHeight2 / winWidth2 === viewportRatio.value) {
+    tempWidth = winWidth2
+    tempHeight = winHeight2
+  }
+  else if (winHeight2 / winWidth2 > viewportRatio.value) {
+    tempWidth = winWidth2
+    tempHeight = winWidth2 * viewportRatio.value
+  }
+  else {
+    tempHeight = winHeight2
+    tempWidth = winHeight2 / viewportRatio.value
+  }
+  // 检查底部空间
+  if (slideHeight.value - tempHeight < 85) {
+    tempHeight = Math.max(slideHeight.value - 85, 0)
+    tempWidth = tempHeight > 0 ? tempHeight / viewportRatio.value : 0
+  }
+  slideWidth2.value = tempWidth
+  slideHeight2.value = tempHeight
+
+
   console.log('calculateSlideSize', slideWidth.value, slideHeight.value, viewportRatio.value, canvasScale.value)
+  console.log('calculateSlideSize', slideWidth2.value, slideHeight2.value, viewportRatio.value, canvasScale.value)
 }
 
 // 使用编辑模式的缩放逻辑
@@ -1455,7 +1527,7 @@ const getHomeworkButtonRight = () => {
     return 30 // 全屏时按钮在右侧30px
   }
   if (props.type === '1') {
-    // 展开作业区:按钮更靠左;收起时:按钮更靠右侧
+    // 展开回答结果:按钮更靠左;收起时:按钮更靠右侧
     return workPanelCollapsed.value ? 60 : 430
   }
   return 30 // type=2时按钮在右侧30px
@@ -1467,7 +1539,7 @@ const getRefreshButtonRight = () => {
     return 160 // 全屏时按钮在右侧150px
   }
   if (props.type === '1') {
-    // 展开作业区:按钮更靠左;收起时:按钮更靠右侧
+    // 展开回答结果:按钮更靠左;收起时:按钮更靠右侧
     return workPanelCollapsed.value ? 190 : 560
   }
   return 160 // type=2时按钮在右侧150px
@@ -1966,7 +2038,7 @@ onUnmounted(() => {
   height: 100vh;
   display: flex;
   background-color: #f4f4f4;
-  padding: 15px 10px;
+  padding: 15px 0;
   box-sizing: border-box;
 
   // 全屏模式样式
@@ -1995,12 +2067,14 @@ onUnmounted(() => {
   width: 200px;
   height: 100%;
   background-color: #fff;
-  border-right: 1px solid #e0e0e0;
-  overflow-y: auto;
+  border-radius: 0 5px 0 5px;
+  overflow: hidden;
   transition: width .2s ease;
+  margin-left: 10px;
 }
 .layout-content-left.collapsed {
   width: 48px;
+  margin-left: 0;
 }
 .slide-header {
   display: flex;
@@ -2017,20 +2091,22 @@ onUnmounted(() => {
   width: 400px;
   height: 100%;
   background-color: #fff;
-  border-left: 1px solid #e0e0e0;
-  overflow-y: auto;
+  border-radius: 5px 0 5px 0;
+  overflow: hidden;
   transition: width .2s ease;
   position: relative;
+  margin-right: 10px;
 }
 
 .panel-content {
-  margin-right: 52px;
-  padding: 0 8px;
-  height: calc(100% - 76px);
+  margin-right: 0;
+  // padding: 0 8px;
+  height: calc(100% - 65px);
   overflow: auto;
 }
 .layout-content-right.collapsed {
   width: 52px;
+  margin-right: 0px;
 }
 .right-panel-header {
   display: flex;
@@ -2160,17 +2236,19 @@ onUnmounted(() => {
   justify-content: center;
   width: 32px;
   height: 32px;
-  border: 1px solid #d9d9d9;
+  // border: 1px solid #d9d9d9;
+  border: none;
   border-radius: 8px;
   background: #fff;
   color: #333;
   cursor: pointer;
   line-height: 1;
   font-weight: 700;
+  position: absolute;
 }
 .collapse-btn:hover {
-  border-color: #1890ff;
-  color: #1890ff;
+  // border-color: #1890ff;
+  // color: #1890ff;
 }
 
 .homework-title {
@@ -2249,6 +2327,8 @@ onUnmounted(() => {
       font-size: 16px;
       font-weight: 600;
       color: #333;
+      text-align: center;
+      width: 100%;
     }
   }
 
@@ -2331,7 +2411,7 @@ onUnmounted(() => {
 }
 
 .viewer-header {
-  height: 60px;
+  height: 45px;
   background-color: #fff;
   border-bottom: 1px solid #e0e0e0;
   display: flex;
@@ -2339,6 +2419,7 @@ onUnmounted(() => {
   justify-content: space-between;
   padding: 0 8px;
   transition: transform 0.3s ease;
+  position: relative;
 
   &.hidden {
     transform: translateY(-100%);
@@ -2411,7 +2492,7 @@ onUnmounted(() => {
 .viewer-canvas {
   flex: 1;
   position: relative;
-  background-color: rgb(249, 249, 249);
+  background-color: rgb(244, 244, 244);
   overflow: hidden;
 
   // 全屏时隐藏滚动条和边框
@@ -2434,6 +2515,20 @@ onUnmounted(() => {
   }
 }
 
+.slide-list-wrap-n{
+  border: 5px solid #595959;
+  background: #000;
+  padding: 15px 0 0 0;
+  box-sizing: border-box;
+}
+
+.slide-bottom{
+  height: 60px;
+  background: #000;
+  position: relative;
+  z-index: 10;
+}
+
 .loading-indicator {
   position: absolute;
   top: 50%;
@@ -2724,4 +2819,52 @@ onUnmounted(() => {
     0% { transform: rotate(0deg); }
     100% { transform: rotate(360deg); }
 }
+
+/* 标签页切换器样式 */
+.tab-switcher {
+  display: flex;
+  flex: 1;
+  margin-right: 12px;
+  border-bottom: 1px solid #e0e0e0;
+  padding-bottom: 0;
+  height: 100%;
+  justify-content: center;
+  gap: 20px;
+}
+
+.tab-btn {
+  // flex: 1;
+  // padding: 12px 16px;
+  border: none;
+  background: transparent;
+  color: #666;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  font-size: 14px;
+  font-weight: 500;
+  text-align: center;
+  white-space: nowrap;
+  position: relative;
+  border-radius: 0;
+  
+  &:hover {
+    color: #333;
+  }
+  
+  &.active {
+    color: #333;
+    font-weight: 600;
+    
+    &::after {
+      content: '';
+      position: absolute;
+      bottom: -1px;
+      left: 0;
+      right: 0;
+      height: 2px;
+      background: #333;
+      border-radius: 1px;
+    }
+  }
+}
 </style>