Merge remote-tracking branch 'origin/main'
commit
b9e6b355b2
@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<Dialog :title="title" v-model="dialogVisible" :appendToBody="true" width="1080">
|
||||
<ContentWrap>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
:row-key="resolveRowKey"
|
||||
:show-overflow-tooltip="true"
|
||||
:stripe="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" reserve-selection />
|
||||
<el-table-column
|
||||
v-for="column in columns"
|
||||
:key="column.prop"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:align="column.align || 'center'"
|
||||
/>
|
||||
</el-table>
|
||||
<Pagination
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
:total="total"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="submitSelection">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ElTable } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'TableSelectDialog' })
|
||||
|
||||
type TableColumn = {
|
||||
label: string
|
||||
prop: string
|
||||
width?: string | number
|
||||
minWidth?: string | number
|
||||
align?: 'left' | 'center' | 'right'
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
title: string
|
||||
columns: TableColumn[]
|
||||
fetchApi: (params: Record<string, any>) => Promise<{ list: any[]; total: number }>
|
||||
rowKey?: string
|
||||
pageSize?: number
|
||||
initialRows?: any[]
|
||||
}>(),
|
||||
{
|
||||
rowKey: 'id',
|
||||
pageSize: 10,
|
||||
initialRows: () => []
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'confirm', value: { ids: (number | string)[]; rows: any[] }): void
|
||||
}>()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const list = ref<any[]>([])
|
||||
const total = ref(0)
|
||||
const tableRef = ref<InstanceType<typeof ElTable>>()
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: props.pageSize
|
||||
})
|
||||
const selectedMap = ref(new Map<number | string, any>())
|
||||
const syncingSelection = ref(false)
|
||||
|
||||
const resolveRowKey = (row: Record<string, any>) => row[props.rowKey]
|
||||
|
||||
const refreshSelectionOnTable = async () => {
|
||||
await nextTick()
|
||||
const table = tableRef.value
|
||||
if (!table) return
|
||||
syncingSelection.value = true
|
||||
try {
|
||||
table.clearSelection()
|
||||
const selectedIds = selectedMap.value
|
||||
list.value.forEach((row) => {
|
||||
const rowId = resolveRowKey(row)
|
||||
if (selectedIds.has(rowId)) {
|
||||
table.toggleRowSelection(row, true)
|
||||
}
|
||||
})
|
||||
} finally {
|
||||
syncingSelection.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await props.fetchApi(queryParams)
|
||||
list.value = data.list || []
|
||||
total.value = data.total || 0
|
||||
await refreshSelectionOnTable()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelectionChange = (rows: any[]) => {
|
||||
if (syncingSelection.value) return
|
||||
const pageIdSet = new Set(list.value.map((item) => resolveRowKey(item)))
|
||||
pageIdSet.forEach((id) => {
|
||||
selectedMap.value.delete(id)
|
||||
})
|
||||
rows.forEach((row) => {
|
||||
selectedMap.value.set(resolveRowKey(row), row)
|
||||
})
|
||||
}
|
||||
|
||||
const open = async (rows?: any[]) => {
|
||||
selectedMap.value.clear()
|
||||
;(rows || props.initialRows).forEach((row) => {
|
||||
selectedMap.value.set(resolveRowKey(row), row)
|
||||
})
|
||||
queryParams.pageNo = 1
|
||||
queryParams.pageSize = props.pageSize
|
||||
dialogVisible.value = true
|
||||
await getList()
|
||||
}
|
||||
|
||||
const submitSelection = () => {
|
||||
const rows = Array.from(selectedMap.value.values())
|
||||
const ids = rows.map((row) => resolveRowKey(row))
|
||||
emit('confirm', { ids, rows })
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
Loading…
Reference in New Issue