From 7941623b1fb108a154ea4270d7c7e2df6031f6e5 Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期四, 11 十二月 2025 12:36:14 +0800
Subject: [PATCH] 优化页面UI更新

---
 pages/tabBar/device.vue |  548 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 452 insertions(+), 96 deletions(-)

diff --git a/pages/tabBar/device.vue b/pages/tabBar/device.vue
index f6ca562..9781fd8 100644
--- a/pages/tabBar/device.vue
+++ b/pages/tabBar/device.vue
@@ -12,36 +12,38 @@
 
 				<view class="card-box dynamic shadow">
 					<view class="title-box margin-bottom-sm">
-						<view  style="width: 100vw;" class="left justify-between">
+						<view style="width: 100vw;" class="left justify-between">
 							<view class="flex align-center">
 								<uni-text class="cuIcon-titles text-blue"></uni-text>
 								<view class="title">鎬昏</view>
 							</view>
 							<view>
-								<text class="text-gray margin-right-lg">2024-07-14</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>
-								<text class="text-bold text-sl margin-top-xs  text-gray margin-top-sm">20
+								<text class="text-bold text-sl margin-top-xs  text-gray margin-top-sm">{{equCount}}
 									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
-							</view>
-							
-							<view class="flex-sub flex flex-direction text-center">
-								<text class="text-df">寮�鏈鸿澶�</text>
-								<text class="text-bold text-sl margin-top-xs text-gray margin-top-sm">10
-									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
-							</view>
-							
-							<view class="flex-sub flex flex-direction text-center">
-								<text class="text-df">杩愯璁惧</text>
-								<text class="text-bold text-sl margin-top-xs text-cyan margin-top-sm">10
-									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
+							</view>
+
+							<view class="flex-sub flex flex-direction text-center">
+								<text class="text-df">寮�鏈鸿澶�</text>
+								<text class="text-bold text-sl margin-top-xs text-gray margin-top-sm">{{onlineCount}}
+									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
+							</view>
+
+							<view class="flex-sub flex flex-direction text-center">
+								<text class="text-df">杩愯璁惧</text>
+								<text class="text-bold text-sl margin-top-xs text-cyan margin-top-sm">{{onlineCount}}
+									<text class="text-gray text-sm margin-left-xs">鍙�</text></text>
 							</view>
 						</view>
 						<view class="margin-top">
@@ -51,116 +53,453 @@
 
 						</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>
 
 
 			</template>
-			
-			 
-			
-			<u-skeleton
-			        class=" "
-					rows="20"
-					:loading="loading"
-					:title="false"
-				>
-			<!-- 濡傛灉甯屾湜鍏朵粬view璺熺潃椤甸潰婊氬姩锛屽彲浠ユ斁鍦▃-paging鏍囩鍐� -->
-			<view class="card-box dynamic shadow" v-for="(item,index) in dataList" :key="index"
-				@click="itemClick(item)">
-				<view class="title-box">
-					<view class="left flex-sub">
-						<uni-text class="cuIcon-titles text-blue"></uni-text>
-						<view class="title text-cut">1#鏅鸿兘骞茬嚗鏈�</view>
-						<view class="flex title text-green text-sm">
-							<u-tag size="mini" text="鍦ㄧ嚎" type="success" plain plainFill></u-tag>
-							<u-tag class="margin-left-xs" size="mini" text="鍋滄満" type="error" plain plainFill></u-tag>
+
+
+
+			<u-skeleton rows="20" :loading="loading" :title="false">
+				<!-- 濡傛灉甯屾湜鍏朵粬view璺熺潃椤甸潰婊氬姩锛屽彲浠ユ斁鍦▃-paging鏍囩鍐� -->
+				<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">
+							<uni-text class="cuIcon-titles text-blue"></uni-text>
+							<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>
+								<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,'realData.workorder')}}</view>
 						</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">10:00:10</view>
-					</view>
-				</view>
 
-				<view class="info-box">
-					<view class="left flex-sub">
-						<view class="title text-sm">鐑樺共鑽潗:</view>
-						<view class="title text-sm">鐢熷湴榛�</view>
+					<view class="info-box">
+						<view class="left flex-sub">
+							<view class="title text-sm">鐑樺共鑽潗:</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">{{$lget(item,'realData.weight1')}}绛�</view>
+						</view>
 					</view>
-					<view class="right" style="min-width: 240rpx;">
-						<view class="title text-sm">鐑樺共鏃堕棿:</view>
-						<view class="title text-sm">01:20:00</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">
-							<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>
+					<view class="info-box">
+						<view class="left flex-sub">
+							<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>
 
-			</view>
-
-		   </u-skeleton>
+			</u-skeleton>
 		</z-paging>
 	</view>
 </template>
 
 <script>
+	import dayjs from 'dayjs'
 	export default {
 		data() {
-			return {
-				loading:true,
+			return {
+				loading: true,
 				// v-model缁戝畾鐨勮繖涓彉閲忎笉瑕佸湪鍒嗛〉璇锋眰缁撴潫涓嚜宸辫祴鍊硷紒锛侊紒
-				dataList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+				dataList: [],
+				curDate: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+				isProcessing: false,
+				// key->璁惧绉熸埛+code 
+				dataMap: new Map(),
+
+				alarmEquCount: 0,
+				faultEquCount: 0,
+				timer: null,
+				mqttThrottleMs: 1000,
+				lastMqttTs: 0,
+				dateTimer: null
+
 			}
 		},
+		onShow() {
+			this.startTimer()
+			this.startDateTimer()
+			this.mqttData()
+		},
+		onHide() {
+			this.stopTimer()
+			this.stopDateTimer()
+			uni.$off(this.$constant.MQTT_TOPIC_MESSAGE)
+		},
+		onTabItemTap: function(e) {
+			getApp().globalData.selectTab = e.index
+		},
 		methods: {
-			queryList(pageNo, pageSize) {
+			queryList(pageNo, pageSize) {
 				this.loading = true;
-				// 缁勪欢鍔犺浇鏃朵細鑷姩瑙﹀彂姝ゆ柟娉曪紝鍥犳榛樿椤甸潰鍔犺浇鏃朵細鑷姩瑙﹀彂锛屾棤闇�鎵嬪姩璋冪敤
-				// 杩欓噷鐨刾ageNo鍜宲ageSize浼氳嚜鍔ㄨ绠楀ソ锛岀洿鎺ヤ紶缁欐湇鍔″櫒鍗冲彲
-				// 妯℃嫙璇锋眰鏈嶅姟鍣ㄨ幏鍙栧垎椤垫暟鎹紝璇锋浛鎹㈡垚鑷繁鐨勭綉缁滆姹�
-				// const params = {
-				// 	pageNo: pageNo,
-				// 	pageSize: pageSize,
-				// }
-				// this.$request.queryList(params).then(res => {
-				// 	// 灏嗚姹傜殑缁撴灉鏁扮粍浼犻�掔粰z-paging
-				this.$refs.paging.complete(this.dataList);
-				// }).catch(res => {
-				// 	// 濡傛灉璇锋眰澶辫触鍐檛his.$refs.paging.complete(false);
-				// 	// 娉ㄦ剰锛屾瘡娆¢兘闇�瑕佸湪catch涓啓杩欏彞璇濆緢楹荤儲锛寊-paging鎻愪緵浜嗘柟妗堝彲浠ュ叏灞�缁熶竴澶勭悊
-				// 	// 鍦ㄥ簳灞傜殑缃戠粶璇锋眰鎶涘嚭寮傚父鏃讹紝鍐檜ni.$emit('z-paging-error-emit');鍗冲彲
-				// 	this.$refs.paging.complete(false);
-				// })
-				setTimeout(() => {
-					this.loading = false
-				}, 1000)
-			},
-			itemClick(item){
-				uni.navigateTo({
-					url:"/pages/device/control"
-				})
+				const params = {
+					pageNo: pageNo,
+					pageSize: pageSize,
+				}
+				this.$api.queryEquList(params).then((res) => {
+					this.$refs.paging.complete(res.result.records);
+					this.loading = false
+				}).catch(res => {
+					this.$refs.paging.complete(false);
+					this.loading = false
+				})
+
+			},
+			// 璁惧鏁版嵁鍜宮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);
+			},
+			startDateTimer() {
+				this.dateTimer = setInterval(() => {
+					this.curDate = dayjs().format('YYYY-MM-DD HH:mm:ss')
+				}, 1000);
+			},
+			stopDateTimer() {
+				clearInterval(this.dateTimer);
+			},
+			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 {
+						const now = Date.now();
+						if (now - this.lastMqttTs < this.mqttThrottleMs) return;
+						this.lastMqttTs = now;
+						// 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() {
-			
-			setTimeout(() => {
-				this.loading = false
-			}, 1000)
+
+
+		},
+		onReady() {
+
+		},
+		computed: {
+			equCount() {
+				return this.dataList.length
+			},
+			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);
+			}
 		}
 	}
 </script>
@@ -179,7 +518,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;
 	}
 
 
@@ -233,4 +589,4 @@
 			}
 		}
 	}
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3