You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
maotu-webtopo/src/components/vue-xq-test/vue-synthesize-table.vue

582 lines
13 KiB
Vue

1 month ago
<template>
3 weeks ago
<div class="table-container">
<el-card class="card" shadow="hover" :body-style="{ padding: '10px' }">
<h2 class="cardHead">运行信息</h2>
<div class="table-wrapper" v-loading="arr.length === 0">
<el-table
:data="arr"
:span-method="objectSpanMethods"
style="width: 100%"
class="full-height-table"
@cell-click="handleCellClick"
>
<el-table-column prop="floorName" label="楼层" />
<el-table-column prop="id" label="设备ID" />
<el-table-column prop="name" label="设备名称" />
<el-table-column label="绑定">
<template #default="{ row }">
<el-tag :type="row.isBinding ? 'primary' : 'info'">
{{ row.isBinding ? '绑定' : '待绑' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="设备状态">
<template #default="{ row }">
<el-tag :type="row.eState === 0 ? 'success' : 'warning'">
{{ row.eState === 0 ? '正常' : '故障' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="当前状态">
<template #default="{ row }">
<el-tag v-if="row.currentState === 0" type="success"></el-tag>
<el-tag v-else-if="row.currentState === 1" type="info">停止</el-tag>
<el-tag v-else type="error">报警</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" class="operation-btn" v-if="row.operation">
屏蔽
</el-button>
<el-button type="primary" class="operation-btn" v-else> </el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
1 month ago
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus';
3 weeks ago
import { ElMessage } from 'element-plus';
import { computed, onMounted, onUnmounted, ref, watch, reactive } from 'vue';
import { modelApi } from '@/utils/request';
import emitter from '@/utils/emitter';
import { type DataItem } from '@/components/mt-edit/store/types';
1 month ago
3 weeks ago
const loading = ref(false);
// 导入全局类型定义
/// <reference path="../../../global.d.ts" />
interface RecRuntimeData {
double: number;
node: {
name: string;
};
}
interface RecServiceType {
service: {
node: {
runtimes: Record<string, RecRuntimeData>;
};
};
}
// interface ExtendedParentWindow extends Window {
// Rec?: RecServiceType;
// }
3 weeks ago
interface ExtendedParentWindow extends Window {
globalData: Map<string, DataItem> | Record<string, DataItem>;
3 weeks ago
}
1 month ago
interface User {
id: string;
name: string;
amount1: string;
amount2: string;
amount3: number;
}
interface Equipment {
id: string; //设备ID
address?: string; //设备地址
name: string; //设备名称
eState: number; //设备状态 0正常 1故障
currentState: number; //当前状态 0运行 1停止 2报警
operation: boolean; //操作 true屏蔽 false取消屏蔽
}
interface FloorObj {
floorName: string; //地址
equipments: Equipment[];
}
3 weeks ago
// node楼层节点
interface FloorNode {
roomId: string;
floorName: string;
eqpList: EquipmentNode[];
}
//node
interface EquipmentNode {
id: string; //设备ID
name: string; //设备名称
isBinding: boolean; //是否绑定
eState: number; //设备状态 0正常 1故障
currentState: number; //当前状态 0运行 1停止 2报警
operation: boolean; //操作 true屏蔽 false取消屏蔽
}
1 month ago
3 weeks ago
function handleCellClick(obj: any) {
console.log('点击:', obj);
emitter.emit('binding-obj-facility-move', obj.id);
}
emitter.on('binding-data-update', () => {
console.log('@@binding-data-update');
dataInit();
});
const props = defineProps({
fontFamily: {
type: String,
default: '黑体'
},
fontSize: {
type: Number,
default: 12
},
testColor: {
type: String,
default: '#ffffff'
},
definitionItemJson: {
type: Object,
default: () => ({})
}
});
console.log('父传子itemjson:', props.definitionItemJson);
// 计算属性——既读取又修改
let computedSize = computed({
// 读取
get() {
return props.fontSize + 'px';
}, // 修改
set(val) {}
});
const arr = ref<any[]>([]);
let targetDataTable: FloorNode[] = [];
let initArrs: any = {};
//数据初始化
async function dataInit() {
// 从 window 获取 globalData可能是 Map 或对象)
const globalDataRaw = (window as unknown as ExtendedParentWindow).globalData;
3 weeks ago
// 清空数组
arr.value = [];
targetDataTable = [];
loading.value = true;
const response = await modelApi.oneRoomFor_Equipment_get();
if (response.code == 200 && response.data && response.data.length > 0) {
// console.log('公共:', window.parent.Rec.service.node.runtimes);
response.data.forEach((floor: any) => {
let targetData: FloorNode = {
roomId: floor.roomId,
floorName: floor.roomName,
eqpList: []
};
let eqpList: EquipmentNode[] = [];
floor.eqpList.forEach((eqp: any) => {
let currentState = 1;
// 根据 globalData 类型选择访问方式
const getNodeData = (key: string) => {
if (globalDataRaw instanceof Map) {
return globalDataRaw.get(key);
} else {
return (globalDataRaw as Record<string, any>)[key];
}
};
3 weeks ago
//故障
if (getNodeData(eqp.nodes[1])?.double != 1) currentState = 1;
else if (getNodeData(eqp.nodes[2])?.double == 1) currentState = 2;
else if (getNodeData(eqp.nodes[1])?.double == 1) currentState = 0;
3 weeks ago
let eqpNode: EquipmentNode = {
id: eqp.id,
name: getNodeData(eqp.nodes[0])?.node?.name || '',
eState: getNodeData(eqp.nodes[0])?.double || 0,
3 weeks ago
currentState: currentState,
isBinding: eqp.isBinding,
operation: getNodeData(eqp.nodes[3])?.double == 1
3 weeks ago
};
eqpList.push(eqpNode);
});
targetData.eqpList = eqpList;
targetDataTable.push(targetData);
});
ElMessage.success('获取接口数据成功');
arr.value = targetDataTable.flatMap((floor) =>
floor.eqpList.map((equipment) => ({
...equipment,
floorName: floor.floorName,
roomId: floor.roomId
}))
);
} else {
ElMessage.error('获取接口数据失败');
}
}
// 将嵌套数据展开为表格数据
const tableDatas = computed(() => {
return targetDataTable.flatMap((floor) =>
floor.eqpList.map((equipment) => ({
...equipment,
floorName: floor.floorName, // 添加楼层信息到每行
roomId: floor.roomId // 添加设备地址到每行
}))
);
});
// 在 onMounted 中
onMounted(async () => {
await dataInit();
});
onUnmounted(() => {
emitter.off('binding-data-update');
});
// 数据源头
1 month ago
const floorData: FloorObj[] = [
{
floorName: '安全工器具室',
equipments: [
{
3 weeks ago
id: 'smokeDetector01',
1 month ago
name: '1号感烟探头',
eState: 0,
currentState: 0,
operation: true
},
{
3 weeks ago
id: 'smokeDetector02',
1 month ago
name: '2号感烟探头',
eState: 0,
currentState: 0,
operation: true
}
]
},
{
floorName: '蓄电池室',
equipments: [
{
3 weeks ago
id: 'smokeDetector03',
1 month ago
name: '3号感烟探头',
eState: 1,
currentState: 1,
operation: false
},
{
3 weeks ago
id: 'smokeDetector04',
1 month ago
name: '4号感烟探头',
eState: 0,
currentState: 0,
operation: true
}
]
},
{
floorName: '220kV保护室',
equipments: [
{
3 weeks ago
id: 'smokeDetector05',
1 month ago
name: '5号感烟探头',
eState: 0,
currentState: 2,
operation: false
},
{
3 weeks ago
id: 'smokeDetector06',
1 month ago
name: '6号感烟探头',
eState: 1,
currentState: 1,
operation: true
}
]
},
{
floorName: '380kV配电室',
equipments: [
{
3 weeks ago
id: 'smokeDetector07',
1 month ago
name: '7号感烟探头',
eState: 0,
currentState: 0,
operation: false
},
{
3 weeks ago
id: 'smokeDetector08',
1 month ago
name: '8号感烟探头',
eState: 0,
currentState: 2,
operation: true
}
]
},
{
floorName: '35kV高压室',
equipments: [
{
3 weeks ago
id: 'smokeDetector09',
1 month ago
name: '9号感烟探头',
eState: 1,
currentState: 1,
operation: false
},
{
3 weeks ago
id: 'smokeDetector10',
1 month ago
name: '10号感烟探头',
eState: 0,
currentState: 0,
operation: true
}
]
},
{
floorName: '2号接地变室',
equipments: [
{
3 weeks ago
id: 'smokeDetector11',
1 month ago
name: '11号感烟探头',
eState: 0,
currentState: 2,
operation: false
},
{
3 weeks ago
id: 'smokeDetector12',
1 month ago
name: '12号感烟探头',
eState: 1,
currentState: 1,
operation: true
}
]
},
{
floorName: '110kV电缆室',
equipments: [
{
3 weeks ago
id: 'smokeDetector13',
1 month ago
name: '13号感烟探头',
eState: 0,
currentState: 0,
operation: false
},
{
3 weeks ago
id: 'smokeDetector14',
1 month ago
name: '14号感烟探头',
eState: 0,
currentState: 0,
operation: true
}
]
},
{
floorName: '2号站用变室',
equipments: [
{
3 weeks ago
id: 'smokeDetector15',
1 month ago
name: '15号感烟探头',
eState: 0,
currentState: 0,
operation: false
},
{
3 weeks ago
id: 'smokeDetector16',
1 month ago
name: '16号感烟探头',
eState: 0,
currentState: 0,
operation: true
}
]
},
{
floorName: '生产综合楼1楼走廊',
equipments: [
{
3 weeks ago
id: 'smokeDetector17',
1 month ago
name: '17号感烟探头',
eState: 0,
currentState: 0,
operation: false
},
{
3 weeks ago
id: 'smokeDetector18',
1 month ago
name: '18号感烟探头',
eState: 0,
currentState: 0,
operation: true
},
{
id: '10028',
name: '1号声光报警器',
eState: 0,
currentState: 0,
operation: false
},
{
id: '10029',
name: '2号声光报警器',
eState: 0,
currentState: 0,
operation: true
},
{
id: '10030',
name: '1号手报',
eState: 0,
currentState: 0,
operation: false
},
{
id: '10031',
name: '2号手报',
eState: 0,
currentState: 0,
operation: true
}
]
}
];
interface SpanMethodProps {
row: any;
column: TableColumnCtx<User>;
rowIndex: number;
columnIndex: number;
}
3 weeks ago
const objectSpanMethods = ({ row, columnIndex }: SpanMethodProps) => {
if (columnIndex === 0) {
// 查找当前行对应的楼层数据
const floor = targetDataTable.find((f) => f.floorName === row.floorName);
if (floor) {
// 找到该楼层下第一个设备的索引
const firstEquipmentIndex = floor.eqpList.findIndex((e) => e.id === row.id);
if (firstEquipmentIndex === 0) {
// 如果是第一个设备,合并该楼层的所有行
return {
rowspan: floor.eqpList.length,
colspan: 1
1 month ago
};
} else {
// 如果不是第一个设备,不显示(被合并)
return {
rowspan: 0,
colspan: 0
};
}
}
}
// 其他列不合并
return {
rowspan: 1,
colspan: 1
};
};
// 将嵌套数据展开为表格数据
const tableData = computed(() => {
return floorData.flatMap((floor) =>
floor.equipments.map((equipment) => ({
...equipment,
floorName: floor.floorName, // 添加楼层信息到每行
// 如果有设备地址就显示,没有就显示楼层作为地址
address: equipment.address || floor.floorName
}))
);
});
</script>
<style scoped>
3 weeks ago
.table-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.card :deep(.el-card__body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 10px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.full-height-table {
flex: 1;
height: 100%;
}
.full-height-table :deep(.el-table__body-wrapper) {
flex: 1;
overflow-y: auto;
}
.cardHead {
margin: 0 0 15px 0;
padding: 0;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #ffffff;
flex-shrink: 0;
}
1 month ago
.operation-btn {
3 weeks ago
width: 60px;
min-width: 50px;
1 month ago
padding: 8px 12px;
3 weeks ago
height: 30px;
}
/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
font-size: 13px;
font-weight: bold;
}
/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
}
/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
font-size: v-bind('computedSize'); /* 标签内的文字可以稍小一些 */
}
/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
font-size: v-bind('computedSize');
color: v-bind('props.testColor');
1 month ago
}
</style>