mirror of
https://github.com/JOYCEQL/magic-resume.git
synced 2026-07-03 14:07:11 +02:00
fix: next error
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import React, { useState, useRef, useEffect, useMemo } from "react";
|
||||
import {
|
||||
Drawer,
|
||||
@@ -47,9 +48,20 @@ const PhotoConfigDrawer: React.FC<Props> = ({
|
||||
const [config, setConfig] = useState<PhotoConfig>(
|
||||
initialConfig || DEFAULT_CONFIG
|
||||
);
|
||||
const isMobile = useMemo(() => {
|
||||
return window.innerWidth <= 768;
|
||||
}, [window.innerWidth]);
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setIsMobile(window.innerWidth <= 768);
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setConfig(initialConfig || DEFAULT_CONFIG);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
import { Settings2, Image, EyeOff, Eye } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
@@ -3,88 +3,85 @@
|
||||
import React, { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Download, Loader2 } from "lucide-react";
|
||||
import html2pdf from "html2pdf.js";
|
||||
import { useResumeStore } from "@/store/useResumeStore";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const html2pdf = dynamic(() => import("html2pdf.js"), {
|
||||
ssr: false
|
||||
});
|
||||
|
||||
export function PdfExport() {
|
||||
const { basic, theme } = useResumeStore();
|
||||
const [isExporting, setIsExporting] = useState(false);
|
||||
|
||||
const handleExport = () => {
|
||||
setIsExporting(true);
|
||||
const element = document.querySelector("#resume-preview");
|
||||
if (!element) {
|
||||
setIsExporting(false);
|
||||
return;
|
||||
}
|
||||
// 内容高度的问题
|
||||
const contentHeight = element.scrollHeight - 30.22;
|
||||
const A4_HEIGHT_MM = 297;
|
||||
const MARGINS_MM = 8;
|
||||
const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - MARGINS_MM;
|
||||
const DPI = 96;
|
||||
const MM_TO_PX = DPI / 25.4;
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
setIsExporting(true);
|
||||
|
||||
const pageHeightPx = Math.ceil(CONTENT_HEIGHT_MM * MM_TO_PX);
|
||||
const numberOfPages = Math.ceil(contentHeight / pageHeightPx);
|
||||
if (typeof window === "undefined") return;
|
||||
|
||||
const pageBreakLines = element.querySelectorAll(".page-break-line");
|
||||
pageBreakLines.forEach((line) => {
|
||||
line.style.display = "none";
|
||||
});
|
||||
const element = document.querySelector("#resume-preview");
|
||||
if (!element) {
|
||||
setIsExporting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 导出后的清理代码
|
||||
const cleanup = () => {
|
||||
const contentHeight = element.scrollHeight - 30.22;
|
||||
const A4_HEIGHT_MM = 297;
|
||||
const MARGINS_MM = 8;
|
||||
const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - MARGINS_MM;
|
||||
const DPI = 96;
|
||||
const MM_TO_PX = DPI / 25.4;
|
||||
|
||||
const pageHeightPx = Math.ceil(CONTENT_HEIGHT_MM * MM_TO_PX);
|
||||
const numberOfPages = Math.ceil(contentHeight / pageHeightPx);
|
||||
|
||||
const pageBreakLines = element.querySelectorAll(".page-break-line");
|
||||
pageBreakLines.forEach((line) => {
|
||||
line.style.display = "none";
|
||||
});
|
||||
|
||||
const html2pdfModule = await import("html2pdf.js");
|
||||
const html2pdfInstance = html2pdfModule.default;
|
||||
|
||||
const opt = {
|
||||
margin: [4, 4, 4, 4],
|
||||
filename: `${basic.name}_简历.pdf`,
|
||||
image: { type: "jpeg", quality: 0.98 },
|
||||
pagebreak: {
|
||||
mode: ["css", "legacy"]
|
||||
},
|
||||
html2canvas: {
|
||||
scale: window.devicePixelRatio * 3,
|
||||
letterRendering: true,
|
||||
scrollY: -window.scrollY,
|
||||
height: pageHeightPx * numberOfPages
|
||||
},
|
||||
jsPDF: {
|
||||
unit: "mm",
|
||||
format: "a4",
|
||||
orientation: "portrait",
|
||||
putTotalPages: false
|
||||
}
|
||||
};
|
||||
|
||||
await html2pdfInstance().set(opt).from(element).save();
|
||||
} catch (error) {
|
||||
console.error("PDF export failed:", error);
|
||||
} finally {
|
||||
const pageBreakLines = document.querySelectorAll(".page-break-line");
|
||||
pageBreakLines.forEach((line) => {
|
||||
line.style.display = "";
|
||||
});
|
||||
setIsExporting(false);
|
||||
};
|
||||
|
||||
const opt = {
|
||||
margin: [4, 4, 4, 4],
|
||||
filename: `${basic.name}_简历.pdf`,
|
||||
image: { type: "jpeg", quality: 0.98 },
|
||||
pagebreak: {
|
||||
mode: ["css", "legacy"]
|
||||
},
|
||||
html2canvas: {
|
||||
scale: window.devicePixelRatio * 3,
|
||||
letterRendering: true,
|
||||
scrollY: -window.scrollY,
|
||||
height: pageHeightPx * numberOfPages
|
||||
},
|
||||
jsPDF: {
|
||||
unit: "mm",
|
||||
format: "a4",
|
||||
orientation: "portrait",
|
||||
putTotalPages: false
|
||||
}
|
||||
};
|
||||
|
||||
html2pdf()
|
||||
.set(opt)
|
||||
.from(element)
|
||||
.save()
|
||||
.then((res: any) => {
|
||||
return res;
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error("PDF export failed:", error);
|
||||
return { notFound: true };
|
||||
})
|
||||
.finally(() => {
|
||||
setIsExporting(false);
|
||||
cleanup();
|
||||
return { finally: true };
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<motion.button
|
||||
className={`bg-indigo-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center space-x-2
|
||||
disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
className="bg-indigo-600 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center space-x-2
|
||||
disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
whileHover={!isExporting ? { scale: 1.02 } : {}}
|
||||
whileTap={!isExporting ? { scale: 0.98 } : {}}
|
||||
onClick={handleExport}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { PlusCircle, GripVertical, Trash2, Eye, EyeOff } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
Reference in New Issue
Block a user