Ver código fonte

feat: fix bug处理

lixiangrui 3 semanas atrás
pai
commit
a1a6275f7d

+ 2 - 1
src/directive/index.js

@@ -1,11 +1,12 @@
1 1
 import hasRole from './permission/hasRole'
2 2
 import hasPermi from './permission/hasPermi'
3 3
 import copyText from './common/copyText'
4
-import { vCardExpand } from './view/index'
4
+import { vCardExpand, autoScrollDirective } from './view/index'
5 5
 
6 6
 export default function directive(app){
7 7
   app.directive('hasRole', hasRole)
8 8
   app.directive('hasPermi', hasPermi)
9 9
   app.directive('copyText', copyText)
10 10
   app.directive('card-expand', vCardExpand)
11
+  app.directive('auto-scroll', autoScrollDirective)
11 12
 }

+ 164 - 0
src/directive/view/index.js

@@ -233,6 +233,170 @@ export const vCardExpand = {
233 233
   }
234 234
 }
235 235
 
236
+
237
+
238
+// 自动滚动公共方法
239
+const autoScrollUtils = {
240
+  /**
241
+   * 初始化自动滚动
242
+   * @param {HTMLElement} scrollContainer - 滚动容器元素
243
+   * @param {Object} options - 配置选项
244
+   * @returns {Object} 控制方法
245
+   */
246
+  init (scrollContainer, options = {}) {
247
+    const defaultOptions = {
248
+      speed: 0.2,
249
+      pauseDuration: 3000,
250
+      autoStart: true
251
+    };
252
+
253
+    const config = { ...defaultOptions, ...options };
254
+
255
+    // 状态变量
256
+    let isScrolling = config.autoStart;
257
+    let animationId = null;
258
+    let direction = 'down';
259
+    let isAtEdge = false;
260
+    let curScrollTop = scrollContainer.scrollTop;
261
+
262
+    // 滚动函数
263
+    const scroll = () => {
264
+      if (!isScrolling) {
265
+        if (animationId) {
266
+          cancelAnimationFrame(animationId);
267
+          animationId = null;
268
+        }
269
+        return;
270
+      }
271
+
272
+      const scrollHeight = scrollContainer.scrollHeight;
273
+      const clientHeight = scrollContainer.clientHeight;
274
+      
275
+      const scrollTop = scrollContainer.scrollTop;
276
+
277
+      // 检查边界
278
+      const isAtBottom = Math.abs(scrollTop + clientHeight - scrollHeight) < 1;
279
+      const isAtTop = scrollTop < 1;
280
+      
281
+
282
+      if ((isAtBottom && direction === 'down') || (isAtTop && direction === 'up')) {
283
+        if (!isAtEdge) {
284
+          isAtEdge = true;
285
+          setTimeout(() => {
286
+            direction = direction === 'down' ? 'up' : 'down';
287
+            isAtEdge = false;
288
+            animationId = requestAnimationFrame(scroll);
289
+          }, config.pauseDuration);
290
+          return;
291
+        }
292
+      } else {
293
+        isAtEdge = false;
294
+      }
295
+      
296
+      // 执行滚动
297
+      if (direction === 'down') {
298
+        curScrollTop += config.speed
299
+      } else {
300
+        curScrollTop -= config.speed
301
+      }
302
+      scrollContainer.scrollTop = Math.floor(curScrollTop)
303
+      animationId = requestAnimationFrame(scroll);
304
+    };
305
+
306
+    // 控制方法
307
+    const start = () => {
308
+      if (isScrolling) return;
309
+      isScrolling = true;
310
+      animationId = requestAnimationFrame(scroll);
311
+    };
312
+
313
+    const pause = () => {
314
+      isScrolling = false;
315
+      if (animationId) {
316
+        cancelAnimationFrame(animationId);
317
+        animationId = null;
318
+      }
319
+    };
320
+
321
+    const resume = () => {
322
+      if (isScrolling && animationId) return;
323
+      curScrollTop = scrollContainer.scrollTop
324
+      isScrolling = true;
325
+      animationId = requestAnimationFrame(scroll);
326
+    };
327
+
328
+    const stop = () => {
329
+      isScrolling = false;
330
+      scrollContainer.scrollTop = 0;
331
+      direction = 'down';
332
+      if (animationId) {
333
+        cancelAnimationFrame(animationId);
334
+        animationId = null;
335
+      }
336
+    };
337
+
338
+    return { start, pause, resume, stop };
339
+  }
340
+};
341
+
342
+export const autoScrollDirective = {
343
+  mounted (el, binding) {
344
+    const config = binding.value || {};
345
+
346
+    // 默认配置
347
+    const defaultConfig = {
348
+      speed: 0.2, // 滚动速度 px/帧
349
+      direction: 'down', // 初始方向
350
+      pauseDuration: 3000, // 到底部/顶部暂停时间
351
+      hoverPause: true, // 鼠标悬停暂停
352
+      autoStart: true // 是否自动开始
353
+    };
354
+
355
+    const options = { ...defaultConfig, ...config };
356
+
357
+    const autoScrollHandler = autoScrollUtils.init(el.querySelector('.el-scrollbar__wrap'), {
358
+      speed: options.speed,
359
+      pauseDuration: options.pauseDuration
360
+    })
361
+
362
+
363
+    // 鼠标悬停暂停功能
364
+    if (options.hoverPause) {
365
+      el.addEventListener('mouseenter', () => {
366
+        autoScrollHandler.pause()
367
+      });
368
+
369
+      el.addEventListener('mouseleave', () => {
370
+        autoScrollHandler.resume()
371
+      });
372
+    }
373
+
374
+    // 存储方法到元素上,供外部调用
375
+    el._autoScroll = {
376
+      start: autoScrollHandler.start,
377
+      pause: autoScrollHandler.pause,
378
+      resume: autoScrollHandler.resume,
379
+      stop: autoScrollHandler.stop
380
+    };
381
+  },
382
+  updated (el, binding) {
383
+    if (el._autoScroll) {
384
+      nextTick(() => {
385
+        el._autoScroll.resume();
386
+      })
387
+    }
388
+  },
389
+  unmounted (el) {
390
+    // 清理
391
+    if (el._autoScroll) {
392
+      el._autoScroll.stop();
393
+      delete el._autoScroll;
394
+    }
395
+  }
396
+};
397
+
398
+
399
+
236 400
 // 导出工具函数供外部使用
237 401
 export {
238 402
   toggleCard,

+ 1 - 2
src/views/portraitManagement/components/ProfileMembers.vue

@@ -36,9 +36,8 @@ const props = defineProps({
36 36
 
37 37
 <style lang="scss" scoped>
38 38
 .table-container {
39
+  height: 100%;
39 40
   max-height: 400px;
40
-  overflow-y: auto;
41
-
42 41
   &::-webkit-scrollbar {
43 42
     width: 6px;
44 43
   }

+ 19 - 7
src/views/portraitManagement/components/rollingTable.vue

@@ -5,8 +5,8 @@
5 5
         <div class="header-cell" v-for="(col, index) in columns" :key="index">{{ col.label }}</div>
6 6
       </div>
7 7
     </div>
8
-    <div class="table-body">
9
-      <div class="scroll-content" ref="scrollContentRef">
8
+    <div class="table-body" v-auto-scroll="{ speed: 0.3 }">
9
+      <div class="scroll-content el-scrollbar__wrap">
10 10
         <div class="body-row" v-for="(row, rowIndex) in scrollData" :key="rowIndex">
11 11
           <div class="body-cell" v-for="(col, cellIndex) in columns" :key="cellIndex">{{ row[col.prop] }}</div>
12 12
         </div>
@@ -98,19 +98,19 @@ const stopScroll = () => {
98 98
 onMounted(() => {
99 99
   isActive = true
100 100
   if (props.data.length > 0) {
101
-    startScroll()
101
+    // startScroll()
102 102
   }
103 103
 })
104 104
 
105 105
 watch(() => props.data, (val) => {
106 106
   if (val && val.length > 0) {
107
-    startScroll()
107
+    // startScroll()
108 108
   }
109 109
 })
110 110
 
111 111
 onUnmounted(() => {
112 112
   isActive = false
113
-  stopScroll()
113
+  // stopScroll()
114 114
 })
115 115
 </script>
116 116
 
@@ -118,6 +118,9 @@ onUnmounted(() => {
118 118
 .rolling-table {
119 119
   width: 100%;
120 120
   overflow: hidden;
121
+  height: 100%;
122
+  display: flex;
123
+  flex-direction: column;
121 124
 }
122 125
 
123 126
 .table-header {
@@ -140,14 +143,23 @@ onUnmounted(() => {
140 143
 
141 144
 .table-body {
142 145
   overflow: hidden;
143
-  max-height: 300px;
146
+  flex: 1;
144 147
 }
145 148
 
146 149
 .scroll-content {
147 150
   display: flex;
148 151
   flex-direction: column;
149 152
   gap: 2px;
150
-  will-change: transform;
153
+  height: 100%;
154
+  // will-change: transform;
155
+  overflow-y: auto;
156
+  &::-webkit-scrollbar-track {
157
+    background: transparent;
158
+  }
159
+  &::-webkit-scrollbar-thumb {
160
+    background: linear-gradient(225deg, #4355cb, #873dc3);
161
+    border-radius: 4px;
162
+  }
151 163
 }
152 164
 
153 165
 .body-row {

+ 1 - 1
src/views/portraitManagement/deptProfile/component/profile.vue

@@ -42,7 +42,7 @@ const teamColumns = [
42 42
   { label: '平均年龄', prop: 'avgAge' },
43 43
   { label: '平均工龄', prop: 'avgWorkYears' },
44 44
   { label: '职业资格等级证书数量', prop: 'qualificationLevel' },
45
-  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
45
+  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
46 46
   { label: '综合得分', prop: 'totalScore' }
47 47
 ]
48 48
 

+ 1 - 3
src/views/portraitManagement/groupProfile/component/profile.vue

@@ -48,10 +48,8 @@ const memberColumns = ref([
48 48
   { label: '民族', prop: 'nation' },
49 49
   { label: '政治面貌', prop: 'politicalStatus' },
50 50
   { label: '职务', prop: 'roleNames' },
51
-  { label: '岗位资质', prop: 'qualificationLevel' },
52
-  { label: '职业技能等级', prop: 'skillLevel' },
51
+  { label: '职业技能等级', prop: 'qualificationLevel' },
53 52
   { label: '开机年限', prop: 'xrayOperatorYears' },
54
-  { label: '平均年限', prop: 'avgYears' },
55 53
   { label: '综合得分', prop: 'totalScore' }
56 54
 ])
57 55
 

+ 1 - 1
src/views/portraitManagement/stationProfile/component/profile.vue

@@ -45,7 +45,7 @@ const teamColumns = [
45 45
   { label: '平均年龄', prop: 'avgAge' },
46 46
   { label: '平均工龄', prop: 'avgWorkYears' },
47 47
   { label: '职业资格等级证书数量', prop: 'qualificationLevel' },
48
-  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
48
+  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
49 49
   { label: '综合得分', prop: 'totalScore' }
50 50
 ]
51 51
 

+ 1 - 1
src/views/portraitManagement/teamProfile/component/profile.vue

@@ -43,7 +43,7 @@ const teamColumns = [
43 43
   { label: '平均年龄', prop: 'avgAge' },
44 44
   { label: '平均工龄', prop: 'avgWorkYears' },
45 45
   { label: '职业资格等级证书数量', prop: 'qualificationLevel' },
46
-  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
46
+  { label: '平均开机年', prop: 'avgXrayOperatorYears' },
47 47
   { label: '综合得分', prop: 'totalScore' }
48 48
 ]
49 49