ソースを参照

feat:咨询页(demo)

任一存 1 年間 前
コミット
5175a0ca88

BIN
public/images/demo-photo-0.jpg


BIN
public/images/demo-photo-1.jpg


BIN
public/images/demo-photo-2.jpg


BIN
public/images/demo-photo-3.jpg


BIN
public/images/demo-photo-4.jpg


BIN
public/images/demo-photo-5.jpg


ファイルの差分が大きいため隠しています
+ 91 - 1
public/staticConfig.js


BIN
src/assets/images/about/demo-photo-1.jpg


BIN
src/assets/images/about/demo-photo-2.jpg


BIN
src/assets/images/about/demo-photo-3.jpg


BIN
src/assets/images/about/icon_date.png


BIN
src/assets/images/about/icon_eye.png


BIN
src/assets/images/icon_arrow-left-blue.png


BIN
src/assets/images/icon_arrow-left-white.png


BIN
src/assets/images/icon_arrow-right-blue.png


BIN
src/assets/images/icon_arrow-right-white.png


BIN
src/assets/images/icon_arrow-top.png


+ 48 - 0
src/components/BtnBack.vue

@@ -0,0 +1,48 @@
+<template>
+  <button
+    class="btn-back"
+    @click="router.go(-1)"
+  >
+    <img
+      src="@/assets/images/icon_arrow-left-blue.png"
+      alt=""
+      class="icon"
+      draggable="false"
+    >
+    <div class="text">
+      返回
+    </div>
+  </button>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, onBeforeUnmount, inject } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const $env = inject('$env')
+</script>
+
+<style lang="less" scoped>
+.btn-back{
+  position: absolute;
+  left: calc(243 / 1920 * 100vw);
+  top: 26px;
+  display: flex;
+  align-items: center;
+  >img.icon{
+    height: 27px;
+  }
+  >.text{
+    margin-left: 13px;
+    font-family: Source Han Sans CN, Source Han Sans CN;
+    font-weight: 400;
+    font-size: 18px;
+    color: #589498;
+  }
+}
+</style>

+ 88 - 0
src/components/BtnTop.vue

@@ -0,0 +1,88 @@
+<template>
+  <button
+    v-show="isShow"
+    class="btn-top"
+    @click="onClick"
+  >
+    <img
+      class="icon"
+      src="@/assets/images/icon_arrow-top.png"
+      alt=""
+      draggable="false"
+    >
+    <div class="text">
+      返回顶部
+    </div>
+  </button>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, onBeforeUnmount, inject, nextTick } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const $env = inject('$env')
+
+const props = defineProps({
+  targetEl: {
+    required: true,
+    type: Object,
+  }
+})
+
+const isShow = ref(false)
+
+function onTargetScroll(e) {
+  console.log('sdf', props.targetEl.scrollTop)
+  if (props.targetEl.scrollTop < window.innerHeight * 0.3) {
+    isShow.value = false
+  } else {
+    isShow.value = true
+  }
+}
+onMounted(() => {
+  nextTick(() => {
+    props.targetEl.addEventListener('scroll', onTargetScroll)
+
+  })
+})
+onBeforeUnmount(() => {
+  props.targetEl.removeEventListener('scroll', onTargetScroll)
+})
+
+function onClick() {
+  // eslint-disable-next-line
+  props.targetEl.scrollTo({
+    top: 0,
+    // left: 0,
+    behavior: 'smooth',
+  })
+}
+
+</script>
+
+<style lang="less" scoped>
+.btn-top{
+  position: absolute;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  bottom: 46px;
+  right: 173px;
+  >img.icon{
+    width: 60px;
+    height: 60px;
+  }
+  >.text{
+    margin-top: 9px;
+    font-family: Source Han Sans CN, Source Han Sans CN;
+    font-weight: 400;
+    font-size: 18px;
+    color: #589498;
+  }
+}
+</style>

+ 4 - 0
src/main.js

@@ -13,6 +13,8 @@ import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
 
 import TableTitle from '@/components/TableTitle.vue'
+import BtnBack from '@/components/BtnBack.vue'
+import BtnTop from '@/components/BtnTop.vue'
 
 console.log(`version: ${process.env.VUE_APP_VERSION}`)
 console.log(`Build time: ${process.env.VUE_APP_UPDATE_TIME}`)
@@ -65,6 +67,8 @@ app.use(store)
   .use(VueViewer)
   .use(ElementPlus)
   .component('TableTitle', TableTitle)
+  .component('BtnBack', BtnBack)
+  .component('BtnTop', BtnTop)
   .mount('#app')
 
 //  you can reset the default options at any other time

+ 15 - 4
src/router/index.js

@@ -14,7 +14,8 @@ import InstitutionView from '@/views/about/InstitutionView.vue'
 import VisitView from '@/views/about/VisitView.vue'
 import ExhibitionView from '@/views/about/ExhibitionView.vue'
 import ServiceView from '@/views/about/ServiceView.vue'
-import ConsultView from '@/views/about/ConsultView.vue'
+import InfoView from '@/views/about/InfoView.vue'
+import InfoDetail from '@/views/about/InfoDetail.vue'
 import CollectionView from '@/views/about/CollectionView.vue'
 
 // import store from '@/store/index.js'
@@ -75,12 +76,22 @@ const routes = [
         },
       },
       {
-        path: 'consult',
-        name: 'ConsultView',
-        component: ConsultView,
+        path: 'info',
+        name: 'InfoView',
+        component: InfoView,
         meta: {
           aboutTabIdx: 4
         },
+        children: [
+          {
+            path: 'info-detail',
+            name: 'InfoDetail',
+            component: InfoDetail,
+            meta: {
+              hideTabBar: true,
+            }
+          },
+        ]
       },
       {
         path: 'collection',

+ 5 - 4
src/views/about/AboutView.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="about-view">
     <menu
+      v-show="!route.meta.hideTabBar"
       class="tab-bar"
     >
       <button
@@ -43,16 +44,16 @@
       >
         服务
       </button>
-      <!-- <button
+      <button
         :class="{
           active: $route.meta.aboutTabIdx === 4
         }"
         @click="$router.push({
-          name: 'ConsultView'
+          name: 'InfoView'
         })"
       >
-        咨询
-      </button> -->
+        资讯
+      </button>
       <!-- <button
         :class="{
           active: $route.meta.aboutTabIdx === 5

+ 1 - 1
src/views/about/CollectionView.vue

@@ -51,7 +51,7 @@
           name: 'ConsultView'
         })"
       >
-        咨询
+        资讯
       </button>
       <button
         :class="{

+ 0 - 92
src/views/about/ConsultView.vue

@@ -1,92 +0,0 @@
-<template>
-  <div class="about-view">
-    <menu
-      class="tab-bar"
-    >
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 0
-        }"
-        @click="$router.push({
-          name: 'InstitutionView'
-        })"
-      >
-        机构
-      </button>
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 1
-        }"
-        @click="$router.push({
-          name: 'VisitView'
-        })"
-      >
-        参观
-      </button>
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 2
-        }"
-        @click="$router.push({
-          name: 'ExhibitionView'
-        })"
-      >
-        展览
-      </button>
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 3
-        }"
-        @click="$router.push({
-          name: 'ServiceView'
-        })"
-      >
-        服务
-      </button>
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 4
-        }"
-        @click="$router.push({
-          name: 'ConsultView'
-        })"
-      >
-        咨询
-      </button>
-      <button
-        :class="{
-          active: $route.meta.aboutTabIdx === 5
-        }"
-        @click="$router.push({
-          name: 'CollectionView'
-        })"
-      >
-        典藏
-      </button>
-    </menu>
-
-    <router-view />
-  </div>
-</template>
-
-<script setup>
-import { ref, computed, watch, onMounted, onBeforeUnmount, inject } from "vue"
-import { useRoute, useRouter } from "vue-router"
-import { useStore } from "vuex"
-
-const route = useRoute()
-const router = useRouter()
-const store = useStore()
-
-const $env = inject('$env')
-</script>
-
-<style lang="less" scoped>
-.about-view{
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-}
-</style>

ファイルの差分が大きいため隠しています
+ 153 - 0
src/views/about/InfoDetail.vue


+ 384 - 0
src/views/about/InfoView.vue

@@ -0,0 +1,384 @@
+<template>
+  <div class="info-view">
+    <div class="content-wrap">
+      <div class="top-area">
+        <TableTitle
+          class="title"
+          text-cn="新闻资讯"
+          text-en="NEWS AND INFORMATION"
+        />
+        <div class="content">
+          <img
+            class="photo"
+            :src="`${$env.BASE_URL}images/demo-photo-${newsPageIdx * 3 + activeNewsIdx}.jpg`"
+            alt=""
+            draggable="false"
+            @click="onClickNews(newsList[newsPageIdx * 3 + activeNewsIdx].id)"
+          >
+          <ul class="list">
+            <div
+              v-for="n in 3"
+              :key="n"
+              class="list-item-wrap"
+            >
+              <li
+                class="list-item"
+                :class="{
+                  active: activeNewsIdx === n - 1,
+                }"
+                @mouseenter="activeNewsIdx = n - 1"
+                @click="onClickNews(newsList[newsPageIdx * 3 + n - 1].id)"
+              >
+                <div class="left">
+                  <div class="month-day">
+                    {{ newsList[newsPageIdx * 3 + n - 1].date.substring(5, 10) }}
+                  </div>
+                  <div class="year">
+                    {{ newsList[newsPageIdx * 3 + n - 1].date.substring(0, 4) }}
+                  </div>
+                </div>
+                <div class="splitter" />
+                <div class="right">
+                  <div
+                    class="title"
+                    :title="newsList[newsPageIdx * 3 + n - 1].title"
+                  >
+                    {{ newsList[newsPageIdx * 3 + n - 1].title }}
+                  </div>
+                  <div
+                    class="desc"
+                    :title="newsList[newsPageIdx * 3 + n - 1].desc"
+                  >
+                    {{ newsList[newsPageIdx * 3 + n - 1].desc }}
+                  </div>
+                </div>
+              </li>
+              <div
+                v-show="n !== 3"
+                class="splitter"
+              />
+            </div>
+          </ul>
+        </div>
+        <div class="page-ctrl">
+          <button
+            :class="{
+              show: newsPageIdx > 0,
+            }"
+            class="prev"
+            @click="newsPageIdx--"
+          />
+          <button
+            :class="{
+              show: newsPageIdx < newsList.length / 3 - 1,
+            }"
+            class="next"
+            @click="newsPageIdx++"
+          />
+        </div>
+      </div>
+      <div class="notification-area">
+        <TableTitle
+          class="title"
+          text-cn="通知公告"
+          text-en="NOTICE ANNOUNCEMENT"
+        />
+        <div class="splitter" />
+        <ul
+          class="table"
+        >
+          <li
+            v-for="(item, idx) in notificationList"
+            :key="idx"
+          >
+            <div
+              class="line"
+              @click="onClickNotification(item.id)"
+            >
+              <div
+                class="key"
+                :title="item.title"
+              >
+                <span class="dot">·</span> <span class="text">{{ item.title }}</span>
+                <span
+                  v-show="item.isNew"
+                  class="icon-new"
+                >新</span>
+              </div>
+              <span
+                class="value"
+                :title="item.desc"
+              >{{ item.date }}</span>
+            </div>
+            <div class="line-splitter" />
+          </li>
+        </ul>
+      </div>
+    </div>
+
+
+    <router-view />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, onBeforeUnmount, inject } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const $env = inject('$env')
+
+const newsList = staticConfig.newsList
+const newsPageIdx = ref(0)
+const activeNewsIdx = ref(0)
+
+const notificationList = staticConfig.notificationList
+
+function onClickNews(id) {
+  router.push({
+    name: 'InfoDetail'
+  })
+}
+
+function onClickNotification(id) {
+  router.push({
+    name: 'InfoDetail'
+  })
+}
+</script>
+
+<style lang="less" scoped>
+.info-view{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  >.content-wrap{
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    >.top-area{
+      height: 811px;
+      padding-left: calc(243 / 1920 * 100vw);
+      padding-right: calc(243 / 1920 * 100vw);
+      background-color: #fff;
+      position: relative;
+      >.title{
+        margin-top: 80px;
+      }
+      >.content{
+        margin-top: 51px;
+        height: 482px;
+        display: flex;
+        align-items: center;
+        >img.photo{
+          flex: 0 0 auto;
+          width: 700px;
+          height: 100%;
+          object-fit: cover;
+          cursor: pointer;
+        }
+        >ul.list{
+          flex: 0 0 auto;
+          height: 100%;
+          width: calc(100% - 700px);
+          >.list-item-wrap{
+            width: 100%;
+            >li.list-item{
+              height: 160px;
+              width: 100%;
+              display: flex;
+              justify-content: space-evenly;
+              align-items: center;
+              cursor: pointer;
+              color: #474747;
+              >.left{
+                flex: 0 0 auto;
+                width: 197px;
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                align-items: center;
+                >.month-day{
+                  font-family: Source Han Serif CN, Source Han Serif CN;
+                  font-weight: bold;
+                  font-size: 40px;
+                }
+                >.year{
+                  margin-top: 0.2em;
+                  font-family: Source Han Serif CN, Source Han Serif CN;
+                  font-weight: bold;
+                  font-size: 18px;
+                }
+              }
+              >.splitter{
+                flex: 0 0 auto;
+                width: 1px;
+                height: 80px;
+                background-color: #474747;
+              }
+              >.right{
+                flex: 1 0 1px;
+                margin-left: 35px;
+                margin-right: 38px;
+                >.title{
+                  display: -webkit-box;
+                  -webkit-box-orient: vertical;
+                  -webkit-line-clamp: 1;
+                  overflow: hidden;
+                  font-family: Source Han Sans CN, Source Han Sans CN;
+                  font-weight: 400;
+                  font-size: 24px;
+                }
+                >.desc{
+                  margin-top: 18px;
+                  display: -webkit-box;
+                  -webkit-box-orient: vertical;
+                  -webkit-line-clamp: 2;
+                  overflow: hidden;
+                  font-family: Source Han Sans CN, Source Han Sans CN;
+                  font-weight: 400;
+                  font-size: 18px;
+                  line-height: 29px;
+                }
+              }
+            }
+            >li.list-item.active{
+              color: #fff;
+              background: #589498;
+            }
+            >.splitter{
+              height: 1px;
+              background: #D9D9D9;
+            }
+          }
+        }
+      }
+      >.page-ctrl{
+        position: absolute;
+        bottom: 40px;
+        right: calc(243 / 1920 * 100vw);
+        >button{
+          width: 60px;
+          height: 60px;
+          opacity: 0;
+          pointer-events: none;
+        }
+        >button.show{
+          opacity: 1;
+          pointer-events: initial;
+        }
+        >button.prev{
+          background-image: url(@/assets/images/icon_arrow-left-round.png);
+          background-size: cover;
+          background-repeat: no-repeat;
+          background-position: center center;
+        }
+        >button.next{
+          margin-left: 22px;
+          background-image: url(@/assets/images/icon_arrow-right-round.png);
+          background-size: cover;
+          background-repeat: no-repeat;
+          background-position: center center;
+        }
+      }
+    }
+    >.notification-area{
+      height: 790px;
+      background-image: url(@/assets/images/about/institu-p3-bg.jpg);
+      background-size: cover;
+      background-repeat: no-repeat;
+      background-position: center center;
+      padding-left: calc(243 / 1920 * 100vw);
+      padding-right: calc(243 / 1920 * 100vw);
+      position: relative;
+      >.title{
+        margin-top: 32px;
+      }
+      >.splitter{
+        margin-top: 9px;
+        height: 1px;
+        background: #589498;
+      }
+      >ul.table{
+        margin-top: 30px;
+        height: 580px;
+        overflow: auto;
+        padding-right: 15px;
+        >li{
+          width: 100%;
+          >.line{
+            width: 100%;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            height: 88px;
+            cursor: pointer;
+            >.key{
+              display: flex;
+              align-items: center;
+              width: calc(100% - 150px);
+              flex: 0 0 auto;
+              font-family: Source Han Sans CN, Source Han Sans CN;
+              font-weight: 400;
+              font-size: 24px;
+              color: #474747;
+              >.dot{
+                font-size: 48px;
+              }
+              >.text{
+                overflow: hidden;
+                white-space: pre;
+                text-overflow: ellipsis;
+              }
+              >.icon-new{
+                margin-left: 16px;
+                width: 29px;
+                height: 29px;
+                background: #B31E23;
+                border-radius: 3px 3px 3px 3px;
+                font-family: Source Han Sans CN, Source Han Sans CN;
+                font-weight: 400;
+                font-size: 18px;
+                color: #FFFFFF;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+              }
+            }
+            >span.value{
+              width: 130px;
+              display: inline-block;
+              flex: 0 0 auto;
+              font-family: Source Han Sans CN, Source Han Sans CN;
+              font-weight: 400;
+              font-size: 24px;
+              color: #474747;
+              overflow: hidden;
+              white-space: pre;
+              text-overflow: ellipsis;
+            }
+          }
+          >.line-splitter{
+            height: 1px;
+            border: 1px dashed rgba(88,148,152,0.5);
+          }
+        }
+        >li:last-of-type{
+          >.line-splitter{
+            display: none;
+          }
+        }
+      }
+    }
+  }
+}
+</style>