Quellcode durchsuchen

🚧 重建整理优化项目4 文物地图页

快乐的梦鱼 vor 1 Monat
Ursprung
Commit
cfbcc88c76

+ 28 - 0
src/assets/scss/main.scss

@@ -172,6 +172,34 @@ main {
   }
 }
 
+.main-map-maker {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  
+  img {
+    width: 30px;
+    height: 30px;
+    border-radius: 50%;
+  }
+  span {
+    padding: 0.1rem;
+    font-size: 0.6rem;
+    border-radius: 0.2rem;
+    background-color: var(--color-light-bg);
+    white-space: nowrap;
+
+  }
+}
+.main-round-box {
+  padding: 1vw;
+  border-radius: 1vw;
+  box-sizing: border-box;
+  border: var(--color-primary) solid 3px;
+  overflow: hidden;
+}
+
 hr {
   border-color: var(--color-divider);
   border-width: 1px;

+ 14 - 1
src/components/parts/Header.vue

@@ -2,6 +2,8 @@
 import { useRouter } from 'vue-router';
 import Clock from '../small/Clock.vue';
 
+const emit = defineEmits(['back']);
+
 const props = defineProps({
   showBack: {
     type: Boolean,
@@ -10,17 +12,28 @@ const props = defineProps({
   absolute: {
     type: Boolean,
     default: false,
+  },
+  customBack: {
+    type: Boolean,
+    default: false,
   }
 });
 
 const router = useRouter();
 
+function handleBack() {
+  if (props.customBack) {
+    emit('back');
+  } else {
+    router.back();
+  }
+}
 </script>
 
 <template>
   <header :class="{ 'absolute': absolute }">
     <div class="logo">
-      <div v-if="showBack" class="back main-any-button" role="button" tabindex="0" @click="router.back()">
+      <div v-if="showBack" class="back main-any-button" role="button" tabindex="0" @click="handleBack()">
         <img src="@/assets/images/IconBack.png" >
         返回上一级
       </div>

+ 6 - 0
src/router/index.ts

@@ -49,6 +49,12 @@ const router = createRouter({
       name: 'IntangibleList',
       component: () => import('../views/Intangible/List.vue'),
     },
+    {
+      path: '/inheritMap',
+      name: 'InheritMap',
+      component: () => import('../views/Intangible/Map.vue'),
+    },
+
 
   ],
 })

+ 30 - 14
src/views/Content/TabInherit.vue

@@ -10,7 +10,7 @@
       itemWidth="100px" 
     />
     <div v-if="tab === 0" class="content flex-fill gap-s">
-      <div class="round-box introduction">
+      <div class="main-round-box introduction">
         <h1>闽南建筑文化简介</h1>
         <Vue3Marquee class="introduction-content" :duration="60" vertical>
           <p>闽南建筑风格独特。闽南建筑风格以红墙、红瓦、燕尾脊为特征,给人以鲜明、热烈的视觉感受。建筑中大量使用装饰性构件,如砖雕、石雕、木雕等,这些雕刻工艺精湛,图案丰富,具有很高的艺术价值。同时,建筑内部的布局和装饰也充满了闽南文化的特色,如“出砖入石”的墙体、精细的石雕和木雕、富有地方特色的彩绘等。</p>
@@ -23,10 +23,31 @@
         </div>
       </div>
       <div class="d-flex flex-col map">
-        <div class="round-box box main-any-button" :tabindex="1" />
+        <div 
+          class="main-round-box box main-any-button" 
+          :tabindex="1"
+          @click="router.push({ name: 'InheritMap' })"
+        >
+          <el-amap
+            style="width: 100%;"
+            :center="[118.137018, 24.500120]"
+            :zoom="10"
+          >
+            <el-amap-marker
+              v-for="value in loader.content.value?.list"
+              :position="[value.longitude, value.latitude]"
+              :content="value.title"
+            >
+              <div class="main-map-maker">
+                <img :src="value.image" alt="">
+                <span>{{ value.title }}</span>
+              </div>
+            </el-amap-marker>
+          </el-amap>
+        </div>
         <GridList 
           :list="loader.content.value?.list"
-          item-style-type="round-box main-any-button" 
+          item-style-type="main-round-box main-any-button" 
           @itemClick="handleItemClick"
         />
       </div>
@@ -235,17 +256,9 @@ function handleItemClick(item: any) {
     height: 100%;
     display: flex;
     flex-direction: column;
-
   }
 }
 
-.round-box {
-  padding: 1vw;
-  border-radius: 1vw;
-  box-sizing: border-box;
-  border: var(--color-primary) solid 3px;
-  overflow: hidden;
-}
 .introduction {
   background: url(https://huli-app.wenlvti.net/app_static/minnanhun/image/jzjs_bg.jpg) no-repeat center;
   background-size: cover;
@@ -272,16 +285,17 @@ function handleItemClick(item: any) {
 
   .box {
     width: 100%;
-    height: 26%;
+    height: 40%;
     background: url('@/assets/images/Inherit/map.jpg') no-repeat center;
     background-size: cover;
+    padding: 0 !important;
   }
   :deep(.grid-container) {
-    height: 72%;
+    height: 60%;
     margin-top: 2%;
     grid-template-rows: repeat(3, 1fr);
   }
-  :deep(.round-box) {
+  :deep(.main-round-box) {
     padding: 1vw;
     border-radius: 1vw;
     box-sizing: border-box;
@@ -289,6 +303,8 @@ function handleItemClick(item: any) {
     overflow: hidden;
   }
 }
+
+
 .intangible-list {
   display: flex;
   flex-direction: row;

+ 1 - 1
src/views/Details/ArtifactDetail.vue

@@ -3,7 +3,7 @@ import CommonDetail from './CommonDetail.vue';
 </script>
 
 <template>
-  <CommonDetail>
+  <CommonDetail v-bind="$attrs">
     <template #afterTitle="{ content }">
       <div class="desc">
         <div>地址: {{ content?.address }}</div>

+ 17 - 3
src/views/Details/CommonDetail.vue

@@ -10,7 +10,14 @@ import Header from '@/components/parts/Header.vue';
 import ImageLine from '@/components/small/ImageLine.vue';
 import ImagePreview from '@/components/small/ImagePreview.vue';
 
-const emit = defineEmits(['contentLoaded']);
+const emit = defineEmits(['contentLoaded','back']);
+
+const props = defineProps({
+  customBack: {
+    type: Boolean,
+    default: false,
+  },
+})
 
 const route = useRoute();
 const loader = useSimpleDataLoader(async () => {
@@ -28,7 +35,8 @@ watch(route, () => loader.loadData(undefined, true));
 
 <template>
   <main class="main-content main-bg main-bg1">
-    <Header show-back absolute />
+    <Header show-back absolute :custom-back="customBack" @back="emit('back')" />
+
     <SimplePageContentLoader :loader="loader">
       <div v-if="loader.content.value" class="content absolute">
         <div class="left" :style="{ backgroundImage: `url(${loader.content.value?.image})` }" />
@@ -37,7 +45,7 @@ watch(route, () => loader.loadData(undefined, true));
           <slot name="afterTitle" :content="loader.content.value" />
           <slot name="content" :content="loader.content.value">
             <Vue3Marquee style="width:100%;" :duration="70" :delay="10" vertical>      
-              <div class="d-flex flex-col">
+              <div class="d-flex flex-col w-100">
                 <slot name="beforeContent" :content="loader.content.value" />
                 <SimpleRichHtml :contents="[ loader.content.value?.content as string || '暂无' ]" noScroll />
                 <slot name="afterContent" :content="loader.content.value" />
@@ -91,6 +99,12 @@ watch(route, () => loader.loadData(undefined, true));
   h1 {
     font-size: 1rem;
     color: var(--color-text-primary);
+    width: 100%;
+    text-align: left;
+  }
+  h3, :deep(h3) { 
+    width: 100%;
+    text-align: left;
   }
 
   :deep(.image-line) { 

+ 101 - 4
src/views/Intangible/Map.vue

@@ -1,14 +1,45 @@
 <script setup lang="ts">
+import CommonContent, { GetContentListItem, GetContentListParams } from '@/api/CommonContent';
 import Header from '@/components/parts/Header.vue';
-import { ref } from 'vue';
+import SimplePopup from '@/components/SimplePopup.vue';
+import { useSimpleDataLoader } from '@/composeable/SimpleDataLoader';
+import { ScrollRect } from '@imengyu/vue-scroll-rect';
+import { nextTick, ref } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import ArtifactDetail from '../Details/ArtifactDetail.vue';
 
+const route = useRoute();
+const router = useRouter();
 const zoom = ref(12);
-const center = ref([121.59996, 31.197646]);
+const center = ref([118.137018, 24.500120]);
+const showDetail = ref(false);
+const currentItem = ref<GetContentListItem>();
+
 let map: any = null;
 
 function handleInit(mapRef: any) {
   map = mapRef;
 }
+function handleFocus(value: any) {
+  map.setCenter([value.longitude, value.latitude]);
+  map.setZoom(15);
+}
+function handleClick(value: any) {
+  router.replace({
+    query: {
+      ...route.query,
+      id: value.id,
+    }
+  });
+  setTimeout(() => {
+    showDetail.value = true;
+    currentItem.value = value;
+  }, 800)
+}
+
+const loader = useSimpleDataLoader(async () => {
+  return CommonContent.getContentList(new GetContentListParams().setModelId(1), 1, 50)
+});
 
 </script>
 
@@ -19,12 +50,78 @@ function handleInit(mapRef: any) {
       :center="center"
       :zoom="zoom"
       @init="handleInit"
-    />
-
+    >
+      <el-amap-marker
+        v-for="value in loader.content.value?.list"
+        :position="[value.longitude, value.latitude]"
+        :content="value.title"
+      >
+        <div class="main-map-maker">
+          <img :src="value.image">
+          <span>{{ value.title }}</span>
+        </div>
+      </el-amap-marker>
+    </el-amap>
+    <ScrollRect class="side-list main-round-box" scroll="vertical">
+      <div class="d-flex flex-col">
+        <div 
+          v-for="value in loader.content.value?.list"
+          :key="value.id"
+          class="item main-card main-any-button"
+          :tabindex="2"
+          @focus="handleFocus(value)"
+          @click="handleClick(value)"
+        >
+          <img :src="value.image" :alt="value.title">
+          <span>{{ value.title }}</span>
+        </div>
+      </div>
+    </ScrollRect>
+    <SimplePopup 
+      :show="showDetail"
+      @update:show="(v) => showDetail = v"
+    >
+      <div v-if="currentItem" class="dialog bg-light">
+        <ArtifactDetail class="h-100" custom-back @back="showDetail = false" />
+      </div>
+    </SimplePopup>
   </main>
 </template>
 
 <style lang="scss" scoped>
+.side-list {
+  position: absolute;
+  top: 100px;
+  left: 2%;
+  bottom: 2%;
+  width: 25%;
+  height: unset;
+  background-color: var(--color-light-bg);
+  padding: 0;
 
+  .item {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    padding: 0.2rem 2rem;
+
+    img {
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+      object-fit: cover;
+      margin-right: 1rem;
+    }
+    span {
+      font-size: 0.7rem;
+      color: var(--color-text);
+    }
+
+  }
+}
+.dialog {
+  width: 70vw;
+  height: 85vh;
+}
 
 </style>