iot-ui-vue/src/components/Metadata/Table/body.vue

283 lines
6.8 KiB
Vue

<template>
<div
v-if="dataSource.length"
class="metadata-edit-table-body-viewport" :style="{ ...style, height: height + 'px'}" ref="viewScrollRef" @scroll="onScroll">
<div :style="{position: 'relative'}">
<div class="metadata-edit-scrollbar" :style="containerStyle"> </div>
<div class="metadata-edit-table-center" ref="tableCenterRef" >
<div
v-if="virtualData.length"
v-for="(item, index) in virtualData"
:class="{
'metadata-edit-table-row': true,
'metadata-edit-table-row-selected': selectedRowKeys?.includes(item[rowKey] || virtualRang.start + index + 1)
}"
:key="`record_${item.__key}`"
:style="{height: `${cellHeight}px`,}"
:data-row-key="item[rowKey] || virtualRang.start + index + 1"
@click.right.native="(e) => showContextMenu(e,item, virtualRang.start + index)"
@click.stop="() => rowClick(item)"
>
<div
v-for="column in columns"
class="metadata-edit-table-cell"
:style="{
width: `${column.width}px`,
left: `${column.left}px`,
}"
>
<div v-if="column.dataIndex === '__serial'" class="body-cell-box">
<slot name="serial" :record="item" :index="item.__dataIndex" :column="column" >
{{ virtualRang.start + index + 1 }}
</slot>
</div>
<div v-else class="body-cell-box">
<slot :name="column.dataIndex" :record="item" :index="item.__dataIndex" :column="column" >
{{ item[column.dataIndex] }}
</slot>
</div>
</div>
</div>
</div>
</div>
</div>
<template v-else>
<slot name="empty">
<div class="metadata-edit-table-body-empty">
<j-empty />
</div>
</slot>
</template>
</template>
<script setup name="MetadataBaseTableBody">
import ContextMenu from './components/ContextMenu'
import {useRightMenuContext} from "@/components/Metadata/Table/context";
import {randomString} from "@/utils/utils";
import {bodyProps} from "./props";
const props = defineProps({
...bodyProps(),
groupKey: {
type: [String, Number],
default: undefined
}
})
const emit = defineEmits(['update:dataSource', 'scrollDown'])
const viewScrollRef = ref()
const tableCenterRef = ref()
// const virtualData = ref([])
const virtualRang = reactive({
start: 0,
end: 15
})
const containerStyle = ref(0)
const context = useRightMenuContext()
let scrollLock = ref(false)
let menuInstance
const maxLen = computed(() => {
return Math.trunc(props.height / props.cellHeight)
})
const selectedRowKeys = ref([])
const virtualData = computed(()=> {
const array = props.dataSource.slice(virtualRang.start, virtualRang.end)
if (tableCenterRef.value) {
tableCenterRef.value.style.webkitTransform = `translate3d(0, ${virtualRang.start * props.cellHeight}px, 0)`
}
return array
})
// const updateVirtualData = (start, end) => {
// debugger
// virtualData.value = props.dataSource.slice(start, end)
// if (tableCenterRef.value) {
// tableCenterRef.value.style.webkitTransform = `translate3d(0, ${start * props.cellHeight}px, 0)`
// }
// }
const onScroll = () => {
const height = viewScrollRef.value.scrollTop
const clientHeight = viewScrollRef.value.clientHeight
const scrollHeight = viewScrollRef.value.scrollHeight
const _index = Math.round(height / props.cellHeight) - 1
const start = _index < 0 ? 0 : _index
const end = start + maxLen.value + 4
if (height + clientHeight >= props.dataSource.length * props.cellHeight && !scrollLock.value) { // 滚动到底
emit('scrollDown')
scrollLock.value = true
}
virtualRang.start = start
virtualRang.end = end
// updateVirtualData(start, end)
}
const scrollTo = (index) => {
if (viewScrollRef.value) {
let top = index * props.cellHeight
viewScrollRef.value.scrollTop = top
}
}
const showContextMenu = (e, record, _index) => {
e.preventDefault()
if (props.disableMenu) {
record = {
...record,
__index: _index
}
menuInstance = ContextMenu(e, record, context)
}
}
// const updateView = () => {
// updateVirtualData(virtualRang.start, virtualRang.start + maxLen.value)
// }
const rowClick = (record) => {
if (props.rowSelection?.selectedRowKeys) {
const rowSet = new Set(selectedRowKeys.value)
const key = record[props.rowKey]
const selected = !rowSet.has(key)
if (selected) {
rowSet.delete(key)
} else {
rowSet.add(key)
}
props.rowSelection.onSelect?.(record, selected )
selectedRowKeys.value = [...rowSet.values()]
}
}
const updateSelectedKeys = (keys) => {
selectedRowKeys.value = keys
}
onMounted(() => {
nextTick(() => {
onScroll()
})
})
onBeforeUnmount(() => {
menuInstance?.destroy()
menuInstance?.cleanCopy()
})
watch(() => JSON.stringify(props.rowSelection?.selectedRowKeys), (val) => {
selectedRowKeys.value = JSON.parse(val || '[]')
}, { immediate: true })
watch(() => props.dataSource, (val, oldVal) => {
props.dataSource.forEach((item, index) => {
if (!item.__key) {
item.__key = randomString()
}
})
// updateView()
}, {
immediate: true,
deep: true
})
watch(() => props.dataSource.length, () => {
scrollLock.value = false
containerStyle.value = {
height: props.dataSource.length * props.cellHeight + 'px'
}
if (props.dataSource.length <= maxLen.value || props.dataSource.length === 0) {
emit('scrollDown', maxLen.value - props.dataSource.length + 3)
}
}, { immediate: true})
// watch(() => props.height, () => {
// updateView()
// })
watch(() => props.groupKey, () => {
if (props.openGroup) {
scrollTo(0)
}
})
defineExpose({
scrollTo,
updateSelectedKeys
})
</script>
<style scoped lang="less">
.metadata-edit-table-body-viewport {
max-height: 100%;
width: 100%;
overflow: hidden auto;
position: relative;
.metadata-edit-scrollbar {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.metadata-edit-table-body-container {
overflow: hidden;
height: 100%;
}
.metadata-edit-table-center {
position: relative;
flex: 1 1 auto;
min-width: 0;
height: 100%;
.metadata-edit-table-row {
width: 100%;
display: flex;
align-items: center;
//position: absolute;
transition: top .2s, height .2s, background-color .1s;
border-bottom: 1px solid #ebebeb;
&:hover {
background-color: rgb(248, 248, 248);
}
&.metadata-edit-table-row-selected {
background-color: var(--ant-primary-1);
}
.body-cell-box {
padding: 0 12px;
position: relative;
}
}
}
}
.metadata-edit-table-body-empty {
display: flex;
width: 100%;
justify-content: center;
padding-top: 24px;
}
</style>