From dd9171eef52864b6d025ef9cc2b5770f5d40ce15 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 11 十月 2025 15:33:48 +0800
Subject: [PATCH] 生产管控-生产报表与绩效分析、库存与物料看板、智能排产三个前端页面开发

---
 src/views/productionControl/stockMaterialBoard/index.vue    |  636 ++++++++++++++++++++
 src/views/productionControl/intelligentScheduling/index.vue |  488 +++++++++++++++
 src/views/productionControl/reportAnalysis/index.vue        |  688 ++++++++++++++++++++++
 3 files changed, 1,812 insertions(+), 0 deletions(-)

diff --git a/src/views/productionControl/intelligentScheduling/index.vue b/src/views/productionControl/intelligentScheduling/index.vue
new file mode 100644
index 0000000..31d8a97
--- /dev/null
+++ b/src/views/productionControl/intelligentScheduling/index.vue
@@ -0,0 +1,488 @@
+<template>
+  <div class="intelligent-scheduling">
+    <!-- 鎼滅储琛ㄥ崟 -->
+    <el-card class="search-form-card" shadow="never">
+      <el-form :inline="true" :model="searchParams" class="search-form">
+        <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 label="鐓ょ">
+          <el-input v-model="searchParams.coalType" placeholder="璇疯緭鍏ョ叅绉�" clearable />
+        </el-form-item>
+        <el-form-item label="鎺掍骇鐘舵��">
+          <el-select v-model="searchParams.status" placeholder="璇烽�夋嫨鎺掍骇鐘舵��" clearable style="width: 200px">
+            <el-option label="鍏ㄩ儴" value="" />
+            <el-option label="寰呮帓浜�" value="pending" />
+            <el-option label="鎺掍骇涓�" value="processing" />
+            <el-option label="宸插畬鎴�" value="completed" />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch" :loading="loading">鏌ヨ</el-button>
+          <el-button @click="handleReset">閲嶇疆</el-button>
+          <el-button type="success" @click="handleRandomScheduling">闅忔満鎺掍骇</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 缁熻鍗$墖 -->
+    <div class="stats-cards">
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-s-order" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">鎬绘帓浜ч噺</div>
+          <div class="card-value">{{ totalScheduledQuantity.toFixed(2) }} 鍚�</div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-check" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">宸插畬鎴愭帓浜�</div>
+          <div class="card-value">{{ completedScheduledQuantity.toFixed(2) }} 鍚�</div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-time" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">寰呮帓浜�</div>
+          <div class="card-value">{{ pendingScheduledQuantity.toFixed(2) }} 鍚�</div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-warning" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">搴撳瓨棰勮</div>
+          <div class="card-value">{{ stockWarningCount }} 椤�</div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 搴撳瓨鍘熸枡鍒楄〃 -->
+    <el-card class="stock-materials-card" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span>搴撳瓨鍘熸枡</span>
+        </div>
+      </template>
+      <el-table v-loading="loading" :data="stockMaterials" style="width: 100%">
+        <el-table-column prop="id" label="搴忓彿" width="80" type="index" />
+        <el-table-column prop="coalType" label="鐓ょ" width="120" />
+        <el-table-column prop="origin" label="浜у湴" width="120" />
+        <el-table-column prop="calorificValue" label="鐑��" width="120" />
+        <el-table-column prop="currentStock" label="褰撳墠搴撳瓨(鍚�)" width="150" align="right">
+          <template #default="scope">
+            <span :class="{ 'stock-warning': scope.row.currentStock < scope.row.minStock }">
+              {{ scope.row.currentStock.toFixed(2) }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="minStock" label="鏈�浣庡簱瀛�(鍚�)" width="150" align="right">
+          <template #default="scope">{{ scope.row.minStock.toFixed(2) }}</template>
+        </el-table-column>
+        <el-table-column prop="unit" label="鍗曚綅" width="80" />
+        <el-table-column prop="updateTime" label="鏇存柊鏃堕棿" width="180" />
+      </el-table>
+    </el-card>
+
+    <!-- 鎺掍骇缁撴灉鍒楄〃 -->
+    <el-card class="scheduling-results-card" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span>鎺掍骇缁撴灉</span>
+        </div>
+      </template>
+      <el-table v-loading="loading" :data="schedulingResults" style="width: 100%">
+        <el-table-column prop="code" label="鎺掍骇缂栫爜" width="180" />
+        <el-table-column prop="productionLine" label="鐢熶骇绾�" width="120" />
+        <el-table-column prop="coalType" label="鐓ょ" width="120" />
+        <el-table-column prop="quantity" label="鎺掍骇鏁伴噺(鍚�)" width="150" align="right">
+          <template #default="scope">{{ scope.row.quantity.toFixed(2) }}</template>
+        </el-table-column>
+        <el-table-column prop="scheduleTime" label="鎺掍骇鏃堕棿" width="180" />
+        <el-table-column prop="status" label="鐘舵��" width="100">
+          <template #default="scope">
+            <el-tag
+              :type="scope.row.status === 'completed' ? 'success' : scope.row.status === 'processing' ? 'warning' : 'info'"
+              size="small"
+            >
+              {{ scope.row.status === 'completed' ? '宸插畬鎴�' : scope.row.status === 'processing' ? '鎺掍骇涓�' : '寰呮帓浜�' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="澶囨敞" width="200" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { ElMessage } from 'element-plus'
+
+// 鎼滅储鍙傛暟
+const searchParams = ref({
+  dateRange: [],
+  coalType: '',
+  status: ''
+})
+
+// 鏃ユ湡蹇嵎閫夐」
+const dateShortcuts = [
+  {
+    text: '浠婂ぉ',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      return [start, end]
+    }
+  },
+  {
+    text: '鏄ㄥぉ',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24)
+      return [start, end]
+    }
+  },
+  {
+    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 totalScheduledQuantity = ref(0)
+const completedScheduledQuantity = ref(0)
+const pendingScheduledQuantity = ref(0)
+const stockWarningCount = ref(0)
+
+// 搴撳瓨鍘熸枡鏁版嵁
+const stockMaterials = ref([
+  { id: 1, coalType: '鐑熺叅', origin: '灞辫タ', calorificValue: '5300澶у崱', currentStock: 1200.5, minStock: 500, unit: '鍚�', updateTime: '2023-05-07 09:30:15' },
+  { id: 2, coalType: '鏃犵儫鐓�', origin: '鍐呰挋鍙�', calorificValue: '5800澶у崱', currentStock: 800.2, minStock: 400, unit: '鍚�', updateTime: '2023-05-07 10:15:30' },
+  { id: 3, coalType: '瑜愮叅', origin: '鏂扮枂', calorificValue: '4200澶у崱', currentStock: 350.8, minStock: 400, unit: '鍚�', updateTime: '2023-05-07 11:05:45' },
+  { id: 4, coalType: '璐叅', origin: '闄曡タ', calorificValue: '5100澶у崱', currentStock: 900.0, minStock: 300, unit: '鍚�', updateTime: '2023-05-07 13:20:00' },
+  { id: 5, coalType: '鐦︾叅', origin: '璐靛窞', calorificValue: '5400澶у崱', currentStock: 650.5, minStock: 350, unit: '鍚�', updateTime: '2023-05-07 14:45:15' }
+])
+
+// 鎺掍骇缁撴灉鏁版嵁
+const schedulingResults = ref([
+  { code: 'PS20230507001', productionLine: '鐢熶骇绾�1', coalType: '鐑熺叅', quantity: 200.5, scheduleTime: '2023-05-07 09:30:15', status: 'completed', remark: '鎸夎鍒掑畬鎴�' },
+  { code: 'PS20230507002', productionLine: '鐢熶骇绾�2', coalType: '鏃犵儫鐓�', quantity: 150.2, scheduleTime: '2023-05-07 10:15:30', status: 'processing', remark: '姝e湪杩涜涓�' },
+  { code: 'PS20230507003', productionLine: '鐢熶骇绾�3', coalType: '璐叅', quantity: 180.0, scheduleTime: '2023-05-07 11:05:45', status: 'pending', remark: '绛夊緟鎺掍骇' }
+])
+
+// 鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 璁$畻缁熻鏁版嵁
+const calculateStats = () => {
+  // 璁$畻鎬绘帓浜ч噺
+  totalScheduledQuantity.value = schedulingResults.value.reduce((sum, item) => sum + item.quantity, 0)
+  
+  // 璁$畻宸插畬鎴愭帓浜�
+  completedScheduledQuantity.value = schedulingResults.value
+    .filter(item => item.status === 'completed')
+    .reduce((sum, item) => sum + item.quantity, 0)
+  
+  // 璁$畻寰呮帓浜�
+  pendingScheduledQuantity.value = schedulingResults.value
+    .filter(item => item.status === 'pending')
+    .reduce((sum, item) => sum + item.quantity, 0)
+  
+  // 璁$畻搴撳瓨棰勮鏁伴噺
+  stockWarningCount.value = stockMaterials.value.filter(item => item.currentStock < item.minStock).length
+}
+
+// 鐢熸垚鎺掍骇缂栫爜
+const generateSchedulingCode = () => {
+  const date = new Date()
+  const year = date.getFullYear()
+  const month = String(date.getMonth() + 1).padStart(2, '0')
+  const day = String(date.getDate()).padStart(2, '0')
+  const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0')
+  return `PS${year}${month}${day}${random}`
+}
+
+// 闅忔満鎺掍骇
+const handleRandomScheduling = async () => {
+  try {
+    loading.value = true
+    
+    // 妯℃嫙API璇锋眰寤惰繜
+    await new Promise(resolve => setTimeout(resolve, 1000))
+    
+    // 鑾峰彇鏈夊簱瀛樼殑鍘熸枡
+    const availableMaterials = stockMaterials.value.filter(item => item.currentStock > 0)
+    
+    if (availableMaterials.length === 0) {
+      ElMessage.warning('娌℃湁鍙敤鐨勫簱瀛樺師鏂�')
+      return
+    }
+    
+    // 闅忔満閫夋嫨鍘熸枡
+    const randomMaterial = availableMaterials[Math.floor(Math.random() * availableMaterials.length)]
+    
+    // 闅忔満鐢熸垚鎺掍骇鏁伴噺锛堜笉瓒呰繃搴撳瓨鐨�50%锛�
+    const maxQuantity = randomMaterial.currentStock * 0.5
+    const quantity = Math.max(50, Math.random() * maxQuantity) // 鑷冲皯鎺掍骇50鍚�
+    
+    // 闅忔満閫夋嫨鐢熶骇绾�
+    const productionLines = ['鐢熶骇绾�1', '鐢熶骇绾�2', '鐢熶骇绾�3']
+    const randomLine = productionLines[Math.floor(Math.random() * productionLines.length)]
+    
+    // 鐢熸垚鏂扮殑鎺掍骇璁″垝
+    const newScheduling = {
+      code: generateSchedulingCode(),
+      productionLine: randomLine,
+      coalType: randomMaterial.coalType,
+      quantity: quantity,
+      scheduleTime: new Date().toLocaleString('zh-CN'),
+      status: 'pending',
+      remark: '闅忔満鎺掍骇鐢熸垚'
+    }
+    
+    // 娣诲姞鍒版帓浜х粨鏋滃垪琛�
+    schedulingResults.value.unshift(newScheduling)
+    
+    // 鏇存柊搴撳瓨鏁伴噺
+    randomMaterial.currentStock -= quantity
+    
+    // 鏇存柊缁熻鏁版嵁
+    calculateStats()
+    
+    ElMessage.success('闅忔満鎺掍骇鎴愬姛')
+  } catch (error) {
+    console.error('闅忔満鎺掍骇澶辫触:', error)
+    ElMessage.error('闅忔満鎺掍骇澶辫触锛岃绋嶅悗閲嶈瘯')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 鏌ヨ鏁版嵁
+const handleSearch = async () => {
+  try {
+    loading.value = true
+    
+    // 妯℃嫙API璇锋眰寤惰繜
+    await new Promise(resolve => setTimeout(resolve, 800))
+    
+    // 杩欓噷鍙互鏍规嵁鎼滅储鏉′欢杩囨护鏁版嵁
+    // 瀹為檯搴旂敤涓簲璇ヨ皟鐢ˋPI鑾峰彇鏁版嵁
+    
+    ElMessage.success('鏌ヨ鎴愬姛')
+  } catch (error) {
+    console.error('鏌ヨ澶辫触:', error)
+    ElMessage.error('鏌ヨ澶辫触锛岃绋嶅悗閲嶈瘯')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 閲嶇疆鎼滅储鍙傛暟
+const handleReset = () => {
+  searchParams.value = {
+    dateRange: [],
+    coalType: '',
+    status: ''
+  }
+  
+  // 閲嶇疆鍚庨噸鏂版煡璇�
+  handleSearch()
+}
+
+// 鍒濆鍖栭〉闈�
+onMounted(() => {
+  // 榛樿鏌ヨ杩�7澶╂暟鎹�
+  const end = new Date()
+  const start = new Date()
+  start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+  searchParams.value.dateRange = [start, end]
+  
+  // 璁$畻缁熻鏁版嵁
+  calculateStats()
+  
+  // 鍒濆鍔犺浇鏁版嵁
+  handleSearch()
+})
+</script>
+
+<style scoped>
+.intelligent-scheduling {
+  padding: 20px;
+}
+
+.page-header {
+  margin-bottom: 20px;
+}
+
+.page-header h2 {
+  font-size: 18px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.search-form-card {
+  margin-bottom: 20px;
+}
+
+.search-form {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+}
+
+.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: #F6FFED;
+  color: #52C41A;
+}
+
+.stat-card:nth-child(3) .card-icon {
+  background: #FFF7E6;
+  color: #FAAD14;
+}
+
+.stat-card:nth-child(4) .card-icon {
+  background: #FFF1F0;
+  color: #F5222D;
+}
+
+.card-content {
+  flex: 1;
+}
+
+.card-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 8px;
+}
+
+.card-value {
+  font-size: 24px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.stock-materials-card,
+.scheduling-results-card {
+  margin-bottom: 24px;
+}
+
+.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;
+}
+
+.stock-warning {
+  color: #F5222D;
+  font-weight: 500;
+}
+
+/* 鍝嶅簲寮忓竷灞� */
+@media (max-width: 768px) {
+  .intelligent-scheduling {
+    padding: 10px;
+  }
+  
+  .stats-cards {
+    grid-template-columns: 1fr;
+  }
+  
+  .search-form {
+    flex-direction: column;
+    align-items: stretch;
+  }
+  
+  .search-form .el-form-item {
+    margin-right: 0;
+    margin-bottom: 10px;
+  }
+}
+</style>
\ No newline at end of file
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
diff --git a/src/views/productionControl/stockMaterialBoard/index.vue b/src/views/productionControl/stockMaterialBoard/index.vue
new file mode 100644
index 0000000..721ddb5
--- /dev/null
+++ b/src/views/productionControl/stockMaterialBoard/index.vue
@@ -0,0 +1,636 @@
+<template>
+  <div class="stock-material-board">
+    <div class="page-header">
+      <h2>搴撳瓨涓庣墿鏂欑湅鏉�</h2>
+    </div>
+
+    <!-- 鎼滅储琛ㄥ崟 -->
+    <el-card class="search-form-card" shadow="never">
+      <el-form :inline="true" :model="searchParams" class="search-form">
+        <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 label="鐓ょ">
+          <el-input v-model="searchParams.coalType" placeholder="璇疯緭鍏ョ叅绉�" clearable />
+        </el-form-item>
+        <el-form-item label="杞︽缂栫爜">
+          <el-input v-model="searchParams.trainCode" placeholder="璇疯緭鍏ヨ溅娆$紪鐮�" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch" :loading="loading">鏌ヨ</el-button>
+          <el-button @click="handleReset">閲嶇疆</el-button>
+          <el-button @click="handleRefresh">鍒锋柊</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 缁熻鍗$墖 -->
+    <div class="stats-cards">
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-download" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">浠婃棩鍏ュ簱鎬婚噺</div>
+          <div class="card-value">{{ todayInStock.toFixed(2) }} 鍚�</div>
+          <div class="card-percentage" :class="{ positive: todayInStockPercentage > 0, negative: todayInStockPercentage < 0 }">
+            <i v-if="todayInStockPercentage > 0" class="el-icon-caret-top" />
+            <i v-else-if="todayInStockPercentage < 0" class="el-icon-caret-bottom" />
+            {{ Math.abs(todayInStockPercentage).toFixed(1) }}%
+          </div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-upload" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">浠婃棩鍑哄簱鎬婚噺</div>
+          <div class="card-value">{{ todayOutStock.toFixed(2) }} 鍚�</div>
+          <div class="card-percentage" :class="{ positive: todayOutStockPercentage > 0, negative: todayOutStockPercentage < 0 }">
+            <i v-if="todayOutStockPercentage > 0" class="el-icon-caret-top" />
+            <i v-else-if="todayOutStockPercentage < 0" class="el-icon-caret-bottom" />
+            {{ Math.abs(todayOutStockPercentage).toFixed(1) }}%
+          </div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-takeaway-box" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">浠婃棩棰嗘枡鎬婚噺</div>
+          <div class="card-value">{{ todayMaterialPick.toFixed(2) }} 鍚�</div>
+          <div class="card-percentage" :class="{ positive: todayMaterialPickPercentage > 0, negative: todayMaterialPickPercentage < 0 }">
+            <i v-if="todayMaterialPickPercentage > 0" class="el-icon-caret-top" />
+            <i v-else-if="todayMaterialPickPercentage < 0" class="el-icon-caret-bottom" />
+            {{ Math.abs(todayMaterialPickPercentage).toFixed(1) }}%
+          </div>
+        </div>
+      </div>
+      
+      <div class="stat-card">
+        <div class="card-icon">
+          <i class="el-icon-shopping-cart-full" />
+        </div>
+        <div class="card-content">
+          <div class="card-title">褰撳墠搴撳瓨鎬婚噺</div>
+          <div class="card-value">{{ currentTotalStock.toFixed(2) }} 鍚�</div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 鍒嗙被鏁版嵁灞曠ず -->
+    <el-card class="category-cards" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span>鍒嗙被鏁版嵁缁熻</span>
+        </div>
+      </template>
+      
+      <!-- 鐓ょ鍒嗙被 -->
+      <div class="category-section">
+        <h3 class="category-title"><i class="el-icon-menu"></i> 鐓ょ鍒嗗竷</h3>
+        <div class="category-items">
+          <div v-for="item in coalTypeData" :key="item.name" class="category-item">
+            <span class="item-name">{{ item.name }}</span>
+            <div class="item-bar">
+              <div class="item-progress" :style="{ width: item.percentage + '%' }"></div>
+            </div>
+            <span class="item-value">{{ item.value.toFixed(2) }} 鍚� ({{ item.percentage.toFixed(1) }}%)</span>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 浜у湴鍒嗙被 -->
+      <div class="category-section">
+        <h3 class="category-title"><i class="el-icon-location"></i> 浜у湴鍒嗗竷</h3>
+        <div class="category-items">
+          <div v-for="item in originData" :key="item.name" class="category-item">
+            <span class="item-name">{{ item.name }}</span>
+            <div class="item-bar">
+              <div class="item-progress" :style="{ width: item.percentage + '%' }"></div>
+            </div>
+            <span class="item-value">{{ item.value.toFixed(2) }} 鍚� ({{ item.percentage.toFixed(1) }}%)</span>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 鐑�煎垎绫� -->
+      <div class="category-section">
+        <h3 class="category-title"><i class="el-icon-fire"></i> 鐑�煎垎甯�</h3>
+        <div class="category-items">
+          <div v-for="item in calorificData" :key="item.name" class="category-item">
+            <span class="item-name">{{ item.name }}</span>
+            <div class="item-bar">
+              <div class="item-progress" :style="{ width: item.percentage + '%' }"></div>
+            </div>
+            <span class="item-value">{{ item.value.toFixed(2) }} 鍚� ({{ item.percentage.toFixed(1) }}%)</span>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 杞︽缂栫爜鍒嗙被 -->
+      <div class="category-section">
+        <h3 class="category-title"><i class="el-icon-train"></i> 杞︽缂栫爜缁熻</h3>
+        <el-table :data="trainCodeData" style="width: 100%">
+          <el-table-column prop="trainCode" label="杞︽缂栫爜" width="160" />
+          <el-table-column prop="count" label="娆℃暟" width="100" align="right" />
+          <el-table-column prop="totalQuantity" label="鎬婚噺(鍚�)" width="120" align="right">
+            <template #default="scope">{{ scope.row.totalQuantity.toFixed(2) }}</template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-card>
+
+    <!-- 鏈�杩戜氦鏄撹褰� -->
+    <el-card class="transactions-card" shadow="never">
+      <template #header>
+        <div class="card-header">
+          <span>鏈�杩戜氦鏄撹褰�</span>
+        </div>
+      </template>
+      <el-table v-loading="loading" :data="recentTransactions" style="width: 100%">
+        <el-table-column prop="code" label="缂栫爜" width="160" />
+        <el-table-column prop="type" label="绫诲瀷" width="80">
+          <template #default="scope">
+            <span class="type-tag"
+                  :class="{
+                    'type-in': scope.row.type === '鍏ュ簱',
+                    'type-out': scope.row.type === '鍑哄簱',
+                    'type-pick': scope.row.type === '棰嗘枡'
+                  }">
+              {{ scope.row.type }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="coalType" label="鐓ょ" width="100" />
+        <el-table-column prop="origin" label="浜у湴" width="100" />
+        <el-table-column prop="calorificValue" label="鐑��" width="120" />
+        <el-table-column prop="quantity" label="鏁伴噺(鍚�)" width="120" />
+        <el-table-column prop="trainCode" label="杞︽缂栫爜" width="120" />
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿" width="180" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { ElMessage } from 'element-plus'
+
+// 鎼滅储鍙傛暟
+const searchParams = ref({
+  dateRange: [],
+  coalType: '',
+  trainCode: ''
+})
+
+// 鏃ユ湡蹇嵎閫夐」
+const dateShortcuts = [
+  {
+    text: '浠婂ぉ',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      return [start, end]
+    }
+  },
+  {
+    text: '鏄ㄥぉ',
+    value: () => {
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24)
+      return [start, end]
+    }
+  },
+  {
+    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 todayInStock = ref(1250.75)
+const todayInStockPercentage = ref(5.2)
+const todayOutStock = ref(890.30)
+const todayOutStockPercentage = ref(-2.1)
+const todayMaterialPick = ref(320.45)
+const todayMaterialPickPercentage = ref(10.3)
+const currentTotalStock = ref(15680.95)
+
+// 鍒嗙被鏁版嵁 - 鐓ょ鍒嗗竷
+const coalTypeData = ref([
+  { name: '鐑熺叅', value: 4500, percentage: 30.0 },
+  { name: '鏃犵儫鐓�', value: 3200, percentage: 21.3 },
+  { name: '瑜愮叅', value: 2800, percentage: 18.7 },
+  { name: '璐叅', value: 2500, percentage: 16.7 },
+  { name: '鐦︾叅', value: 2680, percentage: 17.9 }
+])
+
+// 鍒嗙被鏁版嵁 - 浜у湴鍒嗗竷
+const originData = ref([
+  { name: '灞辫タ', value: 5200, percentage: 33.1 },
+  { name: '鍐呰挋鍙�', value: 3800, percentage: 24.2 },
+  { name: '闄曡タ', value: 2900, percentage: 18.5 },
+  { name: '鏂扮枂', value: 2100, percentage: 13.4 },
+  { name: '璐靛窞', value: 1680, percentage: 10.7 }
+])
+
+// 鍒嗙被鏁版嵁 - 鐑�煎垎甯�
+const calorificData = ref([
+  { name: '4000-4500', value: 2800, percentage: 17.9 },
+  { name: '4500-5000', value: 4200, percentage: 26.8 },
+  { name: '5000-5500', value: 5600, percentage: 35.7 },
+  { name: '5500-6000', value: 2500, percentage: 16.0 },
+  { name: '6000+', value: 580, percentage: 3.7 }
+])
+
+// 鍒嗙被鏁版嵁 - 杞︽缂栫爜缁熻
+const trainCodeData = ref([
+  { trainCode: 'C12345', count: 12, totalQuantity: 4200.5 },
+  { trainCode: 'C12346', count: 8, totalQuantity: 2800.2 },
+  { trainCode: 'C12347', count: 10, totalQuantity: 3500.0 },
+  { trainCode: 'C12348', count: 7, totalQuantity: 2450.8 },
+  { trainCode: 'C12349', count: 5, totalQuantity: 1800.3 }
+])
+
+// 妯℃嫙鏁版嵁 - 鏈�杩戜氦鏄撹褰�
+const recentTransactions = ref([
+  { code: 'RK20230507001', type: '鍏ュ簱', coalType: '鐑熺叅', origin: '灞辫タ', calorificValue: '5300澶у崱', quantity: 350.5, trainCode: 'C12345', createTime: '2023-05-07 09:30:15' },
+  { code: 'CK20230507001', type: '鍑哄簱', coalType: '鏃犵儫鐓�', origin: '鍐呰挋鍙�', calorificValue: '5800澶у崱', quantity: 280.2, trainCode: 'C12346', createTime: '2023-05-07 10:15:30' },
+  { code: 'LL20230507001', type: '棰嗘枡', coalType: '瑜愮叅', origin: '鏂扮枂', calorificValue: '4200澶у崱', quantity: 120.8, trainCode: '', createTime: '2023-05-07 11:05:45' },
+  { code: 'RK20230507002', type: '鍏ュ簱', coalType: '璐叅', origin: '闄曡タ', calorificValue: '5100澶у崱', quantity: 400.0, trainCode: 'C12347', createTime: '2023-05-07 13:20:00' },
+  { code: 'CK20230507002', type: '鍑哄簱', coalType: '鐦︾叅', origin: '璐靛窞', calorificValue: '5400澶у崱', quantity: 310.5, trainCode: 'C12348', createTime: '2023-05-07 14:45:15' },
+  { code: 'LL20230507002', type: '棰嗘枡', coalType: '鐑熺叅', origin: '灞辫タ', calorificValue: '5300澶у崱', quantity: 200.0, trainCode: '', createTime: '2023-05-07 15:30:30' }
+])
+
+// 鍔犺浇鐘舵��
+const loading = ref(false)
+
+// 鏌ヨ鏁版嵁
+const handleSearch = async () => {
+  try {
+    loading.value = true
+    console.log('鎼滅储鍙傛暟:', searchParams.value)
+    
+    // 妯℃嫙API璇锋眰寤惰繜
+    await new Promise(resolve => setTimeout(resolve, 800))
+    
+    // 妯℃嫙鏁版嵁鏇存柊
+    todayInStock.value = 1000 + Math.random() * 500
+    todayInStockPercentage.value = -10 + Math.random() * 20
+    todayOutStock.value = 800 + Math.random() * 400
+    todayOutStockPercentage.value = -10 + Math.random() * 20
+    todayMaterialPick.value = 200 + Math.random() * 200
+    todayMaterialPickPercentage.value = -10 + Math.random() * 20
+    currentTotalStock.value = 15000 + Math.random() * 3000
+    
+    // 鏇存柊鍒嗙被鏁版嵁
+    coalTypeData.value.forEach(item => {
+      item.value = 2000 + Math.random() * 3000
+    })
+    
+    originData.value.forEach(item => {
+      item.value = 1500 + Math.random() * 4000
+    })
+    
+    calorificData.value.forEach(item => {
+      item.value = 500 + Math.random() * 5000
+    })
+    
+    trainCodeData.value.forEach(item => {
+      item.count = 3 + Math.floor(Math.random() * 15)
+      item.totalQuantity = 1000 + Math.random() * 4000
+    })
+    
+    // 閲嶆柊璁$畻鐧惧垎姣�
+    const calculatePercentages = (data) => {
+      const total = data.reduce((sum, item) => sum + item.value, 0)
+      data.forEach(item => {
+        item.percentage = total > 0 ? (item.value / total) * 100 : 0
+      })
+    }
+    
+    calculatePercentages(coalTypeData.value)
+    calculatePercentages(originData.value)
+    calculatePercentages(calorificData.value)
+    
+    ElMessage.success('鏌ヨ鎴愬姛')
+  } catch (error) {
+    console.error('鏌ヨ澶辫触:', error)
+    ElMessage.error('鏌ヨ澶辫触锛岃绋嶅悗閲嶈瘯')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 閲嶇疆鎼滅储鍙傛暟
+const handleReset = () => {
+  searchParams.value = {
+    dateRange: [],
+    coalType: '',
+    trainCode: ''
+  }
+}
+
+// 鍒锋柊鏁版嵁
+const handleRefresh = () => {
+  ElMessage.info('姝e湪鍒锋柊鏁版嵁...')
+  handleSearch()
+}
+
+// 鑷姩鐢熸垚缂栫爜鍑芥暟
+const generateCode = (type) => {
+  const prefix = type === '鍏ュ簱' ? 'RK' : type === '鍑哄簱' ? 'CK' : 'LL'
+  const date = new Date().toISOString().slice(0, 10).replace(/-/g, '')
+  const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0')
+  return `${prefix}${date}${random}`
+}
+
+// 鍒濆鍖栭〉闈�
+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>
+.stock-material-board {
+  padding: 20px;
+}
+
+.page-header {
+  margin-bottom: 20px;
+}
+
+.page-header h2 {
+  margin-bottom: 15px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #303133;
+}
+
+.search-form-card {
+  margin-bottom: 20px;
+}
+
+.search-form {
+  display: flex;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 16px;
+}
+
+.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: #F6FFED;
+  color: #52C41A;
+}
+
+.stat-card:nth-child(2) .card-icon {
+  background: #FFF7E6;
+  color: #FA8C16;
+}
+
+.stat-card:nth-child(3) .card-icon {
+  background: #FFF2F0;
+  color: #FF4D4F;
+}
+
+.stat-card:nth-child(4) .card-icon {
+  background: #E6F7FF;
+  color: #1890FF;
+}
+
+.card-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
+
+.card-title {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 8px;
+}
+
+.card-value {
+  font-size: 24px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 4px;
+}
+
+.card-percentage {
+  font-size: 12px;
+}
+
+.card-percentage.positive {
+  color: #52C41A;
+}
+
+.card-percentage.negative {
+  color: #FF4D4F;
+}
+
+.category-cards {
+  margin-bottom: 24px;
+}
+
+.category-section {
+  margin-bottom: 24px;
+  padding-bottom: 20px;
+  border-bottom: 1px solid #EBEEF5;
+}
+
+.category-section:last-child {
+  margin-bottom: 0;
+  padding-bottom: 0;
+  border-bottom: none;
+}
+
+.category-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 16px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.category-items {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.category-item {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+}
+
+.item-name {
+  width: 100px;
+  font-size: 14px;
+  color: #606266;
+}
+
+.item-bar {
+  flex: 1;
+  height: 8px;
+  background-color: #F5F7FA;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.item-progress {
+  height: 100%;
+  background-color: #409EFF;
+  border-radius: 4px;
+  transition: width 0.3s ease;
+}
+
+.item-value {
+  width: 140px;
+  text-align: right;
+  font-size: 14px;
+  color: #606266;
+}
+
+.transactions-card {
+  background: #fff;
+  border-radius: 8px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 16px 20px;
+  border-bottom: 1px solid #EBEEF5;
+}
+
+.card-header span {
+  font-weight: 600;
+  color: #303133;
+}
+
+.type-tag {
+  padding: 4px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+}
+
+.type-in {
+  background: #F6FFED;
+  color: #52C41A;
+  border: 1px solid #B7EB8F;
+}
+
+.type-out {
+  background: #FFF7E6;
+  color: #FA8C16;
+  border: 1px solid #FFD591;
+}
+
+.type-pick {
+  background: #FFF2F0;
+  color: #FF4D4F;
+  border: 1px solid #FFCCC7;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media screen and (max-width: 1200px) {
+  .stats-cards {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
+
+@media screen and (max-width: 768px) {
+  .stats-cards {
+    grid-template-columns: 1fr;
+  }
+  
+  .search-form {
+    flex-direction: column;
+    align-items: stretch;
+  }
+  
+  .search-form .el-form-item {
+    width: 100%;
+  }
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3