Forráskód Böngészése

feat: 增加气象详情

lxf 3 napja
szülő
commit
5653a54fb6
2 módosított fájl, 391 hozzáadás és 0 törlés
  1. 7 0
      src/router/globalRoutes.js
  2. 384 0
      src/views/old_mini/weather_detail/index.vue

+ 7 - 0
src/router/globalRoutes.js

@@ -466,4 +466,11 @@ export default [
         meta: { keepAlive: true },
         component: () => import("@/views/old_mini/interactionList/confirmArea.vue"),
     },
+    // 天气详情
+    {
+        path: "/weather_detail",
+        name: "WeatherDetail",
+        meta: { keepAlive: true },
+        component: () => import("@/views/old_mini/weather_detail/index.vue"),
+    },
 ];

+ 384 - 0
src/views/old_mini/weather_detail/index.vue

@@ -0,0 +1,384 @@
+<template>
+  <div class="weather-detail">
+    <custom-header name="气象详情"></custom-header>
+
+    <div class="weather-detail-content">
+    <!-- 顶部农场信息 -->
+    <div class="farm-card">
+        <div class="farm-right">
+            <img class="farm-point" src="@/assets/img/home/farm-point.png" alt="">
+        </div>
+      <div class="farm-left">
+        <div class="farm-name-row">
+          <span class="farm-name">{{ farmInfo.name }}</span>
+          <span class="farm-tag">桂味</span>
+        </div>
+        <div class="farm-address">
+          {{ farmInfo.address }}
+        </div>
+      </div>
+    </div>
+
+    <div class="weather-chart-container">
+        <div class="weather-chart-wrapper">
+            <div 
+                class="weather-chart-slider" 
+                :style="{ transform: `translateX(-${currentChartIndex * 50}%)` }"
+            >
+                <div class="weather-chart-item">
+                    <weather-chart :key="1" class="weather-chart" :weather-data="pastWeatherData"></weather-chart>
+                </div>
+                <div class="weather-chart-item">
+                    <weather-chart :key="2" class="weather-chart" :weather-data="weatherData"></weather-chart>
+                </div>
+            </div>
+        </div>
+        
+        <!-- 左箭头 -->
+        <div 
+            v-if="currentChartIndex > 0" 
+            class="weather-arrow weather-arrow-left"
+            @click="prevChart"
+        >
+            <el-icon><ArrowLeftBold /></el-icon>
+        </div>
+        
+        <!-- 右箭头 -->
+        <div 
+            v-if="currentChartIndex < 1" 
+            class="weather-arrow weather-arrow-right"
+            @click="nextChart"
+        >
+            <el-icon><ArrowRightBold /></el-icon>
+        </div>
+    </div>
+
+    <!-- 指标 Tab -->
+    <div class="tab-row">
+      <div
+        v-for="tab in tabs"
+        :key="tab.key"
+        class="tab-item"
+        :class="{ active: currentTab === tab.key }"
+        @click="currentTab = tab.key"
+      >
+        {{ tab.label }}
+      </div>
+    </div>
+
+    <!-- 风险列表 -->
+    <div class="risk-list">
+      <div
+        v-for="(item, index) in currentRiskList"
+        :key="index"
+        class="risk-item"
+      >
+        <div class="risk-title-row">
+          <span class="risk-title">{{ item.title }}</span>
+          <span class="risk-level">{{ item.level }}</span>
+        </div>
+        <div class="risk-desc">
+          {{ item.desc }}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { computed, ref, onMounted } from "vue";
+import customHeader from "@/components/customHeader.vue";
+import weatherChart from "@/components/weatherChart.vue";
+import { useStore } from "vuex";
+import { ArrowLeftBold, ArrowRightBold } from "@element-plus/icons-vue";
+const store = useStore();
+
+onMounted(() => {
+  getWeatherData();
+});
+
+const farmInfo = ref({
+  name: "从化荔博园合作社",
+  address: "广东省广州市从化区某某街道",
+});
+
+const tabs = [
+  { key: "temp", label: "温度" },
+  { key: "hum", label: "湿度" },
+  { key: "light", label: "光照" },
+];
+
+const currentTab = ref("temp");
+
+// 简单静态示例数据,后续可替换为接口返回
+const riskMap = ref({
+  temp: [
+    {
+      title: "阴雨寡照",
+      level: "一级",
+      desc: "阴雨寡照湿度大,荔枝易染疾病,需加强田间通风防",
+    },
+    {
+      title: "阴雨寡照",
+      level: "一级",
+      desc: "阴雨寡照湿度大,荔枝易染疾病,需加强田间通风防",
+    },
+    {
+      title: "阴雨寡照",
+      level: "一级",
+      desc: "阴雨寡照湿度大,荔枝易染疾病,需加强田间通风防",
+    },
+  ],
+  hum: [],
+  light: [],
+});
+
+const currentRiskList = computed(() => {
+  return riskMap.value[currentTab.value] || [];
+});
+
+const weatherData = ref(null);
+// 过去7天天气数据
+const pastWeatherData = ref(null);
+const currentChartIndex = ref(0); // 当前显示的图表索引,0表示第一个,1表示第二个
+
+// 切换到上一个图表(向左滑动)
+const prevChart = () => {
+  if (currentChartIndex.value > 0) {
+    currentChartIndex.value--;
+  }
+};
+
+// 切换到下一个图表(向右滑动)
+const nextChart = () => {
+  if (currentChartIndex.value < 1) {
+    currentChartIndex.value++;
+  }
+};
+
+// 获取天气数据
+function getWeatherData() {
+    const point = store.state.home.miniUserLocationPoint;
+    if (!point) {
+        return;
+    }
+    VE_API.old_mini_map.get7d({ point }).then(({ data }) => {
+        if (data && data.daily && data.daily.length > 0) {
+            weatherData.value = data;
+            pastWeatherData.value = data;
+        }
+    }).catch(() => {
+        // 获取天气数据失败,使用默认值
+    });
+}
+</script>
+
+<style scoped lang="scss">
+.weather-detail {
+  width: 100%;
+  height: 100vh;
+  overflow: hidden;
+  box-sizing: border-box;
+  background: #F2F4F5;
+
+  .weather-detail-content {
+    height: calc(100% - 40px);
+    overflow: auto;
+    padding: 10px;
+    box-sizing: border-box;
+  }
+}
+
+.farm-card {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 14px;
+  background: #ffffff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
+  margin-bottom: 10px;
+
+  .farm-left {
+    flex: 1;
+    min-width: 0;
+  }
+
+  .farm-name-row {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    margin-bottom: 4px;
+
+    .farm-name {
+      font-size: 16px;
+      font-weight: 600;
+      color: #1d2129;
+    }
+
+    .farm-tag {
+      font-size: 12px;
+      padding: 2px 8px;
+      border-radius: 2px;
+      background: #E8F3FF;
+      color: #2199f8;
+    }
+  }
+
+  .farm-address {
+    font-size: 12px;
+    color: rgba(32, 32, 32, 0.45);
+  }
+
+  .farm-right {
+    margin-right: 10px;
+    font-size: 12px;
+    color: rgba(37, 47, 56, 0.6);
+    flex: none;
+    .farm-point {
+        width: 20px;
+    }
+  }
+}
+
+.weather-chart-container {
+  position: relative;
+  background: #ffffff;
+  border-radius: 8px;
+  padding: 10px;
+  box-shadow: 0 2px 8px rgba(15, 35, 52, 0.06);
+  overflow: hidden;
+
+  .weather-chart-wrapper {
+    width: 100%;
+    overflow: hidden;
+    position: relative;
+  }
+
+  .weather-chart-slider {
+    display: flex;
+    transition: transform 0.3s ease-in-out;
+    width: 200%;
+  }
+
+  .weather-chart-item {
+    flex: 0 0 50%;
+    width: 50%;
+    box-sizing: border-box;
+    padding: 0;
+  }
+
+  .weather-chart {
+    width: 100%;
+    height: 180px;
+  }
+
+  .weather-arrow {
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    width: 16px;
+    height: 42px;
+    background: rgba(0, 0, 0, 0.27);
+    border-radius: 2px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    z-index: 10;
+    transition: background 0.2s;
+
+    &:hover {
+      background: rgba(130, 130, 130, 0.8);
+    }
+
+    &:active {
+      background: rgba(130, 130, 130, 1);
+    }
+
+    .el-icon {
+      color: #ffffff;
+      font-size: 14px;
+    }
+  }
+
+  .weather-arrow-left {
+    left: 0;
+  }
+
+  .weather-arrow-right {
+    right: 0;
+  }
+}
+
+.tab-row {
+  display: inline-flex;
+  gap: 8px;
+  padding: 3px;
+  border-radius: 6px;
+  background: #f2f3f5;
+  margin: 10px 0;
+
+  .tab-item {
+    min-width: 52px;
+    padding: 3px 12px;
+    box-sizing: border-box;
+    text-align: center;
+    font-size: 14px;
+    color: #767676;
+    border-radius: 4px;
+    cursor: pointer;
+    transition: all 0.2s;
+    background: #FFFFFF;
+
+    &.active {
+      background: #2199F8;
+      color: #ffffff;
+      box-shadow: 0 2px 6px rgba(29, 125, 247, 0.45);
+    }
+  }
+}
+
+.risk-list {
+  background: #ffffff;
+  border-radius: 8px;
+  padding: 10px;
+}
+
+.risk-item {
+//   background: #ffffff;
+//   border-radius: 10px;
+//   padding: 10px 12px;
+//   box-shadow: 0 2px 8px rgba(15, 35, 52, 0.03);
+  margin-bottom: 12px;
+
+  .risk-title-row {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+    margin-bottom: 6px;
+
+    .risk-title {
+      font-size: 15px;
+      font-weight: 500;
+      color: #1d2129;
+    }
+
+    .risk-level {
+      font-size: 12px;
+      padding: 2px 10px;
+      border-radius: 2px;
+      background: #E8F3FF;
+      color: #2199F8;
+    }
+  }
+
+  .risk-desc {
+    font-size: 13px;
+    color: #4e5969;
+    line-height: 1.5;
+  }
+}
+</style>
+