<template>
|
<div class="coal-blending-efficiency">
|
<div class="page-header">
|
<div class="search-form">
|
<el-form :inline="true" :model="searchParams" class="demo-form-inline">
|
<el-form-item label="时间范围">
|
<el-date-picker
|
v-model="searchParams.dateRange"
|
type="daterange"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
:shortcuts="dateShortcuts"
|
/>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleSearch" :loading="loading">查询</el-button>
|
<el-button @click="handleReset">重置</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
</div>
|
|
<!-- 统计卡片区域 -->
|
<div class="stats-cards">
|
<div class="stat-card">
|
<div class="card-icon">
|
<i class="el-icon-s-operation"></i>
|
</div>
|
<div class="card-content">
|
<div class="card-title">单位热值耗煤量</div>
|
<div class="card-value">{{ unitHeatCoalConsumption.toFixed(2) }} kg/GJ</div>
|
<div class="card-desc">越低越好</div>
|
</div>
|
</div>
|
|
<div class="stat-card">
|
<div class="card-icon">
|
<i class="el-icon-check-circle"></i>
|
</div>
|
<div class="card-content">
|
<div class="card-title">整体达标率</div>
|
<div class="card-value">{{ overallComplianceRate.toFixed(2) }}%</div>
|
<div class="card-desc">发热量≥5000大卡</div>
|
</div>
|
</div>
|
|
<div class="stat-card">
|
<div class="card-icon">
|
<i class="el-icon-data-line"></i>
|
</div>
|
<div class="card-content">
|
<div class="card-title">平均发热量</div>
|
<div class="card-value">{{ averageCalorificValue.toFixed(0) }} 大卡</div>
|
<div class="card-desc">越高越好</div>
|
</div>
|
</div>
|
|
<div class="stat-card">
|
<div class="card-icon">
|
<i class="el-icon-files"></i>
|
</div>
|
<div class="card-content">
|
<div class="card-title">配方使用频次</div>
|
<div class="card-value">{{ totalBatches }} 次</div>
|
<div class="card-desc">时间范围内</div>
|
</div>
|
</div>
|
|
<div class="stat-card">
|
<div class="card-icon">
|
<i class="el-icon-s-data"></i>
|
</div>
|
<div class="card-content">
|
<div class="card-title">总批次</div>
|
<div class="card-value">{{ totalBatches }}</div>
|
<div class="card-desc">时间范围内</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 图表区域 -->
|
<div class="charts-container">
|
<!-- 达标率趋势图 -->
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>达标率趋势</span>
|
</div>
|
</template>
|
<div class="chart-wrapper">
|
<Echarts
|
ref="complianceChartRef"
|
:options="complianceTrendOptions"
|
:chartStyle="{ height: '300px', width: '100%' }"
|
/>
|
</div>
|
</el-card>
|
|
<!-- 煤种发热量对比 -->
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>煤种发热量对比</span>
|
</div>
|
</template>
|
<div class="chart-wrapper">
|
<Echarts
|
ref="calorificChartRef"
|
:options="calorificValueOptions"
|
:chartStyle="{ height: '300px', width: '100%' }"
|
/>
|
</div>
|
</el-card>
|
|
<!-- 配方使用频次 -->
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>配方使用频次</span>
|
</div>
|
</template>
|
<div class="chart-wrapper">
|
<Echarts
|
ref="recipeChartRef"
|
:options="recipeFrequencyOptions"
|
:chartStyle="{ height: '300px', width: '100%' }"
|
/>
|
</div>
|
</el-card>
|
|
<!-- 加工得率分析 -->
|
<el-card class="chart-card">
|
<template #header>
|
<div class="card-header">
|
<span>加工得率分析</span>
|
</div>
|
</template>
|
<div class="chart-wrapper">
|
<Echarts
|
ref="yieldChartRef"
|
:options="processingYieldOptions"
|
:chartStyle="{ height: '300px', width: '100%' }"
|
/>
|
</div>
|
</el-card>
|
|
<!-- 成本结构图谱 -->
|
<el-card class="chart-card cost-structure">
|
<template #header>
|
<div class="card-header">
|
<span>成本结构图谱</span>
|
</div>
|
</template>
|
<div class="chart-wrapper">
|
<Echarts
|
ref="costChartRef"
|
:options="costStructureOptions"
|
:chartStyle="{ height: '300px', width: '100%' }"
|
/>
|
</div>
|
</el-card>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, computed } from 'vue'
|
import * as echarts from 'echarts'
|
import Echarts from '@/components/Echarts/echarts.vue'
|
import { ElMessage } from 'element-plus'
|
|
|
// 搜索参数
|
const searchParams = ref({
|
dateRange: []
|
})
|
|
// 日期快捷选项
|
const dateShortcuts = [
|
{
|
text: '近7天',
|
value: () => {
|
const end = new Date()
|
const start = new Date()
|
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
return [start, end]
|
}
|
},
|
{
|
text: '近30天',
|
value: () => {
|
const end = new Date()
|
const start = new Date()
|
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
return [start, end]
|
}
|
},
|
{
|
text: '本月',
|
value: () => {
|
const end = new Date()
|
const start = new Date(end.getFullYear(), end.getMonth(), 1)
|
return [start, end]
|
}
|
}
|
]
|
|
// 统计数据
|
const unitHeatCoalConsumption = ref(32.5)
|
const overallComplianceRate = ref(85.7)
|
const averageCalorificValue = ref(5260)
|
const totalBatches = ref(48)
|
|
// 模拟数据
|
const mockComplianceData = [
|
{ date: '2023-06-01', rate: 82 },
|
{ date: '2023-06-02', rate: 85 },
|
{ date: '2023-06-03', rate: 88 },
|
{ date: '2023-06-04', rate: 84 },
|
{ date: '2023-06-05', rate: 87 },
|
{ date: '2023-06-06', rate: 90 },
|
{ date: '2023-06-07', rate: 86 },
|
{ date: '2023-06-08', rate: 89 },
|
{ date: '2023-06-09', rate: 92 },
|
{ date: '2023-06-10', rate: 88 }
|
]
|
|
const mockCalorificData = [
|
{ name: '烟煤', value: 5800 },
|
{ name: '无烟煤', value: 6200 },
|
{ name: '褐煤', value: 4500 },
|
{ name: '贫煤', value: 5300 },
|
{ name: '瘦煤', value: 5500 }
|
]
|
|
const mockRecipeData = [
|
{ name: '配方A (烟煤60%+无烟煤40%)', value: 18 },
|
{ name: '配方B (烟煤70%+褐煤30%)', value: 12 },
|
{ name: '配方C (无烟煤50%+贫煤50%)', value: 8 },
|
{ name: '配方D (烟煤50%+瘦煤50%)', value: 6 },
|
{ name: '其他配方', value: 4 }
|
]
|
|
const mockYieldData = [
|
{ name: '烟煤', yield: 85, efficiency: 92 },
|
{ name: '无烟煤', yield: 88, efficiency: 89 },
|
{ name: '褐煤', yield: 75, efficiency: 78 },
|
{ name: '贫煤', yield: 82, efficiency: 85 },
|
{ name: '瘦煤', yield: 80, efficiency: 87 }
|
]
|
|
const mockCostData = [
|
{ name: '耗材', value: 45 },
|
{ name: '能耗', value: 30 },
|
{ name: '人力', value: 25 }
|
]
|
|
// 达标率趋势图配置
|
const complianceTrendOptions = computed(() => ({
|
tooltip: {
|
trigger: 'axis',
|
formatter: '{b}<br/>达标率: {c}%'
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: mockComplianceData.map(item => item.date),
|
axisLabel: {
|
rotate: 45
|
}
|
},
|
yAxis: {
|
type: 'value',
|
name: '达标率 (%)',
|
min: 70,
|
max: 100
|
},
|
series: [
|
{
|
name: '达标率',
|
type: 'line',
|
smooth: true,
|
data: mockComplianceData.map(item => item.rate),
|
itemStyle: {
|
color: '#409EFF'
|
},
|
lineStyle: {
|
width: 3
|
},
|
areaStyle: {
|
color: {
|
type: 'linear',
|
x: 0,
|
y: 0,
|
x2: 0,
|
y2: 1,
|
colorStops: [{
|
offset: 0,
|
color: 'rgba(64, 158, 255, 0.3)'
|
}, {
|
offset: 1,
|
color: 'rgba(64, 158, 255, 0.05)'
|
}]
|
}
|
}
|
}
|
]
|
}))
|
|
// 煤种发热量对比图配置
|
const calorificValueOptions = computed(() => ({
|
tooltip: {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
},
|
formatter: '{b}<br/>发热量: {c} 大卡'
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: mockCalorificData.map(item => item.name)
|
},
|
yAxis: {
|
type: 'value',
|
name: '发热量 (大卡)'
|
},
|
series: [
|
{
|
name: '发热量',
|
type: 'bar',
|
data: mockCalorificData.map(item => item.value),
|
itemStyle: {
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
{ offset: 0, color: '#FF6B81' },
|
{ offset: 1, color: '#FF8E53' }
|
])
|
},
|
label: {
|
show: true,
|
position: 'top',
|
formatter: '{c}大卡'
|
}
|
}
|
]
|
}))
|
|
// 配方使用频次图配置
|
const recipeFrequencyOptions = computed(() => ({
|
tooltip: {
|
trigger: 'item',
|
formatter: '{b}: {c}次 ({d}%)'
|
},
|
legend: {
|
orient: 'vertical',
|
left: 'left',
|
textStyle: {
|
fontSize: 12
|
}
|
},
|
series: [
|
{
|
name: '配方使用频次',
|
type: 'pie',
|
radius: '60%',
|
center: ['60%', '50%'],
|
data: mockRecipeData,
|
emphasis: {
|
itemStyle: {
|
shadowBlur: 10,
|
shadowOffsetX: 0,
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
}
|
},
|
itemStyle: {
|
borderRadius: 8,
|
borderColor: '#fff',
|
borderWidth: 2
|
},
|
label: {
|
show: true,
|
formatter: '{b}\n{c}次'
|
}
|
}
|
]
|
}))
|
|
// 加工得率分析图配置
|
const processingYieldOptions = computed(() => ({
|
tooltip: {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
}
|
},
|
legend: {
|
data: ['出洗率', '加工能效']
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: mockYieldData.map(item => item.name)
|
},
|
yAxis: {
|
type: 'value',
|
name: '百分比 (%)',
|
min: 60,
|
max: 100
|
},
|
series: [
|
{
|
name: '出洗率',
|
type: 'bar',
|
data: mockYieldData.map(item => item.yield),
|
itemStyle: {
|
color: '#52C41A'
|
}
|
},
|
{
|
name: '加工能效',
|
type: 'bar',
|
data: mockYieldData.map(item => item.efficiency),
|
itemStyle: {
|
color: '#1890FF'
|
}
|
}
|
]
|
}))
|
|
// 成本结构图谱配置
|
const costStructureOptions = computed(() => ({
|
tooltip: {
|
trigger: 'item',
|
formatter: '{b}: {c}%'
|
},
|
legend: {
|
orient: 'vertical',
|
left: 'left'
|
},
|
series: [
|
{
|
name: '成本结构',
|
type: 'pie',
|
radius: '60%',
|
center: ['60%', '50%'],
|
data: mockCostData,
|
emphasis: {
|
itemStyle: {
|
shadowBlur: 10,
|
shadowOffsetX: 0,
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
}
|
},
|
roseType: 'radius',
|
itemStyle: {
|
borderRadius: 8,
|
borderColor: '#fff',
|
borderWidth: 2
|
}
|
}
|
]
|
}))
|
|
// 查询数据
|
const loading = ref(false)
|
|
const handleSearch = async () => {
|
try {
|
loading.value = true
|
// 在实际应用中,这里会调用API获取真实数据
|
console.log('搜索参数:', searchParams.value)
|
|
// 获取配煤数据
|
// const blendingRes = await getCoalBlendingList({
|
// startTime: searchParams.value.dateRange[0] ? parseTime(searchParams.value.dateRange[0]) : '',
|
// endTime: searchParams.value.dateRange[1] ? parseTime(searchParams.value.dateRange[1]) : ''
|
// })
|
|
// 模拟API请求延迟
|
await new Promise(resolve => setTimeout(resolve, 800))
|
|
// 模拟数据更新(实际应用中应根据API返回结果更新)
|
unitHeatCoalConsumption.value = 31.8 + Math.random() * 5
|
overallComplianceRate.value = 80 + Math.random() * 15
|
averageCalorificValue.value = 5000 + Math.random() * 500
|
totalBatches.value = 40 + Math.floor(Math.random() * 20)
|
|
// 随机更新部分图表数据
|
mockComplianceData.forEach(item => {
|
item.rate = 80 + Math.random() * 15
|
})
|
|
ElMessage.success('查询成功')
|
} catch (error) {
|
console.error('查询失败:', error)
|
ElMessage.error('查询失败,请稍后重试')
|
} finally {
|
loading.value = false
|
}
|
}
|
|
// 刷新数据
|
const handleRefresh = () => {
|
ElMessage.info('正在刷新数据...')
|
handleSearch()
|
}
|
|
// 导出数据
|
const handleExport = async () => {
|
try {
|
loading.value = true
|
// 模拟导出操作
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
ElMessage.success('数据导出成功')
|
} catch (error) {
|
console.error('导出失败:', error)
|
ElMessage.error('导出失败,请稍后重试')
|
} finally {
|
loading.value = false
|
}
|
}
|
|
// 重置搜索参数
|
const handleReset = () => {
|
searchParams.value = {
|
dateRange: []
|
}
|
}
|
|
// 初始化页面
|
onMounted(() => {
|
// 默认查询近7天数据
|
const end = new Date()
|
const start = new Date()
|
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
searchParams.value.dateRange = [start, end]
|
|
// 初始加载数据
|
handleSearch()
|
})
|
</script>
|
|
<style scoped>
|
.coal-blending-efficiency {
|
padding: 20px;
|
}
|
|
.page-header {
|
margin-bottom: 20px;
|
}
|
|
.page-header h2 {
|
margin-bottom: 15px;
|
font-size: 18px;
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.stats-cards {
|
display: grid;
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
gap: 16px;
|
margin-bottom: 24px;
|
}
|
|
.stat-card {
|
display: flex;
|
padding: 20px;
|
background: #fff;
|
border-radius: 8px;
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
transition: transform 0.3s, box-shadow 0.3s;
|
}
|
|
.stat-card:hover {
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
}
|
|
.card-icon {
|
width: 48px;
|
height: 48px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border-radius: 50%;
|
font-size: 24px;
|
margin-right: 16px;
|
}
|
|
.stat-card:nth-child(1) .card-icon {
|
background: #ECF5FF;
|
color: #409EFF;
|
}
|
|
.stat-card:nth-child(2) .card-icon {
|
background: #F0F9FF;
|
color: #69B1FF;
|
}
|
|
.stat-card:nth-child(3) .card-icon {
|
background: #F6FFED;
|
color: #52C41A;
|
}
|
|
.stat-card:nth-child(4) .card-icon {
|
background: #FFF7E6;
|
color: #FAAD14;
|
}
|
|
.card-content {
|
flex: 1;
|
}
|
|
.card-title {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 8px;
|
}
|
|
.card-value {
|
font-size: 24px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 4px;
|
}
|
|
.card-desc {
|
font-size: 12px;
|
color: #909399;
|
}
|
|
.charts-container {
|
display: grid;
|
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
|
gap: 24px;
|
}
|
|
.chart-card {
|
background: #fff;
|
border-radius: 8px;
|
overflow: hidden;
|
}
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 16px;
|
border-bottom: 1px solid #EBEEF5;
|
}
|
|
.card-header span {
|
font-weight: 600;
|
color: #303133;
|
}
|
|
.chart-wrapper {
|
padding: 20px;
|
}
|
|
.cost-structure {
|
grid-column: 1 / -1;
|
}
|
|
@media (max-width: 1200px) {
|
.charts-container {
|
grid-template-columns: 1fr;
|
}
|
}
|
</style>
|