From aa5530f51b733c6550dba59877a0301763be3d21 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sun, 22 Mar 2026 15:03:02 +0800
Subject: [PATCH] 优化页签功能&支持全屏按钮操作

---
 ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue |   79 +++++++++++++++++++++++++++++++++------
 1 files changed, 67 insertions(+), 12 deletions(-)

diff --git a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
index c110bf1..3dbd9ae 100644
--- a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
+++ b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
@@ -5,7 +5,7 @@
 </template>
 
 <script>
-const tagAndTagSpacing = 4 // tagAndTagSpacing
+const tagAndTagSpacing = 4
 
 export default {
   name: 'ScrollPane',
@@ -26,13 +26,44 @@
     this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
   },
   methods: {
+    smoothScrollTo(target) {
+      const $scrollWrapper = this.scrollWrapper
+      const start = $scrollWrapper.scrollLeft
+      const distance = target - start
+      const duration = 300
+      let startTime = null
+
+      function ease(t, b, c, d) {
+        t /= d / 2
+        if (t < 1) return c / 2 * t * t + b
+        t--
+        return -c / 2 * (t * (t - 2) - 1) + b
+      }
+
+      const emit = this.$emit.bind(this)
+      function step(timestamp) {
+        if (!startTime) startTime = timestamp
+        const elapsed = timestamp - startTime
+        $scrollWrapper.scrollLeft = ease(elapsed, start, distance, duration)
+        if (elapsed < duration) {
+          requestAnimationFrame(step)
+        } else {
+          $scrollWrapper.scrollLeft = target
+          emit('updateArrows')
+        }
+      }
+
+      requestAnimationFrame(step)
+    },
     handleScroll(e) {
       const eventDelta = e.wheelDelta || -e.deltaY * 40
       const $scrollWrapper = this.scrollWrapper
       $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+      this.$emit('updateArrows')
     },
     emitScroll() {
       this.$emit('scroll')
+      this.$emit('updateArrows')
     },
     moveToTarget(currentTag) {
       const $container = this.$refs.scrollContainer.$el
@@ -43,33 +74,55 @@
       let firstTag = null
       let lastTag = null
 
-      // find first tag and last tag
       if (tagList.length > 0) {
         firstTag = tagList[0]
         lastTag = tagList[tagList.length - 1]
       }
 
       if (firstTag === currentTag) {
-        $scrollWrapper.scrollLeft = 0
+        this.smoothScrollTo(0)
       } else if (lastTag === currentTag) {
-        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
+        this.smoothScrollTo($scrollWrapper.scrollWidth - $containerWidth)
       } else {
-        // find preTag and nextTag
         const currentIndex = tagList.findIndex(item => item === currentTag)
         const prevTag = tagList[currentIndex - 1]
         const nextTag = tagList[currentIndex + 1]
-
-        // the tag's offsetLeft after of nextTag
         const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
-
-        // the tag's offsetLeft before of prevTag
         const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
 
         if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
-          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
+          this.smoothScrollTo(afterNextTagOffsetLeft - $containerWidth)
         } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
-          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
+          this.smoothScrollTo(beforePrevTagOffsetLeft)
         }
+      }
+    },
+    // 向左滚动固定距离
+    scrollLeft() {
+      const $scrollWrapper = this.scrollWrapper
+      this.smoothScrollTo(Math.max(0, $scrollWrapper.scrollLeft - 200))
+    },
+    // 向右滚动固定距离
+    scrollRight() {
+      const $scrollWrapper = this.scrollWrapper
+      const maxScroll = $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth
+      this.smoothScrollTo(Math.min(maxScroll, $scrollWrapper.scrollLeft + 200))
+    },
+    // 直接平滑滚动到最左端
+    scrollToStart() {
+      this.smoothScrollTo(0)
+    },
+    // 直接平滑滚动到最右端
+    scrollToEnd() {
+      const $scrollWrapper = this.scrollWrapper
+      this.smoothScrollTo($scrollWrapper.scrollWidth - $scrollWrapper.clientWidth)
+    },
+    // 获取是否可以继续向左/右滚动
+    getScrollState() {
+      const $scrollWrapper = this.scrollWrapper
+      return {
+        canLeft: $scrollWrapper.scrollLeft > 0,
+        canRight: $scrollWrapper.scrollLeft < $scrollWrapper.scrollWidth - $scrollWrapper.clientWidth - 1
       }
     }
   }
@@ -87,7 +140,9 @@
       bottom: 0px;
     }
     .el-scrollbar__wrap {
-      height: 49px;
+      height: 34px;
+      display: flex;
+      align-items: center;
     }
   }
 }

--
Gitblit v1.9.3