diff --git a/package.json b/package.json index 1aa4046..187984c 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "vue3-ace-editor": "^2.2.4", "vue3-json-viewer": "2.3.0", "vuedraggable": "4.1.0", + "xacro-parser": "^0.3.11", "xgplayer": "^3.0.22" }, "devDependencies": { diff --git a/public/inspection/elfin10/elfin10.urdf.xacro b/public/inspection/elfin10/elfin10.urdf.xacro new file mode 100644 index 0000000..4aa83c3 --- /dev/null +++ b/public/inspection/elfin10/elfin10.urdf.xacro @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/inspection/elfin10/elfin10_gazebo.xacro b/public/inspection/elfin10/elfin10_gazebo.xacro new file mode 100644 index 0000000..01581e9 --- /dev/null +++ b/public/inspection/elfin10/elfin10_gazebo.xacro @@ -0,0 +1,134 @@ + + + + + + + + + gazebo_ros2_control/GazeboSystem + $(find elfin10_ros2_gazebo)/config/elfin_arm_controller.yaml + + + + + + + + elfin_hardware_interface/ElfinHWInterface + + + + + fake_components/GenericSystem + + + + gazebo_ros2_control/GazeboSystem + + + + + + + + -3.14 + 3.14 + + + -1.57 + 1.57 + + + + + + + -2.35 + 2.35 + + + -1.57 + 1.57 + + + + + + + -2.61 + 2.61 + + + -1.57 + 1.57 + + + + + + + -3.14 + 3.14 + + + -1.57 + 1.57 + + + + + + + -2.56 + 2.56 + + + -1.57 + 1.57 + + + + + + + -3.14 + 3.14 + + + -1.57 + 1.57 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/inspection/elfin10/elfin10_transmission.xacro b/public/inspection/elfin10/elfin10_transmission.xacro new file mode 100644 index 0000000..12dffc7 --- /dev/null +++ b/public/inspection/elfin10/elfin10_transmission.xacro @@ -0,0 +1,69 @@ + + + + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + transmission_interface/SimpleTransmission + + hardware_interface/PositionJointInterface + + + 1 + + + + + + \ No newline at end of file diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_base.STL b/public/inspection/elfin10/meshes/elfin10/elfin_base.STL new file mode 100644 index 0000000..fa9dd2b Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_base.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_end_link.STL b/public/inspection/elfin10/meshes/elfin10/elfin_end_link.STL new file mode 100644 index 0000000..8536f5d Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_end_link.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link1.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link1.STL new file mode 100644 index 0000000..ca0e111 Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link1.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link2.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link2.STL new file mode 100644 index 0000000..e5a2628 Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link2.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link3.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link3.STL new file mode 100644 index 0000000..bcefa4f Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link3.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link4.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link4.STL new file mode 100644 index 0000000..565329d Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link4.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link5.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link5.STL new file mode 100644 index 0000000..a6d7816 Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link5.STL differ diff --git a/public/inspection/elfin10/meshes/elfin10/elfin_link6.STL b/public/inspection/elfin10/meshes/elfin10/elfin_link6.STL new file mode 100644 index 0000000..996d478 Binary files /dev/null and b/public/inspection/elfin10/meshes/elfin10/elfin_link6.STL differ diff --git a/src/adapters/URDFAdapter.js b/src/adapters/URDFAdapter.js index ab85d93..cbbfceb 100644 --- a/src/adapters/URDFAdapter.js +++ b/src/adapters/URDFAdapter.js @@ -3,7 +3,7 @@ * Converts urdf-loaders result to unified model */ import * as THREE from 'three'; -import { UnifiedRobotModel, Link, Joint, JointLimits, VisualGeometry, CollisionGeometry, InertialProperties } from '../models/UnifiedRobotModel.js'; +import { UnifiedRobotModel, Link, Joint, JointLimits, VisualGeometry, CollisionGeometry, InertialProperties } from '@/models/UnifiedRobotModel.js'; export class URDFAdapter { /** diff --git a/src/adapters/XacroAdapter.js b/src/adapters/XacroAdapter.js index e561d19..97b4c56 100644 --- a/src/adapters/XacroAdapter.js +++ b/src/adapters/XacroAdapter.js @@ -76,6 +76,7 @@ export class XacroAdapter { // Parse xacro to URDF XML const urdfXML = await parser.parse(xacroContent); + // Convert XMLDocument to string const serializer = new XMLSerializer(); let urdfString = serializer.serializeToString(urdfXML); @@ -91,7 +92,6 @@ export class XacroAdapter { // Check for parsing errors const parseError = cleanUrdfXML.querySelector('parsererror'); if (parseError) { - console.error('[XacroAdapter] XML parsing error:', parseError.textContent); throw new Error('Generated URDF has invalid XML: ' + parseError.textContent); } @@ -258,6 +258,8 @@ export class XacroAdapter { done(null, err); }); } else { + let stlPath = path + stlPath = stlPath.replace('file:///', 'inspection/elfin10') originalLoadMeshCb(path, manager, done); } }).catch(error => { @@ -304,13 +306,13 @@ export class XacroAdapter { static async loadFileFromMap(path, fileMap, workingPath) { // Clean path - remove leading slash if present let cleanPath = path; - if (cleanPath.startsWith('/')) { - cleanPath = cleanPath.substring(1); - } - - // Remove leading ./ - cleanPath = cleanPath.replace(/^\.\//, ''); + // if (cleanPath.startsWith('/')) { + // cleanPath = cleanPath.substring(1); + // } + // // Remove leading ./ + // cleanPath = cleanPath.replace(/^\.\//, ''); + cleanPath = cleanPath.split('///')[1]; // Try different path combinations const possiblePaths = [ cleanPath, diff --git a/src/api/inspection/cockpit.js b/src/api/inspection/cockpit.js new file mode 100644 index 0000000..055c658 --- /dev/null +++ b/src/api/inspection/cockpit.js @@ -0,0 +1,97 @@ +import request from '@/utils/request' + +export function getPoseApi(params) { + return request({ + url: '/api/arm/getPose', + method: 'get', + params: params + }) +} + +export function getJointStateApi(params) { + return request({ + url: '/api/arm/getJointState', + method: 'get', + params: params + }) +} + +export function speedLApi(data) { + return request({ + url: '/api/arm/speedL', + method: 'post', + data: data + }) +} + +export function moveJApi(data) { + return request({ + url: '/api/arm/moveJ', + method: 'post', + data: data + }) +} + +export function stopMotionApi(params) { + return request({ + url: '/api/arm/stopMotion', + method: 'get', + params: params + }) +} + +export function torqueOnApi(params) { + return request({ + url: '/api/arm/torqueOn', + method: 'get', + params: params + }) +} + +export function speedJApi(data) { + return request({ + url: '/api/arm/speedJ', + method: 'post', + data: data + }) +} + +export function clearFault(params) { + return request({ + url: '/api/arm/clearFault', + method: 'get', + params: params + }) +} + +export function getMicVolume(params) { + return request({ + url: '/api/Microphone/volume', + method: 'get', + params: params + }) +} + +export function setMicVolume(data) { + return request({ + url: '/api/Microphone/volume', + method: 'post', + data: data + }) +} + +export function getSpeakerVolume(params) { + return request({ + url: '/api/Speaker/volume', + method: 'get', + params: params + }) +} + +export function setSpeakerVolume(data) { + return request({ + url: '/api/Speaker/volume', + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/src/api/inspection/result.js b/src/api/inspection/result.js new file mode 100644 index 0000000..4132315 --- /dev/null +++ b/src/api/inspection/result.js @@ -0,0 +1,23 @@ +import request from '@/utils/request' + +/** + * 查询巡检结果列表。 + */ +export function getInspectionResultList(params) { + return request({ + url: '/inspection/result/list', + method: 'get', + params + }) +} + +/** + * 提交人工复核结果。 + */ +export function reviewInspectionResult(id, data) { + return request({ + url: `/inspection/result/${id}/review`, + method: 'put', + data + }) +} diff --git a/src/api/inspection/robot.js b/src/api/inspection/robot.js index c4963f2..cde224d 100644 --- a/src/api/inspection/robot.js +++ b/src/api/inspection/robot.js @@ -54,4 +54,54 @@ export function getMapJson(params) { method: 'get', params }) -} \ No newline at end of file +} + +/** + * 获取机器人位置 + * @param {*} robotId + * @returns + */ +export function getRobotLocation(robotId) { + return request({ + url: `/inspection/robot/${robotId}/location`, + method: 'get' + }) +} + +/** + * 获取机器人状态 + * @param {*} robotId + * @returns + */ +export function getRobotStatus(robotId) { + return request({ + url: `/inspection/robot/{robotId}/sync-status`, + method: 'get' + }) +} + +/** + * 机器人运动控制 + * @param {*} data + * @returns + */ +export function moveRobot(data) { + return request({ + url: '/api/agv/setVelocity', + method: 'post', + data: data + }) +} + +/** + * 机器人停止运动 + * @param {*} data + * @returns + */ +export function stopRobot(data) { + return request({ + url: '/api/agv/stopVelocityControl', + method: 'post', + data: data + }) +} diff --git a/src/api/intelligenceTest/car.js b/src/api/intelligenceTest/car.js new file mode 100644 index 0000000..5d8c25e --- /dev/null +++ b/src/api/intelligenceTest/car.js @@ -0,0 +1,32 @@ +import request from '@/utils/request' + +export function addVehicle(data) { + return request({ + url: '/aima/vehicle', + method: 'post', + data: data + }) +} + +export function getVehicleList(params) { + return request({ + url: '/aima/vehicle/list', + method: 'get', + params: params + }) +} + +export function updateVehicle(data) { + return request({ + url: '/aima/vehicle', + method: 'put', + data: data + }) +} + +export function deleteVehicle(ids) { + return request({ + url: `/aima/vehicle/${ids}`, + method: 'delete' + }) +} \ No newline at end of file diff --git a/src/api/intelligenceTest/mobilePhone.js b/src/api/intelligenceTest/mobilePhone.js new file mode 100644 index 0000000..b683fc2 --- /dev/null +++ b/src/api/intelligenceTest/mobilePhone.js @@ -0,0 +1,32 @@ +import request from '@/utils/request' + +export function addPhone(data) { + return request({ + url: '/aima/phone', + method: 'post', + data: data + }) +} + +export function getPhoneList(params) { + return request({ + url: '/aima/phone/list', + method: 'get', + params: params + }) +} + +export function updatePhone(data) { + return request({ + url: '/aima/phone', + method: 'put', + data: data + }) +} + +export function deletePhone(ids) { + return request({ + url: `/aima/phone/${ids}`, + method: 'delete' + }) +} \ No newline at end of file diff --git a/src/api/intelligenceTest/runningTask.js b/src/api/intelligenceTest/runningTask.js new file mode 100644 index 0000000..adfd01e --- /dev/null +++ b/src/api/intelligenceTest/runningTask.js @@ -0,0 +1,69 @@ +import request from '@/utils/request' +import { method } from 'lodash' + +export function addTaskinstance(data) { + return request({ + url: '/aima/taskinstance', + method: 'post', + data: data + }) +} + +export function getTaskinstanceList(params) { + return request({ + url: '/aima/taskinstance/list', + method: 'get', + params: params + }) +} + +export function updateTaskinstance(data) { + return request({ + url: '/aima/taskinstance', + method: 'put', + data: data + }) +} + +export function deleteTaskinstance(ids) { + return request({ + url: `/aima/taskinstance/{ids}`, + method: 'delete' + }) +} + +export function startTaskinstance(id) { + return request({ + url: `/aima/taskinstance/start/${id}`, + method: 'put' + }) +} + +export function pauseTaskinstance(id) { + return request({ + url: `/aima/taskinstance/pause/${id}`, + method: 'put' + }) +} + +export function stopTaskinstance(id) { + return request({ + url: `/aima/taskinstance/stop/${id}`, + method: 'put' + }) +} + +export function resumeTaskinstance(id) { + return request({ + url: `/aima/taskinstance/resume/${id}`, + method: 'put' + }) +} + +export function getTaskLogListApi(params) { + return request({ + url: '/aima/testlog/list', + method: 'get', + params: params + }) +} \ No newline at end of file diff --git a/src/api/intelligenceTest/taskManage.js b/src/api/intelligenceTest/taskManage.js new file mode 100644 index 0000000..457d33f --- /dev/null +++ b/src/api/intelligenceTest/taskManage.js @@ -0,0 +1,47 @@ +import request from '@/utils/request' + +export function addTask(data) { + return request({ + url: '/aima/task', + method: 'post', + data: data + }) +} + +export function getTaskList(params) { + return request({ + url: '/aima/task/list', + method: 'get', + params: params + }) +} + +export function updateTask(data) { + return request({ + url: '/aima/task', + method: 'put', + data: data + }) +} + +export function deleteTask(ids) { + return request({ + url: `/aima/task/${ids}`, + method: 'delete' + }) +} + +export function getTestCaseByTaskId(taskId) { + return request({ + url: `/aima/task/testCases/${taskId}`, + method: 'get', + }) +} + +export function bindTastCase(taskId, ids) { + return request({ + url: `/aima/task/bindTestCases/${taskId}`, + method: 'post', + data: ids + }) +} \ No newline at end of file diff --git a/src/api/intelligenceTest/testCase.js b/src/api/intelligenceTest/testCase.js new file mode 100644 index 0000000..374ebe1 --- /dev/null +++ b/src/api/intelligenceTest/testCase.js @@ -0,0 +1,32 @@ +import request from '@/utils/request' + +export function addTestCase(data) { + return request({ + url: '/aima/testcase', + method: 'post', + data: data + }) +} + +export function getTestCaseList(params) { + return request({ + url: '/aima/testcase/list', + method: 'get', + params: params + }) +} + +export function updateTestCase(data) { + return request({ + url: '/aima/testcase', + method: 'put', + data: data + }) +} + +export function deleteTestCase(ids) { + return request({ + url: `/aima/testcase/${ids}`, + method: 'delete' + }) +} \ No newline at end of file diff --git a/src/models/UnifiedRobotModel.js b/src/models/UnifiedRobotModel.js new file mode 100644 index 0000000..1ef44f8 --- /dev/null +++ b/src/models/UnifiedRobotModel.js @@ -0,0 +1,181 @@ +/** + * Unified robot model data interface + * All formats (URDF, MJCF, USD) are converted to this unified format + */ +export class UnifiedRobotModel { + constructor() { + this.name = ''; + this.links = new Map(); // Map + this.joints = new Map(); // Map + this.materials = new Map(); // Map + this.constraints = new Map(); // Map - for parallel mechanism constraints + this.rootLink = null; // Root link name + this.threeObject = null; // Three.js object (if available) + } + + addLink(link) { + this.links.set(link.name, link); + } + + addJoint(joint) { + this.joints.set(joint.name, joint); + } + + addConstraint(constraint) { + this.constraints.set(constraint.name, constraint); + } + + getLink(name) { + return this.links.get(name); + } + + getJoint(name) { + return this.joints.get(name); + } + + getConstraint(name) { + return this.constraints.get(name); + } +} + +/** + * Link interface + */ +export class Link { + constructor(name) { + this.name = name; + this.visuals = []; // VisualGeometry[] + this.collisions = []; // CollisionGeometry[] + this.inertial = null; // InertialProperties + this.threeObject = null; // Three.js object + this.userData = {}; // User-defined data (for adapters to store additional information) + } +} + +/** + * VisualGeometry interface + */ +export class VisualGeometry { + constructor() { + this.name = ''; + this.origin = { xyz: [0, 0, 0], rpy: [0, 0, 0] }; + this.geometry = null; // GeometryType + this.material = null; // Material + this.threeObject = null; // Three.js Mesh + } +} + +/** + * CollisionGeometry interface + */ +export class CollisionGeometry { + constructor() { + this.name = ''; + this.origin = { xyz: [0, 0, 0], rpy: [0, 0, 0] }; + this.geometry = null; // GeometryType + this.threeObject = null; // Three.js Mesh + } +} + +/** + * GeometryType interface + */ +export class GeometryType { + constructor(type) { + this.type = type; // 'box' | 'sphere' | 'cylinder' | 'mesh' + this.size = null; // Size parameters (varies by type) + this.filename = null; // Mesh file path (if mesh type) + } + + clone() { + const cloned = new GeometryType(this.type); + cloned.size = this.size ? { ...this.size } : null; + cloned.filename = this.filename; + return cloned; + } +} + +/** + * InertialProperties interface + */ +export class InertialProperties { + constructor() { + this.mass = 0; + this.origin = { xyz: [0, 0, 0], rpy: [0, 0, 0] }; + this.ixx = 0; + this.iyy = 0; + this.izz = 0; + this.ixy = 0; + this.ixz = 0; + this.iyz = 0; + } +} + +/** + * Joint interface + */ +export class Joint { + constructor(name, type) { + this.name = name; + this.type = type; // 'revolute' | 'prismatic' | 'fixed' | 'continuous' + this.parent = null; // Parent link name + this.child = null; // Child link name + this.origin = { xyz: [0, 0, 0], rpy: [0, 0, 0] }; + this.axis = { xyz: [0, 0, 1] }; // Default z-axis + this.limits = null; // JointLimits + this.currentValue = 0; // Current joint value + this.threeObject = null; // Three.js object (if available) + } +} + +/** + * JointLimits interface + */ +export class JointLimits { + constructor() { + this.lower = -Math.PI; + this.upper = Math.PI; + this.effort = null; + this.velocity = null; + } +} + +/** + * Material interface + */ +export class Material { + constructor(name) { + this.name = name; + this.color = { r: 0.8, g: 0.8, b: 0.8 }; + this.texture = null; + } +} + +/** + * Constraint interface - for describing closed-chain constraints of parallel mechanisms + * Supports MuJoCo equality constraint types + */ +export class Constraint { + constructor(name, type) { + this.name = name; + this.type = type; // 'connect' | 'weld' | 'joint' | 'tendon' | 'distance' + + // Constraint objects (may be body, geom, joint, etc. depending on type) + this.body1 = null; + this.body2 = null; + this.anchor = null; // Connection point coordinates + this.torquescale = null; // Torque scale + + // Joint constraint specific properties + this.joint1 = null; + this.joint2 = null; + this.polycoef = null; // Polynomial coefficients [a0, a1, a2, a3, a4] + + // Visualization object + this.threeObject = null; // Three.js object for displaying constraint + + // Original data (for debugging) + this.userData = {}; + } +} + diff --git a/src/utils/request.js b/src/utils/request.js index 1443ff1..066bf4a 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -17,7 +17,7 @@ const service = axios.create({ // axios中请求配置有baseURL选项,表示请求URL公共部分 baseURL: import.meta.env.VITE_APP_BASE_API, // 超时 - timeout: 100000 + timeout: 10000 }) // request拦截器 @@ -95,7 +95,7 @@ service.interceptors.response.use(res => { } return Promise.reject('无效的会话,或者会话已过期,请重新登录。') } else if (code === 500) { - ElMessage({ message: msg, type: 'error' }) + ElMessage({ message: msg, grouping: true, type: 'error' }) return Promise.reject(new Error(msg)) } else if (code === 601) { ElMessage({ message: msg, type: 'warning' }) @@ -117,7 +117,7 @@ service.interceptors.response.use(res => { } else if (message.includes("Request failed with status code")) { message = "系统接口" + message.substr(message.length - 3) + "异常"; } - ElMessage({ message: message, type: 'error', duration: 5 * 1000 }) + ElMessage({ message: message, type: 'error', grouping: true, duration: 5 * 1000 }) return Promise.reject(error) } ) diff --git a/src/views/flow/components/ParamsDrawer.vue b/src/views/flow/components/ParamsDrawer.vue index 3e325b9..b071c70 100644 --- a/src/views/flow/components/ParamsDrawer.vue +++ b/src/views/flow/components/ParamsDrawer.vue @@ -26,6 +26,7 @@ import BasicNodeParams from './params/BasicNodeParams.vue' import CodeNodeParams from './params/CodeNodeParams.vue' import HttpNodeParams from './params/HttpNodeParams.vue' import SdAgentNodeParams from './params/SdAgentNodeParams.vue' +import RecognizeNodeParams from './params/RecognizeNodeParams.vue' const props = defineProps({ drawer: Boolean, @@ -43,6 +44,7 @@ const currentComponent = computed(() => { if (type === 'code') return CodeNodeParams if (type === 'http') return HttpNodeParams if (type === 'sdAgent') return SdAgentNodeParams + if (type === 'recognize') return RecognizeNodeParams return null }) diff --git a/src/views/flow/components/params/RecognizeNodeParams.vue b/src/views/flow/components/params/RecognizeNodeParams.vue new file mode 100644 index 0000000..8ece251 --- /dev/null +++ b/src/views/flow/components/params/RecognizeNodeParams.vue @@ -0,0 +1,356 @@ + + + + + diff --git a/src/views/flow/config.js b/src/views/flow/config.js index 39db4fa..1cd61e0 100644 --- a/src/views/flow/config.js +++ b/src/views/flow/config.js @@ -436,6 +436,38 @@ function handler(params) { outputParams: [], outputType: 'json' }, + { + icon: dialogueSvg, + name: "巡检仪表读数识别", + type: "recognize", + desc: "巡检仪表读数识别", + action: 'INSPECTION_METER_RECOGNIZE', + nodeType: "LLM", + outputType: 'json', + nodeParams: [ + { name: 'imageUrl', type: "input", input: "", disabled: true }, + { name: 'resultName', type: "input", input: "", disabled: true }, + { name: "alarmRules", type: "input", input: [], disabled: true } + ], + outputParams: [] + }, + { + icon: cameraSvg, + name: "人工巡检判断", + type: "serviceNode", + desc: "创建人工巡检判断任务", + action: 'INSPECTION_MANUAL_REVIEW_CREATE', + nodeType: 'EDGE', + nodeParams: [ + { name: "resultName", type: "input", input: "", disabled: true }, + { name: "videoUrl", type: "input", input: "", required: false, disabled: true }, + { name: "imageUrl", type: "input", input: "", required: false, disabled: true }, + { name: "reviewCriteria", type: "input", input: "", disabled: true }, + { name: "defaultAlarmLevel", type: "input", componentType: 'number', max: 3, step: 1, input: 1, disabled: true }, + ], + outputParams: [], + outputType: 'json' + }, ], }, { diff --git a/src/views/flow/nodes/function/index.js b/src/views/flow/nodes/function/index.js index 3de78bd..1e889bb 100644 --- a/src/views/flow/nodes/function/index.js +++ b/src/views/flow/nodes/function/index.js @@ -8,6 +8,7 @@ import { registerHttpNode } from './httpNode' import { registerCodeNode } from './codeNode' import { registerCurrentLoopNode } from './currentLoopNode' import { registerSdAgentNode } from './sdAgent' +import { registerRecognizeNode } from './recognize' export const registerFunction = (lf) => { registerLoopBodyNode(lf) @@ -20,4 +21,5 @@ export const registerFunction = (lf) => { registerCodeNode(lf) registerCurrentLoopNode(lf) registerSdAgentNode(lf) + registerRecognizeNode(lf) } \ No newline at end of file diff --git a/src/views/flow/nodes/function/recognize.js b/src/views/flow/nodes/function/recognize.js new file mode 100644 index 0000000..1e798d0 --- /dev/null +++ b/src/views/flow/nodes/function/recognize.js @@ -0,0 +1,213 @@ +// 导入 HtmlNode 及其模型,为后续继承做准备 +import { HtmlNode, HtmlNodeModel } from "@logicflow/core"; +// 导入 Vue 相关方法,用于渲染组件 +import { createApp, h, nextTick } from "vue"; +import ElementPlus from "element-plus"; +// 导入 Vue 组件 +// @ts-ignore +import Recognize from "./recognize.vue"; +import OuterNode from "../../components/OuterNode.vue"; +import JsonViewer from 'vue3-json-viewer' + +/** + * 定义一个 元素的 HTML 节点类,继承自 HtmlNode + * 该类负责在 HTML 中渲染 元素,并处理其交互逻辑 + */ +class RecognizeNodeHtmlNode extends HtmlNode { + resizeObserver = null; + isMounted; // 标记组件是否已挂载 + r; // 渲染函数 + app; // Vue 应用实例 + container = null; + + static reusePool = new Map(); // 节点复用池 + + /** + * 构造函数 + * @param props 传递给节点的属性,包括模型、图模型等 + */ + constructor(props) { + super(props); + this.initVueApp(props); + } + + initVueApp(props) { + this.isMounted = false; + + this.hideAnchor = false; + this.autoExpand = true; // 防止锚点被折叠 + this.anchorsPreset = "default"; // 重置锚点预设 + // 创建 元素的渲染函数 + this.r = h(OuterNode, { + model: props.model, + component: Recognize, + properties: { + ...props.model.getProperties(), + }, + onContentChange: this.handleContentChange.bind(this), + onBindRef: this.handleComponentInstance.bind(this) + }); + + // 创建 Vue 应用实例,并指定渲染函数 + this.app = createApp({ + render: () => this.r, + }); + } + + /** + * 将 HTML 内容设置到指定的根元素上 + * @param rootEl 根元素 + */ + async setHtml(rootEl) { + const nodeId = this.props.model.id; + if (RecognizeNodeHtmlNode.reusePool.has(nodeId)) { + rootEl.appendChild(RecognizeNodeHtmlNode.reusePool.get(nodeId)); + return; + } + + if (!this.isMounted) { + this.isMounted = true; + this.container = document.createElement("div"); + this.container.style.display = "inline-block"; // 关键:确保容器自适应内容 + + rootEl.appendChild(this.container); + this.app.use(ElementPlus); + this.app.use(JsonViewer); + + this.app.mount(this.container); + await nextTick(); + this.setupSizeObserver(); + RecognizeNodeHtmlNode.reusePool.set(nodeId, this.container); + } else { + this.r.component.props.properties = this.props.model.getProperties(); + } + } + + /** + * 获取节点文本内容 + * 对于元素,返回 null,因为其内容由特定组件渲染 + * @returns {null} + */ + getText() { + return null; + } + + handleComponentInstance(data) { + // 将组件实例保存到节点模型 + this.props.model.setComponentInstance(data) + } + + handleContentChange() { + // 内容变化时强制更新尺寸 + this.updateNodeSize(); + } + + // 渲染完成后获取实际尺寸 + updateNodeSize() { + if (this.container) { + const { SCALE_X, SCALE_Y } = this.props.graphModel.transformModel; + const node = this.container.querySelector(".node__container"); + const rect = node.getBoundingClientRect(); + this.props.model.updateSize(rect.width / SCALE_X, rect.height / SCALE_Y); + } + } + + setupSizeObserver() { + // 首次渲染立即检测 + requestAnimationFrame(() => { + this.updateNodeSize(); + // 持续监听变化 + this.resizeObserver = new ResizeObserver(() => { + this.updateNodeSize(); + }); + this.resizeObserver.observe(this.container); + }); + } + + // 组件卸载时移除监听 + onDestroy() { + this.resizeObserver?.disconnect(); + } +} + +/** + * 定义一个元素的 HTML 模型类,继承自 HtmlNodeModel + * 该类主要设置节点的属性和样式 + */ +class RecognizeNodeHtmlModel extends HtmlNodeModel { + initNodeData(data) { + super.initNodeData(data); + } + + // 保存组件实例引用 + setComponentInstance(instance) { + this.componentInstance = instance; + } + + closePopover() { + this.componentInstance.closePopover() + } + + /** + * 设置节点属性 + * 包括宽度、高度、文本编辑属性等 + */ + setAttributes() { + // 初始设置为0,后续动态更新 + this.width = 0; + this.height = 0; + this.text.editable = false; + } + + updateSize(width, height) { + this.width = width + 24; + this.height = height + 50; + this.initNodeData(this); // 触发节点重绘 + } + + // 定义节点只有左右两个锚点. 锚点位置通过中心点和宽度算出来。 + getDefaultAnchor() { + let _a = this, + x = _a.x, + y = _a.y, + width = _a.width, + height = _a.height; + return [ + { + x: x + width / 2 + 4, + y: y, + name: "right", + id: "".concat(this.id, "_1"), + properties: { connectionType: "source" }, + }, + { + x: x - width / 2, + y: y, + name: "left", + id: "".concat(this.id, "_3"), + properties: { connectionType: "target" }, + }, + ]; + } + + /** + * 获取节点轮廓样式 + * 覆盖父类方法,设置 stroke 属性为 none,以适应特定的视觉效果 + * @returns {object} 节点轮廓样式 + */ + getOutlineStyle() { + const style = super.getOutlineStyle(); + style.stroke = "none"; + // style.hover.stroke = "none"; + return style; + } +} + +// 导出方法注册 +export function registerRecognizeNode(lf) { + lf.register({ + type: "recognize", + view: RecognizeNodeHtmlNode, + model: RecognizeNodeHtmlModel + }); +} diff --git a/src/views/flow/nodes/function/recognize.vue b/src/views/flow/nodes/function/recognize.vue new file mode 100644 index 0000000..420399e --- /dev/null +++ b/src/views/flow/nodes/function/recognize.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/src/views/inspection/alarm/index.vue b/src/views/inspection/alarm/index.vue index b6a0d09..c306a5d 100644 --- a/src/views/inspection/alarm/index.vue +++ b/src/views/inspection/alarm/index.vue @@ -1,3 +1,452 @@ \ No newline at end of file +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + 查询 + 重置 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + diff --git a/src/views/inspection/cockpit/components/ManualTakeover/DirectionControl.vue b/src/views/inspection/cockpit/components/ManualTakeover/DirectionControl.vue new file mode 100644 index 0000000..4896cf2 --- /dev/null +++ b/src/views/inspection/cockpit/components/ManualTakeover/DirectionControl.vue @@ -0,0 +1,321 @@ + + + \ No newline at end of file diff --git a/src/views/inspection/cockpit/components/ManualTakeover/RoboticArm.vue b/src/views/inspection/cockpit/components/ManualTakeover/RoboticArm.vue new file mode 100644 index 0000000..55d29dc --- /dev/null +++ b/src/views/inspection/cockpit/components/ManualTakeover/RoboticArm.vue @@ -0,0 +1,409 @@ + + + \ No newline at end of file diff --git a/src/views/inspection/cockpit/components/ManualTakeover/UrdfView.vue b/src/views/inspection/cockpit/components/ManualTakeover/UrdfView.vue new file mode 100644 index 0000000..edf45fa --- /dev/null +++ b/src/views/inspection/cockpit/components/ManualTakeover/UrdfView.vue @@ -0,0 +1,240 @@ + + + + + \ No newline at end of file diff --git a/src/views/inspection/cockpit/components/ManualTakeover/VoiceConversation.vue b/src/views/inspection/cockpit/components/ManualTakeover/VoiceConversation.vue new file mode 100644 index 0000000..bf58335 --- /dev/null +++ b/src/views/inspection/cockpit/components/ManualTakeover/VoiceConversation.vue @@ -0,0 +1,1118 @@ + + + + + diff --git a/src/views/inspection/cockpit/components/ManualTakeover/index.vue b/src/views/inspection/cockpit/components/ManualTakeover/index.vue new file mode 100644 index 0000000..c31703a --- /dev/null +++ b/src/views/inspection/cockpit/components/ManualTakeover/index.vue @@ -0,0 +1,554 @@ + + + + \ No newline at end of file diff --git a/src/views/inspection/cockpit/components/MapCanvas.vue b/src/views/inspection/cockpit/components/MapCanvas.vue index 06b9aa1..a237691 100644 --- a/src/views/inspection/cockpit/components/MapCanvas.vue +++ b/src/views/inspection/cockpit/components/MapCanvas.vue @@ -181,7 +181,8 @@ function renderFrame(timestamp) { // 设置 Canvas 变换矩阵(考虑设备像素比) canvasCtx.setTransform(inspectionStore.devicePixelRatio, 0, 0, inspectionStore.devicePixelRatio, 0, 0); - canvasCtx.clearRect(0, 0, inspectionStore.canvasWidthPx, inspectionStore.canvasHeightPx); // 清空画布 + // canvasCtx.clearRect(0, 0, inspectionStore.canvasWidthPx, inspectionStore.canvasHeightPx); // 清空画布 + canvasCtx.clearRect(0, 0, 10000, 10000); // 清空画布 // 如果地图未加载,跳过绘制 if (!applicationState.isMapLoaded) { diff --git a/src/views/inspection/cockpit/components/MapOverview.vue b/src/views/inspection/cockpit/components/MapOverview.vue index 8f418de..97dd44e 100644 --- a/src/views/inspection/cockpit/components/MapOverview.vue +++ b/src/views/inspection/cockpit/components/MapOverview.vue @@ -130,7 +130,8 @@ const getRunningTask = async () => { taskType = '2' } const res = await getRunTaskList({ - taskType + taskType, + statusList: ['1', '3'] }) if (res.code === 200) { taskList.value = res.rows diff --git a/src/views/inspection/cockpit/components/Monitor.vue b/src/views/inspection/cockpit/components/Monitor.vue index d404e90..b158262 100644 --- a/src/views/inspection/cockpit/components/Monitor.vue +++ b/src/views/inspection/cockpit/components/Monitor.vue @@ -20,7 +20,16 @@ -
监控
+
+
+
+ +
+
+
+ +
+
OCR识别
@@ -31,6 +40,9 @@ diff --git a/src/views/intelligenceTest/mobilePhone/index.vue b/src/views/intelligenceTest/mobilePhone/index.vue new file mode 100644 index 0000000..9b7acac --- /dev/null +++ b/src/views/intelligenceTest/mobilePhone/index.vue @@ -0,0 +1,321 @@ + + + diff --git a/src/views/intelligenceTest/runningTask/index.vue b/src/views/intelligenceTest/runningTask/index.vue new file mode 100644 index 0000000..0a23ee3 --- /dev/null +++ b/src/views/intelligenceTest/runningTask/index.vue @@ -0,0 +1,647 @@ + + + \ No newline at end of file diff --git a/src/views/intelligenceTest/runningTask/task-log.vue b/src/views/intelligenceTest/runningTask/task-log.vue new file mode 100644 index 0000000..28b562b --- /dev/null +++ b/src/views/intelligenceTest/runningTask/task-log.vue @@ -0,0 +1,71 @@ + + + \ No newline at end of file diff --git a/src/views/intelligenceTest/runningTask/task-steps.vue b/src/views/intelligenceTest/runningTask/task-steps.vue new file mode 100644 index 0000000..3aa7440 --- /dev/null +++ b/src/views/intelligenceTest/runningTask/task-steps.vue @@ -0,0 +1,88 @@ + + + + \ No newline at end of file diff --git a/src/views/intelligenceTest/taskManage/index.vue b/src/views/intelligenceTest/taskManage/index.vue new file mode 100644 index 0000000..57687c2 --- /dev/null +++ b/src/views/intelligenceTest/taskManage/index.vue @@ -0,0 +1,357 @@ + + + diff --git a/src/views/intelligenceTest/testCase/index.vue b/src/views/intelligenceTest/testCase/index.vue new file mode 100644 index 0000000..ef81792 --- /dev/null +++ b/src/views/intelligenceTest/testCase/index.vue @@ -0,0 +1,330 @@ + + +