2023-05-12 17:32:51 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<a-table
|
2023-11-01 20:10:49 +08:00
|
|
|
|
ref="tableRef"
|
2023-09-21 17:42:57 +08:00
|
|
|
|
class="custom-table"
|
2024-03-20 17:55:57 +08:00
|
|
|
|
:class="['custom-table', canSelect && multiple && mouseMoveSelect ? 'mouse-move-select' : '']"
|
2023-05-12 17:32:51 +08:00
|
|
|
|
v-bind="$attrs"
|
|
|
|
|
|
:data-source="list"
|
|
|
|
|
|
:columns="columns"
|
|
|
|
|
|
:size="size"
|
|
|
|
|
|
:row-key="rowKey"
|
|
|
|
|
|
:loading="loading"
|
|
|
|
|
|
:pagination="pagination"
|
2024-03-20 17:55:57 +08:00
|
|
|
|
:customRow="multiple && mouseMoveSelect ? customMouseMoveSelectRow : customRow"
|
2025-08-11 10:37:34 +08:00
|
|
|
|
:rowClassName="(record, index) => innerRowClassName(record, index)"
|
2023-05-12 17:32:51 +08:00
|
|
|
|
@change="handleTableChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- 处理 scopedSlots -->
|
|
|
|
|
|
<template v-for="slotName of scopedSlotsKeys" :slot="slotName" slot-scope="text, record, index">
|
|
|
|
|
|
<slot :name="slotName" :text="text" :record="record" :index="index"></slot>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-table>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
|
|
|
export default {
|
|
|
|
|
|
props: {
|
|
|
|
|
|
list: {
|
|
|
|
|
|
type: Array,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: () => []
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
columns: {
|
|
|
|
|
|
type: Array,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: () => []
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
size: {
|
|
|
|
|
|
type: String,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: 'middle'
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
rowKey: {
|
|
|
|
|
|
type: String,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: 'id'
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
loading: {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
type: Boolean
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
pagination: {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
type: [Object, Boolean]
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
selectedRowKeys: {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
type: Array
|
2023-05-19 19:17:28 +08:00
|
|
|
|
},
|
2023-07-07 15:45:09 +08:00
|
|
|
|
selectionRows: {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
type: Array
|
2023-07-07 15:45:09 +08:00
|
|
|
|
},
|
2023-05-19 19:17:28 +08:00
|
|
|
|
canSelect: {
|
|
|
|
|
|
type: Boolean,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: true
|
2023-07-05 16:00:43 +08:00
|
|
|
|
},
|
2023-08-28 19:52:35 +08:00
|
|
|
|
canDeselect: {
|
|
|
|
|
|
type: Boolean,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: true
|
2023-07-05 16:00:43 +08:00
|
|
|
|
},
|
2024-03-20 17:55:57 +08:00
|
|
|
|
// 多选
|
2023-07-05 16:00:43 +08:00
|
|
|
|
multiple: {
|
|
|
|
|
|
type: Boolean,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: false
|
2023-09-21 17:42:57 +08:00
|
|
|
|
},
|
2024-03-20 17:55:57 +08:00
|
|
|
|
// 鼠标移动选择
|
|
|
|
|
|
mouseMoveSelect: {
|
|
|
|
|
|
type: Boolean,
|
2025-08-11 10:37:34 +08:00
|
|
|
|
default: true
|
2024-03-20 17:55:57 +08:00
|
|
|
|
},
|
2025-08-11 10:37:34 +08:00
|
|
|
|
customRowClassName: {
|
|
|
|
|
|
type: Function
|
|
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2023-09-21 17:42:57 +08:00
|
|
|
|
innerSelectedRowKeys: [],
|
2025-08-11 10:37:34 +08:00
|
|
|
|
innerSelectedRows: []
|
2023-05-12 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-03-20 17:55:57 +08:00
|
|
|
|
mounted() {
|
|
|
|
|
|
if (this.canSelect && this.multiple && this.mouseMoveSelect) {
|
|
|
|
|
|
const tbody = this.$el.querySelector('.ant-table-tbody')
|
|
|
|
|
|
tbody.addEventListener('mouseleave', () => {
|
|
|
|
|
|
this.mouseMoveStartIndex = undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2023-05-12 17:32:51 +08:00
|
|
|
|
methods: {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
innerRowClassName(record, index) {
|
|
|
|
|
|
let className = ''
|
|
|
|
|
|
if (this.customRowClassName) {
|
|
|
|
|
|
className = this.customRowClassName({ record, index })
|
|
|
|
|
|
}
|
|
|
|
|
|
return (this.canSelect ? 'custom-table-row' : '') + ' ' + className
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2023-05-12 17:32:51 +08:00
|
|
|
|
// 实现单击选中/反选功能
|
2023-08-28 19:52:35 +08:00
|
|
|
|
customRow(record, index) {
|
2023-07-05 16:00:43 +08:00
|
|
|
|
const key = record[this.rowKey]
|
2023-05-12 17:32:51 +08:00
|
|
|
|
return {
|
2023-07-05 16:00:43 +08:00
|
|
|
|
class: this.innerSelectedRowKeys.includes(key) ? 'ant-table-row-selected' : '',
|
2023-05-12 17:32:51 +08:00
|
|
|
|
on: {
|
|
|
|
|
|
click: () => {
|
2023-09-21 17:42:57 +08:00
|
|
|
|
if (!this.canSelect) {
|
2023-05-19 19:17:28 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-08-28 19:52:35 +08:00
|
|
|
|
// 反选
|
2023-07-05 16:00:43 +08:00
|
|
|
|
if (this.innerSelectedRowKeys.includes(key)) {
|
2023-09-21 17:42:57 +08:00
|
|
|
|
if (this.multiple || this.canDeselect) {
|
2025-08-11 10:37:34 +08:00
|
|
|
|
const findIndex = this.innerSelectedRowKeys.findIndex(k => k == key)
|
2023-08-28 19:52:35 +08:00
|
|
|
|
this.innerSelectedRowKeys.splice(findIndex, 1)
|
2023-07-05 16:00:43 +08:00
|
|
|
|
}
|
2023-09-21 17:42:57 +08:00
|
|
|
|
}
|
2023-08-28 19:52:35 +08:00
|
|
|
|
// 选中
|
|
|
|
|
|
else {
|
2023-09-21 17:42:57 +08:00
|
|
|
|
if (this.multiple) {
|
2023-07-05 16:00:43 +08:00
|
|
|
|
this.innerSelectedRowKeys.push(key)
|
2023-09-21 17:42:57 +08:00
|
|
|
|
} else {
|
2023-07-05 16:00:43 +08:00
|
|
|
|
this.innerSelectedRowKeys = [key]
|
|
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
}
|
2023-09-21 17:42:57 +08:00
|
|
|
|
this.$emit('detail', record)
|
2023-08-28 19:52:35 +08:00
|
|
|
|
|
|
|
|
|
|
this.$emit('rowClick', record, index)
|
2023-08-29 19:54:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
dblclick: () => {
|
|
|
|
|
|
this.$emit('rowDblClick', record, index)
|
2025-08-11 10:37:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-03-20 17:55:57 +08:00
|
|
|
|
|
|
|
|
|
|
// 实现鼠标拖移动多选功能
|
|
|
|
|
|
customMouseMoveSelectRow(record, index) {
|
|
|
|
|
|
const key = record[this.rowKey]
|
|
|
|
|
|
return {
|
|
|
|
|
|
class: this.innerSelectedRowKeys.includes(key) ? 'ant-table-row-selected' : '',
|
|
|
|
|
|
on: {
|
|
|
|
|
|
mousedown: () => {
|
|
|
|
|
|
this.innerSelectedRowKeys = []
|
|
|
|
|
|
this.mouseMoveStartIndex = index
|
|
|
|
|
|
},
|
|
|
|
|
|
mouseenter: () => {
|
|
|
|
|
|
if (this.mouseMoveStartIndex !== undefined) {
|
|
|
|
|
|
const indexes = [this.mouseMoveStartIndex, index].sort((a, b) => a - b)
|
2025-08-11 10:37:34 +08:00
|
|
|
|
this.innerSelectedRowKeys = this.list.slice(indexes[0], indexes[1] + 1).map(item => item[this.rowKey])
|
2024-03-20 17:55:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mouseup: () => {
|
|
|
|
|
|
// 开始和结束在同一个,相当于click
|
|
|
|
|
|
if (this.mouseMoveStartIndex == index) {
|
|
|
|
|
|
this.innerSelectedRowKeys = [key]
|
|
|
|
|
|
}
|
|
|
|
|
|
this.mouseMoveStartIndex = undefined
|
2025-08-11 10:37:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-20 17:55:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2023-05-12 17:32:51 +08:00
|
|
|
|
handleTableChange(pagination, filters, sorter) {
|
|
|
|
|
|
this.$emit('change', pagination, filters, sorter)
|
2023-09-21 17:42:57 +08:00
|
|
|
|
},
|
2023-11-01 20:10:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 让第index行滚动到视野范围
|
|
|
|
|
|
scrollIntoView(index) {
|
|
|
|
|
|
const tableEle = this.$refs.tableRef.$el
|
|
|
|
|
|
const tableBodyEle = tableEle.querySelector('.ant-table-body')
|
|
|
|
|
|
const prevEle = tableBodyEle.querySelector(`.ant-table-row:nth-child(${index + 1})`)
|
|
|
|
|
|
tableBodyEle.scrollTop = prevEle.offsetTop
|
2025-08-11 10:37:34 +08:00
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
2023-09-21 17:42:57 +08:00
|
|
|
|
selectedRowKeys(val) {
|
|
|
|
|
|
this.innerSelectedRowKeys = val
|
2023-07-07 15:45:09 +08:00
|
|
|
|
},
|
2023-09-21 17:42:57 +08:00
|
|
|
|
innerSelectedRowKeys() {
|
2023-07-07 15:45:09 +08:00
|
|
|
|
this.$emit('update:selectedRowKeys', this.innerSelectedRowKeys)
|
2025-08-11 10:37:34 +08:00
|
|
|
|
this.innerSelectedRows = this.innerSelectedRowKeys.map(key => {
|
|
|
|
|
|
return this.list.find(item => item[this.rowKey] === key)
|
2023-07-07 15:45:09 +08:00
|
|
|
|
})
|
|
|
|
|
|
this.$emit('update:selectionRows', this.innerSelectedRows)
|
2025-08-11 10:37:34 +08:00
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
scopedSlotsKeys() {
|
|
|
|
|
|
return Object.keys(this.$scopedSlots)
|
2025-08-11 10:37:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-05-12 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
</script>
|
2024-03-20 17:55:57 +08:00
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
|
::v-deep {
|
|
|
|
|
|
.custom-table-row {
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
2025-05-26 18:12:59 +08:00
|
|
|
|
|
|
|
|
|
|
.ant-table-bordered .ant-table-header > table,
|
|
|
|
|
|
.ant-table-bordered .ant-table-body > table,
|
|
|
|
|
|
.ant-table-bordered .ant-table-fixed-left table,
|
|
|
|
|
|
.ant-table-bordered .ant-table-fixed-right table {
|
|
|
|
|
|
border-color: #416f7f;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-11 10:37:34 +08:00
|
|
|
|
.ant-table-bordered .ant-table-thead > tr > th,
|
|
|
|
|
|
.ant-table-bordered .ant-table-tbody > tr > td {
|
2025-05-26 18:12:59 +08:00
|
|
|
|
border-color: #416f7f;
|
|
|
|
|
|
}
|
2024-03-20 17:55:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mouse-move-select {
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep {
|
|
|
|
|
|
td {
|
|
|
|
|
|
transition: none !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-05-16 19:45:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|