@fleet-frontend/mower-maps 0.1.0-beta.1 → 0.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/index.esm.js +218 -111
  2. package/dist/index.js +218 -111
  3. package/dist/processor/MapDataProcessor.d.ts +2 -1
  4. package/dist/processor/MapDataProcessor.d.ts.map +1 -1
  5. package/dist/render/AntennaManager.d.ts +3 -1
  6. package/dist/render/AntennaManager.d.ts.map +1 -1
  7. package/dist/render/BoundaryLabelsManager.d.ts +4 -1
  8. package/dist/render/BoundaryLabelsManager.d.ts.map +1 -1
  9. package/dist/render/MowerMapOverlay.d.ts +4 -1
  10. package/dist/render/MowerMapOverlay.d.ts.map +1 -1
  11. package/dist/render/MowerMapRenderer.d.ts.map +1 -1
  12. package/dist/render/SvgMapView.d.ts +2 -1
  13. package/dist/render/SvgMapView.d.ts.map +1 -1
  14. package/dist/render/layers/BaseLayer.d.ts +1 -0
  15. package/dist/render/layers/BaseLayer.d.ts.map +1 -1
  16. package/dist/render/layers/BoundaryBorderLayer.d.ts.map +1 -1
  17. package/dist/render/layers/BoundaryLayer.d.ts.map +1 -1
  18. package/dist/render/layers/ChannelLayer.d.ts +2 -1
  19. package/dist/render/layers/ChannelLayer.d.ts.map +1 -1
  20. package/dist/render/layers/DrawLayer.d.ts +2 -1
  21. package/dist/render/layers/DrawLayer.d.ts.map +1 -1
  22. package/dist/render/layers/ObstacleLayer.d.ts.map +1 -1
  23. package/dist/render/layers/PathLayer.d.ts +2 -1
  24. package/dist/render/layers/PathLayer.d.ts.map +1 -1
  25. package/dist/render/layers/VisionOffLayer.d.ts.map +1 -1
  26. package/dist/store/useCurrentMowingDataStore.d.ts.map +1 -1
  27. package/dist/store/usePartitionDataStore.d.ts.map +1 -1
  28. package/dist/types/renderer.d.ts +2 -0
  29. package/dist/types/renderer.d.ts.map +1 -1
  30. package/dist/types/store.d.ts +15 -15
  31. package/dist/types/store.d.ts.map +1 -1
  32. package/dist/utils/handleRealTime.d.ts.map +1 -1
  33. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -138,7 +138,7 @@ const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
138
138
  * 使用真正的矢量SVG渲染替代Canvas位图渲染
139
139
  */
140
140
  class SvgMapView {
141
- constructor(containerElement, width = 800, height = 600) {
141
+ constructor(sn, containerElement, width = 800, height = 600) {
142
142
  // 图层管理
143
143
  this.layers = [];
144
144
  // 简单变换参数
@@ -151,6 +151,7 @@ class SvgMapView {
151
151
  this.isDragging = false;
152
152
  this.lastMouseX = 0;
153
153
  this.lastMouseY = 0;
154
+ this.sn = sn;
154
155
  this.container = containerElement;
155
156
  // 创建SVG元素
156
157
  this.svg = this.createSVGElement();
@@ -188,7 +189,7 @@ class SvgMapView {
188
189
  this.svg.setAttribute('shape-rendering', 'geometricPrecision');
189
190
  this.svg.setAttribute('text-rendering', 'geometricPrecision');
190
191
  this.svg.setAttribute('image-rendering', 'optimizeQuality');
191
- this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
192
+ this.svg.setAttribute('id', `${this.sn}-${SVG_MAP_VIEW_ID}`);
192
193
  }
193
194
  /**
194
195
  * 创建SVG组元素
@@ -643,6 +644,7 @@ class BaseLayer {
643
644
  this.needsRedraw = true;
644
645
  this.mapView = null;
645
646
  this.type = '';
647
+ this.sn = '';
646
648
  this.level = 0; // 中等层级
647
649
  }
648
650
  // ==================== 基础属性方法 ====================
@@ -782,11 +784,17 @@ const usePartitionDataStore = create((set, get) => ({
782
784
  addSubBoundaryBorder: (key, element) => set((state) => ({
783
785
  subBoundaryBorder: {
784
786
  ...state.subBoundaryBorder,
785
- [key]: element,
787
+ [key]: { ...element },
786
788
  },
787
789
  })),
788
790
  // 清空所有数据
789
- clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
791
+ deleteSubBoundaryBorder: (key) => set((state) => {
792
+ const newSubBoundaryBorder = { ...state.subBoundaryBorder };
793
+ delete newSubBoundaryBorder[key];
794
+ return {
795
+ subBoundaryBorder: newSubBoundaryBorder,
796
+ };
797
+ }),
790
798
  // 障碍物
791
799
  obstacles: {},
792
800
  addObstacles: (key, element) => set((state) => ({
@@ -795,7 +803,13 @@ const usePartitionDataStore = create((set, get) => ({
795
803
  [key]: element,
796
804
  },
797
805
  })),
798
- clearObstacles: () => set({ obstacles: {} }),
806
+ deleteObstacles: (key) => set((state) => {
807
+ const newObstacles = { ...state.obstacles };
808
+ delete newObstacles[key];
809
+ return {
810
+ obstacles: newObstacles,
811
+ };
812
+ }),
799
813
  // svg数据
800
814
  svgElements: {},
801
815
  addSvgElements: (key, element) => set((state) => ({
@@ -804,7 +818,13 @@ const usePartitionDataStore = create((set, get) => ({
804
818
  [key]: element,
805
819
  },
806
820
  })),
807
- clearSvgElements: () => set({ svgElements: {} }),
821
+ deleteSvgElements: (key) => set((state) => {
822
+ const newSvgElements = { ...state.svgElements };
823
+ delete newSvgElements[key];
824
+ return {
825
+ svgElements: newSvgElements,
826
+ };
827
+ }),
808
828
  }));
809
829
 
810
830
  /**
@@ -3290,11 +3310,12 @@ var index = {
3290
3310
  * 专门处理路径元素的渲染
3291
3311
  */
3292
3312
  class ChannelLayer extends BaseLayer {
3293
- constructor() {
3313
+ constructor(sn) {
3294
3314
  super();
3295
3315
  this.level = 1;
3296
3316
  this.scale = 1;
3297
3317
  this.type = LAYER_DEFAULT_TYPE.CHANNEL;
3318
+ this.sn = sn;
3298
3319
  }
3299
3320
  /**
3300
3321
  * 获取元素
@@ -3327,7 +3348,8 @@ class ChannelLayer extends BaseLayer {
3327
3348
  createExclusionClipPathDefinitions(svgGroup) {
3328
3349
  // 获取所有分区边界数据
3329
3350
  const subBoundaryBorder = usePartitionDataStore.getState().subBoundaryBorder;
3330
- if (!subBoundaryBorder || Object.keys(subBoundaryBorder).length === 0) {
3351
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3352
+ if (!currentSubBoundaryBorder || Object.keys(currentSubBoundaryBorder).length === 0) {
3331
3353
  return {};
3332
3354
  }
3333
3355
  const clipPathIdsMap = {};
@@ -3340,7 +3362,7 @@ class ChannelLayer extends BaseLayer {
3340
3362
  // 计算包含所有分区和通道的边界框
3341
3363
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
3342
3364
  // 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
3343
- const svg = document.getElementById(SVG_MAP_VIEW_ID);
3365
+ const svg = document.getElementById(`${this.sn}-${SVG_MAP_VIEW_ID}`);
3344
3366
  if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
3345
3367
  const viewBox = svg.viewBox.baseVal;
3346
3368
  minX = viewBox.x;
@@ -3349,8 +3371,8 @@ class ChannelLayer extends BaseLayer {
3349
3371
  maxY = viewBox.y + viewBox.height;
3350
3372
  }
3351
3373
  else {
3352
- for (const partitionId in subBoundaryBorder) {
3353
- const boundaryData = subBoundaryBorder[partitionId];
3374
+ for (const partitionId in currentSubBoundaryBorder) {
3375
+ const boundaryData = currentSubBoundaryBorder[partitionId];
3354
3376
  if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
3355
3377
  for (const coord of boundaryData.coordinates) {
3356
3378
  minX = Math.min(minX, coord[0]);
@@ -3362,7 +3384,7 @@ class ChannelLayer extends BaseLayer {
3362
3384
  }
3363
3385
  }
3364
3386
  // 整理出clipPath路径
3365
- const clipPathId = 'channel-exclude-all';
3387
+ const clipPathId = `${this.sn}-channel-exclude-all`;
3366
3388
  // 创建 clipPath
3367
3389
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
3368
3390
  clipPath.setAttribute('id', clipPathId);
@@ -3371,7 +3393,7 @@ class ChannelLayer extends BaseLayer {
3371
3393
  // 外轮廓(顺时针)
3372
3394
  let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
3373
3395
  // 获取所有需要挖空的分区路径
3374
- const partitionPaths = this.mergeOverlappingPartitions(subBoundaryBorder);
3396
+ const partitionPaths = this.mergeOverlappingPartitions(currentSubBoundaryBorder || {});
3375
3397
  // 将所有分区路径追加到clipPath中(逆时针,形成挖空)
3376
3398
  partitionPaths.forEach((partitionCoords) => {
3377
3399
  if (partitionCoords.length >= 3) {
@@ -3497,12 +3519,12 @@ class ChannelLayer extends BaseLayer {
3497
3519
  /**
3498
3520
  * 智能合并重叠的分区,返回所有需要挖空的路径
3499
3521
  */
3500
- mergeOverlappingPartitions(subBoundaryBorder) {
3522
+ mergeOverlappingPartitions(currentSubBoundaryBorder) {
3501
3523
  try {
3502
3524
  // 将所有分区转换为polygon-clipping格式
3503
3525
  const polygons = [];
3504
3526
  const partitionIds = [];
3505
- Object.entries(subBoundaryBorder).forEach(([partitionId, boundaryData]) => {
3527
+ Object.entries(currentSubBoundaryBorder || {}).forEach(([partitionId, boundaryData]) => {
3506
3528
  if (boundaryData?.coordinates && boundaryData.coordinates.length >= 3) {
3507
3529
  // 确保坐标格式正确(去掉第三个z坐标)
3508
3530
  const coords = boundaryData.coordinates.map((coord) => [coord[0], coord[1]]);
@@ -3587,7 +3609,7 @@ class ChannelLayer extends BaseLayer {
3587
3609
  catch (error) {
3588
3610
  console.error('polygon-clipping union failed:', error);
3589
3611
  // 如果合并失败,返回原始分区
3590
- return Object.values(subBoundaryBorder)
3612
+ return Object.values(currentSubBoundaryBorder)
3591
3613
  .filter((boundaryData) => boundaryData?.coordinates && boundaryData.coordinates.length >= 3)
3592
3614
  .map((boundaryData) => boundaryData.coordinates.map((coord) => [coord[0], coord[1]]));
3593
3615
  }
@@ -3599,19 +3621,21 @@ class ChannelLayer extends BaseLayer {
3599
3621
  * 专门处理路径元素的渲染
3600
3622
  */
3601
3623
  class PathLayer extends BaseLayer {
3602
- constructor() {
3624
+ constructor(sn) {
3603
3625
  super();
3604
3626
  this.level = 3;
3605
3627
  this.scale = 1;
3606
3628
  this.lineScale = 1;
3607
3629
  this.boundaryPaths = {};
3608
3630
  this.type = LAYER_DEFAULT_TYPE.PATH;
3631
+ this.sn = sn;
3609
3632
  }
3610
3633
  /**
3611
3634
  * 为每个分区创建独立的 clipPath
3612
3635
  */
3613
3636
  createPartitionClipPaths(svgGroup) {
3614
3637
  const { subBoundaryBorder, obstacles, svgElements } = usePartitionDataStore.getState();
3638
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3615
3639
  // 确保 defs 元素存在
3616
3640
  let defs = svgGroup.querySelector('defs');
3617
3641
  if (!defs) {
@@ -3620,9 +3644,9 @@ class PathLayer extends BaseLayer {
3620
3644
  }
3621
3645
  const clipPathIds = {};
3622
3646
  // 为每个分区创建独立的 clipPath
3623
- Object.keys(subBoundaryBorder).forEach((partitionId) => {
3624
- const partitionData = subBoundaryBorder[partitionId];
3625
- const clipPathId = `clip-partition-${partitionId}`;
3647
+ Object.keys(currentSubBoundaryBorder || {}).forEach((partitionId) => {
3648
+ const partitionData = currentSubBoundaryBorder[partitionId];
3649
+ const clipPathId = `clip-partition-${this.sn}-${partitionId}`;
3626
3650
  // 如果已存在,先移除
3627
3651
  const existing = defs.querySelector(`#${clipPathId}`);
3628
3652
  if (existing)
@@ -3639,7 +3663,8 @@ class PathLayer extends BaseLayer {
3639
3663
  d += ' Z ';
3640
3664
  }
3641
3665
  // 2. 所有禁区(逆时针)- 禁区影响所有分区
3642
- Object.values(obstacles).forEach((item) => {
3666
+ const currentObstacles = obstacles[this.sn];
3667
+ Object.values(currentObstacles || {}).forEach((item) => {
3643
3668
  const obstacleCoords = item.coordinates;
3644
3669
  if (obstacleCoords.length >= 3) {
3645
3670
  d += `M ${obstacleCoords[obstacleCoords.length - 1][0]} ${obstacleCoords[obstacleCoords.length - 1][1]}`;
@@ -3650,7 +3675,8 @@ class PathLayer extends BaseLayer {
3650
3675
  }
3651
3676
  });
3652
3677
  // 3. 所有 svgElements(逆时针)- SVG元素影响所有分区
3653
- Object.values(svgElements).forEach((svgPath) => {
3678
+ const currentSvgElements = svgElements[this.sn];
3679
+ Object.values(currentSvgElements || {}).forEach((svgPath) => {
3654
3680
  const svgPathString = svgPath?.metadata?.svg;
3655
3681
  if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
3656
3682
  // 处理转义字符
@@ -3745,7 +3771,7 @@ class PathLayer extends BaseLayer {
3745
3771
  lineColor = style.lineColor || '#000000';
3746
3772
  }
3747
3773
  // 按分区+类型+样式分组存储
3748
- const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}`;
3774
+ const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}-${this.sn}`;
3749
3775
  if (!partitionTypeGroups.has(groupKey)) {
3750
3776
  partitionTypeGroups.set(groupKey, {
3751
3777
  pathData: [],
@@ -3897,9 +3923,7 @@ class BoundaryLayer extends BaseLayer {
3897
3923
  createBoundaryFill(svgGroup, coordinates, style) {
3898
3924
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3899
3925
  // 构建点集合,使用整数坐标(只取x,y坐标)
3900
- const points = coordinates
3901
- .map((coord) => `${coord[0]},${coord[1]}`)
3902
- .join(' ');
3926
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3903
3927
  const fillColor = style.fillColor;
3904
3928
  polygon.setAttribute('points', points);
3905
3929
  polygon.setAttribute('fill', fillColor);
@@ -3943,9 +3967,7 @@ class ObstacleLayer extends BaseLayer {
3943
3967
  return;
3944
3968
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3945
3969
  // 构建点集合,使用整数坐标
3946
- const points = coordinates
3947
- .map((coord) => `${coord[0]},${coord[1]}`)
3948
- .join(' ');
3970
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3949
3971
  polygon.setAttribute('points', points);
3950
3972
  polygon.setAttribute('fill', style.fillColor || 'rgba(220, 53, 69, 0.2)');
3951
3973
  polygon.setAttribute('stroke', style.lineColor || '#dc3545');
@@ -4225,9 +4247,7 @@ class VisionOffLayer extends BaseLayer {
4225
4247
  return;
4226
4248
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
4227
4249
  // 构建点集合,使用整数坐标
4228
- const points = coordinates
4229
- .map((coord) => `${coord[0]},${coord[1]}`)
4230
- .join(' ');
4250
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
4231
4251
  const fillColor = style.fillColor || 'rgba(0, 255, 0, 0.4)';
4232
4252
  polygon.setAttribute('points', points);
4233
4253
  polygon.setAttribute('fill', fillColor);
@@ -5008,7 +5028,10 @@ currentMowingPartition, }) => {
5008
5028
  // 关于location的分区,需要通过地图数据,结合射线法,判断当前的点在哪个分区里
5009
5029
  let mowingStatus = isMowing || false;
5010
5030
  let newCurrentMowingPartitionId = currentMowingPartition;
5011
- console.info('handleMultipleRealTimeData==newCurrentMowingPartitionId=================', newCurrentMowingPartitionId);
5031
+ // console.info(
5032
+ // 'handleMultipleRealTimeData==newCurrentMowingPartitionId=================',
5033
+ // newCurrentMowingPartitionId
5034
+ // );
5012
5035
  realTimeData.forEach((item) => {
5013
5036
  // 这里需要区分,是割草进度还是割草轨迹
5014
5037
  if (item.type === REAL_TIME_DATA_TYPE.LOCATION) {
@@ -7922,7 +7945,7 @@ class BoundaryBorderLayer extends BaseLayer {
7922
7945
  */
7923
7946
  setMowingBoundarys(mowingBoundarys) {
7924
7947
  if (!mowingBoundarys) {
7925
- this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
7948
+ this.mowingBoundarys = this.elements?.map((item) => item?.originalData?.id);
7926
7949
  }
7927
7950
  else {
7928
7951
  this.mowingBoundarys = mowingBoundarys;
@@ -8242,14 +8265,15 @@ class AntennaLayer extends BaseLayer {
8242
8265
  * 使用具体的图层类来处理不同类型的渲染
8243
8266
  */
8244
8267
  class DrawLayer extends BaseLayer {
8245
- constructor() {
8268
+ constructor(sn) {
8246
8269
  super();
8270
+ this.sn = sn;
8247
8271
  // 初始化各种具体图层
8248
8272
  this.antennaLayer = new AntennaLayer();
8249
8273
  // 通道图层
8250
- this.channelLayer = new ChannelLayer();
8274
+ this.channelLayer = new ChannelLayer(sn);
8251
8275
  // 路径图层
8252
- this.pathLayer = new PathLayer();
8276
+ this.pathLayer = new PathLayer(sn);
8253
8277
  // 边界图层
8254
8278
  this.boundaryLayer = new BoundaryLayer();
8255
8279
  // 边界边框图层
@@ -8672,8 +8696,9 @@ class MapDataProcessor {
8672
8696
  /**
8673
8697
  * 处理地图数据,返回绘制图层
8674
8698
  */
8675
- static processMapData(mapData, mapConfig) {
8699
+ static processMapData(sn, mapData, mapConfig) {
8676
8700
  this.mapConfig = mapConfig;
8701
+ this.sn = sn;
8677
8702
  // 收集所有地图元素
8678
8703
  const allElements = [];
8679
8704
  // 处理子地图中的元素
@@ -8753,6 +8778,9 @@ class MapDataProcessor {
8753
8778
  */
8754
8779
  static processMapElements(elements) {
8755
8780
  const result = [];
8781
+ let subBoundaryBorderObj = {};
8782
+ let obstaclesObj = {};
8783
+ let svgElementsObj = {};
8756
8784
  for (const element of elements) {
8757
8785
  try {
8758
8786
  // 检查必要的基础字段
@@ -8771,10 +8799,18 @@ class MapDataProcessor {
8771
8799
  result.push(boundaryBorderElement);
8772
8800
  // 将边界边框存储到 store 中,以分区ID为key
8773
8801
  if (element.id) {
8802
+ subBoundaryBorderObj = {
8803
+ ...subBoundaryBorderObj,
8804
+ [`${element.id.toString()}`]: {
8805
+ ...boundaryBorderElement,
8806
+ },
8807
+ };
8774
8808
  const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8775
- addSubBoundaryBorder(element.id.toString(), {
8776
- ...boundaryBorderElement,
8777
- });
8809
+ addSubBoundaryBorder(`${this.sn}`, subBoundaryBorderObj);
8810
+ // const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8811
+ // addSubBoundaryBorder(`${element.id.toString()}`, {
8812
+ // ...boundaryBorderElement,
8813
+ // });
8778
8814
  }
8779
8815
  }
8780
8816
  }
@@ -8790,10 +8826,15 @@ class MapDataProcessor {
8790
8826
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
8791
8827
  if (obstacleElement) {
8792
8828
  result.push(obstacleElement);
8793
- const { addObstacles } = usePartitionDataStore.getState();
8794
- addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8829
+ obstaclesObj[`obstacle-${obstacleElement.originalData.id}`] = {
8795
8830
  ...obstacleElement,
8796
- });
8831
+ };
8832
+ const { addObstacles } = usePartitionDataStore.getState();
8833
+ addObstacles(`${this.sn}`, obstaclesObj);
8834
+ // const { addObstacles } = usePartitionDataStore.getState();
8835
+ // addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8836
+ // ...obstacleElement,
8837
+ // });
8797
8838
  }
8798
8839
  }
8799
8840
  catch (error) {
@@ -8843,7 +8884,6 @@ class MapDataProcessor {
8843
8884
  break;
8844
8885
  }
8845
8886
  case 'TIME_LIMIT_OBSTACLE': {
8846
- console.info('TIME_LIMIT_OBSTACLE', element);
8847
8887
  try {
8848
8888
  // 如果有SVG数据,直接创建SVG绘制元素
8849
8889
  if ('svg' in element &&
@@ -8858,10 +8898,15 @@ class MapDataProcessor {
8858
8898
  const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
8859
8899
  if (svgElement) {
8860
8900
  result.push(svgElement);
8861
- const { addSvgElements } = usePartitionDataStore.getState();
8862
- addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8901
+ svgElementsObj[`time-limit-obstacle-${svgElement.originalData.id}`] = {
8863
8902
  ...svgElement,
8864
- });
8903
+ };
8904
+ const { addSvgElements } = usePartitionDataStore.getState();
8905
+ addSvgElements(`${this.sn}`, svgElementsObj);
8906
+ // const { addSvgElements } = usePartitionDataStore.getState();
8907
+ // addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8908
+ // ...svgElement,
8909
+ // });
8865
8910
  }
8866
8911
  }
8867
8912
  // 如果有points数据,按传统方式绘制
@@ -8873,10 +8918,15 @@ class MapDataProcessor {
8873
8918
  const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
8874
8919
  if (polygonElement) {
8875
8920
  result.push(polygonElement);
8876
- const { addObstacles } = usePartitionDataStore.getState();
8877
- addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8921
+ svgElementsObj[`time-limit-obstacle-${polygonElement.originalData.id}`] = {
8878
8922
  ...polygonElement,
8879
- });
8923
+ };
8924
+ const { addSvgElements } = usePartitionDataStore.getState();
8925
+ addSvgElements(`${this.sn}`, svgElementsObj);
8926
+ // const { addObstacles } = usePartitionDataStore.getState();
8927
+ // addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8928
+ // ...polygonElement,
8929
+ // });
8880
8930
  }
8881
8931
  }
8882
8932
  }
@@ -9036,7 +9086,7 @@ class PathDataProcessor {
9036
9086
  * 专门处理边界标签的创建、定位和管理
9037
9087
  */
9038
9088
  class BoundaryLabelsManager {
9039
- constructor(svgView, boundaryData, { unitType, language }) {
9089
+ constructor(svgView, boundaryData, { unitType, language, onlyRead }) {
9040
9090
  this.container = null;
9041
9091
  this.overlayDiv = null;
9042
9092
  this.globalClickHandler = null;
@@ -9049,6 +9099,7 @@ class BoundaryLabelsManager {
9049
9099
  this.initializeContainer();
9050
9100
  this.unitType = unitType;
9051
9101
  this.language = language;
9102
+ this.onlyRead = onlyRead;
9052
9103
  }
9053
9104
  /**
9054
9105
  * 初始化容器
@@ -9123,7 +9174,12 @@ class BoundaryLabelsManager {
9123
9174
  labelDiv.style.whiteSpace = 'nowrap';
9124
9175
  labelDiv.style.maxWidth = '220px';
9125
9176
  labelDiv.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
9126
- labelDiv.style.pointerEvents = 'auto';
9177
+ if (this.onlyRead) {
9178
+ labelDiv.style.pointerEvents = 'none';
9179
+ }
9180
+ else {
9181
+ labelDiv.style.pointerEvents = 'auto';
9182
+ }
9127
9183
  labelDiv.style.boxShadow = '0 2px 8px rgba(0,0,0,0.4)';
9128
9184
  labelDiv.style.cursor = 'pointer';
9129
9185
  labelDiv.style.transition = 'background-color 0.2s ease';
@@ -9209,6 +9265,9 @@ class BoundaryLabelsManager {
9209
9265
  * 展开标签
9210
9266
  */
9211
9267
  expandLabel(boundaryId) {
9268
+ if (this.onlyRead) {
9269
+ return;
9270
+ }
9212
9271
  const labelDiv = this.getLabelElement(boundaryId);
9213
9272
  if (!labelDiv)
9214
9273
  return;
@@ -9217,7 +9276,6 @@ class BoundaryLabelsManager {
9217
9276
  return;
9218
9277
  // 关闭其他展开的标签
9219
9278
  this.collapseOtherLabels(boundaryId);
9220
- // 展开当前标签
9221
9279
  extendedContent.style.display = 'block';
9222
9280
  this.currentExpandedBoundaryId = boundaryId;
9223
9281
  }
@@ -9417,6 +9475,16 @@ class BoundaryLabelsManager {
9417
9475
  const pixelY = relativeY * divHeight;
9418
9476
  return { x: pixelX, y: pixelY };
9419
9477
  }
9478
+ updateReadOnlyMode(onlyRead) {
9479
+ this.onlyRead = onlyRead;
9480
+ if (!this.container)
9481
+ return;
9482
+ const allLabels = this.container.querySelectorAll('.boundary-label');
9483
+ allLabels.forEach((label) => {
9484
+ const labelElement = label;
9485
+ labelElement.style.pointerEvents = onlyRead ? 'none' : 'auto';
9486
+ });
9487
+ }
9420
9488
  /**
9421
9489
  * 更新边界数据
9422
9490
  */
@@ -9725,7 +9793,7 @@ ChargingPileManager.Z_INDEX = {
9725
9793
  * 专门处理天线元素的创建、定位和管理
9726
9794
  */
9727
9795
  class AntennaManager {
9728
- constructor(svgView) {
9796
+ constructor(svgView, onlyRead) {
9729
9797
  this.antennaElements = [];
9730
9798
  this.container = null;
9731
9799
  this.overlayDiv = null;
@@ -9738,6 +9806,7 @@ class AntennaManager {
9738
9806
  // 旋转角度
9739
9807
  this.rotation = 0;
9740
9808
  this.svgView = svgView;
9809
+ this.onlyRead = onlyRead;
9741
9810
  this.initializeContainer();
9742
9811
  this.setupGlobalClickHandler();
9743
9812
  }
@@ -9810,7 +9879,12 @@ class AntennaManager {
9810
9879
  antennaContainer.className = 'antenna-container-item';
9811
9880
  antennaContainer.style.position = 'absolute';
9812
9881
  antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
9813
- antennaContainer.style.pointerEvents = 'auto';
9882
+ if (this.onlyRead) {
9883
+ antennaContainer.style.pointerEvents = 'none';
9884
+ }
9885
+ else {
9886
+ antennaContainer.style.pointerEvents = 'auto';
9887
+ }
9814
9888
  antennaContainer.style.zIndex = AntennaManager.Z_INDEX.DEFAULT.toString();
9815
9889
  antennaContainer.setAttribute('data-antenna-id', antennaData.type.toString());
9816
9890
  // 创建天线图标
@@ -9907,6 +9981,9 @@ class AntennaManager {
9907
9981
  const tooltip = antennaContainer.querySelector('.antenna-tooltip');
9908
9982
  if (!tooltip)
9909
9983
  return;
9984
+ if (this.onlyRead) {
9985
+ return;
9986
+ }
9910
9987
  // 展开当前tooltip
9911
9988
  tooltip.style.display = 'block';
9912
9989
  const extendedContent = tooltip.querySelector('.antenna-tooltip-extended');
@@ -9952,6 +10029,16 @@ class AntennaManager {
9952
10029
  }
9953
10030
  });
9954
10031
  }
10032
+ updateReadOnlyMode(onlyRead) {
10033
+ this.onlyRead = onlyRead;
10034
+ if (!this.container)
10035
+ return;
10036
+ const allAntennas = this.container.querySelectorAll('.antenna-container-item');
10037
+ allAntennas.forEach((antenna) => {
10038
+ const antennaElement = antenna;
10039
+ antennaElement.style.pointerEvents = onlyRead ? 'none' : 'auto';
10040
+ });
10041
+ }
9955
10042
  /**
9956
10043
  * 添加主天线
9957
10044
  */
@@ -10593,24 +10680,29 @@ function isMobileDevice() {
10593
10680
  // 记录割草状态,状态变更的时候,变量不触发重新渲染
10594
10681
  const useCurrentMowingDataStore = create((set) => ({
10595
10682
  // 当前进度数据返回的割草状态是否为在割草
10596
- processStateIsMowing: false,
10597
- updateProcessStateIsMowing: (isMowing) => set({ processStateIsMowing: isMowing }),
10598
- resetProcessStateIsMowing: () => set({ processStateIsMowing: false }),
10683
+ processStateIsMowing: {},
10684
+ updateProcessStateIsMowing: (sn, isMowing) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [sn]: isMowing } })),
10685
+ resetProcessStateIsMowing: (key) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [key]: false } })),
10599
10686
  // 当前割草的分区id
10600
- currentMowingPartitionId: '',
10601
- updateCurrentMowingPartitionId: (partitionId) => set({ currentMowingPartitionId: partitionId }),
10602
- resetCurrentMowingPartitionId: () => set({ currentMowingPartitionId: '' }),
10687
+ currentMowingPartitionId: {},
10688
+ updateCurrentMowingPartitionId: (sn, partitionId) => set((state) => ({
10689
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [sn]: partitionId },
10690
+ })),
10691
+ resetCurrentMowingPartitionId: (key) => set((state) => ({
10692
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [key]: '' },
10693
+ })),
10603
10694
  }));
10604
10695
 
10605
10696
  // Google Maps 叠加层类 - 带编辑功能
10606
10697
  class MowerMapOverlay {
10607
- constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10698
+ constructor(sn, bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', onlyRead = false, mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10608
10699
  this.div = null;
10609
10700
  this.svgMapView = null;
10610
10701
  this.offscreenContainer = null;
10611
10702
  this.overlayView = null;
10612
10703
  this.defaultTransform = { x: 0, y: 0, rotation: 0 };
10613
10704
  this.hasEdger = false;
10705
+ this.sn = '';
10614
10706
  // boundary数据
10615
10707
  this.boundaryData = [];
10616
10708
  // 边界标签管理器
@@ -10648,6 +10740,7 @@ class MowerMapOverlay {
10648
10740
  leading: true,
10649
10741
  trailing: false,
10650
10742
  });
10743
+ this.sn = sn;
10651
10744
  this.bounds = bounds;
10652
10745
  this.mapData = mapData;
10653
10746
  this.partitionBoundary = partitionBoundary;
@@ -10655,6 +10748,7 @@ class MowerMapOverlay {
10655
10748
  this.isEditMode = isEditMode;
10656
10749
  this.unitType = unitType;
10657
10750
  this.language = language;
10751
+ this.onlyRead = onlyRead;
10658
10752
  this.mapConfig = mapConfig;
10659
10753
  this.antennaConfig = antennaConfig;
10660
10754
  this.onMapLoad = onMapLoad;
@@ -10685,6 +10779,7 @@ class MowerMapOverlay {
10685
10779
  this.overlayView.hide = this.hide.bind(this);
10686
10780
  // 添加编辑模式相关方法
10687
10781
  this.overlayView.setEditMode = this.setEditMode.bind(this);
10782
+ this.overlayView.setReadOnlyMode = this.setReadOnlyMode.bind(this);
10688
10783
  this.overlayView.getEditData = this.getEditData.bind(this);
10689
10784
  this.overlayView.handleSave = this.handleSave.bind(this);
10690
10785
  this.overlayView.setCustomIcons = this.setCustomIcons.bind(this);
@@ -10821,6 +10916,7 @@ class MowerMapOverlay {
10821
10916
  this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData, {
10822
10917
  unitType: this.unitType,
10823
10918
  language: this.language,
10919
+ onlyRead: this.onlyRead,
10824
10920
  });
10825
10921
  // 设置叠加层div引用
10826
10922
  this.boundaryLabelsManager.setOverlayDiv(this.div);
@@ -10851,7 +10947,7 @@ class MowerMapOverlay {
10851
10947
  if (!this.div || !this.svgMapView)
10852
10948
  return;
10853
10949
  // 创建天线管理器
10854
- this.antennaManager = new AntennaManager(this.svgMapView);
10950
+ this.antennaManager = new AntennaManager(this.svgMapView, this.onlyRead);
10855
10951
  // 设置叠加层div引用
10856
10952
  this.antennaManager.setOverlayDiv(this.div);
10857
10953
  // 获取容器并添加到主div
@@ -10905,6 +11001,15 @@ class MowerMapOverlay {
10905
11001
  this.chargingPileManager.updatePositions();
10906
11002
  }
10907
11003
  }
11004
+ // 设置编辑模式
11005
+ setReadOnlyMode(enabled) {
11006
+ if (this.boundaryLabelsManager) {
11007
+ this.boundaryLabelsManager.updateReadOnlyMode(enabled);
11008
+ }
11009
+ if (this.antennaManager) {
11010
+ this.antennaManager.updateReadOnlyMode(enabled);
11011
+ }
11012
+ }
10908
11013
  // 创建编辑界面
10909
11014
  createEditInterface() {
10910
11015
  if (!this.div)
@@ -11459,7 +11564,7 @@ class MowerMapOverlay {
11459
11564
  return;
11460
11565
  try {
11461
11566
  // 创建SvgMapView实例
11462
- this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
11567
+ this.svgMapView = new SvgMapView(this.sn, this.offscreenContainer, 800, 600);
11463
11568
  // 加载地图数据
11464
11569
  this.loadMapData();
11465
11570
  // 加载路径数据
@@ -11488,12 +11593,12 @@ class MowerMapOverlay {
11488
11593
  return;
11489
11594
  try {
11490
11595
  // 使用现有的MapDataProcessor处理地图数据
11491
- const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
11596
+ const elements = MapDataProcessor.processMapData(this.sn, this.mapData, this.mapConfig);
11492
11597
  // 分离充电桩和天线元素,其他元素添加到SVG图层
11493
11598
  const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
11494
11599
  const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
11495
11600
  // 处理SVG图层元素
11496
- const drawLayer = new DrawLayer();
11601
+ const drawLayer = new DrawLayer(this.sn);
11497
11602
  drawLayer.addElements(svgElements);
11498
11603
  // 处理天线数据
11499
11604
  let antennaElements = [];
@@ -11562,9 +11667,9 @@ class MowerMapOverlay {
11562
11667
  return pathElement;
11563
11668
  }
11564
11669
  });
11565
- const pathLayer = new PathLayer();
11670
+ const pathLayer = new PathLayer(this.sn);
11566
11671
  pathLayer.addElements(newPathElements);
11567
- // 添加图层到SvgMapView
11672
+ // // 添加图层到SvgMapView
11568
11673
  this.svgMapView.removeLayerByType(LAYER_DEFAULT_TYPE.PATH);
11569
11674
  this.svgMapView.addLayer(pathLayer);
11570
11675
  this.svgMapView.renderLayer(LAYER_DEFAULT_TYPE.PATH);
@@ -11583,9 +11688,10 @@ class MowerMapOverlay {
11583
11688
  updatePathDataByMowingPosition(position) {
11584
11689
  // 找到当前position所在的分区id,将该点更新到pathData中
11585
11690
  // 先查找当前的分区id是多少,然后确定当前的点是否在当前分区id中,如果不在,则重新获取分区id并重新设置
11586
- const currentPartitionId = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11587
- console.info('updatePathDataByMowingPosition==currentPartitionId=================', currentPartitionId);
11588
- const processStateIsMowing = useCurrentMowingDataStore.getState().processStateIsMowing;
11691
+ const partitionIdMap = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11692
+ const processStateIsMowingMap = useCurrentMowingDataStore.getState().processStateIsMowing;
11693
+ const currentPartitionId = partitionIdMap[this.sn];
11694
+ const processStateIsMowing = processStateIsMowingMap[this.sn];
11589
11695
  if (currentPartitionId && this.pathData?.[currentPartitionId]) {
11590
11696
  const currentPathData = this.pathData[currentPartitionId];
11591
11697
  this.pathData[currentPartitionId] = {
@@ -11890,7 +11996,9 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
11890
11996
  // 默认配置
11891
11997
  const defaultMapConfig = DEFAULT_STYLES;
11892
11998
  // 地图渲染器组件
11893
- const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType.Imperial, language = 'en', mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, debug = false, }, ref) => {
11999
+ const MowerMapRenderer = React.forwardRef(({
12000
+ // 唯一的可以标识一个割草机的id
12001
+ sn, edger = false, unitType = UnitsType.Imperial, language = 'en', onlyRead = false, mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, debug = false, }, ref) => {
11894
12002
  const [elementCount, setElementCount] = React.useState(0);
11895
12003
  const [pathCount, setPathCount] = React.useState(0);
11896
12004
  const [currentError, setCurrentError] = React.useState(null);
@@ -11898,10 +12006,9 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
11898
12006
  // const mapRef = useMap();
11899
12007
  const [isGoogleMapsReady, setIsGoogleMapsReady] = React.useState(false);
11900
12008
  const [hasInitializedBounds, setHasInitializedBounds] = React.useState(false);
11901
- const { clearSubBoundaryBorder, clearObstacles, clearSvgElements } = usePartitionDataStore();
11902
- const { resetCurrentMowingPartitionId } = useCurrentMowingDataStore();
12009
+ const { deleteSubBoundaryBorder, deleteObstacles, deleteSvgElements } = usePartitionDataStore();
11903
12010
  const currentProcessMowingStatusRef = React.useRef(false);
11904
- const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, } = useCurrentMowingDataStore();
12011
+ const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, resetCurrentMowingPartitionId, } = useCurrentMowingDataStore();
11905
12012
  const [mowPartitionData, setMowPartitionData] = React.useState(null);
11906
12013
  // Debug相关状态
11907
12014
  const [debugInfo, setDebugInfo] = React.useState({});
@@ -11967,7 +12074,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
11967
12074
  setCurrentError(error);
11968
12075
  onError?.(error);
11969
12076
  };
11970
- const fitBounds = React.useCallback(() => {
12077
+ const fitBounds = React.useCallback((padding = 0) => {
11971
12078
  if (!mapJson || !mapRef)
11972
12079
  return null;
11973
12080
  // 计算边界
@@ -11986,7 +12093,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
11986
12093
  const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
11987
12094
  new window.google.maps.LatLng(neLat, neLng) // 东北角
11988
12095
  );
11989
- mapRef.fitBounds(googleBounds);
12096
+ mapRef.fitBounds(googleBounds, padding);
11990
12097
  }, [mapJson, mapRef, defaultTransform]);
11991
12098
  // 初始化Google Maps叠加层
11992
12099
  const initializeGoogleMapsOverlay = async () => {
@@ -12027,7 +12134,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12027
12134
  overlayRef.current = null;
12028
12135
  }
12029
12136
  // 创建叠加层
12030
- const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12137
+ const overlay = new MowerMapOverlay(sn, googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, onlyRead, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12031
12138
  setElementCount(count);
12032
12139
  onMapLoad?.(count);
12033
12140
  }, (count) => {
@@ -12040,7 +12147,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12040
12147
  overlay.setEdger(edger);
12041
12148
  // 只在首次初始化时自适应视图
12042
12149
  if (!hasInitializedBounds) {
12043
- mapInstance.fitBounds(googleBounds);
12150
+ // mapInstance.fitBounds(googleBounds);
12044
12151
  setHasInitializedBounds(true);
12045
12152
  }
12046
12153
  setIsGoogleMapsReady(true);
@@ -12050,7 +12157,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12050
12157
  }
12051
12158
  };
12052
12159
  const resetInCharginPie = React.useCallback(() => {
12053
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12160
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12054
12161
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12055
12162
  if (!overlayRef.current)
12056
12163
  return;
@@ -12067,24 +12174,34 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12067
12174
  initializeGoogleMapsOverlay();
12068
12175
  // 清理函数
12069
12176
  return () => {
12070
- clearSubBoundaryBorder();
12071
- clearObstacles();
12072
- clearSvgElements();
12073
- resetCurrentMowingPartitionId();
12074
- updateProcessStateIsMowing(false);
12075
- currentProcessMowingStatusRef.current = false;
12076
12177
  if (overlayRef.current) {
12077
12178
  overlayRef.current.setMap(null);
12078
12179
  overlayRef.current = null;
12079
12180
  }
12080
12181
  };
12081
- }, [mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12182
+ }, [sn, mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12183
+ React.useEffect(() => {
12184
+ return () => {
12185
+ deleteSubBoundaryBorder(sn);
12186
+ deleteObstacles(sn);
12187
+ deleteSvgElements(sn);
12188
+ resetCurrentMowingPartitionId(sn);
12189
+ updateProcessStateIsMowing(sn, false);
12190
+ currentProcessMowingStatusRef.current = false;
12191
+ };
12192
+ }, []);
12082
12193
  // 监听编辑模式变化
12083
12194
  React.useEffect(() => {
12084
12195
  if (overlayRef.current) {
12085
12196
  overlayRef.current.setEditMode(isEditMode);
12086
12197
  }
12087
12198
  }, [isEditMode]);
12199
+ // 监听只读模式变化
12200
+ React.useEffect(() => {
12201
+ if (overlayRef.current) {
12202
+ overlayRef.current.setReadOnlyMode(onlyRead);
12203
+ }
12204
+ }, [onlyRead]);
12088
12205
  // 监听路径信息的更新,需要同步更新boundaary的进度信息
12089
12206
  // useEffect(() => {
12090
12207
  // if (!mapJson) return;
@@ -12094,7 +12211,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12094
12211
  React.useEffect(() => {
12095
12212
  if (!mapJson)
12096
12213
  return;
12097
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12214
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12098
12215
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12099
12216
  if (!mowerPositionData || !overlayRef.current)
12100
12217
  return;
@@ -12305,13 +12422,13 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12305
12422
  if (realTimeData.length > 1) {
12306
12423
  const { pathData, isMowing, currentMowingPartition } = handleMultipleRealTimeData({
12307
12424
  realTimeData,
12308
- isMowing: processStateIsMowing,
12425
+ isMowing: processStateIsMowing[sn],
12309
12426
  pathData: pathJson,
12310
- currentMowingPartition: currentMowingPartitionId,
12427
+ currentMowingPartition: currentMowingPartitionId[sn],
12311
12428
  });
12312
- updateProcessStateIsMowing(isMowing);
12313
- if (currentMowingPartition !== currentMowingPartitionId) {
12314
- updateCurrentMowingPartitionId(currentMowingPartition);
12429
+ updateProcessStateIsMowing(sn, isMowing);
12430
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12431
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12315
12432
  }
12316
12433
  if (pathData) {
12317
12434
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
@@ -12321,13 +12438,13 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12321
12438
  else {
12322
12439
  const { isMowing, pathData, currentMowingPartition } = getProcessMowingDataFromRealTimeData({
12323
12440
  realTimeData,
12324
- isMowing: processStateIsMowing,
12441
+ isMowing: processStateIsMowing[sn],
12325
12442
  pathData: pathJson,
12326
- currentMowingPartition: currentMowingPartitionId,
12443
+ currentMowingPartition: currentMowingPartitionId[sn],
12327
12444
  });
12328
- updateProcessStateIsMowing(isMowing);
12329
- if (currentMowingPartition !== currentMowingPartitionId) {
12330
- updateCurrentMowingPartitionId(currentMowingPartition);
12445
+ updateProcessStateIsMowing(sn, isMowing);
12446
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12447
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12331
12448
  }
12332
12449
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
12333
12450
  // 更新进度数据
@@ -12340,16 +12457,6 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12340
12457
  if (!overlayRef.current || !defaultTransform)
12341
12458
  return;
12342
12459
  overlayRef.current?.setTransform(defaultTransform);
12343
- const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
12344
- // 地图数据中的坐标格式是 [longitude, latitude]
12345
- const swLat = validBounds.sw[1] + defaultTransform.y;
12346
- const swLng = validBounds.sw[0] + defaultTransform.x;
12347
- const neLat = validBounds.ne[1] + defaultTransform.y;
12348
- const neLng = validBounds.ne[0] + defaultTransform.x;
12349
- const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
12350
- new window.google.maps.LatLng(neLat, neLng) // 东北角
12351
- );
12352
- mapRef.fitBounds(googleBounds);
12353
12460
  }, [defaultTransform]);
12354
12461
  React.useEffect(() => {
12355
12462
  if (!overlayRef || !overlayRef.current)
@@ -12358,8 +12465,8 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12358
12465
  }, [edger]);
12359
12466
  // 提供ref方法
12360
12467
  React.useImperativeHandle(ref, () => ({
12361
- fitToView: () => {
12362
- fitBounds();
12468
+ fitToView: (padding = 0) => {
12469
+ fitBounds(padding);
12363
12470
  },
12364
12471
  getOverlay: () => {
12365
12472
  return overlayRef.current;