@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.esm.js CHANGED
@@ -136,7 +136,7 @@ const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
136
136
  * 使用真正的矢量SVG渲染替代Canvas位图渲染
137
137
  */
138
138
  class SvgMapView {
139
- constructor(containerElement, width = 800, height = 600) {
139
+ constructor(sn, containerElement, width = 800, height = 600) {
140
140
  // 图层管理
141
141
  this.layers = [];
142
142
  // 简单变换参数
@@ -149,6 +149,7 @@ class SvgMapView {
149
149
  this.isDragging = false;
150
150
  this.lastMouseX = 0;
151
151
  this.lastMouseY = 0;
152
+ this.sn = sn;
152
153
  this.container = containerElement;
153
154
  // 创建SVG元素
154
155
  this.svg = this.createSVGElement();
@@ -186,7 +187,7 @@ class SvgMapView {
186
187
  this.svg.setAttribute('shape-rendering', 'geometricPrecision');
187
188
  this.svg.setAttribute('text-rendering', 'geometricPrecision');
188
189
  this.svg.setAttribute('image-rendering', 'optimizeQuality');
189
- this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
190
+ this.svg.setAttribute('id', `${this.sn}-${SVG_MAP_VIEW_ID}`);
190
191
  }
191
192
  /**
192
193
  * 创建SVG组元素
@@ -641,6 +642,7 @@ class BaseLayer {
641
642
  this.needsRedraw = true;
642
643
  this.mapView = null;
643
644
  this.type = '';
645
+ this.sn = '';
644
646
  this.level = 0; // 中等层级
645
647
  }
646
648
  // ==================== 基础属性方法 ====================
@@ -780,11 +782,17 @@ const usePartitionDataStore = create((set, get) => ({
780
782
  addSubBoundaryBorder: (key, element) => set((state) => ({
781
783
  subBoundaryBorder: {
782
784
  ...state.subBoundaryBorder,
783
- [key]: element,
785
+ [key]: { ...element },
784
786
  },
785
787
  })),
786
788
  // 清空所有数据
787
- clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
789
+ deleteSubBoundaryBorder: (key) => set((state) => {
790
+ const newSubBoundaryBorder = { ...state.subBoundaryBorder };
791
+ delete newSubBoundaryBorder[key];
792
+ return {
793
+ subBoundaryBorder: newSubBoundaryBorder,
794
+ };
795
+ }),
788
796
  // 障碍物
789
797
  obstacles: {},
790
798
  addObstacles: (key, element) => set((state) => ({
@@ -793,7 +801,13 @@ const usePartitionDataStore = create((set, get) => ({
793
801
  [key]: element,
794
802
  },
795
803
  })),
796
- clearObstacles: () => set({ obstacles: {} }),
804
+ deleteObstacles: (key) => set((state) => {
805
+ const newObstacles = { ...state.obstacles };
806
+ delete newObstacles[key];
807
+ return {
808
+ obstacles: newObstacles,
809
+ };
810
+ }),
797
811
  // svg数据
798
812
  svgElements: {},
799
813
  addSvgElements: (key, element) => set((state) => ({
@@ -802,7 +816,13 @@ const usePartitionDataStore = create((set, get) => ({
802
816
  [key]: element,
803
817
  },
804
818
  })),
805
- clearSvgElements: () => set({ svgElements: {} }),
819
+ deleteSvgElements: (key) => set((state) => {
820
+ const newSvgElements = { ...state.svgElements };
821
+ delete newSvgElements[key];
822
+ return {
823
+ svgElements: newSvgElements,
824
+ };
825
+ }),
806
826
  }));
807
827
 
808
828
  /**
@@ -3288,11 +3308,12 @@ var index = {
3288
3308
  * 专门处理路径元素的渲染
3289
3309
  */
3290
3310
  class ChannelLayer extends BaseLayer {
3291
- constructor() {
3311
+ constructor(sn) {
3292
3312
  super();
3293
3313
  this.level = 1;
3294
3314
  this.scale = 1;
3295
3315
  this.type = LAYER_DEFAULT_TYPE.CHANNEL;
3316
+ this.sn = sn;
3296
3317
  }
3297
3318
  /**
3298
3319
  * 获取元素
@@ -3325,7 +3346,8 @@ class ChannelLayer extends BaseLayer {
3325
3346
  createExclusionClipPathDefinitions(svgGroup) {
3326
3347
  // 获取所有分区边界数据
3327
3348
  const subBoundaryBorder = usePartitionDataStore.getState().subBoundaryBorder;
3328
- if (!subBoundaryBorder || Object.keys(subBoundaryBorder).length === 0) {
3349
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3350
+ if (!currentSubBoundaryBorder || Object.keys(currentSubBoundaryBorder).length === 0) {
3329
3351
  return {};
3330
3352
  }
3331
3353
  const clipPathIdsMap = {};
@@ -3338,7 +3360,7 @@ class ChannelLayer extends BaseLayer {
3338
3360
  // 计算包含所有分区和通道的边界框
3339
3361
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
3340
3362
  // 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
3341
- const svg = document.getElementById(SVG_MAP_VIEW_ID);
3363
+ const svg = document.getElementById(`${this.sn}-${SVG_MAP_VIEW_ID}`);
3342
3364
  if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
3343
3365
  const viewBox = svg.viewBox.baseVal;
3344
3366
  minX = viewBox.x;
@@ -3347,8 +3369,8 @@ class ChannelLayer extends BaseLayer {
3347
3369
  maxY = viewBox.y + viewBox.height;
3348
3370
  }
3349
3371
  else {
3350
- for (const partitionId in subBoundaryBorder) {
3351
- const boundaryData = subBoundaryBorder[partitionId];
3372
+ for (const partitionId in currentSubBoundaryBorder) {
3373
+ const boundaryData = currentSubBoundaryBorder[partitionId];
3352
3374
  if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
3353
3375
  for (const coord of boundaryData.coordinates) {
3354
3376
  minX = Math.min(minX, coord[0]);
@@ -3360,7 +3382,7 @@ class ChannelLayer extends BaseLayer {
3360
3382
  }
3361
3383
  }
3362
3384
  // 整理出clipPath路径
3363
- const clipPathId = 'channel-exclude-all';
3385
+ const clipPathId = `${this.sn}-channel-exclude-all`;
3364
3386
  // 创建 clipPath
3365
3387
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
3366
3388
  clipPath.setAttribute('id', clipPathId);
@@ -3369,7 +3391,7 @@ class ChannelLayer extends BaseLayer {
3369
3391
  // 外轮廓(顺时针)
3370
3392
  let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
3371
3393
  // 获取所有需要挖空的分区路径
3372
- const partitionPaths = this.mergeOverlappingPartitions(subBoundaryBorder);
3394
+ const partitionPaths = this.mergeOverlappingPartitions(currentSubBoundaryBorder || {});
3373
3395
  // 将所有分区路径追加到clipPath中(逆时针,形成挖空)
3374
3396
  partitionPaths.forEach((partitionCoords) => {
3375
3397
  if (partitionCoords.length >= 3) {
@@ -3495,12 +3517,12 @@ class ChannelLayer extends BaseLayer {
3495
3517
  /**
3496
3518
  * 智能合并重叠的分区,返回所有需要挖空的路径
3497
3519
  */
3498
- mergeOverlappingPartitions(subBoundaryBorder) {
3520
+ mergeOverlappingPartitions(currentSubBoundaryBorder) {
3499
3521
  try {
3500
3522
  // 将所有分区转换为polygon-clipping格式
3501
3523
  const polygons = [];
3502
3524
  const partitionIds = [];
3503
- Object.entries(subBoundaryBorder).forEach(([partitionId, boundaryData]) => {
3525
+ Object.entries(currentSubBoundaryBorder || {}).forEach(([partitionId, boundaryData]) => {
3504
3526
  if (boundaryData?.coordinates && boundaryData.coordinates.length >= 3) {
3505
3527
  // 确保坐标格式正确(去掉第三个z坐标)
3506
3528
  const coords = boundaryData.coordinates.map((coord) => [coord[0], coord[1]]);
@@ -3585,7 +3607,7 @@ class ChannelLayer extends BaseLayer {
3585
3607
  catch (error) {
3586
3608
  console.error('polygon-clipping union failed:', error);
3587
3609
  // 如果合并失败,返回原始分区
3588
- return Object.values(subBoundaryBorder)
3610
+ return Object.values(currentSubBoundaryBorder)
3589
3611
  .filter((boundaryData) => boundaryData?.coordinates && boundaryData.coordinates.length >= 3)
3590
3612
  .map((boundaryData) => boundaryData.coordinates.map((coord) => [coord[0], coord[1]]));
3591
3613
  }
@@ -3597,19 +3619,21 @@ class ChannelLayer extends BaseLayer {
3597
3619
  * 专门处理路径元素的渲染
3598
3620
  */
3599
3621
  class PathLayer extends BaseLayer {
3600
- constructor() {
3622
+ constructor(sn) {
3601
3623
  super();
3602
3624
  this.level = 3;
3603
3625
  this.scale = 1;
3604
3626
  this.lineScale = 1;
3605
3627
  this.boundaryPaths = {};
3606
3628
  this.type = LAYER_DEFAULT_TYPE.PATH;
3629
+ this.sn = sn;
3607
3630
  }
3608
3631
  /**
3609
3632
  * 为每个分区创建独立的 clipPath
3610
3633
  */
3611
3634
  createPartitionClipPaths(svgGroup) {
3612
3635
  const { subBoundaryBorder, obstacles, svgElements } = usePartitionDataStore.getState();
3636
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3613
3637
  // 确保 defs 元素存在
3614
3638
  let defs = svgGroup.querySelector('defs');
3615
3639
  if (!defs) {
@@ -3618,9 +3642,9 @@ class PathLayer extends BaseLayer {
3618
3642
  }
3619
3643
  const clipPathIds = {};
3620
3644
  // 为每个分区创建独立的 clipPath
3621
- Object.keys(subBoundaryBorder).forEach((partitionId) => {
3622
- const partitionData = subBoundaryBorder[partitionId];
3623
- const clipPathId = `clip-partition-${partitionId}`;
3645
+ Object.keys(currentSubBoundaryBorder || {}).forEach((partitionId) => {
3646
+ const partitionData = currentSubBoundaryBorder[partitionId];
3647
+ const clipPathId = `clip-partition-${this.sn}-${partitionId}`;
3624
3648
  // 如果已存在,先移除
3625
3649
  const existing = defs.querySelector(`#${clipPathId}`);
3626
3650
  if (existing)
@@ -3637,7 +3661,8 @@ class PathLayer extends BaseLayer {
3637
3661
  d += ' Z ';
3638
3662
  }
3639
3663
  // 2. 所有禁区(逆时针)- 禁区影响所有分区
3640
- Object.values(obstacles).forEach((item) => {
3664
+ const currentObstacles = obstacles[this.sn];
3665
+ Object.values(currentObstacles || {}).forEach((item) => {
3641
3666
  const obstacleCoords = item.coordinates;
3642
3667
  if (obstacleCoords.length >= 3) {
3643
3668
  d += `M ${obstacleCoords[obstacleCoords.length - 1][0]} ${obstacleCoords[obstacleCoords.length - 1][1]}`;
@@ -3648,7 +3673,8 @@ class PathLayer extends BaseLayer {
3648
3673
  }
3649
3674
  });
3650
3675
  // 3. 所有 svgElements(逆时针)- SVG元素影响所有分区
3651
- Object.values(svgElements).forEach((svgPath) => {
3676
+ const currentSvgElements = svgElements[this.sn];
3677
+ Object.values(currentSvgElements || {}).forEach((svgPath) => {
3652
3678
  const svgPathString = svgPath?.metadata?.svg;
3653
3679
  if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
3654
3680
  // 处理转义字符
@@ -3743,7 +3769,7 @@ class PathLayer extends BaseLayer {
3743
3769
  lineColor = style.lineColor || '#000000';
3744
3770
  }
3745
3771
  // 按分区+类型+样式分组存储
3746
- const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}`;
3772
+ const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}-${this.sn}`;
3747
3773
  if (!partitionTypeGroups.has(groupKey)) {
3748
3774
  partitionTypeGroups.set(groupKey, {
3749
3775
  pathData: [],
@@ -3895,9 +3921,7 @@ class BoundaryLayer extends BaseLayer {
3895
3921
  createBoundaryFill(svgGroup, coordinates, style) {
3896
3922
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3897
3923
  // 构建点集合,使用整数坐标(只取x,y坐标)
3898
- const points = coordinates
3899
- .map((coord) => `${coord[0]},${coord[1]}`)
3900
- .join(' ');
3924
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3901
3925
  const fillColor = style.fillColor;
3902
3926
  polygon.setAttribute('points', points);
3903
3927
  polygon.setAttribute('fill', fillColor);
@@ -3941,9 +3965,7 @@ class ObstacleLayer extends BaseLayer {
3941
3965
  return;
3942
3966
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3943
3967
  // 构建点集合,使用整数坐标
3944
- const points = coordinates
3945
- .map((coord) => `${coord[0]},${coord[1]}`)
3946
- .join(' ');
3968
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3947
3969
  polygon.setAttribute('points', points);
3948
3970
  polygon.setAttribute('fill', style.fillColor || 'rgba(220, 53, 69, 0.2)');
3949
3971
  polygon.setAttribute('stroke', style.lineColor || '#dc3545');
@@ -4223,9 +4245,7 @@ class VisionOffLayer extends BaseLayer {
4223
4245
  return;
4224
4246
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
4225
4247
  // 构建点集合,使用整数坐标
4226
- const points = coordinates
4227
- .map((coord) => `${coord[0]},${coord[1]}`)
4228
- .join(' ');
4248
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
4229
4249
  const fillColor = style.fillColor || 'rgba(0, 255, 0, 0.4)';
4230
4250
  polygon.setAttribute('points', points);
4231
4251
  polygon.setAttribute('fill', fillColor);
@@ -5006,7 +5026,10 @@ currentMowingPartition, }) => {
5006
5026
  // 关于location的分区,需要通过地图数据,结合射线法,判断当前的点在哪个分区里
5007
5027
  let mowingStatus = isMowing || false;
5008
5028
  let newCurrentMowingPartitionId = currentMowingPartition;
5009
- console.info('handleMultipleRealTimeData==newCurrentMowingPartitionId=================', newCurrentMowingPartitionId);
5029
+ // console.info(
5030
+ // 'handleMultipleRealTimeData==newCurrentMowingPartitionId=================',
5031
+ // newCurrentMowingPartitionId
5032
+ // );
5010
5033
  realTimeData.forEach((item) => {
5011
5034
  // 这里需要区分,是割草进度还是割草轨迹
5012
5035
  if (item.type === REAL_TIME_DATA_TYPE.LOCATION) {
@@ -7920,7 +7943,7 @@ class BoundaryBorderLayer extends BaseLayer {
7920
7943
  */
7921
7944
  setMowingBoundarys(mowingBoundarys) {
7922
7945
  if (!mowingBoundarys) {
7923
- this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
7946
+ this.mowingBoundarys = this.elements?.map((item) => item?.originalData?.id);
7924
7947
  }
7925
7948
  else {
7926
7949
  this.mowingBoundarys = mowingBoundarys;
@@ -8240,14 +8263,15 @@ class AntennaLayer extends BaseLayer {
8240
8263
  * 使用具体的图层类来处理不同类型的渲染
8241
8264
  */
8242
8265
  class DrawLayer extends BaseLayer {
8243
- constructor() {
8266
+ constructor(sn) {
8244
8267
  super();
8268
+ this.sn = sn;
8245
8269
  // 初始化各种具体图层
8246
8270
  this.antennaLayer = new AntennaLayer();
8247
8271
  // 通道图层
8248
- this.channelLayer = new ChannelLayer();
8272
+ this.channelLayer = new ChannelLayer(sn);
8249
8273
  // 路径图层
8250
- this.pathLayer = new PathLayer();
8274
+ this.pathLayer = new PathLayer(sn);
8251
8275
  // 边界图层
8252
8276
  this.boundaryLayer = new BoundaryLayer();
8253
8277
  // 边界边框图层
@@ -8670,8 +8694,9 @@ class MapDataProcessor {
8670
8694
  /**
8671
8695
  * 处理地图数据,返回绘制图层
8672
8696
  */
8673
- static processMapData(mapData, mapConfig) {
8697
+ static processMapData(sn, mapData, mapConfig) {
8674
8698
  this.mapConfig = mapConfig;
8699
+ this.sn = sn;
8675
8700
  // 收集所有地图元素
8676
8701
  const allElements = [];
8677
8702
  // 处理子地图中的元素
@@ -8751,6 +8776,9 @@ class MapDataProcessor {
8751
8776
  */
8752
8777
  static processMapElements(elements) {
8753
8778
  const result = [];
8779
+ let subBoundaryBorderObj = {};
8780
+ let obstaclesObj = {};
8781
+ let svgElementsObj = {};
8754
8782
  for (const element of elements) {
8755
8783
  try {
8756
8784
  // 检查必要的基础字段
@@ -8769,10 +8797,18 @@ class MapDataProcessor {
8769
8797
  result.push(boundaryBorderElement);
8770
8798
  // 将边界边框存储到 store 中,以分区ID为key
8771
8799
  if (element.id) {
8800
+ subBoundaryBorderObj = {
8801
+ ...subBoundaryBorderObj,
8802
+ [`${element.id.toString()}`]: {
8803
+ ...boundaryBorderElement,
8804
+ },
8805
+ };
8772
8806
  const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8773
- addSubBoundaryBorder(element.id.toString(), {
8774
- ...boundaryBorderElement,
8775
- });
8807
+ addSubBoundaryBorder(`${this.sn}`, subBoundaryBorderObj);
8808
+ // const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8809
+ // addSubBoundaryBorder(`${element.id.toString()}`, {
8810
+ // ...boundaryBorderElement,
8811
+ // });
8776
8812
  }
8777
8813
  }
8778
8814
  }
@@ -8788,10 +8824,15 @@ class MapDataProcessor {
8788
8824
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
8789
8825
  if (obstacleElement) {
8790
8826
  result.push(obstacleElement);
8791
- const { addObstacles } = usePartitionDataStore.getState();
8792
- addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8827
+ obstaclesObj[`obstacle-${obstacleElement.originalData.id}`] = {
8793
8828
  ...obstacleElement,
8794
- });
8829
+ };
8830
+ const { addObstacles } = usePartitionDataStore.getState();
8831
+ addObstacles(`${this.sn}`, obstaclesObj);
8832
+ // const { addObstacles } = usePartitionDataStore.getState();
8833
+ // addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8834
+ // ...obstacleElement,
8835
+ // });
8795
8836
  }
8796
8837
  }
8797
8838
  catch (error) {
@@ -8841,7 +8882,6 @@ class MapDataProcessor {
8841
8882
  break;
8842
8883
  }
8843
8884
  case 'TIME_LIMIT_OBSTACLE': {
8844
- console.info('TIME_LIMIT_OBSTACLE', element);
8845
8885
  try {
8846
8886
  // 如果有SVG数据,直接创建SVG绘制元素
8847
8887
  if ('svg' in element &&
@@ -8856,10 +8896,15 @@ class MapDataProcessor {
8856
8896
  const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
8857
8897
  if (svgElement) {
8858
8898
  result.push(svgElement);
8859
- const { addSvgElements } = usePartitionDataStore.getState();
8860
- addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8899
+ svgElementsObj[`time-limit-obstacle-${svgElement.originalData.id}`] = {
8861
8900
  ...svgElement,
8862
- });
8901
+ };
8902
+ const { addSvgElements } = usePartitionDataStore.getState();
8903
+ addSvgElements(`${this.sn}`, svgElementsObj);
8904
+ // const { addSvgElements } = usePartitionDataStore.getState();
8905
+ // addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8906
+ // ...svgElement,
8907
+ // });
8863
8908
  }
8864
8909
  }
8865
8910
  // 如果有points数据,按传统方式绘制
@@ -8871,10 +8916,15 @@ class MapDataProcessor {
8871
8916
  const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
8872
8917
  if (polygonElement) {
8873
8918
  result.push(polygonElement);
8874
- const { addObstacles } = usePartitionDataStore.getState();
8875
- addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8919
+ svgElementsObj[`time-limit-obstacle-${polygonElement.originalData.id}`] = {
8876
8920
  ...polygonElement,
8877
- });
8921
+ };
8922
+ const { addSvgElements } = usePartitionDataStore.getState();
8923
+ addSvgElements(`${this.sn}`, svgElementsObj);
8924
+ // const { addObstacles } = usePartitionDataStore.getState();
8925
+ // addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8926
+ // ...polygonElement,
8927
+ // });
8878
8928
  }
8879
8929
  }
8880
8930
  }
@@ -9034,7 +9084,7 @@ class PathDataProcessor {
9034
9084
  * 专门处理边界标签的创建、定位和管理
9035
9085
  */
9036
9086
  class BoundaryLabelsManager {
9037
- constructor(svgView, boundaryData, { unitType, language }) {
9087
+ constructor(svgView, boundaryData, { unitType, language, onlyRead }) {
9038
9088
  this.container = null;
9039
9089
  this.overlayDiv = null;
9040
9090
  this.globalClickHandler = null;
@@ -9047,6 +9097,7 @@ class BoundaryLabelsManager {
9047
9097
  this.initializeContainer();
9048
9098
  this.unitType = unitType;
9049
9099
  this.language = language;
9100
+ this.onlyRead = onlyRead;
9050
9101
  }
9051
9102
  /**
9052
9103
  * 初始化容器
@@ -9121,7 +9172,12 @@ class BoundaryLabelsManager {
9121
9172
  labelDiv.style.whiteSpace = 'nowrap';
9122
9173
  labelDiv.style.maxWidth = '220px';
9123
9174
  labelDiv.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
9124
- labelDiv.style.pointerEvents = 'auto';
9175
+ if (this.onlyRead) {
9176
+ labelDiv.style.pointerEvents = 'none';
9177
+ }
9178
+ else {
9179
+ labelDiv.style.pointerEvents = 'auto';
9180
+ }
9125
9181
  labelDiv.style.boxShadow = '0 2px 8px rgba(0,0,0,0.4)';
9126
9182
  labelDiv.style.cursor = 'pointer';
9127
9183
  labelDiv.style.transition = 'background-color 0.2s ease';
@@ -9207,6 +9263,9 @@ class BoundaryLabelsManager {
9207
9263
  * 展开标签
9208
9264
  */
9209
9265
  expandLabel(boundaryId) {
9266
+ if (this.onlyRead) {
9267
+ return;
9268
+ }
9210
9269
  const labelDiv = this.getLabelElement(boundaryId);
9211
9270
  if (!labelDiv)
9212
9271
  return;
@@ -9215,7 +9274,6 @@ class BoundaryLabelsManager {
9215
9274
  return;
9216
9275
  // 关闭其他展开的标签
9217
9276
  this.collapseOtherLabels(boundaryId);
9218
- // 展开当前标签
9219
9277
  extendedContent.style.display = 'block';
9220
9278
  this.currentExpandedBoundaryId = boundaryId;
9221
9279
  }
@@ -9415,6 +9473,16 @@ class BoundaryLabelsManager {
9415
9473
  const pixelY = relativeY * divHeight;
9416
9474
  return { x: pixelX, y: pixelY };
9417
9475
  }
9476
+ updateReadOnlyMode(onlyRead) {
9477
+ this.onlyRead = onlyRead;
9478
+ if (!this.container)
9479
+ return;
9480
+ const allLabels = this.container.querySelectorAll('.boundary-label');
9481
+ allLabels.forEach((label) => {
9482
+ const labelElement = label;
9483
+ labelElement.style.pointerEvents = onlyRead ? 'none' : 'auto';
9484
+ });
9485
+ }
9418
9486
  /**
9419
9487
  * 更新边界数据
9420
9488
  */
@@ -9723,7 +9791,7 @@ ChargingPileManager.Z_INDEX = {
9723
9791
  * 专门处理天线元素的创建、定位和管理
9724
9792
  */
9725
9793
  class AntennaManager {
9726
- constructor(svgView) {
9794
+ constructor(svgView, onlyRead) {
9727
9795
  this.antennaElements = [];
9728
9796
  this.container = null;
9729
9797
  this.overlayDiv = null;
@@ -9736,6 +9804,7 @@ class AntennaManager {
9736
9804
  // 旋转角度
9737
9805
  this.rotation = 0;
9738
9806
  this.svgView = svgView;
9807
+ this.onlyRead = onlyRead;
9739
9808
  this.initializeContainer();
9740
9809
  this.setupGlobalClickHandler();
9741
9810
  }
@@ -9808,7 +9877,12 @@ class AntennaManager {
9808
9877
  antennaContainer.className = 'antenna-container-item';
9809
9878
  antennaContainer.style.position = 'absolute';
9810
9879
  antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
9811
- antennaContainer.style.pointerEvents = 'auto';
9880
+ if (this.onlyRead) {
9881
+ antennaContainer.style.pointerEvents = 'none';
9882
+ }
9883
+ else {
9884
+ antennaContainer.style.pointerEvents = 'auto';
9885
+ }
9812
9886
  antennaContainer.style.zIndex = AntennaManager.Z_INDEX.DEFAULT.toString();
9813
9887
  antennaContainer.setAttribute('data-antenna-id', antennaData.type.toString());
9814
9888
  // 创建天线图标
@@ -9905,6 +9979,9 @@ class AntennaManager {
9905
9979
  const tooltip = antennaContainer.querySelector('.antenna-tooltip');
9906
9980
  if (!tooltip)
9907
9981
  return;
9982
+ if (this.onlyRead) {
9983
+ return;
9984
+ }
9908
9985
  // 展开当前tooltip
9909
9986
  tooltip.style.display = 'block';
9910
9987
  const extendedContent = tooltip.querySelector('.antenna-tooltip-extended');
@@ -9950,6 +10027,16 @@ class AntennaManager {
9950
10027
  }
9951
10028
  });
9952
10029
  }
10030
+ updateReadOnlyMode(onlyRead) {
10031
+ this.onlyRead = onlyRead;
10032
+ if (!this.container)
10033
+ return;
10034
+ const allAntennas = this.container.querySelectorAll('.antenna-container-item');
10035
+ allAntennas.forEach((antenna) => {
10036
+ const antennaElement = antenna;
10037
+ antennaElement.style.pointerEvents = onlyRead ? 'none' : 'auto';
10038
+ });
10039
+ }
9953
10040
  /**
9954
10041
  * 添加主天线
9955
10042
  */
@@ -10591,24 +10678,29 @@ function isMobileDevice() {
10591
10678
  // 记录割草状态,状态变更的时候,变量不触发重新渲染
10592
10679
  const useCurrentMowingDataStore = create((set) => ({
10593
10680
  // 当前进度数据返回的割草状态是否为在割草
10594
- processStateIsMowing: false,
10595
- updateProcessStateIsMowing: (isMowing) => set({ processStateIsMowing: isMowing }),
10596
- resetProcessStateIsMowing: () => set({ processStateIsMowing: false }),
10681
+ processStateIsMowing: {},
10682
+ updateProcessStateIsMowing: (sn, isMowing) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [sn]: isMowing } })),
10683
+ resetProcessStateIsMowing: (key) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [key]: false } })),
10597
10684
  // 当前割草的分区id
10598
- currentMowingPartitionId: '',
10599
- updateCurrentMowingPartitionId: (partitionId) => set({ currentMowingPartitionId: partitionId }),
10600
- resetCurrentMowingPartitionId: () => set({ currentMowingPartitionId: '' }),
10685
+ currentMowingPartitionId: {},
10686
+ updateCurrentMowingPartitionId: (sn, partitionId) => set((state) => ({
10687
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [sn]: partitionId },
10688
+ })),
10689
+ resetCurrentMowingPartitionId: (key) => set((state) => ({
10690
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [key]: '' },
10691
+ })),
10601
10692
  }));
10602
10693
 
10603
10694
  // Google Maps 叠加层类 - 带编辑功能
10604
10695
  class MowerMapOverlay {
10605
- constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10696
+ 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) {
10606
10697
  this.div = null;
10607
10698
  this.svgMapView = null;
10608
10699
  this.offscreenContainer = null;
10609
10700
  this.overlayView = null;
10610
10701
  this.defaultTransform = { x: 0, y: 0, rotation: 0 };
10611
10702
  this.hasEdger = false;
10703
+ this.sn = '';
10612
10704
  // boundary数据
10613
10705
  this.boundaryData = [];
10614
10706
  // 边界标签管理器
@@ -10646,6 +10738,7 @@ class MowerMapOverlay {
10646
10738
  leading: true,
10647
10739
  trailing: false,
10648
10740
  });
10741
+ this.sn = sn;
10649
10742
  this.bounds = bounds;
10650
10743
  this.mapData = mapData;
10651
10744
  this.partitionBoundary = partitionBoundary;
@@ -10653,6 +10746,7 @@ class MowerMapOverlay {
10653
10746
  this.isEditMode = isEditMode;
10654
10747
  this.unitType = unitType;
10655
10748
  this.language = language;
10749
+ this.onlyRead = onlyRead;
10656
10750
  this.mapConfig = mapConfig;
10657
10751
  this.antennaConfig = antennaConfig;
10658
10752
  this.onMapLoad = onMapLoad;
@@ -10683,6 +10777,7 @@ class MowerMapOverlay {
10683
10777
  this.overlayView.hide = this.hide.bind(this);
10684
10778
  // 添加编辑模式相关方法
10685
10779
  this.overlayView.setEditMode = this.setEditMode.bind(this);
10780
+ this.overlayView.setReadOnlyMode = this.setReadOnlyMode.bind(this);
10686
10781
  this.overlayView.getEditData = this.getEditData.bind(this);
10687
10782
  this.overlayView.handleSave = this.handleSave.bind(this);
10688
10783
  this.overlayView.setCustomIcons = this.setCustomIcons.bind(this);
@@ -10819,6 +10914,7 @@ class MowerMapOverlay {
10819
10914
  this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData, {
10820
10915
  unitType: this.unitType,
10821
10916
  language: this.language,
10917
+ onlyRead: this.onlyRead,
10822
10918
  });
10823
10919
  // 设置叠加层div引用
10824
10920
  this.boundaryLabelsManager.setOverlayDiv(this.div);
@@ -10849,7 +10945,7 @@ class MowerMapOverlay {
10849
10945
  if (!this.div || !this.svgMapView)
10850
10946
  return;
10851
10947
  // 创建天线管理器
10852
- this.antennaManager = new AntennaManager(this.svgMapView);
10948
+ this.antennaManager = new AntennaManager(this.svgMapView, this.onlyRead);
10853
10949
  // 设置叠加层div引用
10854
10950
  this.antennaManager.setOverlayDiv(this.div);
10855
10951
  // 获取容器并添加到主div
@@ -10903,6 +10999,15 @@ class MowerMapOverlay {
10903
10999
  this.chargingPileManager.updatePositions();
10904
11000
  }
10905
11001
  }
11002
+ // 设置编辑模式
11003
+ setReadOnlyMode(enabled) {
11004
+ if (this.boundaryLabelsManager) {
11005
+ this.boundaryLabelsManager.updateReadOnlyMode(enabled);
11006
+ }
11007
+ if (this.antennaManager) {
11008
+ this.antennaManager.updateReadOnlyMode(enabled);
11009
+ }
11010
+ }
10906
11011
  // 创建编辑界面
10907
11012
  createEditInterface() {
10908
11013
  if (!this.div)
@@ -11457,7 +11562,7 @@ class MowerMapOverlay {
11457
11562
  return;
11458
11563
  try {
11459
11564
  // 创建SvgMapView实例
11460
- this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
11565
+ this.svgMapView = new SvgMapView(this.sn, this.offscreenContainer, 800, 600);
11461
11566
  // 加载地图数据
11462
11567
  this.loadMapData();
11463
11568
  // 加载路径数据
@@ -11486,12 +11591,12 @@ class MowerMapOverlay {
11486
11591
  return;
11487
11592
  try {
11488
11593
  // 使用现有的MapDataProcessor处理地图数据
11489
- const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
11594
+ const elements = MapDataProcessor.processMapData(this.sn, this.mapData, this.mapConfig);
11490
11595
  // 分离充电桩和天线元素,其他元素添加到SVG图层
11491
11596
  const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
11492
11597
  const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
11493
11598
  // 处理SVG图层元素
11494
- const drawLayer = new DrawLayer();
11599
+ const drawLayer = new DrawLayer(this.sn);
11495
11600
  drawLayer.addElements(svgElements);
11496
11601
  // 处理天线数据
11497
11602
  let antennaElements = [];
@@ -11560,9 +11665,9 @@ class MowerMapOverlay {
11560
11665
  return pathElement;
11561
11666
  }
11562
11667
  });
11563
- const pathLayer = new PathLayer();
11668
+ const pathLayer = new PathLayer(this.sn);
11564
11669
  pathLayer.addElements(newPathElements);
11565
- // 添加图层到SvgMapView
11670
+ // // 添加图层到SvgMapView
11566
11671
  this.svgMapView.removeLayerByType(LAYER_DEFAULT_TYPE.PATH);
11567
11672
  this.svgMapView.addLayer(pathLayer);
11568
11673
  this.svgMapView.renderLayer(LAYER_DEFAULT_TYPE.PATH);
@@ -11581,9 +11686,10 @@ class MowerMapOverlay {
11581
11686
  updatePathDataByMowingPosition(position) {
11582
11687
  // 找到当前position所在的分区id,将该点更新到pathData中
11583
11688
  // 先查找当前的分区id是多少,然后确定当前的点是否在当前分区id中,如果不在,则重新获取分区id并重新设置
11584
- const currentPartitionId = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11585
- console.info('updatePathDataByMowingPosition==currentPartitionId=================', currentPartitionId);
11586
- const processStateIsMowing = useCurrentMowingDataStore.getState().processStateIsMowing;
11689
+ const partitionIdMap = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11690
+ const processStateIsMowingMap = useCurrentMowingDataStore.getState().processStateIsMowing;
11691
+ const currentPartitionId = partitionIdMap[this.sn];
11692
+ const processStateIsMowing = processStateIsMowingMap[this.sn];
11587
11693
  if (currentPartitionId && this.pathData?.[currentPartitionId]) {
11588
11694
  const currentPathData = this.pathData[currentPartitionId];
11589
11695
  this.pathData[currentPartitionId] = {
@@ -11888,7 +11994,9 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
11888
11994
  // 默认配置
11889
11995
  const defaultMapConfig = DEFAULT_STYLES;
11890
11996
  // 地图渲染器组件
11891
- const MowerMapRenderer = 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) => {
11997
+ const MowerMapRenderer = forwardRef(({
11998
+ // 唯一的可以标识一个割草机的id
11999
+ 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) => {
11892
12000
  const [elementCount, setElementCount] = useState(0);
11893
12001
  const [pathCount, setPathCount] = useState(0);
11894
12002
  const [currentError, setCurrentError] = useState(null);
@@ -11896,10 +12004,9 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
11896
12004
  // const mapRef = useMap();
11897
12005
  const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
11898
12006
  const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
11899
- const { clearSubBoundaryBorder, clearObstacles, clearSvgElements } = usePartitionDataStore();
11900
- const { resetCurrentMowingPartitionId } = useCurrentMowingDataStore();
12007
+ const { deleteSubBoundaryBorder, deleteObstacles, deleteSvgElements } = usePartitionDataStore();
11901
12008
  const currentProcessMowingStatusRef = useRef(false);
11902
- const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, } = useCurrentMowingDataStore();
12009
+ const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, resetCurrentMowingPartitionId, } = useCurrentMowingDataStore();
11903
12010
  const [mowPartitionData, setMowPartitionData] = useState(null);
11904
12011
  // Debug相关状态
11905
12012
  const [debugInfo, setDebugInfo] = useState({});
@@ -11965,7 +12072,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
11965
12072
  setCurrentError(error);
11966
12073
  onError?.(error);
11967
12074
  };
11968
- const fitBounds = useCallback(() => {
12075
+ const fitBounds = useCallback((padding = 0) => {
11969
12076
  if (!mapJson || !mapRef)
11970
12077
  return null;
11971
12078
  // 计算边界
@@ -11984,7 +12091,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
11984
12091
  const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
11985
12092
  new window.google.maps.LatLng(neLat, neLng) // 东北角
11986
12093
  );
11987
- mapRef.fitBounds(googleBounds);
12094
+ mapRef.fitBounds(googleBounds, padding);
11988
12095
  }, [mapJson, mapRef, defaultTransform]);
11989
12096
  // 初始化Google Maps叠加层
11990
12097
  const initializeGoogleMapsOverlay = async () => {
@@ -12025,7 +12132,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12025
12132
  overlayRef.current = null;
12026
12133
  }
12027
12134
  // 创建叠加层
12028
- const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12135
+ const overlay = new MowerMapOverlay(sn, googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, onlyRead, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12029
12136
  setElementCount(count);
12030
12137
  onMapLoad?.(count);
12031
12138
  }, (count) => {
@@ -12038,7 +12145,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12038
12145
  overlay.setEdger(edger);
12039
12146
  // 只在首次初始化时自适应视图
12040
12147
  if (!hasInitializedBounds) {
12041
- mapInstance.fitBounds(googleBounds);
12148
+ // mapInstance.fitBounds(googleBounds);
12042
12149
  setHasInitializedBounds(true);
12043
12150
  }
12044
12151
  setIsGoogleMapsReady(true);
@@ -12048,7 +12155,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12048
12155
  }
12049
12156
  };
12050
12157
  const resetInCharginPie = useCallback(() => {
12051
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12158
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12052
12159
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12053
12160
  if (!overlayRef.current)
12054
12161
  return;
@@ -12065,24 +12172,34 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12065
12172
  initializeGoogleMapsOverlay();
12066
12173
  // 清理函数
12067
12174
  return () => {
12068
- clearSubBoundaryBorder();
12069
- clearObstacles();
12070
- clearSvgElements();
12071
- resetCurrentMowingPartitionId();
12072
- updateProcessStateIsMowing(false);
12073
- currentProcessMowingStatusRef.current = false;
12074
12175
  if (overlayRef.current) {
12075
12176
  overlayRef.current.setMap(null);
12076
12177
  overlayRef.current = null;
12077
12178
  }
12078
12179
  };
12079
- }, [mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12180
+ }, [sn, mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12181
+ useEffect(() => {
12182
+ return () => {
12183
+ deleteSubBoundaryBorder(sn);
12184
+ deleteObstacles(sn);
12185
+ deleteSvgElements(sn);
12186
+ resetCurrentMowingPartitionId(sn);
12187
+ updateProcessStateIsMowing(sn, false);
12188
+ currentProcessMowingStatusRef.current = false;
12189
+ };
12190
+ }, []);
12080
12191
  // 监听编辑模式变化
12081
12192
  useEffect(() => {
12082
12193
  if (overlayRef.current) {
12083
12194
  overlayRef.current.setEditMode(isEditMode);
12084
12195
  }
12085
12196
  }, [isEditMode]);
12197
+ // 监听只读模式变化
12198
+ useEffect(() => {
12199
+ if (overlayRef.current) {
12200
+ overlayRef.current.setReadOnlyMode(onlyRead);
12201
+ }
12202
+ }, [onlyRead]);
12086
12203
  // 监听路径信息的更新,需要同步更新boundaary的进度信息
12087
12204
  // useEffect(() => {
12088
12205
  // if (!mapJson) return;
@@ -12092,7 +12209,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12092
12209
  useEffect(() => {
12093
12210
  if (!mapJson)
12094
12211
  return;
12095
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12212
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12096
12213
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12097
12214
  if (!mowerPositionData || !overlayRef.current)
12098
12215
  return;
@@ -12303,13 +12420,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12303
12420
  if (realTimeData.length > 1) {
12304
12421
  const { pathData, isMowing, currentMowingPartition } = handleMultipleRealTimeData({
12305
12422
  realTimeData,
12306
- isMowing: processStateIsMowing,
12423
+ isMowing: processStateIsMowing[sn],
12307
12424
  pathData: pathJson,
12308
- currentMowingPartition: currentMowingPartitionId,
12425
+ currentMowingPartition: currentMowingPartitionId[sn],
12309
12426
  });
12310
- updateProcessStateIsMowing(isMowing);
12311
- if (currentMowingPartition !== currentMowingPartitionId) {
12312
- updateCurrentMowingPartitionId(currentMowingPartition);
12427
+ updateProcessStateIsMowing(sn, isMowing);
12428
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12429
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12313
12430
  }
12314
12431
  if (pathData) {
12315
12432
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
@@ -12319,13 +12436,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12319
12436
  else {
12320
12437
  const { isMowing, pathData, currentMowingPartition } = getProcessMowingDataFromRealTimeData({
12321
12438
  realTimeData,
12322
- isMowing: processStateIsMowing,
12439
+ isMowing: processStateIsMowing[sn],
12323
12440
  pathData: pathJson,
12324
- currentMowingPartition: currentMowingPartitionId,
12441
+ currentMowingPartition: currentMowingPartitionId[sn],
12325
12442
  });
12326
- updateProcessStateIsMowing(isMowing);
12327
- if (currentMowingPartition !== currentMowingPartitionId) {
12328
- updateCurrentMowingPartitionId(currentMowingPartition);
12443
+ updateProcessStateIsMowing(sn, isMowing);
12444
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12445
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12329
12446
  }
12330
12447
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
12331
12448
  // 更新进度数据
@@ -12338,16 +12455,6 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12338
12455
  if (!overlayRef.current || !defaultTransform)
12339
12456
  return;
12340
12457
  overlayRef.current?.setTransform(defaultTransform);
12341
- const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
12342
- // 地图数据中的坐标格式是 [longitude, latitude]
12343
- const swLat = validBounds.sw[1] + defaultTransform.y;
12344
- const swLng = validBounds.sw[0] + defaultTransform.x;
12345
- const neLat = validBounds.ne[1] + defaultTransform.y;
12346
- const neLng = validBounds.ne[0] + defaultTransform.x;
12347
- const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
12348
- new window.google.maps.LatLng(neLat, neLng) // 东北角
12349
- );
12350
- mapRef.fitBounds(googleBounds);
12351
12458
  }, [defaultTransform]);
12352
12459
  useEffect(() => {
12353
12460
  if (!overlayRef || !overlayRef.current)
@@ -12356,8 +12463,8 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12356
12463
  }, [edger]);
12357
12464
  // 提供ref方法
12358
12465
  useImperativeHandle(ref, () => ({
12359
- fitToView: () => {
12360
- fitBounds();
12466
+ fitToView: (padding = 0) => {
12467
+ fitBounds(padding);
12361
12468
  },
12362
12469
  getOverlay: () => {
12363
12470
  return overlayRef.current;