@pisell/materials 1.8.54 → 1.8.55

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 (139) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/meta.js +3 -3
  5. package/build/lowcode/render/default/view.css +1 -1
  6. package/build/lowcode/render/default/view.js +35 -35
  7. package/build/lowcode/view.css +1 -1
  8. package/build/lowcode/view.js +35 -35
  9. package/es/components/buttonGroupPreview/index.js +8 -4
  10. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +207 -49
  11. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  12. package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  13. package/es/components/pisellFloorMapLayout/components/EdgeLayer.js +252 -0
  14. package/es/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  15. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  16. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  17. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +131 -0
  18. package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  19. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +5 -4
  20. package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  21. package/es/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  22. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  23. package/es/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  24. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.js +290 -147
  25. package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  26. package/es/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +81 -0
  27. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  28. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +21 -0
  29. package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  30. package/es/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  31. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.js +70 -0
  32. package/es/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  33. package/es/components/pisellFloorMapLayout/components/ViewControls.js +13 -5
  34. package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  35. package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  36. package/es/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  37. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +340 -0
  38. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +102 -0
  39. package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +244 -84
  40. package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  41. package/es/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  42. package/es/components/pisellFloorMapLayout/index.d.ts +5 -1
  43. package/es/components/pisellFloorMapLayout/locales-ja.js +14 -2
  44. package/es/components/pisellFloorMapLayout/locales-pt.js +14 -2
  45. package/es/components/pisellFloorMapLayout/locales.js +161 -8
  46. package/es/components/pisellFloorMapLayout/types.d.ts +86 -4
  47. package/es/components/pisellFloorMapLayout/types.js +5 -1
  48. package/es/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  49. package/es/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +86 -0
  50. package/es/components/pisellFloorMapLayout/utils/edgeRouting.js +942 -0
  51. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  52. package/es/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -1
  53. package/es/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  54. package/es/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +20 -3
  55. package/es/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  56. package/es/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  57. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  58. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +62 -0
  59. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  60. package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  61. package/es/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +51 -0
  62. package/es/components/productCard/cartSkuCard/components/BookingItem/index.js +14 -0
  63. package/es/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  64. package/es/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  65. package/es/components/productCard/cartSkuCard/index.js +17 -11
  66. package/es/components/productCard/lineItem/BookingLineItem.js +6 -4
  67. package/es/components/productCard/lineItem/components/Resources/index.js +45 -0
  68. package/es/components/productCard/lineItem/components/TimeRange/index.js +64 -0
  69. package/es/components/productCard/lineItem/index.js +2 -1
  70. package/es/components/productCard/lineItem/index.less +21 -10
  71. package/es/index.d.ts +6 -2
  72. package/es/index.js +6 -2
  73. package/es/pisell-materials.tw.css +3 -0
  74. package/lib/components/buttonGroupPreview/index.js +8 -4
  75. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +206 -48
  76. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
  77. package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
  78. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.js +255 -0
  79. package/lib/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
  80. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
  81. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
  82. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +134 -0
  83. package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
  84. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +4 -3
  85. package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
  86. package/lib/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
  87. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
  88. package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
  89. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.js +287 -144
  90. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
  91. package/lib/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +84 -0
  92. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
  93. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +23 -0
  94. package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
  95. package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
  96. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.js +73 -0
  97. package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
  98. package/lib/components/pisellFloorMapLayout/components/ViewControls.js +12 -4
  99. package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
  100. package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
  101. package/lib/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
  102. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +341 -0
  103. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +103 -0
  104. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +242 -82
  105. package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
  106. package/lib/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
  107. package/lib/components/pisellFloorMapLayout/index.d.ts +5 -1
  108. package/lib/components/pisellFloorMapLayout/locales-ja.js +14 -2
  109. package/lib/components/pisellFloorMapLayout/locales-pt.js +14 -2
  110. package/lib/components/pisellFloorMapLayout/locales.js +161 -8
  111. package/lib/components/pisellFloorMapLayout/types.d.ts +86 -4
  112. package/lib/components/pisellFloorMapLayout/types.js +5 -0
  113. package/lib/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
  114. package/lib/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +87 -0
  115. package/lib/components/pisellFloorMapLayout/utils/edgeRouting.js +956 -0
  116. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
  117. package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -0
  118. package/lib/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
  119. package/lib/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +21 -2
  120. package/lib/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
  121. package/lib/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
  122. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
  123. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +64 -0
  124. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
  125. package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
  126. package/lib/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +54 -0
  127. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.js +17 -0
  128. package/lib/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
  129. package/lib/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
  130. package/lib/components/productCard/cartSkuCard/index.js +17 -11
  131. package/lib/components/productCard/lineItem/BookingLineItem.js +6 -4
  132. package/lib/components/productCard/lineItem/components/Resources/index.js +47 -0
  133. package/lib/components/productCard/lineItem/components/TimeRange/index.js +67 -0
  134. package/lib/components/productCard/lineItem/index.js +2 -1
  135. package/lib/components/productCard/lineItem/index.less +21 -10
  136. package/lib/index.d.ts +6 -2
  137. package/lib/index.js +11 -0
  138. package/lib/pisell-materials.tw.css +3 -0
  139. package/package.json +4 -1
@@ -1,9 +1,11 @@
1
1
  import { _objectSpread2 } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
+ import { _objectWithoutProperties } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectWithoutProperties.js";
2
3
  import Button$1 from "../button/index.js";
3
4
  import React, { forwardRef, memo, useMemo } from "react";
4
5
  import { Dropdown, Flex, Space } from "antd";
5
6
  import { MoreOutlined } from "@ant-design/icons";
6
7
  //#region src/components/buttonGroupPreview/index.tsx
8
+ const _excluded = ["children"];
7
9
  /**
8
10
  *
9
11
  * @param param0 { buttonConfig, buttonGroupList }
@@ -12,7 +14,7 @@ import { MoreOutlined } from "@ant-design/icons";
12
14
  const updateSourceData = ({ buttonConfig, buttonGroupList }) => {
13
15
  if (Object.keys(buttonConfig).length !== 0) return buttonGroupList.map((subArray) => {
14
16
  return subArray.map((item) => {
15
- if (buttonConfig.hasOwnProperty(item.id)) return buttonConfig[item.id];
17
+ if (item.id && Object.prototype.hasOwnProperty.call(buttonConfig, item.id)) return buttonConfig[item.id];
16
18
  return item;
17
19
  });
18
20
  });
@@ -27,13 +29,15 @@ var buttonGroupPreview_default = memo(forwardRef((props, ref) => {
27
29
  });
28
30
  }, [buttonGroupList, buttonConfig]);
29
31
  return /* @__PURE__ */ React.createElement(Flex, {
30
- wrap: true,
32
+ wrap: "wrap",
31
33
  vertical: true,
32
34
  style: { marginBottom: 10 }
33
- }, sourceDatas.map((item, index) => /* @__PURE__ */ React.createElement(Space, { key: index }, item.map((items, index) => {
35
+ }, sourceDatas.map((item, index) => React.createElement(Space, { key: index }, item.map((items, index) => {
34
36
  const { isMore = false, id = "", menuData = [], buttonProps } = items;
35
37
  const btnProps = _objectSpread2(_objectSpread2({}, buttonProps), props.updateButtonProps);
36
- return isMore ? /* @__PURE__ */ React.createElement(Dropdown, { menu: { items: menuData } }, /* @__PURE__ */ React.createElement(Button$1, null, /* @__PURE__ */ React.createElement(MoreOutlined, null))) : /* @__PURE__ */ React.createElement(Button$1, _objectSpread2({ key: id }, btnProps));
38
+ const { children } = btnProps, dropdownButtonProps = _objectWithoutProperties(btnProps, _excluded);
39
+ const moreButtonChildren = children !== null && children !== void 0 ? children : dropdownButtonProps.icon ? null : /* @__PURE__ */ React.createElement(MoreOutlined, null);
40
+ return isMore ? /* @__PURE__ */ React.createElement(Dropdown, { menu: { items: menuData } }, /* @__PURE__ */ React.createElement(Button$1, _objectSpread2({ key: id }, dropdownButtonProps), moreButtonChildren)) : /* @__PURE__ */ React.createElement(Button$1, _objectSpread2({ key: id }, btnProps));
37
41
  }))));
38
42
  }));
39
43
  //#endregion
@@ -2,7 +2,7 @@ import { _objectSpread2 } from "../../_virtual/_@oxc-project_runtime@0.122.0/hel
2
2
  import MapLayer from "./components/MapLayer.js";
3
3
  import ItemLayer from "./components/ItemLayer.js";
4
4
  import EditableItemLayer from "./components/EditableItemLayer.js";
5
- import { getElementKindConfig, getSceneElementRenderIssue } from "./utils/floorMapElementKindUtils.js";
5
+ import { FLOOR_MAP_RESOURCE_PLACE_DEFAULT, getElementKindConfig, getSceneElementRenderIssue } from "./utils/floorMapElementKindUtils.js";
6
6
  import { isFloorMapPaletteDrag, parsePaletteDragPayload, sceneXYFromContentDropOffset } from "./utils/floorMapDropUtils.js";
7
7
  import { FLOOR_MAP_LAYOUT_CLASS_PREFIX, FLOOR_MAP_OVERVIEW_TAB_ID } from "./floorMapLayoutConstants.js";
8
8
  import FloorMapToolbar from "./components/FloorMapToolbar.js";
@@ -13,8 +13,13 @@ import FloorMapEditTopBar from "./components/FloorMapEditTopBar.js";
13
13
  import { mergeCanvasesForTabs } from "./utils/mergeCanvasesForTabs.js";
14
14
  import FloorMapOverview from "./components/FloorMapOverview.js";
15
15
  import FloorMapEditPanel from "./components/FloorMapEditPanel.js";
16
- import { ViewControlsWithZoom } from "./components/ViewControlsWithZoom.js";
17
16
  import { gapToPx } from "./utils/layoutMeasurements.js";
17
+ import { FloorMapEdgeEditPanel } from "./components/FloorMapEdgeEditPanel.js";
18
+ import { EdgeLayer } from "./components/EdgeLayer.js";
19
+ import { NodePortMarkers } from "./components/NodePortMarkers.js";
20
+ import { useFloorMapEdgeViewModel } from "./hooks/useFloorMapEdgeViewModel.js";
21
+ import { useFloorMapEdgeEditing } from "./hooks/useFloorMapEdgeEditing.js";
22
+ import { ViewControlsWithZoom } from "./components/ViewControlsWithZoom.js";
18
23
  import { useFloorMapEditState } from "./hooks/useFloorMapEditState.js";
19
24
  import { useFloorMapTransformMetrics } from "./hooks/useFloorMapTransformMetrics.js";
20
25
  import { renderFloorMapFallbackPlaceholder, renderFloorMapRenderError } from "./utils/floorMapFallbackRender.js";
@@ -39,8 +44,8 @@ import "./PisellFloorMapLayout.less";
39
44
  * 负责:上下文与 props 合并、编辑态/阅读态分支、Transform 视口、图元层与工具栏联动。
40
45
  */
41
46
  function PisellFloorMapLayoutInner(props, ref) {
42
- var _ref, _currentCanvas$mapLay2, _currentCanvas$mapLay3, _mapLayer$backgroundC, _engineCtx$engine, _mapLayer$boundingPad, _config$sceneElements;
43
- const { className, style, items: itemsProp, renderItem, rowKey, renderItemByKind, getMergedItemWrapperStyle, mapLayer, cellSize: cellSizeProp, itemUnit = "cell", zoom = {}, pan = {}, controls = {}, enableHover = true, readModeSelectedItemId, onItemClick, onItemHover, onItemLeave, mode = "read", floorMapConfig: floorMapConfigProp, dataSources, onSave, onExitEdit, onDataSourceRecordSave, dataSourceLabels, dataSourceFormColumns, dataSourceRecordForm, loading, saveError, onElementRenderError, toolbarShowSave = true, floorMapFullscreenMode, appearanceMode = "light", showDataSourceRecordFormBlock, floorMapViewportOverlay, viewportOverlayPlacement = "top-start", viewportOverlayClassName, editTopBarPhoneLayout = false, canvasTabsBarTrailing, viewportDockToolButtons, viewportDockTrailing, viewportPersist = true, viewportPersistNamespace } = mergeFloorMapLayoutPropsFromContext(props, useFloorMapLayoutContext());
47
+ var _ref, _currentCanvas$mapLay2, _currentCanvas$mapLay3, _mapLayer$backgroundC, _engineCtx$engine, _mapLayer$boundingPad, _config$edges, _config$edges2, _config$sceneElements;
48
+ const { className, style, items: itemsProp, renderItem, rowKey, renderItemByKind, getMergedItemWrapperStyle, enableEdges = false, mapLayer, cellSize: cellSizeProp, itemUnit = "cell", zoom = {}, pan = {}, controls = {}, enableHover = true, readModeSelectedItemId, onItemClick, onItemHover, onItemLeave, mode = "read", floorMapConfig: floorMapConfigProp, dataSources, onSave, onExitEdit, onDataSourceRecordSave, dataSourceLabels, dataSourceFormColumns, dataSourceRecordForm, loading, saveError, onElementRenderError, toolbarShowSave = true, renderResourcePickerModal, paletteSidebarVisibleLimit, floorMapFullscreenMode, appearanceMode = "light", showDataSourceRecordFormBlock, floorMapViewportOverlay, viewportOverlayPlacement = "top-start", viewportOverlayClassName, editTopBarPhoneLayout = false, canvasTabsBarTrailing, viewportDockToolButtons, viewportDockTrailing, viewportPersist = true, viewportPersistNamespace } = mergeFloorMapLayoutPropsFromContext(props, useFloorMapLayoutContext());
44
49
  const { token } = theme.useToken();
45
50
  const isFloorMapView = Boolean(floorMapConfigProp);
46
51
  const contentOffsetRef = useRef({
@@ -49,7 +54,8 @@ function PisellFloorMapLayoutInner(props, ref) {
49
54
  });
50
55
  const mapDropLayerRef = useRef(null);
51
56
  const transformRef = useRef(null);
52
- const { config, currentCanvasId, setCurrentCanvasId, selectedId, setSelectedId, placeMode, setPlaceMode, items, saving, savingRecord, handleAddCanvas, handleRemoveCanvas, handleRenameCanvas, handleUpdateItem, handleCanvasPlaceClick, handleSave, placeSceneElementFromPaletteDrop, editPanelParams, placeOverlayClass, isLayoutDirty, toggleDraftCanvasShowGrid, toggleSelectedLayoutLock, duplicateSelectedElement, deleteSelectedElement, undoDraft, redoDraft, canUndo, canRedo, discardDraft } = useFloorMapEditState({
57
+ const focusViewportOnBoundsRef = useRef(null);
58
+ const { config, currentCanvasId, setCurrentCanvasId, selectedId, setSelectedId, placeMode, setPlaceMode, items, saving, savingRecord, handleAddCanvas, handleRemoveCanvas, handleRenameCanvas, handleUpdateItem, handleCanvasPlaceClick, handleSave, placeSceneElementFromPaletteDrop, bulkPlacePaletteItems, editPanelParams, placeOverlayClass, isLayoutDirty, toggleDraftCanvasShowGrid, toggleSelectedLayoutLock, duplicateSelectedElement, deleteSelectedElement, undoDraft, redoDraft, canUndo, canRedo, discardDraft, commitDraft } = useFloorMapEditState({
53
59
  floorMapConfigProp,
54
60
  isFloorMapView,
55
61
  itemsProp,
@@ -62,8 +68,10 @@ function PisellFloorMapLayoutInner(props, ref) {
62
68
  dataSourceLabels,
63
69
  layoutPrefix: FLOOR_MAP_LAYOUT_CLASS_PREFIX,
64
70
  contentOffsetRef,
65
- showDataSourceRecordFormBlock
71
+ showDataSourceRecordFormBlock,
72
+ focusViewportOnBoundsRef
66
73
  });
74
+ const mapContentRef = useRef(null);
67
75
  /**
68
76
  * 当前选中的画布配置:用于提取当前画布级 mapLayer 显式配置。
69
77
  */
@@ -146,25 +154,26 @@ function PisellFloorMapLayoutInner(props, ref) {
146
154
  const engineLocale = (engineCtx === null || engineCtx === void 0 || (_engineCtx$engine = engineCtx.engine) === null || _engineCtx$engine === void 0 || (_engineCtx$engine = _engineCtx$engine.props) === null || _engineCtx$engine === void 0 ? void 0 : _engineCtx$engine.locale) || "zh-CN";
147
155
  const hasCanvasTabsBarTrailing = canvasTabsBarTrailing != null && canvasTabsBarTrailing !== false;
148
156
  const enabledCanvasCount = useMemo(() => canvasesForTabsBase.filter((c) => c.enabled).length, [canvasesForTabsBase]);
149
- /** 仅阅读态、启用画布 > 1 时,在 Tab 列表最前插入「All」伪 tab */
157
+ /** 仅阅读态、启用画布 > 1 时,在 Tab 列表末尾插入「Overview」伪 tab */
150
158
  const showOverviewTab = isFloorMapView && mode === "read" && enabledCanvasCount > 1;
151
159
  const overviewTabLabel = useMemo(() => {
152
160
  initFloorMapLayoutLocales(engineLocale);
153
161
  return locales.getText("pisell-floor-map-layout.canvas-tabs.overview");
154
162
  }, [engineLocale]);
155
163
  /**
156
- * 给 CanvasTabs 渲染用的最终列表:阅读态多画布时在列表最前插入「All」伪 tab。
157
- * order 取当前最小 order - 1,保证排序后位于第一个;其它字段留空。
164
+ * 给 CanvasTabs 渲染用的最终列表:阅读态多画布时在列表末尾插入「Overview」伪 tab。
165
+ * order 取当前最大 order + 1,保证排序后位于最后一个。
158
166
  */
159
167
  const canvasesForTabs = useMemo(() => {
160
168
  if (!showOverviewTab) return canvasesForTabsBase;
161
- const minOrder = canvasesForTabsBase.reduce((min, c) => c.order < min ? c.order : min, Number.POSITIVE_INFINITY);
162
- return [{
169
+ const maxOrder = canvasesForTabsBase.reduce((max, c) => c.order > max ? c.order : max, Number.NEGATIVE_INFINITY);
170
+ const overviewTab = {
163
171
  id: FLOOR_MAP_OVERVIEW_TAB_ID,
164
172
  name: overviewTabLabel,
165
- order: Number.isFinite(minOrder) ? minOrder - 1 : -1,
173
+ order: Number.isFinite(maxOrder) ? maxOrder + 1 : 0,
166
174
  enabled: true
167
- }, ...canvasesForTabsBase];
175
+ };
176
+ return [...canvasesForTabsBase, overviewTab];
168
177
  }, [
169
178
  canvasesForTabsBase,
170
179
  showOverviewTab,
@@ -257,7 +266,7 @@ function PisellFloorMapLayoutInner(props, ref) {
257
266
  globalMapLayer: mapLayer,
258
267
  cellSize,
259
268
  itemUnit: effectiveItemUnit,
260
- areaGap: 32
269
+ areaGap: 40
261
270
  });
262
271
  }, [
263
272
  isFloorMapView,
@@ -305,7 +314,7 @@ function PisellFloorMapLayoutInner(props, ref) {
305
314
  shape: "rect"
306
315
  }];
307
316
  }, [overviewLayout]);
308
- const { containerRef, mapAreaRef, mapAreaSize, contentWidth, contentHeight, contentOffsetX, contentOffsetY, initialPositionX, initialPositionY, zoomConfig, scale, setScale, isFullscreen, toggleFullscreen, fitBounds, isAtFitBounds, notifyTransformed, persistCurrentViewport, attachTransformContext, isInteractingWithElement, setIsInteractingWithElement, viewportLocked, toggleViewportLocked } = useFloorMapTransformMetrics({
317
+ const { containerRef, mapAreaRef, mapAreaSize, contentWidth, contentHeight, contentOffsetX, contentOffsetY, initialPositionX, initialPositionY, zoomConfig, scale, setScale, isFullscreen, toggleFullscreen, fitBounds, focusContentBounds, isAtFitBounds, notifyTransformed, persistCurrentViewport, attachTransformContext, isInteractingWithElement, setIsInteractingWithElement, viewportLocked, toggleViewportLocked } = useFloorMapTransformMetrics({
309
318
  items: isOverview && overviewLayout ? overviewMetricsItems : items,
310
319
  cellSize,
311
320
  itemGap: isOverview ? 0 : itemGap,
@@ -319,20 +328,81 @@ function PisellFloorMapLayoutInner(props, ref) {
319
328
  frameResetKey: isFloorMapView ? transformWrapperKey : void 0,
320
329
  viewportPersistKey
321
330
  });
322
- /** 手机:选中图元种类后一键落在当前视口中心(与点击画布落点坐标换算一致) */
323
- const handlePlaceActiveAtViewportCenter = useCallback(() => {
324
- if (!placeMode || placeMode.type !== "scene") return;
331
+ useEffect(() => {
332
+ focusViewportOnBoundsRef.current = (bounds) => {
333
+ requestAnimationFrame(() => {
334
+ requestAnimationFrame(() => {
335
+ focusContentBounds(bounds);
336
+ });
337
+ });
338
+ };
339
+ return () => {
340
+ focusViewportOnBoundsRef.current = null;
341
+ };
342
+ }, [focusContentBounds]);
343
+ /**
344
+ * 是否启用连线(edge)渲染与编辑能力。
345
+ * - 必须显式 `enableEdges={true}` 才打开;
346
+ * - pisell-reservation 等通用业务画布默认关闭,避免选中图元出现锚点圆点或拖出连线。
347
+ */
348
+ const showEdgeLayer = enableEdges && isFloorMapView && !isOverview && config != null;
349
+ /** 连线层显隐(仅影响 EdgeLayer 绘制;编辑锚点仍随 `showEdgeLayer`) */
350
+ const [edgesLayerVisible, setEdgesLayerVisible] = useState(true);
351
+ const showEdgesOnCanvas = showEdgeLayer && edgesLayerVisible;
352
+ const toggleEdgesLayerVisible = useCallback(() => {
353
+ setEdgesLayerVisible((v) => !v);
354
+ }, []);
355
+ const readEdgeVm = useFloorMapEdgeViewModel({
356
+ edges: showEdgeLayer && mode === "read" ? (_config$edges = config === null || config === void 0 ? void 0 : config.edges) !== null && _config$edges !== void 0 ? _config$edges : [] : [],
357
+ items: showEdgeLayer ? items : [],
358
+ cellSize,
359
+ itemUnit: effectiveItemUnit,
360
+ itemGap
361
+ });
362
+ const edgeEdit = useFloorMapEdgeEditing({
363
+ enabled: showEdgeLayer && mode === "edit",
364
+ config,
365
+ items,
366
+ mergedItems: items,
367
+ cellSize,
368
+ itemUnit: effectiveItemUnit,
369
+ itemGap,
370
+ contentOffsetRef,
371
+ selectedId,
372
+ setSelectedId,
373
+ commitDraft,
374
+ mapContentRef,
375
+ scale
376
+ });
377
+ const edgeRoutes = mode === "edit" && showEdgeLayer ? edgeEdit.routes : readEdgeVm.routes;
378
+ const edgeRectsById = mode === "edit" && showEdgeLayer ? edgeEdit.rectsById : readEdgeVm.rectsById;
379
+ const displayEdges = mode === "edit" && showEdgeLayer ? edgeEdit.edges : (_config$edges2 = config === null || config === void 0 ? void 0 : config.edges) !== null && _config$edges2 !== void 0 ? _config$edges2 : [];
380
+ const getViewportCenterContentCoords = useCallback(() => {
325
381
  const w = mapAreaSize.width;
326
382
  const h = mapAreaSize.height;
327
- if (w <= 0 || h <= 0) return;
383
+ if (w <= 0 || h <= 0) return null;
328
384
  const { x: ox, y: oy } = contentOffsetRef.current;
329
- placeSceneElementFromPaletteDrop(Math.round(w / 2 - ox), Math.round(h / 2 - oy), placeMode);
385
+ return {
386
+ x: Math.round(w / 2 - ox),
387
+ y: Math.round(h / 2 - oy)
388
+ };
389
+ }, [mapAreaSize.width, mapAreaSize.height]);
390
+ /** 手机:选中图元种类后一键落在当前视口中心(与点击画布落点坐标换算一致) */
391
+ const handlePlaceActiveAtViewportCenter = useCallback(() => {
392
+ if (!placeMode || placeMode.type !== "scene") return;
393
+ const center = getViewportCenterContentCoords();
394
+ if (!center) return;
395
+ placeSceneElementFromPaletteDrop(center.x, center.y, placeMode);
330
396
  }, [
331
397
  placeMode,
332
- mapAreaSize.width,
333
- mapAreaSize.height,
398
+ getViewportCenterContentCoords,
334
399
  placeSceneElementFromPaletteDrop
335
400
  ]);
401
+ /** 侧栏「查看更多」:按数量批量落在画布右侧空白区(方阵网格 + gap) */
402
+ const handleBulkAddPaletteToCanvas = useCallback((items) => {
403
+ if (!items.length) return;
404
+ bulkPlacePaletteItems(items);
405
+ }, [bulkPlacePaletteItems]);
336
406
  /** 编辑态全屏策略:toggle 全屏与编辑态强绑定;locked 始终全屏顶栏;disabled 无全屏 */
337
407
  const fsMode = floorMapFullscreenMode !== null && floorMapFullscreenMode !== void 0 ? floorMapFullscreenMode : "toggle";
338
408
  const useFullTopChrome = isFloorMapView && mode === "edit" && (fsMode === "locked" || fsMode === "toggle" && isFullscreen);
@@ -369,16 +439,18 @@ function PisellFloorMapLayoutInner(props, ref) {
369
439
  * 并默认带出「视口锁定」按钮(与是否将视口保存到本地解耦;无持久化 key 时仅内存态,默认未锁定)。
370
440
  */
371
441
  const viewControlsConfig = useMemo(() => {
372
- var _controls$showFullscr, _controls$showViewpor;
442
+ var _controls$showFullscr, _controls$showViewpor, _controls$showEdgesTo;
373
443
  if (!isFloorMapView) return controls;
374
444
  return _objectSpread2(_objectSpread2({}, controls), {}, {
375
445
  showFullscreen: (_controls$showFullscr = controls.showFullscreen) !== null && _controls$showFullscr !== void 0 ? _controls$showFullscr : Boolean(dockToggleFullscreen),
376
- showViewportLock: (_controls$showViewpor = controls.showViewportLock) !== null && _controls$showViewpor !== void 0 ? _controls$showViewpor : true
446
+ showViewportLock: (_controls$showViewpor = controls.showViewportLock) !== null && _controls$showViewpor !== void 0 ? _controls$showViewpor : true,
447
+ showEdgesToggle: showEdgeLayer ? (_controls$showEdgesTo = controls.showEdgesToggle) !== null && _controls$showEdgesTo !== void 0 ? _controls$showEdgesTo : true : controls.showEdgesToggle
377
448
  });
378
449
  }, [
379
450
  isFloorMapView,
380
451
  controls,
381
- dockToggleFullscreen
452
+ dockToggleFullscreen,
453
+ showEdgeLayer
382
454
  ]);
383
455
  const topBarExtraActions = null;
384
456
  /** 从侧栏/调色板拖入画布时,地图区高亮态(用于 dragleave/over 判定) */
@@ -544,8 +616,17 @@ function PisellFloorMapLayoutInner(props, ref) {
544
616
  return (_transformRef$current3 = transformRef.current) === null || _transformRef$current3 === void 0 ? void 0 : _transformRef$current3.resetTransform();
545
617
  },
546
618
  fitBounds,
547
- saveLayout: () => handleSave()
548
- }), [fitBounds, handleSave]);
619
+ saveLayout: () => handleSave(),
620
+ applySceneSnapshot: (next) => {
621
+ if (mode !== "edit") return;
622
+ commitDraft(() => next);
623
+ }
624
+ }), [
625
+ fitBounds,
626
+ handleSave,
627
+ mode,
628
+ commitDraft
629
+ ]);
549
630
  const showSidebar = isFloorMapView && mode === "edit" && config && dataSources;
550
631
  /** 右侧属性面板打开时给画布区留空,避免落点被挡在面板下 */
551
632
  const editPanelVisible = isFloorMapView && mode === "edit" && Boolean(editPanelParams) && Boolean(config) && Boolean(dataSources);
@@ -684,8 +765,8 @@ function PisellFloorMapLayoutInner(props, ref) {
684
765
  sceneElements: (_config$sceneElements = config.sceneElements) !== null && _config$sceneElements !== void 0 ? _config$sceneElements : [],
685
766
  renderPreviewItem: (item) => effectiveRenderItem(item, 0),
686
767
  placementPreviewSize: {
687
- width: 180,
688
- height: 120
768
+ width: FLOOR_MAP_RESOURCE_PLACE_DEFAULT.width,
769
+ height: FLOOR_MAP_RESOURCE_PLACE_DEFAULT.height
689
770
  },
690
771
  decorationPreviewSize: 48,
691
772
  onSave: onSave && config.canvasUi.canEdit && !useFullTopChrome && toolbarShowSave !== false ? handleSave : void 0,
@@ -696,7 +777,16 @@ function PisellFloorMapLayoutInner(props, ref) {
696
777
  consumeToolbarClickIfTouchDrag: paletteTouchDrag.consumeToolbarClickIfTouchDrag,
697
778
  phoneLayout: editTopBarPhoneLayout,
698
779
  defaultCollapsed: editTopBarPhoneLayout,
699
- onRequestPlaceAtCanvasCenter: editTopBarPhoneLayout ? handlePlaceActiveAtViewportCenter : void 0
780
+ paletteSidebarVisibleLimit,
781
+ onRequestPlaceAtCanvasCenter: editTopBarPhoneLayout ? handlePlaceActiveAtViewportCenter : void 0,
782
+ onBulkAddPaletteToCanvas: handleBulkAddPaletteToCanvas,
783
+ onDirectPlacePaletteItem: (item) => bulkPlacePaletteItems([item]),
784
+ onResourcePickerConfirmPlace: (scene) => {
785
+ const center = getViewportCenterContentCoords();
786
+ if (!center) return false;
787
+ return placeSceneElementFromPaletteDrop(center.x, center.y, scene);
788
+ },
789
+ renderResourcePickerModal
700
790
  }), /* @__PURE__ */ React.createElement("div", {
701
791
  ref: mapAreaRef,
702
792
  className: classNames(showSidebar && `pisell-floor-map-layout-map-area`, editTopBarPhoneLayout && showSidebar && `pisell-floor-map-layout-map-area--phone-fill`, editPanelVisible && !editTopBarPhoneLayout && `pisell-floor-map-layout-map-area--edit-panel-inset`),
@@ -766,7 +856,7 @@ function PisellFloorMapLayoutInner(props, ref) {
766
856
  onPinchingStop: persistCurrentViewport,
767
857
  onWheelStop: persistCurrentViewport
768
858
  }), (ctx) => {
769
- var _effectiveMapLayer$sn;
859
+ var _effectiveMapLayer$sn, _edgeEdit$drawing;
770
860
  /**
771
861
  * 不直接 transformRef.current = ctx:
772
862
  * attachTransformContext 内部会比对 ctx 实例并在每次 wrapper 重挂载时
@@ -817,14 +907,37 @@ function PisellFloorMapLayoutInner(props, ref) {
817
907
  getMergedItemWrapperStyle,
818
908
  readModeSelectedItemId
819
909
  })
820
- ) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(MapLayer, {
910
+ ) : /* @__PURE__ */ React.createElement("div", {
911
+ ref: mapContentRef,
912
+ className: `${FLOOR_MAP_LAYOUT_CLASS_PREFIX}-map-content`,
913
+ style: {
914
+ position: "relative",
915
+ width: contentWidth,
916
+ height: contentHeight
917
+ }
918
+ }, /* @__PURE__ */ React.createElement(MapLayer, {
821
919
  config: effectiveMapLayer,
822
920
  contentWidth,
823
921
  contentHeight,
824
922
  cellSize,
825
923
  preferCanvasGrid: true,
826
924
  pointerEventsNone: isFloorMapView && mode === "edit"
827
- }), isFloorMapView && mode === "edit" ? /* @__PURE__ */ React.createElement(EditableItemLayer, {
925
+ }), showEdgesOnCanvas ? /* @__PURE__ */ React.createElement(EdgeLayer, {
926
+ width: contentWidth,
927
+ height: contentHeight,
928
+ contentOffsetX,
929
+ contentOffsetY,
930
+ edges: displayEdges,
931
+ routes: edgeRoutes,
932
+ rectsById: edgeRectsById,
933
+ appearance: appearanceTokens,
934
+ mode,
935
+ selectedEdgeId: mode === "edit" ? edgeEdit.selectedEdgeId : null,
936
+ ghostPathD: mode === "edit" ? edgeEdit.ghostPathD : null,
937
+ onEdgeClick: mode === "edit" ? (edgeId) => edgeEdit.handleEdgeClick(edgeId) : void 0,
938
+ viewportScale: scale,
939
+ onSegmentDragStart: mode === "edit" ? edgeEdit.startDraggingSegment : void 0
940
+ }) : null, isFloorMapView && mode === "edit" ? /* @__PURE__ */ React.createElement(EditableItemLayer, {
828
941
  items,
829
942
  renderItem: effectiveRenderItem,
830
943
  rowKey,
@@ -836,11 +949,24 @@ function PisellFloorMapLayoutInner(props, ref) {
836
949
  contentOffsetX,
837
950
  contentOffsetY,
838
951
  selectedId,
839
- onSelect: setSelectedId,
952
+ onSelect: edgeEdit.selectNode,
840
953
  onUpdateItem: handleUpdateItem,
841
954
  snapStep: (_effectiveMapLayer$sn = effectiveMapLayer === null || effectiveMapLayer === void 0 ? void 0 : effectiveMapLayer.snapStep) !== null && _effectiveMapLayer$sn !== void 0 ? _effectiveMapLayer$sn : 0,
842
955
  scale,
843
956
  onInteractionChange: setIsInteractingWithElement,
957
+ onLiveRectChange: (itemId, rect) => {
958
+ if (!itemId || !rect) {
959
+ edgeEdit.setPendingRectsById({});
960
+ return;
961
+ }
962
+ edgeEdit.setPendingRectsById({ [itemId]: {
963
+ left: rect.left,
964
+ top: rect.top,
965
+ width: rect.width,
966
+ height: rect.height
967
+ } });
968
+ },
969
+ alignGuideStroke: appearanceTokens.alignGuideStroke,
844
970
  getMergedItemWrapperStyle,
845
971
  editQuickBar
846
972
  }) : /* @__PURE__ */ React.createElement(ItemLayer, {
@@ -863,7 +989,24 @@ function PisellFloorMapLayoutInner(props, ref) {
863
989
  getMergedItemWrapperStyle,
864
990
  onInteractionChange: setIsInteractingWithElement,
865
991
  readModeSelectedItemId
866
- }), isFloorMapView && mode === "edit" && (placeMode === null || placeMode === void 0 ? void 0 : placeMode.type) === "scene" && /* @__PURE__ */ React.createElement("div", {
992
+ }), isFloorMapView && mode === "edit" && showEdgeLayer && selectedId && edgeEdit.selectedNodeRect ? /* @__PURE__ */ React.createElement(NodePortMarkers, {
993
+ rect: edgeEdit.selectedNodeRect,
994
+ contentOffsetX,
995
+ contentOffsetY,
996
+ viewportScale: scale,
997
+ highlightAnchors: ((_edgeEdit$drawing = edgeEdit.drawing) === null || _edgeEdit$drawing === void 0 ? void 0 : _edgeEdit$drawing.fromInstanceId) === selectedId ? [edgeEdit.drawing.fromAnchor] : [],
998
+ onAnchorPointerDown: (anchor) => {
999
+ if (selectedId) edgeEdit.startDrawingFromAnchor(selectedId, anchor);
1000
+ }
1001
+ }) : null, isFloorMapView && mode === "edit" && showEdgeLayer && edgeEdit.drawing && edgeEdit.drawingTargetPreview ? /* @__PURE__ */ React.createElement(NodePortMarkers, {
1002
+ className: `${FLOOR_MAP_LAYOUT_CLASS_PREFIX}-port-markers--draw-target`,
1003
+ rect: edgeEdit.drawingTargetPreview.rect,
1004
+ contentOffsetX,
1005
+ contentOffsetY,
1006
+ viewportScale: scale,
1007
+ previewOnly: true,
1008
+ highlightAnchors: [edgeEdit.drawingTargetPreview.anchor]
1009
+ }) : null, isFloorMapView && mode === "edit" && (placeMode === null || placeMode === void 0 ? void 0 : placeMode.type) === "scene" && /* @__PURE__ */ React.createElement("div", {
867
1010
  className: placeOverlayClass,
868
1011
  style: {
869
1012
  width: contentWidth,
@@ -881,7 +1024,11 @@ function PisellFloorMapLayoutInner(props, ref) {
881
1024
  ev.preventDefault();
882
1025
  ev.stopPropagation();
883
1026
  },
884
- onDrop: handlePaletteDropOnCanvas
1027
+ onDrop: handlePaletteDropOnCanvas,
1028
+ onClick: () => {
1029
+ if ((placeMode === null || placeMode === void 0 ? void 0 : placeMode.type) === "scene") return;
1030
+ edgeEdit.handleMapBackgroundClick();
1031
+ }
885
1032
  }))), /* @__PURE__ */ React.createElement(ViewControlsWithZoom, {
886
1033
  config: viewControlsConfig,
887
1034
  scale,
@@ -891,6 +1038,8 @@ function PisellFloorMapLayoutInner(props, ref) {
891
1038
  toggleFullscreen: dockToggleFullscreen,
892
1039
  mapGridVisible: isOverview ? false : Boolean(effectiveMapLayer === null || effectiveMapLayer === void 0 ? void 0 : effectiveMapLayer.showGrid),
893
1040
  onToggleMapGrid: isFloorMapView && !isOverview ? toggleDraftCanvasShowGrid : void 0,
1041
+ edgesLayerVisible,
1042
+ onToggleEdgesLayer: showEdgeLayer ? toggleEdgesLayerVisible : void 0,
894
1043
  viewportLocked,
895
1044
  onToggleViewportLock: isFloorMapView ? toggleViewportLocked : void 0,
896
1045
  dockChrome: isFloorMapView,
@@ -902,21 +1051,22 @@ function PisellFloorMapLayoutInner(props, ref) {
902
1051
  dataSources,
903
1052
  currentCanvasId,
904
1053
  mode
905
- }) : floorMapViewportOverlay) : null, isFloorMapView && mode === "edit" && editPanelParams && config && dataSources && !editTopBarPhoneLayout && /* @__PURE__ */ React.createElement("div", {
1054
+ }) : floorMapViewportOverlay) : null, isFloorMapView && mode === "edit" && config && dataSources && !editTopBarPhoneLayout && (edgeEdit.selectedEdge || editPanelParams) && /* @__PURE__ */ React.createElement("div", {
906
1055
  className: classNames(`pisell-floor-map-layout-edit-panel-wrap`, mapAreaSize.height > 0 && `pisell-floor-map-layout-edit-panel-wrap-constrained`),
907
- style: mapAreaSize.height > 0 ? {
908
- height: mapAreaSize.height - 32,
909
- maxHeight: mapAreaSize.height - 32,
910
- overflow: "hidden",
911
- top: 16,
912
- transform: "none"
913
- } : void 0
914
- }, /* @__PURE__ */ React.createElement(FloorMapEditPanel, _objectSpread2(_objectSpread2({}, editPanelParams), {}, {
1056
+ style: mapAreaSize.height > 0 ? { overflow: "hidden" } : void 0
1057
+ }, edgeEdit.selectedEdge ? /* @__PURE__ */ React.createElement(FloorMapEdgeEditPanel, {
1058
+ edge: edgeEdit.selectedEdge,
1059
+ config,
1060
+ onUpdate: (patch) => edgeEdit.updateEdge(edgeEdit.selectedEdge.id, patch),
1061
+ onClose: () => edgeEdit.selectEdge(null),
1062
+ onDelete: config.canvasUi.canEdit ? () => edgeEdit.deleteEdge(edgeEdit.selectedEdge.id) : void 0,
1063
+ layoutDraftDirty: isLayoutDirty
1064
+ }) : editPanelParams ? /* @__PURE__ */ React.createElement(FloorMapEditPanel, _objectSpread2(_objectSpread2({}, editPanelParams), {}, {
915
1065
  config,
916
1066
  dataSources,
917
1067
  savingRecord
918
- }))));
919
- })))), editTopBarPhoneLayout && editPanelParams && config && dataSources && /* @__PURE__ */ React.createElement(Drawer, {
1068
+ })) : null));
1069
+ })))), editTopBarPhoneLayout && config && dataSources && (edgeEdit.selectedEdge || editPanelParams) && /* @__PURE__ */ React.createElement(Drawer, {
920
1070
  placement: "right",
921
1071
  open: phoneEditDrawerOpen,
922
1072
  onClose: handlePhoneEditDrawerClose,
@@ -934,12 +1084,20 @@ function PisellFloorMapLayoutInner(props, ref) {
934
1084
  height: "100%"
935
1085
  } },
936
1086
  getContainer: typeof document !== "undefined" ? () => document.body : void 0
937
- }, /* @__PURE__ */ React.createElement("div", { className: classNames(`pisell-floor-map-layout-edit-panel-wrap`, `pisell-floor-map-layout-edit-panel-wrap--phone-drawer`) }, /* @__PURE__ */ React.createElement(FloorMapEditPanel, _objectSpread2(_objectSpread2({}, editPanelParams), {}, {
1087
+ }, /* @__PURE__ */ React.createElement("div", { className: classNames(`pisell-floor-map-layout-edit-panel-wrap`, `pisell-floor-map-layout-edit-panel-wrap--phone-drawer`) }, edgeEdit.selectedEdge ? /* @__PURE__ */ React.createElement(FloorMapEdgeEditPanel, {
1088
+ edge: edgeEdit.selectedEdge,
1089
+ config,
1090
+ onUpdate: (patch) => edgeEdit.updateEdge(edgeEdit.selectedEdge.id, patch),
1091
+ onClose: () => edgeEdit.selectEdge(null),
1092
+ onDelete: config.canvasUi.canEdit ? () => edgeEdit.deleteEdge(edgeEdit.selectedEdge.id) : void 0,
1093
+ layoutDraftDirty: isLayoutDirty,
1094
+ className: `pisell-floor-map-layout-edit-panel--phone-drawer`
1095
+ }) : editPanelParams ? /* @__PURE__ */ React.createElement(FloorMapEditPanel, _objectSpread2(_objectSpread2({}, editPanelParams), {}, {
938
1096
  config,
939
1097
  dataSources,
940
1098
  savingRecord,
941
1099
  className: `pisell-floor-map-layout-edit-panel--phone-drawer`
942
- })))));
1100
+ })) : null)));
943
1101
  }
944
1102
  /** 空间布局根组件:阅读/编辑、列表与平面图双模式,ref 见 {@link PisellFloorMapLayoutRef} */
945
1103
  const PisellFloorMapLayout = React.forwardRef(PisellFloorMapLayoutInner);
@@ -63,12 +63,35 @@ body.pisell-floor-map-layout-fullscreen-host {
63
63
  z-index: 5;
64
64
  }
65
65
 
66
+ /**
67
+ * 右侧编辑面板(图元 / 连线共用):上下锚定,底部留出 ViewControls Dock,
68
+ * 避免面板白底盖住右下缩放等操作栏。
69
+ */
66
70
  &-edit-panel-wrap {
67
71
  position: absolute;
68
- top: 50%;
72
+ top: 16px;
69
73
  right: 16px;
70
- transform: translateY(-50%);
74
+ bottom: calc(16px + var(--fmap-viewport-dock-bottom-clearance, 78px));
75
+ transform: none;
71
76
  z-index: 10;
77
+ display: flex;
78
+ flex-direction: column;
79
+ align-items: stretch;
80
+ min-height: 0;
81
+ max-width: min(280px, calc(100% - 32px));
82
+
83
+ > .pisell-floor-map-layout-edit-panel,
84
+ > .pisell-floor-map-layout-edge-edit-panel {
85
+ flex: 1 1 auto;
86
+ min-height: 0;
87
+ max-height: 100%;
88
+ height: auto;
89
+ box-sizing: border-box;
90
+ }
91
+ }
92
+
93
+ &-edit-panel-wrap-constrained {
94
+ overflow: hidden;
72
95
  }
73
96
 
74
97
  &-edit-panel-wrap--phone-drawer {
@@ -136,6 +159,14 @@ body.pisell-floor-map-layout-fullscreen-host {
136
159
 
137
160
  /** 视口内悬浮层:不随 Transform 缩放平移,与 ViewControls 同级 */
138
161
 
162
+ /**
163
+ * 右下 ViewControls Dock(14px + 56px chrome + 8px 间距),供右侧编辑面板底部留白。
164
+ * 数值与 {@link FLOOR_MAP_VIEWPORT_DOCK_BOTTOM_CLEARANCE} 保持一致。
165
+ */
166
+ &-floor-map-view {
167
+ --fmap-viewport-dock-bottom-clearance: 78px;
168
+ }
169
+
139
170
  &-viewport-overlay {
140
171
  position: absolute;
141
172
  left: 12px;
@@ -3,11 +3,59 @@ import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/
3
3
  const FLOOR_MAP_APPEARANCE_TOKENS = {
4
4
  light: {
5
5
  mode: "light",
6
- fallbackCanvasBackgroundColor: "#F2F4F7"
6
+ fallbackCanvasBackgroundColor: "#F2F4F7",
7
+ edgeStatusStyles: {
8
+ online: {
9
+ stroke: "#12B76A",
10
+ dashed: false
11
+ },
12
+ offline: {
13
+ stroke: "#98A2B3",
14
+ dashed: true
15
+ },
16
+ warning: {
17
+ stroke: "#F79009",
18
+ dashed: false
19
+ },
20
+ unknown: {
21
+ stroke: "#667085",
22
+ dashed: false
23
+ }
24
+ },
25
+ edgeSelectedStroke: "#1570EF",
26
+ edgeGhostStroke: "#84CAFF",
27
+ edgePortLabelBackground: "#FFFFFF",
28
+ edgePortLabelText: "#344054",
29
+ edgePortLabelBorder: "#D0D5DD",
30
+ alignGuideStroke: "#1570EF"
7
31
  },
8
32
  dark: {
9
33
  mode: "dark",
10
- fallbackCanvasBackgroundColor: "#31353d"
34
+ fallbackCanvasBackgroundColor: "#31353d",
35
+ edgeStatusStyles: {
36
+ online: {
37
+ stroke: "#32D583",
38
+ dashed: false
39
+ },
40
+ offline: {
41
+ stroke: "#667085",
42
+ dashed: true
43
+ },
44
+ warning: {
45
+ stroke: "#FDB022",
46
+ dashed: false
47
+ },
48
+ unknown: {
49
+ stroke: "#98A2B3",
50
+ dashed: false
51
+ }
52
+ },
53
+ edgeSelectedStroke: "#53B1FD",
54
+ edgeGhostStroke: "#2E90FA",
55
+ edgePortLabelBackground: "#1D2939",
56
+ edgePortLabelText: "#F2F4F7",
57
+ edgePortLabelBorder: "#475467",
58
+ alignGuideStroke: "#53B1FD"
11
59
  }
12
60
  };
13
61
  /**