Browse Source

feat: 保存

gemercheung 1 year ago
parent
commit
91b02cf32c

+ 38 - 0
src/components/empty.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="empty">
+    <n-empty v-if="show" :description="title" />
+  </div>
+</template>
+<script setup>
+defineOptions({
+  name: "empty",
+});
+
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: () => true,
+  },
+  title: {
+    type: [String, undefined],
+    default: () => "没有数据了~",
+  },
+  height: {
+    type: [String, Number],
+    default: () => 300,
+  },
+});
+</script>
+
+<style>
+.empty {
+  width: 100%;
+  height: 100%;
+  flex: 1;
+  display: inline-flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  min-height: v-bind (height +'px');
+}
+</style>

+ 32 - 7
src/components/exhibitionBox.vue

@@ -1,13 +1,15 @@
 <template>
   <n-card class="exhibition-box" @click="handleTodetail">
     <div class="box">
-      <img class="cover" :src="cover" />
+      <div class="cover">
+        <img :src="cover" />
+      </div>
       <div class="info">
         <div class="title">{{ title }}</div>
-        <div class="content—box">{{ content }}</div>
+        <div class="content—box"><div v-html="content"></div></div>
         <div class="label-box">
-          <div class="label location">{{ location }}</div>
-          <div class="label type">{{ type }}</div>
+          <div class="label location" v-if="location">{{ location }}</div>
+          <div class="label type" v-if="typeLabel(type)">{{ typeLabel(type) }}</div>
           <div v-if="isHasVR" class="vr_button"></div>
         </div>
       </div>
@@ -15,9 +17,21 @@
   </n-card>
 </template>
 <script setup>
+import { computed } from "vue";
 import { useRouter } from "vue-router";
 const router = useRouter();
 
+const typeLabel = computed(() => (type) => {
+  switch (type) {
+    case "long":
+      return "常设展览";
+    case "topic":
+      return "专题展览";
+    case "temp":
+      return "临时展览";
+  }
+});
+
 defineOptions({
   name: "exhibition-box",
 });
@@ -86,8 +100,15 @@ const handleTodetail = () => {
     flex-direction: row;
 
     .cover {
-      height: 215px;
-      width: auto;
+      height: 13.4375rem;
+      width: 22.6875rem;
+      background: #595959;
+      img {
+        width: 100%;
+        height: 100%;
+        object-fit: cover;
+        object-position: top center;
+      }
     }
     .info {
       flex: 1;
@@ -107,7 +128,7 @@ const handleTodetail = () => {
         display: inline-flex;
         height: 40px;
         align-items: center;
-        gap: 0 .625rem;
+        gap: 0 0.625rem;
         width: 100%;
         color: #6e6e6e;
         font-size: 16px;
@@ -117,6 +138,10 @@ const handleTodetail = () => {
           background-repeat: no-repeat;
           padding-left: 22px;
           background-position: center left;
+          max-width: 200px;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          overflow: hidden;
         }
       }
     }

+ 20 - 3
src/store/collect.js

@@ -8,11 +8,12 @@ export const useCollectStore = defineStore({
       lists: [],
       entity: {},
       files: [],
+      currentLevel: null,
       pagination: {
         dictLevel: "",
         endTime: "",
         pageNum: 0,
-        pageSize: 0,
+        pageSize: 20,
         searchKey: "",
         startTime: "",
       },
@@ -20,8 +21,7 @@ export const useCollectStore = defineStore({
   },
   getters: {},
   actions: {
-    async getCollectList(page) {
-      this.pagination.pageNum = page || 1;
+    async fetch() {
       const { data, status } = await request.post("/show/goods/pageList", {
         ...this.pagination,
       });
@@ -33,6 +33,13 @@ export const useCollectStore = defineStore({
         this.pagination.page = page;
       }
     },
+    async getCollectList(page, level) {
+      this.pagination.pageNum = page || 1;
+      this.pagination.dictLevel = level === 0 ? "" : level;
+      this.currentLevel = level;
+      await this.fetch();
+    },
+
     async getDetail(id) {
       const { data, status } = await request.get(`show/goods/detail/${id}`);
       if (data.code === 0) {
@@ -44,5 +51,15 @@ export const useCollectStore = defineStore({
         this.files = [];
       }
     },
+    async search(searchKey, level) {
+      this.pagination.searchKey = searchKey;
+      this.pagination.pageNum = 1;
+      this.pagination.dictLevel = level === 0 ? "" : level;
+      await this.fetch();
+    },
+    async clearSearch() {
+      this.pagination.searchKey = "";
+      // await this.fetch();
+    },
   },
 });

+ 60 - 0
src/store/exhibition.js

@@ -0,0 +1,60 @@
+import { defineStore } from "pinia";
+import { request } from "../api";
+
+export const useExhibitionStore = defineStore({
+  id: "exhibition",
+  state: () => {
+    return {
+      lists: [],
+      detail: {},
+      pagination: {
+        type: "",
+        endTime: "",
+        pageNum: 0,
+        pageSize: 20,
+        searchKey: "",
+        startTime: "",
+      },
+    };
+  },
+  getters: {},
+  actions: {
+    async fetch() {
+      const { data, status } = await request.post("/show/exhibition/pageList", {
+        ...this.pagination,
+      });
+      if (data.code === 0) {
+        const { records, total, current, page } = data.data;
+        this.lists = records;
+        this.pagination.total = total;
+        this.pagination.current = current;
+        this.pagination.page = page;
+      }
+    },
+    async getExhibitionList(page, type) {
+      this.pagination.pageNum = page || 1;
+      this.pagination.type = type === "all" ? "" : type;
+      await this.fetch();
+    },
+
+    async getDetail(id) {
+      const { data, status } = await request.get(
+        `show/exhibition/detail/${id}`
+      );
+      if (data.code === 0) {
+        this.detail = data.data;
+      } else {
+        this.detail = {};
+      }
+    },
+    async search(searchKey, type) {
+      this.pagination.searchKey = searchKey;
+      this.pagination.pageNum = 1;
+      this.pagination.type = type === all ? "" : type;
+      await this.fetch();
+    },
+    async clearSearch() {
+      this.pagination.searchKey = "";
+    },
+  },
+});

+ 52 - 25
src/views/collect.vue

@@ -3,7 +3,7 @@
     <div class="content">
       <sub-header />
       <div class="left">
-        <n-tabs type="line" pane-class="tab-content">
+        <n-tabs type="line" pane-class="tab-content" v-model:value="currentTab">
           <template #prefix>
             <span class="meta-title">
               <img src="@/assets/subtitle_3.png" />
@@ -18,15 +18,18 @@
               <n-input-group round>
                 <n-input
                   round
+                  clearable
                   v-model:value="inputValue"
                   placeholder="请输入要搜索的藏品"
+                  @clear="collectStore.clearSearch"
                 />
-                <n-button round type="primary"> 搜索 </n-button>
+                <n-button round type="primary" @click="handleSearch">
+                  搜索
+                </n-button>
               </n-input-group>
             </span>
           </template>
           <n-tab-pane name="all" tab="全部">
-            <!-- {{ collectLists }} -->
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="3" class="tab-grid">
               <template v-for="item in collectLists">
                 <n-gi>
@@ -39,48 +42,52 @@
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="collectLists.length === 0" :height="500" />
           </n-tab-pane>
-          <n-tab-pane name="one" tab="一级">
+          <n-tab-pane name="1" tab="一级">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="3" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in collectLists">
                 <n-gi>
                   <collect-box
-                    :id="index + 1"
-                    title="里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    time="2023-01-02"
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :time="item.publishDate"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="collectLists.length === 0" :height="500" />
           </n-tab-pane>
-          <n-tab-pane name="two" tab="二级">
+          <n-tab-pane name="2" tab="二级">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="3" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in collectLists">
                 <n-gi>
                   <collect-box
-                    :id="index + 1"
-                    title="里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    time="2023-01-02"
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :time="item.publishDate"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="collectLists.length === 0" :height="500" />
           </n-tab-pane>
-          <n-tab-pane name="three" tab="三级">
+          <n-tab-pane name="3" tab="三级">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="3" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in collectLists">
                 <n-gi>
                   <collect-box
-                    :id="index + 1"
-                    title="里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》里仁学校学生使用的课本——日本东洋博物学 会编《博物标本图汇》"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    time="2023-01-02"
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :time="item.publishDate"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="collectLists.length === 0" :height="500" />
           </n-tab-pane>
         </n-tabs>
       </div>
@@ -90,11 +97,12 @@
 </template>
 
 <script setup>
-import { computed, onMounted, ref } from "vue";
+import { computed, onMounted, ref, unref, watch, watchEffect } from "vue";
 import { useFullscreen } from "@vueuse/core";
 import collectBox from "../components/collectBox";
 import subHeader from "../components/subHeader";
 import sideMenu from "../components/sideMenu";
+import empty from "../components/empty.vue";
 // import noticeBox from "../components/noticeBox";
 import { useCollectStore } from "../store/collect";
 const collectStore = useCollectStore();
@@ -103,10 +111,29 @@ const collectLists = computed(() => collectStore.lists);
 const XGap = ref(50);
 const YGap = ref(50);
 const inputValue = ref("");
+const currentTab = ref("all");
 
-onMounted(() => {
-  collectStore.getCollectList();
-});
+watch(
+  currentTab,
+  (val) => {
+    const level = isNaN(Number(val)) ? 0 : Number(val);
+    collectStore.getCollectList(1, level);
+  },
+  {
+    immediate: true,
+  }
+);
+const handleSearch = () => {
+  if (unref(inputValue).length > 0) {
+    console.log("search");
+    const level = isNaN(Number(currentTab.value))
+      ? 0
+      : Number(currentTab.value);
+    collectStore.search(unref(inputValue), level);
+  } else {
+    collectStore.fetch();
+  }
+};
 </script>
 
 <style lang="scss" scoped>

+ 35 - 7
src/views/exhibition-detail.vue

@@ -16,18 +16,17 @@
 
           <div class="info">
             <div class="show-case"></div>
-            <h3 class="title">第一部分——高举新旗帜</h3>
+            {{ detail }}
+            <h3 class="title">{{ detail.name }}</h3>
             <div class="label-container">
               <div class="label-list">
-                <span>2号楼 1号厅 </span>
-                <span>临时展览</span>
-                <span>11.11-12.12</span>
+                <span>{{ detail.address }}</span>
+                <span v-if="detail.type">{{ typeLabel(detail.type) }}</span>
+                <span>{{ detail.publishDate }}</span>
               </div>
             </div>
 
-            <div class="text">
-              为服务好广大党员干部,浏阳秋收起义纪念馆充分发挥红色场馆、党性教育基地功能,结合“一月一课一片一实践”主题党日线路,主动谋划、精心策划,丰富载体和内容,特推出为期一天的“我的秋收起义学习之旅”五个一活动,致力于为广大基层党组织和党员营造良好氛围,凝聚党员干部服务经济社会发展的强大动能。
-            </div>
+            <div class="text" v-html="detail.richText"></div>
           </div>
         </div>
       </div>
@@ -37,18 +36,47 @@
 </template>
 
 <script setup>
+import { watchEffect, computed } from "vue";
 import heroSubTitle from "../components/heroSubTitle";
 import subHeader from "../components/subHeader";
 import sideMenu from "../components/sideMenu";
 import exBack from "../assets/ex_back.png";
 import vrBtn from "../assets/vr_button.png";
 import { useRouter } from "vue-router";
+import { useExhibitionStore } from "../store/exhibition";
+const exhibitionStore = useExhibitionStore();
 const router = useRouter();
+const detail = computed(() => exhibitionStore.detail);
+
+const typeLabel = computed(() => (type) => {
+  switch (type) {
+    case "long":
+      return "常设展览";
+    case "topic":
+      return "专题展览";
+    case "temp":
+      return "临时展览";
+  }
+});
 
 const handleVRButton = (id) => {
   // const url = `https://sit-qiushoubwg.4dage.com/scene/index.html#/?m=1196`;
   router.push(`/model-viewer/1196`);
 };
+const props = defineProps({
+  id: {
+    type: [String, Number],
+    default: () => null,
+    required: true,
+  },
+});
+
+watchEffect(() => {
+  document.title = "";
+  if (props.id) {
+    exhibitionStore.getDetail(props.id);
+  }
+});
 </script>
 
 <style>

+ 62 - 39
src/views/exhibition.vue

@@ -3,7 +3,9 @@
     <div class="content">
       <sub-header />
       <div class="left">
-        <n-tabs type="line" pane-class="tab-content">
+        <!-- {{ exhibitionList }} -->
+
+        <n-tabs type="line" pane-class="tab-content" v-model:value="currentTab">
           <template #prefix>
             <span class="meta-title">
               <img src="@/assets/subtitle_2.png" />
@@ -11,71 +13,76 @@
           </template>
           <n-tab-pane name="all" tab="全部展览">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="1" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in exhibitionList">
                 <n-gi>
+                  <!-- {{ item }} -->
                   <exhibition-box
-                    :id="index + 1"
-                    title="第一部分——高举新旗帜"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    content="这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段..."
-                    location="2号楼 1号厅"
-                    type="常设展览"
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :content="item.richText"
+                    :location="item.address"
+                    :type="item.type"
                     isHasVR
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="exhibitionList.length === 0" :height="500" />
           </n-tab-pane>
-          <n-tab-pane name="normal" tab="常设展览">
+          <n-tab-pane name="long" tab="常设展览">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="1" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in exhibitionList">
                 <n-gi>
                   <exhibition-box
-                    :id="index + 1"
-                    title="卡片"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    content="这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段..."
-                    location="2号楼 2号厅"
-                    type="常设展览"
-                    isHasVR
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :content="item.richText"
+                    :location="item.address"
+                    :type="item.type"
+                    :isHasVR="item.link.length > 0"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="exhibitionList.length === 0" :height="500" />
           </n-tab-pane>
-          <n-tab-pane name="special" tab="专题展览">
+          <n-tab-pane name="topic" tab="专题展览">
             <n-grid :x-gap="XGap" :y-gap="YGap" :cols="1" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in exhibitionList">
                 <n-gi>
                   <exhibition-box
-                    :id="index + 1"
-                    title="卡片"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    content="这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段..."
-                    location="2号楼 1号厅"
-                    type="常设展览"
-                    isHasVR
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :content="item.richText"
+                    :location="item.address"
+                    :type="item.type"
+                    :isHasVR="item.link.length > 0"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="exhibitionList.length === 0" :height="500" />
           </n-tab-pane>
           <n-tab-pane name="temp" tab="临时展览">
             <n-grid :y-gap="YGap" :cols="1" class="tab-grid">
-              <template v-for="(_, index) in 16">
+              <template v-for="item in exhibitionList">
                 <n-gi>
                   <exhibition-box
-                    :id="index + 1"
-                    title="这是一段标题这是一段标题"
-                    cover="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
-                    content="这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段摘要这是一段..."
-                    location="2号楼 2号厅"
-                    type="常设展览"
-                    isHasVR
+                    :id="item.id"
+                    :title="item.name"
+                    :cover="domain + item.thumb"
+                    :content="item.richText"
+                    :location="item.address"
+                    :type="item.type"
+                    :isHasVR="item.link.length > 0"
                   />
                 </n-gi>
               </template>
             </n-grid>
+            <empty :show="exhibitionList.length === 0" :height="500" />
           </n-tab-pane>
         </n-tabs>
       </div>
@@ -85,18 +92,34 @@
 </template>
 
 <script setup>
-import { onMounted } from "vue";
-import { useFullscreen } from "@vueuse/core";
+import { computed, watch } from "vue";
 import subHeader from "../components/subHeader";
 import sideMenu from "../components/sideMenu";
 import exhibitionBox from "../components/exhibitionBox";
-import { useInfoStore } from "../store/info";
+import { useExhibitionStore } from "../store/exhibition";
+import empty from "../components/empty.vue";
+
+const exhibitionStore = useExhibitionStore();
+const domain = ref(import.meta.env.VITE_DOMAIN_URL);
+const exhibitionList = computed(() => exhibitionStore.lists);
+
+
 
 const XGap = ref(50);
 const YGap = ref(50);
-const { isFullscreen, enter, exit, toggle } = useFullscreen();
 
-onMounted(() => {});
+const currentTab = ref("all");
+
+watch(
+  currentTab,
+  (val) => {
+    console.log("val", val);
+    exhibitionStore.getExhibitionList(1, val);
+  },
+  {
+    immediate: true,
+  }
+);
 </script>
 
 <style lang="scss" scoped>