chenlei 1 yıl önce
ebeveyn
işleme
5d8fafdb08
100 değiştirilmiş dosya ile 2606 ekleme ve 199 silme
  1. 1 0
      .env.development
  2. 1 0
      .env.production
  3. 4 0
      components.d.ts
  4. 1 0
      package.json
  5. 8 0
      pnpm-lock.yaml
  6. BIN
      public/Application_Form.doc
  7. 47 0
      src/App.vue
  8. 42 0
      src/api/collections.ts
  9. 40 0
      src/api/events.ts
  10. 61 0
      src/api/exhibition.ts
  11. 37 0
      src/api/index.ts
  12. 32 0
      src/api/learn.ts
  13. 42 0
      src/api/publications.ts
  14. 27 0
      src/api/search.ts
  15. 42 0
      src/api/visit.ts
  16. BIN
      src/assets/images/title.png
  17. 3 2
      src/components/Calendar.vue
  18. 2 5
      src/components/DateTable/index.vue
  19. 18 10
      src/components/ImgCard.vue
  20. 3 0
      src/components/Layout/components/Sidebar/index.scss
  21. 1 7
      src/components/Layout/components/Sidebar/index.vue
  22. 21 17
      src/components/Layout/data.ts
  23. 30 0
      src/components/Loading.vue
  24. 69 0
      src/configure.tsx
  25. 352 0
      src/data.ts
  26. 11 0
      src/main.ts
  27. 89 1
      src/router/index.ts
  28. 8 0
      src/stores/base.ts
  29. 55 0
      src/utils/date.ts
  30. 15 0
      src/utils/index.ts
  31. 63 0
      src/utils/usePagination.ts
  32. 37 0
      src/views/About/AboutDirector/index.scss
  33. 23 0
      src/views/About/AboutDirector/index.vue
  34. 20 0
      src/views/About/AboutLink/index.scss
  35. 26 0
      src/views/About/AboutLink/index.vue
  36. 43 0
      src/views/About/about.vue
  37. 31 0
      src/views/About/components/Contact/index.vue
  38. 32 0
      src/views/About/components/Director/index.scss
  39. 39 0
      src/views/About/components/Director/index.vue
  40. 94 0
      src/views/About/components/History/index.scss
  41. 131 0
      src/views/About/components/History/index.vue
  42. 29 0
      src/views/About/components/Partners/index.scss
  43. 41 0
      src/views/About/components/Partners/index.vue
  44. 186 0
      src/views/About/data.ts
  45. BIN
      src/views/About/images/bannerA.png
  46. BIN
      src/views/About/images/bgA.png
  47. BIN
      src/views/About/images/bgAD.png
  48. BIN
      src/views/About/images/his/1m.png
  49. BIN
      src/views/About/images/his/2m.png
  50. BIN
      src/views/About/images/his/3m.png
  51. BIN
      src/views/About/images/his/4m.png
  52. BIN
      src/views/About/images/his/back.png
  53. BIN
      src/views/About/images/link/1.jpg
  54. BIN
      src/views/About/images/link/10.jpg
  55. BIN
      src/views/About/images/link/11.jpg
  56. BIN
      src/views/About/images/link/12.jpg
  57. BIN
      src/views/About/images/link/13.jpg
  58. BIN
      src/views/About/images/link/14.jpg
  59. BIN
      src/views/About/images/link/15.jpg
  60. BIN
      src/views/About/images/link/16.jpg
  61. BIN
      src/views/About/images/link/17.jpg
  62. BIN
      src/views/About/images/link/18.jpg
  63. BIN
      src/views/About/images/link/19.jpg
  64. BIN
      src/views/About/images/link/2.jpg
  65. BIN
      src/views/About/images/link/20.jpg
  66. BIN
      src/views/About/images/link/3.jpg
  67. BIN
      src/views/About/images/link/4.jpg
  68. BIN
      src/views/About/images/link/5.jpg
  69. BIN
      src/views/About/images/link/6.jpg
  70. BIN
      src/views/About/images/link/7.jpg
  71. BIN
      src/views/About/images/link/8.jpg
  72. BIN
      src/views/About/images/link/9.jpg
  73. BIN
      src/views/About/images/ren.jpg
  74. 6 0
      src/views/About/index.scss
  75. 12 0
      src/views/About/index.vue
  76. 2 0
      src/views/Collections/List/index.scss
  77. 110 43
      src/views/Collections/List/index.vue
  78. 12 0
      src/views/Collections/index.scss
  79. 54 3
      src/views/Collections/index.vue
  80. 0 0
      src/views/Employment/index.scss
  81. 27 1
      src/views/Employment/index.vue
  82. 40 0
      src/views/Events/Detail/index.scss
  83. 32 0
      src/views/Events/Detail/index.vue
  84. BIN
      src/views/Events/images/banner.png
  85. BIN
      src/views/Events/images/bgEI.png
  86. 41 0
      src/views/Events/index.scss
  87. 22 1
      src/views/Events/index.vue
  88. 56 11
      src/views/Exhibitions/Current/index.vue
  89. 80 40
      src/views/Exhibitions/Detail/index.vue
  90. 1 1
      src/views/Exhibitions/Galleries/index.scss
  91. 27 12
      src/views/Exhibitions/Galleries/index.vue
  92. 1 1
      src/views/Exhibitions/Objects/index.scss
  93. 27 12
      src/views/Exhibitions/Objects/index.vue
  94. 47 3
      src/views/Exhibitions/Overseas/index.vue
  95. 48 3
      src/views/Exhibitions/Past/index.vue
  96. 1 0
      src/views/Exhibitions/Permanent/index.scss
  97. 47 3
      src/views/Exhibitions/Permanent/index.vue
  98. 33 14
      src/views/Exhibitions/index.vue
  99. 23 9
      src/views/Home/index.vue
  100. 0 0
      src/views/JoinSupport/Give/index.scss

+ 1 - 0
.env.development

@@ -0,0 +1 @@
+VITE_BASE_URL=https://sit-shoubov2.4dage.com

+ 1 - 0
.env.production

@@ -0,0 +1 @@
+VITE_BASE_URL=https://sit-shoubov2.4dage.com

+ 4 - 0
components.d.ts

@@ -13,6 +13,7 @@ declare module 'vue' {
     ImgCard: typeof import('./src/components/ImgCard.vue')['default']
     ImgSwiper: typeof import('./src/components/ImgSwiper.vue')['default']
     Layout: typeof import('./src/components/Layout/index.vue')['default']
+    Loading: typeof import('./src/components/Loading.vue')['default']
     PageBanner: typeof import('./src/components/PageBanner.vue')['default']
     PageLabel: typeof import('./src/components/PageLabel/index.vue')['default']
     PageNav: typeof import('./src/components/PageNav.vue')['default']
@@ -25,9 +26,12 @@ declare module 'vue' {
     VanCalendar: typeof import('vant/es')['Calendar']
     VanCollapse: typeof import('vant/es')['Collapse']
     VanCollapseItem: typeof import('vant/es')['CollapseItem']
+    VanEmpty: typeof import('vant/es')['Empty']
     VanIcon: typeof import('vant/es')['Icon']
     VanImage: typeof import('vant/es')['Image']
     VanImagePreview: typeof import('vant/es')['ImagePreview']
+    VanList: typeof import('vant/es')['List']
+    VanLoading: typeof import('vant/es')['Loading']
     VanNoticeBar: typeof import('vant/es')['NoticeBar']
     VanPagination: typeof import('vant/es')['Pagination']
     VanPopup: typeof import('vant/es')['Popup']

+ 1 - 0
package.json

@@ -34,6 +34,7 @@
     "npm-run-all2": "^6.1.2",
     "postcss-px-to-viewport": "^1.1.1",
     "sass": "^1.77.4",
+    "tslib": "^2.6.3",
     "typescript": "~5.4.0",
     "unplugin-vue-components": "^0.27.0",
     "vite": "^5.2.8",

+ 8 - 0
pnpm-lock.yaml

@@ -72,6 +72,9 @@ importers:
       sass:
         specifier: ^1.77.4
         version: 1.77.4
+      tslib:
+        specifier: ^2.6.3
+        version: 2.6.3
       typescript:
         specifier: ~5.4.0
         version: 5.4.5
@@ -1875,6 +1878,9 @@ packages:
     resolution: {integrity: sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==}
     engines: {node: '>= 0.4'}
 
+  tslib@2.6.3:
+    resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
+
   typed-array-buffer@1.0.2:
     resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
     engines: {node: '>= 0.4'}
@@ -3975,6 +3981,8 @@ snapshots:
       typedarray.prototype.slice: 1.0.3
       which-typed-array: 1.1.15
 
+  tslib@2.6.3: {}
+
   typed-array-buffer@1.0.2:
     dependencies:
       call-bind: 1.0.7

BIN
public/Application_Form.doc


+ 47 - 0
src/App.vue

@@ -1,5 +1,39 @@
 <script setup lang="ts">
+import { onBeforeMount, onMounted } from "vue";
 import { RouterView } from "vue-router";
+import { getBannerListApi } from "./api";
+import { useBaseStore } from "./stores/base";
+
+const baseStore = useBaseStore();
+
+onBeforeMount(() => {
+  // 移动端和pc端的切换
+  if (
+    window.navigator.userAgent.match(
+      /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+    )
+  ) {
+    // 移动端
+  } else {
+    console.log("----------", window.location.href);
+    if (window.location.href.includes("en.capitalmuseum.org.cn")) {
+      // PC端
+      window.location.href = window.location.origin;
+      setTimeout(() => {
+        location.reload();
+      }, 200);
+    }
+  }
+});
+
+onMounted(() => {
+  getBannerList();
+});
+
+const getBannerList = async () => {
+  const data = await getBannerListApi();
+  baseStore.bannerList = data;
+};
 </script>
 
 <template>
@@ -14,6 +48,10 @@ import { RouterView } from "vue-router";
   font-style: normal;
 }
 
+.primary {
+  color: var(--van-primary-color);
+}
+
 .more {
   margin: 40px auto 0;
   width: 234px;
@@ -24,4 +62,13 @@ import { RouterView } from "vue-router";
   font-size: 32px;
   background: url("@/assets/images/see.png") no-repeat center / contain;
 }
+
+.page-title {
+  margin-bottom: 40px;
+  padding-left: 60px;
+  font-size: 44px;
+  font-weight: bold;
+  background: url("@/assets/images/chosen.png") 0 no-repeat;
+  background-size: 44px 36px;
+}
 </style>

+ 42 - 0
src/api/collections.ts

@@ -0,0 +1,42 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+
+export interface CollectionThumbListItem {
+  id: number;
+  type: string;
+  thumb: string;
+}
+
+export interface CollectionListParams extends PaginationParams {
+  type?: string;
+}
+
+export interface CollectionListItem {
+  id: number;
+  name: string;
+  thumb: string;
+  /** 年代 */
+  dictAge: string;
+  /** 摘要 */
+  digest: string;
+}
+
+export interface CollectionDetail extends CollectionListItem {
+  rtf: string;
+  size: string;
+}
+
+export const getCollectionThumbListApi = () => {
+  return requestByGet<CollectionThumbListItem[]>("/api/show/collection/thumb");
+};
+
+export const getCollectionListApi = (params: CollectionListParams) => {
+  return requestByPost("/api/show/collection/pageList", params);
+};
+
+export const getCollectionDetailApi = (id: number) => {
+  return requestByGet<CollectionDetail>(`/api/show/collection/detail/${id}`);
+};

+ 40 - 0
src/api/events.ts

@@ -0,0 +1,40 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+
+export interface EventListParams extends PaginationParams {
+  searchKey?: string;
+}
+
+export interface EventListItem {
+  id: number;
+  name: string;
+  rtfTitle: string;
+  thumb: string;
+  dateStart: string;
+  dateEnd: string;
+}
+
+export interface EventDetail extends EventListItem {
+  rtf: string;
+}
+
+export const getEventListApi = (params: EventListParams) => {
+  return requestByPost("/api/show/event/pageList", params);
+};
+
+export const getEventDetailApi = (id: number | string) => {
+  return requestByGet<EventDetail>(`/api/show/event/detail/${id}`);
+};
+
+export interface RecommendEventListParams {
+  limit: number;
+  /** 需要排除的事件 id */
+  id: number | string;
+}
+
+export const getRecommendEventListApi = (params: RecommendEventListParams) => {
+  return requestByGet<EventDetail[]>("/api/show/event/recommend", params);
+};

+ 61 - 0
src/api/exhibition.ts

@@ -0,0 +1,61 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+import type { FileItem } from ".";
+
+export interface GetExhibitionListParams extends PaginationParams {
+  /**
+   * 展览时间, temp:临时展览(需要添加开始-结束时间) | long:常设展览
+   */
+  type?: "temp" | "long";
+  searchKey?: string;
+  /**
+   * 展览地址,inland:国内 | foreign:国外
+   */
+  addrType?: "inland" | "foreign";
+  year?: string;
+  /**
+   * 当前展览, 0: 过去展览 | 1:当前展览
+   */
+  isCurrent?: 0 | 1;
+}
+
+export interface ExhibitionsListItem {
+  id: number;
+  name: string;
+  thumb: string;
+  digest: string;
+}
+
+export interface ExhibitionDetail extends ExhibitionsListItem {
+  rtf: string;
+  thumbPc: string;
+  typeRemark: string;
+  address: string;
+  dateStart: string;
+  dateEnd: string;
+  exhibitsFile: FileItem[];
+  exhibitionFile: FileItem[];
+}
+
+export const getExhibitionListApi = (params: GetExhibitionListParams) => {
+  return requestByPost("/api/show/exhibition/pageList", params, {
+    meta: {
+      showLoading: true,
+    },
+  });
+};
+
+export const getExhibitionDetailApi = (id: number | string) => {
+  return requestByGet<ExhibitionDetail>(
+    `/api/show/exhibition/detail/${id}`,
+    undefined,
+    {
+      meta: {
+        showLoading: true,
+      },
+    }
+  );
+};

+ 37 - 0
src/api/index.ts

@@ -0,0 +1,37 @@
+import { requestByGet } from "@dage/service";
+
+export interface FileItem {
+  id: number;
+  filePath: string;
+  fileName: string;
+}
+
+export interface TxtArrItem {
+  id: number;
+  name: string;
+  txt: string;
+}
+
+export const getHomeListApi = () => {
+  return requestByGet("/api/show/index/getList", undefined, {
+    meta: {
+      showLoading: true,
+    },
+  });
+};
+
+export const getBannerListApi = () => {
+  return requestByGet("/api/show/poster/getList");
+};
+
+export const getBannerApi = (id: number) => {
+  return requestByGet(`/api/show/poster/detail/${id}`);
+};
+
+export * from "./learn";
+export * from "./publications";
+export * from "./collections";
+export * from "./exhibition";
+export * from "./visit";
+export * from "./events";
+export * from "./search";

+ 32 - 0
src/api/learn.ts

@@ -0,0 +1,32 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+
+export interface LearnPageListParams extends PaginationParams {
+  searchKey?: string;
+  type?: string;
+}
+
+export interface LearnPageItem {
+  id: number;
+  name: string;
+  address: string;
+  thumb: string;
+  remark: string;
+  dateStart: string;
+  dateEnd?: string;
+}
+
+export interface LearnDetail extends LearnPageItem {
+  rtf: string;
+}
+
+export const getLearnPageListApi = (params: LearnPageListParams) => {
+  return requestByPost("/api/show/learn/pageList", params);
+};
+
+export const getLearnDetailApi = (id: string | number) => {
+  return requestByGet<LearnDetail>(`/api/show/learn/detail/${id}`);
+};

+ 42 - 0
src/api/publications.ts

@@ -0,0 +1,42 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+
+export interface PublishListParams extends PaginationParams {
+  type?: "Magazines" | "Exhibition";
+  searchKey?: string;
+  year?: number;
+}
+
+/**
+ * 书刊类型
+ */
+export interface PubicationItem {
+  id: number;
+  thumb: string;
+  name: string;
+}
+
+/**
+ * 展会会刊类型
+ */
+export interface ExhibitionCatalogue extends PubicationItem {
+  filePath: string;
+}
+
+/**
+ * 书刊详情类型
+ */
+export interface PublicationDetail extends PubicationItem {
+  rtf: string;
+}
+
+export const getPublishListApi = async (params: PublishListParams) => {
+  return requestByPost("/api/show/publish/pageList", params);
+};
+
+export const getPublishDetailApi = async (id: string | number) => {
+  return requestByGet<PublicationDetail>(`/api/show/publish/detail/${id}`);
+};

+ 27 - 0
src/api/search.ts

@@ -0,0 +1,27 @@
+import { requestByPost, type PaginationParams } from "@dage/service";
+
+export type ModuleType =
+  | "exhibition"
+  | "event"
+  | "collection"
+  | "learn"
+  | "publish";
+
+export interface SearchParams extends PaginationParams {
+  searchKey?: string;
+  module?: ModuleType;
+}
+
+export interface SearchItem {
+  id: number;
+  module: ModuleType;
+  thumb: string;
+  rtf: string;
+  name: string;
+  type: string;
+  filePath: string;
+}
+
+export const searchApi = (params: SearchParams) => {
+  return requestByPost("/api/show/search", params);
+};

+ 42 - 0
src/api/visit.ts

@@ -0,0 +1,42 @@
+import {
+  requestByGet,
+  requestByPost,
+  type PaginationParams,
+} from "@dage/service";
+
+export interface ListByDateItem {
+  /**
+   * 所属分类 id
+   */
+  id: number;
+  name: string;
+  thumb: string;
+  dateStart: string | null;
+  dateEnd: string | null;
+  module: string;
+  type: "learn" | "exhibition" | "event";
+  address: string;
+}
+
+export interface CalendarListParams extends PaginationParams {
+  module: "event" | "exhibition" | "learn" | "all";
+  startTime?: string;
+  endTime?: string;
+  searchKey?: string;
+}
+
+export const getListByDateApi = (params: { date: string }) => {
+  return requestByGet<ListByDateItem[]>("/api/show/findByDate", params);
+};
+
+export const getListByMonthApi = (params: { month: string }) => {
+  return requestByGet<ListByDateItem[]>("/api/show/findByMonth", params);
+};
+
+export const getCalendarListApi = (params: CalendarListParams) => {
+  return requestByPost("/api/show/recommend/pageList", params, {
+    meta: {
+      showLoading: true,
+    },
+  });
+};

BIN
src/assets/images/title.png


+ 3 - 2
src/components/Calendar.vue

@@ -15,8 +15,8 @@
       :first-day-of-week="1"
       @pick="pickDay"
     >
-      <template name="dateCell" slot-scope="{ date, data }">
-        {{ data.day.split("-")[1] }}1
+      <template #dateCell="{ data }">
+        <slot :data="data" />
       </template>
     </DateTable>
 
@@ -115,6 +115,7 @@ export default {
 
       if (day === this.formatedDate) return;
       this.pickDay(day);
+      this.$emit("changeMonth");
     },
   },
 };

+ 2 - 5
src/components/DateTable/index.vue

@@ -27,7 +27,7 @@
           @click="pickDay(cell)"
         >
           <div class="el-calendar-day">
-            {{ cellRenderProxy(cell) }}
+            <slot name="dateCell" :data="cellRenderProxy(cell)" />
           </div>
         </td>
       </tr>
@@ -188,9 +188,6 @@ export default defineComponent({
     }
 
     function cellRenderProxy({ text, type }) {
-      let render = elCalendar.$slots.dateCell;
-      if (!render) return text;
-
       const day = getFormateDate(text, type);
       const date = new Date(day);
       const data = {
@@ -198,7 +195,7 @@ export default defineComponent({
         type: `${type}-month`,
         day,
       };
-      return render({ date, data });
+      return { date, data };
     }
 
     return {

+ 18 - 10
src/components/ImgCard.vue

@@ -1,26 +1,34 @@
 <template>
-  <div class="img-card">
-    <VanImage
-      class="img-card__img"
-      :height="160"
-      src="https://en.capitalmuseum.org.cn/data/Exhibitions/Past/40.jpg"
-    />
+  <div
+    class="img-card"
+    @click="$router.push({ name: 'ExDetail', query: { id: item.id } })"
+  >
+    <VanImage class="img-card__img" :height="160" :src="baseUrl + item.thumb" />
 
     <div class="img-card__inner">
       <p class="limit-line line-4">
-        Three Thousand Boundless Universes in Paintings - Portraits of Taoist
-        and Buddhist Figures Collected in the Capital Museum
+        {{ item.name }}
       </p>
     </div>
   </div>
 </template>
 
-<script lang="ts" setup></script>
+<script lang="ts" setup>
+import type { ExhibitionsListItem } from "@/api";
+import { getBaseURL } from "@dage/service";
+
+defineProps<{
+  item: ExhibitionsListItem;
+}>();
+
+const baseUrl = getBaseURL();
+</script>
 
 <style lang="scss" scoped>
 .img-card {
-  border-radius: 10px;
   overflow: hidden;
+  height: 100%;
+  border-radius: 10px;
   background: white;
   box-shadow: 0 2px 8px 6px #ccc;
 

+ 3 - 0
src/components/Layout/components/Sidebar/index.scss

@@ -53,6 +53,9 @@
         border-bottom: 1px solid #c1aa7b;
       }
     }
+    :deep(.van-cell__right-icon) {
+      padding-left: 10px;
+    }
     &__link {
       padding: 10px 0;
     }

+ 1 - 7
src/components/Layout/components/Sidebar/index.vue

@@ -26,13 +26,7 @@
           :name="item.id"
         >
           <template #title>
-            <div
-              class="sidebar-nav__title"
-              @click.stop="() => {
-                $router.push(item.routeParams!)
-                show = false
-              }"
-            >
+            <div class="sidebar-nav__title" @click.stop="handleClick(item)">
               {{ item.name }}
             </div>
           </template>

+ 21 - 17
src/components/Layout/data.ts

@@ -115,20 +115,20 @@ export const topData: TOP_DATA[] = [
   {
     id: 5,
     name: "Learn & Engage",
-    routeParams: { name: "LearnEngage", params: { type: "Students" } },
+    routeParams: { name: "LearnEngage" },
     children: [
       {
-        routeParams: "/Layout/LearnEngage/Students",
+        routeParams: { name: "LearnStudents" },
         id: 5.1,
         name: "For Students",
       },
       {
-        routeParams: "/Layout/LearnEngage/Adults",
+        routeParams: { name: "LearnAdults" },
         id: 5.2,
         name: "For Adults",
       },
       {
-        routeParams: "/Layout/LearnEngage/Families",
+        routeParams: { name: "LearnFamilies" },
         id: 5.3,
         name: "For Families & Children",
       },
@@ -139,9 +139,13 @@ export const topData: TOP_DATA[] = [
     name: "Publications",
     routeParams: { name: "Publications" },
     children: [
-      { routeParams: "/Layout/Publications/1", id: 6.1, name: "Magazines" },
       {
-        routeParams: "/Layout/Publications/2",
+        routeParams: "/Layout/Publications/Magazines",
+        id: 6.1,
+        name: "Magazines",
+      },
+      {
+        routeParams: "/Layout/Publications/Catalogues",
         id: 6.2,
         name: "Exhibition Catalogues",
       },
@@ -153,39 +157,39 @@ export const topData: TOP_DATA[] = [
     routeParams: { name: "JoinSupport" },
     children: [
       {
-        routeParams: "/Layout/JoinSupport/Volunteer",
+        routeParams: { name: "JoinVo" },
         id: 7.1,
         name: "Ways to Volunteer",
         children: [
           {
-            routeParams: "/Layout/JoinSupport/VolunteerInfo?id=1",
+            routeParams: { name: "JoinInfo", query: { id: 1 } },
             id: 7.11,
             name: "Volunteer Team Introduction",
           },
           {
-            routeParams: "/Layout/JoinSupport/VolunteerInfo?id=2",
+            routeParams: { name: "JoinInfo", query: { id: 2 } },
             id: 7.12,
             name: "Volunteer Apply",
           },
           {
-            routeParams: "/Layout/JoinSupport/VolunteerInfo?id=3",
+            routeParams: { name: "JoinInfo", query: { id: 3 } },
             id: 7.13,
             name: "Volunteer Program",
           },
         ],
       },
       {
-        routeParams: "/Layout/JoinSupport/Give",
+        routeParams: { name: "JoinGi" },
         id: 7.2,
         name: "Ways to Give",
         children: [
           {
-            routeParams: "/Layout/JoinSupport/GiveInfo?id=4",
+            routeParams: "/Layout/Join/GiveInfo?id=4",
             id: 7.21,
             name: "Individuals",
           },
           {
-            routeParams: "/Layout/JoinSupport/GiveInfo?id=5",
+            routeParams: "/Layout/Join/GiveInfo?id=5",
             id: 7.22,
             name: "Corporations Institutions",
           },
@@ -199,22 +203,22 @@ export const topData: TOP_DATA[] = [
     routeParams: { name: "About" },
     children: [
       {
-        routeParams: { name: "About", query: { scroll: 352 } },
+        routeParams: { name: "About", query: { scroll: 0 } },
         id: 8.1,
         name: "From the Director",
       },
       {
-        routeParams: { name: "About", query: { scroll: 816 } },
+        routeParams: { name: "About", query: { scroll: 1 } },
         id: 8.2,
         name: "History",
       },
       {
-        routeParams: { name: "About", query: { scroll: 1319 } },
+        routeParams: { name: "About", query: { scroll: 2 } },
         id: 8.3,
         name: "Partners & Connections",
       },
       {
-        routeParams: { name: "About", query: { scroll: 1525 } },
+        routeParams: { name: "About", query: { scroll: 3 } },
         id: 8.4,
         name: "Contact",
       },

+ 30 - 0
src/components/Loading.vue

@@ -0,0 +1,30 @@
+<template>
+  <div class="loading">
+    <VanLoading color="white" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.loading {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 998;
+
+  &::after {
+    content: "";
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: var(--van-overlay-background);
+    z-index: -1;
+  }
+}
+</style>

+ 69 - 0
src/configure.tsx

@@ -0,0 +1,69 @@
+import { showLoadingToast, showNotify, type ToastWrapperInstance } from "vant";
+import { compose, initial } from "@dage/service";
+import router from "./router";
+
+declare global {
+  interface DageRequestMeta {
+    /**
+     * 显示全局 错误信息, 默认为 true
+     */
+    showError?: boolean;
+    /**
+     * 显示全局 加载提示, 默认为 false
+     */
+    showLoading?: boolean;
+  }
+}
+
+enum RESPONSE_CODE_MAP {
+  NOT_FOUND = 2404,
+  UNDEFINED = 2001,
+}
+
+const showMessage = (msg: string, type = "danger") => {
+  showNotify({
+    // @ts-ignore
+    type,
+    message: msg,
+    duration: 4000,
+  });
+};
+
+initial({
+  fetch: window.fetch.bind(window),
+  baseURL: import.meta.env.VITE_BASE_URL,
+  interceptor: compose(async (request, next) => {
+    let loadingIns: ToastWrapperInstance | null = null;
+    if (request.meta.showLoading) {
+      loadingIns = showLoadingToast({
+        message: "Loading...",
+        forbidClick: true,
+        duration: 0,
+      });
+    }
+
+    const response = await next();
+    const { showError = true } = request.meta;
+
+    if (request.meta.showLoading) {
+      loadingIns?.close();
+    }
+
+    if (response.code !== 0 && showError) {
+      if (
+        [RESPONSE_CODE_MAP.NOT_FOUND, RESPONSE_CODE_MAP.UNDEFINED].includes(
+          response.code
+        )
+      ) {
+        router.replace({ name: "404" });
+
+        return response;
+      }
+
+      const message = response.__raw__.data.msg ?? "System on business trip";
+      showMessage(message);
+    }
+
+    return response;
+  }),
+});

Dosya farkı çok büyük olduğundan ihmal edildi
+ 352 - 0
src/data.ts


+ 11 - 0
src/main.ts

@@ -5,6 +5,11 @@ import { createPinia } from "pinia";
 
 import App from "./App.vue";
 import router from "./router";
+import { Locale, Notify } from "vant";
+import Loading from "@/components/Loading.vue";
+import enUS from "vant/es/locale/lang/en-US";
+import "vant/lib/notify/index.css";
+import "vant/lib/toast/index.css";
 
 import svgIcon from "@/components/SvgIcon/index.vue";
 import "virtual:svg-icons-register";
@@ -12,13 +17,19 @@ import "virtual:svg-icons-register";
 import Vue3TouchEvents from "vue3-touch-events";
 import PageLabel from "./components/PageLabel/index.vue";
 
+import "./configure";
+
 const app = createApp(App);
 
+Locale.use("en-US", enUS);
+
 app.use(createPinia());
 app.use(router);
+app.use(Notify);
 // @ts-ignore
 app.use(Vue3TouchEvents);
 app.component("svg-icon", svgIcon);
 app.component("page-label", PageLabel);
+app.component("comp-loading", Loading);
 
 app.mount("#app");

+ 89 - 1
src/router/index.ts

@@ -117,10 +117,31 @@ const router = createRouter({
         },
         // Learn页面
         {
-          path: "/Layout/Learn/:type",
+          path: "/Layout/Learn",
           name: "LearnEngage",
           component: () => import("../views/Learn/index.vue"),
           meta: { navBgColor: "#997369" },
+          redirect: { name: "LearnStudents" },
+          children: [
+            {
+              path: "/Layout/Learn/Learn/Students",
+              name: "LearnStudents",
+              component: () => import("../views/Learn/Students/index.vue"),
+              meta: { navBgColor: "#997369" },
+            },
+            {
+              path: "/Layout/Learn/Learn/Adults",
+              name: "LearnAdults",
+              component: () => import("../views/Learn/Adults/index.vue"),
+              meta: { navBgColor: "#997369" },
+            },
+            {
+              path: "/Layout/Learn/Learn/Families",
+              name: "LearnFamilies",
+              component: () => import("../views/Learn/Families/index.vue"),
+              meta: { navBgColor: "#997369" },
+            },
+          ],
         },
         {
           path: "/Layout/Learn/Info",
@@ -153,6 +174,65 @@ const router = createRouter({
             },
           ],
         },
+        // Join页面
+        {
+          path: "/Layout/Join",
+          name: "JoinSupport",
+          component: () => import("../views/JoinSupport/index.vue"),
+          meta: { navBgColor: "#b37f52" },
+          redirect: { name: "JoinVo" },
+          children: [
+            // 二级路由子页面
+            {
+              path: "/Layout/Join/Volunteer",
+              name: "JoinVo",
+              component: () =>
+                import("../views/JoinSupport/Volunteer/index.vue"),
+              meta: { navBgColor: "#b37f52" },
+            },
+            {
+              path: "/Layout/Join/Give",
+              name: "JoinGi",
+              component: () => import("../views/JoinSupport/Give/index.vue"),
+              meta: { navBgColor: "#b37f52" },
+            },
+            {
+              path: "/Layout/Join/Info",
+              name: "JoinInfo",
+              component: () => import("../views/JoinSupport/Info/index.vue"),
+              meta: { navBgColor: "#b37f52" },
+            },
+          ],
+        },
+        {
+          path: "/Layout/About",
+          name: "About",
+          meta: {
+            navBgColor: "#9f5b14",
+          },
+          redirect: { name: "AboutIndex" },
+          component: () => import("../views/About/index.vue"),
+          children: [
+            {
+              path: "/Layout/About/Index",
+              name: "AboutIndex",
+              component: () => import("../views/About/about.vue"),
+              meta: { navBgColor: "#9f5b14" },
+            },
+            {
+              path: "/Layout/AboutDirector",
+              name: "AboutDirector",
+              component: () => import("../views/About/AboutDirector/index.vue"),
+              meta: { navBgColor: "#9f5b14" },
+            },
+            {
+              path: "/Layout/AboutLink",
+              name: "AboutLink",
+              component: () => import("../views/About/AboutLink/index.vue"),
+              meta: { navBgColor: "#9f5b14" },
+            },
+          ],
+        },
         {
           path: "/Layout/Employment",
           name: "Employment",
@@ -169,6 +249,14 @@ const router = createRouter({
           },
           component: () => import("../views/Events/index.vue"),
         },
+        {
+          path: "/Layout/EventsInfo/:id",
+          name: "EventsDetail",
+          meta: {
+            navBgColor: "#a39382",
+          },
+          component: () => import("../views/Events/Detail/index.vue"),
+        },
       ],
     },
   ],

+ 8 - 0
src/stores/base.ts

@@ -0,0 +1,8 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+
+export const useBaseStore = defineStore("base", () => {
+  const bannerList = ref<{ id: number; name: string; thumbApp: string }[]>([]);
+
+  return { bannerList };
+});

+ 55 - 0
src/utils/date.ts

@@ -0,0 +1,55 @@
+export const MONTHS = [
+  "January",
+  "February",
+  "March",
+  "April",
+  "May",
+  "June",
+  "July",
+  "August",
+  "September",
+  "October",
+  "November",
+  "December",
+];
+
+export const DAYS_OF_WEEK = [
+  "Sunday",
+  "Monday",
+  "Tuesday",
+  "Wednesday",
+  "Thursday",
+  "Friday",
+  "Saturday",
+];
+
+/**
+ * 格式化日期
+ * @example
+ * getFormatDate('2024-07-05', null) // June 5, 2024
+ */
+export const getFormatDate = (dateStart: string, dateEnd?: string | null) => {
+  let dateTime = "";
+  const start = new Date(dateStart);
+  const end = dateEnd ? new Date(dateEnd) : null;
+
+  if (end) {
+    if (start.getFullYear() === end.getFullYear()) {
+      dateTime = `${MONTHS[start.getDay()]} ${start.getDate()} - ${
+        MONTHS[end.getDay()]
+      } ${end.getDate()}, ${end.getFullYear()}`;
+    } else {
+      dateTime = `${
+        MONTHS[start.getDay()]
+      } ${start.getDate()}, ${start.getFullYear()} - ${
+        MONTHS[end.getDay()]
+      } ${end.getDate()}, ${end.getFullYear()}`;
+    }
+  } else {
+    dateTime = `${
+      MONTHS[start.getDay()]
+    } ${start.getDate()}, ${start.getFullYear()}`;
+  }
+
+  return dateTime;
+};

+ 15 - 0
src/utils/index.ts

@@ -1,3 +1,18 @@
 export const getActualPixelValue = (val: number) => {
   return ((val / 750) * 100 * window.innerWidth) / 100;
 };
+
+export const getHashParams = () => {
+  const hash = window.location.hash.substring(1);
+  const params: Record<string, string> = {};
+
+  const hashParams = hash.split("&");
+  for (const param of hashParams) {
+    const [key, value] = param.split("=");
+    if (key) {
+      params[key] = decodeURIComponent(value || "");
+    }
+  }
+
+  return params;
+};

+ 63 - 0
src/utils/usePagination.ts

@@ -0,0 +1,63 @@
+import { computed, ref } from "vue";
+
+export enum PaginationType {
+  DEFAULT = 0,
+  CONCAT = 1,
+}
+
+export const DEFAULT_PAGE_SIZE = 10;
+
+export const usePagination = <T>(
+  handler: (params: { pageNum: number; pageSize: number }) => any,
+  type = PaginationType.DEFAULT,
+  size = DEFAULT_PAGE_SIZE
+) => {
+  const pageNum = ref(1);
+  const total = ref(0);
+  const loading = ref(false);
+  const list = ref<T[]>([]);
+  /** 最大页数 */
+  const pages = ref(0);
+  const noData = computed(() => !total.value && !loading.value);
+  const noMore = computed(() => size * pageNum.value > total.value);
+
+  const getList = async () => {
+    try {
+      loading.value = true;
+
+      const data = await handler({
+        pageNum: pageNum.value,
+        pageSize: size,
+      });
+      total.value = data.total;
+      pages.value = data.pages;
+
+      if (type === PaginationType.DEFAULT) {
+        list.value = data.records;
+      } else {
+        list.value =
+          pageNum.value > 1 ? list.value.concat(data.records) : data.records;
+      }
+    } finally {
+      loading.value = false;
+    }
+  };
+
+  const resetParams = () => {
+    pageNum.value = 1;
+    total.value = 0;
+    list.value = [];
+  };
+
+  return {
+    pageNum,
+    loading,
+    list,
+    pages,
+    total,
+    noData,
+    noMore,
+    getList,
+    resetParams,
+  };
+};

+ 37 - 0
src/views/About/AboutDirector/index.scss

@@ -0,0 +1,37 @@
+.about-director-detail {
+  padding: 40px 40px 80px;
+  background: url("../images/bgAD.png") no-repeat center top / cover;
+
+  &-profile {
+    margin-bottom: 40px;
+    text-align: center;
+
+    img {
+      display: inline-block;
+      width: 330px;
+      height: 330px;
+      border-radius: 50%;
+      border: 10px solid #fff;
+    }
+    h3 {
+      margin-top: 30px;
+      font-size: 32px;
+      font-weight: bold;
+    }
+    p {
+      text-align: justify;
+      color: var(--van-primary-color);
+      font-size: 24px;
+      line-height: 48px;
+    }
+  }
+
+  &-inner {
+    :deep(p) {
+      margin-bottom: 30px;
+      font-size: 28px;
+      color: #6a6a6a;
+      line-height: 32px;
+    }
+  }
+}

+ 23 - 0
src/views/About/AboutDirector/index.vue

@@ -0,0 +1,23 @@
+<template>
+  <div class="about-director-detail">
+    <p class="page-title">{{ detail.name }}</p>
+
+    <div class="about-director-detail-profile">
+      <img src="../images/ren.jpg" />
+      <h3>Han Zhanming</h3>
+      <p>Director of Capital Museum</p>
+    </div>
+
+    <div class="about-director-detail-inner" v-html="detail.rtf" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { About } from "@/data";
+
+const detail = About.Director;
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 20 - 0
src/views/About/AboutLink/index.scss

@@ -0,0 +1,20 @@
+.about-link {
+  padding: 40px 40px 80px;
+
+  &-item {
+    margin: 0 auto 40px;
+    max-width: 710px;
+
+    .page-title {
+      margin-bottom: 24px;
+    }
+    img {
+      display: block;
+      width: 100%;
+
+      &:not(:last-child) {
+        margin-bottom: 10px;
+      }
+    }
+  }
+}

+ 26 - 0
src/views/About/AboutLink/index.vue

@@ -0,0 +1,26 @@
+<template>
+  <div class="about-link">
+    <div v-for="item in linkData" :key="item.title" class="about-link-item">
+      <p class="page-title">{{ item.title }}</p>
+
+      <img
+        v-for="(subitem, idx) in item.son"
+        :key="idx"
+        :src="subitem.img"
+        @click="open(subitem.url)"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { linkData } from "../data";
+
+const open = (url: string) => {
+  window.open(url);
+};
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 43 - 0
src/views/About/about.vue

@@ -0,0 +1,43 @@
+<template>
+  <div class="about-main">
+    <PageNav ref="tabsRef" v-model="activeTab" scrollspy :swipe-threshold="3">
+      <van-tab title="From the Director">
+        <Director />
+      </van-tab>
+      <van-tab title="History">
+        <History />
+      </van-tab>
+      <van-tab title="Partners & Connections">
+        <Partners />
+      </van-tab>
+      <van-tab title="Contact">
+        <Contact />
+      </van-tab>
+    </PageNav>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { nextTick, ref, watch } from "vue";
+import PageNav from "@/components/PageNav.vue";
+import Director from "./components/Director/index.vue";
+import History from "./components/History/index.vue";
+import Partners from "./components/Partners/index.vue";
+import Contact from "./components/Contact/index.vue";
+import { useRoute } from "vue-router";
+
+const tabsRef = ref();
+const activeTab = ref(0);
+const route = useRoute();
+
+watch(route, () => {
+  route.query.scroll &&
+    nextTick(() => {
+      tabsRef.value?.tabsRef?.scrollTo(Number(route.query.scroll));
+    });
+});
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 31 - 0
src/views/About/components/Contact/index.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="about-contact">
+    <p class="page-title">Contact</p>
+
+    <div class="pp">Official website of Capital Museum:</div>
+    <p>https://en.capitalmuseum.org.cn/#/Layout/Home</p>
+    <div class="pp">Telephone reservation (individual visitors):</div>
+    <p>+86 (10) 63393339</p>
+    <div class="pp">Telephone reservation (group visitors):</div>
+    <p>+86 (10) 63370458</p>
+    <div class="pp">Inquiry Hotline:</div>
+    <p>+86 (10) 63370491</p>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.about-contact {
+  padding: 80px 20px;
+
+  .pp {
+    font-weight: bold;
+    line-height: 40px;
+    color: var(--van-primary-color);
+  }
+  p:not(:first-child) {
+    color: #6a6a6a;
+    line-height: 36px;
+    margin-bottom: 30px;
+  }
+}
+</style>

+ 32 - 0
src/views/About/components/Director/index.scss

@@ -0,0 +1,32 @@
+.about-director {
+  padding: 40px 20px 60px;
+  border-bottom: 1px solid #ccc;
+
+  &-card {
+    &__title {
+      margin-bottom: 30px;
+      padding-left: 60px;
+      font-size: 36px;
+      font-weight: bold;
+      background: url("@/assets/images/chosen.png") no-repeat;
+      background-size: 44px 36px;
+    }
+    &__inner {
+      p {
+        margin-bottom: 30px;
+        font-size: 28px;
+        color: #6a6a6a;
+        line-height: 32px;
+      }
+    }
+    &__more {
+      margin: 40px auto 20px;
+      width: 234px;
+      height: 74px;
+      background: url("@/assets/images/see.png") no-repeat center / contain;
+      color: #c1aa7b;
+      line-height: 74px;
+      text-align: center;
+    }
+  }
+}

+ 39 - 0
src/views/About/components/Director/index.vue

@@ -0,0 +1,39 @@
+<template>
+  <div class="about-director">
+    <div class="about-director-card">
+      <p class="page-title">From the Director</p>
+
+      <div class="about-director-card__inner">
+        <p>Welcome to the website of the Capital Museum of China.</p>
+        <p>
+          We are looking forward to your visit. The Capital Museum is a palace
+          of Beijing culture. Its collections relate to the long development of
+          the capital city, showcasing its magnificent living history of 500,000
+          years, urban history of 3,000 years and history as the Chinese capital
+          for 800 years. The museum also presents cultural and artistic
+          exhibitions from different regions and displays the achievements of
+          various ethnic groups at home and abroad. You can feel the breadth of
+          both Chinese and world civilizations.
+        </p>
+        <p>
+          Historical culture is the soul of a city and in the case of Beijing it
+          is a great witness to the long history of Chinese civilization. We are
+          looking forward to welcoming you to share with us the full
+          interpretation of this glorious civilization while immersing yourself
+          in the great wisdom of Beijing.
+        </p>
+      </div>
+
+      <div
+        class="about-director-card__more"
+        @click="$router.push({ name: 'AboutDirector' })"
+      >
+        See More
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 94 - 0
src/views/About/components/History/index.scss

@@ -0,0 +1,94 @@
+.about-history {
+  padding: 80px 0;
+  border-bottom: 1px solid #ccc;
+
+  &-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 30px;
+  }
+  &-item {
+    width: calc(50% - 15px);
+    border-radius: 12px;
+    box-shadow: 0 0 6px 6px #ccc;
+    background-color: #fff;
+
+    img {
+      width: 100%;
+    }
+    &__inner {
+      padding: 16px 20px;
+      height: 120px;
+      font-size: 24px;
+      line-height: 32px;
+    }
+  }
+}
+
+.hisMainBox {
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  z-index: 998;
+  backdrop-filter: blur(20px);
+  padding: 80px 40px 160px;
+  opacity: 0;
+  pointer-events: none;
+  transition: all 0.3s;
+  .hisMainBox1 {
+    width: 100%;
+    height: 100%;
+    background-color: #fff;
+    box-shadow: 0 0 16px 8px #ccc;
+    border-radius: 12px;
+    padding: 40px 28px;
+    .hisMainBox11 {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+      &::-webkit-scrollbar {
+        height: 0;
+        width: 0;
+        color: transparent;
+      }
+      .hisTxt1 {
+        color: #cb0707;
+        line-height: 40px;
+        font-size: 32px;
+        font-weight: 700;
+        margin-bottom: 30px;
+      }
+      .hisTxt2 {
+        text-align: left;
+        font-size: 28px;
+        color: #444444;
+        line-height: 36px;
+        :deep(p) {
+          margin-bottom: 30px;
+          line-height: 48px;
+        }
+        :deep(b) {
+          display: block;
+          font-weight: 700;
+        }
+      }
+    }
+  }
+  .hisBack {
+    position: absolute;
+    width: 80px;
+    height: 80px;
+    bottom: 40px;
+    left: 50%;
+    transform: translateX(-50%);
+    z-index: 99;
+    background-image: url("../../images/his/back.png");
+    background-size: 100% 100%;
+  }
+}
+.hisMainBoxAc {
+  opacity: 1;
+  pointer-events: auto;
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 131 - 0
src/views/About/components/History/index.vue


+ 29 - 0
src/views/About/components/Partners/index.scss

@@ -0,0 +1,29 @@
+.about-partners {
+  padding: 80px 0;
+  border-bottom: 1px solid #ccc;
+
+  ul {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    justify-content: space-between;
+
+    li {
+      width: calc(50% - 10px);
+    }
+    img {
+      display: block;
+      width: 100%;
+    }
+  }
+
+  &__more {
+    margin: 40px auto 20px;
+    width: 234px;
+    height: 74px;
+    background: url("@/assets/images/see.png") no-repeat center / contain;
+    color: #c1aa7b;
+    line-height: 74px;
+    text-align: center;
+  }
+}

+ 41 - 0
src/views/About/components/Partners/index.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="about-partners">
+    <p class="page-title">Partners & Connections</p>
+
+    <ul>
+      <li v-for="(item, idx) in links" :key="idx">
+        <img :src="item.img" />
+      </li>
+    </ul>
+
+    <div
+      class="about-partners__more"
+      @click="$router.push({ name: 'AboutLink' })"
+    >
+      See More
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { linkData } from "../../data";
+
+const list = linkData.reduce<(typeof linkData)[0]["son"]>((prev, cur) => {
+  prev.push(...cur.son);
+  return prev;
+}, []);
+const links = list.filter((i) =>
+  [
+    "Edo-Tokyo Museum",
+    "Russian State Historical Museum",
+    "Royal Ontario Museum",
+    "Seoul Museum of History",
+    "Museums Victoria",
+    "Virginia Museum of Fine Arts",
+  ].includes(i.pop)
+);
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 186 - 0
src/views/About/data.ts

@@ -0,0 +1,186 @@
+import Img1 from "./images/link/1.jpg";
+import Img2 from "./images/link/2.jpg";
+import Img3 from "./images/link/3.jpg";
+import Img4 from "./images/link/4.jpg";
+import Img5 from "./images/link/5.jpg";
+import Img6 from "./images/link/6.jpg";
+import Img7 from "./images/link/7.jpg";
+import Img8 from "./images/link/8.jpg";
+import Img9 from "./images/link/9.jpg";
+import Img10 from "./images/link/10.jpg";
+import Img11 from "./images/link/11.jpg";
+import Img12 from "./images/link/12.jpg";
+import Img13 from "./images/link/13.jpg";
+import Img14 from "./images/link/14.jpg";
+import Img15 from "./images/link/15.jpg";
+import Img16 from "./images/link/16.jpg";
+import Img17 from "./images/link/17.jpg";
+import Img18 from "./images/link/18.jpg";
+import Img19 from "./images/link/19.jpg";
+import Img20 from "./images/link/20.jpg";
+
+export const linkData = [
+  {
+    title: "Australia",
+    son: [
+      {
+        img: Img1,
+        url: "https://museumsvictoria.com.au/",
+        pop: "Museums Victoria",
+      },
+    ],
+  },
+  {
+    title: "Cambodia",
+    bac: true,
+    son: [
+      {
+        img: Img2,
+        url: "https://apsaraauthority.gov.kh/?page=front&lg=en",
+        pop: "The Authority for the protection of the site and the Management of the Region of Angkor (APSARA National Authority or ANA)",
+      },
+    ],
+  },
+  {
+    title: "Canada",
+    son: [
+      {
+        img: Img3,
+        url: "https://www.rom.on.ca/en",
+        pop: "Royal Ontario Museum",
+      },
+      {
+        img: Img4,
+        url: "https://royalbcmuseum.bc.ca/",
+        pop: "The Royal British Columbia Museum",
+      },
+    ],
+  },
+  {
+    title: "Colombia",
+    bac: true,
+    son: [
+      {
+        img: Img5,
+        url: "http://www.museonacional.gov.co/Paginas/default.aspx",
+        pop: "Museo Nacional de Columbia",
+      },
+    ],
+  },
+  {
+    title: "Hungary",
+    son: [
+      { img: Img6, url: "https://mnm.hu/en", pop: "Hungarian National Museum" },
+      {
+        img: Img7,
+        url: "http://www.btm.hu/en/",
+        pop: "Budapesti Történeti Múzeum",
+      },
+    ],
+  },
+  {
+    title: "Japan",
+    bac: true,
+    son: [
+      {
+        img: Img8,
+        url: "http://www.edo-tokyo-museum.or.jp/en/",
+        pop: "Edo-Tokyo Museum",
+      },
+    ],
+  },
+  {
+    title: "Mauritius",
+    son: [
+      {
+        img: Img9,
+        url: "http://www.mauritiusmuseums.mu/English/Pages/default.aspx",
+        pop: "Mauritius Museums Council",
+      },
+    ],
+  },
+  {
+    title: "Poland",
+    bac: true,
+    son: [
+      {
+        img: Img10,
+        url: "https://mnwr.pl/en/",
+        pop: "National Museum in Wroclaw",
+      },
+    ],
+  },
+  {
+    title: "Republic of Korea",
+    son: [
+      {
+        img: Img11,
+        url: "https://museum.seoul.go.kr/eng/index.do",
+        pop: "Seoul Museum of History",
+      },
+    ],
+  },
+  {
+    title: "Russia",
+    bac: true,
+    son: [
+      {
+        img: Img12,
+        url: "https://en.shm.ru/",
+        pop: "Russian State Historical Museum",
+      },
+      { img: Img13, url: "https://mosmuseum.ru/", pop: "Museum of Moscow" },
+    ],
+  },
+  {
+    title: "Thailand",
+    son: [
+      {
+        img: Img14,
+        url: "https://www.mynmv.com/",
+        pop: "National Museum Bangkok",
+      },
+    ],
+  },
+  {
+    title: "Ukraine",
+    bac: true,
+    son: [
+      {
+        img: Img15,
+        url: "http://www.lhm.lviv.ua/eng/index.html",
+        pop: "Lviv Historical Museum",
+      },
+      {
+        img: Img16,
+        url: "https://khanenkomuseum.kiev.ua/en/main",
+        pop: "The Khanenko Museum",
+      },
+      {
+        img: Img17,
+        url: "http://www.kyivhistorymuseum.org/en/museum-affiliates",
+        pop: "Museum of Kyiv History",
+      },
+    ],
+  },
+  {
+    title: "United States of America",
+    son: [
+      {
+        img: Img18,
+        url: "https://fisher.usc.edu/",
+        pop: "University of Southern California Fisher Museum of Art",
+      },
+      {
+        img: Img19,
+        url: "https://www.samuseum.org/",
+        pop: "San Antonio Museum of Art",
+      },
+      {
+        img: Img20,
+        url: "https://www.vmfa.museum/",
+        pop: "Virginia Museum of Fine Arts",
+      },
+    ],
+  },
+];

BIN
src/views/About/images/bannerA.png


BIN
src/views/About/images/bgA.png


BIN
src/views/About/images/bgAD.png


BIN
src/views/About/images/his/1m.png


BIN
src/views/About/images/his/2m.png


BIN
src/views/About/images/his/3m.png


BIN
src/views/About/images/his/4m.png


BIN
src/views/About/images/his/back.png


BIN
src/views/About/images/link/1.jpg


BIN
src/views/About/images/link/10.jpg


BIN
src/views/About/images/link/11.jpg


BIN
src/views/About/images/link/12.jpg


BIN
src/views/About/images/link/13.jpg


BIN
src/views/About/images/link/14.jpg


BIN
src/views/About/images/link/15.jpg


BIN
src/views/About/images/link/16.jpg


BIN
src/views/About/images/link/17.jpg


BIN
src/views/About/images/link/18.jpg


BIN
src/views/About/images/link/19.jpg


BIN
src/views/About/images/link/2.jpg


BIN
src/views/About/images/link/20.jpg


BIN
src/views/About/images/link/3.jpg


BIN
src/views/About/images/link/4.jpg


BIN
src/views/About/images/link/5.jpg


BIN
src/views/About/images/link/6.jpg


BIN
src/views/About/images/link/7.jpg


BIN
src/views/About/images/link/8.jpg


BIN
src/views/About/images/link/9.jpg


BIN
src/views/About/images/ren.jpg


+ 6 - 0
src/views/About/index.scss

@@ -0,0 +1,6 @@
+.about-main {
+  :deep(.van-tabs__content) {
+    padding: 0 30px;
+    background: url("./images/bgA.png") no-repeat center top / cover;
+  }
+}

+ 12 - 0
src/views/About/index.vue

@@ -0,0 +1,12 @@
+<template>
+  <div class="about">
+    <PageBanner title="About" :img="BannerImg" />
+
+    <RouterView />
+  </div>
+</template>
+
+<script lang="ts" setup>
+import PageBanner from "@/components/PageBanner.vue";
+import BannerImg from "./images/bannerA.png";
+</script>

+ 2 - 0
src/views/Collections/List/index.scss

@@ -1,4 +1,6 @@
 .collections-list {
+  background: #f7f6f3;
+
   &-card {
     padding-bottom: 30px;
     background-color: #fff;

+ 110 - 43
src/views/Collections/List/index.vue

@@ -1,59 +1,126 @@
 <template>
   <div class="collections-list">
-    <PageBanner
-      title="Ceramics"
-      img="https://en.capitalmuseum.org.cn/data/Collections/topImg/Ceramics.png"
-    />
-
-    <Waterfall
-      background-color="#f7f6f3"
-      :list="list"
-      :breakpoints="{
-        500: { rowPerView: 2 },
-      }"
-      :gutter="20"
+    <PageBanner title="Ceramics" :img="bgImg" />
+
+    <VanList
+      v-model:loading="loading"
+      :finished="noMore"
+      finished-text="no more"
+      @load="onLoad"
     >
-      <template #item="{ item, url }">
-        <div
-          class="collections-list-card"
-          @click="$router.push({ name: 'CollectionsDetail', query: { id: 1 } })"
-        >
-          <LazyImg :url="url" />
-          <p class="limit-line line-2">{{ item.p }}</p>
-        </div>
-      </template>
-    </Waterfall>
+      <Waterfall
+        background-color="#f7f6f3"
+        :list="list"
+        :breakpoints="{
+          500: { rowPerView: 2 },
+        }"
+        :gutter="20"
+      >
+        <template #item="{ item, url }">
+          <div
+            class="collections-list-card"
+            @click="
+              $router.push({
+                name: 'CollectionsDetail',
+                query: { id: item.id },
+              })
+            "
+          >
+            <LazyImg :url="url" />
+            <p class="limit-line line-2">{{ item.name }}</p>
+          </div>
+        </template>
+      </Waterfall>
+    </VanList>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { computed, onMounted, ref, watch } from "vue";
 import { LazyImg, Waterfall } from "vue-waterfall-plugin-next";
-import type { ViewCard } from "vue-waterfall-plugin-next/dist/types/types/waterfall";
+import { getBaseURL } from "@dage/service";
+import { getCollectionListApi, type CollectionListItem } from "@/api";
 import PageBanner from "@/components/PageBanner.vue";
 import "vue-waterfall-plugin-next/dist/style.css";
+import { useRoute } from "vue-router";
+import { PaginationType, usePagination } from "@/utils/usePagination";
 
-import Img1 from "./1.png";
-import Img2 from "./5.png";
-import Img3 from "./6.png";
+const baseUrl = getBaseURL();
+const route = useRoute();
+// 当前页图片数据是否全部加载完成
+const rendering = ref(false);
+const list = ref<any[]>([]);
+const bgImg = computed(() => decodeURIComponent(route.query.bg as string));
 
-const list = ref<ViewCard[]>([
-  {
-    id: "1",
-    src: Img1,
-    p: "Blue-and-white Snuff Bottle with Mythic Fungus Design",
-  },
-  {
-    id: "2",
-    src: Img2,
-    p: "Blue-and-white Snuff Bottle with Mythic Fungus Design",
-  },
-  {
-    id: "3",
-    src: Img3,
-    p: "Blue-and-white Snuff Bottle with Mythic Fungus Design",
+const {
+  pageNum,
+  list: sourceList,
+  noMore,
+  loading: fetchLoading,
+  getList,
+} = usePagination<CollectionListItem>(
+  (params) => {
+    rendering.value = true;
+
+    return getCollectionListApi({
+      type: route.params.name as string,
+      ...params,
+    });
   },
-]);
+  PaginationType.DEFAULT,
+  20
+);
+
+const loading = computed(() => rendering.value || fetchLoading.value);
+
+const onLoad = () => {
+  // 检查用户是否滚动到页面底部
+  if (!loading.value && !noMore.value) {
+    console.log("===");
+    console.log("Scrolled to bottom");
+    pageNum.value++;
+    getList();
+  }
+};
+
+onMounted(() => {
+  getList();
+});
+
+watch(sourceList, (v) => {
+  if (!v.length) return;
+
+  const promises = v.map(async (i) => {
+    const url = baseUrl + i.thumb;
+    const ratio = await getImgRatio(url);
+
+    list.value.push({
+      ...i,
+      imgHeight: 303 * ratio,
+      src: url,
+    });
+
+    return i;
+  });
+
+  Promise.allSettled(promises).then(() => {
+    rendering.value = false;
+  });
+});
+
+const getImgRatio: (url: string) => Promise<number> = (url: string) => {
+  return new Promise((res) => {
+    const img = new Image();
+    img.src = url;
+    img.onload = () => {
+      const ratio = Math.round((img.height / img.width) * 100) / 100;
+      res(ratio);
+    };
+    img.onerror = () => {
+      res(0);
+    };
+  });
+};
 </script>
 
 <style lang="scss" scoped>

+ 12 - 0
src/views/Collections/index.scss

@@ -19,7 +19,19 @@
       font-size: 48px;
       font-weight: bold;
       color: white;
+      white-space: nowrap;
       transform: translate(-50%, -50%);
+      z-index: 2;
+    }
+    &::after {
+      content: "";
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      background: rgba($color: #000000, $alpha: 0.6);
+      z-index: 1;
     }
   }
 }

+ 54 - 3
src/views/Collections/index.vue

@@ -3,19 +3,70 @@
     <PageBanner title="Collections" :img="BannerImg" />
 
     <ul class="collections-main">
-      <li v-for="item in 5" :key="item" class="collections-card">
+      <li
+        v-for="item in NAV_LIST"
+        :key="item.type"
+        class="collections-card"
+        @click="
+          $router.push({
+            name: 'CollectionsList',
+            params: {
+              name: item.name,
+            },
+            query: {
+              bg: encodeURIComponent(
+                baseUrl + list.find((i) => i.type === item.name)?.thumb
+              ),
+            },
+          })
+        "
+      >
         <VanImage
-          src="https://en.capitalmuseum.org.cn/mobile/img/Bronzes.f986eec7.png"
+          :src="baseUrl + list.find((i) => i.type === item.name)?.thumb"
+          width="100%"
+          :height="100"
+          style="display: block"
         />
-        <p>Bronzes</p>
+        <p>{{ item.name }}</p>
       </li>
     </ul>
   </div>
 </template>
 
 <script lang="ts" setup>
+import { onMounted, ref } from "vue";
 import PageBanner from "@/components/PageBanner.vue";
+import { getCollectionThumbListApi, type CollectionThumbListItem } from "@/api";
 import BannerImg from "./images/bannerC.png";
+import { getBaseURL } from "@dage/service";
+
+const baseUrl = getBaseURL();
+const list = ref<CollectionThumbListItem[]>([]);
+const NAV_LIST = [
+  {
+    name: "Bronzes",
+    type: "Bronzes",
+  },
+  { name: "Ceramics", type: "Ceramics" },
+  { name: "Buddhist Statues", type: "Buddhist" },
+  { name: "Jadewares", type: "Jadewares" },
+  { name: "Calligraphies", type: "Calligraphies" },
+  { name: "Paintings", type: "Paintings" },
+  { name: "Gold & Silverwares", type: "Gold" },
+  { name: "Coins & Banknotes", type: "Coins" },
+  { name: "Brocades & Embroideries", type: "Brocades" },
+  { name: "Cultural Supplies", type: "Cultural" },
+  { name: "Miscellaneous", type: "Miscellaneous" },
+];
+
+onMounted(() => {
+  getThumbList();
+});
+
+const getThumbList = async () => {
+  const data = await getCollectionThumbListApi();
+  list.value = data;
+};
 </script>
 
 <style lang="scss" scoped>

+ 0 - 0
src/views/Employment/index.scss


+ 27 - 1
src/views/Employment/index.vue

@@ -1,3 +1,29 @@
 <template>
-  <div></div>
+  <div class="use">
+    <PageBanner title="Employment" :img="BannerImg" />
+
+    <div class="use-main">
+      <div class="use-top">
+        <div class="page-title">{{ Employment.name }}</div>
+        <p class="use-top__date">2018</p>
+        <p class="use-top__address">Capital Museum</p>
+      </div>
+
+      <div class="use-inner">
+        <h3>Exhibition Overview</h3>
+
+        <div v-html="Employment.rtf" />
+      </div>
+    </div>
+  </div>
 </template>
+
+<script setup lang="ts">
+import { Employment } from "@/data";
+import PageBanner from "@/components/PageBanner.vue";
+import BannerImg from "../Use/images/bannerUse.png";
+</script>
+
+<style lang="scss" scoped>
+@import "../Use/index.scss";
+</style>

+ 40 - 0
src/views/Events/Detail/index.scss

@@ -0,0 +1,40 @@
+.events-detail {
+  &-main {
+    padding: 40px 30px 80px;
+    background: url("../images/bgEI.png") repeat top / cover;
+  }
+  &-top {
+    padding: 0 30px 50px;
+    border-bottom: 1px solid #ccc;
+
+    .page-title {
+      margin-bottom: 10px;
+      background-position: left 8px;
+    }
+    p {
+      padding-left: 60px;
+      line-height: 60px;
+      color: #666;
+    }
+    &__date {
+      background: url("@/assets/images/bg_5.png") left 10px no-repeat;
+    }
+  }
+  &-directory {
+    padding: 40px 30px;
+    border-bottom: 1px solid #ccc;
+
+    p {
+      position: relative;
+      padding-left: 30px;
+      color: #6a6a6a;
+      line-height: 48px;
+
+      span {
+        position: absolute;
+        left: 0;
+        top: 0;
+      }
+    }
+  }
+}

+ 32 - 0
src/views/Events/Detail/index.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="events-detail">
+    <PageBanner title="Events" :img="BannerImg" />
+
+    <div class="events-detail-main">
+      <div class="events-detail-top">
+        <div class="page-title">International Museum Day 2021</div>
+        <p class="events-detail-top__date">May 18, 2021</p>
+      </div>
+
+      <div class="events-detail-directory">
+        <p>
+          <span>■</span> Forum "The Future of Museums: New Journey and New
+          Actions"
+        </p>
+        <p>
+          <span>■</span> Museum Youth Forum "The Future of Museums: The Mission
+          and Responsibility of Young Museum Professionals"
+        </p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import PageBanner from "@/components/PageBanner.vue";
+import BannerImg from "../images/banner.png";
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

BIN
src/views/Events/images/banner.png


BIN
src/views/Events/images/bgEI.png


+ 41 - 0
src/views/Events/index.scss

@@ -0,0 +1,41 @@
+.events {
+  &-list {
+    padding: 44px 34px 80px;
+    background-color: #faf9f6;
+  }
+  &-item {
+    margin-bottom: 30px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    overflow: hidden;
+    height: 422px;
+    color: white;
+    background: red;
+    border-radius: 16px;
+
+    h3 {
+      position: relative;
+      margin-bottom: 30px;
+      padding-bottom: 16px;
+      font-weight: bold;
+      font-size: 32px;
+
+      &::after {
+        content: "";
+        position: absolute;
+        display: inline-block;
+        width: 60%;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        height: 4px;
+        background-color: #fff;
+      }
+    }
+    i {
+      font-style: italic;
+    }
+  }
+}

+ 22 - 1
src/views/Events/index.vue

@@ -1,3 +1,24 @@
 <template>
-  <div></div>
+  <div class="events">
+    <PageBanner title="Events" :img="BannerImg" />
+
+    <div
+      class="events-list"
+      @click="$router.push({ name: 'EventsDetail', params: { id: 2 } })"
+    >
+      <div class="events-item">
+        <h3>International Museum Day 2021</h3>
+        <i>Date:May 18, 2021</i>
+      </div>
+    </div>
+  </div>
 </template>
+
+<script setup lang="ts">
+import PageBanner from "@/components/PageBanner.vue";
+import BannerImg from "./images/banner.png";
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 56 - 11
src/views/Exhibitions/Current/index.vue

@@ -1,25 +1,70 @@
 <template>
   <div class="current">
     <div
+      v-for="item in list"
+      :key="item.id"
       class="current-item"
-      @click="$router.push({ name: 'ExDetail', query: { id: 10 } })"
+      @click="$router.push({ name: 'ExDetail', query: { id: item.id } })"
     >
-      <VanImage
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/2.jpg"
-      />
-      <h3>Splendid Central Axis of Beijing</h3>
+      <VanImage :src="baseUrl + item.thumb" style="width: 100%" />
+      <h3>{{ item.name }}</h3>
       <p>
-        Starting from the planning and construction of the Central Axis of the
-        Capital Dadu of the Yuan Dynasty and with the ongoing inheritance and
-        carrying forward of past achievements over the later dynasties, the
-        Central Axis of Beijing has finally been made such a magnificent
-        presence as it stands now, with originality and creativeness to be found
-        everywhere along the Axis.
+        {{ item.digest }}
       </p>
     </div>
+
+    <van-pagination
+      v-if="total"
+      v-model="pageNum"
+      :page-count="total"
+      style="margin-bottom: 20px"
+      @change="handlePage"
+    >
+      <template #prev-text>
+        <van-icon name="arrow-left" />
+      </template>
+      <template #next-text>
+        <van-icon name="arrow" />
+      </template>
+    </van-pagination>
+
+    <VanEmpty v-if="noData" image="search" description="No data" />
   </div>
 </template>
 
+<script setup lang="ts">
+import {
+  getExhibitionListApi,
+  type ExhibitionsListItem,
+  type GetExhibitionListParams,
+} from "@/api";
+import { usePagination } from "@/utils/usePagination";
+import { getBaseURL } from "@dage/service";
+import { onMounted } from "vue";
+
+const baseUrl = getBaseURL();
+const { pageNum, total, list, noData, getList } =
+  usePagination<ExhibitionsListItem>((params) => {
+    const _params: GetExhibitionListParams = {
+      isCurrent: 1,
+      addrType: "inland",
+      ...params,
+    };
+
+    return getExhibitionListApi(_params);
+  });
+
+onMounted(() => {
+  getList();
+});
+
+// 切换页码
+const handlePage = (val: number) => {
+  pageNum.value = val;
+  getList();
+};
+</script>
+
 <style lang="scss" scoped>
 .current {
   &-item {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 80 - 40
src/views/Exhibitions/Detail/index.vue


+ 1 - 1
src/views/Exhibitions/Galleries/index.scss

@@ -21,7 +21,7 @@
     gap: 40px;
     padding: 60px 40px;
 
-    img {
+    .van-image {
       width: 100%;
       border-radius: 10px;
     }

+ 27 - 12
src/views/Exhibitions/Galleries/index.vue

@@ -3,17 +3,16 @@
     <PageBanner title="Exhibition Galleries" :img="BannerImg" />
 
     <div class="ex-objects-main">
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/galleries2/galleries1.jpg"
-        alt=""
-      />
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/galleries2/galleries1.jpg"
-        alt=""
-      />
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/galleries2/galleries1.jpg"
-        alt=""
+      <VanImage
+        v-for="(img, idx) in previewList"
+        :key="img"
+        :src="img"
+        @click="
+          () => {
+            showPreview = true;
+            curPreviewIdx = idx;
+          }
+        "
       />
     </div>
   </div>
@@ -26,13 +25,29 @@
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { ref, onMounted } from "vue";
+import { useRoute } from "vue-router";
+import { getExhibitionDetailApi, type ExhibitionDetail } from "@/api";
 import PageBanner from "@/components/PageBanner.vue";
+import { getBaseURL } from "@dage/service";
 import BannerImg from "../Objects/images/banner-min.jpg";
 
+const baseUrl = getBaseURL();
+const route = useRoute();
 const showPreview = ref(false);
 const curPreviewIdx = ref(0);
 const previewList = ref<string[]>([]);
+const detail = ref<ExhibitionDetail | null>(null);
+
+onMounted(() => {
+  getExhibitionDetail();
+});
+
+const getExhibitionDetail = async () => {
+  const data = await getExhibitionDetailApi(route.query.id as string);
+  detail.value = data;
+  previewList.value = data.exhibitionFile.map((i) => `${baseUrl}${i.filePath}`);
+};
 </script>
 
 <style lang="scss" scoped>

+ 1 - 1
src/views/Exhibitions/Objects/index.scss

@@ -21,7 +21,7 @@
     flex-wrap: wrap;
     padding: 40px 20px;
 
-    img {
+    .van-image {
       margin: 20px;
       width: calc(50% - 40px);
       border-radius: 10px;

+ 27 - 12
src/views/Exhibitions/Objects/index.vue

@@ -3,17 +3,16 @@
     <PageBanner title="Exhibition Objects" :img="BannerImg" />
 
     <div class="ex-objects-main">
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/objects2/objects2.jpg"
-        alt=""
-      />
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/objects2/objects2.jpg"
-        alt=""
-      />
-      <img
-        src="https://en.capitalmuseum.org.cn/data/Exhibitions/Current/objects2/objects2.jpg"
-        alt=""
+      <VanImage
+        v-for="(img, idx) in previewList"
+        :key="img"
+        :src="img"
+        @click="
+          () => {
+            showPreview = true;
+            curPreviewIdx = idx;
+          }
+        "
       />
     </div>
   </div>
@@ -26,13 +25,29 @@
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { ref, onMounted } from "vue";
+import { useRoute } from "vue-router";
+import { getExhibitionDetailApi, type ExhibitionDetail } from "@/api";
 import PageBanner from "@/components/PageBanner.vue";
 import BannerImg from "./images/banner-min.jpg";
+import { getBaseURL } from "@dage/service";
 
+const baseUrl = getBaseURL();
+const route = useRoute();
 const showPreview = ref(false);
 const curPreviewIdx = ref(0);
 const previewList = ref<string[]>([]);
+const detail = ref<ExhibitionDetail | null>(null);
+
+onMounted(() => {
+  getExhibitionDetail();
+});
+
+const getExhibitionDetail = async () => {
+  const data = await getExhibitionDetailApi(route.query.id as string);
+  detail.value = data;
+  previewList.value = data.exhibitsFile.map((i) => `${baseUrl}${i.filePath}`);
+};
 </script>
 
 <style lang="scss" scoped>

+ 47 - 3
src/views/Exhibitions/Overseas/index.vue

@@ -1,15 +1,59 @@
 <template>
   <div class="permanent">
-    <div class="permanent-main">
-      <div v-for="key in 10" :key="key" class="permanent-card">
-        <ImgCard />
+    <div v-if="list.length" class="permanent-main">
+      <div v-for="item in list" :key="item.id" class="permanent-card">
+        <ImgCard :item="item" />
       </div>
     </div>
+
+    <VanEmpty v-if="noData" image="search" description="No data" />
+
+    <van-pagination
+      v-if="pages > 1"
+      v-model="pageNum"
+      :page-count="total"
+      style="padding-bottom: 20px"
+      @change="handlePage"
+    >
+      <template #prev-text>
+        <van-icon name="arrow-left" />
+      </template>
+      <template #next-text>
+        <van-icon name="arrow" />
+      </template>
+    </van-pagination>
   </div>
 </template>
 
 <script lang="ts" setup>
+import {
+  getExhibitionListApi,
+  type ExhibitionsListItem,
+  type GetExhibitionListParams,
+} from "@/api";
 import ImgCard from "@/components/ImgCard.vue";
+import { usePagination } from "@/utils/usePagination";
+import { onMounted } from "vue";
+
+const { pageNum, total, pages, list, noData, getList } =
+  usePagination<ExhibitionsListItem>((params) => {
+    const _params: GetExhibitionListParams = {
+      addrType: "foreign",
+      ...params,
+    };
+
+    return getExhibitionListApi(_params);
+  });
+
+onMounted(() => {
+  getList();
+});
+
+// 切换页码
+const handlePage = (val: number) => {
+  pageNum.value = val;
+  getList();
+};
 </script>
 
 <style lang="scss" scoped>

+ 48 - 3
src/views/Exhibitions/Past/index.vue

@@ -1,15 +1,60 @@
 <template>
   <div class="permanent">
-    <div class="permanent-main">
-      <div v-for="key in 10" :key="key" class="permanent-card">
-        <ImgCard />
+    <div v-if="list.length" class="permanent-main">
+      <div v-for="item in list" :key="item.id" class="permanent-card">
+        <ImgCard :item="item" />
       </div>
     </div>
+
+    <VanEmpty v-if="noData" image="search" description="No data" />
+
+    <van-pagination
+      v-if="pages > 1"
+      v-model="pageNum"
+      :page-count="total"
+      style="padding-bottom: 20px"
+      @change="handlePage"
+    >
+      <template #prev-text>
+        <van-icon name="arrow-left" />
+      </template>
+      <template #next-text>
+        <van-icon name="arrow" />
+      </template>
+    </van-pagination>
   </div>
 </template>
 
 <script lang="ts" setup>
+import {
+  getExhibitionListApi,
+  type ExhibitionsListItem,
+  type GetExhibitionListParams,
+} from "@/api";
 import ImgCard from "@/components/ImgCard.vue";
+import { usePagination } from "@/utils/usePagination";
+import { onMounted } from "vue";
+
+const { pageNum, total, pages, list, noData, getList } =
+  usePagination<ExhibitionsListItem>((params) => {
+    const _params: GetExhibitionListParams = {
+      addrType: "inland",
+      isCurrent: 0,
+      ...params,
+    };
+
+    return getExhibitionListApi(_params);
+  });
+
+onMounted(() => {
+  getList();
+});
+
+// 切换页码
+const handlePage = (val: number) => {
+  pageNum.value = val;
+  getList();
+};
 </script>
 
 <style lang="scss" scoped>

+ 1 - 0
src/views/Exhibitions/Permanent/index.scss

@@ -6,6 +6,7 @@
     padding: 20px 40px 40px;
     display: flex;
     flex-wrap: wrap;
+    align-items: stretch;
   }
   &-card {
     padding: 15px;

+ 47 - 3
src/views/Exhibitions/Permanent/index.vue

@@ -1,15 +1,59 @@
 <template>
   <div class="permanent">
-    <div class="permanent-main">
-      <div v-for="key in 10" :key="key" class="permanent-card">
-        <ImgCard />
+    <div v-if="list.length" class="permanent-main">
+      <div v-for="item in list" :key="item.id" class="permanent-card">
+        <ImgCard :item="item" />
       </div>
     </div>
+
+    <VanEmpty v-if="noData" image="search" description="No data" />
+
+    <van-pagination
+      v-if="pages > 1"
+      v-model="pageNum"
+      :page-count="total"
+      style="padding-bottom: 20px"
+      @change="handlePage"
+    >
+      <template #prev-text>
+        <van-icon name="arrow-left" />
+      </template>
+      <template #next-text>
+        <van-icon name="arrow" />
+      </template>
+    </van-pagination>
   </div>
 </template>
 
 <script lang="ts" setup>
+import {
+  getExhibitionListApi,
+  type ExhibitionsListItem,
+  type GetExhibitionListParams,
+} from "@/api";
 import ImgCard from "@/components/ImgCard.vue";
+import { usePagination } from "@/utils/usePagination";
+import { onMounted } from "vue";
+
+const { pageNum, total, pages, list, noData, getList } =
+  usePagination<ExhibitionsListItem>((params) => {
+    const _params: GetExhibitionListParams = {
+      type: "long",
+      ...params,
+    };
+
+    return getExhibitionListApi(_params);
+  });
+
+onMounted(() => {
+  getList();
+});
+
+// 切换页码
+const handlePage = (val: number) => {
+  pageNum.value = val;
+  getList();
+};
 </script>
 
 <style lang="scss" scoped>

+ 33 - 14
src/views/Exhibitions/index.vue

@@ -1,24 +1,24 @@
 <template>
   <div class="exhibitions">
-    <PageBanner title="Exhibitions" :img="BannerImg" />
+    <PageBanner title="Exhibitions" :img="bannerUrl || BannerImg" />
 
-    <PageNav v-model="activeTab" @change="handleNav">
-      <van-tab title="Current"></van-tab>
-      <van-tab title="Permanent"></van-tab>
-      <van-tab title="Past"></van-tab>
-      <van-tab title="Overseas"></van-tab>
+    <PageNav v-model="activeTab" @click-tab="handleNav">
+      <van-tab title="Current"><RouterView /></van-tab>
+      <van-tab title="Permanent"><RouterView /></van-tab>
+      <van-tab title="Past"><RouterView /></van-tab>
+      <van-tab title="Overseas"><RouterView /></van-tab>
     </PageNav>
-
-    <RouterView />
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { computed, ref, watch } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { getBaseURL } from "@dage/service";
+import { useBaseStore } from "@/stores/base";
 import PageBanner from "@/components/PageBanner.vue";
 import PageNav from "@/components/PageNav.vue";
 import BannerImg from "./images/bannerE.png";
-import { useRoute, useRouter } from "vue-router";
 
 const ROUTE_MAP: Record<number, string> = {
   0: "ExhibitionsCurrent",
@@ -29,11 +29,30 @@ const ROUTE_MAP: Record<number, string> = {
 
 const route = useRoute();
 const router = useRouter();
-const activeTab = ref(
-  Object.values(ROUTE_MAP).findIndex((key) => key === route.name) || 0
+const activeTab = ref(0);
+
+const baseUrl = getBaseURL();
+const baseStore = useBaseStore();
+const bannerUrl = computed(() => {
+  return (
+    baseUrl +
+    baseStore.bannerList.find((i) => i.name === "Exhibition")?.thumbApp
+  );
+});
+
+watch(
+  route,
+  () => {
+    activeTab.value = Object.values(ROUTE_MAP).findIndex(
+      (key) => key === route.name
+    );
+  },
+  {
+    immediate: true,
+  }
 );
 
-const handleNav = (v: number) => {
-  router.push({ name: ROUTE_MAP[v] });
+const handleNav = (v: any) => {
+  router.push({ name: ROUTE_MAP[v.name] });
 };
 </script>

+ 23 - 9
src/views/Home/index.vue

@@ -1,16 +1,15 @@
 <template>
   <div class="home">
     <VanSwipe class="home-banner" :autoplay="3000" indicator-color="white">
-      <VanSwipeItem>
-        <img
-          src="https://en.capitalmuseum.org.cn/mobile/img/banner7.42692dcb.png"
+      <van-swipe-item v-for="item in list" :key="item.id">
+        <van-image
+          width="100%"
+          height="100%"
+          :src="baseUrl + item.thumbApp"
+          fit="cover"
+          @click="item.link && $router.push(item.link)"
         />
-      </VanSwipeItem>
-      <VanSwipeItem>
-        <img
-          src="https://en.capitalmuseum.org.cn/mobile/img/banner7.42692dcb.png"
-        />
-      </VanSwipeItem>
+      </van-swipe-item>
     </VanSwipe>
 
     <div class="home-main">
@@ -22,8 +21,23 @@
 </template>
 
 <script setup lang="ts">
+import { onMounted, ref } from "vue";
+import { getHomeListApi } from "@/api";
+import { getBaseURL } from "@dage/service";
 import VisitInfo from "./components/VisitInfo.vue";
 import Connections from "./components/Connections.vue";
+
+const list = ref<any[]>([]);
+const baseUrl = getBaseURL();
+
+onMounted(() => {
+  getList();
+});
+
+const getList = async () => {
+  const data = await getHomeListApi();
+  list.value = data;
+};
 </script>
 
 <style lang="scss" scoped>

+ 0 - 0
src/views/JoinSupport/Give/index.scss


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor