You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
483 lines
16 KiB
483 lines
16 KiB
<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>
|