bonus-ui/src/views/material/cost/component/leaseCostRangeReportHome.vue

686 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container" id="leaseCostRangeReportList">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="查询时间范围" prop="dateRange">
<el-date-picker
v-model="queryParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
style="width: 240px"
@change="handleDateRangeChange">
</el-date-picker>
</el-form-item>
<el-form-item label="协议号" prop="agreementCode">
<el-input v-model="queryParams.agreementCode" placeholder="请输入协议号" clearable style="width: 180px"/>
</el-form-item>
<el-form-item label="结算状态" prop="settlementStatus">
<el-select v-model="queryParams.settlementStatus" placeholder="请选择结算状态" clearable style="width: 160px">
<el-option label="未结算" value="0"></el-option>
<el-option label="已结算" value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="success" icon="el-icon-download" size="mini" @click="exportExcel" :disabled="tableList.length === 0">导出Excel</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="tableList" border stripe :max-height="650">
<el-table-column label="序号" align="center" type="index" width="60">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="协议号" align="center" prop="agreementCode" :show-overflow-tooltip="true" width="150"/>
<el-table-column label="结算单位" align="center" prop="unitName" :show-overflow-tooltip="true" width="180"/>
<el-table-column label="结算工程" align="center" prop="projectName" :show-overflow-tooltip="true" width="200"/>
<el-table-column label="结算状态" align="center" prop="isSettled" width="90">
<template slot-scope="scope">
<el-tag :type="scope.row.isSettled === '1' ? 'success' : 'warning'">
{{ scope.row.isSettled === '1' ? '已结算' : '未结算' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="设备类型数" align="center" prop="equipmentTypeCount" width="100"/>
<el-table-column label="设备总数量" align="center" prop="totalEquipmentCount" width="100">
<template slot-scope="scope">
{{ scope.row.totalEquipmentCount ? parseFloat(scope.row.totalEquipmentCount).toFixed(3) : '0.000' }}
</template>
</el-table-column>
<el-table-column label="总租赁天数" align="center" prop="totalLeaseDays" width="100"/>
<el-table-column label="总租赁费用(元)" align="center" prop="totalLeaseCost" width="130">
<template slot-scope="scope">
{{ scope.row.totalLeaseCost ? parseFloat(scope.row.totalLeaseCost).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="日均租金(元)" align="center" prop="avgDailyRent" width="120">
<template slot-scope="scope">
{{ scope.row.avgDailyRent ? parseFloat(scope.row.avgDailyRent).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="查询开始日期" align="center" prop="queryStartDate" width="120"/>
<el-table-column label="查询结束日期" align="center" prop="queryEndDate" width="120"/>
<el-table-column label="最早租赁时间" align="center" prop="earliestLeaseTime" width="120">
<template slot-scope="scope">
{{ scope.row.earliestLeaseTime || '-' }}
</template>
</el-table-column>
<el-table-column label="最晚归还时间" align="center" prop="latestReturnTime" width="120">
<template slot-scope="scope">
{{ scope.row.latestReturnTime || '-' }}
</template>
</el-table-column>
<el-table-column label="结算时间" align="center" prop="settlementTime" width="120">
<template slot-scope="scope">
{{ scope.row.settlementTime || '-' }}
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" min-width="100">
<template slot-scope="scope">
{{ scope.row.remark || '-' }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-view" @click="handleViewDetails(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<!-- 详情弹窗 -->
<el-dialog
title="租赁费用明细详情"
:visible.sync="detailDialogVisible"
width="90%"
:close-on-click-modal="false">
<div v-if="detailDialogVisible">
<div class="detail-header">
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-info">
<span class="label">协议号:</span>
<span class="value">{{ selectedRowData.agreementCode }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="detail-info">
<span class="label">结算单位:</span>
<span class="value">{{ selectedRowData.unitName }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="detail-info">
<span class="label">结算工程</span>
<span class="value">{{ selectedRowData.projectName }}</span>
</div>
</el-col>
</el-row>
</div>
<div class="detail-operations">
<el-button type="success" icon="el-icon-download" size="mini" @click="exportDetailExcel" :disabled="detailTableList.length === 0">导出明细Excel</el-button>
</div>
<el-table v-loading="detailLoading" :data="detailTableList" border stripe max-height="400">
<el-table-column label="序号" align="center" type="index" width="60">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="机具名称" align="center" prop="typeName" :show-overflow-tooltip="true" width="150"/>
<el-table-column label="机具规格" align="center" prop="modelName" :show-overflow-tooltip="true" width="120">
<template slot-scope="scope">
{{ scope.row.modelName || '-' }}
</template>
</el-table-column>
<el-table-column label="物资编码" align="center" prop="maCode" :show-overflow-tooltip="true" width="120">
<template slot-scope="scope">
{{ scope.row.maCode || '-' }}
</template>
</el-table-column>
<el-table-column label="租赁数量" align="center" prop="num" width="100">
<template slot-scope="scope">
{{ scope.row.num ? parseFloat(scope.row.num).toFixed(3) : '0.000' }}
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="mtUnitName" width="80"/>
<el-table-column label="租赁单价(元)" align="center" prop="leasePrice" width="120">
<template slot-scope="scope">
{{ scope.row.leasePrice ? parseFloat(scope.row.leasePrice).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="计算开始时间" align="center" prop="calcStartTime" width="120"/>
<el-table-column label="计算结束时间" align="center" prop="calcEndTime" width="120"/>
<el-table-column label="租赁天数" align="center" prop="leaseDays" width="100"/>
<el-table-column label="租赁费用(元)" align="center" prop="leaseCost" width="120">
<template slot-scope="scope">
{{ scope.row.leaseCost ? parseFloat(scope.row.leaseCost).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="结算状态" align="center" prop="isSettled" width="90">
<template slot-scope="scope">
<el-tag :type="scope.row.isSettled === '1' ? 'success' : 'warning'">
{{ scope.row.isSettled === '1' ? '已结算' : '未结算' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="结算时间" align="center" prop="settlementTime" width="120">
<template slot-scope="scope">
{{ scope.row.settlementTime || '-' }}
</template>
</el-table-column>
<el-table-column label="出场时间" align="center" prop="startTime" width="120">
<template slot-scope="scope">
{{ scope.row.startTime || '-' }}
</template>
</el-table-column>
<el-table-column label="退场时间" align="center" prop="endTime" width="120">
<template slot-scope="scope">
{{ scope.row.endTime || '-' }}
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" min-width="100">
<template slot-scope="scope">
{{ scope.row.remark || '-' }}
</template>
</el-table-column>
</el-table>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getProjectList,
getUnitList,
getAgreementInfoById,
getUnitListFilterTeam,
} from '@/api/back/index.js'
import { getLeaseCostRangeReportList, getLeaseCostDetails } from '@/api/cost/cost'
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import * as XLSX from 'xlsx';
export default {
name: 'LeaseCostRangeReportHome',
components: { Treeselect },
data() {
return {
// 遮罩层
loading: false,
// 显示搜索条件
showSearch: true,
// 单位数据
unitList: [],
// 工程数据
proList: [],
// 表格数据
tableList: [],
// 查询参数
queryParams: {
unitId: null,
projectId: null,
agreementCode: null,
isSettled: null,
dateRange: null,
startDate: null,
endDate: null,
},
// 详情弹窗相关
detailDialogVisible: false,
detailLoading: false,
detailTableList: [],
selectedRowData: {},
detailQueryParams: {
agreementId: null,
startDate: null,
endDate: null,
},
}
},
created() {
this.initDefaultDateRange()
this.GetUnitData()
this.GetProData()
this.getList()
},
methods: {
// 初始化默认日期范围(当月第一天到最后一天)
initDefaultDateRange() {
const now = new Date()
const year = now.getFullYear()
const month = now.getMonth()
// 当月第一天
const firstDay = new Date(year, month, 1)
const firstDayStr = this.formatDate(firstDay)
// 当月最后一天
const lastDay = new Date(year, month + 1, 0)
const lastDayStr = this.formatDate(lastDay)
this.queryParams.dateRange = [firstDayStr, lastDayStr]
this.queryParams.startDate = firstDayStr
this.queryParams.endDate = lastDayStr
},
// 格式化日期为 yyyy-MM-dd 格式
formatDate(date) {
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}`
},
// 处理日期范围变化
handleDateRangeChange(dateRange) {
if (dateRange && dateRange.length === 2) {
this.queryParams.startDate = dateRange[0]
this.queryParams.endDate = dateRange[1]
} else {
this.queryParams.startDate = null
this.queryParams.endDate = null
}
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.name,
children: node.children,
};
},
// 获取 来往单位 列表数据
async GetUnitData() {
const params = {}
const res = await getUnitListFilterTeam(params)
this.unitList = res.data;
this.getAgreementInfo()
},
unitChange(val){
setTimeout(()=>{
this.queryParams.projectId=null
this.queryParams.agreementCode = null
this.GetProData()
},500)
},
// 获取 工程名称 列表数据
async GetProData() {
const params = {
unitId: this.queryParams.unitId,
}
const res = await getProjectList(params)
this.proList = res.data;
this.getAgreementInfo()
},
proChange(val){
setTimeout(()=>{
this.GetUnitData()
},500)
},
// 获取 协议id
async getAgreementInfo() {
if (this.queryParams.unitId && this.queryParams.projectId) {
const params = {
unitId: this.queryParams.unitId,
projectId: this.queryParams.projectId,
}
const res = await getAgreementInfoById(params)
if (!(res.data && res.data.agreementId)) {
this.$message.error('当前单位和工程无协议!')
this.queryParams.unitId = null
this.queryParams.projectId = null
this.GetUnitData()
this.GetProData()
} else {
this.queryParams.agreementCode = res.data.agreementCode
}
}
},
/** 查询列表 */
getList() {
this.loading = true
getLeaseCostRangeReportList(this.queryParams).then((response) => {
this.tableList = response.rows || []
this.loading = false
}).catch((error) => {
console.error('获取租赁费用区间报表失败:', error)
this.tableList = []
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
unitId: null,
projectId: null,
agreementCode: null,
isSettled: null,
dateRange: null,
startDate: null,
endDate: null,
}
// 重新初始化默认日期范围
this.initDefaultDateRange()
this.resetForm('queryForm')
this.handleQuery()
},
// 导出Excel
exportExcel() {
if (!this.tableList || this.tableList.length === 0) {
this.$modal.msgWarning('没有可导出的数据');
return;
}
try {
// 定义Excel列配置
const columns = [
{ key: 'index', title: '序号' },
{ key: 'agreementCode', title: '协议号' },
{ key: 'unitName', title: '结算单位' },
{ key: 'projectName', title: '结算工程' },
{ key: 'isSettled', title: '结算状态' },
{ key: 'equipmentTypeCount', title: '设备类型数' },
{ key: 'totalEquipmentCount', title: '设备总数量' },
{ key: 'totalLeaseDays', title: '总租赁天数' },
{ key: 'totalLeaseCost', title: '总租赁费用(元)' },
{ key: 'avgDailyRent', title: '日均租金(元)' },
{ key: 'queryStartDate', title: '查询开始日期' },
{ key: 'queryEndDate', title: '查询结束日期' },
{ key: 'earliestLeaseTime', title: '最早租赁时间' },
{ key: 'latestReturnTime', title: '最晚归还时间' },
{ key: 'settlementTime', title: '结算时间' },
{ key: 'remark', title: '备注' }
];
// 准备Excel数据
const excelData = [];
// 添加表头
const headerRow = columns.map(col => col.title);
excelData.push(headerRow);
// 添加数据行
this.tableList.forEach((row, index) => {
const dataRow = columns.map(col => {
if (col.key === 'index') {
return index + 1;
} else if (col.key === 'isSettled') {
return row.isSettled === '1' ? '已结算' : '未结算';
} else if (col.key === 'totalEquipmentCount') {
return row.totalEquipmentCount ? parseFloat(row.totalEquipmentCount).toFixed(3) : '0.000';
} else if (col.key === 'totalLeaseCost' || col.key === 'avgDailyRent') {
return row[col.key] ? parseFloat(row[col.key]).toFixed(2) : '0.00';
} else {
return row[col.key] || '';
}
});
excelData.push(dataRow);
});
// 创建工作簿和工作表
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.aoa_to_sheet(excelData);
// 设置列宽
const columnWidths = [
{ wch: 8 }, // 序号
{ wch: 18 }, // 协议号啊
{ wch: 20 }, // 结算单位
{ wch: 25 }, // 结算工程
{ wch: 10 }, // 结算状态
{ wch: 12 }, // 设备类型数
{ wch: 12 }, // 设备总数量
{ wch: 12 }, // 总租赁天数
{ wch: 15 }, // 总租赁费用
{ wch: 15 }, // 日均租金
{ wch: 15 }, // 查询开始日期
{ wch: 15 }, // 查询结束日期
{ wch: 15 }, // 最早租赁时间
{ wch: 15 }, // 最晚归还时间
{ wch: 12 }, // 结算时间
{ wch: 20 } // 备注
];
worksheet['!cols'] = columnWidths;
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, '租赁费用区间报表');
// 生成文件名(包含日期范围)
let fileName = '租赁费用区间报表';
if (this.queryParams.startDate && this.queryParams.endDate) {
fileName += `_${this.queryParams.startDate}_至_${this.queryParams.endDate}`;
}
fileName += `_${new Date().toISOString().slice(0, 10)}.xlsx`;
// 生成Excel文件并下载
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
// 创建下载链接
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', fileName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 清理URL对象
URL.revokeObjectURL(url);
this.$modal.msgSuccess('Excel导出成功');
} catch (error) {
console.error('导出Excel失败:', error);
this.$modal.msgError('导出Excel失败请稍后重试');
}
},
/** 查看详情 */
handleViewDetails(row) {
this.selectedRowData = row
this.detailQueryParams = {
agreementId: row.agreementId,
startDate: this.queryParams.startDate,
endDate: this.queryParams.endDate,
}
this.detailDialogVisible = true
this.getDetailList()
},
/** 获取详情列表 */
getDetailList() {
this.detailLoading = true
getLeaseCostDetails(this.detailQueryParams).then((response) => {
this.detailTableList = response.rows || []
this.detailLoading = false
}).catch((error) => {
console.error('获取租赁费用明细失败:', error)
this.detailTableList = []
this.detailLoading = false
})
},
/** 导出详情Excel */
exportDetailExcel() {
if (!this.detailTableList || this.detailTableList.length === 0) {
this.$modal.msgWarning('没有可导出的详情数据');
return;
}
try {
// 定义详情Excel列配置
const columns = [
{ key: 'index', title: '序号' },
{ key: 'agreementCode', title: '协议号' },
{ key: 'typeName', title: '机具名称' },
{ key: 'modelName', title: '机具规格' },
{ key: 'maCode', title: '物资编码' },
{ key: 'num', title: '租赁数量' },
{ key: 'mtUnitName', title: '单位' },
{ key: 'leasePrice', title: '租赁单价(元)' },
{ key: 'calcStartTime', title: '计算开始时间' },
{ key: 'calcEndTime', title: '计算结束时间' },
{ key: 'leaseDays', title: '租赁天数' },
{ key: 'leaseCost', title: '租赁费用(元)' },
{ key: 'isSettled', title: '结算状态' },
{ key: 'settlementTime', title: '结算时间' },
{ key: 'startTime', title: '出场时间' },
{ key: 'endTime', title: '退场时间' },
{ key: 'remark', title: '备注' }
];
// 准备Excel数据
const excelData = [];
// 添加表头
const headerRow = columns.map(col => col.title);
excelData.push(headerRow);
// 添加数据行
this.detailTableList.forEach((row, index) => {
const dataRow = columns.map(col => {
if (col.key === 'index') {
return index + 1;
} else if (col.key === 'isSettled') {
return row.isSettled === '1' ? '已结算' : '未结算';
} else if (col.key === 'num') {
return row.num ? parseFloat(row.num).toFixed(3) : '0.000';
} else if (col.key === 'leasePrice' || col.key === 'leaseCost') {
return row[col.key] ? parseFloat(row[col.key]).toFixed(2) : '0.00';
} else {
return row[col.key] || '';
}
});
excelData.push(dataRow);
});
// 创建工作簿和工作表
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.aoa_to_sheet(excelData);
// 设置列宽
const columnWidths = [
{ wch: 8 }, // 序号
{ wch: 18 }, // 协议号
{ wch: 20 }, // 机具名称
{ wch: 15 }, // 机具规格
{ wch: 15 }, // 物资编码
{ wch: 12 }, // 租赁数量
{ wch: 8 }, // 单位
{ wch: 15 }, // 租赁单价
{ wch: 15 }, // 计算开始时间
{ wch: 15 }, // 计算结束时间
{ wch: 10 }, // 租赁天数
{ wch: 15 }, // 租赁费用
{ wch: 10 }, // 结算状态
{ wch: 15 }, // 结算时间
{ wch: 15 }, // 出场时间
{ wch: 15 }, // 退场时间
{ wch: 20 } // 备注
];
worksheet['!cols'] = columnWidths;
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, '租赁费用明细');
// 生成文件名
let fileName = `租赁费用明细_${this.selectedRowData.agreementCode}`;
if (this.detailQueryParams.startDate && this.detailQueryParams.endDate) {
fileName += `_${this.detailQueryParams.startDate}_至_${this.detailQueryParams.endDate}`;
}
fileName += `_${new Date().toISOString().slice(0, 10)}.xlsx`;
// 生成Excel文件并下载
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
// 创建下载链接
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
link.setAttribute('download', fileName);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 清理URL对象
URL.revokeObjectURL(url);
this.$modal.msgSuccess('详情Excel导出成功');
} catch (error) {
console.error('导出详情Excel失败:', error);
this.$modal.msgError('导出详情Excel失败请稍后重试');
}
},
},
}
</script>
<style lang="scss" scoped>
::v-deep.el-table .fixed-width .el-button--mini {
width: 80px !important;
margin-bottom: 10px;
}
.detail-header {
background-color: #f5f7fa;
padding: 15px;
border-radius: 4px;
margin-bottom: 15px;
.detail-info {
margin-bottom: 10px;
.label {
font-weight: bold;
color: #606266;
}
.value {
color: #303133;
margin-left: 5px;
}
}
}
.detail-operations {
margin-bottom: 15px;
text-align: right;
}
</style>