Jelajahi Sumber

Merge branch 'master' of http://192.168.0.115:3000/renyicun/NanjingMuseumWuJinZang-PC

aamin 1 tahun lalu
induk
melakukan
bda44cccb3

TEMPAT SAMPAH
src/assets/images/bg-paper.jpg


TEMPAT SAMPAH
src/assets/images/decoration-sun.png


TEMPAT SAMPAH
src/assets/images/fade-chapter-wood/1-min.png


TEMPAT SAMPAH
src/assets/images/hide-more-btn.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-cover-bg-ming.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-cover-bg-qing.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-cover-bg-song.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-cover-bg-yuan.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-title-ming.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-title-qing.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-title-song.png


TEMPAT SAMPAH
src/assets/images/painting-menu-item-title-yuan.png


TEMPAT SAMPAH
src/assets/images/painting-menu-special-content-title.png


TEMPAT SAMPAH
src/assets/images/painting-style-title.png


TEMPAT SAMPAH
src/assets/images/painting-thumb-border.png


TEMPAT SAMPAH
src/assets/images/painting-thumb-window.png


TEMPAT SAMPAH
src/assets/images/see-more-btn.png


TEMPAT SAMPAH
src/assets/images/serial-frame-painting-list-bottom.png


TEMPAT SAMPAH
src/assets/images/serial-frame-painting-list-top.png


+ 6 - 0
src/router/index.js

@@ -4,6 +4,7 @@ import MoreContent from '../views/MoreContent.vue'
 import ShuangGou from '../views/ShuangGou.vue'
 import BambooList from '../views/BambooList.vue'
 import PoemList from '../views/PoemList.vue'
+import PaintingList from '../views/PaintingList.vue'
 import PaintingDetail from '../views/PaintingDetail'
 
 // import store from '@/store/index.js'
@@ -40,6 +41,11 @@ const routes = [
     component: PoemList,
   },
   {
+    path: '/painting-list',
+    name: 'PaintingList',
+    component: PaintingList,
+  },
+  {
     path: '/painting-detail',
     name: 'PaintingDetail',
     component: PaintingDetail,

+ 19 - 20
src/useFunctions/useSmoothSwipe.js

@@ -75,29 +75,26 @@ export default function useSmoothSwipe({
   })
 
   // compute maxTranslateLengthInner
-  if (maxTranslateLength) {
-    watchEffect(() => {
+  watchEffect(() => {
+    if (maxTranslateLength) {
       maxTranslateLengthInner = unref(maxTranslateLength) - unref(viewportWidth)
       if (maxTranslateLengthInner < 0) {
         maxTranslateLengthInner = 0
       }
-    })
-  } else if (scrollTargetRef) {
-    watchEffect(() => {
-      if (scrollTargetRef.value) {
-        maxTranslateLengthInner = scrollTargetRef.value.scrollWidth - unref(viewportWidth)
-        if (maxTranslateLengthInner < 0) {
-          maxTranslateLengthInner = 0
-        }
-      } else {
-        maxTranslateLengthInner = Infinity
-      }
-    })
+    }
+  })
+
+  function computeMaxTranslateLengthInnerByScrollTarget() {
+    maxTranslateLengthInner = scrollTargetRef.value.scrollWidth - unref(viewportWidth)
   }
 
   function onWheel(e) {
-    translateLength.value += e.deltaY / 0.5
-    console.log(translateLength.value)
+    moveSpeed.value += e.deltaY / 200
+  }
+
+  function speedUp(v) {
+    console.log('sdf')
+    moveSpeed.value += v
   }
 
   /**
@@ -262,10 +259,10 @@ export default function useSmoothSwipe({
     watch(scrollTargetRef, (v) => {
       if (v) {
         v.addEventListener('wheel', onWheel)
-        // v.addEventListener('mousedown', onMouseDown)
-        // v.addEventListener('mouseleave', onMouseLeave)
-        // v.addEventListener('mousemove', onMouseMove)
-        // v.addEventListener('mouseup', onMouseUp)
+        v.addEventListener('mousedown', onMouseDown)
+        v.addEventListener('mouseleave', onMouseLeave)
+        v.addEventListener('mousemove', onMouseMove)
+        v.addEventListener('mouseup', onMouseUp)
         // v.addEventListener('touchstart', onTouchStart)
         // v.addEventListener('touchmove', onTouchMove)
         // v.addEventListener('touchend', onTouchEnd)
@@ -292,5 +289,7 @@ export default function useSmoothSwipe({
     onTouchCancel,
     translateLength,
     haveSwipedThisTime,
+    computeMaxTranslateLengthInnerByScrollTarget,
+    speedUp
   }
 }

+ 11 - 0
src/utils.js

@@ -114,4 +114,15 @@ export default {
       throw (`invalid objectFit value: ${objectFit}`)
     }
   },
+  getPaintingSize(raw) {
+    const temp = raw.split('\n')
+    let height = temp[0]
+    let width = temp[1]
+    height = Number(height.substring(1, height.length - 2))
+    width = Number(width.substring(1, width.length - 2))
+    return {
+      width,
+      height,
+    }
+  },
 }

+ 644 - 0
src/views/PaintingList.vue

@@ -0,0 +1,644 @@
+<template>
+  <div
+    class="painting-list"
+  >
+    <!-- 背景序列帧 -->
+    <SerialFrames
+      class="bg-serial-frames-top"
+      :image-src="require(`@/assets/images/serial-frame-painting-list-top.png`)"
+      :total-width="13194"
+      :height="865"
+      :frame-number="33"
+      :frame-duration="55"
+    />
+    <SerialFrames
+      class="bg-serial-frames-bottom"
+      :image-src="require(`@/assets/images/serial-frame-painting-list-bottom.png`)"
+      :total-width="13194"
+      :height="865"
+      :frame-number="33"
+      :frame-duration="55"
+    />
+
+    <ul
+      ref="menuEl"
+    >
+      <div
+        v-for="(paintingGroup, ageName) in menuInfo"
+        :id="`menu-item-${ageName}`"
+        :key="ageName"
+        class="menu-item"
+      >
+        <div
+          class="cover"
+          :style="{
+            backgroundImage: `url(${ageRenderInfo[ageName].coverBg})`,
+          }"
+          @click="onClickAge(ageName)"
+        >
+          <img
+            class="age"
+            :src="ageRenderInfo[ageName].artFontImg"
+            alt=""
+            draggable="false"
+          >
+          <div class="age-en">
+            {{ `${ageRenderInfo[ageName].En} dynasty` }}
+          </div>
+          <div class="author-list">
+            {{ getAuthorList(paintingGroup).join('\\') }}
+          </div>
+        </div>
+        <div
+          v-if="ageName !== '清' && !expandedAgeNameList.has(ageName)"
+          class="splitter"
+        />
+        <div
+          :class="`hiddable-content`"
+          :style="{
+            width: expandedAgeNameList.has(ageName) ? getHiddenContentWidth(paintingGroup, ageName) : '0',
+          }"
+        >
+          <div class="shadow" />
+          <div
+            v-if="ageName === '宋'"
+            class="special-desc"
+            :class="{
+              showDetail: isShowPaintingStyleDesc ? 'show-detail' : '',
+            }"
+          >
+            <img
+              class="title"
+              src="@/assets/images/painting-menu-special-content-title.png"
+              alt=""
+              draggable="false"
+            >
+            <p
+              v-show="!isShowPaintingStyleDesc"
+              class="desc-short"
+            >
+              “湖州竹派”其实是学术界公认的中国古代最具代表性的十五大画派之一,传承至今已有千年历史。
+            </p>
+            <div
+              v-show="isShowPaintingStyleDesc"
+              class="desc-long"
+            >
+              <p>
+                “湖州竹派”其实是学术界公认的中国古代最具代表性的15大画派之一,传承至今已有千年历史。
+              </p>
+              <p>
+                “湖州竹派”是成熟于北宋中后期的文人画代表之一,以竹为主要表现内容。竹派作品抒情寄兴,状物言志,不拘形似格法,品格高洁,以完全独立的面目立于中国画坛,在明清成主流。“湖州竹派”这一中国画艺术的新形态,打开了中国文人画的大门,是影响中国整个绘画史的重要画派。
+              </p>
+              <p>
+                “湖州竹派”公认的四大代表艺术家中,两位创始人文同和苏轼都来自四川,元代的赵孟、近代的吴昌硕均为湖州人。他们对后世产生的影响绵延至今。由文同、苏轼开创的墨竹潮流,作为一种经典绘画样式确立下来,成为后世画家模仿的典范,堪称“湖州竹派一代宗师”。
+              </p>
+            </div>
+            <button
+              v-show="!isShowPaintingStyleDesc"
+              class="see-more"
+              @click="isShowPaintingStyleDesc = true"
+            />
+            <button
+              v-show="isShowPaintingStyleDesc"
+              class="hide-more"
+              @click="isShowPaintingStyleDesc = false"
+            />
+          </div>
+          <div
+            v-for="item in paintingGroup"
+            :key="item['标题']"
+            class="painting-item"
+          >
+            <div
+              v-if="item['音']"
+              class="top-wrap-img"
+            >
+              <img
+                :style="{height:item['音图'] == 'zhaomengfu1.png' ? '78%':''}"
+                :src="`${$env.BASE_URL}configMultiMedia/author/${item['音图']}`"
+              >
+            </div>
+            <div
+              v-else
+              class="top-wrap"
+            >
+              <div
+                class="author"
+                :class="{
+                  long: item['作者'].length >= 6,
+                }"
+              >
+                <img
+                  class="bg"
+                  src="@/assets/images/decoration-sun.png"
+                  alt=""
+                  draggable="false"
+                >
+                <div
+                  v-if="item['音']"
+                  class="yin-name"
+                >
+                  <div
+                    v-for="(itemm,index) in item['音']"
+                    :key="index"
+                  >
+                    {{ itemm }}
+                  </div>
+                </div>
+                <div
+                  v-else
+                  class="name"
+                >
+                  {{ item['作者'] }}
+                </div>
+              </div>
+              <div class="title">
+                {{ item['标题(展示)'].split('\n').join('') }}
+              </div>
+              <div class="type">
+                {{ item['装裱\/材质\/笔类型'] }}
+              </div>
+            </div>
+            <div
+              class="img-wrap"
+              @click="router.push({
+                name: 'PaintingDetailList',
+                query: {
+                  idx: Number(item['序号']) - 1,
+                }
+              })"
+            >
+              <img
+                class="thumb"
+                :src="`${$env.BASE_URL}configMultiMedia/paintings-thumb/${item['标题']}.jpg`"
+                alt=""
+                draggable="false"
+              >
+              <img
+                class="window"
+                src="@/assets/images/painting-thumb-window.png"
+                alt=""
+                draggable="false"
+              >
+              <img
+                class="border"
+                src="@/assets/images/painting-thumb-border.png"
+                alt=""
+                draggable="false"
+              >
+            </div>
+            <div class="size">
+              {{ item['尺寸'] ? getPaintingSizeStringForShow(getPaintingSize(item['尺寸'])):'' }}
+            </div>
+            <div class="position">
+              {{ item['馆藏'] }}
+            </div>
+          </div>
+        </div>
+      </div>
+    </ul>
+    <BtnBack
+      class="button-back"
+      @click="router.go(-1)"
+    />
+    <OperationTip
+      class="operation-tip"
+      direction="h"
+      :is-show="isShowOperationTip"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, inject } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import useSmoothSwipe from "@/useFunctions/useSmoothSwipe.js"
+import { useWindowSize } from "@vueuse/core"
+
+const getPaintingSize = utils.getPaintingSize
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const $env = inject('$env')
+
+const menuEl = ref(null)
+const menuElScrollLeft = ref(0)
+
+const { width: windowWidth, height: windowHeight } = useWindowSize()
+const windowHeightDesign = 1080 - 71 - 37 // 设计稿里视口高度。注意要减去上下边栏
+
+const paintingWidthWhenDesign = 307
+const paintingMarginWhenDesin = 95
+const specialDescShortWidthWhenDesin = 500
+const specialDescLongWidthWhenDesin = 1198
+function getHiddenContentWidth(paintingGroup, ageName) {
+  let temp = paintingGroup.length * (paintingWidthWhenDesign + paintingMarginWhenDesin) + paintingMarginWhenDesin
+  if (ageName === '宋') {
+    if (isShowPaintingStyleDesc.value) {
+      temp += specialDescLongWidthWhenDesin
+    } else {
+      temp += specialDescShortWidthWhenDesin
+    }
+  }
+  return `${temp / windowHeightDesign * windowHeight.value}px`
+}
+
+const {
+  translateLength,
+  computeMaxTranslateLengthInnerByScrollTarget,
+  speedUp,
+} = useSmoothSwipe({
+  scrollTargetRef: menuEl,
+  maxTranslateLength: undefined,
+  viewportWidth: windowWidth,
+})
+onMounted(() => {
+  computeMaxTranslateLengthInnerByScrollTarget()
+})
+watch(translateLength, (v) => {
+  menuEl.value.scrollLeft = v
+})
+
+const menuInfo = {}
+const temp = configExcel['画作'].map((item) => {
+  return item['朝代']
+})
+for (const painting of configExcel['画作']) {
+  if (!menuInfo[painting['朝代']]) {
+    menuInfo[painting['朝代']] = []
+  }
+  menuInfo[painting['朝代']].push(painting)
+}
+// for (const key in menuInfo) {
+//   if (Object.hasOwnProperty.call(menuInfo, key)) {
+//     const element = menuInfo[key]
+//     element.hiddableContentWidth = getHiddenContentWidth(element, key)
+//   }
+// }
+
+const ageRenderInfo = {
+  '宋': {
+    En: 'Song',
+    artFontImg: require(`@/assets/images/painting-menu-item-title-song.png`),
+    coverBg: require(`@/assets/images/painting-menu-item-cover-bg-song.png`),
+  },
+  '元': {
+    En: 'Yuan',
+    artFontImg: require(`@/assets/images/painting-menu-item-title-yuan.png`),
+    coverBg: require(`@/assets/images/painting-menu-item-cover-bg-yuan.png`),
+  },
+  '明': {
+    En: 'Ming',
+    artFontImg: require(`@/assets/images/painting-menu-item-title-ming.png`),
+    coverBg: require(`@/assets/images/painting-menu-item-cover-bg-ming.png`),
+  },
+  '清': {
+    En: 'Qing',
+    artFontImg: require(`@/assets/images/painting-menu-item-title-qing.png`),
+    coverBg: require(`@/assets/images/painting-menu-item-cover-bg-qing.png`),
+  },
+}
+
+function getAuthorList(paintingGroup) {
+  const temp = paintingGroup.map((item) => {
+    let author = item['作者']
+    return author
+  })
+  return Array.from(new Set(temp))
+}
+
+function getPaintingSizeStringForShow({ width, height }) {
+  return `${width}\u00D7${height} 厘米`
+}
+
+const expandedAgeNameList = ref(new Set(['宋']))
+
+const isShowOperationTip = ref(true)
+const unwatch = watch(menuElScrollLeft, (v) => {
+  isShowOperationTip.value = false
+  unwatch()
+})
+
+function onClickAge(ageName) {
+  isShowOperationTip.value = false
+  if (expandedAgeNameList.value.has(ageName)) {
+    expandedAgeNameList.value.delete(ageName)
+  } else {
+    expandedAgeNameList.value.add(ageName)
+    // const menuItemEl = document.getElementById(`menu-item-${ageName}`)
+    setTimeout(() => {
+      speedUp(1)
+    }, 520)
+  }
+  setTimeout(() => {
+    computeMaxTranslateLengthInnerByScrollTarget()
+  }, 510)
+}
+
+const isShowPaintingStyleDesc = ref(false)
+
+</script>
+
+<style lang="less" scoped>
+// ::-webkit-scrollbar {
+//   display:none;
+// }
+
+.painting-list{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(121, 143, 108, 1);
+  >.bg-serial-frames-top{
+    position: absolute;
+    top: 0;
+    right: 0;
+    transform: translate(0, 0) scale(0.8);
+    transform-origin: top right;
+  }
+  >.bg-serial-frames-bottom{
+    position: absolute;
+    bottom: 0;
+    right: 175px;
+    transform: translate(0, 10%) scale(1);
+    transform-origin: bottom left;
+  }
+  >ul{
+    position: absolute;
+    left: 0;
+    top: 0;
+    width:100%;
+    height: 100%;
+    display: flex;
+    overflow: auto;
+    >.menu-item{
+      flex: 0 0 auto;
+      overflow: auto;
+      height: 100%;
+      display: flex;
+      align-items: center;
+      >.cover{
+        flex: 0 0 auto;
+        height: calc(684 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        padding-left: calc(22 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        padding-right: calc(22 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        writing-mode: vertical-lr;
+        background-size: cover;
+        background-repeat: no-repeat;
+        background-position: center center;
+        >.age{
+          margin-top: calc(160 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          width: calc(44 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          height: calc(57 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        }
+        >.age-en{
+          margin-top: calc(166 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          font-family: KingHwa_OldSong;
+          font-weight: 400;
+          font-size: calc(26 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          color: #FFFFFF;
+          line-height: calc(30 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        }
+        >.author-list{
+          margin-top: calc(166 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          font-family: KaiTi;
+          font-weight: 400;
+          font-size: calc(20 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          color: #FFFFFF;
+          line-height: calc(24 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          letter-spacing: 0.2em;
+          height: 20em;
+          overflow: hidden;
+          white-space: pre;
+          text-overflow: ellipsis;
+        }
+      }
+      >.splitter{
+        height: calc(684 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        width: 1px;
+        background-color: #fff;
+      }
+      >.hiddable-content{
+        transition: width 0.5s;
+        overflow: hidden;
+        display: flex;
+        align-items: flex-end;
+        background-color: #f9f7f2;
+        height: 100%;
+        background-image: url(@/assets/images/bg-paper.jpg);
+        background-size: auto 100%;
+        background-repeat: repeat;
+        position: relative;
+        >.shadow{
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          width: 100%;
+          height: calc(285 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          background: linear-gradient( 360deg, rgba(0, 0, 0, 0.2) 0%, rgba(0,0,0,0) 100%);
+        }
+        >.special-desc{
+          flex: 0 0 auto;
+          align-self: center;
+          width: calc(v-bind('specialDescShortWidthWhenDesin') / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          >img.title{
+            flex: 0 0 auto;
+            width: calc(170 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            height: calc(170 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            margin-right: calc(29 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          }
+          >p.desc-short{
+            writing-mode: vertical-lr;
+            font-family: KaiTi;
+            font-weight: 400;
+            font-size: calc(26 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            color: #476446;
+            line-height: 2;
+            text-align: justify;
+            height: calc(696 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            letter-spacing: 0.15em;
+          }
+          >.desc-long{
+            width: calc(802 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            font-family: KaiTi, KaiTi;
+            font-weight: 400;
+            font-size: calc(30 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            color: #474747;
+            line-height: calc(45 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            text-indent: 2em;
+          }
+          >button.see-more, button.hide-more{
+            width: calc(42 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            height: calc(119 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            background-size: contain;
+            background-repeat: no-repeat;
+            background-position: center center;
+            margin-left: calc(20 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            transform: translateY(220%);
+          }
+          >button.see-more{
+            background-image: url(@/assets/images/see-more-btn.png);
+          }
+          >button.hide-more{
+            background-image: url(@/assets/images/hide-more-btn.png);
+          }
+        }
+        >.special-desc.showDetail{
+          width: calc(v-bind('specialDescLongWidthWhenDesin') / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        }
+        >.painting-item:last-of-type {
+          margin-right: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+        }
+        >.painting-item{
+          flex: 0 0 auto;
+          margin-left: calc(v-bind('paintingMarginWhenDesin') / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          width: calc(v-bind('paintingWidthWhenDesign') / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          margin-bottom: calc(248 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+          >.top-wrap{
+            margin-bottom: calc(29 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            position: relative;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            height:20vh;
+            >.author{
+              writing-mode: vertical-lr;
+              font-family: KingHwa_OldSong;
+              font-weight: 400;
+              font-size: calc(44 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+              color: #474747;
+              margin-right: calc(27 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+              position: relative;
+              letter-spacing: 0em;
+              >img.bg{
+                width: calc(27 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+                position: absolute;
+                right: 0;
+                top: 50%;
+                transform: translate(-24%, -40%);
+                z-index: 1;
+              }
+              >.name{
+                writing-mode: vertical-lr;
+                position: relative;
+                z-index: 2;
+              }
+              >.yin-name{
+                // writing-mode: horizontal-tb;
+                display: flex;
+                // flex-direction: column;
+                position: relative;
+                z-index: 2;
+                >div{
+                  writing-mode: horizontal-tb;
+                }
+                >div:nth-child(2){
+                  color: rgba(71,71,71,0.7 );
+                  letter-spacing: -1px;
+                  font-size: 20px;
+                  transform: translateX(-20px);
+                }
+              }
+            }
+            >.author.long{
+              transform: translateY(0);
+              letter-spacing: initial;
+            }
+            >.title{
+              writing-mode: vertical-lr;
+              font-family: KingHwa_OldSong;
+              font-weight: 400;
+              font-size: calc(17 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+              color: #474747;
+              white-space: pre;
+              margin-right: calc(12 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+              letter-spacing: 0.2em;
+            }
+            >.type{
+              writing-mode: vertical-lr;
+              font-family: KingHwa_OldSong;
+              font-weight: 400;
+              font-size: calc(17 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+              color: #474747;
+              white-space: pre;
+              letter-spacing: 0.2em;
+            }
+          }
+          >.top-wrap-img{
+            height:20vh;
+            >img{
+              height: 65%;
+            }
+          }
+          >.img-wrap{
+            cursor: pointer;
+            width: calc(240 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            height: calc(240 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            border-radius: 50%;
+            overflow: hidden;
+            margin-bottom: calc(21 / v-bind('windowHeightDesign') * v-bind('windowHeight') * 1px);
+            position: relative;
+            >img.thumb{
+              width: 100%;
+              height: 100%;
+              object-fit: cover;
+            }
+            >img.window{
+              position: absolute;
+              top: 0;
+              height: 100%;
+              left: 70%;
+              transition: left 1s;
+            }
+            >img.border{
+              position: absolute;
+              left: 0;
+              top: 0;
+              width: 100%;
+              height: 100%;
+            }
+          }
+          >.img-wrap:hover{
+            >img.window{
+              left: 100%;
+            }
+          }
+          >.size{
+            font-family: KingHwa_OldSong;
+            font-weight: 400;
+            font-size: 17px;
+            color: #474747;
+            line-height: 19px;
+            margin-bottom: 0.5em;
+          }
+          >.position{
+            font-family: KingHwa_OldSong;
+            font-weight: 400;
+            font-size: 17px;
+            color: #474747;
+            line-height: 19px;
+          }
+        }
+      }
+    }
+  }
+  >.operation-tip{
+    position: absolute;
+    left: 43px;
+    bottom: 102px;
+    transform: translateX(-50%);
+    z-index: 10;
+  }
+}
+</style>