123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- <template>
- <div class="container">
- <!-- 顶部操作栏 -->
- <div class="toolbar">
- <el-button class="custom-button" :loading="isCalculating" @click="calculate">计算</el-button>
- <el-button class="custom-button" :disabled="isCalculating || !mapBlob" @click="exportMap">导出地图</el-button>
- <el-button class="custom-button" :disabled="isCalculating || !histogramBlob" @click="exportHistogram">导出直方图</el-button>
- <el-button class="custom-button" :disabled="isCalculating || !tableData.length" @click="exportData">导出数据</el-button>
- </div>
- <!-- 主体内容区,计算后显示 -->
- <div v-if="result" class="content-area">
- <!-- 地图区域 - 现在包含两个图片展示区 -->
- <div class="map-area">
- <div class="map-container">
- <!-- 地图展示 -->
- <div class="map-section">
- <h3>有效态Cd预测地图</h3>
- <img v-if="mapImageUrl" :src="mapImageUrl" alt="有效态Cd预测地图" class="map-image">
- <div v-if="loadingMap" class="loading-container">
- <el-icon class="loading-icon"><Loading /></el-icon>
- <span>地图加载中...</span>
- </div>
- </div>
-
- <!-- 直方图展示 -->
- <div class="histogram-section">
- <h3>有效态Cd预测直方图</h3>
- <img v-if="histogramImageUrl" :src="histogramImageUrl" alt="有效态Cd预测直方图" class="histogram-image">
- <div v-if="loadingMap" class="loading-container">
- <el-icon class="loading-icon"><Loading /></el-icon>
- <span>直方图加载中...</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 表格区域 -->
- <div class="table-area">
- <h3>表格数据</h3>
- <el-table :data="tableData" style="width: 100%;">
- <el-table-column prop="name" label="名称" width="180" />
- <el-table-column prop="value" label="值" width="100" />
- <el-table-column prop="unit" label="单位" width="100" />
- <el-table-column prop="description" label="描述" />
- </el-table>
- </div>
- </div>
- </div>
- </template>
- <script>
- import * as XLSX from 'xlsx';
- import { saveAs } from 'file-saver';
- import axios from 'axios';
- import { Loading } from '@element-plus/icons-vue';
- export default {
- name: 'EffectiveCadmiumPrediction',
- components: { Loading },
- data() {
- return {
- isCalculating: false,
- loadingMap: false,
- loadingHistogram: false,
- result: false,
- tableData: [],
- mapImageUrl: null, // 存储地图图片 URL
- histogramImageUrl: null, // 存储直方图图片 URL
- mapBlob: null, // 存储地图原始Blob数据
- histogramBlob: null // 存储直方图原始Blob数据
- };
- },
- methods: {
- async calculate() {
- try {
- // 重置状态
- this.isCalculating = true;
- this.loadingMap = true;
- this.loadingHistogram = true;
- this.result = false;
- this.mapImageUrl = null;
- this.histogramImageUrl = null;
- this.mapBlob = null;
- this.histogramBlob = null;
- this.tableData = [];
-
- // 调用有效态Cd地图接口
- const mapResponse = await axios.post('https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-map', {}, {
- responseType: 'blob'
- });
-
- // 调用有效态Cd直方图接口
- const histogramResponse = await axios.post('https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-histogram', {}, {
- responseType: 'blob'
- });
-
- // 保存原始Blob数据用于导出
- this.mapBlob = mapResponse.data;
- this.histogramBlob = histogramResponse.data;
-
- // 为图片数据创建 URL
- this.mapImageUrl = URL.createObjectURL(this.mapBlob);
- this.histogramImageUrl = URL.createObjectURL(this.histogramBlob);
-
- // 更新表格数据
- this.result = true;
- this.tableData = [
- { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
- { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
- ];
-
- } catch (error) {
- console.error('获取地图或直方图失败:', error);
- this.$message.error('获取预测结果失败,请重试');
- } finally {
- // 无论成功失败都重置加载状态
- this.isCalculating = false;
- this.loadingMap = false;
- this.loadingHistogram = false;
- }
- },
-
- // 导出地图方法
- exportMap() {
- if (!this.mapBlob) {
- this.$message.warning('请先计算生成地图');
- return;
- }
-
- // 创建下载链接并添加到文档中
- const link = document.createElement('a');
- link.href = URL.createObjectURL(this.mapBlob);
- link.download = '有效态Cd预测地图.jpg';
- link.style.display = 'none';
- document.body.appendChild(link);
-
- // 触发点击事件
- link.click();
-
- // 清理临时URL和链接元素
- setTimeout(() => {
- document.body.removeChild(link);
- URL.revokeObjectURL(link.href);
- }, 100);
- },
-
- // 导出直方图方法 - 修复:确保链接元素被添加到文档中
- exportHistogram() {
- if (!this.histogramBlob) {
- this.$message.warning('请先计算生成直方图');
- return;
- }
-
- // 创建下载链接并添加到文档中
- const link = document.createElement('a');
- link.href = URL.createObjectURL(this.histogramBlob);
- link.download = '有效态Cd预测直方图.jpg';
- link.style.display = 'none';
- document.body.appendChild(link);
-
- // 触发点击事件
- link.click();
-
- // 清理临时URL和链接元素
- setTimeout(() => {
- document.body.removeChild(link);
- URL.revokeObjectURL(link.href);
- }, 100);
- },
-
- // 导出数据方法
- exportData() {
- // 创建工作簿
- const workbook = XLSX.utils.book_new();
-
- // 创建数据表
- const worksheet = XLSX.utils.json_to_sheet(this.tableData);
-
- // 将工作表添加到工作簿
- XLSX.utils.book_append_sheet(workbook, worksheet, '有效态Cd数据');
-
- // 生成Excel文件
- const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
- const excelData = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
-
- // 保存文件
- saveAs(excelData, 'effective-cd-data.xlsx');
- }
- },
- beforeDestroy() {
- // 组件销毁时释放图片 URL 防止内存泄漏
- if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
- if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
- }
- };
- </script>
- <style scoped>
- /* 样式保持不变 */
- .container {
- padding: 20px;
- background-color: #f5f7fa;
- min-height: 100vh;
- box-sizing: border-box;
- }
- .toolbar {
- display: flex;
- align-items: center;
- gap: 10px;
- margin-bottom: 20px;
- }
- .custom-button {
- background-color: #47C3B9 !important;
- color: #DCFFFA !important;
- border: none;
- border-radius: 155px;
- padding: 10px 20px;
- font-weight: bold;
- }
- .content-area {
- display: flex;
- gap: 20px;
- }
- .map-area {
- flex: 1;
- min-width: 300px;
- }
- .map-container {
- display: flex;
- flex-direction: column;
- gap: 20px;
- }
- .map-section, .histogram-section {
- background-color: white;
- border-radius: 8px;
- padding: 15px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- position: relative;
- }
- .map-image, .histogram-image {
- width: 100%;
- max-height: 600px;
- object-fit: contain;
- border-radius: 4px;
- }
- .map-placeholder {
- background-color: #cce5ff;
- height: 200px;
- border-radius: 8px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: bold;
- font-size: 16px;
- color: #003366;
- }
- .table-area {
- flex: 1;
- background-color: white;
- border-radius: 8px;
- padding: 15px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
- }
- .loading-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- height: 200px;
- color: #47C3B9;
- }
- .loading-icon {
- font-size: 36px;
- margin-bottom: 10px;
- animation: rotate 2s linear infinite;
- }
- @keyframes rotate {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
- }
- </style>
|