style:仓库数量汇总报表页优化显示(KPI概览/对比图/网格/合计/安全库存预警)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ee40da3461
commit
b301a09cac
|
|
@ -19,61 +19,104 @@
|
|||
style="margin-right: 12px;"
|
||||
/>
|
||||
<el-button type="primary" icon="el-icon-search" @click="fetchData" :loading="loading">查询</el-button>
|
||||
<span style="margin-left: auto; color: #909399; font-size: 13px;">分组维度: 物料型号(model)</span>
|
||||
</el-header>
|
||||
<el-main v-loading="loading">
|
||||
<!-- ds0: 库存量 + 安全库存上下限 -->
|
||||
<el-card shadow="never" class="rpt-card">
|
||||
<template #header>库存量 与 安全库存上下限(个人设定)</template>
|
||||
<el-table :data="ds0" border stripe size="small" :span-method="ds0Span">
|
||||
<el-table-column label="区块" prop="区块" width="90" />
|
||||
<el-table-column label="型号" prop="型号" width="120" />
|
||||
<el-table-column label="库存量" prop="库存量" align="right" />
|
||||
<el-table-column label="安全库存下限" prop="安全库存下限" align="right" />
|
||||
<el-table-column label="安全库存上限" prop="安全库存上限" align="right" />
|
||||
</el-table>
|
||||
|
||||
<el-main id="elMain" v-loading="loading">
|
||||
<!-- KPI 概览 -->
|
||||
<el-row :gutter="15" style="margin-bottom: 15px;">
|
||||
<el-col :md="6" :sm="12" v-for="k in kpiList" :key="k.label">
|
||||
<el-card shadow="hover" class="kpi-card" :style="{ borderLeft: '4px solid ' + k.color }">
|
||||
<div class="kpi-label">{{ k.label }} · 现有库存合计</div>
|
||||
<div class="kpi-value" :style="{ color: k.color }">{{ fmtNum(k.total) }}</div>
|
||||
<div class="kpi-sub">覆盖 {{ k.count }} 个型号</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 库存量对比图 -->
|
||||
<el-card shadow="never" style="margin-bottom: 15px;">
|
||||
<template #header><b>各库/工段 现有库存量对比(按型号)</b></template>
|
||||
<scEcharts height="320px" :option="chartOption" />
|
||||
</el-card>
|
||||
|
||||
<!-- ds1: 成品库周数据 -->
|
||||
<!-- 明细表格 2x2 网格 -->
|
||||
<el-row :gutter="15">
|
||||
<el-col :lg="12">
|
||||
<el-card shadow="never" class="rpt-card">
|
||||
<template #header>成品库周数据(入库=生产入库 / 出库=销售发货)</template>
|
||||
<el-table :data="ds1" border stripe size="small">
|
||||
<el-table-column label="型号" prop="型号" width="120" />
|
||||
<el-table-column label="入库数据" prop="入库数据" align="right" />
|
||||
<el-table-column label="出库数据" prop="出库数据" align="right" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" />
|
||||
<template #header><b>库存量 与 安全库存上下限</b><span class="hd-tip">(个人设定)</span></template>
|
||||
<el-table :data="ds0" border stripe size="small" :span-method="ds0Span"
|
||||
show-summary :summary-method="sumRow" :row-class-name="ds0RowClass">
|
||||
<el-table-column label="区块" prop="区块" width="70" align="center" />
|
||||
<el-table-column label="型号" prop="型号" width="90" />
|
||||
<el-table-column label="库存量" prop="库存量" align="right" :formatter="numCell" />
|
||||
<el-table-column label="下限" prop="安全库存下限" align="right" :formatter="numCell" />
|
||||
<el-table-column label="上限" prop="安全库存上限" align="right" :formatter="numCell" />
|
||||
<el-table-column label="状态" width="72" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="safeState(row).type" size="small" effect="light">{{ safeState(row).text }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- ds2: 原料库(棒料)周数据 -->
|
||||
<el-col :lg="12">
|
||||
<el-card shadow="never" class="rpt-card">
|
||||
<template #header>原料库(棒料)周数据</template>
|
||||
<el-table :data="ds2" border stripe size="small">
|
||||
<el-table-column label="型号" prop="型号" width="120" />
|
||||
<el-table-column label="入库数据" prop="入库数据" align="right" />
|
||||
<el-table-column label="外协出库" prop="外协出库" align="right" />
|
||||
<el-table-column label="光芯出库" prop="光芯出库" align="right" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" />
|
||||
<template #header><b>成品库周数据</b><span class="hd-tip">(入库=生产入库 / 出库=销售发货)</span></template>
|
||||
<el-table :data="ds1" border stripe size="small" show-summary :summary-method="sumRow">
|
||||
<el-table-column label="型号" prop="型号" width="110" />
|
||||
<el-table-column label="入库数据" prop="入库数据" align="right" :formatter="numCell" />
|
||||
<el-table-column label="出库数据" prop="出库数据" align="right" :formatter="numCell" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" :formatter="numCell" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- ds3: 白玻 / 黑玻 周数据 -->
|
||||
<el-col :lg="12">
|
||||
<el-card shadow="never" class="rpt-card">
|
||||
<template #header>白玻 / 黑玻 周数据(外协以"外协%"工段判定)</template>
|
||||
<el-table :data="ds3" border stripe size="small" :span-method="ds3Span">
|
||||
<el-table-column label="区块" prop="区块" width="90" />
|
||||
<el-table-column label="型号" prop="型号" width="120" />
|
||||
<el-table-column label="外协外发数量" prop="外协外发数量" align="right" />
|
||||
<el-table-column label="外协来料数量" prop="外协来料数量" align="right" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" />
|
||||
<template #header><b>原料库(棒料)周数据</b></template>
|
||||
<el-table :data="ds2" border stripe size="small" show-summary :summary-method="sumRow">
|
||||
<el-table-column label="型号" prop="型号" width="90" />
|
||||
<el-table-column label="入库数据" prop="入库数据" align="right" :formatter="numCell" />
|
||||
<el-table-column label="外协出库" prop="外协出库" align="right" :formatter="numCell" />
|
||||
<el-table-column label="光芯出库" prop="光芯出库" align="right" :formatter="numCell" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" :formatter="numCell" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :lg="12">
|
||||
<el-card shadow="never" class="rpt-card">
|
||||
<template #header><b>白玻 / 黑玻 周数据</b><span class="hd-tip">(外协以"外协%"工段判定)</span></template>
|
||||
<el-table :data="ds3" border stripe size="small" :span-method="ds3Span"
|
||||
show-summary :summary-method="sumRow">
|
||||
<el-table-column label="区块" prop="区块" width="70" align="center" />
|
||||
<el-table-column label="型号" prop="型号" width="90" />
|
||||
<el-table-column label="外协外发" prop="外协外发数量" align="right" :formatter="numCell" />
|
||||
<el-table-column label="外协来料" prop="外协来料数量" align="right" :formatter="numCell" />
|
||||
<el-table-column label="现有库存" prop="现有库存" align="right" :formatter="numCell" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import scEcharts from "@/components/scEcharts/index.vue";
|
||||
|
||||
const BLOCKS = [
|
||||
{ key: "原料", color: "#409EFF" },
|
||||
{ key: "成品", color: "#67C23A" },
|
||||
{ key: "白玻", color: "#E6A23C" },
|
||||
{ key: "黑玻", color: "#909399" },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "materialWhSummary",
|
||||
components: { scEcharts },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
|
@ -84,15 +127,85 @@ export default {
|
|||
ds3: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 顶部 KPI: 各区块现有库存合计与型号数
|
||||
kpiList() {
|
||||
return BLOCKS.map((b) => {
|
||||
const rows = this.ds0.filter((r) => r["区块"] === b.key);
|
||||
return {
|
||||
label: b.key,
|
||||
color: b.color,
|
||||
total: rows.reduce((s, r) => s + this.num(r["库存量"]), 0),
|
||||
count: rows.length,
|
||||
};
|
||||
});
|
||||
},
|
||||
// 库存量对比柱状图
|
||||
chartOption() {
|
||||
const models = [...new Set(this.ds0.map((r) => r["型号"]))];
|
||||
const series = BLOCKS.map((b) => ({
|
||||
name: b.key,
|
||||
type: "bar",
|
||||
itemStyle: { color: b.color },
|
||||
barMaxWidth: 28,
|
||||
data: models.map((m) =>
|
||||
this.ds0
|
||||
.filter((r) => r["区块"] === b.key && r["型号"] === m)
|
||||
.reduce((s, r) => s + this.num(r["库存量"]), 0)
|
||||
),
|
||||
}));
|
||||
return {
|
||||
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
|
||||
legend: { data: BLOCKS.map((b) => b.key), top: 0 },
|
||||
grid: { left: 10, right: 20, bottom: 10, top: 40, containLabel: true },
|
||||
xAxis: { type: "category", data: models },
|
||||
yAxis: { type: "value" },
|
||||
series,
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.dateRange = this.currentWeekRange();
|
||||
this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
// 当周周一 ~ 周末
|
||||
num(v) {
|
||||
const n = Number(v);
|
||||
return isNaN(n) ? 0 : n;
|
||||
},
|
||||
fmtNum(v) {
|
||||
return this.num(v).toLocaleString();
|
||||
},
|
||||
numCell(row, col, val) {
|
||||
return val === null || val === undefined || val === "" ? "-" : this.num(val).toLocaleString();
|
||||
},
|
||||
// 安全库存状态: 库存量对比上下限
|
||||
safeState(row) {
|
||||
const c = this.num(row["库存量"]);
|
||||
const lo = row["安全库存下限"];
|
||||
const hi = row["安全库存上限"];
|
||||
const noLo = lo === null || lo === undefined || lo === "";
|
||||
const noHi = hi === null || hi === undefined || hi === "";
|
||||
if (noLo && noHi) return { type: "info", text: "未设定" };
|
||||
if (!noLo && c < this.num(lo)) return { type: "danger", text: "偏低" };
|
||||
if (!noHi && c > this.num(hi)) return { type: "warning", text: "偏高" };
|
||||
return { type: "success", text: "正常" };
|
||||
},
|
||||
ds0RowClass({ row }) {
|
||||
return this.safeState(row).type === "danger" ? "row-warn" : "";
|
||||
},
|
||||
// 合计行: 数值列求和
|
||||
sumRow({ columns, data }) {
|
||||
return columns.map((col, i) => {
|
||||
if (i === 0) return "合计";
|
||||
if (!col.property || col.label === "状态" || col.property === "型号" || col.property === "区块") return "";
|
||||
const total = data.reduce((s, r) => s + this.num(r[col.property]), 0);
|
||||
return total ? total.toLocaleString() : "";
|
||||
});
|
||||
},
|
||||
currentWeekRange() {
|
||||
const now = new Date();
|
||||
const day = now.getDay() || 7; // 周日记为 7
|
||||
const day = now.getDay() || 7;
|
||||
const monday = new Date(now);
|
||||
monday.setDate(now.getDate() - day + 1);
|
||||
const sunday = new Date(monday);
|
||||
|
|
@ -123,14 +236,11 @@ export default {
|
|||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 合并"区块"列相同值的单元格
|
||||
mergeFirstCol(rows, key, rowIndex, columnIndex) {
|
||||
if (columnIndex !== 0) return;
|
||||
const cur = rows[rowIndex] && rows[rowIndex][key];
|
||||
const prev = rows[rowIndex - 1] && rows[rowIndex - 1][key];
|
||||
if (rowIndex > 0 && cur === prev) {
|
||||
return { rowspan: 0, colspan: 0 };
|
||||
}
|
||||
if (rowIndex > 0 && cur === prev) return { rowspan: 0, colspan: 0 };
|
||||
let span = 1;
|
||||
for (let i = rowIndex + 1; i < rows.length; i++) {
|
||||
if (rows[i][key] === cur) span++;
|
||||
|
|
@ -149,7 +259,31 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.kpi-card {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.kpi-label {
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
.kpi-value {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.kpi-sub {
|
||||
color: #c0c4cc;
|
||||
font-size: 12px;
|
||||
}
|
||||
.rpt-card {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.hd-tip {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
:deep(.row-warn) {
|
||||
background: #fef0f0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue