Files
vue3/packages/select-table-modal/index.vue
2023-07-22 17:52:31 +08:00

270 lines
6.9 KiB
Vue

<!--
* @Author: zhaojinfeng 121016171@qq.com
* @Date: 2023-07-18 12:30:07
* @LastEditors: zhaojinfeng 121016171@qq.com
* @LastEditTime: 2023-07-22 17:52:02
* @FilePath: \vue3\packages\select-table-modal\index.vue
* @Description: 模态框选择表格
*
-->
<template>
<span v-if="!hideButton" @click="open">
<slot>
<el-button type="primary" plain>点击选择</el-button>
</slot>
</span>
<el-config-provider :locale="locale">
<el-dialog v-model="showDialog" :title="title" :width="width" append-to-body :z-index="zIndex" @open="getList" @closed="closed">
<el-form ref="queryRef" :modal="queryParams" inline>
<el-form-item v-for="formItem in formItems" :key="formItem.prop" :label="formItem.label" :prop="formItem.prop">
<el-select v-if="formItem.selectOptions" :placeholder="formItem.placeholder">
<el-option v-for="option in formItem.selectOptions" :key="option.value" :value="option.value">
{{ option.label }}
</el-option>
</el-select>
<el-input v-else v-model="queryParams[formItem.prop]" :placeholder="formItem.placeholder" />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="getList">
查询
</el-button>
<el-button :loading="loading" @click="resetQuery">
重置
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
border
:data="tableData"
highlight-current-row
:row-key="rowKey"
:empty-text="emptyText"
:reserve-selection="multiple"
@current-change="handleCurrentChange"
@selection-change="handleSelectionChange"
>
<el-table-column v-if="multiple" type="selection" width="55" align="center" />
<el-table-column
v-for="column in columns"
:key="column.prop"
:align="column.align || 'center'"
:label="column.label"
:prop="column.prop"
:formatter="column.formatter"
>
<template v-if="isExist(column.prop)" #default="{ row, $index }">
<!-- element自带的属性$index -->
<!-- eslint-disable-next-line vue/valid-attribute-name -->
<slot :name="`column-${column.prop}`" :row="row" :$index="$index" />
</template>
</el-table-column>
</el-table>
<div w-full h-70px relative>
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
absolute
right-50px
top-20px
background
hide-on-single-page
:layout="layout"
:page-sizes="pageSizes"
:pager-count="pagerCount"
:total="total"
@size-change="handleSizeChange"
@current-change="getList"
/>
</div>
<template #footer>
<el-space>
<el-button :disabled="disabled" type="primary" @click="confirm">
确定
</el-button>
<el-button @click="showDialog = false">
取消
</el-button>
</el-space>
</template>
</el-dialog>
</el-config-provider>
</template>
<script lang="ts" setup name="ThSelectTableModal">
import type { FormInstance, TableColumnCtx, TableInstance } from 'element-plus'
import locale from 'element-plus/lib/locale/lang/zh-cn'
const props = withDefaults(
defineProps<{
emptyText?: string
value?: any
rowKey?: string
show?: boolean
columns: Partial<TableColumnCtx<any>>[]
formItems: FormItem[]
defaultParams?: Record<string, any>
request: (args: any) => Promise<Page>
layout?: string
pageSizes?: number[]
pagerCount?: number
hideButton?: boolean
hidePagination?: boolean
title?: string
width?: string | number
/** 是否多选 */
multiple?: boolean
zIndex?: number
multipleFormattter?: (row: Record<string, any>) => any
}>(),
{
hidePagination: false,
layout: 'total, sizes, prev, pager, next, jumper',
rowKey: 'id',
pageSizes: () => [10, 20, 30, 50],
pagerCount: () => document.body.clientWidth < 992 ? 5 : 7,
hideButton: false,
width: '1000px',
title: '选择',
emptyText: '暂无数据',
zIndex: 2023,
multipleFormattter(row: Record<string, any>) {
return { ...row }
},
},
)
const emit = defineEmits<{
(event: 'update:show', show: boolean): void
(event: 'update:value', show: any): void
(event: 'confirm', row: any): void
}>()
interface FormItem {
label: string
prop: string
placeholder?: string
selectOptions?: {
label: string
value: string
}[]
}
const showDialog = ref(false)
const slots = Object.keys(useSlots())
function isExist(prop: string) {
return slots.includes(`column-${prop}`)
}
let tableData = $ref<any[]>([])
let selection = $ref<any>()
let selections = $ref<Record<string, any>[] | null>(null)
const disabled = computed(() => {
if (props.multiple)
return !selections?.length
return !selection
})
function open() {
if (props.hideButton)
emit('update:show', true)
else
showDialog.value = true
}
let total = $ref(0)
function handleCurrentChange(val?: any) {
selection = val
}
/* 表单绑定的ref */
const queryRef = $ref<FormInstance>(null)
const tableRef = $ref<TableInstance>(null)
/* 初始加载 */
let loading = $ref(false)
/* 查询参数 */
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
})
function initSelections() {
const rows = tableData.map(props.multipleFormattter)
tableRef?.toggleRowSelection(rows, true)
}
function initSelection() {
const row = tableData.find(row => row[props.rowKey] === props.value)
if (row)
tableRef?.setCurrentRow(row)
}
/** 查询表格数据 */
async function getList() {
loading = true
tableData = []
try {
const response = await props.request({
...props.defaultParams,
...queryParams,
})
tableData = response.rows
total = response.total
if (props.multiple)
initSelections()
else
initSelection()
}
finally {
loading = false
}
}
/** 多选框选中数据 */
function handleSelectionChange(rows: any[]) {
selections = rows.map(props.multipleFormattter)
}
function confirm() {
if (props.multiple) {
emit('confirm', selections)
emit('update:value', selections)
}
else {
emit('confirm', selection)
emit('update:value', selection && selection[props.rowKey])
}
if (props.hideButton)
emit('update:show', false)
else
showDialog.value = false
}
/** 重置按钮操作 */
function resetQuery() {
queryRef?.resetFields()
queryParams.pageNum = 1
getList()
}
function handleSizeChange(val: number) {
if (queryParams.pageNum * val > total)
queryParams.pageNum = 1
}
function closed() {
queryRef?.resetFields()
tableData = []
queryParams.pageNum = 1
selection = undefined
}
watch(() => props.show,
(show) => {
showDialog.value = show
})
</script>