Files

275 lines
7.1 KiB
Vue

<!--
* @Author: zhaojinfeng 121016171@qq.com
* @Date: 2023-08-14 11:07:15
* @LastEditors: zhaojinfeng 121016171@qq.com
* @LastEditTime: 2023-12-14 18:05:02
* @FilePath: \vue3\packages\select-transfer-modal\index.vue
* @Description:
*
-->
<template>
<span v-if="!hideButton" @click="openDialog">
<slot>
<el-button type="primary" plain>点击选择</el-button>
</slot>
</span>
<el-config-provider :locale="locale">
<el-dialog
v-model="showDialog" class="select-transfer-modal" :title="title" :width="width" append-to-body
:z-index="zIndex" @open="getList" @closed="closed"
>
<div flex>
<slot name="left" />
<div grow>
<el-form ref="queryRef" :model="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" v-model="queryParams[formItem.prop]" filterable :placeholder="formItem.placeholder">
<el-option v-for="option in formItem.selectOptions" :key="option.value" :label="$options.label" :value="option.value" />
</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="handleQuery">
查询
</el-button>
<el-button :loading="loading" @click="resetQuery">
重置
</el-button>
</el-form-item>
</el-form>
<el-transfer
v-model="transferValue"
v-loading="loading"
inline-block
text-left
style="--el-transfer-panel-width:25vw"
:titles="['待选项', '已选项']"
:button-texts="['移除', '添加']"
:format="{
hasChecked: '${checked}',
noChecked: ' ',
}"
:data="data"
:filter-method="filterMethod"
:props="props"
>
<template #default="{ option }">
<slot name="transfer" :option="option">
{{ option[props.label] }}
</slot>
</template>
<template #left-footer>
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize" background small layout="total, sizes, prev,pager, next" mt-9px
:page-sizes="pageSizes" :pager-count="pagerCount" :total="total" @size-change="handleSizeChange"
@current-change="getList"
/>
</template>
</el-transfer>
</div>
</div>
<template #footer>
<el-space>
<el-button 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="ThSelectTransferModal">
import type { FormInstance, TransferDataItem, TransferKey, TransferPropsAlias } from 'element-plus'
import locale from 'element-plus/es/locale/lang/zh-cn'
const properties = withDefaults(
defineProps<{
value?: any[]
show?: boolean
defaultParams?: Record<string, any>
formItems?: FormItem[]
request: (args: any) => Promise<Page>
pageSizes?: number[]
pagerCount?: number
/** 禁用按钮 */
disabledButton?: boolean
hideButton?: boolean
hidePagination?: boolean
title?: string
width?: string | number
zIndex?: number
props?: TransferPropsAlias
lockList?: TransferKey[]
formattter?: (row: Record<string, any>) => any
}>(),
{
props: () => ({ key: 'id', label: 'name', disabled: 'disabled' }),
show: false,
defaultParams: () => ({}),
pageSizes: () => [20, 50, 100, 200],
pagerCount: document.body.clientWidth < 992 ? 5 : 7,
hidePagination: false,
title: '选择',
width: '70%',
zIndex: 2023,
formattter: (row: Record<string, any>) => {
return { ...row }
},
},
)
const emit = defineEmits<{
(event: 'update:show', show: boolean): void
(event: 'update:value', value: any[]): void
(event: 'confirm', rows: Record<string, any>[], keys: TransferKey[]): void
}>()
const showDialog = ref(false)
let transferValue = $ref<TransferKey[]>([])
let temp = $ref({})
let currentKeyList = $ref<TransferKey[]>([])
function filterMethod(_query: string, item: TransferDataItem) {
const { key = 'id' } = properties.props
return currentKeyList.includes(item[key]) || transferValue.includes(item[key])
}
const queryParams = reactive({
pageNum: 1,
pageSize: properties.pageSizes[0] || 10,
})
const data = computed(() => {
const all: any[] = []
const { props: { disabled = 'disabled', key = 'id' }, lockList } = properties
for (const i in temp) {
all.push({
...temp[i],
[disabled]: lockList?.includes(temp[i][key]),
})
}
return all
})
let total = $ref(0)
let loading = $ref(false)
/* 表单绑定的ref */
const queryRef = $ref<FormInstance>(null)
function handleQuery() {
queryParams.pageNum = 1
return getList()
}
/** 查询表格数据 */
async function getList() {
loading = true
try {
const response = await properties.request({
...properties.defaultParams,
...queryParams,
})
const { key = 'id' } = properties.props
currentKeyList = response.rows.map((e) => {
temp[e[key]] = e
return e[key]
})
total = response.total
}
finally {
loading = false
}
}
function openDialog() {
if (properties.disabledButton)
return
if (properties.hideButton)
emit('update:show', true)
else
showDialog.value = true
}
function closeDialog() {
if (properties.hideButton)
emit('update:show', false)
else
showDialog.value = false
}
function confirm() {
const selections = transferValue.map(key => properties.formattter(temp[key]))
emit('update:value', selections)
emit('confirm', selections, [...transferValue])
closeDialog()
}
function closed() {
queryRef?.resetFields()
queryParams.pageNum = 1
currentKeyList = []
closeDialog()
}
/** 重置按钮操作 */
function resetQuery() {
queryRef?.resetFields()
handleQuery()
}
function handleSizeChange(val: number) {
if (queryParams.pageNum * val > total)
queryParams.pageNum = 1
getList()
}
function transferValueInit() {
const { value = [] } = properties
const { key = 'id' } = properties.props
const newTemp = {}
transferValue = value.map((e) => {
newTemp[e[key]] = e
return e[key]
})
temp = newTemp
}
transferValueInit()
watch(() => properties.defaultParams, () => {
if (showDialog.value)
handleQuery()
}, { deep: true })
watch(() => properties.value, transferValueInit)
watch(() => properties.show, (show) => {
showDialog.value = show
})
</script>
<style lang="scss">
.select-transfer-modal {
.el-checkbox:last-of-type {
margin-right: 30px;
}
.el-transfer {
width: 100%;
display: flex;
.el-transfer-panel {
flex: 1;
}
}
}
</style>