Files
yudao-dev/src/views/cost/index.vue
2025-12-11 12:51:41 +08:00

431 lines
11 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">
<!-- 顶部日期&筛选栏 -->
<el-row :gutter="20" class="top-bar">
<el-col :span="8">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd" />
<el-button type="primary" style="margin-left: 10px">查询</el-button>
</el-col>
<el-col :span="16">
<el-tag type="info" @click="changeTime('yesterday')">昨日</el-tag>
<el-tag type="info" @click="changeTime('week')">本周</el-tag>
<el-tag type="info" @click="changeTime('month')">本月</el-tag>
<el-tag type="info" @click="changeTime('year')">本年</el-tag>
</el-col>
</el-row>
<!-- 成本概览卡片 -->
<el-row :gutter="20" class="card-row">
<el-col :span="8">
<el-card class="cost-card">
<div class="card-title">总制造成本/平米</div>
<div class="card-content">
<div>
目标
<span class="target-val">16</span>
</div>
<div>
实际
<span class="actual-val">12.8</span>
</div>
<el-progress :stroke-width="13" :percentage="80" color="#42b983" />
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="cost-card">
<div class="card-title">原片成本/平米</div>
<div class="card-content">
<div>
目标
<span class="target-val">16</span>
</div>
<div>
实际
<span class="actual-val">12.8</span>
</div>
<el-progress :stroke-width="13" :percentage="99" color="#42b983" />
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="cost-card">
<div class="card-title">加工成本/平米</div>
<div class="card-content">
<div>
目标
<span class="target-val">16</span>
</div>
<div>
实际
<span class="actual-val">12.8</span>
</div>
<el-progress :stroke-width="13" :percentage="99" color="#42b983" />
</div>
</el-card>
</el-col>
</el-row>
<!-- 成本构成区域 -->
<el-row :gutter="20" class="composition-row">
<!-- 饼图 -->
<el-col :span="6">
<el-card class="composition-card">
<div class="card-title">成本构成</div>
<div id="costPie" class="chart" style="height: 350px"></div>
</el-card>
</el-col>
<!-- 原片/加工成本子项 -->
<el-col :span="18">
<el-card class="composition-card">
<div class="card-title">成本构成</div>
<!-- 原片成本子项 -->
<div class="sub-cost-group">
<div class="sub-cost-title">原片成本</div>
<div class="sub-cost">
<div
v-for="(item, idx) in rawSubCosts"
:key="idx"
class="sub-cost-div">
<div class="sub-cost-name">
{{ item.name }}
<div class="sub-cost-val">{{ item.val }}</div>
</div>
<div style="text-align: center">
<el-progress
type="circle"
:percentage="89"
:width="60"
:stroke-width="10"
:show-text="false"
color="#e74c3c" />
</div>
<div class="sub-cost-name">
目标
<span class="red-text">{{ item.target }}</span>
</div>
<div class="sub-cost-name">
完成率
<span class="red-text">89%</span>
</div>
</div>
</div>
</div>
<el-divider></el-divider>
<!-- 加工成本子项 -->
<div class="sub-cost-group" style="margin-top: 20px">
<div class="sub-cost-title">加工成本</div>
<div class="sub-cost">
<div
v-for="(item, idx) in processSubCosts"
:key="idx"
class="sub-cost-div">
<div class="sub-cost-name">
{{ item.name }}
<div class="sub-cost-val">{{ item.val }}</div>
</div>
<div style="text-align: center">
<el-progress
type="circle"
:percentage="89"
:width="60"
:stroke-width="10"
:show-text="false"
color="#e74c3c" />
</div>
<div class="sub-cost-name">
目标
<span class="red-text">{{ item.target }}</span>
</div>
<div class="sub-cost-name">
完成率
<span class="red-text">89%</span>
</div>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 趋势图区域 -->
<el-row :gutter="20" class="trend-row">
<!-- 总制造成本趋势 -->
<el-col :span="8">
<el-card class="trend-card">
<div class="card-title">总制造成本趋势</div>
<div id="totalTrend" class="chart" style="height: 300px"></div>
</el-card>
</el-col>
<!-- 原片/加工成本趋势 -->
<el-col :span="8">
<el-card class="trend-card">
<div class="card-title">原片/加工成本趋势</div>
<el-tabs v-model="costTab" type="card" style="margin-bottom: 10px">
<el-tab-pane label="原片成本" name="raw"></el-tab-pane>
<el-tab-pane label="加工成本" name="process"></el-tab-pane>
</el-tabs>
<div id="rawProcessTrend" class="chart" style="height: 300px"></div>
</el-card>
</el-col>
<!-- 单项成本趋势 -->
<el-col :span="8">
<el-card class="trend-card">
<div class="card-title">单项成本趋势</div>
<el-tabs v-model="itemTab" type="card" style="margin-bottom: 10px">
<el-tab-pane label="人工成本" name="labor"></el-tab-pane>
<el-tab-pane label="原料成本" name="material"></el-tab-pane>
<el-tab-pane label="制造费用" name="expense"></el-tab-pane>
<el-tab-pane label="玻璃热耗" name="heat"></el-tab-pane>
<el-tab-pane label="原片成品率" name="yield"></el-tab-pane>
</el-tabs>
<div id="itemTrend" class="chart" style="height: 300px"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'CostDashboard',
data() {
return {
dateRange: ['2023-05-06', '2023-05-06'],
costTab: 'raw',
itemTab: 'labor',
// 原片成本子项
rawSubCosts: [
{ name: '人工成本', val: 4.56, target: 4.32 },
{ name: '原料成本', val: 4.56, target: 4.32 },
{ name: '原片制造费用', val: 4.56, target: 4.32 },
{ name: '玻璃热耗', val: 4.56, target: 4.32 },
{ name: '原片成品率', val: 4.56, target: 4.32 },
],
// 加工成本子项
processSubCosts: [
{ name: '人工成本', val: 4.56, target: 4.32 },
{ name: '加工动力成本', val: 4.56, target: 4.32 },
{ name: '加工制造费用', val: 4.56, target: 4.32 },
{ name: '加工投入产出率', val: 4.56, target: 4.32 },
],
// 趋势图模拟数据
trendX: ['00:00', '01:00', '02:00'],
trendY: [20, 40, 50],
targetY: 12.54,
};
},
mounted() {
this.initCostPie();
this.initTotalTrend();
this.initRawProcessTrend();
this.initItemTrend();
},
methods: {
// 切换时间范围(示例)
changeTime(type) {
// 实际项目中需根据type请求对应数据
console.log('切换时间:', type);
},
// 初始化成本构成饼图
initCostPie() {
const pieChart = echarts.init(document.getElementById('costPie'));
pieChart.setOption({
tooltip: { trigger: 'item' },
legend: {
orient: 'horizontal', // 水平排列
bottom: 0, // 放在底部
icon: 'circle',
left: 'center',
formatter: function (name) {
return name;
},
},
series: [
{
type: 'pie',
data: [
{ name: '原料成本(4.2元)', value: 29.9 },
{ name: '动力成本(2.1元)', value: 24 },
{ name: '人工成本(1.5元)', value: 24 },
{ name: '辅料成本(0.5元)', value: 21.2 },
{ name: '制造费用(0.5元)', value: 21.2 },
],
label: { show: false },
labelLine: { show: false },
bottom: 10,
},
],
});
window.addEventListener('resize', () => pieChart.resize());
},
// 初始化总制造成本趋势图
initTotalTrend() {
const totalChart = echarts.init(document.getElementById('totalTrend'));
totalChart.setOption({
grid: { top: 20, bottom: 30, left: 30, right: 10 },
xAxis: { type: 'category', data: this.trendX },
yAxis: { type: 'value', min: -20, max: 60 },
series: [
{
name: '实际值',
type: 'line',
data: this.trendY,
lineStyle: { color: '#409eff' },
},
{
name: '目标值',
type: 'line',
data: [this.targetY, this.targetY, this.targetY],
lineStyle: { type: 'dashed', color: '#e6a23c' },
},
],
});
window.addEventListener('resize', () => totalChart.resize());
},
// 初始化原片/加工成本趋势图
initRawProcessTrend() {
const rpChart = echarts.init(document.getElementById('rawProcessTrend'));
rpChart.setOption({
grid: { top: 10, bottom: 20, left: 20, right: 10 },
xAxis: { type: 'category', data: this.trendX },
yAxis: { type: 'value', min: -20, max: 60 },
series: [
{
name: '实际值',
type: 'line',
data: this.trendY,
lineStyle: { color: '#409eff' },
},
{
name: '目标值',
type: 'line',
data: [this.targetY, this.targetY, this.targetY],
lineStyle: { type: 'dashed', color: '#e6a23c' },
},
],
});
window.addEventListener('resize', () => rpChart.resize());
},
// 初始化单项成本趋势图
initItemTrend() {
const itemChart = echarts.init(document.getElementById('itemTrend'));
itemChart.setOption({
grid: { top: 10, bottom: 20, left: 20, right: 10 },
xAxis: { type: 'category', data: this.trendX },
yAxis: { type: 'value', min: -20, max: 60 },
series: [
{
name: '实际值',
type: 'line',
data: this.trendY,
lineStyle: { color: '#409eff' },
},
{
name: '目标值',
type: 'line',
data: [this.targetY, this.targetY, this.targetY],
lineStyle: { type: 'dashed', color: '#e6a23c' },
},
],
});
window.addEventListener('resize', () => itemChart.resize());
},
},
};
</script>
<style scoped>
.top-bar {
margin-bottom: 20px;
}
.card-row,
.composition-row {
margin-bottom: 20px;
}
.cost-card .card-title {
font-size: 22px;
font-weight: bold;
margin-bottom: 15px;
}
.cost-card .card-content {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
align-items: center;
font-size: 18px;
}
.target-val {
color: #666;
margin-left: 5px;
font-size: 20px;
}
.actual-val {
color: #42b983;
margin-left: 5px;
font-size: 20px;
}
.composition-card {
height: 480px;
}
.composition-card .card-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
}
.sub-cost {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
gap: 10px;
align-items: center;
}
.sub-cost-group .sub-cost-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
.sub-cost-group .sub-cost-div {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
align-items: center;
border: 1px solid rgb(220, 220, 220, 0.5);
padding: 10px;
}
.sub-cost-name {
text-align: center;
margin-top: 5px;
font-size: 14px;
}
.sub-cost-val {
font-size: 16px;
font-weight: bold;
}
.completion {
text-align: center;
font-size: 12px;
color: #666;
}
.red-text {
color: #e74c3c;
}
.trend-card {
height: 450px;
}
.trend-card .card-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
}
</style>