index.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <template>
  2. <div class="carbon-footprint-module">
  3. <el-header class="header">
  4. <h2>碳足迹评估认证模块</h2>
  5. </el-header>
  6. <el-main>
  7. <el-tabs v-model="activeTab">
  8. <el-tab-pane label="产品模型库" name="productLibrary">
  9. <h3>产品模型库</h3>
  10. <el-form style="display: flex;">
  11. <el-form-item label="产品">
  12. <el-input v-model="searchQuery" placeholder="搜索产品" style="margin-bottom: 20px;" />
  13. </el-form-item>
  14. <el-form-item label="行业">
  15. <el-select v-model="selectedIndustry" placeholder="请选择行业" style="width: 300px;margin-bottom: 20px;">
  16. <el-option
  17. v-for="industry in industries"
  18. :key="industry.value"
  19. :label="industry.label"
  20. :value="industry.value"
  21. />
  22. </el-select>
  23. </el-form-item>
  24. </el-form>
  25. <el-table :data="filteredProducts" style="width: 100%" @row-click="showProductDetails">
  26. <el-table-column prop="name" label="产品名称" />
  27. <el-table-column prop="description" label="描述" />
  28. <el-table-column prop="carbonFootprint" label="碳足迹" />
  29. </el-table>
  30. <el-dialog v-model="productDialogVisible" title="产品详细信息">
  31. <p><strong>产品名称:</strong> {{ selectedProduct.name }}</p>
  32. <p><strong>描述:</strong> {{ selectedProduct.description }}</p>
  33. <p><strong>碳足迹:</strong> {{ selectedProduct.carbonFootprint }} kg CO2e</p>
  34. </el-dialog>
  35. </el-tab-pane>
  36. <el-tab-pane label="工序积木图" name="processDiagram">
  37. <h3>工序积木图</h3>
  38. <el-select v-model="selectedIndustry" placeholder="请选择行业" style="margin-bottom: 20px;">
  39. <el-option
  40. v-for="industry in industries"
  41. :key="industry.value"
  42. :label="industry.label"
  43. :value="industry.value"
  44. />
  45. </el-select>
  46. <div ref="processChart" style="width: 100%; height: 400px;"></div>
  47. </el-tab-pane>
  48. </el-tabs>
  49. </el-main>
  50. </div>
  51. </template>
  52. <script setup>
  53. import { ref, onMounted, watch, computed } from 'vue'
  54. import * as echarts from 'echarts'
  55. import { ElHeader, ElMain, ElSelect, ElOption, ElTable, ElTableColumn, ElTabs, ElTabPane, ElInput, ElDialog } from 'element-plus'
  56. const activeTab = ref('productLibrary')
  57. const selectedIndustry = ref('')
  58. const searchQuery = ref('')
  59. const productDialogVisible = ref(false)
  60. const selectedProduct = ref({})
  61. const industries = [
  62. { label: '钢铁', value: 'steel' },
  63. { label: '水泥', value: 'cement' },
  64. { label: '动力电池', value: 'battery' }
  65. ]
  66. const industryData = {
  67. steel: [
  68. { name: '高炉炼铁', description: '高炉炼铁过程', carbonFootprint: 1.5 },
  69. { name: '电炉炼钢', description: '电炉炼钢过程', carbonFootprint: 0.8 },
  70. { name: '轧钢', description: '轧钢过程', carbonFootprint: 0.5 },
  71. { name: '热处理', description: '钢材热处理过程', carbonFootprint: 0.6 },
  72. { name: '冷轧', description: '冷轧过程', carbonFootprint: 0.4 },
  73. { name: '涂层', description: '钢材表面涂层过程', carbonFootprint: 0.3 },
  74. { name: '检验', description: '钢材质量检验过程', carbonFootprint: 0.2 },
  75. { name: '包装', description: '钢材包装过程', carbonFootprint: 0.1 }
  76. ],
  77. cement: [
  78. { name: '石灰石开采', description: '石灰石开采过程', carbonFootprint: 0.3 },
  79. { name: '熟料烧成', description: '熟料烧成过程', carbonFootprint: 1.2 },
  80. { name: '水泥粉磨', description: '水泥粉磨过程', carbonFootprint: 0.4 },
  81. { name: '包装', description: '水泥包装过程', carbonFootprint: 0.2 },
  82. { name: '运输', description: '水泥运输过程', carbonFootprint: 0.1 },
  83. { name: '存储', description: '水泥存储过程', carbonFootprint: 0.1 },
  84. { name: '检验', description: '水泥质量检验过程', carbonFootprint: 0.2 },
  85. { name: '销售', description: '水泥销售过程', carbonFootprint: 0.1 }
  86. ],
  87. battery: [
  88. { name: '锂矿开采', description: '锂矿开采过程', carbonFootprint: 0.5 },
  89. { name: '正极材料生产', description: '正极材料生产过程', carbonFootprint: 1.0 },
  90. { name: '负极材料生产', description: '负极材料生产过程', carbonFootprint: 0.8 },
  91. { name: '电解液制备', description: '电解液制备过程', carbonFootprint: 0.6 },
  92. { name: '电池组装', description: '电池组装过程', carbonFootprint: 0.7 },
  93. { name: '性能测试', description: '电池性能测试过程', carbonFootprint: 0.3 },
  94. { name: '包装', description: '电池包装过程', carbonFootprint: 0.2 },
  95. { name: '运输', description: '电池运输过程', carbonFootprint: 0.1 }
  96. ]
  97. }
  98. const filteredProducts = computed(() => {
  99. const query = searchQuery.value.toLowerCase()
  100. return selectedIndustry.value
  101. ? industryData[selectedIndustry.value].filter(product =>
  102. product.name.toLowerCase().includes(query) ||
  103. product.description.toLowerCase().includes(query) ||
  104. product.carbonFootprint.toString().includes(query)
  105. )
  106. : []
  107. })
  108. const processChart = ref(null)
  109. const initProcessChart = () => {
  110. const chart = echarts.init(processChart.value)
  111. const option = {
  112. title: {
  113. text: '工序积木图',
  114. left: 'center'
  115. },
  116. tooltip: {
  117. trigger: 'item',
  118. formatter: function (params) {
  119. if (params.seriesType === 'sankey') {
  120. if (params.dataType === 'node') {
  121. const product = filteredProducts.value.find(p => p.name === params.name)
  122. return `<strong>${product.name}</strong><br>碳足迹: ${product.carbonFootprint} kg CO2e<br>描述: ${product.description}`
  123. } else if (params.dataType === 'edge') {
  124. const sourceProduct = filteredProducts.value.find(p => p.name === params.data.source)
  125. const targetProduct = filteredProducts.value.find(p => p.name === params.data.target)
  126. return `${sourceProduct.name} -> ${targetProduct.name}<br>碳足迹: ${params.data.value} kg CO2e`
  127. }
  128. }
  129. return ''
  130. }
  131. },
  132. legend: {
  133. data: ['低', '中', '高'],
  134. top: 'bottom'
  135. },
  136. series: [
  137. {
  138. type: 'sankey',
  139. layout: 'none',
  140. data: filteredProducts.value.map(product => ({
  141. name: product.name,
  142. itemStyle: {
  143. color: getColorForCarbonFootprint(product.carbonFootprint)
  144. }
  145. })),
  146. links: filteredProducts.value.map((product, index) => ({
  147. source: index === 0 ? '原料' : product.name,
  148. target: index === filteredProducts.value.length - 1 ? '成品' : filteredProducts.value[index + 1].name,
  149. value: product.carbonFootprint,
  150. lineStyle: {
  151. color: 'source'
  152. }
  153. })),
  154. lineStyle: {
  155. curveness: 0.5
  156. },
  157. emphasis: {
  158. focus: 'adjacency'
  159. }
  160. }
  161. ]
  162. }
  163. chart.setOption(option)
  164. // 直接设置高亮
  165. if (selectedIndustry.value) {
  166. chart.dispatchAction({
  167. type: 'highlight',
  168. seriesIndex: 0,
  169. dataIndex: 0
  170. })
  171. }
  172. // 添加点击事件
  173. chart.on('click', (params) => {
  174. if (params.dataType === 'node') {
  175. const product = filteredProducts.value.find(p => p.name === params.name)
  176. if (product) {
  177. selectedProduct.value = product
  178. productDialogVisible.value = true
  179. }
  180. }
  181. })
  182. }
  183. const getColorForCarbonFootprint = (carbonFootprint) => {
  184. if (carbonFootprint < 0.5) return '#67C23A' // 绿色
  185. if (carbonFootprint < 1.0) return '#E6A23C' // 橙色
  186. return '#F56C6C' // 红色
  187. }
  188. watch(selectedIndustry, (newVal) => {
  189. if (newVal && activeTab.value === 'processDiagram') {
  190. initProcessChart()
  191. }
  192. })
  193. onMounted(() => {
  194. if (selectedIndustry.value && activeTab.value === 'processDiagram') {
  195. initProcessChart()
  196. }
  197. })
  198. const showProductDetails = (row) => {
  199. selectedProduct.value = row
  200. productDialogVisible.value = true
  201. }
  202. </script>
  203. <style scoped>
  204. .carbon-footprint-module {
  205. display: flex;
  206. flex-direction: column;
  207. height: 90vh;
  208. }
  209. .header {
  210. background-color: #409eff;
  211. color: white;
  212. text-align: center;
  213. padding: 10px 0;
  214. }
  215. .main {
  216. flex: 1;
  217. padding: 20px;
  218. }
  219. </style>