双向删除同步

This commit is contained in:
liaibo
2026-01-02 07:25:50 +08:00
parent 1db64c1c55
commit b1288487af
48 changed files with 2406 additions and 8841 deletions
@@ -22,6 +22,7 @@ interface FileTreeProps {
disableSelection?: boolean;
onDropFiles?: (docId: string, files: FileList) => void;
onAssetContextMenu?: (event: React.MouseEvent, asset: MediaAsset) => void;
onAssetClick?: (asset: MediaAsset, event: React.MouseEvent) => void;
}
const INDENT = 16;
@@ -42,6 +43,7 @@ export function FileTree({
disableSelection = false,
onDropFiles,
onAssetContextMenu,
onAssetClick,
}: FileTreeProps) {
if (nodes.length === 0) {
return <div className="px-4 py-6 text-sm text-gray-400"></div>;
@@ -83,6 +85,7 @@ export function FileTree({
disableSelection={disableSelection}
onDropFiles={onDropFiles}
onAssetContextMenu={onAssetContextMenu}
onAssetClick={onAssetClick}
/>
))}
</div>
@@ -106,6 +109,7 @@ interface FileTreeNodeProps {
disableSelection: boolean;
onDropFiles?: (docId: string, files: FileList) => void;
onAssetContextMenu?: (event: React.MouseEvent, asset: MediaAsset) => void;
onAssetClick?: (asset: MediaAsset, event: React.MouseEvent) => void;
}
function FileTreeNode({
@@ -125,6 +129,7 @@ function FileTreeNode({
disableSelection,
onDropFiles,
onAssetContextMenu,
onAssetClick,
}: FileTreeNodeProps) {
const isExpanded = expanded.has(node.id);
const assets = useMemo(() => assetsByDoc[node.id] ?? [], [assetsByDoc, node.id]);
@@ -202,13 +207,23 @@ function FileTreeNode({
onToggleAssetSelect ? () => onToggleAssetSelect(asset.id) : undefined
}
onSelectOnly={onSelectOnlyAsset ? () => onSelectOnlyAsset(asset.id) : undefined}
onClick={() => onOpenAsset(asset)}
onClick={(e) => {
if (onAssetClick) {
onAssetClick(asset, e);
} else {
onOpenAsset(asset);
}
}}
onDoubleClick={() => onOpenAsset(asset)}
stopBubble
onContextMenu={
onAssetContextMenu
? (e) => {
e.preventDefault();
e.stopPropagation();
if (onAssetClick) {
onAssetClick(asset, e);
}
onAssetContextMenu(e, asset);
}
: undefined
@@ -264,17 +279,23 @@ function FileLeafRow({
onSelectOnly?: () => void;
stopBubble?: boolean;
onContextMenu?: (event: React.MouseEvent) => void;
onDoubleClick?: () => void;
}) {
return (
<div
className="flex items-center gap-2 rounded-md px-2 py-1 text-sm text-gray-600 hover:bg-[#f8fafc]"
className={cn(
"flex items-center gap-2 rounded-md px-2 py-1 text-sm text-gray-600 hover:bg-[#f8fafc]",
selected && "bg-[#e8f2ff] text-[#2563eb]",
)}
style={{ paddingLeft: depth * INDENT + 32 }}
onClick={(e) => {
if (stopBubble) e.stopPropagation();
// 附件行默认只负责选中,不直接打开,避免误触下载
if (selectable) return;
onClick();
}}
onDoubleClick={(e) => {
if (stopBubble) e.stopPropagation();
onDoubleClick?.();
}}
onMouseDown={(e) => {
if (stopBubble) e.stopPropagation();
}}