Explorar el Código

📦 对接传播交流理论研究文旅融合

imengyu hace 5 días
padre
commit
e4632d1b8b

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

@@ -1,6 +1,7 @@
 @use "./fonts.scss";
 @use "./fix.scss";
 @use "./components.scss";
+@use "./news.scss";
 @use "./colors.scss" as *;
 
 body,
@@ -159,6 +160,10 @@ $small-banner-height: 445px;
   &.light {
     color: $text-color-light;
   }
+  &.small-h {
+    padding-top: 40px;
+    padding-bottom: 40px;
+  }
 
   h2 {
     display: flex;
@@ -225,11 +230,19 @@ $small-banner-height: 445px;
 @media (max-width: 1280px) {
   .main-section {
     padding: 100px 80px;
+    &.small-h {
+      padding-top: 40px;
+      padding-bottom: 40px;
+    }
   }
 }
 @media (max-width: 1024px) {
   .main-section {
     padding: 80px 60px;
+    &.small-h {
+      padding-top: 30px;
+      padding-bottom: 30px;
+    }
   }
   .main-header-tab {
     .list {
@@ -243,11 +256,19 @@ $small-banner-height: 445px;
 @media (max-width: 768px) {
   .main-section {
     padding: 80px 40px;
+    &.small-h {
+      padding-top: 20px;
+      padding-bottom: 20px;
+    }
   }
 }
 @media (max-width: 425px) {
   .main-section {
     padding: 80px 20px;
+    &.small-h {
+      padding-top: 20px;
+      padding-bottom: 20px;
+    }
   }
 }
 @media (max-width: 500px) {

+ 66 - 0
src/assets/scss/news.scss

@@ -0,0 +1,66 @@
+
+@use "sass:list";
+@use '@/assets/scss/colors.scss' as *;
+
+.news-list {
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+
+  .item {
+    display: flex;
+    flex-direction: row;
+    padding: 25px;
+    border-radius: 6px;
+    background-color: $box-color;
+
+    &:hover { 
+      background-color: $box-hover-color;
+    }
+    &:active {
+      transform: scale(0.95);
+    }
+
+    img {
+      width: 320px;
+      height: 180px;
+      margin-right: 25px;
+    }
+
+   
+  }
+}
+
+
+@media (max-width: 768px) {
+  .news-list {
+    .item {
+      display: flex;
+      flex-direction: row;
+      padding: 25px;
+      border-radius: 6px;
+      background-color: $box-color;
+
+      img {
+        width: 200px;
+        height: 140px;
+        margin-right: 25px;
+      }
+    }
+  }
+}
+@media (max-width: 540px) {
+  .news-list {
+    .item {
+      flex-direction: column;
+
+      img {
+        width: 100%;
+        height: 180px;
+        
+        margin-right: 0;
+        margin-bottom: 16px;
+      }
+    }
+  }
+}

+ 6 - 5
src/components/NavBar.vue

@@ -31,6 +31,7 @@
   <!-- 导航栏 -->
   <nav 
     :class="[
+      'main',
       headerBlur ? 'need-blur' : '',
       scrollValue > 200 ? 'nav-scrolled' : 'nav-not-scrolled',
     ]"
@@ -99,7 +100,7 @@ $nav-height: 70px;
   height: $nav-height; 
   background-color: $primary-color;
 }
-nav {
+nav.main {
   position: fixed;
   display: flex;
   justify-content: space-around;
@@ -230,7 +231,7 @@ nav {
 }
 
 @media (max-width: 1260px) {
-  nav {
+  nav.main {
     
     .group {
       gap: 0.5rem; 
@@ -248,7 +249,7 @@ nav {
  
 }
 @media (max-width: 768px) {
-  nav {
+  nav.main {
     justify-content: space-between;
     padding: 0 30px;
 
@@ -264,7 +265,7 @@ nav {
   } 
 }
 @media (max-width: 550px) {
-  nav {
+  nav.main {
     .headerlogos {
       img {
         width: 35px;
@@ -294,7 +295,7 @@ nav {
   }
 }
 @media (max-width: 388px) {
-  nav {
+  nav.main {
     .headerlogos > div {
       display: none;
     }

+ 211 - 0
src/components/content/CommonListPage.vue

@@ -0,0 +1,211 @@
+<template>
+  <!-- 资讯详情页 -->
+  <div class="main-background">
+    <div class="nav-placeholder"></div>
+    <!-- 新闻 -->
+    <section class="main-section main-background main-background-type0 small-h">
+      <div class="content mb-2">
+        <!-- 路径 -->
+        <a-breadcrumb>
+          <a-breadcrumb-item><a href="" @click="navTo('/')">首页</a></a-breadcrumb-item>
+          <a-breadcrumb-item>{{ title }}</a-breadcrumb-item>
+        </a-breadcrumb>
+      </div>
+      <div class="content mb-2">
+        <!-- 搜素栏 -->
+        <div class="row mt-3">
+          <!-- 左栏 -->
+          <div class="col-sm-12 col-md-6 col-lg-6">
+            <!-- 分类 -->
+            <TagBar 
+              :tags="tagsData || []"
+              :margin="[30, 70]" 
+              v-model:selectedTag="selectedTag"
+            />
+          </div>
+          <!-- 右栏 -->
+          <div class="col-sm-12 col-md-6 col-lg-6 d-flex flex-row justify-content-end">
+            <Dropdown
+              v-for="(drop, k) in dropDownNames" :key="k" 
+              :selectedValue="dropDownValues[k] || drop.defaultSelectedValue"
+              :options="drop.options" 
+              @update:selectedValue="(v) => handleChangeDropDownValue(k, v)"
+            />
+            <SimpleInput v-if="showSearch" v-model="searchText" placeholder="请输入关键词" @enter="handleSearch">
+              <template #suffix>
+                <img
+                  class="search-icon"
+                  src="@/assets/images/news/IconSearch.png"
+                  alt="搜索" 
+                  @click="newsLoader.loadData(undefined, true)"
+                />
+              </template>
+            </SimpleInput>
+          </div>
+        </div>
+      </div>
+      <div class="content news-list">
+        <!-- 新闻列表 -->
+        <SimplePageContentLoader :loader="newsLoader">
+          <div 
+            v-for="(item, k) in newsLoader.list.value"
+            :key="item.id"
+            class="item user-select-none main-clickable"
+            :style="{ width: rowWidth }"
+            @click="navTo('/news/detail', { id: item.id })"
+          >
+            <img :src="item.image" alt="新闻图片" />
+            <TitleDescBlock
+              :title="item.title"
+              :desc="item.desc || item.title"
+              :date="DateUtils.formatDate(item.publish_at, DateUtils.FormatStrings.YearCommon)"
+              @click="handleShowDetail(item)"
+            />
+          </div>
+        </SimplePageContentLoader>
+        <!-- 分页 -->
+        <Pagination
+          v-model:currentPage="newsLoader.page.value"
+          :totalPages="newsLoader.totalPages.value"
+        />
+      </div>
+    </section>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, onMounted, ref, watch, type PropType } from 'vue';
+import { useSimplePagerDataLoader } from '@/composeable/SimplePagerDataLoader';
+import { usePageAction } from '@/composeable/PageAction';
+import DateUtils from '@/common/utils/DateUtils';
+import TagBar from '../content/TagBar.vue';
+import Dropdown from '../controls/Dropdown.vue';
+import SimpleInput from '../controls/SimpleInput.vue';
+import SimplePageContentLoader from '@/components/content/SimplePageContentLoader.vue';
+import Pagination from '../controls/Pagination.vue';
+import TitleDescBlock from '../parts/TitleDescBlock.vue';
+
+const { navTo } = usePageAction();
+
+export interface DropdownCommonItem {
+  value: number; 
+  title: string;
+}
+export interface DropDownNames {
+  options: (string|DropdownCommonItem)[],
+  defaultSelectedValue: number|string,
+}
+
+const props = defineProps({	
+  title: {
+    type: String,
+    default: '',
+  },
+  dropDownNames: {
+    type: Object as PropType<DropDownNames[]>,
+    default: null,
+  },
+  showSearch: {
+    type: Boolean,
+    default: true,
+  },
+  tagsData: {
+    type: Object as PropType<{
+      id: number,
+      name: string,
+    }[]>,
+    default: null,
+  },
+  pageSize: {
+    type: Number,
+    default: 8,
+  },
+  rowCount: {
+    type: Number,
+    default: 2,
+  },
+  rowType: {
+    type: Number,
+    default: 1,
+  },
+  defaultSelectTag: {
+    type: Number,
+    default: 1,
+  },
+  load: {
+    type: Function as PropType<(
+      page: number, 
+      pageSize: number,
+      selectedTag: number,
+      searchText: string,
+      dropDownValues: number[],
+    ) => Promise<{
+      page: number,
+      total: number,
+      data: any[],
+    }>>,
+    required: true,
+  },
+})
+
+const rowWidth = computed(() => {
+  switch (props.rowCount) {
+    case 2:
+      return `calc(50% - 100px)`;
+    case 3:
+      return `calc(33% - 100px)`;
+    case 4:
+      return `calc(25% - 100px)`;
+  }
+});
+const rowMargin = computed(() => {
+  switch (props.rowCount) {
+    case 2:
+      return 30;
+    case 3:
+      return 30;
+    case 4:
+      return 30;
+  }
+  return '0';
+});
+const searchText = ref('');
+const dropDownValues = ref<any>([]);
+
+function handleSearch() {
+  newsLoader.loadData(undefined, true);
+}
+function handleChangeDropDownValue(index: number, value: number) {
+  dropDownValues.value[index] = value;
+  newsLoader.loadData(undefined, true);
+}
+function handleShowDetail(item: any) {
+  navTo('/news/detail', { id: item.id });
+}
+
+const newsLoader = useSimplePagerDataLoader(props.pageSize, (page, size) => props.load(
+  page, size, 
+  selectedTag.value, 
+  searchText.value,
+  dropDownValues.value,
+));
+
+//子分类
+const selectedTag = ref(props.defaultSelectTag);
+
+watch(selectedTag, () => {
+  newsLoader.loadData(undefined, true);
+})
+onMounted(() => {
+  newsLoader.loadData(undefined, true);
+});
+</script>
+
+<style lang="scss">
+.search-icon {
+  width: 20px;
+  height: 20px;
+  cursor: pointer;
+}
+</style>
+

+ 68 - 0
src/components/content/TagBar.vue

@@ -0,0 +1,68 @@
+<template>
+  <!-- 单选标签选择按钮条,可显示一行标签,然后高亮选中项 -->
+  <div class="d-flex flex-row flex-wrap">
+    <div
+      :class="[
+        'tag-button',
+        { 'active': tag.id === selectedTag },
+      ]"
+      v-for="tag in tags"
+      :key="tag.id"
+      @click="emit('update:selectedTag', tag.id ?? tag)"
+    >
+      {{ tag.name?? tag }}
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import type { PropType } from 'vue';
+
+defineProps({	
+  /**
+   * 标签列表
+   */
+  tags: {
+    type: Object as PropType<Array<{
+      id: number|string,
+      name: string,
+    }>>,
+    required: true,
+  },
+  /**
+   * 选中的标签,可双向绑定
+   */
+  selectedTag: {
+    type: [Number,String],
+    default: null,
+  }
+})
+
+const emit = defineEmits([	
+  "update:selectedTag"	
+])
+</script>
+
+<style lang="scss">
+@use '@/assets/scss/colors.scss' as *;
+
+.tag-button {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  background-color: $box-inset-color;
+  color: $text-color;
+  padding: 10px 15px;
+  margin-right: 8px;
+  cursor: pointer;
+  user-select: none;
+
+  &:hover {
+    background-color: $box-hover-color;
+  }
+  &:active, &.active {
+    color: $text-color-light;
+    background-color: $primary-color;
+  }
+}
+</style>

+ 4 - 0
src/components/parts/ImageTitleBlock.vue

@@ -5,6 +5,7 @@
       title ? 'has-title' : '',
     ]" 
     :style="{ backgroundImage: `url('${image}')` }"
+    @click="$emit('click')"
   >
     <div class="desc">
       <h5>{{ title }}</h5>
@@ -28,6 +29,9 @@ defineProps({
     default: '' 
   },
 })
+defineEmits([
+  'click',
+])
 </script>
 
 <style lang="scss">

+ 6 - 0
src/components/parts/LeftRightBox.vue

@@ -8,6 +8,7 @@
         :desc="desc" 
         :descLines="descLines"
         more
+        @moreClick="emit('moreClick')"
       />
     </div>
     <div class="col col-12 col-lg-6 col-md-6">
@@ -17,6 +18,7 @@
         :desc="desc"
         :descLines="descLines"
         more
+        @moreClick="emit('moreClick')"
       />
       <img v-else :src="image" alt="image" />
     </div>
@@ -33,6 +35,10 @@ defineProps({
   descLines: Number,
   left: Boolean,	
 })
+
+const emit = defineEmits([	
+  "moreClick"	
+])
 </script>
 
 <style lang="scss">

+ 2 - 1
src/components/parts/ThreeImageList.vue

@@ -6,6 +6,7 @@
       :image="item.image"
       :title="item.title"
       :desc="item.desc"
+      @click="item.onClick?.()"
     />
   </div>
 </template>
@@ -16,7 +17,7 @@ import ImageTitleBlock from './ImageTitleBlock.vue';
 
 defineProps({	
   list : {
-    type: Object as PropType<{title: string, image: string, desc: string}[]>,
+    type: Object as PropType<{title: string, image: string, desc: string,onClick?:() => void}[]>,
     default: () => [],
   }	
 })

+ 5 - 1
src/components/parts/TitleDescBlock.vue

@@ -4,7 +4,7 @@
     <span v-if="date" class="time">{{ date }}</span>
     <p>{{ desc }}</p>
 
-    <div v-if="more" class="more">
+    <div v-if="more" class="more" @click="emit('moreClick')">
       更多
       <img src="@/assets/images/IconArrowRight.png" alt="更多" />
     </div>
@@ -22,6 +22,10 @@ const props = defineProps({
   more: Boolean,
   date: String,
 })
+
+const emit = defineEmits([	
+  "moreClick"	
+])
 </script>
 
 <style lang="scss">

+ 2 - 0
src/main.ts

@@ -14,6 +14,7 @@ import App from './App.vue'
 import router from './router'
 import Antd from 'ant-design-vue';
 import VueAMap, {initAMapApiLoader} from '@vuemap/vue-amap';
+import CommonListPage from './components/content/CommonListPage.vue';
 import { registryConvert } from './common/ConvertRgeistry'
 
 initAMapApiLoader({
@@ -28,6 +29,7 @@ app.use(createPinia())
 app.use(VueAMap)
 app.use(Antd)
 app.use(router)
+app.component('CommonListPage', CommonListPage)
 
 app.mount('#app')
 

+ 75 - 0
src/router/index.ts

@@ -39,16 +39,91 @@ const router = createRouter({
       component: () => import('../views/CommunicateView.vue'),
     },
     {
+      path: '/communicate/fujian-and-taiwan',
+      name: 'CommunicateFujianAndTaiwan',
+      component: () => import('../views/communicate/fujian-and-taiwan.vue'),
+    },
+    {
+      path: '/communicate/hk-macao-and-taiwan',
+      name: 'CommunicateHKMacaoAndTiwanAndTaiwan',
+      component: () => import('../views/communicate/hk-macao-and-taiwan.vue'),
+    },
+    {
+      path: '/communicate/south-asian',
+      name: 'CommunicateSouthAsian',
+      component: () => import('../views/communicate/south-asian.vue'),
+    },
+    {
+      path: '/communicate/activity',
+      name: 'CommunicateActivity',
+      component: () => import('../views/communicate/activity.vue'),
+    },
+    {
+      path: '/communicate/outside',
+      name: 'CommunicateOutside',
+      component: () => import('../views/communicate/outside.vue'),
+    },
+    {
       path: '/research',
       name: 'research',
       component: () => import('../views/ResearchView.vue'),
     },
     {
+      path: '/research/teams',
+      name: 'ResearchTeams',
+      component: () => import('../views/research/teams.vue'),
+    },
+    {
+      path: '/research/discuss',
+      name: 'ResearchDiscuss',
+      component: () => import('../views/research/discuss.vue'),
+    },
+    {
+      path: '/research/projects',
+      name: 'ResearchProjects',
+      component: () => import('../views/research/projects.vue'),
+    },
+    {
+      path: '/research/result',
+      name: 'ResearchResult',
+      component: () => import('../views/research/result.vue'),
+    },
+    {
+      path: '/research/expert',
+      name: 'ResearchExpert',
+      component: () => import('../views/research/expert.vue'),
+    },
+    {
       path: '/fusion',
       name: 'fusion',
       component: () => import('../views/FusionView.vue'),
     },
     {
+      path: '/fusion/scenic-spot',
+      name: 'FusionScenicSpot',
+      component: () => import('../views/fusion/scenic-spot.vue'),
+    },
+    {
+      path: '/fusion/route',
+      name: 'FusionRoute',
+      component: () => import('../views/fusion/route.vue'),
+    },
+    {
+      path: '/fusion/products',
+      name: 'FusionProducts',
+      component: () => import('../views/fusion/products.vue'),
+    },
+    {
+      path: '/fusion/demo-site',
+      name: 'FusionDemoSite',
+      component: () => import('../views/fusion/demo-site.vue'),
+    },
+    {
+      path: '/fusion/fashion',
+      name: 'FusionFashion',
+      component: () => import('../views/fusion/fashion.vue'),
+    },
+    {
       path: '/inheritor',
       name: 'inheritor',
       component: () => import('../views/InheritorView.vue'),

+ 6 - 0
src/views/CommunicateView.vue

@@ -23,6 +23,7 @@
           title="闽南地区文化交流"
           desc="闽南地区总人口约一千余万,河南地区包括泉州、厦门、州三个地级市以及龙岩市的新罗区和漳平市。闽南地区的泉州港在未元时期是世界第一大港,闽南人分布广泛,海内外使用闽南方言的人很多,不少被闽南人影响的当地民族和马来人也会使用闽南语。闽南这个词..---闽南方言。明末时,闽南发生大旱,郑芝龙....."
           :image="Image1"
+          @moreClick="navTo('/communicate/fujian-and-taiwan')"
         />
         <LeftRightBox 
           class="mt-4"
@@ -30,12 +31,14 @@
           desc="闽南地区总人口约一千余万,河南地区包括泉州、厦门、州三个地级市以及龙岩市的新罗区和漳平市。闽南地区的泉州港在未元时期是世界第一大港,闽南人分布广泛,海内外使用闽南方言的人很多,不少被闽南人影响的当地民族和马来人也会使用闽南语。闽南这个词....---闽南方言。明末时,闽南发生大旱,郑芝龙....."
           :image="Image2"
           left
+          @moreClick="navTo('/communicate/hk-macao-and-taiwan')"
         />
         <LeftRightBox 
           class="mt-4"
           title="对外文化交流"
           desc="闽南地区总人口约一千余万,河南地区包括泉州、厦门、州三个地级市以及龙岩市的新罗区和漳平市。闽南地区的泉州港在未元时期是世界第一大港,闽南人分布广泛,海内外使用闽南方言的人很多,不少被闽南人影响的当地民族和马来人也会使用闽南语。闽南这个词....---闽南方言。明末时,闽南发生大旱,郑芝龙....."
           :image="Image3"
+          @moreClick="navTo('/communicate/south-asian')"
         />
       
       </div>
@@ -48,6 +51,7 @@
 <script setup lang="ts">
 import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel'
 import { onMounted, ref } from 'vue';
+import { usePageAction } from '@/composeable/PageAction';
 import Image1 from '@/assets/images/communicate/Image1.jpg'
 import Image2 from '@/assets/images/communicate/Image2.jpg'
 import Image3 from '@/assets/images/communicate/Image3.jpg'
@@ -59,6 +63,8 @@ const carouselConfig = {
   autoPlay: 5000,
 }
 
+const { navTo } = usePageAction();
+
 </script>
 
 <style lang="scss">

+ 18 - 0
src/views/FusionView.vue

@@ -75,6 +75,7 @@ import Image5 from '@/assets/images/fusion/Image5.jpg'
 import LeftRightBox from '@/components/parts/LeftRightBox.vue';
 import ImageTitleDescBlock from '@/components/parts/ImageTitleDescBlock.vue';
 import ThreeImageList from '@/components/parts/ThreeImageList.vue';
+import { usePageAction } from '@/composeable/PageAction';
 
 const carouselConfig = {
   itemsToShow: 1,
@@ -86,26 +87,41 @@ const list = [
     title: '闽南文化景区',
     desc: '让文化因传承而永存',
     image: Image1,
+    onClick: () => {
+      navTo('/fusion/scenic-spot');
+    }
   },
   {
     title: '文化旅游路线',
     desc: '让文化因传承而永存',
     image: Image2,
+    onClick: () => {
+      navTo('/fusion/route');
+    }
   },
   {
     title: '文化产品',
     desc: '让文化因传承而永存',
     image: Image3,
+    onClick: () => {
+      navTo('/fusion/products');
+    }
   },
   {
     title: '文旅融合示范点',
     desc: '让文化因传承而永存',
     image: Image4,
+    onClick: () => {
+      navTo('/fusion/demo-site');
+    }
   },
   {
     title: '闽南时尚',
     desc: '让文化因传承而永存',
     image: Image5,
+    onClick: () => {
+      navTo('/fusion/fashion');
+    }
   },
   {
     title: '',
@@ -182,6 +198,8 @@ const monthData = [
   },
 ]
 
+const { navTo } = usePageAction();
+
 </script>
 
 <style lang="scss">

+ 9 - 0
src/views/NewsDetailView.vue

@@ -124,6 +124,15 @@ function back() {
       font-size: 0.75rem;
     }
   }
+
+  .news-content {
+    position: relative;
+
+    img {
+      max-width: 100%;
+      text-align: center;
+    }
+  }
 }
 
 

+ 24 - 93
src/views/NewsView.vue

@@ -31,7 +31,7 @@
                 @search="newsLoader.loadData(undefined, true)"
               >
                 <template #prefix>
-                  <img src="@/assets/images/news/IconSearch.png" alt="搜索" />
+                  <img src="@/assets/images/news/IconSearch.png" alt="搜索" @click="newsLoader.loadData(undefined, true)" />
                 </template>
               </SimpleInput>
             </div>
@@ -57,29 +57,29 @@
 
     <!-- 新闻 -->
     <section class="main-section main-background main-background-type0">
-        <div class="content news-list">
-          <!-- 新闻列表 -->
-          <SimplePageContentLoader :loader="newsLoader">
-            <div 
-              v-for="(item, k) in newsLoader.list.value"
-              :key="item.id"
-              class="item"
-              @click="router.push({ name: 'news-detail', query: { id: item.id }})"
-            >
-              <img :src="item.image" alt="新闻图片" />
-              <TitleDescBlock
-                :title="item.title"
-                :desc="item.desc || item.title"
-                :date="DateUtils.formatDate(item.publish_at, DateUtils.FormatStrings.YearCommon)"
-              />
-            </div>
-          </SimplePageContentLoader>
-          <!-- 分页 -->
-          <Pagination2
-            v-model:currentPage="newsLoader.page.value"
-            :totalPages="newsLoader.totalPages.value"
-          />
-        </div>
+      <div class="content news-list">
+        <!-- 新闻列表 -->
+        <SimplePageContentLoader :loader="newsLoader">
+          <div 
+            v-for="(item, k) in newsLoader.list.value"
+            :key="item.id"
+            class="item"
+            @click="router.push({ name: 'news-detail', query: { id: item.id }})"
+          >
+            <img :src="item.image" alt="新闻图片" />
+            <TitleDescBlock
+              :title="item.title"
+              :desc="item.desc || item.title"
+              :date="DateUtils.formatDate(item.publish_at, DateUtils.FormatStrings.YearCommon)"
+            />
+          </div>
+        </SimplePageContentLoader>
+        <!-- 分页 -->
+        <Pagination2
+          v-model:currentPage="newsLoader.page.value"
+          :totalPages="newsLoader.totalPages.value"
+        />
+      </div>
     </section>
 
 
@@ -146,72 +146,3 @@ onMounted(async () => {
   ]
 })
 </script>
-
-<style lang="scss">
-@use "sass:list";
-@use '@/assets/scss/colors.scss' as *;
-
-.news-list {
-  display: flex;
-  flex-direction: column;
-  gap: 24px;
-
-  .item {
-    display: flex;
-    flex-direction: row;
-    padding: 25px;
-    border-radius: 6px;
-    background-color: $box-color;
-
-    &:hover { 
-      background-color: $box-hover-color;
-    }
-    &:active {
-      transform: scale(0.95);
-    }
-
-    img {
-      width: 320px;
-      height: 180px;
-      margin-right: 25px;
-    }
-
-   
-  }
-}
-
-
-@media (max-width: 768px) {
-  .news-list {
-    .item {
-      display: flex;
-      flex-direction: row;
-      padding: 25px;
-      border-radius: 6px;
-      background-color: $box-color;
-
-      img {
-        width: 200px;
-        height: 140px;
-        margin-right: 25px;
-      }
-    }
-  }
-}
-@media (max-width: 540px) {
-  .news-list {
-    .item {
-      flex-direction: column;
-
-      img {
-        width: 100%;
-        height: 180px;
-        
-        margin-right: 0;
-        margin-bottom: 16px;
-      }
-    }
-  }
-}
-</style>
-

+ 18 - 1
src/views/ResearchView.vue

@@ -27,7 +27,7 @@
 
 <script setup lang="ts">
 import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel'
-import { onMounted, ref } from 'vue';
+import { usePageAction } from '@/composeable/PageAction';
 import Image1 from '@/assets/images/research/Image1.jpg';
 import Image2 from '@/assets/images/research/Image2.jpg';
 import Image3 from '@/assets/images/research/Image3.jpg';
@@ -46,26 +46,41 @@ const list = [
     title: '研究团队',
     desc: '让文化因传承而永存',
     image: Image1,
+    onClick: () => {
+      navTo('/research/team');
+    }
   },
   {
     title: '研究项目',
     desc: '让文化因传承而永存',
     image: Image2,
+    onClick: () => {
+      navTo('/research/projects');
+    }
   },
   {
     title: '理论研讨',
     desc: '让文化因传承而永存',
     image: Image3,
+    onClick: () => {
+      navTo('/research/discuss');
+    }
   },
   {
     title: '研究成果',
     desc: '让文化因传承而永存',
     image: Image4,
+    onClick: () => {
+      navTo('/research/result');
+    }
   },
   {
     title: '专家学者',
     desc: '让文化因传承而永存',
     image: Image5,
+    onClick: () => {
+      navTo('/research/expert');
+    }
   },
   {
     title: '',
@@ -73,6 +88,8 @@ const list = [
     image: '',
   }
 ]
+
+const { navTo } = usePageAction();
 </script>
 
 <style lang="scss">

+ 54 - 0
src/views/communicate/activity.vue

@@ -0,0 +1,54 @@
+<template>
+  <!-- 传播交流 - 品牌活动 -->
+   <CommonListPage
+    :title="'品牌活动'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import CommunicateContent from '@/api/communicate/CommunicateContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await CommunicateContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await CommunicateContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 297
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 54 - 0
src/views/communicate/fujian-and-taiwan.vue

@@ -0,0 +1,54 @@
+<template>
+  <!-- 传播交流 - 闽台文化交流 -->
+   <CommonListPage
+    :title="'闽台文化交流'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import CommunicateContent from '@/api/communicate/CommunicateContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await CommunicateContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await CommunicateContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 260
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 54 - 0
src/views/communicate/hk-macao-and-taiwan.vue

@@ -0,0 +1,54 @@
+<template>
+  <!-- 传播交流 - 台港澳地区文化交流 -->
+   <CommonListPage
+    :title="'港澳台地区文化交流'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import CommunicateContent from '@/api/communicate/CommunicateContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await CommunicateContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await CommunicateContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 261
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 54 - 0
src/views/communicate/outside.vue

@@ -0,0 +1,54 @@
+<template>
+  <!-- 传播交流 - 对外文化交流 -->
+   <CommonListPage
+    :title="'对外文化交流'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import CommunicateContent from '@/api/communicate/CommunicateContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await CommunicateContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await CommunicateContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 262
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 54 - 0
src/views/communicate/south-asian.vue

@@ -0,0 +1,54 @@
+<template>
+  <!-- 传播交流 - 东南亚地区文化交流 -->
+   <CommonListPage
+    :title="'东南亚地区文化交流'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import CommunicateContent from '@/api/communicate/CommunicateContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await CommunicateContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await CommunicateContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 296
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/fusion/demo-site.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 文旅融合 - 文旅融合示范点 -->
+   <CommonListPage
+    :title="'文旅融合示范点'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import DemoSiteContent from '@/api/fusion/DemoSiteContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await DemoSiteContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await DemoSiteContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/fusion/fashion.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 文旅融合 - 闽南时尚 -->
+   <CommonListPage
+    :title="'闽南时尚'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import FashionContent from '@/api/fusion/FashionContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await FashionContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await FashionContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/fusion/products.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 文旅融合 - 文创产品 -->
+   <CommonListPage
+    :title="'文创产品'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import ProductContent from '@/api/fusion/ProductContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await ProductContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ProductContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 61 - 0
src/views/fusion/route.vue

@@ -0,0 +1,61 @@
+<template>
+  <!-- 文旅融合 - 文化旅游路线 -->
+   <CommonListPage
+    :title="'文化旅游路线'"
+    :dropDownNames="[]"
+    :showSearch="true"
+    :tagsData="tagsData"
+    :pageSize="8"
+    :defaultSelectTag="274"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { GetContentListParams } from '@/api/CommonContent';
+import ResultContent from '@/api/research/ResultContent';
+
+async function loadDetail(id: number, item: any) {
+  return await ResultContent.getContentDetail(id);
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ResultContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: selectedTag,
+    keywords: searchText,
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+      };
+    }),
+  }
+}
+
+//子分类
+const tagsData = ref([
+  { id: 274, name: '全部' },
+  { id: 275, name: '非遗旅游路线' },
+  { id: 276, name: '闽南红色文化旅游路线' },
+  { id: 277, name: '闽南美食旅游路线' },
+]);
+</script>
+
+<style>
+</style>
+

+ 47 - 0
src/views/fusion/scenic-spot.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 文化传承 - 文化景区 -->
+   <CommonListPage
+    :title="'文化文化景区'"
+    :dropDownNames="[]"
+    :showSearch="true"
+    :pageSize="8"
+    :load="loadData"
+  />
+</template>
+
+<script setup lang="ts">
+import ScenicSpotContent from '@/api/fusion/ScenicSpotContent';
+import { GetContentListParams } from '@/api/CommonContent';
+
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ScenicSpotContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: 260
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+
+</script>
+
+<style>
+</style>

+ 52 - 0
src/views/research/discuss.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 传播交流 - 理论研讨 -->
+   <CommonListPage
+    :title="'理论研讨'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import DiscussContent from '@/api/research/DiscussContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await DiscussContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await DiscussContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/research/expert.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 传播交流 - 专家学者 -->
+   <CommonListPage
+    :title="'专家学者'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import ExpertContent from '@/api/research/ExpertContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await ExpertContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ExpertContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/research/projects.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 传播交流 - 研究项目 -->
+   <CommonListPage
+    :title="'研究项目'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import ProjectContent from '@/api/research/ProjectContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await ProjectContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ProjectContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+

+ 60 - 0
src/views/research/result.vue

@@ -0,0 +1,60 @@
+<template>
+  <!-- 传播交流 - 研究成果 -->
+   <CommonListPage
+    :title="'研究成果'"
+    :dropDownNames="[]"
+    :showSearch="true"
+    :tagsData="tagsData"
+    :pageSize="8"
+    :defaultSelectTag="269"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue';
+import { GetContentListParams } from '@/api/CommonContent';
+import ResultContent from '@/api/research/ResultContent';
+
+async function loadDetail(id: number, item: any) {
+  return await ResultContent.getContentDetail(id);
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await ResultContent.getContentList(new GetContentListParams().setSelfValues({
+    mainBodyColumnId: selectedTag,
+    keywords: searchText,
+  }), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+      };
+    }),
+  }
+}
+
+//子分类
+const tagsData = ref([
+  { id: 269, name: '全部' },
+  { id: 270, name: '文献' },
+  { id: 271, name: '著作' },
+]);
+</script>
+
+<style>
+</style>
+

+ 52 - 0
src/views/research/teams.vue

@@ -0,0 +1,52 @@
+<template>
+  <!-- 传播交流 - 研究团队 -->
+   <CommonListPage
+    :title="'研究团队'"
+    :dropDownNames="[]"
+    :pageSize="8"
+    :load="loadData"
+    :loadDetail="loadDetail"
+  />
+</template>
+
+<script setup lang="ts">
+import { GetContentListParams } from '@/api/CommonContent';
+import TeamsContent from '@/api/research/TeamsContent';
+
+async function loadDetail(id: number, item: any) {
+  const res = await TeamsContent.getContentDetail(id);
+  res.content = res.content || res.intro as string;
+  res.addItems = [
+  ];
+  return res;
+}
+async function loadData(
+  page: number, 
+  pageSize: number,
+  selectedTag: number,
+  searchText: string,
+  dropDownValues: number[]
+) {
+
+  const res = await TeamsContent.getContentList(new GetContentListParams(), page, pageSize);
+
+  return { 
+    page: page,
+    total: res.total,
+    data: res.list.map((item, index) => {
+      return {
+        id: item.id,
+        title: item.title,
+        desc: item.desc,
+        image: item.image,
+        addItems: [
+        ],
+      };
+    }),
+  }
+}
+</script>
+
+<style>
+</style>
+