lanxin недель назад: 2
Родитель
Сommit
dc04129d5a
2 измененных файлов с 438 добавлено и 496 удалено
  1. 85 334
      src/assets/data/Model/index.ts
  2. 353 162
      src/view/bldgPanorama/index.vue

+ 85 - 334
src/assets/data/Model/index.ts

@@ -3,347 +3,112 @@ export const baseURL = "https://houseoss.4dkankan.com/project/yifangyice2";
 export const countyMapData = [
   {
     name: "镜湖区",
-    bgImg: "镜湖区.png",
+    bgImg: "镜湖区定制.png",
+    enableZoom: true,
     labels: [
-      {
-        name: "天主堂",
-        fullName: "芜湖天主堂",
-        top: "19rem",
-        left: "4.2rem",
-        height: "6rem",
-        width: "4rem",
-         isBottom: true,
-      },
-      {
-        name: "老芜湖海关旧址",
-        fullName: "老芜湖海关旧址",
-        top: "18rem",
-        left: "2.2rem",
-        height: "7rem",
-        // 是否有拐角
-        width: "3rem",
-         isBottom: true,
-      },
-      {
-        name: "英驻芜领事官邸旧址",
-        fullName: "英驻芜领事官邸旧址",
-
-        top: "17.8rem",
-        left: "4.2rem",
-        width: "1rem",
-        height: "6rem",
-         isBottom: true,
-      },
-      {
-        name: "英驻芜领事署旧址",
-        fullName: "英驻芜领事署旧址",
-
-        top: "18.2rem",
-        left: "4.5rem",
-        width: "2rem",
-        height: "6rem",
-         isBottom: true,
-      },
-      {
-        name: "总税务司公所旧址",
-        fullName: "总税务司公所旧址",
-        top: "18.3rem",
-        left: "3.3rem",
-        height: "6rem",
-        width: "1rem",
-         isBottom: true,
-      },
-      // {
-      //   name: "洋员帮办楼旧址",
-      //   top: "22rem",
-      //   left: "15rem",
-      // },
-      {
-        name: "神父楼旧址",
-        fullName: "神父楼旧址",
-        top: "18.5rem",
-        left: "3rem",
-        width: "3rem",
-        height: "6rem",
-         isBottom: true,
-      },
-      // {
-      //   name: "天主教主教公署旧址",
-      //   top: "4.5rem",
-      //   left: "3rem",
-      //   width: "5rem",
-      //   height: "16.5rem"
-      // },
-      // {
-      //   name: "圣母院旧址",
-      //   top: "16.6rem",
-      //   left: "18.6rem",
-      // },
-      // {
-      //   name: "天主教修士楼旧址",
-      //   top: "19rem",
-      //   left: "12rem",
-      // },
-      {
-        name: "内思高级工业职业学校旧址",
-        fullName: "芜湖內思高级工业职业学校旧址",
-        top: "18.5rem",
-        left: "5.1rem",
-        width: "2rem",
-        height: "7.5rem",
-         isBottom: true,
-      },
-      {
-        name: "博仁堂",
-        fullName: "圣雅各中学旧址-博仁堂",
-        top: "18.5rem",
-        left: "2.5rem",
-        height: "6.8rem",
-        width: "1rem",
-         isBottom: true,
-      },
-
-      {
-        name: "中国银行旧址",
-        fullName: "芜湖中国银行旧址",
-        top: "18rem",
-        left: "6rem",
-        height: "4rem",
-        width: "1rem",
-         isBottom: true,
-      },
-
-      {
-        name: "中江塔",
-        fullName: "中江塔",
-        top: "19.8rem",
-        left: "6.2rem",
-        height: "4rem",
-        width: "3rem",
-         isBottom: true,
-      },
-      {
-        name: "大成殿",
-        fullName: "大成殿(县学记碑 歉卦碑)",
-        top: "19.5rem",
-        left: "7.2rem",
-        height: "4rem",
-        width: "1rem",
-         isBottom: true,
-      },
-      // {
-      //   name: "义德堂",
-      //   top: "19rem",
-      //   left: "12rem",
-      // },
-      // {
-      //   name: "经方堂",
-      //   top: "22rem",
-      //   left: "15rem",
-      // },
-      {
-        name: "广济寺塔",
-        fullName: "芜湖广济寺塔",
-        top: "19rem",
-        left: "4rem",
-        height: "12rem",
-        width: "2rem",
-         isBottom: true,
-      },
-      {
-        name: "老芜湖医院旧址",
-        fullName: "老芜湖医院旧址",
-        top: "17.7rem",
-        left: "1.9rem",
-        height: "7.5rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "院长楼旧址",
-        fullName: "院长楼旧址",
-        top: "17.7rem",
-        left: "1.9rem",
-        height: "7.5rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "专家楼旧址",
-        fullName: "专家楼旧址",
-        top: "17.7rem",
-        left: "1.9rem",
-        height: "7.5rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "沈克非、陈翠贞旧居",
-        fullName: "沈克非、陈翠贞旧居",
-        top: "17.7rem",
-        left: "1.9rem",
-        height: "7.5rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "外国主教公署旧址",
-        fullName: "外国主教公署旧址",
-        top: "18.4rem",
-        left: "3rem",
-        height: "6rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "中国主教公署旧址",
-        fullName: "中国主教公署旧址",
-        top: "18.4rem",
-        left: "3rem",
-        height: "6rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "基督教牧师楼旧址",
-        fullName: "基督教牧师楼旧址",
-        top: "18.4rem",
-        left: "3rem",
-        height: "6rem",
-        width: "2rem",
-        isBottom: true,
-      },
-
-      {
-        name: "圣雅各教堂",
-        fullName: "圣雅各教堂",
-        top: "19.4rem",
-        left: "5.1rem",
-        height: "3rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "牧师楼",
-        fullName: "牧师楼",
-        top: "19.8rem",
-        left: "5.1rem",
-        height: "4rem",
-        width: "2rem",
-        isBottom: true,
-      },
-      {
-        name: "崔国因公馆旧址",
-        fullName: "崔国因公馆旧址",
-        top: "19.8rem",
-        left: "5.4rem",
-        height: "5rem",
-        width: "2rem",
-        isBottom: true,
-      }
+      // 西北·弋矶山医院
+      { name: "老芜湖医院旧址-内科楼", fullName: "老芜湖医院旧址-内科楼", top: "41.4%", left: "69%", height: "7.2rem", width: "2rem" },
+      { name: "老芜湖医院旧址-院长楼", fullName: "老芜湖医院旧址-院长楼", top: "43.9%", left: "69%", height: "4.8rem", width: "2rem" },
+      { name: "老芜湖医院旧址-专家楼", fullName: "老芜湖医院旧址-专家楼", top: "46.4%", left: "69%", height: "2.4rem", width: "2rem" },
+      { name: "沈克非、陈翠贞故居", fullName: "沈克非、陈翠贞故居", top: "48.9%", left: "69%", height: "0", width: "2rem" },
+      // 北·花津圣雅各组团
+      { name: "外国主教公署旧址", fullName: "外国主教公署旧址",top: "51%", left: "78.4%", height: "7.8rem", width: "1.8rem",isRight: true  },
+      { name: "中国主教公署旧址", fullName: "中国主教公署旧址", top: "53.5%", left: "78.4%", height: "5.4rem", width: "1.8rem",isRight: true  },
+      { name: "圣雅各教堂", fullName: "圣雅各教堂", top: "84.2%", left: "137.1%", height: "4rem", width: "1.6rem", isBottom: true },
+      { name: "牧师楼", fullName: "牧师楼", top: "84.2%", left: "137.1%", height: "1.6rem", width: "1.4rem", isBottom: true },
+      { name: "基督教牧师楼旧址", fullName: "基督教牧师楼旧址", top: "56%", left: "78.4%", height: "3rem", width: "1.8rem",isRight: true },
+      // 北中·大官山 / 小官山 / 狮子山 / 凤凰山 / 赭山
+      { name: "天主教修士楼旧址", fullName: "天主教修士楼旧址", top: "55.4%", left: "105.6%", height: "2.2rem", width: "1.8rem" },
+      { name: "基督教内地会圣经学校旧址", fullName: "基督教内地会圣经学校旧址", top: "57.7%", left: "134.4%", height: "0rem", width: "1.6rem", isBottom: true },
+      { name: "芜湖英商亚细亚煤油公司旧址", fullName: "芜湖英商亚细亚煤油公司旧址", top: "63.5%", left: "138.7%", height: "0", width: "1.6rem" },
+      { name: "博仁堂", fullName: "圣雅各中学旧址-博仁堂", top: "59.4%", left: "91.7%", height: "1.2rem", width: "1.5rem" },
+      { name: "义德堂", fullName: "圣雅各中学旧址-义德堂", top: "60.4%", left: "91.7%", height: "1.6rem", width: "1.5rem", isBottom: true },
+      { name: "经方堂", fullName: "圣雅各中学旧址-经方堂", top: "60.4%", left: "91.7%", height: "4rem", width: "1.5rem", isBottom: true },
+      { name: "竟成楼", fullName: "萃文中学旧址竟成楼", top: "60.3%", left: "129.9%", height: "4.6rem", width: "1.6rem" },
+      { name: "教务处楼", fullName: "萃文中学旧址教务处楼", top: "60.3%", left: "129.9%", height: "4.6rem", width: "5.6rem" },
+      { name: "广济寺塔", fullName: "芜湖广济寺塔", top: "66.8%", left: "152.7%", height: "0rem", width: "1.6rem" },
+      { name: "崔国因公馆旧址", fullName: "崔国因公馆旧址",  top: "71.5%", left: "104.4%", height: "0.6rem", width: "1.6rem"  },
+      { name: "乐育楼旧址", fullName: "乐育楼旧址", top: "70.5%", left: "142.4%", height: "1.6rem", width: "1.6rem" , isBottom: true},
+      { name: "皖江中学", fullName: "皖江中学堂暨省立五中旧址", top: "69.5%", left: "149.7%", height: "0rem", width: "1.8rem" },
+      // 西·滨江 / 范罗山 / 吉和路
+      { name: "芜湖英商太古公司洋员宿舍旧址", fullName: "芜湖英商太古公司洋员宿舍旧址", top: "58.7%", left: "58.7%", height: "1.6rem", width: "2.4rem",isRight:true },
+      { name: "芜湖英商怡和轮船公司旧址", fullName: "芜湖英商怡和轮船公司旧址", top: "61%", left: "62.6%", height: "1rem", width: "2.2rem", isRight: true },
+      { name: "芜湖美商美孚石油公司旧址", fullName: "芜湖美商美孚石油公司旧址",  top: "62%", left: "81.7%", height: "6rem", width: "1.6rem" ,isBottom: true},
+      { name: "圣母院旧址", fullName: "圣母院旧址",top: "63.5%", left: "67.9%", height: "2.4rem", width: "1.8rem",isRight: true, isBottom: true},
+      { name: "天主教主教公署旧址", fullName: "天主教主教公署旧址", top: "63.4%", left: "67.9%", height: "0", width: "1.8rem",isRight: true },
+      { name: "英驻芜领事署旧址", fullName: "英驻芜领事署旧址", top: "74%", left: "107.4%", height: "0rem", width: "1.6rem", isBottom: true },
+      { name: "洋员帮办楼旧址", fullName: "洋员帮办楼旧址", top: "74%", left: "107.4%", height: "2.4rem", width: "1.6rem", isBottom: true },
+      { name: "总税务司公所旧址", fullName: "总税务司公所旧址", top: "74%", left: "107.4%", height: "4.8rem", width: "1.6rem", isBottom: true },
+      { name: "英驻芜领事官邸旧址", fullName: "英驻芜领事官邸旧址", top: "74%", left: "107.4%", height: "2.4rem", width: "8.6rem", isBottom: true },
+      { name: "老芜湖海关旧址", fullName: "老芜湖海关旧址", top: "68.7%", left: "61.9%", height: "3.2rem", width: "2rem", isBottom: true },
+      { name: "芜湖市图书馆老馆", fullName: "芜湖市图书馆老馆", top: "80.9%", left: "133%", height: "0", width: "1.8rem" },
+      // 西南·鹤儿山 / 雨耕山
+      { name: "天主堂", fullName: "芜湖天主堂", top: "76.7%", left: "83.1%", height: "0", width: "1.6rem",isRight: true },
+      { name: "神父楼旧址", fullName: "神父楼旧址", top: "76.7%", left: "83.1%", height: "2.4rem", width: "1.6rem", isRight: true,isBottom: true },
+      { name: "芜湖内思高级工业职业学校旧址", fullName: "芜湖内思高级工业职业学校旧址", top: "78.5%", left: "86.4%", height: "3.2rem", width: "2.2rem", isRight: true,isBottom: true },
+      { name: "中江塔", fullName: "中江塔", top: "82.1%", left: "90.8%", height: "0", width: "1.6rem" },
+      // 南·古城
+      { name: "中国银行旧址", fullName: "芜湖中国银行旧址", top: "82.2%", left: "133%", height: "1.3rem", width: "1.6rem" ,isBottom: true},
+      { name: "华牧师楼旧址", fullName: "华牧师楼旧址", top: "81.2%", left: "178.3%", height: "6rem", width: "1.8rem" },
+      { name: "段谦厚堂", fullName: "段谦厚堂", top: "83.3%", left: "178.3%", height: "2.8rem", width: "1.5rem"},
+      { name: "小天朝", fullName: "芜湖“小天朝”", top: "90.9%", left: "182.9%", height: "4.8rem", width: "1.6rem", isBottom: true },
+      { name: "大成殿", fullName: "大成殿(县学记碑 歉卦碑)", top: "91.3%", left: "190.3%", height: "1.6rem", width: "1.9rem", isBottom: true  },
+      { name: "衙署前门", fullName: "衙署前门",  top: "85.8%", left: "183.1%", height: "0.6rem", width: "1.5rem" },
+      { name: "芜湖模范监狱旧址-十字楼", fullName: "芜湖模范监狱旧址-十字楼", top: "87.8%", left: "194.5%", height: "0.4rem", width: "2rem",isBottom: true  },
+      { name: "芜湖模范监狱旧址-典狱长楼", fullName: "芜湖模范监狱旧址-典狱长楼",top: "87.8%", left: "194.5%", height: "2.8rem", width: "1.8rem", isBottom: true },
+      { name: "益新公司旧址", fullName: "益新公司旧址", top: "91.6%", left: "256.3%", height: "0", width: "1.6rem" },
     ],
   },
   {
     name: "无为市",
     bgImg: "无为市.png",
     labels: [
-      {
-        name: "洪巷周氏宗祠",
-        fullName: "洪巷周氏宗祠",
-        top: "20.7rem",
-        left: "8.9rem",
-        height: "7rem",
-        width: "2rem",
-      },
-      {
-        name: "新四军七师司令部旧址",
-        fullName: "新四军七师司令部旧址",
-        top: "19.7rem",
-        left: "10.4rem",
-        height: "4rem",
-        width: "2rem",
-        isBottom: true,
-      },
+      { name: "洪巷周氏宗祠", fullName: "洪巷周氏宗祠", top: "8.7rem", left: "8.7rem", height: "16rem", width: "2rem" },
+      { name: "新四军七师司令部旧址", fullName: "新四军七师司令部旧址", top: "11.2rem", left: "10.2rem", height: "5rem", width: "2rem" },
+      { name: "黄金塔", fullName: "黄金塔", top: "13.5rem", left: "15.6rem", height: "6rem", width: "2rem" },
+      { name: "卞氏宗祠", fullName: "卞氏宗祠", top: "16.8rem", left: "12.6rem", height: "5rem", width: "2rem" },
+    ],
+  },
+  {
+    name: "鸠江区",
+    bgImg: "鸠江区.png",
+    labels: [
+      { name: "六洲暴动旧址及胡竺冰故居", fullName: "六洲暴动旧址及胡竺冰故居", top: "18.4rem", left: "5rem", height: "6rem", width: "2.2rem" },
     ],
   },
-  // {
-  //   name: "鸠江区",
-  //   bgImg: "鸠江区.png",
-  //   labels: [],
-  // },
-  // {
-  //   name: "弋江区",
-  //   bgImg: "弋江区.png",
-  //   labels: [],
-  // },
-
   {
     name: "繁昌区",
     bgImg: "繁昌区.png",
-    labels: [{
-        name: "孙村章氏祠堂",
-        fullName: "孙村章氏祠堂",
-        top: "19.5rem",
-        left: "4rem",
-        height: "5rem",
-        width: "2rem",
-      }],
+    labels: [
+      { name: "孙村章氏祠堂", fullName: "孙村章氏祠堂", top: "13rem", left: "4rem", height: "8rem", width: "2rem" },
+      { name: "桃冲日军兵部大楼旧址", fullName: "桃冲日军兵部大楼旧址", top: "10.4rem", left: "5.2rem", height: "6rem", width: "1rem" },
+      { name: "朱氏宗祠(中共繁昌县委旧址)", fullName: "朱氏宗祠(中共繁昌县委旧址)", top: "16.8rem", left: "9.1rem", height: "9rem", width: "2rem", isBottom: true },
+      { name: "皖南特委旧址", fullName: "皖南特委旧址", top: "16.8rem", left: "9.1rem", height: "6.4rem", width: "2rem", isBottom: true },
+      { name: "城关夫子庙", fullName: "城关夫子庙", top: "13rem", left: "12.7rem", height: "7rem", width: "2rem" },
+      { name: "板子矶明塔", fullName: "板子矶明塔", top: "8rem", left: "3.3rem", height: "8.5rem", width: "1.8rem" },
+      { name: "黄公阁", fullName: "黄公阁", top: "5.5rem", left: "3.3rem", height: "11rem", width: "1.8rem" },
+      { name: "鹊起庵", fullName: "鹊起庵", top: "3rem", left: "3.3rem", height: "13.6rem", width: "1.8rem" },
+    ],
   },
   {
     name: "南陵县",
     bgImg: "南陵县.png",
     labels: [
-      {
-        name: "张氏宗祠",
-        fullName: "张氏宗祠",
-        top: "18.9rem",
-        left: "2.8rem",
-        height: "6rem",
-        width: "2rem",
-      },],
+      { name: "张氏宗祠", fullName: "张氏宗祠", top: "15rem", left: "3rem", height: "6rem", width: "2rem" },
+      { name: "徐家大屋", fullName: "徐家大屋", top: "9.4rem", left: "14.3rem", height: "8.5rem", width: "2rem" },
+      { name: "圣公会乐育学堂", fullName: "圣公会乐育学堂", top: "13.2rem", left: "15.3rem", height: "5rem", width: "1rem" },
+      { name: "牧师楼旧址", fullName: "牧师楼旧址", top: "15.7rem", left: "15.3rem", height: "2.5rem", width: "1rem"},
+    ],
   },
   {
     name: "湾沚区",
     bgImg: "湾沚区.png",
-    labels: [{
-        name: "胡湾胡氏宗祠",
-        fullName: "胡湾胡氏宗祠",
-        top: "14.3rem",
-        left: "4.1rem",
-        height: "10rem",
-        width: "2rem",
-      },],
-  },
-  {
-    name: "其他",
-    // 全部的位置
-    bgImg: "panoramaBG2.png",
-    // 图上标签
     labels: [
-      {
-        name: "黄金塔",
-        fullName: "黄金塔",
-        top: "16.5rem",
-        left: "6.1rem",
-        width: "2rem",
-        height: "6rem",
-      },
-      {
-        name: "徐家大屋",
-        fullName: "徐家大屋",
-        top: "21.5rem",
-        left: "14rem",
-        width: "2rem",
-        height: "5.5rem",
-      },
-      {
-        name: "珩琅塔",
-        fullName: "珩琅塔",
-        top: "19rem",
-        left: "20rem",
-        width: "-1.9rem",
-        height: "7rem",
-      },
+      { name: "胡湾胡氏宗祠", fullName: "胡湾胡氏宗祠", top: "11rem", left: "4.1rem", height: "10rem", width: "2rem" },
+      { name: "白沙圩农民暴动旧址", fullName: "白沙圩农民暴动旧址", top: "14rem", left: "4.6rem", height: "8rem", width: "2.2rem"},
+      { name: "西班牙天主教堂", fullName: "西班牙天主教堂",top: "17.7rem", left: "12.7rem", height: "2.4rem", width: "2rem" },
+      { name: "神甫楼", fullName: "神甫楼", top: "20.2rem", left: "12.7rem", height: "0rem", width: "2rem"},
+      { name: "珩琅塔", fullName: "珩琅塔", top: "28.9rem", left: "5.3rem", height: "2rem", width: "1.9rem", isBottom: true },
     ],
   },
 ];
@@ -373,12 +138,7 @@ const ModelList = [
     },
     viewTop: "75.7%",
     viewLeft: "29.4%",
-    swiperImage: [
-      `${baseURL}/image/swiperImage/26/DJI_0710.JPG`,
-      `${baseURL}/image/swiperImage/26/DJI_0714.JPG`,
-      `${baseURL}/image/swiperImage/26/DJI_0722.JPG`,
-      `${baseURL}/image/swiperImage/26/DJI_0723.JPG`,
-    ],
+    swiperImage: [`${baseURL}/image/swiperImage/26/DJI_0710.JPG`, `${baseURL}/image/swiperImage/26/DJI_0714.JPG`, `${baseURL}/image/swiperImage/26/DJI_0722.JPG`, `${baseURL}/image/swiperImage/26/DJI_0723.JPG`],
     videoName: "26.mp4",
   },
   {
@@ -964,7 +724,6 @@ const ModelList = [
     viewLeft: "40%",
     swiperImage: [`${baseURL}/image/swiperImage/衙署前门/DJI_0387.JPG`, `${baseURL}/image/swiperImage/衙署前门/DJI_0389.JPG`],
     videoName: "16.mp4",
-    
   },
   {
     id: 22,
@@ -990,7 +749,6 @@ const ModelList = [
     viewLeft: "14.4%",
     swiperImage: [`${baseURL}/image/swiperImage/中江塔/DJI_0503.JPG`],
     videoName: "22.mp4",
-    
   },
   {
     id: 20,
@@ -1016,7 +774,6 @@ const ModelList = [
     viewLeft: "37.9%",
     swiperImage: [`${baseURL}/image/swiperImage/大成殿/DJI_0471.JPG`, `${baseURL}/image/swiperImage/大成殿/DJI_0472.JPG`],
     videoName: "20.mp4",
-    
   },
   {
     id: 19,
@@ -1042,7 +799,6 @@ const ModelList = [
     viewLeft: "34.5%",
     swiperImage: [`${baseURL}/image/swiperImage/小天朝/DJI_0445.JPG`, `${baseURL}/image/swiperImage/小天朝/DJI_0457.JPG`, `${baseURL}/image/swiperImage/小天朝/DJI_0464.JPG`],
     videoName: "19.mp4",
-    
   },
   {
     id: 17,
@@ -1068,7 +824,6 @@ const ModelList = [
     viewLeft: "39.8%",
     swiperImage: [`${baseURL}/image/swiperImage/监狱旧址/DJI_0397.JPG`, `${baseURL}/image/swiperImage/监狱旧址/DJI_0398.JPG`, `${baseURL}/image/swiperImage/监狱旧址/DJI_0399.JPG`],
     videoName: "17.mp4",
-    
   },
   {
     id: 18,
@@ -1119,7 +874,6 @@ const ModelList = [
     viewLeft: "30.1%",
     swiperImage: [`${baseURL}/image/swiperImage/皖江中学/DJI_0501.JPG`, `${baseURL}/image/swiperImage/皖江中学/DJI_0510.JPG`, `${baseURL}/image/swiperImage/皖江中学/DJI_0512.JPG`],
     videoName: "21.mp4",
-    
   },
   {
     id: 23,
@@ -1145,7 +899,6 @@ const ModelList = [
     viewLeft: "28.1%",
     swiperImage: [`${baseURL}/image/swiperImage/中国银行旧址/DJI_0483.JPG`],
     videoName: "23.mp4",
-    
   },
   {
     id: 2,
@@ -2088,7 +1841,6 @@ const ModelList = [
     viewLeft: "83.5%",
     swiperImage: [`${baseURL}/image/swiperImage/徐家大屋/DJI_0626.JPG`],
     videoName: "52.mp4",
-    
   },
   {
     id: 53,
@@ -2114,7 +1866,6 @@ const ModelList = [
     viewLeft: "92.2%",
     swiperImage: [`${baseURL}/image/swiperImage/珩琅塔/DJI_0608.JPG`, `${baseURL}/image/swiperImage/珩琅塔/DJI_0618.JPG`, `${baseURL}/image/swiperImage/珩琅塔/DJI_0620.JPG`],
     videoName: "53.mp4",
-    
   },
   {
     id: 54,

+ 353 - 162
src/view/bldgPanorama/index.vue

@@ -1,68 +1,331 @@
 <script setup lang="ts">
 import Tabbar from "@/components/Tabbar.vue";
+import Back from "@/components/Back.vue";
 import { countyMapData } from "@/assets/data/Model";
 import { usePanorama } from "@/store/Panorama/index";
 
+type CountyItem = (typeof countyMapData)[number] & { enableZoom?: boolean };
+
+type MapLabel = {
+  name: string;
+  fullName: string;
+  top: string;
+  left: string;
+  height?: string;
+  width?: string;
+  isBottom?: boolean;
+  isRight?: boolean;
+};
+
+const DESIGN_WIDTH = 375;
+const DESIGN_HEIGHT = 667;
+const DESIGN_REM = DESIGN_WIDTH / 24;
+
+const MIN_SCALE = 0.5;
+const MAX_SCALE = 4;
+const DEFAULT_SCALE = 1;
+
 const currentIndex = ref(0);
 const router = useRouter();
 const store = usePanorama();
-const selectedName = ref(countyMapData[0].labels[0].name);
+const viewportRef = ref<HTMLElement | null>(null);
 
-const goDetail = (param: string | number) => {
-  if (typeof param == "number") {
-    // 当前为芜湖市地图,更换地图
-    currentIndex.value = param + 1;
-  } else {
-    router.push({
-      path: "/bldgPanorama/detail",
-      query: {
-        name: param,
-      },
-    });
+const scale = ref(DEFAULT_SCALE);
+const translateX = ref(0);
+const translateY = ref(0);
+
+const currentCounty = computed(() => countyMapData[currentIndex.value] as CountyItem);
+const isJinghu = computed(() => currentCounty.value.name === "镜湖区");
+const enableZoom = computed(() => isJinghu.value || !!currentCounty.value.enableZoom);
+const viewportSize = ref({ width: DESIGN_WIDTH, height: DESIGN_HEIGHT });
+
+const canvasScale = computed(() => {
+  const { width, height } = viewportSize.value;
+  return Math.max(width / DESIGN_WIDTH, height / DESIGN_HEIGHT);
+});
+
+const canvasOffset = computed(() => {
+  const s = canvasScale.value;
+  return {
+    x: (viewportSize.value.width - DESIGN_WIDTH * s) / 2,
+    y: (viewportSize.value.height - DESIGN_HEIGHT * s) / 2,
+  };
+});
+
+const toDesignPx = (value?: string) => {
+  if (!value || value === "auto") return value;
+  if (value.endsWith("%")) return value;
+  if (value.endsWith("rem")) return `${parseFloat(value) * DESIGN_REM}px`;
+  return value;
+};
+
+const labelBoxStyle = (label: MapLabel) => ({
+  top: toDesignPx(label.top),
+  left: toDesignPx(label.left),
+  height: toDesignPx(label.height) || `${10 * DESIGN_REM}px`,
+  width: toDesignPx(label.width) || "auto",
+});
+
+const mapLayerStyle = computed(() => {
+  const s = canvasScale.value;
+  const { x, y } = canvasOffset.value;
+  const base = `translate3d(${x}px, ${y}px, 0) scale(${s})`;
+  if (enableZoom.value) {
+    return {
+      width: `${DESIGN_WIDTH}px`,
+      transform: `${base} translate3d(${translateX.value}px, ${translateY.value}px, 0) scale(${scale.value})`,
+      transformOrigin: "0 0",
+    };
   }
+  return {
+    width: `${DESIGN_WIDTH}px`,
+    height: `${DESIGN_HEIGHT}px`,
+    transform: base,
+    transformOrigin: "0 0",
+  };
+});
+
+const touchState = {
+  mode: "" as "" | "pan" | "pinch",
+  startX: 0,
+  startY: 0,
+  originX: 0,
+  originY: 0,
+  startDist: 0,
+  startScale: 1,
+  pinchMidX: 0,
+  pinchMidY: 0,
+};
+
+const mouseState = {
+  dragging: false,
+  startX: 0,
+  startY: 0,
+  originX: 0,
+  originY: 0,
+};
+
+const getTitleTransform = (label: MapLabel) => {
+  const height = toDesignPx(label.height);
+  const width = toDesignPx(label.width);
+  const yOff = `${1.2 * DESIGN_REM}px`;
+  const y = label.isBottom ? `calc(${height} - ${yOff})` : "-50%";
+  if (label.isRight) {
+    return `translate(-100%, ${y})`;
+  }
+  if (width) {
+    return `translate(${width}, ${y})`;
+  }
+  return `translate(-50%, ${y})`;
+};
+
+const goDetail = (name: string) => {
+  router.push({
+    path: "/bldgPanorama/detail",
+    query: {
+      name,
+    },
+  });
 };
 
 const getAssetURL = (image: string) => {
   return new URL(`../../assets/img/panorama/${image}`, import.meta.url).href;
 };
 
-watch(currentIndex, (newVale: any) => {
-  store.currentIndex = newVale;
-  selectedName.value = countyMapData[newVale].labels[0].name;
-  console.log(selectedName.value);
+const clampScale = (value: number) => Math.min(MAX_SCALE, Math.max(MIN_SCALE, value));
+
+const getTouchDistance = (touches: TouchList) => {
+  const dx = touches[0].clientX - touches[1].clientX;
+  const dy = touches[0].clientY - touches[1].clientY;
+  return Math.hypot(dx, dy);
+};
+
+const initJinghuView = () => {
+  if (!enableZoom.value) return;
+  scale.value = DEFAULT_SCALE;
+  translateX.value = -130;
+  translateY.value = -500;
+};
+
+const resetTransform = () => {
+  if (enableZoom.value) {
+    nextTick(initJinghuView);
+  } else {
+    scale.value = 1;
+    translateX.value = 0;
+    translateY.value = 0;
+  }
+};
+
+const zoomAt = (clientX: number, clientY: number, nextScale: number) => {
+  const viewport = viewportRef.value;
+  if (!viewport) return;
+  const rect = viewport.getBoundingClientRect();
+  const s = canvasScale.value || 1;
+  const { x: ox, y: oy } = canvasOffset.value;
+  const x = (clientX - rect.left - ox) / s;
+  const y = (clientY - rect.top - oy) / s;
+  const clamped = clampScale(nextScale);
+  const ratio = clamped / scale.value;
+  translateX.value = x - (x - translateX.value) * ratio;
+  translateY.value = y - (y - translateY.value) * ratio;
+  scale.value = clamped;
+};
+
+const onTouchStart = (event: TouchEvent) => {
+  if (!enableZoom.value) return;
+  if (event.touches.length === 1) {
+    touchState.mode = "pan";
+    touchState.startX = event.touches[0].clientX;
+    touchState.startY = event.touches[0].clientY;
+    touchState.originX = translateX.value;
+    touchState.originY = translateY.value;
+  } else if (event.touches.length >= 2) {
+    touchState.mode = "pinch";
+    touchState.startDist = getTouchDistance(event.touches);
+    touchState.startScale = scale.value;
+    touchState.pinchMidX = (event.touches[0].clientX + event.touches[1].clientX) / 2;
+    touchState.pinchMidY = (event.touches[0].clientY + event.touches[1].clientY) / 2;
+  }
+};
+
+const onTouchMove = (event: TouchEvent) => {
+  if (!enableZoom.value || !touchState.mode) return;
+  event.preventDefault();
+  if (touchState.mode === "pan" && event.touches.length === 1) {
+    translateX.value = touchState.originX + (event.touches[0].clientX - touchState.startX) / (canvasScale.value || 1);
+    translateY.value = touchState.originY + (event.touches[0].clientY - touchState.startY) / (canvasScale.value || 1);
+  } else if (touchState.mode === "pinch" && event.touches.length >= 2) {
+    const dist = getTouchDistance(event.touches);
+    if (!touchState.startDist) return;
+    const nextScale = touchState.startScale * (dist / touchState.startDist);
+    zoomAt(touchState.pinchMidX, touchState.pinchMidY, nextScale);
+  }
+};
+
+const onTouchEnd = (event: TouchEvent) => {
+  if (!enableZoom.value) return;
+  if (event.touches.length === 1) {
+    touchState.mode = "pan";
+    touchState.startX = event.touches[0].clientX;
+    touchState.startY = event.touches[0].clientY;
+    touchState.originX = translateX.value;
+    touchState.originY = translateY.value;
+  } else if (event.touches.length === 0) {
+    touchState.mode = "";
+  }
+};
+
+const onWheel = (event: WheelEvent) => {
+  if (!enableZoom.value) return;
+  event.preventDefault();
+  const factor = event.deltaY > 0 ? 0.9 : 1.1;
+  zoomAt(event.clientX, event.clientY, scale.value * factor);
+};
+
+const onMouseDown = (event: MouseEvent) => {
+  if (!enableZoom.value || event.button !== 0) return;
+  mouseState.dragging = true;
+  mouseState.startX = event.clientX;
+  mouseState.startY = event.clientY;
+  mouseState.originX = translateX.value;
+  mouseState.originY = translateY.value;
+};
+
+const onMouseMove = (event: MouseEvent) => {
+  if (!mouseState.dragging) return;
+  const s = canvasScale.value || 1;
+  translateX.value = mouseState.originX + (event.clientX - mouseState.startX) / s;
+  translateY.value = mouseState.originY + (event.clientY - mouseState.startY) / s;
+};
+
+const onMouseUp = () => {
+  mouseState.dragging = false;
+};
+
+const onMapLoad = (index: number) => {
+  if (enableZoom.value && index === currentIndex.value) {
+    nextTick(initJinghuView);
+  }
+};
+
+watch(currentIndex, (newValue: number) => {
+  store.currentIndex = newValue;
+  resetTransform();
 });
 
+const updateViewportSize = () => {
+  const viewport = viewportRef.value;
+  if (!viewport) return;
+  viewportSize.value = {
+    width: viewport.clientWidth,
+    height: viewport.clientHeight,
+  };
+};
+
+let viewportObserver: ResizeObserver | null = null;
+
 onMounted(() => {
-  console.log(store.currentIndex);
   currentIndex.value = store.currentIndex == null ? 0 : store.currentIndex;
+  const viewport = viewportRef.value;
+  if (viewport) {
+    updateViewportSize();
+    viewportObserver = new ResizeObserver(updateViewportSize);
+    viewportObserver.observe(viewport);
+    viewport.addEventListener("touchstart", onTouchStart, { passive: true });
+    viewport.addEventListener("touchmove", onTouchMove, { passive: false });
+    viewport.addEventListener("touchend", onTouchEnd, { passive: true });
+    viewport.addEventListener("touchcancel", onTouchEnd, { passive: true });
+    viewport.addEventListener("wheel", onWheel, { passive: false });
+    viewport.addEventListener("mousedown", onMouseDown);
+  }
+  window.addEventListener("mousemove", onMouseMove);
+  window.addEventListener("mouseup", onMouseUp);
+  nextTick(resetTransform);
+});
+
+onBeforeUnmount(() => {
+  viewportObserver?.disconnect();
+  viewportObserver = null;
+  const viewport = viewportRef.value;
+  if (viewport) {
+    viewport.removeEventListener("touchstart", onTouchStart);
+    viewport.removeEventListener("touchmove", onTouchMove);
+    viewport.removeEventListener("touchend", onTouchEnd);
+    viewport.removeEventListener("touchcancel", onTouchEnd);
+    viewport.removeEventListener("wheel", onWheel);
+    viewport.removeEventListener("mousedown", onMouseDown);
+  }
+  window.removeEventListener("mousemove", onMouseMove);
+  window.removeEventListener("mouseup", onMouseUp);
 });
 </script>
 
 <template>
-  <!-- 全部 -->
   <div class="panorama">
-    <div class="panorama-box" v-for="(item, index) in countyMapData" :key="index">
-      <div class="boxC" v-show="index === currentIndex">
-        <img :src="getAssetURL(item.bgImg)" alt="" id="box" />
+    <div class="viewport" ref="viewportRef" :class="{ 'is-zoom': enableZoom }">
+      <div
+        class="map-layer"
+        v-for="(item, index) in countyMapData"
+        v-show="index === currentIndex"
+        :key="index"
+        :style="index === currentIndex ? mapLayerStyle : undefined"
+      >
+        <img :src="getAssetURL(item.bgImg)" alt="" draggable="false" @load="onMapLoad(index)" />
         <div
-          :class="['box-1', { 'box-1-bottom': label.isBottom }]"
+          :class="['box-1', { 'box-1-bottom': label.isBottom, 'box-1-right': (label as MapLabel).isRight }]"
           v-for="(label, index2) in item.labels"
-          v-show="label.name === selectedName"
           :key="index2"
-          :style="{
-            top: label.top,
-            left: label.left,
-            height: label.height ? label.height : '10rem',
-            width: label.width ? label.width : 'auto',
-          }"
+          :style="labelBoxStyle(label)"
         >
           <div
             class="title"
-            :style="{
-              transform: label.isBottom ? `translate(${label.width},calc(${label.height} - 1.2rem)` : label.width ? `translate(${label.width},-50%)` : 'translate(-50%,-50%)',
-            }"
+            :style="{ transform: getTitleTransform(label) }"
+            @click.stop="goDetail(label.name)"
+            @mousedown.stop
+            @touchstart.stop
           >
-            {{ `${label.fullName ? label.fullName : label.name}` }}
+            {{ isJinghu ? label.name : label.fullName ? label.fullName : label.name }}
           </div>
           <div class="dian-small"></div>
           <div class="dian-big"></div>
@@ -70,17 +333,7 @@ onMounted(() => {
       </div>
     </div>
 
-    <div class="tabItems">
-      <div class="scrollC">
-        <div v-for="(item, i) in countyMapData[currentIndex].labels" :key="i" class="tabItem" :class="item.name === selectedName ? 'tabItem_ac' : ''" @click="selectedName = item.name">
-          {{ item.name }}
-        </div>
-      </div>
-    </div>
-    <div class="btns">
-      <div class="backBtn" @click="router.back()">返回</div>
-      <div class="panoBtn" :class="{ 'panoBtn-active': selectedName }" @click="goDetail(selectedName)">全景漫游</div>
-    </div>
+    <Back />
 
     <div class="option-box">
       <div
@@ -88,11 +341,7 @@ onMounted(() => {
         :key="index"
         class="btn"
         :style="{ background: index == currentIndex ? '#fff' : '#767265' }"
-        @click="
-          () => {
-            currentIndex = index;
-          }
-        "
+        @click="currentIndex = index"
       >
         <div class="circle" :class="{ 'circle-active': index === currentIndex }">
           {{ item.name }}
@@ -108,118 +357,79 @@ onMounted(() => {
   width: 100%;
   height: 100%;
   position: relative;
+  overflow: hidden;
 
-  .boxC {
-    transition: all 0.2s ease-in-out;
-  }
-
-  img {
-    width: 100%;
-    height: 100%;
-    object-fit: cover;
-    transform: translateY(-46px);
-  }
-
-  .tabItems {
-    padding: 25px 0;
+  .viewport {
     position: absolute;
-    width: 80%;
-    height: 40%;
-    left: 50%;
-    transform: translateX(-50%);
-    top: 5%;
-    overflow: auto;
-    border-radius: 10px;
-    background: linear-gradient(to bottom, rgba(224, 230, 242, 1), rgba(224, 230, 242, 0));
-
-    .scrollC {
+    inset: 0;
+    overflow: hidden;
+    user-select: none;
+
+    .map-layer {
       width: 100%;
-      height: 80%;
-      overflow: auto;
-      display: flex;
-      align-items: center;
-      flex-direction: column;
-      gap: 10px;
-      .tabItem {
-        text-align: center;
+      height: 100%;
+      position: relative;
+      transform-origin: 0 0;
+
+      img {
         width: 100%;
-        height: 24px;
-        line-height: 24px;
-        font-size: 14px;
-        color: rgba(104, 94, 71, 1);
-      }
-      .tabItem_ac {
-        background-image: url(/src\assets\img\panorama\item_active.png);
-        background-size: 100% 100%;
+        height: 100%;
+        object-fit: cover;
+        transform: translateY(-46px);
+        pointer-events: none;
       }
     }
-  }
 
-  .btns {
-    position: absolute;
-    left: 50%;
-    transform: translateX(-50%);
-    bottom: 20%;
-    width: 100%;
-    height: 50px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: 20px;
-    color: rgba(118, 114, 101, 1);
-    font-size: 16px;
-    .backBtn {
-      width: 60px;
-      height: 40px;
-      text-align: center;
-      line-height: 40px;
-      background-image: url(/src\assets\img\panorama\btn_back.png);
-      background-size: 100% 100%;
-    }
-    .panoBtn {
-      width: 120px;
-      height: 40px;
-      text-align: center;
-      line-height: 40px;
-      background-image: url(/src\assets\img\panorama\btn_back.png);
-      background-size: 100% 100%;
-      opacity: 0.5;
-      pointer-events: none;
-    }
-    .panoBtn-active {
-      opacity: 1;
-      pointer-events: auto;
+    &.is-zoom {
+      background: #000;
+      touch-action: none;
+      cursor: grab;
+
+      .map-layer {
+        height: auto;
+        transform-origin: 0 0;
+        will-change: transform;
+
+        img {
+          width: 1487px;
+          height: auto;
+          display: block;
+          object-fit: contain;
+          transform: none;
+        }
+      }
     }
   }
 
   .box-1 {
-    // width: 10%;
     height: 10rem;
     background: rgba(0, 128, 0, 0);
-    border-left: 1px dashed #2058bd;
-    border-top: 1px dashed #2058bd;
+    border-left: 1px dashed #fff;
+    border-top: 1px dashed #fff;
     position: absolute;
     left: 6.6rem;
     top: 16rem;
     box-sizing: border-box;
-    // position: relative;
-    transition: all 0.2s ease-in-out;
+    pointer-events: none;
 
     .title {
       background-image: url(/src\assets\img\map\regionBg.jpg);
       background-size: 100% 100%;
       padding: 8px 10px;
-      font-size: 0.8rem;
+      font-size: 12.5px;
       white-space: nowrap;
       position: absolute;
       transform: translate(-50%, -50%);
       z-index: 2;
+      pointer-events: auto;
+      cursor: pointer;
+      touch-action: none;
     }
 
     .dian-small {
       width: 8px;
       height: 8px;
-      background: #2159c2;
+      background: #fff;
       border-radius: 50%;
       position: absolute;
       bottom: -4px;
@@ -244,13 +454,11 @@ onMounted(() => {
     @keyframes fadenum {
       from {
         transform: scale(0.8);
-        /*放大1.1倍*/
         opacity: 0.5;
       }
 
       to {
         transform: scale(1);
-        /*放大1.1倍*/
         opacity: 1;
       }
     }
@@ -258,7 +466,7 @@ onMounted(() => {
 
   .box-1-bottom {
     border-top: transparent;
-    border-bottom: 1px dashed #2058bd;
+    border-bottom: 1px dashed #fff;
     .dian-small {
       top: -4px;
     }
@@ -267,41 +475,24 @@ onMounted(() => {
     }
   }
 
-  .div-1 {
-    width: 10%;
-    height: 10rem;
-    background: rgba(0, 128, 0, 0);
-    border-left: 1px dashed #2058bd;
-    left: 10.6rem;
-    top: 13rem;
-    position: absolute;
-
-    // .dian-small {
-    //   width: 8px;
-    //   height: 8px;
-    //   background: #2159c2;
-    //   border-radius: 50%;
-    //   position: absolute;
-    //   bottom: -4px;
-    //   left: -4px;
-    // }
-
-    // .dian-big {
-    //   width: 20px;
-    //   height: 20px;
-    //   background: #235ac073;
-    //   border-radius: 50%;
-    //   position: absolute;
-    //   bottom: -10px;
-    //   left: -10px;
-    // }
+  .box-1-right {
+    border-left: transparent;
+    border-right: 1px dashed #fff;
+    .dian-small {
+      left: auto;
+      right: -4px;
+    }
+    .dian-big {
+      left: auto;
+      right: -10px;
+    }
   }
 
   .option-box {
     width: 100%;
     height: 9.5rem;
     position: fixed;
-    z-index: 2;
+    z-index: 4;
     bottom: 0;
     background: rgba(83, 83, 83, 0.384);
     display: flex;