2 changed files with 489 additions and 227 deletions
@ -0,0 +1,311 @@
@@ -0,0 +1,311 @@
|
||||
<template> |
||||
<div class="app-container app-container-bg"> |
||||
<el-card class="first-card" ref='firstCard' shadow="always"> |
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" @submit.native.prevent> |
||||
<el-form-item label="测站属性" prop="prop"> |
||||
<el-select v-model="queryParams.prop" placeholder="请选择测站属性" style="width:100%" @change="propChange"> |
||||
<el-option v-for="dict in propsList" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item label="测站名称" prop="stnmId"> |
||||
<el-select v-model="queryParams.stnmId" placeholder="请选择测站名称" style="width:100%" @change="handleQuery"> |
||||
<el-option v-for="dict in stationList" :key="dict.stnmId" :label="dict.stnm" :value="dict.stnmId"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
<el-form-item> |
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> |
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button> |
||||
</el-form-item> |
||||
</el-form> |
||||
<el-row :gutter="10" class="mb8"> |
||||
<el-col :span="1.5"> |
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['data:currdata:export']">导出</el-button> |
||||
</el-col> |
||||
</el-row> |
||||
</el-card> |
||||
<div class="el-card-p card-shadow carder-border mt10 pad10 currdata" v-loading="fullscreenLoading"> |
||||
<div class="table-container" v-if="processedTables.length > 0" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="30"> |
||||
<div class="table-grid" :style="{ gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)` }"> |
||||
<div class="table-item" v-for="(table, index) in processedTables" :key="index"> |
||||
<el-table :data="table.data" class="double-header-table" :show-header="true" :header-cell-style="{ backgroundColor: '#3F7DEC !important', }" style="width: 100%;" size="mini"> |
||||
<el-table-column :label="table.stnm" width="120" show-overflow-tooltip> |
||||
<template #header #default="scope"> |
||||
<div class="header-content"> |
||||
<el-tooltip effect="dark" :content="table.stnm" placement="top-end" :open-delay="300"> |
||||
<div class="item-station cursor"> |
||||
<div> |
||||
{{ table.stnm }} |
||||
</div> |
||||
<div>{{ table.stcd }}</div> |
||||
</div> |
||||
</el-tooltip> |
||||
<div class="header-right "> |
||||
<span class="item-time">{{ table.tm }}</span> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<el-table-column prop="typeName" label="名称" show-overflow-tooltip /> |
||||
<el-table-column prop="value" label="值" :class-name="value-name" /> |
||||
<el-table-column prop="unit" label="单位" width="80" /> |
||||
</el-table-column> |
||||
</el-table> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<el-empty class="table-container " v-else :image-size="200"></el-empty> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<script setup> |
||||
import { ref, reactive, onMounted, } from 'vue' |
||||
import _ from 'lodash' |
||||
const { proxy } = getCurrentInstance() |
||||
const alignment = 'center' |
||||
const queryParams = reactive({ |
||||
page: 1, |
||||
limit: 10, |
||||
stnmId: '', |
||||
prop: "", |
||||
mainType: "A" |
||||
}) |
||||
const fullscreenLoading = ref(false) |
||||
let currdataList = [] |
||||
let total = 0 |
||||
const getList = async () => { |
||||
fullscreenLoading.value = true; |
||||
try { |
||||
const res = await proxy.axiosGet('/data/currdata/queryAll', queryParams) |
||||
if (res.code == 0) { |
||||
currdataList = res.data |
||||
total = currdataList.length |
||||
formatTableData() |
||||
} |
||||
|
||||
} catch (error) { |
||||
} finally { |
||||
fullscreenLoading.value = false |
||||
} |
||||
} |
||||
let tableList = ref([]) |
||||
const formatTableData = () => { |
||||
const result = _.chain(currdataList) |
||||
.groupBy('stnm') |
||||
.map((group, stnm) => ({ |
||||
stnm, |
||||
stcd: group[0].stcd, |
||||
tm: group[0].latestTm, |
||||
data: group.map(item => ({ |
||||
...item, |
||||
value: item.val !== null ? item.val : item.latestValue |
||||
})) |
||||
})) |
||||
.value(); |
||||
tableList.value = result |
||||
} |
||||
// 滚动加载更多 |
||||
const busy = ref(false) |
||||
const loadMore = async () => { |
||||
let all = total <= queryParams.page * queryParams.limit |
||||
if (busy.value && all) return; // 如果已经在加载中,则不执行加载操作 |
||||
busy.value = true; // 设置加载状态为忙碌 |
||||
queryParams.page += 1 |
||||
let response = await proxy.axiosGet('/data/currdata/queryAll', queryParams); |
||||
if (response.code == 0) { |
||||
let rawData = response.data |
||||
let concatData = currdataList.concat(rawData) |
||||
currdataList = concatData |
||||
formatTableData() |
||||
} |
||||
busy.value = false; |
||||
|
||||
} |
||||
const itemsPerRow = ref(5) |
||||
const processedTables = computed(() => { |
||||
let data = tableList.value |
||||
const result = []; |
||||
const rows = Math.ceil(data.length / itemsPerRow.value); |
||||
|
||||
for (let i = 0; i < rows; i++) { |
||||
const startIndex = i * itemsPerRow.value; |
||||
const endIndex = Math.min(startIndex + itemsPerRow.value, data.length); |
||||
const rowTables = data.slice(startIndex, endIndex); |
||||
|
||||
// 找出当前行中数据最多的表格 |
||||
const maxRows = Math.max(...rowTables.map(table => table.data.length)); |
||||
|
||||
// 处理当前行的每个表格 |
||||
rowTables.forEach(table => { |
||||
const newTable = { ...table }; |
||||
|
||||
// 如果数据行数不足,补充空行 |
||||
if (table.data.length < maxRows) { |
||||
const emptyRows = Array(maxRows - table.data.length).fill({}); |
||||
newTable.data = [...table.data, ...emptyRows]; |
||||
} |
||||
|
||||
|
||||
result.push(newTable); |
||||
}); |
||||
} |
||||
|
||||
return result; |
||||
}) |
||||
// 根据测站属性获取测站名称 |
||||
const stationList = ref([]) |
||||
const propChange = async () => { |
||||
try { |
||||
let res = await proxy.axiosGet('/basic/station/queryStnmandStnmId', queryParams); |
||||
if (res.code == 200) { |
||||
stationList.value = res.data; |
||||
} |
||||
} catch (error) { |
||||
|
||||
} |
||||
} |
||||
/** 搜索按钮操作 */ |
||||
const handleQuery = () => { |
||||
queryParams.pageNum = 1 |
||||
getList() |
||||
} |
||||
const resetQuery = () => { |
||||
proxy.resetForm("queryForm"); |
||||
handleQuery(); |
||||
} |
||||
// 导出按钮 |
||||
const handleExport = async () => { |
||||
let p = { |
||||
page: 1, |
||||
limit: 9999, |
||||
stnm: queryParams.stnm, |
||||
mainType: queryParams.mainType, |
||||
} |
||||
let res = await proxy.axiosGet('/data/currdata/queryAll', p); |
||||
if (res.code === 0) { |
||||
let table = []; |
||||
table.push({ |
||||
A: "站点名称", |
||||
B: "设备ID", |
||||
C: "类型", |
||||
D: "最新数值", |
||||
E: "最新上传时间", |
||||
}); |
||||
res.data.forEach(d => { |
||||
let row = { |
||||
A: d.stnm, |
||||
B: d.stcd, |
||||
C: d.typeName, |
||||
D: d.latestValue, |
||||
E: d.latestTm |
||||
}; |
||||
table.push(row); |
||||
}); |
||||
let header = ["A", "B", "C", "D", "E"]; |
||||
let fileName = "站点实时数据"; |
||||
proxy.exportExcel(header, table, fileName); |
||||
} |
||||
} |
||||
|
||||
onMounted(() => { |
||||
getList() |
||||
propChange() |
||||
}) |
||||
const propsList = ref([ |
||||
{ label: '水文测站', value: 0 }, |
||||
{ label: '气象站', value: 1 } |
||||
]) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.currdata { |
||||
overflow-y: scroll; |
||||
} |
||||
|
||||
.table-container { |
||||
width: 100%; |
||||
|
||||
.table-grid { |
||||
display: grid; |
||||
grid-template-columns: repeat(var(--grid-columns), 1fr); |
||||
gap: 20px; |
||||
width: 100%; |
||||
|
||||
.table-item { |
||||
min-width: 240px; |
||||
/* 防止表格溢出*/ |
||||
} |
||||
} |
||||
|
||||
.header-content { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
flex-wrap: nowrap; |
||||
|
||||
.item-station { |
||||
width: 150px; |
||||
white-space: nowrap !important; |
||||
text-overflow: ellipsis; |
||||
word-break: break-all; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
|
||||
.item-station, |
||||
.item-icon, |
||||
.item-time { |
||||
font-size: 12px; |
||||
color: #fff; |
||||
/* flex-wrap: nowrap; */ |
||||
|
||||
} |
||||
|
||||
.item-icon { |
||||
cursor: pointer; |
||||
margin-left: 2px; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/* 表格样式 */ |
||||
:deep(.double-header-table) { |
||||
border-radius: 12px; |
||||
|
||||
&::before { |
||||
display: none; |
||||
} |
||||
|
||||
.el-table__fixed-right::before { |
||||
display: none; |
||||
} |
||||
|
||||
.el-table__body-wrapper::-webkit-scrollbar { |
||||
display: none; |
||||
} |
||||
|
||||
/* 统一行高 */ |
||||
.el-table__row { |
||||
height: 39.6667px; |
||||
} |
||||
|
||||
/* 空行样式 */ |
||||
.el-table__row--empty { |
||||
background-color: #f5f7fa; |
||||
} |
||||
|
||||
/* 隐藏子表头 */ |
||||
.el-table__header tr:nth-child(2) { |
||||
display: none; |
||||
} |
||||
|
||||
/* 调整主表头样式 */ |
||||
.el-table__header tr:first-child th { |
||||
background: #f5f7fa; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
|
||||
/** 取消表格滑上的背景色 */ |
||||
:deep(.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell) { |
||||
background: #fff !important; |
||||
} |
||||
</style> |
||||
Loading…
Reference in new issue