Просмотр исходного кода

底图切换成arcgis服务,完成外边框样式

DESKTOP-6LTVLN7\Liumouren 2 месяцев назад
Родитель
Сommit
f4bf312d9c

BIN
public/static/images/bottomBg.png


BIN
public/static/images/headerBg.png


BIN
public/static/images/leftRightBg.png


BIN
src/assets/images/headerBg.png


+ 90 - 56
src/components/map/appMap.vue

@@ -12,9 +12,34 @@ export default {
   name: "appMap",
   data() {
     return {
+      // 底图服务配置,支持后期扩展
+      baseMapServices: {
+        // 原有底图服务
+        localVector: {
+          name: "本地矢量底图",
+          type: "tile",
+          url:
+            "https://szlszxdt.qpservice.org.cn/internal_map//tile/{z}/{y}/{x}?servertype=shmap_blue_web&proxyToken=" +
+            localStorage.getItem("TOKEN"),
+          options: {},
+        },
+        // ArcGIS World Imagery 底图服务
+        arcgisImagery: {
+          name: "ArcGIS卫星影像",
+          type: "tile",
+          url:
+            "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
+          options: {
+            token: localStorage.getItem("TOKEN"),
+          },
+        },
+      },
+      // 当前激活的底图
+      activeBaseMap: "localVector",
+      // 底图图层实例
+      baseMapLayers: {},
       map: "",
       layers: "",
-      layersState: false,
       marker: "",
       center: "",
       polygonOldClickTitle: "",
@@ -64,70 +89,19 @@ export default {
   methods: {
     mapInit() {
       let center_ = [31.146179026117824, 121.11121627562943];
-      L.TileLayer.TdtTileLayer = L.TileLayer.extend({
-        // 拓展天地图瓦片图层
-        initialize: function (type, key, options) {
-          var templateUrl =
-            "//t{s}.tianditu.gov.cn/DataServer?T={t}&x={x}&y={y}&l={z}&tk={k}";
-          options = L.extend(
-            {
-              t: type,
-              l: type.substr(0, 3),
-              k: key,
-              subdomains: "01234567",
-              minZoom: 0,
-              maxZoom: 23,
-              minNativeZoom: type === "ibo_w" ? 3 : 1,
-              maxNativeZoom: type === "ibo_w" ? 10 : 18,
-            },
-            options
-          );
-          L.TileLayer.prototype.initialize.call(this, templateUrl, options);
-        },
-      });
-
-      L.tileLayer.tdtTileLayer = function (type, key, options) {
-        return new L.TileLayer.TdtTileLayer(type, key, options);
-      };
-      let img_Layer = L.tileLayer.tdtTileLayer(
-        "img_w",
-        "8adb2a7873dff59469aa9dcfd84c4c8f"
-      );
-      let cia_Layer = L.tileLayer.tdtTileLayer(
-        "cia_w",
-        "8adb2a7873dff59469aa9dcfd84c4c8f"
-      );
-      let vec_Layer = L.tileLayer.tdtTileLayer(
-        "vec_w",
-        "8adb2a7873dff59469aa9dcfd84c4c8f"
-      );
-      let cva_Layer = L.tileLayer.tdtTileLayer(
-        "cva_w",
-        "8adb2a7873dff59469aa9dcfd84c4c8f"
-      );
       this.map = L.map(this.$refs.appMap, {
         center: center_,
         zoom: 15,
         minZoom: 9,
         maxZoom: 18,
-        layers: [vec_Layer, cva_Layer],
         zoomControl: true,
         attributionControl: false,
         doubleClickZoom: false,
       });
-      this.layersState = true;
-      var overlayLayers = {
-        电子底图: vec_Layer,
-        电子注记: cva_Layer,
-        影像底图: img_Layer,
-        影像注记: cia_Layer,
-      };
-      L.control.layers([], overlayLayers, { autoZIndex: false }).addTo(this.map);
-      for (let node of document.querySelectorAll(
-        ".leaflet-control-layers-overlays label"
-      )) {
-        this.controlLayers[node.innerText.trim()] = node.querySelector("input");
-      }
+      // 加载初始底图
+      this.loadBaseMap(this.activeBaseMap);
+      // 移除缩放控件
+      this.map.removeControl(this.map.zoomControl);
 
       // 监听地图点击事件
       // this.map.on("click", function (e) {
@@ -158,6 +132,65 @@ export default {
         that.mapResize();
       });
     },
+
+    // 加载底图
+    loadBaseMap(mapKey) {
+      const service = this.baseMapServices[mapKey];
+      if (!service) return;
+
+      try {
+        // 移除当前底图
+        Object.values(this.baseMapLayers).forEach((layer) => {
+          this.map.removeLayer(layer);
+        });
+
+        let layer;
+
+        // 根据底图类型创建图层
+        switch (service.type) {
+          case "esriVector":
+            // 这个有BUG
+            layer = L.esri.Vector.vectorBasemapLayer(service.url, {
+              ...service.options,
+              version: service.options.version || 1, // 确保版本号存在
+            });
+            break;
+          case "tile":
+            layer = L.tileLayer(service.url, service.options);
+            break;
+          // 支持更多底图类型...
+          case "wms":
+            layer = L.tileLayer.wms(service.url, service.options);
+            break;
+          default:
+            console.error("不支持的底图类型:", service.type);
+            return;
+        }
+
+        // 添加到底图并保存实例
+        layer.addTo(this.map);
+        this.baseMapLayers[mapKey] = layer;
+        this.activeBaseMap = mapKey;
+
+        // 监听底图加载事件
+        layer.on("load", () => {
+          console.log(`${service.name} 加载成功`);
+        });
+
+        // 监听底图加载错误事件
+        layer.on("error", (err) => {
+          console.error(`${service.name} 加载失败:`, err);
+          // 可以添加用户提示
+        });
+      } catch (error) {
+        console.error("加载底图失败:", error);
+      }
+    },
+
+    // 切换底图
+    switchBaseMap(mapKey) {
+      this.loadBaseMap(mapKey);
+    },
     // 重新计算地图容器的大小并更新地图边界
     mapResize() {
       this.map.invalidateSize();
@@ -612,5 +645,6 @@ export default {
 .appMapViewer {
   width: 100%;
   height: 100%;
+  background: #000;
 }
 </style>

+ 298 - 40
src/views/qpjyj.vue

@@ -2,12 +2,57 @@
 <template>
   <el-container class="container" style="height: 100%">
     <el-header class="container_header">
+      <!-- 首页按钮 -->
+      <div class="container_header_home">
+        <!-- 首页按钮 -->
+        <i class="el-icon-s-home" />
+      </div>
+      <!-- header背景 -->
+      <el-image
+        class="container_header_bg"
+        fit="fill"
+        draggable="false"
+        src="/static/images/headerBg.png"
+      ></el-image>
+      <!-- 左侧背景 -->
+      <el-image
+        class="container_header_leftBg"
+        fit="fill"
+        draggable="false"
+        src="/static/images/leftRightBg.png"
+      ></el-image>
+      <!-- 右侧背景 -->
+      <el-image
+        class="container_header_rightBg"
+        fit="fill"
+        draggable="false"
+        src="/static/images/leftRightBg.png"
+      ></el-image>
+      <!-- 底部背景 -->
       <el-image
-        style="width: 305px; height: 74px"
-        src="/static/images/headerLogo.png"
+        class="container_header_bottomBg"
+        fit="fill"
+        draggable="false"
+        src="/static/images/bottomBg.png"
       ></el-image>
-      <div class="container_header_divider"></div>
-      <span class="container_header_title">青浦区科委产业地图</span>
+      <!-- header标题 -->
+      <div class="container_header_title">
+        <div class="container_header_title_zh">青浦区科委产业地图</div>
+        <div class="container_header_title_en">Qingpu Industrial Park Map</div>
+      </div>
+      <!-- 数据同步信息区域 -->
+      <div class="data-sync-info">
+        <span class="sync-label">数据最后同步</span>
+        <span class="sync-date">{{ formattedDate }}</span>
+        <span class="sync-time">{{ formattedTime }}</span>
+        <el-button
+          class="sync-btn"
+          type="primary"
+          icon="el-icon-refresh"
+          @click="handleSync"
+          >{{ isSyncing ? "同步中..." : "立即同步" }}</el-button
+        >
+      </div>
     </el-header>
     <el-main class="main" v-loading="getDataLoading">
       <div class="main_left">
@@ -27,19 +72,47 @@ export default {
     return {
       VUE_APP_SystemType: "",
       getDataLoading: false,
+      lastSyncTime: new Date(), // 最后同步时间
+      isSyncing: false, // 同步状态
+      syncTimer: null, // 同步定时器
     };
   },
+  computed: {
+    // 格式化日期:YYYY/MM/DD
+    formattedDate() {
+      return this.$dayjs(this.lastSyncTime).format("YYYY/MM/DD");
+    },
+    // 格式化时间:星期X HH:mm:ss
+    formattedTime() {
+      const weekDays = [
+        "星期日",
+        "星期一",
+        "星期二",
+        "星期三",
+        "星期四",
+        "星期五",
+        "星期六",
+      ];
+      const weekdayIndex = this.$dayjs(this.lastSyncTime).day();
+      const time = this.$dayjs(this.lastSyncTime).format("HH:mm:ss");
+      return `${weekDays[weekdayIndex]} ${time}`;
+    },
+  },
   // 自定义指令 —— 拖动div
   directives: {},
   created() {
     this.VUE_APP_SystemType = process.env.VUE_APP_SystemType;
   },
   mounted() {
+    // 组件挂载时可以启动自动同步
+    this.startAutoSync();
     // 自定义数据录入
     // this.dataPush();
   },
-  beforeDestroyed() {},
-  destroy() {},
+  beforeDestroyed() {
+    // 组件卸载时停止自动同步
+    this.stopAutoSync();
+  },
   methods: {
     dataPush() {
       // 获取json中的数据
@@ -62,64 +135,249 @@ export default {
       //   });
       // });
     },
+
+    // 处理同步操作
+    async handleSync() {
+      if (this.isSyncing) return;
+
+      try {
+        this.isSyncing = true;
+
+        // 模拟同步数据的异步操作
+        await this.syncData();
+
+        // 同步成功,更新最后同步时间
+        this.lastSyncTime = new Date();
+
+        this.$message({
+          type: "success",
+          message: "数据同步成功",
+        });
+        // 可以添加同步成功的提示
+        console.log("数据同步成功");
+      } catch (error) {
+        console.error("数据同步失败:", error);
+        // 可以添加同步失败的提示
+      } finally {
+        this.isSyncing = false;
+      }
+    },
+
+    // 模拟同步数据的异步函数
+    syncData() {
+      return new Promise((resolve) => {
+        // 模拟网络请求延迟
+        setTimeout(() => {
+          resolve();
+        }, 2000);
+      });
+    },
+
+    // 自动同步(可选,根据需求添加)
+    startAutoSync() {
+      // 每30分钟自动同步一次
+      this.syncTimer = setInterval(() => {
+        this.handleSync();
+      }, 30 * 60 * 1000);
+    },
+
+    // 停止自动同步
+    stopAutoSync() {
+      if (this.syncTimer) {
+        clearInterval(this.syncTimer);
+        this.syncTimer = null;
+      }
+    },
   },
 };
 </script>
 
 <style lang="less" scoped>
-@letterSpacing: 0.2rem;
+@mainColor: #1dc8dc;
+@mainHoverColor: #22dcf0;
 .container {
+  position: relative;
   &_header {
-    display: flex;
-    align-items: center;
-    position: relative;
-    height: 80px !important;
-    background: linear-gradient(90deg, #40b28c 0%, #5fbbf1 100%);
-    &_divider {
-      height: 40px;
-      margin: 0 37px;
-      width: 1px;
-      background: #92d3cd;
-    }
-    &_title {
-      color: #ffffff;
-      font-weight: bold;
-      font-size: 28px;
-      line-height: normal;
-      letter-spacing: 2px;
-    }
-    &_info {
-      color: #f2f6fc;
-      font-size: 14px;
-      letter-spacing: 2px;
-    }
-    .parentFeedbackSheet {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 70px !important;
+    background: #0000;
+    padding: 0;
+    margin: 0;
+    z-index: 999;
+    // 首页按钮
+    &_home {
       position: absolute;
-      right: 20px;
       top: 50%;
-      display: flex;
+      left: 32px;
       transform: translateY(-50%);
-      font-size: 28px;
-      color: #ffffff;
+      color: @mainColor;
+      font-size: 24px;
+      display: flex;
+      align-items: center;
       cursor: pointer;
+      padding: 10px;
+      border-radius: 100px;
+      // 背景颜色设置渐变色,从中心向四周展开
+      background: radial-gradient(circle at center, #1612de24 0%, #2082e033 100%);
       &:hover {
-        text-shadow: 0 0 5px #fff;
+        color: @mainHoverColor;
+        background: radial-gradient(circle at center, #1612de56 0%, #2082e065 100%);
       }
-      &:active {
-        color: #f2f6fc;
-        text-shadow: 0 0 2px #fff;
+    }
+    // header背景
+    &_bg {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: -1;
+      // 设置图片禁止拖动
+      /* 针对 Webkit 内核浏览器(Chrome、Safari 等) */
+      -webkit-user-drag: none;
+      /* 标准属性(部分现代浏览器支持) */
+      user-drag: none;
+      /* 禁止选中图片(可选,防止拖拽时选中图片) */
+      user-select: none;
+      -webkit-user-select: none;
+    }
+    &_leftBg {
+      position: fixed;
+      top: 63px;
+      left: 0;
+      width: 4px;
+      height: calc(100vh - 63px);
+      z-index: 999;
+    }
+    &_rightBg {
+      position: fixed;
+      top: 63px;
+      right: 0;
+      width: 4px;
+      height: calc(100vh - 63px);
+      z-index: 999;
+    }
+    &_bottomBg {
+      position: fixed;
+      bottom: 0;
+      left: 0;
+      width: 100%;
+      height: 4px;
+      z-index: 999;
+    }
+    // header标题
+    &_title {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      /* 字体设置 */
+      font-family: "Alibaba PuHuiTi 3.0", sans-serif;
+      /* 对齐方式 */
+      text-align: center;
+      vertical-align: middle;
+      /* 使用线性渐变文字 */
+      background: linear-gradient(180deg, #ffffff 0%, #88d9ff 100%);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+      background-clip: text;
+      // 中文标题
+      &_zh {
+        font-weight: 900; /* Heavy */
+        line-height: 100%; /* 行高100% */
+        letter-spacing: 6px; /* 字间距6px */
+        font-size: 32px; /* 截图显示32px */
+      }
+      // 英文标题
+      &_en {
+        font-weight: 800; /* Heavy */
+        font-size: 14px; /* 截图显示24px */
+        color: #87d9ff;
       }
     }
   }
 }
 .main {
+  position: absolute;
+  top: 50px;
+  left: 0;
   margin: 0;
   padding: 0;
-  height: calc(100% - 80px);
+  width: 100vw;
+  height: calc(100vh - 50px);
   display: flex;
   &_left {
     height: 100%;
     width: 100%;
   }
 }
+
+// 右侧信息展示区域
+
+.data-sync-info {
+  position: absolute;
+  right: 32px;
+  top: 50%;
+  transform: translateY(-50%);
+  display: flex;
+  align-items: center;
+  padding: 8px 16px;
+  color: #ffffff;
+  font-family: "Alibaba PuHuiTi 3.0", sans-serif;
+  font-size: 14px;
+}
+
+.sync-label {
+  color: @mainHoverColor;
+  margin-right: 12px;
+  opacity: 0.8;
+}
+
+.sync-date {
+  /* 使用线性渐变文字 */
+  background: linear-gradient(180deg, #ffffff 0%, #88d9ff 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+  margin-right: 8px;
+  font-weight: 500;
+}
+
+.sync-time {
+  /* 使用线性渐变文字 */
+  background: linear-gradient(180deg, #ffffff 0%, #88d9ff 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+  margin-right: 20px;
+  font-weight: 500;
+}
+
+.sync-btn {
+  display: flex;
+  align-items: center;
+  padding: 8px 16px;
+  background-color: @mainColor;
+  font-weight: bold;
+  border: none;
+  color: #ffffff;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.sync-btn:hover {
+  background-color: @mainHoverColor;
+  transform: translateY(-1px);
+  box-shadow: 0 2px 8px rgba(0, 204, 255, 0.4);
+}
+
+.sync-icon {
+  margin-right: 6px;
+  font-size: 16px;
+}
 </style>