余晋文 2 years ago
parent
commit
42f6b0f9da
2 changed files with 271 additions and 380 deletions
  1. 97 0
      src/api/report.js
  2. 174 380
      src/views/report/List.vue

+ 97 - 0
src/api/report.js

@@ -4,3 +4,100 @@
 import {get,post} from './http'
 
 
+/**
+ * 研报详情
+ * @param report_id 
+ */
+export const apiReportDetail=params=>{
+    return get('/report/detail',params)
+}
+
+/**
+ * 章节详情
+ * @param report_chapter_id
+ */
+export const apiChapterDetail=params=>{
+    return get('/report/chapter/detail',params)
+}
+
+/**
+ * 研报首页顶部权限菜单
+ */
+export const apiReportIndexPageAuthList=()=>{
+    return get('/company/getPermissionList',{})
+}
+
+/**
+ * 研报首页报告列表
+ * @param chart_permission_id
+ */
+export const apiReportIndexPageList=params=>{
+    return get('/report/collect',params)
+}
+
+/**
+ * 研报搜索
+ * @param key_word
+ */
+export const apiReportSearch=params=>{
+    return get('/report/search',params)
+}
+
+/**
+ * 分类数据
+ */
+export const apiReportClassify=()=>{
+    return get('/classify/ficc',{})
+}
+
+/**
+ * 研报列表
+ * @param classify_id_first
+ * @param key_word
+ */
+export const apiReportList=params=>{
+    return get('/report/list',params)
+}
+
+/**
+ * 二级分类列表
+ * @param classify_id_first
+ * @param classify_id_second
+ */
+export const apiSubClassifyList=params=>{
+    return get('/classify/simple/list',params)
+}
+
+/**
+ * 专栏列表
+ * @param classify_id_first
+ */
+export const apiSpecialColumnList=params=>{
+    return get('/classify/list',params)
+}
+
+/**
+ * 专栏详情
+ * @param classify_id_second
+ */
+export const apiSpecialColumnDetail=params=>{
+    return get('/classify/detail',params)
+}
+
+/**
+ * 专栏详情中目录
+ * @param classify_id_second
+ * @param current_index
+ * @param page_size
+ */
+export const apiSpecialColumnReportList=params=>{
+    return get('/classify/detail/reports',params)
+}
+
+/**
+ * 章节详情中指标数据
+ * @param report_chapter_id
+ */
+export const apiChapterTickerValue=params=>{
+    return get('/report/chapter/ticker',params)
+}

+ 174 - 380
src/views/report/List.vue

@@ -1,230 +1,155 @@
 <script setup>
+import {apiReportIndexPageAuthList,apiReportIndexPageList} from '@/api/report'
 import { computed, onMounted, reactive, ref } from "vue";
-import {
-  varietyData,
-  informationData,
-  reportData,
-  searchData,
-} from "./staticData.js";
 import { useRouter } from "vue-router";
 import throttle from "lodash/throttle";
 import Search from "@/components/Search.vue";
 
-/*通过ref=xxx获取的dom */
-let report = ref(null);
-let reportContainer = ref(null);
-
-let icon_more_path = new URL("../../assets/icon-more.png", import.meta.url)
-  .href; //查看更多的icon
-let report_empty_path = new URL("../../assets/report-empty.png",import.meta.url)
-let mounted = ref(false);
-let pageModel = ref("normal");
+const router = useRouter();
 
-/*nav数据 */
-let activeTab = ref("宏观经济");
-let activeSubTab = ref("宏观");
-let varietySubData = computed(() => {
-  return varietyData.find((i) => i.label === activeTab.value).child;
-});
 
-const getData = () => {
-  return new Promise((resolve, _) => {
-    resolve("aaa");
-  });
-};
-const getSearchData = (keyWord) => {
-  changePageStyle("search");
-};
+// 获取顶部权限分类数据
+let firstTypeList=ref([])//一级分类数据
+let subTypeList=ref([])//二级分类数据
+let selectFirstType=ref('')//选择的一级分类
+let selectSubType=ref('')//选择的二级分类ID
+const getTopPermissionList=async ()=>{
+  const res=await apiReportIndexPageAuthList()
+  if(res.code===200){
+    firstTypeList.value=res.data.permission_list.filter(item=>item.sort!=100000)
+    clickFirstType(firstTypeList.value[0])
+  }
+}
+getTopPermissionList()
 
-const changePageStyle = (model) => {
-  pageModel.value = model;
-  //normal,search
-  if (model === "normal") {
-  } else {
-    report.value.style.height = "auto";
+// 获取报告列表数据
+let reportState=reactive({
+  list:[],
+  page:1,
+  pageSize:20,
+  finished:false,
+  loading:false,
+  dateArr:[],//日期数据
+})
+const getReportList=async ()=>{
+  reportState.loading=true
+  const res=await apiReportIndexPageList({
+    chart_permission_id:Number(selectSubType.value),
+    current_index:reportState.page,
+    page_size:reportState.pageSize
+  })
+  reportState.loading=false 
+  if(res.code===200){
+    if(res.data.paging.is_end){
+      reportState.finished=true
+    }
+    //处理数据
+    if(res.data.list){
+      // 第一页数据
+      reportState.list=res.data.list
+      res.data.list.forEach(item=>{
+        reportState.dateArr.push(item.date)
+      })
+    }else{
+      //判断是否前面已经有相同日期数据 有的话添加合并
+      let arr=[]
+      let temTimearr=[]
+      res.data.list.forEach(item => {
+        if(reportState.dateArr.includes(item.date)){
+          this.list.forEach(_item=>{
+            if(item.date===_item.date){
+              _item.sub_list=[..._item.sub_list,...item.sub_list]
+            }
+          })
+        }else{
+          arr.push(item)
+          temTimearr.push(item.date)
+        }
+      });
+      reportState.list=[...this.list,...arr]
+      reportState.dateArr=[...this.dateArr,...temTimearr]
+    }
   }
-};
-const handleSearch = (data) => {
-  console.log("data", data.value);
-  getSearchData(data.value);
-};
+}
+
+//点击顶部一级分类
+const clickFirstType=(item)=>{
+  selectFirstType.value=item.classify_name
+  subTypeList.value=item.list
+  clickSubType(item.list[0])
+}
+//点击二级分类
+const clickSubType=(item)=>{
+  selectSubType.value=item.chart_permission_id
+  reportState.list=[]
+  reportState.page=1
+  reportState.finished=false
+  getReportList()
+}
+
+
+let icon_more_path = new URL("../../assets/icon-more.png", import.meta.url).href; //查看更多的icon
+let mounted = ref(false);
+
+
 
-let showMore = ref(false); //是否展示加载更多按钮
-let autoShow = ref(false); //是否展示研报主体内容
-let showData = ref([]); //有加载更多的情况下,展示的研报主体内容
 let showBackTop = ref(false); //是否显示回到顶部按钮
-const checkMore = () => {
-  //检查reportData长度是否超过el-main的clientHeight,reportData-item的minHeight为(125*childNum+56)
-  const clientHeight =
-    document.getElementsByClassName("el-main")[0].clientHeight;
-  let sumHeight = 0,
-    showIndex = 0;
-  reportData.forEach((item, index) => {
-    sumHeight += item.child.length * 125 + 56;
-    if (sumHeight >= clientHeight) {
-      showIndex = index;
-      showMore.value = true;
-      report.value.style.height = clientHeight - 40 + "px";
-    }
-  });
-  showData.value = reportData.slice(0, showIndex);
-  autoShow.value = true;
-};
-const showMoreData = () => {
-  showData.value = reportData;
-  showMore.value = false;
-  report.value.style.height = "auto";
-  reportContainer.value.style.overflow = "auto";
-};
+
 const backToTop = () => {
   window.scrollTo({ top: 0, behavior: "smooth" });
 };
-const checkScroll = throttle(() => {
-  const { clientHeight, scrollHeight } =
-    document.getElementsByClassName("layout-wrap")[0];
-  const scrollTop =
-    document.documentElement.scrollTop || document.body.scrollTop;
-  if (scrollTop >= 125) {
-    showBackTop.value = true;
-  } else {
-    showBackTop.value = false;
-  }
-  if (scrollTop + clientHeight >= scrollHeight) {
-    //请求下一页数据
-    getData();
-  }
-}, 300);
 
-const router = useRouter();
+
 const toClassPage = () => {
   //跳转至研报分类页
   router.push({ name: "ReportClassify" });
 };
-const toReportDetail = () => {};
-const changeTab = (className, item) => {
-  if (className === "main") {
-    activeTab.value = item.label;
-    activeSubTab.value = item.child[0].label;
-  } else {
-    activeSubTab.value = item.label;
-  }
-};
 
-onMounted(async () => {
-  await getData();
-  checkMore();
-  document.addEventListener("scroll", checkScroll);
+onMounted(() => {
   mounted.value = true;
 });
 </script>
 <template>
-  <div class="report-list-page" ref="report">
-    <template v-if="pageModel === 'normal'">
-      <div class="report-main">
-        <div class="nav-wrap">
-          <div class="main-nav">
-            <div
-              class="main-nav-item"
-              :class="{ active: activeTab === item.label }"
-              v-for="item in varietyData"
-              :key="item.label"
-              @click="changeTab('main', item)"
-            >
-              {{ item.label }}
-            </div>
-            <div class="more" @click="toClassPage">
-              <span>查看更多</span>
-              <img :src="icon_more_path" class="more-img" />
-            </div>
-          </div>
-          <div class="sub-nav">
-            <div
-              class="sub-nav-item"
-              v-for="item in varietySubData"
-              :key="item.label"
-              :class="{ active: activeSubTab === item.label }"
-              @click="changeTab('sub', item)"
-            >
-              {{ item.label }}
-            </div>
-          </div>
+  <div class="report-list-page">
+    <div class="report-main">
+      <div class="top-nav-wrap">
+        <div class="flex first-nav">
+          <div 
+            :class="['item',item.classify_name==selectFirstType&&'item-active']" 
+            v-for="item in firstTypeList" 
+            :key="item.classify_name"
+            @click="clickFirstType(item)"
+          >{{item.classify_name}}</div>
         </div>
-        <div class="container" ref="reportContainer">
-          <template v-if="autoShow">
-            <div
-              class="report-item"
-              v-for="item in showData"
-              :key="item.timeLabel"
-            >
-              <div class="item-title">{{ item.timeLabel }}</div>
-              <div class="time-point-wrap">
-                <div
-                  class="time-point-item"
-                  v-for="point in item.child"
-                  :key="point.timeLabel"
-                >
-                  <div class="point-time">{{ point.timeLabel }}</div>
-                  <div class="point-title">{{ point.title }}</div>
-                  <div class="point-content multy-ellipsis">{{ point.abstract }}</div>
-                  <div class="point-tab" v-for="tab in point.label" :key="tab">
-                    #{{ tab }}
-                  </div>
-                  <div class="point-see" @click="toReportDetail">查看全部</div>
-                </div>
-              </div>
-            </div>
-          </template>
-
-          <div class="check-more-wrap" v-if="showMore">
-            <div class="check-more" @click="showMoreData">加载更多</div>
-          </div>
+        <div class="flex sub-nav">
+          <span 
+            :class="['sub-item',item.chart_permission_id==selectSubType&&'sub-active']"
+            v-for="item in subTypeList"
+            :key="item.chart_permission_id"
+            @click="clickSubType(item)"
+          >{{item.chart_permission_name}}</span>
         </div>
       </div>
-      <div class="report-aside">
-        <div class="aside-item">
-          <div class="aside-title">最新资讯</div>
-          <div class="infomation-wrap">
-            <div
-              class="infomation-item"
-              v-for="item in informationData"
-              :key="item.title"
-            >
-              <div class="item-title">{{ item.title }}</div>
-              <div class="item-content">{{ item.no }}|{{ item.main }}</div>
-            </div>
+    </div>
+    <div class="report-aside">
+      <div class="aside-item">
+        <div class="aside-title">最新资讯</div>
+        <div class="infomation-wrap">
+          <div class="infomation-item" v-for="item in informationData" :key="item.title">
+            <div class="item-title">{{ item.title }}</div>
+            <div class="item-content">{{ item.no }}|{{ item.main }}</div>
           </div>
         </div>
-        <div class="aside-item">
-          <div class="aside-title" style="margin-top: 60px">上新公告</div>
-          <div class="annoucement">
-            <div class="title">行业调研</div>
-            <p class="content">带您感知最微观的行业变化</p>
-          </div>
+      </div>
+      <div class="aside-item">
+        <div class="aside-title" style="margin-top: 60px">上新公告</div>
+        <div class="annoucement">
+          <div class="title">行业调研</div>
+          <p class="content">带您感知最微观的行业变化</p>
         </div>
-      </div></template
-    >
-    <template v-if="pageModel === 'search'">
-      <div class="search-main">
-        <!-- <div class="search-item" v-for="item in searchData" :key="item.title">
-          <div class="search-title">
-            {{ item.title }}
-          </div>
-          <div class="search-content multy-ellipsis">
-            {{ item.abstract }}
-          </div>
-          <div class="search-label" v-for="tab in item.label" :key="tab">
-            #{{ tab }}
-          </div>
-          <div class="search-time">
-            {{item.time}}
-          </div>
-        </div> -->
-        <template v-if="searchData.length">
-          <el-empty :image="report_empty_path" :image-size="400"
-          description="找不到对应报告,试试别的搜索词吧" />
-        </template>
       </div>
-    </template>
+    </div>
+
     <transition name="fade">
       <div class="back-top" v-show="showBackTop" @click="backToTop"></div>
     </transition>
@@ -239,196 +164,56 @@ onMounted(async () => {
   </template> -->
 </template>
 
-
-
 <style lang="scss" scoped>
 $bg-color: #f6f6f6;
 $active-color: #f3a52f;
+
 .report-list-page {
   position: relative;
   .report-main {
-    display: flex;
-    flex-direction: column;
-    height: 100%;
-    margin-right: 220px;
-    margin-left: -20px;
-    .nav-wrap {
-      padding: 10px 30px;
-      box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.04);
-      .main-nav {
-        display: flex;
-        justify-content: space-between;
-        .main-nav-item {
-          cursor: pointer;
+    .top-nav-wrap{
+      .first-nav{
+        .item{
           width: 140px;
           height: 40px;
-          background-color: $bg-color;
-          color: #333333;
-          box-sizing: border-box;
+          background: #F6F6F6;
+          border-radius: 20px;
           text-align: center;
           line-height: 40px;
-          border-radius: 20px;
-          border: 1px solid $bg-color;
-          transition: 0.3s;
-          &.active,
-          &:hover {
-            background-color: #fffbf5;
-            color: $active-color;
-            border: 1px solid $active-color;
-            box-shadow: 0px 6px 7px #fff7eb;
-          }
-          &.active {
-            box-shadow: none;
-          }
-        }
-        .more {
+          font-size: 16px;
+          margin-right: 30px;
           cursor: pointer;
-          align-self: center;
-          color: $active-color;
-          display: flex;
-          align-items: center;
-          margin-left: 80px;
-          .more-img {
-            width: 16px;
-            height: 16px;
-            margin-left: 6px;
+          &:hover{
+            background: #FFFBF5;
+            color: #F3A52F;
+            border: 1px solid #F3A52F;
+            box-shadow: 0px 6px 7px 1px #FFF7EB;
           }
         }
+        .item-active{
+          background: #FFFBF5;
+          color: #F3A52F;
+          border: 1px solid #F3A52F;
+          box-shadow: 0px 6px 7px 1px #FFF7EB;
+        }
       }
-      .sub-nav {
+      .sub-nav{
         margin-top: 30px;
-        margin-bottom: 2px;
-        display: flex;
-        justify-content: left;
-        .sub-nav-item {
-          cursor: pointer;
-          color: #666666;
+        overflow-x: scroll;
+        &::-webkit-scrollbar{display:none;}
+        .sub-item{
+          flex-shrink: 0;
           margin-right: 30px;
-          transition: 0.3s;
-          &:last-child {
-            margin-right: 0;
-          }
-          &.active,
-          &:hover {
-            color: $active-color;
-          }
-        }
-      }
-    }
-    .container {
-      position: relative;
-      flex: 1;
-      padding: 30px;
-      overflow: hidden;
-      .report-item {
-        margin-top: 20px;
-        &:first-child {
-          margin-top: 0;
-        }
-        .item-title {
-          color: #333333;
-        }
-        .time-point-wrap {
-          margin-top: 20px;
-          .time-point-item {
-            position: relative;
-            margin: 35px 0 0 35px;
-            &:first-child {
-              margin-top: 20px;
-            }
-            &:last-child {
-              &::after {
-                height: calc(100% - 16px);
-              }
-            }
-            &::before {
-              position: absolute;
-              top: 5px;
-              left: -32px;
-              content: "";
-              width: 8px;
-              height: 8px;
-              border-radius: 50%;
-              background-color: $active-color;
-              box-shadow: 0 0 0 4px rgb(250, 219, 172);
-            }
-            &::after {
-              position: absolute;
-              top: 16px;
-              left: -28px;
-              content: "";
-              width: 1px;
-              height: calc(100% + 35px);
-              background-color: $active-color;
-            }
-            .point-time,
-            .point-content {
-              margin-bottom: 10px;
-              font-size: 14px;
-              color: #666666;
-              max-height: 50px;
-            }
-            .point-time {
-              &::before {
-                content: "";
-                display: inline-block;
-                margin-left: -20px;
-                margin-bottom: 4px;
-                width: 20px;
-                height: 1px;
-                background-color: $active-color;
-              }
-            }
-            .point-title {
-              color: #333333;
-              margin-bottom: 10px;
-            }
-            .point-tab {
-              display: inline-block;
-              font-size: 14px;
-              color: $active-color;
-              margin-top: 10px;
-              margin-right: 30px;
-              &:last-child {
-                margin-right: 0;
-              }
-            }
-            .point-see {
-              float: right;
-              cursor: pointer;
-              width: 88px;
-              height: 30px;
-              color: $active-color;
-              text-align: center;
-              line-height: 30px;
-              background: #fffbf5;
-              border: 1px solid $active-color;
-              border-radius: 15px;
-            }
-          }
-        }
-      }
-      .check-more-wrap {
-        position: absolute;
-        width: 100%;
-        left: 0;
-        bottom: 0;
-        background-color: white;
-        .check-more {
-          margin: auto;
+          font-size: 16px;
+          color: #666666;
           cursor: pointer;
-          width: 140px;
-          height: 40px;
-          box-sizing: border-box;
-          text-align: center;
-          line-height: 40px;
-          border-radius: 20px;
-          background-color: #fffbf5;
-          color: $active-color;
-          border: 1px solid $active-color;
+        }
+        .sub-active{
+          color: #F3A52F;
         }
       }
     }
+    
   }
 
   .report-aside {
@@ -440,9 +225,11 @@ $active-color: #f3a52f;
     box-sizing: border-box;
     padding: 30px;
     border-left: 2px solid #f2f2f2;
+
     .aside-title {
       font-size: 18px;
       color: #333333;
+
       &::before {
         content: "";
         display: inline-block;
@@ -452,22 +239,28 @@ $active-color: #f3a52f;
         margin-right: 10px;
       }
     }
+
     .infomation-wrap {
       margin-top: 20px;
       font-size: 14px;
+
       .infomation-item {
         margin-top: 20px;
         padding-bottom: 12px;
         border-bottom: 1px solid #f2f2f2;
         cursor: pointer;
+
         .item-title {
           color: #333333;
           margin-bottom: 10px;
         }
+
         .item-content {
           color: #666666;
         }
+
         &:hover {
+
           .item-title,
           .item-content {
             color: $active-color;
@@ -476,6 +269,7 @@ $active-color: #f3a52f;
         }
       }
     }
+
     .annoucement {
       margin-top: 20px;
       padding: 18px;
@@ -483,6 +277,7 @@ $active-color: #f3a52f;
       border: 1px solid black;
       border-radius: 5px;
       background: no-repeat center/cover url("../../assets/announce-pic.png");
+
       /*  background-image: url("../../assets/announce-pic.png");
         background-repeat: no-repeat;
         background-position: center;
@@ -491,12 +286,14 @@ $active-color: #f3a52f;
         color: #cfc09f;
         font-size: 18px;
       }
+
       .content {
         color: #cfc09f;
         line-height: 18px;
       }
     }
   }
+
   .back-top {
     position: fixed;
     z-index: 2000;
@@ -509,6 +306,7 @@ $active-color: #f3a52f;
     background-color: #ffffff;
     border: 2px solid #e6e6e6;
     box-shadow: 0px 0px 6px #e3e3e3;
+
     &::before {
       content: "";
       width: 0;
@@ -518,6 +316,7 @@ $active-color: #f3a52f;
       border-color: transparent transparent $active-color transparent;
     }
   }
+
   .search-main {
     .search-item {
       cursor: pointer;
@@ -528,47 +327,42 @@ $active-color: #f3a52f;
       border: 1px solid #e5e5e5;
       box-shadow: 3px 3px 12px rgba(184, 184, 184, 0.16);
       border-radius: 4px;
-      &:first-child{
+
+      &:first-child {
         margin-top: 0px;
       }
+
       .search-title {
         color: #333333;
         font-size: 18px;
       }
+
       .search-content {
         font-size: 14px;
         color: #666666;
         margin: 15px 0;
         max-height: 50px;
       }
+
       .search-label {
         display: inline-block;
         font-size: 14px;
         color: $active-color;
         margin-right: 30px;
+
         &:last-child {
           margin-right: 0;
         }
       }
-      .search-time{
+
+      .search-time {
         float: right;
         color: #999999;
       }
     }
-    :deep .el-empty__description{
-      p{
-        color: #333333;
-      }
-    }
-  }
 
-  .multy-ellipsis {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    display: -webkit-box;
-    -webkit-line-clamp: 3;
-    -webkit-box-orient: vertical;
   }
+
   .fade-enter-active,
   .fade-leave-active {
     transition: opacity 0.3s ease;
@@ -579,4 +373,4 @@ $active-color: #f3a52f;
     opacity: 0;
   }
 }
-</style>
+</style>