添加表格导出功能
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
"vue-draggable-resizable": "3.0.0-beta.2",
|
||||
"vue-router": "4",
|
||||
"vxe-table": "^4.5.17",
|
||||
"vxe-table-plugin-export-xlsx": "^4.0.7",
|
||||
"xe-utils": "^3.5.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
4987
pnpm-lock.yaml
generated
4987
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,8 @@
|
||||
</el-button>
|
||||
<el-button @click="onComSearch" v-if="showSearch" type="primary" :icon="Search">查询</el-button>
|
||||
<el-button @click="onResetForm" v-if="showSearch && showReset" :icon="RefreshLeft">重置</el-button>
|
||||
<el-button @click="onExport" v-if="showExport" :loading="tableStore.table.loading" type="primary"
|
||||
icon="el-icon-Download">导出</el-button>
|
||||
</template>
|
||||
<slot name="operation"></slot>
|
||||
</div>
|
||||
@@ -55,6 +57,7 @@ interface Props {
|
||||
nextFlag?: boolean //控制时间是否可以往后推
|
||||
theCurrentTime?: boolean //控制时间前3天展示上个月时间
|
||||
showReset?: boolean //是否显示重置
|
||||
showExport?: boolean //导出控制
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -63,7 +66,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
showSearch: true,
|
||||
nextFlag: false,
|
||||
theCurrentTime: true,
|
||||
showReset: true
|
||||
showReset: true,
|
||||
showExport:false
|
||||
})
|
||||
// 动态计算table高度
|
||||
let resizeObserver = new ResizeObserver(entries => {
|
||||
@@ -169,7 +173,10 @@ const onResetForm = () => {
|
||||
const setInterval = (val: any) => {
|
||||
datePickerRef.value.setInterval(val)
|
||||
}
|
||||
|
||||
// 导出
|
||||
const onExport = () => {
|
||||
tableStore.onTableAction('export', {showAllFlag:true})
|
||||
}
|
||||
|
||||
defineExpose({ onComSearch, areaRef, setDatePicker, setInterval, datePickerRef, showSelectChange, computedSearchRow })
|
||||
</script>
|
||||
|
||||
@@ -1,40 +1,23 @@
|
||||
<template>
|
||||
<div :style="{ height: tableStore.table.height }">
|
||||
<vxe-table
|
||||
ref="tableRef"
|
||||
height="auto"
|
||||
:data="tableStore.table.data"
|
||||
v-loading="tableStore.table.loading"
|
||||
v-bind="Object.assign({}, defaultAttribute, $attrs)"
|
||||
@checkbox-all="selectChangeEvent"
|
||||
@checkbox-change="selectChangeEvent"
|
||||
>
|
||||
<vxe-table ref="tableRef" height="auto" :data="tableStore.table.data" v-loading="tableStore.table.loading"
|
||||
v-bind="Object.assign({}, defaultAttribute, $attrs)" @checkbox-all="selectChangeEvent"
|
||||
@checkbox-change="selectChangeEvent" :showOverflow="showOverflow">
|
||||
<!-- Column 组件内部是 el-table-column -->
|
||||
<template v-if="isGroup">
|
||||
<GroupColumn :column="tableStore.table.column" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<Column
|
||||
:attr="item"
|
||||
:key="key + '-column'"
|
||||
v-for="(item, key) in tableStore.table.column"
|
||||
:tree-node="item.treeNode"
|
||||
>
|
||||
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
|
||||
:tree-node="item.treeNode">
|
||||
<!-- tableStore 预设的列 render 方案 -->
|
||||
<template v-if="item.render" #default="scope">
|
||||
<FieldRender
|
||||
:field="item"
|
||||
:row="scope.row"
|
||||
:column="scope.column"
|
||||
:index="scope.rowIndex"
|
||||
:key="
|
||||
key +
|
||||
'-' +
|
||||
item.render +
|
||||
'-' +
|
||||
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
||||
"
|
||||
/>
|
||||
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
|
||||
'-' +
|
||||
item.render +
|
||||
'-' +
|
||||
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
||||
" />
|
||||
</template>
|
||||
</Column>
|
||||
</template>
|
||||
@@ -43,22 +26,17 @@
|
||||
</div>
|
||||
|
||||
<div v-if="tableStore.showPage" class="table-pagination">
|
||||
<el-pagination
|
||||
:currentPage="tableStore.table.params!.pageNum"
|
||||
:page-size="tableStore.table.params!.pageSize"
|
||||
:page-sizes="pageSizes"
|
||||
background
|
||||
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
|
||||
:page-sizes="pageSizes" background
|
||||
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
|
||||
:total="tableStore.table.total"
|
||||
@size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"
|
||||
></el-pagination>
|
||||
:total="tableStore.table.total" @size-change="onTableSizeChange"
|
||||
@current-change="onTableCurrentChange"></el-pagination>
|
||||
</div>
|
||||
<slot name="footer"></slot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, inject, computed, onMounted } from 'vue'
|
||||
import { ref, nextTick, inject, computed, onMounted, watch } from 'vue'
|
||||
import type { ElTable } from 'element-plus'
|
||||
import { VxeTableEvents, VxeTableInstance } from 'vxe-table'
|
||||
import FieldRender from '@/components/table/fieldRender/index.vue'
|
||||
@@ -66,19 +44,22 @@ import Column from '@/components/table/column/index.vue'
|
||||
import GroupColumn from '@/components/table/column/groupColumn.vue'
|
||||
import { useConfig } from '@/stores/config'
|
||||
import type TableStoreClass from '@/utils/tableStore'
|
||||
|
||||
import { useRouter } from 'vue-router'
|
||||
import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
|
||||
const config = useConfig()
|
||||
const tableRef = ref<VxeTableInstance>()
|
||||
const tableStore = inject('tableStore') as TableStoreClass
|
||||
const router = useRouter()
|
||||
|
||||
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
|
||||
isGroup?: boolean
|
||||
showOverflow?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
isGroup: false
|
||||
isGroup: false,
|
||||
showOverflow: true
|
||||
})
|
||||
onMounted(() => {
|
||||
tableStore.table.ref = tableRef.value as VxeTableInstance
|
||||
@@ -93,7 +74,7 @@ const onTableCurrentChange = (val: number) => {
|
||||
}
|
||||
|
||||
const pageSizes = computed(() => {
|
||||
let defaultSizes = [10, 20, 50, 100]
|
||||
let defaultSizes = [10, 20, 50, 100, 200]
|
||||
if (tableStore.table.params!.pageSize) {
|
||||
if (!defaultSizes.includes(tableStore.table.params!.pageSize)) {
|
||||
defaultSizes.push(tableStore.table.params!.pageSize)
|
||||
@@ -113,6 +94,37 @@ const selectChangeEvent: VxeTableEvents.CheckboxChange<any> = ({ checked }) => {
|
||||
const getRef = () => {
|
||||
return tableRef.value
|
||||
}
|
||||
watch(
|
||||
() => tableStore.table.allFlag,
|
||||
newVal => {
|
||||
|
||||
|
||||
if (tableStore.table.allFlag) {
|
||||
|
||||
tableRef.value?.exportData({
|
||||
filename: document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '', // 文件名字
|
||||
sheetName: 'Sheet1',
|
||||
type: 'xlsx', //导出文件类型 xlsx 和 csv
|
||||
useStyle: true,
|
||||
data: tableStore.table.allData, // 数据源 // 过滤那个字段导出
|
||||
columnFilterMethod: function (column: any) {
|
||||
|
||||
return !(column.column.title === undefined || column.column.title === '序号' || column.column.title === '操作')
|
||||
}
|
||||
})
|
||||
tableStore.table.allFlag = false
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => tableStore.table.data,
|
||||
newVal => {
|
||||
tableStore.onTableAction('selection-change', [])
|
||||
}
|
||||
)
|
||||
|
||||
defineExpose({
|
||||
getRef
|
||||
|
||||
@@ -14,7 +14,11 @@ import '@fortawesome/fontawesome-free/css/all.css'
|
||||
import '@/styles/index.scss'
|
||||
import '@/assets/font/iconfont.css'
|
||||
import { ElDialog } from 'element-plus'
|
||||
|
||||
import ExcelJS from 'exceljs'
|
||||
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
|
||||
VXETable.use(VXETablePluginExportXLSX, {
|
||||
ExcelJS
|
||||
})
|
||||
window.XEUtils = XEUtils
|
||||
|
||||
|
||||
|
||||
35
src/utils/tableMethod.ts
Normal file
35
src/utils/tableMethod.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
// 过滤表格导出数据
|
||||
export const filtration = (arr: Array<{ dealFlag?: number; fileFlag?: number; onlineEvaluate?: number }>) => {
|
||||
const dealFlagMap: Record<number, string> = {
|
||||
0: '未处理',
|
||||
1: '已处理',
|
||||
2: '已处理,无结果',
|
||||
3: '计算失败'
|
||||
}
|
||||
const fileFlagMap: Record<number, string> = {
|
||||
0: '不存在',
|
||||
1: '存在'
|
||||
}
|
||||
|
||||
arr.forEach((item: any) => {
|
||||
if (item.dealFlag !== undefined) {
|
||||
item.dealFlag = dealFlagMap[item.dealFlag] || ''
|
||||
}
|
||||
if (item.fileFlag !== undefined) {
|
||||
item.fileFlag = fileFlagMap[item.fileFlag] || ''
|
||||
}
|
||||
if (item.onlineEvaluate !== undefined) {
|
||||
if (item.onlineEvaluate == null) {
|
||||
} else if (item.onlineEvaluate == 3.14159) {
|
||||
item.onlineEvaluate = '/'
|
||||
} else if (item.onlineEvaluate * 100 > 90) {
|
||||
item.onlineEvaluate = '优'
|
||||
} else if (item.onlineEvaluate * 100 > 60) {
|
||||
item.onlineEvaluate = '良'
|
||||
} else {
|
||||
item.onlineEvaluate = '差'
|
||||
}
|
||||
}
|
||||
})
|
||||
return arr
|
||||
}
|
||||
@@ -3,19 +3,20 @@ import createAxios from '@/utils/request'
|
||||
import { requestPayload } from '@/utils/request'
|
||||
import { Method } from 'axios'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { filtration } from './tableMethod'
|
||||
|
||||
interface TableStoreParams {
|
||||
url: string // 请求地址
|
||||
pk?: string
|
||||
pk?: string
|
||||
column: TableColumn[]
|
||||
params?: anyObj
|
||||
method?: Method // 请求方式
|
||||
params?: anyObj
|
||||
method?: Method // 请求方式
|
||||
isWebPaging?: boolean // 是否前端分页
|
||||
showPage?: boolean //是否需要分页
|
||||
paramsPOST?: boolean // post请求 params传参
|
||||
publicHeight?: number //计算高度
|
||||
resetCallback?: () => void // 重置
|
||||
loadCallback?: () => void // 接口调用后的回调
|
||||
loadCallback?: () => void // 接口调用后的回调
|
||||
beforeSearchFun?: () => void // 接口调用前的回调
|
||||
}
|
||||
|
||||
@@ -31,6 +32,8 @@ export default class TableStore {
|
||||
ref: null,
|
||||
selection: [],
|
||||
data: [],
|
||||
allData: [],
|
||||
allFlag: false,
|
||||
webPagingData: [],
|
||||
total: 0,
|
||||
params: {
|
||||
@@ -78,26 +81,28 @@ export default class TableStore {
|
||||
},
|
||||
requestPayload(this.method, this.table.params, this.paramsPOST)
|
||||
)
|
||||
).then((res: any) => {
|
||||
if (res.data) {
|
||||
this.table.data = res.data.records || res.data
|
||||
this.table.total = res.data?.total || res.data.length || 0
|
||||
} else {
|
||||
this.table.data = []
|
||||
this.table.total = 0
|
||||
}
|
||||
if (Array.isArray(res)) {
|
||||
this.table.data = res
|
||||
}
|
||||
if (this.isWebPaging) {
|
||||
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
|
||||
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
||||
}
|
||||
this.table.loadCallback && this.table.loadCallback()
|
||||
this.table.loading = false
|
||||
}).catch(() => {
|
||||
this.table.loading = false
|
||||
})
|
||||
)
|
||||
.then((res: any) => {
|
||||
if (res.data) {
|
||||
this.table.data = res.data.records || res.data
|
||||
this.table.total = res.data?.total || res.data.length || 0
|
||||
} else {
|
||||
this.table.data = []
|
||||
this.table.total = 0
|
||||
}
|
||||
if (Array.isArray(res)) {
|
||||
this.table.data = res
|
||||
}
|
||||
if (this.isWebPaging) {
|
||||
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
|
||||
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
||||
}
|
||||
this.table.loadCallback && this.table.loadCallback()
|
||||
this.table.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.table.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,6 +178,25 @@ export default class TableStore {
|
||||
() => {
|
||||
console.warn('No action defined')
|
||||
}
|
||||
],
|
||||
[
|
||||
'export',
|
||||
() => {
|
||||
// this.index()
|
||||
let params = { ...this.table.params, pageNum: 1, pageSize: this.table.total }
|
||||
createAxios(
|
||||
Object.assign(
|
||||
{
|
||||
url: this.url,
|
||||
method: this.method
|
||||
},
|
||||
requestPayload(this.method, params, this.paramsPOST)
|
||||
)
|
||||
).then(res => {
|
||||
this.table.allData = filtration(res.data.records || res.data)
|
||||
this.table.allFlag = data.showAllFlag || true
|
||||
})
|
||||
}
|
||||
]
|
||||
])
|
||||
const action = actionFun.get(event) || actionFun.get('default')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<!-- 异常事件 -->
|
||||
<TableHeader datePicker ref="refheader">
|
||||
<TableHeader datePicker ref="refheader" showExport>
|
||||
<!-- <template v-slot:select>
|
||||
<el-form-item label="数据来源">
|
||||
<el-cascader
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<TableHeader datePicker ref="refheader">
|
||||
<TableHeader datePicker ref="refheader" showExport>
|
||||
<template v-slot:select>
|
||||
<el-form-item label="数据来源">
|
||||
<el-cascader v-model.trim="tableStore.table.params.cascader" placeholder="请选择数据来源"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<TableHeader datePicker ref="refheader">
|
||||
<TableHeader datePicker ref="refheader" showExport>
|
||||
<template v-slot:select>
|
||||
<el-form-item label="数据来源">
|
||||
<el-cascader v-model.trim="tableStore.table.params.cascader" placeholder="请选择数据来源"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div ref="refheader" v-if="!isWaveCharts">
|
||||
<TableHeader datePicker>
|
||||
<TableHeader datePicker showExport>
|
||||
<template v-slot:select>
|
||||
<el-form-item label="数据来源">
|
||||
<el-cascader placeholder="请选择数据来源" @change="sourceChange"
|
||||
|
||||
@@ -223,9 +223,7 @@
|
||||
{{ child.anotherName }}:
|
||||
{{ child.dataValue === 3.1415926 ? '暂无数据' : child.dataValue }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.children.length" class="box-card-div">
|
||||
<div style="display: flex; align-items: center">
|
||||
|
||||
@@ -47,21 +47,30 @@
|
||||
{{ deviceData.appCheck }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-tabs v-model.trim="dataSet" type="border-card" class="device-manage-box-card" @tab-click="handleClick">
|
||||
<el-tab-pane lazy :label="item.name" :name="item.id" v-for="(item, index) in deviceData.dataSetList"
|
||||
:key="index"></el-tab-pane>
|
||||
<div :style="{ height: tableHeight }" v-loading="tableLoading">
|
||||
<vxe-table v-bind="defaultAttribute" :data="tableData" height="auto" style="width: 100%">
|
||||
<vxe-column type="seq" title="序号" width="80"></vxe-column>
|
||||
<vxe-column field="name" title="数据名称"></vxe-column>
|
||||
<vxe-column field="phasic" title="相别"></vxe-column>
|
||||
<vxe-column field="type" title="数据类型"></vxe-column>
|
||||
<vxe-column field="unit" title="单位"></vxe-column>
|
||||
<vxe-column field="startTimes" title="开始次数"></vxe-column>
|
||||
<vxe-column field="endTimes" title="结束次数"></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-tabs>
|
||||
<div style="position: relative">
|
||||
|
||||
|
||||
<el-tabs v-model.trim="dataSet" type="border-card" class="device-manage-box-card"
|
||||
@tab-click="handleClick">
|
||||
<el-tab-pane lazy :label="item.name" :name="item.id" v-for="(item, index) in deviceData.dataSetList"
|
||||
:key="index"></el-tab-pane>
|
||||
<div :style="{ height: tableHeight }" v-loading="tableLoading">
|
||||
<vxe-table v-bind="defaultAttribute" :data="tableData" height="auto" ref="xTableRef"
|
||||
style="width: 100%">
|
||||
<vxe-column type="seq" title="序号" width="80"></vxe-column>
|
||||
<vxe-column field="name" title="数据名称"></vxe-column>
|
||||
<vxe-column field="phasic" title="相别"></vxe-column>
|
||||
<vxe-column field="type" title="数据类型"></vxe-column>
|
||||
<vxe-column field="unit" title="单位"></vxe-column>
|
||||
<vxe-column field="startTimes" title="开始次数"></vxe-column>
|
||||
<vxe-column field="endTimes" title="结束次数"></vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
</div>
|
||||
|
||||
</el-tabs>
|
||||
<el-button icon="el-icon-Download" type="primary" @click="exportData" class="export-btn">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="请选择设备" class="device-manage-right" />
|
||||
<MangePopup ref="mangePopup" />
|
||||
@@ -103,6 +112,7 @@ const tableData = ref([])
|
||||
const tableHeight = mainHeight(260).height
|
||||
const mangePopup = ref()
|
||||
const activeName = ref(0)
|
||||
const xTableRef = ref()
|
||||
//治理设备和便携式设备切换判断
|
||||
const deviceType = ref('0')
|
||||
const deviceTypeChange = (val: any, obj: any) => {
|
||||
@@ -250,6 +260,21 @@ const handleRestartDevice = () => {
|
||||
deviceRestartLoading.value = false
|
||||
})
|
||||
}
|
||||
const exportData = () => {
|
||||
|
||||
|
||||
xTableRef.value.exportData({
|
||||
filename: deviceData.value.dataSetList.filter((item: any) => item.id == dataSet.value)[0]?.name, // 文件名字
|
||||
sheetName: 'Sheet1',
|
||||
type: 'xlsx', //导出文件类型 xlsx 和 csv
|
||||
useStyle: true,
|
||||
download: false,
|
||||
data: tableData.value, // 数据源 // 过滤那个字段导出
|
||||
columnFilterMethod: function (column, $columnIndex) {
|
||||
return !(column.$columnIndex === 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -279,4 +304,11 @@ const handleRestartDevice = () => {
|
||||
-webkit-text-security: disc !important;
|
||||
}
|
||||
}
|
||||
|
||||
.export-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
|
||||
2
types/table.d.ts
vendored
2
types/table.d.ts
vendored
@@ -8,6 +8,8 @@ declare global {
|
||||
interface CnTable {
|
||||
ref: VxeTableInstance | null
|
||||
data: TableRow[] | any
|
||||
allData: TableRow[] | any
|
||||
allFlag: Boolean
|
||||
// 前端分页数据
|
||||
webPagingData: TableRow[][]
|
||||
// 表格加载状态
|
||||
|
||||
Reference in New Issue
Block a user