@fleet-frontend/mower-maps 0.1.0-beta.4 → 0.1.0-beta.5

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.
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,10 @@ 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
+ console.info('subBoundaryBorder===', subBoundaryBorder);
3351
+ console.info('currentSubBoundaryBorder===', currentSubBoundaryBorder);
3352
+ if (!currentSubBoundaryBorder || Object.keys(currentSubBoundaryBorder).length === 0) {
3329
3353
  return {};
3330
3354
  }
3331
3355
  const clipPathIdsMap = {};
@@ -3338,7 +3362,7 @@ class ChannelLayer extends BaseLayer {
3338
3362
  // 计算包含所有分区和通道的边界框
3339
3363
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
3340
3364
  // 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
3341
- const svg = document.getElementById(SVG_MAP_VIEW_ID);
3365
+ const svg = document.getElementById(`${this.sn}-${SVG_MAP_VIEW_ID}`);
3342
3366
  if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
3343
3367
  const viewBox = svg.viewBox.baseVal;
3344
3368
  minX = viewBox.x;
@@ -3347,8 +3371,8 @@ class ChannelLayer extends BaseLayer {
3347
3371
  maxY = viewBox.y + viewBox.height;
3348
3372
  }
3349
3373
  else {
3350
- for (const partitionId in subBoundaryBorder) {
3351
- const boundaryData = subBoundaryBorder[partitionId];
3374
+ for (const partitionId in currentSubBoundaryBorder) {
3375
+ const boundaryData = currentSubBoundaryBorder[partitionId];
3352
3376
  if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
3353
3377
  for (const coord of boundaryData.coordinates) {
3354
3378
  minX = Math.min(minX, coord[0]);
@@ -3360,7 +3384,7 @@ class ChannelLayer extends BaseLayer {
3360
3384
  }
3361
3385
  }
3362
3386
  // 整理出clipPath路径
3363
- const clipPathId = 'channel-exclude-all';
3387
+ const clipPathId = `${this.sn}-channel-exclude-all`;
3364
3388
  // 创建 clipPath
3365
3389
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
3366
3390
  clipPath.setAttribute('id', clipPathId);
@@ -3369,7 +3393,7 @@ class ChannelLayer extends BaseLayer {
3369
3393
  // 外轮廓(顺时针)
3370
3394
  let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
3371
3395
  // 获取所有需要挖空的分区路径
3372
- const partitionPaths = this.mergeOverlappingPartitions(subBoundaryBorder);
3396
+ const partitionPaths = this.mergeOverlappingPartitions(currentSubBoundaryBorder || {});
3373
3397
  // 将所有分区路径追加到clipPath中(逆时针,形成挖空)
3374
3398
  partitionPaths.forEach((partitionCoords) => {
3375
3399
  if (partitionCoords.length >= 3) {
@@ -3495,12 +3519,12 @@ class ChannelLayer extends BaseLayer {
3495
3519
  /**
3496
3520
  * 智能合并重叠的分区,返回所有需要挖空的路径
3497
3521
  */
3498
- mergeOverlappingPartitions(subBoundaryBorder) {
3522
+ mergeOverlappingPartitions(currentSubBoundaryBorder) {
3499
3523
  try {
3500
3524
  // 将所有分区转换为polygon-clipping格式
3501
3525
  const polygons = [];
3502
3526
  const partitionIds = [];
3503
- Object.entries(subBoundaryBorder).forEach(([partitionId, boundaryData]) => {
3527
+ Object.entries(currentSubBoundaryBorder || {}).forEach(([partitionId, boundaryData]) => {
3504
3528
  if (boundaryData?.coordinates && boundaryData.coordinates.length >= 3) {
3505
3529
  // 确保坐标格式正确(去掉第三个z坐标)
3506
3530
  const coords = boundaryData.coordinates.map((coord) => [coord[0], coord[1]]);
@@ -3585,7 +3609,7 @@ class ChannelLayer extends BaseLayer {
3585
3609
  catch (error) {
3586
3610
  console.error('polygon-clipping union failed:', error);
3587
3611
  // 如果合并失败,返回原始分区
3588
- return Object.values(subBoundaryBorder)
3612
+ return Object.values(currentSubBoundaryBorder)
3589
3613
  .filter((boundaryData) => boundaryData?.coordinates && boundaryData.coordinates.length >= 3)
3590
3614
  .map((boundaryData) => boundaryData.coordinates.map((coord) => [coord[0], coord[1]]));
3591
3615
  }
@@ -3597,19 +3621,21 @@ class ChannelLayer extends BaseLayer {
3597
3621
  * 专门处理路径元素的渲染
3598
3622
  */
3599
3623
  class PathLayer extends BaseLayer {
3600
- constructor() {
3624
+ constructor(sn) {
3601
3625
  super();
3602
3626
  this.level = 3;
3603
3627
  this.scale = 1;
3604
3628
  this.lineScale = 1;
3605
3629
  this.boundaryPaths = {};
3606
3630
  this.type = LAYER_DEFAULT_TYPE.PATH;
3631
+ this.sn = sn;
3607
3632
  }
3608
3633
  /**
3609
3634
  * 为每个分区创建独立的 clipPath
3610
3635
  */
3611
3636
  createPartitionClipPaths(svgGroup) {
3612
3637
  const { subBoundaryBorder, obstacles, svgElements } = usePartitionDataStore.getState();
3638
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3613
3639
  // 确保 defs 元素存在
3614
3640
  let defs = svgGroup.querySelector('defs');
3615
3641
  if (!defs) {
@@ -3618,9 +3644,9 @@ class PathLayer extends BaseLayer {
3618
3644
  }
3619
3645
  const clipPathIds = {};
3620
3646
  // 为每个分区创建独立的 clipPath
3621
- Object.keys(subBoundaryBorder).forEach((partitionId) => {
3622
- const partitionData = subBoundaryBorder[partitionId];
3623
- const clipPathId = `clip-partition-${partitionId}`;
3647
+ Object.keys(currentSubBoundaryBorder || {}).forEach((partitionId) => {
3648
+ const partitionData = currentSubBoundaryBorder[partitionId];
3649
+ const clipPathId = `clip-partition-${this.sn}-${partitionId}`;
3624
3650
  // 如果已存在,先移除
3625
3651
  const existing = defs.querySelector(`#${clipPathId}`);
3626
3652
  if (existing)
@@ -3637,7 +3663,8 @@ class PathLayer extends BaseLayer {
3637
3663
  d += ' Z ';
3638
3664
  }
3639
3665
  // 2. 所有禁区(逆时针)- 禁区影响所有分区
3640
- Object.values(obstacles).forEach((item) => {
3666
+ const currentObstacles = obstacles[this.sn];
3667
+ Object.values(currentObstacles || {}).forEach((item) => {
3641
3668
  const obstacleCoords = item.coordinates;
3642
3669
  if (obstacleCoords.length >= 3) {
3643
3670
  d += `M ${obstacleCoords[obstacleCoords.length - 1][0]} ${obstacleCoords[obstacleCoords.length - 1][1]}`;
@@ -3648,7 +3675,8 @@ class PathLayer extends BaseLayer {
3648
3675
  }
3649
3676
  });
3650
3677
  // 3. 所有 svgElements(逆时针)- SVG元素影响所有分区
3651
- Object.values(svgElements).forEach((svgPath) => {
3678
+ const currentSvgElements = svgElements[this.sn];
3679
+ Object.values(currentSvgElements || {}).forEach((svgPath) => {
3652
3680
  const svgPathString = svgPath?.metadata?.svg;
3653
3681
  if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
3654
3682
  // 处理转义字符
@@ -3743,7 +3771,7 @@ class PathLayer extends BaseLayer {
3743
3771
  lineColor = style.lineColor || '#000000';
3744
3772
  }
3745
3773
  // 按分区+类型+样式分组存储
3746
- const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}`;
3774
+ const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}-${this.sn}`;
3747
3775
  if (!partitionTypeGroups.has(groupKey)) {
3748
3776
  partitionTypeGroups.set(groupKey, {
3749
3777
  pathData: [],
@@ -3895,9 +3923,7 @@ class BoundaryLayer extends BaseLayer {
3895
3923
  createBoundaryFill(svgGroup, coordinates, style) {
3896
3924
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3897
3925
  // 构建点集合,使用整数坐标(只取x,y坐标)
3898
- const points = coordinates
3899
- .map((coord) => `${coord[0]},${coord[1]}`)
3900
- .join(' ');
3926
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3901
3927
  const fillColor = style.fillColor;
3902
3928
  polygon.setAttribute('points', points);
3903
3929
  polygon.setAttribute('fill', fillColor);
@@ -3941,9 +3967,7 @@ class ObstacleLayer extends BaseLayer {
3941
3967
  return;
3942
3968
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3943
3969
  // 构建点集合,使用整数坐标
3944
- const points = coordinates
3945
- .map((coord) => `${coord[0]},${coord[1]}`)
3946
- .join(' ');
3970
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3947
3971
  polygon.setAttribute('points', points);
3948
3972
  polygon.setAttribute('fill', style.fillColor || 'rgba(220, 53, 69, 0.2)');
3949
3973
  polygon.setAttribute('stroke', style.lineColor || '#dc3545');
@@ -4223,9 +4247,7 @@ class VisionOffLayer extends BaseLayer {
4223
4247
  return;
4224
4248
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
4225
4249
  // 构建点集合,使用整数坐标
4226
- const points = coordinates
4227
- .map((coord) => `${coord[0]},${coord[1]}`)
4228
- .join(' ');
4250
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
4229
4251
  const fillColor = style.fillColor || 'rgba(0, 255, 0, 0.4)';
4230
4252
  polygon.setAttribute('points', points);
4231
4253
  polygon.setAttribute('fill', fillColor);
@@ -7923,7 +7945,7 @@ class BoundaryBorderLayer extends BaseLayer {
7923
7945
  */
7924
7946
  setMowingBoundarys(mowingBoundarys) {
7925
7947
  if (!mowingBoundarys) {
7926
- this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
7948
+ this.mowingBoundarys = this.elements?.map((item) => item?.originalData?.id);
7927
7949
  }
7928
7950
  else {
7929
7951
  this.mowingBoundarys = mowingBoundarys;
@@ -8243,14 +8265,15 @@ class AntennaLayer extends BaseLayer {
8243
8265
  * 使用具体的图层类来处理不同类型的渲染
8244
8266
  */
8245
8267
  class DrawLayer extends BaseLayer {
8246
- constructor() {
8268
+ constructor(sn) {
8247
8269
  super();
8270
+ this.sn = sn;
8248
8271
  // 初始化各种具体图层
8249
8272
  this.antennaLayer = new AntennaLayer();
8250
8273
  // 通道图层
8251
- this.channelLayer = new ChannelLayer();
8274
+ this.channelLayer = new ChannelLayer(sn);
8252
8275
  // 路径图层
8253
- this.pathLayer = new PathLayer();
8276
+ this.pathLayer = new PathLayer(sn);
8254
8277
  // 边界图层
8255
8278
  this.boundaryLayer = new BoundaryLayer();
8256
8279
  // 边界边框图层
@@ -8673,8 +8696,9 @@ class MapDataProcessor {
8673
8696
  /**
8674
8697
  * 处理地图数据,返回绘制图层
8675
8698
  */
8676
- static processMapData(mapData, mapConfig) {
8699
+ static processMapData(sn, mapData, mapConfig) {
8677
8700
  this.mapConfig = mapConfig;
8701
+ this.sn = sn;
8678
8702
  // 收集所有地图元素
8679
8703
  const allElements = [];
8680
8704
  // 处理子地图中的元素
@@ -8754,6 +8778,9 @@ class MapDataProcessor {
8754
8778
  */
8755
8779
  static processMapElements(elements) {
8756
8780
  const result = [];
8781
+ let subBoundaryBorderObj = {};
8782
+ let obstaclesObj = {};
8783
+ let svgElementsObj = {};
8757
8784
  for (const element of elements) {
8758
8785
  try {
8759
8786
  // 检查必要的基础字段
@@ -8772,10 +8799,18 @@ class MapDataProcessor {
8772
8799
  result.push(boundaryBorderElement);
8773
8800
  // 将边界边框存储到 store 中,以分区ID为key
8774
8801
  if (element.id) {
8802
+ subBoundaryBorderObj = {
8803
+ ...subBoundaryBorderObj,
8804
+ [`${element.id.toString()}`]: {
8805
+ ...boundaryBorderElement,
8806
+ },
8807
+ };
8775
8808
  const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8776
- addSubBoundaryBorder(element.id.toString(), {
8777
- ...boundaryBorderElement,
8778
- });
8809
+ addSubBoundaryBorder(`${this.sn}`, subBoundaryBorderObj);
8810
+ // const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8811
+ // addSubBoundaryBorder(`${element.id.toString()}`, {
8812
+ // ...boundaryBorderElement,
8813
+ // });
8779
8814
  }
8780
8815
  }
8781
8816
  }
@@ -8791,10 +8826,15 @@ class MapDataProcessor {
8791
8826
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
8792
8827
  if (obstacleElement) {
8793
8828
  result.push(obstacleElement);
8794
- const { addObstacles } = usePartitionDataStore.getState();
8795
- addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8829
+ obstaclesObj[`obstacle-${obstacleElement.originalData.id}`] = {
8796
8830
  ...obstacleElement,
8797
- });
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
+ // });
8798
8838
  }
8799
8839
  }
8800
8840
  catch (error) {
@@ -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
  }
@@ -10593,24 +10643,29 @@ function isMobileDevice() {
10593
10643
  // 记录割草状态,状态变更的时候,变量不触发重新渲染
10594
10644
  const useCurrentMowingDataStore = create((set) => ({
10595
10645
  // 当前进度数据返回的割草状态是否为在割草
10596
- processStateIsMowing: false,
10597
- updateProcessStateIsMowing: (isMowing) => set({ processStateIsMowing: isMowing }),
10598
- resetProcessStateIsMowing: () => set({ processStateIsMowing: false }),
10646
+ processStateIsMowing: {},
10647
+ updateProcessStateIsMowing: (sn, isMowing) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [sn]: isMowing } })),
10648
+ resetProcessStateIsMowing: (key) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [key]: false } })),
10599
10649
  // 当前割草的分区id
10600
- currentMowingPartitionId: '',
10601
- updateCurrentMowingPartitionId: (partitionId) => set({ currentMowingPartitionId: partitionId }),
10602
- resetCurrentMowingPartitionId: () => set({ currentMowingPartitionId: '' }),
10650
+ currentMowingPartitionId: {},
10651
+ updateCurrentMowingPartitionId: (sn, partitionId) => set((state) => ({
10652
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [sn]: partitionId },
10653
+ })),
10654
+ resetCurrentMowingPartitionId: (key) => set((state) => ({
10655
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [key]: '' },
10656
+ })),
10603
10657
  }));
10604
10658
 
10605
10659
  // Google Maps 叠加层类 - 带编辑功能
10606
10660
  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) {
10661
+ constructor(sn, bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10608
10662
  this.div = null;
10609
10663
  this.svgMapView = null;
10610
10664
  this.offscreenContainer = null;
10611
10665
  this.overlayView = null;
10612
10666
  this.defaultTransform = { x: 0, y: 0, rotation: 0 };
10613
10667
  this.hasEdger = false;
10668
+ this.sn = '';
10614
10669
  // boundary数据
10615
10670
  this.boundaryData = [];
10616
10671
  // 边界标签管理器
@@ -10648,6 +10703,7 @@ class MowerMapOverlay {
10648
10703
  leading: true,
10649
10704
  trailing: false,
10650
10705
  });
10706
+ this.sn = sn;
10651
10707
  this.bounds = bounds;
10652
10708
  this.mapData = mapData;
10653
10709
  this.partitionBoundary = partitionBoundary;
@@ -11459,7 +11515,7 @@ class MowerMapOverlay {
11459
11515
  return;
11460
11516
  try {
11461
11517
  // 创建SvgMapView实例
11462
- this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
11518
+ this.svgMapView = new SvgMapView(this.sn, this.offscreenContainer, 800, 600);
11463
11519
  // 加载地图数据
11464
11520
  this.loadMapData();
11465
11521
  // 加载路径数据
@@ -11488,12 +11544,12 @@ class MowerMapOverlay {
11488
11544
  return;
11489
11545
  try {
11490
11546
  // 使用现有的MapDataProcessor处理地图数据
11491
- const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
11547
+ const elements = MapDataProcessor.processMapData(this.sn, this.mapData, this.mapConfig);
11492
11548
  // 分离充电桩和天线元素,其他元素添加到SVG图层
11493
11549
  const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
11494
11550
  const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
11495
11551
  // 处理SVG图层元素
11496
- const drawLayer = new DrawLayer();
11552
+ const drawLayer = new DrawLayer(this.sn);
11497
11553
  drawLayer.addElements(svgElements);
11498
11554
  // 处理天线数据
11499
11555
  let antennaElements = [];
@@ -11562,9 +11618,9 @@ class MowerMapOverlay {
11562
11618
  return pathElement;
11563
11619
  }
11564
11620
  });
11565
- const pathLayer = new PathLayer();
11621
+ const pathLayer = new PathLayer(this.sn);
11566
11622
  pathLayer.addElements(newPathElements);
11567
- // 添加图层到SvgMapView
11623
+ // // 添加图层到SvgMapView
11568
11624
  this.svgMapView.removeLayerByType(LAYER_DEFAULT_TYPE.PATH);
11569
11625
  this.svgMapView.addLayer(pathLayer);
11570
11626
  this.svgMapView.renderLayer(LAYER_DEFAULT_TYPE.PATH);
@@ -11583,8 +11639,10 @@ class MowerMapOverlay {
11583
11639
  updatePathDataByMowingPosition(position) {
11584
11640
  // 找到当前position所在的分区id,将该点更新到pathData中
11585
11641
  // 先查找当前的分区id是多少,然后确定当前的点是否在当前分区id中,如果不在,则重新获取分区id并重新设置
11586
- const currentPartitionId = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11587
- const processStateIsMowing = useCurrentMowingDataStore.getState().processStateIsMowing;
11642
+ const partitionIdMap = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11643
+ const processStateIsMowingMap = useCurrentMowingDataStore.getState().processStateIsMowing;
11644
+ const currentPartitionId = partitionIdMap[this.sn];
11645
+ const processStateIsMowing = processStateIsMowingMap[this.sn];
11588
11646
  if (currentPartitionId && this.pathData?.[currentPartitionId]) {
11589
11647
  const currentPathData = this.pathData[currentPartitionId];
11590
11648
  this.pathData[currentPartitionId] = {
@@ -11889,7 +11947,9 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
11889
11947
  // 默认配置
11890
11948
  const defaultMapConfig = DEFAULT_STYLES;
11891
11949
  // 地图渲染器组件
11892
- 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) => {
11950
+ const MowerMapRenderer = forwardRef(({
11951
+ // 唯一的可以标识一个割草机的id
11952
+ sn, 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) => {
11893
11953
  const [elementCount, setElementCount] = useState(0);
11894
11954
  const [pathCount, setPathCount] = useState(0);
11895
11955
  const [currentError, setCurrentError] = useState(null);
@@ -11897,10 +11957,9 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
11897
11957
  // const mapRef = useMap();
11898
11958
  const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
11899
11959
  const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
11900
- const { clearSubBoundaryBorder, clearObstacles, clearSvgElements } = usePartitionDataStore();
11901
- const { resetCurrentMowingPartitionId } = useCurrentMowingDataStore();
11960
+ const { deleteSubBoundaryBorder, deleteObstacles, deleteSvgElements } = usePartitionDataStore();
11902
11961
  const currentProcessMowingStatusRef = useRef(false);
11903
- const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, } = useCurrentMowingDataStore();
11962
+ const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, resetCurrentMowingPartitionId, } = useCurrentMowingDataStore();
11904
11963
  const [mowPartitionData, setMowPartitionData] = useState(null);
11905
11964
  // Debug相关状态
11906
11965
  const [debugInfo, setDebugInfo] = useState({});
@@ -12026,7 +12085,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12026
12085
  overlayRef.current = null;
12027
12086
  }
12028
12087
  // 创建叠加层
12029
- const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12088
+ const overlay = new MowerMapOverlay(sn, googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12030
12089
  setElementCount(count);
12031
12090
  onMapLoad?.(count);
12032
12091
  }, (count) => {
@@ -12049,7 +12108,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12049
12108
  }
12050
12109
  };
12051
12110
  const resetInCharginPie = useCallback(() => {
12052
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12111
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12053
12112
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12054
12113
  if (!overlayRef.current)
12055
12114
  return;
@@ -12066,18 +12125,22 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12066
12125
  initializeGoogleMapsOverlay();
12067
12126
  // 清理函数
12068
12127
  return () => {
12069
- clearSubBoundaryBorder();
12070
- clearObstacles();
12071
- clearSvgElements();
12072
- resetCurrentMowingPartitionId();
12073
- updateProcessStateIsMowing(false);
12074
- currentProcessMowingStatusRef.current = false;
12075
12128
  if (overlayRef.current) {
12076
12129
  overlayRef.current.setMap(null);
12077
12130
  overlayRef.current = null;
12078
12131
  }
12079
12132
  };
12080
- }, [mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12133
+ }, [sn, mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12134
+ useEffect(() => {
12135
+ return () => {
12136
+ deleteSubBoundaryBorder(sn);
12137
+ deleteObstacles(sn);
12138
+ deleteSvgElements(sn);
12139
+ resetCurrentMowingPartitionId(sn);
12140
+ updateProcessStateIsMowing(sn, false);
12141
+ currentProcessMowingStatusRef.current = false;
12142
+ };
12143
+ }, []);
12081
12144
  // 监听编辑模式变化
12082
12145
  useEffect(() => {
12083
12146
  if (overlayRef.current) {
@@ -12093,7 +12156,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12093
12156
  useEffect(() => {
12094
12157
  if (!mapJson)
12095
12158
  return;
12096
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12159
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12097
12160
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12098
12161
  if (!mowerPositionData || !overlayRef.current)
12099
12162
  return;
@@ -12304,13 +12367,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12304
12367
  if (realTimeData.length > 1) {
12305
12368
  const { pathData, isMowing, currentMowingPartition } = handleMultipleRealTimeData({
12306
12369
  realTimeData,
12307
- isMowing: processStateIsMowing,
12370
+ isMowing: processStateIsMowing[sn],
12308
12371
  pathData: pathJson,
12309
- currentMowingPartition: currentMowingPartitionId,
12372
+ currentMowingPartition: currentMowingPartitionId[sn],
12310
12373
  });
12311
- updateProcessStateIsMowing(isMowing);
12312
- if (currentMowingPartition !== currentMowingPartitionId) {
12313
- updateCurrentMowingPartitionId(currentMowingPartition);
12374
+ updateProcessStateIsMowing(sn, isMowing);
12375
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12376
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12314
12377
  }
12315
12378
  if (pathData) {
12316
12379
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
@@ -12320,13 +12383,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
12320
12383
  else {
12321
12384
  const { isMowing, pathData, currentMowingPartition } = getProcessMowingDataFromRealTimeData({
12322
12385
  realTimeData,
12323
- isMowing: processStateIsMowing,
12386
+ isMowing: processStateIsMowing[sn],
12324
12387
  pathData: pathJson,
12325
- currentMowingPartition: currentMowingPartitionId,
12388
+ currentMowingPartition: currentMowingPartitionId[sn],
12326
12389
  });
12327
- updateProcessStateIsMowing(isMowing);
12328
- if (currentMowingPartition !== currentMowingPartitionId) {
12329
- updateCurrentMowingPartitionId(currentMowingPartition);
12390
+ updateProcessStateIsMowing(sn, isMowing);
12391
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12392
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12330
12393
  }
12331
12394
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
12332
12395
  // 更新进度数据