diff --git a/.env.development b/.env.development
index 290b571..08bbd6f 100644
--- a/.env.development
+++ b/.env.development
@@ -7,8 +7,6 @@ VITE_APP_ENV = 'development'
# 招商车研物联网平台/开发环境
VITE_APP_BASE_API = '/dev-api'
-VITE_API_URL = http://192.168.0.10:13080
-VITE_WS_URL = ws://192.168.0.10:13080/ws
-# VITE_API_URL = http://10.148.108.95:13080 //杨溪IP
-# VITE_API_URL = http://10.148.108.58:13080 //赵培利IP
+VITE_API_URL = http://192.168.28.10:13080
+VITE_WS_URL = ws://192.168.28.10:13080/ws
diff --git a/.env.production b/.env.production
index 9c2c339..45f5456 100644
--- a/.env.production
+++ b/.env.production
@@ -13,5 +13,5 @@ VITE_BUILD_COMPRESS = gzip
#node-red 服务地址
VITE_NODE_RED_URL = 'http://10.148.108.59:13080'
-VITE_API_URL = http://192.168.0.100:13080
-VITE_WS_URL = ws://192.168.0.100:13080/ws
+VITE_API_URL = http://192.168.28.10:13080
+VITE_WS_URL = ws://192.168.28.10:13080/ws
diff --git a/src/views/inspection/cockpit/canvasUtils.js b/src/views/inspection/cockpit/canvasUtils.js
index d185745..99c4aae 100644
--- a/src/views/inspection/cockpit/canvasUtils.js
+++ b/src/views/inspection/cockpit/canvasUtils.js
@@ -23,10 +23,11 @@ function hexToCssRgba(hexString, alpha) {
* @param {number} worldY - 世界坐标 Y(米)
* @returns {{x: number, y: number}} Canvas 上的屏幕像素坐标
*/
-export const worldToScreen = (worldX, worldY) => {
- const camera = inspectionStore.camera;
- const screenX = (worldX - camera.centerX) * camera.pixelsPerMeter + inspectionStore.canvasWidthPx / 2; // 水平偏移 + 居中
- const screenY = -(worldY - camera.centerY) * camera.pixelsPerMeter + inspectionStore.canvasHeightPx / 2; // 垂直翻转 + 居中
+export const worldToScreen = (worldX, worldY, dataStore) => {
+ const store = dataStore || inspectionStore;
+ const camera = store.camera
+ const screenX = (worldX - camera.centerX) * camera.pixelsPerMeter + store.canvasWidthPx / 2; // 水平偏移 + 居中
+ const screenY = -(worldY - camera.centerY) * camera.pixelsPerMeter + store.canvasHeightPx / 2; // 垂直翻转 + 居中
return { x: screenX, y: screenY };
};
@@ -37,10 +38,11 @@ export const worldToScreen = (worldX, worldY) => {
* @param {number} screenY - Canvas 像素 Y
* @returns {{x: number, y: number}} 世界坐标(米)
*/
-export const screenToWorld = (screenX, screenY) => {
- const camera = inspectionStore.camera;
- const worldX = (screenX - inspectionStore.canvasWidthPx / 2) / camera.pixelsPerMeter + camera.centerX; // 水平反算
- const worldY = -(screenY - inspectionStore.canvasHeightPx / 2) / camera.pixelsPerMeter + camera.centerY; // 垂直反算(带翻转)
+export const screenToWorld = (screenX, screenY, dataStore) => {
+ const store = dataStore || inspectionStore;
+ const camera = store.camera;
+ const worldX = (screenX - store.canvasWidthPx / 2) / camera.pixelsPerMeter + camera.centerX; // 水平反算
+ const worldY = -(screenY - store.canvasHeightPx / 2) / camera.pixelsPerMeter + camera.centerY; // 垂直反算(带翻转)
return { x: worldX, y: worldY };
};
@@ -79,13 +81,15 @@ export const toCssRgba = (colorObj, alphaOverride) => {
* 将预渲染的离屏 Canvas 图像绘制到主 Canvas 上,并根据当前地图范围进行缩放和平移
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} gridOffscreen
*/
-export const drawGrid = (canvasCtx, map) => {
- const topLeftScreen = worldToScreen(map.originX, map.maxY); // 图像左上角(世界坐标→屏幕)
- const bottomRightScreen = worldToScreen(map.maxX, map.originY); // 图像右下角(世界坐标→屏幕)
+export const drawGrid = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
+ const topLeftScreen = worldToScreen(map.originX, map.maxY, store); // 图像左上角(世界坐标→屏幕)
+ const bottomRightScreen = worldToScreen(map.maxX, map.originY, store); // 图像右下角(世界坐标→屏幕)
canvasCtx.imageSmoothingEnabled = false; // 关闭抗锯齿(保持像素清晰)
canvasCtx.drawImage(
- inspectionStore.gridOffscreen, // 离屏 Canvas 图像源
+ store.gridOffscreen, // 离屏 Canvas 图像源
topLeftScreen.x, topLeftScreen.y, // 目标左上角
bottomRightScreen.x - topLeftScreen.x, // 目标宽度
bottomRightScreen.y - topLeftScreen.y // 目标高度
@@ -98,10 +102,11 @@ export const drawGrid = (canvasCtx, map) => {
* @param {*} canvasWidthPx
* @param {*} canvasHeightPx
*/
-export const drawGridlines = (canvasCtx) => {
+export const drawGridlines = (canvasCtx, dataStore) => {
// 计算当前可视范围的世界坐标
- const viewTopLeft = screenToWorld(0, 0); // 视口左上角世界坐标
- const viewBottomRight = screenToWorld(inspectionStore.canvasWidthPx, inspectionStore.canvasHeightPx); // 视口右下角世界坐标
+ const store = dataStore || inspectionStore;
+ const viewTopLeft = screenToWorld(0, 0, store); // 视口左上角世界坐标
+ const viewBottomRight = screenToWorld(store.canvasWidthPx, store.canvasHeightPx, store); // 视口右下角世界坐标
const viewMinX = Math.floor(Math.min(viewTopLeft.x, viewBottomRight.x)); // 可视X最小整数
const viewMaxX = Math.ceil(Math.max(viewTopLeft.x, viewBottomRight.x)); // 可视X最大整数
const viewMinY = Math.floor(Math.min(viewTopLeft.y, viewBottomRight.y)); // 可视Y最小整数
@@ -112,14 +117,14 @@ export const drawGridlines = (canvasCtx) => {
canvasCtx.lineWidth = 0.5; // 细线
canvasCtx.beginPath();
for (let worldX = viewMinX; worldX <= viewMaxX; worldX++) { // 逐列绘制垂直线
- const screenPos = worldToScreen(worldX, 0);
+ const screenPos = worldToScreen(worldX, 0, store);
canvasCtx.moveTo(screenPos.x, 0); // 从画布顶部
- canvasCtx.lineTo(screenPos.x, inspectionStore.canvasHeightPx); // 到画布底部
+ canvasCtx.lineTo(screenPos.x, store.canvasHeightPx); // 到画布底部
}
for (let worldY = viewMinY; worldY <= viewMaxY; worldY++) { // 逐行绘制水平线
- const screenPos = worldToScreen(0, worldY);
+ const screenPos = worldToScreen(0, worldY, store);
canvasCtx.moveTo(0, screenPos.y); // 从画布左边
- canvasCtx.lineTo(inspectionStore.canvasWidthPx, screenPos.y); // 到画布右边
+ canvasCtx.lineTo(store.canvasWidthPx, screenPos.y); // 到画布右边
}
canvasCtx.stroke();
}
@@ -128,8 +133,10 @@ export const drawGridlines = (canvasCtx) => {
* 绘制高级区域列表
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} dataStore
*/
-export const drawAdvancedAreaList = (canvasCtx, map) => {
+export const drawAdvancedAreaList = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
for (let areaIndex = 0; areaIndex < map.advancedAreas.length; areaIndex++) {
const area = map.advancedAreas[areaIndex]; // 当前区域
const vertices = area.posGroup || []; // 多边形顶点数组
@@ -155,10 +162,10 @@ export const drawAdvancedAreaList = (canvasCtx, map) => {
canvasCtx.strokeStyle = strokeColorCss; // 设置描边色
canvasCtx.lineWidth = 1.2; // 描边宽度
canvasCtx.beginPath();
- const firstVertexScreen = worldToScreen(vertices[0].x, vertices[0].y); // 第一个顶点的屏幕位置
+ const firstVertexScreen = worldToScreen(vertices[0].x, vertices[0].y, store); // 第一个顶点的屏幕位置
canvasCtx.moveTo(firstVertexScreen.x, firstVertexScreen.y); // 移动到起点
for (let i = 1; i < vertices.length; i++) { // 依次连接后续顶点
- const vertexScreen = worldToScreen(vertices[i].x, vertices[i].y);
+ const vertexScreen = worldToScreen(vertices[i].x, vertices[i].y, store);
canvasCtx.lineTo(vertexScreen.x, vertexScreen.y);
}
canvasCtx.closePath(); // 闭合路径
@@ -170,7 +177,7 @@ export const drawAdvancedAreaList = (canvasCtx, map) => {
for (const v of vertices) { centroidWorldX += v.x; centroidWorldY += v.y; } // 累加顶点坐标
centroidWorldX /= vertices.length; // 求平均得到质心 X
centroidWorldY /= vertices.length; // 求平均得到质心 Y
- const centroidScreen = worldToScreen(centroidWorldX, centroidWorldY);
+ const centroidScreen = worldToScreen(centroidWorldX, centroidWorldY, store);
canvasCtx.font = '500 8px "JetBrains Mono"'; // 标签字体
canvasCtx.fillStyle = strokeColorCss; // 与描边同色
canvasCtx.textAlign = 'center'; // 居中对齐
@@ -183,14 +190,15 @@ export const drawAdvancedAreaList = (canvasCtx, map) => {
* @param {*} canvasCtx
* @param {*} map
*/
-export const drawAdvancedLineList = (canvasCtx, map) => {
+export const drawAdvancedLineList = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
for (let advLineIndex = 0; advLineIndex < map.advancedLines.length; advLineIndex++) {
const advLine = map.advancedLines[advLineIndex]; // 当前高级线
const lineData = advLine.line; // 内部的 line 对象
if (!lineData || !lineData.startPos || !lineData.endPos) continue; // 缺少端点则跳过
- const startScreen = worldToScreen(lineData.startPos.x, lineData.startPos.y);
- const endScreen = worldToScreen(lineData.endPos.x, lineData.endPos.y);
+ const startScreen = worldToScreen(lineData.startPos.x, lineData.startPos.y, store);
+ const endScreen = worldToScreen(lineData.endPos.x, lineData.endPos.y, store);
// ── 根据 className 决定颜色和线型 ──
let lineColorHex = '#ff6e40'; // 默认橙色
@@ -233,12 +241,14 @@ export const drawAdvancedLineList = (canvasCtx, map) => {
* 绘制基础直线列表
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} dataStore
*/
-export const drawNormalLines = (canvasCtx, map) => {
+export const drawNormalLines = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
for (let lineIndex = 0; lineIndex < map.normalLines.length; lineIndex++) {
const line = map.normalLines[lineIndex]; // 当前直线
- const startScreen = worldToScreen(line.startPos.x, line.startPos.y); // 起点屏幕位置
- const endScreen = worldToScreen(line.endPos.x, line.endPos.y); // 终点屏幕位置
+ const startScreen = worldToScreen(line.startPos.x, line.startPos.y, store); // 起点屏幕位置
+ const endScreen = worldToScreen(line.endPos.x, line.endPos.y, store); // 终点屏幕位置
// 绘制发光直线
canvasCtx.save();
@@ -272,8 +282,10 @@ export const drawNormalLines = (canvasCtx, map) => {
* 绘制高级曲线列表
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} dataStore
*/
-export const drawAdvancedCurveList = (canvasCtx, map) => {
+export const drawAdvancedCurveList = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
for (let curveIndex = 0; curveIndex < map.advancedCurves.length; curveIndex++) {
const curve = map.advancedCurves[curveIndex]; // 当前曲线
@@ -285,10 +297,10 @@ export const drawAdvancedCurveList = (canvasCtx, map) => {
if (!startPoint || !endPoint) continue; // 缺少端点则跳过
// 转换为屏幕坐标
- const startScreen = worldToScreen(startPoint.x, startPoint.y);
- const endScreen = worldToScreen(endPoint.x, endPoint.y);
- const cp1Screen = controlPoint1 ? worldToScreen(controlPoint1.x, controlPoint1.y) : null; // 可能不存在
- const cp2Screen = controlPoint2 ? worldToScreen(controlPoint2.x, controlPoint2.y) : null;
+ const startScreen = worldToScreen(startPoint.x, startPoint.y, store);
+ const endScreen = worldToScreen(endPoint.x, endPoint.y, store);
+ const cp1Screen = controlPoint1 ? worldToScreen(controlPoint1.x, controlPoint1.y, store) : null; // 可能不存在
+ const cp2Screen = controlPoint2 ? worldToScreen(controlPoint2.x, controlPoint2.y, store) : null;
// ── 绘制贝塞尔曲线(虚线)──
canvasCtx.save();
@@ -357,16 +369,18 @@ export const drawAdvancedCurveList = (canvasCtx, map) => {
* 绘制高级点列表
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} dataStore
*/
-export const drawAdvancedPointList = (canvasCtx, map) => {
+export const drawAdvancedPointList = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
for (let pointIndex = 0; pointIndex < map.advancedPoints.length; pointIndex++) {
const advPoint = map.advancedPoints[pointIndex]; // 当前高级点
- const pointScreen = worldToScreen(advPoint.pos.x, advPoint.pos.y); // 屏幕位置
+ const pointScreen = worldToScreen(advPoint.pos.x, advPoint.pos.y, store); // 屏幕位置
// 判断是否被鼠标悬停
- const isHovered = inspectionStore.hoveredElement &&
- inspectionStore.hoveredElement.kind === 'point' &&
- inspectionStore.hoveredElement.index === pointIndex;
+ const isHovered = store.hoveredElement &&
+ store.hoveredElement.kind === 'point' &&
+ store.hoveredElement.index === pointIndex;
// ── 根据 className 决定颜色 ──
let pointColorHex = '#ffd600'; // 默认琥珀色
@@ -385,7 +399,7 @@ export const drawAdvancedPointList = (canvasCtx, map) => {
// ── 绘制菱形标记 ──
const diamondRadius = isHovered ? 8 : 5; // 悬停时放大
- const pulseAlpha = isHovered ? Math.sin(inspectionStore.animationTimeSeconds * 5) * 0.2 + 0.8 : 1; // 悬停时脉冲闪烁
+ const pulseAlpha = isHovered ? Math.sin(store.animationTimeSeconds * 5) * 0.2 + 0.8 : 1; // 悬停时脉冲闪烁
canvasCtx.save();
canvasCtx.globalAlpha = pulseAlpha; // 应用透明度
@@ -442,10 +456,12 @@ export const drawAdvancedPointList = (canvasCtx, map) => {
* 绘制地图边界
* @param {*} canvasCtx
* @param {*} map
+ * @param {*} dataStore
*/
-export const drawMapBoundary = (canvasCtx, map) => {
- const boundaryTopLeft = worldToScreen(map.originX, map.maxY); // 边界左上角屏幕位置
- const boundaryBottomRight = worldToScreen(map.maxX, map.originY); // 边界右下角屏幕位置
+export const drawMapBoundary = (canvasCtx, map, dataStore) => {
+ const store = dataStore || inspectionStore;
+ const boundaryTopLeft = worldToScreen(map.originX, map.maxY, store); // 边界左上角屏幕位置
+ const boundaryBottomRight = worldToScreen(map.maxX, map.originY, store); // 边界右下角屏幕位置
canvasCtx.strokeStyle = 'rgba(0,229,160,0.1)'; // 极淡的青绿色
canvasCtx.lineWidth = 1;
canvasCtx.setLineDash([5, 4]); // 虚线
@@ -543,7 +559,6 @@ export const buildOccupancyGridImage = (parsedMap, showEdgeGlow) => {
return offscreenCanvas;
}
-// import bot from '@/assets/icons/svg/bot.svg'
export class MobileRobot {
constructor(id, name, x, y, angleRad = 0, color= "#00D4FF", imageUrl = null) {
this.id = id;
@@ -560,23 +575,28 @@ export class MobileRobot {
}
async init(color, imageUrl) {
- console.log('imageUrl', imageUrl)
const response = await fetch(imageUrl);
let svgText = await response.text();
- console.log('svgText', svgText)
// 替换颜色
svgText = svgText.replace(/currentColor/g, color);
- svgText = svgText.replace(/fill="[^"]*"/g, `fill="${color}"`);
+ svgText = svgText.replace(/stroke="[^"]*"/g, `stroke="${color}"`);
// 创建Blob URL
const blob = new Blob([svgText], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
this.imgElement = new Image();
this.imgElement.src = url;
}
+ // 命中检测: 检查世界坐标是否在机器人区域内 (半径0.35米)
+ hitTest(worldX, worldY, pixelsPerMeter){
+ const dx = worldX - this.x;
+ const dy = worldY - this.y;
+ const distance = Math.hypot(dx, dy);
+ const hitRadius = 0.35; // 米
+ return distance < hitRadius;
+ }
// 绘制到canvas上下文 (屏幕坐标)
draw(ctx, screenX, screenY, scale = 1) {
- console.log('imgElement', this.imgElement)
const size = 18; // 绘制大小px
if (this.imgElement && this.imgElement.complete) {
ctx.save();
@@ -586,10 +606,10 @@ export class MobileRobot {
ctx.restore();
}
// 名字标签
- ctx.font = '8px "JetBrains Mono"';
+ ctx.font = '12px "JetBrains Mono"';
ctx.fillStyle = '#a0c0f0';
ctx.shadowBlur = 0;
- ctx.fillText(this.name, screenX - 10, screenY - 10);
+ ctx.fillText(this.name, screenX - 30, screenY - 20);
}
// 更新位置
diff --git a/src/views/inspection/cockpit/components/MapCanvas.vue b/src/views/inspection/cockpit/components/MapCanvas.vue
index 965ec9a..bf6ebb1 100644
--- a/src/views/inspection/cockpit/components/MapCanvas.vue
+++ b/src/views/inspection/cockpit/components/MapCanvas.vue
@@ -1,6 +1,10 @@