jwyu 2 years ago
parent
commit
9000773159

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "normalize.css": "^8.0.1",
     "vue": "^3.2.25",
     "vue-router": "^4.0.12",
+    "vuedraggable": "^4.1.0",
     "vuex": "^4.0.2"
   },
   "devDependencies": {

+ 45 - 0
src/api/chart.js

@@ -0,0 +1,45 @@
+/**
+ * 图库模块
+ */
+ import {get,post} from './http'
+
+/**
+ * 图库列表
+ * @param Keywords 搜索关键词 
+ * @param ClassifyId 图表类型ID 
+ * @param Page 
+ * @param Limit
+ * @returns 
+ */
+ export const apiChartList=params=>{
+    return get('/my_chart/getChartList',params)
+}
+
+/**
+ * 图库分类
+ * @param Keywords 搜索关键词 
+ */
+export const apiChartClassifyList=params=>{
+    return get('/my_chart/getChartChassify',params)
+}
+
+/**
+ * 图库移动排序
+ * @param MyChartId 
+ * @param MyChartClassifyId 
+ * @param PrevMyChartId 
+ * @param NextMyChartId 
+ */
+export const apiChartMove=params=>{
+    return post('/my_chart/moveMyChart',params)
+}
+
+/**
+ * 分类移动排序
+ * @param MyChartClassifyId
+ * @param PrevClassifyId
+ * @param NextClassifyId
+ */
+export const apiChartClassifyMove=params=>{
+    return post('/my_chart/moveMyChartClassify',params)
+}

BIN
src/assets/icon-filter.png


BIN
src/assets/icon-move.png


+ 12 - 6
src/components/Search.vue

@@ -1,5 +1,11 @@
 <script setup>
-import { computed, ref ,defineEmits} from "vue";
+import { computed, ref } from "vue";
+const props=defineProps({
+  placeholder:{
+    type:String,
+    default:'请输入关键词'
+  }
+})
 
 const emit = defineEmits(["search",'clean','blur'])
 let searchData = ref("");
@@ -33,7 +39,7 @@ const handleSearch = ()=>{
     <span v-show="!isFocus"></span>
     <input
       type="text"
-      placeholder="请输入标题/关键词"
+      :placeholder="props.placeholder"
       v-model="searchData"
       @blur="handleBlur"
       @keyup.enter="handleSearch"
@@ -50,12 +56,12 @@ const handleSearch = ()=>{
   display: flex;
   align-items: center;
   padding: 10px 20px;
-  position: absolute;
-  right: 160px;
+  // position: absolute;
+  // right: 160px;
   width: 300px;
   height: 40px;
-  top: 50%;
-  margin-top: -20px;
+  // top: 50%;
+  // margin-top: -20px;
   border-radius: 20px;
   background-color: #ebebeb;
   border: 1px solid #ebebeb;

+ 3 - 0
src/components/SelfList.vue

@@ -1,4 +1,7 @@
 <script setup>
+/**
+ * 公共列表组件
+ */
 const props=defineProps({
     loading:false,
     finished:false,//是否加载完

+ 2 - 1
src/layout/Index.vue

@@ -107,7 +107,8 @@ store.state.audioData.INS=globalAudioIns
 }
 .el-main {
   .page-container{
-    max-width: 820px;
+    min-width: 880px;
+    max-width: 1240px;
     margin: 0 auto;
   }
 }

+ 5 - 2
src/layout/component/Footer.vue

@@ -7,7 +7,7 @@
                 <div class="info-item">公司名称:弘则弥道(上海)投资咨询有限公司</div>
                 <div class="info-item">地址:上海市世纪大道210号 21世纪大厦12层1206室</div>
                 <div class="info-item">电话:86-21-61645300</div>
-                <div class="info-item">官网:http//www.hzinsights.com</div>
+                <a class="info-item" href="https://www.hzinsights.com" target="blank">官网:https://www.hzinsights.com</a>
                 <div class="info-item">邮箱:service@hzinsights.com</div>
             </div>
             <div class="right-con">
@@ -16,7 +16,7 @@
                 <div style="font-size:14px;color:#666">弘则研究:专注为全球投资<br/>者提供中立客观的研究服务</div>
             </div>
         </div>
-        <div class="copy-right-box">Copyright ©2020 弘则弥道(上海)投资咨询有限公司 沪ICP备15035458号-1</div>
+        <a class="copy-right-box" href="https://beian.miit.gov.cn/#/Integrated/index" target="blank">Copyright ©2020 弘则弥道(上海)投资咨询有限公司 沪ICP备15035458号-1</a>
     </div>
 </template>
 
@@ -51,6 +51,8 @@
                 font-weight: 300;
                 font-size: 14px;
                 margin-bottom: 6px;
+                display: block;
+                color: #333;
             }
         }
         .right-con{
@@ -71,6 +73,7 @@
         text-align: center;
         font-size: 14px;
         color: #666;
+        display: block;
     }
 }
 </style>

+ 6 - 0
src/layout/component/Header.vue

@@ -200,6 +200,8 @@ const goBack=()=>{
         <img @click="goBack" class="back-icon" src="@/assets/icon-back.png" alt="" v-if="$route.meta.hasBack">
         <span class="breadcrumb-item" v-for="item in $store.state.breadCrumbList" :key="item.path">{{item.name}}</span>
       </div>
+      <!-- 图库模块搜索与筛选 -->
+      <div id="chart-in-head"></div>
     </div>
   </div>
 </template>
@@ -262,6 +264,10 @@ const goBack=()=>{
         }
       }
     }
+    #chart-in-head{
+      float: right;
+      height: 100%;
+    }
     
   }
 }

+ 22 - 0
src/router/index.js

@@ -125,6 +125,28 @@ const routes=[
     ]
   },
 
+  // 图库模块
+  {
+    path:'/chart',
+    name:"Chart",
+    component: () => import("@/layout/Index.vue"),
+    meta:{
+      title:"ETA图库"
+    },
+    children:[
+      {
+        path:"list",
+        name:"ChartList",
+        component:()=>import('@/views/chart/List.vue'),
+        meta: {
+          title: "ETA图库",
+          keepAlive:true,
+          isRoot:true
+        }
+      }
+    ]
+  },
+
   {
     path: '/:pathMatch(.*)',
     name: 'error',

+ 9 - 0
src/style/global.scss

@@ -137,4 +137,13 @@ img{
     background-color: #F3A52F;
     color: #fff;
   }
+}
+
+// 两行省略
+.multi-ellipsis-l2{
+  display: -webkit-box;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
 }

+ 273 - 0
src/views/chart/List.vue

@@ -0,0 +1,273 @@
+<script setup>
+import { onMounted , reactive, ref , computed } from 'vue';
+import Search from '@/components/Search.vue'
+import SelfList from '@/components/SelfList.vue'
+import draggable from 'vuedraggable'
+import {apiChartList,apiChartClassifyList,apiChartMove,apiChartClassifyMove} from '@/api/chart.js'
+
+// 获取分类
+let chartMyClassifyList=ref([])//我的图库分类
+let chartPubClassifyList=ref([])//公共图库分类
+let selectChartClassifyId=ref('')//当前选中的分类id
+let curChartClassifyType=ref('')//当前选中的是公共图库\我的图库
+//获取图库分类
+const getChartClassifyList=async ()=>{
+    const res=await apiChartClassifyList()
+    if(res.code===200){
+        chartMyClassifyList.value=res.data.private_classify||[]
+        chartPubClassifyList.value=res.data.public_classify||[]
+        if(res.data.private_classify){
+            selectChartClassifyId.value=res.data.private_classify[0].myChartClassifyId
+            curChartClassifyType.value='我的图库'
+        }else{
+            selectChartClassifyId.value=res.data.public_classify[0].myChartClassifyId
+            curChartClassifyType.value='公共图库'
+        }
+        getChartList()
+    }
+}
+getChartClassifyList()
+const curChartClassifyList=computed(()=>{
+    if(curChartClassifyType.value==='我的图库'){
+        return chartMyClassifyList.value
+    }else{
+        return chartPubClassifyList.value
+    }
+})
+
+// 获取图表数据
+let chartList=reactive({
+    page:1,
+    pageSize:20,
+    list:[],
+    finished:false,
+    loading:false
+})
+const getChartList=async ()=>{
+    chartList.loading=true
+    const res=await apiChartList({
+        Page:chartList.page,
+        Limit:chartList.pageSize,
+        ClassifyId:selectChartClassifyId.value,
+        Keywords:''
+    })
+    chartList.loading=false
+    if(res.code===200){
+        if(res.data){
+            chartList.list=[...chartList.list,...res.data]
+            if(res.data.length<20){
+                chartList.finished=true
+            }
+        }else{
+            chartList.finished=true
+        }
+    }
+}
+
+// 加载更多图表
+const onLoad=()=>{
+    chartList.page++
+    getChartList()
+}
+
+// 点击分类
+const handleClickChartClassifyItem=(item)=>{
+    chartList.finished=false
+    chartList.list=[]
+    chartList.page=1
+    selectChartClassifyId.value=item.myChartClassifyId
+    getChartList()
+}
+
+let isMounted=ref(false)
+onMounted(()=>{
+    isMounted.value=true
+})
+</script>
+
+<template>
+    <!-- 图库放置在公共顶部的搜索和筛选 -->
+    <template v-if="isMounted&&$route.path=='/chart/list'">
+        <teleport to="#chart-in-head">
+            <div class="flex-col-center chart-search-filter-wrap">
+                <Search
+                    placeholder="图表名称搜索"
+                ></Search>
+                <el-popover 
+                    :width="400" 
+                    trigger="click"
+                    placement="bottom-end"
+                    popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;"
+                >
+                    <template #reference>
+                        <div class="filter-btn">筛选</div>
+                    </template>
+                    <template #default>
+                        <div class="filter-box">
+                            <!-- 内部员工才有 客户只有公共图库分类 -->
+                            <div class="top-type" v-if="$store.state.userInfo&&$store.state.userInfo.is_inner==1">
+                                <span 
+                                    :class="curChartClassifyType=='公共图库'&&'type-active'" 
+                                    @click="curChartClassifyType='公共图库'"
+                                >公共图库</span>
+                                <span
+                                    :class="curChartClassifyType=='我的图库'&&'type-active'" 
+                                    @click="curChartClassifyType='我的图库'"
+                                >我的图库</span>
+                            </div>
+                            <draggable 
+                                class="filter-list"
+                                v-model="curChartClassifyList" 
+                                item-key="myChartClassifyId"
+                                animation="300"
+                                :disabled="curChartClassifyType=='公共图库'"
+                            >
+                                <template #item="{element}">
+                                    <div 
+                                        :class="['item',selectChartClassifyId==element.myChartClassifyId&&'item-active']" 
+                                        @click="handleClickChartClassifyItem(element)"
+                                    >{{element.myChartClassifyName}}</div>
+                                </template>
+                            </draggable>
+                        </div>
+                    </template>
+                </el-popover>
+                
+            </div>
+        </teleport>
+    </template>
+    
+    <div class="chart-list-page">
+        <SelfList 
+            :finished="chartList.finished" 
+            :isEmpty="chartList.list.length===0&&chartList.finished"
+            :loading="chartList.loading"
+            @listOnload="onLoad"
+        >
+            <draggable 
+                class="flex list-wrap"
+                v-model="chartList.list" 
+                item-key="UniqueCode"
+                animation="300"
+                :disabled="false"
+            >
+                <template #item="{element}">
+                    <div class="chart-item">
+                        <el-tooltip
+                            effect="dark"
+                            placement="top-start"
+                        >
+                            <template #content>
+                                <div style="max-width: 250px;" v-html="element.ChartName"></div>
+                            </template>
+                            <div class="multi-ellipsis-l2 title" v-html="element.ChartName"></div>
+                        </el-tooltip>
+                        <el-image class="chart-img" :src="element.ChartImage" fit="cover" lazy />
+                    </div>
+                </template>
+                
+            </draggable>
+        </SelfList>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.chart-search-filter-wrap{
+    height: 100%;
+    .filter-btn{
+        cursor: pointer;
+        margin-left: 25px;
+        color: #F3A52F;
+        font-size: 16px;
+        &::before{
+            content: '';
+            display: inline-block;
+            width: 17px;
+            height: 13px;
+            background-image: url('@/assets/icon-filter.png');
+            background-size: cover;
+            vertical-align: middle;
+            margin-right: 3px;
+        }
+    }
+}
+.filter-box{
+    .top-type{
+        background-color: #fff;
+        padding-bottom: 12px;
+        span{
+            font-size: 16px;
+            color: #999;
+            display: inline-block;
+            margin-right: 40px;
+            cursor: pointer;
+            &:hover{
+                color: #F3A52F;
+            }
+        }    
+        .type-active{
+            color: #F3A52F;
+            font-weight: bold;
+            position: relative;
+            &::after{
+                content: '';
+                position: absolute;
+                left: 50%;
+                transform: translateX(-50%);
+                top: 105%;
+                width: 40px;
+                height: 4px;
+                background: #F3A52F;
+                border-radius: 37px;
+            }
+        }
+    }
+    .filter-list{
+        height: 300px;
+        overflow-y: auto;
+        &::-webkit-scrollbar{
+            display: none;
+        }
+        .item{
+            padding: 10px 0;
+            font-size: 16px;
+            border-bottom: 1px solid #F2F2F2;
+            cursor: pointer;
+        }
+        .item-active{
+            color: #F3A52F;
+        }
+    }
+}
+.chart-list-page{
+    .list-wrap{
+        flex-wrap: wrap;
+    }
+    .chart-item{
+        flex-shrink: 0;
+        width: 270px;
+        height: 300px;
+        background: #FFFFFF;
+        box-shadow: 0px 4px 12px 1px rgba(0, 0, 0, 0.08);
+        border-radius: 8px;
+        border: 1px solid #F2F2F2;
+        margin: 0 10px 20px 10px;
+        position: relative;
+        padding: 20px;
+        &:hover{
+            border-color: #F3A52F;
+        }
+        .title{
+            font-size: 16px;
+        }
+        .chart-img{
+            position: absolute;
+            left: 20px;
+            width: calc(100% - 40px);
+            bottom: 20px;
+            height:215px;
+            object-fit: cover;
+        }
+    }
+}
+</style>

+ 2 - 2
src/views/report/List.vue

@@ -229,14 +229,14 @@ onMounted(async () => {
       <div class="back-top" v-show="showBackTop" @click="backToTop"></div>
     </transition>
   </div>
-  <template v-if="mounted">
+  <!-- <template v-if="mounted">
     <teleport to=".head-main">
       <Search
         @search="handleSearch"
         @clean="changePageStyle('normal')"
       ></Search>
     </teleport>
-  </template>
+  </template> -->
 </template>