chenlei 7 kuukautta sitten
vanhempi
commit
f3c5b7c5e8
100 muutettua tiedostoa jossa 2096 lisäystä ja 10 poistoa
  1. 38 5
      packages/base/index.js
  2. 18 0
      packages/base/utils.js
  3. 4 1
      packages/mobile/package.json
  4. 3 3
      packages/mobile/postcss.config.js
  5. 21 0
      packages/mobile/src/App.vue
  6. BIN
      packages/mobile/src/assets/images/14-min.png
  7. BIN
      packages/mobile/src/assets/images/19-min.png
  8. BIN
      packages/mobile/src/assets/images/20-min.png
  9. BIN
      packages/mobile/src/assets/images/21-min.png
  10. BIN
      packages/mobile/src/assets/images/22-min.png
  11. BIN
      packages/mobile/src/assets/images/bg.jpg
  12. BIN
      packages/mobile/src/assets/images/footer.jpg
  13. BIN
      packages/mobile/src/assets/images/more-min.png
  14. BIN
      packages/mobile/src/assets/images/top.jpg
  15. 79 0
      packages/mobile/src/components/Card.vue
  16. 54 0
      packages/mobile/src/components/Card2.vue
  17. 37 0
      packages/mobile/src/components/ChapterLayout.vue
  18. 4 0
      packages/mobile/src/main.js
  19. 35 0
      packages/mobile/src/router/index.js
  20. BIN
      packages/mobile/src/views/Chapter1/images/1-min.png
  21. BIN
      packages/mobile/src/views/Chapter1/images/2-min.png
  22. BIN
      packages/mobile/src/views/Chapter1/images/3-min.png
  23. BIN
      packages/mobile/src/views/Chapter1/images/4-min.png
  24. BIN
      packages/mobile/src/views/Chapter1/images/5-min.png
  25. BIN
      packages/mobile/src/views/Chapter1/images/6-min.png
  26. BIN
      packages/mobile/src/views/Chapter1/images/7-min.png
  27. BIN
      packages/mobile/src/views/Chapter1/images/img-min.png
  28. BIN
      packages/mobile/src/views/Chapter1/images/img2-min.png
  29. BIN
      packages/mobile/src/views/Chapter1/images/img3-min.png
  30. BIN
      packages/mobile/src/views/Chapter1/images/img4-min.png
  31. BIN
      packages/mobile/src/views/Chapter1/images/label1-min.png
  32. BIN
      packages/mobile/src/views/Chapter1/images/label2-min.png
  33. BIN
      packages/mobile/src/views/Chapter1/images/label3-min.png
  34. BIN
      packages/mobile/src/views/Chapter1/images/label4-min.png
  35. BIN
      packages/mobile/src/views/Chapter1/images/label5-min.png
  36. BIN
      packages/mobile/src/views/Chapter1/images/label6-min.png
  37. 196 0
      packages/mobile/src/views/Chapter1/index.scss
  38. 204 0
      packages/mobile/src/views/Chapter1/index.vue
  39. BIN
      packages/mobile/src/views/Chapter2/images/1-min.png
  40. BIN
      packages/mobile/src/views/Chapter2/images/2-min.png
  41. BIN
      packages/mobile/src/views/Chapter2/images/3-min.png
  42. 138 0
      packages/mobile/src/views/Chapter2/index.scss
  43. 57 0
      packages/mobile/src/views/Chapter2/index.vue
  44. BIN
      packages/mobile/src/views/Chapter3/images/1-min.png
  45. BIN
      packages/mobile/src/views/Chapter3/images/2-min.jpg
  46. BIN
      packages/mobile/src/views/Chapter3/images/3-min.jpg
  47. BIN
      packages/mobile/src/views/Chapter3/images/4-min.jpg
  48. BIN
      packages/mobile/src/views/Chapter3/images/5-min.png
  49. BIN
      packages/mobile/src/views/Chapter3/images/6-min.png
  50. BIN
      packages/mobile/src/views/Chapter3/images/label-min.png
  51. 165 0
      packages/mobile/src/views/Chapter3/index.scss
  52. 101 0
      packages/mobile/src/views/Chapter3/index.vue
  53. BIN
      packages/mobile/src/views/Chapter4/images/1-min.png
  54. BIN
      packages/mobile/src/views/Chapter4/images/10-min.png
  55. BIN
      packages/mobile/src/views/Chapter4/images/2-min.png
  56. BIN
      packages/mobile/src/views/Chapter4/images/3-min.png
  57. BIN
      packages/mobile/src/views/Chapter4/images/4-min.png
  58. BIN
      packages/mobile/src/views/Chapter4/images/5-min.png
  59. BIN
      packages/mobile/src/views/Chapter4/images/6-min.png
  60. BIN
      packages/mobile/src/views/Chapter4/images/7-min.png
  61. BIN
      packages/mobile/src/views/Chapter4/images/8-min.png
  62. BIN
      packages/mobile/src/views/Chapter4/images/9-min.png
  63. BIN
      packages/mobile/src/views/Chapter4/images/step/1-min.png
  64. BIN
      packages/mobile/src/views/Chapter4/images/step/2-min.png
  65. BIN
      packages/mobile/src/views/Chapter4/images/step/3-min.png
  66. BIN
      packages/mobile/src/views/Chapter4/images/step/4-min.png
  67. BIN
      packages/mobile/src/views/Chapter4/images/step/5-min.png
  68. BIN
      packages/mobile/src/views/Chapter4/images/step/6-min.png
  69. 378 0
      packages/mobile/src/views/Chapter4/index.scss
  70. 183 0
      packages/mobile/src/views/Chapter4/index.vue
  71. BIN
      packages/mobile/src/views/Detail/images/360-min.png
  72. BIN
      packages/mobile/src/views/Detail/images/card-bg-min.png
  73. BIN
      packages/mobile/src/views/Detail/images/ft-bg-min.jpg
  74. BIN
      packages/mobile/src/views/Detail/images/icon-min.png
  75. BIN
      packages/mobile/src/views/Detail/images/logo-min.png
  76. 71 0
      packages/mobile/src/views/Detail/index.scss
  77. 81 0
      packages/mobile/src/views/Detail/index.vue
  78. BIN
      packages/mobile/src/views/Home/images/bg-min.png
  79. BIN
      packages/mobile/src/views/Home/images/bg2-min.png
  80. BIN
      packages/mobile/src/views/Home/images/chapter1-img-min.png
  81. BIN
      packages/mobile/src/views/Home/images/chapter1-title-min.png
  82. BIN
      packages/mobile/src/views/Home/images/chapter2-img-min.png
  83. BIN
      packages/mobile/src/views/Home/images/chapter2-title-min.png
  84. BIN
      packages/mobile/src/views/Home/images/chapter3-img-min.png
  85. BIN
      packages/mobile/src/views/Home/images/chapter3-title-min.png
  86. BIN
      packages/mobile/src/views/Home/images/chapter4-img-min.png
  87. BIN
      packages/mobile/src/views/Home/images/chapter4-title-min.png
  88. BIN
      packages/mobile/src/views/Home/images/label-min.png
  89. BIN
      packages/mobile/src/views/Home/images/left.png
  90. BIN
      packages/mobile/src/views/Home/images/logo-min.png
  91. BIN
      packages/mobile/src/views/Home/images/muted.png
  92. BIN
      packages/mobile/src/views/Home/images/play.png
  93. BIN
      packages/mobile/src/views/Home/images/right.png
  94. BIN
      packages/mobile/src/views/Home/images/skip.png
  95. BIN
      packages/mobile/src/views/Home/images/unmuted.png
  96. BIN
      packages/mobile/src/views/Home/images/video-cover-min.jpg
  97. BIN
      packages/mobile/src/views/Home/index.mp4
  98. 102 0
      packages/mobile/src/views/Home/index.scss
  99. 127 1
      packages/mobile/src/views/Home/index.vue
  100. 0 0
      packages/mobile/src/views/Index/components/Chapter1/images/1-1-min.png

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 38 - 5
packages/base/index.js


+ 18 - 0
packages/base/utils.js

@@ -5,3 +5,21 @@ export const getEnvImagePath = (path) => {
     ? "http://192.168.0.18:8080" + path
     : `${window.origin}/project/yz-enamel-exhibition/base${path}`;
 };
+
+export function isMobile() {
+  const userAgent = navigator.userAgent.toLowerCase();
+  return /iphone|ipod|android|windows phone|blackberry|mobile/i.test(userAgent);
+}
+
+export function checkDeviceAndRedirect() {
+  const isMobileDevice = isMobile();
+  const currentPath = window.location.pathname;
+  const isInMobilePath = currentPath.includes("/mobile/");
+  const isInPCPath = currentPath.includes("/pc/");
+
+  if (isMobileDevice && !isInMobilePath) {
+    window.location.href = currentPath.replace("/pc/", "/mobile/");
+  } else if (!isMobileDevice && !isInPCPath) {
+    window.location.href = currentPath.replace("/mobile/", "/pc/");
+  }
+}

+ 4 - 1
packages/mobile/package.json

@@ -9,12 +9,15 @@
     "preview": "vite preview"
   },
   "dependencies": {
-    "element-plus": "^2.9.0",
+    "@enamel/base": "workspace:*",
     "pinia": "^2.2.6",
+    "swiper": "^11.1.15",
+    "vant": "^4.9.15",
     "vue": "^3.5.13",
     "vue-router": "^4.4.5"
   },
   "devDependencies": {
+    "@vant/auto-import-resolver": "^1.2.1",
     "@vitejs/plugin-vue": "^5.2.1",
     "autoprefixer": "^10.4.20",
     "postcss-px-to-viewport": "^1.1.1",

+ 3 - 3
packages/mobile/postcss.config.js

@@ -3,7 +3,7 @@ export default {
     autoprefixer: {},
     "postcss-px-to-viewport": {
       unitToConvert: "px", // 需要转换的单位,默认为"px"
-      viewportWidth: 1920, // 设计稿的视口宽度
+      viewportWidth: 750, // 设计稿的视口宽度
       unitPrecision: 5, // 单位转换后保留的精度
       propList: ["*"], // 能转化为vw的属性列表
       viewportUnit: "vw", // 希望使用的视口单位
@@ -12,11 +12,11 @@ export default {
       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, // 横屏时使用的视口宽度
+      landscapeWidth: 750, // 横屏时使用的视口宽度
+      exclude: [/node_modules/],
     },
   },
 };

+ 21 - 0
packages/mobile/src/App.vue

@@ -12,6 +12,27 @@ import { RouterView } from "vue-router";
   --design-height: 1080;
 }
 
+body {
+  font-size: 23px;
+  line-height: 51px;
+  text-indent: 2em;
+}
+
+.chapter-end {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  width: 100%;
+}
+
+.chapter-more {
+  position: absolute;
+  width: 181px;
+  height: 53px;
+  z-index: 9;
+}
+
 @media screen and (max-width: 768px) {
   :root {
     --design-width: 750;

BIN
packages/mobile/src/assets/images/14-min.png


BIN
packages/mobile/src/assets/images/19-min.png


BIN
packages/mobile/src/assets/images/20-min.png


BIN
packages/mobile/src/assets/images/21-min.png


BIN
packages/mobile/src/assets/images/22-min.png


BIN
packages/mobile/src/assets/images/bg.jpg


BIN
packages/mobile/src/assets/images/footer.jpg


BIN
packages/mobile/src/assets/images/more-min.png


BIN
packages/mobile/src/assets/images/top.jpg


+ 79 - 0
packages/mobile/src/components/Card.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="card" :class="`${chapter}-theme`">
+    <div class="card-img">
+      <img :src="getEnvImagePath(detail?.cover)" />
+    </div>
+    <div class="card-inner">
+      <p class="card__title">{{ detail?.name }}</p>
+      <p class="card__size">尺寸:{{ detail?.size }}</p>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { getEnvImagePath } from "@enamel/base/utils";
+
+defineProps(["detail", "initImgIndex", "chapter"]);
+</script>
+
+<style lang="scss" scoped>
+.card {
+  max-width: 310px;
+  cursor: pointer;
+
+  &.chapter2-theme {
+    .card-img {
+      background-image: url("@/assets/images/20-min.png");
+    }
+  }
+  &.chapter3-theme {
+    .card-img {
+      background-image: url("@/assets/images/21-min.png");
+    }
+  }
+  &.chapter4-theme {
+    .card-img {
+      background-image: url("@/assets/images/22-min.png");
+    }
+  }
+  &-img {
+    padding: 30px;
+    width: 300px;
+    height: 207px;
+    background: url("@/assets/images/19-min.png") no-repeat center / contain;
+
+    img {
+      display: block;
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+    }
+  }
+  &-inner {
+    position: relative;
+    padding: 15px 0 0 44px;
+    text-indent: 0;
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 17px;
+      left: 0;
+      width: 25px;
+      height: 25px;
+      background: url("@/assets/images/14-min.png") no-repeat center / contain;
+    }
+  }
+  &__title {
+    color: #1f1f1f;
+    line-height: 29px;
+  }
+  &__size {
+    margin-top: 8px;
+    color: #767676;
+    font-size: 14px;
+    line-height: 18px;
+    letter-spacing: 1px;
+  }
+}
+</style>

+ 54 - 0
packages/mobile/src/components/Card2.vue

@@ -0,0 +1,54 @@
+<template>
+  <div class="card2">
+    <slot name="img" />
+    <p class="card2__title">{{ title }}</p>
+    <p class="card2__author">{{ author }}</p>
+    <p v-if="content" class="card2__content">{{ content }}</p>
+  </div>
+</template>
+
+<script setup>
+defineProps(["title", "author", "content"]);
+</script>
+
+<style lang="scss" scoped>
+.card2 {
+  text-indent: 0;
+  color: #000000;
+  width: 452px;
+  cursor: pointer;
+
+  &__title {
+    position: relative;
+    padding: 20px 0 10px 30px;
+    font-size: 22px;
+    letter-spacing: 4px;
+    white-space: nowrap;
+    line-height: 33px;
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 26px;
+      left: 0;
+      width: 22px;
+      height: 21px;
+      background: url("@/assets/images/14-min.png") no-repeat center / contain;
+    }
+  }
+  &__author {
+    line-height: 25px;
+    text-align: right;
+    letter-spacing: 4px;
+    font-size: 14px;
+  }
+  &__content {
+    margin-top: 10px;
+    text-indent: 2em;
+    font-size: 17px;
+    color: #7d7d7d;
+    line-height: 34px;
+    font-family: "SourceHanSerifSC-Bold";
+  }
+}
+</style>

+ 37 - 0
packages/mobile/src/components/ChapterLayout.vue

@@ -0,0 +1,37 @@
+<template>
+  <div class="chapter-layout">
+    <img class="chapter-layout-top" src="@/assets/images/top.jpg" />
+    <div class="chapter-layout-border" :style="{ background: borderColor }" />
+
+    <slot />
+
+    <img class="chapter-layout-footer" src="@/assets/images/footer.jpg" />
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  borderColor: {
+    type: String,
+    default: "#c9a69b",
+  },
+});
+</script>
+
+<style lang="scss" scoped>
+.chapter-layout {
+  background: url("@/assets/images/bg.jpg") repeat;
+
+  &-top,
+  &-footer {
+    display: block;
+    width: 100%;
+  }
+  &-border {
+    margin-left: auto;
+    width: 435px;
+    height: 35px;
+    background: #c9a69b;
+  }
+}
+</style>

+ 4 - 0
packages/mobile/src/main.js

@@ -6,6 +6,10 @@ import { createPinia } from "pinia";
 import App from "./App.vue";
 import router from "./router";
 
+import { isDevelopment, checkDeviceAndRedirect } from "@enamel/base/utils";
+
+!isDevelopment && checkDeviceAndRedirect();
+
 const app = createApp(App);
 
 app.use(createPinia());

+ 35 - 0
packages/mobile/src/router/index.js

@@ -8,6 +8,41 @@ const router = createRouter({
       name: "home",
       component: () => import("../views/Home/index.vue"),
     },
+    {
+      path: "/index",
+      name: "index",
+      component: () => import("../views/Index/index.vue"),
+    },
+    {
+      path: "/chapter1",
+      name: "chapter1",
+      component: () => import("../views/Chapter1/index.vue"),
+    },
+    {
+      path: "/chapter2",
+      name: "chapter2",
+      component: () => import("../views/Chapter2/index.vue"),
+    },
+    {
+      path: "/chapter3",
+      name: "chapter3",
+      component: () => import("../views/Chapter3/index.vue"),
+    },
+    {
+      path: "/chapter4",
+      name: "chapter4",
+      component: () => import("../views/Chapter4/index.vue"),
+    },
+    {
+      path: "/chapter4",
+      name: "chapter4",
+      component: () => import("../views/Chapter4/index.vue"),
+    },
+    {
+      path: "/detail/:chapter/:index",
+      name: "detail",
+      component: () => import("../views/Detail/index.vue"),
+    },
   ],
 });
 

BIN
packages/mobile/src/views/Chapter1/images/1-min.png


BIN
packages/mobile/src/views/Chapter1/images/2-min.png


BIN
packages/mobile/src/views/Chapter1/images/3-min.png


BIN
packages/mobile/src/views/Chapter1/images/4-min.png


BIN
packages/mobile/src/views/Chapter1/images/5-min.png


BIN
packages/mobile/src/views/Chapter1/images/6-min.png


BIN
packages/mobile/src/views/Chapter1/images/7-min.png


BIN
packages/mobile/src/views/Chapter1/images/img-min.png


BIN
packages/mobile/src/views/Chapter1/images/img2-min.png


BIN
packages/mobile/src/views/Chapter1/images/img3-min.png


BIN
packages/mobile/src/views/Chapter1/images/img4-min.png


BIN
packages/mobile/src/views/Chapter1/images/label1-min.png


BIN
packages/mobile/src/views/Chapter1/images/label2-min.png


BIN
packages/mobile/src/views/Chapter1/images/label3-min.png


BIN
packages/mobile/src/views/Chapter1/images/label4-min.png


BIN
packages/mobile/src/views/Chapter1/images/label5-min.png


BIN
packages/mobile/src/views/Chapter1/images/label6-min.png


+ 196 - 0
packages/mobile/src/views/Chapter1/index.scss

@@ -0,0 +1,196 @@
+.chapter1 {
+  position: relative;
+  height: 5631px;
+
+  &-img {
+    position: absolute;
+    top: 66px;
+    left: 0;
+    width: 655px;
+    height: 289px;
+  }
+  &-content {
+    position: absolute;
+    top: 397px;
+    left: 50%;
+    width: 560px;
+    transform: translateX(-50%);
+  }
+  &-label {
+    position: absolute;
+    top: 727px;
+    left: 89px;
+    width: 129px;
+    height: 54px;
+  }
+  &-list1 {
+    position: absolute;
+    top: 828px;
+    left: 89px;
+    display: flex;
+  }
+  &-label2 {
+    position: absolute;
+    top: 1180px;
+    left: 89px;
+    width: 249px;
+    height: 55px;
+  }
+  &-content2 {
+    position: absolute;
+    top: 1300px;
+    left: 50%;
+    width: 560px;
+    transform: translateX(-50%);
+  }
+  &-list2 {
+    position: absolute;
+    top: 1629px;
+    left: 50%;
+    display: flex;
+    gap: 30px;
+    transform: translateX(-50%);
+
+    .img1 {
+      width: 269px;
+      height: 300px;
+    }
+    .img2 {
+      width: 304px;
+      height: 296px;
+    }
+  }
+  &-card {
+    width: 278px !important;
+  }
+  &-card2 {
+    width: 300px !important;
+  }
+  &-list3 {
+    position: absolute;
+    top: 2174px;
+    left: 50%;
+    display: flex;
+    gap: 35px;
+    transform: translateX(-50%);
+
+    :deep(.card-img) {
+      width: 283px;
+      height: 195px;
+    }
+  }
+  &-label3 {
+    position: absolute;
+    top: 2550px;
+    left: 69px;
+    width: 248px;
+    height: 53px;
+  }
+  &-card1 {
+    position: absolute;
+    top: 2650px;
+    left: 90px;
+    width: 352px !important;
+
+    .img3 {
+      width: 294px;
+      height: 340px;
+    }
+    :deep(.card2__title) {
+      padding: 22px 0 15px 30px;
+      font-size: 29px;
+    }
+    :deep(.card2__author) {
+      font-size: 18px;
+    }
+  }
+  &-content3 {
+    position: absolute;
+    top: 3120px;
+    left: 50%;
+    width: 560px;
+    transform: translateX(-50%);
+  }
+  &-list4 {
+    position: absolute;
+    left: 73px;
+    top: 3408px;
+  }
+  &-label4 {
+    position: absolute;
+    top: 3800px;
+    left: 73px;
+    width: 123px;
+    height: 48px;
+  }
+  &-list6 {
+    position: absolute;
+    left: 50%;
+    top: 3900px;
+    display: flex;
+    gap: 35px;
+    transform: translateX(-50%);
+
+    :deep(.card-img) {
+      width: 283px;
+      height: 195px;
+    }
+  }
+  &-label5 {
+    position: absolute;
+    top: 4260px;
+    left: 72px;
+    width: 124px;
+    height: 54px;
+  }
+  &-list5 {
+    position: absolute;
+    left: 73px;
+    top: 4360px;
+  }
+  &-label6 {
+    position: absolute;
+    bottom: 857px;
+    left: 72px;
+    width: 489px;
+    height: 54px;
+  }
+  &-swiper {
+    --swiper-scrollbar-sides-offset: 72px;
+    --swiper-scrollbar-border-radius: 11px;
+    --swiper-scrollbar-drag-bg-color: #cd8b71;
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 128px;
+    cursor: pointer;
+
+    :deep(.swiper-wrapper) {
+      padding-bottom: 50px;
+    }
+    .swiper-slide {
+      width: 218px;
+      height: 595px;
+      text-indent: 0;
+
+      &:first-child {
+        margin-left: 72px;
+      }
+      &:last-child {
+        margin-right: 72px;
+      }
+    }
+    img {
+      width: 100%;
+      height: 100%;
+    }
+    :deep(.swiper-scrollbar) {
+      top: unset;
+      bottom: 0;
+      height: 11px;
+      overflow: hidden;
+      border: none;
+      background: transparent;
+    }
+  }
+}

+ 204 - 0
packages/mobile/src/views/Chapter1/index.vue

@@ -0,0 +1,204 @@
+<template>
+  <ChapterLayout>
+    <div class="chapter1">
+      <img src="./images/img-min.png" class="chapter1-img" />
+
+      <p class="chapter1-content">
+        明清时期,珐琅器因制作工艺复杂,釉料配制和烧造技术难度大,生产成本高,故主要是在宫廷中制作,专供皇室享用,民间鲜有流传。明崇祯年间,“景泰御前作坊之珐琅,精巧远迈前古,四方好事者,亦于内市重价购之。”至康雍乾时期,珐琅器更成为帝王挚爱的“内廷秘玩”,是“庶民弗得一窥”的御用品。
+      </p>
+
+      <!-- 陈设 -->
+      <img class="chapter1-label" src="./images/label1-min.png" />
+
+      <div class="chapter1-list1">
+        <Card
+          :detail="data.chapter1[0]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 0 },
+            })
+          "
+        />
+      </div>
+
+      <!-- 宫廷珐琅 -->
+      <img class="chapter1-label2" src="./images/label2-min.png" />
+
+      <p class="chapter1-content2">
+        宫廷珐琅是指专为宫廷制作和使用的珐琅制品。以胎体的不同,一般可分为金胎珐琅、铜胎珐琅、瓷胎珐琅、玻璃胎珐琅等。明清两代在宫廷内均设有专门机构进行生产珐琅器。明代是“御用监”;清代为“造办处”,并专门设“珐琅作”生产供皇室使用的金属珐琅器。
+      </p>
+
+      <div class="chapter1-list2">
+        <Card2
+          class="chapter1-card"
+          title="《乾隆雪景行乐图轴》"
+          author="郎世宁等(故宫博物院藏)"
+          content="此图描绘乾隆皇帝及皇子等多人在宫苑内观赏雪景的情景。房舍梁柱之间放有两个珐琅熏炉。"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 2 },
+            })
+          "
+        >
+          <template #img>
+            <img class="img1" draggable="false" src="./images/img2-min.png" />
+          </template>
+        </Card2>
+
+        <Card2
+          class="chapter1-card2"
+          title="《康熙帝万寿图(下卷)》"
+          author="清佚名(故宫博物院藏)"
+          content="画中上面中间帐篷桌几上放有一掐丝珐琅香熏。"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 3 },
+            })
+          "
+        >
+          <template #img>
+            <img class="img2" draggable="false" src="./images/img3-min.png" />
+          </template>
+        </Card2>
+      </div>
+
+      <div class="chapter1-list3">
+        <Card
+          :detail="data.chapter1[1]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 1 },
+            })
+          "
+        />
+        <Card
+          :detail="data.chapter1[4]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 4 },
+            })
+          "
+        />
+      </div>
+
+      <!-- 扬州珐琅 -->
+      <img src="./images/label3-min.png" class="chapter1-label3" />
+
+      <Card2
+        class="chapter1-card1"
+        title="《雍正行乐图册》"
+        author="佚名(故宫博物院藏)"
+        @click="
+          $router.push({
+            name: 'detail',
+            params: { chapter: 'chapter1', index: 6 },
+          })
+        "
+      >
+        <template #img>
+          <img class="img3" draggable="false" src="./images/img4-min.png" />
+        </template>
+      </Card2>
+
+      <p class="chapter1-content3">
+        扬州地区生产的掐丝珐琅器。清乾隆年间逐渐兴起。器物造型标新立异有天球瓶、桌灯、动物形尊等。图案装饰变化多端,与内廷珐琅作和广州风格截然不同,掐丝技巧娴熟线条匀细流畅。珐琅釉料色彩基调多为冷色对比强烈。
+      </p>
+
+      <div class="chapter1-list4">
+        <Card
+          :detail="data.chapter1[5]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 5 },
+            })
+          "
+        />
+      </div>
+
+      <!-- 生活 -->
+      <img src="./images/label4-min.png" class="chapter1-label4" />
+
+      <div class="chapter1-list6">
+        <Card
+          :detail="data.chapter1[8]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 8 },
+            })
+          "
+        />
+        <Card
+          :detail="data.chapter1[9]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 9 },
+            })
+          "
+        />
+      </div>
+
+      <!-- 宗教 -->
+      <img src="./images/label5-min.png" class="chapter1-label5" />
+
+      <div class="chapter1-list5">
+        <Card
+          :detail="data.chapter1[7]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter1', index: 7 },
+            })
+          "
+        />
+      </div>
+
+      <!-- 掐丝珐琅 -->
+      <img src="./images/label6-min.png" class="chapter1-label6" />
+
+      <Swiper
+        class="chapter1-swiper"
+        :modules="[FreeMode, Scrollbar]"
+        :slides-per-view="'auto'"
+        :space-between="30"
+        :free-mode="true"
+        :scrollbar="{ draggable: true }"
+      >
+        <SwiperSlide v-for="(img, index) in LIST" :key="index">
+          <img :src="img" />
+        </SwiperSlide>
+      </Swiper>
+    </div>
+  </ChapterLayout>
+</template>
+
+<script setup>
+import { data } from "@enamel/base";
+import Card from "@/components/Card.vue";
+import Card2 from "@/components/Card2.vue";
+import ChapterLayout from "@/components/ChapterLayout.vue";
+import { Swiper, SwiperSlide } from "swiper/vue";
+import { FreeMode, Scrollbar } from "swiper/modules";
+import "swiper/swiper-bundle.css";
+
+import Img1 from "./images/1-min.png";
+import Img2 from "./images/2-min.png";
+import Img3 from "./images/3-min.png";
+import Img4 from "./images/4-min.png";
+import Img5 from "./images/5-min.png";
+import Img6 from "./images/6-min.png";
+import Img7 from "./images/7-min.png";
+
+const LIST = [Img1, Img2, Img3, Img4, Img5, Img6, Img7];
+</script>
+
+<style lang="scss" scoped>
+@use "./index.scss";
+</style>

BIN
packages/mobile/src/views/Chapter2/images/1-min.png


BIN
packages/mobile/src/views/Chapter2/images/2-min.png


BIN
packages/mobile/src/views/Chapter2/images/3-min.png


+ 138 - 0
packages/mobile/src/views/Chapter2/index.scss

@@ -0,0 +1,138 @@
+.chapter2 {
+  position: relative;
+  height: 2250px;
+
+  &-img {
+    position: absolute;
+    top: 66px;
+    left: 0;
+    width: 659px;
+    height: 289px;
+  }
+  &-content {
+    position: absolute;
+    top: 397px;
+    left: 50%;
+    width: 600px;
+    transform: translateX(-50%);
+  }
+  &-card {
+    position: absolute;
+    top: 636px;
+    left: 82px;
+    width: 614px;
+    height: 441px;
+
+    &-img {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 244px;
+      height: 441px;
+    }
+    &-label {
+      position: absolute;
+      top: 144px;
+      right: 0;
+      width: 304px;
+      font-size: 25px;
+      line-height: 37px;
+      text-indent: 0;
+
+      span {
+        font-size: 15px;
+      }
+      &::before {
+        content: "";
+        position: absolute;
+        top: 50%;
+        left: -33px;
+        width: 25px;
+        height: 24px;
+        transform: translateY(-50%);
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+    }
+    &-content {
+      position: absolute;
+      top: 241px;
+      right: 40px;
+      width: 292px;
+      color: #7d7d7d;
+      line-height: 34px;
+      font-size: 20px;
+      font-family: "SourceHanSerifSC-Bold";
+    }
+  }
+  &-card2 {
+    position: absolute;
+    top: 1123px;
+    right: 73px;
+    display: flex;
+    gap: 20px;
+
+    &-inner {
+      position: relative;
+      flex: 1;
+      text-indent: 0;
+    }
+    &-label {
+      position: absolute;
+      top: 120px;
+      right: 0;
+      width: 203px;
+      font-size: 24px;
+      line-height: 37px;
+      letter-spacing: 1px;
+
+      &::before {
+        content: "";
+        position: absolute;
+        top: 50%;
+        left: -33px;
+        width: 25px;
+        height: 24px;
+        transform: translateY(-50%);
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+    }
+    span {
+      position: absolute;
+      top: 190px;
+      right: 15px;
+      white-space: nowrap;
+      font-size: 15px;
+    }
+    &-content {
+      position: absolute;
+      right: 30px;
+      bottom: 10px;
+      color: #7d7d7d;
+      white-space: nowrap;
+      font-family: "SourceHanSerifSC-Bold";
+    }
+    img {
+      flex-shrink: 0;
+      width: 355px;
+      height: 290px;
+    }
+  }
+  &-list {
+    position: absolute;
+    left: 50%;
+    bottom: 114px;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 30px;
+    width: 594px;
+    transform: translateX(-50%);
+
+    > * {
+      width: 282px;
+    }
+    :deep(.card-img) {
+      width: 282px;
+      height: 195px;
+    }
+  }
+}

+ 57 - 0
packages/mobile/src/views/Chapter2/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <ChapterLayout border-color="#C8CFD4">
+    <div class="chapter2">
+      <img src="./images/1-min.png" class="chapter2-img" />
+
+      <p class="chapter2-content">
+        在明清时期的宫廷和贵族府邸中,珐琅器还被广泛用于室内装饰。无论是作为屏风、壁画还是摆件,珐琅器都能以其独特的色彩和图案为室内空间增添一份华贵与雅致。
+      </p>
+
+      <div class="chapter2-card">
+        <img src="./images/2-min.png" class="chapter2-card-img" />
+        <p class="chapter2-card-label">
+          《清雍正十二美人图<br />之捻珠观猫》<span>(故宫博物院藏)</span>
+        </p>
+        <p class="chapter2-card-content">
+          美人手持珊瑚十八子手串,桌面摆放着铜铸方鼎式香薰炉和青田石印章,身后的壶门券口带托泥架钟架上放置着一只紫檀木画珐琅自鸣钟。
+        </p>
+      </div>
+
+      <div class="chapter2-card2">
+        <div class="chapter2-card2-inner">
+          <p class="chapter2-card2-label">《清周慕桥闺中十二景图册》</p>
+          <span>(来源网络)</span>
+          <p class="chapter2-card2-content">墙面上挂有插屏。</p>
+        </div>
+        <img src="./images/3-min.png" />
+      </div>
+
+      <div class="chapter2-list">
+        <Card
+          v-for="index in LIST"
+          :key="index"
+          :detail="data.chapter2[index]"
+          chapter="chapter2"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter2', index },
+            })
+          "
+        />
+      </div>
+    </div>
+  </ChapterLayout>
+</template>
+
+<script setup>
+import { data } from "@enamel/base";
+import Card from "@/components/Card.vue";
+import ChapterLayout from "@/components/ChapterLayout.vue";
+
+const LIST = [0, 1, 2, 3];
+</script>
+
+<style lang="scss" scoped>
+@use "./index.scss";
+</style>

BIN
packages/mobile/src/views/Chapter3/images/1-min.png


BIN
packages/mobile/src/views/Chapter3/images/2-min.jpg


BIN
packages/mobile/src/views/Chapter3/images/3-min.jpg


BIN
packages/mobile/src/views/Chapter3/images/4-min.jpg


BIN
packages/mobile/src/views/Chapter3/images/5-min.png


BIN
packages/mobile/src/views/Chapter3/images/6-min.png


BIN
packages/mobile/src/views/Chapter3/images/label-min.png


+ 165 - 0
packages/mobile/src/views/Chapter3/index.scss

@@ -0,0 +1,165 @@
+.chapter3 {
+  position: relative;
+  height: 3537px;
+
+  &-img {
+    position: absolute;
+    top: 65px;
+    left: 0;
+    width: 656px;
+    height: 291px;
+  }
+  &-content {
+    position: absolute;
+    top: 397px;
+    left: 50%;
+    width: 577px;
+    transform: translateX(-50%);
+  }
+  &-list {
+    position: absolute;
+    top: 675px;
+    left: 91px;
+    display: flex;
+    gap: 20px;
+
+    .card2:first-child {
+      width: 291px;
+    }
+    .card2:last-child {
+      width: 263px;
+    }
+    .img1 {
+      width: 291px;
+      height: 347px;
+    }
+    .img2 {
+      width: 263px;
+      height: 348px;
+    }
+  }
+  &-card {
+    position: absolute;
+    top: 1302px;
+    right: 91px;
+    display: flex;
+    align-items: flex-end;
+    gap: 25px;
+
+    img {
+      flex-shrink: 0;
+      width: 252px;
+      height: 532px;
+    }
+    &-inner {
+      position: relative;
+      flex: 1;
+      text-align: right;
+      padding-bottom: 20px;
+    }
+    &-label {
+      position: relative;
+      font-size: 29px;
+
+      &::before {
+        content: "";
+        position: absolute;
+        top: 50%;
+        left: 0;
+        width: 25px;
+        height: 24px;
+        transform: translateY(-50%);
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+    }
+    span {
+      font-size: 18px;
+    }
+    &-content {
+      width: 273px;
+      color: #7d7d7d;
+      font-size: 20px;
+      line-height: 34px;
+      text-align: justify;
+      font-family: "SourceHanSerifSC-Bold";
+    }
+  }
+  &-label {
+    position: absolute;
+    top: 1929px;
+    left: 69px;
+    width: 316px;
+    height: 54px;
+  }
+  &-content2 {
+    position: absolute;
+    top: 2048px;
+    left: 50%;
+    width: 577px;
+    transform: translateX(-50%);
+  }
+  &-list2 {
+    position: absolute;
+    top: 2336px;
+    left: 81px;
+    display: flex;
+    gap: 28px;
+    text-indent: 0;
+
+    > div {
+      display: flex;
+      flex-direction: column;
+      gap: 15px;
+
+      p {
+        position: relative;
+        padding-left: 42px;
+        font-size: 29px;
+        line-height: 44px;
+        letter-spacing: 2px;
+
+        &::before {
+          content: "";
+          position: absolute;
+          top: 50%;
+          left: 0;
+          width: 25px;
+          height: 24px;
+          transform: translateY(-50%);
+          background: url("@/assets/images/14-min.png") no-repeat center /
+            contain;
+        }
+      }
+    }
+    > div:first-child {
+      img {
+        width: 247px;
+        height: 343px;
+      }
+    }
+    > div:last-child {
+      img {
+        width: 300px;
+        height: 343px;
+      }
+    }
+  }
+  &-list3 {
+    position: absolute;
+    top: 2788px;
+    left: 50%;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 30px;
+    width: 576px;
+    transform: translateX(-50%);
+
+    .card {
+      width: 273px;
+    }
+    :deep(.card-img) {
+      width: 273px;
+      height: 189px;
+    }
+  }
+}

+ 101 - 0
packages/mobile/src/views/Chapter3/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <ChapterLayout border-color="#C9AE8E">
+    <div class="chapter3">
+      <img class="chapter3-img" src="./images/1-min.png" />
+
+      <p class="chapter3-content">
+        明清时期,随着金石学的发展和文人士大夫对古器物的热衷,仿古礼器制作达到一个高峰。这一时期,模仿古代青铜器或其他古代器物的造型、纹样和风格,结合珐琅工艺制作而成的工艺品也受到帝王及贵族的追捧,用于祭祀、陈设或把玩。
+      </p>
+
+      <div class="chapter3-list">
+        <Card2
+          title="《雍正行乐图册》"
+          author="清 佚名 (故宫博物院藏)"
+          content="某冬日,雍正帝在书房内炭火旁悠然阅读。室内书架及桌面放有珐琅器。"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter3', index: 5 },
+            })
+          "
+        >
+          <template #img>
+            <img class="img1" draggable="false" src="./images/2-min.jpg" />
+          </template>
+        </Card2>
+
+        <Card2
+          title="《月曼清游图册》"
+          author="清 陈枚 (故宫博物院藏)"
+          content="画面内容为宫内的妃子们在赏玩收藏的画卷及青铜器。"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter3', index: 7 },
+            })
+          "
+        >
+          <template #img>
+            <img class="img2" draggable="false" src="./images/3-min.jpg" />
+          </template>
+        </Card2>
+      </div>
+
+      <div class="chapter3-card">
+        <div class="chapter3-card-inner">
+          <p class="chapter3-card-label">《弘历观画图轴》</p>
+          <span> 郎世宁 (故宫博物院藏)</span>
+          <p class="chapter3-card-content">
+            画中乾隆皇帝命人打开画轴,进行品评,其旁边桌上放有珐琅瓷器、哥窑瓷壶、熏炉、青铜钟等,应均是乾隆收藏或仿制的器物。
+          </p>
+        </div>
+        <img src="./images/4-min.jpg" />
+      </div>
+
+      <img class="chapter3-label" src="./images/label-min.png" />
+
+      <p class="chapter3-content2">
+        明清时期,依据商周时期青铜器造型、纹饰等,运用掐丝珐琅工艺制作的珐琅器,一般称为仿古珐琅器。清代乾隆年间,下令制作了许多仿古珐琅作品,有鬲(炉)、尊、壶、觥、觚、甗等,这些多源自商周青铜器,并在其基础上进行了创新和发展。
+      </p>
+
+      <div class="chapter3-list2">
+        <div>
+          <img src="./images/5-min.png" />
+          <p>商周青铜器</p>
+        </div>
+        <div>
+          <img src="./images/6-min.png" />
+          <p>明清珐琅器</p>
+        </div>
+      </div>
+
+      <div class="chapter3-list3">
+        <Card
+          v-for="index in LIST"
+          :key="index"
+          chapter="chapter3"
+          :detail="data.chapter3[index + 1]"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { chapter: 'chapter3', index: index + 1 },
+            })
+          "
+        />
+      </div>
+    </div>
+  </ChapterLayout>
+</template>
+
+<script setup>
+import { data } from "@enamel/base";
+import Card from "@/components/Card.vue";
+import Card2 from "@/components/Card2.vue";
+import ChapterLayout from "@/components/ChapterLayout.vue";
+
+const LIST = [0, 1, 2, 3];
+</script>
+
+<style lang="scss" scoped>
+@use "./index.scss";
+</style>

BIN
packages/mobile/src/views/Chapter4/images/1-min.png


BIN
packages/mobile/src/views/Chapter4/images/10-min.png


BIN
packages/mobile/src/views/Chapter4/images/2-min.png


BIN
packages/mobile/src/views/Chapter4/images/3-min.png


BIN
packages/mobile/src/views/Chapter4/images/4-min.png


BIN
packages/mobile/src/views/Chapter4/images/5-min.png


BIN
packages/mobile/src/views/Chapter4/images/6-min.png


BIN
packages/mobile/src/views/Chapter4/images/7-min.png


BIN
packages/mobile/src/views/Chapter4/images/8-min.png


BIN
packages/mobile/src/views/Chapter4/images/9-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/1-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/2-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/3-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/4-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/5-min.png


BIN
packages/mobile/src/views/Chapter4/images/step/6-min.png


+ 378 - 0
packages/mobile/src/views/Chapter4/index.scss

@@ -0,0 +1,378 @@
+.chapter4 {
+  position: relative;
+  height: 6781px;
+
+  &-img {
+    position: absolute;
+    top: 66px;
+    left: 0;
+    width: 653px;
+    height: 289px;
+  }
+  &-content {
+    position: absolute;
+    top: 397px;
+    left: 50%;
+    width: 578px;
+    transform: translateX(-50%);
+  }
+  &-content2 {
+    position: absolute;
+    top: 787px;
+    left: 50%;
+    width: 553px;
+    font-size: 20px;
+    color: #352a28;
+    line-height: 44px;
+    transform: translateX(-50%);
+  }
+  &-img2 {
+    position: absolute;
+    top: 1125px;
+    left: 50%;
+    width: 458px;
+    height: 340px;
+    transform: translateX(-50%);
+  }
+  &-card {
+    position: absolute;
+    top: 1478px;
+    left: 50%;
+    text-indent: 0;
+    transform: translateX(-50%);
+
+    img {
+      display: block;
+      width: 564px;
+      height: 326px;
+    }
+    .label {
+      position: relative;
+      margin-top: 10px;
+      padding-left: 58px;
+      font-size: 34px;
+      letter-spacing: 4px;
+
+      span {
+        font-size: 21px;
+      }
+      &::before {
+        content: "";
+        position: absolute;
+        top: 50%;
+        left: 10px;
+        width: 25px;
+        height: 24px;
+        transform: translateY(-50%);
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+    }
+    .sublabel {
+      text-align: right;
+      font-size: 21px;
+      letter-spacing: 4px;
+    }
+  }
+  &-card2 {
+    position: absolute;
+    top: 1979px;
+    left: 78px;
+  }
+  &-img3 {
+    position: absolute;
+    top: 2339px;
+    left: 76px;
+    width: 191px;
+    height: 51px;
+  }
+  &-content3 {
+    position: absolute;
+    top: 2442px;
+    left: 50%;
+    width: 596px;
+    transform: translateX(-50%);
+  }
+  &-content4 {
+    position: absolute;
+    top: 2788px;
+    left: 50%;
+    width: 589px;
+    font-size: 20px;
+    line-height: 44px;
+    transform: translateX(-50%);
+  }
+  &-card3 {
+    position: absolute;
+    top: 2962px;
+    left: 50%;
+    width: 585px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    transform: translateX(-50%);
+
+    img {
+      width: 472px;
+      height: 219px;
+    }
+    .label {
+      position: relative;
+      margin: 25px 0;
+      padding-left: 53px;
+      font-size: 28px;
+      color: #000000;
+      width: 100%;
+      text-indent: 0;
+      letter-spacing: 4px;
+
+      span {
+        font-size: 17px;
+      }
+      &::before {
+        content: "";
+        position: absolute;
+        top: calc(50% - 4px);
+        left: 10px;
+        width: 25px;
+        height: 24px;
+        transform: translateY(-50%);
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+    }
+    .content {
+      font-size: 20px;
+      color: #7d7d7d;
+      line-height: 34px;
+      font-family: "SourceHanSerifSC-Bold";
+    }
+  }
+  &-list {
+    position: absolute;
+    top: 3493px;
+    left: 50%;
+    display: flex;
+    gap: 30px;
+    flex-wrap: wrap;
+    width: 592px;
+    transform: translateX(-50%);
+
+    .card {
+      width: 281px;
+    }
+    :deep(.card-img) {
+      width: 281px;
+      height: 194px;
+    }
+  }
+  &-img4 {
+    position: absolute;
+    top: 4252px;
+    left: 79px;
+    width: 503px;
+    height: 50px;
+  }
+  &-swiper {
+    --swiper-scrollbar-sides-offset: 72px;
+    --swiper-scrollbar-border-radius: 11px;
+    --swiper-scrollbar-drag-bg-color: #9f899d;
+    position: absolute;
+    top: 4352px;
+    left: 0;
+    right: 0;
+
+    :deep(.swiper-wrapper) {
+      padding-bottom: 60px;
+    }
+    .swiper-slide:nth-child(1) {
+      width: 215px;
+      height: 503px;
+    }
+    .swiper-slide:nth-child(2) {
+      width: 313px;
+      height: 503px;
+    }
+    .swiper-slide:nth-child(3) {
+      width: 215px;
+      height: 503px;
+    }
+    .swiper-slide:nth-child(4) {
+      width: 261px;
+      height: 503px;
+    }
+    .swiper-slide:nth-child(5) {
+      width: 333px;
+      height: 503px;
+    }
+    .swiper-slide:nth-child(6) {
+      width: 215px;
+      height: 503px;
+    }
+    .swiper-slide {
+      text-indent: 0;
+
+      &:first-child {
+        margin-left: 79px;
+      }
+      &:last-child {
+        margin-right: 79px;
+      }
+    }
+    img {
+      width: 100%;
+      height: 100%;
+    }
+    :deep(.swiper-scrollbar) {
+      top: unset;
+      bottom: 0;
+      height: 11px;
+      overflow: hidden;
+      border: none;
+      background: transparent;
+    }
+  }
+  &-content5 {
+    position: absolute;
+    top: 4952px;
+    left: 50%;
+    width: 587px;
+    font-size: 20px;
+    line-height: 44px;
+    transform: translateX(-50%);
+  }
+  &-card5 {
+    position: absolute;
+    top: 5073px;
+    left: 78px;
+  }
+  &-img5 {
+    position: absolute;
+    top: 5453px;
+    left: 77px;
+    width: 235px;
+    height: 50px;
+  }
+  &-content6 {
+    position: absolute;
+    top: 5533px;
+    left: 50%;
+    width: 596px;
+    transform: translateX(-50%);
+  }
+  &-content7 {
+    position: absolute;
+    top: 5771px;
+    left: 50%;
+    width: 587px;
+    font-size: 20px;
+    line-height: 44px;
+    transform: translateX(-50%);
+  }
+  &-list2 {
+    position: absolute;
+    left: 50%;
+    bottom: 556px;
+    display: flex;
+    align-items: flex-start;
+    gap: 74px;
+    transform: translateX(-50%);
+
+    > div {
+      position: relative;
+      text-indent: 0;
+      letter-spacing: 4px;
+      line-height: 39px;
+      white-space: nowrap;
+
+      &::before {
+        content: "";
+        position: absolute;
+        width: 27px;
+        height: 27px;
+        background: url("@/assets/images/14-min.png") no-repeat center / contain;
+      }
+      .label {
+        position: absolute;
+        font-size: 28px;
+
+        span {
+          font-size: 17px;
+        }
+      }
+      .sub {
+        position: absolute;
+        font-size: 17px;
+      }
+    }
+  }
+  .chapter4-card6 {
+    &::before {
+      top: 256px;
+      left: -12px;
+    }
+    img {
+      width: 226px;
+      height: 226px;
+    }
+    .label {
+      top: 250px;
+      left: 30px;
+    }
+    .sub {
+      top: 290px;
+      left: 13px;
+    }
+  }
+  .chapter4-card7 {
+    &::before {
+      top: 259px;
+      left: 0;
+    }
+    img {
+      width: 237px;
+      height: 263px;
+    }
+    .label {
+      top: 255px;
+      left: 43px;
+    }
+    .sub {
+      top: 300px;
+      left: 43px;
+    }
+  }
+  &-card8 {
+    position: absolute;
+    left: 50%;
+    bottom: 90px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    transform: translateX(-50%);
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 258px;
+      left: 21px;
+      width: 30px;
+      height: 29px;
+      background: url("@/assets/images/14-min.png") no-repeat center / contain;
+    }
+    img {
+      width: 584px;
+      height: 262px;
+    }
+    .label {
+      margin-top: -10px;
+      padding-left: 60px;
+      font-size: 30px;
+      letter-spacing: 4px;
+      text-indent: 0;
+      white-space: nowrap;
+
+      span {
+        font-size: 19px;
+      }
+    }
+  }
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 183 - 0
packages/mobile/src/views/Chapter4/index.vue


BIN
packages/mobile/src/views/Detail/images/360-min.png


BIN
packages/mobile/src/views/Detail/images/card-bg-min.png


BIN
packages/mobile/src/views/Detail/images/ft-bg-min.jpg


BIN
packages/mobile/src/views/Detail/images/icon-min.png


BIN
packages/mobile/src/views/Detail/images/logo-min.png


+ 71 - 0
packages/mobile/src/views/Detail/index.scss

@@ -0,0 +1,71 @@
+.detail {
+  min-height: 100vh;
+  background: url("@/assets/images/bg.jpg") repeat;
+
+  &-main {
+    padding: 100px 70px 60px;
+    min-height: calc(100vh - 200px);
+    letter-spacing: 4px;
+
+    h3 {
+      padding: 25px 0 20px;
+      font-size: 34px;
+      color: #4b4b4b;
+      text-indent: 0;
+      font-family: "SourceHanSerifSC-Bold";
+    }
+    > p {
+      text-indent: 0;
+      font-size: 17px;
+      color: #535353;
+      line-height: 34px;
+    }
+    > img {
+      margin: 40px 0 35px;
+      display: block;
+      width: 48px;
+      height: 40px;
+    }
+    > div {
+      font-size: 18px;
+      color: #414141;
+      line-height: 36px;
+    }
+  }
+  &-img {
+    position: relative;
+    padding: 40px;
+    width: 100%;
+    height: 610px;
+    text-indent: 0;
+    background: url("./images/card-bg-min.png") no-repeat center / contain;
+
+    .van-swipe,
+    .van-image {
+      height: 100%;
+    }
+    .van-image {
+      width: 100%;
+    }
+    &__360 {
+      position: absolute;
+      top: 47px;
+      right: 40px;
+      width: 66px;
+      height: 38px;
+    }
+  }
+  &-footer {
+    position: relative;
+    height: 200px;
+    background: url("./images/ft-bg-min.jpg") no-repeat center / cover;
+
+    img {
+      position: absolute;
+      top: 80px;
+      right: 25px;
+      width: 400px;
+      height: 73px;
+    }
+  }
+}

+ 81 - 0
packages/mobile/src/views/Detail/index.vue

@@ -0,0 +1,81 @@
+<template>
+  <div class="detail">
+    <div class="detail-main">
+      <div v-if="detail" class="detail-img">
+        <VanImage
+          v-if="!Array.isArray(detail.img)"
+          fit="contain"
+          :src="getEnvImagePath(detail.img)"
+        />
+        <VanSwipe v-else height="100%">
+          <VanSwipeItem v-for="(item, index) in detail.img" :key="item">
+            <VanImage
+              fit="contain"
+              :src="getEnvImagePath(item)"
+              @click="
+                () => {
+                  show = true;
+                  startPosition = index;
+                }
+              "
+            />
+          </VanSwipeItem>
+        </VanSwipe>
+
+        <a v-if="model" :href="model">
+          <img
+            class="detail-img__360"
+            draggable="false"
+            src="./images/360-min.png"
+          />
+        </a>
+      </div>
+
+      <h3>{{ detail?.name }}</h3>
+      <p v-if="detail.size" class="size">尺寸:{{ detail?.size }}</p>
+      <img class="icon" draggable="false" src="./images/icon-min.png" />
+      <div class="content" v-html="detail?.content" />
+    </div>
+
+    <div class="detail-footer">
+      <img src="./images/logo-min.png" />
+    </div>
+
+    <VanImagePreview
+      v-model:show="show"
+      :images="images"
+      :startPosition="startPosition"
+    />
+  </div>
+</template>
+
+<script setup>
+import { computed, ref } from "vue";
+import { data } from "@enamel/base";
+import { useRoute } from "vue-router";
+import { getEnvImagePath } from "@enamel/base/utils";
+
+const route = useRoute();
+const show = ref(false);
+const startPosition = ref(0);
+const detail = computed(() => data[route.params.chapter][route.params.index]);
+const MODEL_LIST = {
+  chapter1: {
+    0: "https://4dscene.4dage.com/culturalrelics/demo2/Model.html?m=YZ_02yxz",
+    1: "https://4dscene.4dage.com/culturalrelics/demo2/Model.html?m=YZ_03xl",
+  },
+  chapter3: {
+    0: "https://4dscene.4dage.com/culturalrelics/demo2/Model.html?m=YZ_01ep",
+  },
+};
+const model = computed(
+  () => MODEL_LIST[route.params.chapter]?.[route.params.index]
+);
+const images = computed(
+  () => detail.value?.img.map((i) => getEnvImagePath(i)) || []
+);
+</script>
+
+<style lang="scss" scoped>
+@use "./index.scss";
+</style>

BIN
packages/mobile/src/views/Home/images/bg-min.png


BIN
packages/mobile/src/views/Home/images/bg2-min.png


BIN
packages/mobile/src/views/Home/images/chapter1-img-min.png


BIN
packages/mobile/src/views/Home/images/chapter1-title-min.png


BIN
packages/mobile/src/views/Home/images/chapter2-img-min.png


BIN
packages/mobile/src/views/Home/images/chapter2-title-min.png


BIN
packages/mobile/src/views/Home/images/chapter3-img-min.png


BIN
packages/mobile/src/views/Home/images/chapter3-title-min.png


BIN
packages/mobile/src/views/Home/images/chapter4-img-min.png


BIN
packages/mobile/src/views/Home/images/chapter4-title-min.png


BIN
packages/mobile/src/views/Home/images/label-min.png


BIN
packages/mobile/src/views/Home/images/left.png


BIN
packages/mobile/src/views/Home/images/logo-min.png


BIN
packages/mobile/src/views/Home/images/muted.png


BIN
packages/mobile/src/views/Home/images/play.png


BIN
packages/mobile/src/views/Home/images/right.png


BIN
packages/mobile/src/views/Home/images/skip.png


BIN
packages/mobile/src/views/Home/images/unmuted.png


BIN
packages/mobile/src/views/Home/images/video-cover-min.jpg


BIN
packages/mobile/src/views/Home/index.mp4


+ 102 - 0
packages/mobile/src/views/Home/index.scss

@@ -1 +1,103 @@
 @use "@/assets/utils.scss";
+
+.home {
+  height: 100vh;
+  background: url("./images/bg-min.png") no-repeat center / cover;
+
+  &-video {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    text-indent: 0;
+    z-index: 999;
+
+    video {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+    }
+    &-play {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      width: 64px;
+      height: 64px;
+      transform: translate(-50%, -50%);
+    }
+    &-skip {
+      position: absolute;
+      right: 30px;
+      bottom: 40px;
+      width: 170px;
+      height: 60px;
+    }
+    .muted {
+      position: absolute;
+      top: 30px;
+      right: 30px;
+      width: 60px;
+      height: 60px;
+    }
+  }
+  &__logo {
+    position: absolute;
+    top: utils.vh-calc(29);
+    left: utils.vh-calc(32);
+    width: utils.vh-calc(239);
+    height: utils.vh-calc(349);
+  }
+  &__label {
+    position: absolute;
+    top: utils.vh-calc(84);
+    right: utils.vh-calc(103);
+    width: utils.vh-calc(251);
+    height: utils.vh-calc(848);
+  }
+  &::after {
+    content: "";
+    position: absolute;
+    top: utils.vh-calc(377);
+    left: 0;
+    width: utils.vh-calc(324);
+    height: utils.vh-calc(877);
+    background: url("./images/bg2-min.png") no-repeat center / contain;
+  }
+  &-swipe {
+    position: absolute;
+    left: 50%;
+    bottom: utils.vh-calc(90);
+    width: 327px;
+    transform: translateX(-50%);
+
+    &-item {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      gap: 20px;
+      width: 100%;
+
+      img {
+        width: 100%;
+      }
+      &__img {
+        height: 355px;
+        object-fit: contain;
+      }
+    }
+    &-toggle {
+      position: absolute;
+      width: 57px;
+      height: 74px;
+      bottom: utils.vh-calc(258);
+
+      &.left {
+        left: 120px;
+      }
+      &.right {
+        right: 120px;
+      }
+    }
+  }
+}

+ 127 - 1
packages/mobile/src/views/Home/index.vue

@@ -1,7 +1,133 @@
 <template>
-  <div class="home"></div>
+  <div v-if="!showVideo" class="home">
+    <img class="home__logo" src="./images/logo-min.png" />
+    <img class="home__label" src="./images/label-min.png" />
+
+    <VanSwipe
+      ref="swipe"
+      class="home-swipe"
+      lazy-render
+      :show-indicators="false"
+    >
+      <VanSwipeItem
+        v-for="item in LIST"
+        :key="item.id"
+        class="home-swipe-item"
+        @click="$router.push({ name: 'index', query: { index: item.id } })"
+      >
+        <img :src="item.img" class="home-swipe-item__img" />
+        <img :src="item.label" class="home-swipe-item__label" />
+      </VanSwipeItem>
+    </VanSwipe>
+    <img
+      class="home-swipe-toggle left"
+      src="./images/left.png"
+      @click="handleChange"
+    />
+    <img
+      class="home-swipe-toggle right"
+      src="./images/right.png"
+      @click="handleChange('next')"
+    />
+  </div>
+
+  <div v-else class="home-video">
+    <video
+      ref="video"
+      src="./index.mp4"
+      poster="./images/video-cover-min.jpg"
+      x5-playsinline="true"
+      playsinline="true"
+      webkit-playsinline="true"
+      x-webkit-airplay="true"
+      x5-video-player-type="h5-page"
+      @ended="showVideo = false"
+    />
+
+    <img
+      v-if="!play"
+      src="./images/play.png"
+      class="home-video-play"
+      @click="handlePlayVideo"
+    />
+
+    <img
+      class="home-video-skip"
+      src="./images/skip.png"
+      @click="showVideo = false"
+    />
+
+    <img
+      class="muted"
+      :src="muted ? MutedIcon : UnMutedIcon"
+      @click="handleMuted"
+    />
+  </div>
 </template>
 
+<script setup>
+import { ref } from "vue";
+import Chapter1Img from "./images/chapter1-img-min.png";
+import Chapter2Img from "./images/chapter2-img-min.png";
+import Chapter3Img from "./images/chapter3-img-min.png";
+import Chapter4Img from "./images/chapter4-img-min.png";
+import Chapter1TitleImg from "./images/chapter1-title-min.png";
+import Chapter2TitleImg from "./images/chapter2-title-min.png";
+import Chapter3TitleImg from "./images/chapter3-title-min.png";
+import Chapter4TitleImg from "./images/chapter4-title-min.png";
+import MutedIcon from "./images/muted.png";
+import UnMutedIcon from "./images/unmuted.png";
+
+const showVideo = ref(true);
+const muted = ref(false);
+const play = ref(false);
+const video = ref(null);
+
+const LIST = [
+  {
+    id: 1,
+    img: Chapter1Img,
+    label: Chapter1TitleImg,
+  },
+  {
+    id: 2,
+    img: Chapter2Img,
+    label: Chapter2TitleImg,
+  },
+  {
+    id: 3,
+    img: Chapter3Img,
+    label: Chapter3TitleImg,
+  },
+  {
+    id: 4,
+    img: Chapter4Img,
+    label: Chapter4TitleImg,
+  },
+];
+const swipe = ref(null);
+
+const handleChange = (type) => {
+  if (type === "next") {
+    swipe.value.next();
+  } else {
+    swipe.value.prev();
+  }
+};
+
+const handleMuted = () => {
+  if (!video.value) return;
+  muted.value = !muted.value;
+  video.value.muted = muted.value;
+};
+
+const handlePlayVideo = () => {
+  if (!video.value) return;
+  video.value.play();
+  play.value = true;
+};
+</script>
+
 <style lang="scss" scoped>
 @use "./index.scss";
 </style>

+ 0 - 0
packages/mobile/src/views/Index/components/Chapter1/images/1-1-min.png


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä