feat: 更新AMR Redis状态接口,增强数据解析逻辑并添加DI/DO信息处理功能,优化机器人详细卡片的数据展示

This commit is contained in:
xudan 2025-08-15 09:19:39 +08:00
parent f69f699f4a
commit b73f6dcbf3
3 changed files with 108 additions and 13 deletions

View File

@ -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<AmrRedisState | null> {
type D = AmrRedisState;
try {
const data = await http.get<D>(`${API.AMR状态}/${id}`);
return data ?? null;
// 调用真实的AMR Redis接口期望返回一个字符串
const rawData = await http.get<string>(`${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;
}
}

View File

@ -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字符串
}

View File

@ -27,15 +27,23 @@ const lastUpdateTime = ref<string>('');
// 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 [];
}
};
</script>
<template>
@ -179,7 +228,9 @@ const handleModalClose = () => {
<a-tabs v-else>
<a-tab-pane key="basic" :tab="$t('基本信息')">
<a-descriptions :column="2" bordered>
<a-descriptions-item :label="$t('序列号')">{{ amrDetailData.serialnumber || '-' }}</a-descriptions-item>
<a-descriptions-item :label="$t('机器人名称')">{{
amrDetailData.serialnumber || '-'
}}</a-descriptions-item>
<a-descriptions-item :label="$t('制造商')">{{ amrDetailData.manufacturer || '-' }}</a-descriptions-item>
<a-descriptions-item :label="$t('版本')">{{ amrDetailData.version || '-' }}</a-descriptions-item>
<a-descriptions-item :label="$t('订单ID')">{{ amrDetailData.orderid || '-' }}</a-descriptions-item>