黄琪勇 il y a 1 an
Parent
commit
9d5d5aa078
36 fichiers modifiés avec 696 ajouts et 472 suppressions
  1. 1 1
      .editorconfig
  2. 22 0
      public/roll-call/css/index.css
  3. BIN
      public/roll-call/img/back.png
  4. 19 3
      public/roll-call/index.html
  5. 1 1
      public/version.json
  6. 70 30
      src/views/attend-class/component/audio-pay.tsx
  7. 20 16
      src/views/attend-class/component/audio.module.less
  8. 6 2
      src/views/attend-class/component/rhythm-modal/index.tsx
  9. 1 1
      src/views/attend-class/component/tools/pen.module.less
  10. 8 1
      src/views/attend-class/component/tools/pen.tsx
  11. 231 106
      src/views/attend-class/component/video-play.tsx
  12. 19 14
      src/views/attend-class/component/video.module.less
  13. BIN
      src/views/attend-class/image/bg.png
  14. BIN
      src/views/attend-class/image/bottom_icon1.png
  15. BIN
      src/views/attend-class/image/bottom_icon2.png
  16. BIN
      src/views/attend-class/image/bottom_icon3.png
  17. BIN
      src/views/attend-class/image/bottom_icon4.png
  18. BIN
      src/views/attend-class/image/icon-pause.png
  19. BIN
      src/views/attend-class/image/icon-play.png
  20. BIN
      src/views/attend-class/image/icon-replay.png
  21. BIN
      src/views/attend-class/image/icon-speed.png
  22. BIN
      src/views/attend-class/image/left_hide_icon.png
  23. BIN
      src/views/attend-class/image/right_hide_icon.png
  24. BIN
      src/views/attend-class/image/right_icon1.png
  25. BIN
      src/views/attend-class/image/right_icon10.png
  26. BIN
      src/views/attend-class/image/right_icon11.png
  27. BIN
      src/views/attend-class/image/right_icon12.png
  28. BIN
      src/views/attend-class/image/right_icon2.png
  29. BIN
      src/views/attend-class/image/right_icon3.png
  30. BIN
      src/views/attend-class/image/right_icon4.png
  31. BIN
      src/views/attend-class/image/right_icon5.png
  32. BIN
      src/views/attend-class/image/right_icon7.png
  33. BIN
      src/views/attend-class/image/right_icon8.png
  34. BIN
      src/views/attend-class/image/right_icon9.png
  35. 92 171
      src/views/attend-class/index.module.less
  36. 206 126
      src/views/attend-class/index.tsx

+ 1 - 1
.editorconfig

@@ -5,7 +5,7 @@ root = true
 charset = utf-8
 indent_style = space
 indent_size = 2
-end_of_line = lf
+end_of_line = CRLF
 insert_final_newline = true
 trim_trailing_whitespace = true
 

+ 22 - 0
public/roll-call/css/index.css

@@ -64,6 +64,15 @@ a {
   width: 100%;
   text-align: center;
 }
+#menu.menuRight{
+  display: flex;
+  padding: 0 100px;
+  flex-direction: row-reverse;
+}
+#menu.menuLeft{
+  display: flex;
+  padding: 0 100px;
+}
 .bss {
   height: 100vh;
   width: 100%;
@@ -131,6 +140,19 @@ a {
 #table.disabled:hover {
   opacity: 1;
 }
+#backBtn {
+  width: 171px;
+  height: 69px;
+  background: url('../img/back.png') no-repeat center;
+  background-size: contain;
+  border: none;
+  cursor: pointer;
+  transition: opacity 0.2s ease;
+}
+#backBtn:hover {
+  opacity: 0.9;
+  transition: opacity 0.2s ease;
+}
 #sphere {
   width: 171px;
   height: 69px;

BIN
public/roll-call/img/back.png


+ 19 - 3
public/roll-call/index.html

@@ -29,11 +29,12 @@
   <div id="vueBoxs">
     <div class="bss">
       <div class="pageTitle"></div>
-      <div class="iconBack" @click="onBack()"></div>
-      <div id="menu">
+      <div v-if="platform!=='modal'"  class="iconBack" @click="onBack()"></div>
+      <div id="menu" :class="[platform==='modal'?(imagePos==='right'?'menuRight':'menuLeft'):'']">
         <button id="table" :class="tableIndex <= 1 ? 'disabled' : ''" v-show="!animationStatus"
           @click="start()"></button>
         <button id="sphere" v-show="animationStatus" @click="closes()"></button>
+        <button v-if="platform==='modal'" id="backBtn" @click="onBack()"></button>
         <!-- <button id="reset" style="margin-left:40px;" @click="resets()">照片墙</button> -->
         <!-- <button id="lists" @click="listShow = true">中奖名单</button> -->
       </div>
@@ -328,7 +329,10 @@
     data: {
       animationStatus: false,
       tableIndex: 0,
-      listShow: false
+      listShow: false,
+      platform: "",
+      imagePos: ""
+
     },
     methods: {
       keyDowns: function () {
@@ -387,6 +391,11 @@
           api: 'callBack',
           loading: false,
         }, '*');
+      },
+      handleUrlParmas(){
+        const params=getUrlParams(location.href)
+        params?.platform&&(this.platform = params?.platform)
+        params?.imagePos&&(this.imagePos = params?.imagePos)
       }
     },
     created: function () {
@@ -395,6 +404,13 @@
 
       // getStar();
       // this.ckPrice();
+      this.handleUrlParmas()
     }
   })
+  function getUrlParams(url) {
+    let urlStr = url.split('?')[1]
+    const urlSearchParams = new URLSearchParams(urlStr)
+    const result = Object.fromEntries(urlSearchParams.entries())
+    return result
+  }
 </script>

+ 1 - 1
public/version.json

@@ -1 +1 @@
-{"version":1713531208995}
+{"version":1713854848723}

+ 70 - 30
src/views/attend-class/component/audio-pay.tsx

@@ -30,6 +30,10 @@ export default defineComponent({
     isEmtry: {
       type: Boolean,
       default: false
+    },
+    imagePos: {
+      type: String,
+      default: 'left'
     }
   },
   emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'],
@@ -219,21 +223,6 @@ export default defineComponent({
             e.stopPropagation();
             emit('reset');
           }}>
-          <div class={styles.actions}>
-            <div class={styles.actionWrap}>
-              <div class={styles.actionBtn} onClick={onToggleAudio}>
-                {audioForms.paused ? (
-                  <img class={styles.playIcon} src={iconplay} />
-                ) : (
-                  <img class={styles.playIcon} src={iconpause} />
-                )}
-              </div>
-              <button class={styles.iconReplay} onClick={onReplay}>
-                <img src={iconReplay} />
-              </button>
-            </div>
-          </div>
-
           <div class={styles.slider}>
             <NSlider
               value={audioForms.currentTimeNum}
@@ -247,21 +236,72 @@ export default defineComponent({
               }}
             />
           </div>
-
-          <div class={styles.actions}>
-            <div class={styles.time}>
-              <div
-                class="plyr__time plyr__time--current"
-                aria-label="Current time">
-                {audioForms.currentTime}
-              </div>
-              <span class={styles.line}>/</span>
-              <div
-                class="plyr__time plyr__time--duration"
-                aria-label="Duration">
-                {audioForms.duration}
-              </div>
-            </div>
+          <div class={styles.tools}>
+            {props.imagePos === 'right' ? (
+              <>
+                <div class={styles.actions}>
+                  <div class={styles.time}>
+                    <div
+                      class="plyr__time plyr__time--current"
+                      aria-label="Current time">
+                      {audioForms.currentTime}
+                    </div>
+                    <span class={styles.line}>/</span>
+                    <div
+                      class="plyr__time plyr__time--duration"
+                      aria-label="Duration">
+                      {audioForms.duration}
+                    </div>
+                  </div>
+                </div>
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <button class={styles.iconReplay} onClick={onReplay}>
+                      <img src={iconReplay} />
+                    </button>
+                    <div class={styles.actionBtn} onClick={onToggleAudio}>
+                      {audioForms.paused ? (
+                        <img class={styles.playIcon} src={iconplay} />
+                      ) : (
+                        <img class={styles.playIcon} src={iconpause} />
+                      )}
+                    </div>
+                  </div>
+                </div>
+              </>
+            ) : (
+              <>
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <div class={styles.actionBtn} onClick={onToggleAudio}>
+                      {audioForms.paused ? (
+                        <img class={styles.playIcon} src={iconplay} />
+                      ) : (
+                        <img class={styles.playIcon} src={iconpause} />
+                      )}
+                    </div>
+                    <button class={styles.iconReplay} onClick={onReplay}>
+                      <img src={iconReplay} />
+                    </button>
+                  </div>
+                </div>
+                <div class={styles.actions}>
+                  <div class={styles.time}>
+                    <div
+                      class="plyr__time plyr__time--current"
+                      aria-label="Current time">
+                      {audioForms.currentTime}
+                    </div>
+                    <span class={styles.line}>/</span>
+                    <div
+                      class="plyr__time plyr__time--duration"
+                      aria-label="Duration">
+                      {audioForms.duration}
+                    </div>
+                  </div>
+                </div>
+              </>
+            )}
           </div>
         </div>
       </div>

+ 20 - 16
src/views/attend-class/component/audio.module.less

@@ -50,14 +50,15 @@
   left: 0;
   right: 0;
   width: 100%;
-  background-color: rgba(0, 0, 0, 0.7);
+  background: url('../image/../image/bg.png') no-repeat;
+  background-size: 100% 100%;
   // backdrop-filter: blur(26px);
-  height: 108px;
-  padding: 0 330px 0 40px !important;
+  height: 120px;
+  padding: 0 40px !important;
   transition: all 0.301s;
   display: flex;
-  align-items: center;
-
+  justify-content: center;
+  flex-direction: column;
   .time {
     display: flex;
     justify-content: space-between;
@@ -69,7 +70,8 @@
     line-height: 33px;
 
     &>div {
-      font-size: 24px !important;
+      font-size: 20px !important;
+      color: rgba(255,255,255,0.8);
     }
 
     .line {
@@ -84,7 +86,12 @@
     }
   }
 }
-
+.tools{
+  display: flex;
+  justify-content: space-between;
+  padding: 0 10px;
+  margin-top: 10px;
+}
 .actions {
   display: flex;
   justify-content: space-between;
@@ -100,10 +107,8 @@
   }
 
   .actionBtn {
-    display: flex;
-    width: 60px;
-    height: 60px;
-    padding: 4px 0;
+    width: 40px;
+    height: 40px;
     background: transparent;
     cursor: pointer;
 
@@ -116,11 +121,10 @@
 
   .iconReplay {
     width: 40px;
-    height: 39px;
+    height: 40px;
     background-color: transparent;
     cursor: pointer;
-    margin-left: 22px;
-    margin-right: 10px;
+    margin: 0 22px;
 
     &>img {
       width: 100%;
@@ -131,7 +135,7 @@
 
 .slider {
   width: 100%;
-  padding: 0 8px 0 12px;
+  padding-top: 6px;
 
   :global {
 
@@ -140,4 +144,4 @@
       transition: all .2s;
     }
   }
-}
+}

+ 6 - 2
src/views/attend-class/component/rhythm-modal/index.tsx

@@ -14,6 +14,10 @@ export default defineComponent({
     activeStatus: {
       type: Boolean,
       default: false
+    },
+    imagePos: {
+      type: String,
+      default: 'left'
     }
   },
   emits: ['setIframe'],
@@ -25,11 +29,11 @@ export default defineComponent({
       location.origin
     }/classroom-app/#/tempo-practice?v=${+new Date()}&platform=modal&dataJson=${
       props.item.dataJson
-    }&Authorization=${userStore.getToken}&win=pc`;
+    }&Authorization=${userStore.getToken}&win=pc&imagePos=${props.imagePos}`;
     if (/(localhost)/.test(location.host)) {
       src = `http://localhost:9002/#/tempo-practice?v=${+new Date()}&platform=modal&dataJson=${
         props.item.dataJson
-      }&Authorization=${userStore.getToken}&win=pc`;
+      }&Authorization=${userStore.getToken}&win=pc&imagePos=${props.imagePos}`;
     }
 
     watch(

+ 1 - 1
src/views/attend-class/component/tools/pen.module.less

@@ -4,7 +4,7 @@
   right: 0;
   bottom: 0;
   top: 0;
-  z-index: 501;
+  z-index: 2899;
 }
 
 .open {

+ 8 - 1
src/views/attend-class/component/tools/pen.tsx

@@ -22,6 +22,10 @@ export default defineComponent({
     callStudents: {
       type: Array,
       default: () => []
+    },
+    imagePos: {
+      type: String,
+      default: 'left'
     }
   },
   setup(props) {
@@ -42,7 +46,9 @@ export default defineComponent({
     let src = `${origin}/classroom-whiteboard?t=${+new Date()}`;
 
     if (props.type === 'call') {
-      src = `${origin}/roll-call/index.html?t=${+new Date()}`;
+      src = `${origin}/roll-call/index.html?t=${+new Date()}&platform=modal&imagePos=${
+        props.imagePos
+      }`;
     }
 
     return () => (
@@ -108,6 +114,7 @@ export default defineComponent({
 
         {/* 布置作业 */}
         <NModal
+          z-index={3000}
           transformOrigin="center"
           v-model:show={modal.status}
           preset="card"

+ 231 - 106
src/views/attend-class/component/video-play.tsx

@@ -37,6 +37,10 @@ export default defineComponent({
     isEmtry: {
       type: Boolean,
       default: false
+    },
+    imagePos: {
+      type: String,
+      default: 'left'
     }
   },
   emits: [
@@ -69,7 +73,6 @@ export default defineComponent({
     const videoRef = ref();
     const videoItem = ref();
     const videoID = ref('video' + Date.now() + Math.floor(Math.random() * 100));
-    const speedBtnId = 'speed' + Date.now() + Math.floor(Math.random() * 100);
 
     // 对时间进行格式化
     const timeFormat = (num: number) => {
@@ -219,11 +222,6 @@ export default defineComponent({
       }); // player-container-id 为播放器容器 ID,必须与 html 中一致
 
       __init();
-
-      document.getElementById(speedBtnId)?.addEventListener('click', e => {
-        e.stopPropagation();
-        videoFroms.speedControl = !videoFroms.speedControl;
-      });
     });
     const stop = () => {
       videoItem.value.currentTime(0);
@@ -295,91 +293,6 @@ export default defineComponent({
             emit('close');
             emit('reset');
           }}>
-          <div class={styles.actions}>
-            <div class={styles.actionWrap}>
-              <div
-                class={styles.actionBtn}
-                onClick={() => {
-                  videoFroms.speedControl = false;
-                  onToggleVideo();
-                }}>
-                {videoFroms.paused ? (
-                  <img class={styles.playIcon} src={iconplay} />
-                ) : (
-                  <img class={styles.playIcon} src={iconpause} />
-                )}
-              </div>
-
-              <button class={styles.iconReplay} onClick={onReplay}>
-                <img src={iconLoop} />
-              </button>
-
-              <div class={styles.actionBtnSpeed} id={speedBtnId}>
-                <img src={iconSpeed} />
-
-                <div
-                  style={{
-                    display: videoFroms.speedControl ? 'block' : 'none'
-                  }}>
-                  <div
-                    class={styles.sliderPopup}
-                    onClick={(e: Event) => {
-                      e.stopPropagation();
-                    }}>
-                    <i
-                      class={styles.iconAdd}
-                      onClick={() => {
-                        if (videoFroms.defaultSpeed >= 1.5) {
-                          return;
-                        }
-
-                        if (videoItem.value) {
-                          videoFroms.defaultSpeed =
-                            (videoFroms.defaultSpeed * 10 + 1) / 10;
-                          videoItem.value.playbackRate(videoFroms.defaultSpeed);
-                        }
-                      }}></i>
-                    <NSlider
-                      value={videoFroms.defaultSpeed}
-                      step={0.1}
-                      max={1.5}
-                      min={0.5}
-                      vertical
-                      tooltip={false}
-                      onUpdate:value={(val: number) => {
-                        videoFroms.defaultSpeed = val;
-
-                        if (videoItem.value) {
-                          videoItem.value.playbackRate(videoFroms.defaultSpeed);
-                        }
-                      }}>
-                      {{
-                        thumb: () => (
-                          <div class={styles.sliderPoint}>
-                            {videoFroms.defaultSpeed}
-                            <span>x</span>
-                          </div>
-                        )
-                      }}
-                    </NSlider>
-                    <i
-                      class={[styles.iconCut]}
-                      onClick={() => {
-                        if (videoFroms.defaultSpeed <= 0.5) {
-                          return;
-                        }
-                        if (videoItem.value) {
-                          videoFroms.defaultSpeed =
-                            (videoFroms.defaultSpeed * 10 - 1) / 10;
-                          videoItem.value.playbackRate(videoFroms.defaultSpeed);
-                        }
-                      }}></i>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-
           <div class={styles.slider}>
             <NSlider
               value={videoFroms.currentTimeNum}
@@ -394,23 +307,235 @@ export default defineComponent({
               }}
             />
           </div>
-
-          <div class={styles.actions}>
-            <div class={styles.actionWrap}>
-              <div class={styles.time}>
-                <div
-                  class="plyr__time plyr__time--current"
-                  aria-label="Current time">
-                  {videoFroms.currentTime}
+          <div class={styles.tools}>
+            {props.imagePos === 'right' ? (
+              <>
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <div class={styles.time}>
+                      <div
+                        class="plyr__time plyr__time--current"
+                        aria-label="Current time">
+                        {videoFroms.currentTime}
+                      </div>
+                      <span class={styles.line}>/</span>
+                      <div
+                        class="plyr__time plyr__time--duration"
+                        aria-label="Duration">
+                        {videoFroms.duration}
+                      </div>
+                    </div>
+                  </div>
                 </div>
-                <span class={styles.line}>/</span>
-                <div
-                  class="plyr__time plyr__time--duration"
-                  aria-label="Duration">
-                  {videoFroms.duration}
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <div
+                      class={styles.actionBtnSpeed}
+                      onClick={e => {
+                        e.stopPropagation();
+                        videoFroms.speedControl = !videoFroms.speedControl;
+                      }}>
+                      <img src={iconSpeed} />
+                      <div
+                        style={{
+                          display: videoFroms.speedControl ? 'block' : 'none'
+                        }}>
+                        <div
+                          class={styles.sliderPopup}
+                          onClick={(e: Event) => {
+                            e.stopPropagation();
+                          }}>
+                          <i
+                            class={styles.iconAdd}
+                            onClick={() => {
+                              if (videoFroms.defaultSpeed >= 1.5) {
+                                return;
+                              }
+
+                              if (videoItem.value) {
+                                videoFroms.defaultSpeed =
+                                  (videoFroms.defaultSpeed * 10 + 1) / 10;
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}></i>
+                          <NSlider
+                            value={videoFroms.defaultSpeed}
+                            step={0.1}
+                            max={1.5}
+                            min={0.5}
+                            vertical
+                            tooltip={false}
+                            onUpdate:value={(val: number) => {
+                              videoFroms.defaultSpeed = val;
+
+                              if (videoItem.value) {
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}>
+                            {{
+                              thumb: () => (
+                                <div class={styles.sliderPoint}>
+                                  {videoFroms.defaultSpeed}
+                                  <span>x</span>
+                                </div>
+                              )
+                            }}
+                          </NSlider>
+                          <i
+                            class={[styles.iconCut]}
+                            onClick={() => {
+                              if (videoFroms.defaultSpeed <= 0.5) {
+                                return;
+                              }
+                              if (videoItem.value) {
+                                videoFroms.defaultSpeed =
+                                  (videoFroms.defaultSpeed * 10 - 1) / 10;
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}></i>
+                        </div>
+                      </div>
+                    </div>
+                    <button class={styles.iconReplay} onClick={onReplay}>
+                      <img src={iconLoop} />
+                    </button>
+                    <div
+                      class={styles.actionBtn}
+                      onClick={() => {
+                        videoFroms.speedControl = false;
+                        onToggleVideo();
+                      }}>
+                      {videoFroms.paused ? (
+                        <img class={styles.playIcon} src={iconplay} />
+                      ) : (
+                        <img class={styles.playIcon} src={iconpause} />
+                      )}
+                    </div>
+                  </div>
+                </div>
+              </>
+            ) : (
+              <>
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <div
+                      class={styles.actionBtn}
+                      onClick={() => {
+                        videoFroms.speedControl = false;
+                        onToggleVideo();
+                      }}>
+                      {videoFroms.paused ? (
+                        <img class={styles.playIcon} src={iconplay} />
+                      ) : (
+                        <img class={styles.playIcon} src={iconpause} />
+                      )}
+                    </div>
+
+                    <button class={styles.iconReplay} onClick={onReplay}>
+                      <img src={iconLoop} />
+                    </button>
+
+                    <div
+                      class={styles.actionBtnSpeed}
+                      onClick={e => {
+                        e.stopPropagation();
+                        videoFroms.speedControl = !videoFroms.speedControl;
+                      }}>
+                      <img src={iconSpeed} />
+
+                      <div
+                        style={{
+                          display: videoFroms.speedControl ? 'block' : 'none'
+                        }}>
+                        <div
+                          class={styles.sliderPopup}
+                          onClick={(e: Event) => {
+                            e.stopPropagation();
+                          }}>
+                          <i
+                            class={styles.iconAdd}
+                            onClick={() => {
+                              if (videoFroms.defaultSpeed >= 1.5) {
+                                return;
+                              }
+
+                              if (videoItem.value) {
+                                videoFroms.defaultSpeed =
+                                  (videoFroms.defaultSpeed * 10 + 1) / 10;
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}></i>
+                          <NSlider
+                            value={videoFroms.defaultSpeed}
+                            step={0.1}
+                            max={1.5}
+                            min={0.5}
+                            vertical
+                            tooltip={false}
+                            onUpdate:value={(val: number) => {
+                              videoFroms.defaultSpeed = val;
+
+                              if (videoItem.value) {
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}>
+                            {{
+                              thumb: () => (
+                                <div class={styles.sliderPoint}>
+                                  {videoFroms.defaultSpeed}
+                                  <span>x</span>
+                                </div>
+                              )
+                            }}
+                          </NSlider>
+                          <i
+                            class={[styles.iconCut]}
+                            onClick={() => {
+                              if (videoFroms.defaultSpeed <= 0.5) {
+                                return;
+                              }
+                              if (videoItem.value) {
+                                videoFroms.defaultSpeed =
+                                  (videoFroms.defaultSpeed * 10 - 1) / 10;
+                                videoItem.value.playbackRate(
+                                  videoFroms.defaultSpeed
+                                );
+                              }
+                            }}></i>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class={styles.actions}>
+                  <div class={styles.actionWrap}>
+                    <div class={styles.time}>
+                      <div
+                        class="plyr__time plyr__time--current"
+                        aria-label="Current time">
+                        {videoFroms.currentTime}
+                      </div>
+                      <span class={styles.line}>/</span>
+                      <div
+                        class="plyr__time plyr__time--duration"
+                        aria-label="Duration">
+                        {videoFroms.duration}
+                      </div>
+                    </div>
+                  </div>
                 </div>
-              </div>
-            </div>
+              </>
+            )}
           </div>
         </div>
       </div>

+ 19 - 14
src/views/attend-class/component/video.module.less

@@ -29,14 +29,15 @@
     left: 0;
     right: 0;
     width: 100%;
-    background-color: rgba(0, 0, 0, 0.7);
+    background: url('../image/../image/bg.png') no-repeat;
+    background-size: 100% 100%;
     // backdrop-filter: blur(26px);
-    height: 108px;
-    padding: 0 330px 0 40px !important;
-    display: flex;
-    align-items: center;
+    height: 120px;
+    padding: 0 40px !important;
     transition: all 0.301s;
-    z-index: 9;
+    display: flex;
+    justify-content: center;
+    flex-direction: column;
 
     .time {
       display: flex;
@@ -49,7 +50,8 @@
       line-height: 33px;
 
       &>div {
-        font-size: 24px !important;
+        font-size: 20px !important;
+        color: rgba(255,255,255,0.8);
       }
 
       .line {
@@ -64,7 +66,12 @@
       }
     }
   }
-
+  .tools{
+    display: flex;
+    justify-content: space-between;
+    padding: 0 10px;
+    margin-top: 10px;
+  }
   .actions {
     display: flex;
     justify-content: space-between;
@@ -80,10 +87,8 @@
     }
 
     .actionBtn {
-      display: flex;
-      width: 60px;
-      height: 60px;
-      padding: 4px 0;
+      width: 40px;
+      height: 40px;
       background: transparent;
       cursor: pointer;
 
@@ -123,7 +128,7 @@
 
   .slider {
     width: 100%;
-    padding: 0 4px 0 16px;
+    padding-top: 6px;
 
     :global {
 
@@ -345,4 +350,4 @@
 //       }
 //     }
 //   }
-// }
+// }

BIN
src/views/attend-class/image/bg.png


BIN
src/views/attend-class/image/bottom_icon1.png


BIN
src/views/attend-class/image/bottom_icon2.png


BIN
src/views/attend-class/image/bottom_icon3.png


BIN
src/views/attend-class/image/bottom_icon4.png


BIN
src/views/attend-class/image/icon-pause.png


BIN
src/views/attend-class/image/icon-play.png


BIN
src/views/attend-class/image/icon-replay.png


BIN
src/views/attend-class/image/icon-speed.png


BIN
src/views/attend-class/image/left_hide_icon.png


BIN
src/views/attend-class/image/right_hide_icon.png


BIN
src/views/attend-class/image/right_icon1.png


BIN
src/views/attend-class/image/right_icon10.png


BIN
src/views/attend-class/image/right_icon11.png


BIN
src/views/attend-class/image/right_icon12.png


BIN
src/views/attend-class/image/right_icon2.png


BIN
src/views/attend-class/image/right_icon3.png


BIN
src/views/attend-class/image/right_icon4.png


BIN
src/views/attend-class/image/right_icon5.png


BIN
src/views/attend-class/image/right_icon7.png


BIN
src/views/attend-class/image/right_icon8.png


BIN
src/views/attend-class/image/right_icon9.png


+ 92 - 171
src/views/attend-class/index.module.less

@@ -23,8 +23,6 @@
   }
 }
 
-
-
 .coursewarePlay {
   position: relative;
   height: 100vh;
@@ -222,7 +220,6 @@
 }
 
 :global {
-
   .top-enter-active,
   .top-leave-active {
     transition: transform 0.5s;
@@ -272,11 +269,10 @@
 
   :global {
     .n-drawer-header {
-      background-color: #F5F6FA !important;
+      background-color: #f5f6fa !important;
     }
   }
 
-
   .cardContainer {
     margin-bottom: 24px;
   }
@@ -286,7 +282,7 @@
       padding: 8px 0px 0px !important;
       text-align: center;
 
-      &>div {
+      & > div {
         // margin-bottom: 24px;
       }
     }
@@ -365,7 +361,6 @@
     gap: 0 48px !important;
   }
 
-
   .btnItem {
     display: flex;
     align-items: center;
@@ -386,16 +381,13 @@
     p {
       padding-top: 6px;
       font-size: 18px;
-      color: #FFFFFF;
+      color: #ffffff;
       line-height: 25px;
       text-align: center;
     }
-
-
   }
 }
 
-
 .attendClassModal {
   width: 442px;
   border-radius: 16px;
@@ -426,8 +418,6 @@
     }
   }
 
-
-
   .modelAttendContent {
     font-size: max(18px, 16px);
     color: #777777;
@@ -467,7 +457,6 @@
   }
 }
 
-
 .toolboxImg {
   width: 83px;
   height: 83px;
@@ -566,7 +555,6 @@
   background-color: #fff;
 }
 
-
 .showModalTone {
   width: 500px;
 
@@ -580,7 +568,7 @@
       text-align: center;
 
       span {
-        color: #EA4132;
+        color: #ea4132;
       }
     }
   }
@@ -605,7 +593,7 @@
       text-align: center;
 
       span {
-        color: #EA4132;
+        color: #ea4132;
       }
     }
   }
@@ -638,136 +626,125 @@
   }
 }
 
-.rightColumn {
+.rightColumn,
+.leftColumn {
   position: absolute;
-  right: 0;
-  top: 50%;
-  transform: translateY(-50%);
+  right: 14px;
+  bottom: 130px;
   background: rgba(0, 0, 0, 0.3);
   border-radius: 10px;
-  width: 76px;
+  width: 52px;
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 10px 0;
+  padding: 10px;
   transition: all 0.3s;
-
-  .rightItem {
-    width: 54px;
-    height: 54px;
-    margin-bottom: 12px;
+  .columnItemBox {
+    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+    padding: 5px 0;
+    &:last-child {
+      border-bottom: none;
+    }
+  }
+  .columnItem {
+    padding: 5px;
     cursor: pointer;
     position: relative;
     display: flex;
     align-items: center;
     justify-content: center;
     z-index: 9;
-
     &.active,
     &:hover {
       background: RGBA(255, 255, 255, 0.3);
       border-radius: 8px;
       z-index: 9;
     }
-
-    &::after {
-      content: "";
-      position: absolute;
-      left: 50%;
-      bottom: -6px;
-      transform: translateX(-50%);
-      width: 44px;
-      height: 1px;
-      background: rgba(255, 255, 255, 0.2);
-    }
-
     img {
-      width: 34px;
-      height: 34px;
-      margin: auto;
+      width: 28px;
+      height: 28px;
       z-index: 9;
     }
-
-    .rightTips {
-      position: absolute;
-      right: 24px;
-      top: 50;
-      transform: translateX(-50%);
-      background: rgba(0, 0, 0, 0.7);
-      border-radius: 6px;
-      width: 88px;
-      height: 34px;
-      line-height: 34px;
-      text-align: center;
-      font-size: max(16px, 12Px);
-      font-family: PingFangSC, PingFang SC;
-      font-weight: 500;
-      color: #FFFFFF;
-      // transition: all 0.8s;
-      z-index: 1;
-      opacity: 0;
-    }
-
-    &:hover {
-      .rightTips {
-        opacity: 1;
-      }
-    }
-  }
-
-  .rightItem:last-child {
-    width: 54px;
-    height: 36px;
-
-    img {
-      width: 18px;
-      height: 18px;
-    }
-
-    &::after {
-      display: none;
-    }
   }
 
   .itemDisabled {
     opacity: 0.7;
     cursor: not-allowed;
   }
-
-  .itemHide {
-    display: none;
+}
+:global {
+  .columnItemTooltip.n-tooltip {
+    background: #ffffff !important;
+    box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.1) !important;
+    border-radius: 20px !important;
+    padding: 0 !important;
+    margin-left: 22px !important;
+    &.rightColumnItemTooltip {
+      margin-right: 22px !important;
+    }
+    .tools {
+      padding: 10px 20px;
+      display: flex;
+      > div {
+        display: flex;
+        flex-direction: column;
+        margin-right: 16px;
+        cursor: pointer;
+        &.active,
+        &:hover {
+          opacity: 0.8;
+        }
+        &:last-child {
+          margin-right: 0;
+        }
+        img {
+          width: 56px;
+          height: 56px;
+        }
+        .tit {
+          margin-top: 4px;
+          text-align: center;
+          font-weight: 400;
+          font-size: max(6px, 12Px);
+          color: #383a3d;
+        }
+      }
+    }
   }
 }
-
-.rightColumnZ {
-  z-index: -1;
+.leftColumn {
+  left: 14px;
 }
-
 .rightColumnHide {
-  transform: translate(80px, -50%);
-
-  .rightTips {
-    display: none;
-  }
+  transform: translate(80px);
 }
-
-.rightHideIcon {
-  width: 30px;
+.leftColumnHide {
+  transform: translate(-80px);
+}
+.rightHideIcon,
+.leftHideIcon {
+  width: 28px;
   height: 60px;
   position: absolute;
   right: 0;
-  top: 50%;
-  transform: translate(60px, -50%);
+  bottom: 300px;
+  transform: translate(60px);
   z-index: 10;
   cursor: pointer;
   // transition: all 0.5s;
 }
-
+.leftHideIcon {
+  left: 0;
+  transform: translate(-60px);
+}
 .rightIconShow {
   animation: rightIn 0.3s ease 0.3s;
   animation-fill-mode: forwards;
 }
-
+.leftIconShow {
+  animation: leftIn 0.3s ease 0.3s;
+  animation-fill-mode: forwards;
+}
 @keyframes rightIn {
   0% {
     transform: translate(60px, -50%);
@@ -777,75 +754,20 @@
     transform: translate(0, -50%);
   }
 }
-
-.instrumentContainer {
-  background: #FFFFFF;
-  padding: 68px;
-  height: 100%;
-}
-
-.bottomColumn {
-  position: fixed;
-  right: 40px;
-  bottom: 26px;
-  display: flex;
-  z-index: 2;
-
-  .bottomItem {
-    width: 54px;
-    height: 54px;
-    background: rgba(0, 0, 0, 0.3);
-    border-radius: 10px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    margin-right: 16px;
-    position: relative;
-    cursor: pointer;
-
-    .bottomTips {
-      position: absolute;
-      left: 50%;
-      top: -40px;
-      transform: translateX(-50%);
-      opacity: 0;
-      background: rgba(0, 0, 0, 0.7);
-      border-radius: 6px;
-      width: 88px;
-      height: 34px;
-      line-height: 34px;
-      text-align: center;
-      font-size: max(16px, 12Px);
-      font-family: PingFangSC, PingFang SC;
-      font-weight: 500;
-      color: #FFFFFF;
-    }
-
-    &.active,
-    &:hover {
-      background: rgba(0, 0, 0, 0.5);
-
-      .bottomTips {
-        opacity: 1;
-      }
-    }
-
-    img {
-      width: 40px;
-      height: 40px;
-    }
-  }
-
-  .bottomItem:last-child {
-    margin-right: 0;
+@keyframes leftIn {
+  0% {
+    transform: translate(-60px, -50%);
   }
 
-  .itemDisabled {
-    opacity: 0.7;
-    cursor: not-allowed;
+  100% {
+    transform: translate(0, -50%);
   }
+}
 
-
+.instrumentContainer {
+  background: #ffffff;
+  padding: 68px;
+  height: 100%;
 }
 
 .selectMusicModal {
@@ -882,11 +804,10 @@
     flex: 1;
     height: 75vh;
 
-    &>div {
+    & > div {
       padding-top: 15px;
     }
   }
-
   :global {
     .train-container {
       // max-height: calc(var(--window-page-lesson-height) - 135px) !important;
@@ -903,4 +824,4 @@
     height: 75vh;
     box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
   }
-}
+}

+ 206 - 126
src/views/attend-class/index.tsx

@@ -67,13 +67,16 @@ import rightIconMetronome from './image/right_icon5.png';
 import rightIconTuner from './image/right_icon6.png';
 import rightIconTimer from './image/right_icon7.png';
 import rightIconCall from './image/right_icon10.png';
-import rightIconPackUp from './image/right_icon8.png';
+import rightIconPackUp from './image/right_icon11.png';
+import leftIconPackUp from './image/right_icon8.png';
 import rightIconMusic from './image/right_icon9.png';
 import bottomIconSwitch from './image/bottom_icon1.png';
 import bottomIconResource from './image/bottom_icon2.png';
 import bottomIconPre from './image/bottom_icon3.png';
 import bottomIconNext from './image/bottom_icon4.png';
+import rightIconTool from './image/right_icon12.png';
 import rightHideIcon from './image/right_hide_icon.png';
+import leftHideIcon from './image/left_hide_icon.png';
 import SelectResources from '../prepare-lessons/model/select-resources';
 import { getStudentAfterWork, getStudentList } from '../studentList/api';
 import TheNoticeBar from '/src/components/TheNoticeBar';
@@ -350,7 +353,16 @@ export default defineComponent({
       getDetail();
       getLessonCoursewareDetail();
       if (data.type === 'preview') {
-        rightList.splice(6, 1);
+        // 预览隐藏点名和布置作业
+        const hideListIds = [2, 10];
+        let index = rightList.length - 1;
+        while (index >= 0) {
+          if (hideListIds.includes(rightList[index].id)) {
+            console.log(index);
+            rightList.splice(index, 1);
+          }
+          index--;
+        }
       }
       rollCallStudentList();
     });
@@ -398,7 +410,6 @@ export default defineComponent({
         }, 200);
       }
     );
-
     const formatParentId = (id: any, list: any, ids = [] as any) => {
       for (const item of list) {
         if (item.knowledgeList && item.knowledgeList.length > 0) {
@@ -1165,36 +1176,30 @@ export default defineComponent({
     // 右侧菜单栏
     const rightList = reactive([
       {
-        name: '曲目资源',
-        name2: '曲目资源',
-        icon: rightIconMusic,
-        id: 9
+        name: '上一张',
+        icon: bottomIconPre,
+        id: 11
       },
       {
-        name: '批注',
-        icon: rightIconPostil,
-        id: 3
+        name: '下一张',
+        icon: bottomIconNext,
+        id: 12
       },
       {
-        name: '白板',
-        icon: rightIconWhiteboard,
-        id: 4
+        name: '切换章节',
+        icon: bottomIconSwitch,
+        id: 13
       },
       {
-        name: '节拍器',
-        icon: rightIconMetronome,
-        id: 5
+        name: '资源列表',
+        icon: bottomIconResource,
+        id: 14
       },
       {
-        name: '计时器',
-        icon: rightIconTimer,
-        id: 7
+        name: '曲目资源',
+        icon: rightIconMusic,
+        id: 9
       },
-      // {
-      //   name: '调音器',
-      //   icon: rightIconTuner,
-      //   id: 6
-      // },
       {
         name: '点名',
         icon: rightIconCall,
@@ -1206,6 +1211,11 @@ export default defineComponent({
         id: 2
       },
       {
+        name: '工具箱',
+        icon: rightIconTool,
+        id: 15
+      },
+      {
         name: '结束课程',
         name2: '结束预览',
         icon: rightIconEnd,
@@ -1213,40 +1223,55 @@ export default defineComponent({
       },
       {
         name: '收起',
-        icon: rightIconPackUp,
+        icon: leftIconPackUp,
         id: 8
       }
     ]);
-
-    // 底部菜单栏
-    const bottomList = reactive([
+    const tooltipList = [
       {
-        name: '切换章节',
-        icon: bottomIconSwitch,
-        id: 1
+        name: '节拍器',
+        icon: rightIconMetronome,
+        id: 5
       },
       {
-        name: '资源列表',
-        icon: bottomIconResource,
-        id: 2
+        name: '计时器',
+        icon: rightIconTimer,
+        id: 7
       },
       {
-        name: '上一张',
-        icon: bottomIconPre,
+        name: '批注',
+        icon: rightIconPostil,
         id: 3
       },
       {
-        name: '下一张',
-        icon: bottomIconNext,
+        name: '白板',
+        icon: rightIconWhiteboard,
         id: 4
       }
-    ]);
+      // {
+      //   name: '调音器',
+      //   icon: rightIconTuner,
+      //   id: 6
+      // }
+    ];
     // 默认收起菜单
-    const rightColumnShow = ref(false);
-
+    const columnShow = ref(true);
+    // 菜单位置
+    const columnPos = ref<'left' | 'right'>('left');
+    watch(columnPos, () => {
+      for (let i = 0; i < data.itemList.length; i++) {
+        const activeItem = data.itemList[i];
+        if (activeItem.type === 'RHYTHM') {
+          activeItem.iframeRef?.contentWindow?.postMessage(
+            { api: 'imagePos', data: columnPos.value },
+            '*'
+          );
+        }
+      }
+    });
     // 右边栏操作
     const operateRightBtn = async (id: number) => {
-      if (id !== 8) {
+      if (![8, 11, 12, 13, 14].includes(id)) {
         handleStop(false);
       }
 
@@ -1327,7 +1352,7 @@ export default defineComponent({
           startShowModal('setTimeIcon');
           break;
         case 8:
-          rightColumnShow.value = false;
+          columnShow.value = false;
           break;
         case 9:
           // 选择曲目时需要暂停所有播放
@@ -1346,6 +1371,23 @@ export default defineComponent({
             return;
           }
           break;
+        case 11:
+          if (!isUpArrow.value) return;
+          handlePreAndNext('up');
+          break;
+        case 12:
+          if (!isDownArrow.value) return;
+          handlePreAndNext('down');
+          break;
+        case 13:
+          popupData.chapterOpen = true;
+          break;
+        case 14:
+          popupData.open = true;
+          nextTick(() => {
+            scrollResourceSection();
+          });
+          break;
         default:
           break;
       }
@@ -1377,31 +1419,6 @@ export default defineComponent({
       }
     };
 
-    // 底部悬浮按钮操作
-    const operateBottomBtn = (id: number) => {
-      switch (id) {
-        case 1:
-          popupData.chapterOpen = true;
-          break;
-        case 2:
-          popupData.open = true;
-          nextTick(() => {
-            scrollResourceSection();
-          });
-          break;
-        case 3:
-          if (!isUpArrow.value) return;
-          handlePreAndNext('up');
-          break;
-        case 4:
-          if (!isDownArrow.value) return;
-          handlePreAndNext('down');
-          break;
-        default:
-          break;
-      }
-    };
-
     // 滚动到某个元素的位置
     const scrollResourceSection = () => {
       const drawerCardItemRefs =
@@ -1456,6 +1473,7 @@ export default defineComponent({
                   }
                   class={styles.itemDiv}>
                   <VideoPlay
+                    imagePos={columnPos.value}
                     ref={(el: any) => (data.videoItemRef = el)}
                     item={activeVideoItem.value}
                     showModel={activeData.model}
@@ -1585,6 +1603,7 @@ export default defineComponent({
                         <img src={m.content} />
                       ) : m.type === 'SONG' ? (
                         <AudioPay
+                          imagePos={columnPos.value}
                           item={m}
                           activeStatus={popupData.activeIndex === mIndex}
                           ref={(v: any) => (data.audioRefs[mIndex] = v)}
@@ -1628,6 +1647,7 @@ export default defineComponent({
                         <RhythmModal
                           item={m}
                           activeStatus={popupData.activeIndex === mIndex}
+                          imagePos={columnPos.value}
                           onSetIframe={(el: any) => {
                             m.iframeRef = el;
                           }}
@@ -1689,71 +1709,130 @@ export default defineComponent({
         <div
           class={[
             styles.rightColumn,
-            !rightColumnShow.value ? styles.rightColumnHide : '',
-            studyData.type !== 'init' &&
-            (studyData.penShow || studyData.whiteboardShow)
-              ? styles.rightColumnZ
-              : ''
+            columnShow.value && columnPos.value === 'right'
+              ? ''
+              : styles.rightColumnHide
           ]}>
-          {rightList.map((item: any, index: number) => (
-            <div
-              class={[
-                styles.rightItem,
-                (item.id === 2 && data.preStudentNum <= 0) ||
-                (item.id === 10 && studyData.callStudentList.length <= 0)
-                  ? styles.itemDisabled
-                  : '',
-                item.id === 10 && !data.classId ? styles.itemHide : ''
-              ]}
-              onClick={() => operateRightBtn(item.id)}>
-              <NTooltip showArrow={false} placement="left">
-                {{
-                  trigger: () => <img src={item.icon} />,
-                  default: (
-                    <>
-                      {index === rightList.length - 2 && data.type === 'preview'
-                        ? item.name2
-                        : item.name}
-                    </>
-                  )
-                }}
-              </NTooltip>
+          {rightList.map((item: any) => (
+            <div class={styles.columnItemBox}>
+              <div
+                class={[
+                  styles.columnItem,
+                  (item.id === 2 && data.preStudentNum <= 0) ||
+                  (item.id === 10 && studyData.callStudentList.length <= 0) ||
+                  (item.id === 11 && !isUpArrow.value) ||
+                  (item.id === 12 && !isDownArrow.value)
+                    ? styles.itemDisabled
+                    : ''
+                ]}
+                onClick={() => operateRightBtn(item.id)}>
+                <NTooltip
+                  showArrow={false}
+                  placement="left"
+                  class={[
+                    item.id === 15
+                      ? 'columnItemTooltip rightColumnItemTooltip'
+                      : ''
+                  ]}>
+                  {{
+                    trigger: () => (
+                      <img src={item.id === 8 ? rightIconPackUp : item.icon} />
+                    ),
+                    default: () =>
+                      item.id === 15 ? (
+                        <div class="tools">
+                          {tooltipList.map(i => (
+                            <div onClick={() => operateRightBtn(i.id)}>
+                              <img src={i.icon} />
+                              <div class="tit">{i.name}</div>
+                            </div>
+                          ))}
+                        </div>
+                      ) : item.id === 1 && data.type === 'preview' ? (
+                        item.name2
+                      ) : (
+                        item.name
+                      )
+                  }}
+                </NTooltip>
+              </div>
             </div>
           ))}
         </div>
-        {!rightColumnShow.value && (
-          <img
-            class={[
-              styles.rightHideIcon,
-              !rightColumnShow.value ? styles.rightIconShow : ''
-            ]}
-            src={rightHideIcon}
-            onClick={() => (rightColumnShow.value = true)}
-          />
-        )}
-        {/* 右下角悬浮按钮 */}
-        <div class={styles.bottomColumn}>
-          {bottomList.map((item: any, index: number) => (
-            <div
-              class={[
-                styles.bottomItem,
-                (item.id === 3 && !isUpArrow.value) ||
-                (item.id === 4 && !isDownArrow.value)
-                  ? styles.itemDisabled
-                  : ''
-              ]}
-              onClick={() => operateBottomBtn(item.id)}>
-              <NTooltip showArrow={false} placement="top">
-                {{
-                  trigger: () => <img src={item.icon} />,
-                  default: <>{item.name}</>
-                }}
-              </NTooltip>
-              {/* <img src={item.icon} />
-              <div class={styles.bottomTips}>{item.name}</div> */}
+        <img
+          class={[
+            styles.rightHideIcon,
+            !(columnShow.value && columnPos.value === 'right')
+              ? styles.rightIconShow
+              : ''
+          ]}
+          src={rightHideIcon}
+          onClick={() => {
+            columnPos.value = 'right';
+            columnShow.value = true;
+          }}
+        />
+        {/* 左边操作栏 */}
+        <div
+          class={[
+            styles.leftColumn,
+            columnShow.value && columnPos.value === 'left'
+              ? ''
+              : styles.leftColumnHide
+          ]}>
+          {rightList.map((item: any) => (
+            <div class={styles.columnItemBox}>
+              <div
+                class={[
+                  styles.columnItem,
+                  (item.id === 2 && data.preStudentNum <= 0) ||
+                  (item.id === 10 && studyData.callStudentList.length <= 0) ||
+                  (item.id === 11 && !isUpArrow.value) ||
+                  (item.id === 12 && !isDownArrow.value)
+                    ? styles.itemDisabled
+                    : ''
+                ]}
+                onClick={() => operateRightBtn(item.id)}>
+                <NTooltip
+                  showArrow={false}
+                  placement="right"
+                  class={[item.id === 15 ? 'columnItemTooltip' : '']}>
+                  {{
+                    trigger: () => <img src={item.icon} />,
+                    default: () =>
+                      item.id === 15 ? (
+                        <div class="tools">
+                          {tooltipList.map(i => (
+                            <div onClick={() => operateRightBtn(i.id)}>
+                              <img src={i.icon} />
+                              <div class="tit">{i.name}</div>
+                            </div>
+                          ))}
+                        </div>
+                      ) : item.id === 1 && data.type === 'preview' ? (
+                        item.name2
+                      ) : (
+                        item.name
+                      )
+                  }}
+                </NTooltip>
+              </div>
             </div>
           ))}
         </div>
+        <img
+          class={[
+            styles.leftHideIcon,
+            !(columnShow.value && columnPos.value === 'left')
+              ? styles.leftIconShow
+              : ''
+          ]}
+          src={leftHideIcon}
+          onClick={() => {
+            columnPos.value = 'left';
+            columnShow.value = true;
+          }}
+        />
 
         {/* 显示列表 */}
         <NDrawer
@@ -1826,6 +1905,7 @@ export default defineComponent({
 
         {studyData.callShow && (
           <Pen
+            imagePos={columnPos.value}
             callStudents={studyData.callStudentList}
             show={studyData.type === 'call'}
             type={studyData.type}