| | |
| | | <template> |
| | | <div class="task-step"> |
| | | <div v-for="(item, index) in props.steps" :key="index" class="task-step-item" :style="{ 'flex-basis': flexBasis }"> |
| | | <el-icon v-if="index + 1 < active" class="icon" size="22" color="#01f304"><CircleCheck /></el-icon> |
| | | <el-scrollbar ref="scrollerRef" always> |
| | | <div class="task-step"> |
| | | <div |
| | | v-for="(item, index) in props.steps" |
| | | :key="index" |
| | | ref="activeItemRef" |
| | | class="task-step-item" |
| | | :style="{ 'flex-basis': flexBasis }" |
| | | > |
| | | <el-icon v-if="index + 1 < active" class="icon" size="22" color="#01f304"><CircleCheck /></el-icon> |
| | | |
| | | <el-icon v-if="index + 1 === active" class="icon" size="22" color="#c25915"><Clock /></el-icon> |
| | | <el-icon v-if="index + 1 > active" class="icon" size="22" color="#7d7f83"><Clock /></el-icon> |
| | | <span class="text" :class="{ green: index + 1 < active, red: index + 1 === active, gray: index + 1 > active }"> |
| | | {{ item }} |
| | | </span> |
| | | <span class="line"></span> |
| | | <el-icon v-if="index + 1 === active" class="icon" size="22" color="#c25915"> |
| | | <Clock /> |
| | | </el-icon> |
| | | <el-icon v-if="index + 1 > active" class="icon" size="22" color="#7d7f83"><Clock /></el-icon> |
| | | <span class="text" :class="{ green: index + 1 < active, red: index + 1 === active, gray: index + 1 > active }"> |
| | | {{ item }} |
| | | </span> |
| | | <span class="line"></span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-scrollbar> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { CircleCheck, Clock } from '@element-plus/icons-vue' |
| | | import { computed } from 'vue' |
| | | import { computed, onMounted, ref, watch } from 'vue' |
| | | import { ElIcon, ElScrollbar } from 'element-plus' |
| | | |
| | | export interface TaskStepProps { |
| | | active: number |
| | |
| | | |
| | | const flexBasis = computed(() => { |
| | | if (props.steps.length) { |
| | | return `${Math.floor((1 / props.steps.length) * 100)}%` |
| | | const percentage = Math.floor((1 / props.steps.length) * 100) |
| | | |
| | | return `${percentage > 20 ? percentage : 20}%` |
| | | } |
| | | return '0' |
| | | }) |
| | | |
| | | const activeItemRef = ref<(typeof HTMLDivElement)[]>() |
| | | const scrollerRef = ref<typeof ElScrollbar>() |
| | | |
| | | onMounted(() => { |
| | | watch( |
| | | () => [props.steps, activeItemRef.value, scrollerRef.value], |
| | | () => { |
| | | if (props.steps.length > 0 && activeItemRef.value?.length && scrollerRef?.value) { |
| | | console.log(scrollerRef?.value) |
| | | const left = props.active - 1 >= 0 ? activeItemRef.value[props.active - 1]?.offsetLeft ?? 20 : 20 |
| | | requestAnimationFrame(() => { |
| | | scrollerRef?.value?.setScrollLeft?.(left - 20) |
| | | }) |
| | | } |
| | | } |
| | | ) |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .task-step { |
| | | display: flex; |
| | | align-items: center; |
| | | width: 100%; |
| | | } |
| | | .task-step-item { |
| | | display: flex; |
| | | align-items: center; |
| | | flex: 1; |
| | | flex-grow: 1; |
| | | flex-shrink: 0; |
| | | &:last-child { |
| | | flex-basis: auto !important; |
| | | flex-shrink: 0; |