Kaynağa Gözat

Merge remote-tracking branch 'origin/lili'

yangtaodemon 1 ay önce
ebeveyn
işleme
fe8d6561a7

+ 1 - 0
src/App.vue

@@ -1,6 +1,7 @@
 <script setup lang='ts'>
 import { RouterView } from "vue-router"
 import request from './utils/request';
+import Acidmodelmap from "./views/User/acidModel/acidmodelmap.vue";
 
 </script>
 

+ 1 - 1
src/components/layout/AppLayout.vue

@@ -264,7 +264,7 @@ const tabs = computed(() => {
         name: "soilAcidificationPrediction",
         label: "土壤酸化预测",
         icon: "el-icon-magic-stick",
-        routes: ["/Calculation", "/AcidNeutralizationModel"],
+        routes: ["/Calculation", "/AcidNeutralizationModel","/acidmodelmap"],
       },
       // {
       //   name: "scenarioSimulation",

+ 336 - 366
src/components/layout/menuItems.ts

@@ -26,370 +26,340 @@ export interface MenuItem {
   children?: MenuItem[];
 }
 
-export const menuItems: MenuItem[] = [
-  {
-    index: '/shuJuKanBan',
-    label: 'shuJuKanBan.Title',//<!--i18n:shuJuKanBan.Title-->数据看板
-    icon: Monitor,
-    tab: 'shuJuKanBan'
-  },
-  {
-    index: '/SoilPro',
-    label: 'SoilPro.Title',//<!--i18n:SoilPro.Title-->软件简介
-    icon: InfoFilled,
-    tab: 'introduction'
-  },
-  {
-    index: '/Overview',
-    label: 'Overview.Title',//<!--i18n:Overview.Title-->项目简介
-    icon: Collection,
-    tab: 'introduction'
-  },
-  {
-    index: '/ResearchFindings',
-    label: 'ResearchFindings.Title',//<!--i18n:ResearchFindings.Title-->研究成果
-    icon: Histogram,
-    tab: 'introduction'
-  },
-  {
-    index: '/Unit',
-    label: 'Unit.Title',//<!--i18n:Unit.Title-->团队信息
-    icon: HelpFilled,
-    tab: 'introduction'
-  },
-   {
-    index: '/CropCadmiumPrediction',
-    label: 'CropCadmiumPrediction.Title',//<!--i18n:CropCadmiumPrediction.Title-->土壤镉作物态含量预测
-    icon: PieChart,
-    tab: 'cadmiumPrediction'
-  },
-  {
-    index: '/EffectiveCadmiumPrediction',
-    label: 'EffectiveCadmiumPrediction.Title',//<!--i18n:EffectiveCadmiumPrediction.Title-->土壤镉有效态含量预测
-    icon: PieChart,
-    tab: 'cadmiumPrediction'
-  },
-  {
-    index: '/FutureCadmiumPrediction',
-    label: 'FutureCadmiumPrediction.Title',//<!--i18n:EffectiveCadmiumPrediction.Title-->土壤镉有效态含量预测
-    icon: PieChart,
-    tab: 'cadmiumPrediction'
-  },
-  {
-    index: '/netFlux',
-    label: 'netFlux.Title',//<!--i18n:netFlux.Title-->净通量
-    icon: PieChart,
-    tab: 'cadmiumPrediction'
-  },
-  {
-    index: '/currentYearConcentration',
-    label: 'currentYearConcentration.Title',//<!--i18n:currentYearConcentration.Title-->当年浓度
-    icon: PieChart,
-    tab: 'cadmiumPrediction'
-  },
-  {
-    index: 'irrigationWater',
-    label: 'irrigationwater.Title',//灌溉水
-    icon: Watermelon,
-    tab: 'HmOutFlux',
-    children: [
-      {
-        index: '/samplingMethodDevice1',
-        label: 'irrigationwater.irrigationwaterMethodsTitle',
-        icon: Sunny,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/irriSampleData',
-        label: 'irrigationwater.pointTitle',
-        icon: Coin,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/csSampleData',
-        label: 'irrigationwater.crosssectionTitle',
-        icon: Cloudy,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/irriInputFlux',
-        label: 'irrigationwater.InputfluxTitle',
-        icon: Cloudy,
-        tab: 'HmOutFlux'
-      }
-    ]
-  },
-  {
-    index: 'inputFlux',
-    label: 'agriInput.Title',//农产品投入
-    icon: Watermelon,
-    tab: 'HmOutFlux',
-    children: [
-      {
-        index: '/farmInputSamplingDesc',
-        label: 'agriInput.farmInputSamplingDescTitle',//采样说明
-        icon: Sunny,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/prodInputFlux',
-        label: 'agriInput.prodInputFluxTitle',//农产品输入通量
-        icon: Coin,
-        tab: 'HmOutFlux'
-      },
-    ]
-  },
-  {
-    index: 'atmosDeposition',
-    label: 'atmosDeposition.Title',//大气干湿沉降
-    icon: Watermelon,
-    tab: 'HmOutFlux',
-    children: [
-      {
-        index: '/AtmosDepositionSamplingDesc',
-        label: 'atmosDeposition.AtmosDepositionSamplingDescTitle',//采样说明
-        icon: Sunny,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/heavyMetalEnterprise',
-        label: 'atmosDeposition.heavyMetalEnterpriseTitle',//涉重企业
-        icon: Coin,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/airSampleData',
-        label: 'atmosDeposition.airSampleDataTitle',//大气采样数据
-        icon: Sunny,
-        tab: 'HmOutFlux'
-      },
-      {
-        index: '/airInputFlux',
-        label: 'atmosDeposition.airInputFluxTitle',//大气输入通量
-        icon: Coin,
-        tab: 'HmOutFlux'
-      },
-    ]
-  },
-  {
-    index: 'totalInputFlux',
-    label: '输入总通量',
-    icon: WindPower,
-    tab: 'HmOutFlux',
-    children: [
-      {
-        index: '/totalInputFluxDesc',
-        label: '输入总通量说明',
-        icon: Watermelon,
-        tab: 'HmOutFlux',
-      },
-      {
-        index: '/totalInputFlux',
-        label: '输入总通量结果',
-        icon: List,
-        tab: 'HmOutFlux',
-      },
-    ]
-  },
-  {
-    index: 'grainRemoval',
-    label: 'grainRemoval.Title',//<!--i18n:grainRemoval.Title-->籽粒移除
-    icon: WindPower,
-    tab: 'hmInFlux',
-    children: [
-      {
-        index: '/samplingDesc1',
-        label: 'grainRemoval.samplingDesc1',//<!--i18n:grainRemoval.samplingDesc1-->采样说明
-        icon: Watermelon,
-        tab: 'hmInFlux'
-      },
-      {
-        index: '/grainRemovalInputFlux',
-        label: 'grainRemoval.grainRemovalInputFlux',//<!--i18n:grainRemoval.grainRemovalInputFlux-->籽粒移除输出通量
-        icon: List,
-        tab: 'hmInFlux'
-      }
-    ]
-  },
-  {
-    index: 'strawRemoval',
-    label: 'strawRemoval.Title',//<!--i18n:strawRemoval.Title-->秸秆移除
-    icon: WindPower,
-    tab: 'hmInFlux',
-    children: [
-      {
-        index: '/samplingDesc2',
-        label: 'strawRemoval.samplingDesc2',//<!--i18n:strawRemoval.samplingDesc2-->采样说明
-        icon: Watermelon,
-        tab: 'hmInFlux'
-      },
-      {
-        index: '/strawRemovalInputFlux',
-        label: 'strawRemoval.strawRemovalInputFlux',//<!--i18n:strawRemoval.strawRemovalInputFlux-->秸秆移除输出通量
-        icon: List,
-        tab: 'hmInFlux'
-      }
-    ]
-  },
-  {
-    index: 'subsurfaceLeakage',
-    label: 'subsurfaceLeakage.Title',//<!--i18n:subsurfaceLeakage.Title-->地下渗漏
-    icon: WindPower,
-    tab: 'hmInFlux',
-    children: [
-      {
-        index: '/samplingDesc3',
-        label: 'subsurfaceLeakage.samplingDesc3',//<!--i18n:subsurfaceLeakage.samplingDesc3-->采样说明
-        icon: Watermelon,
-        tab: 'hmInFlux'
-      },
-      {
-        index: '/subsurfaceLeakageInputFlux',
-        label: 'subsurfaceLeakage.subsurfaceLeakageInputFlux',//<!--i18n:subsurfaceLeakage.subsurfaceLeakageInputFlux-->地下渗漏输入通量
-        icon: List,
-        tab: 'hmInFlux'
-      }
-    ]
-  },
-  {
-    index: 'surfaceRunoff',
-    label: 'surfaceRunoff.Title',//<!--i18n:surfaceRunoff.Title-->地表径流
-    icon: WindPower,
-    tab: 'hmInFlux',
-    children: [
-      {
-        index: '/samplingDesc4',
-        label: 'surfaceRunoff.samplingDesc4',//<!--i18n:surfaceRunoff.samplingDesc4-->采样说明
-        icon: Watermelon,
-        tab: 'hmInFlux'
-      },
-      {
-        index: '/surfaceRunoffInputFlux',
-        label: 'surfaceRunoff.surfaceRunoffInputFlux',//<!--i18n:surfaceRunoff.surfaceRunoffInputFlux-->地表径流输入通量
-        icon: List,
-        tab: 'hmInFlux'
-      }
-    ]
-  },
-  {
-    index: 'totalOutputFlux',
-    label: '输出总通量',
-    icon: WindPower,
-    tab: 'hmInFlux',
-    children: [
-      {
-        index: '/totalOutputFluxDesc',
-        label: '输出总通量说明',
-        icon: Watermelon,
-        tab: 'hmInFlux',
-      },
-      {
-        index: '/totalOutputFlux',
-        label: '输出总通量结果',
-        icon: List,
-        tab: 'hmInFlux',
-      },
-    ]
-  },
-  {
-    index: '/mapView',
-    label: 'mapView.Title',//<!--i18n:mapView.Title-->地图展示
-    icon: Location,
-    tab: 'mapView'
-  },
-  // {
-  //   index: '/cropRiskAssessment',
-  //   label: 'cropRiskAssessment.Title',//<!--i18n:cropRiskAssessment.Title-->水稻镉污染风险
-  //   icon: Compass,
-  //   tab: 'cropRiskAssessment'
-  // },
-  {
-    index: '/farmlandQualityAssessment',
-    label: 'farmlandQualityAssessment.Title',//<!--i18n:farmlandQualityAssessment.Title-->韶关
-    icon: DataLine,
-    tab: 'farmlandQualityAssessment'
-  },
-  {
-    index: '/acidModel',
-    label: 'acidModel.Title',//<!--i18n:acidModel.Title-->土壤反酸
-    icon: MagicStick,
-    tab: 'soilAcidificationPrediction',
-    children: [
-      {
-        index: '/Calculation',
-        label: 'acidModel.CalculationTitle',//<!--i18n:acidModel.CalculationTitle-->土壤反酸预测
-        icon: Sunny,
-        tab: 'heavyMetalFluxCalculation'
-      },
-      {
-        index: '/SoilAcidReductionIterativeEvolution',
-        label: 'acidModel.SoilAcidReductionIterativeEvolutionTitle',//<!--i18n:acidModel.SoilAcidReductionIterativeEvolutionTitle-->反酸模型迭代可视化
-        icon: Coin,
-        tab: 'heavyMetalFluxCalculation'
-      }
-    ]
-  },
-  {
-    index: '/neutralizationModel',
-    label: 'neutralizationModel.Title',//<!--i18n:neutralizationModel.Title-->土壤降酸
-    icon: MagicStick,
-    tab: 'soilAcidificationPrediction',
-    children: [
-      {
-        index: '/AcidNeutralizationModel',
-        label: 'neutralizationModel.AcidNeutralizationModelTitle',//<!--i18n:neutralizationModel.AcidNeutralizationModelTitle-->土壤降酸预测
-        icon: Sunny,
-        tab: 'heavyMetalFluxCalculation'
-      },
-      {
-        index: '/SoilAcidificationIterativeEvolution',
-        label: 'neutralizationModel.SoilAcidificationIterativeEvolutionTitle',//<!--i18n:neutralizationModel.SoilAcidificationIterativeEvolutionTitle-->土壤降酸可视化
-        icon: Coin,
-        tab: 'heavyMetalFluxCalculation'
-      }
-    ]
-  },
-  // {
-  //   index: '/TraditionalFarmingRisk',
-  //   label: 'TraditionalFarmingRisk.Title',//<!--i18n:TraditionalFarmingRisk.Title-->传统耕种习惯风险趋势
-  //   icon: MenuIcon,
-  //   tab: 'scenarioSimulation'
-  // },
-  // {
-  //   index: '/HeavyMetalCadmiumControl',
-  //   label: 'HeavyMetalCadmiumControl.Title',//<!--i18n:HeavyMetalCadmiumControl.Title-->重金属镉污染治理
-  //   icon: MenuIcon,
-  //   tab: 'scenarioSimulation'
-  // },
-  // {
-  //   index: '/SoilAcidificationControl',
-  //   label: 'SoilAcidificationControl.Title',//<!--i18n:SoilAcidificationControl.Title-->土壤酸化治理
-  //   icon: MenuIcon,
-  //   tab: 'scenarioSimulation'
-  // },
-  {
-    index: '/DetectionStatistics',
-    label: 'DetectionStatistics.Title',//<!--i18n:DetectionStatistics.Title-->检测信息统计
-    icon: List,
-    tab: 'dataStatistics'
-  },
-  {
-    index: '/FarmlandPollutionStatistics',
-    label: 'FarmlandPollutionStatistics.Title',//<!--i18n:FarmlandPollutionStatistics.Title-->土壤镉含量统计
-    icon: List,
-    tab: 'dataStatistics'
-  },
-  {
-    index: '/LandClutivatesStatistics',
-    label: 'LandClutivatesStatistics.Title',//<!--i18n:LandClutivatesStatistics.Title-->作物风险评估统计
-    icon: List,
-    tab: 'dataStatistics'
-  },
-  {
-    index: '/SoilacidificationStatistics',
-    label: 'SoilacidificationStatistics.Title',//<!--i18n:SoilacidificationStatistics.Title-->酸化预测数据统计
-    icon: List,
-    tab: 'dataStatistics'
-  }
-].filter(({ tab: menuTab }) => !["shuJuKanBan", "mapView", "introduction"].includes(menuTab));
+// 按 tab 分组的菜单映射
+export const tabMenuMap: Record<string, MenuItem[]> = {
+  shuJuKanBan: [
+    {
+      index: "/shuJuKanBan",
+      label: "shuJuKanBan.Title",
+      icon: Monitor,
+    },
+  ],
 
+  introduction: [
+    {
+      index: "/SoilPro",
+      label: "SoilPro.Title",
+      icon: InfoFilled,
+    },
+    {
+      index: "/Overview",
+      label: "Overview.Title",
+      icon: Collection,
+    },
+    {
+      index: "/ResearchFindings",
+      label: "ResearchFindings.Title",
+      icon: Histogram,
+    },
+    {
+      index: "/Unit",
+      label: "Unit.Title",
+      icon: HelpFilled,
+    },
+  ],
+
+  mapView: [
+    {
+      index: "/mapView",
+      label: "mapView.Title",
+      icon: Location,
+    },
+  ],
+
+  HmOutFlux: [
+    {
+      index: "irrigationWater",
+      label: "irrigationwater.Title",
+      icon: Watermelon,
+      children: [
+        {
+          index: "/samplingMethodDevice1",
+          label: "irrigationwater.irrigationwaterMethodsTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/irriSampleData",
+          label: "irrigationwater.pointTitle",
+          icon: Coin,
+        },
+        {
+          index: "/csSampleData",
+          label: "irrigationwater.crosssectionTitle",
+          icon: Cloudy,
+        },
+        {
+          index: "/irriInputFlux",
+          label: "irrigationwater.InputfluxTitle",
+          icon: Cloudy,
+        },
+      ],
+    },
+    {
+      index: "inputFlux",
+      label: "agriInput.Title",
+      icon: Watermelon,
+      children: [
+        {
+          index: "/farmInputSamplingDesc",
+          label: "agriInput.farmInputSamplingDescTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/prodInputFlux",
+          label: "agriInput.prodInputFluxTitle",
+          icon: Coin,
+        },
+      ],
+    },
+    {
+      index: "atmosDeposition",
+      label: "atmosDeposition.Title",
+      icon: Watermelon,
+      children: [
+        {
+          index: "/AtmosDepositionSamplingDesc",
+          label: "atmosDeposition.AtmosDepositionSamplingDescTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/heavyMetalEnterprise",
+          label: "atmosDeposition.heavyMetalEnterpriseTitle",
+          icon: Coin,
+        },
+        {
+          index: "/airSampleData",
+          label: "atmosDeposition.airSampleDataTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/airInputFlux",
+          label: "atmosDeposition.airInputFluxTitle",
+          icon: Coin,
+        },
+      ],
+    },
+    {
+      index: "/totalInputFlux",
+      label: "totalInputFlux.Title",
+      icon: Watermelon,
+      children: [
+        {
+          index: "/totalInputFluxDesc",
+          label: "输入总通量说明",
+          icon: Watermelon,
+        },
+        {
+          index: "/totalInputFlux",
+          label: "输入总通量结果",
+          icon: List,
+        },
+      ],
+    },
+  ],
+
+  hmInFlux: [
+    {
+      index: "grainRemoval",
+      label: "grainRemoval.Title",
+      icon: WindPower,
+      children: [
+        {
+          index: "/samplingDesc1",
+          label: "grainRemoval.samplingDesc1",
+          icon: Watermelon,
+        },
+        {
+          index: "/grainRemovalInputFlux",
+          label: "grainRemoval.grainRemovalInputFlux",
+          icon: List,
+        },
+      ],
+    },
+    {
+      index: "strawRemoval",
+      label: "strawRemoval.Title",
+      icon: WindPower,
+      children: [
+        {
+          index: "/samplingDesc2",
+          label: "strawRemoval.samplingDesc2",
+          icon: Watermelon,
+        },
+        {
+          index: "/strawRemovalInputFlux",
+          label: "strawRemoval.strawRemovalInputFlux",
+          icon: List,
+        },
+      ],
+    },
+    {
+      index: "subsurfaceLeakage",
+      label: "subsurfaceLeakage.Title",
+      icon: WindPower,
+      children: [
+        {
+          index: "/samplingDesc3",
+          label: "subsurfaceLeakage.samplingDesc3",
+          icon: Watermelon,
+        },
+        {
+          index: "/subsurfaceLeakageInputFlux",
+          label: "subsurfaceLeakage.subsurfaceLeakageInputFlux",
+          icon: List,
+        },
+      ],
+    },
+    {
+      index: "surfaceRunoff",
+      label: "surfaceRunoff.Title",
+      icon: WindPower,
+      children: [
+        {
+          index: "/samplingDesc4",
+          label: "surfaceRunoff.samplingDesc4",
+          icon: Watermelon,
+        },
+        {
+          index: "/surfaceRunoffInputFlux",
+          label: "surfaceRunoff.surfaceRunoffInputFlux",
+          icon: List,
+        },
+      ],
+    },
+    {
+      index: "totalOutputFlux",
+      label: "totalOutputFlux.Title",
+      icon: WindPower,
+      children: [
+        {
+          index: "/totalOutputFluxDesc",
+          label: "输入总通量说明",
+          icon: Watermelon,
+        },
+        {
+          index: "/totalOutputFlux",
+          label: "输出总通量结果",
+          icon: List,
+        },
+      ],
+    },
+  ],
+
+  cadmiumPrediction: [
+    {
+      index: "/netFlux",
+      label: "netFlux.Title",
+      icon: PieChart,
+    },
+    {
+      index: "/currentYearConcentration",
+      label: "currentYearConcentration.Title",
+      icon: PieChart,
+    },
+    {
+      index: "/EffectiveCadmiumPrediction",
+      label: "EffectiveCadmiumPrediction.Title",
+      icon: PieChart,
+    },
+    {
+      index: "/CropCadmiumPrediction",
+      label: "CropCadmiumPrediction.Title",
+      icon: PieChart,
+    },
+  ],
+
+  cropRiskAssessment: [
+    {
+      index: "/cropRiskAssessment",
+      label: "cropRiskAssessment.Title",
+      icon: Compass,
+    },
+  ],
+
+  farmlandQualityAssessment: [
+    {
+      index: "/farmlandQualityAssessment",
+      label: "farmlandQualityAssessment.Title",
+      icon: DataLine,
+    },
+  ],
+
+  soilAcidificationPrediction: [
+    {
+      index: "acidModel",
+      label: "acidModel.Title",
+      icon: MagicStick,
+      children: [
+        {
+          index: "/Calculation",
+          label: "acidModel.CalculationTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/SoilAcidReductionIterativeEvolution",
+          label: "acidModel.SoilAcidReductionIterativeEvolutionTitle",
+          icon: Coin,
+        },
+      ],
+    },
+    {
+      index: "neutralizationModel",
+      label: "neutralizationModel.Title",
+      icon: MagicStick,
+      children: [
+        {
+          index: "/AcidNeutralizationModel",
+          label: "neutralizationModel.AcidNeutralizationModelTitle",
+          icon: Sunny,
+        },
+        {
+          index: "/SoilAcidificationIterativeEvolution",
+          label: "neutralizationModel.SoilAcidificationIterativeEvolutionTitle",
+          icon: Coin,
+        },
+      ],
+    },
+  ],
+
+  scenarioSimulation: [
+    {
+      index: "/TraditionalFarmingRisk",
+      label: "TraditionalFarmingRisk.Title",
+      icon: MenuIcon,
+    },
+    {
+      index: "/HeavyMetalCadmiumControl",
+      label: "HeavyMetalCadmiumControl.Title",
+      icon: MenuIcon,
+    },
+    {
+      index: "/SoilAcidificationControl",
+      label: "SoilAcidificationControl.Title",
+      icon: MenuIcon,
+    },
+  ],
+
+  dataStatistics: [
+    {
+      index: "/DetectionStatistics",
+      label: "DetectionStatistics.Title",
+      icon: List,
+    },
+    {
+      index: "/FarmlandPollutionStatistics",
+      label: "FarmlandPollutionStatistics.Title",
+      icon: List,
+    },
+    {
+      index: "/LandClutivatesStatistics",
+      label: "LandClutivatesStatistics.Title", //<!--i18n:LandClutivatesStatistics.Title-->作物风险评估统计
+      icon: List,
+    },
+    {
+      index: "/SoilacidificationStatistics",
+      label: "SoilacidificationStatistics.Title", //<!--i18n:SoilacidificationStatistics.Title-->酸化预测数据统计
+      icon: List,
+    },
+  ],
+};

+ 9 - 0
src/router/index.ts

@@ -393,6 +393,15 @@ const routes = [
           ), // 修复路径
         meta: { title: "韶关" },
       },
+      {
+        path: "acidmodelmap",
+        name: "acidmodelmap",
+        component: () =>
+          import(
+            "@/views/User/acidModel/acidmodelmap.vue"
+          ),
+        meta: { title: "土壤酸化地图" }
+      },
 
       {
         path: "SoilAcidReboundPrediction",

+ 94 - 3
src/views/User/acidModel/Calculation.vue

@@ -25,6 +25,20 @@
         ></el-input>
       </el-form-item>
 
+        <el-form-item
+          label="土壤粘粒(g/kg)"
+          prop="CL"
+          :error="errorMessages.CL"
+          required
+        >
+          <el-input
+            v-model="form.CL"
+            size="large"
+            placeholder="请输入土壤粘粒50~400(g/kg)"
+            @input="handleInput('CL', $event, 50, 400)"
+          >
+          </el-input>
+        </el-form-item>
       <el-form-item label="土壤粘粒(g/kg)" prop="CL" :error="errorMessages.CL" required>
         <el-input
           v-model="form.CL"
@@ -34,6 +48,20 @@
         ></el-input>
       </el-form-item>
 
+        <el-form-item
+          label="阳离子交换量(cmol/kg)"
+          prop="CEC"
+          :error="errorMessages.CEC"
+          required
+        >
+          <el-input
+            v-model="form.CEC"
+            size="large"
+            placeholder="请输入阳离子交换量0~15(cmol/kg)"
+            @input="handleInput('CEC', $event, 0, 15)"
+          >
+          </el-input>
+        </el-form-item>
       <el-form-item label="阳离子交换量(cmol/kg)" prop="CEC" :error="errorMessages.CEC" required>
         <el-input
           v-model="form.CEC"
@@ -43,6 +71,20 @@
         ></el-input>
       </el-form-item>
 
+        <el-form-item
+          label="交换性氢(cmol/kg)"
+          prop="H_plus"
+          :error="errorMessages.H_plus"
+          required
+        >
+          <el-input
+            v-model="form.H_plus"
+            size="large"
+            placeholder="请输入交换性氢0~1(cmol/kg)"
+            @input="handleInput('H_plus', $event, 0, 1)"
+          >
+          </el-input>
+        </el-form-item>
       <el-form-item label="交换性氢(cmol/kg)" prop="H_plus" :error="errorMessages.H_plus" required>
         <el-input
           v-model="form.H_plus"
@@ -52,6 +94,20 @@
         ></el-input>
       </el-form-item>
 
+        <el-form-item
+          label="水解氮(g/kg)"
+          prop="N"
+          :error="errorMessages.N"
+          required
+        >
+          <el-input
+            v-model="form.N"
+            size="large"
+            placeholder="请输入水解氮0~0.2(g/kg)"
+            @input="handleInput('N', $event, 0, 0.2)"
+          >
+          </el-input>
+        </el-form-item>
       <el-form-item label="水解氮(g/kg)" prop="N" :error="errorMessages.N" required>
         <el-input
           v-model="form.N"
@@ -61,6 +117,20 @@
         ></el-input>
       </el-form-item>
 
+        <el-form-item
+          label="交换性铝(cmol/kg)"
+          prop="Al3_plus"
+          :error="errorMessages.Al3_plus"
+          required
+        >
+          <el-input
+            v-model="form.Al3_plus"
+            size="large"
+            placeholder="请输入交换性铝0~6(cmol/kg)"
+            @input="handleInput('Al3_plus', $event, 0, 6)"
+          >
+          </el-input>
+        </el-form-item>
       <el-form-item label="交换性铝(cmol/kg)" prop="Al3_plus" :error="errorMessages.Al3_plus" required>
         <el-input
           v-model="form.Al3_plus"
@@ -70,6 +140,9 @@
         ></el-input>
       </el-form-item>
 
+        <el-button type="primary" @click="onSubmit" class="onSubmit"
+          >计算</el-button
+        >
       <el-button type="primary" @click="onSubmit" class="onSubmit">计算</el-button>
 
       <el-dialog v-model="dialogVisible" @close="onDialogClose" :close-on-click-modal="false" width="500px" align-center title="计算结果">
@@ -97,6 +170,7 @@ interface Form {
   Al3_plus: number | null;
 }
 
+// 表单数据
 const form = reactive<Form>({
   OM: null,
   CL: null,
@@ -126,7 +200,7 @@ const selectedModelName = ref<string>("默认模型");
 const handleInput = (field: keyof Form, event: Event, min: number, max: number) => {
   const target = event.target as HTMLInputElement;
   let value = target.value.replace(/[^0-9.]/g, "");
-  form[field] = value ? parseFloat(value) : null;
+  (form as any)[field] = value ? parseFloat(value) : null;
 
   if (!value) {
     errorMessages[field] = "";
@@ -164,6 +238,7 @@ const onSubmit = async () => {
     { field: "OM" as keyof Form, min: 0, max: 30 },
     { field: "CL" as keyof Form, min: 50, max: 400 },
     { field: "CEC" as keyof Form, min: 0, max: 15 },
+    { field: "CEC" as keyof Form, min: 0, max: 15 },
     { field: "H_plus" as keyof Form, min: 0, max: 1 },
     { field: "N" as keyof Form, min: 0, max: 0.2 },
     { field: "Al3_plus" as keyof Form, min: 0, max: 6 },
@@ -238,8 +313,16 @@ onMounted(() => {
 </script>
 
 <style scoped>
-.box-card {
-  max-width: 850px;
+.container {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  max-width: 1400px;
+  margin: 0 auto;
+}
+
+.form-card {
+  width: 850px;
   margin: 0 auto;
   padding: 20px;
   background-color: #f0f5ff;
@@ -261,6 +344,14 @@ onMounted(() => {
   color: #555;
 }
 
+.model-info {
+  text-align: center;
+  margin-bottom: 20px;
+  font-size: 16px;
+  color: #555;
+}
+
+
 .el-form-item {
   margin-bottom: 20px;
 }

+ 869 - 0
src/views/User/acidModel/acidmodelmap.vue

@@ -0,0 +1,869 @@
+<template>
+  <el-card class="map-card">
+    <div class="title">
+      <div class="section-icon">🗺️</div>
+      <p class="map-title">乐昌市三种用地类型分布地图</p>
+    </div>
+
+    <div id="map-container" class="map-container">
+      <div v-if="mapLoading" class="loading">
+        <div class="loading-spinner"></div>
+        <span>地图加载中...</span>
+      </div>
+      <div v-if="mapError" class="error-tip">
+        <el-alert title="地图加载失败" type="error" show-icon>
+          <template #description>
+            <p>请检查GeoServer服务和配置</p>
+            <el-button @click="reloadMap" type="primary">重试加载</el-button>
+          </template>
+        </el-alert>
+      </div>
+    </div>
+
+    <!-- 整合后的信息弹窗 -->
+    <div v-if="showPopup"  class="feature-popup fixed-center">
+      <div class="popup-content">
+        <div class="popup-header">
+          <h4>地块信息</h4>
+          <button @click="closePopup" class="close-btn">×</button>
+        </div>
+        <div class="popup-body">
+          <!-- 坐标信息 -->
+          <div class="coordinate-info">
+            <div class="info-item">
+              <label>经度:</label>
+              <span>{{ currentClickCoords.lng.toFixed(6) }}</span>
+            </div>
+            <div class="info-item">
+              <label>纬度:</label>
+              <span>{{ currentClickCoords.lat.toFixed(6) }}</span>
+            </div>
+          </div>
+
+          <!-- 地块信息 -->
+          <div v-if="featureInfo.loading" class="loading-info">
+            <div class="loading-spinner small"></div>
+            <span>加载地块信息中...</span>
+          </div>
+          <div v-else-if="featureInfo.error" class="error-info">获取地块信息失败</div>
+          <div v-else-if="featureInfo.data" class="feature-info">
+            <div class="info-item">
+              <label>所属村:</label>
+              <span>{{ featureInfo.data.village || '未知' }}</span>
+            </div>
+            <div class="info-item">
+              <label>用地类型:</label>
+              <span>{{ featureInfo.data.landType || '未知' }}</span>
+            </div>
+          </div>
+          <div v-else class="no-data">无地块信息</div>
+
+          <!-- 操作按钮 -->
+          <div class="action-buttons" v-if="!showPredictionResult && !showAcidReductionInput">
+            <el-button 
+              size="small" 
+              type="primary" 
+              @click="startAcidReductionPrediction"
+            >
+              降酸预测
+            </el-button>
+            <el-button 
+              size="small" 
+              type="success" 
+              @click="handleAcidInversionPrediction"
+            >
+              反酸预测
+            </el-button>
+          </div>
+
+          <!-- 降酸预测参数输入 -->
+          <div v-if="showAcidReductionInput" class="acid-reduction-input">
+            <div class="section-title">降酸预测参数</div>
+            <el-form :model="acidReductionParams" :rules="acidReductionRules" ref="acidReductionFormRef" label-width="80px" size="small">
+              <el-form-item label="目标pH" prop="targetPH">
+                <el-input
+                  v-model.number="acidReductionParams.targetPH"
+                  type="number"
+                  step="0.01"
+                  placeholder="0-14"
+                />
+              </el-form-item>
+              <el-form-item label="NO3" prop="no3">
+                <el-input
+                  v-model.number="acidReductionParams.no3"
+                  type="number"
+                  step="0.01"
+                  min="0"
+                  placeholder="非负数"
+                />
+              </el-form-item>
+              <el-form-item label="CEC" prop="cec">
+                <el-input
+                  v-model.number="acidReductionParams.cec"
+                  type="number"
+                  step="0.01"
+                  min="0"
+                  placeholder="非负数"
+                />
+              </el-form-item>
+            </el-form>
+            <div class="input-buttons">
+              <el-button size="small" @click="cancelAcidReduction">取消</el-button>
+              <el-button size="small" type="primary" @click="confirmAcidReduction" :loading="predictionLoading">
+                开始预测
+              </el-button>
+            </div>
+          </div>
+
+          <!-- 预测结果展示 -->
+          <div v-if="showPredictionResult" class="prediction-section">
+            <div class="section-title">{{ predictionTitle }}</div>
+            <div v-if="predictionLoading" class="loading-info">
+              <div class="loading-spinner small"></div>
+              <span>预测中...</span>
+            </div>
+            <div v-else-if="predictionError" class="error-info">
+              {{ predictionError }}
+            </div>
+            <div v-else-if="predictionResult" class="prediction-result">
+              <div class="result-item">
+                <label>最近点位信息:</label>
+                <div class="point-info">
+                  <div>经度: {{ predictionResult.nearest_point?.lon }}</div>
+                  <div>纬度: {{ predictionResult.nearest_point?.lan }}</div>
+                </div>
+              </div>
+              <div class="result-item" v-if="currentPredictionType === 'reduction' && predictionResult.prediction_model33 !== undefined">
+                <label>降酸预测结果:</label>
+                <span class="prediction-value reduction">每亩地土壤表层20cm撒{{ formatPredictionValue(predictionResult.prediction_model33)}} 吨</span>
+              </div>
+              <div class="result-buttons">
+                <el-button size="small" @click="resetPrediction">重新预测</el-button>
+                <el-button size="small" type="primary" @click="closePopup">关闭</el-button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import {reactive, ref, nextTick, onMounted ,onUnmounted, computed} from "vue";
+import { ElMessage } from "element-plus";
+import type { LeafletMouseEvent } from "leaflet";
+import type { FormInstance } from "element-plus";
+
+// 地图状态
+const mapLoading = ref(true);
+const mapError = ref(false);
+const map = ref<any>(null);
+const showPopup = ref(false);
+
+
+// 预测状态
+const predictionLoading = ref(false);
+const predictionError = ref('');
+const predictionResult = ref<any>(null);
+const showPredictionResult = ref(false);
+const showAcidReductionInput = ref(false);
+
+let L:any = null;
+
+// 地块信息状态
+const featureInfo = reactive({
+  loading: false,
+  error: false,
+  data: null as any
+});
+
+// 当前坐标
+const currentClickCoords = reactive({
+  lng: 0,
+  lat: 0
+});
+
+const currentPredictionType = ref<'reduction' | 'inversion' | null>(null);
+
+// 降酸预测参数输入相关
+const acidReductionFormRef = ref<FormInstance | null>(null);
+const acidReductionParams = reactive({
+  targetPH: 7.0, // 设置一个合理的默认值
+  no3: 34.05,    // 设置一个合理的默认值
+  cec: 7.87      // 设置一个合理的默认值
+});
+
+// 过滤警告信息
+const filteredWarnings = computed(() => {
+  if (!predictionResult.value?.warnings) return [];
+  return predictionResult.value.warnings.filter((warning: string) => {
+    return !warning.includes('模型24');
+  });
+});
+
+// 预测标题
+const predictionTitle = computed(() => {
+  if (currentPredictionType.value === 'reduction') return '降酸预测结果';
+  if (currentPredictionType.value === 'inversion') return '反酸预测结果';
+  return '预测结果';
+});
+
+// 输入校验规则
+const acidReductionRules = reactive({
+  targetPH: [
+    { required: true, message: '请输入目标pH值', trigger: 'blur' },
+    { type: 'number', message: '请输入有效数字', trigger: 'blur' },
+    { 
+      validator: (rule: any, value: number, callback: any) => {
+        if (value < 0 || value > 14) {
+          callback(new Error('值范围在0-14之间'));
+        } else {
+          callback();
+        }
+      }, 
+      trigger: 'blur' 
+    }
+  ],
+  no3: [
+    { required: true, message: '请输入NO3', trigger: 'blur' },
+    { type: 'number', message: '请输入有效数字', trigger: 'blur' },
+    { 
+      validator: (rule: any, value: number, callback: any) => {
+        if (value < 0) {
+          callback(new Error('值不能为负数'));
+        } else {
+          callback();
+        }
+      }, 
+      trigger: 'blur' 
+    }
+  ],
+  cec: [
+    { required: true, message: '请输入CEC', trigger: 'blur' },
+    { type: 'number', message: '请输入有效数字', trigger: 'blur' },
+    { 
+      validator: (rule: any, value: number, callback: any) => {
+        if (value < 0) {
+          callback(new Error('值不能为负数'));
+        } else {
+          callback();
+        }
+      }, 
+      trigger: 'blur' 
+    }
+  ]
+});
+
+// 格式化预测值
+const formatPredictionValue = (value: any): string => {
+  console.log('预测值原始数据:', value, '类型:', typeof value);
+  
+  if (value === null || value === undefined) return '无数据';
+  
+  if (Array.isArray(value)) {
+    if (value.length === 0) return '无数据';
+    const num = Number(value[0]);
+    return isNaN(num) ? '无效数据' : num.toFixed(4);
+  }
+  
+  if (typeof value === 'object') {
+    console.warn('预测值是对象类型:', value);
+    return '数据格式错误';
+  }
+  
+  const num = Number(value);
+  return isNaN(num) ? '无效数据' : num.toFixed(4);
+};
+
+// 获取地块信息
+const getFeatureInfo = async (latlng: any, point: any): Promise<boolean> => {
+  if (!map.value) return false;
+  
+  featureInfo.loading = true;
+  featureInfo.error = false;
+  featureInfo.data = null;
+
+  try {
+    const GEOSERVER_CONFIG = {
+      url: "/geoserver/wms",
+      workspace: "acidmap",
+      layerGroup: "mapwithboundary", 
+    };
+
+    const bounds = map.value.getBounds();
+    const size = map.value.getSize();
+    
+    const params = new URLSearchParams();
+    params.append('service', 'WMS');
+    params.append('version', '1.1.1');
+    params.append('request', 'GetFeatureInfo');
+    params.append('layers', `${GEOSERVER_CONFIG.workspace}:${GEOSERVER_CONFIG.layerGroup}`);
+    params.append('query_layers', `${GEOSERVER_CONFIG.workspace}:${GEOSERVER_CONFIG.layerGroup}`);
+    params.append('info_format', 'application/json');
+    params.append('feature_count', '10');
+    params.append('x', Math.round(point.x).toString());
+    params.append('y', Math.round(point.y).toString());
+    params.append('width', size.x.toString());
+    params.append('height', size.y.toString());
+    params.append('srs', 'EPSG:4326');
+    params.append('bbox', `${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}`);
+
+    const url = `${GEOSERVER_CONFIG.url}?${params.toString()}`;
+    
+    const response = await fetch(url);
+    
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+    
+    const data = await response.json();
+    
+    if (data.features && data.features.length > 0) {
+      const properties = data.features[0].properties;
+      const hasValidData = properties.QSDWMC || properties.DLMC;
+      
+      if (hasValidData) {
+        featureInfo.data = {
+          village: properties.QSDWMC,
+          landType: properties.DLMC,
+        };
+        return true;
+      }
+    }
+    
+    return false;
+    
+  } catch (error) {
+    console.error('获取地块信息失败:', error);
+    featureInfo.error = true;
+    return false;
+  } finally {
+    featureInfo.loading = false;
+  }
+};
+
+// 调用预测接口
+const callPredictionAPI = async (lng: number, lat: number, acidReductionParams?: {
+    targetPH: number;
+    no3: number;
+    cec: number;
+  }) => {
+  predictionLoading.value = true;
+  predictionError.value = '';
+  predictionResult.value = null;
+
+  try {
+    const urlParams = new URLSearchParams();
+    urlParams.append('target_lon', lng.toString());
+    urlParams.append('target_lan', lat.toString());
+    
+    // 如果是降酸预测,添加参数
+    if (acidReductionParams) {
+      urlParams.append('target_pH', acidReductionParams.targetPH.toString());
+      urlParams.append('NO3', acidReductionParams.no3.toString());
+      urlParams.append('CEC', acidReductionParams.cec.toString());
+    }
+
+    console.log('调用预测接口,参数:', urlParams.toString());
+
+    const response = await fetch(
+      `http://localhost:8000/api/vector/nearest-with-predictions?${urlParams.toString()}`
+    );
+
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    }
+
+    const data = await response.json();
+    predictionResult.value = data;
+    console.log('预测结果:', data);
+
+    // 显示预测结果
+    showPredictionResult.value = true;
+    showAcidReductionInput.value = false;
+
+  } catch (error) {
+    console.error('调用预测接口失败:', error);
+    predictionError.value = `预测失败: ${error instanceof Error ? error.message : '未知错误'}`;
+    ElMessage.error('预测请求失败,请检查后端服务是否启动');
+  } finally {
+    predictionLoading.value = false;
+  }
+};
+
+// 开始降酸预测(显示参数输入)
+const startAcidReductionPrediction = () => {
+  currentPredictionType.value = 'reduction';
+  showAcidReductionInput.value = true;
+};
+
+// 取消降酸预测
+const cancelAcidReduction = () => {
+  showAcidReductionInput.value = false;
+  currentPredictionType.value = null;
+};
+
+// 确认降酸预测
+const confirmAcidReduction = async () => {
+  if (!acidReductionFormRef.value) return;
+  
+  try {
+    await acidReductionFormRef.value.validate();
+    
+    await callPredictionAPI(
+      currentClickCoords.lng,
+      currentClickCoords.lat,
+      {
+        targetPH: acidReductionParams.targetPH,
+        no3: acidReductionParams.no3,
+        cec: acidReductionParams.cec
+      }
+    );
+    
+  } catch (error) {
+    ElMessage.error('输入参数不合法,请检查后重试');
+    console.error('表单校验失败:', error);
+  }
+};
+
+// 反酸预测按钮点击
+const handleAcidInversionPrediction = () => {
+  currentPredictionType.value = 'inversion';
+  callPredictionAPI(currentClickCoords.lng, currentClickCoords.lat);
+};
+
+// 重置预测
+const resetPrediction = () => {
+  showPredictionResult.value = false;
+  predictionResult.value = null;
+  currentPredictionType.value = null;
+  showAcidReductionInput.value = false;
+};
+
+// 地图点击事件处理
+const handleMapClick = async (e: any) => {
+  const lng = e.latlng.lng;
+  const lat = e.latlng.lat;
+  
+  // 更新当前坐标
+  currentClickCoords.lng = lng;
+  currentClickCoords.lat = lat;
+
+  showPopup.value = true;
+  
+  // 重置预测状态
+  resetPrediction();
+  
+  // 获取地块信息
+  try {
+    const containerPoint = map.value.latLngToContainerPoint(e.latlng);
+    await getFeatureInfo(e.latlng, containerPoint);
+  } catch (error) {
+    console.error('处理地块信息失败:', error);
+  }
+};
+
+// 关闭弹窗
+const closePopup = () => {
+  showPopup.value = false;
+  resetPrediction();
+};
+
+const initMap = async () => {
+  mapLoading.value = true;
+  mapError.value = false;
+
+  try {
+    // 动态导入Leaflet
+    if (!L) {
+      L = await import('leaflet');
+      await import('leaflet/dist/leaflet.css');
+      
+      delete (L.Icon.Default.prototype as any)._getIconUrl;
+      L.Icon.Default.mergeOptions({
+        iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png',
+        iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png',
+        shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
+      });
+    }
+
+    // 清除现有地图
+    if (map.value) {
+      map.value.remove();
+      map.value = null;
+    }
+
+    // 创建地图实例
+    map.value = L.map('map-container', {
+      zoomControl: true,
+      attributionControl: false,
+      center: [25.202903, 113.25383],
+      zoom: 10
+    });
+
+    // WMS配置
+    const GEOSERVER_CONFIG = {
+      url: "/geoserver/wms",
+      workspace: "acidmap",
+      layerGroup: "mapwithboundary", 
+    };
+
+    // WMS图层配置
+    const wmsLayer = L.tileLayer.wms(GEOSERVER_CONFIG.url, {
+      layers: `${GEOSERVER_CONFIG.workspace}:${GEOSERVER_CONFIG.layerGroup}`,
+      format: "image/png",
+      transparent: true,
+      version: "1.1.1",
+      crs: L.CRS.EPSG4326,
+      attribution: "Data from GeoServer"
+    });
+
+    // 添加图层到地图
+    wmsLayer.addTo(map.value);
+
+    // 绑定点击事件
+    map.value.on('click', handleMapClick);
+
+    mapLoading.value = false;
+
+  } catch (error) {
+    console.error('地图初始化失败:', error);
+    mapError.value = true;
+    mapLoading.value = false;
+    
+    let errorMessage = '地图初始化失败';
+    if (error instanceof Error) {
+      errorMessage += ': ' + error.message;
+    }
+    ElMessage.error(errorMessage);
+  }
+};
+
+const reloadMap = () => {
+  initMap();
+};
+
+// 组件卸载时清理
+onUnmounted(() => {
+  if (map.value) {
+    map.value.remove();
+  }
+});
+
+onMounted(() => {
+  nextTick(() => {
+    initMap();
+  });
+});
+</script>
+
+<style scoped>
+.feature-popup {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+  z-index: 1000;
+  background: white;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  min-width: 320px;
+  max-width: 380px;
+}
+
+.popup-content {
+  padding: 0;
+}
+
+.popup-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 15px;
+  border-bottom: 1px solid #ebeef5;
+  background: #f5f7fa;
+  border-radius: 8px 8px 0 0;
+}
+
+.popup-header h4 {
+  margin: 0;
+  font-size: 14px;
+  color: #303133;
+}
+
+.close-btn {
+  background: none;
+  border: none;
+  font-size: 18px;
+  cursor: pointer;
+  color: #909399;
+  padding: 0;
+  width: 20px;
+  height: 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.close-btn:hover {
+  color: #606266;
+}
+
+.popup-body {
+  padding: 15px;
+  max-height: 500px;
+  overflow-y: auto;
+}
+
+.coordinate-info {
+  margin-bottom: 12px;
+  padding-bottom: 12px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.loading-info, .error-info, .no-data {
+  text-align: center;
+  color: #909399;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  margin: 10px 0;
+}
+
+.error-info {
+  color: #f56c6c;
+}
+
+.feature-info {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.info-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.info-item label {
+  font-weight: 600;
+  color: #606266;
+  font-size: 14px;
+}
+
+.info-item span {
+  color: #303133;
+  font-size: 14px;
+  text-align: right;
+}
+
+.action-buttons {
+  display: flex;
+  gap: 8px;
+  justify-content: center;
+  margin: 12px 0;
+  padding-top: 12px;
+  border-top: 1px solid #f0f0f0;
+}
+
+.acid-reduction-input {
+  margin-top: 12px;
+  padding-top: 12px;
+  border-top: 1px solid #f0f0f0;
+}
+
+.input-buttons {
+  display: flex;
+  gap: 8px;
+  justify-content: flex-end;
+  margin-top: 12px;
+}
+
+.prediction-section {
+  margin-top: 12px;
+  padding-top: 12px;
+  border-top: 1px solid #f0f0f0;
+}
+
+.section-title {
+  font-weight: 600;
+  color: #303133;
+  font-size: 13px;
+  margin-bottom: 8px;
+}
+
+.prediction-result {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.result-item {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.result-item label {
+  font-weight: 600;
+  color: #606266;
+  font-size: 14px;
+}
+
+.point-info {
+  font-size: 11px;
+  color: #666;
+  background: #f8f9fa;
+  padding: 6px;
+  border-radius: 4px;
+  line-height: 1.4;
+}
+
+.prediction-value {
+  font-weight: bold;
+  font-size: 13px;
+}
+
+.prediction-value.reduction {
+  color: #e6a23c;
+}
+
+.warnings {
+  margin-top: 8px;
+  padding: 6px;
+  background: #fff6f6;
+  border: 1px solid #fbc4c4;
+  border-radius: 4px;
+}
+
+.warning-item {
+  font-size: 11px;
+  color: #f56c6c;
+  line-height: 1.3;
+}
+
+.result-buttons {
+  display: flex;
+  gap: 8px;
+  justify-content: flex-end;
+  margin-top: 12px;
+}
+
+.loading-spinner {
+  width: 20px;
+  height: 20px;
+  border: 2px solid #f3f3f3;
+  border-top: 2px solid #409eff;
+  border-radius: 50%;
+  animation: spin 1s linear infinite;
+}
+
+.loading-spinner.small {
+  width: 16px;
+  height: 16px;
+  border-width: 1.5px;
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+.map-card {
+  width: 850px;
+  flex: 1;
+  min-height: 600px;
+  margin: 0 auto;
+}
+
+.map-container {
+  height: 550px;
+  width: 100%;
+  position: relative;
+  border-radius: 4px;
+  overflow: hidden;
+  background: #f0f2f5;
+  border: 1px solid #dcdfe6;
+}
+
+.loading {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  text-align: center;
+  z-index: 1000;
+  background: rgba(255, 255, 255, 0.95);
+  padding: 20px;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.loading span {
+  margin-left: 8px;
+  color: #606266;
+}
+
+.error-tip {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 80%;
+  z-index: 1000;
+}
+
+.title {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.map-title {
+  color: #1a365d;
+  font-size: 1.6rem;
+  font-weight: 600;
+}
+
+.section-icon {
+  font-size: 2.2rem;
+  color: #3a9fd3;
+}
+
+/* 表单样式调整 */
+:deep(.el-form-item) {
+  margin-bottom: 12px;
+}
+
+:deep(.el-form-item__label) {
+  font-size: 12px;
+  line-height: 28px;
+}
+
+:deep(.el-input) {
+  font-size: 12px;
+}
+
+:deep(.el-input__inner) {
+  height: 28px;
+  line-height: 28px;
+}
+
+.popup-body {
+  padding: 15px;
+  overflow-y: auto;
+  max-height: calc(80vh - 60px); /* 减去头部高度 */
+}
+
+.popup-content {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+</style>

+ 22 - 35
src/views/login/loginView.vue

@@ -311,8 +311,7 @@ const onSubmit = async () => {
     ElMessage.success(t("login.loginSuccess"));
 
     // 跳转到目标页面
-    await router.push({ name: 'CropCadmiumPrediction' });
-
+    await router.push({ name: "samplingMethodDevice1" });
   } catch (error: any) {
     console.error("登录失败:", {
       error: error.message,
@@ -350,39 +349,27 @@ const onRegister = async () => {
 
     // 注册成功
     if (res.data?.message) {
-      // 注册成功后自动登录
-      try {
-        // 调用登录API
-        const loginResponse = await login({
-          name: registerForm.name,
-          password: registerForm.password,
-          usertype: userType.value,
-        });
-
-        // 检查登录响应结构
-        if (loginResponse.data?.user) {
-          const userData = loginResponse.data.user;
-          
-          // 保存用户信息到store
-          store.saveToken({
-            userId: Number(userData.id),
-            name: userData.name,
-            loginType: userData.userType || userType.value,
-          });
-
-          // 跳转到目标页面
-          await router.push({ name: 'CropCadmiumPrediction' });
-        } else {
-          showErrorMsg(loginResponse.data?.message || '自动登录失败,请手动登录');
-          toggleForm(); // 返回登录页面
-        }
-      } catch (loginError: any) {
-        console.error('自动登录失败:', loginError);
-        showErrorMsg(
-          loginError?.response?.data?.message || '自动登录失败,请手动登录'
-        );
-        toggleForm(); // 返回登录页面
-      }
+      // 显示注册成功消息
+      showMsg(t("register.registerSuccess"), "success");
+      ElMessage.success(t("register.registerSuccess"));
+
+      // 延迟一段时间后自动跳转到登录页并填充信息
+      setTimeout(() => {
+        // 切换到登录表单
+        isLogin.value = true;
+
+        // 将注册的用户名和密码填入登录表单
+        form.name = registerForm.name;
+        form.password = registerForm.password; // 填充密码
+
+        // 清空注册表单
+        registerForm.name = "";
+        registerForm.password = "";
+        registerForm.confirmPassword = "";
+
+        // 可选:给用户一个提示
+        ElMessage.info(t("register.autoLoginPrompt"));
+      }, 1500); // 1.5秒后执行
     } else {
       const errorMsg = res.data?.message || t("register.registerFailed");
       showMsg(errorMsg, "error");