l3能源成本分摊
This commit is contained in:
419
klp-ui/src/views/ems/cost/cost.vue
Normal file
419
klp-ui/src/views/ems/cost/cost.vue
Normal file
@@ -0,0 +1,419 @@
|
||||
<template>
|
||||
<div class="coil-total-cost-page">
|
||||
<el-card class="search-card">
|
||||
<el-form :model="queryParams" inline label-width="100px" size="small">
|
||||
<el-form-item label="入场卷号" required>
|
||||
<el-input v-model="queryParams.enterCoilNo" placeholder="必填,支持模糊"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前卷号">
|
||||
<el-input v-model="queryParams.currentCoilNo" placeholder="支持模糊"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始日期">
|
||||
<el-date-picker v-model="queryParams.startDate" type="date" value-format="yyyy-MM-dd" placeholder="开始日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束日期">
|
||||
<el-date-picker v-model="queryParams.endDate" type="date" value-format="yyyy-MM-dd" placeholder="结束日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="20" class="summary-row">
|
||||
<el-col :xs="24" :md="6">
|
||||
<div class="summary-card">
|
||||
<div class="label">能源成本</div>
|
||||
<div class="value">¥ {{ formatNumber(energySummary.totalEnergyCost, 2) }}</div>
|
||||
<div class="desc">耗能 {{ formatNumber(energySummary.totalConsumption, 2) }},时长 {{ formatNumber(energySummary.totalDuration, 1) }}h</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="6">
|
||||
<div class="summary-card">
|
||||
<div class="label">本日囤积成本</div>
|
||||
<div class="value">¥ {{ formatNumber(stockSummary.todayCost, 2) }}</div>
|
||||
<div class="desc">净重 {{ formatNumber(stockSummary.totalNetWeight, 2) }},毛重 {{ formatNumber(stockSummary.totalGrossWeight, 2) }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="6">
|
||||
<div class="summary-card">
|
||||
<div class="label">辅料成本</div>
|
||||
<div class="value">¥ 0.00</div>
|
||||
<div class="desc">暂不计</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :md="6">
|
||||
<div class="summary-card highlight">
|
||||
<div class="label">总成本</div>
|
||||
<div class="value">¥ {{ formatNumber(totalCost, 2) }}</div>
|
||||
<div class="desc">能源 + 囤积 + 辅料</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="block-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="card-title">成本汇总(按入场卷号)</span>
|
||||
</div>
|
||||
<el-table :data="mergedRows" border stripe>
|
||||
<el-table-column prop="enterCoilNo" label="入场卷号"></el-table-column>
|
||||
<el-table-column prop="currentCoilNo" label="当前卷号"></el-table-column>
|
||||
<el-table-column prop="energyCost" label="能源成本">
|
||||
<template slot-scope="scope">¥ {{ formatNumber(scope.row.energyCost, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stockCost" label="囤积成本(当日)">
|
||||
<template slot-scope="scope">¥ {{ formatNumber(scope.row.stockCost, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalCost" label="总成本">
|
||||
<template slot-scope="scope">¥ {{ formatNumber(scope.row.totalCost, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalNetWeight" label="净重">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.totalNetWeight, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalGrossWeight" label="毛重">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.totalGrossWeight, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openDetail(scope.row)">查看详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="table-actions">
|
||||
<el-button size="mini" type="primary" icon="el-icon-download" @click="exportSummary">导出汇总</el-button>
|
||||
</div>
|
||||
<pagination
|
||||
v-show="mergedTotal > 0"
|
||||
:total="mergedTotal"
|
||||
:page.sync="mergedQuery.pageNum"
|
||||
:limit.sync="mergedQuery.pageSize"
|
||||
@pagination="loadMerged"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog title="钢卷成本详情" :visible.sync="detailVisible" width="80%" :close-on-click-modal="false">
|
||||
<div class="detail-section">
|
||||
<div class="detail-title">能源分摊明细({{ detailEnterCoilNo }})</div>
|
||||
<el-table :data="detailEnergyRows" stripe border max-height="300">
|
||||
<el-table-column prop="enterCoilNo" label="入场卷号" width="140"></el-table-column>
|
||||
<el-table-column prop="currentCoilNo" label="当前卷号" width="140"></el-table-column>
|
||||
<el-table-column prop="warehouseName" label="库区" width="140"></el-table-column>
|
||||
<el-table-column prop="duration" label="时长(h)" width="100">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.duration, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="consumption" label="分摊能耗" width="120">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.consumption, 4) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalCost" label="分摊成本" width="120">
|
||||
<template slot-scope="scope">¥ {{ formatNumber(scope.row.totalCost, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间" width="180">
|
||||
<template slot-scope="scope">{{ formatTime(scope.row.startTime) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间" width="180">
|
||||
<template slot-scope="scope">{{ formatTime(scope.row.endTime) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<div class="detail-title">囤积成本({{ detailEnterCoilNo }})</div>
|
||||
<el-table :data="detailStockRow ? [detailStockRow] : []" stripe border>
|
||||
<el-table-column prop="enterCoilNo" label="入场卷号"></el-table-column>
|
||||
<el-table-column prop="totalNetWeight" label="净重">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.totalNetWeight, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalGrossWeight" label="毛重">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.totalGrossWeight, 2) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="avgStorageDays" label="平均在库天数">
|
||||
<template slot-scope="scope">{{ formatNumber(scope.row.avgStorageDays, 1) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="todayCost" label="本日囤积成本">
|
||||
<template slot-scope="scope">¥ {{ formatNumber(scope.row.todayCost != null ? scope.row.todayCost : scope.row.totalCost, 2) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="detailVisible = false">关 闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fetchCoilTotalEnergySummary, fetchCoilTotalEnergyDetail } from '@/api/ems/energyCostReport'
|
||||
import { fetchCoilTotalMerged } from '@/api/ems/energyCostReport'
|
||||
import { exportCoilTotalMerged } from '@/api/ems/energyCostReport'
|
||||
import { getStockpileCostList } from '@/api/wms/cost'
|
||||
|
||||
export default {
|
||||
name: 'CoilTotalCost',
|
||||
data() {
|
||||
return {
|
||||
queryParams: {
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
startDate: undefined,
|
||||
endDate: undefined
|
||||
},
|
||||
energyQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 50
|
||||
},
|
||||
mergedQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 50
|
||||
},
|
||||
stockQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 50
|
||||
},
|
||||
energySummary: {
|
||||
coilCount: 0,
|
||||
totalDuration: 0,
|
||||
totalConsumption: 0,
|
||||
totalEnergyCost: 0
|
||||
},
|
||||
energyDetail: {
|
||||
rows: [],
|
||||
total: 0
|
||||
},
|
||||
mergedRows: [],
|
||||
mergedTotal: 0,
|
||||
stockDetail: {
|
||||
rows: [],
|
||||
total: 0
|
||||
},
|
||||
stockSummary: {
|
||||
totalCost: 0,
|
||||
todayCost: 0,
|
||||
totalNetWeight: 0,
|
||||
totalGrossWeight: 0
|
||||
},
|
||||
energyLoading: false,
|
||||
stockLoading: false,
|
||||
detailVisible: false,
|
||||
detailEnterCoilNo: '',
|
||||
detailEnergyRows: [],
|
||||
detailStockRow: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalCost() {
|
||||
const energy = Number(this.energySummary.totalEnergyCost) || 0
|
||||
const stock = Number(this.stockSummary.todayCost ?? this.stockSummary.totalCost) || 0
|
||||
return energy + stock
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.handleSearch()
|
||||
},
|
||||
methods: {
|
||||
handleSearch() {
|
||||
this.energyQuery.pageNum = 1
|
||||
this.mergedQuery.pageNum = 1
|
||||
this.stockQuery.pageNum = 1
|
||||
this.loadEnergy()
|
||||
this.loadMerged()
|
||||
this.loadStockDetail()
|
||||
},
|
||||
handleReset() {
|
||||
this.queryParams = {
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
startDate: undefined,
|
||||
endDate: undefined
|
||||
}
|
||||
this.energyQuery.pageNum = 1
|
||||
this.mergedQuery.pageNum = 1
|
||||
this.stockQuery.pageNum = 1
|
||||
this.energySummary = { coilCount: 0, totalDuration: 0, totalConsumption: 0, totalEnergyCost: 0 }
|
||||
this.energyDetail = { rows: [], total: 0 }
|
||||
this.mergedRows = []
|
||||
this.mergedTotal = 0
|
||||
this.stockDetail = { rows: [], total: 0 }
|
||||
this.stockSummary = { totalCost: 0, totalNetWeight: 0, totalGrossWeight: 0 }
|
||||
this.handleSearch()
|
||||
},
|
||||
loadMerged() {
|
||||
const params = {
|
||||
...this.queryParams,
|
||||
pageNum: this.mergedQuery.pageNum,
|
||||
pageSize: this.mergedQuery.pageSize
|
||||
}
|
||||
fetchCoilTotalMerged(params).then(res => {
|
||||
this.mergedRows = res.rows || []
|
||||
this.mergedTotal = res.total || 0
|
||||
})
|
||||
},
|
||||
loadEnergy() {
|
||||
this.energyLoading = true
|
||||
const params = { ...this.queryParams }
|
||||
fetchCoilTotalEnergySummary(params).then(res => {
|
||||
this.energySummary = res.data || this.energySummary
|
||||
}).finally(() => {
|
||||
this.loadEnergyDetail()
|
||||
})
|
||||
},
|
||||
loadEnergyDetail() {
|
||||
const params = {
|
||||
...this.queryParams,
|
||||
pageNum: this.energyQuery.pageNum,
|
||||
pageSize: this.energyQuery.pageSize
|
||||
}
|
||||
fetchCoilTotalEnergyDetail(params).then(res => {
|
||||
this.energyDetail = {
|
||||
rows: res.rows || [],
|
||||
total: res.total || 0
|
||||
}
|
||||
}).finally(() => {
|
||||
this.energyLoading = false
|
||||
})
|
||||
},
|
||||
loadStockDetail() {
|
||||
this.stockLoading = true
|
||||
const params = {
|
||||
enterCoilNo: this.queryParams.enterCoilNo,
|
||||
currentCoilNo: this.queryParams.currentCoilNo,
|
||||
pageNum: this.stockQuery.pageNum,
|
||||
pageSize: this.stockQuery.pageSize
|
||||
}
|
||||
getStockpileCostList(params).then(res => {
|
||||
const data = res.data || {}
|
||||
this.stockDetail = {
|
||||
rows: data.rows || [],
|
||||
total: data.total || 0
|
||||
}
|
||||
const summary = data.summary || {}
|
||||
this.stockSummary = {
|
||||
totalCost: summary.totalCost ?? 0,
|
||||
todayCost: summary.todayCost ?? summary.totalCost ?? 0,
|
||||
totalNetWeight: summary.totalNetWeight ?? 0,
|
||||
totalGrossWeight: summary.totalGrossWeight ?? 0
|
||||
}
|
||||
}).finally(() => {
|
||||
this.stockLoading = false
|
||||
})
|
||||
},
|
||||
openDetail(row) {
|
||||
if (!row || !row.enterCoilNo) return
|
||||
this.detailEnterCoilNo = row.enterCoilNo
|
||||
this.detailVisible = true
|
||||
this.loadDetailEnergy(row.enterCoilNo)
|
||||
this.loadDetailStock(row.enterCoilNo)
|
||||
},
|
||||
loadDetailEnergy(enterCoilNo) {
|
||||
const params = {
|
||||
enterCoilNo,
|
||||
pageNum: 1,
|
||||
pageSize: 200
|
||||
}
|
||||
fetchCoilTotalEnergyDetail(params).then(res => {
|
||||
this.detailEnergyRows = res.rows || []
|
||||
})
|
||||
},
|
||||
loadDetailStock(enterCoilNo) {
|
||||
const params = {
|
||||
enterCoilNo,
|
||||
pageNum: 1,
|
||||
pageSize: 1
|
||||
}
|
||||
getStockpileCostList(params).then(res => {
|
||||
const data = res.data || {}
|
||||
const rows = data.rows || []
|
||||
this.detailStockRow = rows.find(item => item.enterCoilNo === enterCoilNo) || null
|
||||
})
|
||||
},
|
||||
exportSummary() {
|
||||
const params = { ...this.queryParams }
|
||||
exportCoilTotalMerged(params).then(res => {
|
||||
const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = 'coil_cost_summary.xlsx'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
},
|
||||
formatNumber(val, digits = 2) {
|
||||
const num = Number(val)
|
||||
if (isNaN(num)) return '0'.padEnd(2 + digits, '0')
|
||||
return num.toFixed(digits)
|
||||
},
|
||||
formatTime(val) {
|
||||
if (!val) return '-'
|
||||
const date = new Date(val)
|
||||
if (Number.isNaN(date.getTime())) return val
|
||||
return date.toLocaleString('zh-CN')
|
||||
},
|
||||
formatStatus(status) {
|
||||
const map = { 0: '在产', 1: '在产', 2: '完成' }
|
||||
return map[status] || '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.coil-total-cost-page {
|
||||
padding: 20px;
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.summary-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
|
||||
.label {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
.value {
|
||||
margin-top: 8px;
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
}
|
||||
.desc {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
&.highlight {
|
||||
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
|
||||
border-color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.block-card {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.card-title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
.sub {
|
||||
margin-left: 12px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
.cost {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user