0.1.14 上线前更改
This commit is contained in:
@@ -17,9 +17,10 @@ interface FileTreeProps {
|
||||
onRowContextMenu: (row: FileTreeRow, event: React.MouseEvent) => void;
|
||||
onRowDragStart?: (row: FileTreeRow, event: React.DragEvent) => void;
|
||||
onToggleExpand: (docId: string) => void;
|
||||
onToggleAssetFolderExpand?: (assetId: string) => void;
|
||||
onCreateChild: (parentId: string | null) => void;
|
||||
onBlankMouseDown?: (event: React.MouseEvent) => void;
|
||||
onDropFiles?: (docId: string, files: FileList) => void;
|
||||
onDropFiles?: (docId: string, files: FileList, targetRow?: FileTreeRow) => void;
|
||||
onInternalDrop?: (args: { targetRow: FileTreeRow; rowIds: string[]; copy: boolean }) => void;
|
||||
}
|
||||
|
||||
@@ -34,6 +35,7 @@ export function FileTree({
|
||||
onRowContextMenu,
|
||||
onRowDragStart,
|
||||
onToggleExpand,
|
||||
onToggleAssetFolderExpand,
|
||||
onCreateChild,
|
||||
onBlankMouseDown,
|
||||
onDropFiles,
|
||||
@@ -53,8 +55,8 @@ export function FileTree({
|
||||
// 标记为 drop feedback(包含它的所有可见子节点)。我们用“扁平化 rows +
|
||||
// depth”来近似计算该范围。
|
||||
let endIndex = startIndex + 1;
|
||||
if (target.kind === "doc" && target.isExpanded && target.hasChildren) {
|
||||
while (endIndex < rows.length && rows[endIndex].depth > targetDepth) {
|
||||
if ((target.kind === "doc" || target.kind === "asset-folder") && target.isExpanded && target.hasChildren) {
|
||||
while (endIndex < rows.length && rows[endIndex].depth > targetDepth) {
|
||||
endIndex += 1;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +93,7 @@ export function FileTree({
|
||||
(row) => row.kind === "doc" && row.docId === activeId,
|
||||
);
|
||||
const firstDocRow = rows.find((row) => row.kind === "doc");
|
||||
const targetDocId = activeDocRow?.docId ?? firstDocRow?.docId ?? "";
|
||||
const targetDocId = activeDocRow?.docId ?? firstDocRow?.docId ?? "";
|
||||
onDropFiles(targetDocId, files);
|
||||
}
|
||||
}}
|
||||
@@ -210,7 +212,7 @@ export function FileTree({
|
||||
if (onDropFiles && event.dataTransfer.files?.length) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onDropFiles(row.docId, event.dataTransfer.files);
|
||||
onDropFiles(row.docId, event.dataTransfer.files, row);
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
@@ -258,6 +260,31 @@ export function FileTree({
|
||||
<FileText className="h-4 w-4 text-gray-500" />
|
||||
<span className="min-w-0 flex-1 truncate text-left">{label}</span>
|
||||
</>
|
||||
) : row.kind === "asset-folder" ? (
|
||||
<>
|
||||
{row.hasChildren ? (
|
||||
<button
|
||||
type="button"
|
||||
aria-label="展开或折叠"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
onToggleAssetFolderExpand?.(row.asset.id);
|
||||
}}
|
||||
className="flex h-5 w-5 items-center justify-center rounded-md hover:bg-gray-100"
|
||||
>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"h-3.5 w-3.5 transition-transform",
|
||||
row.isExpanded && "rotate-90",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
) : (
|
||||
<span className="h-5 w-5" />
|
||||
)}
|
||||
<Folder className="h-4 w-4 text-[#2563eb]" />
|
||||
<span className="min-w-0 flex-1 truncate text-left">{label}</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="h-4 w-4" />
|
||||
|
||||
@@ -6,10 +6,8 @@ import { useRouter, useSelectedLayoutSegments } from "next/navigation";
|
||||
import {
|
||||
ArrowRightLeft,
|
||||
ArrowUpRight,
|
||||
Bell,
|
||||
ChevronRight,
|
||||
Copy,
|
||||
Dice5,
|
||||
Edit3,
|
||||
GitMerge,
|
||||
Globe,
|
||||
@@ -19,7 +17,6 @@ import {
|
||||
Link as LinkIcon,
|
||||
MoreHorizontal,
|
||||
PanelRightOpen,
|
||||
PenSquare,
|
||||
Plus,
|
||||
Search as SearchIcon,
|
||||
Share2,
|
||||
@@ -66,10 +63,10 @@ const TOP_BUTTONS = [
|
||||
{ id: "graph", icon: Share2, label: "关系图" },
|
||||
{ id: "import", icon: Upload, label: "导入" },
|
||||
{ id: "members", icon: Users, label: "成员" },
|
||||
{ id: "inbox", icon: Bell, label: "消息箱" },
|
||||
{ id: "quick-note", icon: PenSquare, label: "今日速记" },
|
||||
{ id: "lucky", icon: Dice5, label: "手气不错" },
|
||||
{ id: "more", icon: MoreHorizontal, label: "更多" },
|
||||
{ id: "starred", icon: Star, label: "星标置顶" },
|
||||
{ id: "public", icon: Globe, label: "公共页面" },
|
||||
{ id: "shared", icon: Shield, label: "共享页面" },
|
||||
{ id: "templates", icon: LayoutGrid, label: "模板中心" },
|
||||
] as const;
|
||||
|
||||
const SECTION_ICONS: Record<Exclude<SidebarSectionId, "private">, React.ReactNode> = {
|
||||
@@ -79,6 +76,29 @@ const SECTION_ICONS: Record<Exclude<SidebarSectionId, "private">, React.ReactNod
|
||||
templates: <LayoutGrid className="h-4 w-4 text-[#34d399]" />,
|
||||
};
|
||||
|
||||
const normalizeStoragePath = (storagePath: string): string => storagePath.replaceAll("\\", "/");
|
||||
|
||||
const extractMindmapIdFromStoragePath = (
|
||||
storagePath: string | null | undefined,
|
||||
): string | null => {
|
||||
if (!storagePath) return null;
|
||||
const normalized = normalizeStoragePath(storagePath);
|
||||
|
||||
const prefix = "mindmaps/";
|
||||
if (normalized.startsWith(prefix)) {
|
||||
const rest = normalized.slice(prefix.length);
|
||||
const id = rest.split("/")[0];
|
||||
return id ? id : null;
|
||||
}
|
||||
|
||||
const marker = "/mindmaps/";
|
||||
const idx = normalized.indexOf(marker);
|
||||
if (idx === -1) return null;
|
||||
const rest = normalized.slice(idx + marker.length);
|
||||
const id = rest.split("/")[0];
|
||||
return id ? id : null;
|
||||
};
|
||||
|
||||
interface SidebarProps {
|
||||
initialData: SidebarInitialData;
|
||||
}
|
||||
@@ -90,8 +110,11 @@ interface ContextMenuState {
|
||||
}
|
||||
|
||||
export function Sidebar({ initialData }: SidebarProps) {
|
||||
const { open, setOpen, width, setWidth, collapsedSections, toggleSection, trashConfirm, setTrashConfirm } =
|
||||
const { open, setOpen, width, setWidth, collapsedSections, toggleSection, setSectionCollapsed, trashConfirm, setTrashConfirm } =
|
||||
useSidebarStore();
|
||||
const sectionsTrayOpen = useSidebarStore((state) => state.sectionsTrayOpen);
|
||||
const toggleSectionsTray = useSidebarStore((state) => state.toggleSectionsTray);
|
||||
const setSectionsTrayOpen = useSidebarStore((state) => state.setSectionsTrayOpen);
|
||||
const viewMode = useSidebarStore((state) => state.viewMode);
|
||||
const setViewMode = useSidebarStore((state) => state.setViewMode);
|
||||
const openSearchPalette = useSearchPaletteStore((state) => state.openSearch);
|
||||
@@ -274,9 +297,67 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
return assets.filter((item) => (item.file_name ?? "未命名附件").toLowerCase().includes(keyword));
|
||||
}, [sidebarData.trashedMediaAssets, sidebarData.trashedMindmapAssets, trashSearch]);
|
||||
|
||||
const mindmapChildrenSnapshot = useMemo(() => {
|
||||
const mapping = sidebarData.mindmapAssetChildren ?? {};
|
||||
const mindmapDocById = new Map<string, string>(
|
||||
(mindmapAssets ?? [])
|
||||
.filter((asset) => asset.asset_type === "mindmap")
|
||||
.map((asset) => [asset.id, asset.document_id]),
|
||||
);
|
||||
const mindmapIds = new Set(mindmapDocById.keys());
|
||||
|
||||
const mediaById = new Map<string, MediaAsset>(
|
||||
(mediaAssets ?? []).map((asset) => [asset.id, asset]),
|
||||
);
|
||||
|
||||
const childAssetsByMindmapId: Record<string, MediaAsset[]> = {};
|
||||
const childIds = new Set<string>();
|
||||
const assigned = new Set<string>();
|
||||
|
||||
// 物理目录:storage_path 归属到 mindmaps/<mindmapId>/ 的附件,作为导图文件夹内容
|
||||
(mediaAssets ?? []).forEach((asset) => {
|
||||
const sp = asset.storage_path;
|
||||
if (!sp || typeof sp !== "string") return;
|
||||
const mindmapId = extractMindmapIdFromStoragePath(sp);
|
||||
if (!mindmapId) return;
|
||||
if (!mindmapIds.has(mindmapId)) return;
|
||||
const docId = mindmapDocById.get(mindmapId);
|
||||
if (docId && asset.document_id !== docId) return;
|
||||
if (assigned.has(asset.id)) return;
|
||||
assigned.add(asset.id);
|
||||
childIds.add(asset.id);
|
||||
if (!childAssetsByMindmapId[mindmapId]) childAssetsByMindmapId[mindmapId] = [];
|
||||
childAssetsByMindmapId[mindmapId].push(asset);
|
||||
});
|
||||
|
||||
// 引用图片:从 mindmap JSON 解析出的 assetIds,也放到导图文件夹下(去重)
|
||||
(mindmapAssets ?? []).forEach((mindmapAsset) => {
|
||||
const ids = mapping[mindmapAsset.id] ?? [];
|
||||
if (!Array.isArray(ids) || ids.length === 0) return;
|
||||
ids.forEach((id) => {
|
||||
const asset = mediaById.get(id);
|
||||
if (!asset) return;
|
||||
if (asset.document_id !== mindmapAsset.document_id) return;
|
||||
if (assigned.has(asset.id)) return;
|
||||
assigned.add(asset.id);
|
||||
childIds.add(asset.id);
|
||||
if (!childAssetsByMindmapId[mindmapAsset.id]) childAssetsByMindmapId[mindmapAsset.id] = [];
|
||||
childAssetsByMindmapId[mindmapAsset.id].push(asset);
|
||||
});
|
||||
});
|
||||
|
||||
return { childAssetsByMindmapId, childIds };
|
||||
}, [mediaAssets, mindmapAssets, sidebarData.mindmapAssetChildren]);
|
||||
|
||||
const assetsByDoc = useMemo(() => {
|
||||
const map: Record<string, MediaAsset[]> = {};
|
||||
const assets = [...(mediaAssets ?? []), ...(mindmapAssets ?? []), ...(tableAssets ?? [])];
|
||||
const assets = [
|
||||
...((mediaAssets ?? []).filter(
|
||||
(asset) => !mindmapChildrenSnapshot.childIds.has(asset.id),
|
||||
)),
|
||||
...(mindmapAssets ?? []),
|
||||
...(tableAssets ?? []),
|
||||
];
|
||||
|
||||
assets.forEach((asset) => {
|
||||
if (!map[asset.document_id]) {
|
||||
@@ -288,7 +369,9 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}, [mediaAssets, mindmapAssets, tableAssets]);
|
||||
}, [mediaAssets, mindmapAssets, tableAssets, mindmapChildrenSnapshot.childIds]);
|
||||
|
||||
const [expandedAssetFolders, setExpandedAssetFolders] = useState<Set<string>>(() => new Set());
|
||||
|
||||
const fileTreeRows = useMemo(
|
||||
() =>
|
||||
@@ -296,8 +379,10 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
nodes: filteredPrivateTree,
|
||||
expanded,
|
||||
assetsByDoc,
|
||||
assetChildrenByAssetId: mindmapChildrenSnapshot.childAssetsByMindmapId,
|
||||
expandedAssetFolderIds: expandedAssetFolders,
|
||||
}),
|
||||
[assetsByDoc, expanded, filteredPrivateTree],
|
||||
[assetsByDoc, expanded, expandedAssetFolders, filteredPrivateTree, mindmapChildrenSnapshot.childAssetsByMindmapId],
|
||||
);
|
||||
|
||||
const fileTreeVisibleRowIds = useMemo(() => fileTreeRows.map((row) => row.rowId), [fileTreeRows]);
|
||||
@@ -406,6 +491,29 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const knownMindmapFolderIdsRef = useRef<Set<string>>(new Set());
|
||||
useEffect(() => {
|
||||
setExpandedAssetFolders((prev) => {
|
||||
const next = new Set(prev);
|
||||
(mindmapAssets ?? []).forEach((asset) => {
|
||||
if (asset.asset_type !== "mindmap") return;
|
||||
if (knownMindmapFolderIdsRef.current.has(asset.id)) return;
|
||||
knownMindmapFolderIdsRef.current.add(asset.id);
|
||||
next.add(asset.id);
|
||||
});
|
||||
return next;
|
||||
});
|
||||
}, [mindmapAssets]);
|
||||
|
||||
const toggleAssetFolderExpand = useCallback((assetId: string) => {
|
||||
setExpandedAssetFolders((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(assetId)) next.delete(assetId);
|
||||
else next.add(assetId);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleOpenAsset = useCallback((asset: MediaAsset) => {
|
||||
if (asset.asset_type === "mindmap") {
|
||||
router.push(`/mindmap/${asset.document_id}/${asset.id}`);
|
||||
@@ -480,7 +588,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
|
||||
const handleFileTreeRowDoubleClick = useCallback(
|
||||
(row: FileTreeRow, _event?: React.MouseEvent) => {
|
||||
if (row.kind === "asset") {
|
||||
if (row.kind === "asset" || row.kind === "asset-folder") {
|
||||
handleOpenAsset(row.asset);
|
||||
return;
|
||||
}
|
||||
@@ -497,8 +605,8 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
reduceFileTreeSelection(prev, { type: "contextmenu", rowId: row.rowId }),
|
||||
);
|
||||
|
||||
if (row.kind === "asset") {
|
||||
setAssetMenu({ asset: row.asset, x: event.clientX, y: event.clientY });
|
||||
if (row.kind === "asset" || row.kind === "asset-folder") {
|
||||
setAssetMenu({ asset: row.asset, x: event.clientX, y: event.clientY });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1052,11 +1160,26 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
);
|
||||
|
||||
const handleFileTreeDropFiles = useCallback(
|
||||
(docId: string, files: FileList) => {
|
||||
(docId: string, files: FileList, targetRow?: FileTreeRow) => {
|
||||
void (async () => {
|
||||
const droppedFiles = Array.from(files ?? []);
|
||||
if (droppedFiles.length === 0) return;
|
||||
|
||||
const targetMindmapId = (() => {
|
||||
if (!targetRow) return null;
|
||||
if (targetRow.kind === "asset-folder" && targetRow.asset.asset_type === "mindmap") {
|
||||
return targetRow.asset.id;
|
||||
}
|
||||
if (targetRow.kind === "asset") {
|
||||
return extractMindmapIdFromStoragePath(targetRow.asset.storage_path);
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
|
||||
if (targetMindmapId) {
|
||||
setExpandedAssetFolders((prev) => new Set(prev).add(targetMindmapId));
|
||||
}
|
||||
|
||||
const inferredTargetDocId =
|
||||
docId ||
|
||||
inferPasteTargetDocId({
|
||||
@@ -1085,6 +1208,9 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
form.append("file", file);
|
||||
form.append("workspaceId", workspaceId);
|
||||
form.append("documentId", inferredTargetDocId);
|
||||
if (targetMindmapId) {
|
||||
form.append("mindmapId", targetMindmapId);
|
||||
}
|
||||
const resp = await fetch("/api/media/upload", { method: "POST", body: form });
|
||||
if (!resp.ok) {
|
||||
const payload = await resp.json().catch(() => ({}));
|
||||
@@ -1095,7 +1221,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
if (payload.asset?.id) {
|
||||
emitAssetsChanged(inferredTargetDocId, payload.asset);
|
||||
// 拖拽文件进文件树:如果落点就是当前打开的页面,则把文件也插入到主编辑区
|
||||
if (inferredTargetDocId === activeId) {
|
||||
if (inferredTargetDocId === activeId && !targetMindmapId) {
|
||||
editorBridge?.insertMediaAsset?.(payload.asset);
|
||||
}
|
||||
} else {
|
||||
@@ -1140,6 +1266,22 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetMindmapId = (() => {
|
||||
if (args.targetRow.kind === "asset-folder" && args.targetRow.asset.asset_type === "mindmap") {
|
||||
return args.targetRow.asset.id;
|
||||
}
|
||||
if (args.targetRow.kind === "asset") {
|
||||
return extractMindmapIdFromStoragePath(args.targetRow.asset.storage_path);
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
|
||||
const targetSubPath = targetMindmapId ? `mindmaps/${targetMindmapId}` : undefined;
|
||||
|
||||
if (targetMindmapId) {
|
||||
setExpandedAssetFolders((prev) => new Set(prev).add(targetMindmapId));
|
||||
}
|
||||
|
||||
const uniqueRowIds: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
args.rowIds.forEach((id) => {
|
||||
@@ -1188,6 +1330,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
action: "copy",
|
||||
assetIds: copyableAssetIds,
|
||||
targetDocumentId: targetDocId,
|
||||
targetSubPath,
|
||||
}),
|
||||
});
|
||||
if (!resp.ok) {
|
||||
@@ -1248,6 +1391,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
action: "move",
|
||||
assetIds: copyableAssetIds,
|
||||
targetDocumentId: targetDocId,
|
||||
targetSubPath,
|
||||
}),
|
||||
});
|
||||
if (!resp.ok) {
|
||||
@@ -1533,9 +1677,20 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
openSearchPalette();
|
||||
return;
|
||||
}
|
||||
if (
|
||||
buttonId === "starred" ||
|
||||
buttonId === "public" ||
|
||||
buttonId === "shared" ||
|
||||
buttonId === "templates"
|
||||
) {
|
||||
setViewMode("section");
|
||||
setSectionsTrayOpen(true);
|
||||
setSectionCollapsed(buttonId, false);
|
||||
return;
|
||||
}
|
||||
window.alert("该功能即将上线,敬请期待");
|
||||
},
|
||||
[openSearchPalette],
|
||||
[openSearchPalette, setSectionCollapsed, setSectionsTrayOpen, setViewMode],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -1666,34 +1821,55 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
|
||||
{viewMode === "section" ? (
|
||||
<>
|
||||
<SectionList
|
||||
label="星标置顶"
|
||||
icon={SECTION_ICONS.starred}
|
||||
nodes={starredNodes}
|
||||
collapsed={collapsedSections.starred}
|
||||
onToggle={() => toggleSection("starred")}
|
||||
/>
|
||||
<SectionList
|
||||
label="公共页面"
|
||||
icon={SECTION_ICONS.public}
|
||||
nodes={publicNodes}
|
||||
collapsed={collapsedSections.public}
|
||||
onToggle={() => toggleSection("public")}
|
||||
/>
|
||||
<SectionList
|
||||
label="共享页面"
|
||||
icon={SECTION_ICONS.shared}
|
||||
nodes={sharedNodes}
|
||||
collapsed={collapsedSections.shared}
|
||||
onToggle={() => toggleSection("shared")}
|
||||
/>
|
||||
<SectionList
|
||||
label="模板中心"
|
||||
icon={SECTION_ICONS.templates}
|
||||
nodes={templateNodes}
|
||||
collapsed={collapsedSections.templates}
|
||||
onToggle={() => toggleSection("templates")}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between border-b border-[#f1f1f1] px-4 py-3 text-sm font-medium text-gray-600 hover:bg-gray-50"
|
||||
onClick={toggleSectionsTray}
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<Star className="h-4 w-4 text-[#f5a623]" />
|
||||
星标 / 公共 / 共享 / 模板
|
||||
</span>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"h-4 w-4 text-gray-400 transition-transform",
|
||||
sectionsTrayOpen && "rotate-90",
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
|
||||
{sectionsTrayOpen ? (
|
||||
<>
|
||||
<SectionList
|
||||
label="星标置顶"
|
||||
icon={SECTION_ICONS.starred}
|
||||
nodes={starredNodes}
|
||||
collapsed={collapsedSections.starred}
|
||||
onToggle={() => toggleSection("starred")}
|
||||
/>
|
||||
<SectionList
|
||||
label="公共页面"
|
||||
icon={SECTION_ICONS.public}
|
||||
nodes={publicNodes}
|
||||
collapsed={collapsedSections.public}
|
||||
onToggle={() => toggleSection("public")}
|
||||
/>
|
||||
<SectionList
|
||||
label="共享页面"
|
||||
icon={SECTION_ICONS.shared}
|
||||
nodes={sharedNodes}
|
||||
collapsed={collapsedSections.shared}
|
||||
onToggle={() => toggleSection("shared")}
|
||||
/>
|
||||
<SectionList
|
||||
label="模板中心"
|
||||
icon={SECTION_ICONS.templates}
|
||||
nodes={templateNodes}
|
||||
collapsed={collapsedSections.templates}
|
||||
onToggle={() => toggleSection("templates")}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<div className="flex flex-1 flex-col border-t border-[#f1f1f1]">
|
||||
<button
|
||||
@@ -1740,6 +1916,7 @@ export function Sidebar({ initialData }: SidebarProps) {
|
||||
onRowContextMenu={handleFileTreeRowContextMenu}
|
||||
onRowDragStart={(row) => handleFileTreeRowDragStart(row)}
|
||||
onToggleExpand={toggleExpand}
|
||||
onToggleAssetFolderExpand={toggleAssetFolderExpand}
|
||||
onCreateChild={handleCreate}
|
||||
onBlankMouseDown={handleFileTreeBlankMouseDown}
|
||||
onDropFiles={handleFileTreeDropFiles}
|
||||
|
||||
@@ -32,6 +32,11 @@ export interface SidebarInitialData {
|
||||
* 思维导图文件列表(用于文件树显示,多导图时一页可有多个)
|
||||
*/
|
||||
mindmapAssets?: MediaAsset[];
|
||||
/**
|
||||
* 思维导图(mindmapAssets)引用的图片附件:mindmapId -> media_asset ids
|
||||
* 用于在文件树中把“导图图片”显示在对应 mindmap 文件下一级。
|
||||
*/
|
||||
mindmapAssetChildren?: Record<string, string[]>;
|
||||
/**
|
||||
* 可选的媒体资源列表(旧字段向后兼容)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user