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