vue3项目使用@micosoft/signalr(长链接/服务端推送到客户端),Web实时通信signalr

适用于:vue3项目使用@micosoft/signalr(长链接/服务端推送到客户端),大数据看板后台接口自动定时推送前端接收渲染
推送接口地址:在这里插入图片描述
先安装"@microsoft/signalr": “^7.0.10”,
npm install @microsoft/signalr

import * as signalR from '@microsoft/signalr'
const connection =new signalR.HubConnectionBuilder()
			.withUrl("/hubs/j03/kanban")
		    .withAutomaticReconnect({
		        nextRetryDelayInMilliseconds: function (val) {
		          // _this.$TF.closeLoading()
		          let arr = [1000, 5000, 10000, 30000]
		          if (val.previousRetryCount <= 3) {
		            return arr[val.previousRetryCount]
		          } else {
		            return arr[3]
		          }
		        }
		      })
		    .configureLogging(signalR.LogLevel.Information)
		    .build();
   	   //接口推送1
		connection.on('receivedDeviceRealTimeInfos', function (infos){
		    console.log(123,infos);//拿到后台推送的数据
			});
		//接口推送2
		connection.on('receivedDeviceStopTop5', function (infos){
		    console.log('停机TOP5',infos);;//拿到后台推送的数据
		});
		//接口推送3
		connection.on('receivedDeviceAlarm', function (infos){
		    console.log('报警',infos);;//拿到后台推送的数据
		});
	
	
		async function start() {
		    try {
		        await connection.start();
		        console.log("SignalR Connected.");
		        //此处当前端参数改变时候传参模式,JTB03暂时写死触发传参:
		        connection.invoke('register', 'JTB03');
		//connection.invoke('method', arguments);
		    } catch (err) {
		        console.log(err);
		        setTimeout(start, 5000);
		    }
		};
	
		connection.onclose(async () => {
		    await start();
		});
	
		//Start the connection.启动
		start();
	
		

其他相关文章参考:https://blog.csdn.net/Elliot_Wang/article/details/131665055

以下举例具体在项目中的应用:

在这里插入图片描述
在这里插入图片描述

父页面(看板主页面)kanban.vue

<template>
	<div class="board" v-cloak>
		<div class="board-T">
			<div class="board-T-item T1">
				<!-- <allDevice v-if="isBoard" :boardData="boardData" :upIndex="upIndex" :fId="fId" class="board-border"></allDevice> -->
				<allDevice class="board-border" @nameSelect="nameSelectGet"></allDevice>
			</div>
			<div class="board-T-item T2">
				<div class="board-l">
					<div class="board-item">
						<top5Tingji :StopTop5="state.StopTop5" class="board-border">
						</top5Tingji>
					</div>
				</div>
				<div class="board-m">
					<div class="board-item">
						<top5Weixiu class="board-border" />
					</div>
				</div>
				<div class="board-r">
					<div class="board-item">
						<alarm :infosAlarm="state.geolocation" class="board-border">
						</alarm>
					</div>
				</div>
			</div>
		</div>

	</div>
</template>

<script lang="ts" setup>
	import * as signalR from '@microsoft/signalr'
	import { onMounted, reactive, ref, provide, watch } from 'vue';
	import allDevice from '/@/views/device-overview/kanbanBox/allDevice.vue'
	import top5Tingji from '/@/views/device-overview/kanbanBox/top5Tingji.vue'
	import top5Weixiu from '/@/views/device-overview/kanbanBox/top5Weixiu.vue'
	import alarm from '/@/views/device-overview/kanbanBox/alarm.vue'
	const state = reactive({
		tableHeight: window.innerHeight - 370,
		pageIndex: 1,
		pageSize: 20,
		total: 0,
		tableData: [],
		deviceSN: '',
		fromData: {},
		index: 0,
		date: [
			// new Date(formatDate(getCycle(-7), 2) + ' 00:00:00'),
			// new Date(formatDate(getCycle(0), 2) + ' 00:00:00'),
		],
		geolocation: ref([]),
		StopTop5: ref({}),
		MaintenanceTop5: ref([]),
		DeviceInfos: ref({}),
		connecData:''
	});
// 改变传参.触发传送
	const nameSelectGet = (val : any) => {
		console.log(val, 888) // 50
		state.connecData=val;
		console.log(state.connecData, 8889) // 50
		connection.invoke('register', val);
	}
	onMounted(() => {
	})
	// 处理推送开始
	const connection = new signalR.HubConnectionBuilder()
		.withUrl("/hubs/j03/kanban")
		.withAutomaticReconnect({
			nextRetryDelayInMilliseconds: function (val) {
				// _this.$TF.closeLoading()
				let arr = [1000, 5000, 10000, 30000]
				if (val.previousRetryCount <= 3) {
					return arr[val.previousRetryCount]
				} else {
					return arr[3]
				}
			}
		})
		.configureLogging(signalR.LogLevel.Information)
		.build();

	connection.on('receivedDeviceRealTimeInfos', function (infos) {
		console.log('设备汇总', infos);
		state.DeviceInfos.values = infos;
	});
	provide('DeviceInfos', state.DeviceInfos)
	connection.on('receivedDeviceStopTop5', function (infos) {
		// console.log('停机TOP5', infos);
		state.StopTop5.values = infos;
		// console.log('2停机TOP5', state.StopTop5.values);
	});
	provide('StopTop5', state.StopTop5)
	connection.on('receivedMaintenanceTop5', function (infos) {
		// console.log('维修top5', infos);
		state.MaintenanceTop5.values = infos;
	});
	provide('infosMaintenanceTop5', state.MaintenanceTop5)
	// const alarmInfos = ref([])
	connection.on('receivedDeviceAlarm', function (infos) {
		// console.log('报警', infos);
		state.geolocation.values = infos;
	});
	provide('infosAlarm2', state.geolocation)

	async function start() {
		try {
			await connection.start();
			console.log("SignalR Connected.");
			// connection.invoke('register', 'JTB03');
			connection.invoke('register', state.connecData);
			//connection.invoke('method', arguments);
		} catch (err) {
			console.log('错误', err);
			setTimeout(start, 5000);
		}
	};

	connection.onclose(async () => {
		await start();
	});

	// Start the connection.
	start();
	// 处理后台推送结束
</script>

<style lang="scss" scoped>
	.board {
		width: 100%;
		height: calc(100vh - 70px);
		// height: calc(100vh);
		overflow: hidden;
		display: flex;
		box-sizing: border-box;
		background: url(../../assets/img/bcg.png);
		background-size: 100% 100%;
		background-position: center center;

		.board-T {
			width: 100%;
			height: 100%;

			.board-T-item {
				// width: 100%;
				// height: calc((100% - 70px) / 1.5);
				height: 70%;
				color: #fff;
				padding: 10px;
				padding-bottom: 0px;
				display: flex;

				.board-l,
				.board-m,
				.board-r {
					width: 33%;
					height: 100%;
					border: 1px solid blue;
					margin-right: 8px;

					.board-item {
						width: 100%;
						height: 100%;
						border: 1px solid #0d2451;
						position: relative;
						overflow: hidden;
						background: #151456;
						width: 100%;
						background: url(../../assets/img/bcg3.png);
						height: 100%;
						background-size: 100% 100%;
						background-position: center center;
					}
				}

				&:last-child {
					border: none;
					padding-bottom: 10px;
					height: 30%;
					// border: 1px solid red;
				}
			}
		}

		.board-border {
			width: 100%;
			height: 100%;
			// border: 1px solid #0d2451;
			position: relative;
			overflow: hidden;
			// background: #151456;
		}
	}

	.T1 {
		background: url(/j03/src/assets/img/bcg3.png);
		background-size: 98.5% 100%;
		background-position: center center;
		background-repeat: no-repeat;
	}

	[v-cloak] {
		display: none;
	}
</style>

子页面:allDevice.vue

<template>
	<div class="default-main">
		<!-- <div>电能表数据监控</div> -->
		<div class='allBox'>
			<div><span class="title">单机设备信息</span>
				<dv-decoration8 class="decoration8" :reverse="true" style="width:250px;height:20px;" />
				<span style="margin: 0 20px;">总数</span><span class="color1">{{state.totalStatus.totalCount}}台</span>
				<span class="box1" :class="addClass(1,item.status)"
					v-for="item in state.totalStatus.statusOverview"><span>{{item.name}}</span><span>{{item.count}}台</span></span>
				<el-select class="ft" v-model="state.value" @change="chooseValue" style="width:120px" value-key="id"
					placeholder="请选择">
					<el-option v-for="item in state.lineData" :label="item.value" :value="item.value" :key="item.key">
					</el-option>
				</el-select>
			</div>
			<div class="device_list">
				<div class="loading">
					<el-carousel indicator-position="outside" height="550px" interval='3000'>
						<!-- 暂时是三条线3*8=24,一个页面展示24条数据轮播 -->
						<el-carousel-item v-for="item in Math.ceil(state.pages / 8)" :key="item">
							<div v-for="val in state.deviceData" class="lineBox">
								<!-- <h3>{{ val.name }}</h3> -->
								<div v-for="(item,index) in val.deviceItems.slice((item - 1) * 8,item * 8)"
									@click="toDetail(item)">
									<div class="device_info" :class="addClass(2,item.status)">
										<div class="greenCenter"><span>{{item.deviceName}}</span></div>
										<div class="greenCenter"><span>{{item.deviceSn}}</span></div>
										<div class='line'></div>
										<div v-if="item.status==2">当日产量:<span class="color2">{{item.quantity}}PCS</span>
										</div>
										<div v-if="item.status==2">OEE:<span class="greenOEE"><el-progress
													:percentage="item.oee" color="#3b9e00"></el-progress></span>
										</div>
										<div v-if="item.status!==2" class="statusName greenCenter"
											:class="addClass(1,item.status)">{{item.statusStr}}</div>
										<div>持续时间:<span :class="addClass(1,item.status)">{{item.durationStr}}分钟</span>
										</div>
									</div>
								</div>
							</div>
						</el-carousel-item>
					</el-carousel>
				</div>
			</div>
		</div>
	</div>

</template>
<script lang="ts" setup>
	import * as signalR from '@microsoft/signalr'
	import * as echarts from 'echarts';
	import { onMounted, reactive, ref, watch, inject, provide } from 'vue';
	import { Download, Search } from '@element-plus/icons-vue';
	import { ElMessage } from 'element-plus';
	import { ChartQuery, GetProductCodeSelect } from '../../../api/j03';
	import { formatDate, getCycle } from '../../../utils/time';

	const myRef = ref(null);
	const state = reactive({
		totalStatus: {},
		value: '',
		pages: 1,
		lineData: [],
		deviceData: [],
		deviceSN: '',
	});
	onMounted(() => {
		GetProductCodeSelect2();
		setInterval(() => {
			// console.log('子设备汇总', DeviceInfos.values)
			state.totalStatus = DeviceInfos.values.statusOverview;
			// state.tableData=DeviceInfos.values.lines;
			// 挑选出每条线体数组长度最长的进行计算轮播的页数pages
			state.deviceData = DeviceInfos.values.lines;
			let data = DeviceInfos.values.lines;
			let arr = []
			for (let i = 0; i < data.length; i++) {
				arr.push(data[i].deviceItems.length)
			}
			// console.log(arr,788)
			const max = Math.max(...arr);
			state.pages = max;//已挑选出线体最大长度,这个长度决定轮播分几页展示
			// console.log(max,state.pages,789); // 输出:最大值
		}, 3000)
	});
	let DeviceInfos = inject('DeviceInfos')
	// 子传父改变值重新推送
	const emits = defineEmits(['nameSelect']);
	const chooseValue = ((val) => {
		// console.log(val, 7777)
		state.value = val;
		emits('nameSelect', val)
	})
	const addClass = ((num, status) => {
		// 设备运行状态离线=0,1=待机,运行=2,3=空转,故障中=4,
		var cname = '';
		var cdevice = '';
		switch (status) {
			case 0: //离线
				cname = 'color0';
				cdevice = 'device0';
				break;
			case 1: //运行
				cname = 'color1';
				cdevice = 'device1';
				break;
			case 2: //停止
				cname = 'color2';
				cdevice = 'device2';
				break;
			case 3: //停止
				cname = 'color3';
				cdevice = 'device3';
				break;
			case 4: //停止
				cname = 'color4';
				cdevice = 'device4';
				break;
		}
		if (num == 1) {
			return cname;
		} else {
			return cdevice;
		}
		// return cname, cdevice;
	})

	const GetProductCodeSelect2 = (id : string) => {//下拉查询
		GetProductCodeSelect().then((res : any) => {
			if (res.status === 0) {
				// ElMessage({ type: 'success', message: '操作成功' });
				state.lineData = res.data;
				// 如果下拉有值,则默认请求第一条数据
				if(state.lineData!=[]||state.lineData.length>0){
					chooseValue(state.lineData[0].value)
				}
			}
		});
	};
	
		
</script>
<style>
	.ft .el-input__wrapper {
		cursor: pointer;
		background-color: #13214d;
		border: 1px solid #64f5f7;
		color: #64f5f7 !important;
		text-align: center;
	}

	.decoration8 {
		width: 250px;
		height: 20px;
		display: inline-block;
		position: absolute;
		left: 16px;
		top: 44px;
	}
	.el-select .el-input__inner {
	    cursor: pointer;
	    color: #62efe7;
	}
</style>
<style lang="scss" scoped>
	.lineBox {
		display: flow-root;
	}

	.allBox {
		margin: 14px 21px;
		font-size: 1rem;

		.ft {
			float: right;
			margin-right: 2%;
		}

	}

	.box1 {
		display: inline-block;
		width: 100px;
		border: 1px solid;
		height: 40px;
		line-height: 40px;
		border-radius: 10px;
		text-align: center;
		margin: 0 10px;
	}

	.title {
		font-size: 1.2rem;
		color: #62efe7;
		margin-right: 22rem;
	}

	.line {}

	.greenOEE {
		display: inline-block;
		width: 70%;
	}

	.greenCenter {
		text-align: center;
	}

	.device_info {
		width: 11%;
		height: 10rem;
		display: inline-block;
		float: left;
		font-size: 0.8rem;
		background-color: rgba(5, 85, 168, 0.388235294117647);
		box-sizing: border-box;
		position: relative;
		border-radius: 10px;
		text-align: left;
		margin: 1.3rem 0.66%;
		padding: 5px;
		overflow: hidden;

		.statusName {
			font-size: 1.5rem;
		}

		div {
			margin: 5px 0;
		}

		.line {
			width: 100%;
		}
	}

	.device0 {
		box-shadow: inset 0px 0px 10px #797979;
		border: 1px solid #797979;

		.line {
			border: 1px solid #797979;
		}
	}

	.device1 {
		box-shadow: inset 0px 0px 10px #f6f700;
		border: 1px solid #f6f700;

		.line {
			border: 1px solid #f6f700;
		}
	}

	.device2 {
		box-shadow: inset 0px 0px 10px #32e751;
		border: 1px solid #32e751;

		.line {
			border: 1px solid green;
		}
	}

	.device3 {
		box-shadow: inset 0px 0px 10px #ffffff;
		border: 1px solid #ffffff;

		.line {
			border: 1px solid #ffffff;
		}

	}

	.device4 {
		box-shadow: inset 0px 0px 10px #e72225;
		border: 1px solid #e72225;

		.line {
			border: 1px solid #e72225;
		}

	}

	// 设备运行状态离线=0,1=待机,运行=2,3=空转,故障中=4,
	.color0 {
		color: #797979;
	}

	.color1 {
		color: #f6f700;
	}

	.color2 {
		color: #32e751;
	}

	.color3 {
		color: #ffffff;
	}

	.color4 {
		color: #e72225;
	}
</style>

数据结构:在这里插入图片描述

{
    "statusOverview": {
        "totalCount": 3,
        "statusOverview": [
            {
                "status": 0,
                "name": "离线中",
                "count": 3
            },
            {
                "status": 1,
                "name": "待机中",
                "count": 0
            },
            {
                "status": 2,
                "name": "运行中",
                "count": 0
            },
            {
                "status": 4,
                "name": "故障中",
                "count": 0
            }
        ]
    },
    "productCode": "JTB02",
    "lines": [
        {
            "name": "A",
            "deviceItems": [
                {
                    "quantity": 0,
                    "duration": 0,
                    "durationStr": "0秒",
                    "oee": 0,
                    "sort": 1,
                    "deviceName": "SM-P2-MA-164_名称",
                    "deviceSn": "SM-P2-MA-164",
                    "status": 0,
                    "statusStr": "离线中"
                }
            ]
        },
        {
            "name": "B",
            "deviceItems": [
                {
                    "quantity": 0,
                    "duration": 0,
                    "durationStr": "0秒",
                    "oee": 0,
                    "sort": 1,
                    "deviceName": "咪头PCB气动压装机",
                    "deviceSn": "SM-XA-01-P7-MA-0285",
                    "status": 0,
                    "statusStr": "离线中"
                }
            ]
        },
        {
            "name": "C",
            "deviceItems": [
                {
                    "quantity": 1,
                    "duration": 12.6753261,
                    "durationStr": "13秒",
                    "oee": 0,
                    "sort": 1,
                    "deviceName": "咪头PCB气动压装机",
                    "deviceSn": "SM-XA-01-P8-MA-0695",
                    "status": 0,
                    "statusStr": "离线中"
                }
            ]
        }
    ]
}

子页面2:alarm.vue
在这里插入图片描述

<template>
	<div class="default-main">
		<!-- <div>电能表数据监控</div> -->
		<div class="titleKanban">设备报警</div>
		<!-- <div item in infosAlarm>{{item}}</div> -->
		<dv-decoration8 :reverse="true" style="width:250px;height:20px;" />
		<div demo-bg>
			<dv-scroll-board :config="config" style="height:180px"  />
		</div>
	</div>

</template>
<script lang="ts" setup>
	import * as echarts from 'echarts';
	import { onMounted, reactive, ref,toRefs,inject} from 'vue';
	import { ElMessage } from 'element-plus';
	import { ChartQuery, SelectQuery } from '../../../api/j03';
	const myRef = ref(null);
	const state = reactive({
		chartData: {},
		deviceSN: '',
	});
	const config = reactive({
		indexHeader: '序号',
		header: ['设备名称', '消息内容', '故障类型', '时间'],
		indexHeader: '序号',
		rowNum: 6, // 表行数
		headerBGC: 'rgba(37, 92, 149, 0.8);', // 表头背景色
		oddRowBGC: 'rgba(35, 90, 146, 0.5);', // 奇数行背景色
		evenRowBGC: 'rgba(30, 69, 119, 0.1);', // 偶数行背景色
		data: [
			['无', '无', '无', '无'],
			// ['行1列1', '行1列2', '行1列3', '行1列3'],
			// ['行2列1', '行2列2', '行2列3', '行1列3'],
			// ['行3列1', '行3列2', '行3列3', '行1列3'],
			// ['行4列1', '行4列2', '行4列3', '行1列3'],
			// ['行1列1', '行1列2', '行1列3', '行1列3'],
			// ['行2列1', '行2列2', '行2列3', '行1列3'],
			// ['行3列1', '行3列2', '行3列3', '行1列3'],
			// ['行4列1', '行4列2', '行4列3', '行1列3'],
			// ['行1列1', '行1列2', '行1列3', '行1列3'],
			// ['行2列1', '行2列2', '行2列3', '行1列3'],
		],
		index: true,
		columnWidth: [50],
		align: ['center'],
	})
	let infosAlarm2 = inject('infosAlarm2')
	// console.log('子报警',infosAlarm2)
	onMounted(() => {
		setInterval(() => {
			  let val = infosAlarm2.values;
			  let arr = []
			  for (let i in val) {
			  	let deviceName = val[i].deviceName
			  	let content = val[i].content
			  	let alarmTypeStr = val[i].alarmTypeStr
			  	let startDateTime = val[i].startDateTimeStr
			  	arr.push([deviceName, content,alarmTypeStr,startDateTime])
			  }
			  config.data=arr;
			  // console.log('子报警2',arr)
		    }, 3000)
	});
</script>

<style lang="scss" scoped>


</style>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值