Browse Source

修改显示背景图的逻辑,优化未来cd样式

yangtaodemon 1 month ago
parent
commit
2920aa6b0f

+ 3 - 84
src/components/layout/AppLayout.vue

@@ -121,91 +121,10 @@ const showGlobalMessage = ref(false);
 const globalMessage = ref("");
 const messageType = ref("success"); // 消息类型: success/error
 
-// 特殊背景路由映射
-const bgRouteMap: Record<string, string> = {
-  "/samplingMethodDevice1": "irrigation.jpg",
-  "/irriSampleData": "irrigation.jpg",
-  "/csSampleData": "irrigation.jpg",
-  "/irriInputFlux": "irrigation.jpg",
-  "/farmInputSamplingDesc": "agricultural_input.png",
-  "/prodInputFlux": "agricultural_input.png",
-  "/AtmosDepositionSamplingDesc": "atmospheric_deposition.png",
-  "/heavyMetalEnterprise": "atmospheric_deposition.png",
-  "/airSampleData": "atmospheric_deposition.png",
-  "/airInputFlux": "atmospheric_deposition.png",
-  "/samplingDesc1": "rain_removal.png",
-  "/grainRemovalInputFlux": "rain_removal.png",
-  "/samplingDesc2": "straw-removal.png",
-  "/strawRemovalInputFlux": "straw-removal.png",
-  "/samplingDesc3": "subsurface-leakage.jpg",
-  "/subsurfaceLeakageInputFlux": "subsurface-leakage.jpg",
-  "/samplingDesc4": "surface-runoff.jpg",
-  "/surfaceRunoffInputFlux": "surface-runoff.jpg",
-  "/totalInputFlux": "background.jpg",
-  "/totalInputFluxDesc": "background.jpg",
-  "/totalOutputFlux": "background.jpg",
-  "/totalOutputFluxDesc": "background.jpg",
-  "/netFlux": "background.jpg",
-  "/currentYearConcentration": "background.jpg",
-  "/TotalCadmiumPrediction": "background.jpg",
-  "/EffectiveCadmiumPrediction": "background.jpg",
-  "/CropCadmiumPrediction": "background.jpg",
-  "/cropRiskAssessment": "background.jpg",
-  "/farmlandQualityAssessment": "background.jpg",
-  "/Calculation": "background.jpg",
-  "/SoilAcidReductionIterativeEvolution": "background.jpg",
-  "/AcidNeutralizationModel": "background.jpg",
-  "/SoilAcidificationIterativeEvolution": "background.jpg",
-  "/TraditionalFarmingRisk": "background.jpg",
-  "/HeavyMetalCadmiumControl": "background.jpg",
-  "/SoilAcidificationControl": "background.jpg",
-  "/DetectionStatistics": "background.jpg",
-  "/FarmlandPollutionStatistics": "background.jpg",
-  "/LandClutivatesStatistics": "background.jpg",
-  "/soilAcidReductionData": "background.jpg",
-  "/soilAcidificationData": "background.jpg",
-  "/crossSectionSampleData": "background.jpg",
-  "/irrigationWaterInputFluxData": "background.jpg",
-  "/heavyMetalEnterpriseData": "background.jpg",
-  "/atmosphericSampleData": "background.jpg",
-  "/CadmiumPredictionModel": "background.jpg",
-  "/ModelSelection": "background.jpg",
-  "/thres": "background.jpg",
-  "/ModelTrain": "background.jpg",
-  "/RiceRiskModel": "background.jpg",
-  "/WheatRiskModel": "background.jpg",
-  "/VegetableRiskModel": "background.jpg",
-  "/UserManagement": "background.jpg",
-  "/UserRegistration": "background.jpg",
-  "/SoilacidificationStatistics": "background.jpg",
-};
-
-// 当前是否特殊背景
-const isSpecialBg = computed(() =>
-  Object.keys(bgRouteMap).includes(route.path)
-);
+currentBgImage.value = `url(${new URL('../../assets/bg/background.jpg', import.meta.url).href})`;
 
-function getBgImageUrl(): string {
-  const bgFile = bgRouteMap[route.path];
-  if (bgFile) {
-    try {
-      const url = `url(${new URL(`../../assets/bg/background.jpg`, import.meta.url).href})`;
-      return url;
-    } catch (error) {
-      console.error("加载背景图失败:", error);
-      return "";
-    }
-  }
-  return "";
-}
-
-watch(
-  () => route.path,
-  () => {
-    currentBgImage.value = getBgImageUrl();
-  },
-  { immediate: true }
-);
+// 是否特殊背景(始终返回true → 所有页面应用特殊背景样式)
+const isSpecialBg = computed(() => true);
 
 const backgroundStyle = computed(() => ({
   backgroundImage: currentBgImage.value,

+ 199 - 146
src/views/User/cadmiumPrediction/FutureCadmiumPrediction.vue

@@ -1,36 +1,40 @@
 <template>
   <div class="container">
     <!-- 顶部操作栏 -->
-    <div class="forecast-controls">
-      <div class="year-selector">
-        <el-input
-          v-model.number="forecastYear"
-          type="number"
-          placeholder="输入预测年份(1-100)"
-          :min="1"
-          :max="100"
-          @keypress.enter="generateForecast"
-          :class="{ 'is-invalid': !isValidYear }"
-        ></el-input>
-        <el-button 
-          class="custom-button"
-          :loading="isGenerating"
-          :disabled="(!isValidYear || isGenerating)"
-          @click="generateForecast"
-        >
-          <el-icon><Right /></el-icon>
-          开始预测
-        </el-button>
+    <div class="toolbar">
+      <div class="forecast-controls">
+        <div class="year-selector">
+          <!-- 新增:年份输入标题 -->
+          <span class="input-label">预测年份:</span>
+          <el-input
+            v-model.number="forecastYear"
+            type="number"
+            placeholder="输入预测年份(1-100)"
+            :min="1"
+            :max="100"
+            @keypress.enter="generateForecast"
+            :class="{ 'is-invalid': !isValidYear }"
+            class="custom-input"
+          ></el-input>
+          <el-button 
+            class="custom-button"
+            :loading="isGenerating"
+            :disabled="(!isValidYear || isGenerating)"
+            @click="generateForecast"
+          >
+            开始预测
+          </el-button>
+        </div>
       </div>
     </div>
 
     <!-- 主体内容区 -->
     <div class="content-area">
       <!-- 预测结果展示区 - 垂直排列 -->
-      <div class="result-display">
         <!-- 地图部分 -->
         <div class="visualization-section">
-          <h3>未来Cd浓度预测地图</h3>
+          <h3>土壤Cd未来浓度预测地图</h3>
+          <div class="image-container">
           <div v-if="loadingMap" class="loading-container">
             <el-icon class="loading-icon"><Loading /></el-icon>
             <span>地图加载中...</span>
@@ -41,10 +45,12 @@
             <p>暂无地图数据</p>
           </div>
         </div>
+        </div>
 
         <!-- 直方图部分 -->
         <div class="visualization-section">
           <h3>预测直方图</h3>
+          <div class="image-container">
           <div v-if="loadingHistogram" class="loading-container">
             <el-icon class="loading-icon"><Loading /></el-icon>
             <span>直方图加载中...</span>
@@ -56,7 +62,7 @@
           </div>
         </div>
       </div>
-    </div>
+      </div>
   </div>
 </template>
 
@@ -200,185 +206,232 @@ export default {
 </script>
 
 <style scoped>
-/* 全局颜色变量 */
-:root {
-  --primary-color: #47C3B9;
-  --secondary-color: #36A897;
-  --text-color: #333;
-  --bg-color: #F5F7FA;
-  --border-color: #E0E0E0;
-  --loading-color: #47C3B9;
-  --error-color: #FF4D4F;
+/* 自定义覆盖样式 */
+.container {
+  padding: 20px;
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 100vh;
+  box-sizing: border-box;
 }
 
-/* 容器样式 */
-.container {
-  max-width: 1400px;
-  margin: 20px auto;
-  padding: 0 20px;
-  background: var(--bg-color);
-  border-radius: 8px;
-  box-shadow: 0 2px 12px rgba(0,0,0,0.1);
+/* 结果展示区 - 垂直排列 */
+.content-area {
+  display: flex;
+  flex-direction: column;
+  gap: 25px;
+  margin-top: 15px;
+}
+
+/* 可视化区域通用样式 */
+.visualization-section {
+  background-color: rgba(255, 255, 255, 0.85);
+  border-radius: 10px;
+  padding: 20px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
+  position: relative;
+  backdrop-filter: blur(5px);
   overflow: hidden;
+  transition: all 0.3s ease;
+  border: 1px solid rgba(100, 180, 255, 0.2);
 }
 
-/* 顶部工具栏 */
-.forecast-controls {
+.visualization-section:hover {
+  box-shadow: 0 6px 20px rgba(0, 100, 200, 0.12);
+  transform: translateY(-3px);
+}
+
+.visualization-section h3 {
+  margin-top: 0;
+  margin-bottom: 15px;
+  color: #2c3e50;
+  font-size: 1.3rem;
+  padding-bottom: 10px;
+  border-bottom: 1px solid #eaeaea;
   display: flex;
-  justify-content: space-between;
   align-items: center;
-  padding: 15px 20px;
-  background-color: rgba(230, 247, 255, 0.7);
-  border-radius: 8px;
-  margin-bottom: 20px;
 }
 
-/* 预测控制区 */
-.year-selector {
+.visualization-section h3 i {
+  margin-right: 8px;
+  color: #47C3B9;
+}
+
+/* 图片容器样式 */
+.image-container {
+  position: relative;
+  min-height: 350px;
+  border-radius: 6px;
+  overflow: hidden;
+  background-color: #f8fafc;
+  border: 1px dashed #cbd5e0;
   display: flex;
-  gap: 10px;
   align-items: center;
+  justify-content: center;
 }
 
-/* 自定义按钮 */
-.custom-button {
-  padding: 8px 16px;
+.result-img {
+  width: 100%;
+  max-height: 500px;
+  object-fit: contain;
   border-radius: 4px;
-  font-size: 14px;
-  background-color: var(--primary-color) !important;
-  color: white !important;
-  border: none;
-  cursor: pointer;
-  transition: all 0.3s;
-  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-  display: flex;
-  align-items: center;
-  gap: 5px;
+  transition: opacity 0.3s;
 }
 
-.custom-button:hover {
-  background-color: #36a897;
+/* 加载状态样式 */
+.loading-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  color: #4a5568;
 }
 
-.custom-button:active {
-  transform: translateY(0);
+.loading-icon {
+  font-size: 2rem;
+  margin-bottom: 10px;
+  color: #47C3B9;
+  animation: spin 1.5s linear infinite;
 }
 
-.custom-button:disabled {
-  background-color: #cccccc !important;
-  color: rgba(255,255,255,0.5) !important;
-  cursor: not-allowed;
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
 }
 
-/* 结果展示区 - 垂直布局 */
-.result-display {
+/* 无数据状态样式 */
+.no-data {
   display: flex;
   flex-direction: column;
-  gap: 20px;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+  color: #a0aec0;
+  text-align: center;
+  padding: 20px;
+}
+
+.no-data p {
   margin-top: 10px;
+  font-size: 1.1rem;
 }
 
-/* 可视化部分通用样式 */
-.visualization-section {
-  background-color: white;
-  padding: 20px;
-  border-radius: 8px;
-  box-shadow: 0 2px 4px rgba(0,0,0,0.05);
-  min-height: 400px;
+/* 工具栏样式增强 */
+.toolbar {
   display: flex;
   flex-direction: column;
+  gap: 15px;
+  margin-bottom: 20px;
+  padding: 20px;
+  background-color: rgba(255, 255, 255, 0.9);
+  border-radius: 10px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+  backdrop-filter: blur(5px);
+  border: 1px solid rgba(100, 180, 255, 0.2);
 }
 
-.visualization-section h3 {
-  margin-top: 0;
-  margin-bottom: 15px;
-  font-size: 16px;
-  color: var(--text-color);
-  border-bottom: 2px solid var(--secondary-color);
-  padding-bottom: 5px;
-  flex-shrink: 0;
-}
-
-/* 加载状态 */
-.loading-container {
+.forecast-controls {
   display: flex;
+  flex-wrap: wrap;
+  gap: 15px;
   align-items: center;
-  gap: 10px;
-  color: var(--loading-color);
-  min-height: 300px;
-  justify-content: center;
-  flex-grow: 1;
 }
 
-/* 无数据提示 */
-.no-data {
+.year-selector {
   display: flex;
-  flex-direction: column;
+  flex-wrap: wrap;
+  gap: 15px;
   align-items: center;
-  gap: 10px;
-  color: #999;
-  min-height: 300px;
-  justify-content: center;
-  flex-grow: 1;
+  flex: 1;
 }
 
-/* 结果图片 */
-.result-img {
-  width: 100%;
-  height: 350px;
-  object-fit: contain;
-  border-radius: 4px;
-  margin-top: 10px;
-  flex-grow: 1;
-  background-color: #f9f9f9;
-  display: flex;
-  align-items: center;
-  justify-content: center;
+.custom-input {
+  flex: 1;
+  min-width: 200px;
+}
+
+.custom-input.is-invalid {
+  border-color: #fc8181;
+}
+
+.custom-button {
+  background: linear-gradient(135deg, #47C3B9 0%, #3ba0a0 100%) !important;
+  color: white !important;
+  border: none;
+  border-radius: 15px;
+  padding: 10px 25px;
+  font-weight: bold;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 6px rgba(71, 195, 185, 0.2);
 }
 
-.result-img:empty {
-  display: none;
+.custom-button:hover:not(:disabled) {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 8px rgba(71, 195, 185, 0.3);
+}
+
+.custom-button:disabled {
+  opacity: 0.7;
+  cursor: not-allowed;
 }
 
 /* 响应式设计 */
-@media (max-width: 992px) {
-  .forecast-controls {
-    flex-direction: column;
-    gap: 15px;
-    align-items: stretch;
+@media (min-width: 992px) {
+  .content-area {
+    flex-direction: row;
+    flex-wrap: wrap;
+  }
+  
+  .visualization-section {
+    flex: 1;
+    min-width: calc(50% - 15px);
+  }
+}
+
+@media (max-width: 768px) {
+  .toolbar {
+    padding: 15px;
   }
   
-  .year-selector {
-    flex-direction: column;
-    align-items: stretch;
+  .visualization-section {
+    padding: 15px;
   }
   
-  .custom-button {
-    width: 100%;
+  .image-container {
+    min-height: 300px;
   }
 }
 
-/* 图标样式 */
-.el-icon {
-  color: var(--primary-color);
-  font-size: 18px;
+/* 结果提示动画 */
+.fade-enter-active, .fade-leave-active {
+  transition: opacity 0.5s;
+}
+.fade-enter, .fade-leave-to {
+  opacity: 0;
 }
 
-/* 输入框样式 */
-.el-input {
-  border: 1px solid var(--border-color);
-  border-radius: 4px;
-  transition: border-color 0.3s;
+/* 新增:输入栏标题样式 */
+.input-label {
+  font-size: 14px;
+  color: #666;
+  white-space: nowrap; /* 禁止换行,保持标签与输入框对齐 */
+  margin-right: 8px; /* 与输入框的间距 */
 }
 
-.el-input:focus {
-  border-color: var(--primary-color);
-  box-shadow: 0 0 5px var(--primary-color);
+/* 新增:限定输入框长度 */
+.custom-input {
+  flex: 1;
+  min-width: 200px; /* 最小宽度,避免过窄 */
+  max-width: 320px; /* 最大宽度,限制输入栏长度 */
 }
 
-.el-input__inner {
-  padding: 8px 12px;
-  font-size: 14px;
-  color: var(--text-color);
+/* 调整按钮与输入框的间距(可选) */
+.custom-button {
+  margin-left: auto; /* 让按钮靠右(若需要) */
+  /* 原有按钮样式不变 */
 }
 </style>