交通管理局公文项目
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

<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>