<template>
|
<!-- 实时监测列表 -->
|
<div ref="containerRef" class="w-full flex justify-center" v-resize="resizeHandler">
|
<div class="inline-block">
|
<div
|
:class="`space-y-[${THICK_BORDER_WIDTH}px]`"
|
:style="{
|
border: `${THICK_BORDER_WIDTH}px solid ${BORDER_COLOR}`,
|
backgroundColor: BORDER_COLOR,
|
}"
|
>
|
<div class="flex-center font-bold text-base bg-[#8db4e2]" :style="{ height: `${CELL_HEIGHT}px` }">
|
{{ data.title }}
|
</div>
|
<div
|
v-for="(rowChunk, index) in currentRowChunkList"
|
:key="index"
|
:class="`space-y-[${THIN_BORDER_WIDTH}px]`"
|
:style="{
|
backgroundColor: BORDER_COLOR,
|
}"
|
>
|
<!-- 表头,和表格内容第一行 -->
|
<div
|
:class="`space-y-[${THICK_BORDER_WIDTH}px]`"
|
:style="{
|
backgroundColor: BORDER_COLOR,
|
}"
|
>
|
<div
|
class="flex"
|
:class="`space-x-[${THICK_BORDER_WIDTH}px]`"
|
:style="{
|
backgroundColor: BORDER_COLOR,
|
}"
|
>
|
<div
|
v-for="(item, index) in maxColsNum"
|
:key="item"
|
:class="COL_HEADER_CELL_CLASS"
|
:style="{
|
width: `${index === 0 ? firstColWidth : restColWidth}px`,
|
height: `${CELL_HEIGHT}px`,
|
backgroundColor: COL_HEADER_CELL_BG_COLOR,
|
}"
|
>
|
{{ index === 0 ? '' : rowChunk[index - 1]?.OTITLE }}
|
</div>
|
</div>
|
<MonitorContent
|
v-if="firstRow"
|
:firstColWidth="firstColWidth"
|
:restColWidth="restColWidth"
|
:title="firstRow.title"
|
:type="firstRow.id"
|
:values="rowChunk"
|
@itemClick="valueClick"
|
/>
|
</div>
|
<!-- 剩余行 -->
|
<MonitorContent
|
v-for="(row, index) in restRows"
|
:key="index"
|
:firstColWidth="firstColWidth"
|
:restColWidth="restColWidth"
|
:title="row.title"
|
:type="row.id"
|
:values="rowChunk"
|
@itemClick="valueClick"
|
/>
|
</div>
|
</div>
|
<el-pagination
|
style="margin-bottom: 0 !important"
|
small
|
hide-on-single-page
|
v-model:current-page="pageIndex"
|
v-model:page-size="pageSize"
|
layout="total,prev,pager,next,jumper"
|
:total="total"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
<RecordSetDialog v-model="chartDlgIsShow" :otype="chartDlgMapRow?.OTYPE" :oname="chartDlgMapRow?.ONAME" :indexName="indexName"/>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import _ from 'lodash';
|
import { computed, onActivated, onMounted, ref } from 'vue';
|
import MonitorContent from './MonitorContent.vue';
|
import { debounce, getTextWidth } from '/@/utils/util';
|
|
import { chatComProps } from '../../../common';
|
import {
|
BORDER_COLOR,
|
CELL_HEIGHT,
|
CELL_MAX_WIDTH,
|
COL_HEADER_CELL_BG_COLOR,
|
COL_HEADER_CELL_CLASS,
|
PAGE_HEIGHT,
|
ROW_HEADER_CELL_MAX_WIDTH,
|
THICK_BORDER_WIDTH,
|
THIN_BORDER_WIDTH,
|
} from './constants';
|
import type { Monitor, MonitorValue } from './types';
|
import RecordSetDialog from '../recordSet/RecordSetDialog.vue';
|
|
const props = defineProps(chatComProps) as {
|
data: Monitor;
|
};
|
const total = props.data?.values?.length ?? 0;
|
const pageIndex = ref(null);
|
const pageSize = ref(null);
|
|
const containerRef = ref<HTMLDivElement>(null);
|
const measureWidthOffset = 2;
|
/** @description 测量首列内容宽度 */
|
const rowHeaderCellContentWidth = computed(() => {
|
if (!props.data.rows || props.data.rows.length === 0) return 0;
|
let maxLen = 0;
|
let maxTitle = '';
|
for (const item of props.data.rows) {
|
const { title } = item;
|
const len = title.gblen();
|
if (len > maxLen) {
|
maxLen = len;
|
maxTitle = title;
|
}
|
}
|
let maxWidth = getTextWidth(maxTitle, {
|
size: '0.875rem',
|
});
|
|
maxWidth += measureWidthOffset;
|
|
if (maxWidth > ROW_HEADER_CELL_MAX_WIDTH) {
|
maxWidth = ROW_HEADER_CELL_MAX_WIDTH;
|
}
|
|
return maxWidth;
|
});
|
/** @description 测量其他列内容宽度 */
|
const colHeaderCellContentWidth = computed(() => {
|
if (!props.data.values || props.data.values.length === 0) return 0;
|
let maxLen = 0;
|
let maxTitle = '';
|
for (const item of props.data.values) {
|
const { OTITLE } = item;
|
const len = OTITLE.gblen();
|
if (len > maxLen) {
|
maxLen = len;
|
maxTitle = OTITLE;
|
}
|
}
|
|
let maxWidth = getTextWidth(maxTitle, {
|
size: '0.875rem',
|
});
|
maxWidth += measureWidthOffset;
|
|
if (maxWidth > CELL_MAX_WIDTH) {
|
maxWidth = CELL_MAX_WIDTH;
|
}
|
|
return maxWidth;
|
});
|
|
const firstColWidth = ref(rowHeaderCellContentWidth.value);
|
const restColWidth = ref(colHeaderCellContentWidth.value);
|
const calcMaxRowsNum = (groupCount: number, height, extraHeight = 0) => {
|
return Math.floor(
|
(height - 2 * THICK_BORDER_WIDTH - CELL_HEIGHT - extraHeight) /
|
(CELL_HEIGHT * groupCount + 2 * THICK_BORDER_WIDTH + THIN_BORDER_WIDTH * (groupCount - 2))
|
);
|
};
|
let maxColsNum = ref<number>(null);
|
const resizeEvent = ({ width, height }) => {
|
if (width === 0 || height === 0) {
|
return;
|
}
|
// 按最大宽度算最大列数
|
maxColsNum.value = Math.floor(
|
(width - THICK_BORDER_WIDTH + colHeaderCellContentWidth.value - rowHeaderCellContentWidth.value) /
|
(colHeaderCellContentWidth.value + THICK_BORDER_WIDTH)
|
);
|
|
const currentWidth =
|
(maxColsNum.value - 1) * colHeaderCellContentWidth.value +
|
rowHeaderCellContentWidth.value +
|
THICK_BORDER_WIDTH * (maxColsNum.value - 1) +
|
THICK_BORDER_WIDTH * 2;
|
let restWidth = width - currentWidth;
|
if (restWidth > 0) {
|
// 尽可能分给第一列
|
if (rowHeaderCellContentWidth.value + restWidth > ROW_HEADER_CELL_MAX_WIDTH) {
|
restWidth = rowHeaderCellContentWidth.value + restWidth - ROW_HEADER_CELL_MAX_WIDTH;
|
firstColWidth.value = ROW_HEADER_CELL_MAX_WIDTH;
|
} else {
|
firstColWidth.value = rowHeaderCellContentWidth.value + restWidth;
|
restWidth = 0;
|
}
|
|
// 其余分给其他列
|
if (restWidth !== 0) {
|
const averageWidth = restWidth / (maxColsNum.value - 1);
|
const currentWidth = colHeaderCellContentWidth.value + averageWidth;
|
restColWidth.value = currentWidth > CELL_MAX_WIDTH ? CELL_MAX_WIDTH : currentWidth;
|
}
|
}
|
|
const groupCount = (props.data?.rows?.length ?? 0) + 1;
|
|
// 按最大高度算最大行数
|
let rowsNum = calcMaxRowsNum(groupCount, height);
|
|
// 按最大列数铺
|
const maxColsRowsNum = Math.ceil(total / maxColsNum.value);
|
const isNeedPage = maxColsRowsNum > rowsNum;
|
rowsNum = isNeedPage ? calcMaxRowsNum(groupCount, height, PAGE_HEIGHT) : maxColsRowsNum;
|
// rowsNum 行,maxColsNum列,第一列不算
|
pageSize.value = isNeedPage
|
? rowsNum * (maxColsNum.value - 1)
|
: total % (maxColsNum.value - 1) === 0
|
? total
|
: (Math.floor(total / (maxColsNum.value - 1)) + 1) * (maxColsNum.value - 1);
|
pageIndex.value = 1;
|
// isNeedPage 是否分页,rowsNum 行数,maxColsNum 列数,
|
};
|
const resizeHandler = debounce(resizeEvent);
|
|
const handleCurrentChange = () => {};
|
|
const firstRow = computed(() => props.data?.rows?.[0]);
|
const restRows = computed(() => props.data?.rows?.slice(1));
|
const pageChunkList = computed(() => {
|
const chunkResult = _.chunk(props.data.values ?? [], pageSize.value);
|
const last = chunkResult.at(-1);
|
if (last) {
|
const restNum = pageSize.value - last.length;
|
const emptyData = _.fill(Array(restNum), {
|
ONAME: '',
|
OTIME: '',
|
OTITLE: '',
|
OTYPE: '',
|
} as MonitorValue);
|
const lastData = last.concat(emptyData);
|
chunkResult[chunkResult.length - 1] = lastData;
|
}
|
|
return chunkResult;
|
});
|
const currentPageChunk = computed(() => {
|
pageChunkList.value;
|
if (pageIndex.value == null) return [];
|
const pageChunk = pageChunkList.value[pageIndex.value - 1];
|
|
return pageChunk;
|
});
|
|
const currentRowChunkList = computed(() => {
|
if (!currentPageChunk.value || currentPageChunk.value.length === 0) return [];
|
const chunkResult = _.chunk(currentPageChunk.value, maxColsNum.value - 1);
|
return chunkResult;
|
});
|
|
//#region ====================== 点击看曲线 ======================
|
|
const chartDlgIsShow = ref(false);
|
const chartDlgMapRow = ref(null);
|
/** @description 指标名称 */
|
const indexName = ref(null);
|
const valueClick = (item,type) => {
|
chartDlgMapRow.value = item;
|
chartDlgIsShow.value = true;
|
indexName.value = type;
|
};
|
//#endregion
|
|
// 计算最大列数
|
// (x-1)* cellWidth + rowHeaderCellContentWidth.value+thickBorderWidth*(x-1)+thickBorderWidth*2 <= width;
|
|
// x*(cellWidth+thickBorderWidth)+thickBorderWidth - cellWidth + rowHeaderCellContentWidth.value<=width;
|
// x<= (width-thickBorderWidth + cellWidth-rowHeaderCellContentWidth.value)/(cellWidth+thickBorderWidth);
|
|
// const groupCount = (TEST_DATA?.rows?.length ?? 0) + 1;
|
// 计算最大行数
|
// y * (cellHeight * groupCount) +
|
// (y - 1) * (2 * thickBorderWidth) +cellHeight+thickBorderWidth
|
// thickBorderWidth +
|
// thickBorderWidth * 2 +
|
// y * (groupCount - 2) * thinBorderWidth <=
|
// height;
|
|
// (cellHeight * groupCount + 2 * thickBorderWidth + thinBorderWidth(groupCount - 2) * y + thickBorderWidth <=height;
|
|
// y<= (height-thickBorderWidth)/(cellHeight * groupCount + 2 * thickBorderWidth + thinBorderWidth(groupCount - 2) )
|
|
onMounted(() => {
|
resizeEvent({
|
width: containerRef.value.clientWidth,
|
height: 0.7 * document.body.clientHeight,
|
});
|
});
|
</script>
|
<style scoped lang="scss">
|
:deep(.space-y-\[2px\] > :not([hidden]) ~ :not([hidden])) {
|
--tw-space-y-reverse: 0;
|
margin-top: calc(2px * calc(1 - var(--tw-space-y-reverse)));
|
margin-bottom: calc(2px * var(--tw-space-y-reverse));
|
}
|
:deep(.space-y-\[1px\] > :not([hidden]) ~ :not([hidden])) {
|
--tw-space-y-reverse: 0;
|
margin-top: calc(1px * calc(1 - var(--tw-space-y-reverse)));
|
margin-bottom: calc(1px * var(--tw-space-y-reverse));
|
}
|
|
:deep(.space-x-\[2px\] > :not([hidden]) ~ :not([hidden])) {
|
--tw-space-x-reverse: 0;
|
margin-right: calc(2px * var(--tw-space-x-reverse));
|
margin-left: calc(2px * calc(1 - var(--tw-space-x-reverse)));
|
}
|
:deep(.space-x-\[1px\] > :not([hidden]) ~ :not([hidden])) {
|
--tw-space-x-reverse: 0;
|
margin-right: calc(1px * var(--tw-space-x-reverse));
|
margin-left: calc(1px * calc(1 - var(--tw-space-x-reverse)));
|
}
|
</style>
|