This commit is contained in:
2026-02-26 15:14:13 +08:00
parent eb68553baf
commit 911c669d81
7 changed files with 278 additions and 22 deletions
+83 -15
View File
@@ -2,8 +2,8 @@
import React, { createContext, useContext, useRef, useState, useCallback } from "react";
import { useEditorStore } from "@/lib/store";
import { marked } from "marked";
import JSZip from "jszip";
import { markdownToImportHtml } from "@/lib/markdown-import";
interface ImportContextType {
triggerImport: (parentId?: string | null) => void;
@@ -27,13 +27,14 @@ export function ImportProvider({ children }: { children: React.ReactNode }) {
const [isImporting, setIsImporting] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const targetParentIdRef = useRef<string | null>(null);
const { fetchPages } = useEditorStore();
const { pages, fetchPages } = useEditorStore();
const postPage = useCallback(
async (
payload: {
title: string;
content?: string;
importMarkdown?: string;
parentId?: string | null;
type: "file" | "folder";
},
@@ -62,6 +63,41 @@ export function ImportProvider({ children }: { children: React.ReactNode }) {
[]
);
const putPage = useCallback(
async (
id: string,
payload: {
title?: string;
content?: string;
importMarkdown?: string;
parentId?: string | null;
type?: "file" | "folder";
},
contextLabel: string
) => {
const res = await fetch(`/api/pages/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
credentials: "same-origin",
});
if (!res.ok) {
let detail = "";
try {
const data = await res.json();
detail = typeof data?.error === "string" ? data.error : JSON.stringify(data);
} catch {
detail = await res.text();
}
throw new ImportApiError(`${contextLabel}失败(${res.status}${detail ? `: ${detail}` : ""}`, res.status, detail);
}
return res.json();
},
[]
);
const triggerImport = useCallback((parentId: string | null = null) => {
targetParentIdRef.current = parentId;
if (fileInputRef.current) {
@@ -94,13 +130,30 @@ export function ImportProvider({ children }: { children: React.ReactNode }) {
const handleSingleFileImport = async (file: File) => {
const text = await file.text();
const title = file.name.replace(/\.md$/i, "");
const html = await marked.parse(text);
const html = markdownToImportHtml(text);
const parentId = targetParentIdRef.current;
const existing = pages.find((p) => p.type === "file" && p.parentId === parentId && (p.title || "").trim() === title.trim());
if (existing) {
await putPage(
existing.id,
{
title,
content: html,
importMarkdown: text,
parentId,
type: "file",
},
"更新导入文件"
);
return;
}
await postPage(
{
title,
content: html,
parentId: targetParentIdRef.current,
importMarkdown: text,
parentId,
type: "file",
},
"创建导入文件"
@@ -199,17 +252,32 @@ export function ImportProvider({ children }: { children: React.ReactNode }) {
const markdown = await zipFile.async("string");
const title = fileName.replace(/\.md$/i, "").replace(/\.txt$/i, "");
const html = await marked.parse(markdown);
await postPage(
{
title,
content: html,
parentId,
type: "file",
},
`创建文件 ${path}`
);
const html = markdownToImportHtml(markdown);
const existing = pages.find((p) => p.type === "file" && p.parentId === parentId && (p.title || "").trim() === title.trim());
if (existing) {
await putPage(
existing.id,
{
title,
content: html,
importMarkdown: markdown,
parentId,
type: "file",
},
`更新文件 ${path}`
);
} else {
await postPage(
{
title,
content: html,
importMarkdown: markdown,
parentId,
type: "file",
},
`创建文件 ${path}`
);
}
}
};