123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- <template>
- <div class="container">
- <div class="gradient-card">
- <div class="card-header">
- <h1>籽粒移除输出通量计算结果</h1>
- <p>{{ area }}地区作物籽粒移除Cd通量分析报告</p>
- </div>
- <div v-if="loading" class="loading-section">
- <i class="fas fa-spinner fa-spin"></i> 正在加载数据...
- </div>
- <div v-if="error" class="error-section">
- <i class="fas fa-exclamation-triangle"></i> {{ error }}
- </div>
- <template v-if="!loading && !error">
- <div class="statistics-section">
- <h2><i class="fas fa-chart-bar"></i> 统计分析</h2>
- <div class="stats-grid">
- <div class="stat-card">
- <div class="stat-value">{{ statistics.total_samples.toLocaleString() }}</div>
- <div class="stat-label">总样本数</div>
- </div>
- <div class="stat-card">
- <div class="stat-value">{{ statistics.mean_flux.toFixed(2) }} g/ha/a</div>
- <div class="stat-label">平均通量</div>
- </div>
- <div class="stat-card">
- <div class="stat-value">{{ statistics.max_flux.toFixed(2) }} g/ha/a</div>
- <div class="stat-label">最大通量</div>
- </div>
- <div class="stat-card">
- <div class="stat-value">{{ statistics.min_flux.toFixed(2) }} g/ha/a</div>
- <div class="stat-label">最小通量</div>
- </div>
- </div>
- </div>
- <div class="visualization-section">
- <h2><i class="fas fa-map"></i> 可视化分析图</h2>
- <img v-if="visualizationImage" :src="visualizationImage" alt="Cd含量地图" class="result-image">
- <div v-if="visualizationError" class="error-section">
- <i class="fas fa-exclamation-triangle"></i> {{ visualizationError }}
- </div>
- <div v-else class="image-container">
-
- </div>
- </div>
- <div class="data-section">
- <h2><i class="fas fa-table"></i> 详细数据</h2>
- <el-table
- :data="tableData"
- height="400"
- style="width: 100%"
- class="custom-table"
- :header-cell-style="{ background: 'rgba(0, 150, 136, 0.1)', color: '#006064', fontWeight: '600' }"
- >
- <el-table-column prop="farmland_id" label="农田ID" width="120" align="center"></el-table-column>
- <el-table-column prop="sample_id" label="样本ID" width="120" align="center"></el-table-column>
- <el-table-column prop="crop_cd_value" label="作物镉Cd(mg/kg)" align="center">
- <template #default="scope">
- {{ scope.row.crop_cd_value.toFixed(5) }}
- </template>
- </el-table-column>
- <el-table-column prop="f11_yield" label="作物亩产量(斤)" width="150" align="center"></el-table-column>
- <el-table-column prop="grain_removal_flux" label="籽粒移除通量(g/ha/a)" width="170" align="center">
- <template #default="scope">
- {{ scope.row.grain_removal_flux.toFixed(5) }}
- </template>
- </el-table-column>
- </el-table>
-
- <el-pagination
- background
- layout="prev, pager, next, sizes, total"
- :total="results.length"
- :page-size="pageSize"
- :current-page="currentPage"
- :page-sizes="[5, 10, 20, 50]"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- class="custom-pagination"
- >
- </el-pagination>
- </div>
- <div class="formula-section">
- <h2><i class="fas fa-calculator"></i> 计算公式</h2>
- <div class="formula-card">
- {{ formula }}
- </div>
- <div class="unit-note">
- <i class="fas fa-info-circle"></i> 单位: {{ unit }}
- </div>
- </div>
- <div class="card-footer">
- <p><i class="fas fa-clock"></i> 报告生成时间: {{ reportTime }}</p>
- </div>
- </template>
- </div>
- </div>
- </template>
- <script>
- import { ref, computed, onMounted } from 'vue';
- import { ElTable, ElTableColumn, ElPagination } from 'element-plus';
- export default {
- name: 'GrainRemovalResult',
- components: {
- ElTable,
- ElTableColumn,
- ElPagination
- },
- props: {
- area: {
- type: String,
- default: '韶关'
- }
- },
- setup(props) {
- // 响应式数据
- const results = ref([]);
- const statistics = ref({
- total_samples: 0,
- mean_flux: 0,
- max_flux: 0,
- min_flux: 0
- });
- const formula = ref("");
- const unit = ref("");
- const visualizationImage = ref("");
- const reportTime = ref("");
- const loading = ref(true);
- const error = ref(null);
-
- // 分页相关变量
- const currentPage = ref(1);
- const pageSize = ref(5);
-
- // 计算分页后的数据
- const tableData = computed(() => {
- const start = (currentPage.value - 1) * pageSize.value;
- const end = start + pageSize.value;
- return results.value.slice(start, end);
- });
-
- // 分页事件处理
- const handleSizeChange = (newSize) => {
- pageSize.value = newSize;
- currentPage.value = 1; // 重置到第一页
- };
-
- const handleCurrentChange = (newPage) => {
- currentPage.value = newPage;
- };
-
- // 从API获取数据
- const fetchData = async () => {
- try {
- // 获取计算结果数据
- const dataResponse = await fetch(
- `http://127.0.0.1:8000/api/cd-flux-removal/grain-removal?area=${encodeURIComponent(props.area)}`
- );
-
- if (!dataResponse.ok) {
- throw new Error(`数据获取失败: ${dataResponse.statusText}`);
- }
-
- const dataJson = await dataResponse.json();
-
- if (!dataJson.success) {
- throw new Error(`API错误: ${dataJson.message}`);
- }
-
- // 设置数据
- results.value = dataJson.data.results;
- statistics.value = dataJson.data.statistics;
- formula.value = dataJson.data.formula;
- unit.value = dataJson.data.unit;
-
- // 获取可视化图片
- const imageResponse = await fetch(
- `http://127.0.0.1:8000/api/cd-flux-removal/grain-removal/visualize?area=${encodeURIComponent(props.area)}&level=city`
- );
-
- if (!imageResponse.ok) {
- throw new Error(`图片获取失败: ${imageResponse.statusText}`);
- }
-
- // 创建图片Blob URL
- const blob = await imageResponse.blob();
- visualizationImage.value = URL.createObjectURL(blob);
-
- // 设置报告时间
- reportTime.value = new Date().toLocaleString('zh-CN', {
- year: 'numeric',
- month: 'long',
- day: 'numeric',
- hour: '2-digit',
- minute: '2-digit'
- });
-
- } catch (err) {
- console.error('数据获取错误:', err);
- error.value = err.message || '获取数据时发生错误';
- } finally {
- loading.value = false;
- }
- };
-
- // 组件挂载时获取数据
- onMounted(() => {
- fetchData();
- });
-
- return {
- results,
- statistics,
- formula,
- unit,
- visualizationImage,
- reportTime,
- loading,
- error,
- tableData,
- currentPage,
- pageSize,
- handleSizeChange,
- handleCurrentChange
- };
- }
- };
- </script>
- <style scoped>
- /* 保留您原有的样式,只添加Element UI的自定义样式 */
- .container {
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 100vh;
- padding: 20px;
- background: linear-gradient(135deg, #e6f7ff, #b3e0ff);
- }
- .gradient-card {
- background: linear-gradient(135deg,
- rgba(250, 253, 255, 0.9),
- rgba(220, 240, 255, 0.9));
- border-radius: 20px;
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
- padding: 30px;
- width: 100%;
- max-width: 1000px;
- backdrop-filter: blur(8px);
- border: none;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
- .card-header {
- text-align: center;
- margin-bottom: 30px;
- border-bottom: 2px solid rgba(0, 96, 100, 0.1);
- padding-bottom: 20px;
- }
- .card-header h1 {
- font-size: 2.2rem;
- color: #006064;
- margin-bottom: 10px;
- font-weight: 700;
- }
- .card-header p {
- font-size: 1.2rem;
- color: #00838f;
- opacity: 0.9;
- }
- .loading-section, .error-section {
- text-align: center;
- padding: 40px;
- font-size: 1.4rem;
- color: #006064;
- }
- .loading-section i {
- margin-right: 15px;
- font-size: 1.8rem;
- color: #00838f;
- }
- .error-section i {
- margin-right: 15px;
- font-size: 1.8rem;
- color: #d32f2f;
- }
- .stats-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: 20px;
- margin-top: 20px;
- }
- .stat-card {
- background: rgba(178, 235, 242, 0.3);
- border-radius: 15px;
- padding: 20px;
- text-align: center;
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
- transition: transform 0.3s ease;
- }
- .stat-card:hover {
- transform: translateY(-5px);
- background: rgba(178, 235, 242, 0.5);
- }
- .stat-value {
- font-size: 1.8rem;
- font-weight: 700;
- color: #006064;
- margin-bottom: 8px;
- }
- .stat-label {
- font-size: 1.1rem;
- color: #00838f;
- }
- .visualization-section,
- .data-section,
- .formula-section,
- .statistics-section {
- margin-bottom: 30px;
- padding: 20px;
- background: rgba(255, 255, 255, 0.6);
- border-radius: 15px;
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
- }
- .visualization-section h2,
- .data-section h2,
- .formula-section h2,
- .statistics-section h2 {
- font-size: 1.6rem;
- color: #006064;
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .result-image {
- max-width: 100%;
- max-height: 500px;
- border-radius: 10px;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
- }
- .formula-card {
- font-family: 'Courier New', monospace;
- font-size: 1.2rem;
- background: rgba(255, 255, 255, 0.8);
- padding: 20px;
- border-radius: 10px;
- text-align: center;
- margin: 20px 0;
- border: 1px dashed #00838f;
- color: #006064;
- }
- .unit-note {
- text-align: center;
- font-size: 1.1rem;
- color: #00838f;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- }
- .card-footer {
- text-align: center;
- font-size: 1rem;
- color: #00838f;
- padding-top: 20px;
- border-top: 1px solid rgba(0, 150, 136, 0.2);
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 10px;
- }
- /* 响应式设计 */
- @media (max-width: 768px) {
- .stats-grid {
- grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
- }
-
- .card-header h1 {
- font-size: 1.8rem;
- }
-
- .visualization-section h2,
- .data-section h2,
- .formula-section h2,
- .statistics-section h2 {
- font-size: 1.4rem;
- }
- }
- @media (max-width: 480px) {
- .gradient-card {
- padding: 15px;
- }
-
- .stats-grid {
- grid-template-columns: 1fr;
- }
-
- .stat-card {
- padding: 15px;
- }
-
- .stat-value {
- font-size: 1.5rem;
- }
- }
- .result-image {
- width: 100%;
- max-height: 400px;
- object-fit: contain;
- border-radius: 8px;
- border: 1px solid #e4e7ed;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
- background-color: #f8f8f8;
- }
- /* Element UI 自定义样式 */
- .custom-table {
- border-radius: 10px;
- overflow: hidden;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
- margin-top: 20px;
- }
- .custom-table .el-table__row {
- transition: background-color 0.3s;
- }
- .custom-table .el-table__row:hover {
- background-color: rgba(178, 235, 242, 0.3) !important;
- }
- .custom-table .el-table__row:nth-child(even) {
- background-color: rgba(178, 235, 242, 0.15);
- }
- .custom-pagination {
- margin-top: 20px;
- display: flex;
- justify-content: center;
- }
- </style>
|