3
0

6 کامیت‌ها 3c98e9b19d ... 756a6a9261

نویسنده SHA1 پیام تاریخ
  yes-yes-yes-k 756a6a9261 Merge branch 'master' of http://139.9.51.218:3000/qw/12 into lili 1 ماه پیش
  Ding 12e5f0044b Merge branch 'ding' of qw/12 into master 2 ماه پیش
  yangtaodemon 5bb5c57bbb Merge branch 'master' of http://139.9.51.218:3000/qw/12 into ding 2 ماه پیش
  yangtaodemon 3651feac03 补充Cd模型上传并计算 2 ماه پیش
  qw 732805f7df 优化项目结构,生成项目结构文件 2 ماه پیش
  qw a7bcf02b18 优化项目结构,生成项目结构文件 2 ماه پیش
33فایلهای تغییر یافته به همراه1042 افزوده شده و 494 حذف شده
  1. 1 1
      .env
  2. 1 1
      auto-imports.d.ts
  3. 7 1
      components.d.ts
  4. 2 2
      index.html
  5. 12 12
      package-lock.json
  6. 2 2
      package.json
  7. BIN
      public/favicon.ico
  8. 5 1
      src/assets/logo.svg
  9. 3 3
      src/components/layout/AppLayout.vue
  10. 178 85
      src/components/layout/menuItems2.ts
  11. 20 20
      src/router/index.ts
  12. 0 0
      src/views/Admin/Wheat Cadmium Pollution Risk Model Management/WheatRiskModel.vue
  13. 0 0
      src/views/Admin/dataManagement/Administrative Area Data Management/AdminRegionData.vue
  14. 0 0
      src/views/Admin/dataManagement/Climate Information Data Management/ClimateInfoData.vue
  15. 0 0
      src/views/Admin/dataManagement/Crop Heavy Metal Sampling Data Management/CropHeavyMetalData.vue
  16. 0 0
      src/views/Admin/dataManagement/Geographic Environmental Information Management/GeographicEnvInfoData.vue
  17. 0 0
      src/views/Admin/dataManagement/Land Use Type Data Management/LandUseTypeData.vue
  18. 0 0
      src/views/Admin/dataManagement/Soil Acidification Sampling Data Management/SoilAcidificationData.vue
  19. 0 0
      src/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidReductionData.vue
  20. 0 0
      src/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidificationData.vue
  21. 0 0
      src/views/Admin/dataManagement/Soil Heavy Metal Sampling Data Management/SoilHeavyMetalData.vue
  22. 0 0
      src/views/Admin/dataManagement/SoilAssessmentUnitData/SoilAssessmentUnitData.vue
  23. 0 0
      src/views/Admin/modelManagement/Rice Cadmium Pollution Risk Model Management/RiceRiskModel.vue
  24. 0 0
      src/views/Admin/modelManagement/Soil Cadmium Content Prediction Model Management/CadmiumPredictionModel.vue
  25. 0 0
      src/views/Admin/modelManagement/Vegetable Cadmium Pollution Risk Model Management/VegetableRiskModel.vue
  26. 267 119
      src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue
  27. 267 119
      src/views/User/cadmiumPrediction/EffectiveCadmiumPrediction.vue
  28. 267 119
      src/views/User/cadmiumPrediction/TotalCadmiumPrediction.vue
  29. 8 1
      src/views/User/mapView/tencentMapView.vue
  30. 2 2
      src/views/api.vue
  31. BIN
      structure.txt
  32. 0 1
      tsconfig.app.json
  33. 0 5
      vite.config.ts

+ 1 - 1
.env

@@ -1,2 +1,2 @@
-VITE_API_URL= 'https://soilgd.com:5000'
+VITE_API_URL= 'https://www.soilgd.com:5000'
 VITE_TMAP_KEY='2R4BZ-FF4RM-Q6C6U-6TCJL-O2EN5-DVFH5'

+ 1 - 1
auto-imports.d.ts

@@ -68,6 +68,6 @@ declare global {
 // for type re-export
 declare global {
   // @ts-ignore
-  export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
   import('vue')
 }

+ 7 - 1
components.d.ts

@@ -2,7 +2,6 @@
 // @ts-nocheck
 // Generated by unplugin-vue-components
 // Read more: https://github.com/vuejs/core/pull/3399
-// biome-ignore lint: disable
 export {}
 
 /* prettier-ignore */
@@ -12,6 +11,7 @@ declare module 'vue' {
     AppAsideForTab2: typeof import('./src/components/layout/AppAsideForTab2.vue')['default']
     AppHeader: typeof import('./src/components/layout/AppHeader.vue')['default']
     AppLayout: typeof import('./src/components/layout/AppLayout.vue')['default']
+    ElAlert: typeof import('element-plus/es')['ElAlert']
     ElAside: typeof import('element-plus/es')['ElAside']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
@@ -33,6 +33,7 @@ declare module 'vue' {
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
+    ElPagination: typeof import('element-plus/es')['ElPagination']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
@@ -41,6 +42,8 @@ declare module 'vue' {
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTabPane: typeof import('element-plus/es')['ElTabPane']
     ElTabs: typeof import('element-plus/es')['ElTabs']
+    ElTooltip: typeof import('element-plus/es')['ElTooltip']
+    ElUpload: typeof import('element-plus/es')['ElUpload']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
     IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
     IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
@@ -53,4 +56,7 @@ declare module 'vue' {
     TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
     WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
   }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
 }

+ 2 - 2
index.html

@@ -2,9 +2,9 @@
 <html lang="">
   <head>
     <meta charset="UTF-8">
-    <link rel="icon" href="/favicon.ico">
+    <link rel="icon" href="/logo.ico">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Vite App</title>
+    <title>区域土壤重金属评估</title>
   </head>
   <body>
     <div id="app"></div>

+ 12 - 12
package-lock.json

@@ -32,10 +32,10 @@
       },
       "devDependencies": {
         "@iconify-json/ep": "^1.2.2",
-        "@tsconfig/node22": "^22.0.0",
+        "@tsconfig/node22": "^22.0.2",
         "@types/jsdom": "^21.1.7",
         "@types/leaflet": "^1.9.16",
-        "@types/node": "^22.13.8",
+        "@types/node": "^22.15.31",
         "@types/vue": "^2.0.0",
         "@vitejs/plugin-vue": "^5.2.1",
         "@vue/test-utils": "^2.4.6",
@@ -2078,9 +2078,9 @@
       "license": "MIT"
     },
     "node_modules/@tsconfig/node22": {
-      "version": "22.0.0",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.0.tgz",
-      "integrity": "sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==",
+      "version": "22.0.2",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.2.tgz",
+      "integrity": "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==",
       "dev": true,
       "license": "MIT"
     },
@@ -2142,13 +2142,13 @@
       }
     },
     "node_modules/@types/node": {
-      "version": "22.13.8",
-      "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.8.tgz",
-      "integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
+      "version": "22.15.31",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.31.tgz",
+      "integrity": "sha512-jnVe5ULKl6tijxUhvQeNbQG/84fHfg+yMak02cT8QVhBx/F05rAVxCGBYYTh2EKz22D6JF5ktXuNwdx7b9iEGw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "undici-types": "~6.20.0"
+        "undici-types": "~6.21.0"
       }
     },
     "node_modules/@types/tough-cookie": {
@@ -6049,9 +6049,9 @@
       "license": "MIT"
     },
     "node_modules/undici-types": {
-      "version": "6.20.0",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
-      "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
       "dev": true,
       "license": "MIT"
     },

+ 2 - 2
package.json

@@ -36,10 +36,10 @@
   },
   "devDependencies": {
     "@iconify-json/ep": "^1.2.2",
-    "@tsconfig/node22": "^22.0.0",
+    "@tsconfig/node22": "^22.0.2",
     "@types/jsdom": "^21.1.7",
     "@types/leaflet": "^1.9.16",
-    "@types/node": "^22.13.8",
+    "@types/node": "^22.15.31",
     "@types/vue": "^2.0.0",
     "@vitejs/plugin-vue": "^5.2.1",
     "@vue/test-utils": "^2.4.6",

BIN
public/favicon.ico


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5 - 1
src/assets/logo.svg


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

@@ -16,7 +16,7 @@ const isFullScreen = computed(() => route.meta.fullScreen === true);
 const tabs = computed(() => {
   if (tokenStore.token.loginType === "admin") {
     return [
-      { name: "dataManagement", label: "数据管理", icon: "el-icon-folder", routes: ["/Visualizatio","/Visualization", "/AdminRegionData", "/SoilAssessmentUnitData", "/SoilHeavyMetalData", "/CropHeavyMetalData", "/LandUseTypeData", "/SoilAcidificationData", "/ClimateInfoData", "/GeographicEnvInfoData"] },
+      { name: "dataManagement", label: "数据管理", icon: "el-icon-folder", routes: ["/soilAcidReductionData","/soilAcidificationData", "/AdminRegionData", "/SoilAssessmentUnitData", "/SoilHeavyMetalData", "/CropHeavyMetalData", "/LandUseTypeData", "/SoilAcidificationData", "/ClimateInfoData", "/GeographicEnvInfoData"] },
       { name: "infoManagement", label: "信息管理", icon: "el-icon-document", routes: ["/IntroductionUpdate"] },
       { name: "modelManagement", label: "模型管理及配置", icon: "el-icon-cpu", routes: ["/CadmiumPredictionModel", "/EffectiveCadmiumModel", "/Admin/RiceRiskModel", "/AdminModelSelection", "/Admin/thres", "/Admin/ModelTrain", "/Admin/WheatRiskModel", "/Admin/VegetableRiskModel"] },
       { name: "userManagement", label: "用户管理", icon: "el-icon-user", routes: ["/UserManagement", "/UserRegistration"] },
@@ -246,7 +246,7 @@ const scrollbarStyle = computed(() => {
 
 .tab-icon {
   font-size: 36px; /* 原 20px */
-  margin-right: 8px;
+  margin-right: 2px;
   color: inherit; /* 跟随文字颜色 */
 }
 
@@ -263,7 +263,7 @@ const scrollbarStyle = computed(() => {
 }
 
 .layout-aside {
-  width: 200px;
+  width: 270px;
   background-color: #fff;
   border-right: 1px solid #dcdfe6;
   overflow-y: auto;

+ 178 - 85
src/components/layout/menuItems2.ts

@@ -1,86 +1,179 @@
 import {
-    Setting,
-    Menu,
-    Folder,
-    Document,
-    User,
-    Grid,
-    Reading,
-    Location,
-    TrendCharts,
-    Collection,
-    Postcard,
-    Star,
-    Warning,
-  } from "@element-plus/icons-vue";
-  
-  export const tabMenuMap: Record<string, any[]> = {
-    dataManagement: [
-      { index: "/Visualizatio", label: "降酸数据管理", icon: Document },
-      { index: "/Visualization", label: "反酸数据管理", icon: Document },
-      { index: "/AdminRegionData", label: "行政区域数据", icon: Location },
-      {
-        index: "/SoilAssessmentUnitData",
-        label: "土壤评估单元格数据",
-        icon: Grid,
-      },
-      {
-        index: "/SoilHeavyMetalData",
-        label: "土壤重金属采集数据",
-        icon: Collection,
-      },
-      {
-        index: "/CropHeavyMetalData",
-        label: "农作物重金属采集样数据",
-        icon: Postcard,
-      },
-      { index: "/LandUseTypeData", label: "用地类型数据", icon: Menu },
-      {
-        index: "/SoilAcidificationData",
-        label: "土壤酸化采样数据",
-        icon: Warning,
-      },
-      { index: "/ClimateInfoData", label: "气候信息数据", icon: TrendCharts },
-      { index: "/GeographicEnvInfoData", label: "地理环境信息", icon: Reading },
-    ],
-    infoManagement: [
-      { index: "/IntroductionUpdate", label: "介绍信息管理", icon: Document },
-    ],
-    modelManagement: [
-      {
-        index: "/CadmiumPredictionModel",
-        label: "土壤镉含量预测模型",
-        icon: Star,
-      },
-      {
-        index: "/AcidReductionModel",
-        label: "反酸及降酸模型",
-        icon: Star,
-        children: [
-          {
-            index: '/ModelSelection',
-            label: '模型选择',
-            icon: Setting
-          },
-          {
-            index: '/thres',
-            label: '阈值选择',
-            icon: Menu
-          },
-          {
-            index: '/ModelTrain',
-            label: '模型训练',
-            icon: Folder,
-          }
-        ]
-      },      
-      { index: "/RiceRiskModel", label: "水稻镉污染风险模型", icon: Star },
-      { index: "/WheatRiskModel", label: "小麦镉污染风险模型", icon: Star },
-      { index: "/VegetableRiskModel", label: "蔬菜镉污染风险模型", icon: Star },
-    ],
-    userManagement: [
-      { index: "/UserManagement", label: "用户信息", icon: User },
-      { index: "/UserRegistration", label: "普通用户", icon: User },
-    ],
-  };
-  
+  Setting,
+  Menu,
+  Folder,
+  Document,
+  User,
+  Grid,
+  Reading,
+  Location,
+  TrendCharts,
+  Collection,
+  Postcard,
+  Star,
+  Warning,
+  Tickets,
+  List,
+  DataAnalysis,
+  Tools,
+  Histogram,
+  Guide,
+  Platform,
+  Box,
+  Avatar,
+  Briefcase,
+} from "@element-plus/icons-vue";
+
+export const tabMenuMap: Record<string, any[]> = {
+  dataManagement: [
+    {
+      index: "/Soil Acidification and Acid Reduction Data Management",
+      label: "反酸及降酸数据管理",
+      icon: Tools,
+      children: [
+        { index: "/soilAcidReductionData", label: "降酸数据", icon: DataAnalysis },
+        { index: "/soilAcidificationData", label: "反酸数据", icon: Warning },
+      ],
+    },
+    {
+      index: "/Administrative Area Data Management",
+      label: "行政区域数据管理",
+      icon: Location,
+      children: [
+        { index: "/AdminRegionData", label: "行政区域数据", icon: Location },
+      ],
+    },
+    {
+      index: "/Soil Assessment Cell Data Management",
+      label: "土壤评估单元格数据管理",
+      icon: Grid,
+      children: [
+        { index: "/SoilAssessmentUnitData", label: "土壤评估单元格数据", icon: Grid },
+      ],
+    },
+    {
+      index: "/Soil Heavy Metal Sampling Data Management",
+      label: "土壤重金属采集数据管理",
+      icon: Collection,
+      children: [
+        { index: "/SoilHeavyMetalData", label: "土壤重金属采集数据", icon: Collection },
+      ],
+    },
+    {
+      index: "/Crop Heavy Metal Sampling Data Management",
+      label: "农作物重金属采集样数据管理",
+      icon: Postcard,
+      children: [
+        { index: "/CropHeavyMetalData", label: "农作物重金属采集样数据", icon: Postcard },
+      ],
+    },
+    {
+      index: "/Land Use Type Data Management",
+      label: "用地类型数据管理",
+      icon: Briefcase,
+      children: [
+        { index: "/LandUseTypeData", label: "用地类型数据", icon: List },
+      ],
+    },
+    {
+      index: "/Soil Acidification Sampling Data Management",
+      label: "土壤酸化采样数据管理",
+      icon: Warning,
+      children: [
+        { index: "/SoilAcidificationData", label: "土壤酸化采样数据", icon: Warning },
+      ],
+    },
+    {
+      index: "/Climate Information Data Management",
+      label: "气候信息数据管理",
+      icon: TrendCharts,
+      children: [
+        { index: "/ClimateInfoData", label: "气候信息数据", icon: TrendCharts },
+      ],
+    },
+    {
+      index: "/Geographic Environmental Information Management",
+      label: "地理环境信息管理",
+      icon: Reading,
+      children: [
+        { index: "/GeographicEnvInfoData", label: "地理环境信息", icon: Reading },
+      ],
+    },
+  ],
+  infoManagement: [
+    {
+      index: "/IntroductionUpdate",
+      label: "介绍信息管理",
+      icon: Guide,
+    },
+  ],
+  modelManagement: [
+    {
+      index: "/Soil Cadmium Content Prediction Model Management",
+      label: "土壤镉含量预测模型管理",
+      icon: DataAnalysis,
+      children: [
+        {
+          index: "/CadmiumPredictionModel",
+          label: "土壤镉含量预测模型",
+          icon: Star,
+        },
+      ],
+    },
+    {
+      index: "/AcidReductionModel",
+      label: "反酸及降酸模型管理",
+      icon: Tools,
+      children: [
+        {
+          index: "/ModelSelection",
+          label: "模型选择",
+          icon: Setting,
+        },
+        {
+          index: "/thres",
+          label: "阈值选择",
+          icon: Histogram,
+        },
+        {
+          index: "/ModelTrain",
+          label: "模型训练",
+          icon: Folder,
+        },
+      ],
+    },
+    {
+      index: "/Rice Cadmium Pollution Risk Model Management",
+      label: "水稻镉污染风险模型管理",
+      icon: Star,
+      children: [
+        { index: "/RiceRiskModel", label: "水稻镉污染风险模型", icon: Star },
+      ],
+    },
+    {
+      index: "/Wheat Cadmium Pollution Risk Model Management",
+      label: "小麦镉污染风险模型管理",
+      icon: Star,
+      children: [
+        { index: "/WheatRiskModel", label: "小麦镉污染风险模型", icon: Star },
+      ],
+    },
+    {
+      index: "/Vegetable Cadmium Pollution Risk Model Management",
+      label: "蔬菜镉污染风险模型管理",
+      icon: Star,
+      children: [
+        {
+          index: "/VegetableRiskModel",
+          label: "蔬菜镉污染风险模型",
+          icon: Star,
+        },
+      ],
+    },
+    
+  ],
+  userManagement: [
+    { index: "/UserManagement", label: "用户信息", icon: Avatar },
+    { index: "/UserRegistration", label: "普通用户", icon: User },
+  ],
+};

+ 20 - 20
src/router/index.ts

@@ -211,73 +211,73 @@ const routes = [
         meta: { title: "种植风险信息统计" },
       },
       {
-        path: "Visualizatio",
-        name: "Visualizatio",
+        path: "soilAcidReductionData",
+        name: "soilAcidReductionData",
         component: () =>
-          import("@/views/Admin/dataManagement/Visualizatio.vue"), // 修复路径
-        meta: { title: "降酸数据管理" },
+          import("@/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidReductionData.vue"), // 修复路径
+        meta: { title: "降酸数据" },
       },
       {
-        path: "Visualization",
-        name: "Visualization",
+        path: "soilAcidificationData",
+        name: "soilAcidificationData",
         component: () =>
-          import("@/views/Admin/dataManagement/Visualization.vue"), // 修复路径
-        meta: { title: "反酸数据管理" },
+          import("@/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidificationData.vue"), // 修复路径
+        meta: { title: "反酸数据" },
       },
       {
         path: "AdminRegionData",
         name: "AdminRegionData",
         component: () =>
-          import("@/views/Admin/dataManagement/AdminRegionData.vue"), // 修复路径
+          import("@/views/Admin/dataManagement/Administrative Area Data Management/AdminRegionData.vue"), // 修复路径
         meta: { title: "行政区域数据" },
       },
       {
         path: "SoilAssessmentUnitData",
         name: "SoilAssessmentUnitData",
         component: () =>
-          import("@/views/Admin/dataManagement/SoilAssessmentUnitData.vue"),
+          import("@/views/Admin/dataManagement/SoilAssessmentUnitData/SoilAssessmentUnitData.vue"),
         meta: { title: "土壤评估单元格数据" },
       },
       {
         path: "SoilHeavyMetalData",
         name: "SoilHeavyMetalData",
         component: () =>
-          import("@/views/Admin/dataManagement/SoilHeavyMetalData.vue"),
+          import("@/views/Admin/dataManagement/Soil Heavy Metal Sampling Data Management/SoilHeavyMetalData.vue"),
         meta: { title: "土壤重金属采集数据" },
       },
       {
         path: "CropHeavyMetalData",
         name: "CropHeavyMetalData",
         component: () =>
-          import("@/views/Admin/dataManagement/CropHeavyMetalData.vue"),
+          import("@/views/Admin/dataManagement/Crop Heavy Metal Sampling Data Management/CropHeavyMetalData.vue"),
         meta: { title: "农作物重金属采集样数据" },
       },
       {
         path: "LandUseTypeData",
         name: "LandUseTypeData",
         component: () =>
-          import("@/views/Admin/dataManagement/LandUseTypeData.vue"),
+          import("@/views/Admin/dataManagement/Land Use Type Data Management/LandUseTypeData.vue"),
         meta: { title: "用地类型数据" },
       },
       {
         path: "SoilAcidificationData",
         name: "SoilAcidificationData",
         component: () =>
-          import("@/views/Admin/dataManagement/SoilAcidificationData.vue"),
+          import("@/views/Admin/dataManagement/Soil Acidification Sampling Data Management/SoilAcidificationData.vue"),
         meta: { title: "土壤酸化采样数据" },
       },
       {
         path: "ClimateInfoData",
         name: "ClimateInfoData",
         component: () =>
-          import("@/views/Admin/dataManagement/ClimateInfoData.vue"),
+          import("@/views/Admin/dataManagement/Climate Information Data Management/ClimateInfoData.vue"),
         meta: { title: "气候信息数据" },
       },
       {
         path: "GeographicEnvInfoData",
         name: "GeographicEnvInfoData",
         component: () =>
-          import("@/views/Admin/dataManagement/GeographicEnvInfoData.vue"),
+          import("@/views/Admin/dataManagement/Geographic Environmental Information Management/GeographicEnvInfoData.vue"),
         meta: { title: "地理环境信息" },
       },
       {
@@ -317,7 +317,7 @@ const routes = [
         path: "CadmiumPredictionModel",
         name: "CadmiumPredictionModel",
         component: () =>
-          import("@/views/Admin/modelManagement/CadmiumPredictionModel.vue"),
+          import("@/views/Admin/modelManagement/Soil Cadmium Content Prediction Model Management/CadmiumPredictionModel.vue"),
         meta: { title: "土壤镉含量预测模型" },
       },
       {
@@ -331,21 +331,21 @@ const routes = [
         path: "RiceRiskModel",
         name: "RiceRiskModel",
         component: () =>
-          import("@/views/Admin/modelManagement/RiceRiskModel.vue"),
+          import("@/views/Admin/modelManagement/Rice Cadmium Pollution Risk Model Management/RiceRiskModel.vue"),
         meta: { title: "水稻镉污染风险模型" },
       },
       {
         path: "WheatRiskModel",
         name: "WheatRiskModel",
         component: () =>
-          import("@/views/Admin/modelManagement/WheatRiskModel.vue"),
+          import("@/views/Admin/Wheat Cadmium Pollution Risk Model Management/WheatRiskModel.vue"),
         meta: { title: "小麦镉污染风险模型" },
       },
       {
         path: "VegetableRiskModel",
         name: "VegetableRiskModel",
         component: () =>
-          import("@/views/Admin/modelManagement/VegetableRiskModel.vue"),
+          import("@/views/Admin/modelManagement/Vegetable Cadmium Pollution Risk Model Management/VegetableRiskModel.vue"),
         meta: { title: "蔬菜镉污染风险模型" },
       },
       {

+ 0 - 0
src/views/Admin/modelManagement/WheatRiskModel.vue → src/views/Admin/Wheat Cadmium Pollution Risk Model Management/WheatRiskModel.vue


+ 0 - 0
src/views/Admin/dataManagement/AdminRegionData.vue → src/views/Admin/dataManagement/Administrative Area Data Management/AdminRegionData.vue


+ 0 - 0
src/views/Admin/dataManagement/ClimateInfoData.vue → src/views/Admin/dataManagement/Climate Information Data Management/ClimateInfoData.vue


+ 0 - 0
src/views/Admin/dataManagement/CropHeavyMetalData.vue → src/views/Admin/dataManagement/Crop Heavy Metal Sampling Data Management/CropHeavyMetalData.vue


+ 0 - 0
src/views/Admin/dataManagement/GeographicEnvInfoData.vue → src/views/Admin/dataManagement/Geographic Environmental Information Management/GeographicEnvInfoData.vue


+ 0 - 0
src/views/Admin/dataManagement/LandUseTypeData.vue → src/views/Admin/dataManagement/Land Use Type Data Management/LandUseTypeData.vue


+ 0 - 0
src/views/Admin/dataManagement/SoilAcidificationData.vue → src/views/Admin/dataManagement/Soil Acidification Sampling Data Management/SoilAcidificationData.vue


+ 0 - 0
src/views/Admin/dataManagement/Visualizatio.vue → src/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidReductionData.vue


+ 0 - 0
src/views/Admin/dataManagement/Visualization.vue → src/views/Admin/dataManagement/Soil Acidification and Acid Reduction Data Management/soilAcidificationData.vue


+ 0 - 0
src/views/Admin/dataManagement/SoilHeavyMetalData.vue → src/views/Admin/dataManagement/Soil Heavy Metal Sampling Data Management/SoilHeavyMetalData.vue


+ 0 - 0
src/views/Admin/dataManagement/SoilAssessmentUnitData.vue → src/views/Admin/dataManagement/SoilAssessmentUnitData/SoilAssessmentUnitData.vue


+ 0 - 0
src/views/Admin/modelManagement/RiceRiskModel.vue → src/views/Admin/modelManagement/Rice Cadmium Pollution Risk Model Management/RiceRiskModel.vue


+ 0 - 0
src/views/Admin/modelManagement/CadmiumPredictionModel.vue → src/views/Admin/modelManagement/Soil Cadmium Content Prediction Model Management/CadmiumPredictionModel.vue


+ 0 - 0
src/views/Admin/modelManagement/VegetableRiskModel.vue → src/views/Admin/modelManagement/Vegetable Cadmium Pollution Risk Model Management/VegetableRiskModel.vue


+ 267 - 119
src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue

@@ -2,35 +2,67 @@
   <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 class="upload-section">
+        <input type="file" ref="fileInput" accept=".csv" @change="handleFileUpload" style="display: none">
+        <el-button class="custom-button" @click="triggerFileUpload">
+          <el-icon class="upload-icon"><Upload /></el-icon>
+          选择CSV文件
+        </el-button>
+        <span v-if="selectedFile" class="file-name">{{ selectedFile.name }}</span>
+        <el-button 
+          class="custom-button" 
+          :loading="isCalculating" 
+          :disabled="!selectedFile" 
+          @click="calculate"
+        >
+        <el-icon class="upload-icon"><Document /></el-icon>  
+        上传并计算
+        </el-button>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="action-buttons">
+        <el-button class="custom-button" :disabled="!mapBlob" @click="exportMap">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出地图</el-button>
+        <el-button class="custom-button" :disabled="!histogramBlob" @click="exportHistogram">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出直方图</el-button>
+        <el-button class="custom-button" :disabled="!tableData.length" @click="exportData">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出数据</el-button>
+      </div>
     </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 class="content-area">
+      <!-- 地图区域 - 修改为横向布局 -->
+      <div class="horizontal-container">
+        <!-- 地图展示 -->
+        <div class="map-section">
+          <h3>作物态Cd预测地图</h3>
+          <div v-if="loadingMap" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>地图加载中...</span>
           </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>
+          <img v-if="mapImageUrl && !loadingMap" :src="mapImageUrl" alt="作物态Cd预测地图" class="map-image">
+          <div v-if="!mapImageUrl && !loadingMap" class="no-data">
+            <el-icon><Picture /></el-icon>
+            <p>暂无地图数据</p>
+          </div>
+        </div>
+        
+        <!-- 直方图展示 -->
+        <div class="histogram-section">
+          <h3>作物态Cd预测直方图</h3>
+          <div v-if="loadingHistogram" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>直方图加载中...</span>
+          </div>
+          <img v-if="histogramImageUrl && !loadingHistogram" :src="histogramImageUrl" alt="作物态Cd预测直方图" class="histogram-image">
+          <div v-if="!histogramImageUrl && !loadingHistogram" class="no-data">
+            <el-icon><Histogram /></el-icon>
+            <p>暂无直方图数据</p>
           </div>
         </div>
       </div>
@@ -53,143 +85,209 @@
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
 import axios from 'axios';
-import { Loading } from '@element-plus/icons-vue';
+import { Loading, Upload, Picture, Histogram, Download, Document } from '@element-plus/icons-vue';
 
 export default {
   name: 'CropCadmiumPrediction',
-  components: { Loading },
+  components: { Loading, Upload, Picture, Histogram, Download, Document },
   data() {
     return {
       isCalculating: false,
       loadingMap: false,
       loadingHistogram: false,
-      result: false,
       tableData: [],
-      mapImageUrl: null,       // 存储地图图片 URL
-      histogramImageUrl: null, // 存储直方图图片 URL
-      mapBlob: null,           // 存储地图原始Blob数据
-      histogramBlob: null      // 存储直方图原始Blob数据
+      mapImageUrl: null,
+      histogramImageUrl: null,
+      mapBlob: null,
+      histogramBlob: null,
+      selectedFile: null,
+      countyName: '乐昌市' // 默认县市名称
     };
   },
+  mounted() {
+    // 组件挂载时获取最新数据
+    this.fetchLatestResults();
+  },
   methods: {
+    // 触发文件选择
+    triggerFileUpload() {
+      this.$refs.fileInput.click();
+    },
+    
+    // 处理文件上传
+    handleFileUpload(event) {
+      const files = event.target.files;
+      if (files && files.length > 0) {
+        this.selectedFile = files[0];
+      } else {
+        this.selectedFile = null;
+      }
+    },
+    
+    // 获取最新结果
+    async fetchLatestResults() {
+      try {
+        this.loadingMap = true;
+        this.loadingHistogram = true;
+        
+        // 获取最新地图
+        await this.fetchLatestMap();
+        
+        // 获取最新直方图
+        await this.fetchLatestHistogram();
+        
+      } catch (error) {
+        console.error('获取最新结果失败:', error);
+        this.$message.error('获取最新结果失败');
+      } finally {
+        this.loadingMap = false;
+        this.loadingHistogram = false;
+      }
+    },
+    
+    // 获取最新地图
+    async fetchLatestMap() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/crop-cd/latest-map/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.mapBlob = response.data;
+        this.mapImageUrl = URL.createObjectURL(this.mapBlob);
+      } catch (error) {
+        console.error('获取最新地图失败:', error);
+        this.$message.warning('获取最新地图失败,请先执行预测');
+      }
+    },
+    
+    // 获取最新直方图
+    async fetchLatestHistogram() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/crop-cd/latest-histogram/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.histogramBlob = response.data;
+        this.histogramImageUrl = URL.createObjectURL(this.histogramBlob);
+      } catch (error) {
+        console.error('获取最新直方图失败:', error);
+        this.$message.warning('获取最新直方图失败,请先执行预测');
+      }
+    },
+    
+    // 上传并计算
     async calculate() {
+      if (!this.selectedFile) {
+        this.$message.warning('请先选择CSV文件');
+        return;
+      }
+      
       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/crop-cd/generate-and-get-map', {}, {
-          responseType: 'blob'
-        });
+        // 创建FormData
+        const formData = new FormData();
+        formData.append('county_name', this.countyName);
+        formData.append('data_file', this.selectedFile);
         
-        // 调用有效态Cd直方图接口
-        const histogramResponse = await axios.post('https://soilgd.com:8000/api/cd-prediction/crop-cd/generate-and-get-histogram', {}, {
-          responseType: 'blob'
-        });
+        // 调用有效态Cd地图接口
+        const mapResponse = await axios.post(
+          'https://soilgd.com:8000/api/cd-prediction/crop-cd/generate-and-get-map',
+          formData,
+          {
+            headers: {
+              'Content-Type': 'multipart/form-data'
+            },
+            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;
+        // 更新后重新获取直方图(因为生成新数据后直方图也会更新)
+        await this.fetchLatestHistogram();
+        
+        // 更新表格数据(示例)
         this.tableData = [
           { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
           { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
         ];
         
+        this.$message.success('计算完成!');
+        
       } catch (error) {
-        console.error('获取地图或直方图失败:', error);
-        this.$message.error('获取预测结果失败,请重试');
+        console.error('计算失败:', error);
+        let errorMessage = '计算失败,请重试';
+        
+        if (error.response) {
+          // 处理不同错误状态码
+          if (error.response.status === 400) {
+            errorMessage = '文件格式错误:' + (error.response.data.detail || '请上传正确的CSV文件');
+          } else if (error.response.status === 404) {
+            errorMessage = '不支持的县市:' + this.countyName;
+          } else if (error.response.status === 500) {
+            errorMessage = '服务器错误:' + (error.response.data.detail || '请稍后重试');
+          }
+        }
+        
+        this.$message.error(errorMessage);
       } 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.download = `${this.countyName}_作物态Cd预测地图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出直方图方法 - 修复:确保链接元素被添加到文档中
+    // 导出直方图
     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.download = `${this.countyName}_作物态Cd预测直方图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出数据方法
+    // 导出数据
     exportData() {
-      // 创建工作簿
-      const workbook = XLSX.utils.book_new();
+      if (!this.tableData.length) {
+        this.$message.warning('暂无数据可导出');
+        return;
+      }
       
-      // 创建数据表
+      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, 'crop-cd-data.xlsx');
+      saveAs(excelData, `${this.countyName}_作物态Cd数据.xlsx`);
     }
   },
   beforeDestroy() {
-    // 组件销毁时释放图片 URL 防止内存泄漏
     if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
     if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
   }
@@ -197,7 +295,6 @@ export default {
 </script>
 
 <style scoped>
-/* 样式保持不变 */
 .container {
   padding: 20px;
   background-color: #f5f7fa;
@@ -206,10 +303,37 @@ export default {
 }
 
 .toolbar {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.upload-section {
   display: flex;
   align-items: center;
+  gap: 15px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid #eee;
+}
+
+.file-name {
+  flex: 1;
+  padding: 0 10px;
+  color: #666;
+  font-size: 14px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.action-buttons {
+  display: flex;
   gap: 10px;
-  margin-bottom: 20px;
 }
 
 .custom-button {
@@ -219,57 +343,54 @@ export default {
   border-radius: 155px;
   padding: 10px 20px;
   font-weight: bold;
+  display: flex;
+  align-items: center;
+}
+
+.upload-icon {
+  margin-right: 5px;
 }
 
 .content-area {
   display: flex;
+  flex-direction: column;
   gap: 20px;
 }
 
-.map-area {
-  flex: 1;
-  min-width: 300px;
-}
-
-.map-container {
+/* 横向布局容器 */
+.horizontal-container {
   display: flex;
-  flex-direction: column;
+  flex-wrap: wrap;
   gap: 20px;
+  width: 100%;
 }
 
 .map-section, .histogram-section {
+  flex: 1;
+  min-width: 300px; /* 最小宽度,确保在小屏幕上也能正常显示 */
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
   position: relative;
+  min-height: 400px;
 }
 
 .map-image, .histogram-image {
   width: 100%;
+  height: 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;
+  width: 100%;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  margin-top: 20px;
 }
 
 .loading-container {
@@ -277,10 +398,25 @@ export default {
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  height: 200px;
+  height: 300px;
   color: #47C3B9;
 }
 
+.no-data {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #999;
+  font-size: 16px;
+}
+
+.no-data .el-icon {
+  font-size: 48px;
+  margin-bottom: 10px;
+}
+
 .loading-icon {
   font-size: 36px;
   margin-bottom: 10px;
@@ -295,4 +431,16 @@ export default {
     transform: rotate(360deg);
   }
 }
+
+/* 响应式布局调整 */
+@media (max-width: 992px) {
+  .horizontal-container {
+    flex-direction: column;
+  }
+  
+  .map-section, .histogram-section {
+    width: 100%;
+    flex: none;
+  }
+}
 </style>

+ 267 - 119
src/views/User/cadmiumPrediction/EffectiveCadmiumPrediction.vue

@@ -2,35 +2,67 @@
   <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 class="upload-section">
+        <input type="file" ref="fileInput" accept=".csv" @change="handleFileUpload" style="display: none">
+        <el-button class="custom-button" @click="triggerFileUpload">
+          <el-icon class="upload-icon"><Upload /></el-icon>
+          选择CSV文件
+        </el-button>
+        <span v-if="selectedFile" class="file-name">{{ selectedFile.name }}</span>
+        <el-button 
+          class="custom-button" 
+          :loading="isCalculating" 
+          :disabled="!selectedFile" 
+          @click="calculate"
+        >
+        <el-icon class="upload-icon"><Document /></el-icon>  
+        上传并计算
+        </el-button>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="action-buttons">
+        <el-button class="custom-button" :disabled="!mapBlob" @click="exportMap">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出地图</el-button>
+        <el-button class="custom-button" :disabled="!histogramBlob" @click="exportHistogram">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出直方图</el-button>
+        <el-button class="custom-button" :disabled="!tableData.length" @click="exportData">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出数据</el-button>
+      </div>
     </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 class="content-area">
+      <!-- 地图区域 - 修改为横向布局 -->
+      <div class="horizontal-container">
+        <!-- 地图展示 -->
+        <div class="map-section">
+          <h3>有效态Cd预测地图</h3>
+          <div v-if="loadingMap" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>地图加载中...</span>
           </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>
+          <img v-if="mapImageUrl && !loadingMap" :src="mapImageUrl" alt="有效态Cd预测地图" class="map-image">
+          <div v-if="!mapImageUrl && !loadingMap" class="no-data">
+            <el-icon><Picture /></el-icon>
+            <p>暂无地图数据</p>
+          </div>
+        </div>
+        
+        <!-- 直方图展示 -->
+        <div class="histogram-section">
+          <h3>有效态Cd预测直方图</h3>
+          <div v-if="loadingHistogram" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>直方图加载中...</span>
+          </div>
+          <img v-if="histogramImageUrl && !loadingHistogram" :src="histogramImageUrl" alt="有效态Cd预测直方图" class="histogram-image">
+          <div v-if="!histogramImageUrl && !loadingHistogram" class="no-data">
+            <el-icon><Histogram /></el-icon>
+            <p>暂无直方图数据</p>
           </div>
         </div>
       </div>
@@ -53,143 +85,209 @@
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
 import axios from 'axios';
-import { Loading } from '@element-plus/icons-vue';
+import { Loading, Upload, Picture, Histogram, Download, Document } from '@element-plus/icons-vue';
 
 export default {
   name: 'EffectiveCadmiumPrediction',
-  components: { Loading },
+  components: { Loading, Upload, Picture, Histogram, Download, Document },
   data() {
     return {
       isCalculating: false,
       loadingMap: false,
       loadingHistogram: false,
-      result: false,
       tableData: [],
-      mapImageUrl: null,       // 存储地图图片 URL
-      histogramImageUrl: null, // 存储直方图图片 URL
-      mapBlob: null,           // 存储地图原始Blob数据
-      histogramBlob: null      // 存储直方图原始Blob数据
+      mapImageUrl: null,
+      histogramImageUrl: null,
+      mapBlob: null,
+      histogramBlob: null,
+      selectedFile: null,
+      countyName: '乐昌市' // 默认县市名称
     };
   },
+  mounted() {
+    // 组件挂载时获取最新数据
+    this.fetchLatestResults();
+  },
   methods: {
+    // 触发文件选择
+    triggerFileUpload() {
+      this.$refs.fileInput.click();
+    },
+    
+    // 处理文件上传
+    handleFileUpload(event) {
+      const files = event.target.files;
+      if (files && files.length > 0) {
+        this.selectedFile = files[0];
+      } else {
+        this.selectedFile = null;
+      }
+    },
+    
+    // 获取最新结果
+    async fetchLatestResults() {
+      try {
+        this.loadingMap = true;
+        this.loadingHistogram = true;
+        
+        // 获取最新地图
+        await this.fetchLatestMap();
+        
+        // 获取最新直方图
+        await this.fetchLatestHistogram();
+        
+      } catch (error) {
+        console.error('获取最新结果失败:', error);
+        this.$message.error('获取最新结果失败');
+      } finally {
+        this.loadingMap = false;
+        this.loadingHistogram = false;
+      }
+    },
+    
+    // 获取最新地图
+    async fetchLatestMap() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/effective-cd/latest-map/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.mapBlob = response.data;
+        this.mapImageUrl = URL.createObjectURL(this.mapBlob);
+      } catch (error) {
+        console.error('获取最新地图失败:', error);
+        this.$message.warning('获取最新地图失败,请先执行预测');
+      }
+    },
+    
+    // 获取最新直方图
+    async fetchLatestHistogram() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/effective-cd/latest-histogram/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.histogramBlob = response.data;
+        this.histogramImageUrl = URL.createObjectURL(this.histogramBlob);
+      } catch (error) {
+        console.error('获取最新直方图失败:', error);
+        this.$message.warning('获取最新直方图失败,请先执行预测');
+      }
+    },
+    
+    // 上传并计算
     async calculate() {
+      if (!this.selectedFile) {
+        this.$message.warning('请先选择CSV文件');
+        return;
+      }
+      
       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'
-        });
+        // 创建FormData
+        const formData = new FormData();
+        formData.append('county_name', this.countyName);
+        formData.append('data_file', this.selectedFile);
         
-        // 调用有效态Cd直方图接口
-        const histogramResponse = await axios.post('https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-histogram', {}, {
-          responseType: 'blob'
-        });
+        // 调用有效态Cd地图接口
+        const mapResponse = await axios.post(
+          'https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-map',
+          formData,
+          {
+            headers: {
+              'Content-Type': 'multipart/form-data'
+            },
+            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;
+        // 更新后重新获取直方图(因为生成新数据后直方图也会更新)
+        await this.fetchLatestHistogram();
+        
+        // 更新表格数据(示例)
         this.tableData = [
           { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
           { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
         ];
         
+        this.$message.success('计算完成!');
+        
       } catch (error) {
-        console.error('获取地图或直方图失败:', error);
-        this.$message.error('获取预测结果失败,请重试');
+        console.error('计算失败:', error);
+        let errorMessage = '计算失败,请重试';
+        
+        if (error.response) {
+          // 处理不同错误状态码
+          if (error.response.status === 400) {
+            errorMessage = '文件格式错误:' + (error.response.data.detail || '请上传正确的CSV文件');
+          } else if (error.response.status === 404) {
+            errorMessage = '不支持的县市:' + this.countyName;
+          } else if (error.response.status === 500) {
+            errorMessage = '服务器错误:' + (error.response.data.detail || '请稍后重试');
+          }
+        }
+        
+        this.$message.error(errorMessage);
       } 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.download = `${this.countyName}_有效态Cd预测地图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出直方图方法 - 修复:确保链接元素被添加到文档中
+    // 导出直方图
     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.download = `${this.countyName}_有效态Cd预测直方图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出数据方法
+    // 导出数据
     exportData() {
-      // 创建工作簿
-      const workbook = XLSX.utils.book_new();
+      if (!this.tableData.length) {
+        this.$message.warning('暂无数据可导出');
+        return;
+      }
       
-      // 创建数据表
+      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');
+      saveAs(excelData, `${this.countyName}_有效态Cd数据.xlsx`);
     }
   },
   beforeDestroy() {
-    // 组件销毁时释放图片 URL 防止内存泄漏
     if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
     if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
   }
@@ -197,7 +295,6 @@ export default {
 </script>
 
 <style scoped>
-/* 样式保持不变 */
 .container {
   padding: 20px;
   background-color: #f5f7fa;
@@ -206,10 +303,37 @@ export default {
 }
 
 .toolbar {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.upload-section {
   display: flex;
   align-items: center;
+  gap: 15px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid #eee;
+}
+
+.file-name {
+  flex: 1;
+  padding: 0 10px;
+  color: #666;
+  font-size: 14px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.action-buttons {
+  display: flex;
   gap: 10px;
-  margin-bottom: 20px;
 }
 
 .custom-button {
@@ -219,57 +343,54 @@ export default {
   border-radius: 155px;
   padding: 10px 20px;
   font-weight: bold;
+  display: flex;
+  align-items: center;
+}
+
+.upload-icon {
+  margin-right: 5px;
 }
 
 .content-area {
   display: flex;
+  flex-direction: column;
   gap: 20px;
 }
 
-.map-area {
-  flex: 1;
-  min-width: 300px;
-}
-
-.map-container {
+/* 横向布局容器 */
+.horizontal-container {
   display: flex;
-  flex-direction: column;
+  flex-wrap: wrap;
   gap: 20px;
+  width: 100%;
 }
 
 .map-section, .histogram-section {
+  flex: 1;
+  min-width: 300px; /* 最小宽度,确保在小屏幕上也能正常显示 */
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
   position: relative;
+  min-height: 400px;
 }
 
 .map-image, .histogram-image {
   width: 100%;
+  height: 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;
+  width: 100%;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  margin-top: 20px;
 }
 
 .loading-container {
@@ -277,10 +398,25 @@ export default {
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  height: 200px;
+  height: 300px;
   color: #47C3B9;
 }
 
+.no-data {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #999;
+  font-size: 16px;
+}
+
+.no-data .el-icon {
+  font-size: 48px;
+  margin-bottom: 10px;
+}
+
 .loading-icon {
   font-size: 36px;
   margin-bottom: 10px;
@@ -295,4 +431,16 @@ export default {
     transform: rotate(360deg);
   }
 }
+
+/* 响应式布局调整 */
+@media (max-width: 992px) {
+  .horizontal-container {
+    flex-direction: column;
+  }
+  
+  .map-section, .histogram-section {
+    width: 100%;
+    flex: none;
+  }
+}
 </style>

+ 267 - 119
src/views/User/cadmiumPrediction/TotalCadmiumPrediction.vue

@@ -2,35 +2,67 @@
   <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 class="upload-section">
+        <input type="file" ref="fileInput" accept=".csv" @change="handleFileUpload" style="display: none">
+        <el-button class="custom-button" @click="triggerFileUpload">
+          <el-icon class="upload-icon"><Upload /></el-icon>
+          选择CSV文件
+        </el-button>
+        <span v-if="selectedFile" class="file-name">{{ selectedFile.name }}</span>
+        <el-button 
+          class="custom-button" 
+          :loading="isCalculating" 
+          :disabled="!selectedFile" 
+          @click="calculate"
+        >
+        <el-icon class="upload-icon"><Document /></el-icon>  
+        上传并计算
+        </el-button>
+      </div>
+      <!-- 操作按钮 -->
+      <div class="action-buttons">
+        <el-button class="custom-button" :disabled="!mapBlob" @click="exportMap">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出地图</el-button>
+        <el-button class="custom-button" :disabled="!histogramBlob" @click="exportHistogram">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出直方图</el-button>
+        <el-button class="custom-button" :disabled="!tableData.length" @click="exportData">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出数据</el-button>
+      </div>
     </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 class="content-area">
+      <!-- 地图区域 - 修改为横向布局 -->
+      <div class="horizontal-container">
+        <!-- 地图展示 -->
+        <div class="map-section">
+          <h3>有效态Cd预测地图</h3>
+          <div v-if="loadingMap" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>地图加载中...</span>
           </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>
+          <img v-if="mapImageUrl && !loadingMap" :src="mapImageUrl" alt="有效态Cd预测地图" class="map-image">
+          <div v-if="!mapImageUrl && !loadingMap" class="no-data">
+            <el-icon><Picture /></el-icon>
+            <p>暂无地图数据</p>
+          </div>
+        </div>
+        
+        <!-- 直方图展示 -->
+        <div class="histogram-section">
+          <h3>有效态Cd预测直方图</h3>
+          <div v-if="loadingHistogram" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>直方图加载中...</span>
+          </div>
+          <img v-if="histogramImageUrl && !loadingHistogram" :src="histogramImageUrl" alt="有效态Cd预测直方图" class="histogram-image">
+          <div v-if="!histogramImageUrl && !loadingHistogram" class="no-data">
+            <el-icon><Histogram /></el-icon>
+            <p>暂无直方图数据</p>
           </div>
         </div>
       </div>
@@ -53,143 +85,209 @@
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
 import axios from 'axios';
-import { Loading } from '@element-plus/icons-vue';
+import { Loading, Upload, Picture, Histogram, Download, Document } from '@element-plus/icons-vue';
 
 export default {
   name: 'EffectiveCadmiumPrediction',
-  components: { Loading },
+  components: { Loading, Upload, Picture, Histogram, Download, Document },
   data() {
     return {
       isCalculating: false,
       loadingMap: false,
       loadingHistogram: false,
-      result: false,
       tableData: [],
-      mapImageUrl: null,       // 存储地图图片 URL
-      histogramImageUrl: null, // 存储直方图图片 URL
-      mapBlob: null,           // 存储地图原始Blob数据
-      histogramBlob: null      // 存储直方图原始Blob数据
+      mapImageUrl: null,
+      histogramImageUrl: null,
+      mapBlob: null,
+      histogramBlob: null,
+      selectedFile: null,
+      countyName: '乐昌市' // 默认县市名称
     };
   },
+  mounted() {
+    // 组件挂载时获取最新数据
+    this.fetchLatestResults();
+  },
   methods: {
+    // 触发文件选择
+    triggerFileUpload() {
+      this.$refs.fileInput.click();
+    },
+    
+    // 处理文件上传
+    handleFileUpload(event) {
+      const files = event.target.files;
+      if (files && files.length > 0) {
+        this.selectedFile = files[0];
+      } else {
+        this.selectedFile = null;
+      }
+    },
+    
+    // 获取最新结果
+    async fetchLatestResults() {
+      try {
+        this.loadingMap = true;
+        this.loadingHistogram = true;
+        
+        // 获取最新地图
+        await this.fetchLatestMap();
+        
+        // 获取最新直方图
+        await this.fetchLatestHistogram();
+        
+      } catch (error) {
+        console.error('获取最新结果失败:', error);
+        this.$message.error('获取最新结果失败');
+      } finally {
+        this.loadingMap = false;
+        this.loadingHistogram = false;
+      }
+    },
+    
+    // 获取最新地图
+    async fetchLatestMap() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/effective-cd/latest-map/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.mapBlob = response.data;
+        this.mapImageUrl = URL.createObjectURL(this.mapBlob);
+      } catch (error) {
+        console.error('获取最新地图失败:', error);
+        this.$message.warning('获取最新地图失败,请先执行预测');
+      }
+    },
+    
+    // 获取最新直方图
+    async fetchLatestHistogram() {
+      try {
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/effective-cd/latest-histogram/${this.countyName}`,
+          { responseType: 'blob' }
+        );
+        
+        this.histogramBlob = response.data;
+        this.histogramImageUrl = URL.createObjectURL(this.histogramBlob);
+      } catch (error) {
+        console.error('获取最新直方图失败:', error);
+        this.$message.warning('获取最新直方图失败,请先执行预测');
+      }
+    },
+    
+    // 上传并计算
     async calculate() {
+      if (!this.selectedFile) {
+        this.$message.warning('请先选择CSV文件');
+        return;
+      }
+      
       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'
-        });
+        // 创建FormData
+        const formData = new FormData();
+        formData.append('county_name', this.countyName);
+        formData.append('data_file', this.selectedFile);
         
-        // 调用有效态Cd直方图接口
-        const histogramResponse = await axios.post('https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-histogram', {}, {
-          responseType: 'blob'
-        });
+        // 调用有效态Cd地图接口
+        const mapResponse = await axios.post(
+          'https://soilgd.com:8000/api/cd-prediction/effective-cd/generate-and-get-map',
+          formData,
+          {
+            headers: {
+              'Content-Type': 'multipart/form-data'
+            },
+            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;
+        // 更新后重新获取直方图(因为生成新数据后直方图也会更新)
+        await this.fetchLatestHistogram();
+        
+        // 更新表格数据(示例)
         this.tableData = [
           { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
           { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
         ];
         
+        this.$message.success('计算完成!');
+        
       } catch (error) {
-        console.error('获取地图或直方图失败:', error);
-        this.$message.error('获取预测结果失败,请重试');
+        console.error('计算失败:', error);
+        let errorMessage = '计算失败,请重试';
+        
+        if (error.response) {
+          // 处理不同错误状态码
+          if (error.response.status === 400) {
+            errorMessage = '文件格式错误:' + (error.response.data.detail || '请上传正确的CSV文件');
+          } else if (error.response.status === 404) {
+            errorMessage = '不支持的县市:' + this.countyName;
+          } else if (error.response.status === 500) {
+            errorMessage = '服务器错误:' + (error.response.data.detail || '请稍后重试');
+          }
+        }
+        
+        this.$message.error(errorMessage);
       } 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.download = `${this.countyName}_有效态Cd预测地图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出直方图方法 - 修复:确保链接元素被添加到文档中
+    // 导出直方图
     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.download = `${this.countyName}_有效态Cd预测直方图.jpg`;
       link.click();
-      
-      // 清理临时URL和链接元素
-      setTimeout(() => {
-        document.body.removeChild(link);
-        URL.revokeObjectURL(link.href);
-      }, 100);
+      URL.revokeObjectURL(link.href);
     },
     
-    // 导出数据方法
+    // 导出数据
     exportData() {
-      // 创建工作簿
-      const workbook = XLSX.utils.book_new();
+      if (!this.tableData.length) {
+        this.$message.warning('暂无数据可导出');
+        return;
+      }
       
-      // 创建数据表
+      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');
+      saveAs(excelData, `${this.countyName}_有效态Cd数据.xlsx`);
     }
   },
   beforeDestroy() {
-    // 组件销毁时释放图片 URL 防止内存泄漏
     if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
     if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
   }
@@ -197,7 +295,6 @@ export default {
 </script>
 
 <style scoped>
-/* 样式保持不变 */
 .container {
   padding: 20px;
   background-color: #f5f7fa;
@@ -206,10 +303,37 @@ export default {
 }
 
 .toolbar {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+  margin-bottom: 20px;
+  padding: 15px;
+  background-color: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.upload-section {
   display: flex;
   align-items: center;
+  gap: 15px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid #eee;
+}
+
+.file-name {
+  flex: 1;
+  padding: 0 10px;
+  color: #666;
+  font-size: 14px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.action-buttons {
+  display: flex;
   gap: 10px;
-  margin-bottom: 20px;
 }
 
 .custom-button {
@@ -219,57 +343,54 @@ export default {
   border-radius: 155px;
   padding: 10px 20px;
   font-weight: bold;
+  display: flex;
+  align-items: center;
+}
+
+.upload-icon {
+  margin-right: 5px;
 }
 
 .content-area {
   display: flex;
+  flex-direction: column;
   gap: 20px;
 }
 
-.map-area {
-  flex: 1;
-  min-width: 300px;
-}
-
-.map-container {
+/* 横向布局容器 */
+.horizontal-container {
   display: flex;
-  flex-direction: column;
+  flex-wrap: wrap;
   gap: 20px;
+  width: 100%;
 }
 
 .map-section, .histogram-section {
+  flex: 1;
+  min-width: 300px; /* 最小宽度,确保在小屏幕上也能正常显示 */
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
   position: relative;
+  min-height: 400px;
 }
 
 .map-image, .histogram-image {
   width: 100%;
+  height: 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;
+  width: 100%;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  margin-top: 20px;
 }
 
 .loading-container {
@@ -277,10 +398,25 @@ export default {
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  height: 200px;
+  height: 300px;
   color: #47C3B9;
 }
 
+.no-data {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #999;
+  font-size: 16px;
+}
+
+.no-data .el-icon {
+  font-size: 48px;
+  margin-bottom: 10px;
+}
+
 .loading-icon {
   font-size: 36px;
   margin-bottom: 10px;
@@ -295,4 +431,16 @@ export default {
     transform: rotate(360deg);
   }
 }
+
+/* 响应式布局调整 */
+@media (max-width: 992px) {
+  .horizontal-container {
+    flex-direction: column;
+  }
+  
+  .map-section, .histogram-section {
+    width: 100%;
+    flex: none;
+  }
+}
 </style>

+ 8 - 1
src/views/User/mapView/tencentMapView.vue

@@ -1551,10 +1551,17 @@ function initMapWithGeoJSON(geojsonData, map) {
     geoJSONLayer.setMap(null);
     geoJSONLayer = null;
   }
+  const filteredData = {
+    ...geojsonData,
+    features: geojsonData.features.filter(feature => 
+      feature.properties['raster_value'] !== null && 
+      feature.properties['raster_value'] !== undefined
+    )
+  };
   // 创建 GeoJSONLayer
   geoJSONLayer = new TMap.value.vector.GeoJSONLayer({
     map: map,
-    data: geojsonData,
+    data: filteredData,
     zIndex: 1,
     polygonStyle: new TMap.value.PolygonStyle({ // 必须用 PolygonStyle 类实例
       color: 'rgba(255, 0, 0, 0.25)', 

+ 2 - 2
src/views/api.vue

@@ -3,12 +3,12 @@
 import axios from 'axios';
 
 export const fetchData = async () => {
-  const response = await axios.post('https://soilgd.com:5000/table', { table: 'Datasets' });
+  const response = await axios.post('https://www.soilgd.com:5000/table', { table: 'Datasets' });
   return response.data.rows;
 };
 
 export const trainAndSaveModel = async (trainData) => {
-  const response = await axios.post('https://soilgd.com:5000/train-and-save-model', trainData);
+  const response = await axios.post('https://www.soilgd.com:5000/train-and-save-model', trainData);
   return response;
 };
 </script>

BIN
structure.txt


+ 0 - 1
tsconfig.app.json

@@ -1,4 +1,3 @@
-// filepath: c:\Users\lhf\OneDrive\Desktop\AcidWeb\tsconfig.app.json
 {
   "extends": "@vue/tsconfig/tsconfig.dom.json",
   "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],

+ 0 - 5
vite.config.ts

@@ -14,11 +14,6 @@ import IconsResolver from 'unplugin-icons/resolver'
 // https://vite.dev/config/
 export default defineConfig({
   plugins: [
-    {
-      "compilerOptions": {
-        "types": ["node"]
-      }
-    },
     vue(),
     vueDevTools(),
     AutoImport({

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است