feat(task): 优化任务步骤组件显示和交互
- 添加当前步骤状态显示区域,展示步骤计数和名称 - 实现步骤激活状态的标准化计算逻辑 - 优化滚动到当前步骤的功能,使用watch监听属性变化 - 改进步骤列表的样式布局,设置固定宽度和响应式设计 - 统一两个相似组件的代码结构和功能实现
This commit is contained in:
parent
b185b64de8
commit
e50a6a481f
@ -1,8 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div v-if="list.length" class="step-current">
|
||||||
|
<span class="step-current__count">{{ currentStepText }}</span>
|
||||||
|
<span class="step-current__name">{{ currentStep?.waypointName || '未命名点位' }}</span>
|
||||||
|
</div>
|
||||||
<el-scrollbar ref="scrollbarRef" style="width: 100%;" class="step-scrollbar">
|
<el-scrollbar ref="scrollbarRef" style="width: 100%;" class="step-scrollbar">
|
||||||
<div class="step-wrapper" ref="stepWrapperRef">
|
<div class="step-wrapper" ref="stepWrapperRef">
|
||||||
<el-steps :active="activeStep" finish-status="success">
|
<el-steps :active="normalizedActiveStep" finish-status="success" process-status="process">
|
||||||
<el-step v-for="item in list" :key="value" :title="item.waypointName" :description="item.remark" />
|
<el-step v-for="(item, index) in list" :key="item.id || item.waypointId || item.detectItemId || index"
|
||||||
|
:title="item.waypointName" :description="item.remark" />
|
||||||
</el-steps>
|
</el-steps>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -22,6 +27,13 @@ const props = defineProps({
|
|||||||
const scrollbarRef = ref(null)
|
const scrollbarRef = ref(null)
|
||||||
const stepWrapperRef = ref(null)
|
const stepWrapperRef = ref(null)
|
||||||
|
|
||||||
|
const currentStepIndex = computed(() => Math.min(Math.max(props.activeStep, 0), Math.max(props.list.length - 1, 0)))
|
||||||
|
const currentStep = computed(() => props.list[currentStepIndex.value])
|
||||||
|
const normalizedActiveStep = computed(() => Math.min(Math.max(props.activeStep, 0), props.list.length))
|
||||||
|
const currentStepText = computed(() => props.activeStep >= props.list.length
|
||||||
|
? `已完成 ${props.list.length}/${props.list.length}`
|
||||||
|
: `当前 ${currentStepIndex.value + 1}/${props.list.length}`)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 滚动到当前激活的步骤
|
* 滚动到当前激活的步骤
|
||||||
@ -37,50 +49,67 @@ const scrollToActiveStep = () => {
|
|||||||
|
|
||||||
// 获取所有 step 元素
|
// 获取所有 step 元素
|
||||||
const steps = stepWrapperRef.value?.querySelectorAll('.el-step')
|
const steps = stepWrapperRef.value?.querySelectorAll('.el-step')
|
||||||
if (!steps || !steps[props.activeStep]) return
|
if (!steps || !steps[currentStepIndex.value]) return
|
||||||
|
|
||||||
// 计算激活 step 的位置
|
// 计算激活 step 的位置
|
||||||
const activeEl = steps[props.activeStep]
|
const activeEl = steps[currentStepIndex.value]
|
||||||
const stepLeft = activeEl.offsetLeft
|
const stepLeft = activeEl.offsetLeft
|
||||||
const stepWidth = activeEl.offsetWidth
|
const stepWidth = activeEl.offsetWidth
|
||||||
|
|
||||||
// 让激活 step 居中显示
|
// 让激活 step 居中显示
|
||||||
const scrollLeft = stepLeft - viewWidth / 2 + stepWidth / 2
|
const scrollLeft = stepLeft - viewWidth / 2 + stepWidth / 2
|
||||||
console.log('滚动位置:', scrollLeft)
|
|
||||||
// 使用 el-scrollbar 提供的方法滚动
|
|
||||||
scrollbarRef.value.setScrollLeft(Math.max(0, scrollLeft))
|
scrollbarRef.value.setScrollLeft(Math.max(0, scrollLeft))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
watch(
|
||||||
scrollToActiveStep()
|
() => [props.activeStep, props.list.length],
|
||||||
}, 1000)
|
scrollToActiveStep,
|
||||||
|
{ immediate: true, flush: 'post' }
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.step-scrollbar {
|
.step-current {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-current__count {
|
||||||
|
flex: none;
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-current__name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-scrollbar {
|
||||||
|
margin-top: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
.step-wrapper {
|
.step-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
/* 让wrapper宽度由内容决定 */
|
width: max-content;
|
||||||
width: 100%;
|
min-width: 100%;
|
||||||
/* 至少和容器一样宽 */
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
/* 防止 flex 项换行 */
|
|
||||||
|
|
||||||
margin: 10px 0 20px 0;
|
margin: 10px 0 20px 0;
|
||||||
|
|
||||||
:deep(.el-steps) {
|
:deep(.el-steps) {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
width: calc(100% - 150px);
|
width: max-content;
|
||||||
|
min-width: 100%;
|
||||||
|
|
||||||
.el-step {
|
.el-step {
|
||||||
flex-shrink: 0 !important;
|
flex: 0 0 180px !important;
|
||||||
/* 禁止步骤项被压缩 */
|
min-width: 180px;
|
||||||
min-width: 150px;
|
|
||||||
/* 每个步骤的最小宽度,按需调整 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div v-if="list.length" class="step-current">
|
||||||
|
<span class="step-current__count">{{ currentStepText }}</span>
|
||||||
|
<span class="step-current__name">{{ currentStep?.caseName || '未命名检测项' }}</span>
|
||||||
|
</div>
|
||||||
<el-scrollbar ref="scrollbarRef" style="width: 100%;" class="step-scrollbar">
|
<el-scrollbar ref="scrollbarRef" style="width: 100%;" class="step-scrollbar">
|
||||||
<div class="step-wrapper" ref="stepWrapperRef">
|
<div class="step-wrapper" ref="stepWrapperRef">
|
||||||
<el-steps :active="activeStep" finish-status="success">
|
<el-steps :active="normalizedActiveStep" finish-status="success" process-status="process">
|
||||||
<el-step v-for="item in list" :key="value" :title="item.caseName" :description="item.remark" />
|
<el-step v-for="(item, index) in list" :key="item.id || item.testCaseId || item.detectItemId || index"
|
||||||
|
:title="item.caseName" :description="item.remark" />
|
||||||
</el-steps>
|
</el-steps>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
@ -22,6 +27,13 @@ const props = defineProps({
|
|||||||
const scrollbarRef = ref(null)
|
const scrollbarRef = ref(null)
|
||||||
const stepWrapperRef = ref(null)
|
const stepWrapperRef = ref(null)
|
||||||
|
|
||||||
|
const currentStepIndex = computed(() => Math.min(Math.max(props.activeStep, 0), Math.max(props.list.length - 1, 0)))
|
||||||
|
const currentStep = computed(() => props.list[currentStepIndex.value])
|
||||||
|
const normalizedActiveStep = computed(() => Math.min(Math.max(props.activeStep, 0), props.list.length))
|
||||||
|
const currentStepText = computed(() => props.activeStep >= props.list.length
|
||||||
|
? `已完成 ${props.list.length}/${props.list.length}`
|
||||||
|
: `当前 ${currentStepIndex.value + 1}/${props.list.length}`)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 滚动到当前激活的步骤
|
* 滚动到当前激活的步骤
|
||||||
@ -37,50 +49,67 @@ const scrollToActiveStep = () => {
|
|||||||
|
|
||||||
// 获取所有 step 元素
|
// 获取所有 step 元素
|
||||||
const steps = stepWrapperRef.value?.querySelectorAll('.el-step')
|
const steps = stepWrapperRef.value?.querySelectorAll('.el-step')
|
||||||
if (!steps || !steps[props.activeStep]) return
|
if (!steps || !steps[currentStepIndex.value]) return
|
||||||
|
|
||||||
// 计算激活 step 的位置
|
// 计算激活 step 的位置
|
||||||
const activeEl = steps[props.activeStep]
|
const activeEl = steps[currentStepIndex.value]
|
||||||
const stepLeft = activeEl.offsetLeft
|
const stepLeft = activeEl.offsetLeft
|
||||||
const stepWidth = activeEl.offsetWidth
|
const stepWidth = activeEl.offsetWidth
|
||||||
|
|
||||||
// 让激活 step 居中显示
|
// 让激活 step 居中显示
|
||||||
const scrollLeft = stepLeft - viewWidth / 2 + stepWidth / 2
|
const scrollLeft = stepLeft - viewWidth / 2 + stepWidth / 2
|
||||||
console.log('滚动位置:', scrollLeft)
|
|
||||||
// 使用 el-scrollbar 提供的方法滚动
|
|
||||||
scrollbarRef.value.setScrollLeft(Math.max(0, scrollLeft))
|
scrollbarRef.value.setScrollLeft(Math.max(0, scrollLeft))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
watch(
|
||||||
scrollToActiveStep()
|
() => [props.activeStep, props.list.length],
|
||||||
}, 1000)
|
scrollToActiveStep,
|
||||||
|
{ immediate: true, flush: 'post' }
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.step-scrollbar {
|
.step-current {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
min-width: 0;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-current__count {
|
||||||
|
flex: none;
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-current__name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-scrollbar {
|
||||||
|
margin-top: 4px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
.step-wrapper {
|
.step-wrapper {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
/* 让wrapper宽度由内容决定 */
|
width: max-content;
|
||||||
width: 100%;
|
min-width: 100%;
|
||||||
/* 至少和容器一样宽 */
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
/* 防止 flex 项换行 */
|
|
||||||
|
|
||||||
margin: 10px 0 20px 0;
|
margin: 10px 0 20px 0;
|
||||||
|
|
||||||
:deep(.el-steps) {
|
:deep(.el-steps) {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
width: calc(100% - 150px);
|
width: max-content;
|
||||||
|
min-width: 100%;
|
||||||
|
|
||||||
.el-step {
|
.el-step {
|
||||||
flex-shrink: 0 !important;
|
flex: 0 0 180px !important;
|
||||||
/* 禁止步骤项被压缩 */
|
min-width: 180px;
|
||||||
min-width: 150px;
|
|
||||||
/* 每个步骤的最小宽度,按需调整 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user