chenlei 2 ماه پیش
کامیت
fc08ce913e
100فایلهای تغییر یافته به همراه5493 افزوده شده و 0 حذف شده
  1. 1 0
      .env
  2. 37 0
      .gitignore
  3. 2 0
      .npmrc
  4. 33 0
      index.html
  5. 9 0
      jsconfig.json
  6. 34 0
      package.json
  7. 2 0
      pano-viewer/.npmrc
  8. 16 0
      pano-viewer/index.html
  9. 26 0
      pano-viewer/package.json
  10. 1926 0
      pano-viewer/pnpm-lock.yaml
  11. 124 0
      pano-viewer/public/tour.xml
  12. 110 0
      pano-viewer/src/App.tsx
  13. 58 0
      pano-viewer/src/components/PanoList.tsx
  14. BIN
      pano-viewer/src/images/Component-19_01.png
  15. BIN
      pano-viewer/src/images/Component-19_02.png
  16. BIN
      pano-viewer/src/images/Component-19_03.png
  17. BIN
      pano-viewer/src/images/down.png
  18. BIN
      pano-viewer/src/images/icon_address.png
  19. 161 0
      pano-viewer/src/index.scss
  20. 11 0
      pano-viewer/src/main.tsx
  21. 16 0
      pano-viewer/src/scenes.ts
  22. 7 0
      pano-viewer/src/utils.scss
  23. 1 0
      pano-viewer/src/vite-env.d.ts
  24. 17 0
      pano-viewer/tsconfig.json
  25. 65 0
      pano-viewer/vite.config.ts
  26. 2540 0
      pnpm-lock.yaml
  27. 23 0
      postcss.config.js
  28. 1 0
      public/pano/assets/index-C5C85eRq.css
  29. 132 0
      public/pano/assets/index-CaEWFS2W.js
  30. 17 0
      public/pano/index.html
  31. 124 0
      public/pano/tour.xml
  32. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_01.jpg
  33. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_02.jpg
  34. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_03.jpg
  35. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_01.jpg
  36. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_02.jpg
  37. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_03.jpg
  38. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_01.jpg
  39. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_02.jpg
  40. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_03.jpg
  41. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_01.jpg
  42. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_02.jpg
  43. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_03.jpg
  44. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_04.jpg
  45. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_05.jpg
  46. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_01.jpg
  47. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_02.jpg
  48. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_03.jpg
  49. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_04.jpg
  50. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_05.jpg
  51. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_01.jpg
  52. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_02.jpg
  53. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_03.jpg
  54. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_04.jpg
  55. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_05.jpg
  56. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_01.jpg
  57. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_02.jpg
  58. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_03.jpg
  59. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_04.jpg
  60. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_05.jpg
  61. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_01.jpg
  62. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_02.jpg
  63. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_03.jpg
  64. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_04.jpg
  65. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_05.jpg
  66. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_01.jpg
  67. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_02.jpg
  68. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_03.jpg
  69. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_04.jpg
  70. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_05.jpg
  71. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_06.jpg
  72. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_07.jpg
  73. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_08.jpg
  74. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_09.jpg
  75. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_01.jpg
  76. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_02.jpg
  77. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_03.jpg
  78. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_04.jpg
  79. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_05.jpg
  80. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_06.jpg
  81. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_07.jpg
  82. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_08.jpg
  83. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_09.jpg
  84. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_01.jpg
  85. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_02.jpg
  86. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_03.jpg
  87. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_04.jpg
  88. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_05.jpg
  89. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_06.jpg
  90. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_07.jpg
  91. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_08.jpg
  92. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_09.jpg
  93. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_01.jpg
  94. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_02.jpg
  95. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_03.jpg
  96. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_04.jpg
  97. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_05.jpg
  98. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_06.jpg
  99. BIN
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_07.jpg
  100. 0 0
      public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_08.jpg

+ 1 - 0
.env

@@ -0,0 +1 @@
+VITE_PUBLIC_URL=.

+ 37 - 0
.gitignore

@@ -0,0 +1,37 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules/*
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
+
+.eslintcache
+
+# Cypress
+/cypress/videos/
+/cypress/screenshots/
+
+# Vitest
+__screenshots__/
+node_modules

+ 2 - 0
.npmrc

@@ -0,0 +1,2 @@
+registry=https://registry.npmmirror.com/
+@dage:registry=http://192.168.20.245:4873/

+ 33 - 0
index.html

@@ -0,0 +1,33 @@
+<!doctype html>
+<html lang="">
+  <head>
+    <meta charset="UTF-8" />
+    <link rel="icon" href="/favicon.ico" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>绥芬河市中东铁路</title>
+    <style>
+      * {
+        margin: 0;
+        padding: 0;
+        box-sizing: border-box;
+      }
+
+      #app-container {
+        width: 100vw;
+        height: 100vh;
+        overflow-y: auto;
+      }
+
+      #app {
+        width: 100%;
+        height: 100%;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="app-container">
+      <div id="app"></div>
+    </div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

+ 9 - 0
jsconfig.json

@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "jsx": "react",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}

+ 34 - 0
package.json

@@ -0,0 +1,34 @@
+{
+  "name": "sfh-pano",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "dev:pano": "pnpm --dir pano-viewer dev",
+    "build:pano": "pnpm --dir pano-viewer build",
+    "build": "pnpm build:pano && vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "@vueuse/core": "^12.0.0",
+    "autoprefixer": "^10.4.20",
+    "element-plus": "^2.9.0",
+    "lodash": "^4.18.1",
+    "pinia": "^2.2.6",
+    "postcss-px-to-viewport": "^1.1.1",
+    "swiper": "^11.1.15",
+    "vue": "^3.5.13",
+    "vue-lazyload-next": "^0.0.2",
+    "vue-qrcode": "^2.2.2",
+    "vue-router": "^4.4.5"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^5.2.1",
+    "sass": "^1.82.0",
+    "unplugin-auto-import": "^0.18.6",
+    "unplugin-vue-components": "^0.27.5",
+    "vite": "^6.0.1"
+  }
+}

+ 2 - 0
pano-viewer/.npmrc

@@ -0,0 +1,2 @@
+registry=https://registry.npmmirror.com/
+@dage:registry=http://192.168.20.245:4873/

+ 16 - 0
pano-viewer/index.html

@@ -0,0 +1,16 @@
+<!doctype html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <meta
+      name="viewport"
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
+    />
+    <title>全景</title>
+    <script src="../tour.js"></script>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="module" src="/src/main.tsx"></script>
+  </body>
+</html>

+ 26 - 0
pano-viewer/package.json

@@ -0,0 +1,26 @@
+{
+  "name": "pano-viewer",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@dage/krpano": "^4.0.0",
+    "@dage/utils": "^1.3.0",
+    "react": "^18.3.1",
+    "react-dom": "^18.3.1",
+    "swiper": "^11.1.15",
+    "tslib": "^2.8.1"
+  },
+  "devDependencies": {
+    "@types/react": "^18.3.12",
+    "@types/react-dom": "^18.3.1",
+    "@vitejs/plugin-react": "^4.3.4",
+    "sass": "^1.82.0",
+    "typescript": "^5.6.3",
+    "vite": "^6.0.1"
+  }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1926 - 0
pano-viewer/pnpm-lock.yaml


+ 124 - 0
pano-viewer/public/tour.xml

@@ -0,0 +1,124 @@
+<krpano version="1.19" title="">
+	<scene name="scene_SG-6C2hfsv0XgF" title="SG-6C2hfsv0XgF" onstart="" thumburl="../panos/SG-6C2hfsv0XgF.tiles/thumb.jpg" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-6C2hfsv0XgF.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-AvlgkYjZjVb" title="SG-AvlgkYjZjVb" onstart="" thumburl="../panos/SG-AvlgkYjZjVb.tiles/thumb.jpg" lat="44.39056044" lng="131.15041353" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-AvlgkYjZjVb.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-L0hjrhuL68K" title="SG-L0hjrhuL68K" onstart="" thumburl="../panos/SG-L0hjrhuL68K.tiles/thumb.jpg" lat="44.39122000" lng="131.15422208" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-L0hjrhuL68K.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-rBuP7Q8VGem" title="SG-rBuP7Q8VGem" onstart="" thumburl="../panos/SG-rBuP7Q8VGem.tiles/thumb.jpg" lat="44.39227553" lng="131.15545886" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-rBuP7Q8VGem.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-Uhfwlhc8ff2" title="SG-Uhfwlhc8ff2" onstart="" thumburl="../panos/SG-Uhfwlhc8ff2.tiles/thumb.jpg" lat="44.39094692" lng="131.15259697" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-Uhfwlhc8ff2.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-yNl9f7UXWhg" title="SG-yNl9f7UXWhg" onstart="" thumburl="../panos/SG-yNl9f7UXWhg.tiles/thumb.jpg" lat="44.39128461" lng="131.15492306" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-yNl9f7UXWhg.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+
+</krpano>
+

+ 110 - 0
pano-viewer/src/App.tsx

@@ -0,0 +1,110 @@
+import { Krpano } from "@dage/krpano";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+
+import PanoList from "./components/PanoList";
+import { getSceneNameByNum } from "./scenes";
+
+const FOOTER_RESIZE_MESSAGE = "pano-footer-resize";
+
+function getSceneNum() {
+  return new URLSearchParams(window.location.search).get("num") ?? "";
+}
+
+function postFooterHeight(height: number) {
+  if (window.parent === window) {
+    return;
+  }
+
+  window.parent.postMessage(
+    {
+      type: FOOTER_RESIZE_MESSAGE,
+      height,
+    },
+    "*",
+  );
+}
+
+export default function App() {
+  const initialNum = useMemo(() => getSceneNum(), []);
+  const [activeNum, setActiveNum] = useState(initialNum);
+  const [footerHidden, setFooterHidden] = useState(false);
+  const footerWrapRef = useRef<HTMLDivElement>(null);
+  const sceneName = activeNum ? getSceneNameByNum(activeNum) : "";
+
+  const notifyFooterHeight = useCallback(() => {
+    const el = footerWrapRef.current;
+
+    if (!el) {
+      return;
+    }
+
+    const { top, bottom } = el.getBoundingClientRect();
+    const viewportHeight = window.innerHeight;
+
+    if (bottom <= 0 || top >= viewportHeight) {
+      postFooterHeight(0);
+      return;
+    }
+
+    const height = Math.max(0, viewportHeight - top);
+    postFooterHeight(height);
+  }, []);
+
+  useEffect(() => {
+    const el = footerWrapRef.current;
+
+    if (!el) {
+      return;
+    }
+
+    notifyFooterHeight();
+
+    const observer = new ResizeObserver(notifyFooterHeight);
+    observer.observe(el);
+
+    window.addEventListener("resize", notifyFooterHeight);
+
+    return () => {
+      observer.disconnect();
+      window.removeEventListener("resize", notifyFooterHeight);
+    };
+  }, [notifyFooterHeight, footerHidden]);
+
+  const toggleFooter = () => {
+    setFooterHidden((hidden) => !hidden);
+  };
+
+  if (!sceneName) {
+    return <div className="pano-error">缺少 num 参数</div>;
+  }
+
+  return (
+    <div className="pano-container">
+      <Krpano
+        basepath="../"
+        xml="tour.xml"
+        currentScene={sceneName}
+        initvars={{ startscene: sceneName }}
+        littlePlanetIntro={true}
+        passQueryParameters={true}
+      />
+
+      <div
+        className={`pano-footer-wrap ${footerHidden ? "is-hidden" : ""}`}
+        ref={footerWrapRef}
+      >
+        <button
+          type="button"
+          className={`pano-footer-hide-btn ${footerHidden ? "is-hidden" : ""}`}
+          onClick={toggleFooter}
+        >
+          <span>{footerHidden ? "展开" : "收起"}</span>
+        </button>
+
+        <div className={`pano-footer`}>
+          <PanoList activeNum={activeNum} onChange={setActiveNum} />
+        </div>
+      </div>
+    </div>
+  );
+}

+ 58 - 0
pano-viewer/src/components/PanoList.tsx

@@ -0,0 +1,58 @@
+import { useRef } from "react";
+import type { Swiper as SwiperInstance } from "swiper";
+import { Swiper, SwiperSlide } from "swiper/react";
+
+import { getThumbUrl, SCENES } from "../scenes";
+
+import "swiper/css";
+
+type PanoListProps = {
+  activeNum: string;
+  onChange: (num: string) => void;
+};
+
+export default function PanoList({ activeNum, onChange }: PanoListProps) {
+  const swiperRef = useRef<SwiperInstance | null>(null);
+
+  const slideToActiveIfNeeded = (index: number) => {
+    const swiper = swiperRef.current;
+
+    if (!swiper || index < 0 || swiper.isLocked) {
+      return;
+    }
+
+    swiper.slideTo(index);
+  };
+
+  return (
+    <Swiper
+      className="pano-list"
+      slidesPerView="auto"
+      spaceBetween={20}
+      slidesOffsetBefore={15}
+      slidesOffsetAfter={15}
+      watchOverflow
+      onSwiper={(swiper) => {
+        swiperRef.current = swiper;
+        slideToActiveIfNeeded(
+          SCENES.findIndex((item) => item.num === activeNum),
+        );
+      }}
+    >
+      {SCENES.map((item, index) => (
+        <SwiperSlide key={item.num}>
+          <div
+            className={`pano-card ${item.num === activeNum ? "active" : ""}`}
+            style={{ backgroundImage: `url(${getThumbUrl(item.num)})` }}
+            onClick={() => {
+              onChange(item.num);
+              slideToActiveIfNeeded(index);
+            }}
+          >
+            <p>{item.name}</p>
+          </div>
+        </SwiperSlide>
+      ))}
+    </Swiper>
+  );
+}

BIN
pano-viewer/src/images/Component-19_01.png


BIN
pano-viewer/src/images/Component-19_02.png


BIN
pano-viewer/src/images/Component-19_03.png


BIN
pano-viewer/src/images/down.png


BIN
pano-viewer/src/images/icon_address.png


+ 161 - 0
pano-viewer/src/index.scss

@@ -0,0 +1,161 @@
+@use "./utils.scss";
+
+:root {
+  --design-width: 1920;
+  --design-height: 973;
+}
+
+html,
+body,
+#root {
+  width: 100%;
+  height: 100%;
+  margin: 0;
+  overflow: hidden;
+  background: #000;
+}
+
+.pano-container {
+  width: 100%;
+  height: 100%;
+}
+
+#krpano {
+  width: 100%;
+  height: 100%;
+}
+
+.pano-error {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  color: #fff;
+  font-size: 16px;
+}
+
+.pano-footer-wrap {
+  position: fixed;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  transition: bottom 0.35s ease;
+
+  &.is-hidden {
+    bottom: utils.vh-calc(-165);
+  }
+}
+
+.pano-footer {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  height: utils.vh-calc(165);
+  border: 1px solid #d6b280;
+  overflow: hidden;
+  box-sizing: border-box;
+  background: linear-gradient(#2b5b6d, #183d4b);
+
+  &-hide-btn {
+    position: relative;
+    top: 1px;
+    display: flex;
+    align-items: center;
+    gap: utils.vw-calc(4);
+    justify-content: center;
+    flex-shrink: 0;
+    margin-left: utils.vw-calc(20);
+    width: utils.vw-calc(90);
+    height: utils.vh-calc(20);
+    padding: 0;
+    font-size: utils.vh-calc(14);
+    border-radius: 5px;
+    color: #d6b280;
+    border: 1px solid #d6b280;
+    border-bottom: 0;
+    border-bottom-left-radius: 0;
+    border-bottom-right-radius: 0;
+    background: #2b5b6d;
+    cursor: pointer;
+    z-index: 9;
+
+    &::before {
+      content: "";
+      width: utils.vw-calc(10);
+      height: utils.vw-calc(10);
+      background: url("./images/down.png") center / contain no-repeat;
+      transition: transform 0.35s ease;
+    }
+
+    &.is-hidden {
+      margin-bottom: 0;
+
+      &::before {
+        transform: rotate(180deg);
+      }
+    }
+  }
+}
+
+.pano-list {
+  width: 100%;
+
+  .swiper-slide {
+    width: utils.vw-calc(203);
+    height: auto;
+  }
+}
+
+.pano-card {
+  position: relative;
+  width: 100%;
+  height: utils.vh-calc(130);
+  cursor: pointer;
+  background: center / cover no-repeat;
+  box-sizing: border-box;
+
+  &::before {
+    content: "";
+    position: absolute;
+    inset: 0;
+    background: rgba($color: #000000, $alpha: 0.5);
+  }
+  p {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    margin: 0;
+    color: white;
+    font-size: utils.vh-calc(14);
+    text-wrap: nowrap;
+    transform: translate(-50%, -50%);
+  }
+  &.active {
+    border: 2px solid #ffdc98;
+
+    &::before {
+      display: none;
+    }
+    p {
+      top: unset;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      margin: 0;
+      padding: 0 utils.vw-calc(10);
+      text-align: center;
+      color: white;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      height: utils.vh-calc(30);
+      line-height: utils.vh-calc(30);
+      background: rgba($color: #000000, $alpha: 0.5);
+      transform: none;
+    }
+  }
+}

+ 11 - 0
pano-viewer/src/main.tsx

@@ -0,0 +1,11 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+
+import App from "./App";
+import "./index.scss";
+
+createRoot(document.getElementById("root")!).render(
+  <StrictMode>
+    <App />
+  </StrictMode>,
+);

+ 16 - 0
pano-viewer/src/scenes.ts

@@ -0,0 +1,16 @@
+export const SCENES = [
+  { num: "SG-yNl9f7UXWhg", name: "苏俄学校旧址" },
+  { num: "SG-6C2hfsv0XgF", name: "绥芬河市铁路大白楼" },
+  { num: "SG-AvlgkYjZjVb", name: "火车站候车室" },
+  { num: "SG-Uhfwlhc8ff2", name: "东正教堂" },
+  { num: "SG-L0hjrhuL68K", name: "苏俄领事旧馆" },
+  { num: "SG-rBuP7Q8VGem", name: "日本领事馆旧址" },
+];
+
+export function getSceneNameByNum(num: string) {
+  return `scene_${num}`;
+}
+
+export function getThumbUrl(num: string) {
+  return `../panos/${num}.tiles/thumb.jpg`;
+}

+ 7 - 0
pano-viewer/src/utils.scss

@@ -0,0 +1,7 @@
+@function vh-calc($num) {
+  @return calc(100vh * ($num / var(--design-height)));
+}
+
+@function vw-calc($num) {
+  @return calc(100vw * ($num / var(--design-width)));
+}

+ 1 - 0
pano-viewer/src/vite-env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />

+ 17 - 0
pano-viewer/tsconfig.json

@@ -0,0 +1,17 @@
+{
+  "compilerOptions": {
+    "target": "ES2020",
+    "useDefineForClassFields": true,
+    "lib": ["ES2020", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "skipLibCheck": true,
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "strict": true
+  },
+  "include": ["src"]
+}

+ 65 - 0
pano-viewer/vite.config.ts

@@ -0,0 +1,65 @@
+import fs from "node:fs";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+import react from "@vitejs/plugin-react";
+import { defineConfig, type Plugin } from "vite";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const publicRoot = path.resolve(__dirname, "../public");
+
+/** 开发时从主项目 public 目录提供 tour.js / panos / skin 等静态资源 */
+function servePublicAssets(): Plugin {
+  const mimeTypes: Record<string, string> = {
+    ".js": "application/javascript",
+    ".xml": "application/xml",
+    ".jpg": "image/jpeg",
+    ".png": "image/png",
+    ".svg": "image/svg+xml",
+  };
+
+  return {
+    name: "serve-public-assets",
+    configureServer(server) {
+      server.middlewares.use((req, res, next) => {
+        const pathname = decodeURIComponent(req.url?.split("?")[0] ?? "");
+
+        if (
+          !pathname ||
+          pathname.startsWith("/@") ||
+          pathname.startsWith("/src/") ||
+          pathname.startsWith("/node_modules/") ||
+          pathname.startsWith("/assets/")
+        ) {
+          next();
+          return;
+        }
+
+        const relativePath = pathname.replace(/^\//, "");
+        const filePath = path.join(publicRoot, relativePath);
+
+        if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
+          next();
+          return;
+        }
+
+        const ext = path.extname(filePath);
+        res.setHeader("Content-Type", mimeTypes[ext] ?? "application/octet-stream");
+        fs.createReadStream(filePath).pipe(res);
+      });
+    },
+  };
+}
+
+export default defineConfig({
+  plugins: [react(), servePublicAssets()],
+  base: "./",
+  server: {
+    host: "0.0.0.0",
+    port: 5176,
+  },
+  build: {
+    outDir: "../public/pano",
+    emptyOutDir: true,
+  },
+});

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2540 - 0
pnpm-lock.yaml


+ 23 - 0
postcss.config.js

@@ -0,0 +1,23 @@
+export default {
+  plugins: {
+    autoprefixer: {},
+    "postcss-px-to-viewport": {
+      unitToConvert: "px", // 需要转换的单位,默认为"px"
+      viewportWidth: 1920, // 设计稿的视口宽度
+      unitPrecision: 5, // 单位转换后保留的精度
+      propList: ["*"], // 能转化为vw的属性列表
+      viewportUnit: "vw", // 希望使用的视口单位
+      fontViewportUnit: "vw", // 字体使用的视口单位
+      selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
+      minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
+      mediaQuery: true, // 媒体查询里的单位是否需要转换单位
+      replace: true, //  是否直接更换属性值,而不添加备用属性
+      exclude: undefined, // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
+      include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换
+      landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
+      landscapeUnit: "vw", // 横屏时使用的单位
+      landscapeWidth: 1920, // 横屏时使用的视口宽度
+      exclude: [/node_modules/],
+    },
+  },
+};

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
public/pano/assets/index-C5C85eRq.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 132 - 0
public/pano/assets/index-CaEWFS2W.js


+ 17 - 0
public/pano/index.html

@@ -0,0 +1,17 @@
+<!doctype html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <meta
+      name="viewport"
+      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
+    />
+    <title>全景</title>
+    <script src="../tour.js"></script>
+    <script type="module" crossorigin src="./assets/index-CaEWFS2W.js"></script>
+    <link rel="stylesheet" crossorigin href="./assets/index-C5C85eRq.css">
+  </head>
+  <body>
+    <div id="root"></div>

+  </body>
+</html>

+ 124 - 0
public/pano/tour.xml

@@ -0,0 +1,124 @@
+<krpano version="1.19" title="">
+	<scene name="scene_SG-6C2hfsv0XgF" title="SG-6C2hfsv0XgF" onstart="" thumburl="../panos/SG-6C2hfsv0XgF.tiles/thumb.jpg" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-6C2hfsv0XgF.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-6C2hfsv0XgF.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-AvlgkYjZjVb" title="SG-AvlgkYjZjVb" onstart="" thumburl="../panos/SG-AvlgkYjZjVb.tiles/thumb.jpg" lat="44.39056044" lng="131.15041353" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-AvlgkYjZjVb.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-AvlgkYjZjVb.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-L0hjrhuL68K" title="SG-L0hjrhuL68K" onstart="" thumburl="../panos/SG-L0hjrhuL68K.tiles/thumb.jpg" lat="44.39122000" lng="131.15422208" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-L0hjrhuL68K.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-L0hjrhuL68K.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-rBuP7Q8VGem" title="SG-rBuP7Q8VGem" onstart="" thumburl="../panos/SG-rBuP7Q8VGem.tiles/thumb.jpg" lat="44.39227553" lng="131.15545886" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-rBuP7Q8VGem.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-rBuP7Q8VGem.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-Uhfwlhc8ff2" title="SG-Uhfwlhc8ff2" onstart="" thumburl="../panos/SG-Uhfwlhc8ff2.tiles/thumb.jpg" lat="44.39094692" lng="131.15259697" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-Uhfwlhc8ff2.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-Uhfwlhc8ff2.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+	<scene name="scene_SG-yNl9f7UXWhg" title="SG-yNl9f7UXWhg" onstart="" thumburl="../panos/SG-yNl9f7UXWhg.tiles/thumb.jpg" lat="44.39128461" lng="131.15492306" heading="0.0">
+
+		<view hlookat="0.0" vlookat="0.0" fovtype="MFOV" fov="120" maxpixelzoom="2.0" fovmin="70" fovmax="140" limitview="auto" />
+
+		<preview url="../panos/SG-yNl9f7UXWhg.tiles/preview.jpg" />
+
+		<image type="CUBE" prealign="0|0.0|0" multires="true" tilesize="512">
+			<level tiledimagewidth="4608" tiledimageheight="4608">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l3/%0v/l3_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="2304" tiledimageheight="2304">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l2/%0v/l2_%s_%0v_%0h.jpg" />
+			</level>
+			<level tiledimagewidth="1152" tiledimageheight="1152">
+				<cube url="../panos/SG-yNl9f7UXWhg.tiles/%s/l1/%0v/l1_%s_%0v_%0h.jpg" />
+			</level>
+		</image>
+
+	</scene>
+
+
+</krpano>
+

BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/01/l1_b_01_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/02/l1_b_02_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l1/03/l1_b_03_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/01/l2_b_01_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/02/l2_b_02_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/03/l2_b_03_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/04/l2_b_04_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l2/05/l2_b_05_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_06.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_07.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_08.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/01/l3_b_01_09.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_06.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_07.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_08.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/02/l3_b_02_09.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_06.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_07.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_08.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/03/l3_b_03_09.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_01.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_02.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_03.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_04.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_05.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_06.jpg


BIN
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_07.jpg


+ 0 - 0
public/panos/SG-6C2hfsv0XgF.tiles/b/l3/04/l3_b_04_08.jpg


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است