| 
					
				 | 
			
			
				@@ -1,4 +1,6 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <script setup lang="ts"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import axios from 'axios' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { v4 as uuidv4 } from 'uuid'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import Viewer from 'viewerjs' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import 'viewerjs/dist/viewer.css' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -6,7 +8,6 @@ const positiveDirectionPOptions = ref([{ label: '+', value: '+' }, { label: '-', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const positiveDirectionTOptions = ref([{ label: '+', value: '+' }, { label: '-', value: '-' }]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const system = useSystemStore() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const currentBallCamera = ref('') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const addDialogV = ref(false) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -52,18 +53,109 @@ function imgSrcLoad() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   imgSrcLoading.value = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-interface MarkItemType { id: number, x: number, y: number, color: string } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+interface MarkItemType { id: string, p: number, t: number, x: number, y: number, color: string } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type MarkType = MarkItemType[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const mark = ref<MarkType>([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const markClone = ref<MarkType>([]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const currentMark = ref<MarkItemType>({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  id: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  t: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   x: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   y: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   color: '#000', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// opencv ==============start 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+async function buildMatrix() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let srcPoints: any = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let dstPoints: any = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 遍历点集收集源点和目标点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Object.values(_imgController.p).forEach(v => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //     if (v.p !== undefined && v.t !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //         srcPoints.push([v.x, v.y]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //         dstPoints.push([v.p, v.t]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  //     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  PTXYMap.forEach(function (v: any, key) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (v.P !== undefined && v.T !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      srcPoints.push([v.X, v.Y]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      dstPoints.push([v.P, v.T]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let matrix = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (srcPoints.length >= 4) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 将点集转换为OpenCV矩阵格式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const srcMat = pointsToMat(srcPoints); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const dstMat = pointsToMat(dstPoints); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算单应性矩阵 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    matrix = findHomography(srcMat, dstMat); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log(matrix); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 清理临时矩阵(OpenCV.js内存管理) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    srcMat.delete(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dstMat.delete(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 应用矩阵到所有点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  PTXYMap.forEach(function (v: any, key) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (v.P !== undefined && v.T !== undefined) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      matrix2Point(v, matrix); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 将点数组转换为OpenCV矩阵(CV_64FC2类型) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function pointsToMat(points: any) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const data = new Float64Array(points.length * 2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  points.forEach(([x, y]:[any, any], i: number) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data[i * 2] = x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data[i * 2 + 1] = y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return window.cv.matFromArray(points.length, 1, window.cv.CV_64FC2, data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 计算单应性矩阵 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function findHomography(srcPoints:any, dstPoints:any) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const homography = new window.cv.Mat(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 使用基本参数版本:src, dst, method (0), ransacReprojThreshold (3) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    window.cv.findHomography(srcPoints, dstPoints, homography, 0, 3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return homography; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 应用矩阵变换到单个点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function matrix2Point(v:any, matrix:any) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!matrix || matrix.empty()) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 创建输入矩阵(齐次坐标) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const src = window.cv.matFromArray(3, 1, window.cv.CV_64FC1, [v.X, v.Y, 1]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const dst = new window.cv.Mat(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 执行矩阵变换 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  window.cv.gemm(matrix, src, 1, null, 0, dst); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 转换为笛卡尔坐标 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const w = dst.data64F[2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (Math.abs(w) > Number.EPSILON) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    v.p_transformed = dst.data64F[0] / w; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    v.t_transformed = dst.data64F[1] / w; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清理临时矩阵 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  src.delete(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  dst.delete(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// opencv =============end 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function markClick(item: MarkItemType) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  console.log(item); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   currentMark.value = item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   colorReset(item.id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -76,7 +168,7 @@ function calculateOriginalCoords(x: number, y: number, originalWidth: number, or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 重置颜色 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-function colorReset(id: number) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function colorReset(id: string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   mark.value.forEach((v, i) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     v.color = '#000' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     markClone.value[i].color = '#000' 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -90,19 +182,22 @@ function colorReset(id: number) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 删除标记 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-function del(id: number) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function del(id: string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   mark.value = mark.value.filter(v => v.id !== id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   markClone.value = markClone.value.filter(v => v.id !== id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  currentMark.value = mark.value[mark.value.length - 1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  mark.value.length && (currentMark.value = mark.value[mark.value.length - 1]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  mark.value.length && colorReset(currentMark.value.id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 清空标记 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function clear() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   mark.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   markClone.value = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   currentMark.value = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    id: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    id: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    p: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    t: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     x: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     y: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     color: '#000', 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -125,22 +220,25 @@ function markPointOnImageWithMargin(imgElement: HTMLImageElement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       id: v.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       x: v.x * (scaledWidth / originalWidth) + left - 12, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       y: v.y * (scaledHeight / originalHeight) + top - 12, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p: v.p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      t: v.t, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       color: v.color, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   mark.value.length && colorReset(currentMark.value.id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-let id = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 function dbClick(e: MouseEvent) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 获取鼠标点击位置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const { offsetX, offsetY } = e 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const { originalX, originalY } = calculateOriginalCoords(offsetX, offsetY, (imgElement as HTMLImageElement).naturalWidth, (imgElement as HTMLImageElement).naturalHeight, (imgElement as HTMLImageElement).offsetWidth, (imgElement as HTMLImageElement).offsetHeight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const markV = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    id: ++id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    id: uuidv4(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     x: originalX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     y: originalY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    p: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    t: 0.0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     color: '#000', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   mark.value.push(markV) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -149,9 +247,92 @@ function dbClick(e: MouseEvent) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   markPointOnImageWithMargin(imgElement as HTMLImageElement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const PTXYMap = new Map<string, { P: number, T: number, X: number, Y: number }>() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function getPTXY(id: string, x: number, y: number) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!system.globalConfig.serverUrl) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    system.msg('请先设置服务器地址') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!currentMark.value.id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    system.msg('请双击创建标记') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    system.msg('请选择球机') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  axios.get(`https://${system.globalConfig.serverUrl}/api/BallCamera/PtzGet?CameraId=${id}`).then(res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PTXYMap.set(currentMark.value.id, { P: res.data.data.P, T: res.data.data.T, X: x, Y: y }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mark.value.forEach((v, i) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (v.id === currentMark.value.id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const p = system.mapping(system.positiveConfig.P_Start, system.positiveConfig.P_Max, res.data.data.P, system.positiveConfig.P_Direction, "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const t = system.mapping(system.positiveConfig.T_Start, system.positiveConfig.T_Max, res.data.data.T, system.positiveConfig.T_Direction, "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v.p = p 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        v.t = t 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        markClone.value[i].p = p 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        markClone.value[i].t = t 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const loadOld = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!system.ballCameraInfo) return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  console.log(system.ballCameraInfo); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  PTXYMap.clear() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const ps: any = system.ballCameraInfo.Matrix.PointSet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  console.log(ps); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (const key in ps) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PTXYMap.set(key, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      P: ps[key].P, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      T: ps[key].T, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      X: ps[key].X, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Y: ps[key].Y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mark.value.push({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      id: key, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x: ps[key].X, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      y: ps[key].Y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p: ps[key].P, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      t: ps[key].T, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      color: '#000', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  markClone.value = JSON.parse(JSON.stringify(mark.value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  colorReset(mark.value[mark.value.length - 1].id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  currentMark.value = mark.value[mark.value.length - 1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  markPointOnImageWithMargin(imgElement as HTMLImageElement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const jumpToPT = (p: number, t: number) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!system.globalConfig.serverUrl) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    system.msg('请先设置服务器地址') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const pV = system.mapping(system.positiveConfig.P_Start, system.positiveConfig.P_Max, p, system.positiveConfig.P_Direction, "inv") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const tV = system.mapping(system.positiveConfig.T_Start, system.positiveConfig.T_Max, t, system.positiveConfig.T_Direction, "inv") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  axios.put(`https://${system.globalConfig.serverUrl}/api/BallCamera/PtzSet?CameraId=${currentBallCamera.value}&Action=1`, { P: pV, T: tV, Z: 0 }).then(res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log(res); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let viewer: Viewer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+watch(() => system.drawer, () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  console.log(viewer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+function initViewer() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const updloadImg = document.getElementById('uploadImage') as HTMLImageElement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const _ = new Viewer(updloadImg, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  viewer = new Viewer(updloadImg, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     inline: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     backdrop: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     navbar: false, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -184,6 +365,10 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       markPointOnImageWithMargin(imgElement as HTMLImageElement) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  initViewer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -191,30 +376,21 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   <v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <v-col class="relative" cols="12" md="6"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       <div class="flex-1"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <v-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          v-if="system.type?.Baseline === 'BoGuan'" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          v-model="system.currentDevice" :items="system.deviceList" item-title="name" item-value="id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          label="选择设备" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          @update:model-value="system.getBallCameraList" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <v-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          v-model="currentBallCamera" :items="system.ballCameraList" label="球机列表" item-title="name" item-value="id" @update:model-value="system.getBallCameraInfo" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <v-select v-if="system.type?.Baseline === 'BoGuan'" v-model="system.currentDevice" :items="system.deviceList" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          item-title="name" item-value="id" label="选择设备" @update:model-value="system.getBallCameraList" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <v-select v-model="currentBallCamera" :items="system.ballCameraList" label="球机列表" item-title="name" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          item-value="id" @update:model-value="system.getBallCameraInfo"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <template #append> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <add-ball v-model:dialog="addDialogV"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               <template #activator="{ props: activatorProps }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                <v-btn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  v-tooltip:top="'添加球机'" size="large" rounded="0" variant="flat" icon="mdi-plus-thick" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  v-bind="activatorProps" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <v-btn v-tooltip:top="'添加球机'" size="large" rounded="0" variant="flat" icon="mdi-plus-thick" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-bind="activatorProps" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </add-ball> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-dialog max-width="400"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               <template #activator="{ props: activatorProps }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                <v-btn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  v-tooltip:top="'删除球机'" size="large" rounded="0" variant="flat" icon="mdi-trash-can" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  v-bind="activatorProps" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <v-btn v-tooltip:top="'删除球机'" size="large" rounded="0" variant="flat" icon="mdi-trash-can" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  v-bind="activatorProps" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               <template #default="{ isActive }"> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -236,47 +412,62 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         <v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-number-input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v-model="system.positiveConfig.P_Start" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                hide-details="auto" label="P 起始值" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-number-input v-model="system.positiveConfig.P_Start" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hide-details="auto" label="P 起始值" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-number-input v-model="system.positiveConfig.T_Start" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hide-details="auto" label="T 起始值" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-number-input v-model="system.positiveConfig.P_Max" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hide-details="auto" label="P 最大值" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-number-input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v-model="system.positiveConfig.T_Start" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                hide-details="auto" label="T 起始值" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-number-input v-model="system.positiveConfig.T_Max" control-variant="stacked" :precision="1" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                hide-details="auto" label="T 最大值" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         </v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         <v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v-model="system.positiveConfig.p" :items="positiveDirectionPOptions" item-title="label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                item-value="value" label="P 正方向" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-select v-model="system.positiveConfig.P_Direction" :items="positiveDirectionPOptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                item-title="label" item-value="value" label="P 正方向" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-select 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                v-model="system.positiveConfig.t" :items="positiveDirectionTOptions" item-title="label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                item-value="value" label="T 正方向" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-select v-model="system.positiveConfig.T_Direction" :items="positiveDirectionTOptions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                item-title="label" item-value="value" label="T 正方向" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </v-sheet> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         </v-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         <!-- 视频播放 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         <div class="p-1"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <v-card loading title="画面预览" subtitle="当前P0.0,当前T0.0,当前标定点位的个数0" text=""> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <div class="aspect-ratio-video b-1 b-#ccc b-solid bg-black" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <v-card :loading="system.canvasVideoLoading" title="画面预览" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :subtitle="`当前P ${system.PT.p},当前T ${system.PT.t},当前标定点位的个数0`" text=""> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="relative aspect-ratio-video b-1 b-#ccc b-solid bg-black"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-icon icon="mdi-plus" color="#ef4444" class="absolute top-50% left-50% transform-translate--50%" :style="{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                textShadow: `0 -1px #fff, 1px 0px #fff, 0 1px #fff, -1px 0 #fff, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          -1px -1px #fff, 1px 1px #fff, 1px -1px #fff, -1px 1px #fff`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              }" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <canvas v-if="system.resetDom" class="canvas-video h-full w-full" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-card-actions> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-btn block variant="tonal"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-btn :disabled="system.canvasVideoLoading" block variant="tonal" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @click="system.playBallCamera(currentBallCamera)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </v-card-actions> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -286,7 +477,9 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <div class="grid grid-cols-3 grid-rows-3"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <div v-for="tool in tools" :key="tool.type"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               <div v-if="!tool.type" class="invisible" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-btn v-else width="60" height="40" variant="tonal" color="blue-darken-2"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-btn v-else width="60" height="40" variant="tonal" color="blue-darken-2" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mousedown="system.ballMove(currentBallCamera, { Speed: step, Direction: tool.value })" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mouseup="system.ballStop(currentBallCamera, { Direction: tool.value })"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 {{ tool.icon }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </div> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -294,10 +487,14 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-divider class="mx-2" vertical opacity="8" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <div class="flex-1"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <div class="flex justify-around"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-btn variant="tonal" color="blue-darken-2"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-btn variant="tonal" color="blue-darken-2" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mousedown="system.ballMove(currentBallCamera, { Speed: step, Direction: 9 })" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mouseup="system.ballStop(currentBallCamera, { Direction: 9 })"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 🔍+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-btn variant="tonal" color="blue-darken-2"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-btn variant="tonal" color="blue-darken-2" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mousedown="system.ballMove(currentBallCamera, { Speed: step, Direction: 10 })" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @mouseup="system.ballStop(currentBallCamera, { Direction: 10 })"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 🔎- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </div> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -308,8 +505,8 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               云台转动速度:{{ step }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <div class="mt-1 text-center"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <v-btn color="blue"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                使用旧节点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <v-btn color="blue" @click="loadOld"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                使用旧的点 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </div> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -323,20 +520,18 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-skeleton-loader v-if="imgSrcLoading" height="100%" type="image" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <img id="uploadImage" class="w-full" :src="imgSrc" alt="图片预览" @load="imgSrcLoad"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-empty-state v-if="!imgSrcLoading && !imgSrc" icon="mdi-image-broken-variant" title="暂无上传图片" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <v-icon 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            v-for="(item, index) in mark" :key="index" :style="{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              top: `${item.y}px`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              left: `${item.x}px`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              textShadow: `0 -1px #fff, 1px 0px #fff, 0 1px #fff, -1px 0 #fff, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <v-icon v-for="(item, index) in mark" :key="index" :style="{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            top: `${item.y}px`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            left: `${item.x}px`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            textShadow: `0 -1px #fff, 1px 0px #fff, 0 1px #fff, -1px 0 #fff, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           -1px -1px #fff, 1px 1px #fff, 1px -1px #fff, -1px 1px #fff`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }" :color="item.color" icon="mdi-plus-thick" class="absolute bottom-0" variant="tonal" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            @click="markClick(item)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }" :color="item.color" icon="mdi-plus-thick" class="absolute bottom-0" variant="tonal" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            @click="markClick(item)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         <div class="flex flex-col items-center"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-chip class="ma-2" color="blue" label> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-icon icon="mdi-map-marker-radius" start /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            选中的标记 P: {{ currentMark.x }}, T: {{ currentMark.y }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            选中的标记 P: {{ currentMark.p }}, T: {{ currentMark.t }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           </v-chip> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           <v-card min-width="90%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             <v-card-text> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -348,23 +543,23 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 <v-row justify="center"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    <v-btn width="100%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                      当前PT位置装在PT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <v-btn width="100%" @click="getPTXY(currentBallCamera, currentMark.x, currentMark.y)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      当前PT位置装载PT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     <v-btn width="100%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                      根据映射矩阵装在PT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      根据映射矩阵装载PT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    <v-btn width="100%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <v-btn width="100%" @click="buildMatrix"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                       生成映射矩阵 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   </v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   <v-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    <v-btn width="100%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <v-btn width="100%" @click="jumpToPT(currentMark.p, currentMark.t)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                       跳转到PT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     </v-btn> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   </v-col> 
			 |