|
|
<template> <div style="height: calc(100vh - 234px); margin-top: 20px; padding-bottom: 20px; overflow-y: scroll;"> <el-button :disabled="tableData.length===0" :loading="exportLoading" style="padding: 7px 10px; position: absolute; right: 6px; top: -6px;" @click="handleExport"> <i class="iconfont icon-daochu" /> 导出 </el-button> <div> <div class="table-content"> <div v-if="activeIndex===0" class="table-right-date">截止到:{{ nowDate }}</div> <div v-if="activeIndex===1" class="table-right-date">选择年份: <el-select v-model="yearValue" placeholder="请选择" style="width: 90px;" @change="handleYear"> <el-option v-for="item in yearsOptions" :key="item.id" :label="item.label" :value="item.id" /> </el-select> </div> <div v-if="activeIndex===2" class="table-right-date">自定义起止时间: <el-date-picker v-model="customYear" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" @change="handleCustomYear" /> </div> <el-table v-if="tableData.length!==0" ref="table" v-loading="tableDataLoading" :data="tableData" border :cell-style="tableCellStyle"> <el-table-column :prop="getFirstColumnProp()" :label="getFirstColumnLabel()" width="100" align="center" show-overflow-tooltip /> <el-table-column v-for="(column, index) in tableColumns" :key="index" :prop="column" :label="column" :width="column === '省市领导批示件' ? '120' : '80'" align="center" /> <el-table-column prop="合计" label="合计" width="60" align="center" /> </el-table> </div> </div> </div> </template>
<script> import CRUD, { presenter, crud } from '@crud/crud' import { getCurrentTime } from '@/utils/index' import { FetchAnnualStatistics, FetchAnnualStatisticsByMonth, FetchAnnualStatisticsByBorrow } from '@/api/system/documentArchives' import * as XLSX from 'xlsx' import { saveAs } from 'file-saver' // 简化文件保存
export default { name: 'MiodTable', components: { }, mixins: [presenter(), crud()], cruds() { return CRUD({ url: 'api/archivesUtilize/initborrowLog', title: '公文统计', optShow: { add: false, edit: false, del: false, download: false, reset: false, group: false } }) }, props: { activeIndex: { type: Number, default: 0 }, isUserCenter: { type: Boolean, default: false } }, data() { return { exportLoading: false, nowDate: getCurrentTime(), yearValue: 2025, yearsOptions: [], customYear: this.calculateDefaultRange(), tableDataLoading: false, tableData: [], fixedColumnOrder: ['中共中央', '国务院', '省交通厅', '省委', '市委', '省政府', '市政府', '省市领导批示件', '综合'], tableColumns: [] } }, watch: { activeIndex: function(newValue, oldValue) { this.loadDataByTab(newValue) } }, created() { this.generateYearsData() }, mounted() { this.loadDataByTab(this.activeIndex) }, methods: { loadDataByTab(tabIndex) { this.tableDataLoading = true this.tableData = [] switch (tabIndex) { case 0: this.getAnnualStatistics() break case 1: this.getAnnualStatisticsByMonth() break case 2: this.getAnnualStatisticsByBorrow() break default: break } }, handleYear(val) { this.tableDataLoading = true this.tableData = [] this.yearValue = val this.getAnnualStatisticsByMonth() }, handleCustomYear(val) { console.log('this.customYear', this.customYear) console.log('this.val', val) this.tableDataLoading = true this.tableData = [] this.getAnnualStatisticsByBorrow() }, getFirstColumnProp() { switch (this.activeIndex) { case 0: return 'year' // 年度统计:年份
case 1: return 'month' // 月度统计:月份
case 2: return 'name' // 传阅统计:借阅者(假设prop为name)
default: return '' } }, getFirstColumnLabel() { switch (this.activeIndex) { case 0: return '年度' case 1: return '月份' case 2: return '借阅者' default: return '' } }, getAnnualStatistics() { FetchAnnualStatistics().then((res) => { this.tableData = this.formatTableData('year', res) setTimeout(() => { this.tableDataLoading = false }, 500) }).catch(err => { console.log(err) }) },
getAnnualStatisticsByMonth() { const params = { year: this.yearValue } FetchAnnualStatisticsByMonth(params).then((res) => { this.tableData = this.formatTableData('month', res) setTimeout(() => { this.tableDataLoading = false }, 500) }).catch(err => { console.log(err) }) }, getAnnualStatisticsByBorrow() { console.log('customYear', this.customYear) const params = { 'startTime': this.customYear[0], 'endTime': this.customYear[1] } console.log('params', params) FetchAnnualStatisticsByBorrow(params).then((res) => { this.tableData = this.formatTableData('name', res) setTimeout(() => { this.tableDataLoading = false }, 500) }).catch(err => { console.log(err) }) }, formatTableData(dataType, rawData) { const allColumns = new Set() Object.keys(rawData).forEach(key => { if (key === '合计') return // 跳过合计行
Object.keys(rawData[key]).forEach(column => { if (column !== '合计') { // 排除合计字段
allColumns.add(column) } }) })
// 按固定顺序过滤并排序列名
this.tableColumns = this.fixedColumnOrder.filter(column => allColumns.has(column) )
// 处理不在固定顺序中的额外列(如果有)
const extraColumns = [...allColumns].filter( column => !this.fixedColumnOrder.includes(column) ) this.tableColumns = [...this.tableColumns, ...extraColumns]
// 处理数据行
const formattedData = [] let sortedKeys
if (dataType === 'year') { // 年份数据:倒序排列(最新年份在前)
sortedKeys = Object.keys(rawData) .filter(key => key !== '合计') .sort((a, b) => parseInt(b) - parseInt(a)) } else if (dataType === 'month') { // 月份数据:正序排列(1月到12月)
sortedKeys = Object.keys(rawData) .filter(key => key !== '合计') .sort((a, b) => parseInt(a) - parseInt(b)) } else if (dataType === 'name') { // 名称数据:按字母顺序排序
sortedKeys = Object.keys(rawData) .filter(key => key !== '合计') .sort((a, b) => a.localeCompare(b)) } else { // 默认不排序
sortedKeys = Object.keys(rawData).filter(key => key !== '合计') }
// 格式化数据行
sortedKeys.forEach(key => { const values = rawData[key] const item = dataType === 'year' ? { year: key, ...values } // 年份数据
: dataType === 'month' ? { month: `${key}月`, ...values } // 月份数据
: { name: key, ...values } // 名称数据
formattedData.push(item) })
// 处理合计行
if (rawData['合计']) { formattedData.push({ [dataType === 'year' ? 'year' : dataType === 'month' ? 'month' : 'name']: '合计', ...rawData['合计'] }) }
return formattedData }, getExportMeta() { console.log('this.customYear', this.customYear) let sheetName, firstColumnLabel, firstColumnProp
const formatDateRange = (dates) => { if (!dates || dates.length !== 2) return ''
// 解析日期字符串并获取年月日信息
const formatDate = (dateStr) => { const date = new Date(dateStr) const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}${month}${day}` }
const startDate = formatDate(dates[0]) const endDate = formatDate(dates[1])
return `${startDate}-${endDate}` }
const dateRange = formatDateRange(this.customYear)
switch (this.activeIndex) { case 0: sheetName = '馆藏年度统计' firstColumnLabel = '年度' firstColumnProp = 'year' // 对应数据中的年份字段
break case 1: // 月度统计:拼接 yearValue(需确保已正确获取)
sheetName = `馆藏月份统计_${this.yearValue}年度` firstColumnLabel = '月份' firstColumnProp = 'month' // 对应数据中的月份字段(如 '1月')
break case 2: sheetName = `传阅统计_${dateRange}` firstColumnLabel = '借阅者' firstColumnProp = 'name' // 对应数据中的借阅者名称字段
break default: return [null, null, null] } return [sheetName, firstColumnLabel, firstColumnProp] }, async handleExport() { this.exportLoading = true try { // 直接使用统一的 tableData(需确保切换 tab 时已更新为对应数据)
if (!this.tableData || this.tableData.length === 0) { this.$message.warning('无数据可导出') return }
// 动态生成 sheetName 和首列标签
const [sheetName, firstColumnLabel, firstColumnProp] = this.getExportMeta()
// 生成导出数据
const exportData = this.tableData.map(item => { const row = { [firstColumnLabel]: item[firstColumnProp] } // 首列数据
this.tableColumns.forEach(column => { row[column] = item[column] })
// 添加合计列(若存在)
if (item['合计'] !== undefined) { row['合计'] = item['合计'] } return row })
// 生成工作簿
const workbook = XLSX.utils.book_new() const sheet = XLSX.utils.json_to_sheet(exportData) XLSX.utils.book_append_sheet(workbook, sheet, sheetName)
// 导出文件(文件名与 sheetName 一致,添加时间戳)
const fileName = `${sheetName}_${new Date().getTime()}.xlsx` // const now = new Date()
// const fileName = `${sheetName}_${now.getFullYear()}-${
// String(now.getMonth() + 1).padStart(2, '0')}-${
// String(now.getDate()).padStart(2, '0')}_${
// String(now.getHours()).padStart(2, '0')}-${
// String(now.getMinutes()).padStart(2, '0')}-${
// String(now.getSeconds()).padStart(2, '0')}.xlsx`
const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'array', cellDates: true }) const blob = new Blob([wbout], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) saveAs(blob, fileName) } catch (error) { console.error('导出错误:', error) this.$message.error('导出失败,请检查数据格式!') } finally { this.exportLoading = false } }, tableCellStyle({ row, column, rowIndex, columnIndex }) { // 最后一列设置背景色为 lightblue
if (columnIndex === this.$refs.table.columns.length - 1) { return 'background-color: #f5f7fa;border-top: 1px solid #dfe6ec;' } return '' }, generateYearsData() { const currentYear = new Date().getFullYear() // 获取当前年份
const startYear = 2007 // 起始年份
const years = [] for (let year = currentYear; year >= startYear; year--) { years.push({ id: year, label: year }) }
this.yearsOptions = years }, // 计算默认时间范围的方法
calculateDefaultRange() { const now = new Date() // 获取当前时间
const oneMonthAgo = new Date() // 创建一个月前的时间对象
oneMonthAgo.setMonth(now.getMonth() - 1) // 月份减 1(当前月的第一天向前推一个月)
// 处理日期边界:若当前是月初,需取上个月的同一天(避免跨月错误)
if (now.getDate() < oneMonthAgo.getDate()) { oneMonthAgo.setDate(1) // 若上月天数不足,设为上月第一天
}
// 转换为 ISO 格式字符串(需与组件的时间格式匹配,默认支持 'YYYY-MM-DD HH:mm:ss')
const start = this.formatDate(oneMonthAgo) const end = this.formatDate(now) // 结束时间为当前日期
return [start, end] }, formatDate(date) { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') // 月份补零
const day = String(date.getDate()).padStart(2, '0') // 日期补零
const hours = String(date.getHours()).padStart(2, '0') // 小时补零(可选)
const minutes = String(date.getMinutes()).padStart(2, '0') // 分钟补零(可选)
const seconds = String(date.getSeconds()).padStart(2, '0') // 秒补零(可选)
// 若不需要时分秒,可省略后面部分,格式为 'YYYY-MM-DD'
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` } } } </script>
<style lang="scss" scoped> .table-content { box-sizing: border-box; display: inline-block; // border: 1px solid #dfe6ec;
border-bottom: none; border-right: none; font-size: 14px; .table-right-date{ line-height: 40px; text-align: right; padding: 5px 10px; font-weight: bold; color: #0c0e1e; // border-bottom: 1px solid #dfe6ec;
// border-right: 1px solid #dfe6ec;
} } // ::v-deep .el-table{
// width: auto !important;
// }
// ::v-deep .el-table .cell{
// padding: 0 !important;
// margin-left: -2px !important;
// margin-top: -2px !important;
// }
// ::v-deep .el-table tr .el-table__cell{
// height: 28px !important;
// }
::v-deep .el-table__header-wrapper { background-color: transparent !important; border-top: 1px solid #dfe6ec; border-left: 1px solid #dfe6ec; } ::v-deep .el-table::before, .el-table--group::after, ::v-deep .el-table--border::after{ background-color: transparent !important; } ::v-deep .el-table__body-wrapper { border-left: 1px solid #dfe6ec !important; } // ::v-deep .el-table .el-table__body-wrapper td.el-table__cell,
// ::v-deep .el-table .el-table__fixed-right td.el-table__cell {
// padding: 0 !important;
// border-left: 1px solid #000;
// border-bottom: 1px solid #000;
// border-right: 1px solid #000;
// }
// ::v-deep.el-table .el-table__header-wrapper th.el-table__cell,
// ::v-deep.el-table .el-table__header th.el-table__cell{
// border: 1px solid #000;
// }
::v-deep .el-table--group, .el-table--border{ border: none !important; }
/* 在 style 中 */ ::v-deep .el-table .el-table__body tr:last-child td { background-color: #f5f7fa !important; border-top: 1px solid #dfe6ec !important; border-bottom: 1px solid #dfe6ec !important; } </style>
|