<script setup lang="ts">
import { Empty } from 'ant-design-vue';
export interface TBColumn {
title: string
dataIndex: string
// key: string
ellipsis?: boolean
width?: string
align?: string
[key: string]: any
}
const props = withDefaults(defineProps<{
modelValue: any[] // 重要: 外部在使用这个的时候,不要修改,要通过endSuccess这些方法来修改
columns: TBColumn[]
defaultPageSize: number
defaultPage: number
}>(), {
modelValue: () => [],
columns: () => [],
defaultPageSize: 10,
defaultPage: 1,
});
const emit = defineEmits<{
(e: 'update:modelValue', val: any[]): void
(e: 'load', val: { page: number, pageSize: number }): void
(e: 'clickRow', val: any): void
}>();
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
const dataSource = ref<any[]>([]);
const page = ref(props.defaultPage);
const pageSize = ref(props.defaultPageSize);
const noMoreData = ref(false); // 是否有更多数据
const loading = ref(false); // 是否正在加载中
let lockFlag = false; // 锁,用于保证一次加载只能调用一次回调方法
const clickIdx = ref(-1); // 当前点击的数据序号
watch(() => props.modelValue, () => {
dataSource.value = props.modelValue || [];
}, { immediate: true });
onMounted(() => {
// dataSource.value = [];
// page.value = props.defaultPage;
// pageSize.value = props.defaultPageSize;
// noMoreData.value = false;
// loading.value = false;
nextTick(() => {
lockFlag = false;
emit('load', { page: page.value, pageSize: pageSize.value });
});
});
/**
* 加载更多
*/
function loadMore() {
if (noMoreData.value) {
return;
}
if (loading.value) {
return;
}
loading.value = true;
lockFlag = false;
emit('load', { page: page.value, pageSize: pageSize.value });
}
function endSuccess(data: any[]) {
if (lockFlag) {
return;
}
lockFlag = true;
if (page.value === 1) {
dataSource.value = data;
}
else {
dataSource.value = [...dataSource.value, ...data];
}
if (data.length < pageSize.value) {
noMoreData.value = true;
}
else {
noMoreData.value = false;
page.value += 1;
}
emit('update:modelValue', [...dataSource.value]);
loading.value = false;
}
function endError() {
if (lockFlag) {
return;
}
lockFlag = true;
loading.value = false;
}
function reload() {
if (loading.value && page.value === props.defaultPage) {
return;
}
dataSource.value = [];
page.value = props.defaultPage;
pageSize.value = props.defaultPageSize;
noMoreData.value = false;
loading.value = false;
clickIdx.value = -1;
emit('update:modelValue', []);
lockFlag = false;
emit('load', { page: page.value, pageSize: pageSize.value });
}
function onClickRow(val: any) {
if (clickIdx.value === val.index) {
clickIdx.value = -1;
}
else {
clickIdx.value = val.index;
}
emit('clickRow', { ...val, highlighted: clickIdx.value !== -1 });
}
function deselectRow() {
clickIdx.value = -1;
}
defineExpose({
endSuccess,
endError,
reload,
deselectRow,
});
</script>
<template>
<div class="loadmore-table">
<div class="loadmore-table-head">
<div
v-for="(column, index) in columns"
:key="index"
class="loadmore-table-th"
:style="{
width: column.width ? column.width : 'auto',
textAlign: column.align ? column.align : 'center',
}"
>
{{ column.title }}
</div>
</div>
<ScrollLoad class="loddmore-table-body" @load-more="loadMore">
<div v-if="!dataSource.length">
<a-empty :image="simpleImage" />
</div>
<div v-else>
<div
v-for="(record, index) in dataSource"
:key="index"
class="loadmore-table-tr"
:class="[clickIdx === index ? 'actived-cls' : '']"
>
<div
v-for="(column, idx) in columns"
:key="idx"
class="loadmore-table-td"
:style="{
width: column.width ? column.width : 'auto',
textAlign: column.align ? column.align : 'center',
}"
@click="onClickRow({ text: record[column.dataIndex], record, index, column })"
>
<div class="loadmore-table-td-con" :class="[column.ellipsis ? 'ellipsis' : '']">
<slot name="bodyCell" :text="record[column.dataIndex]" :record="record" :index="index" :column="column">
<a-tooltip>
<template #title>
{{ record[column.dataIndex] || '' }}
</template>
{{ record[column.dataIndex] || '' }}
</a-tooltip>
</slot>
</div>
</div>
</div>
</div>
</ScrollLoad>
</div>
</template>
<style lang="less" scoped>
.loadmore-table {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.loadmore-table-head {
display: flex;
background-color: rgba(28, 85, 155, 0.7);
.loadmore-table-th {
flex-shrink: 1;
flex-grow: 1;
position: relative;
padding: 7px 5px;
// height: 34px;
line-height: 20px;
font-weight: 500;
font-size: 15px;
color: #FFFFFF;
&::after {
content: '';
display: inline-block;
width: 1px;
height: 20px;
background-color: #1C559B;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
}
}
}
.loddmore-table-body {
flex: 1;
overflow: auto;
padding-top: 4px;
.loadmore-table-tr {
display: flex;
.loadmore-table-td {
flex-shrink: 1;
flex-grow: 1;
display: flex;
align-items: center;
// height: 40px;
line-height: 20px;
padding: 10px 5px;
font-weight: 400;
font-size: 15px;
color: rgba(255, 255, 255, 0.9);
overflow: hidden;
.loadmore-table-td-con {
flex-grow: 1;
flex-shrink: 1;
}
}
}
.loadmore-table-tr:nth-of-type(2n) {
background-color: rgba(10, 46, 81, 0.4);
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
</style>
<script setup lang="ts">
import dayjs from 'dayjs';
import loadMoreTable from '@/views/components/loadMoreTable.vue';
import type { TBColumn } from '@/views/components/loadMoreTable.vue';
import { postAlarmAlarmSum } from '@/api/modules/backend';
const emit = defineEmits<{
(e: 'choose', val: any): void
(e: 'addAlarm', val: any): void
}>();
const tableRef = ref();
const list = ref<any[]>([]);
// 表格选项
const columns: TBColumn[] = [
{
title: '设备ID/SN',
dataIndex: 'deviceSn',
key: 'deviceSn',
ellipsis: true,
width: '48%',
align: 'left',
},
{
title: '更新时间',
dataIndex: 'maxAlarmTime',
key: 'maxAlarmTime',
ellipsis: true,
width: '24%',
align: 'center',
},
{
title: '告警',
dataIndex: 'alarmCount',
key: 'alarmCount',
ellipsis: true,
width: '14%',
align: 'center',
},
{
title: '处置',
dataIndex: 'alarmStatus',
key: 'alarmStatus',
ellipsis: true,
width: '14%',
align: 'center',
},
];
async function featchData(pageConfig: { page: number, pageSize: number }) {
try {
const params = {
currentPage: pageConfig.page,
pageSize: pageConfig.pageSize,
};
const res = await postAlarmAlarmSum(params);
if (res.success) {
const arr = res.data?.records || [];
tableRef.value.endSuccess(arr);
}
else {
tableRef.value.endError();
}
}
/* eslint-disable-next-line */
catch (error) {
tableRef.value.endError();
}
}
function onClickRow(val: any) {
const obj = { ...val.record, highlighted: val.highlighted };
emit('choose', obj);
emit('addAlarm', obj);
}
function deselectRow() {
tableRef.value.deselectRow();
}
function getData() {
tableRef.value?.reload();
}
defineExpose({
getData,
deselectRow,
});
</script>
<template>
<div class="w-full h-full">
<loadMoreTable
ref="tableRef"
v-model="list"
:columns="columns"
:default-page-size="25"
:default-page="1"
@load="featchData"
@click-row="onClickRow"
>
<template #bodyCell="{ column, text }">
<template v-if="column.dataIndex === 'maxAlarmTime'">
<div>{{ text ? dayjs(text).format('HH:mm:ss') : '' }}</div>
</template>
<template v-if="column.dataIndex === 'alarmCount'">
<div class="text-[#FF4242] font-medium">
{{ text }}
</div>
</template>
<template v-if="column.dataIndex === 'alarmStatus'">
<div :class="[text === '1' ? 'tag-gray' : text === '3' ? 'tag-green' : '']">
{{ text === '1' ? '否' : text === '3' ? '是' : text }}
</div>
</template>
</template>
</loadMoreTable>
</div>
</template>
<style lang="less" scoped>
.tag-green {
width: 28px;
height: 20px;
background: #002800;
background-image: radial-gradient(circle at 50% 100%, #00ff47c9 0%, #00430b00 76%);
box-shadow: inset 0 0 20px 0 #00ff0361;
border-radius: 2px;
}
.tag-gray {
width: 28px;
height: 20px;
background: #333333;
background-image: radial-gradient(circle at 50% 100%, #cdcdcdc9 0%, #43434300 76%);
box-shadow: inset 0 0 20px 0 #cfcfcf61;
border-radius: 2px;
}
:deep(.loadmore-table) {
.loadmore-table-td {
color: rgba(255, 255, 255, 0.6) !important;
}
.actived-cls {
box-shadow: 0 0 9px 0 #32669C, inset 0 0 21px 0 #4B8ED3;
background-color: rgba(10, 46, 81, 1) !important;
border-radius: 4px;
}
}
</style>