cadeditfronttest/components/DrawingViewer.js
2025-09-12 18:44:30 +08:00

158 lines
7.3 KiB
JavaScript

const { useState, useEffect, useRef } = React;
function DraggableTable({ drawingId, position, onPositionChange, children }) {
const tableRef = useRef(null);
const [isDragging, setIsDragging] = useState(false);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const handleMouseDown = (e) => {
if (!tableRef.current) return;
setIsDragging(true);
const rect = tableRef.current.getBoundingClientRect();
setOffset({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
});
e.preventDefault();
};
const handleMouseMove = (e) => {
if (!isDragging || !tableRef.current) return;
const parentRect = tableRef.current.parentElement.getBoundingClientRect();
// 计算新的 left 和 bottom
let newX = e.clientX - parentRect.left - offset.x;
let newY = parentRect.height - (e.clientY - parentRect.top) - tableRef.current.offsetHeight + offset.y;
// 边界检测
newX = Math.max(0, Math.min(newX, parentRect.width - tableRef.current.offsetWidth));
newY = Math.max(0, Math.min(newY, parentRect.height - tableRef.current.offsetHeight));
onPositionChange(drawingId, { x: newX, y: newY });
e.preventDefault();
};
const handleMouseUp = () => {
setIsDragging(false);
};
useEffect(() => {
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
} else {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging, handleMouseMove, handleMouseUp]);
return React.createElement('div', {
ref: tableRef,
className: `absolute bg-white border border-gray-300 shadow-lg p-2 rounded-lg ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`,
style: { left: `${position.x}px`, bottom: `${position.y}px` },
onMouseDown: handleMouseDown
}, children);
}
function DrawingViewer({ drawing, item, items, tablePositions, setTablePositions, drawings, onItemUpdate, onBindDrawing, onItemRename, onCycleDrawing }) {
const [editedItemId, setEditedItemId] = React.useState('');
React.useEffect(() => {
if (item) {
setEditedItemId(item.id);
}
}, [item]);
if (!item) {
return React.createElement('div', { className: 'workspace-panel flex items-center justify-center h-full' },
React.createElement('p', { className: 'text-gray-500' }, '请在左侧选择一个件号')
);
}
if (!drawing) {
return React.createElement('div', { className: 'workspace-panel flex flex-col items-center justify-center h-full' },
React.createElement('p', { className: 'text-gray-500 mb-4' }, `件号 "${item.id}" 尚未绑定图纸`),
// 假设我们总是可以绑定到一张默认图纸上,或者需要一个图纸选择器
// 这里为了简化,我们假设绑定到 'drawing-1'
React.createElement('button', {
className: 'btn-primary',
onClick: () => onBindDrawing(item.id, 'drawing-1')
}, '为此件号绑定图纸')
);
}
const tablePos = tablePositions[drawing.id] || { x: 50, y: 50 };
// 获取子项
const childItems = item.children.map(childId => items[childId]);
const handleRenameItem = () => {
if (!editedItemId.trim() || editedItemId.trim() === item.id) return;
onItemRename(item.id, editedItemId.trim());
};
const isRoot = item && item.isRoot;
return React.createElement('div', { className: 'workspace-panel h-full p-4 relative bg-gray-50 overflow-hidden' },
!isRoot && React.createElement('div', { className: 'absolute top-4 left-4 z-10 bg-white p-2 rounded-lg shadow-md flex items-center gap-2' },
React.createElement('span', { className: 'text-sm font-medium mr-2' }, '修改件号:'),
React.createElement('input', {
type: 'text',
placeholder: '输入新件号',
className: 'form-input w-48',
value: editedItemId,
onChange: (e) => setEditedItemId(e.target.value),
onBlur: handleRenameItem, // 失去焦点时也触发
onKeyPress: (e) => { if (e.key === 'Enter') handleRenameItem() } // 回车触发
}),
React.createElement('button', { className: 'btn-primary', onClick: handleRenameItem }, '确认')
),
React.createElement('button', {
className: 'absolute left-4 top-1/2 -translate-y-1/2 z-10 p-3 bg-white/60 rounded-full hover:bg-white transition-colors shadow-md',
onClick: () => onCycleDrawing(-1)
}, React.createElement('i', { className: 'lucide lucide-chevron-left w-8 h-8' })),
React.createElement('button', {
className: 'absolute right-4 top-1/2 -translate-y-1/2 z-10 p-3 bg-white/60 rounded-full hover:bg-white transition-colors shadow-md',
onClick: () => onCycleDrawing(1)
}, React.createElement('i', { className: 'lucide lucide-chevron-right w-8 h-8' })),
drawing.url ?
React.createElement('img', { src: drawing.url, className: 'w-full h-full object-contain' }) :
React.createElement('div', { className: 'absolute inset-0 flex items-center justify-center' },
React.createElement('h2', {className: 'text-9xl font-bold text-gray-200 select-none'}, drawing.drawingNumber)
),
React.createElement(DraggableTable, {
drawingId: drawing.id,
position: tablePos,
onPositionChange: (drawingId, newPos) => {
setTablePositions(prev => ({...prev, [drawingId]: newPos}))
}
},
React.createElement('table', { className: 'w-full text-sm text-left' },
React.createElement('thead', {},
React.createElement('tr', { className: 'bg-gray-100' },
React.createElement('th', {className: 'p-2'}, '件号'),
React.createElement('th', {className: 'p-2'}, '名称'),
React.createElement('th', {className: 'p-2'}, '数量'),
React.createElement('th', {className: 'p-2'}, '重量'),
React.createElement('th', {className: 'p-2'}, '图号')
)
),
React.createElement('tbody', {},
childItems.map(child => React.createElement('tr', { key: child.id, className: 'border-b' },
React.createElement('td', {className: 'p-2'}, child.id),
React.createElement('td', {className: 'p-2'}, child.name),
React.createElement('td', {className: 'p-2'}, child.quantity),
React.createElement('td', {className: 'p-2'}, child.weight.toFixed(2)),
React.createElement('td', {className: 'p-2'}, drawings[child.drawingId]?.drawingNumber || 'N/A')
))
)
)
)
);
}