From 9cc59c17892a7e69de54e06b5931e78c9b05551c Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期二, 02 九月 2025 09:24:34 +0800
Subject: [PATCH] 添加mqtt登出

---
 pages/tabBar/device.vue |  406 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 365 insertions(+), 41 deletions(-)

diff --git a/pages/tabBar/device.vue b/pages/tabBar/device.vue
index 9adac13..f5526b2 100644
--- a/pages/tabBar/device.vue
+++ b/pages/tabBar/device.vue
@@ -18,14 +18,15 @@
 								<view class="title">鎬昏</view>
 							</view>
 							<view>
-								<text
-									class="text-gray margin-right-lg">{{curDate}}</text>
+								<text class="text-gray text-sm">{{curDate}}</text>
 							</view>
 
 						</view>
 
 					</view>
-					<view class="flex flex-direction padding-xs">
+
+
+					<!-- <view class="flex flex-direction padding-xs">
 						<view class="flex">
 							<view class="flex-sub flex flex-direction text-center">
 								<text class="text-df">璁惧鎬绘暟</text>
@@ -52,7 +53,65 @@
 
 						</view>
 
+					</view> -->
+
+					<view class="flex flex-direction padding-xs">
+						<view class="flex">
+							<view class="flex-sub flex flex-direction">
+								<text class="text-df">鍦ㄧ嚎璁惧</text>
+								<text class="text-bold text-sl margin-top-xs text-green margin-top-sm">{{onlineCount}}
+									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
+
+							</view>
+							<view class="flex-twice flex flex-direction justify-between">
+								<view class="flex-sub flex">
+									<view class="flex flex-direction flex-sub">
+										<text class="text-gray text-xs">璁惧淇℃伅</text>
+
+										<text class="text-black">璁惧鎬绘暟:</text>
+										<text class="margin-lr-xs text-gray text-bold text-xl">{{equCount}}</text>
+										<text class="text-gray text-xs"></text>
+
+
+									</view>
+									<view class="flex flex-direction flex-sub">
+										<text class="text-gray text-xs">鎶ヨ淇℃伅</text>
+
+										<text class="text-black">鏁呴殰鏈哄彴:</text>
+										<text class="margin-lr-xs text-red text-bold text-xl">{{faultEquCount}}</text>
+										<text class="text-gray text-xs"></text>
+
+
+									</view>
+
+								</view>
+								<view class="flex-sub flex">
+									<view class="flex flex-direction flex-sub">
+										<text class="text-white text-xs">鎶ヨ淇℃伅</text>
+										<text class="text-black">鍋滅敤璁惧:</text>
+										<text class="margin-lr-xs text-orange text-bold text-xl">0</text>
+										<text class="text-gray text-xs"></text>
+
+
+									</view>
+									<view class="flex flex-direction flex-sub">
+										<text class="text-white text-xs">鏈哄彴淇℃伅</text>
+										<text class="text-black">鍛婅鏈哄彴:</text>
+										<text
+											class="margin-lr-xs text-orange text-bold text-xl">{{alarmEquCount}}</text>
+										<text class="text-gray text-xs"></text>
+
+									</view>
+
+								</view>
+
+							</view>
+
+						</view>
+
+
 					</view>
+
 
 
 				</view>
@@ -62,9 +121,9 @@
 
 
 
-			<u-skeleton   rows="20" :loading="loading" :title="false">
+			<u-skeleton rows="20" :loading="loading" :title="false">
 				<!-- 濡傛灉甯屾湜鍏朵粬view璺熺潃椤甸潰婊氬姩锛屽彲浠ユ斁鍦▃-paging鏍囩鍐� -->
-				<view class="card-box dynamic shadow" v-for="(item,index) in dataList" :key="index"
+				<view class="card-item-box dynamic shadow" v-for="(item,index) in dataList" :key="index"
 					@click="itemClick(item)">
 					<view class="title-box">
 						<view class="left flex-sub">
@@ -72,48 +131,66 @@
 							<view class="title text-cut">{{$lget(item,'name')}}</view>
 							<view class="flex title text-green text-sm">
 								<u-tag v-if="item.online" size="mini" text="鍦ㄧ嚎" type="success" plain plainFill></u-tag>
-								<u-tag v-else  size="mini" text="绂荤嚎" type="warning" plain plainFill></u-tag>
-								<u-tag v-if="item.online" class="margin-left-sm" size="mini" text="鍦ㄧ嚎" type="success" plain plainFill></u-tag>
-								<u-tag  v-else class="margin-left-sm" size="mini" text="鍋滄満" type="error" plain plainFill></u-tag>
+								<u-tag v-else size="mini" text="绂荤嚎" type="warning" plain plainFill></u-tag>
+								<view style="width: 20rpx;height: 2rpx"></view>
+								<template v-if="$lget(item,'realData.level')!= '--'">
+									<u-tag size="mini" :text="$lget(item,'realData.level')" plain plainFill></u-tag>
+								</template>
+
 							</view>
 						</view>
 						<view class="right" style="min-width: 240rpx;">
 							<!-- <u-badge :isDot="true" type="success"></u-badge> -->
 							<!-- <view class="title text-gray text-sm">寮�鏈烘椂闂�:</view> -->
-							<view class="title text-gray text-sm">{{$lget(item,'upTime')}}</view>
+							<view class="title text-gray text-sm">{{$lget(item,'realData.workorder')}}</view>
 						</view>
 					</view>
 
 					<view class="info-box">
 						<view class="left flex-sub">
 							<view class="title text-sm">鐑樺共鑽潗:</view>
-							<view class="title text-sm text-gray">--</view>
+							<view class="title text-sm">{{$lget(item,'realData.name')}}</view>
 						</view>
 						<view class="right" style="min-width: 240rpx;">
-							<view class="title text-sm">鐑樺共鏃堕棿:</view>
-							<view class="title text-sm text-gray">--</view>
+							<view class="title text-sm">鎶曟枡閲�:</view>
+							<view class="title text-sm text-gray">{{$lget(item,'realData.weight1')}}绛�</view>
 						</view>
 					</view>
 
 					<view class="info-box">
 						<view class="left flex-sub">
-							<view class="title text-sm text-cut">鎶ヨ淇℃伅:</view>
-							<view class="flex  title text-sm">
-								<template v-if="item.online && !item.fault">
-									<u-tag size="mini" text="姝e父" type="success" plain plainFill></u-tag>
-								</template>
-								<template v-else-if="item.fault">
-									<u-tag size="mini" text="娓╁害浼犳劅鍣ㄦ姤璀�" type="warning" plain plainFill></u-tag>
-									<u-tag size="mini" class="margin-left-xs" text="鍓嶉棬鏈叧" type="warning" plain
-										plainFill></u-tag>
-									<u-tag size="mini" class="margin-left-xs" text="椋庣浣庝綅鎶ヨ" type="error" plain
-										plainFill></u-tag>
-								</template>
-								<template v-else>
-								</template>
-							</view>
+							<view class="title text-sm">宸茬敤鏃堕棿:</view>
+							<view class="title text-sm">{{$lget(item,'realData.time3')}}min</view>
 						</view>
+						<view class="right" style="min-width: 240rpx;">
+							<view class="title text-sm">棰勬祴鍓╀綑:</view>
+							<view class="title text-sm text-gray">{{$lget(item,'realData.ai_total_time')}}min</view>
+						</view>
+					</view>
 
+					<view class="info-box">
+						<view class="left flex-sub" style="width: 60%;">
+							<view class="title text-sm text-cut">鎶ヨ淇℃伅:</view>
+							<template v-if="item.errorData">
+								<view class="title text-sm text-red text-cut">{{ (item.errorData.length > 0) ? item.errorData[0]:'' }}</view>
+							</template>
+
+						     <template v-else-if="item.warnData">
+								<view class="title text-sm text-yellow text-cut"> {{(item.warnData.length > 0) ? item.warnData[0]:''}}</view>
+							</template> 
+							<view v-if="getErrorCount(item) > 0">
+								<u-tag  size="mini" :text="getErrorCount(item)" type="error" plain></u-tag>
+							</view>
+							<view style="width: 20rpx;"></view>
+							<view v-if="getWarnCount(item) > 0">
+								<u-tag  size="mini" :text="getWarnCount(item)" type="warning" plain></u-tag>
+							</view>
+
+						</view>
+						<view class="right" style="min-width: 240rpx;">
+							<view class="title text-sm">鏇存柊鏃堕棿:</view>
+							<view class="title text-sm text-gray">{{ item.refreshTime}}</view>
+						</view>
 					</view>
 
 				</view>
@@ -124,46 +201,268 @@
 </template>
 
 <script>
+	import dayjs from 'dayjs'
 	export default {
 		data() {
 			return {
 				loading: true,
 				// v-model缁戝畾鐨勮繖涓彉閲忎笉瑕佸湪鍒嗛〉璇锋眰缁撴潫涓嚜宸辫祴鍊硷紒锛侊紒
 				dataList: [],
-				curDate:uni.$u.timeFormat(new Date(), 'yyyy-mm-dd'),
+				curDate: uni.$u.timeFormat(new Date(), 'yyyy-mm-dd'),
+				isProcessing: false,
+				// key->璁惧绉熸埛+code 
+				dataMap: new Map(),
+
+				alarmEquCount: 0,
+				faultEquCount: 0,
+				timer: null
+
 			}
-		},
-		onTabItemTap : function(e) {
-		getApp().globalData.selectTab = e.index
+		},
+		mounted() {
+			this.startTimer()
+			this.mqttData()
+		},
+		beforeDestroy() {
+			this.stopTimer()
+			uni.$off(this.$constant.MQTT_TOPIC_MESSAGE)
+		},
+		onTabItemTap: function(e) {
+			getApp().globalData.selectTab = e.index
 		},
 		methods: {
 			queryList(pageNo, pageSize) {
 				this.loading = true;
-				// 缁勪欢鍔犺浇鏃朵細鑷姩瑙﹀彂姝ゆ柟娉曪紝鍥犳榛樿椤甸潰鍔犺浇鏃朵細鑷姩瑙﹀彂锛屾棤闇�鎵嬪姩璋冪敤
-				// 杩欓噷鐨刾ageNo鍜宲ageSize浼氳嚜鍔ㄨ绠楀ソ锛岀洿鎺ヤ紶缁欐湇鍔″櫒鍗冲彲
-				// 妯℃嫙璇锋眰鏈嶅姟鍣ㄨ幏鍙栧垎椤垫暟鎹紝璇锋浛鎹㈡垚鑷繁鐨勭綉缁滆姹�
 				const params = {
 					pageNo: pageNo,
 					pageSize: pageSize,
 				}
 				this.$api.queryEquList(params).then((res) => {
-					// 	// 灏嗚姹傜殑缁撴灉鏁扮粍浼犻�掔粰z-paging
 					this.$refs.paging.complete(res.result.records);
 					this.loading = false
 				}).catch(res => {
-					// 濡傛灉璇锋眰澶辫触鍐檛his.$refs.paging.complete(false);
-					// 娉ㄦ剰锛屾瘡娆¢兘闇�瑕佸湪catch涓啓杩欏彞璇濆緢楹荤儲锛寊-paging鎻愪緵浜嗘柟妗堝彲浠ュ叏灞�缁熶竴澶勭悊
-					// 鍦ㄥ簳灞傜殑缃戠粶璇锋眰鎶涘嚭寮傚父鏃讹紝鍐檜ni.$emit('z-paging-error-emit');鍗冲彲
 					this.$refs.paging.complete(false);
 					this.loading = false
 				})
 
 			},
-			itemClick(item) {
-				uni.navigateTo({
-					url: "/pages/device/control?code="+item.code+"&clientId="+item.clientId
+			// 璁惧鏁版嵁鍜宮tqq瀹炴椂鏁版嵁鍚堝苟
+			mergeMqttRealData(mqttData) {
+
+				const {
+					tenantid,
+					machineid
+				} = mqttData;
+				if (!tenantid || !machineid) return;
+				const key = `${tenantid}_${machineid}`;
+				const targetItem = this.dataList.find(item =>
+					item.tenantId === tenantid && item.code === machineid
+				);
+				if (targetItem && !targetItem.online) {
+					mqttData = {};
+				}
+				if (targetItem) {
+					const updatedItem = {
+						...targetItem,
+						realData: mqttData
+					};
+					updatedItem.refreshTime = dayjs().format('HH:mm:ss');
+					this.$set(this.dataList, this.dataList.indexOf(targetItem), updatedItem);
+
+				}
+
+
+			},
+			
+			getErrorCount(item){
+				let count = 0;
+				if(item.errorData){
+					count += item.errorData.length
+				}
+				return count;
+			},
+			getWarnCount(item){
+				let count = 0;
+				if(item.warnData){
+					count += item.warnData.length
+				}
+				return count;
+			},
+			
+			startTimer() {
+				this.timer = setInterval(() => {
+					//this.queryRealFaultData();
+				}, 3000);
+			},
+			stopTimer() {
+				clearInterval(this.timer);
+			},
+			queryRealFaultData() {
+				//鍙戦�佹暟鎹�
+				const message = {
+					req: this.deviceId,
+					tenantId: this.tenantId,
+					timeStamp: new Date(),
+
+				}
+				let opts = {
+					topic: this.$constant.MOBILE_REQ_EQU_REAL_FAULT,
+					message: JSON.stringify(message),
+				}
+
+				this.$mqttTool.publish(opts).then(res => {
+
 				})
+			},
+
+			itemClick(item) {
+				uni.navigateTo({
+					url: "/packageA/pages/device/control?code=" + item.code + "&name=" + item.name + "&clientId=" +
+						item.clientId
+				})
+			},
+			mqttData() {
+				uni.$on(this.$constant.MQTT_TOPIC_MESSAGE, (data) => {
+					try {
+						// 1. 鏁版嵁瑙f瀽鍜岄獙璇�
+						const {
+							data: wdata,
+							topic
+						} = this.parseAndValidateMqttData(data);
+						if (!wdata || !topic) return;
+
+						// 2. 鍑嗗涓婚甯搁噺
+						const topics = this.prepareMqttTopics();
+
+						// 3. 鏇存柊鍒锋柊鏃堕棿
+						this.refreshTime = dayjs().format('HH:mm:ss');
+
+						// 4. 鏍规嵁涓婚澶勭悊鏁版嵁
+						switch (topic) {
+							case topics.updateEquStatu:
+								this.handleEquipmentStatusUpdate(wdata);
+								break;
+							case topics.realData:
+								this.mergeMqttRealData(wdata);
+								break;
+							case topics.realFaultTopic:
+							case topics.oneceFaultTopic:
+								this.handleFaultData(wdata);
+								break;
+						}
+					} catch (error) {
+						console.error('MQTT鏁版嵁澶勭悊閿欒:', error);
+					}
+				});
+			},
+
+			// 杈呭姪鏂规硶锛氳В鏋愬拰楠岃瘉MQTT鏁版嵁
+			parseAndValidateMqttData(data) {
+				try {
+					const json = JSON.parse(data);
+					if (!json?.data || !json?.topic) return {
+						data: null,
+						topic: null
+					};
+					return {
+						data: json.data,
+						topic: json.topic
+					};
+				} catch (e) {
+					return {
+						data: null,
+						topic: null
+					};
+				}
+			},
+
+			// 杈呭姪鏂规硶锛氬噯澶嘙QTT涓婚
+			prepareMqttTopics() {
+				return {
+					updateEquStatu: this.$constant.SERVICE_BROADCAST_TENANT_UPDATE_EQU_STATU
+						.replace('%s', this.tenantId),
+					realData: this.$constant.SERVICE_BROADCAST_TENANT_REAL_DATA
+						.replace('%s', this.tenantId),
+					realFaultTopic: this.$constant.SERVICE_BROADCAST_TENANT_REAL_FAULT
+						.replace('%s', this.tenantId),
+					oneceFaultTopic: this.$constant.SERVICE_ONECE_TENANT_REAL_FAULT.replace('%s', this
+						.deviceId)
+				};
+			},
+
+			// 杈呭姪鏂规硶锛氬鐞嗚澶囩姸鎬佹洿鏂�
+			handleEquipmentStatusUpdate(wdata) {
+				const {
+					connected,
+					tenantId,
+					code
+				} = wdata;
+				const index = this.dataList.findIndex(item =>
+					(item.tenantId + "") === tenantId && item.code === code
+				);
+
+				if (index === -1) return;
+
+				// 鏇存柊鍦ㄧ嚎鐘舵��
+				this.$set(this.dataList[index], 'online', connected);
+
+				// 濡傛灉绂荤嚎锛屽垹闄ゅ疄鏃舵暟鎹�
+				if (!connected && this.dataList[index]?.realData) {
+					this.$delete(this.dataList[index], 'realData');
+				}
+			},
+
+			// 杈呭姪鏂规硶锛氬鐞嗘晠闅滄暟鎹�
+			handleFaultData(wdata) {
+				if (!Array.isArray(wdata)) return;
+
+				// 鎸夎澶囧垎缁勬晠闅滄暟鎹�
+				const faultMap = wdata.reduce((map, item) => {
+					const key = `${item.tenantId}_${item.equCode}`;
+					map.get(key)?.push(item) || map.set(key, [item]);
+					return map;
+				}, new Map());
+
+				// 鏇存柊姣忎釜璁惧鐨勬晠闅滀俊鎭�
+				faultMap.forEach((faults, key) => {
+					const [tenantId, equCode] = key.split("_");
+					const targetItem = this.dataList.find(i =>
+						i.tenantId == tenantId && i.code == equCode
+					);
+					
+					if (targetItem) {
+						const updatedItem = {
+							...targetItem,
+							errorData: targetItem.online ? faults.filter(f => f.faultType === 1).map(n => n.faultName) : [],
+							warnData: targetItem.online ? faults.filter(f => f.faultType === 2).map(n => n.faultName) : [],
+						};
+						if(targetItem.online){
+							updatedItem.refreshTime = dayjs().format('HH:mm:ss');
+						}
+						
+						this.$set(this.dataList, this.dataList.indexOf(targetItem), updatedItem);
+					}
+				});
+
+				this.faultEquCount = this.dataList.filter(item => {
+					return (
+						item.errorData &&
+						Array.isArray(item.errorData) &&
+						item.errorData.length > 0
+					);
+				}).length || 0;
+
+				this.alarmEquCount = this.dataList.filter(item => {
+					return (
+						item.warnData &&
+						Array.isArray(item.warnData) &&
+						item.warnData.length > 0
+					);
+				}).length || 0;
+
 			}
+
+
 
 		},
 		onReady() {
@@ -176,6 +475,14 @@
 			onlineCount() {
 				const list = this.dataList.filter(item => item.online)
 				return list.length
+			},
+			tenantId() {
+				const userinfo = uni.getStorageSync('userinfo');
+				const tenantid = userinfo.loginTenantId
+				return tenantid + "";
+			},
+			deviceId() {
+				return uni.getStorageSync(this.$constant.DEVICE_ID);
 			}
 		}
 	}
@@ -195,7 +502,24 @@
 		background-color: white;
 		border-radius: 20rpx;
 		font-family: Helvetica Neue, Helvetica, sans-serif;
+	}
 
+	.card-item-box {
+		margin: 0rpx 20rpx 10rpx 20rpx;
+		padding: 20rpx;
+		box-sizing: border-box;
+		background-color: white;
+		border-radius: 20rpx;
+		font-family: Helvetica Neue, Helvetica, sans-serif;
+	}
+
+	/* 绗簩涓強涔嬪悗鐨� item */
+	.card-item-box:not(:first-child) {
+		margin: 10rpx 20rpx;
+	}
+
+	.margin-left-sm {
+		margin-left: 20rpx;
 	}
 
 

--
Gitblit v1.9.3