@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.
- package/build/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/meta.js +3 -3
- package/build/lowcode/render/default/view.css +1 -1
- package/build/lowcode/render/default/view.js +35 -35
- package/build/lowcode/view.css +1 -1
- package/build/lowcode/view.js +35 -35
- package/es/components/buttonGroupPreview/index.js +8 -4
- package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +207 -49
- package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
- package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
- package/es/components/pisellFloorMapLayout/components/EdgeLayer.js +252 -0
- package/es/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
- package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
- package/es/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
- package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +131 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +5 -4
- package/es/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
- package/es/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
- package/es/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
- package/es/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.js +290 -147
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
- package/es/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +81 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +21 -0
- package/es/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
- package/es/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
- package/es/components/pisellFloorMapLayout/components/NodePortMarkers.js +70 -0
- package/es/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
- package/es/components/pisellFloorMapLayout/components/ViewControls.js +13 -5
- package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
- package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
- package/es/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +340 -0
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +102 -0
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +244 -84
- package/es/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
- package/es/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
- package/es/components/pisellFloorMapLayout/index.d.ts +5 -1
- package/es/components/pisellFloorMapLayout/locales-ja.js +14 -2
- package/es/components/pisellFloorMapLayout/locales-pt.js +14 -2
- package/es/components/pisellFloorMapLayout/locales.js +161 -8
- package/es/components/pisellFloorMapLayout/types.d.ts +86 -4
- package/es/components/pisellFloorMapLayout/types.js +5 -1
- package/es/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
- package/es/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +86 -0
- package/es/components/pisellFloorMapLayout/utils/edgeRouting.js +942 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -1
- package/es/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
- package/es/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +20 -3
- package/es/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
- package/es/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +62 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
- package/es/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +51 -0
- package/es/components/productCard/cartSkuCard/components/BookingItem/index.js +14 -0
- package/es/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
- package/es/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
- package/es/components/productCard/cartSkuCard/index.js +17 -11
- package/es/components/productCard/lineItem/BookingLineItem.js +6 -4
- package/es/components/productCard/lineItem/components/Resources/index.js +45 -0
- package/es/components/productCard/lineItem/components/TimeRange/index.js +64 -0
- package/es/components/productCard/lineItem/index.js +2 -1
- package/es/components/productCard/lineItem/index.less +21 -10
- package/es/index.d.ts +6 -2
- package/es/index.js +6 -2
- package/es/pisell-materials.tw.css +3 -0
- package/lib/components/buttonGroupPreview/index.js +8 -4
- package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +206 -48
- package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.less +33 -2
- package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +50 -2
- package/lib/components/pisellFloorMapLayout/components/EdgeLayer.js +255 -0
- package/lib/components/pisellFloorMapLayout/components/EdgeLayer.less +11 -0
- package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +179 -29
- package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.less +0 -28
- package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.js +134 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapEdgeEditPanel.less +65 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.js +4 -3
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditPanel.less +12 -1
- package/lib/components/pisellFloorMapLayout/components/FloorMapEditQuickActions.js +8 -1
- package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.js +16 -8
- package/lib/components/pisellFloorMapLayout/components/FloorMapOverview.less +69 -17
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.js +287 -144
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbar.less +210 -11
- package/lib/components/pisellFloorMapLayout/components/FloorMapToolbarViewAllModal.js +84 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.d.ts +8 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.js +23 -0
- package/lib/components/pisellFloorMapLayout/components/FloorMapZoneElement.less +74 -0
- package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +3 -1
- package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.js +73 -0
- package/lib/components/pisellFloorMapLayout/components/NodePortMarkers.less +33 -0
- package/lib/components/pisellFloorMapLayout/components/ViewControls.js +12 -4
- package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +2 -0
- package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +2 -1
- package/lib/components/pisellFloorMapLayout/floorMapLayoutConstants.js +1 -1
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeEditing.js +341 -0
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEdgeViewModel.js +103 -0
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapEditState.js +242 -82
- package/lib/components/pisellFloorMapLayout/hooks/useFloorMapTransformMetrics.js +54 -0
- package/lib/components/pisellFloorMapLayout/hooks/useShopFloorPlanSubscription.js +7 -4
- package/lib/components/pisellFloorMapLayout/index.d.ts +5 -1
- package/lib/components/pisellFloorMapLayout/locales-ja.js +14 -2
- package/lib/components/pisellFloorMapLayout/locales-pt.js +14 -2
- package/lib/components/pisellFloorMapLayout/locales.js +161 -8
- package/lib/components/pisellFloorMapLayout/types.d.ts +86 -4
- package/lib/components/pisellFloorMapLayout/types.js +5 -0
- package/lib/components/pisellFloorMapLayout/utils/alignSnap.js +170 -0
- package/lib/components/pisellFloorMapLayout/utils/batchScenePlacementLayout.js +87 -0
- package/lib/components/pisellFloorMapLayout/utils/edgeRouting.js +956 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasDisplay.d.ts +7 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapCanvasStage.js +23 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapConfigMerge.js +11 -2
- package/lib/components/pisellFloorMapLayout/utils/floorMapElementKindUtils.js +21 -2
- package/lib/components/pisellFloorMapLayout/utils/floorMapFallbackRender.js +11 -5
- package/lib/components/pisellFloorMapLayout/utils/floorMapOverviewLayout.js +5 -3
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.d.ts +20 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerDisplay.js +64 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.d.ts +83 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapResourcePickerTypes.js +29 -0
- package/lib/components/pisellFloorMapLayout/utils/floorMapToolbarPalette.js +54 -0
- package/lib/components/productCard/cartSkuCard/components/BookingItem/index.js +17 -0
- package/lib/components/productCard/cartSkuCard/components/BookingItem/index.less +32 -0
- package/lib/components/productCard/cartSkuCard/components/timeRange/index.js +1 -2
- package/lib/components/productCard/cartSkuCard/index.js +17 -11
- package/lib/components/productCard/lineItem/BookingLineItem.js +6 -4
- package/lib/components/productCard/lineItem/components/Resources/index.js +47 -0
- package/lib/components/productCard/lineItem/components/TimeRange/index.js +67 -0
- package/lib/components/productCard/lineItem/index.js +2 -1
- package/lib/components/productCard/lineItem/index.less +21 -10
- package/lib/index.d.ts +6 -2
- package/lib/index.js +11 -0
- package/lib/pisell-materials.tw.css +3 -0
- package/package.json +4 -1
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
|
|
2
2
|
import { _objectWithoutProperties } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectWithoutProperties.js";
|
|
3
|
-
import { FLOOR_MAP_STAGE_ELEMENT_KIND } from "../types.js";
|
|
3
|
+
import { FLOOR_MAP_STAGE_ELEMENT_KIND, FLOOR_MAP_ZONE_ELEMENT_KIND } from "../types.js";
|
|
4
4
|
import { STAGE_DECO_DEFAULT } from "../utils/floorMapStageDefaults.js";
|
|
5
5
|
import { FLOOR_MAP_BUILTIN_SHAPES, getFloorMapBuiltinShapeDef } from "../utils/floorMapBuiltinShapes.js";
|
|
6
|
-
import { getElementKindConfig, isFloorMapBuiltinShapeElementKind, isFloorMapImageElementKind, resolveDataBindingPolicy } from "../utils/floorMapElementKindUtils.js";
|
|
6
|
+
import { FLOOR_MAP_RESOURCE_PLACE_DEFAULT, getElementKindConfig, isFloorMapBuiltinShapeElementKind, isFloorMapImageElementKind, resolveDataBindingPolicy } from "../utils/floorMapElementKindUtils.js";
|
|
7
7
|
import useEngineContext from "../../../hooks/useEngineContext.js";
|
|
8
8
|
import { createTranslationText } from "../../translation/utils.js";
|
|
9
9
|
import { initFloorMapLayoutLocales } from "../utils/floorMapCanvasDisplay.js";
|
|
10
|
+
import { gapToPx } from "../utils/layoutMeasurements.js";
|
|
10
11
|
import { mergeCanvasItems } from "../utils/floorMapConfigMerge.js";
|
|
11
12
|
import { useDraftConfigHistory } from "./useDraftConfigHistory.js";
|
|
12
13
|
import { floorMapViewConfigsEqual, normalizeFloorMapViewConfigFromProp } from "../utils/floorMapViewConfigDiff.js";
|
|
14
|
+
import { computeFloorMapContentStage } from "../utils/floorMapCanvasStage.js";
|
|
15
|
+
import { computeBatchScenePlacementPositions, getPlacementBoundingBox } from "../utils/batchScenePlacementLayout.js";
|
|
13
16
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
14
17
|
import { locales } from "@pisell/utils";
|
|
15
18
|
import { message } from "antd";
|
|
@@ -34,6 +37,11 @@ const BUILTIN_SHAPE_PLACE_DEFAULT = {
|
|
|
34
37
|
height: 96
|
|
35
38
|
};
|
|
36
39
|
const I18N_PLACEMENT_FALLBACK_IMAGE = "pisell-floor-map-layout.placement.fallback-image-name";
|
|
40
|
+
const I18N_PLACEMENT_ZONE_NAME = "pisell-floor-map-layout.zone.unnamed";
|
|
41
|
+
const ZONE_PLACE_DEFAULT = {
|
|
42
|
+
width: 240,
|
|
43
|
+
height: 160
|
|
44
|
+
};
|
|
37
45
|
const GRID_VIS_STORAGE_PREFIX = "pisell-floor-map-layout.grid-visible";
|
|
38
46
|
function getGridVisStorageKey(canvasId) {
|
|
39
47
|
return `${GRID_VIS_STORAGE_PREFIX}:${canvasId}`;
|
|
@@ -54,8 +62,18 @@ function writeStoredGridVisible(canvasId, visible) {
|
|
|
54
62
|
localStorage.setItem(getGridVisStorageKey(canvasId), visible ? "1" : "0");
|
|
55
63
|
} catch (_unused2) {}
|
|
56
64
|
}
|
|
57
|
-
/**
|
|
58
|
-
|
|
65
|
+
/** 与 props 同步 / dirty 基线一致:合并 localStorage 中的网格显隐偏好 */
|
|
66
|
+
function normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp) {
|
|
67
|
+
const baseConfig = normalizeFloorMapViewConfigFromProp(floorMapConfigProp);
|
|
68
|
+
return _objectSpread2(_objectSpread2({}, baseConfig), {}, { canvases: baseConfig.canvases.map((canvas) => {
|
|
69
|
+
var _canvas$mapLayer;
|
|
70
|
+
const stored = readStoredGridVisible(canvas.id);
|
|
71
|
+
if (stored == null) return canvas;
|
|
72
|
+
return _objectSpread2(_objectSpread2({}, canvas), {}, { mapLayer: _objectSpread2(_objectSpread2({}, (_canvas$mapLayer = canvas.mapLayer) !== null && _canvas$mapLayer !== void 0 ? _canvas$mapLayer : {}), {}, { showGrid: stored }) });
|
|
73
|
+
}) });
|
|
74
|
+
}
|
|
75
|
+
/** 复制单个图元时的错位偏移(内容坐标) */
|
|
76
|
+
const DUPLICATE_PLACE_OFFSET = 16;
|
|
59
77
|
function newInstanceId() {
|
|
60
78
|
return `elm_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
61
79
|
}
|
|
@@ -65,9 +83,61 @@ function duplicateBinding(elements, binding, exceptInstanceId) {
|
|
|
65
83
|
return e.instanceId !== exceptInstanceId && ((_e$dataBinding = e.dataBinding) === null || _e$dataBinding === void 0 ? void 0 : _e$dataBinding.dataSourceKey) === binding.dataSourceKey && ((_e$dataBinding2 = e.dataBinding) === null || _e$dataBinding2 === void 0 ? void 0 : _e$dataBinding2.recordId) === binding.recordId;
|
|
66
84
|
});
|
|
67
85
|
}
|
|
86
|
+
/** 解析落点图元的默认像素尺寸(与 applyScenePlacementAtCoords 一致) */
|
|
87
|
+
function resolveScenePlacementDimensions(config, scene) {
|
|
88
|
+
var _scene$builtinShapeKe, _FLOOR_MAP_BUILTIN_SH, _builtinDef$defaultSi, _builtinDef$defaultSi2;
|
|
89
|
+
const defaultPlacementWidth = FLOOR_MAP_RESOURCE_PLACE_DEFAULT.width;
|
|
90
|
+
const defaultPlacementHeight = FLOOR_MAP_RESOURCE_PLACE_DEFAULT.height;
|
|
91
|
+
const defaultDecoSize = 48;
|
|
92
|
+
const kindConfig = getElementKindConfig(config, scene.elementKind);
|
|
93
|
+
const policy = resolveDataBindingPolicy(kindConfig);
|
|
94
|
+
const isStage = scene.elementKind === FLOOR_MAP_STAGE_ELEMENT_KIND;
|
|
95
|
+
const isZone = scene.elementKind === FLOOR_MAP_ZONE_ELEMENT_KIND;
|
|
96
|
+
const isImage = isFloorMapImageElementKind(scene.elementKind);
|
|
97
|
+
const isBuiltinShape = isFloorMapBuiltinShapeElementKind(scene.elementKind);
|
|
98
|
+
const initialBuiltinShapeKey = isBuiltinShape ? (_scene$builtinShapeKe = scene.builtinShapeKey) !== null && _scene$builtinShapeKe !== void 0 ? _scene$builtinShapeKe : (_FLOOR_MAP_BUILTIN_SH = FLOOR_MAP_BUILTIN_SHAPES[0]) === null || _FLOOR_MAP_BUILTIN_SH === void 0 ? void 0 : _FLOOR_MAP_BUILTIN_SH.key : void 0;
|
|
99
|
+
const builtinDef = isBuiltinShape ? getFloorMapBuiltinShapeDef(initialBuiltinShapeKey) : void 0;
|
|
100
|
+
const width = isImage ? IMAGE_PLACE_DEFAULT.width : isZone ? ZONE_PLACE_DEFAULT.width : isStage ? STAGE_DECO_DEFAULT.width : isBuiltinShape ? (_builtinDef$defaultSi = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.width) !== null && _builtinDef$defaultSi !== void 0 ? _builtinDef$defaultSi : BUILTIN_SHAPE_PLACE_DEFAULT.width : defaultPlacementWidth;
|
|
101
|
+
const height = isImage ? IMAGE_PLACE_DEFAULT.height : isZone ? ZONE_PLACE_DEFAULT.height : isStage ? STAGE_DECO_DEFAULT.height : isBuiltinShape ? (_builtinDef$defaultSi2 = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.height) !== null && _builtinDef$defaultSi2 !== void 0 ? _builtinDef$defaultSi2 : BUILTIN_SHAPE_PLACE_DEFAULT.height : defaultPlacementHeight;
|
|
102
|
+
const useDecoSize = policy === "none" && !isStage && !isZone && !isImage && !isBuiltinShape;
|
|
103
|
+
return {
|
|
104
|
+
width: useDecoSize ? defaultDecoSize : width,
|
|
105
|
+
height: useDecoSize ? defaultDecoSize : height,
|
|
106
|
+
useDecoSize,
|
|
107
|
+
isStage,
|
|
108
|
+
isZone,
|
|
109
|
+
isImage,
|
|
110
|
+
isBuiltinShape,
|
|
111
|
+
initialBuiltinShapeKey,
|
|
112
|
+
kindConfig
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function buildPlacedSceneElement(params, dims) {
|
|
116
|
+
const { canvasId, scene, x, y, name, dataBinding } = params;
|
|
117
|
+
const { width, height, isStage, isZone, isImage, isBuiltinShape, initialBuiltinShapeKey, kindConfig } = dims;
|
|
118
|
+
return _objectSpread2(_objectSpread2(_objectSpread2({
|
|
119
|
+
instanceId: newInstanceId(),
|
|
120
|
+
canvasId,
|
|
121
|
+
x: Math.round(x),
|
|
122
|
+
y: Math.round(y),
|
|
123
|
+
name,
|
|
124
|
+
zIndex: isZone ? -100 : isImage || isBuiltinShape ? -5 : 0,
|
|
125
|
+
width: Math.round(width),
|
|
126
|
+
height: Math.round(height),
|
|
127
|
+
elementKind: scene.elementKind,
|
|
128
|
+
shape: isStage || isZone || isImage || isBuiltinShape ? "rect" : kindConfig === null || kindConfig === void 0 ? void 0 : kindConfig.defaultShape,
|
|
129
|
+
dataBinding
|
|
130
|
+
}, isZone ? { isZone: true } : {}), isImage ? { imageUrl: "" } : {}), isBuiltinShape ? { builtinShapeKey: initialBuiltinShapeKey } : {});
|
|
131
|
+
}
|
|
68
132
|
function useFloorMapEditState(params) {
|
|
69
133
|
var _engineCtx$engine, _selectedItem$_sceneE;
|
|
70
|
-
const { floorMapConfigProp, isFloorMapView, itemsProp, cellSizeProp, dataSources, onSave, onDataSourceRecordSave, dataSourceFormColumns, dataSourceRecordForm, dataSourceLabels, layoutPrefix, contentOffsetRef, showDataSourceRecordFormBlock } = params;
|
|
134
|
+
const { floorMapConfigProp, isFloorMapView, itemsProp, cellSizeProp, dataSources, onSave, onDataSourceRecordSave, dataSourceFormColumns, dataSourceRecordForm, dataSourceLabels, layoutPrefix, contentOffsetRef, showDataSourceRecordFormBlock, focusViewportOnBoundsRef } = params;
|
|
135
|
+
const scheduleFocusOnPlacements = useCallback((positions, sizes) => {
|
|
136
|
+
var _focusViewportOnBound;
|
|
137
|
+
const box = getPlacementBoundingBox(positions, sizes);
|
|
138
|
+
if (!box) return;
|
|
139
|
+
focusViewportOnBoundsRef === null || focusViewportOnBoundsRef === void 0 || (_focusViewportOnBound = focusViewportOnBoundsRef.current) === null || _focusViewportOnBound === void 0 || _focusViewportOnBound.call(focusViewportOnBoundsRef, box);
|
|
140
|
+
}, [focusViewportOnBoundsRef]);
|
|
71
141
|
const engineCtx = useEngineContext();
|
|
72
142
|
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";
|
|
73
143
|
/**
|
|
@@ -96,21 +166,32 @@ function useFloorMapEditState(params) {
|
|
|
96
166
|
const config = isFloorMapView ? draftConfig !== null && draftConfig !== void 0 ? draftConfig : floorMapConfigProp : null;
|
|
97
167
|
const configRef = useRef(config);
|
|
98
168
|
configRef.current = config;
|
|
169
|
+
/** 上一次已从 props 写入草稿的配置;用于区分「接口刚下发」与「用户本地改过」 */
|
|
170
|
+
const lastSyncedPropConfigRef = useRef(null);
|
|
99
171
|
useEffect(() => {
|
|
100
|
-
if (!floorMapConfigProp)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
172
|
+
if (!floorMapConfigProp) {
|
|
173
|
+
lastSyncedPropConfigRef.current = null;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const nextConfig = normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp);
|
|
177
|
+
const lastSynced = lastSyncedPropConfigRef.current;
|
|
178
|
+
/**
|
|
179
|
+
* 仅当「自上次 props 同步后用户又改过草稿」时拒绝覆盖:
|
|
180
|
+
* - 接口/订阅首次带回 layout:草稿仍等于上次 props → 必须 replace,否则会空白;
|
|
181
|
+
* - 编辑中落了新图元:草稿已与 lastSynced 不同 → 拒绝旧 props 覆盖。
|
|
182
|
+
*/
|
|
183
|
+
if (draftConfig && lastSynced != null) {
|
|
184
|
+
const propMatchesDraft = floorMapViewConfigsEqual(draftConfig, nextConfig);
|
|
185
|
+
const draftMatchesLastSynced = floorMapViewConfigsEqual(draftConfig, lastSynced);
|
|
186
|
+
if (!propMatchesDraft && !draftMatchesLastSynced) return;
|
|
187
|
+
}
|
|
108
188
|
/**
|
|
109
189
|
* 上游配置变更:直接 replace(不进入历史栈),并清空 undo/redo;
|
|
110
190
|
* 同时清空本地临时保存基线,让 dirty/未保存提示与上游对齐。
|
|
111
191
|
*/
|
|
112
192
|
replaceDraft(nextConfig);
|
|
113
|
-
|
|
193
|
+
lastSyncedPropConfigRef.current = nextConfig;
|
|
194
|
+
setSavedBaselineConfig((prev) => prev != null && floorMapViewConfigsEqual(prev, nextConfig) ? prev : null);
|
|
114
195
|
const enabled = nextConfig.canvases.filter((c) => c.enabled).sort((a, b) => a.order - b.order);
|
|
115
196
|
setCurrentCanvasId((prev) => {
|
|
116
197
|
var _enabled$0$id, _enabled$;
|
|
@@ -120,7 +201,7 @@ function useFloorMapEditState(params) {
|
|
|
120
201
|
/** 当前草稿与上游持久化 `floorMapConfig`(经同等规范化)是否不一致 */
|
|
121
202
|
const isLayoutDirty = useMemo(() => {
|
|
122
203
|
if (!isFloorMapView || !draftConfig || !floorMapConfigProp) return false;
|
|
123
|
-
return !floorMapViewConfigsEqual(draftConfig, savedBaselineConfig !== null && savedBaselineConfig !== void 0 ? savedBaselineConfig :
|
|
204
|
+
return !floorMapViewConfigsEqual(draftConfig, savedBaselineConfig !== null && savedBaselineConfig !== void 0 ? savedBaselineConfig : normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp));
|
|
124
205
|
}, [
|
|
125
206
|
isFloorMapView,
|
|
126
207
|
draftConfig,
|
|
@@ -215,6 +296,40 @@ function useFloorMapEditState(params) {
|
|
|
215
296
|
cellSizeProp
|
|
216
297
|
]);
|
|
217
298
|
const items = isFloorMapView ? mergedItems : itemsProp;
|
|
299
|
+
const getBatchPlacementLayoutContext = useCallback(() => {
|
|
300
|
+
var _config$sceneElements, _config$mapLayer, _canvas$mapLayer2;
|
|
301
|
+
const existingElements = ((_config$sceneElements = config === null || config === void 0 ? void 0 : config.sceneElements) !== null && _config$sceneElements !== void 0 ? _config$sceneElements : []).filter((e) => e.canvasId === currentCanvasId).map((e) => {
|
|
302
|
+
var _e$x, _e$y, _e$width, _e$height;
|
|
303
|
+
return {
|
|
304
|
+
x: Math.round((_e$x = e.x) !== null && _e$x !== void 0 ? _e$x : 0),
|
|
305
|
+
y: Math.round((_e$y = e.y) !== null && _e$y !== void 0 ? _e$y : 0),
|
|
306
|
+
width: Math.round((_e$width = e.width) !== null && _e$width !== void 0 ? _e$width : FLOOR_MAP_RESOURCE_PLACE_DEFAULT.width),
|
|
307
|
+
height: Math.round((_e$height = e.height) !== null && _e$height !== void 0 ? _e$height : FLOOR_MAP_RESOURCE_PLACE_DEFAULT.height)
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
const canvas = config === null || config === void 0 ? void 0 : config.canvases.find((c) => c.id === currentCanvasId);
|
|
311
|
+
const mapLayer = _objectSpread2(_objectSpread2({}, (_config$mapLayer = config === null || config === void 0 ? void 0 : config.mapLayer) !== null && _config$mapLayer !== void 0 ? _config$mapLayer : {}), (_canvas$mapLayer2 = canvas === null || canvas === void 0 ? void 0 : canvas.mapLayer) !== null && _canvas$mapLayer2 !== void 0 ? _canvas$mapLayer2 : {});
|
|
312
|
+
const padSingle = typeof mapLayer.boundingPadding === "number" ? mapLayer.boundingPadding : 56;
|
|
313
|
+
const stage = computeFloorMapContentStage({
|
|
314
|
+
items: mergedItems,
|
|
315
|
+
cellSize: cellSizeProp !== null && cellSizeProp !== void 0 ? cellSizeProp : 64,
|
|
316
|
+
itemGap: gapToPx(mapLayer.gap),
|
|
317
|
+
itemUnit: "pixel",
|
|
318
|
+
boundingPadding: padSingle,
|
|
319
|
+
preferPixelBoundingBox: true
|
|
320
|
+
});
|
|
321
|
+
return {
|
|
322
|
+
existingElements,
|
|
323
|
+
contentWidth: stage.contentWidth,
|
|
324
|
+
contentHeight: stage.contentHeight,
|
|
325
|
+
boundingPadding: padSingle
|
|
326
|
+
};
|
|
327
|
+
}, [
|
|
328
|
+
config,
|
|
329
|
+
currentCanvasId,
|
|
330
|
+
mergedItems,
|
|
331
|
+
cellSizeProp
|
|
332
|
+
]);
|
|
218
333
|
const updateDraftSceneElement = useCallback((instanceId, patch) => {
|
|
219
334
|
commitDraft((prev) => {
|
|
220
335
|
var _prev$sceneElements2, _prev$sceneElements3;
|
|
@@ -243,43 +358,15 @@ function useFloorMapEditState(params) {
|
|
|
243
358
|
* @returns 是否已成功写入草稿(校验失败时为 false)
|
|
244
359
|
*/
|
|
245
360
|
const applyScenePlacementAtCoords = useCallback((contentX, contentY, scene) => {
|
|
246
|
-
var _kindConfig$allowedDa, _ref, _scene$dataSourceKey
|
|
361
|
+
var _kindConfig$allowedDa, _ref, _scene$dataSourceKey;
|
|
247
362
|
if (!config || !currentCanvasId) return false;
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
const defaultDecoSize = 48;
|
|
251
|
-
const kindConfig = getElementKindConfig(config, scene.elementKind);
|
|
363
|
+
const dims = resolveScenePlacementDimensions(config, scene);
|
|
364
|
+
const kindConfig = dims.kindConfig;
|
|
252
365
|
const policy = resolveDataBindingPolicy(kindConfig);
|
|
253
366
|
const allKeys = Object.keys(dataSources !== null && dataSources !== void 0 ? dataSources : {});
|
|
254
367
|
const allowedKeys = (kindConfig === null || kindConfig === void 0 || (_kindConfig$allowedDa = kindConfig.allowedDataSourceKeys) === null || _kindConfig$allowedDa === void 0 ? void 0 : _kindConfig$allowedDa.length) ? kindConfig.allowedDataSourceKeys.filter((k) => allKeys.includes(k)) : allKeys;
|
|
255
368
|
const pickKey = (_ref = (_scene$dataSourceKey = scene.dataSourceKey) !== null && _scene$dataSourceKey !== void 0 ? _scene$dataSourceKey : allowedKeys[0]) !== null && _ref !== void 0 ? _ref : allKeys[0];
|
|
256
369
|
const recordIdsToPlace = scene.recordIds && scene.recordIds.length > 0 ? scene.recordIds : scene.recordId ? [scene.recordId] : [];
|
|
257
|
-
const isStage = scene.elementKind === FLOOR_MAP_STAGE_ELEMENT_KIND;
|
|
258
|
-
const isImage = isFloorMapImageElementKind(scene.elementKind);
|
|
259
|
-
const isBuiltinShape = isFloorMapBuiltinShapeElementKind(scene.elementKind);
|
|
260
|
-
/**
|
|
261
|
-
* 内置图形 kind 的初始 `builtinShapeKey`:优先用侧栏 Select 预选的 key
|
|
262
|
-
* (`scene.builtinShapeKey`,由 toolbar 写入 placeMode / drag payload 透传),
|
|
263
|
-
* 未预选时回退为枚举首项,避免空白占位。
|
|
264
|
-
*/
|
|
265
|
-
const initialBuiltinShapeKey = isBuiltinShape ? (_scene$builtinShapeKe = scene.builtinShapeKey) !== null && _scene$builtinShapeKe !== void 0 ? _scene$builtinShapeKe : (_FLOOR_MAP_BUILTIN_SH = FLOOR_MAP_BUILTIN_SHAPES[0]) === null || _FLOOR_MAP_BUILTIN_SH === void 0 ? void 0 : _FLOOR_MAP_BUILTIN_SH.key : void 0;
|
|
266
|
-
const builtinDef = isBuiltinShape ? getFloorMapBuiltinShapeDef(initialBuiltinShapeKey) : void 0;
|
|
267
|
-
const w = isImage ? IMAGE_PLACE_DEFAULT.width : isStage ? STAGE_DECO_DEFAULT.width : isBuiltinShape ? (_builtinDef$defaultSi = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.width) !== null && _builtinDef$defaultSi !== void 0 ? _builtinDef$defaultSi : BUILTIN_SHAPE_PLACE_DEFAULT.width : defaultPlacementWidth;
|
|
268
|
-
const h = isImage ? IMAGE_PLACE_DEFAULT.height : isStage ? STAGE_DECO_DEFAULT.height : isBuiltinShape ? (_builtinDef$defaultSi2 = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.height) !== null && _builtinDef$defaultSi2 !== void 0 ? _builtinDef$defaultSi2 : BUILTIN_SHAPE_PLACE_DEFAULT.height : defaultPlacementHeight;
|
|
269
|
-
const useDecoSize = policy === "none" && scene.elementKind !== "stage" && !isImage && !isBuiltinShape;
|
|
270
|
-
const buildOneElement = (dataBinding, x, y, name) => _objectSpread2(_objectSpread2({
|
|
271
|
-
instanceId: newInstanceId(),
|
|
272
|
-
canvasId: currentCanvasId,
|
|
273
|
-
x,
|
|
274
|
-
y,
|
|
275
|
-
name,
|
|
276
|
-
zIndex: isImage || isBuiltinShape ? -5 : 0,
|
|
277
|
-
width: useDecoSize ? defaultDecoSize : w,
|
|
278
|
-
height: useDecoSize ? defaultDecoSize : h,
|
|
279
|
-
elementKind: scene.elementKind,
|
|
280
|
-
shape: isStage || isImage || isBuiltinShape ? "rect" : kindConfig === null || kindConfig === void 0 ? void 0 : kindConfig.defaultShape,
|
|
281
|
-
dataBinding
|
|
282
|
-
}, isImage ? { imageUrl: "" } : {}), isBuiltinShape ? { builtinShapeKey: initialBuiltinShapeKey } : {});
|
|
283
370
|
let dataBinding;
|
|
284
371
|
if (policy !== "none" && pickKey) {
|
|
285
372
|
var _dataSources$pickKey;
|
|
@@ -309,10 +396,9 @@ function useFloorMapEditState(params) {
|
|
|
309
396
|
}
|
|
310
397
|
dataBinding = cand;
|
|
311
398
|
} else {
|
|
312
|
-
const
|
|
399
|
+
const pending = [];
|
|
313
400
|
let skippedDup = 0;
|
|
314
401
|
let skippedMissing = 0;
|
|
315
|
-
let placeIndex = 0;
|
|
316
402
|
const seenInBatch = /* @__PURE__ */ new Set();
|
|
317
403
|
recordIdsToPlace.forEach((rid) => {
|
|
318
404
|
var _row$name;
|
|
@@ -331,46 +417,78 @@ function useFloorMapEditState(params) {
|
|
|
331
417
|
}
|
|
332
418
|
seenInBatch.add(rid);
|
|
333
419
|
const row = record;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
420
|
+
pending.push({
|
|
421
|
+
binding: cand,
|
|
422
|
+
name: String((_row$name = row === null || row === void 0 ? void 0 : row.name) !== null && _row$name !== void 0 ? _row$name : rid)
|
|
423
|
+
});
|
|
337
424
|
});
|
|
338
425
|
if (skippedDup > 0) message.warning(`已跳过 ${skippedDup} 条已在平面图中绑定的记录`);
|
|
339
426
|
if (skippedMissing > 0) message.warning(`有 ${skippedMissing} 条记录不存在,已跳过`);
|
|
340
|
-
if (
|
|
427
|
+
if (pending.length === 0) {
|
|
341
428
|
message.warning("没有可落位的记录");
|
|
342
429
|
return false;
|
|
343
430
|
}
|
|
431
|
+
const sizes = pending.map(() => ({
|
|
432
|
+
width: dims.width,
|
|
433
|
+
height: dims.height
|
|
434
|
+
}));
|
|
435
|
+
const positions = computeBatchScenePlacementPositions(sizes, getBatchPlacementLayoutContext());
|
|
436
|
+
const newEls = pending.map((p, i) => buildPlacedSceneElement({
|
|
437
|
+
canvasId: currentCanvasId,
|
|
438
|
+
scene,
|
|
439
|
+
x: positions[i].x,
|
|
440
|
+
y: positions[i].y,
|
|
441
|
+
name: p.name,
|
|
442
|
+
dataBinding: p.binding
|
|
443
|
+
}, dims));
|
|
344
444
|
commitDraft((prev) => {
|
|
345
445
|
var _prev$sceneElements4;
|
|
346
446
|
return prev ? _objectSpread2(_objectSpread2({}, prev), {}, { sceneElements: [...(_prev$sceneElements4 = prev.sceneElements) !== null && _prev$sceneElements4 !== void 0 ? _prev$sceneElements4 : [], ...newEls] }) : prev;
|
|
347
447
|
});
|
|
448
|
+
scheduleFocusOnPlacements(positions, sizes);
|
|
348
449
|
return true;
|
|
349
450
|
}
|
|
350
451
|
}
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
452
|
+
const newEl = buildPlacedSceneElement({
|
|
453
|
+
canvasId: currentCanvasId,
|
|
454
|
+
scene,
|
|
455
|
+
x: contentX,
|
|
456
|
+
y: contentY,
|
|
457
|
+
name: (() => {
|
|
458
|
+
var _kindConfig$defaultPr, _kindConfig$defaultPr2;
|
|
459
|
+
if (dims.isStage) return STAGE_DECO_DEFAULT.name;
|
|
460
|
+
if (dims.isZone) return locales.getText(I18N_PLACEMENT_ZONE_NAME);
|
|
461
|
+
if (dims.isImage) return locales.getText(I18N_PLACEMENT_FALLBACK_IMAGE);
|
|
462
|
+
const db = dataBinding;
|
|
463
|
+
const rid = recordIdsToPlace[0];
|
|
464
|
+
if (db && rid) {
|
|
465
|
+
var _dataSources$db$dataS, _row$name2;
|
|
466
|
+
const row = dataSources === null || dataSources === void 0 || (_dataSources$db$dataS = dataSources[db.dataSourceKey]) === null || _dataSources$db$dataS === void 0 ? void 0 : _dataSources$db$dataS.find((r) => r.id === rid);
|
|
467
|
+
return String((_row$name2 = row === null || row === void 0 ? void 0 : row.name) !== null && _row$name2 !== void 0 ? _row$name2 : rid);
|
|
468
|
+
}
|
|
469
|
+
return (_kindConfig$defaultPr = kindConfig === null || kindConfig === void 0 || (_kindConfig$defaultPr2 = kindConfig.defaultPresentation) === null || _kindConfig$defaultPr2 === void 0 ? void 0 : _kindConfig$defaultPr2.title) !== null && _kindConfig$defaultPr !== void 0 ? _kindConfig$defaultPr : "";
|
|
470
|
+
})(),
|
|
471
|
+
dataBinding
|
|
472
|
+
}, dims);
|
|
365
473
|
commitDraft((prev) => {
|
|
366
474
|
var _prev$sceneElements5;
|
|
367
475
|
return prev ? _objectSpread2(_objectSpread2({}, prev), {}, { sceneElements: [...(_prev$sceneElements5 = prev.sceneElements) !== null && _prev$sceneElements5 !== void 0 ? _prev$sceneElements5 : [], newEl] }) : prev;
|
|
368
476
|
});
|
|
477
|
+
scheduleFocusOnPlacements([{
|
|
478
|
+
x: contentX,
|
|
479
|
+
y: contentY
|
|
480
|
+
}], [{
|
|
481
|
+
width: dims.width,
|
|
482
|
+
height: dims.height
|
|
483
|
+
}]);
|
|
369
484
|
return true;
|
|
370
485
|
}, [
|
|
371
486
|
config,
|
|
372
487
|
currentCanvasId,
|
|
373
|
-
dataSources
|
|
488
|
+
dataSources,
|
|
489
|
+
getBatchPlacementLayoutContext,
|
|
490
|
+
commitDraft,
|
|
491
|
+
scheduleFocusOnPlacements
|
|
374
492
|
]);
|
|
375
493
|
const handleCanvasPlaceClick = useCallback((e) => {
|
|
376
494
|
if (!placeMode || placeMode.type !== "scene" || !config || !currentCanvasId) return;
|
|
@@ -386,8 +504,48 @@ function useFloorMapEditState(params) {
|
|
|
386
504
|
]);
|
|
387
505
|
/** 从左侧图元栏拖拽到画布落位(与点击落点规则一致) */
|
|
388
506
|
const placeSceneElementFromPaletteDrop = useCallback((contentX, contentY, scene) => {
|
|
389
|
-
|
|
507
|
+
const ok = applyScenePlacementAtCoords(contentX, contentY, scene);
|
|
508
|
+
if (ok) setPlaceMode(null);
|
|
509
|
+
return ok;
|
|
390
510
|
}, [applyScenePlacementAtCoords]);
|
|
511
|
+
/**
|
|
512
|
+
* 批量落点(弹窗多选、侧栏多选数据行等):在画布右侧空白区按近方阵网格排列。
|
|
513
|
+
*/
|
|
514
|
+
const bulkPlacePaletteItems = useCallback((items) => {
|
|
515
|
+
if (!items.length || !config || !currentCanvasId) return;
|
|
516
|
+
const scenes = items.map((item) => _objectSpread2({
|
|
517
|
+
type: "scene",
|
|
518
|
+
elementKind: item.elementKind
|
|
519
|
+
}, item.builtinShapeKey ? { builtinShapeKey: item.builtinShapeKey } : {}));
|
|
520
|
+
const dimsList = scenes.map((scene) => resolveScenePlacementDimensions(config, scene));
|
|
521
|
+
const sizes = dimsList.map((d) => ({
|
|
522
|
+
width: d.width,
|
|
523
|
+
height: d.height
|
|
524
|
+
}));
|
|
525
|
+
const positions = computeBatchScenePlacementPositions(sizes, getBatchPlacementLayoutContext());
|
|
526
|
+
const newEls = scenes.map((scene, i) => {
|
|
527
|
+
var _ref2, _dimsList$i$kindConfi, _dimsList$i$kindConfi2, _dimsList$i$kindConfi3;
|
|
528
|
+
return buildPlacedSceneElement({
|
|
529
|
+
canvasId: currentCanvasId,
|
|
530
|
+
scene,
|
|
531
|
+
x: positions[i].x,
|
|
532
|
+
y: positions[i].y,
|
|
533
|
+
name: (_ref2 = (_dimsList$i$kindConfi = (_dimsList$i$kindConfi2 = dimsList[i].kindConfig) === null || _dimsList$i$kindConfi2 === void 0 ? void 0 : _dimsList$i$kindConfi2.label) !== null && _dimsList$i$kindConfi !== void 0 ? _dimsList$i$kindConfi : (_dimsList$i$kindConfi3 = dimsList[i].kindConfig) === null || _dimsList$i$kindConfi3 === void 0 || (_dimsList$i$kindConfi3 = _dimsList$i$kindConfi3.defaultPresentation) === null || _dimsList$i$kindConfi3 === void 0 ? void 0 : _dimsList$i$kindConfi3.title) !== null && _ref2 !== void 0 ? _ref2 : scene.elementKind
|
|
534
|
+
}, dimsList[i]);
|
|
535
|
+
});
|
|
536
|
+
commitDraft((prev) => {
|
|
537
|
+
var _prev$sceneElements6;
|
|
538
|
+
return prev ? _objectSpread2(_objectSpread2({}, prev), {}, { sceneElements: [...(_prev$sceneElements6 = prev.sceneElements) !== null && _prev$sceneElements6 !== void 0 ? _prev$sceneElements6 : [], ...newEls] }) : prev;
|
|
539
|
+
});
|
|
540
|
+
scheduleFocusOnPlacements(positions, sizes);
|
|
541
|
+
setPlaceMode(null);
|
|
542
|
+
}, [
|
|
543
|
+
config,
|
|
544
|
+
currentCanvasId,
|
|
545
|
+
getBatchPlacementLayoutContext,
|
|
546
|
+
commitDraft,
|
|
547
|
+
scheduleFocusOnPlacements
|
|
548
|
+
]);
|
|
391
549
|
const handleSave = useCallback(() => {
|
|
392
550
|
if (!draftConfig || !onSave) return;
|
|
393
551
|
setSaving(true);
|
|
@@ -414,16 +572,13 @@ function useFloorMapEditState(params) {
|
|
|
414
572
|
const discardDraft = useCallback(() => {
|
|
415
573
|
if (!floorMapConfigProp) {
|
|
416
574
|
replaceDraft(null);
|
|
575
|
+
lastSyncedPropConfigRef.current = null;
|
|
417
576
|
setSavedBaselineConfig(null);
|
|
418
577
|
return;
|
|
419
578
|
}
|
|
420
|
-
const
|
|
421
|
-
replaceDraft(
|
|
422
|
-
|
|
423
|
-
const stored = readStoredGridVisible(canvas.id);
|
|
424
|
-
if (stored == null) return canvas;
|
|
425
|
-
return _objectSpread2(_objectSpread2({}, canvas), {}, { mapLayer: _objectSpread2(_objectSpread2({}, (_canvas$mapLayer2 = canvas.mapLayer) !== null && _canvas$mapLayer2 !== void 0 ? _canvas$mapLayer2 : {}), {}, { showGrid: stored }) });
|
|
426
|
-
}) }));
|
|
579
|
+
const nextConfig = normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp);
|
|
580
|
+
replaceDraft(nextConfig);
|
|
581
|
+
lastSyncedPropConfigRef.current = nextConfig;
|
|
427
582
|
setSavedBaselineConfig(null);
|
|
428
583
|
}, [floorMapConfigProp, replaceDraft]);
|
|
429
584
|
/** 切换当前画布草稿中的 mapLayer.showGrid(随布局保存持久化) */
|
|
@@ -460,12 +615,15 @@ function useFloorMapEditState(params) {
|
|
|
460
615
|
const handleEditPanelDelete = useCallback(() => {
|
|
461
616
|
if (!selectedId) return;
|
|
462
617
|
commitDraft((prev) => {
|
|
463
|
-
var _prev$
|
|
618
|
+
var _prev$sceneElements7, _prev$edges;
|
|
464
619
|
if (!prev) return prev;
|
|
465
|
-
return _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
620
|
+
return _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
621
|
+
sceneElements: ((_prev$sceneElements7 = prev.sceneElements) !== null && _prev$sceneElements7 !== void 0 ? _prev$sceneElements7 : []).filter((e) => e.instanceId !== selectedId),
|
|
622
|
+
edges: ((_prev$edges = prev.edges) !== null && _prev$edges !== void 0 ? _prev$edges : []).filter((edge) => edge.sourceId !== selectedId && edge.targetId !== selectedId)
|
|
623
|
+
});
|
|
466
624
|
});
|
|
467
625
|
setSelectedId(null);
|
|
468
|
-
}, [selectedId]);
|
|
626
|
+
}, [selectedId, commitDraft]);
|
|
469
627
|
/** 与编辑侧栏锁定按钮同源:切换 `layoutTransformLocked` */
|
|
470
628
|
const toggleSelectedLayoutLock = useCallback(() => {
|
|
471
629
|
var _configRef$current2;
|
|
@@ -477,21 +635,21 @@ function useFloorMapEditState(params) {
|
|
|
477
635
|
* 复制选中图元:新实例 + 位移,**清除 dataBinding**(避免与侧栏一致的「同一记录不可重复绑定」冲突)。
|
|
478
636
|
*/
|
|
479
637
|
const duplicateSelectedElement = useCallback(() => {
|
|
480
|
-
var _prev$
|
|
638
|
+
var _prev$sceneElements8, _el$x, _el$y, _prev$sceneElements9;
|
|
481
639
|
if (!selectedId) return;
|
|
482
640
|
const prev = configRef.current;
|
|
483
641
|
if (!prev) return;
|
|
484
|
-
const el = ((_prev$
|
|
642
|
+
const el = ((_prev$sceneElements8 = prev.sceneElements) !== null && _prev$sceneElements8 !== void 0 ? _prev$sceneElements8 : []).find((e) => e.instanceId === selectedId);
|
|
485
643
|
if (!el) return;
|
|
486
644
|
const newId = newInstanceId();
|
|
487
645
|
const copy = _objectSpread2(_objectSpread2({}, el), {}, {
|
|
488
646
|
instanceId: newId,
|
|
489
|
-
x: Math.round(((_el$x = el.x) !== null && _el$x !== void 0 ? _el$x : 0) +
|
|
490
|
-
y: Math.round(((_el$y = el.y) !== null && _el$y !== void 0 ? _el$y : 0) +
|
|
647
|
+
x: Math.round(((_el$x = el.x) !== null && _el$x !== void 0 ? _el$x : 0) + DUPLICATE_PLACE_OFFSET),
|
|
648
|
+
y: Math.round(((_el$y = el.y) !== null && _el$y !== void 0 ? _el$y : 0) + DUPLICATE_PLACE_OFFSET),
|
|
491
649
|
dataBinding: void 0,
|
|
492
650
|
layoutTransformLocked: false
|
|
493
651
|
});
|
|
494
|
-
commitDraft(_objectSpread2(_objectSpread2({}, prev), {}, { sceneElements: [...(_prev$
|
|
652
|
+
commitDraft(_objectSpread2(_objectSpread2({}, prev), {}, { sceneElements: [...(_prev$sceneElements9 = prev.sceneElements) !== null && _prev$sceneElements9 !== void 0 ? _prev$sceneElements9 : [], copy] }));
|
|
495
653
|
setSelectedId(newId);
|
|
496
654
|
}, [selectedId]);
|
|
497
655
|
const selectedItem = selectedId ? mergedItems.find((m) => m.id === selectedId) : null;
|
|
@@ -515,6 +673,7 @@ function useFloorMapEditState(params) {
|
|
|
515
673
|
handleSave,
|
|
516
674
|
discardDraft,
|
|
517
675
|
placeSceneElementFromPaletteDrop,
|
|
676
|
+
bulkPlacePaletteItems,
|
|
518
677
|
editPanelParams: selectedItem && config && selectedId && !((_selectedItem$_sceneE = selectedItem._sceneElement) === null || _selectedItem$_sceneE === void 0 ? void 0 : _selectedItem$_sceneE.layoutTransformLocked) ? {
|
|
519
678
|
itemId: selectedId,
|
|
520
679
|
sceneElement: selectedItem._sceneElement,
|
|
@@ -537,7 +696,8 @@ function useFloorMapEditState(params) {
|
|
|
537
696
|
undoDraft,
|
|
538
697
|
redoDraft,
|
|
539
698
|
canUndo,
|
|
540
|
-
canRedo
|
|
699
|
+
canRedo,
|
|
700
|
+
commitDraft
|
|
541
701
|
};
|
|
542
702
|
}
|
|
543
703
|
//#endregion
|
|
@@ -346,6 +346,59 @@ function useFloorMapTransformMetrics(params) {
|
|
|
346
346
|
/** 让"进入伪全屏后自动 fit"的 effect 能拿到最新的 fitBounds 实现 */
|
|
347
347
|
fitBoundsRef.current = fitBounds;
|
|
348
348
|
/**
|
|
349
|
+
* 将视口平移/缩放至能看见指定内容区包围盒(场景坐标,与 sceneElement x/y 一致)。
|
|
350
|
+
* 批量落点后调用;视口锁定时跳过。
|
|
351
|
+
*/
|
|
352
|
+
const focusContentBounds = useCallback((bounds) => {
|
|
353
|
+
var _ref, _cur$scale;
|
|
354
|
+
if (viewportLockedRef.current || !bounds) return false;
|
|
355
|
+
const ctx = transformRef.current;
|
|
356
|
+
const container = containerRef.current;
|
|
357
|
+
if (!ctx || !container) return false;
|
|
358
|
+
const wrapper = container.querySelector(".react-transform-wrapper");
|
|
359
|
+
if (!wrapper) return false;
|
|
360
|
+
const wEl = wrapper;
|
|
361
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
362
|
+
const layoutW = wEl.clientWidth > 0 ? wEl.clientWidth : wrapperRect.width;
|
|
363
|
+
const layoutH = wEl.clientHeight > 0 ? wEl.clientHeight : wrapperRect.height;
|
|
364
|
+
if (layoutW <= 0 || layoutH <= 0) return false;
|
|
365
|
+
const ox = contentOffsetRef.current.x;
|
|
366
|
+
const oy = contentOffsetRef.current.y;
|
|
367
|
+
const visMinL = bounds.minLeft + ox;
|
|
368
|
+
const visMinT = bounds.minTop + oy;
|
|
369
|
+
const visMaxR = bounds.maxRight + ox;
|
|
370
|
+
const visMaxB = bounds.maxBottom + oy;
|
|
371
|
+
const bw = Math.max(1, visMaxR - visMinL);
|
|
372
|
+
const bh = Math.max(1, visMaxB - visMinT);
|
|
373
|
+
const edgePx = 48;
|
|
374
|
+
const availW = Math.max(1, layoutW - 2 * edgePx);
|
|
375
|
+
const availH = Math.max(1, layoutH - 2 * edgePx);
|
|
376
|
+
const clampFitScale = (raw) => {
|
|
377
|
+
var _zoom$min3, _zoom$max3;
|
|
378
|
+
return Math.max((_zoom$min3 = zoom.min) !== null && _zoom$min3 !== void 0 ? _zoom$min3 : .5, Math.min(raw, (_zoom$max3 = zoom.max) !== null && _zoom$max3 !== void 0 ? _zoom$max3 : 2));
|
|
379
|
+
};
|
|
380
|
+
const cur = lastTransformRef.current;
|
|
381
|
+
const curScale = (_ref = (_cur$scale = cur === null || cur === void 0 ? void 0 : cur.scale) !== null && _cur$scale !== void 0 ? _cur$scale : zoomConfig.initialScale) !== null && _ref !== void 0 ? _ref : 1;
|
|
382
|
+
const rawFit = Math.min(availW / bw, availH / bh);
|
|
383
|
+
let nextScale = curScale;
|
|
384
|
+
if (bw * curScale > availW || bh * curScale > availH) nextScale = clampFitScale(rawFit);
|
|
385
|
+
const bboxCx = visMinL + bw / 2;
|
|
386
|
+
const bboxCy = visMinT + bh / 2;
|
|
387
|
+
const x = layoutW / 2 - bboxCx * nextScale;
|
|
388
|
+
const y = layoutH / 2 - bboxCy * nextScale;
|
|
389
|
+
clearFitBoundsTweenHold();
|
|
390
|
+
lastFitSnapshotRef.current = null;
|
|
391
|
+
setIsAtFitBounds(false);
|
|
392
|
+
ctx.setTransform(x, y, nextScale);
|
|
393
|
+
return true;
|
|
394
|
+
}, [
|
|
395
|
+
clearFitBoundsTweenHold,
|
|
396
|
+
contentOffsetRef,
|
|
397
|
+
transformRef,
|
|
398
|
+
zoom,
|
|
399
|
+
zoomConfig.initialScale
|
|
400
|
+
]);
|
|
401
|
+
/**
|
|
349
402
|
* autoFitOnMount:每个画布在「有图元且 content 尺寸已按包围盒算好」后执行一次 fitBounds。
|
|
350
403
|
* 避免首帧 items 仍为空时用占位尺寸 fit 完并标记 done,导致异步图元加载后不再适配。
|
|
351
404
|
*/
|
|
@@ -693,6 +746,7 @@ function useFloorMapTransformMetrics(params) {
|
|
|
693
746
|
isFullscreen,
|
|
694
747
|
toggleFullscreen,
|
|
695
748
|
fitBounds,
|
|
749
|
+
focusContentBounds,
|
|
696
750
|
isAtFitBounds,
|
|
697
751
|
notifyTransformed,
|
|
698
752
|
persistCurrentViewport,
|
|
@@ -11,11 +11,15 @@ function useShopFloorPlanSubscription(params) {
|
|
|
11
11
|
onDetailRef.current = onDetail;
|
|
12
12
|
const onLoadErrorRef = useRef(onLoadError);
|
|
13
13
|
onLoadErrorRef.current = onLoadError;
|
|
14
|
+
const ensureByCodeRef = useRef(ensureByCode);
|
|
15
|
+
ensureByCodeRef.current = ensureByCode;
|
|
16
|
+
const unsubscribeQueryRef = useRef(unsubscribeQuery);
|
|
17
|
+
unsubscribeQueryRef.current = unsubscribeQuery;
|
|
14
18
|
useEffect(() => {
|
|
15
19
|
if (!enabled) return;
|
|
16
20
|
let cancelled = false;
|
|
17
21
|
const subId = subscriberId;
|
|
18
|
-
|
|
22
|
+
ensureByCodeRef.current(code, {
|
|
19
23
|
osServer,
|
|
20
24
|
subscriberId: subId,
|
|
21
25
|
callback: (res) => {
|
|
@@ -35,14 +39,13 @@ function useShopFloorPlanSubscription(params) {
|
|
|
35
39
|
});
|
|
36
40
|
return () => {
|
|
37
41
|
cancelled = true;
|
|
38
|
-
|
|
42
|
+
unsubscribeQueryRef.current(subId);
|
|
39
43
|
};
|
|
44
|
+
/** ensureByCode / unsubscribeQuery 走 ref,避免调用方内联函数导致反复退订再订阅 */
|
|
40
45
|
}, [
|
|
41
46
|
enabled,
|
|
42
47
|
code,
|
|
43
48
|
subscriberId,
|
|
44
|
-
ensureByCode,
|
|
45
|
-
unsubscribeQuery,
|
|
46
49
|
osServer
|
|
47
50
|
]);
|
|
48
51
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FloorMapResourcePickerSlotProps, PisellCardPickerCardMeta, PisellCardPickerCategoryConfig, PisellCardPickerCategoryLevelConfig, PisellCardPickerCategoryMode, PisellCardPickerCategoryPath, PisellCardPickerItem, PisellCardPickerMode, parseNestedPathSegments } from "./utils/floorMapResourcePickerTypes.js";
|
|
2
|
+
import { DataSourceFormColumn, FLOOR_MAP_BUILTIN_SHAPE_ELEMENT_KIND, FLOOR_MAP_IMAGE_ELEMENT_KIND, FLOOR_MAP_STAGE_ELEMENT_KIND, FLOOR_MAP_ZONE_ELEMENT_KIND, FloorMapBackgroundType, FloorMapCanvas, FloorMapCanvasNameI18n, FloorMapCanvasUiConfig, FloorMapControlsConfig, FloorMapDataSourceRecordFormContent, FloorMapDataSources, FloorMapEdge, FloorMapEdgeAnchor, FloorMapEdgeStatus, FloorMapElementDataBindingPolicy, FloorMapElementDefaultPresentation, FloorMapElementKindCategory, FloorMapElementKindConfig, FloorMapFullscreenMode, FloorMapGridLayoutConfig, FloorMapItemBase, FloorMapItemShape, FloorMapItemUnit, FloorMapLayerConfig, FloorMapLayoutContextValue, FloorMapLayoutMode, FloorMapMergedItem, FloorMapPanBoundary, FloorMapPanConfig, FloorMapRecordFormRenderContext, FloorMapRenderOptions, FloorMapSceneElement, FloorMapSceneElementDataBinding, FloorMapTextSlot, FloorMapViewConfig, FloorMapViewportOverlayRenderArgs, FloorMapZoomConfig, PisellFloorMapLayoutProps, PisellFloorMapLayoutRef } from "./types.js";
|
|
2
3
|
import { PisellFloorMapLayout } from "./PisellFloorMapLayout.js";
|
|
3
4
|
import { renderFloorMapFallbackPlaceholder } from "./utils/floorMapFallbackRender.js";
|
|
4
5
|
import { isFloorMapBuiltinShapeElementKind, isFloorMapImageElementKind } from "./utils/floorMapElementKindUtils.js";
|
|
@@ -13,6 +14,9 @@ import { sceneElementsToShopLayout, shopLayoutToSceneElements } from "./shopFloo
|
|
|
13
14
|
import { WrapFloorMapOnSaveWithRemotePersistParams, wrapFloorMapOnSaveWithRemotePersist } from "./utils/floorMapRemotePersist.js";
|
|
14
15
|
import { EMPTY_FLOOR_MAP_LAYOUT_CONTEXT, FloorMapLayoutProvider, FloorMapLayoutProviderProps, useFloorMapLayoutContext } from "./context/FloorMapLayoutContext.js";
|
|
15
16
|
import { mergeFloorMapLayoutPropsFromContext } from "./context/mergeFloorMapLayoutContext.js";
|
|
17
|
+
import { FloorMapResourcePickerRecord, floorMapResourcePickerRecordSearchText, getFloorMapCardPickerCategoryConfig, getFloorMapResourcePickerCardMeta } from "./utils/floorMapResourcePickerDisplay.js";
|
|
18
|
+
import { initFloorMapLayoutLocales } from "./utils/floorMapCanvasDisplay.js";
|
|
16
19
|
import { FloorMapImageElement } from "./components/FloorMapImageElement.js";
|
|
17
20
|
import { FloorMapBuiltinShapeElement } from "./components/FloorMapBuiltinShapeElement.js";
|
|
21
|
+
import { FloorMapZoneElement } from "./components/FloorMapZoneElement.js";
|
|
18
22
|
import { FigmaTableCardItem, FigmaTableStatus, getFigmaTableCardFromMerged, getRenderItemByKindRoundTable, getRenderItemByKindTable, renderFigmaStyleRoundTableCard, renderFigmaStyleTableCard } from "./components/FigmaTableCard.js";
|