WQQ 1 месяц назад
Родитель
Сommit
ea4cf57574

+ 6 - 2
src/router/index.js

@@ -1,19 +1,23 @@
 import { createRouter, createWebHashHistory } from "vue-router"
 
 const map = () => import("@/views/map/index.vue")
+const waterResource = () => import("@/views/waterResource/index.vue")
+
 const router = createRouter({
   history: createWebHashHistory(),
   routes: [
     {
       path: "/",
       redirect: "/map",
-      component: map,
     },
     {
       path: "/map",
       component: map,
     },
-
+    {
+      path: "/waterResource",
+      component: waterResource,
+    },
     {
       path: "/:pathMatch(.*)",
       redirect: "/",

+ 320 - 0
src/views/waterResource/components/CollaborativeProcess.vue

@@ -0,0 +1,320 @@
+<template>
+  <m-card title="协同业务流程" :width="398" :height="450">
+    <div class="collaborative-process">
+      <div class="process-tabs">
+        <div
+          class="tab-item"
+          v-for="(tab, index) in processTabs"
+          :key="index"
+          :class="{ active: activeTab === index }"
+          @click="activeTab = index"
+        >
+          {{ tab.name }}
+        </div>
+      </div>
+      <div class="process-flow">
+        <div class="flow-container">
+          <div
+            class="flow-node"
+            v-for="(node, index) in currentProcessData"
+            :key="index"
+            :class="{ active: index === currentStep }"
+          >
+            <div class="node-thumbnail">
+              <div class="thumbnail-icon">{{ node.icon }}</div>
+            </div>
+            <div class="node-content">
+              <div class="node-title">{{ node.title }}</div>
+              <div class="node-desc">{{ node.desc }}</div>
+            </div>
+            <div class="node-connector" v-if="index < currentProcessData.length - 1">
+              <div class="connector-line"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="process-actions">
+        <button class="action-btn primary" @click="showAnimation">
+          <span>🎬</span> 查看完整流程动画
+        </button>
+        <button class="action-btn secondary" @click="jumpToScene">
+          <span>🔗</span> 跳转会商场景
+        </button>
+      </div>
+    </div>
+  </m-card>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted } from "vue"
+import mCard from "@/components/mCard/index.vue"
+
+const activeTab = ref(0)
+const currentStep = ref(0)
+
+const processTabs = ref([
+  { name: "水旱防御" },
+  { name: "水资源调度" },
+  { name: "水质管控" },
+])
+
+const processData = ref({
+  0: [
+    {
+      icon: "👁‍🗨",
+      title: "联合值班",
+      desc: "24小时值守监控水情变化",
+    },
+    {
+      icon: "🔍",
+      title: "联合巡查",
+      desc: "多部门协同巡检重点区域",
+    },
+    {
+      icon: "💬",
+      title: "联合会商",
+      desc: "多部门在线研判水情,形成调度方案",
+    },
+    {
+      icon: "📡",
+      title: "指令下达",
+      desc: "一键下达调度指令,实时跟踪执行",
+    },
+  ],
+  1: [
+    {
+      icon: "📊",
+      title: "联合值班",
+      desc: "实时监测水资源存量与用量",
+    },
+    {
+      icon: "🗺️",
+      title: "联合巡查",
+      desc: "管网全覆盖巡检,排查异常",
+    },
+    {
+      icon: "🤝",
+      title: "联合会商",
+      desc: "供需平衡分析,制定调度策略",
+    },
+    {
+      icon: "🎯",
+      title: "指令下达",
+      desc: "智能调度指令下达,优化配置",
+    },
+  ],
+  2: [
+    {
+      icon: "🌊",
+      title: "联合值班",
+      desc: "实时监测水质指标变化",
+    },
+    {
+      icon: "🧪",
+      title: "联合巡查",
+      desc: "采样检测重点断面水质状况",
+    },
+    {
+      icon: "📈",
+      title: "联合会商",
+      desc: "水质趋势分析,制定管控措施",
+    },
+    {
+      icon: "⚡",
+      title: "指令下达",
+      desc: "应急处置指令快速下达",
+    },
+  ],
+})
+
+const currentProcessData = computed(() => processData.value[activeTab.value] || [])
+
+let stepInterval = null
+
+onMounted(() => {
+  startStepAnimation()
+})
+
+onUnmounted(() => {
+  if (stepInterval) clearInterval(stepInterval)
+})
+
+function startStepAnimation() {
+  stepInterval = setInterval(() => {
+    currentStep.value = (currentStep.value + 1) % currentProcessData.value.length
+  }, 4000)
+}
+
+function showAnimation() {
+  console.log("查看完整流程动画")
+}
+
+function jumpToScene() {
+  console.log("跳转会商场景")
+}
+</script>
+
+<style lang="scss" scoped>
+.collaborative-process {
+  padding: 12px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  box-sizing: border-box;
+}
+
+.process-tabs {
+  display: flex;
+  gap: 8px;
+  background: rgba(0, 180, 255, 0.05);
+  padding: 6px;
+  border-radius: 6px;
+}
+
+.tab-item {
+  flex: 1;
+  padding: 8px 10px;
+  text-align: center;
+  border-radius: 4px;
+  font-size: 11px;
+  color: rgba(255, 255, 255, 0.6);
+  cursor: pointer;
+  transition: all 0.3s ease;
+  &:hover {
+    color: rgba(255, 255, 255, 0.9);
+    background: rgba(48, 220, 255, 0.1);
+  }
+  &.active {
+    background: linear-gradient(135deg, #30DCFF, #00BFFF);
+    color: #fff;
+    box-shadow: 0 0 15px rgba(48, 220, 255, 0.4);
+  }
+}
+
+.process-flow {
+  flex: 1;
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 6px;
+  padding: 12px;
+  overflow-y: auto;
+}
+
+.flow-container {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.flow-node {
+  display: flex;
+  align-items: flex-start;
+  gap: 10px;
+  padding: 10px;
+  background: rgba(48, 220, 255, 0.05);
+  border-radius: 6px;
+  border: 1px solid rgba(48, 220, 255, 0.1);
+  transition: all 0.3s ease;
+  position: relative;
+  &.active {
+    background: rgba(48, 220, 255, 0.15);
+    border-color: rgba(48, 220, 255, 0.5);
+    box-shadow: 0 0 10px rgba(48, 220, 255, 0.2);
+    .node-thumbnail {
+      background: linear-gradient(135deg, #30DCFF, #00BFFF);
+      box-shadow: 0 0 15px rgba(48, 220, 255, 0.5);
+    }
+    .node-title {
+      color: #30DCFF;
+    }
+  }
+}
+
+.node-thumbnail {
+  width: 40px;
+  height: 40px;
+  border-radius: 8px;
+  background: rgba(255, 255, 255, 0.1);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  transition: all 0.3s ease;
+  .thumbnail-icon {
+    font-size: 20px;
+  }
+}
+
+.node-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.node-title {
+  font-size: 13px;
+  font-weight: 600;
+  color: rgba(255, 255, 255, 0.9);
+  margin-bottom: 4px;
+  transition: all 0.3s ease;
+}
+
+.node-desc {
+  font-size: 11px;
+  color: rgba(255, 255, 255, 0.5);
+  line-height: 1.4;
+}
+
+.node-connector {
+  position: absolute;
+  left: 21px;
+  bottom: -12px;
+  width: 2px;
+  height: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  .connector-line {
+    width: 2px;
+    height: 100%;
+    background: linear-gradient(to bottom, rgba(48, 220, 255, 0.5), rgba(48, 220, 255, 0.1));
+  }
+}
+
+.process-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.action-btn {
+  flex: 1;
+  padding: 10px 12px;
+  border-radius: 6px;
+  border: none;
+  cursor: pointer;
+  font-size: 11px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+  transition: all 0.3s ease;
+  &.primary {
+    background: linear-gradient(135deg, #30DCFF, #00BFFF);
+    color: #fff;
+    &:hover {
+      box-shadow: 0 0 15px rgba(48, 220, 255, 0.5);
+      transform: translateY(-2px);
+    }
+  }
+  &.secondary {
+    background: rgba(48, 220, 255, 0.15);
+    border: 1px solid rgba(48, 220, 255, 0.4);
+    color: #30DCFF;
+    &:hover {
+      background: rgba(48, 220, 255, 0.25);
+    }
+  }
+  span {
+    font-size: 14px;
+  }
+}
+</style>

+ 259 - 0
src/views/waterResource/components/DemonstrationBase.vue

@@ -0,0 +1,259 @@
+<template>
+  <m-card title="示范基地全景" :width="398" :height="450">
+    <div class="demonstration-base">
+      <div class="base-tabs">
+        <div
+          class="tab-item"
+          v-for="(tab, index) in baseTabs"
+          :key="index"
+          :class="{ active: activeTab === index }"
+          @click="activeTab = index"
+        >
+          {{ tab.name }}
+        </div>
+      </div>
+      <div class="base-detail">
+        <div class="detail-thumbnail">
+          <div class="thumbnail-icon">{{ currentTabData.icon }}</div>
+          <div class="thumbnail-overlay"></div>
+        </div>
+        <div class="detail-info">
+          <div class="info-title">{{ currentTabData.title }}</div>
+          <div class="info-desc">{{ currentTabData.desc }}</div>
+          <div class="info-partner">
+            <span class="partner-label">合作单位:</span>
+            <span class="partner-value">{{ currentTabData.partner }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="base-cycle">
+        <div class="cycle-title">产学研闭环流程</div>
+        <div class="cycle-container">
+          <div class="cycle-item" v-for="(item, index) in cycleData" :key="index">
+            <div class="cycle-icon">{{ item.icon }}</div>
+            <div class="cycle-label">{{ item.label }}</div>
+            <div class="cycle-desc">{{ item.desc }}</div>
+            <div class="cycle-arrow" v-if="index < cycleData.length - 1">→</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </m-card>
+</template>
+
+<script setup>
+import { ref, computed } from "vue"
+import mCard from "@/components/mCard/index.vue"
+
+const activeTab = ref(0)
+
+const baseTabs = ref([
+  { name: "实习实训区" },
+  { name: "技术研发区" },
+  { name: "决策实验室" },
+])
+
+const tabData = ref([
+  {
+    icon: "🎓",
+    title: "实习实训区",
+    desc: "为高校师生提供实践实训平台,开展水文监测、水质分析等专业技能培训,培养专业技术人才。",
+    partner: "河海大学、南京大学",
+  },
+  {
+    icon: "🔬",
+    title: "技术研发区",
+    desc: "联合高校研发面源污染预警模型,开展水文监测新技术、新设备的研发与测试。",
+    partner: "河海大学、清华大学",
+  },
+  {
+    icon: "🧠",
+    title: "决策实验室",
+    desc: "基于数字孪生技术的仿真决策平台,开展水旱灾害防御、水资源调度模拟推演。",
+    partner: "中科院地理所",
+  },
+])
+
+const currentTabData = computed(() => tabData.value[activeTab.value] || tabData.value[0])
+
+const cycleData = ref([
+  { icon: "📚", label: "学", desc: "高校师生实训" },
+  { icon: "🔬", label: "研", desc: "联合攻关模型" },
+  { icon: "🏭", label: "产", desc: "技术产品化" },
+  { icon: "💡", label: "用", desc: "业务落地应用" },
+])
+</script>
+
+<style lang="scss" scoped>
+.demonstration-base {
+  padding: 12px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  box-sizing: border-box;
+}
+
+.base-tabs {
+  display: flex;
+  gap: 8px;
+  background: rgba(0, 180, 255, 0.05);
+  padding: 6px;
+  border-radius: 6px;
+}
+
+.tab-item {
+  flex: 1;
+  padding: 8px 10px;
+  text-align: center;
+  border-radius: 4px;
+  font-size: 10px;
+  color: rgba(255, 255, 255, 0.6);
+  cursor: pointer;
+  transition: all 0.3s ease;
+  &:hover {
+    color: rgba(255, 255, 255, 0.9);
+    background: rgba(48, 220, 255, 0.1);
+  }
+  &.active {
+    background: linear-gradient(135deg, #30DCFF, #00BFFF);
+    color: #fff;
+    box-shadow: 0 0 15px rgba(48, 220, 255, 0.4);
+  }
+}
+
+.base-detail {
+  flex: 1;
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 6px;
+  padding: 12px;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.detail-thumbnail {
+  height: 65px;
+  border-radius: 6px;
+  background: linear-gradient(135deg, rgba(48, 220, 255, 0.1) 0%, rgba(67, 233, 123, 0.1) 100%);
+  border: 1px solid rgba(48, 220, 255, 0.2);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  overflow: hidden;
+  .thumbnail-icon {
+    font-size: 36px;
+    z-index: 1;
+  }
+  .thumbnail-overlay {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: 
+      radial-gradient(circle at 30% 30%, rgba(48, 220, 255, 0.2) 0%, transparent 50%),
+      radial-gradient(circle at 70% 70%, rgba(67, 233, 123, 0.15) 0%, transparent 50%);
+  }
+}
+
+.detail-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.info-title {
+  font-size: 12px;
+  font-weight: 600;
+  color: #30DCFF;
+}
+
+.info-desc {
+  font-size: 10px;
+  color: rgba(255, 255, 255, 0.7);
+  line-height: 1.4;
+  flex: 1;
+}
+
+.info-partner {
+  background: rgba(48, 220, 255, 0.1);
+  border-radius: 4px;
+  padding: 6px 8px;
+  font-size: 10px;
+  .partner-label {
+    color: rgba(255, 255, 255, 0.5);
+  }
+  .partner-value {
+    color: #43e97b;
+    font-weight: 500;
+  }
+}
+
+.base-cycle {
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 8px;
+  padding: 10px;
+}
+
+.cycle-title {
+  font-size: 11px;
+  color: #30DCFF;
+  font-weight: 600;
+  text-align: center;
+  margin-bottom: 10px;
+}
+
+.cycle-container {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 5px;
+}
+
+.cycle-item {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  text-align: center;
+  position: relative;
+}
+
+.cycle-icon {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+  background: linear-gradient(135deg, rgba(48, 220, 255, 0.2), rgba(67, 233, 123, 0.2));
+  border: 2px solid rgba(48, 220, 255, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 16px;
+  margin-bottom: 4px;
+}
+
+.cycle-label {
+  font-size: 12px;
+  font-weight: 600;
+  color: #30DCFF;
+  margin-bottom: 2px;
+}
+
+.cycle-desc {
+  font-size: 9px;
+  color: rgba(255, 255, 255, 0.5);
+  line-height: 1.2;
+}
+
+.cycle-arrow {
+  position: absolute;
+  right: -10px;
+  top: 12px;
+  color: rgba(48, 220, 255, 0.6);
+  font-size: 12px;
+  font-weight: bold;
+}
+</style>

+ 401 - 0
src/views/waterResource/components/IntegrationEffect.vue

@@ -0,0 +1,401 @@
+<template>
+  <m-card title="融合成效数据" :width="398" :height="450">
+    <div class="integration-effect">
+      <div class="effect-tabs">
+        <div
+          class="tab-item"
+          v-for="(tab, index) in effectTabs"
+          :key="index"
+          :class="{ active: activeTab === index }"
+          @click="activeTab = index"
+        >
+          {{ tab.name }}
+        </div>
+      </div>
+      <div class="effect-chart">
+        <div v-if="activeTab === 0" class="chart-line">
+          <div class="chart-title">应急响应速度提升 30%</div>
+          <div class="line-container">
+            <div class="line-item">
+              <div class="line-label">融合前</div>
+              <div class="line-bar-wrapper">
+                <div class="line-bar before" style="width: 60%"></div>
+              </div>
+              <div class="line-value">40分钟</div>
+            </div>
+            <div class="line-item">
+              <div class="line-label">融合后</div>
+              <div class="line-bar-wrapper">
+                <div class="line-bar after" style="width: 90%"></div>
+              </div>
+              <div class="line-value">26分钟</div>
+            </div>
+          </div>
+        </div>
+        <div v-if="activeTab === 1" class="chart-bar">
+          <div class="chart-title">成本降低成效</div>
+          <div class="bar-container">
+            <div class="bar-item">
+              <div class="bar-value">-50%</div>
+              <div class="bar-fill" style="height: 70%"></div>
+              <div class="bar-label">数据共享耗时</div>
+            </div>
+            <div class="bar-item">
+              <div class="bar-value">-20%</div>
+              <div class="bar-fill" style="height: 45%"></div>
+              <div class="bar-label">运维成本</div>
+            </div>
+          </div>
+        </div>
+        <div v-if="activeTab === 2" class="chart-ring">
+          <div class="chart-title">决策精准度提升</div>
+          <div class="ring-container">
+            <div class="ring-item">
+              <div class="ring-wrapper">
+                <svg width="80" height="80" viewBox="0 0 80 80">
+                  <circle cx="40" cy="40" r="35" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="6" />
+                  <circle cx="40" cy="40" r="35" fill="none" stroke="url(#gradient1)" stroke-width="6" stroke-linecap="round"
+                    stroke-dasharray="220" stroke-dashoffset="66" transform="rotate(-90 40 40)" />
+                  <defs>
+                    <linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="0%">
+                      <stop offset="0%" stop-color="#30DCFF" />
+                      <stop offset="100%" stop-color="#43e97b" />
+                    </linearGradient>
+                  </defs>
+                </svg>
+                <div class="ring-text">
+                  <span class="percent">+40%</span>
+                  <span class="label">调度命中率</span>
+                </div>
+              </div>
+            </div>
+            <div class="ring-item">
+              <div class="ring-wrapper">
+                <svg width="80" height="80" viewBox="0 0 80 80">
+                  <circle cx="40" cy="40" r="35" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="6" />
+                  <circle cx="40" cy="40" r="35" fill="none" stroke="url(#gradient2)" stroke-width="6" stroke-linecap="round"
+                    stroke-dasharray="220" stroke-dashoffset="110" transform="rotate(-90 40 40)" />
+                  <defs>
+                    <linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="0%">
+                      <stop offset="0%" stop-color="#ff6b6b" />
+                      <stop offset="100%" stop-color="#ffd93d" />
+                    </linearGradient>
+                  </defs>
+                </svg>
+                <div class="ring-text">
+                  <span class="percent down">-25%</span>
+                  <span class="label">内涝误报率</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="effect-compare">
+        <div class="compare-title">融合前后对比</div>
+        <div class="compare-container">
+          <div class="compare-card before">
+            <div class="card-label">融合前</div>
+            <div class="card-items">
+              <div class="card-item">
+                <span class="item-label">应急响应</span>
+                <span class="item-value">40分钟</span>
+              </div>
+              <div class="card-item">
+                <span class="item-label">数据共享</span>
+                <span class="item-value">2小时</span>
+              </div>
+              <div class="card-item">
+                <span class="item-label">调度精准</span>
+                <span class="item-value">60%</span>
+              </div>
+            </div>
+          </div>
+          <div class="compare-arrow">→</div>
+          <div class="compare-card after">
+            <div class="card-label">融合后</div>
+            <div class="card-items">
+              <div class="card-item">
+                <span class="item-label">应急响应</span>
+                <span class="item-value highlight">26分钟</span>
+              </div>
+              <div class="card-item">
+                <span class="item-label">数据共享</span>
+                <span class="item-value highlight">1小时</span>
+              </div>
+              <div class="card-item">
+                <span class="item-label">调度精准</span>
+                <span class="item-value highlight">100%</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </m-card>
+</template>
+
+<script setup>
+import { ref } from "vue"
+import mCard from "@/components/mCard/index.vue"
+
+const activeTab = ref(0)
+
+const effectTabs = ref([
+  { name: "效率提升" },
+  { name: "成本降低" },
+  { name: "决策精准" },
+])
+</script>
+
+<style lang="scss" scoped>
+.integration-effect {
+  padding: 12px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  box-sizing: border-box;
+}
+
+.effect-tabs {
+  display: flex;
+  gap: 8px;
+  background: rgba(0, 180, 255, 0.05);
+  padding: 6px;
+  border-radius: 6px;
+}
+
+.tab-item {
+  flex: 1;
+  padding: 8px 10px;
+  text-align: center;
+  border-radius: 4px;
+  font-size: 10px;
+  color: rgba(255, 255, 255, 0.6);
+  cursor: pointer;
+  transition: all 0.3s ease;
+  &:hover {
+    color: rgba(255, 255, 255, 0.9);
+    background: rgba(48, 220, 255, 0.1);
+  }
+  &.active {
+    background: linear-gradient(135deg, #30DCFF, #00BFFF);
+    color: #fff;
+    box-shadow: 0 0 15px rgba(48, 220, 255, 0.4);
+  }
+}
+
+.effect-chart {
+  flex: 1;
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 6px;
+  padding: 12px;
+  display: flex;
+  flex-direction: column;
+}
+
+.chart-title {
+  font-size: 11px;
+  color: #30DCFF;
+  font-weight: 600;
+  text-align: center;
+  margin-bottom: 12px;
+}
+
+.chart-line .line-container {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.line-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.line-label {
+  width: 50px;
+  font-size: 10px;
+  color: rgba(255, 255, 255, 0.7);
+}
+
+.line-bar-wrapper {
+  flex: 1;
+  height: 18px;
+  background: rgba(255, 255, 255, 0.1);
+  border-radius: 9px;
+  overflow: hidden;
+}
+
+.line-bar {
+  height: 100%;
+  border-radius: 10px;
+  transition: width 1.5s ease;
+  &.before {
+    background: linear-gradient(90deg, rgba(255, 107, 107, 0.8), rgba(255, 217, 61, 0.8));
+  }
+  &.after {
+    background: linear-gradient(90deg, #30DCFF, #43e97b);
+    box-shadow: 0 0 10px rgba(48, 220, 255, 0.4);
+  }
+}
+
+.line-value {
+  width: 50px;
+  font-size: 12px;
+  font-weight: 600;
+  color: #30DCFF;
+  text-align: right;
+}
+
+.chart-bar .bar-container {
+  display: flex;
+  justify-content: space-around;
+  align-items: flex-end;
+  flex: 1;
+  padding: 0 20px;
+}
+
+.bar-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 8px;
+}
+
+.bar-value {
+  font-size: 14px;
+  font-weight: 700;
+  color: #ff6b6b;
+}
+
+.bar-fill {
+  width: 40px;
+  background: linear-gradient(to top, #30DCFF, #43e97b);
+  border-radius: 5px 5px 0 0;
+  transition: height 1.5s ease;
+}
+
+.bar-label {
+  font-size: 10px;
+  color: rgba(255, 255, 255, 0.6);
+}
+
+.chart-ring .ring-container {
+  display: flex;
+  justify-content: space-around;
+  flex: 1;
+}
+
+.ring-item {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.ring-wrapper {
+  position: relative;
+  width: 80px;
+  height: 80px;
+}
+
+.ring-text {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  text-align: center;
+  .percent {
+    display: block;
+    font-size: 14px;
+    font-weight: 700;
+    color: #30DCFF;
+    &.down {
+      color: #ff6b6b;
+    }
+  }
+  .label {
+    display: block;
+    font-size: 9px;
+    color: rgba(255, 255, 255, 0.6);
+    margin-top: 2px;
+  }
+}
+
+.effect-compare {
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 8px;
+  padding: 10px;
+}
+
+.compare-title {
+  font-size: 11px;
+  color: #30DCFF;
+  font-weight: 600;
+  text-align: center;
+  margin-bottom: 10px;
+}
+
+.compare-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 10px;
+}
+
+.compare-card {
+  flex: 1;
+  background: rgba(255, 255, 255, 0.05);
+  border-radius: 6px;
+  padding: 8px;
+  &.before {
+    border: 1px solid rgba(255, 107, 107, 0.3);
+    .card-label {
+      color: #ff6b6b;
+    }
+  }
+  &.after {
+    border: 1px solid rgba(48, 220, 255, 0.3);
+    .card-label {
+      color: #30DCFF;
+    }
+  }
+}
+
+.card-label {
+  font-size: 10px;
+  font-weight: 600;
+  text-align: center;
+  margin-bottom: 6px;
+}
+
+.card-items {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.card-item {
+  display: flex;
+  justify-content: space-between;
+  font-size: 10px;
+  .item-label {
+    color: rgba(255, 255, 255, 0.5);
+  }
+  .item-value {
+    color: rgba(255, 255, 255, 0.8);
+    &.highlight {
+      color: #30DCFF;
+      font-weight: 600;
+    }
+  }
+}
+
+.compare-arrow {
+  font-size: 18px;
+  color: #30DCFF;
+  font-weight: bold;
+}
+</style>

+ 304 - 0
src/views/waterResource/components/SystemIntegration.vue

@@ -0,0 +1,304 @@
+<template>
+  <m-card title="机制体制融合" :width="398" :height="450">
+    <div class="system-integration">
+      <div class="core-indicator">
+        <div class="indicator-main">
+          <span class="main-value">92</span>
+          <span class="main-unit">%</span>
+        </div>
+        <div class="indicator-label">协同工作考核优秀率</div>
+      </div>
+      <div class="stats-grid">
+        <div class="stat-item" v-for="(item, index) in statsData" :key="index">
+          <div class="stat-value">{{ item.value }}</div>
+          <div class="stat-label">{{ item.label }}</div>
+        </div>
+      </div>
+      <div class="architecture-flow">
+        <div class="architecture-title">架构体系</div>
+        <div class="architecture-chain">
+          <div class="arch-node">
+            <div class="node-icon">🎯</div>
+            <div class="node-label">融合发展委员会</div>
+          </div>
+          <div class="arch-arrow">→</div>
+          <div class="arch-node">
+            <div class="node-icon">👥</div>
+            <div class="node-label">项目混编团队</div>
+          </div>
+          <div class="arch-arrow">→</div>
+          <div class="arch-node">
+            <div class="node-icon">🏢</div>
+            <div class="node-label">基层工作组</div>
+          </div>
+        </div>
+        <div class="flow-title">运作流程</div>
+        <div class="flow-chain">
+          <div class="flow-item" v-for="(item, index) in flowData" :key="index" :class="{ active: index === currentStep }">
+            <div class="flow-number">{{ index + 1 }}</div>
+            <div class="flow-label">{{ item.label }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="action-buttons">
+        <button class="action-btn primary" @click="showTeamDetail">
+          <span>📋</span> 查看混编团队详情
+        </button>
+        <button class="action-btn secondary" @click="showOfficeScene">
+          <span>🏢</span> 查看办公场景
+        </button>
+      </div>
+    </div>
+  </m-card>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted } from "vue"
+import mCard from "@/components/mCard/index.vue"
+
+const currentStep = ref(1)
+
+const statsData = ref([
+  { value: "132", label: "共同决策事项" },
+  { value: "4", label: "混编共建团队" },
+  { value: "365", label: "联合值班(天)" },
+  { value: "156", label: "共派监测人员" },
+])
+
+const flowData = ref([
+  { label: "统一派遣" },
+  { label: "统一管理" },
+  { label: "统一考核" },
+])
+
+let stepInterval = null
+
+onMounted(() => {
+  startStepAnimation()
+})
+
+onUnmounted(() => {
+  if (stepInterval) clearInterval(stepInterval)
+})
+
+function startStepAnimation() {
+  stepInterval = setInterval(() => {
+    currentStep.value = (currentStep.value + 1) % flowData.value.length
+  }, 3000)
+}
+
+function showTeamDetail() {
+  console.log("查看混编团队详情")
+}
+
+function showOfficeScene() {
+  console.log("查看办公场景")
+}
+</script>
+
+<style lang="scss" scoped>
+.system-integration {
+  padding: 12px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  box-sizing: border-box;
+}
+
+.core-indicator {
+  text-align: center;
+  padding: 12px;
+  background: linear-gradient(135deg, rgba(48, 220, 255, 0.1) 0%, rgba(0, 191, 255, 0.05) 100%);
+  border-radius: 8px;
+  border: 1px solid rgba(48, 220, 255, 0.3);
+}
+
+.indicator-main {
+  margin-bottom: 5px;
+}
+
+.main-value {
+  font-size: 40px;
+  font-weight: 700;
+  color: #30DCFF;
+  font-family: "D-DIN";
+  text-shadow: 0 0 20px rgba(48, 220, 255, 0.5);
+}
+
+.main-unit {
+  font-size: 20px;
+  color: rgba(48, 220, 255, 0.8);
+  font-weight: 600;
+}
+
+.indicator-label {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 12px;
+  letter-spacing: 1px;
+}
+
+.stats-grid {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 6px;
+}
+
+.stat-item {
+  background: rgba(0, 180, 255, 0.08);
+  border: 1px solid rgba(0, 180, 255, 0.2);
+  border-radius: 4px;
+  padding: 6px 4px;
+  text-align: center;
+  transition: all 0.3s ease;
+  &:hover {
+    background: rgba(0, 180, 255, 0.15);
+    border-color: rgba(48, 220, 255, 0.5);
+  }
+}
+
+.stat-value {
+  font-size: 16px;
+  font-weight: 700;
+  color: #30DCFF;
+  font-family: "D-DIN";
+  margin-bottom: 2px;
+}
+
+.stat-label {
+  font-size: 9px;
+  color: rgba(255, 255, 255, 0.6);
+  line-height: 1.2;
+}
+
+.architecture-flow {
+  flex: 1;
+  background: rgba(0, 180, 255, 0.05);
+  border-radius: 6px;
+  padding: 8px;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+
+.architecture-title,
+.flow-title {
+  font-size: 11px;
+  color: #30DCFF;
+  font-weight: 600;
+  padding-bottom: 4px;
+  border-bottom: 1px solid rgba(48, 220, 255, 0.2);
+}
+
+.architecture-chain {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 4px;
+  padding: 6px 0;
+}
+
+.arch-node {
+  background: rgba(48, 220, 255, 0.15);
+  border: 1px solid rgba(48, 220, 255, 0.4);
+  border-radius: 6px;
+  padding: 6px 8px;
+  text-align: center;
+  min-width: 80px;
+}
+
+.node-icon {
+  font-size: 16px;
+  margin-bottom: 2px;
+}
+
+.node-label {
+  font-size: 9px;
+  color: rgba(255, 255, 255, 0.9);
+}
+
+.arch-arrow {
+  color: #30DCFF;
+  font-size: 14px;
+  font-weight: bold;
+}
+
+.flow-chain {
+  display: flex;
+  justify-content: space-around;
+  padding: 6px 0;
+}
+
+.flow-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 4px;
+  opacity: 0.5;
+  transition: all 0.3s ease;
+  &.active {
+    opacity: 1;
+    .flow-number {
+      background: linear-gradient(135deg, #30DCFF, #00BFFF);
+      box-shadow: 0 0 15px rgba(48, 220, 255, 0.6);
+    }
+  }
+}
+
+.flow-number {
+  width: 20px;
+  height: 20px;
+  border-radius: 50%;
+  background: rgba(255, 255, 255, 0.2);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 11px;
+  font-weight: 700;
+  color: #fff;
+  transition: all 0.3s ease;
+}
+
+.flow-label {
+  font-size: 11px;
+  color: rgba(255, 255, 255, 0.8);
+}
+
+.action-buttons {
+  display: flex;
+  gap: 10px;
+}
+
+.action-btn {
+  flex: 1;
+  padding: 10px 12px;
+  border-radius: 6px;
+  border: none;
+  cursor: pointer;
+  font-size: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+  transition: all 0.3s ease;
+  &.primary {
+    background: linear-gradient(135deg, #30DCFF, #00BFFF);
+    color: #fff;
+    &:hover {
+      box-shadow: 0 0 15px rgba(48, 220, 255, 0.5);
+      transform: translateY(-2px);
+    }
+  }
+  &.secondary {
+    background: rgba(48, 220, 255, 0.15);
+    border: 1px solid rgba(48, 220, 255, 0.4);
+    color: #30DCFF;
+    &:hover {
+      background: rgba(48, 220, 255, 0.25);
+    }
+  }
+  span {
+    font-size: 14px;
+  }
+}
+</style>

+ 288 - 0
src/views/waterResource/index.vue

@@ -0,0 +1,288 @@
+<template>
+  <div class="water-resource-page">
+    <mapScene ref="mapSceneRef"></mapScene>
+    <div class="water-resource-wrap" id="water-resource">
+      <m-header title="昆山水务水文系统" sub-text="Hydrological Visualization System">
+        <template v-slot:left>
+          <div class="m-header-weather"><span>小雪</span><span>-4℃</span></div>
+        </template>
+        <template v-slot:right>
+          <div class="m-header-date"><span>2025-12-11</span><span>17:53:16</span></div>
+        </template>
+      </m-header>
+      <div class="top-menu">
+        <mMenu :default-active="state.activeIndex" @select="handleMenuSelect">
+          <mMenuItem index="1">流域总览</mMenuItem>
+          <mMenuItem index="2">水质监测</mMenuItem>
+          <mMenuItem index="3">水文数据</mMenuItem>
+          <div class="top-menu-mid-space"></div>
+          <mMenuItem index="4">防洪预警</mMenuItem>
+          <mMenuItem index="5">水资源管理</mMenuItem>
+          <mMenuItem index="6">系统设置</mMenuItem>
+        </mMenu>
+      </div>
+      <div class="left-column">
+        <div class="left-column-3d">
+          <div class="module-card">
+            <SystemIntegration />
+          </div>
+          <div class="module-card">
+            <IntegrationEffect />
+          </div>
+        </div>
+      </div>
+      <div class="right-column">
+        <div class="right-column-3d">
+          <div class="module-card">
+            <CollaborativeProcess />
+          </div>
+          <div class="module-card">
+            <DemonstrationBase />
+          </div>
+        </div>
+      </div>
+      <div class="water-resource-left-zsline"></div>
+      <div class="water-resource-right-zsline"></div>
+    </div>
+    <div class="loading">
+      <div class="loading-text">
+        <span style="--index: 1">L</span>
+        <span style="--index: 2">O</span>
+        <span style="--index: 3">A</span>
+        <span style="--index: 4">D</span>
+        <span style="--index: 5">I</span>
+        <span style="--index: 6">N</span>
+        <span style="--index: 7">G</span>
+      </div>
+      <div class="loading-progress">
+        <span class="value">{{ state.progress }}</span>
+        <span class="unit">%</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { shallowRef, ref, reactive, onMounted, onBeforeUnmount } from "vue"
+import { useRouter } from "vue-router"
+import mapScene from "@/views/map/map.vue"
+import mHeader from "@/components/mHeader/index.vue"
+import mMenu from "@/components/mMenu/index.vue"
+import mMenuItem from "@/components/mMenuItem/index.vue"
+import SystemIntegration from "./components/SystemIntegration.vue"
+import CollaborativeProcess from "./components/CollaborativeProcess.vue"
+import IntegrationEffect from "./components/IntegrationEffect.vue"
+import DemonstrationBase from "./components/DemonstrationBase.vue"
+import { Assets } from "@/views/map/assets.js"
+import emitter from "@/utils/emitter"
+import gsap from "gsap"
+import autofit from "autofit.js"
+
+const router = useRouter()
+const assets = shallowRef(null)
+const assetsInstance = shallowRef(null)
+const mapSceneRef = ref(null)
+const state = reactive({
+  progress: 0,
+  activeIndex: "5",
+})
+
+onMounted(() => {
+  emitter.$on("mapPlayComplete", handleMapPlayComplete)
+  assets.value = autofit.init({
+    dh: 1080,
+    dw: 1920,
+    el: "#water-resource",
+    resize: true,
+  })
+  initAssets(async () => {
+    emitter.$emit("loadMap", assetsInstance.value)
+    await hideLoading()
+    mapSceneRef.value.play()
+  })
+})
+
+onBeforeUnmount(() => {
+  emitter.$off("mapPlayComplete", handleMapPlayComplete)
+})
+
+function initAssets(onLoadCallback) {
+  assetsInstance.value = new Assets()
+  let params = { progress: 0 }
+  assetsInstance.value.instance.on("onProgress", (path, itemsLoaded, itemsTotal) => {
+    let p = Math.floor((itemsLoaded / itemsTotal) * 100)
+    gsap.to(params, {
+      progress: p,
+      onUpdate: () => {
+        state.progress = Math.floor(params.progress)
+      },
+    })
+  })
+  assetsInstance.value.instance.on("onLoad", () => {
+    onLoadCallback && onLoadCallback()
+  })
+}
+
+async function hideLoading() {
+  return new Promise((resolve) => {
+    let tl = gsap.timeline()
+    tl.to(".loading-text span", {
+      y: "200%",
+      opacity: 0,
+      ease: "power4.inOut",
+      duration: 2,
+      stagger: 0.2,
+    })
+    tl.to(".loading-progress", { opacity: 0, ease: "power4.inOut", duration: 2 }, "<")
+    tl.to(".loading", {
+      opacity: 0,
+      ease: "power4.inOut",
+      onComplete: () => resolve(),
+    }, "-=1")
+  })
+}
+
+function handleMenuSelect(index) {
+  state.activeIndex = index
+  if (index === "1") {
+    router.push("/map")
+  }
+}
+
+function handleMapPlayComplete() {
+  let tl = gsap.timeline({ paused: false })
+  let leftCards = gsap.utils.toArray(".left-column .module-card")
+  let rightCards = gsap.utils.toArray(".right-column .module-card")
+  tl.addLabel("start", 0.5)
+  tl.to(".m-header", { y: 0, opacity: 1, duration: 1.5, ease: "power4.out" }, "start")
+  tl.to(".top-menu", { y: 0, opacity: 1, duration: 1.5, ease: "power4.out" }, "-=1")
+  tl.to(leftCards, { x: 0, opacity: 1, stagger: 0.2, duration: 1.5, ease: "power4.out" }, "-=1")
+  tl.to(rightCards, { x: 0, opacity: 1, stagger: 0.2, duration: 1.5, ease: "power4.out" }, "-=1.3")
+}
+</script>
+
+<style lang="scss">
+@use "~@/assets/style/home.scss";
+
+.water-resource-page {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.water-resource-wrap {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 2;
+  pointer-events: none;
+}
+
+.m-header-weather,
+.m-header-date {
+  span {
+    padding-right: 10px;
+    color: #c4f3fe;
+    font-size: 14px;
+  }
+}
+
+.top-menu {
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 40px;
+  z-index: 3;
+  display: flex;
+  justify-content: center;
+  transform: translateY(-250%);
+  opacity: 0;
+  .top-menu-mid-space {
+    width: 800px;
+  }
+}
+
+.left-column {
+  position: absolute;
+  z-index: 4;
+  width: 398px;
+  left: 32px;
+  top: 126px;
+  bottom: 50px;
+  perspective: 500px;
+  perspective-origin: 50% 50%;
+  .left-column-3d {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    transform: translate3d(0px, 0px, 0px) scaleX(1) scaleY(1) rotateX(0deg) rotateY(6deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
+    z-index: 4;
+  }
+  .module-card {
+    transform: translateX(-150%);
+    opacity: 0;
+  }
+}
+
+.right-column {
+  position: absolute;
+  z-index: 4;
+  width: 398px;
+  right: 32px;
+  top: 126px;
+  bottom: 50px;
+  perspective: 800px;
+  perspective-origin: 50% 50%;
+  .right-column-3d {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    transform: translate3d(0px, 0px, 0px) scaleX(1) scaleY(1) rotateX(0deg) rotateY(-6deg) rotateZ(0deg) skewX(0deg) skewY(0deg);
+  }
+  .module-card {
+    transform: translateX(150%);
+    opacity: 0;
+  }
+}
+
+.m-header {
+  transform: translateY(-100%);
+  opacity: 0;
+}
+
+.water-resource-left-zsline,
+.water-resource-right-zsline {
+  position: absolute;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 30px;
+  height: 60%;
+  background-size: contain;
+  background-repeat: no-repeat;
+  opacity: 0.6;
+}
+
+.water-resource-left-zsline {
+  left: 0;
+  background-image: url("~@/assets/images/left-kuang.svg");
+  background-position: left center;
+}
+
+.water-resource-right-zsline {
+  right: 0;
+  background-image: url("~@/assets/images/right-kuang.svg");
+  background-position: right center;
+}
+</style>