<template>
|
<div class="charts-container">
|
<!-- <div id="preWarning"></div>-->
|
<div class="table-wrapper">
|
<table class="scrollable-table">
|
<thead>
|
<tr>
|
<th>企业名称</th>
|
<th>预警情况</th>
|
<th>分类</th>
|
</tr>
|
</thead>
|
</table>
|
<div class="scroll-viewport" ref="viewport">
|
<div class="scroll-content" :style="contentStyle">
|
<table class="scrollable-table">
|
<tbody>
|
<tr v-for="(item,index) in warningData" :key="item.id">
|
<td>{{ item.name }}</td>
|
<td>{{ item.info }}</td>
|
<td :class="{'red': item.type == '红色','yellow': item.type == '黄色','blue': item.type == '蓝色'}">{{ item.type }}</td>
|
</tr>
|
<tr v-for="(item,index) in loopData" :key="`loop-${item.id}`">
|
<td>{{ item.name }}</td>
|
<td>{{ item.info }}</td>
|
<td :class="{'red': item.type == '红色','yellow': item.type == '黄色','blue': item.type == '蓝色'}">{{ item.type }}</td>
|
</tr>
|
</tbody>
|
</table>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
<script setup>
|
import * as echarts from 'echarts';
|
import {computed, onBeforeUnmount, onMounted, ref} from "vue";
|
import {getCompanyMessage, getDailywarningCount} from "@/api/monitor/screenCharts";
|
import {ElMessage} from "element-plus";
|
|
const warningData = [
|
{name: '企业1',info: 'XXXXXXXX',type: '红色' },
|
{name: '企业2',info: 'XXXXXXXX',type: '蓝色' },
|
{name: '企业3',info: 'XXXXXXXX',type: '黄色' },
|
{name: '企业4',info: 'XXXXXXXX',type: '蓝色' },
|
{name: '企业5',info: 'XXXXXXXX',type: '红色' },
|
{name: '企业6',info: 'XXXXXXXX',type: '黄色' },
|
{name: '企业7',info: 'XXXXXXXX',type: '蓝色' }
|
]
|
// 配置参数
|
const visibleRows = 7 // 显示的行数
|
const scrollSpeed = 0.5 // 每次滚动的像素数
|
const rowHeight = 36 // 行高,与CSS一致
|
const viewport = ref(null)
|
const scrollPosition = ref(0)
|
let animationFrame = null
|
|
onMounted(()=>{
|
// getList()
|
// 设置视口高度
|
if (viewport.value) {
|
viewport.value.style.height = `${visibleRows * rowHeight}px`
|
}
|
// 延迟启动滚动,确保初始渲染完成
|
setTimeout(() => {
|
scrollAnimation()
|
}, 100)
|
})
|
|
onBeforeUnmount(() => {
|
if (animationFrame) {
|
cancelAnimationFrame(animationFrame)
|
}
|
})
|
|
// 复制前几行数据用于循环
|
const loopData = computed(() => {
|
return warningData.slice(0, visibleRows)
|
})
|
|
// 内容区域样式
|
const contentStyle = computed(() => {
|
return {
|
transform: `translateY(-${scrollPosition.value}px)`
|
}
|
})
|
|
// 滚动动画
|
const scrollAnimation = () => {
|
const totalHeight = warningData.length * rowHeight
|
const loopHeight = loopData.value.length * rowHeight
|
// 更新滚动位置
|
scrollPosition.value += scrollSpeed
|
// 当滚动到循环数据部分时,重置位置实现无缝衔接
|
if (scrollPosition.value >= totalHeight) {
|
scrollPosition.value -= totalHeight
|
}
|
animationFrame = requestAnimationFrame(scrollAnimation)
|
}
|
|
const getList = async () => {
|
const res = await getDailywarningCount()
|
if(res.code == 200){
|
if(res.data && Array.isArray(res.data) && res.data.length>0){
|
initChart(res.data)
|
}else{
|
initChart([])
|
}
|
}else{
|
ElMessage.warning(res.message)
|
}
|
}
|
|
const initChart =(data)=>{
|
var chartDom = document.getElementById('preWarning');
|
var myChart = echarts.init(chartDom);
|
var option;
|
|
option = {
|
title: [
|
{
|
text: '近30天预警信息趋势',
|
left: '0',
|
top: '2%',
|
textStyle: {
|
fontSize: 12,
|
color: 'rgba(255,255,255,.6)',
|
fontWeight: 'normal'
|
}
|
}
|
],
|
xAxis: {
|
type: 'category',
|
data: data.map(i=>i.day) || [],
|
axisLabel:{
|
color: '#fff'
|
},
|
axisTick: {
|
show: false
|
}
|
},
|
yAxis: {
|
type: 'value',
|
splitLine: {
|
lineStyle:{
|
color: 'rgba(255,255,255,.1)',
|
type: 'dashed'
|
}
|
},
|
axisLabel:{
|
color: 'rgba(255,255,255,.6)'
|
}
|
},
|
grid: [
|
{
|
top: '15%',
|
right: '2%',
|
bottom: '10%'
|
}
|
],
|
series: [
|
{
|
data: data.map(i=>i.count) || [],
|
type: 'line',
|
label:{
|
show: true,
|
color: '#fff',
|
textBorderColor: 'transparent',
|
fontSize: 8
|
},
|
// showSymbol: false,
|
lineStyle:{
|
color: '#54d5ff'
|
},
|
itemStyle:{
|
color: '#54d5ff',
|
}
|
}
|
]
|
};
|
|
option && myChart.setOption(option);
|
}
|
|
</script>
|
|
<style lang="postcss" scoped>
|
.charts-container{
|
width: 100%;
|
height: 100%;
|
display: flex;
|
}
|
|
#preWarning{
|
flex: 2;
|
height: 100%;
|
}
|
|
.table-wrapper {
|
position: relative;
|
flex: 1;
|
height: 100%;
|
border: 1px solid rgba(255,255,255,.1);
|
border-radius: 2px;
|
overflow: hidden;
|
|
.scrollable-table {
|
width: 100%;
|
border-collapse: collapse;
|
|
th,td {
|
padding: 12px 15px;
|
color: #fff;
|
text-align: left;
|
border-bottom: 1px solid rgba(255,255,255,.1);
|
height: 36px; /* 与rowHeight一致 */
|
box-sizing: border-box;
|
font-size: 12px;
|
font-weight: normal;
|
flex: 1;
|
}
|
.red{
|
color: red
|
}
|
.yellow{
|
color: yellow
|
}
|
.blue{
|
color: #51ccff
|
}
|
th {
|
position: sticky;
|
top: 0;
|
z-index: 10; /* 确保表头在内容之上 */
|
}
|
tr{
|
background: rgb(6,38,87);
|
display: flex;
|
|
&:nth-of-type(2n){
|
background: rgb(19,72,127);
|
}
|
}
|
thead tr{
|
background: rgba(0,0,0,0);
|
}
|
}
|
.scroll-viewport {
|
position: relative;
|
overflow: hidden;
|
.scroll-content {
|
will-change: transform; /* 优化性能 */
|
}
|
.danger {
|
color: #ff2f2f;
|
animation: blink 1s infinite;
|
}
|
.warning {
|
color: yellow;
|
animation: blink 1s infinite;
|
}
|
}
|
}
|
</style>
|