提交基础采购

This commit is contained in:
2025-11-18 16:45:05 +08:00
parent cc9b1c0e92
commit 7c04e13198
77 changed files with 5733 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
<template>
<div class="erp-report-page">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>采购汇总</span>
<el-date-picker
v-model="range"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
size="small"
unlink-panels
start-placeholder="开始时间"
end-placeholder="结束时间"
@change="loadSummary"
/>
</div>
<el-row :gutter="16">
<el-col :span="6">
<div class="metric-card">
<p class="label">采购总金额</p>
<p class="value">{{ summary.totalAmount | formatMoney }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">供应商数量</p>
<p class="value">{{ supplierBrief.length }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">最大供应商金额</p>
<p class="value">{{ topSupplierAmount | formatMoney }}</p>
</div>
</el-col>
<el-col :span="6">
<div class="metric-card">
<p class="label">平均订单金额</p>
<p class="value">{{ avgSupplierAmount | formatMoney }}</p>
</div>
</el-col>
</el-row>
</el-card>
<el-row :gutter="16">
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商汇总</span>
</div>
<el-table :data="supplierBrief" border size="small" height="320">
<el-table-column prop="supplierId" label="供应商ID" width="140" />
<el-table-column prop="orderCount" label="订单数" width="100" />
<el-table-column prop="totalAmount" label="总金额" />
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>价格趋势</span>
</div>
<el-table :data="priceTrend" border size="small" height="320">
<el-table-column prop="period" label="月份" width="120" />
<el-table-column prop="materialCode" label="物料编码" width="140" />
<el-table-column prop="avgPrice" label="平均含税价" />
</el-table>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="never" class="panel-card">
<div slot="header" class="panel-header">
<span>供应商退货率</span>
</div>
<el-table :data="supplierQuality" border size="small" height="320">
<el-table-column prop="supplierId" label="供应商ID" width="140" />
<el-table-column prop="receivedQty" label="收货量" />
<el-table-column prop="returnQty" label="退货量" />
<el-table-column label="退货率">
<template slot-scope="scope">
{{ formatPercent(scope.row.returnRate) }}
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getPurchaseReportSummary, getPurchasePriceTrend, getSupplierQuality } from '@/api/erp/purchase'
export default {
name: 'ErpPurchaseReport',
data() {
return {
range: [],
summary: { totalAmount: 0 },
supplierBrief: [],
priceTrend: [],
supplierQuality: []
}
},
filters: {
formatMoney(value) {
return Number(value || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}
},
computed: {
topSupplierAmount() {
if (!this.supplierBrief.length) return 0
return Math.max(...this.supplierBrief.map(item => Number(item.totalAmount || 0)))
},
avgSupplierAmount() {
if (!this.supplierBrief.length) return 0
const sum = this.supplierBrief.reduce((acc, cur) => acc + Number(cur.totalAmount || 0), 0)
return sum / this.supplierBrief.length
}
},
created() {
this.loadSummary()
},
methods: {
buildParams() {
const params = {}
if (this.range && this.range.length === 2) {
params.beginTime = this.range[0]
params.endTime = this.range[1]
}
return params
},
loadSummary() {
const params = this.buildParams()
getPurchaseReportSummary(params).then(res => {
this.summary = { totalAmount: res.totalAmount || 0 }
this.supplierBrief = res.bySupplier || []
})
getPurchasePriceTrend(params).then(res => {
this.priceTrend = res || []
})
getSupplierQuality(params).then(res => {
this.supplierQuality = res || []
})
},
formatPercent(value) {
if (!value || !isFinite(value)) return '0%'
return `${(Number(value) * 100).toFixed(2)}%`
}
}
}
</script>
<style lang="scss" scoped>
.erp-report-page {
padding: 16px;
background: #eef1f3;
min-height: 100%;
}
.panel-card {
margin-bottom: 18px;
border: 1px solid #d0d5d8;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #1f2d3d;
}
.metric-card {
border: 1px solid #d9dee4;
padding: 16px;
background: #fff;
.label {
color: #5b6875;
margin-bottom: 6px;
}
.value {
font-size: 20px;
font-weight: 600;
color: #1f2d3d;
}
}
</style>