Revert "fix: preserve PSD super lock mask editing"

This reverts commit 6d60d53910cf8cb3d65aade75496cf514d3df617.
This commit is contained in:
Your Name 2026-06-01 18:37:26 +08:00
parent f5ee1fe592
commit 641cd800b2
3 changed files with 59 additions and 169 deletions

View File

@ -1780,7 +1780,7 @@ export function PsdTemplatesSettingsClient({
超级锁 超级锁
</div> </div>
<div className="text-xs text-muted-foreground"> <div className="text-xs text-muted-foreground">
开启后锁定目标图层的位置、层级和删除操作;图片槽位仍可替换图片,并只能在蒙版内拖动替换图。 开启后用户前台无法选中、编辑、拖动或临时删除该图层,鼠标点击会自动穿透到下方图层。
</div> </div>
</div> </div>
<Switch <Switch
@ -1792,8 +1792,11 @@ export function PsdTemplatesSettingsClient({
...current, ...current,
isSuperLocked: checked, isSuperLocked: checked,
isRequired: checked ? false : current.isRequired, isRequired: checked ? false : current.isRequired,
isDefaultResultSource: checked
? false
: current.isDefaultResultSource,
allowUserUploadOverride: checked allowUserUploadOverride: checked
? true ? false
: current.allowUserUploadOverride, : current.allowUserUploadOverride,
}; };
} }

View File

@ -872,7 +872,9 @@ function getDefaultSourceImageLayer(
): AgentPsdTemplateImageLayerSlot | null { ): AgentPsdTemplateImageLayerSlot | null {
const editableImageLayers = layers.filter( const editableImageLayers = layers.filter(
(layer): layer is AgentPsdTemplateImageLayerSlot => (layer): layer is AgentPsdTemplateImageLayerSlot =>
layer.isEditable && isAgentPsdImageLayerSlot(layer) layer.isEditable &&
!isAgentPsdLayerSuperLocked(layer) &&
isAgentPsdImageLayerSlot(layer)
); );
return ( return (
@ -910,6 +912,9 @@ function createInitialState(
for (const layer of template.layers) { for (const layer of template.layers) {
layerOrderIds.push(layer.id); layerOrderIds.push(layer.id);
if (isAgentPsdLayerSuperLocked(layer)) {
continue;
}
if ( if (
isAgentPsdImageLayerSlot(layer) && isAgentPsdImageLayerSlot(layer) &&
layer.id === defaultSourceImageLayerId && layer.id === defaultSourceImageLayerId &&
@ -918,9 +923,6 @@ function createInitialState(
imageAssignments[layer.id] = sourceImageUrl; imageAssignments[layer.id] = sourceImageUrl;
imagePlacements[layer.id] = getDefaultAgentPsdImagePlacement(); imagePlacements[layer.id] = getDefaultAgentPsdImagePlacement();
} }
if (isAgentPsdLayerSuperLocked(layer)) {
continue;
}
if (isAgentPsdTextLayerSlot(layer) && layer.defaultText) { if (isAgentPsdTextLayerSlot(layer) && layer.defaultText) {
textAssignments[layer.id] = layer.defaultText; textAssignments[layer.id] = layer.defaultText;
} }
@ -1730,13 +1732,6 @@ export function AgentPsdTemplateEditorDialog({
startClientY: number; startClientY: number;
startOffset: AgentPsdLayerPositionOffset; startOffset: AgentPsdLayerPositionOffset;
} | null>(null); } | null>(null);
const imagePlacementDragStateRef = useRef<{
layerId: string;
pointerId: number;
startClientX: number;
startClientY: number;
startPlacement: AgentPsdImagePlacement;
} | null>(null);
const textDragStateRef = useRef<{ const textDragStateRef = useRef<{
layerId: string; layerId: string;
pointerId: number; pointerId: number;
@ -1943,7 +1938,9 @@ export function AgentPsdTemplateEditorDialog({
() => () =>
selectedTemplateLayers.filter( selectedTemplateLayers.filter(
(layer): layer is AgentPsdTemplateImageLayerSlot => (layer): layer is AgentPsdTemplateImageLayerSlot =>
layer.isEditable && isAgentPsdImageLayerSlot(layer) layer.isEditable &&
!isAgentPsdLayerSuperLocked(layer) &&
isAgentPsdImageLayerSlot(layer)
), ),
[selectedTemplateLayers] [selectedTemplateLayers]
); );
@ -2038,11 +2035,11 @@ export function AgentPsdTemplateEditorDialog({
); );
const orderedEditableImageLayers = useMemo( const orderedEditableImageLayers = useMemo(
() => () =>
orderedPreviewLayers.filter( orderedEditableLayers.filter(
(layer): layer is AgentPsdTemplateImageLayerSlot => (layer): layer is AgentPsdTemplateImageLayerSlot =>
layer.isEditable && isAgentPsdImageLayerSlot(layer) isAgentPsdImageLayerSlot(layer)
), ),
[orderedPreviewLayers] [orderedEditableLayers]
); );
const orderedEditableTextLayers = useMemo( const orderedEditableTextLayers = useMemo(
() => () =>
@ -2193,24 +2190,17 @@ export function AgentPsdTemplateEditorDialog({
const layer = const layer =
selectedTemplateLayers.find((entry) => entry.id === selectedLayerId) || selectedTemplateLayers.find((entry) => entry.id === selectedLayerId) ||
null; null;
return layer; return layer && !isAgentPsdLayerSuperLocked(layer) ? layer : null;
}, [selectedLayerId, selectedTemplateLayers]); }, [selectedLayerId, selectedTemplateLayers]);
const isSelectedLayerSuperLocked = Boolean(
selectedLayer && isAgentPsdLayerSuperLocked(selectedLayer)
);
const isSelectedLayerHidden = Boolean( const isSelectedLayerHidden = Boolean(
selectedLayer && hiddenLayerIdSet.has(selectedLayer.id) selectedLayer && hiddenLayerIdSet.has(selectedLayer.id)
); );
const selectedImageLayer = const selectedImageLayer =
selectedLayer && selectedLayer && isAgentPsdImageLayerSlot(selectedLayer)
selectedLayer.isEditable &&
isAgentPsdImageLayerSlot(selectedLayer)
? selectedLayer ? selectedLayer
: null; : null;
const selectedTextLayer = const selectedTextLayer =
selectedLayer && selectedLayer && isAgentPsdTextLayerSlot(selectedLayer)
!isSelectedLayerSuperLocked &&
isAgentPsdTextLayerSlot(selectedLayer)
? selectedLayer ? selectedLayer
: null; : null;
const selectedImageAssignmentUrl = selectedImageLayer const selectedImageAssignmentUrl = selectedImageLayer
@ -2262,9 +2252,8 @@ export function AgentPsdTemplateEditorDialog({
current.filter((currentLayerId) => currentLayerId !== normalizedLayerId) current.filter((currentLayerId) => currentLayerId !== normalizedLayerId)
); );
} }
const selectedLayerPositionPanel = const selectedLayerPositionPanel = selectedLayer ? (
selectedLayer && !isSelectedLayerSuperLocked ? ( <div className="space-y-4 rounded-2xl border border-white/10 bg-white/[0.03] p-5 shadow-inner">
<div className="space-y-4 rounded-2xl border border-white/10 bg-white/[0.03] p-5 shadow-inner">
<div className="flex items-start justify-between gap-4"> <div className="flex items-start justify-between gap-4">
<div> <div>
<div className="font-semibold text-sm text-white">图层层级</div> <div className="font-semibold text-sm text-white">图层层级</div>
@ -2488,7 +2477,7 @@ export function AgentPsdTemplateEditorDialog({
槽位内图片位置 槽位内图片位置
</div> </div>
<div className="mt-1.5 text-white/50 text-xs"> <div className="mt-1.5 text-white/50 text-xs">
目标图层保持固定;拖动预览中的替换图可在蒙版内微调位置。 图层整体拖动已经改到中间预览区;这里保留槽位内图片的细调。
</div> </div>
</div> </div>
<ImageIcon className="h-5 w-5 shrink-0 text-orange-300" /> <ImageIcon className="h-5 w-5 shrink-0 text-orange-300" />
@ -3456,72 +3445,6 @@ export function AgentPsdTemplateEditorDialog({
window.addEventListener("pointercancel", handlePointerUp); window.addEventListener("pointercancel", handlePointerUp);
} }
function handleAssignedImagePlacementDragStart(
layer: AgentPsdTemplateImageLayerSlot,
event: ReactPointerEvent<HTMLElement>
) {
const assignmentUrl = String(
effectiveImageAssignments[layer.id] || ""
).trim();
if (!assignmentUrl) {
return;
}
event.preventDefault();
event.stopPropagation();
setSelectedLayerId(layer.id);
imagePlacementDragStateRef.current = {
layerId: layer.id,
pointerId: event.pointerId,
startClientX: event.clientX,
startClientY: event.clientY,
startPlacement: normalizeAgentPsdImagePlacement(
effectiveImagePlacements[layer.id]
),
};
const nextTarget = event.currentTarget;
try {
nextTarget.setPointerCapture?.(event.pointerId);
} catch (error) {
console.warn(
"[AgentPsdTemplateEditorDialog] setPointerCapture failed:",
error
);
}
const handlePointerMove = (moveEvent: PointerEvent) => {
const dragState = imagePlacementDragStateRef.current;
if (!dragState || dragState.layerId !== layer.id) {
return;
}
updateImagePlacement(layer.id, () => ({
...dragState.startPlacement,
offsetX:
dragState.startPlacement.offsetX +
(moveEvent.clientX - dragState.startClientX) / stageScale,
offsetY:
dragState.startPlacement.offsetY +
(moveEvent.clientY - dragState.startClientY) / stageScale,
}));
};
const handlePointerUp = (upEvent: PointerEvent) => {
if (imagePlacementDragStateRef.current?.pointerId === upEvent.pointerId) {
imagePlacementDragStateRef.current = null;
}
window.removeEventListener("pointermove", handlePointerMove);
window.removeEventListener("pointerup", handlePointerUp);
window.removeEventListener("pointercancel", handlePointerUp);
};
window.addEventListener("pointermove", handlePointerMove);
window.addEventListener("pointerup", handlePointerUp);
window.addEventListener("pointercancel", handlePointerUp);
}
function handleTextDragStart( function handleTextDragStart(
layer: AgentPsdTemplateTextLayerSlot, layer: AgentPsdTemplateTextLayerSlot,
event: ReactPointerEvent<HTMLDivElement> event: ReactPointerEvent<HTMLDivElement>
@ -4217,11 +4140,6 @@ export function AgentPsdTemplateEditorDialog({
if (isAgentPsdImageLayerSlot(layer)) { if (isAgentPsdImageLayerSlot(layer)) {
const assignedUrl = const assignedUrl =
effectiveImageAssignments[layer.id]; effectiveImageAssignments[layer.id];
const hasAssignedImage = Boolean(
String(assignedUrl || "").trim()
);
const canDragAssignedImage =
isLayerSuperLocked && hasAssignedImage;
const layerImageUrl = const layerImageUrl =
assignedUrl || assignedUrl ||
getPsdLayerPreviewSourceUrl(layer); getPsdLayerPreviewSourceUrl(layer);
@ -4238,51 +4156,39 @@ export function AgentPsdTemplateEditorDialog({
return ( return (
<div <div
className={`absolute overflow-hidden ${ className={`absolute overflow-hidden ${
isLayerSuperLocked && !hasAssignedImage isLayerSuperLocked
? "pointer-events-none" ? "pointer-events-none"
: "pointer-events-auto" : "pointer-events-auto"
}`} }`}
key={layer.id} key={layer.id}
onClick={(event) => { onClick={
event.stopPropagation(); isLayerSuperLocked
setSelectedLayerId(layer.id); ? undefined
}} : (event) => {
onPointerDown={(event) => { event.stopPropagation();
if (canDragAssignedImage) { setSelectedLayerId(layer.id);
handleAssignedImagePlacementDragStart( }
layer, }
event onPointerDown={(event) =>
); isLayerSuperLocked
return; ? undefined
} : handleLayerDragStart(layer, event)
if (!isLayerSuperLocked) { }
handleLayerDragStart(layer, event);
}
}}
style={{ style={{
...assignedImageContainerStyle, ...assignedImageContainerStyle,
zIndex: baseZIndex, zIndex: baseZIndex,
cursor: canDragAssignedImage cursor:
? imagePlacementDragStateRef.current isLayerSuperLocked
?.layerId === layer.id
? "grabbing"
: "grab"
: isLayerSuperLocked
? "default" ? "default"
: layerDragStateRef.current?.layerId === : layerDragStateRef.current?.layerId ===
layer.id layer.id
? "grabbing" ? "grabbing"
: "grab", : "grab",
touchAction: touchAction: isLayerSuperLocked
isLayerSuperLocked && !hasAssignedImage ? "auto"
? "auto" : "none",
: "none",
}} }}
title={ title={`${getLayerLabel(layer)}:${layer.layerName}`}
canDragAssignedImage
? `${getLayerLabel(layer)}:${layer.layerName}(目标已锁定,可拖动替换图)`
: `${getLayerLabel(layer)}:${layer.layerName}`
}
> >
<img <img
alt={layer.layerName} alt={layer.layerName}
@ -4523,8 +4429,6 @@ export function AgentPsdTemplateEditorDialog({
effectiveImageAssignments[layer.id] || "" effectiveImageAssignments[layer.id] || ""
).trim() ).trim()
); );
const isLayerSuperLocked =
isAgentPsdLayerSuperLocked(layer);
return isSelected && hasAssignedImage ? ( return isSelected && hasAssignedImage ? (
<div <div
@ -4552,18 +4456,9 @@ export function AgentPsdTemplateEditorDialog({
className="absolute overflow-hidden rounded-lg transition-all" className="absolute overflow-hidden rounded-lg transition-all"
key={layer.id} key={layer.id}
onClick={() => setSelectedLayerId(layer.id)} onClick={() => setSelectedLayerId(layer.id)}
onPointerDown={(event) => { onPointerDown={(event) =>
if (isLayerSuperLocked && hasAssignedImage) { handleLayerDragStart(layer, event)
handleAssignedImagePlacementDragStart( }
layer,
event
);
return;
}
if (!isLayerSuperLocked) {
handleLayerDragStart(layer, event);
}
}}
style={{ style={{
...frameStyle, ...frameStyle,
zIndex: zIndex:
@ -4575,15 +4470,10 @@ export function AgentPsdTemplateEditorDialog({
? "rgba(249,115,22,0.08)" ? "rgba(249,115,22,0.08)"
: "transparent", : "transparent",
cursor: cursor:
isLayerSuperLocked && hasAssignedImage layerDragStateRef.current?.layerId ===
? imagePlacementDragStateRef.current layer.id
?.layerId === layer.id ? "grabbing"
? "grabbing" : "grab",
: "grab"
: layerDragStateRef.current?.layerId ===
layer.id
? "grabbing"
: "grab",
touchAction: "none", touchAction: "none",
}} }}
title={`${getLayerLabel(layer)}:${layer.layerName}`} title={`${getLayerLabel(layer)}:${layer.layerName}`}

View File

@ -576,13 +576,13 @@ export async function renderAgentPsdTemplate(params: {
for (const layer of orderedTemplateLayers) { for (const layer of orderedTemplateLayers) {
if (hiddenLayerIdSet.has(layer.id)) { if (hiddenLayerIdSet.has(layer.id)) {
continue; continue;
} }
const storedLayerSourceUrl = getStoredLayerSourceUrl(layer); const storedLayerSourceUrl = getStoredLayerSourceUrl(layer);
if (shouldRenderAsStaticLayer(layer)) { if (shouldRenderAsStaticLayer(layer)) {
if (shouldUseRenderBaseFallback || shouldUseRenderSegments) { if (shouldUseRenderBaseFallback || shouldUseRenderSegments) {
continue; continue;
} }
pushAsset( pushAsset(
storedLayerSourceUrl, storedLayerSourceUrl,
"PSD 图层素材", "PSD 图层素材",
@ -913,10 +913,7 @@ export async function renderAgentPsdTemplate(params: {
} }
for (const layer of [...orderedTemplateLayers].reverse()) { for (const layer of [...orderedTemplateLayers].reverse()) {
if ( if (shouldUseRenderSegments && isAgentPsdTemplateLayerUserEditable(layer)) {
shouldUseRenderSegments &&
(isAgentPsdTemplateLayerUserEditable(layer) || hasImageAssignment(layer))
) {
await appendRenderSegmentBeforeLayer(layer.id); await appendRenderSegmentBeforeLayer(layer.id);
} }
@ -924,7 +921,7 @@ export async function renderAgentPsdTemplate(params: {
continue; continue;
} }
if (shouldRenderAsStaticLayer(layer)) { if (!isAgentPsdTemplateLayerUserEditable(layer)) {
if (shouldUseRenderBaseFallback || shouldUseRenderSegments) { if (shouldUseRenderBaseFallback || shouldUseRenderSegments) {
continue; continue;
} }