Browse Source

历史回顾:人物照片可放大查看

任一存 1 year ago
parent
commit
07f461270a
6 changed files with 59 additions and 434 deletions
  1. 3 1
      package.json
  2. 9 0
      src/components/HistoryPersonCard.vue
  3. 19 3
      src/main.js
  4. 0 427
      src/views/History.vue
  5. 15 3
      src/views/HistoryNew.vue
  6. 13 0
      yarn.lock

+ 3 - 1
package.json

@@ -20,8 +20,10 @@
     "mitt": "^3.0.0",
     "qrcode": "^1.5.3",
     "swiper": "^10.0.4",
-    "vue": "^3.2.13",
+    "v-viewer": "^3.0.11",
+    "viewerjs": "^1.11.6",
     "vue-router": "^4.0.3",
+    "vue": "^3.2.13",
     "vuex": "^4.0.0"
   },
   "devDependencies": {

+ 9 - 0
src/components/HistoryPersonCard.vue

@@ -39,6 +39,7 @@
       >
         <img
           v-if="img"
+          v-viewer
           class="portrait"
           :class="{
             tall: tallOrFat === 'tall',
@@ -47,6 +48,8 @@
           :src="img"
           alt=""
           draggable="false"
+          @show="$emit('showBigImg')"
+          @hide="$emit('hideBigImg')"
         >
         <div
           class="text"
@@ -69,6 +72,10 @@ export default {
     'img',
     'text',
     'tallOrFat',
+  ],
+  emits: [
+    'showBigImg',
+    'hideBigImg',
   ]
 }
 </script>
@@ -137,6 +144,7 @@ export default {
       >img.portrait{
         flex: 0 0 auto;
         object-fit: cover;
+        cursor: pointer;
         &.tall{
           margin-top: 20px;
           width: 210px;
@@ -242,6 +250,7 @@ export default {
         >img.portrait{
           flex: 0 0 auto;
           object-fit: cover;
+          cursor: pointer;
           &.tall{
             margin-top: calc(20 / 1080 * 100vh);
             width: calc(210 / 1080 * 100vh);

+ 19 - 3
src/main.js

@@ -9,8 +9,8 @@ import clickOutside from "@/directives/v-click-outside.js"
 import mitt from "mitt"
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
-// import 'viewerjs/dist/viewer.css'
-// import VueViewer from 'v-viewer'
+import 'viewerjs/dist/viewer.css'
+import VueViewer from 'v-viewer'
 
 console.log(`version: ${process.env.VUE_APP_VERSION}`)
 console.log(`Build time: ${process.env.VUE_APP_UPDATE_TIME}`)
@@ -67,10 +67,26 @@ app.use(store)
   .use(router)
   .use(clickOutside)
   .use(ElementPlus)
-  // .use(VueViewer)
+  .use(VueViewer)
   // .component('HotSpot', HotSpot)
   .mount('#app')
 
+VueViewer.setDefaults({
+  inline: false,
+  button: true,
+  navbar: false,
+  title: false,
+  toolbar: false,
+  tooltip: false,
+  movable: true,
+  zoomable: true,
+  rotatable: false,
+  // "scalable": true,
+  transition: true,
+  fullscreen: true,
+  keyboard: true,
+})
+
 if (app.config.globalProperties.$isMobile) {
   document.body.classList.add('mobile')
 }

+ 0 - 427
src/views/History.vue

@@ -1,427 +0,0 @@
-<template>
-  <div class="history">
-    <iframe
-      id="iframe-echart"
-      src="./chart.html"
-      frameborder="0"
-    />
-
-    <h1>
-      {{ Number.isInteger(activeTimeIdx) ? timeNameList[activeTimeIdx] : '历史回顾' }}
-    </h1>
-    <menu>
-      <img
-        class="circle-no-light"
-        src="@/assets/images/circle-no-light.png"
-        alt=""
-        draggable="false"
-      >
-      <img
-        class="circle"
-        src="@/assets/images/circle.png"
-        alt=""
-        draggable="false"
-      >
-      <ul>
-        <li
-          v-for="(time, idx) in timeNameList"
-          :key="idx"
-          :class="{active: activeTimeIdx === idx}"
-          @click="onClickTimeItem(idx)"
-        >
-          <div
-            class="point"
-          />
-          {{ time }}
-        </li>
-      </ul>
-    </menu>
-
-    <article v-if="articleTitle">
-      <h2>{{ articleTitle }}</h2>
-      <img
-        class="splitter"
-        src="@/assets/images/splitter-history-top.png"
-        alt=""
-        draggable="false"
-      >
-      <div class="txt-wrapper">
-        <img
-          v-show="articleBannerUrl"
-          class="banner"
-          :src="articleBannerUrl"
-          alt=""
-          draggable="false"
-        >
-        <div
-          class="txt"
-          v-html="articleDesc"
-        />
-        <button
-          v-show="activeTimeIdx !== 0"
-          class="left"
-          @click="onClickLeftArrow"
-        />
-        <button
-          v-show="activeTimeIdx !== timeNameList.length - 1"
-          class="right"
-          @click="onClickRightArrow"
-        />
-      </div>
-      <img
-        class="splitter"
-        src="@/assets/images/splitter-history-bottom.png"
-        alt=""
-        draggable="false"
-      >
-    </article>
-  </div>
-</template>
-
-<script>
-import {
-  ref,
-  reactive,
-  onMounted,
-  onBeforeUnmount,
-  computed,
-  watch,
-  watchEffect,
-  onBeforeMount,
-} from 'vue'
-import dataRaw from "@/assets/mock/history.json"
-import { ElLoading } from 'element-plus'
-
-export default {
-  name: 'HistoryView',
-  setup () {
-    const timeNameList = [
-      '开埠通商',
-      '曲折发展',
-      '步履维艰',
-      '筚路蓝缕',
-      '改革开放',
-      '战略负重',
-      '创新驱动',
-      '追梦未来',
-    ]
-
-    const activeTimeIdx = ref(null)
-    const activeCorpId = ref('')
-
-    const loadingInstance = ElLoading.service({
-      background: 'transparent',
-    })
-
-    function onIframeMessage(e) {
-      console.log(e)
-      if (e.data === 'fetch data done') {
-        loadingInstance.close()
-      } else if (e.data.msg == 'node-selected') {
-        if (e.data.nodeLevel === 0) {
-          activeTimeIdx.value = null
-          activeCorpId.value = null
-        } else if (e.data.nodeLevel === 1) {
-          activeTimeIdx.value = e.data.nodeStageIdx
-          activeCorpId.value = null
-        } else if (e.data.nodeLevel === 2) {
-          activeTimeIdx.value = e.data.nodeStageIdx
-          activeCorpId.value = e.data.nodeId
-        }
-      }
-    }
-    window.addEventListener('message', onIframeMessage)
-    onBeforeUnmount(() => {
-      window.removeEventListener('message', onIframeMessage)
-    })
-
-    function onClickLeftArrow() {
-      if (activeTimeIdx.value > 0) {
-        activeTimeIdx.value--
-        activeCorpId.value = ''
-      }
-    }
-    function onClickRightArrow() {
-      if (activeTimeIdx.value < timeNameList.length - 1) {
-        activeTimeIdx.value++
-        activeCorpId.value = ''
-      }
-    }
-
-    function onClickTimeItem(idx) {
-      if (activeTimeIdx.value === idx) {
-        activeTimeIdx.value = null
-        activeCorpId.value = null
-        if (document.getElementById('iframe-echart')?.contentWindow?.showAll) {
-          document.getElementById('iframe-echart').contentWindow.showAll()
-        }
-      } else {
-        activeTimeIdx.value = idx
-        activeCorpId.value = null
-        if (document.getElementById('iframe-echart')?.contentWindow?.changeTime) {
-          document.getElementById('iframe-echart').contentWindow.changeTime(idx)
-        }
-      }
-    }
-
-    const articleTitle = ref('')
-    const articleDesc = ref('')
-    const articleBannerUrl = ref('')
-    watchEffect(async () => {
-      if (Number.isInteger(activeTimeIdx.value) && !Number.isInteger(activeCorpId.value)) {
-        articleTitle.value = timeNameList[activeTimeIdx.value]
-        articleDesc.value = dataRaw['阶段介绍'][activeTimeIdx.value]['介绍']
-        articleBannerUrl.value = ''
-      } else if (Number.isInteger(activeTimeIdx.value) && Number.isInteger(activeCorpId.value)) {
-        const corpDetail = await api.getHistoryDetail(activeCorpId.value)
-        articleTitle.value = corpDetail.entity?.name || corpDetail.entity?.companyName || ''
-        articleDesc.value = corpDetail.entity?.description || corpDetail.entity?.story || ''
-        articleBannerUrl.value = corpDetail?.file[0]?.filePath ? process.env.VUE_APP_API_ORIGIN + corpDetail?.file[0]?.filePath : ''
-      } else {
-        articleTitle.value = ''
-        articleDesc.value = ''
-        articleBannerUrl.value = ''
-      }
-    })
-
-    return {
-      timeNameList,
-      activeTimeIdx,
-      onClickTimeItem,
-      articleTitle,
-      articleDesc,
-      articleBannerUrl,
-      onClickLeftArrow,
-      onClickRightArrow,
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-.history {
-  >iframe {
-    position: absolute;
-    left: 0;
-    top: 0;
-    width: 100%;
-    height: 100%;
-  }
-  >h1 {
-    position: absolute;
-    top: 51px;
-    left: 81px;
-    max-width: 50%;
-    overflow: hidden;
-    white-space: pre;
-    text-overflow: ellipsis;
-    font-size: 48px;
-    font-family: Source Han Sans CN-Heavy, Source Han Sans CN;
-    font-weight: 800;
-    color: #FFFFFF;
-    padding-top: 20px;
-    padding-bottom: 20px;
-    border-top: 1px solid rgba(217, 217, 217, 0.2);
-    border-bottom: 1px solid rgba(217, 217, 217, 0.2);
-  }
-  >menu {
-    position: absolute;
-    top: 214px;
-    left: 0;
-    >img.circle-no-light {
-      position: absolute;
-      top: -20%;
-      left: -60px;
-      height: 130%;
-      pointer-events: none;
-    }
-    >img.circle {
-      position: absolute;
-      top: -20%;
-      left: -60px;
-      height: 130%;
-      pointer-events: none;
-      z-index: 1;
-    }
-    >ul {
-      >li {
-        display: flex;
-        justify-content: flex-end;
-        align-items: center;
-        height: 50px;
-        background: linear-gradient(270deg, #3A454F 0%, rgba(22,28,33,0) 100%);
-        // border-radius: 3px;
-        border: 1px solid;
-        border-left: none;
-        border-image: linear-gradient(270deg, rgba(78, 96, 112, 1), rgba(78, 96, 112, 0)) 1 1;
-        margin-bottom: 15px;
-        font-size: 20px;
-        font-family: Source Han Sans CN-Light, Source Han Sans CN;
-        font-weight: 400;
-        color: rgba(255, 255, 255, 0.5);
-        // backdrop-filter: blur(10px); // 会导致产生层叠上下文!!!使得圆点无法在弧线上层!!!
-        padding-right: 14px;
-        cursor: pointer;
-        position: relative;
-        >.point {
-          position: absolute;
-          top: 50%;
-          transform: translateY(-50%);
-          width: 8px;
-          height: 8px;
-          border-radius: 4px;
-          background: #D1DCE5;
-          box-shadow: 0px 0px 12px 0px #6D9DC6, 0px 0px 8px 0px #6D9DC6;
-          z-index: 2;
-        }
-        &:hover {
-          background: linear-gradient(270deg, #B0A179 0%, rgba(255,209,91,0) 100%);
-          border-image: linear-gradient(270deg, rgba(176, 161, 121, 1), rgba(176, 161, 121, 0)) 1 1;
-        }
-        &.active {
-          font-size: 22px;
-          font-family: Source Han Sans CN-Bold, Source Han Sans CN;
-          font-weight: bold;
-          color: #FFFFFF;
-          text-shadow: 0px 0px 10px #8B7C54;
-          background: linear-gradient(270deg, #B0A179 0%, rgba(255,209,91,0) 100%);
-          border-image: linear-gradient(270deg, rgba(176, 161, 121, 1), rgba(176, 161, 121, 0)) 1 1;
-          >.point {
-            background: #FFFFFF;
-            box-shadow: 0px 0px 12px 0px #FFD15B, 0px 0px 8px 0px #FFD15B, 0px 0px 10px 0px #FFD15B, 0px 0px 5px 0px #FFD15B;
-          }
-        }
-        &:nth-of-type(1) {
-          width: calc(170px + 25px * 1);
-          >.point {
-            margin-right: calc(48px + 80px);
-          }
-        }
-        &:nth-of-type(2) {
-          width: calc(170px + 25px * 2);
-          >.point {
-            margin-right: calc(43px + 80px);
-          }
-        }
-        &:nth-of-type(3) {
-          width: calc(170px + 25px * 3);
-          >.point {
-            margin-right: calc(50px + 80px);
-          }
-        }
-        &:nth-of-type(4) {
-          width: calc(170px + 25px * 4);
-          >.point {
-            margin-right: calc(65px + 80px);
-          }
-        }
-        &:nth-of-type(5) {
-          width: calc(170px + 25px * 3);
-          >.point {
-            margin-right: calc(40px + 80px);
-          }
-        }
-        &:nth-of-type(6) {
-          width: calc(170px + 25px * 2);
-          >.point {
-            margin-right: calc(23px + 80px);
-          }
-        }
-        &:nth-of-type(7) {
-          width: calc(170px + 25px * 1);
-          >.point {
-            margin-right: calc(15px + 80px);
-          }
-        }
-        &:nth-of-type(8) {
-          width: 170px;
-          >.point {
-            margin-right: calc(17px + 80px);
-          }
-        }
-      }
-    }
-  }
-
-  >article {
-    position: absolute;
-    top: 134px;
-    right: 114px;
-    width: 458px;
-    @media only screen and (max-width: 1700px) {
-      right: 20px;
-    }
-    >h2 {
-      display: flex;
-      align-items: center;
-      font-size: 24px;
-      font-family: Source Han Sans CN-Bold, Source Han Sans CN;
-      font-weight: bold;
-      color: #FFFFFF;
-      text-shadow: 0px 0px 9px #B0A179;
-      margin-bottom: 28px;
-      &::before {
-        content: '';
-        display: inline-block;
-        margin-right: 10px;
-        width: 3px;
-        height: 3px;
-        background: #B0A179;
-      }
-    }
-    >img.splitter {
-      width: 100%;
-      margin-bottom: 25px;
-    }
-    >.txt-wrapper {
-      margin-bottom: 20px;
-      position: relative;
-      padding-left: 40px;
-      padding-right: 40px;
-      > img.banner {
-        width: 100%;
-        max-height: 300px;
-        object-fit: contain;
-        margin-top: 10px;
-      }
-      >.txt {
-        max-height: calc(100vh - 400px);
-        overflow: auto;
-        font-size: 20px;
-        font-family: Source Han Sans CN-Light, Source Han Sans CN;
-        font-weight: 400;
-        color: rgba(255, 255, 255, 0.8);
-        line-height: 1.5;
-        padding-right: 10px;
-        margin-right: -10px;
-        white-space: pre-wrap;
-        text-indent: 2em;
-        &::-webkit-scrollbar { background: transparent; width: 4px; } /*宽度是对垂直滚动条而言,高度是对水平滚动条而言*/
-        &::-webkit-scrollbar-thumb {
-          background: rgba(220, 231, 240, 0.2);
-          border-radius: 2px;
-        }
-      }
-      >button {
-        width: 36px;
-        height: 36px;
-        position: absolute;
-        top: 50%;
-        transform: translateY(-50%);
-        background-size: 90%;
-        background-repeat: no-repeat;
-        &.left {
-          left: 0;
-          background-image: url(@/assets/images/arrow_left.png);
-          background-position: left center;
-        }
-        &.right {
-          right: 0;
-          background-image: url(@/assets/images/arrow_right.png);
-          background-position: right center;
-        }
-      }
-    }
-  }
-}
-</style>

+ 15 - 3
src/views/HistoryNew.vue

@@ -99,6 +99,8 @@
         zIndex: item.zIndex,
         filter: item.filter,
       }"
+      @showBigImg="onShowBigImg"
+      @hideBigImg="onHideBigImg"
     />
     <!-- element-ui的loading效果从调用到出现有延时,这期间要遮盖住组件 -->
     <div
@@ -293,7 +295,7 @@ export default {
     function onMouseUp(e) {
       isMouseDown.value = false
       beginAutoMoveIntervalId = setInterval(() => {
-        if (moveSpeed.value === 0) {
+        if (moveSpeed.value === 0 && !isShowingBigImg.value) {
           isAutoMoving.value = true
         }
       }, 2000)
@@ -301,7 +303,7 @@ export default {
     function onTouchEnd(e) {
       isMouseDown.value = false
       beginAutoMoveIntervalId = setInterval(() => {
-        if (moveSpeed.value === 0) {
+        if (moveSpeed.value === 0 && !isShowingBigImg.value) {
           isAutoMoving.value = true
         }
       }, 2000)
@@ -340,10 +342,18 @@ export default {
     /**
      * 镜头自动平移
      */
+    const isShowingBigImg = ref(false)
+    function onShowBigImg() {
+      isShowingBigImg.value = true
+    }
+    function onHideBigImg() {
+      isShowingBigImg.value = false
+    }
+
     let isAutoMoving = ref(false)
     let beginAutoMoveIntervalId = null
     beginAutoMoveIntervalId = setInterval(() => {
-      if (moveSpeed.value === 0) {
+      if (moveSpeed.value === 0 && !isShowingBigImg.value) {
         isAutoMoving.value = true
       }
     }, 2000)
@@ -517,6 +527,8 @@ export default {
       onTouchMove,
       onTouchEnd,
       onTouchCancel,
+      onShowBigImg,
+      onHideBigImg,
       personList,
       stageLabelList,
       stageList,

+ 13 - 0
yarn.lock

@@ -6149,6 +6149,14 @@ uuid@^8.3.2:
   resolved "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
   integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
 
+v-viewer@^3.0.11:
+  version "3.0.11"
+  resolved "https://registry.npmmirror.com/v-viewer/-/v-viewer-3.0.11.tgz#c03855eb56436bd0f5323c34a61c10fa8fd05026"
+  integrity sha512-E8LOdAxhzuktt4HB3PswVCccQ1Q1sYHYnLsS6zaJISpb5EvmAFs5sYNfXnDLFxVb5DQ82v4ZlGxkYlseXwWRJw==
+  dependencies:
+    lodash "^4.17.21"
+    viewerjs "^1.9.0"
+
 v8-compile-cache@^2.0.3:
   version "2.3.0"
   resolved "https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
@@ -6167,6 +6175,11 @@ vary@~1.1.2:
   resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
   integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
 
+viewerjs@^1.11.6, viewerjs@^1.9.0:
+  version "1.11.6"
+  resolved "https://registry.npmmirror.com/viewerjs/-/viewerjs-1.11.6.tgz#19a1e78c15eba5a9fbbf34ebc5ab312d6e8932ed"
+  integrity sha512-TlhdSp2oEOLFXvEp4psKaeTjR5zBjTRcM/sHUN8PkV1UWuY8HKC8n7GaVdW5Xqnwdr/F1OmzLik1QwDjI4w/nw==
+
 vue-demi@*:
   version "0.14.5"
   resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"