表格乱序下钻,返回,保留表单和分页,查询时候重新在第一页查询

table.vue

<template>
    <div class="drill-table">
      <!-- 过滤区域 -->
      <div class="filter-area">
        <el-input 
          v-model="filters.keyword" 
          placeholder="搜索关键词" 
          class="filter-input"
          @input="handleFilterChange"
        >
          <template #append>
            <el-button @click="handleFilterChange">
              <el-icon><Search /></el-icon>
            </el-button>
          </template>
        </el-input>
        
        <el-select 
          v-model="filters.status" 
          placeholder="状态过滤" 
          class="filter-select"
          @change="handleFilterChange"
        >
          <el-option label="全部" value=""></el-option>
          <el-option label="活跃" value="active"></el-option>
          <el-option label="待处理" value="pending"></el-option>
          <el-option label="完成" value="completed"></el-option>
        </el-select>
      </div>
      
      <!-- 数据表格 -->
      <el-table 
        :data="currentData" 
        style="width: 100%"
        row-key="id"
        border
        v-loading="loading"
      >
        <el-table-column 
          v-for="column in columns" 
          :key="column.prop"
          :prop="column.prop"
          :label="column.label"
        >
          <template #default="scope">
            <!-- 根据列的 drillable 属性决定是否可以下钻 -->
            <div 
              :class="{'drillable': column.drillable}"
              @click="column.drillable ? handleDrillDown(scope.row, column) : null"
            >
              {{ scope.row[column.prop] }}
              <el-icon v-if="column.drillable" class="drill-icon">
                <Right />
              </el-icon>
            </div>
          </template>
        </el-table-column>
      </el-table>
      
      <!-- 分页控件 -->
      <el-pagination
        :current-page="pagination.page"
        :page-size="pagination.pageSize"
        :page-sizes="[10, 20, 50, 100]"
        :total="pagination.total"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
      />
    </div>
  </template>
  
  <script setup>
  import { computed, ref, watch, onMounted } from 'vue';
  import { Search, Right } from '@element-plus/icons-vue';
  import { useDrillStore } from '@/store/modules/drillStore';
  import {
  aboveStatistics,
  tableHead,
  statisticsList,
  dateDifference,
  weekInfo,
  deptTree,
  list
} from "@/api/main_sys/overview/index";
  const drillStore = useDrillStore();
  const loading = ref(false);
  
  // 从store获取状态
  const currentData = computed(() => drillStore.currentState.tableData);
  const filters = computed(() => drillStore.currentState.filters);
  const pagination = computed(() => drillStore.currentState.pagination);
  
  // 列配置 (任何列都可设置为可下钻)
  const columns = ref([
    { prop: 'name', label: '名称', drillable: true },
    { prop: 'category', label: '类别', drillable: true },
    { prop: 'status', label: '状态', drillable: true },
    { prop: 'value', label: '数值', drillable: false },
    { prop: 'date', label: '日期', drillable: true }
  ]);
  
  // 处理下钻操作
  const handleDrillDown = (row, column) => {
    drillStore.drillDown({
      title: `${column.label}: ${row[column.prop]}`,
      dataRef: row.id
    });
    
    // 模拟获取新一级数据
    fetchData();
  };
  
  // 处理过滤变化
  const handleFilterChange = () => {
    drillStore.updateFilters(filters.value);
    drillStore.updatePagination({
      page: 1,
      pageSize: 10
    });
    fetchData();
  };
  
  // 处理分页大小变化
  const handleSizeChange = (size) => {
    drillStore.updatePagination({
      ...pagination.value,
      page: 1,
      pageSize: size
    });
    fetchData();
  };
  
  // 处理页码变化
  const handlePageChange = (page) => {
    drillStore.updatePagination({
      ...pagination.value,
      page: page
    });
    fetchData();
  };
  
  // 模拟API获取数据
  const fetchData = async () => {
    loading.value = true;
    
    // 实际项目中替换为真实的API调用
    try {
      // 模拟网络延迟
      await new Promise(resolve => setTimeout(resolve, 500));
      
      const mockData = generateMockData(
        pagination.value.page,
        pagination.value.pageSize,
        drillStore.currentState.level,
        filters.value
      );
      
      drillStore.updateTableData(mockData.rows);
      drillStore.updatePagination({
        ...pagination.value,
        total: mockData.total
      });
    } finally {
      loading.value = false;
    }
  };
  
  // 监听层级变化
  watch(() => drillStore.currentState.level, (newLevel) => {
    if (newLevel !== 0 && drillStore.historyStack.length === 0) {
      // 刚进入时的初始加载
      fetchData();
    }
  });
  
  // 初始化数据
  onMounted(() => {
    // 设置初始路径
    if (drillStore.currentState.drillPath.length === 0) {
      drillStore.drillDown({
        title: '首页',
        dataRef: '',
        level: 0
      });
    }
    
    fetchData();
  });
  
  // 模拟数据生成函数
  const generateMockData = (page, pageSize, level, filters) => {
    const statuses = ['active', 'pending', 'completed'];
    const categories = ['A', 'B', 'C', 'D', 'E'];
    
    const startIndex = (page - 1) * pageSize;
    const data = [];
    
    for (let i = 1; i <= pageSize; i++) {
      const index = startIndex + i;
      const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
      
      // 应用过滤器
      if (filters.status && filters.status !== randomStatus) {
        continue;
      }
      
      // 应用关键词过滤器
      if (filters.keyword && !`${level}-${index}`.includes(filters.keyword)) {
        continue;
      }
      
      data.push({
        id: `${level}-${index}`,
        name: `项目 ${level}-${index}`,
        category: categories[Math.floor(Math.random() * categories.length)],
        status: randomStatus,
        value: Math.floor(Math.random() * 1000),
        date: new Date(Date.now() - Math.floor(Math.random() * 10000000000)).toLocaleDateString()
      });
    }
    
    // 总数据量模拟(实际应用中来自API)
    const total = level * 1000 + 500 - Math.floor(Math.random() * 100);
    
    return {
      rows: data,
      total: total > data.length ? total : data.length
    };
  };
  </script>
  
  <style scoped>
  .drill-table {
    padding: 15px;
  }
  
  .filter-area {
    display: flex;
    margin-bottom: 15px;
    gap: 15px;
  }
  
  .filter-input {
    width: 300px;
  }
  
  .el-pagination {
    margin-top: 20px;
    justify-content: flex-end;
  }
  
  .drillable {
    cursor: pointer;
    color: #409eff;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  
  .drillable:hover {
    text-decoration: underline;
  }
  
  .drill-icon {
    margin-left: 5px;
  }
  </style>

bre.vue

<template>
    <el-breadcrumb separator="/" class="breadcrumb">
      <el-breadcrumb-item 
        v-for="(item, index) in drillPath" 
        :key="item.level"
        :class="{ 'current-level': index === drillPath.length - 1 }"
        @click="goBack(item.level)"
      >
        {{ item.title }}
      </el-breadcrumb-item>
    </el-breadcrumb>
  </template>
  
  <script setup>
  import { computed } from 'vue';
  import { useDrillStore } from '@/store/modules/drillStore';
  
  const drillStore = useDrillStore();
  const drillPath = computed(() => drillStore.currentState.drillPath);
  
  const goBack = (level) => {
    drillStore.goBack(level);
  };
  </script>
  
  <style scoped>
  .breadcrumb {
    margin-bottom: 20px;
    padding: 10px;
    background: #f5f7fa;
    border-radius: 4px;
  }
  
  .el-breadcrumb-item {
    cursor: pointer;
  }
  
  .el-breadcrumb-item:not(.current-level):hover {
    color: #409eff;
    text-decoration: underline;
  }
  
  .current-level {
    color: #909399;
    cursor: default;
  }
  </style>

store/modules/drillStore.js

import { defineStore } from 'pinia';

export const useDrillStore = defineStore('drill', {
    state: () => ({
        historyStack: [], // 保存历史状态
        currentState: {
            level: 0, // 当前层级
            tableData: [], // 当前表格数据
            filters: {},
            pagination: {
                page: 1,
                pageSize: 10,
                total: 0
            },
            drillPath: [] // 下钻路径 [{level: 0, title: '首页', dataRef: ''}]
        }
    }),
    actions: {
        // 保存当前状态并推进历史堆栈
        saveState() {
            this.historyStack.push({
                ...JSON.parse(JSON.stringify(this.currentState))
            });
        },

        // 下钻操作
        drillDown(payload) {

            this.saveState();

            // 更新当前状态
            this.currentState.level = payload.level || this.currentState.level + 1;
            this.currentState.drillPath.push({
                level: this.currentState.level,
                title: payload.title,
                dataRef: payload.dataRef
            });

            // 重置为初始状态(保留钻取级别)
            this.currentState.filters = { };
            this.currentState.pagination = {
                page: 1,
                pageSize: 10,
                total: 0
            };
        },

        // 返回操作
        goBack(toLevel) {
            if (this.historyStack.length === 0) return;

            // 查找目标状态
            const targetState = this.historyStack.find(state => state.level === toLevel);

            if (targetState) {
                // 应用状态
                this.currentState = targetState;

                // 清理历史堆栈中更深的状态
                this.historyStack = this.historyStack.filter(
                    state => state.level <= toLevel
                );

                // 更新钻取路径
                this.currentState.drillPath = this.currentState.drillPath.filter(
                    path => path.level <= toLevel
                );
            }
        },

        // 更新表格数据
        updateTableData(data) {
            this.currentState.tableData = data;
        },

        // 更新分页信息
        updatePagination(pagination) {
            this.currentState.pagination = { ...pagination };
        },

        // 更新过滤条件
        updateFilters(filters) {
            this.currentState.filters = { ...filters };
        }
    }
});

页面使用

 <template>
	<div class="container">
	  <el-card>
		<!-- 面包屑导航 -->
		<BreadcrumbNav />
		
		<!-- 数据表格 -->
		<DrillTable />
	  </el-card>
	</div>
  </template>
  
  <script setup>
  import BreadcrumbNav from '@/components/bre.vue';
  import DrillTable from '@/components/demo/table.vue';
  
  onMounted(async () => {
  
  })
  </script>
  
  <style scoped lang="scss">
  .container {
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
  }
  </style>

需求截图

返回第一页

数据是自己mock的 可以替换为接口!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值