From b73f6dcbf3328ef473fd825e64e8267857eaae89 Mon Sep 17 00:00:00 2001 From: xudan Date: Fri, 15 Aug 2025 09:19:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0AMR=20Redis=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=A2=9E=E5=BC=BA=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=A7=A3=E6=9E=90=E9=80=BB=E8=BE=91=E5=B9=B6=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0DI/DO=E4=BF=A1=E6=81=AF=E5=A4=84=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E6=9C=BA=E5=99=A8=E4=BA=BA?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E5=8D=A1=E7=89=87=E7=9A=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/robot/api.ts | 39 ++++++++++++-- src/apis/robot/type.ts | 19 +++++-- src/components/card/robot-detail-card.vue | 63 ++++++++++++++++++++--- 3 files changed, 108 insertions(+), 13 deletions(-) diff --git a/src/apis/robot/api.ts b/src/apis/robot/api.ts index d587a54..1e5cd28 100644 --- a/src/apis/robot/api.ts +++ b/src/apis/robot/api.ts @@ -1,3 +1,5 @@ + + import http from '@core/http'; import type { AmrRedisState, RobotDetail, RobotGroup, RobotInfo } from './type'; @@ -65,12 +67,41 @@ export async function syncGroupRobotsById(id: RobotGroup['id'], sid: RobotGroup[ } export async function getAmrRedisState(id: string): Promise { - type D = AmrRedisState; try { - const data = await http.get(`${API.获取AMR状态}/${id}`); - return data ?? null; + // 调用真实的AMR Redis接口,期望返回一个字符串 + const rawData = await http.get(`${API.获取AMR状态}/${id}`); + // const rawData = "{\"headerid\":64380,\"timestamp\":\"2025-08-15T01:06:30.650Z\",\"version\":\"2.0.0\",\"manufacturer\":\"SEER\",\"serialnumber\":\"AMB-32\",\"orderid\":\"1956034600945082369\",\"orderupdateid\":86,\"lastnodeid\":\"CP361\",\"lastnodesequenceid\":336,\"driving\":false,\"waitingforinteractionzonerelease\":false,\"paused\":false,\"newbaserequest\":false,\"distancesincelastnode\":0.0,\"operatingmode\":\"AUTOMATIC\",\"nodestates\":[],\"edgestates\":[],\"agvposition\":{\"x\":26.3182,\"y\":-25.7896,\"theta\":-3.1397,\"mapid\":\"beidaceshi_1_1\",\"mapdescription\":\"\",\"positioninitialized\":true,\"deviationrange\":0.0,\"localizationscore\":0.7088},\"velocity\":{\"vx\":0.0,\"vy\":0.0,\"omega\":0.0},\"loads\":[],\"actionstates\":[{\"actionid\":\"1955900119873552385\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955900355450830850\",\"actiontype\":\"pick\",\"actiondescription\":\"pick\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955901162296508417\",\"actiontype\":\"pick\",\"actiondescription\":\"pick\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955901437283467266\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955901581278117889\",\"actiontype\":\"pick\",\"actiondescription\":\"pick\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955901764200103938\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955902050960474114\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955902222524284929\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955902444134531073\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955980772799488001\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1955996489338892289\",\"actiontype\":\"pick\",\"actiondescription\":\"pick\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956000338049101825\",\"actiontype\":\"pick\",\"actiondescription\":\"pick\",\"actionstatus\":\"FAILED\",\"resultdescription\":\"\"},{\"actionid\":\"1956002277461716993\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956022573744807937\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956023260138463233\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956023550472380418\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956032209566851074\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956032767774187521\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"},{\"actionid\":\"1956033183660400641\",\"actiontype\":\"drop\",\"actiondescription\":\"drop\",\"actionstatus\":\"FINISHED\",\"resultdescription\":\"\"}],\"batterystate\":{\"batterycharge\":86.0,\"batteryvoltage\":51.319,\"batteryhealth\":100,\"charging\":true,\"reach\":0.0},\"errors\":[],\"information\":[{\"infotype\":\"DI\",\"inforeferences\":[{\"referencekey\":\"DI\",\"referencevalue\":\"[{\\\"id\\\":0,\\\"source\\\":\\\"normal\\\",\\\"status\\\":false,\\\"valid\\\":true},{\\\"id\\\":1,\\\"source\\\":\\\"normal\\\",\\\"status\\\":false,\\\"valid\\\":true},{\\\"id\\\":2,\\\"source\\\":\\\"normal\\\",\\\"status\\\":true,\\\"valid\\\":true},{\\\"id\\\":3,\\\"source\\\":\\\"normal\\\",\\\"status\\\":false,\\\"valid\\\":true},{\\\"id\\\":6,\\\"source\\\":\\\"normal\\\",\\\"status\\\":true,\\\"valid\\\":true}]\"}],\"infodescription\":\"info of DI\",\"infolevel\":\"INFO\"},{\"infotype\":\"DO\",\"inforeferences\":[{\"referencekey\":\"DO\",\"referencevalue\":\"[{\\\"id\\\":0,\\\"status\\\":true}]\"}],\"infodescription\":\"info of DO\",\"infolevel\":\"INFO\"}],\"safetystate\":{\"estop\":\"NONE\",\"fieldviolation\":false}}"; + + if (!rawData) { + console.error('AMR Redis接口调用失败: 返回数据为空'); + return null; + } + + try { + // 第一次解析:处理API本身返回的JSON字符串 + let parsedData = JSON.parse(rawData); + + // 检查第一次解析的结果是否仍然是字符串(双重编码的情况) + if (typeof parsedData === 'string') { + try { + // 第二次解析:处理嵌套的JSON字符串 + parsedData = JSON.parse(parsedData); + } catch (e) { + console.error('第二次解析AMR Redis数据失败(数据可能不是双重编码):', e); + console.log('将返回第一次解析的结果'); + } + } + + return parsedData as AmrRedisState; + } catch (e) { + console.error('解析AMR Redis数据失败:', e); + console.error('原始数据:', rawData); + // 如果解析失败,但rawData本身就是个对象,那可能不是JSON字符串,直接返回 + if (typeof rawData === 'object') return rawData as AmrRedisState; + return null; + } } catch (error) { - console.debug(error); + console.error('获取AMR Redis状态失败:', error); return null; } } diff --git a/src/apis/robot/type.ts b/src/apis/robot/type.ts index e9d8e26..0594aa4 100644 --- a/src/apis/robot/type.ts +++ b/src/apis/robot/type.ts @@ -47,7 +47,7 @@ export interface RobotRealtimeInfo extends RobotInfo { isFault?: boolean; // 是否故障 } -// AMR Redis状态接口 +// AMR Redis状态接口 - 更新为实际返回的数据结构 export interface AmrRedisState { headerid: number; timestamp: string; @@ -64,8 +64,8 @@ export interface AmrRedisState { newbaserequest: boolean; distancesincelastnode: number; operatingmode: string; - nodestates: any[]; - edgestates: any[]; + nodestates: unknown[]; + edgestates: unknown[]; agvposition: { x: number; y: number; @@ -134,3 +134,16 @@ export interface AmrRedisState { fieldviolation: boolean; }; } + +// 新增:DI/DO信息结构 +export interface DiDoInfo { + id: number; + source?: string; + status: boolean; + valid: boolean; +} + +export interface DiDoReference { + referencekey: string; + referencevalue: string; // 实际是JSON字符串 +} diff --git a/src/components/card/robot-detail-card.vue b/src/components/card/robot-detail-card.vue index 1ef9988..3fd729c 100644 --- a/src/components/card/robot-detail-card.vue +++ b/src/components/card/robot-detail-card.vue @@ -27,15 +27,23 @@ const lastUpdateTime = ref(''); // 获取AMR详情 const fetchAmrDetail = async () => { - if (!robot.value?.id) return; + if (!robot.value?.label) return; // 先打开弹窗,数据未到时展示空 amrDetailVisible.value = true; try { // 调用真实接口 - const data = await getAmrRedisState(robot.value.id); - console.log(data + 'AMR全量redis接口返回数据'); - amrDetailData.value = data; - lastUpdateTime.value = new Date().toLocaleString('zh-CN'); + const data = await getAmrRedisState(robot.value.label); + if (data) { + amrDetailData.value = data; + lastUpdateTime.value = new Date().toLocaleString('zh-CN'); + } else { + // 接口返回null,设置错误标记 + amrDetailData.value = { error: true, message: '接口返回空数据' } as AmrRedisState & { + error: boolean; + message: string; + }; + lastUpdateTime.value = new Date().toLocaleString('zh-CN'); + } } catch (error) { console.error('获取AMR详情失败:', error); // 如果接口调用失败,设置一个错误标记 @@ -62,6 +70,47 @@ const handleModalClose = () => { amrDetailData.value = null; lastUpdateTime.value = ''; }; + +// 获取DI信息 +const getDiInfo = (information: AmrRedisState['information'] | undefined) => { + if (!information) return []; + + const diInfo = information.find((info) => info.infotype === 'DI'); + if (!diInfo) return []; + + try { + const diData = JSON.parse(diInfo.inforeferences[0]?.referencevalue || '[]'); + return diData.map((item: { id: number; source?: string; status: boolean; valid: boolean }) => ({ + id: item.id, + source: item.source, + status: item.status, + valid: item.valid, + })); + } catch (error) { + console.error('解析DI信息失败:', error); + return []; + } +}; + +// 获取DO信息 +const getDoInfo = (information: AmrRedisState['information'] | undefined) => { + if (!information) return []; + + const doInfo = information.find((info) => info.infotype === 'DO'); + if (!doInfo) return []; + + try { + const doData = JSON.parse(doInfo.inforeferences[0]?.referencevalue || '[]'); + return doData.map((item: { id: number; status: boolean }) => ({ + id: item.id, + status: item.status, + valid: true, // DO通常都是有效的 + })); + } catch (error) { + console.error('解析DO信息失败:', error); + return []; + } +};