实现效果:
实现过程:
主文件:
<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>