大屏表格滚动效果

实现效果:

实现过程:

主文件:


<template>
  <CardLayout v-loading="loading" v-bind="$attrs" :show-title="false" direction="vertical">
    <div class="main-content">
      <div class="tabs">
        <div 
          v-for="(item,index) in tabs" 
          :key="index"
          class="tab-item"
          :class="{active:currentIndex === index}" 
          @click="handleClick(index)"
        >
          {{ item.name }}
        </div>
      </div>
      
      <div v-if="tableData.length" ref="resizeBox" class="resizeBox">
        <TableHeader :header-list="headerList" :header-data="headerData" />
        <TableScroll v-if="isShow" :table-data="tableData" :header-data="headerData" :height="height" />
      </div>
      <div v-else class="empty">
        <el-empty description="暂无数据" image-size="100"></el-empty>
      </div>
    </div>
  </CardLayout>
</template>
  
<script>
import CardClass from '@/components/diy-dashboard/cards/card-class'
import TableScroll from './components/table-scroll.vue'
import TableHeader from './components/table-header.vue'

export default {
  name: 'TiketHomeTableDefect',
  components: { TableScroll, TableHeader },
  mixins: [CardClass],
  props: {},
  data() {
    return {
      loading: false,
      tabs: [
        { name: '未完成' },
        { name: '超24H未完成' },
        { name: '超48H未完成' }
      ],
      currentIndex: 0,
      tableData: [{}],
      headerList: [
        {
          aa: '序号',
          wfStatus: '流程状态',
          description: '缺陷描述',
          confirmDefectTypeName: '缺陷类别',
          leadName: '负责人',
          keepHour: '持续时长'
        }
      ],
      headerData: [
        { prop: 'wfStatus', label: '流程状态', align: 'center' },
        { prop: 'description', label: '缺陷描述', align: 'left' },
        { prop: 'confirmDefectTypeName', label: '缺陷类别', align: 'center' },
        { prop: 'leadName', label: '负责人', align: 'center' },
        { prop: 'keepHour', label: '持续时长', align: 'center' }
      ],
      width: 0, // 容器宽度
      height: 0, // 容器高度
      resizeObserver: null,
      isShow: true,
      url: '/sbtz/SbtzCountService/queryDefectUnCompleteList',
      params: {
        keepHour24: '',
        keepHour48: ''
      }
    }
  },
  mounted() {
    this.getData()

    // 监听容器大小变化
    this.resizeObserver = new ResizeObserver(entries => {
      this.isShow = false
      entries.forEach(entry => {
        this.height = entry.contentRect.height
      })
      setTimeout(() => {
        this.isShow = true
      }, 200)
    })
    if (this.$refs.resizeBox) {
      this.$nextTick(() => {
        this.resizeObserver.observe(this.$refs.resizeBox)
      })
    }
    // 全屏监听
    document.addEventListener('fullscreenchange', this.handleFullScreenChange)
  },
  destroyed() {
    this.resizeObserver.disconnect() 
  },
  methods: {
    getData() {
      this.loading = true
      try {
        this.$request({ url: this.url, params: this.params }).then(res => {
          if (this.tool.isSuccess(res)) {
            this.tableData = res.data
            if (this.currentIndex === 0) {
              this.getNum(this.tableData)
            }
            this.loading = false
          }
        })
      } catch (error) {
        this.loading = false
      }
    },
    // 统计个数
    getNum(tableData) {
      const all = tableData.length
      const keepHour24 = tableData.filter(item => item.keepHour > 24 && item.keepHour <= 48).length
      const keepHour48 = tableData.filter(item => item.keepHour > 48).length
      this.tabs[0].name = `未完成(${all})`
      this.tabs[1].name = `超24H未完成(${keepHour24})`
      this.tabs[2].name = `超48H未完成(${keepHour48})`
    },
    handleFullScreenChange() {
      this.isShow = false
      setTimeout(() => {
        this.isShow = true
      }, 200)
    },
    handleClick(index) {
      this.currentIndex = index
      if (index === 0) {
        this.params.keepHour24 = ''
        this.params.keepHour48 = ''
      } else if (index === 1) {
        this.params.keepHour24 = '1'
        this.params.keepHour48 = ''
      } else if (index === 2) {
        this.params.keepHour24 = ''
        this.params.keepHour48 = '1'
      }
      this.getData()
    }
  }
}
</script>
<style lang="scss" scoped>
  $fontSize: 1.8em;
  .main-content {
    height: 100%;
    padding-bottom: 30px;
    .tabs {
      display: flex;
      font-size: $fontSize;
      width: 100%;
      height: 30px;
      .tab-item {
        cursor: pointer;
        flex: 1;
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 3px 5px;
        color: #fff;
        &:nth-child(2) {
          color: #FFBE22;
        }
        &:nth-child(3) {
          color: #FC3B3B;
        }
      }
      .active{
        background-color: #2756a8;
      }
    }
    .resizeBox {
      width: 100%;
      height: calc(100% - 45px);
      color: #fff;
    }
    .empty {
      width: 100%;
      height: calc(100% - 45px);
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
  ::v-deep .el-table tr {
    background-color: #15274d;
    color: #fff;
  }

  //去掉最下面的那一条线
  ::v-deep .el-table::before {
    // height: 0px !important;
    background-color: #266AB9 !important;
  }
</style>
  

子组件table-header.vue

<template>
  <el-table 
    :data="headerList" 
    stripe 
    style="width: 100%;" 
    size="mini" 
    :show-header="false"
  >
    <el-table-column prop="aa" label="序号" align="center" width="45"></el-table-column>
    <el-table-column 
      v-for="(item, index) in headerData"
      :key="index"
      :prop="item.prop" 
      :label="item.label" 
      align="center"
    >
    </el-table-column>
  </el-table>
</template>
            
<script>
export default {
  name: 'TitleCard',
  props: {
    headerList: {
      type: Array,
      default() {
        return []
      }
    },
    headerData: {
      type: Array,
      default() {
        return []
      }
    }
  },
  data() {
    return {
    }
  }
}
</script>
<style lang="scss" scoped>
::v-deep .el-table__body-wrapper {
  border-right: 1px solid #19274a !important;
}
</style>
    
  

子组件:table-scroll.vue

<template>
  <vue-seamless-scroll
    :data="tableData"
    :class-option="classOption"
    class="warp"
  >
    <el-table 
      ref="scrollTable" 
      :data="tableData" 
      stripe 
      style="width: 100%;" 
      size="mini" 
      :show-header="false"
      :row-class-name="tableAddClass"
    >
      <el-table-column label="序号" align="center" width="45">
        <template slot-scope="scope">
          {{ scope.$index + 1 }}
        </template>>
      </el-table-column>
      <el-table-column 
        v-for="(item, index) in headerData"
        :key="index"
        :show-overflow-tooltip="true"
        :prop="item.prop"
        :label="item.label" 
        :align="item.align"
        :width="item.width"
      >
        <template slot-scope="scope">
          <span v-if="item.prop === 'keepHour'">
            <span v-if="scope.row[item.prop] > 48" style="color: red;">{{ scope.row[item.prop] + 'H' }}</span>
            <span v-else style="color: orange;">{{ scope.row[item.prop] + 'H' }}</span>
          </span>
          <span v-else>{{ scope.row[item.prop] }}</span>
        </template>
      </el-table-column>
    </el-table>
  </vue-seamless-scroll>
</template>
      
<script>
import vueSeamlessScroll from 'vue-seamless-scroll'
export default {
  name: 'TableScroll',
  components: { vueSeamlessScroll },
  props: {
    tableData: {
      type: Array,
      default() {
        return []
      }
    },
    headerData: {
      type: Array,
      default() {
        return []
      }
    },
    height: {
      type: Number,
      default: 0
    },
    type: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      limitMoveNum: 5 // 超过这个数目就开始滚动
    }
  },
  computed: {
    classOption() {
      return {
        direction: 1, // 0向下 1向上 2向左 3向右
        openWatch: true, // 开启数据实时监控刷新dom
        step: 0.5, // 滚动速度
        // limitMoveNum: 5 // 开启无缝滚动的数据量
        limitMoveNum: this.limitMoveNum // 开启无缝滚动的数据量
      }
    }
  },
  watch: {
    'height': {
      handler(val) {
        this.limitMoveNum = Math.floor((val / 30))
      },
      immediate: true
    }
  },

  methods: {
    tableAddClass({ row, rowIndex }) {
      if (this.type === 'worktiket') {
        return row.dataColor ? row.dataColor : ''
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.warp {
  height: 100%;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
}

::v-deep .el-table .red {
  color: red !important;
}
::v-deep .el-table .orange {
  color: orange !important;
}
::v-deep .el-table .white{
  color: white !important;
}

// 浅颜色
::v-deep .el-table tr {
  background-color: #1a3360 !important;
  color: #fff;
  // color: orange !important;
}

// 深颜色
::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell {
  background-color: #15274d !important;
  // color: #fff;
  // color: red;
  border-top: 1px solid #266AB9 !important;
  border-bottom: 1px solid #266AB9 !important;
}

::v-deep .el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf {
  border: none !important;
}

//去掉最下面的那一条线
::v-deep .el-table::before {
  // height: 0px !important;
  // border-bottom: 1px solid #266AB9 !important;
  background-color: #266AB9 !important;
}

::v-deep .el-table__body-wrapper {
  border-right: 1px solid #19274a !important;
}
</style>
    
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值