Pārlūkot izejas kodu

共享表格列表、详情、筛选搜索

chenlei 6 mēneši atpakaļ
vecāks
revīzija
59dd2cffc6

+ 18 - 1
src/api/sheet.js

@@ -39,5 +39,22 @@ export default {
     // 平衡表中图表删除
     balanceSheetChartDel(params){
         return post('/datamanage/excel_info/balance/chart_del',params)
-    }
+    },
+
+    /**
+     * 表格分类列表
+     * @param Source 表格类型
+     * @param IsShowMe 是否只显示我创建的
+     */
+       excelClassifyList(params){
+        return get('/datamanage/excel_classify/list',params)
+    },
+
+    /**
+     * 表格详情
+     * @param ExcelInfoId 表格ID
+     */
+    excelDetail(params){
+        return get('/datamanage/excel_info/detail',params)
+    },
 }

+ 16 - 0
src/lang/cn.js

@@ -4,4 +4,20 @@ export default {
     home: '首页',
     my: '我的',
   },
+  // 表格tabbar
+  tableTabbar: {
+    shared_table: '共享表格',
+    timeline_table: '时间序列表格',
+    mixed_table: '混合表格',
+    balance_sheet: '平衡表',
+  },
+  // 表格
+  shared_table: {
+    enter_table_name: '请输入表格名称',
+    tables_total: '共{totalNum}张表格',
+    just_look_mine: '只看我的',
+    no_table: '暂无表格',
+    no_more: '没有更多了',
+    choose_category: '选择分类',
+  },
 }

+ 16 - 0
src/lang/en.js

@@ -3,4 +3,20 @@ export default {
     home: 'home',
     my: 'my',
   },
+   // 表格tabbar
+   tableTabbar: {
+    shared_table: 'Shared table',
+    timeline_table: 'Timeline table',
+    mixed_table: 'Mixed Table',
+    balance_sheet: 'Balance Sheet',
+  },
+  // 表格
+  shared_table: {
+    enter_table_name: 'Please enter the table name',
+    tables_total: '{totalNum} tables in total',
+    just_look_mine: 'Just look at mine',
+    no_table: 'No table available',
+    no_more: 'No more',
+    choose_category: 'Choose a category',
+  },
 }

+ 5 - 2
src/router/index.js

@@ -20,6 +20,7 @@ import {reportRoutes} from './report'
 import {reportEnRoutes} from './reportEn'
 import {chartETARoutes} from './chartETA'
 import {dataEDBRoutes} from './dataEDB'
+import {sheetListRoutes} from './sheetList'
 import { storeToRefs } from "pinia";
 
 const routes = [
@@ -69,10 +70,12 @@ const routes = [
 			...reportRoutes,
 			// 英文研报模块
 			...reportEnRoutes,
-            //ETA图库模块
-            ...chartETARoutes,
+			//ETA图库模块
+			...chartETARoutes,
 			//ETA指标库模块
 			...dataEDBRoutes,
+			//表格模块
+			...sheetListRoutes
 		]
 	},
 	

+ 50 - 0
src/router/sheetList.js

@@ -0,0 +1,50 @@
+// ETA指标库模块
+export const sheetListRoutes=[
+    {
+        path:"/sheetList/index",
+        name:"sheetListIndex",
+        redirect: "/shared/list",
+        component: () => import("@/views/sheetList/index.vue"),
+        children: [
+            {
+                path: "/shared/list",
+                name: "sharedList",
+                component: () => import("@/views/sheetList/sharedList.vue"),
+                meta: { title: "共享表格",noBack:true },
+            },
+            {
+                path: "/shared/search",
+                name: "sharedSearch",
+                component: () => import("@/views/sheetList/sharedSearch.vue"),
+                meta: { title: "共享表格",noBack:true },
+            },
+            {
+                path: "/shared/detail",
+                name: "sharedDetail",
+                component: () => import("@/views/sheetList/sharedDetail.vue"),
+                meta: { title: "共享表格",noBack:true },
+            },
+            {
+                path: "/timeline/list",
+                name: "timelineList",
+                component: () => import("@/views/sheetList/timelineList.vue"),
+                meta: { title: "时间排序表格",noBack:true },
+            },
+            {
+                path: "/mixed/list",
+                name: "mixedList",
+                component: () => import("@/views/sheetList/mixedList.vue"),
+                meta: { title: "混合表格",noBack:true },
+            },
+            {
+                path: "/balance/list",
+                name: "balanceList",
+                component: () => import("@/views/sheetList/balanceList.vue"),
+                meta: { title: "平衡表",noBack:true },
+            },
+        ],
+        meta: { 
+            title: "ETA表格",
+        },
+    },
+]

+ 127 - 0
src/views/sheetList/Index.vue

@@ -0,0 +1,127 @@
+<script setup>
+import {getStaticImg} from '@/hooks/common.js'
+import { useRouter } from 'vue-router'
+import {getCurrentInstance, computed} from 'vue'
+const { appContext : { config: { globalProperties } } } = getCurrentInstance();
+
+const router=useRouter()
+
+const tabbarList = computed(() => {
+    return [
+        {
+            name:"shared",
+            icon:getStaticImg('tabbar/home.png'),
+            iconActive:getStaticImg('tabbar/home-s.png'),
+            text: globalProperties.$t('tableTabbar.shared_table'),
+            path:"/shared/list"
+        },
+        {
+            name:"timeline",
+            icon:getStaticImg('tabbar/user.png'),
+            iconActive:getStaticImg('tabbar/user-s.png'),
+            text:globalProperties.$t('tableTabbar.timeline_table'),
+            path:"/timeline/list"
+        },
+        {
+            name:"mixed",
+            icon:getStaticImg('tabbar/home.png'),
+            iconActive:getStaticImg('tabbar/home-s.png'),
+            text: globalProperties.$t('tableTabbar.mixed_table'),
+            path:"/mixed/list"
+        },
+        {
+            name:"balance",
+            icon:getStaticImg('tabbar/user.png'),
+            iconActive:getStaticImg('tabbar/user-s.png'),
+            text:globalProperties.$t('tableTabbar.balance_sheet'),
+            path:"/balance/list"
+        }
+    ]
+})
+
+function goPage(item){
+    router.replace(item.path)
+}
+
+</script>
+
+<template>
+    <div class="tabbar-page">
+        <router-view></router-view>
+        <div class="tabbar-box">
+            <div 
+                :class="['tabbar-item',$route.path==item.path?'tabbar-item_active':'']"
+                v-for="item in tabbarList"
+                :key="item.name"
+                @click="goPage(item)"
+            >   
+                <div class="tabbar-item-con">
+                    <img class="icon" :src="$route.path==item.path?item.iconActive:item.icon" />
+                    <div class="text">{{item.text}}</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.tabbar-box{
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 99;
+    background: #FFFFFF;
+    box-shadow: 0px -1px 12px rgba(0, 0, 0, 0.08);
+    height: 112px;
+    display: flex;
+    align-items: center;
+    .tabbar-item{
+        flex: 1;
+        padding: 16px;
+        height: 100%;
+        position: relative;
+        &::after{
+            content: '';
+            width: 1px;
+            height: calc(100% - 32px);
+            background-color: $border-color;
+            position: absolute;
+            top: 16px;
+            right: 0;
+        }
+        .tabbar-item-con{
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            height: 100%;
+            .icon{
+                width: 48px;
+                height: 48px;
+            }
+            .text{
+                font-size: 20px;
+                margin-top: 5px;
+            }
+        }
+        &:last-child::after{
+            display: none;
+        }
+    }
+    .tabbar-item_active{
+        .tabbar-item-con{
+            background-color: #F2F3FF;
+            border-radius: 112px;
+            // .text{
+            //     color: $theme-color;
+            // }
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .tabbar-box{
+        display: none;
+    }
+}
+</style>

+ 433 - 0
src/views/sheetList/balanceList.vue

@@ -0,0 +1,433 @@
+<script setup name="SheetETAList">
+import apiSheetChart from '@/api/sheet'
+import {ref,reactive,watch,computed} from 'vue'
+import { useRouter } from "vue-router";
+import useLocaleStore from "@/store/modules/i18n";
+import CatalogTree from './components/CatalogTree.vue';
+import CatalogItem from './components/CatalogItem.vue';
+//激活的目录路径
+const catalogMenu = ref('')
+const router = useRouter()
+//表格列表
+const listState = reactive({
+    cid:0,
+    list:[],
+    page:1,
+    pageSize:15,
+    finished:false,
+    loading:false,
+    total:0,
+    IsShowMe:false
+})
+//是否展示目录列表
+const IsShowCatalog = ref(false)
+const localeStore = useLocaleStore()
+const temp = localeStore.locale === 'zhCn' ? 'zhCn' : 'en'; //根据当前i18n语言设置表格默认语言
+localeStore.SET_LOCALE(temp)
+
+watch(()=>listState.IsShowMe,()=>{
+    window.scrollTo({top:0})
+    listState.list=[]
+    listState.page=1
+    //设置数据已加载完毕,因为当滚动条不在顶部时,清空列表内容会触发onLoad
+    listState.finished = true 
+    //这个函数调用完成后,会把finished重置成正确的值
+    getSheetList()
+})
+
+getSheetList()
+//获取表格列表
+async function getSheetList(){
+    const {pageSize,cid,page,IsShowMe} = listState
+    const res = await apiSheetChart.sheetList({
+        PageSize: pageSize,
+        CurrentIndex: page,
+        Source: 5,
+        ExcelClassifyId: cid,
+        IsShowMe,
+    })
+    if(res.Ret!==200) return 
+    const arr = res.Data?res.Data.List:[]
+    listState.list = [...listState.list,...arr]
+    listState.total = res.Data?res.Data.Paging.Totals:0
+    listState.finished = res.Data?res.Data.Paging.IsEnd:true
+    listState.loading=false
+}
+
+//目录被点击 type:['top'一级目录,'node'二级目录,'item'三级目录]
+function catalogItemClick({item,type='node',parent={}}){
+    console.log(item);
+    console.log(type);
+    console.log(parent);
+    
+    const topMenu = type==='top'?item.ExcelClassifyName:type==='node'?item.parentName:parent.parentName
+    const nodeMenu = type==='node'?item.ExcelClassifyName:type==='item'?parent.ExcelClassifyName:''
+    const itemMenu = type==='item'?item.ExcelClassifyName:''
+
+    catalogMenu.value = `${topMenu}${nodeMenu.length?`/${nodeMenu}`:''}${itemMenu.length?`/${itemMenu}`:''}`
+    console.log();
+    
+    listState.cid = item.ExcelClassifyId
+    listState.list=[]
+    listState.page=1
+    getSheetList()
+}
+
+//展示目录列表
+function showCatalog(){
+    IsShowCatalog.value = true
+}
+
+//下拉加载
+function onLoad(){
+    if(IsShowCatalog.value) return
+    listState.page++
+    getSheetList()
+}
+
+//展开的目录
+const activeCatalogs = ref([])
+
+//目录列表
+const catalogNodes = ref([])
+const dataNodes = ref([])
+getCatalogList()
+//获取目录列表
+async function getCatalogList(){
+    const {IsShowMe} = listState
+    const res = await apiSheetChart.excelClassifyList({
+        Source: 5,
+        IsShowMe: IsShowMe
+    })
+    if(res.Ret!==200) return 
+    console.log(res);
+    dataNodes.value = res.Data?res.Data.AllNodes:[]||[]
+    catalogNodes.value = dataNodes.value.map(node=>{
+        if(node.Children){
+            node.Children = node.Children.map(child=>{
+                child.parentName = node.ExcelClassifyName //添加子分类时需要显示父级分类名称
+                if(child.Children){//改成三级目录了
+                    child.Children = child.Children.map(_child=>{
+                        _child.parentName = child.ExcelClassifyName
+                        return _child
+                    })
+                }
+                return child
+            })
+        }
+        return node
+    })
+}
+
+function showFileOpt(item){
+    console.log(item);
+}
+//跳转至图表详情页
+const goSheetDetail = (item)=>{
+    router.push({
+        path:'/shared/detail',
+        query:{
+            id:item.ExcelInfoId,
+        }
+    })
+}
+</script>
+
+<template>
+  <div class="excel-eta-list-wrap">
+    <div class="select-wrap">
+      <div class="search-box">
+        <van-search 
+          shape="round" 
+          readonly 
+          :placeholder="$t('shared_table.enter_table_name')"
+          style="flex:1;padding-left:0"
+          @click-input="$router.push('/shared/search')"
+        />
+        <div class="list-icon icon" @click="showCatalog">
+          <img src="@/assets/imgs/chartETA/list-icon.png" alt="">
+        </div>
+      </div>
+      <p style="font-weight: bold;word-break: break-all;margin-bottom: 5px;">{{ catalogMenu }}</p>
+      <div class="select-box">
+        <span>{{ $t('shared_table.tables_total', {totalNum: listState.total}) }}</span>
+        <span> <van-checkbox v-model="listState.IsShowMe">{{ $t('shared_table.just_look_mine') }}</van-checkbox></span>
+      </div>
+    </div>
+    <div class="excel-list-wrap">
+      <van-list
+          v-model:loading="listState.loading"
+          :finished="listState.finished"
+          :finished-text="listState.list.length > 0 ? $t('shared_table.no_more') : $t('shared_table.no_table')"
+          :immediate-check="false"
+          @load="onLoad"
+      >
+          <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+          <ul class="excel-list">
+              <li 
+                  class="excel-list-item" 
+                  v-for="item in listState.list" 
+                  :key="item.ChartInfoId"
+                  @click="goSheetDetail(item)"
+              >
+                  <div class="title">{{item.ExcelName}}</div>
+                  <img class="img" :src="item.ExcelImage" alt="">   
+                  <div class="time">
+                      <span>{{item.CreateTime.slice(0,10)}}</span>
+                  </div>
+              </li>
+          </ul>
+      </van-list>
+    </div>
+     <!-- 目录列表 -->
+     <van-popup v-model:show="IsShowCatalog" position="right" class="catalog-list-wrap" style="height:100%">
+        <div class="catalog-list">
+            <div class="top sticky-part">
+                <h3>{{ $t('shared_table.choose_category') }}</h3>
+                <van-icon name="cross" @click.stop="IsShowCatalog=false"/>
+            </div>
+            <!-- 将目录改为三级 -->
+            <div class="list-box catalog-tree-wrap">
+                <van-collapse v-model="activeCatalogs" :border="false">
+                    <van-collapse-item 
+                        v-for="catalog in catalogNodes" :key="catalog.UniqueCode" :name="catalog.UniqueCode"
+                        @click.stop="catalogItemClick({item:catalog,type:'top'})">
+                        <template #title>
+                            <CatalogItem
+                                :node="catalog" 
+                                @showPopup="showFileOpt"/>
+                        </template>
+                        <CatalogTree 
+                            :catalog-nodes="catalog.Children"
+                            :showFileOpt="showFileOpt"
+                            :activeId="listState.cid"
+                            @handleCatalogItemClick="catalogItemClick"
+                        />
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+        </div>
+    </van-popup>
+  </div>
+</template>
+<style lang="scss">
+.excel-eta-list-wrap{
+    .catalog-list-wrap{
+        width: 65%;
+    }
+    .rename-wrap{
+        padding:48px;
+        input{
+            padding: 24px 32px;
+            border-radius: 12px;
+            background-color: #F6F6F6;
+            width: 100%;
+        }
+        .label{
+            color: #666666;
+            margin-bottom: 32px;
+            text-align: center;
+        }
+    }
+    @media screen and (min-width:$media-width){
+        .catalog-list-wrap{
+            width: 30%;
+        }
+        .move-popup{
+            width:375px;
+        }
+        .rename-wrap{
+            padding:24px;
+            input{
+                padding: 12px 16px;
+                border-radius: 6px;
+                background-color: #F6F6F6;
+                width: 100%;
+            }
+            .label{
+                margin-bottom: 16px;
+            }
+        }
+    }
+}
+</style>
+<style scoped lang="scss">
+.excel-eta-list-wrap{
+  .select-wrap{
+      padding: 30px;
+      position: sticky;
+      top:0;
+      background-color: #fff;
+      .search-box{
+          display: flex;
+          align-items: center;
+          .icon{
+              margin-left: 10px;
+              width: 70px;
+              height:70px;
+              background-color: #F2F3FF;
+              border-radius: 50%;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              img{
+                  width:45px;
+                  height:45px;
+              }
+          }
+      }
+      .select-box{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+      }
+  }
+  .excel-list-wrap{
+      //margin-top:15px;
+      padding: 0 30px; 
+      padding-bottom: 30px;
+      .excel-list{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+          gap: 30px 0;
+          .excel-list-item{
+              box-sizing: border-box;
+              width: 330px;
+              padding: 10px 14px;
+              border: 1px solid $border-color;
+              border-radius: 12px;
+              .title{
+                  min-height: 70px;
+                  overflow: hidden;
+                  -webkit-line-clamp: 2;
+                  text-overflow: ellipsis;
+                  display:-webkit-box !important;
+                  -webkit-box-orient:vertical;
+                  word-break: break-word;
+              }
+              .img{
+                      width: 100%;
+                      height: 220px;
+                      display: block;
+                      margin: 10px 0;
+                  }
+              .time{
+                  display: flex;
+                  justify-content: space-between;
+                  font-size: 28px;
+                  color: $font-grey_999;
+                  .tool-icon{
+                      width:30px;
+                      text-align: right;
+                      img{
+                          width:5px;
+                      }
+                  }
+              }
+              
+          }
+      }
+  }
+  .catalog-list{
+        box-sizing: border-box;
+        height: 100%;
+        .sticky-part{
+            position:sticky;
+            background-color: white;
+            z-index: 99;
+            left:0;
+            right:0;
+        }
+        .top{
+            display: flex;
+            justify-content: space-between;
+            border-bottom: 1px solid #DCDFE6;
+            padding: 0 15px;
+            align-items: center;
+            top:0;
+        }
+        .bottom{
+            display: flex;
+            padding:48px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:16px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  @media screen and (min-width:$media-width){
+    .select-wrap{
+        top:60px;
+        padding:30px;
+        .search-box{
+            .icon{
+                margin-left: 10px;
+                width: 40px;
+                height:40px;
+                background-color: #F2F3FF;
+                border-radius: 50%;
+                img{
+                    width:25px;
+                    height:25px;
+                }
+            }
+        }
+        .select-box{
+            margin-top:20px;
+        }
+    }
+    .excel-list-wrap{
+        padding:0 30px;
+        .excel-list{
+            gap: 20px 4%;
+            justify-content:flex-start;
+            .excel-list-item{
+                box-sizing: border-box;
+                width: 22%;
+                padding: 10px 14px;
+                border: 1px solid $border-color;
+                border-radius: 6px;
+                .title{
+                    min-height: 36px;
+                }
+                .img{
+                    width: 100%;
+                    height: auto;
+                    display: block;
+                    margin: 10px 0;
+                }
+                .time{
+                    font-size: 14px;
+                    .tool-icon>img{
+                        width:3px;
+                    }
+                }
+            }
+        }
+    }
+    .catalog-list{
+        .bottom{
+            display: flex;
+            padding:24px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:8px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  }
+}
+</style>

+ 92 - 0
src/views/sheetList/components/CatalogItem.vue

@@ -0,0 +1,92 @@
+<script setup>
+import {ref} from 'vue'
+const props = defineProps({
+    showFileImg:{
+        type:Boolean,
+        default:true
+    },
+    node:{
+        type:Object,
+        default:{}
+    },
+    activeId:{
+        type:Number,
+        default:0
+    }
+})
+
+const emits=defineEmits(['showFileOptClick','showPopup'])
+function showPopup(){
+    emits('showPopup',{node:props.node,optArr:props.optArr})
+}
+</script>
+
+<template>
+    <div class="catalog-item" :class="{'leaf-padding':!showFileImg}">
+        <span class="van-ellipsis" :class="{'leaf-padding':!showFileImg,'choosed':activeId===node.ExcelClassifyId}">{{node.ExcelClassifyName||''}}</span>
+        <!-- <div @click.stop="showPopup">
+            <div class="menu-icon"  v-if="node.HaveOperaAuth">
+                <img class="icon" src="@/assets/imgs/ppt/ppt_icon_menu.png" alt="">
+            </div>
+        </div> -->
+    </div>
+</template>
+
+<style scoped lang="scss">
+.catalog-item{
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    overflow: hidden;
+    &.leaf-padding{
+        padding: var(--van-cell-vertical-padding) 0;
+    }
+    span{
+        flex: 1;
+        text-align: left;
+        box-sizing: border-box;
+        padding: 0 15px;
+        font-size: 30px;
+        &.leaf-padding{
+            padding:0 60px;
+            //color:#969799;
+            color: #323233;
+        }
+        &.choosed{
+            color:#969799;
+        }
+    }
+    img{
+        display: inline-block;
+        width: 48px;
+        height: auto;
+        &.icon{
+            width: 6px;
+            margin-right: 0;
+        }
+    }
+    .menu-icon{
+        width: 30px;
+        text-align: center;
+        img{
+            transform: rotate(90deg);
+            transform-origin: left;
+        }
+        
+    }
+    @media screen and (min-width:$media-width){
+        span{
+            font-size: 16px;
+            &.leaf-padding{
+                padding:0 60px;
+            }
+        }
+        img{
+            width: 32px;
+            &.icon{
+                width:4px;
+            }
+        }
+    }
+}
+</style>

+ 78 - 0
src/views/sheetList/components/CatalogTree.vue

@@ -0,0 +1,78 @@
+<script setup>
+import {ref} from 'vue'
+// import {useCatalogList} from '../hooks/useCatalogList'
+import CatalogItem from './CatalogItem.vue';
+const props = defineProps({
+    catalogNodes:{
+        type:Array,
+        default:[]
+    },
+    activeId:{
+        type:Number,
+        default:0
+    },
+    showFileOpt:Function
+})
+const emits=defineEmits(['handleCatalogItemClick'])
+//展开的目录
+const activeCatalogs = ref([])
+//目录操作栏
+// const {optArrNode,optArrItem,authOptArr} = useCatalogList()
+//点击目录
+function handleCatalogItemClick(item,type,node){
+    emits('handleCatalogItemClick',{item,type,parent:node})
+}
+</script>
+
+<template>
+    <div class="catalog-tree-wrap">
+        <van-collapse v-model="activeCatalogs" :border="false">
+            <van-collapse-item 
+                v-for="node in catalogNodes"
+                :key="node.UniqueCode"
+                :name="node.UniqueCode"
+                :is-link="true"
+                @click.stop="handleCatalogItemClick(node)"
+            >
+            <template #title>
+                <CatalogItem 
+                    :node="node" 
+                    @showPopup="showFileOpt"/>
+            </template>
+            <div 
+                class="list-item"
+                v-for="item in node.Children" 
+                :key="item.UniqueCode"
+                @click.stop="handleCatalogItemClick(item,'item',node)"
+            >
+                <CatalogItem 
+                    :node="item" 
+                    :showFileImg="false" 
+                    :activeId="activeId"
+                    @showPopup="showFileOpt"/>
+            </div>
+            </van-collapse-item>
+        </van-collapse>
+    </div>
+</template>
+
+<style lang="scss">
+.catalog-tree-wrap{
+    .van-collapse{
+        .van-collapse-item{
+            >.van-cell{
+                // flex-direction: row-reverse;
+                .van-cell__title{
+                    overflow: hidden;
+                }
+            }
+            .van-collapse-item__wrapper{
+                .van-collapse-item__content{
+                    padding-top: 0;
+                    padding-bottom: 0;
+                }
+            }
+        }
+    }
+}
+</style>

+ 433 - 0
src/views/sheetList/mixedList.vue

@@ -0,0 +1,433 @@
+<script setup name="SheetETAList">
+import apiSheetChart from '@/api/sheet'
+import {ref,reactive,watch,computed} from 'vue'
+import { useRouter } from "vue-router";
+import useLocaleStore from "@/store/modules/i18n";
+import CatalogTree from './components/CatalogTree.vue';
+import CatalogItem from './components/CatalogItem.vue';
+//激活的目录路径
+const catalogMenu = ref('')
+const router = useRouter()
+//表格列表
+const listState = reactive({
+    cid:0,
+    list:[],
+    page:1,
+    pageSize:15,
+    finished:false,
+    loading:false,
+    total:0,
+    IsShowMe:false
+})
+//是否展示目录列表
+const IsShowCatalog = ref(false)
+const localeStore = useLocaleStore()
+const temp = localeStore.locale === 'zhCn' ? 'zhCn' : 'en'; //根据当前i18n语言设置表格默认语言
+localeStore.SET_LOCALE(temp)
+
+watch(()=>listState.IsShowMe,()=>{
+    window.scrollTo({top:0})
+    listState.list=[]
+    listState.page=1
+    //设置数据已加载完毕,因为当滚动条不在顶部时,清空列表内容会触发onLoad
+    listState.finished = true 
+    //这个函数调用完成后,会把finished重置成正确的值
+    getSheetList()
+})
+
+getSheetList()
+//获取表格列表
+async function getSheetList(){
+    const {pageSize,cid,page,IsShowMe} = listState
+    const res = await apiSheetChart.sheetList({
+        PageSize: pageSize,
+        CurrentIndex: page,
+        Source: 3,
+        ExcelClassifyId: cid,
+        IsShowMe,
+    })
+    if(res.Ret!==200) return 
+    const arr = res.Data?res.Data.List:[]
+    listState.list = [...listState.list,...arr]
+    listState.total = res.Data?res.Data.Paging.Totals:0
+    listState.finished = res.Data?res.Data.Paging.IsEnd:true
+    listState.loading=false
+}
+
+//目录被点击 type:['top'一级目录,'node'二级目录,'item'三级目录]
+function catalogItemClick({item,type='node',parent={}}){
+    console.log(item);
+    console.log(type);
+    console.log(parent);
+    
+    const topMenu = type==='top'?item.ExcelClassifyName:type==='node'?item.parentName:parent.parentName
+    const nodeMenu = type==='node'?item.ExcelClassifyName:type==='item'?parent.ExcelClassifyName:''
+    const itemMenu = type==='item'?item.ExcelClassifyName:''
+
+    catalogMenu.value = `${topMenu}${nodeMenu.length?`/${nodeMenu}`:''}${itemMenu.length?`/${itemMenu}`:''}`
+    console.log();
+    
+    listState.cid = item.ExcelClassifyId
+    listState.list=[]
+    listState.page=1
+    getSheetList()
+}
+
+//展示目录列表
+function showCatalog(){
+    IsShowCatalog.value = true
+}
+
+//下拉加载
+function onLoad(){
+    if(IsShowCatalog.value) return
+    listState.page++
+    getSheetList()
+}
+
+//展开的目录
+const activeCatalogs = ref([])
+
+//目录列表
+const catalogNodes = ref([])
+const dataNodes = ref([])
+getCatalogList()
+//获取目录列表
+async function getCatalogList(){
+    const {IsShowMe} = listState
+    const res = await apiSheetChart.excelClassifyList({
+        Source: 3,
+        IsShowMe: IsShowMe
+    })
+    if(res.Ret!==200) return 
+    console.log(res);
+    dataNodes.value = res.Data?res.Data.AllNodes:[]||[]
+    catalogNodes.value = dataNodes.value.map(node=>{
+        if(node.Children){
+            node.Children = node.Children.map(child=>{
+                child.parentName = node.ExcelClassifyName //添加子分类时需要显示父级分类名称
+                if(child.Children){//改成三级目录了
+                    child.Children = child.Children.map(_child=>{
+                        _child.parentName = child.ExcelClassifyName
+                        return _child
+                    })
+                }
+                return child
+            })
+        }
+        return node
+    })
+}
+
+function showFileOpt(item){
+    console.log(item);
+}
+//跳转至图表详情页
+const goSheetDetail = (item)=>{
+    router.push({
+        path:'/shared/detail',
+        query:{
+            id:item.ExcelInfoId,
+        }
+    })
+}
+</script>
+
+<template>
+  <div class="excel-eta-list-wrap">
+    <div class="select-wrap">
+      <div class="search-box">
+        <van-search 
+          shape="round" 
+          readonly 
+          :placeholder="$t('shared_table.enter_table_name')"
+          style="flex:1;padding-left:0"
+          @click-input="$router.push('/shared/search')"
+        />
+        <div class="list-icon icon" @click="showCatalog">
+          <img src="@/assets/imgs/chartETA/list-icon.png" alt="">
+        </div>
+      </div>
+      <p style="font-weight: bold;word-break: break-all;margin-bottom: 5px;">{{ catalogMenu }}</p>
+      <div class="select-box">
+        <span>{{ $t('shared_table.tables_total', {totalNum: listState.total}) }}</span>
+        <span> <van-checkbox v-model="listState.IsShowMe">{{ $t('shared_table.just_look_mine') }}</van-checkbox></span>
+      </div>
+    </div>
+    <div class="excel-list-wrap">
+      <van-list
+          v-model:loading="listState.loading"
+          :finished="listState.finished"
+          :finished-text="listState.list.length > 0 ? $t('shared_table.no_more') : $t('shared_table.no_table')"
+          :immediate-check="false"
+          @load="onLoad"
+      >
+          <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+          <ul class="excel-list">
+              <li 
+                  class="excel-list-item" 
+                  v-for="item in listState.list" 
+                  :key="item.ChartInfoId"
+                  @click="goSheetDetail(item)"
+              >
+                  <div class="title">{{item.ExcelName}}</div>
+                  <img class="img" :src="item.ExcelImage" alt="">   
+                  <div class="time">
+                      <span>{{item.CreateTime.slice(0,10)}}</span>
+                  </div>
+              </li>
+          </ul>
+      </van-list>
+    </div>
+     <!-- 目录列表 -->
+     <van-popup v-model:show="IsShowCatalog" position="right" class="catalog-list-wrap" style="height:100%">
+        <div class="catalog-list">
+            <div class="top sticky-part">
+                <h3>{{ $t('shared_table.choose_category') }}</h3>
+                <van-icon name="cross" @click.stop="IsShowCatalog=false"/>
+            </div>
+            <!-- 将目录改为三级 -->
+            <div class="list-box catalog-tree-wrap">
+                <van-collapse v-model="activeCatalogs" :border="false">
+                    <van-collapse-item 
+                        v-for="catalog in catalogNodes" :key="catalog.UniqueCode" :name="catalog.UniqueCode"
+                        @click.stop="catalogItemClick({item:catalog,type:'top'})">
+                        <template #title>
+                            <CatalogItem
+                                :node="catalog" 
+                                @showPopup="showFileOpt"/>
+                        </template>
+                        <CatalogTree 
+                            :catalog-nodes="catalog.Children"
+                            :showFileOpt="showFileOpt"
+                            :activeId="listState.cid"
+                            @handleCatalogItemClick="catalogItemClick"
+                        />
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+        </div>
+    </van-popup>
+  </div>
+</template>
+<style lang="scss">
+.excel-eta-list-wrap{
+    .catalog-list-wrap{
+        width: 65%;
+    }
+    .rename-wrap{
+        padding:48px;
+        input{
+            padding: 24px 32px;
+            border-radius: 12px;
+            background-color: #F6F6F6;
+            width: 100%;
+        }
+        .label{
+            color: #666666;
+            margin-bottom: 32px;
+            text-align: center;
+        }
+    }
+    @media screen and (min-width:$media-width){
+        .catalog-list-wrap{
+            width: 30%;
+        }
+        .move-popup{
+            width:375px;
+        }
+        .rename-wrap{
+            padding:24px;
+            input{
+                padding: 12px 16px;
+                border-radius: 6px;
+                background-color: #F6F6F6;
+                width: 100%;
+            }
+            .label{
+                margin-bottom: 16px;
+            }
+        }
+    }
+}
+</style>
+<style scoped lang="scss">
+.excel-eta-list-wrap{
+  .select-wrap{
+      padding: 30px;
+      position: sticky;
+      top:0;
+      background-color: #fff;
+      .search-box{
+          display: flex;
+          align-items: center;
+          .icon{
+              margin-left: 10px;
+              width: 70px;
+              height:70px;
+              background-color: #F2F3FF;
+              border-radius: 50%;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              img{
+                  width:45px;
+                  height:45px;
+              }
+          }
+      }
+      .select-box{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+      }
+  }
+  .excel-list-wrap{
+      //margin-top:15px;
+      padding: 0 30px; 
+      padding-bottom: 30px;
+      .excel-list{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+          gap: 30px 0;
+          .excel-list-item{
+              box-sizing: border-box;
+              width: 330px;
+              padding: 10px 14px;
+              border: 1px solid $border-color;
+              border-radius: 12px;
+              .title{
+                  min-height: 70px;
+                  overflow: hidden;
+                  -webkit-line-clamp: 2;
+                  text-overflow: ellipsis;
+                  display:-webkit-box !important;
+                  -webkit-box-orient:vertical;
+                  word-break: break-word;
+              }
+              .img{
+                      width: 100%;
+                      height: 220px;
+                      display: block;
+                      margin: 10px 0;
+                  }
+              .time{
+                  display: flex;
+                  justify-content: space-between;
+                  font-size: 28px;
+                  color: $font-grey_999;
+                  .tool-icon{
+                      width:30px;
+                      text-align: right;
+                      img{
+                          width:5px;
+                      }
+                  }
+              }
+              
+          }
+      }
+  }
+  .catalog-list{
+        box-sizing: border-box;
+        height: 100%;
+        .sticky-part{
+            position:sticky;
+            background-color: white;
+            z-index: 99;
+            left:0;
+            right:0;
+        }
+        .top{
+            display: flex;
+            justify-content: space-between;
+            border-bottom: 1px solid #DCDFE6;
+            padding: 0 15px;
+            align-items: center;
+            top:0;
+        }
+        .bottom{
+            display: flex;
+            padding:48px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:16px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  @media screen and (min-width:$media-width){
+    .select-wrap{
+        top:60px;
+        padding:30px;
+        .search-box{
+            .icon{
+                margin-left: 10px;
+                width: 40px;
+                height:40px;
+                background-color: #F2F3FF;
+                border-radius: 50%;
+                img{
+                    width:25px;
+                    height:25px;
+                }
+            }
+        }
+        .select-box{
+            margin-top:20px;
+        }
+    }
+    .excel-list-wrap{
+        padding:0 30px;
+        .excel-list{
+            gap: 20px 4%;
+            justify-content:flex-start;
+            .excel-list-item{
+                box-sizing: border-box;
+                width: 22%;
+                padding: 10px 14px;
+                border: 1px solid $border-color;
+                border-radius: 6px;
+                .title{
+                    min-height: 36px;
+                }
+                .img{
+                    width: 100%;
+                    height: auto;
+                    display: block;
+                    margin: 10px 0;
+                }
+                .time{
+                    font-size: 14px;
+                    .tool-icon>img{
+                        width:3px;
+                    }
+                }
+            }
+        }
+    }
+    .catalog-list{
+        .bottom{
+            display: flex;
+            padding:24px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:8px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  }
+}
+</style>

+ 53 - 0
src/views/sheetList/sharedDetail.vue

@@ -0,0 +1,53 @@
+<script setup name="sharedDetail">
+import {nextTick, onMounted,ref,reactive} from 'vue'
+import { useRoute } from "vue-router";
+import apiSheetChart from '@/api/sheet'
+const route = useRoute()
+const queryData = ref({})
+
+onMounted(() => {
+    getExcelDetail()
+})
+//获取表格列表
+async function getExcelDetail(){
+    const res = await apiSheetChart.excelDetail({
+        ExcelInfoId: route.query.id,
+    })
+    if(res.Ret!==200) return 
+    queryData.value = res.Data
+    console.log(queryData.value)
+}
+</script>
+
+<template>
+    <div class="page">
+        <div class="top-box">
+            <div class="top-item">作者:{{ queryData.SysUserRealName }}</div>
+            <div class="top-item">最近保存时间:{{ queryData.CreateTime?.slice(0,10) }}</div>
+            <div class="top-item"><van-icon name="cross" @click.stop="IsShowCatalog=false"/></div>
+        </div>
+        <div class="sheet-box"></div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.page{
+    width: 100%;
+    height: 100vh;
+    padding: 24px;
+    .top-box {
+        width: 100%;
+        height: 40px;
+        display: flex;
+        justify-content: space-between;
+        .item {
+
+        }
+    }
+    .sheet-box{
+        width: 100%;
+        height: 100%;
+        background-color: pink;
+    }
+}
+</style> 

+ 433 - 0
src/views/sheetList/sharedList.vue

@@ -0,0 +1,433 @@
+<script setup name="SheetETAList">
+import apiSheetChart from '@/api/sheet'
+import {ref,reactive,watch,computed} from 'vue'
+import { useRouter } from "vue-router";
+import useLocaleStore from "@/store/modules/i18n";
+import CatalogTree from './components/CatalogTree.vue';
+import CatalogItem from './components/CatalogItem.vue';
+//激活的目录路径
+const catalogMenu = ref('')
+const router = useRouter()
+//表格列表
+const listState = reactive({
+    cid:0,
+    list:[],
+    page:1,
+    pageSize:15,
+    finished:false,
+    loading:false,
+    total:0,
+    IsShowMe:false
+})
+//是否展示目录列表
+const IsShowCatalog = ref(false)
+const localeStore = useLocaleStore()
+const temp = localeStore.locale === 'zhCn' ? 'zhCn' : 'en'; //根据当前i18n语言设置表格默认语言
+localeStore.SET_LOCALE(temp)
+
+watch(()=>listState.IsShowMe,()=>{
+    window.scrollTo({top:0})
+    listState.list=[]
+    listState.page=1
+    //设置数据已加载完毕,因为当滚动条不在顶部时,清空列表内容会触发onLoad
+    listState.finished = true 
+    //这个函数调用完成后,会把finished重置成正确的值
+    getSheetList()
+})
+
+getSheetList()
+//获取表格列表
+async function getSheetList(){
+    const {pageSize,cid,page,IsShowMe} = listState
+    const res = await apiSheetChart.sheetList({
+        PageSize: pageSize,
+        CurrentIndex: page,
+        Source: 1,
+        ExcelClassifyId: cid,
+        IsShowMe,
+    })
+    if(res.Ret!==200) return 
+    const arr = res.Data?res.Data.List:[]
+    listState.list = [...listState.list,...arr]
+    listState.total = res.Data?res.Data.Paging.Totals:0
+    listState.finished = res.Data?res.Data.Paging.IsEnd:true
+    listState.loading=false
+}
+
+//目录被点击 type:['top'一级目录,'node'二级目录,'item'三级目录]
+function catalogItemClick({item,type='node',parent={}}){
+    console.log(item);
+    console.log(type);
+    console.log(parent);
+    
+    const topMenu = type==='top'?item.ExcelClassifyName:type==='node'?item.parentName:parent.parentName
+    const nodeMenu = type==='node'?item.ExcelClassifyName:type==='item'?parent.ExcelClassifyName:''
+    const itemMenu = type==='item'?item.ExcelClassifyName:''
+
+    catalogMenu.value = `${topMenu}${nodeMenu.length?`/${nodeMenu}`:''}${itemMenu.length?`/${itemMenu}`:''}`
+    console.log();
+    
+    listState.cid = item.ExcelClassifyId
+    listState.list=[]
+    listState.page=1
+    getSheetList()
+}
+
+//展示目录列表
+function showCatalog(){
+    IsShowCatalog.value = true
+}
+
+//下拉加载
+function onLoad(){
+    if(IsShowCatalog.value) return
+    listState.page++
+    getSheetList()
+}
+
+//展开的目录
+const activeCatalogs = ref([])
+
+//目录列表
+const catalogNodes = ref([])
+const dataNodes = ref([])
+getCatalogList()
+//获取目录列表
+async function getCatalogList(){
+    const {IsShowMe} = listState
+    const res = await apiSheetChart.excelClassifyList({
+        Source: 1,
+        IsShowMe: IsShowMe
+    })
+    if(res.Ret!==200) return 
+    console.log(res);
+    dataNodes.value = res.Data?res.Data.AllNodes:[]||[]
+    catalogNodes.value = dataNodes.value.map(node=>{
+        if(node.Children){
+            node.Children = node.Children.map(child=>{
+                child.parentName = node.ExcelClassifyName //添加子分类时需要显示父级分类名称
+                if(child.Children){//改成三级目录了
+                    child.Children = child.Children.map(_child=>{
+                        _child.parentName = child.ExcelClassifyName
+                        return _child
+                    })
+                }
+                return child
+            })
+        }
+        return node
+    })
+}
+
+function showFileOpt(item){
+    console.log(item);
+}
+//跳转至图表详情页
+const goSheetDetail = (item)=>{
+    router.push({
+        path:'/shared/detail',
+        query:{
+            id:item.ExcelInfoId,
+        }
+    })
+}
+</script>
+
+<template>
+  <div class="excel-eta-list-wrap">
+    <div class="select-wrap">
+      <div class="search-box">
+        <van-search 
+          shape="round" 
+          readonly 
+          :placeholder="$t('shared_table.enter_table_name')"
+          style="flex:1;padding-left:0"
+          @click-input="$router.push('/shared/search')"
+        />
+        <div class="list-icon icon" @click="showCatalog">
+          <img src="@/assets/imgs/chartETA/list-icon.png" alt="">
+        </div>
+      </div>
+      <p style="font-weight: bold;word-break: break-all;margin-bottom: 5px;">{{ catalogMenu }}</p>
+      <div class="select-box">
+        <span>{{ $t('shared_table.tables_total', {totalNum: listState.total}) }}</span>
+        <span> <van-checkbox v-model="listState.IsShowMe">{{ $t('shared_table.just_look_mine') }}</van-checkbox></span>
+      </div>
+    </div>
+    <div class="excel-list-wrap">
+      <van-list
+          v-model:loading="listState.loading"
+          :finished="listState.finished"
+          :finished-text="listState.list.length > 0 ? $t('shared_table.no_more') : $t('shared_table.no_table')"
+          :immediate-check="false"
+          @load="onLoad"
+      >
+          <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+          <ul class="excel-list">
+              <li 
+                  class="excel-list-item" 
+                  v-for="item in listState.list" 
+                  :key="item.ChartInfoId"
+                  @click="goSheetDetail(item)"
+              >
+                  <div class="title">{{item.ExcelName}}</div>
+                  <img class="img" :src="item.ExcelImage" alt="">   
+                  <div class="time">
+                      <span>{{item.CreateTime.slice(0,10)}}</span>
+                  </div>
+              </li>
+          </ul>
+      </van-list>
+    </div>
+     <!-- 目录列表 -->
+     <van-popup v-model:show="IsShowCatalog" position="right" class="catalog-list-wrap" style="height:100%">
+        <div class="catalog-list">
+            <div class="top sticky-part">
+                <h3>{{ $t('shared_table.choose_category') }}</h3>
+                <van-icon name="cross" @click.stop="IsShowCatalog=false"/>
+            </div>
+            <!-- 将目录改为三级 -->
+            <div class="list-box catalog-tree-wrap">
+                <van-collapse v-model="activeCatalogs" :border="false">
+                    <van-collapse-item 
+                        v-for="catalog in catalogNodes" :key="catalog.UniqueCode" :name="catalog.UniqueCode"
+                        @click.stop="catalogItemClick({item:catalog,type:'top'})">
+                        <template #title>
+                            <CatalogItem
+                                :node="catalog" 
+                                @showPopup="showFileOpt"/>
+                        </template>
+                        <CatalogTree 
+                            :catalog-nodes="catalog.Children"
+                            :showFileOpt="showFileOpt"
+                            :activeId="listState.cid"
+                            @handleCatalogItemClick="catalogItemClick"
+                        />
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+        </div>
+    </van-popup>
+  </div>
+</template>
+<style lang="scss">
+.excel-eta-list-wrap{
+    .catalog-list-wrap{
+        width: 65%;
+    }
+    .rename-wrap{
+        padding:48px;
+        input{
+            padding: 24px 32px;
+            border-radius: 12px;
+            background-color: #F6F6F6;
+            width: 100%;
+        }
+        .label{
+            color: #666666;
+            margin-bottom: 32px;
+            text-align: center;
+        }
+    }
+    @media screen and (min-width:$media-width){
+        .catalog-list-wrap{
+            width: 30%;
+        }
+        .move-popup{
+            width:375px;
+        }
+        .rename-wrap{
+            padding:24px;
+            input{
+                padding: 12px 16px;
+                border-radius: 6px;
+                background-color: #F6F6F6;
+                width: 100%;
+            }
+            .label{
+                margin-bottom: 16px;
+            }
+        }
+    }
+}
+</style>
+<style scoped lang="scss">
+.excel-eta-list-wrap{
+  .select-wrap{
+      padding: 30px;
+      position: sticky;
+      top:0;
+      background-color: #fff;
+      .search-box{
+          display: flex;
+          align-items: center;
+          .icon{
+              margin-left: 10px;
+              width: 70px;
+              height:70px;
+              background-color: #F2F3FF;
+              border-radius: 50%;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              img{
+                  width:45px;
+                  height:45px;
+              }
+          }
+      }
+      .select-box{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+      }
+  }
+  .excel-list-wrap{
+      //margin-top:15px;
+      padding: 0 30px; 
+      padding-bottom: 30px;
+      .excel-list{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+          gap: 30px 0;
+          .excel-list-item{
+              box-sizing: border-box;
+              width: 330px;
+              padding: 10px 14px;
+              border: 1px solid $border-color;
+              border-radius: 12px;
+              .title{
+                  min-height: 70px;
+                  overflow: hidden;
+                  -webkit-line-clamp: 2;
+                  text-overflow: ellipsis;
+                  display:-webkit-box !important;
+                  -webkit-box-orient:vertical;
+                  word-break: break-word;
+              }
+              .img{
+                      width: 100%;
+                      height: 220px;
+                      display: block;
+                      margin: 10px 0;
+                  }
+              .time{
+                  display: flex;
+                  justify-content: space-between;
+                  font-size: 28px;
+                  color: $font-grey_999;
+                  .tool-icon{
+                      width:30px;
+                      text-align: right;
+                      img{
+                          width:5px;
+                      }
+                  }
+              }
+              
+          }
+      }
+  }
+  .catalog-list{
+        box-sizing: border-box;
+        height: 100%;
+        .sticky-part{
+            position:sticky;
+            background-color: white;
+            z-index: 99;
+            left:0;
+            right:0;
+        }
+        .top{
+            display: flex;
+            justify-content: space-between;
+            border-bottom: 1px solid #DCDFE6;
+            padding: 0 15px;
+            align-items: center;
+            top:0;
+        }
+        .bottom{
+            display: flex;
+            padding:48px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:16px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  @media screen and (min-width:$media-width){
+    .select-wrap{
+        top:60px;
+        padding:30px;
+        .search-box{
+            .icon{
+                margin-left: 10px;
+                width: 40px;
+                height:40px;
+                background-color: #F2F3FF;
+                border-radius: 50%;
+                img{
+                    width:25px;
+                    height:25px;
+                }
+            }
+        }
+        .select-box{
+            margin-top:20px;
+        }
+    }
+    .excel-list-wrap{
+        padding:0 30px;
+        .excel-list{
+            gap: 20px 4%;
+            justify-content:flex-start;
+            .excel-list-item{
+                box-sizing: border-box;
+                width: 22%;
+                padding: 10px 14px;
+                border: 1px solid $border-color;
+                border-radius: 6px;
+                .title{
+                    min-height: 36px;
+                }
+                .img{
+                    width: 100%;
+                    height: auto;
+                    display: block;
+                    margin: 10px 0;
+                }
+                .time{
+                    font-size: 14px;
+                    .tool-icon>img{
+                        width:3px;
+                    }
+                }
+            }
+        }
+    }
+    .catalog-list{
+        .bottom{
+            display: flex;
+            padding:24px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:8px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  }
+}
+</style>

+ 164 - 0
src/views/sheetList/sharedSearch.vue

@@ -0,0 +1,164 @@
+<script setup name="ChartETASearch">
+import {ref,reactive} from 'vue'
+import apiSheetChart from '@/api/sheet'
+import { showToast } from 'vant'
+import moment from 'moment'
+import { useRouter } from 'vue-router'
+import { useNoAuth } from '@/hooks/useNoAuth'
+
+const router=useRouter()
+
+const keyword=ref('')
+const listState = reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false
+})
+async function getList(){
+    const res=await apiSheetChart.sheetList({
+        CurrentIndex:listState.page,
+        PageSize:listState.pageSize,
+        Keyword:keyword.value,
+        IsShowMe:false
+    })
+    if(res.Ret===200){
+        listState.loading=false
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        
+        listState.finished=res.Data.Paging.IsEnd
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+    }
+}
+function onLoad(){
+    listState.page++
+    getList()
+}
+
+function handleSearch(){
+    if(!keyword.value){
+        showToast('请输入关键词')
+        return
+    }
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getList()
+}
+
+function goDetail(item){
+    router.push({
+        path:'/shared/detail',
+        query:{
+            id:item.ExcelInfoId,
+        }
+    })
+}
+
+</script>
+
+<template>
+    <div class="excel-search-list-page">
+        <div class="search-box">
+            <van-search 
+                shape="round"
+                :placeholder="$t('shared_table.enter_table_name')"
+                v-model="keyword"
+                @search="handleSearch"
+            />
+        </div>
+        <img v-if="listState.list.length==0&&listState.finished&&keyword" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+        <van-list
+            v-model:loading="listState.loading"
+            :finished="listState.finished"
+            :finished-text="listState.list.length > 0 ? $t('shared_table.no_more') : $t('shared_table.no_table')"
+            :immediate-check="false"
+            @load="onLoad"
+        >
+            <ul class="list-wrap">
+                <li class="item" v-for="item in listState.list" :key="item.ChartInfoId" @click="goDetail(item)">
+                    <div class="van-ellipsis name">{{item.ExcelName}}</div>
+                    <img class="img" :src="item.ExcelImage" alt="">
+                    <div class="time">
+                        <span>{{moment(item.CreateTime).format('YYYY-MM-DD')}}</span>
+                        <span>{{item.SysUserRealName}}</span>
+                    </div>
+                </li>
+                <li class="item" style="height:0;padding:0;border:none"></li>
+                <li class="item" style="height:0;padding:0;border:none"></li>
+                <li class="item" style="height:0;padding:0;border:none"></li>
+            </ul>
+        </van-list>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.search-box{
+    position: sticky;
+    top: 0;
+    background-color: #fff;
+    z-index: 99;
+}
+.list-wrap{
+    padding: $page-padding;
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    .item{
+        width: 326px;
+        padding: 14px;
+        background: #FFFFFF;
+        border: 1px solid $border-color;
+        box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.03);
+        border-radius: 12px;
+        box-sizing: border-box;
+        margin-bottom: 30px;
+        .img{
+            margin: 14px 0;
+            width: 100%;
+            height: 220px;
+        }
+        .time{
+            display: flex;
+            justify-content: space-between;
+            color: $font-grey_999;
+            font-size: 28px;
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .search-box{
+        top: 60px;
+    }
+    .list-wrap{
+        padding: 20px 30px;
+        justify-content: center;
+        .item{
+            width: 260px;
+            padding: 14px;
+            border-radius: 6px;
+            margin-left: 8px;
+            margin-right: 8px;
+            margin-bottom: 15px;
+            .img{
+                margin: 14px 0;
+                width: 100%;
+                height: 200px;
+            }
+            .time{
+                font-size: 14px;
+                justify-content: flex-start;
+                span{
+                    margin-right: 20px;
+                }
+            }
+        }
+        
+    }
+}
+</style>

+ 433 - 0
src/views/sheetList/timelineList.vue

@@ -0,0 +1,433 @@
+<script setup name="SheetETAList">
+import apiSheetChart from '@/api/sheet'
+import {ref,reactive,watch,computed} from 'vue'
+import { useRouter } from "vue-router";
+import useLocaleStore from "@/store/modules/i18n";
+import CatalogTree from './components/CatalogTree.vue';
+import CatalogItem from './components/CatalogItem.vue';
+//激活的目录路径
+const catalogMenu = ref('')
+const router = useRouter()
+//表格列表
+const listState = reactive({
+    cid:0,
+    list:[],
+    page:1,
+    pageSize:15,
+    finished:false,
+    loading:false,
+    total:0,
+    IsShowMe:false
+})
+//是否展示目录列表
+const IsShowCatalog = ref(false)
+const localeStore = useLocaleStore()
+const temp = localeStore.locale === 'zhCn' ? 'zhCn' : 'en'; //根据当前i18n语言设置表格默认语言
+localeStore.SET_LOCALE(temp)
+
+watch(()=>listState.IsShowMe,()=>{
+    window.scrollTo({top:0})
+    listState.list=[]
+    listState.page=1
+    //设置数据已加载完毕,因为当滚动条不在顶部时,清空列表内容会触发onLoad
+    listState.finished = true 
+    //这个函数调用完成后,会把finished重置成正确的值
+    getSheetList()
+})
+
+getSheetList()
+//获取表格列表
+async function getSheetList(){
+    const {pageSize,cid,page,IsShowMe} = listState
+    const res = await apiSheetChart.sheetList({
+        PageSize: pageSize,
+        CurrentIndex: page,
+        Source: 2,
+        ExcelClassifyId: cid,
+        IsShowMe,
+    })
+    if(res.Ret!==200) return 
+    const arr = res.Data?res.Data.List:[]
+    listState.list = [...listState.list,...arr]
+    listState.total = res.Data?res.Data.Paging.Totals:0
+    listState.finished = res.Data?res.Data.Paging.IsEnd:true
+    listState.loading=false
+}
+
+//目录被点击 type:['top'一级目录,'node'二级目录,'item'三级目录]
+function catalogItemClick({item,type='node',parent={}}){
+    console.log(item);
+    console.log(type);
+    console.log(parent);
+    
+    const topMenu = type==='top'?item.ExcelClassifyName:type==='node'?item.parentName:parent.parentName
+    const nodeMenu = type==='node'?item.ExcelClassifyName:type==='item'?parent.ExcelClassifyName:''
+    const itemMenu = type==='item'?item.ExcelClassifyName:''
+
+    catalogMenu.value = `${topMenu}${nodeMenu.length?`/${nodeMenu}`:''}${itemMenu.length?`/${itemMenu}`:''}`
+    console.log();
+    
+    listState.cid = item.ExcelClassifyId
+    listState.list=[]
+    listState.page=1
+    getSheetList()
+}
+
+//展示目录列表
+function showCatalog(){
+    IsShowCatalog.value = true
+}
+
+//下拉加载
+function onLoad(){
+    if(IsShowCatalog.value) return
+    listState.page++
+    getSheetList()
+}
+
+//展开的目录
+const activeCatalogs = ref([])
+
+//目录列表
+const catalogNodes = ref([])
+const dataNodes = ref([])
+getCatalogList()
+//获取目录列表
+async function getCatalogList(){
+    const {IsShowMe} = listState
+    const res = await apiSheetChart.excelClassifyList({
+        Source: 2,
+        IsShowMe: IsShowMe
+    })
+    if(res.Ret!==200) return 
+    console.log(res);
+    dataNodes.value = res.Data?res.Data.AllNodes:[]||[]
+    catalogNodes.value = dataNodes.value.map(node=>{
+        if(node.Children){
+            node.Children = node.Children.map(child=>{
+                child.parentName = node.ExcelClassifyName //添加子分类时需要显示父级分类名称
+                if(child.Children){//改成三级目录了
+                    child.Children = child.Children.map(_child=>{
+                        _child.parentName = child.ExcelClassifyName
+                        return _child
+                    })
+                }
+                return child
+            })
+        }
+        return node
+    })
+}
+
+function showFileOpt(item){
+    console.log(item);
+}
+//跳转至图表详情页
+const goSheetDetail = (item)=>{
+    router.push({
+        path:'/shared/detail',
+        query:{
+            id:item.ExcelInfoId,
+        }
+    })
+}
+</script>
+
+<template>
+  <div class="excel-eta-list-wrap">
+    <div class="select-wrap">
+      <div class="search-box">
+        <van-search 
+          shape="round" 
+          readonly 
+          :placeholder="$t('shared_table.enter_table_name')"
+          style="flex:1;padding-left:0"
+          @click-input="$router.push('/shared/search')"
+        />
+        <div class="list-icon icon" @click="showCatalog">
+          <img src="@/assets/imgs/chartETA/list-icon.png" alt="">
+        </div>
+      </div>
+      <p style="font-weight: bold;word-break: break-all;margin-bottom: 5px;">{{ catalogMenu }}</p>
+      <div class="select-box">
+        <span>{{ $t('shared_table.tables_total', {totalNum: listState.total}) }}</span>
+        <span> <van-checkbox v-model="listState.IsShowMe">{{ $t('shared_table.just_look_mine') }}</van-checkbox></span>
+      </div>
+    </div>
+    <div class="excel-list-wrap">
+      <van-list
+          v-model:loading="listState.loading"
+          :finished="listState.finished"
+          :finished-text="listState.list.length > 0 ? $t('shared_table.no_more') : $t('shared_table.no_table')"
+          :immediate-check="false"
+          @load="onLoad"
+      >
+          <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+          <ul class="excel-list">
+              <li 
+                  class="excel-list-item" 
+                  v-for="item in listState.list" 
+                  :key="item.ChartInfoId"
+                  @click="goSheetDetail(item)"
+              >
+                  <div class="title">{{item.ExcelName}}</div>
+                  <img class="img" :src="item.ExcelImage" alt="">   
+                  <div class="time">
+                      <span>{{item.CreateTime.slice(0,10)}}</span>
+                  </div>
+              </li>
+          </ul>
+      </van-list>
+    </div>
+     <!-- 目录列表 -->
+     <van-popup v-model:show="IsShowCatalog" position="right" class="catalog-list-wrap" style="height:100%">
+        <div class="catalog-list">
+            <div class="top sticky-part">
+                <h3>{{ $t('shared_table.choose_category') }}</h3>
+                <van-icon name="cross" @click.stop="IsShowCatalog=false"/>
+            </div>
+            <!-- 将目录改为三级 -->
+            <div class="list-box catalog-tree-wrap">
+                <van-collapse v-model="activeCatalogs" :border="false">
+                    <van-collapse-item 
+                        v-for="catalog in catalogNodes" :key="catalog.UniqueCode" :name="catalog.UniqueCode"
+                        @click.stop="catalogItemClick({item:catalog,type:'top'})">
+                        <template #title>
+                            <CatalogItem
+                                :node="catalog" 
+                                @showPopup="showFileOpt"/>
+                        </template>
+                        <CatalogTree 
+                            :catalog-nodes="catalog.Children"
+                            :showFileOpt="showFileOpt"
+                            :activeId="listState.cid"
+                            @handleCatalogItemClick="catalogItemClick"
+                        />
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+        </div>
+    </van-popup>
+  </div>
+</template>
+<style lang="scss">
+.excel-eta-list-wrap{
+    .catalog-list-wrap{
+        width: 65%;
+    }
+    .rename-wrap{
+        padding:48px;
+        input{
+            padding: 24px 32px;
+            border-radius: 12px;
+            background-color: #F6F6F6;
+            width: 100%;
+        }
+        .label{
+            color: #666666;
+            margin-bottom: 32px;
+            text-align: center;
+        }
+    }
+    @media screen and (min-width:$media-width){
+        .catalog-list-wrap{
+            width: 30%;
+        }
+        .move-popup{
+            width:375px;
+        }
+        .rename-wrap{
+            padding:24px;
+            input{
+                padding: 12px 16px;
+                border-radius: 6px;
+                background-color: #F6F6F6;
+                width: 100%;
+            }
+            .label{
+                margin-bottom: 16px;
+            }
+        }
+    }
+}
+</style>
+<style scoped lang="scss">
+.excel-eta-list-wrap{
+  .select-wrap{
+      padding: 30px;
+      position: sticky;
+      top:0;
+      background-color: #fff;
+      .search-box{
+          display: flex;
+          align-items: center;
+          .icon{
+              margin-left: 10px;
+              width: 70px;
+              height:70px;
+              background-color: #F2F3FF;
+              border-radius: 50%;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              img{
+                  width:45px;
+                  height:45px;
+              }
+          }
+      }
+      .select-box{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+      }
+  }
+  .excel-list-wrap{
+      //margin-top:15px;
+      padding: 0 30px; 
+      padding-bottom: 30px;
+      .excel-list{
+          display: flex;
+          justify-content: space-between;
+          flex-wrap: wrap;
+          gap: 30px 0;
+          .excel-list-item{
+              box-sizing: border-box;
+              width: 330px;
+              padding: 10px 14px;
+              border: 1px solid $border-color;
+              border-radius: 12px;
+              .title{
+                  min-height: 70px;
+                  overflow: hidden;
+                  -webkit-line-clamp: 2;
+                  text-overflow: ellipsis;
+                  display:-webkit-box !important;
+                  -webkit-box-orient:vertical;
+                  word-break: break-word;
+              }
+              .img{
+                      width: 100%;
+                      height: 220px;
+                      display: block;
+                      margin: 10px 0;
+                  }
+              .time{
+                  display: flex;
+                  justify-content: space-between;
+                  font-size: 28px;
+                  color: $font-grey_999;
+                  .tool-icon{
+                      width:30px;
+                      text-align: right;
+                      img{
+                          width:5px;
+                      }
+                  }
+              }
+              
+          }
+      }
+  }
+  .catalog-list{
+        box-sizing: border-box;
+        height: 100%;
+        .sticky-part{
+            position:sticky;
+            background-color: white;
+            z-index: 99;
+            left:0;
+            right:0;
+        }
+        .top{
+            display: flex;
+            justify-content: space-between;
+            border-bottom: 1px solid #DCDFE6;
+            padding: 0 15px;
+            align-items: center;
+            top:0;
+        }
+        .bottom{
+            display: flex;
+            padding:48px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:16px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  @media screen and (min-width:$media-width){
+    .select-wrap{
+        top:60px;
+        padding:30px;
+        .search-box{
+            .icon{
+                margin-left: 10px;
+                width: 40px;
+                height:40px;
+                background-color: #F2F3FF;
+                border-radius: 50%;
+                img{
+                    width:25px;
+                    height:25px;
+                }
+            }
+        }
+        .select-box{
+            margin-top:20px;
+        }
+    }
+    .excel-list-wrap{
+        padding:0 30px;
+        .excel-list{
+            gap: 20px 4%;
+            justify-content:flex-start;
+            .excel-list-item{
+                box-sizing: border-box;
+                width: 22%;
+                padding: 10px 14px;
+                border: 1px solid $border-color;
+                border-radius: 6px;
+                .title{
+                    min-height: 36px;
+                }
+                .img{
+                    width: 100%;
+                    height: auto;
+                    display: block;
+                    margin: 10px 0;
+                }
+                .time{
+                    font-size: 14px;
+                    .tool-icon>img{
+                        width:3px;
+                    }
+                }
+            }
+        }
+    }
+    .catalog-list{
+        .bottom{
+            display: flex;
+            padding:24px;
+            bottom:0;
+            span{
+                flex: 1;
+                background-color: #0052D9;
+                color: white;
+                text-align: center;
+                border-radius: 6px;
+                padding:8px;
+                box-sizing: border-box;
+            }
+        }
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/tabbar/Home.vue

@@ -184,7 +184,7 @@ const menuConfig=[
         key:'表格',
         type:'zh',
         level:1,
-        path:'',
+        path:'/sheetList/index',
         icon:getStaticImg('tabbar/icon_table.png'),
         backgroundColor:'#FFFBF6',
         show:false