458 lines
12 KiB
Vue
458 lines
12 KiB
Vue
|
|
<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>
|