jinx 9 bulan lalu
induk
melakukan
efbb9d03f0
54 mengubah file dengan 627 tambahan dan 640 penghapusan
  1. 2 2
      index.html
  2. 1 0
      package.json
  3. TEMPAT SAMPAH
      public/static/image/美食/封面/三色蒸回头鱼.png
  4. TEMPAT SAMPAH
      public/static/image/美食/封面/华容团子.png
  5. TEMPAT SAMPAH
      public/static/image/美食/封面/姜辣凤爪.png
  6. TEMPAT SAMPAH
      public/static/image/美食/封面/岳阳口味虾.png
  7. TEMPAT SAMPAH
      public/static/image/美食/封面/岳阳豆皮.png
  8. TEMPAT SAMPAH
      public/static/image/美食/封面/平江酱干.png
  9. TEMPAT SAMPAH
      public/static/image/美食/封面/张谷英油豆腐.png
  10. TEMPAT SAMPAH
      public/static/image/美食/封面/清炒樟树港辣椒.png
  11. TEMPAT SAMPAH
      public/static/image/美食/封面/清炒藜蒿.png
  12. TEMPAT SAMPAH
      public/static/image/美食/封面/白灼河虾.png
  13. TEMPAT SAMPAH
      public/static/image/美食/封面/腊味芦笋.png
  14. TEMPAT SAMPAH
      public/static/image/美食/封面/荷塘三宝.png
  15. TEMPAT SAMPAH
      public/static/image/美食/封面/金汤小米桂鱼打边炉.png
  16. TEMPAT SAMPAH
      public/static/image/美食/封面/银鱼炒蛋.png
  17. TEMPAT SAMPAH
      public/static/image/美食/封面/青椒铁山鱼头.png
  18. TEMPAT SAMPAH
      public/static/image/美食/封面/香煎原味翘白.png
  19. TEMPAT SAMPAH
      public/static/image/美食/视频/三色蒸回头鱼.mp4
  20. TEMPAT SAMPAH
      public/static/image/美食/视频/姜辣凤爪.mp4
  21. TEMPAT SAMPAH
      public/static/image/美食/视频/岳阳口味虾.mp4
  22. TEMPAT SAMPAH
      public/static/image/美食/视频/清炒樟树港辣椒.mp4
  23. TEMPAT SAMPAH
      public/static/image/美食/视频/清炒藜蒿.mp4
  24. TEMPAT SAMPAH
      public/static/image/美食/视频/白灼河虾.mp4
  25. TEMPAT SAMPAH
      public/static/image/美食/视频/腊味芦笋.mp4
  26. TEMPAT SAMPAH
      public/static/image/美食/视频/荷塘三宝.mp4
  27. TEMPAT SAMPAH
      public/static/image/美食/视频/金汤小米桂鱼打边炉.mp4
  28. TEMPAT SAMPAH
      public/static/image/美食/视频/银鱼炒蛋.mp4
  29. TEMPAT SAMPAH
      public/static/image/美食/视频/青椒铁山鱼头.mp4
  30. TEMPAT SAMPAH
      public/static/image/美食/视频/香煎原味翘白.mp4
  31. TEMPAT SAMPAH
      public/static/image/美食/辣姜凤爪.png
  32. TEMPAT SAMPAH
      src/assets/images/effect/boat.png
  33. TEMPAT SAMPAH
      src/assets/images/effect/cloud1.png
  34. TEMPAT SAMPAH
      src/assets/images/effect/cloud2.png
  35. TEMPAT SAMPAH
      src/assets/images/effect/role.png
  36. TEMPAT SAMPAH
      src/assets/images/line-btn_active@2x.png
  37. TEMPAT SAMPAH
      src/assets/images/line_btn_normal@2x.png
  38. TEMPAT SAMPAH
      src/assets/images/tag-1.png
  39. TEMPAT SAMPAH
      src/assets/images/tag-2.png
  40. TEMPAT SAMPAH
      src/assets/images/tag-3.png
  41. TEMPAT SAMPAH
      src/assets/images/tag-4.png
  42. TEMPAT SAMPAH
      src/assets/images/tag-5.png
  43. TEMPAT SAMPAH
      src/assets/images/tag-6.png
  44. TEMPAT SAMPAH
      src/assets/images/video-btn.png
  45. TEMPAT SAMPAH
      src/assets/images/video-close.png
  46. 1 0
      src/views/answer/index.vue
  47. 86 0
      src/views/data/index.vue
  48. 144 5
      src/views/food/data.js
  49. 129 34
      src/views/food/index.vue
  50. 14 13
      src/views/home/index.vue
  51. 17 521
      src/views/line/data.js
  52. 77 50
      src/views/line/index.vue
  53. 151 15
      src/views/map/index.vue
  54. 5 0
      yarn.lock

+ 2 - 2
index.html

@@ -10,7 +10,7 @@
     <div id="app"></div>
     <script src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
     <script type="module" src="/src/main.js"></script>
-    <script src="https://cdn.bootcss.com/vConsole/3.2.2/vconsole.min.js"></script>
-    <script>  var vConsole = new VConsole();  </script>
+    <!-- <script src="https://cdn.bootcss.com/vConsole/3.2.2/vconsole.min.js"></script>
+    <script>  var vConsole = new VConsole();  </script> -->
   </body>
 </html>

+ 1 - 0
package.json

@@ -13,6 +13,7 @@
     "animate.css": "^4.1.1",
     "axios": "^1.9.0",
     "crypto-js": "^4.2.0",
+    "hammerjs": "^2.0.8",
     "jsonp": "^0.2.1",
     "lib-flexible": "^0.3.2",
     "markdown-it": "^14.1.0",

TEMPAT SAMPAH
public/static/image/美食/封面/三色蒸回头鱼.png


TEMPAT SAMPAH
public/static/image/美食/封面/华容团子.png


TEMPAT SAMPAH
public/static/image/美食/封面/姜辣凤爪.png


TEMPAT SAMPAH
public/static/image/美食/封面/岳阳口味虾.png


TEMPAT SAMPAH
public/static/image/美食/封面/岳阳豆皮.png


TEMPAT SAMPAH
public/static/image/美食/封面/平江酱干.png


TEMPAT SAMPAH
public/static/image/美食/封面/张谷英油豆腐.png


TEMPAT SAMPAH
public/static/image/美食/封面/清炒樟树港辣椒.png


TEMPAT SAMPAH
public/static/image/美食/封面/清炒藜蒿.png


TEMPAT SAMPAH
public/static/image/美食/封面/白灼河虾.png


TEMPAT SAMPAH
public/static/image/美食/封面/腊味芦笋.png


TEMPAT SAMPAH
public/static/image/美食/封面/荷塘三宝.png


TEMPAT SAMPAH
public/static/image/美食/封面/金汤小米桂鱼打边炉.png


TEMPAT SAMPAH
public/static/image/美食/封面/银鱼炒蛋.png


TEMPAT SAMPAH
public/static/image/美食/封面/青椒铁山鱼头.png


TEMPAT SAMPAH
public/static/image/美食/封面/香煎原味翘白.png


TEMPAT SAMPAH
public/static/image/美食/视频/三色蒸回头鱼.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/姜辣凤爪.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/岳阳口味虾.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/清炒樟树港辣椒.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/清炒藜蒿.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/白灼河虾.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/腊味芦笋.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/荷塘三宝.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/金汤小米桂鱼打边炉.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/银鱼炒蛋.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/青椒铁山鱼头.mp4


TEMPAT SAMPAH
public/static/image/美食/视频/香煎原味翘白.mp4


TEMPAT SAMPAH
public/static/image/美食/辣姜凤爪.png


TEMPAT SAMPAH
src/assets/images/effect/boat.png


TEMPAT SAMPAH
src/assets/images/effect/cloud1.png


TEMPAT SAMPAH
src/assets/images/effect/cloud2.png


TEMPAT SAMPAH
src/assets/images/effect/role.png


TEMPAT SAMPAH
src/assets/images/line-btn_active@2x.png


TEMPAT SAMPAH
src/assets/images/line_btn_normal@2x.png


TEMPAT SAMPAH
src/assets/images/tag-1.png


TEMPAT SAMPAH
src/assets/images/tag-2.png


TEMPAT SAMPAH
src/assets/images/tag-3.png


TEMPAT SAMPAH
src/assets/images/tag-4.png


TEMPAT SAMPAH
src/assets/images/tag-5.png


TEMPAT SAMPAH
src/assets/images/tag-6.png


TEMPAT SAMPAH
src/assets/images/video-btn.png


TEMPAT SAMPAH
src/assets/images/video-close.png


+ 1 - 0
src/views/answer/index.vue

@@ -255,6 +255,7 @@ const reStartOrContinue = (type = 1) => {
       // overflow-y: auto;
       background: url("@/assets/images/reviewBg.png") no-repeat;
       background-size: 100% 100%;
+      background-color: #f2f2f2;
       position: absolute;
       bottom: 0;
       left: 0;

+ 86 - 0
src/views/data/index.vue

@@ -1,7 +1,10 @@
 vue3
 <!--  -->
 <template>
+  <p>点位</p>
   <input type="file" @change="readFile" accept=".xlsx" />
+  <p>美食</p>
+  <input type="file" @change="readFileFood" accept=".xlsx" />
 </template>
 
 <script setup>
@@ -150,6 +153,89 @@ const procressData = (list) => {
   return array;
 };
 
+const readFileFood = (e) => {
+  const files = e.target.files;
+  // 如果没有文件名
+  if (files.length <= 0) {
+    return false;
+  } else if (!/\.(xls|xlsx)$/.test(files[0].name.toLowerCase())) {
+    this.$Message.error("上传格式不正确,请上传xls或者xlsx格式");
+    return false;
+  }
+
+  const fileReader = new FileReader();
+  fileReader.onload = (ev) => {
+    try {
+      const data = ev.target.result;
+      // 切换为新的调用方式
+      const workbook = XLSX.read(data, {
+        type: "binary",
+      });
+
+      let table = workbook.Sheets;
+      let keys = workbook.SheetNames;
+      console.log(workbook);
+      let array = [];
+
+      keys.forEach((item) => {
+        let obj = {};
+        obj.name = item;
+        // obj.list = XLSX.utils.sheet_to_json(table[item]);
+        obj.list = procressFoodData(
+          XLSX.utils.sheet_to_json(table[item], {
+            /** Default value for null/undefined values */
+            defval: "", //给defval赋值为空的字符串
+          })
+        );
+        array.push(obj);
+      });
+    } catch (e) {
+      return false;
+    }
+  };
+  fileReader.readAsBinaryString(files[0]);
+};
+const procressFoodData = (list) => {
+  let array = [];
+  // list = list.filter((item) => item["提供日期"]);
+
+  console.error(list);
+  list.forEach((item, index) => {
+    let obj = {};
+    obj.id = index + 1;
+    for (let key in item) {
+      switch (key) {
+        case "菜品名称":
+          obj["name"] = item[key];
+
+          break;
+        case "介绍":
+          obj["desc"] = item[key];
+
+          break;
+        case "封面":
+          obj["thumb"] = item[key];
+
+          break;
+        case "视频":
+          if (item[key]) {
+            obj["video"] = item[key];
+          }
+
+          break;
+        case "模型链接":
+          obj["url"] = item[key];
+
+          break;
+      }
+    }
+    // obj.vrLink = "https://www.4dkankan.com/panorama/show.html?id=WK1768236336482967552&vr=fd720_NZ0i3ASIq&lang=zh"
+    array.push(obj);
+  });
+
+  console.error(array);
+  return array;
+};
 onMounted(() => {});
 </script>
 <style lang="scss" scoped></style>

+ 144 - 5
src/views/food/data.js

@@ -1,7 +1,146 @@
 export const foodList = [
-  { url: "https://www.720yun.com/3dm/603ze82Of6s", name: "辣姜凤爪" },
-  { url: "https://www.720yun.com/3dm/603ze82Of6s", name: "辣姜凤爪1" },
-  { url: "https://www.720yun.com/3dm/603ze82Of6s", name: "辣姜凤爪2" },
-  { url: "https://www.720yun.com/3dm/603ze82Of6s", name: "辣姜凤爪3" },
-  { url: "https://www.720yun.com/3dm/603ze82Of6s", name: "辣姜凤爪4" },
+  {
+    id: 1,
+    name: "青椒铁山鱼头",
+    desc: "产自铁山水库的雄鱼,头大,体小,颜色黑亮。岳阳人烹饪鱼汤是有讲究的,开始用大火将水烧开,然后转为小火,慢炖几个小时,鱼肉完整鲜嫩,鱼汤会渐至奶白。随着青椒与佐料的加入,轻轻搅动勺子,香气扑面而来,让人瞬间打开味蕾。",
+    thumb: "青椒铁山鱼头.png",
+    video: "青椒铁山鱼头.mp4",
+    url: "",
+  },
+  {
+    id: 2,
+    name: "三色蒸回头鱼",
+    desc: "回头鱼又称江团。三色蒸回头鱼以蒜蓉、豆豉、红剁椒为佐料蒸制,三色对比,既有蒜豉椒香,又得鱼味的自然鲜美。",
+    thumb: "三色蒸回头鱼.png",
+    video: "三色蒸回头鱼.mp4",
+    url: "",
+  },
+  {
+    id: 3,
+    name: "岳阳口味虾",
+    desc: "岳阳有大小湖泊165个,大小河流280多条,域内活水绵延,全市养虾面积超100万亩。好水出好虾,岳阳小龙虾具有出货早、供货时间长、肚皮干净、肉质Q弹等特点。口味虾重点在高汤现卤,其肉既嫩又辣又爽,给人满口的幸福感。",
+    thumb: "岳阳口味虾.png",
+    video: "岳阳口味虾.mp4",
+    url: "",
+  },
+  {
+    id: 4,
+    name: "银鱼炒蛋",
+    desc: "银鱼古称玉簪鱼,鱼头扁平鱼身无鳞,洁白如银,银鱼体柔,若无骨无肠,漫游水中,快似银箭离弦。银鱼炒蛋讲究香鲜嫩,白黄相间,鱼蛋滑嫩,诱人食欲。",
+    thumb: "银鱼炒蛋.png",
+    video: "银鱼炒蛋.mp4",
+    url: "",
+  },
+  {
+    id: 5,
+    name: "平江酱干",
+    desc: "平江酱干是一道历史悠久的传统小吃,以黄豆为主要原料,经过多次加工而成。酱干口感独特、味道鲜美,是佐餐佳品。",
+    thumb: "平江酱干.png",
+    video: "平江酱干.mp4",
+    url: "",
+  },
+  {
+    id: 6,
+    name: "华容团子",
+    desc: "华容团子是岳阳的传统小吃,以其独特的制法和口感而闻名。团子外皮软糯、馅料丰富,有肉馅和菜馅等多种选择。在品尝团子的同时,不妨再配上一碗热气腾腾的米粥,更能感受到其美味。",
+    thumb: "华容团子.png",
+    video: "华容团子.mp4",
+    url: "",
+  },
+  {
+    id: 7,
+    name: "姜辣凤爪",
+    desc: "凤凰是中国传统文化中的神鸟,因为鸡爪的形状类似凤凰的爪子,因此把鸡爪称为凤爪,寓意吉祥如意。姜辣系列是源自岳阳的新派湘菜,近年来风靡大江南北的湘菜馆。烹饪凤爪时,做料头的生姜丁是极多的,成菜味型突出姜香冲辣,姜辣凤爪与姜蒜干辣椒相熬出汁,因味型霸道,刺激味蕾,而独具岳阳地方特色。",
+    thumb: "姜辣凤爪.png",
+    video: "姜辣凤爪.mp4",
+    url: "https://www.720yun.com/3dm/603ze82Of6s",
+  },
+  {
+    id: 8,
+    name: "清炒樟树港辣椒",
+    desc: "湘阴县樟树镇,是一江一湖两港相夹而成的小“盆地”,形成了适合辣椒生长独特的环境。樟树港辣椒清炒时皮肉不分离,清脆柔软,椒香浓烈,曾被食客们戏称为辣椒中的“劳斯莱斯”。",
+    thumb: "清炒樟树港辣椒.png",
+    video: "清炒樟树港辣椒.mp4",
+    url: "",
+  },
+  {
+    id: 9,
+    name: "张谷英油豆腐",
+    desc: "张谷英村做油豆腐已经有几百年历史了,当地人会100多种豆腐做法,因此张谷英也被称作最会做豆腐的“古镇”。做油豆腐,必须用当地黄豆、渭洞茶油和龙涎井清泉来做,只有这样才足够外黄内白、外实内空,更好地吸汁。除了好的食材,采取传统工艺加工而成,也是张谷英油豆腐闻名遐迩的主要原因。",
+    thumb: "张谷英油豆腐.png",
+    video: "张谷英油豆腐.mp4",
+    url: "",
+  },
+  {
+    id: 10,
+    name: "铁山刁子鱼",
+    desc: "",
+    thumb: "铁山刁子鱼.png",
+    video: "铁山刁子鱼.mp4",
+    url: "",
+  },
+  {
+    id: 11,
+    name: "岳阳豆皮",
+    desc: "洞庭湖畔的岳阳豆皮,是本土早餐的灵魂。外皮以洞庭绿豆与早稻米(2:1)浸泡9小时磨浆,经发酵、摊凉、炸制等工序,成就金黄酥脆、内里柔韧的独特层次。\n2019年起,其制作技艺先后入选岳阳楼区、市级非遗。凭借咸香地道的口感、饱腹便携的特性,既是市井烟火味的承载,也是岳阳人舌尖的乡愁。",
+    thumb: "岳阳豆皮.png",
+    video: "岳阳豆皮.mp4",
+    url: "",
+  },
+  {
+    id: 12,
+    name: "岳阳烧烤",
+    desc: "岳阳烧烤,湘北夜宵江湖的味觉名片,以炭火淬炼湖湘风味。招牌烤牛油在烈焰中化作金黄脆珠,奶香与焦香交织;嫩滑牛肉裹着红亮辣衣,锁住丰盈肉汁;五花肉在高温下蜕变成酥脆脂香,搭配现烤洞庭鲫鱼的剁椒嫩鲜,每一串都诠释着粗犷与精细并存的烧烤哲学。",
+    thumb: "岳阳烧烤.png",
+    video: "岳阳烧烤.mp4",
+    url: "",
+  },
+  {
+    id: 13,
+    name: "香煎原味翘白",
+    desc: "翘白鱼就是翘嘴白鱼,其肉白而细,首尾上翘,猎食性强,是我国淡水四大名鱼之一。制作香煎翘白时,得把翘白鱼切成几段,两面煎得金黄,上桌时完美不破皮,外脆内嫩,原汁原味。",
+    thumb: "香煎原味翘白.png",
+    video: "香煎原味翘白.mp4",
+    url: "",
+  },
+  {
+    id: 14,
+    name: "白灼河虾",
+    desc: "洞庭湖区人对大湖习惯称为河,如汴河街,下河街等,对洞庭湖广袤水域里的虾习惯称为河虾。白灼河虾就是等清水沸腾后,倒入河虾至红色,辅以佐料即成鲜活美味。",
+    thumb: "白灼河虾.png",
+    video: "白灼河虾.mp4",
+    url: "",
+  },
+  {
+    id: 15,
+    name: "金汤小米桂鱼打边炉",
+    desc: "这道菜得到湘菜泰斗王墨泉大师的嫡传弟子、祖庵菜技艺传承人、湘菜大师杨龙的亲自指点,把桂鱼肉质的鲜嫩爽滑完美呈现出来。经过特殊熬制的小米,其清香醇厚包裹住细嫩的鱼肉,异常爽滑,久煮不柴。",
+    thumb: "金汤小米桂鱼打边炉.png",
+    video: "金汤小米桂鱼打边炉.mp4",
+    url: "",
+  },
+  {
+    id: 16,
+    name: "腊味芦笋",
+    desc: "洞庭湖的芦苇荡里遍布一种俯拾皆是的时鲜芦笋,将芦笋煮沸焯水,去掉苦涩,这时鲜嫩的颜色更加讨喜,暖色的鹅黄交融着淡淡的乳白,当香喷喷的腊肉遇上新鲜芦笋,锅中翻炒时,芦笋就像一只只蝴蝶在锅里跳舞,起锅上桌让人口齿留香。",
+    thumb: "腊味芦笋.png",
+    video: "腊味芦笋.mp4",
+    url: "",
+  },
+  {
+    id: 17,
+    name: "清炒藜蒿",
+    desc: "正月藜,二月蒿,藜蒿广泛生长在洞庭湖区,冰雪未消融就冲破严寒,簇簇绽放,清香鲜嫩,风味冠春蔬,最是人家美味,只要藜蒿独特香,不炒腊肉饭也光,在烹饪藜蒿时,可以采用简单的方法来保留其最原始的风味,将藜蒿洗净切段,用热油快速翻炒,加入适量的盐和蒜末调味,便能品尝到藜蒿的鲜嫩于清香。",
+    thumb: "清炒藜蒿.png",
+    video: "清炒藜蒿.mp4",
+    url: "",
+  },
+  {
+    id: 18,
+    name: "荷塘三宝(藕丁、莲子、菱角合炒)",
+    desc: "洞庭湖区民间早就有荷莲一身宝,秋藕最补人的说法,家住大湖边,荷塘随处是,吃菱角,闻荷香,尝藕尖,吃莲子,品湖藕,记忆中的味道如此根深蒂固地成为一抹淡淡地乡愁。湖区人眼里地荷塘三宝就是湖藕,莲子,菱角。烹饪时要把新鲜的湖藕与菱角切丁与莲子合炒,怎么炒都能诱人品尝,清香可口。",
+    thumb: "荷塘三宝.png",
+    video: "荷塘三宝.mp4",
+    url: "",
+  },
 ];

+ 129 - 34
src/views/food/index.vue

@@ -2,25 +2,40 @@
 <template>
   <div class="food">
     <Header title="数字美食" path="map" />
-    <div class="food-title">{{ foodList[swipeIndex].name }}</div>
-    <div class="food-container">
-      <div class="swiper-wrapper">
-        <div class="swiper-slide" @click="goToViwe(i)" v-for="i in foodList">
-          <div class="slide-bg"></div>
+    <div class="top">
+      <div class="food-title">{{ foodList[swipeIndex].name }}</div>
+      <div class="food-container">
+        <div class="swiper-wrapper">
+          <div class="swiper-slide" @click="goToViwe(i)" v-for="i in foodList">
+            <div class="slide-bg"></div>
 
-          <img src="https://img1.baidu.com/it/u=2406584972,1640672778&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" alt="" />
-        </div>
+            <img :src="`./static/image/美食/封面/${i.thumb}`" alt="" />
+          </div>
 
-        <!-- 更多幻灯片 -->
+          <!-- 更多幻灯片 -->
+        </div>
+        <!-- 如果需要分页器 -->
+        <!-- <div class="swiper-pagination"></div> -->
       </div>
-      <!-- 如果需要分页器 -->
-      <!-- <div class="swiper-pagination"></div> -->
     </div>
 
+    <div class="food-msg">
+      <div class="video-btn" @click="videoUrl = foodList[swipeIndex].video" v-if="foodList[swipeIndex].video"></div>
+      <div class="desc">
+        {{ foodList[swipeIndex].desc }}
+      </div>
+      <div class="miniprogram-btn">气味王国</div>
+    </div>
     <!-- <div class="model-btn"></div> -->
-    <div class="miniprogram-btn">气味王国</div>
   </div>
   <WebView v-if="showWebView" :link="openData.url" :title="openData.name" @close="closeWebView" />
+
+  <div class="video-layer" v-if="videoUrl">
+    <div class="video-box">
+      <video controls :autoplay="true" :src="`./static/image/美食/视频/${foodList[swipeIndex].video}`"></video>
+    </div>
+    <div class="close-btn" @click="videoUrl = null"></div>
+  </div>
 </template>
 
 <script setup>
@@ -30,13 +45,13 @@ import Header from "@/components/header/index.vue";
 import "swiper/css/swiper.css";
 import { foodList } from "./data.js";
 import WebView from "../webview/index.vue";
-console.error(foodList);
 const swipeIndex = ref(0);
 let swiper = null;
 const showWebView = ref(false);
 const closeWebView = () => {
   showWebView.value = false;
 };
+const videoUrl = ref(null);
 const openData = ref({});
 const initTab = () => {
   swiper = new Swiper(".food-container", {
@@ -48,13 +63,15 @@ const initTab = () => {
     loop: false,
     on: {
       slideChange: (e) => {
-        console.error(swiper);
         swipeIndex.value = swiper.activeIndex;
       },
     },
   });
 };
 const goToViwe = (item) => {
+  if (!item.url) {
+    return;
+  }
   openData.value = {
     url: item.url,
     name: item.name,
@@ -66,6 +83,34 @@ onMounted(() => {
 });
 </script>
 <style lang="scss" scoped>
+.video-layer {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.9);
+  z-index: 100000;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  .video-box {
+    width: 100%;
+    height: 5.7333rem;
+    video {
+      width: 100%;
+      height: auto;
+    }
+  }
+  .close-btn {
+    width: 0.9333rem;
+    height: 0.9333rem;
+    margin-top: 2.2133rem;
+    background: url("@/assets/images/video-close.png") no-repeat;
+    background-size: 100% 100%;
+  }
+}
 .food {
   width: 100%;
   height: 100%;
@@ -73,7 +118,14 @@ onMounted(() => {
   position: relative;
   overflow-x: hidden;
   background: url("@/assets/images/foodBg.png") no-repeat;
-  background-size: cover;
+  background-size: 100% 100%;
+  .top {
+    width: 100%;
+    height: 50%;
+    position: absolute;
+    left: 0;
+    // top: 13%;
+  }
   .food-title {
     font-weight: bold;
     font-size: 0.4267rem;
@@ -83,7 +135,7 @@ onMounted(() => {
     align-items: center;
     justify-content: center;
     position: absolute;
-    top: 12%;
+    top: 30%;
     left: 50%;
     transform: translateX(-50%);
     min-width: 5.5333rem;
@@ -91,30 +143,68 @@ onMounted(() => {
     background: url("@/assets/images/foodTitleBg.png") no-repeat;
     background-size: 100% 100%;
   }
-  
-  .miniprogram-btn {
-    font-weight: bold;
-    font-size: 0.4667rem;
-    color: #ffffff;
-    line-height: 0.3733rem;
-    width: 4.2666rem;
-    height: 1.0933rem;
-    background: url("@/assets/images/fristBtn.png") no-repeat;
-    background-size: 100% 100%;
+  .food-msg {
     position: absolute;
-    bottom: 10%;
-    left: 50%;
-    transform: translateX(-50%);
-    display: flex;
-    align-items: center;
-    justify-content: center;
+    width: 100%;
+    height: 50%;
+    left: 0;
+    bottom: 0;
+    padding: 0 1.3333rem;
+    .video-btn {
+      width: 1.3333rem;
+      height: 1.3333rem;
+      background: url("@/assets/images/video-btn.png") no-repeat;
+      background-size: 100% 100%;
+      position: absolute;
+      top: 23%;
+      left: 50%;
+      transform: translateX(-50%);
+      z-index: 2;
+    }
+    .desc {
+      padding: 0 1.3333rem;
+      width: 100%;
+      max-height: 44%;
+      overflow-y: auto;
+      position: absolute;
+      top: 35%;
+      left: 50%;
+      transform: translateX(-50%);
+      font-weight: 400;
+      font-size: 0.28rem;
+      color: #707070;
+      line-height: 0.4133rem;
+      letter-spacing: 0.0267rem;
+      z-index: 1;
+    }
+    .miniprogram-btn {
+      font-weight: bold;
+      font-size: 0.4667rem;
+      color: #ffffff;
+      line-height: 0.3733rem;
+      width: 4.2666rem;
+      height: 1.0933rem;
+      background: url("@/assets/images/fristBtn.png") no-repeat;
+      background-size: 100% 100%;
+      position: absolute;
+      bottom: 5%;
+      left: 50%;
+      transform: translateX(-50%);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      z-index: 2;
+    }
   }
+
   .food-container {
     // margin-top: 28vh;
-    height: 38%;
+    // height: 38%;
+    height: 76%;
     width: 100%;
     position: absolute;
-    top: 22%;
+    // top: 22%;
+    top: 50%;
     left: 0;
     .swiper-slide {
       // background: red;
@@ -126,6 +216,10 @@ onMounted(() => {
       display: flex;
       align-items: center;
       justify-content: center;
+      transform: scale(0.8);
+      &.swiper-slide-active {
+        transform: scale(1);
+      }
       .slide-bg {
         position: absolute;
         width: 110%;
@@ -140,7 +234,7 @@ onMounted(() => {
       img {
         width: 80%;
         height: 36%;
-        object-fit: cover;
+        object-fit: contain;
         z-index: 2;
         position: relative;
       }
@@ -150,6 +244,7 @@ onMounted(() => {
       transform: scale(0.64);
     }
     .swiper-slide-active {
+      transform: scale(1);
     }
     .swiper-slide-next {
       transform: scale(0.64);

+ 14 - 13
src/views/home/index.vue

@@ -14,7 +14,8 @@
         <div class="cloud-2"></div>
       </div>
       <div class="title"></div>
-      <div class="btn" @click="enter"><span class="animate__animated animate__infinite animate__pulse animate__slow">即刻游览</span></div>
+      <!-- class="animate__animated animate__infinite animate__pulse animate__slow" -->
+      <div class="btn" @click="enter"><span >即刻游览</span></div>
     </div>
   </div>
 </template>
@@ -263,28 +264,28 @@ const goItem = (type) => {
       background: url("@/assets/images/effect/boat.png") no-repeat;
       background-size: 100% 100%;
       position: absolute;
-      bottom: 20%;
-      left: 12%;
-      transform: scale(0.8);
+      bottom: 18%;
+      left: 8%;
+      transform: scale(0.6);
     }
     .cloud-1 {
-      width: 8.7733rem;
-      height: 5.3333rem;
+      width: 5.264rem;
+      height: 3.2rem;
       background: url("@/assets/images/effect/cloud1.png") no-repeat;
       background-size: 100% 100%;
       position: absolute;
-      top: 40%;
-      left: 50%;
-      transform: translateX(-50%);
+      top: 50%;
+      left: 18%;
     }
     .cloud-2 {
-      width: 6.3733rem;
-      height: 4.8267rem;
+      width: 3.824rem;
+      height: 2.896rem;
       background: url("@/assets/images/effect/cloud2.png") no-repeat;
       background-size: 100% 100%;
       position: absolute;
-      bottom: 10%;
-      right: -10%;
+      bottom: 12%;
+      right: 0;
+      // transform: scale(0.7);
     }
   }
   .title {

File diff ditekan karena terlalu besar
+ 17 - 521
src/views/line/data.js


+ 77 - 50
src/views/line/index.vue

@@ -13,8 +13,8 @@
           <span>江湖风味游</span>
         </div>
         <div class="time">
-          <span class="num">7个景点</span>
-          <span>预计用时:10小时</span>
+          <span class="num">{{ lineData.length }}个景点</span>
+          <span>预计用时:{{ Math.round(overTime / 3600) }}小时</span>
         </div>
       </div>
       <div class="bottom">
@@ -37,8 +37,28 @@ import AMapLoader from "@amap/amap-jsapi-loader";
 import jsonp from "jsonp";
 import Header from "@/components/header/index.vue";
 import { mapData } from "../map/data.js";
+import { trvelLine } from "./data.js";
+import { useRoute } from "vue-router";
+
 import Dialog from "../map/dialog.vue";
+import tagIcon1 from "@/assets/images/tag-1.png";
+import tagIcon2 from "@/assets/images/tag-2.png";
+import tagIcon3 from "@/assets/images/tag-3.png";
+import tagIcon4 from "@/assets/images/tag-4.png";
+import tagIcon5 from "@/assets/images/tag-5.png";
+import tagIcon6 from "@/assets/images/tag-6.png";
 import tagIcon from "@/assets/images/tagIcon.png";
+import router from "@/router/index.js";
+const route = useRoute();
+const lineId = ref(route.params.id || 1);
+let iconList = {
+  tagIcon1,
+  tagIcon2,
+  tagIcon3,
+  tagIcon4,
+  tagIcon5,
+  tagIcon6,
+};
 let AMap = null;
 let map = null;
 let imageLayer = null;
@@ -50,32 +70,9 @@ const vrLink = ref(null);
 const goVr = () => {
   vrLink.value = props.dialogData.vrLink;
 };
+const trvelList = ref(trvelLine);
+const overTime = ref(3600);
 
-const test = (data) => {
-  let zoom = map.getZoom();
-  let item = markers.find((i) => i.getExtData().id == data.id);
-  // let data = item.getExtData();
-  infoWindow = new AMap.InfoWindow({
-    content: getHtml(data), // 设置弹窗内容为自定义的HTML元素
-    offset: new AMap.Pixel(0, -30), // 设置弹窗偏移量,可根据需要调整
-  });
-
-  // infoWindow.open(map, e.target.getPosition());
-  infoWindow.open(map, item.getPosition());
-
-  let center = data.location.split(",");
-  map.setZoomAndCenter(zoom, center, false, 300);
-  setTimeout(() => {
-    setTimeout(() => {
-      const button = document.getElementById("detailsBtn");
-      button.addEventListener("click", openDetails);
-      const vrBtn = document.getElementById("vrBtn");
-      vrBtn.addEventListener("click", openVrLink);
-      const closeBtn = document.getElementById("closeBtn");
-      closeBtn.addEventListener("click", closeTag);
-    }, 100);
-  }, 100);
-};
 const getHtml = (data) => {
   activeTagData.value = data;
   let html = `<div class="map-window">
@@ -96,7 +93,6 @@ const openDetails = (data) => {
   dialogData.value = activeTagData.value;
 };
 const openVrLink = () => {
-  console.error(activeTagData.value);
   // vrLink.value = activeTagData.value.vrLink;
   vrLink.value = 'https://www.4dkankan.com/panorama/show.html?id=WK1916704161229172736&lang=zh&rnd=0.7835560589743076"';
   if (activeTagData.value.vrLink) {
@@ -114,7 +110,6 @@ const hanlderMakerEvent = (e) => {
   let data = e.target.getExtData();
   // dialogData.value = data;
 
-  console.error(e);
 
   infoWindow = new AMap.InfoWindow({
     content: getHtml(data), // 设置弹窗内容为自定义的HTML元素
@@ -123,30 +118,65 @@ const hanlderMakerEvent = (e) => {
   infoWindow.open(map, e.target.getPosition());
   setTimeout(() => {
     const button = document.getElementById("detailsBtn");
-    button.addEventListener("click", openDetails);
     const vrBtn = document.getElementById("vrBtn");
-    vrBtn.addEventListener("click", openVrLink);
     const closeBtn = document.getElementById("closeBtn");
+
+    button.addEventListener("click", openDetails);
+    vrBtn.addEventListener("click", openVrLink);
     closeBtn.addEventListener("click", closeTag);
+    button.addEventListener("touchstart", openDetails);
+    vrBtn.addEventListener("touchstart", openVrLink);
+    closeBtn.addEventListener("touchstart", closeTag);
   }, 100);
 };
 let markers = [];
 const lineData = ref([]);
-const gotoItem = (item) => {
-  // let marker = markers.find((i) => i.getExtData().id == item.id);
-  // let data = marker.getExtData();
-  // dialogData.value = data;
-  test(item);
+const gotoItem = (data) => {
+  let zoom = map.getZoom();
+  let item = markers.find((i) => i.getExtData().id == data.id);
+  // let data = item.getExtData();
+  infoWindow = new AMap.InfoWindow({
+    content: getHtml(data), // 设置弹窗内容为自定义的HTML元素
+    offset: new AMap.Pixel(0, -30), // 设置弹窗偏移量,可根据需要调整
+  });
+
+  // infoWindow.open(map, e.target.getPosition());
+  infoWindow.open(map, item.getPosition());
+
+  let center = data.location.split(",");
+  map.setZoomAndCenter(zoom, center, false, 300);
+  setTimeout(() => {
+    setTimeout(() => {
+      const button = document.getElementById("detailsBtn");
+      const vrBtn = document.getElementById("vrBtn");
+      const closeBtn = document.getElementById("closeBtn");
+
+      button.addEventListener("click", openDetails);
+      vrBtn.addEventListener("click", openVrLink);
+      closeBtn.addEventListener("click", closeTag);
+
+      button.addEventListener("touchstart", openDetails);
+      vrBtn.addEventListener("touchstart", openVrLink);
+      closeBtn.addEventListener("touchstart", closeTag);
+    }, 100);
+  }, 100);
 };
 const setMarker = () => {
-  let data = mapData.filter((item) => item.type == 4);
-  lineData.value = data;
+  let data = trvelList.value.find((item) => item.id == lineId.value);
+
+  data.list.forEach((item) => {
+    let info = mapData.find((mapItem) => item == mapItem.id);
+    lineData.value.push(info);
+  });
+
+  // let data = mapData.filter((item) => item.type == 4);
+  // lineData.value = data;
   let scale = 0.2;
   const markerContent = `<div class="custom-content-marker">
     <div class="title">sdasdas</div>
     <div class="icon"></div>
       </div>`;
-  for (let i = 0; i < data.length; i++) {
+  for (let i = 0; i < lineData.value.length; i++) {
     let iconW = 41;
     let iconH = 57;
     let customIcon = null;
@@ -164,13 +194,14 @@ const setMarker = () => {
     offset = new AMap.Pixel(-(iconW / 2), -(iconH / 2));
     customIcon = new AMap.Icon({
       size: new AMap.Size(iconW, iconH),
-      image: tagIcon,
+      // image: eval(`tagIcon${lineData.value[i].type}`),
+      image: iconList[`tagIcon${lineData.value[i].type}`],
       imageSize: new AMap.Size(iconW, iconH),
     });
     // }
 
-    let pos = data[i].location.split(",");
-    let extData = data[i];
+    let pos = lineData.value[i].location.split(",");
+    let extData = lineData.value[i];
     let marker = new AMap.Marker({
       // position: new AMap.LngLat(106.837106, 29.712762),
 
@@ -187,7 +218,7 @@ const setMarker = () => {
       icon: customIcon, //添加 icon 图标 URL
       // title: data[i].name,
       zooms: [9, 20], // 设置可见级别,[最小级别,最大级别]
-      id: `marker_${data[i].id}`,
+      id: `marker_${lineData.value[i].id}`,
       extData: {
         //自定义数据
         ...extData,
@@ -206,8 +237,7 @@ const setMarker = () => {
 };
 
 const createdLine = () => {
-  let data = mapData.filter((item) => item.type == 4);
-  console.error(data);
+  let data = lineData.value;
   var driving = new AMap.Driving({
     //驾车路线规划策略,0是速度优先的策略
     policy: AMap.DrivingPolicy.LEAST_TIME,
@@ -232,8 +262,8 @@ const createdLine = () => {
   driving.search(startLngLat, endLngLat, opts, function (status, result) {
     if (status === "complete") {
       if (result.routes && result.routes.length) {
-        console.error(result);
         drawRoute(result);
+        overTime.value = result.routes[0].time;
         // log.success('绘制步行路线完成')
       }
     } else {
@@ -459,9 +489,7 @@ const initMap = async () => {
   // });
   // map.add(circle);
   // tilerLayer.setMap(map);
-  tilerLayer.on("click", () => {
-    console.error("click");
-  });
+  tilerLayer.on("click", () => {});
   map.on("zoomchange", () => {
     console.log("当前缩放级别:", map.getZoom());
     // if (map.getZoom() < 10 || map.getZoom() > 15) {
@@ -484,7 +512,6 @@ const initMap = async () => {
 
     //触发事件类型
     var type = ev.type;
-    console.error(pixel);
   });
 
   map.add(imageLayer);

+ 151 - 15
src/views/map/index.vue

@@ -1,4 +1,5 @@
 <template>
+  <!-- <div class="test-box" ref="testDom" :style="`transform:rotate(${angle}deg);`">1</div> -->
   <div class="map-box">
     <Header title="智游岳阳" />
 
@@ -40,7 +41,7 @@
     <!-- </div> -->
 
     <!-- <div class="open-line" @click="showLineList = true"></div> -->
-    <div class="open-chat" @click="switchChat()"></div>
+    <div class="open-chat" @click="switchChat()" :class="roleShow ? 'in' : 'out'"></div>
     <div class="slide-tab">
       <div class="btn" @click="slideToView('/food')"></div>
       <div class="btn"></div>
@@ -85,11 +86,11 @@
       <transition appear name="fade" enter-active-class="animate__animated animate__slideInUp short faster" leave-active-class="animate__animated animate__slideOutDown short faster">
         <div class="line-box" v-show="showLineBox">
           <div class="line-list">
-            <div class="list-item" @click.stop="goLine(i)" v-for="i in 4">
+            <div class="list-item" @click.stop="goLine(i)" v-for="i in trvelList">
               <div class="content">
-                <p class="title">江湖风味游</p>
+                <p class="title">{{ i.name }}</p>
                 <span class="tag">拍照必打卡</span>
-                <p class="desc">预计用时:10小时,共7个景点</p>
+                <p class="desc">预计用时:{{ Math.round(i.time / 3600) }}小时,共{{ i.list.length }}个景点</p>
               </div>
               <div class="ticket"></div>
             </div>
@@ -112,13 +113,89 @@ import Dialog from "./dialog.vue";
 import Header from "@/components/header/index.vue";
 import "swiper/css/swiper.css";
 import { mapData, typeData } from "./data.js";
+import { trvelLine } from "../line/data.js";
+import tagIcon1 from "@/assets/images/tag-1.png";
+import tagIcon2 from "@/assets/images/tag-2.png";
+import tagIcon3 from "@/assets/images/tag-3.png";
+import tagIcon4 from "@/assets/images/tag-4.png";
+import tagIcon5 from "@/assets/images/tag-5.png";
+import tagIcon6 from "@/assets/images/tag-6.png";
 import tagIcon from "@/assets/images/tagIcon.png";
 import MarkdownIt from "markdown-it";
-// import { mapStores } from "pinia";
+import { mapStores } from "pinia";
 import router from "@/router";
+// import Hammer from "hammerjs";
+// const testDom = ref(null);
+// let hammer = null;
+// const angle = ref(0);
+// const initHammer = () => {
+//   hammer = new Hammer(testDom.value);
+//   hammer.on("pan", function (ev) {
+//     //回调
+//     // angle = ev;
+//     // angle = ev.angle;
+//     angle.value = Math.ceil(ev.angle);
+
+//     // console.log(angle * (Math.PI / 180));
+//     console.log(Math.ceil(ev.angle));
+//     // console.log(angle * (180 / Math.PI));
+//   });
+// };
+let iconList = {
+  tagIcon1,
+  tagIcon2,
+  tagIcon3,
+  tagIcon4,
+  tagIcon5,
+  tagIcon6,
+};
+const trvelList = ref(trvelLine);
 const compass = ref(null);
 const showLineList = ref(false);
 const showLineBox = ref(false);
+const initTrvel = () => {
+  trvelList.value.forEach((item, index) => {
+    let stratObj = mapData.find((i) => item.list[0] == i.id);
+    let endObj = mapData.find((i) => item.list[item.list.length - 1] == i.id);
+
+    var startLngLat = [stratObj.location.split(",")[0], stratObj.location.split(",")[1]]; //起始点坐标
+    var endLngLat = [endObj.location.split(",")[0], endObj.location.split(",")[1]]; //终点坐标
+
+    var opts = {
+      waypoints: [], //途经点参数,最多支持传入16个途经点
+    };
+    item.list.map((j_item, j_index) => {
+      if (j_index != 0 || j_index != item.list.length - 1) {
+        let obj = mapData.find((data) => j_item == data.id);
+        opts.waypoints.push([obj.location.split(",")[0], obj.location.split(",")[1]]);
+      }
+    });
+    // return obj
+    // j_item = obj;
+
+    var driving = new AMap.Driving({
+      //驾车路线规划策略,0是速度优先的策略
+      policy: AMap.DrivingPolicy.LEAST_TIME,
+      //map 指定将路线规划方案绘制到对应的 AMap.Map 对象上
+      // map: map,
+      //panel 指定将结构化的路线详情数据显示的对应的 DOM 上,传入值需是 DOM 的 ID
+      // panel: "panel",
+    });
+
+    // //搜索完成后,将自动绘制路线到地图上
+    driving.search(startLngLat, endLngLat, opts, function (status, result) {
+      if (status === "complete") {
+        if (result.routes && result.routes.length) {
+          item.time = result.routes[0].time;
+          // drawRoute(result);
+          // log.success('绘制步行路线完成')
+        }
+      } else {
+        // log.error('步行路线数据查询失败' + result)
+      }
+    });
+  });
+};
 const getDeg = () => {
   let deg = 0;
   switch (tabType.value) {
@@ -160,8 +237,8 @@ const md = new MarkdownIt();
 const scrollRef = ref(null);
 // console.error(mapData);
 
-const goLine = (id) => {
-  router.replace(`/line/${id}`);
+const goLine = (i) => {
+  router.replace(`/line/${i.id}`);
 };
 const messages = ref([]);
 if (sessionStorage.getItem("messages")) {
@@ -346,7 +423,8 @@ const setMarker = () => {
     offset = new AMap.Pixel(-(iconW / 2), -(iconH / 2));
     customIcon = new AMap.Icon({
       size: new AMap.Size(iconW, iconH),
-      image: tagIcon,
+      // image: eval(`tagIcon${data[i].type}`),
+      image: iconList[`tagIcon${data[i].type}`],
       imageSize: new AMap.Size(iconW, iconH),
     });
     // customIcon = markerContent;
@@ -543,6 +621,8 @@ const initMap = async () => {
     resizeEnable: true, // 是否监控地图容器尺寸变化
   });
 
+  initTrvel();
+
   // tilerLayer.setMap(map);
   tilerLayer.on("click", () => {
     console.error("click");
@@ -600,7 +680,6 @@ const addImageLayer = () => {
   });
 };
 
-
 //*
 // *effect 是否false 需要过渡
 // /
@@ -618,6 +697,8 @@ const switchView = (effect = true) => {
         break;
       case 4:
         scale = 13;
+      case 3:
+        scale = 12;
         break;
     }
   }
@@ -706,10 +787,25 @@ const searchPos = () => {
 const rotateNum = ref(0);
 let tabNum = ref(0);
 const questW = ref(10000);
+const roleShow = ref(true);
+const initKeyFrames = () => {
+  let timer = null;
+  sto();
+  function sto() {
+    timer = setTimeout(() => {
+      roleShow.value = !roleShow.value;
+      clearTimeout(timer);
+      timer = null;
+      sto();
+    }, 2000);
+  }
+};
 onMounted(() => {
   initMap();
   nextTick(() => {
-    initTab();
+    // initHammer();
+    // initTab();
+    initKeyFrames();
     setTimeout(() => {
       let questItems = document.querySelectorAll(".quest-item");
       let w = 0;
@@ -724,6 +820,19 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
+.test-box {
+  width: 200px;
+  height: 200px;
+  position: fixed;
+  z-index: 100;
+  left: 50%;
+  top: 50%;
+  transform: translate(-50%, -50%);
+  background: #fff;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
 .map-box {
   width: 100%;
   height: 100%;
@@ -854,15 +963,42 @@ onMounted(() => {
   }
 
   .open-chat {
-    width: 1.3333rem;
-    height: 1.3333rem;
-    background: url("@/assets/images/deepseekBtn.png") no-repeat;
+    width: 2.4rem;
+    height: 2.9333rem;
+    background: url("@/assets/images/effect/role.png") no-repeat;
     background-size: 100% 100%;
-    position: absolute;
-    bottom: 20%;
+    position: fixed;
+    bottom: 10%;
     right: 0;
     z-index: 1000;
+    transform: translateX(30%) scale(1) rotate(0deg);
+
+    transform-origin: center right;
+    &.out {
+      animation: moveOut 0.3s ease-in-out forwards;
+    }
+    &.in {
+      // animation: moveIn 0.5s linear infinite alternate;
+      animation: moveIn 0.3s ease forwards;
+    }
+  }
+  @keyframes moveOut {
+    0% {
+      transform: translateX(30%) scale(1) rotate(0deg);
+    }
+    100% {
+      transform: translateX(100%) scale(0) rotate(60deg);
+    }
   }
+  @keyframes moveIn {
+    0% {
+      transform: translateX(100%) scale(0) rotate(30deg);
+    }
+    100% {
+      transform: translateX(30%) scale(1) rotate(0deg);
+    }
+  }
+
   .slide-tab {
     width: 1.4933rem;
     height: 4.6933rem;

+ 5 - 0
yarn.lock

@@ -1270,6 +1270,11 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0:
   resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
   integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
 
+hammerjs@^2.0.8:
+  version "2.0.8"
+  resolved "https://registry.npmmirror.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
+  integrity sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==
+
 has-symbols@^1.0.3, has-symbols@^1.1.0:
   version "1.1.0"
   resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"