timeLine.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <div class="time-line" v-show="isShow">
  3. <div class="play" @click="handleChange">
  4. <img
  5. class="icon"
  6. :src="`/src/assets/images/warningHome/${isCounting ? 'transparent-pause-icon.png' : 'transparent-play-icon.png'}`"
  7. alt=""
  8. />
  9. </div>
  10. <div class="line">
  11. <div class="active-line" :style="{ width: numList[active] + '%' }"></div>
  12. <div :class="['dot-item', { mr: index === list.length - 1 }]" v-for="(item, index) in list" :key="index">
  13. <div :class="['dot', { active: active === index }]"></div>
  14. <span :class="{ text: active === index }">{{ item }}</span>
  15. </div>
  16. </div>
  17. </div>
  18. </template>
  19. <script setup>
  20. import { ref, onDeactivated,computed ,watch, onMounted} from "vue";
  21. import { useStore } from "vuex";
  22. const store = useStore();
  23. const isShow = ref(true)
  24. // const explainParams = computed(() => store.state.home.explainData);
  25. // // 监听 periodId 的变化
  26. // watch(() => explainParams.value, (newValue, oldValue) => {
  27. // isShow.value = false
  28. // if (newValue.id) {
  29. // isShow.value = true
  30. // }
  31. // });
  32. onMounted(()=>{
  33. // restActive()
  34. fetchYearQuarter()
  35. })
  36. const fetchYearQuarter = () => {
  37. VE_API.warning.fetchYearQuarter().then(res => {
  38. if (res.code === 0 && res.data && res.data.length > 0) {
  39. // 转换接口数据为时间轴显示格式
  40. const formattedList = res.data.map((item) =>
  41. formatYearQuarter(item.year, item.quarter)
  42. );
  43. // 更新时间轴列表
  44. list.value = formattedList;
  45. // 重置激活状态
  46. // restActive();
  47. }
  48. });
  49. }
  50. const active = ref(0);
  51. const isCounting = ref(false);
  52. // 计算进度条百分比位置(根据数据数量动态计算)
  53. const numList = computed(() => {
  54. return [4,17,31,45,59,72,86,99];
  55. // const count = list.value.length;
  56. // if (count <= 1) return [100];
  57. // const step = 100 / (count - 1);
  58. // return Array.from({ length: count }, (_, i) => parseFloat((i * step).toFixed(1)));
  59. });
  60. // 格式化年季度数据为显示文本
  61. function formatYearQuarter(year, quarter) {
  62. return `${year}Q${quarter}`;
  63. }
  64. // 时间轴列表数据
  65. const list = ref([]);
  66. const incrementInterval = 3000; // 默认间隔3秒
  67. const specialIncrementInterval = 3000; // 特殊间隔3秒
  68. const timer = ref(null);
  69. const incrementCount = (type) => {
  70. const maxIndex = list.value.length - 1;
  71. if (active.value >= maxIndex) {
  72. active.value = 0;
  73. } else {
  74. if(type!=='original'){
  75. active.value += 1;
  76. }
  77. }
  78. let time = incrementInterval;
  79. if (active.value === 0 || active.value === maxIndex) {
  80. time = specialIncrementInterval;
  81. }
  82. timer.value = setTimeout(() => {
  83. if (isCounting.value) incrementCount();
  84. }, time);
  85. };
  86. const timerId = ref(null);
  87. const handleChange = () => {
  88. clearTime()
  89. const maxIndex = list.value.length - 1;
  90. if (active.value === 0 || active.value === maxIndex) {
  91. timerId.value = setTimeout(() => {
  92. if (isCounting.value) incrementCount();
  93. }, specialIncrementInterval);
  94. } else {
  95. incrementCount('original');
  96. }
  97. isCounting.value = !isCounting.value;
  98. };
  99. onDeactivated(() => {
  100. clearTime();
  101. });
  102. //清除定时器
  103. const clearTime = () => {
  104. if (timerId.value) {
  105. clearTimeout(timerId.value);
  106. }
  107. if (timer.value) {
  108. clearTimeout(timer.value);
  109. }
  110. };
  111. const restActive = () => {
  112. clearTime();
  113. active.value = 0;
  114. isCounting.value = false;
  115. handleChange();
  116. };
  117. defineExpose({ restActive });
  118. </script>
  119. <style lang="scss" scoped>
  120. .time-line {
  121. width: 100%;
  122. height: 100%;
  123. border-radius: 10px 10px 20px 20px;
  124. background: rgba(35, 35, 35, 0.6);
  125. border: 1px solid rgba(255,255,255,0.4);
  126. display: flex;
  127. align-items: center;
  128. box-sizing: border-box;
  129. padding: 0 20px;
  130. .play {
  131. display: flex;
  132. align-items: center;
  133. margin-right: 25px;
  134. .icon {
  135. width: 46px;
  136. }
  137. }
  138. .line {
  139. background: linear-gradient(30deg, #fff 0% , rgba(44, 44, 44,0.6) 100%);
  140. border-radius: 2px;
  141. width: 88%;
  142. height: 2px;
  143. display: flex;
  144. justify-content: space-between;
  145. position: relative;
  146. z-index: 2;
  147. position: relative;
  148. top: -4px;
  149. .active-line {
  150. background: linear-gradient(30deg, #eccd9b 0% ,#F3C11D 100%,);
  151. position: absolute;
  152. top: 0;
  153. left: 0;
  154. height: 2px;
  155. z-index: 1;
  156. }
  157. .dot-item {
  158. color: #fff;
  159. font-size: 16px;
  160. position: relative;
  161. z-index: 2;
  162. .dot {
  163. width: 8px;
  164. height: 8px;
  165. background: #E6E6E6;
  166. border-radius: 50%;
  167. margin: -2.2px 0 6px 28px;
  168. position: relative;
  169. &::after{
  170. content: '';
  171. position: absolute;
  172. top: -2px;
  173. left: -2px;
  174. width: 8px;
  175. height: 8px;
  176. border-radius: 50%;
  177. border: 2px solid rgba(255,255,255,0.2);
  178. }
  179. }
  180. .active {
  181. width: 8px;
  182. height: 8px;
  183. position: relative;
  184. background: #F3C11D;
  185. &::after{
  186. content: '';
  187. position: absolute;
  188. top: -2px;
  189. left: -2px;
  190. width: 8px;
  191. height: 8px;
  192. border-radius: 50%;
  193. border: 2px solid rgba(243,193,29,0.2);
  194. }
  195. }
  196. .text {
  197. background: #ED9E1E;
  198. padding: 1px 10px;
  199. border-radius: 36px;
  200. margin-left: -8px;
  201. }
  202. }
  203. .mr{
  204. margin-right: -35px;
  205. }
  206. }
  207. }
  208. </style>