|
@@ -0,0 +1,449 @@
|
|
|
+<template>
|
|
|
+ <div class="exhibition">
|
|
|
+ <div class="exhibition-container">
|
|
|
+ <div class="exhibition-header">
|
|
|
+ <h3>家园——中国少数民族传统体育文化展</h3>
|
|
|
+
|
|
|
+ <div class="exhibition-header__search">
|
|
|
+ <ElSelectV2
|
|
|
+ v-model="selected"
|
|
|
+ :options="filteredOptions"
|
|
|
+ :remote-method="handleFilter"
|
|
|
+ filterable
|
|
|
+ remote
|
|
|
+ placeholder="请输入搜索内容"
|
|
|
+ no-data-text="没有数据"
|
|
|
+ style="width: 100%"
|
|
|
+ @change="handleSelect"
|
|
|
+ >
|
|
|
+ <template #default="{ item }">
|
|
|
+ <ElTooltip :content="item.label" placement="left">
|
|
|
+ {{ item.label }}
|
|
|
+
|
|
|
+ <template #content>
|
|
|
+ <p style="max-width: 300px">{{ item.label }}</p>
|
|
|
+ </template>
|
|
|
+ </ElTooltip>
|
|
|
+ </template>
|
|
|
+ </ElSelectV2>
|
|
|
+ <div class="exhibition-header__search__icon" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="exhibition-main">
|
|
|
+ <div class="exhibition-menu">
|
|
|
+ <ElScrollbar class="exhibition-menu-scrollbar">
|
|
|
+ <p
|
|
|
+ v-for="(item, index) in data"
|
|
|
+ :key="index"
|
|
|
+ :class="['limit-line', { active: activeMenu === index }]"
|
|
|
+ @click="
|
|
|
+ () => {
|
|
|
+ activeSecondMenu = 0;
|
|
|
+ activeThirdMenu = 0;
|
|
|
+ activeMenu = index;
|
|
|
+ }
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ item.title }}
|
|
|
+ </p>
|
|
|
+ </ElScrollbar>
|
|
|
+
|
|
|
+ <div class="exhibition-menu-footer">
|
|
|
+ <img
|
|
|
+ draggable="false"
|
|
|
+ src="@/assets/images/icon-home-1-min.png"
|
|
|
+ @click="$router.push({ name: 'home' })"
|
|
|
+ />
|
|
|
+ <img
|
|
|
+ draggable="false"
|
|
|
+ src="@/assets/images/icon-quanjing-min.png"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <ElScrollbar
|
|
|
+ class="exhibition-inner"
|
|
|
+ :style="{ width: list.length ? '1000px' : '1340px' }"
|
|
|
+ >
|
|
|
+ <div class="exhibition-cover">
|
|
|
+ <ElImage src="" fit="cover" />
|
|
|
+
|
|
|
+ <Swiper
|
|
|
+ class="exhibition-cover-swiper"
|
|
|
+ free-mode
|
|
|
+ :modules="[FreeMode]"
|
|
|
+ slides-per-view="auto"
|
|
|
+ >
|
|
|
+ <SwiperSlide v-for="item in 20" :key="item">
|
|
|
+ <ElImage src="" fit="cover" />
|
|
|
+ </SwiperSlide>
|
|
|
+ </Swiper>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="exhibition-inner-content" v-html="curDetail.content" />
|
|
|
+ </ElScrollbar>
|
|
|
+
|
|
|
+ <div v-if="list.length" class="exhibition-right">
|
|
|
+ <ElScrollbar height="100%" style="padding: 0 5px">
|
|
|
+ <ElCollapse v-model="collapse">
|
|
|
+ <ElCollapseItem
|
|
|
+ v-for="(item, index) in list"
|
|
|
+ :key="index"
|
|
|
+ :title="item.title"
|
|
|
+ :name="index"
|
|
|
+ :class="{ active: index === activeSecondMenu }"
|
|
|
+ >
|
|
|
+ <ElTooltip
|
|
|
+ v-for="(subItem, subIndex) in item.children"
|
|
|
+ :key="subIndex"
|
|
|
+ :content="subItem.description"
|
|
|
+ placement="left"
|
|
|
+ effect="light"
|
|
|
+ >
|
|
|
+ <p
|
|
|
+ :class="[
|
|
|
+ 'limit-line',
|
|
|
+ { active: subIndex === activeThirdMenu },
|
|
|
+ ]"
|
|
|
+ @click="
|
|
|
+ () => {
|
|
|
+ activeSecondMenu = index;
|
|
|
+ activeThirdMenu = subIndex;
|
|
|
+ }
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ subItem.title }}
|
|
|
+ </p>
|
|
|
+ </ElTooltip>
|
|
|
+ </ElCollapseItem>
|
|
|
+ </ElCollapse>
|
|
|
+ </ElScrollbar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, watch } from "vue";
|
|
|
+import { data } from "@syjy/base";
|
|
|
+import { FreeMode } from "swiper/modules";
|
|
|
+import { Swiper, SwiperSlide } from "swiper/vue";
|
|
|
+import "swiper/css";
|
|
|
+import { ElTooltip } from "element-plus";
|
|
|
+
|
|
|
+const activeMenu = ref(0);
|
|
|
+const activeSecondMenu = ref(0);
|
|
|
+const activeThirdMenu = ref(0);
|
|
|
+const selected = ref(null);
|
|
|
+const filteredOptions = ref([]);
|
|
|
+const collapse = ref([]);
|
|
|
+
|
|
|
+const list = computed(() => {
|
|
|
+ if (!data[activeMenu.value].children) return [];
|
|
|
+ return data[activeMenu.value].children;
|
|
|
+});
|
|
|
+const curDetail = computed(() => {
|
|
|
+ const firstItem = data[activeMenu.value];
|
|
|
+
|
|
|
+ if (!firstItem.children) return firstItem;
|
|
|
+ else
|
|
|
+ return firstItem.children[activeSecondMenu.value].children[
|
|
|
+ activeThirdMenu.value
|
|
|
+ ];
|
|
|
+});
|
|
|
+
|
|
|
+watch(list, (v) => {
|
|
|
+ const stack = [];
|
|
|
+ for (let i = 0; i < v.length; i++) {
|
|
|
+ stack.push(i);
|
|
|
+ }
|
|
|
+ collapse.value = stack;
|
|
|
+});
|
|
|
+
|
|
|
+const extractText = (html) => {
|
|
|
+ // 提取纯文本,去掉HTML标签
|
|
|
+ const tmpDiv = document.createElement("div");
|
|
|
+ tmpDiv.innerHTML = html;
|
|
|
+ return tmpDiv.innerText.trim();
|
|
|
+};
|
|
|
+
|
|
|
+const findKeywordContext = (text, keyword, radius = 20) => {
|
|
|
+ const index = text.indexOf(keyword);
|
|
|
+ if (index === -1) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const start = Math.max(0, index - radius);
|
|
|
+ const end = Math.min(text.length, index + keyword.length + radius);
|
|
|
+
|
|
|
+ return text.substring(start, end);
|
|
|
+};
|
|
|
+
|
|
|
+const flattenData = (query, list = data, parentTitles = [], path = []) => {
|
|
|
+ const result = [];
|
|
|
+ list.forEach((item, index) => {
|
|
|
+ const titles = [...parentTitles, item.title];
|
|
|
+ const currentPath = [...path, index];
|
|
|
+
|
|
|
+ if (item.content) {
|
|
|
+ const contentText = extractText(item.content).replace(/[\n\s]/g, "");
|
|
|
+
|
|
|
+ if (contentText.indexOf(query) > -1) {
|
|
|
+ result.push({
|
|
|
+ value: currentPath.join(","),
|
|
|
+ label: `${titles.join(" | ")} | ${findKeywordContext(
|
|
|
+ contentText,
|
|
|
+ query
|
|
|
+ )}`,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (item.children) {
|
|
|
+ result.push(...flattenData(query, item.children, titles, currentPath));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+};
|
|
|
+
|
|
|
+const handleFilter = (query) => {
|
|
|
+ if (!query) {
|
|
|
+ filteredOptions.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ filteredOptions.value = flattenData(query);
|
|
|
+};
|
|
|
+
|
|
|
+const handleSelect = (v) => {
|
|
|
+ const res = v.split(",").map((i) => Number(i));
|
|
|
+ activeMenu.value = res[0];
|
|
|
+ activeSecondMenu.value = res[1] ?? 0;
|
|
|
+ activeThirdMenu.value = res[2] ?? 0;
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.exhibition {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ &-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ &-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin: 40px 0 25px;
|
|
|
+
|
|
|
+ h3 {
|
|
|
+ color: white;
|
|
|
+ font-family: "Source Han Serif CN-Bold";
|
|
|
+ font-size: 28px;
|
|
|
+ }
|
|
|
+ &__search {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding-left: 14px;
|
|
|
+ width: 320px;
|
|
|
+ height: 45px;
|
|
|
+ border-radius: 50px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: rgba(255, 255, 255, 0.9);
|
|
|
+ border: 2px solid #f5dd8c;
|
|
|
+
|
|
|
+ .el-select {
|
|
|
+ --el-fill-color-blank: none;
|
|
|
+ --el-select-border-color-hover: none;
|
|
|
+ --el-select-input-color: none;
|
|
|
+ --el-select-input-focus-border-color: none;
|
|
|
+ --el-select-multiple-input-color: none;
|
|
|
+ --el-select-font-size: 16px;
|
|
|
+ --el-select-input-font-size: 16px;
|
|
|
+
|
|
|
+ ::v-deep(.el-select__wrapper) {
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &__icon {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 56px;
|
|
|
+ height: 100%;
|
|
|
+ background: #9d222d;
|
|
|
+ border-left: 2px solid #f5dd8c;
|
|
|
+ box-sizing: border-box;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: "";
|
|
|
+ width: 26px;
|
|
|
+ height: 24px;
|
|
|
+ background: url("@/assets/images/search-min.png") no-repeat center /
|
|
|
+ contain;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-main {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 20px;
|
|
|
+ height: 760px;
|
|
|
+ }
|
|
|
+ &-menu {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 50px 4px 0;
|
|
|
+ width: 240px;
|
|
|
+ height: inherit;
|
|
|
+ background: rgba(255, 255, 255, 0.9);
|
|
|
+ box-shadow: 0px 4px 10px 0px rgba(30, 0, 0, 0.3);
|
|
|
+ border-radius: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &-footer {
|
|
|
+ margin: 24px 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 16px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-scrollbar {
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ p {
|
|
|
+ position: relative;
|
|
|
+ padding: 0 30px 0 60px;
|
|
|
+ height: 60px;
|
|
|
+ line-height: 60px;
|
|
|
+ font-size: 18px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #f5dd8c;
|
|
|
+ background: #9d222d;
|
|
|
+ }
|
|
|
+ &.active {
|
|
|
+ color: #f5dd8c;
|
|
|
+ background: #9d222d;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 20px;
|
|
|
+ width: 28px;
|
|
|
+ height: 30px;
|
|
|
+ background: url("@/assets/images/icon-flower-min.png") no-repeat
|
|
|
+ center / contain;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-inner {
|
|
|
+ flex: 1;
|
|
|
+ width: 1000px;
|
|
|
+ height: inherit;
|
|
|
+
|
|
|
+ &-content {
|
|
|
+ margin-top: 12px;
|
|
|
+ padding: 0 35px;
|
|
|
+ font-size: 16px;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-cover {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 650px;
|
|
|
+ box-shadow: 0px 4px 10px 0px rgba(30, 0, 0, 0.3);
|
|
|
+ border-radius: 10px;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .el-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ &-swiper {
|
|
|
+ position: absolute;
|
|
|
+ right: 20px;
|
|
|
+ bottom: 15px;
|
|
|
+ max-width: 50%;
|
|
|
+
|
|
|
+ .swiper-slide {
|
|
|
+ position: relative;
|
|
|
+ margin-left: 10px;
|
|
|
+ width: 100px;
|
|
|
+ height: 60px;
|
|
|
+ border-radius: 5px;
|
|
|
+ overflow: hidden;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.4);
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-right {
|
|
|
+ padding: 70px 0;
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 320px;
|
|
|
+ height: inherit;
|
|
|
+ background: rgba(255, 255, 255, 0.9);
|
|
|
+ box-shadow: 0px 4px 10px 0px rgba(30, 0, 0, 0.3);
|
|
|
+ border-radius: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ .el-collapse {
|
|
|
+ --el-collapse-header-bg-color: none;
|
|
|
+ --el-collapse-content-bg-color: none;
|
|
|
+ --el-collapse-header-height: 40px;
|
|
|
+ --el-collapse-content-font-size: 14px;
|
|
|
+ --el-collapse-header-font-size: 16px;
|
|
|
+ --el-collapse-header-text-color: #333333;
|
|
|
+ --el-collapse-content-text-color: #999999;
|
|
|
+
|
|
|
+ > .active {
|
|
|
+ ::v-deep(.el-collapse-item__header) {
|
|
|
+ color: #f5dd8c;
|
|
|
+ background: #9d222d;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ::v-deep(.el-collapse-item__header) {
|
|
|
+ padding-left: 24px;
|
|
|
+ }
|
|
|
+ ::v-deep(.el-collapse-item__content p) {
|
|
|
+ display: block;
|
|
|
+ margin-left: 90px;
|
|
|
+ line-height: 34px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ color: #9d222d;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|