zhzf/client/src/components/BusinessTable.vue

458 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="business-table">
<el-table
ref="tableRef"
:data="cData"
:height="'100%'"
:width="'100%'"
:cell-style="tableConfig.cellStyleFunc"
:row-style="tableConfig.rowStyleFunc"
:id="tableConfig.tableId || tableId"
:default-sort="tableConfig.defaultSort"
class="el-table--scrollable-y"
:show-summary="tableConfig.hasSummary"
:summary-method="tableConfig.summaryMethod"
:span-method="tableConfig.spanMethod"
:tree-props="tableConfig.treeProps"
:lazy="tableConfig.lazy"
:load="tableConfig.load"
:row-class-name="tableConfig.rowClassNameFun"
:row-key="tableConfig.rowKey"
header-row-class-name="table-header"
v-bind="$attrs"
@cell-click="tableConfig.cellClick"
@selection-change="handleSelectionChange"
@sort-change="sortChange"
>
<el-table-column
v-if="tableConfig.multipleSelect"
:reserve-selection="tableConfig.reserveSelect"
:selectable="tableConfig.selectable"
type="selection"
header-align="center"
align="center"
/>
<slot />
<slot
name="control-column"
:canDelete="mergePermissions.delete"
:canModify="mergePermissions.modify"
:canDetail="mergePermissions.detail"
:modifyMethod="modify"
:removeMethod="remove"
:detailMethod="showDetail"
>
<el-table-column
fixed="right"
align="center"
class-name="control-column"
label="操作"
:width="tableConfig.controlWidth"
v-if="tableConfig.hasControlColumn"
>
<template #default="scope">
<template v-if="mergePermissions.canModifyCustom(scope.row)">
<el-link
type="primary"
v-if="mergePermissions.modify"
@click="modify(scope.row)"
title="修改"
>
修改
</el-link>
</template>
<template v-if="mergePermissions.canDeleteCustom(scope.row)">
<el-link
type="primary"
v-if="mergePermissions.delete"
@click="remove(scope.row)"
title="删除"
>
删除
</el-link>
</template>
<template v-if="mergePermissions.canDetailCustom(scope.row)">
<el-link
type="primary"
@click="showDetail(scope.row)"
title="详情"
v-if="mergePermissions.detail"
>
详情
</el-link>
</template>
<slot
name="otherControlButtons"
:data="scope"
/>
</template>
</el-table-column>
</slot>
</el-table>
<el-pagination
v-if="hasPagerBar"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
v-model:current-page="pagination.page"
:page-sizes="tableConfig.pageSizes"
v-model:page-size="pagination.pageSize"
:layout="tableConfig.pagerLayout"
:total="pagination.total"
background
>
<template #default>
<span
class="pager total"
:class="{ link: pageUnlimitCondition }"
@click="queryUnLimit"
>
{{ pagerTotal }}
</span>
</template>
</el-pagination>
</div>
</template>
<script setup>
import {ref, reactive, computed, watch, onMounted, nextTick, getCurrentInstance} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import { DATA_FLAGS } from '../utils/Constants'
import watermark from '@/utils/WarterMark'
import { v4 as uuid } from 'uuid'
import { merge } from 'lodash'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { useUserStore } from '@/stores/modules/user'
import {
exportExcelFile,
toExportExcelFileByUrl,
toExportXmlAllFileByUrl,
toExportXmlSelectFileByUrl
} from "@/utils/ExportExcel.js";
const userStore = useUserStore()
const emit = defineEmits([
'query-params',
'do-query',
'show-detail',
'show-modify',
'do-remove',
'table-selection',
'do-customize',
])
const defaultConfig = {
tableLoading: false,
hasControlColumn: false,
controlWidth: '300',
pageSizes: [20, 40, 60, 100],
usePage: true,
multipleSelect: true,
selectable: null,
reserveSelect: false,
cellStyleFunc: null,
rowStyleFunc: null,
rowClassNameFun: null,
hasSummary: false,
summaryMethod: null,
spanMethod: null,
userInfo: {},
defaultSort: {},
treeProps: { children: 'children', hasChildren: 'hasChildren' },
useWaterMark: true,
istick: false,
pagerLayout: '->, slot, sizes, prev, pager, next'
}
const props = defineProps({
queryParams: {
type: Object,
default: () => ({}),
},
config: Object,
dataRes: {
type: Object,
default: () => ({}),
},
permissions: {
type: Object,
default: () => ({
modify: false,
delete: false,
detail: true,
canDeleteCustom: () => true,
canDetailCustom: () => true,
canModifyCustom: () => true,
}),
},
})
const defaultPermissions = {
modify: false,
delete: false,
detail: true,
canDeleteCustom: () => true,
canDetailCustom: () => true,
canModifyCustom: () => true,
}
const tableConfig = reactive(merge({}, defaultConfig, props.config))
const mergePermissions = reactive(merge({}, defaultPermissions, props.permissions))
// 响应式状态
const pagination = reactive({
page: 1,
pageSize: tableConfig.pageSizes[0] || 20,
total: 0,
})
const { proxy } = getCurrentInstance()
props.queryParams
const data = ref([])
const once = ref(true)
const tableHeaderLabel = ref([])
const tableHeaderProps = ref([])
// 计算属性
const cData = computed(() => data.value.filter((d) => !d.dataFlag || d.dataFlag !== DATA_FLAGS.REMOVE))
const pagerTotal = computed(() => {
const totalVal = pagination.total || 0
return totalVal === 0 || props.dataRes.relation === 'eq' ? `${totalVal}` : `>=${totalVal}`
})
const pageUnlimitCondition = computed(() => props.dataRes.relation === 'gte' && props.queryParams.limit && !tableConfig.tableLoading)
const hasPagerBar = computed(() => tableConfig.usePage)
const tableId = computed(() => uuid())
// 生命周期
onMounted(() => {
if (tableConfig.useWaterMark) {
watermark.set('el-table', { username: userStore.username, mobile: userStore.mobile })
}
initQueryParams()
})
// 方法
const initQueryParams = () => {
emit('query-params', {
// 查询参数
...props.queryParams,
//
page: pagination.page,
pageSize: pagination.pageSize,
// 兼容旧接口
pagesize: pagination.pageSize,
// 初始化默认排序
sort: tableConfig.defaultSort.prop,
dir: tableConfig.defaultSort.order,
})
}
const query = (pageNum) => {
emit('query-params', {
...props.queryParams,
page: pageNum,
total: pagination.total,
})
emit('do-query')
}
const handleSizeChange = (size) => {
pagination.pageSize = size
pagination.page = 1
emit('query-params', { pagesize: size, pageSize: size })
}
const handleCurrentChange = (current) => {
pagination.page = current
query(current)
}
const showDetail = (row) => {
if (mergePermissions.detail) {
emit('show-detail', row)
}
}
const modify = (row) => {
if (mergePermissions.modify) {
emit('show-modify', row)
}
}
const remove = (row) => {
if (mergePermissions.delete) {
ElMessageBox.confirm('是否要删除选中的数据?', '确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
}).then(() => emit('do-remove', row))
.catch(() => {})
}
}
const handleSelectionChange = (val) => {
if (tableConfig.multipleSelect) {
emit('table-selection', val)
}
}
const sortChange = ({ prop, order, column }) => {
const dir = order === 'descending' ? 'desc' : 'asc'
emit('query-params', {
...props.queryParams,
sort: column.sortBy || prop,
dir: dir,
})
if (!once.value) emit('do-query')
once.value = false
}
const queryUnLimit = () => {
if (pageUnlimitCondition.value) {
emit('query-params', {
...props.queryParams,
limit: false,
total: 0,
})
emit('do-query')
}
}
const resetQuery = () => {
// 重置时不保留之前的查询参数,只设置分页相关参数
emit('query-params', {
page: 1,
total: 0,
pageSize: pagination.pageSize,
})
pagination.page = 1
once.value = true
}
const exportExcelFileForCurrentPage = (tableId, excelFileName) => { // 导出当前页数据为excel(不访问后台)
if (pagination.total === 0) {
ElMessage.warning('没有数据可以导出!')
return
}
exportExcelFile(tableId, excelFileName)
}
const exportExcelFileForAllData = (url, excelFileName, params) => { // 导出table页中所有数据需要传入到后台进行查询并组装excel,params为自定义参数用于配合在后台对应的查询条件
if (pagination.total === 0) {
ElMessage.warning('没有数据可以导出!')
return
}
toExportExcelFileByUrl(url, tableHeaderLabel.value, tableHeaderProps.value, excelFileName, params, proxy)
}
const exportXmlSelectFileForData = (url, codeList) => {
if (codeList.length === 0) {
ElMessage.warning('没有数据可以导出!')
return
}
toExportXmlSelectFileByUrl(url, codeList, '企业XML格式数据', {}, proxy)
}
const exportXmlAllFileForData = (url, params) => {
toExportXmlAllFileByUrl(url, '企业XML格式数据', params, proxy)
}
// 数据监听
watch(
() => props.dataRes,
(val) => {
if (val?.success) {
data.value = tableConfig.istick ? [] : val.data
pagination.total = val.total
if (once.value) {
once.value = false
}
}
},
{ immediate: true, deep: true }
)
watch(
() => pagination.page,
(newVal, oldVal) => {
if (newVal !== oldVal) query(newVal)
}
)
defineExpose({
query,
resetQuery,
exportExcelFileForCurrentPage,
exportExcelFileForAllData,
exportXmlSelectFileForData,
exportXmlAllFileForData
})
</script>
<style lang="scss" scoped>
.business-table {
// 给表格添加圆角
border-radius: 8px;
overflow: hidden;
:deep(.el-table) {
// 给表格添加圆角
border-radius: 8px;
overflow: hidden;
// 设置表头背景色
.el-table__header th {
background-color: #D1E5FB !important;
}
// 设置表格内容行的样式
.el-table__row {
background-color: #ffffff;
// 斑马纹样式
&:nth-child(even) {
background-color: #D9E1F3;
}
}
.el-table__cell {
font-size: 1rem;
}
}
// 给分页组件添加圆角
::v-deep(.el-pagination) {
border-radius: 8px;
overflow: hidden;
margin-top: 10px;
padding: 10px;
background-color: transparent;
}
.control-column {
.el-link {
margin-right: 10px;
&:last-child {
margin-right: 0;
}
&.el-link--primary {
color: var(--el-color-primary);
}
&.el-link--danger {
color: var(--el-color-danger);
}
&.el-link--info {
color: var(--el-color-info);
}
svg {
margin-right: 2px;
}
}
}
}
</style>