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

1037 lines
46 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="costApplyList">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item prop="unitIds">
<treeselect
v-model="queryParams.unitId"
:options="unitList" :normalizer="normalizer"
:show-count="true" style="width: 240px" :disable-branch-nodes="true"
noChildrenText="没有数据了" noOptionsText="没有数据" noResultsText="没有搜索结果"
placeholder="请选择结算单位" @select="unitChange"
/>
</el-form-item>
<el-form-item prop="projectIds">
<treeselect
v-model="queryParams.projectId"
:options="proList" :normalizer="normalizer"
:show-count="true" style="width: 240px" :disable-branch-nodes="true"
noChildrenText="没有数据了" noOptionsText="没有数据" noResultsText="没有搜索结果"
placeholder="请选择结算工程" @select="proChange"
/>
</el-form-item>
<el-form-item prop="agreementCode">
<el-input v-model="queryParams.agreementCode" placeholder="请输入协议号" clearable/>
</el-form-item>
<el-form-item 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>
<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" >
<el-table-column label="序号" align="center" type="index" width="60">
<template slot-scope="scope">
<span>{{
(queryParams.pageNum - 1) * 10 + scope.$index + 1
}}</span>
</template>
</el-table-column>
<el-table-column label="协议号" align="center" prop="agreementCode" :show-overflow-tooltip="true"/>
<el-table-column label="结算单位" align="center" prop="unitName" />
<el-table-column label="结算工程" align="center" prop="projectName" />
<el-table-column label="结算时间" align="center" prop="createTime" width="100" />
<el-table-column label="结算类型" align="center" prop="sltStatus" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-tag v-if="scope.row.settlementType === 1" effect="plain">工器具</el-tag>
<el-tag type="warning" v-if="scope.row.settlementType === 2" effect="plain">安全工器具</el-tag>
<el-tag v-if="scope.row.settlementType == null || scope.row.settlementType === 0" effect="plain">总费用</el-tag>
</template>
</el-table-column>
<el-table-column label="租赁费用" align="center" prop="leaseCost" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
type="text"
@click="showCostDetail(scope.row, 'lease')"
:style="{color: scope.row.leaseCost > 0 ? '#409EFF' : '#606266'}"
:disabled="!(scope.row.leaseCost > 0)">
{{ scope.row.leaseCost || 0 }}
</el-button>
</template>
</el-table-column>
<el-table-column label="维修费用" align="center" prop="repairCost" width="80">
<template slot-scope="scope">
<el-button
type="text"
@click="showCostDetail(scope.row, 'repair')"
:style="{color: scope.row.repairCost > 0 ? '#409EFF' : '#606266'}"
:disabled="!(scope.row.repairCost > 0)">
{{ scope.row.repairCost || 0 }}
</el-button>
</template>
</el-table-column>
<el-table-column label="丢失费用" align="center" prop="loseCost" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
type="text"
@click="showCostDetail(scope.row, 'lose')"
:style="{color: scope.row.loseCost > 0 ? '#409EFF' : '#606266'}"
:disabled="!(scope.row.loseCost > 0)">
{{ scope.row.loseCost || 0 }}
</el-button>
</template>
</el-table-column>
<el-table-column label="报废费用" align="center" prop="scrapCost" width="80">
<template slot-scope="scope">
<el-button
type="text"
@click="showCostDetail(scope.row, 'scrap')"
:style="{color: scope.row.scrapCost > 0 ? '#409EFF' : '#606266'}"
:disabled="!(scope.row.scrapCost > 0)">
{{ scope.row.scrapCost || 0 }}
</el-button>
</template>
</el-table-column>
<el-table-column label="合计费用(元)" align="center" prop="costs" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
type="text"
@click="showCostDetail(scope.row, 'total')"
:style="{color: scope.row.costs > 0 ? '#409EFF' : '#606266'}"
:disabled="!(scope.row.costs > 0)">
<span v-if="scope.row.costs != null && scope.row.costs != ''">
{{ scope.row.costs.toFixed(2) }}
</span>
<span v-else>{{ 0.00 }}</span>
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <pagination-->
<!-- v-show="total > 0"-->
<!-- :total="total"-->
<!-- :page.sync="queryParams.pageNum"-->
<!-- :limit.sync="queryParams.pageSize"-->
<!-- @pagination="getList"-->
<!-- />-->
<!-- 费用详情弹窗 -->
<el-dialog
:title="costDetailTitle"
:visible.sync="costDetailVisible"
width="80%"
top="5vh"
:close-on-click-modal="false"
@closed="handleCostDetailDialogClosed">
<!-- 租赁费用详情表格 -->
<el-table
v-if="costDetailType === 'lease'"
v-loading="costDetailLoading"
:data="costDetailList"
:key="'lease-table-' + costDetailType"
border
stripe
height="500">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="型号" align="center" prop="model" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="单价(元)" align="center" prop="unitPrice" width="100" />
<el-table-column label="数量" align="center" prop="quantity" width="80" />
<el-table-column label="归还数量" align="center" prop="returnQuantity" width="100" />
<el-table-column label="租赁日期" align="center" prop="leaseDate" width="120" />
<el-table-column label="退还日期" align="center" prop="returnDate" width="120" />
<el-table-column label="天数" align="center" prop="days" width="80" />
<el-table-column label="费用(元)" align="center" prop="cost" width="100">
<template slot-scope="scope">
{{ scope.row.cost ? scope.row.cost.toFixed(2) : '0.00' }}
</template>
</el-table-column>
</el-table>
<!-- 维修费用详情表格 -->
<el-table
v-if="costDetailType === 'repair'"
v-loading="costDetailLoading"
:data="costDetailList"
:key="'repair-table-' + costDetailType"
border
stripe
height="500">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="机具名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="规格型号" align="center" prop="model" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="维修数量" align="center" prop="repairQuantity" width="100" />
<el-table-column label="维修费用(元)" align="center" prop="cost" width="120">
<template slot-scope="scope">
{{ scope.row.cost ? scope.row.cost.toFixed(2) : '0.00' }}
</template>
</el-table-column>
</el-table>
<!-- 丢失费用详情表格 -->
<el-table
v-if="costDetailType === 'lose'"
v-loading="costDetailLoading"
:data="costDetailList"
:key="'lose-table-' + costDetailType"
border
stripe
height="500">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="机具名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="规格型号" align="center" prop="model" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="丢失数量" align="center" prop="loseQuantity" width="100" />
<el-table-column label="丢失费用(元)" align="center" prop="cost" width="120">
<template slot-scope="scope">
{{ scope.row.cost ? scope.row.cost.toFixed(2) : '0.00' }}
</template>
</el-table-column>
</el-table>
<!-- 报废费用详情表格 -->
<el-table
v-if="costDetailType === 'scrap'"
v-loading="costDetailLoading"
:data="costDetailList"
:key="'scrap-table-' + costDetailType"
border
stripe
height="500">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="机具名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="机具规格" align="center" prop="model" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="报废数量" align="center" prop="scrapQuantity" width="100" />
<el-table-column label="报废费用(元)" align="center" prop="cost" width="120">
<template slot-scope="scope">
{{ scope.row.cost ? scope.row.cost.toFixed(2) : '0.00' }}
</template>
</el-table-column>
</el-table>
<!-- 合计费用详情表格 -->
<el-table
v-if="costDetailType === 'total'"
v-loading="costDetailLoading"
:data="costDetailList"
:key="'total-table-' + costDetailType"
border
stripe
height="500">
<el-table-column label="序号" align="center" type="index" width="60" />
<el-table-column label="名称" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table-column label="型号" align="center" prop="model" :show-overflow-tooltip="true" />
<el-table-column label="单位" align="center" prop="unit" width="80" />
<el-table-column label="单价(元)" align="center" width="100">
<template slot-scope="scope">
{{ scope.row.costType === 'lease' ? (scope.row.unitPrice || 0) : '-' }}
</template>
</el-table-column>
<el-table-column label="数量" align="center" width="80">
<template slot-scope="scope">
<span v-if="scope.row.costType === 'lease'">{{ scope.row.quantity || 0 }}</span>
<span v-else-if="scope.row.costType === 'repair'">{{ scope.row.repairQuantity || 0 }}</span>
<span v-else-if="scope.row.costType === 'lose'">{{ scope.row.loseQuantity || 0 }}</span>
<span v-else-if="scope.row.costType === 'scrap'">{{ scope.row.scrapQuantity || 0 }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="归还数量" align="center" width="100">
<template slot-scope="scope">
{{ scope.row.costType === 'lease' ? (scope.row.returnQuantity || 0) : '-' }}
</template>
</el-table-column>
<el-table-column label="租赁日期" align="center" width="120">
<template slot-scope="scope">
{{ scope.row.costType === 'lease' ? (scope.row.leaseDate || '-') : '-' }}
</template>
</el-table-column>
<el-table-column label="退还日期" align="center" width="120">
<template slot-scope="scope">
{{ scope.row.costType === 'lease' ? (scope.row.returnDate || '-') : '-' }}
</template>
</el-table-column>
<el-table-column label="天数" align="center" width="80">
<template slot-scope="scope">
{{ scope.row.costType === 'lease' ? (scope.row.days || 0) : '-' }}
</template>
</el-table-column>
<el-table-column label="费用(元)" align="center" prop="cost" width="100">
<template slot-scope="scope">
{{ scope.row.cost ? scope.row.cost.toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="费用类型" align="center" prop="costType" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.costType === 'lease'" type="primary">租赁费用</el-tag>
<el-tag v-else-if="scope.row.costType === 'repair'" type="warning">维修费用</el-tag>
<el-tag v-else-if="scope.row.costType === 'lose'" type="danger">丢失费用</el-tag>
<el-tag v-else-if="scope.row.costType === 'scrap'" type="info">报废费用</el-tag>
<el-tag v-else>未知</el-tag>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button type="primary" icon="el-icon-download" @click="exportCostDetail">导出Excel</el-button>
<el-button @click="costDetailVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getProjectList,
getUnitList,
getAgreementInfoById, getUnitListFilterTeam,
} from '@/api/back/index.js'
import {getSltList, costExamine, getSltInfo, getSltReportedList} from '@/api/cost/cost'
import { toChineseAmount } from '@/utils/bonus.js'
import vueEasyPrint from "vue-easy-print";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import * as XLSX from 'xlsx';
export default {
name: 'ReportHome',
dicts: ['cost_status'],
components: { Treeselect, vueEasyPrint },
data() {
return {
// 遮罩层
loading: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 单位数据
unitList: [],
// 工程数据
proList: [],
unitIds: null,
projectIds: null,
selectTreeProps: {
children: 'children',
label: 'name',
value: 'id',
// multiple: true,//false
},
statusList: [
{ id: '1', name: '待审核' },
{ id: '2', name: '审核通过' },
{ id: '3', name: '审核驳回' },
], //集合
// 表格数据
tableList: [],
// 查询参数
queryParams: {
disabled: false,
pageNum: 1,
pageSize: 10000,
keyWord: undefined,
sltStatus: '',
isCommit: '',
unitId: null,
projectId: null,
agreementId: null,
agreementCode: null,
dateRange: null,
startTime: null,
endTime: null,
},
openPrint: false,
// 审批弹窗
aform: { status: '2' },
//审批弹窗是否开启
applyVisible: false,
id: '',
agreementIdTemp: '',
// 协议书内容
agreementContent: {
agreementCode: '',
projectName: '',
unitName: '',
leaseCost: '', // 租赁费用
repairCost: '', // 维修费用
loseCost: '', // 丢失费用
scrapCost: '', // 报废费用
reductionCost: '', // 减免费用
costAll: '', // 合计费用
costAllUpper: '', // 合计费用大写
},
// 费用详情弹窗相关
costDetailVisible: false,
costDetailLoading: false,
costDetailTitle: '',
costDetailList: [],
costDetailType: '', // 当前查看的费用类型
}
},
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.startTime = firstDayStr
this.queryParams.endTime = 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.startTime = dateRange[0]
this.queryParams.endTime = dateRange[1]
} else {
this.queryParams.startTime = null
this.queryParams.endTime = 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 = {
// projectId: this.queryParams.projectId /* */,
}
const res = await getUnitListFilterTeam(params)
this.unitList = res.data;
this.getAgreementInfo()
},
unitChange(val){
setTimeout(()=>{
this.queryParams.projectId=null
this.queryParams.agreementId = 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)
console.log(res)
if (!(res.data && res.data.agreementId)) {
this.$message.error('当前单位和工程无协议!')
this.queryParams.unitId = null
this.queryParams.projectId = null
this.GetUnitData()
this.GetProData()
} else {
this.queryParams.agreementId = res.data.agreementId
this.queryParams.agreementCode = res.data.agreementCode
}
}
},
/** 查询列表 */
getList() {
this.loading = true
getSltReportedList(this.queryParams).then((response) => {
this.tableList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams={
pageNum: 1,
pageSize: 10000,
sltStatus: '',
isCommit:'',
unitId: null,
projectId: null,
agreementId: '',
agreementCode: '',
dateRange: null,
startTime: null,
endTime: null,
}
// 重新初始化默认日期范围
this.initDefaultDateRange()
this.resetForm('queryForm')
this.handleQuery()
},
//结算审批查看
handleView(row) {
let arr = [];
arr.push(row);
this.$emit("goDetail",JSON.stringify(arr));
},
//结算审批
handleExame(row) {
this.id = row.id
this.agreementIdTemp = row.agreementId
this.applyVisible = true
},
//提交按钮
submitListForm() {
let param = {
id: this.id,
status: this.aform.status,
remark: this.aform.remark,
agreementId: this.agreementIdTemp,
}
costExamine(param).then((res) => {
if (res.code == 200) {
this.$modal.msgSuccess("审批成功");
this.getList();
this.applyVisible = false;
} else {
this.$modal.msgError(res.msg);
}
}).catch(() => {});
},
//取消按钮
cancel() {
this.applyVisible = false;
this.aform = { status: '2' };
},
async openPrintDialog(row){
this.openPrint = true
try {
const res = await getSltInfo([row])
console.log('🚀 ~ openPrintDialog ~ res:', res)
if (!res.data) return
this.agreementContent = res.data
this.agreementContent.agreementCode = row.agreementCode
this.agreementContent.costAll = Number(res.data.leaseCost) + Number(res.data.repairCost) + Number(res.data.scrapCost) + Number(res.data.loseCost) - Number(res.data.reductionCost)
// costAllUpper 中文大写
this.agreementContent.costAllUpper = toChineseAmount(this.agreementContent.costAll.toFixed(2))
} catch (error) {
console.log('🚀 ~ openPrintDialog ~ error:', error)
}
},
//维修任务单打印
print() {
this.$refs.remarksPrintRef.print();
},
// 显示费用详情
async showCostDetail(row, costType) {
const costTypeMap = {
'lease': '租赁费用',
'repair': '维修费用',
'lose': '丢失费用',
'scrap': '报废费用',
'total': '合计费用'
};
this.costDetailTitle = `${costTypeMap[costType]}详情 - ${row.agreementCode}`;
this.costDetailType = costType;
this.costDetailVisible = true;
this.costDetailLoading = true;
// 确保完全清空之前的数据,避免数据污染
this.costDetailList = [];
try {
// 构造请求参数,使用与现有方法相同的格式
const requestData = [row];
const response = await getSltInfo(requestData);
if (response.code === 200 && response.data) {
let sourceList = [];
// 根据费用类型获取对应的数据列表
switch (costType) {
case 'lease':
sourceList = response.data.leaseList || [];
break;
case 'repair':
sourceList = response.data.repairList || [];
break;
case 'lose':
sourceList = response.data.loseList || [];
break;
case 'scrap':
sourceList = response.data.scrapList || [];
break;
case 'total':
// 合计费用显示所有类型的数据
const allLists = [
...(response.data.leaseList || []).map(item => ({...item, costType: 'lease'})),
...(response.data.repairList || []).map(item => ({...item, costType: 'repair'})),
...(response.data.loseList || []).map(item => ({...item, costType: 'lose'})),
...(response.data.scrapList || []).map(item => ({...item, costType: 'scrap'}))
];
sourceList = allLists;
break;
default:
sourceList = [];
}
// 根据不同费用类型处理数据,创建完全独立的数据对象避免引用污染
const newDetailList = sourceList.map(item => {
// 创建深度拷贝的基础数据对象
const baseData = {
name: (item.typeName || '').toString(),
model: (item.modelName || '').toString(),
unit: (item.mtUnitName || '').toString(),
cost: Number(item.costs || 0),
costType: (item.costType || costType).toString()
};
// 根据费用类型添加特定字段,确保每个对象都是独立的
if (costType === 'lease' || (costType === 'total' && item.costType === 'lease')) {
return {
name: baseData.name,
model: baseData.model,
unit: baseData.unit,
cost: baseData.cost,
costType: baseData.costType,
unitPrice: Number(item.leasePrice || 0),
quantity: Number(item.num || 0),
returnQuantity: Number(item.backNum || 0),
leaseDate: (item.startTime || '').toString(),
returnDate: (item.endTime || '').toString(),
days: Number(item.leaseDays || 0)
};
} else if (costType === 'repair' || (costType === 'total' && item.costType === 'repair')) {
return {
name: baseData.name,
model: baseData.model,
unit: baseData.unit,
cost: baseData.cost,
costType: baseData.costType,
repairQuantity: Number(item.num || 0)
};
} else if (costType === 'lose' || (costType === 'total' && item.costType === 'lose')) {
return {
name: baseData.name,
model: baseData.model,
unit: baseData.unit,
cost: baseData.cost,
costType: baseData.costType,
loseQuantity: Number(item.num || 0)
};
} else if (costType === 'scrap' || (costType === 'total' && item.costType === 'scrap')) {
return {
name: baseData.name,
model: baseData.model,
unit: baseData.unit,
cost: baseData.cost,
costType: baseData.costType,
scrapQuantity: Number(item.num || 0)
};
}
return baseData;
});
// 使用$nextTick确保DOM完全更新后再赋值数据
this.$nextTick(() => {
this.costDetailList = newDetailList;
});
} else {
this.$modal.msgError(response.msg || '获取费用详情失败');
}
} catch (error) {
console.error('获取费用详情失败:', error);
this.$modal.msgError('获取费用详情失败,请稍后重试');
} finally {
this.costDetailLoading = false;
}
},
// 费用详情弹窗关闭时的数据清理
handleCostDetailDialogClosed() {
// 完全清理数据,确保下次打开时是全新状态
this.costDetailList = [];
this.costDetailType = '';
this.costDetailTitle = '';
this.costDetailLoading = false;
},
// 导出费用详情为Excel
exportCostDetail() {
if (!this.costDetailList || this.costDetailList.length === 0) {
this.$modal.msgWarning('没有可导出的数据');
return;
}
try {
// 根据费用类型定义不同的列配置
let columns = [];
let fileName = '';
let sheetName = '';
switch (this.costDetailType) {
case 'lease':
columns = [
{ key: 'name', title: '名称' },
{ key: 'model', title: '型号' },
{ key: 'unit', title: '单位' },
{ key: 'unitPrice', title: '单价(元)' },
{ key: 'quantity', title: '数量' },
{ key: 'returnQuantity', title: '归还数量' },
{ key: 'leaseDate', title: '租赁日期' },
{ key: 'returnDate', title: '退还日期' },
{ key: 'days', title: '天数' },
{ key: 'cost', title: '费用(元)' }
];
fileName = '租赁费用详情';
sheetName = '租赁费用';
break;
case 'repair':
columns = [
{ key: 'name', title: '机具名称' },
{ key: 'model', title: '规格型号' },
{ key: 'unit', title: '单位' },
{ key: 'repairQuantity', title: '维修数量' },
{ key: 'cost', title: '维修费用(元)' }
];
fileName = '维修费用详情';
sheetName = '维修费用';
break;
case 'lose':
columns = [
{ key: 'name', title: '机具名称' },
{ key: 'model', title: '规格型号' },
{ key: 'unit', title: '单位' },
{ key: 'loseQuantity', title: '丢失数量' },
{ key: 'cost', title: '丢失费用(元)' }
];
fileName = '丢失费用详情';
sheetName = '丢失费用';
break;
case 'scrap':
columns = [
{ key: 'name', title: '机具名称' },
{ key: 'model', title: '机具规格' },
{ key: 'unit', title: '单位' },
{ key: 'scrapQuantity', title: '报废数量' },
{ key: 'cost', title: '报废费用(元)' }
];
fileName = '报废费用详情';
sheetName = '报废费用';
break;
case 'total':
columns = [
{ key: 'name', title: '名称' },
{ key: 'model', title: '型号' },
{ key: 'unit', title: '单位' },
{ key: 'unitPrice', title: '单价(元)' },
{ key: 'quantity', title: '数量' },
{ key: 'returnQuantity', title: '归还数量' },
{ key: 'leaseDate', title: '租赁日期' },
{ key: 'returnDate', title: '退还日期' },
{ key: 'days', title: '天数' },
{ key: 'cost', title: '费用(元)' },
{ key: 'costType', title: '费用类型' }
];
fileName = '合计费用详情';
sheetName = '合计费用';
break;
default:
this.$modal.msgError('未知的费用类型');
return;
}
// 准备Excel数据
const excelData = [];
// 添加表头
const headerRow = columns.map(col => col.title);
excelData.push(headerRow);
// 添加数据行
this.costDetailList.forEach(row => {
const dataRow = columns.map(col => {
let value = row[col.key] || '';
// 特殊处理费用类型字段
if (col.key === 'costType') {
const typeMap = {
'lease': '租赁费用',
'repair': '维修费用',
'lose': '丢失费用',
'scrap': '报废费用'
};
value = typeMap[value] || value;
}
// 处理数值字段的格式
if (col.key === 'cost' || col.key === 'unitPrice') {
value = typeof value === 'number' ? parseFloat(value.toFixed(2)) : value;
}
return value;
});
excelData.push(dataRow);
});
// 创建工作簿和工作表
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.aoa_to_sheet(excelData);
// 设置列宽
const columnWidths = columns.map(col => {
// 根据列内容设置不同的宽度
if (col.key === 'name') return { wch: 20 };
if (col.key === 'model') return { wch: 15 };
if (col.key === 'leaseDate' || col.key === 'returnDate') return { wch: 12 };
if (col.key === 'cost' || col.key === 'unitPrice') return { wch: 12 };
if (col.key === 'costType') return { wch: 12 };
return { wch: 10 };
});
worksheet['!cols'] = columnWidths;
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
// 生成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}_${new Date().toISOString().slice(0, 10)}.xlsx`);
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失败请稍后重试');
}
},
// 导出主表格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: 'createTime', title: '结算时间' },
{ key: 'settlementType', title: '结算类型' },
{ key: 'leaseCost', title: '租赁费用' },
{ key: 'repairCost', title: '维修费用' },
{ key: 'loseCost', title: '丢失费用' },
{ key: 'scrapCost', title: '报废费用' },
{ key: 'costs', 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 (this.queryParams.pageNum - 1) * 10 + index + 1;
} else if (col.key === 'settlementType') {
// 处理结算类型显示
if (row.settlementType === 1) return '工器具';
if (row.settlementType === 2) return '安全工器具';
return '总费用';
} else if (col.key === 'costs') {
// 处理合计费用格式
return row.costs != null && row.costs !== '' ? parseFloat(row.costs.toFixed(2)) : 0.00;
} else if (col.key === 'leaseCost' || col.key === 'repairCost' || col.key === 'loseCost' || col.key === 'scrapCost') {
// 处理费用字段格式
return row[col.key] || 0;
} 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: 20 }, // 协议号
{ wch: 15 }, // 结算单位
{ wch: 20 }, // 结算工程
{ wch: 12 }, // 结算时间
{ wch: 12 }, // 结算类型
{ wch: 12 }, // 租赁费用
{ wch: 12 }, // 维修费用
{ wch: 12 }, // 丢失费用
{ wch: 12 }, // 报废费用
{ wch: 15 } // 合计费用
];
worksheet['!cols'] = columnWidths;
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, '结算记录');
// 生成文件名(包含日期范围)
let fileName = '结算记录';
if (this.queryParams.startTime && this.queryParams.endTime) {
fileName += `_${this.queryParams.startTime}_至_${this.queryParams.endTime}`;
}
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;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
}
.tabelColumn {
width:1000px;
height: 50px;
display: flex;
align-items: center;
border: 1px solid #9c9c9c;
// margin-bottom: 1px;
border-bottom: none;
}
.columnLabel {
height: 50px;
line-height: 50px;
text-align: center;
border-left: none;
}
.columnContent {
height: 50px;
line-height: 50px;
text-align: center;
border-left: 1px solid #9c9c9c;
}
</style>