新增物料管理看板功能,包含统计卡片和图表展示 优化物料选择器组件,支持分页和搜索功能 重构物料详情展示组件,支持动态加载数据 添加多个ECharts图表组件用于数据可视化 完善出入库和采购单相关功能,增加在途数量显示 修复若干界面显示问题和交互逻辑
149 lines
4.7 KiB
Vue
149 lines
4.7 KiB
Vue
<!-- @/components/StickyDragContainer/index.vue -->
|
||
<template>
|
||
<div class="sticky-drag-wrapper" :style="wrapperStyle">
|
||
<!-- 拖拽条 -->
|
||
<div class="drag-bar" ref="dragBarRef" @mousedown="handleDragStart"></div>
|
||
<!-- 高度可调节+内部滚动容器 -->
|
||
<div
|
||
class="content-scroll-container"
|
||
ref="scrollContainerRef"
|
||
:style="{ height: `${containerHeight}px` }"
|
||
>
|
||
<!-- 默认插槽:接收外部传入的任意内容 -->
|
||
<slot></slot>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup name="StickyDragContainer">
|
||
import { ref, onMounted, onUnmounted, defineProps, watch, nextTick } from 'vue'
|
||
|
||
// 新增:接收父容器Ref(必传,用于获取父容器布局信息)
|
||
const props = defineProps({
|
||
parentRef: { // 父容器的Ref对象,外部传入
|
||
type: Object,
|
||
required: true
|
||
},
|
||
initialHeight: { // 容器初始高度(px)
|
||
type: Number,
|
||
default: 300
|
||
},
|
||
minHeight: { // 容器最小高度(px)
|
||
type: Number,
|
||
default: 200
|
||
},
|
||
zIndex: { // 容器层级
|
||
type: Number,
|
||
default: 99
|
||
}
|
||
})
|
||
|
||
// 响应式变量
|
||
const dragBarRef = ref(null)
|
||
const scrollContainerRef = ref(null)
|
||
const startY = ref(0)
|
||
const startHeight = ref(props.initialHeight)
|
||
const containerHeight = ref(props.initialHeight)
|
||
// 新增:组件外层样式(动态绑定宽度、左侧偏移、z-index等)
|
||
const wrapperStyle = ref({
|
||
zIndex: props.zIndex,
|
||
width: '0px',
|
||
left: '0px'
|
||
})
|
||
|
||
// 核心方法:更新组件布局(宽度/左侧偏移),与父容器保持一致
|
||
const updateContainerLayout = () => {
|
||
nextTick(() => {
|
||
// 校验父容器Ref是否有效
|
||
console.log(props.parentRef)
|
||
if (!props.parentRef) {
|
||
console.warn('StickyDragContainer:传入的parentRef无效,请确保绑定了正确的DOM Ref')
|
||
return
|
||
}
|
||
// 获取父容器的实际布局信息(相对于视口的位置、宽度)
|
||
const parentRect = props.parentRef.getBoundingClientRect()
|
||
// 动态设置组件宽度(与父容器完全一致)、左侧偏移(与父容器左对齐)
|
||
wrapperStyle.value = {
|
||
zIndex: props.zIndex,
|
||
width: `${parentRect.width}px`, // 继承父容器宽度
|
||
left: `${parentRect.left}px` // 与父容器左对齐
|
||
}
|
||
})
|
||
}
|
||
|
||
// 拖拽相关方法(保持不变)
|
||
const handleDragStart = (e) => {
|
||
e.preventDefault()
|
||
startY.value = e.clientY
|
||
startHeight.value = scrollContainerRef.value?.getBoundingClientRect().height || containerHeight.value
|
||
document.addEventListener('mousemove', handleDragMove)
|
||
document.addEventListener('mouseup', handleDragEnd)
|
||
}
|
||
const handleDragMove = (e) => {
|
||
e.preventDefault()
|
||
const diffY = startY.value - e.clientY
|
||
const newHeight = Math.max(props.minHeight, startHeight.value + diffY)
|
||
containerHeight.value = newHeight
|
||
}
|
||
const handleDragEnd = () => {
|
||
document.removeEventListener('mousemove', handleDragMove)
|
||
document.removeEventListener('mouseup', handleDragEnd)
|
||
}
|
||
|
||
// 生命周期:初始化+监听窗口缩放
|
||
onMounted(() => {
|
||
containerHeight.value = props.initialHeight
|
||
updateContainerLayout() // 初始化时适配父容器布局
|
||
// 新增:监听窗口缩放,父容器宽度变化时同步更新组件布局
|
||
window.addEventListener('resize', updateContainerLayout)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
// 解绑所有事件,防止内存泄漏
|
||
document.removeEventListener('mousemove', handleDragMove)
|
||
document.removeEventListener('mouseup', handleDragEnd)
|
||
window.removeEventListener('resize', updateContainerLayout) // 解绑窗口监听
|
||
})
|
||
|
||
// 监听props变化,动态更新
|
||
watch([() => props.initialHeight, () => props.zIndex], () => {
|
||
containerHeight.value = props.initialHeight
|
||
wrapperStyle.value.zIndex = props.zIndex
|
||
}, { immediate: true })
|
||
|
||
// 新增:如果父容器Ref变化,重新适配布局
|
||
watch(() => props.parentRef, () => {
|
||
updateContainerLayout()
|
||
}, { deep: true, immediate: true })
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 吸底外层容器:移除left/right:0,改为动态绑定;保留fixed+bottom:0核心吸底 */
|
||
.sticky-drag-wrapper {
|
||
position: fixed;
|
||
bottom: 0; /* 仅保留吸底,宽度/左侧偏移由JS动态设置 */
|
||
background: #ffffff;
|
||
border-top: 1px solid #e6e6e6;
|
||
box-sizing: border-box;
|
||
transition: all 0.1s ease; /* 宽度/高度变化平滑过渡 */
|
||
}
|
||
|
||
/* 拖拽条样式(保持不变) */
|
||
.drag-bar {
|
||
height: 6px;
|
||
background-color: #e6e6e6;
|
||
cursor: n-resize;
|
||
transition: background-color 0.2s ease;
|
||
}
|
||
.drag-bar:hover {
|
||
background-color: #409eff;
|
||
}
|
||
|
||
/* 内容滚动容器样式(保持不变) */
|
||
.content-scroll-container {
|
||
width: 100%; /* 继承外层wrapper的宽度(即父容器宽度) */
|
||
overflow: auto;
|
||
box-sizing: border-box;
|
||
transition: height 0.1s ease;
|
||
}
|
||
</style> |