<template>
|
<div class="dynamic-table-container">
|
<el-table
|
ref="tableRef"
|
v-loading="loading"
|
:data="tableData"
|
:border="border"
|
:height="height"
|
:header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
|
style="width: 100%"
|
@selection-change="handleSelectionChange"
|
@row-click="handleRowClick"
|
>
|
<!-- 选择列 -->
|
<el-table-column
|
v-if="showSelection"
|
align="center"
|
type="selection"
|
width="55"
|
/>
|
|
<!-- 序号列 -->
|
<el-table-column
|
v-if="showIndex"
|
align="center"
|
label="序号"
|
type="index"
|
width="60"
|
/>
|
|
<!-- 固定列:部门 -->
|
<el-table-column
|
label="部门"
|
prop="department"
|
width="120"
|
show-overflow-tooltip
|
align="center"
|
/>
|
|
<!-- 固定列:姓名 -->
|
<el-table-column
|
label="姓名"
|
prop="name"
|
width="100"
|
show-overflow-tooltip
|
align="center"
|
/>
|
|
<!-- 固定列:工号 -->
|
<el-table-column
|
label="工号"
|
prop="employeeId"
|
width="100"
|
show-overflow-tooltip
|
align="center"
|
/>
|
|
<!-- 动态列:根据字典渲染 -->
|
<el-table-column
|
v-for="(dictItem, index) in dynamicColumns"
|
:key="dictItem.value"
|
:label="dictItem.label"
|
:prop="dictItem.value"
|
:width="dictItem.width || 120"
|
show-overflow-tooltip
|
align="center"
|
>
|
<template #default="scope">
|
<!-- 根据字典类型渲染不同的显示方式 -->
|
<template v-if="dictItem.renderType === 'tag'">
|
<el-tag
|
:type="getTagType(scope.row[dictItem.value])"
|
size="small"
|
>
|
{{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}
|
</el-tag>
|
</template>
|
<template v-else-if="dictItem.renderType === 'select'">
|
<el-select
|
v-model="scope.row[dictItem.value]"
|
placeholder="请选择"
|
size="small"
|
@change="handleSelectChange(scope.row, dictItem.value, $event)"
|
>
|
<el-option
|
v-for="option in dictItem.options"
|
:key="option.value"
|
:label="option.label"
|
:value="option.value"
|
/>
|
</el-select>
|
</template>
|
<template v-else-if="dictItem.renderType === 'input'">
|
<el-input
|
v-model="scope.row[dictItem.value]"
|
size="small"
|
placeholder="请输入"
|
@blur="handleInputChange(scope.row, dictItem.value, $event)"
|
/>
|
</template>
|
<template v-else>
|
<span>{{ getDictValueLabel(dictItem.dictType, scope.row[dictItem.value]) }}</span>
|
</template>
|
</template>
|
</el-table-column>
|
|
<!-- 操作列 -->
|
<el-table-column
|
v-if="showActions"
|
label="操作"
|
width="150"
|
align="center"
|
fixed="right"
|
>
|
<template #default="scope">
|
<el-button
|
type="primary"
|
link
|
size="small"
|
@click="handleEdit(scope.row, scope.$index)"
|
>
|
编辑
|
</el-button>
|
<el-button
|
type="danger"
|
link
|
size="small"
|
@click="handleDelete(scope.row, scope.$index)"
|
>
|
删除
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页组件 -->
|
<div v-if="showPagination" class="pagination-container">
|
<el-pagination
|
v-model:current-page="pagination.current"
|
v-model:page-size="pagination.size"
|
:page-sizes="[10, 20, 50, 100]"
|
:total="pagination.total"
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, computed, onMounted, watch } from 'vue'
|
import { useDict } from '@/utils/dict'
|
|
// 定义组件属性
|
const props = defineProps({
|
// 表格数据
|
data: {
|
type: Array,
|
default: () => []
|
},
|
// 字典类型数组,用于动态生成列
|
dictTypes: {
|
type: Array,
|
default: () => []
|
},
|
// 是否显示选择列
|
showSelection: {
|
type: Boolean,
|
default: false
|
},
|
// 是否显示序号列
|
showIndex: {
|
type: Boolean,
|
default: true
|
},
|
// 是否显示操作列
|
showActions: {
|
type: Boolean,
|
default: false
|
},
|
// 是否显示分页
|
showPagination: {
|
type: Boolean,
|
default: false
|
},
|
// 表格高度
|
height: {
|
type: [String, Number],
|
default: 'auto'
|
},
|
// 是否显示边框
|
border: {
|
type: Boolean,
|
default: true
|
},
|
// 加载状态
|
loading: {
|
type: Boolean,
|
default: false
|
},
|
// 分页配置
|
pagination: {
|
type: Object,
|
default: () => ({
|
current: 1,
|
size: 10,
|
total: 0
|
})
|
}
|
})
|
|
// 定义事件
|
const emit = defineEmits([
|
'selection-change',
|
'row-click',
|
'edit',
|
'delete',
|
'select-change',
|
'input-change',
|
'size-change',
|
'current-change'
|
])
|
|
// 响应式数据
|
const tableRef = ref(null)
|
const tableData = ref([])
|
|
// 获取字典数据
|
const dictData = ref({})
|
|
// 动态列配置
|
const dynamicColumns = computed(() => {
|
const columns = []
|
|
props.dictTypes.forEach(dictType => {
|
const dictItems = dictData.value[dictType] || []
|
// 为每个字典类型创建一个列,而不是为每个字典项创建列
|
if (dictItems.length > 0) {
|
columns.push({
|
label: getDictLabel(dictType), // 获取字典类型的显示名称
|
value: dictType, // 使用字典类型作为字段名
|
width: 120,
|
renderType: 'tag', // 默认使用标签显示
|
options: dictItems, // 提供选项
|
dictType: dictType
|
})
|
}
|
})
|
|
return columns
|
})
|
|
// 获取字典类型的显示名称
|
const getDictLabel = (dictType) => {
|
const labelMap = {
|
'sys_normal_disable': '状态',
|
'sys_user_level': '级别',
|
'sys_user_position': '职位',
|
'sys_yes_no': '是否',
|
'sys_user_sex': '性别',
|
'sys_lavor_issue': '劳务问题' // 添加劳务问题字典
|
}
|
return labelMap[dictType] || dictType
|
}
|
|
// 获取字典数据
|
const loadDictData = async () => {
|
try {
|
const dictPromises = props.dictTypes.map(async (dictType) => {
|
const { getDicts } = await import('@/api/system/dict/data')
|
const response = await getDicts(dictType)
|
return {
|
type: dictType,
|
data: response.data.map(item => ({
|
label: item.dictLabel,
|
value: item.dictValue,
|
elTagType: item.listClass,
|
elTagClass: item.cssClass
|
}))
|
}
|
})
|
|
const results = await Promise.all(dictPromises)
|
results.forEach(result => {
|
dictData.value[result.type] = result.data
|
})
|
} catch (error) {
|
console.error('加载字典数据失败:', error)
|
// 如果字典加载失败,使用默认数据
|
props.dictTypes.forEach(dictType => {
|
if (!dictData.value[dictType]) {
|
dictData.value[dictType] = []
|
}
|
})
|
}
|
}
|
|
// 获取标签类型
|
const getTagType = (value) => {
|
// 根据值返回不同的标签类型
|
if (value === '1' || value === 'true' || value === '是') return 'success'
|
if (value === '0' || value === 'false' || value === '否') return 'danger'
|
if (value === '2' || value === 'warning') return 'warning'
|
return 'info'
|
}
|
|
// 获取字典值的标签
|
const getDictValueLabel = (dictType, value) => {
|
if (!value) return '-'
|
const dictItems = dictData.value[dictType] || []
|
const item = dictItems.find(item => item.value === value)
|
return item ? item.label : value
|
}
|
|
// 事件处理函数
|
const handleSelectionChange = (selection) => {
|
emit('selection-change', selection)
|
}
|
|
const handleRowClick = (row, column, event) => {
|
emit('row-click', row, column, event)
|
}
|
|
const handleEdit = (row, index) => {
|
emit('edit', row, index)
|
}
|
|
const handleDelete = (row, index) => {
|
emit('delete', row, index)
|
}
|
|
const handleSelectChange = (row, prop, value) => {
|
emit('select-change', row, prop, value)
|
}
|
|
const handleInputChange = (row, prop, event) => {
|
emit('input-change', row, prop, event.target.value)
|
}
|
|
const handleSizeChange = (size) => {
|
emit('size-change', size)
|
}
|
|
const handleCurrentChange = (current) => {
|
emit('current-change', current)
|
}
|
|
// 监听数据变化
|
watch(() => props.data, (newData) => {
|
tableData.value = newData
|
}, { immediate: true })
|
|
// 监听字典类型变化
|
watch(() => props.dictTypes, () => {
|
loadDictData()
|
}, { immediate: true })
|
|
// 组件挂载时加载字典数据
|
onMounted(() => {
|
loadDictData()
|
})
|
|
// 暴露方法给父组件
|
defineExpose({
|
tableRef,
|
getSelection: () => tableRef.value?.getSelectionRows() || [],
|
clearSelection: () => tableRef.value?.clearSelection(),
|
toggleRowSelection: (row, selected) => tableRef.value?.toggleRowSelection(row, selected),
|
setCurrentRow: (row) => tableRef.value?.setCurrentRow(row)
|
})
|
</script>
|
|
<style scoped>
|
.dynamic-table-container {
|
width: 100%;
|
}
|
|
.pagination-container {
|
margin-top: 20px;
|
display: flex;
|
justify-content: flex-end;
|
}
|
|
:deep(.el-table .el-table__header-wrapper th) {
|
background-color: #F0F1F5 !important;
|
color: #333333;
|
font-weight: 600;
|
}
|
|
:deep(.el-table .el-table__body-wrapper td) {
|
padding: 8px 0;
|
}
|
|
:deep(.el-select) {
|
width: 100%;
|
}
|
|
:deep(.el-input) {
|
width: 100%;
|
}
|
</style>
|