车间能级提升-智能设备管理系统
朱桂飞
2025-01-09 3e8f7f239bedae0b4f04a1ac6bd443ba6298f73c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<script lang="ts" setup>
import { ref, watch } from 'vue';
 
import { cn } from '@vben-core/shared/utils';
 
interface Props {
  class?: string;
  /**
   * @zh_CN 最小加载时间
   * @en_US Minimum loading time
   */
  minLoadingTime?: number;
  /**
   * @zh_CN loading状态开启
   */
  spinning?: boolean;
}
 
defineOptions({
  name: 'VbenSpinner',
});
 
const props = withDefaults(defineProps<Props>(), {
  minLoadingTime: 50,
});
// const startTime = ref(0);
const showSpinner = ref(false);
const renderSpinner = ref(true);
const timer = ref<ReturnType<typeof setTimeout>>();
 
watch(
  () => props.spinning,
  (show) => {
    if (!show) {
      showSpinner.value = false;
      clearTimeout(timer.value);
      return;
    }
 
    // startTime.value = performance.now();
    timer.value = setTimeout(() => {
      // const loadingTime = performance.now() - startTime.value;
 
      showSpinner.value = true;
      if (showSpinner.value) {
        renderSpinner.value = true;
      }
    }, props.minLoadingTime);
  },
  {
    immediate: true,
  },
);
 
function onTransitionEnd() {
  if (!showSpinner.value) {
    renderSpinner.value = false;
  }
}
</script>
 
<template>
  <div
    :class="
      cn(
        'flex-center z-100 bg-overlay-content absolute left-0 top-0 size-full backdrop-blur-sm transition-all duration-500',
        {
          'invisible opacity-0': !showSpinner,
        },
        props.class,
      )
    "
    @transitionend="onTransitionEnd"
  >
    <div
      class="loader before:bg-primary/50 after:bg-primary relative size-12 before:absolute before:left-0 before:top-[60px] before:h-[5px] before:w-12 before:rounded-[50%] before:content-[''] after:absolute after:left-0 after:top-0 after:h-full after:w-full after:rounded after:content-['']"
    ></div>
  </div>
</template>
 
<style scoped>
.loader {
  &::before {
    animation: loader-shadow-ani 0.5s linear infinite;
  }
 
  &::after {
    animation: loader-jump-ani 0.5s linear infinite;
  }
}
 
@keyframes loader-jump-ani {
  15% {
    border-bottom-right-radius: 3px;
  }
 
  25% {
    transform: translateY(9px) rotate(22.5deg);
  }
 
  50% {
    border-bottom-right-radius: 40px;
    transform: translateY(18px) scale(1, 0.9) rotate(45deg);
  }
 
  75% {
    transform: translateY(9px) rotate(67.5deg);
  }
 
  100% {
    transform: translateY(0) rotate(90deg);
  }
}
 
@keyframes loader-shadow-ani {
  0%,
  100% {
    transform: scale(1, 1);
  }
 
  50% {
    transform: scale(1.2, 1);
  }
}
</style>