|
@@ -4,91 +4,94 @@
|
|
|
<div v-loading="loading" class="mec-content">
|
|
<div v-loading="loading" class="mec-content">
|
|
|
<div class="mec-item" v-for="(item, index) in varDictMecGroupData" :key="index">
|
|
<div class="mec-item" v-for="(item, index) in varDictMecGroupData" :key="index">
|
|
|
<div class="mec-title">
|
|
<div class="mec-title">
|
|
|
- {{ (item.MecType
|
|
|
|
|
- ? (dictStore.getDictLabel("mec_type", item.MecType) as any)
|
|
|
|
|
|
|
+ {{ (item.mec_type
|
|
|
|
|
+ ? (dictStore.getDictLabel("mec_type", item.mec_type) as any)
|
|
|
: undefined
|
|
: undefined
|
|
|
- )?.dict_label || detailFormData.MecType }}
|
|
|
|
|
|
|
+ )?.dict_label || item.mec_type }}
|
|
|
</div>
|
|
</div>
|
|
|
<div class="mec-content-item">
|
|
<div class="mec-content-item">
|
|
|
- <div class="number-type-content" v-for="(temp, index1) in item.numberTypeList" :key="index1">
|
|
|
|
|
- <span>{{ temp.VarName }}</span>
|
|
|
|
|
|
|
+ <div class="number-type-content" v-for="(temp, index1) in item.number_type_list" :key="index1">
|
|
|
|
|
+ <span>{{ temp.var_name }}</span>
|
|
|
<div>
|
|
<div>
|
|
|
- <span style="font-size: 22px;">{{ temp.Value }}</span>
|
|
|
|
|
|
|
+ <span style="font-size: 22px;">{{ temp.value }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div style="margin-top: 30px;">
|
|
<div style="margin-top: 30px;">
|
|
|
- <div class="bool-type-content" v-for="(temp, index1) in item.boolTypeList" :key="index1">
|
|
|
|
|
- <span>{{ temp.VarName }}</span>
|
|
|
|
|
- <span :class="getBgColor(temp.Value, temp.SwitchType)"></span>
|
|
|
|
|
|
|
+ <div class="bool-type-content" v-for="(temp, index1) in item.bool_type_list" :key="index1">
|
|
|
|
|
+ <span>{{ temp.var_name }}</span>
|
|
|
|
|
+ <span :class="getBgColor(temp.value, temp.switch_type)"></span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div v-if="varDictMecGroupData.length === 0" class="el-table-empty">
|
|
|
|
|
+ <el-image :src="emptybg"></el-image>
|
|
|
|
|
+ <span>当前无数据</span>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import BizVarDictAPI, { } from '@/api/module_business/vardict'
|
|
|
|
|
|
|
+import BizVarDictAPI, { BizVarDictTable,VarDictMecGroupData,MecDataItem } from '@/api/module_business/vardict'
|
|
|
import { useRoute } from 'vue-router'
|
|
import { useRoute } from 'vue-router'
|
|
|
import { useDictStore } from "@/store";
|
|
import { useDictStore } from "@/store";
|
|
|
-import mqtt, { MqttClient } from 'mqtt';
|
|
|
|
|
-//import MqttService from '@/utils/mqttService';
|
|
|
|
|
-//import { getCraneMecTree } from '@/api/crane';
|
|
|
|
|
-//import { mecDataFormat, gearCalculation } from '@/utils/hooks'
|
|
|
|
|
|
|
+import emptybgUrl from '@/assets/images/empty-bg.png';
|
|
|
|
|
+import MqttUtil, { MqttMessageCallback } from '@/utils/mqttUtil';
|
|
|
|
|
+import { reactive, onMounted, onUnmounted, inject } from 'vue';
|
|
|
|
|
+import { gearCalculation } from '@/utils/common';
|
|
|
|
|
+import { S } from 'vue-router/dist/router-CWoNjPRp.mjs';
|
|
|
|
|
|
|
|
const route = useRoute()
|
|
const route = useRoute()
|
|
|
const receiveData = inject<(data: { craneName: string; isShowHomeButton: boolean }) => void>('receiveData');
|
|
const receiveData = inject<(data: { craneName: string; isShowHomeButton: boolean }) => void>('receiveData');
|
|
|
const craneInfo = JSON.parse(localStorage.getItem('craneInfo') || '{}')
|
|
const craneInfo = JSON.parse(localStorage.getItem('craneInfo') || '{}')
|
|
|
-const varDictMecGroupData = ref([])
|
|
|
|
|
|
|
+const varDictMecGroupData = ref<VarDictMecGroupData[]>([])
|
|
|
const loading = ref(true);
|
|
const loading = ref(true);
|
|
|
-const MQTT_WS_URL = import.meta.env.VITE_APP_WS_ENDPOINT || 'ws://127.0.0.1:9001';
|
|
|
|
|
-const VAR_TOPIC = 'gc/var/' + craneInfo.crane_no;
|
|
|
|
|
-let mqttClient: MqttClient | null = null;
|
|
|
|
|
|
|
+const emptybg = ref(emptybgUrl)
|
|
|
|
|
+
|
|
|
|
|
+const mqttConfig = {
|
|
|
|
|
+ wsUrl: import.meta.env.VITE_APP_WS_ENDPOINT || 'ws://127.0.0.1:9001',
|
|
|
|
|
+ topics: ['cdc/'+craneInfo.crane_no+'/analog/batch/#','cdc/'+craneInfo.crane_no+'/digital/#']
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const mqttUtil = new MqttUtil(mqttConfig);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
const getCraneMecTreeData = async () => {
|
|
const getCraneMecTreeData = async () => {
|
|
|
- const response = await BizVarDictAPI.varDictMecGroup(craneInfo.id);
|
|
|
|
|
|
|
+ const response = await BizVarDictAPI.varDictMecGroup(craneInfo.crane_no);
|
|
|
varDictMecGroupData.value = mecDataFormat(response.data.data)
|
|
varDictMecGroupData.value = mecDataFormat(response.data.data)
|
|
|
- console.log(varDictMecGroupData.value)
|
|
|
|
|
|
|
+ //挡位计算
|
|
|
|
|
+ gearCalculation(varDictMecGroupData.value)
|
|
|
|
|
+ loading.value = false;
|
|
|
//localStorage.setItem('varDict', JSON.stringify(deviceStateData.value))
|
|
//localStorage.setItem('varDict', JSON.stringify(deviceStateData.value))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const mecDataFormat = (mecData) => {
|
|
|
|
|
- const resultData = []
|
|
|
|
|
|
|
+const mecDataFormat = (mecData: MecDataItem[]) => {
|
|
|
|
|
+ const resultData: VarDictMecGroupData[] = []
|
|
|
if (mecData) {
|
|
if (mecData) {
|
|
|
mecData.forEach((item) => {
|
|
mecData.forEach((item) => {
|
|
|
- const numberTypelist = []
|
|
|
|
|
- const boolTypeList = []
|
|
|
|
|
- const gearList = []
|
|
|
|
|
- item.varList_simple.forEach((simpleItem) => {
|
|
|
|
|
- if (simpleItem.data_type === 1) {
|
|
|
|
|
- boolTypeList.push({
|
|
|
|
|
- VarName: simpleItem.var_name,
|
|
|
|
|
- Value: true,
|
|
|
|
|
- VarCode: simpleItem.var_code,
|
|
|
|
|
- SwitchType: simpleItem.switch_type
|
|
|
|
|
- })
|
|
|
|
|
- } else {
|
|
|
|
|
- numberTypelist.push({
|
|
|
|
|
- VarName: simpleItem.var_name,
|
|
|
|
|
- Value: 0,
|
|
|
|
|
- VarCategory: simpleItem.var_category,
|
|
|
|
|
- VarCode: simpleItem.var_code
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- if (simpleItem.var_category == 1) {
|
|
|
|
|
- gearList.push({
|
|
|
|
|
- VarName: simpleItem.var_name,
|
|
|
|
|
- Value: false,
|
|
|
|
|
- VarCode: simpleItem.var_code,
|
|
|
|
|
- VarCategory: simpleItem.var_category
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ let numberTypelist: BizVarDictTable[] = []
|
|
|
|
|
+ let boolTypeList: BizVarDictTable[] = []
|
|
|
|
|
+ let gearList: BizVarDictTable[] = []
|
|
|
|
|
+ numberTypelist = [...item.analog_varList]
|
|
|
|
|
+ boolTypeList = [...item.digital_varList]
|
|
|
|
|
+ if(item.mec_type != '0' && item.mec_type != '6'){
|
|
|
|
|
+ numberTypelist.push({
|
|
|
|
|
+ var_code: 'G00'+item.mec_type,
|
|
|
|
|
+ var_name: '挡位',
|
|
|
|
|
+ value: '0'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ boolTypeList.forEach((boolItem) => {
|
|
|
|
|
+ if (boolItem.var_category == "1") {
|
|
|
|
|
+ gearList.push(boolItem)
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
resultData.push({
|
|
resultData.push({
|
|
|
- MecType: item.mec_type,
|
|
|
|
|
- numberTypeList: numberTypelist,
|
|
|
|
|
- boolTypeList: boolTypeList,
|
|
|
|
|
- gearList: gearList
|
|
|
|
|
|
|
+ mec_type: item.mec_type,
|
|
|
|
|
+ bool_type_list: boolTypeList,
|
|
|
|
|
+ gear_list: gearList,
|
|
|
|
|
+ number_type_list: numberTypelist
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
@@ -104,84 +107,60 @@ const dictTypes: any = [
|
|
|
const getData = () => {
|
|
const getData = () => {
|
|
|
getCraneMecTreeData()
|
|
getCraneMecTreeData()
|
|
|
}
|
|
}
|
|
|
-const getBgColor = (bool, type) => {
|
|
|
|
|
- switch (type) {
|
|
|
|
|
- case 1:
|
|
|
|
|
- return bool ? 'pilot-lamp-bg-green' : 'pilot-lamp-bg-grey';
|
|
|
|
|
- case 2:
|
|
|
|
|
- return bool ? 'pilot-lamp-bg-green' : 'pilot-lamp-bg-yellow';
|
|
|
|
|
- case 3:
|
|
|
|
|
- return bool ? 'pilot-lamp-bg-green' : 'pilot-lamp-bg-orange';
|
|
|
|
|
- case 4:
|
|
|
|
|
- return bool ? 'pilot-lamp-bg-green' : 'pilot-lamp-bg-red';
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+const getBgColor = (bool: string | undefined, type: string | undefined) => {
|
|
|
|
|
+
|
|
|
|
|
+ const validType = type || '0';
|
|
|
|
|
|
|
|
-//初始化 MQTT 连接并订阅主题
|
|
|
|
|
-const initMqttClient = () => {
|
|
|
|
|
- // 避免重复连接
|
|
|
|
|
- if (mqttClient && mqttClient.connected) {
|
|
|
|
|
- console.log('[MQTT] 客户端已连接,无需重复初始化');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- console.log(`[MQTT] 开始连接 Broker: ${MQTT_WS_URL}`);
|
|
|
|
|
|
|
+ const falseColorMap: Record<string, string> = {
|
|
|
|
|
+ '0': 'pilot-lamp-bg-grey',
|
|
|
|
|
+ '1': 'pilot-lamp-bg-grey',
|
|
|
|
|
+ '2': 'pilot-lamp-bg-green',
|
|
|
|
|
+ '3': 'pilot-lamp-bg-green',
|
|
|
|
|
+ '4': 'pilot-lamp-bg-green'
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- // 创建 MQTT 客户端
|
|
|
|
|
- mqttClient = mqtt.connect(MQTT_WS_URL);
|
|
|
|
|
|
|
+ const trueColorMap: Record<string, string> = {
|
|
|
|
|
+ '0': 'pilot-lamp-bg-green',
|
|
|
|
|
+ '1': 'pilot-lamp-bg-green',
|
|
|
|
|
+ '2': 'pilot-lamp-bg-yellow',
|
|
|
|
|
+ '3': 'pilot-lamp-bg-orange',
|
|
|
|
|
+ '4': 'pilot-lamp-bg-red'
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- // 连接成功回调
|
|
|
|
|
- mqttClient.on('connect', () => {
|
|
|
|
|
- console.log('[MQTT] 连接成功');
|
|
|
|
|
|
|
+ const class_name = bool
|
|
|
|
|
+ ? trueColorMap[validType]
|
|
|
|
|
+ : falseColorMap[validType] || 'pilot-lamp-bg-grey';
|
|
|
|
|
|
|
|
- // 同时订阅两个主题
|
|
|
|
|
- mqttClient?.subscribe([VAR_TOPIC], (err) => {
|
|
|
|
|
- if (err) {
|
|
|
|
|
- console.error('[MQTT] 订阅主题失败:', err);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- console.log(`[MQTT] 订阅主题成功:${VAR_TOPIC}`);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // 接收消息回调(统一处理所有主题消息)
|
|
|
|
|
- mqttClient.on('message', (topic, payload) => {
|
|
|
|
|
- console.log(`[MQTT] 收到主题 ${topic} 的消息:`, payload.toString());
|
|
|
|
|
- try {
|
|
|
|
|
- const message = JSON.parse(payload.toString());
|
|
|
|
|
- //挡位计算
|
|
|
|
|
- message = gearCalculation(message, varDictMecGroupData.value)
|
|
|
|
|
- message.data.forEach(msgItem => {
|
|
|
|
|
- deviceStateData.value.forEach(item => {
|
|
|
|
|
- item.numberTypeList.forEach(numberItem => {
|
|
|
|
|
- if (msgItem.var_code === numberItem.VarCode) {
|
|
|
|
|
- numberItem.Value = msgItem.value
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- item.boolTypeList.forEach(boolItem => {
|
|
|
|
|
- if (msgItem.var_code === boolItem.VarCode) {
|
|
|
|
|
- boolItem.Value = msgItem.value
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ return class_name;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleMqttMessage: MqttMessageCallback = (topic, payload) => {
|
|
|
|
|
+ let topic_levels = topic.split('/')
|
|
|
|
|
+ let crane_no = topic_levels[1]
|
|
|
|
|
+ let type = topic_levels[2]
|
|
|
|
|
+ let var_code = topic_levels[3]
|
|
|
|
|
+ varDictMecGroupData.value.forEach(item => {
|
|
|
|
|
+ if(type == 'analog' && item.number_type_list && Array(item.number_type_list)){
|
|
|
|
|
+ item.number_type_list.forEach(numberItem => {
|
|
|
|
|
+ payload.data.forEach((payloadItem: any) => {
|
|
|
|
|
+ if (payloadItem.var_code === numberItem.var_code) {
|
|
|
|
|
+ numberItem.value = payloadItem.value
|
|
|
|
|
+ }
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
- loading.value = false
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- console.error('[MQTT] 解析消息失败:', err);
|
|
|
|
|
|
|
+ }else if(type == 'digital' && item.bool_type_list && Array(item.bool_type_list)){
|
|
|
|
|
+ item.bool_type_list.forEach(boolItem => {
|
|
|
|
|
+ if (var_code === boolItem.var_code) {
|
|
|
|
|
+ boolItem.value = payload.value
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- // 连接断开回调
|
|
|
|
|
- mqttClient.on('close', () => {
|
|
|
|
|
- console.log('[MQTT] 连接已断开');
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ })
|
|
|
|
|
+ //挡位计算
|
|
|
|
|
+ gearCalculation(varDictMecGroupData.value)
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // 连接错误回调
|
|
|
|
|
- mqttClient.on('error', (err) => {
|
|
|
|
|
- console.error('[MQTT] 连接错误:', err);
|
|
|
|
|
- });
|
|
|
|
|
-};
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
|
if (dictTypes.length > 0) {
|
|
if (dictTypes.length > 0) {
|
|
@@ -191,22 +170,11 @@ onMounted(async () => {
|
|
|
receiveData({ craneName: craneInfo.crane_name ?? '', isShowHomeButton: true });
|
|
receiveData({ craneName: craneInfo.crane_name ?? '', isShowHomeButton: true });
|
|
|
}
|
|
}
|
|
|
getData()
|
|
getData()
|
|
|
- mqttService.connect();
|
|
|
|
|
- topics.forEach(topic => {
|
|
|
|
|
- mqttService.subscribe(topic, (message) => {
|
|
|
|
|
-
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ mqttUtil.initConnect(handleMqttMessage);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
|
- // 页面销毁时主动断开 MQTT 连接
|
|
|
|
|
- if (mqttClient) {
|
|
|
|
|
- mqttClient.end(true, () => {
|
|
|
|
|
- console.log('[MQTT] 主动断开连接');
|
|
|
|
|
- mqttClient = null;
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ mqttUtil.releaseResources();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
</script>
|
|
</script>
|
|
@@ -315,4 +283,34 @@ onUnmounted(() => {
|
|
|
background: #f39902;
|
|
background: #f39902;
|
|
|
border-radius: 50%;
|
|
border-radius: 50%;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.el-table-empty {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ color: #8ECAFF;
|
|
|
|
|
+
|
|
|
|
|
+ img {
|
|
|
|
|
+ width: 200px;
|
|
|
|
|
+ height: auto;
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::-webkit-scrollbar {
|
|
|
|
|
+ width: 5px;
|
|
|
|
|
+ height: 5px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::-webkit-scrollbar-track {
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::-webkit-scrollbar-thumb {
|
|
|
|
|
+ border-radius: 7px;
|
|
|
|
|
+ background-color: #798DAE;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|