From 0ad2c4106d6f570e0ca63c8fe5093e6f97492534 Mon Sep 17 00:00:00 2001
From: maven <2163098428@qq.com>
Date: 星期六, 11 十月 2025 17:44:10 +0800
Subject: [PATCH] yys 1.修改销售出库-煤种选中问题 2.采购管理增加车牌字段

---
 src/views/productionControl/reportAnalysis/index.vue |  688 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 688 insertions(+), 0 deletions(-)

diff --git a/src/views/productionControl/reportAnalysis/index.vue b/src/views/productionControl/reportAnalysis/index.vue
new file mode 100644
index 0000000..e6533c6
--- /dev/null
+++ b/src/views/productionControl/reportAnalysis/index.vue
@@ -0,0 +1,688 @@
+<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))
+		
+		// 妯℃嫙鏁版嵁鏇存柊锛堝疄闄呭簲鐢ㄤ腑搴旀牴鎹瓵PI杩斿洖缁撴灉鏇存柊锛�
+		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('姝e湪鍒锋柊鏁版嵁...')
+	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>
\ No newline at end of file

--
Gitblit v1.9.3