@eternalheart/vue-file-preview 1.3.6 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/FilePreviewContent.vue.d.ts.map +1 -1
- package/lib/FilePreviewEmbed.vue.d.ts.map +1 -1
- package/lib/FilePreviewModal.vue.d.ts.map +1 -1
- package/lib/chunks/index-BI0dSTSM.mjs +77 -0
- package/lib/chunks/index-BI0dSTSM.mjs.map +1 -0
- package/lib/chunks/index-BW61ZRev.mjs +111 -0
- package/lib/chunks/index-BW61ZRev.mjs.map +1 -0
- package/lib/chunks/index-C8ZF84WX.mjs +113 -0
- package/lib/chunks/index-C8ZF84WX.mjs.map +1 -0
- package/lib/chunks/index-CB0zCxJb.mjs +353 -0
- package/lib/chunks/index-CB0zCxJb.mjs.map +1 -0
- package/lib/chunks/index-CBCQs1ZC.mjs +116 -0
- package/lib/chunks/index-CBCQs1ZC.mjs.map +1 -0
- package/lib/chunks/index-CbKSdAt_.mjs +391 -0
- package/lib/chunks/index-CbKSdAt_.mjs.map +1 -0
- package/lib/chunks/index-CcJ5NmY1.mjs +152 -0
- package/lib/chunks/index-CcJ5NmY1.mjs.map +1 -0
- package/lib/chunks/index-ClxBxmPR.mjs +249 -0
- package/lib/chunks/index-ClxBxmPR.mjs.map +1 -0
- package/lib/chunks/index-D9lByoJw.mjs +111 -0
- package/lib/chunks/index-D9lByoJw.mjs.map +1 -0
- package/lib/chunks/index-DTLDLOGO.mjs +129 -0
- package/lib/chunks/index-DTLDLOGO.mjs.map +1 -0
- package/lib/chunks/index-DUUsS_T4.mjs +134 -0
- package/lib/chunks/index-DUUsS_T4.mjs.map +1 -0
- package/lib/chunks/index-Doy0FvQW.mjs +136 -0
- package/lib/chunks/index-Doy0FvQW.mjs.map +1 -0
- package/lib/chunks/index-DpAxU2JM.mjs +2017 -0
- package/lib/chunks/index-DpAxU2JM.mjs.map +1 -0
- package/lib/chunks/index-DsznjwsH.mjs +103 -0
- package/lib/chunks/index-DsznjwsH.mjs.map +1 -0
- package/lib/chunks/index-SAfVQyNJ.mjs +281 -0
- package/lib/chunks/index-SAfVQyNJ.mjs.map +1 -0
- package/lib/chunks/index-S_kGRh6H.mjs +203 -0
- package/lib/chunks/index-S_kGRh6H.mjs.map +1 -0
- package/lib/chunks/index-kBPb_OKm.mjs +139 -0
- package/lib/chunks/index-kBPb_OKm.mjs.map +1 -0
- package/lib/chunks/index-yMb1JUC4.mjs +84 -0
- package/lib/chunks/index-yMb1JUC4.mjs.map +1 -0
- package/lib/composables/useResolvedTheme.d.ts +15 -0
- package/lib/composables/useResolvedTheme.d.ts.map +1 -0
- package/lib/index.cjs +24 -499
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +12 -44597
- package/lib/index.mjs.map +1 -1
- package/lib/renderers/Audio/index.vue.d.ts.map +1 -1
- package/lib/renderers/Csv/index.vue.d.ts.map +1 -1
- package/lib/renderers/Json/index.vue.d.ts.map +1 -1
- package/lib/renderers/Markdown/index.vue.d.ts.map +1 -1
- package/lib/renderers/Pptx/index.vue.d.ts.map +1 -1
- package/lib/renderers/RendererLoading.vue.d.ts +3 -0
- package/lib/renderers/RendererLoading.vue.d.ts.map +1 -0
- package/lib/renderers/Text/index.vue.d.ts.map +1 -1
- package/lib/renderers/Video/index.vue.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.vue.d.ts.map +1 -1
- package/lib/renderers/Xml/index.vue.d.ts.map +1 -1
- package/lib/renderers/Zip/index.vue.d.ts.map +1 -1
- package/lib/renderers/lazy.d.ts +19 -0
- package/lib/renderers/lazy.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CcJ5NmY1.mjs","sources":["../../src/renderers/Pptx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { Presentation } from 'lucide-vue-next';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst props = withDefaults(\n defineProps<{\n url: string;\n tiled?: boolean;\n }>(),\n { tiled: true }\n);\n\nconst { t } = useTranslator();\n\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst slideCount = ref(0);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet previewer: ReturnType<typeof init> | null = null;\nlet resizeObserver: ResizeObserver | null = null;\nlet arrayBufferRef: ArrayBuffer | null = null;\nlet resizeTimeout: number | null = null;\nlet lastDimensions = { width: 0, height: 0 };\n\nconst calculateDimensions = () => {\n if (!containerRef.value) return { width: 960, height: 540 };\n const rawWidth = containerRef.value.clientWidth;\n const parentWidth = containerRef.value.parentElement?.clientWidth || 0;\n const containerWidth = rawWidth > 100 ? rawWidth : parentWidth > 100 ? parentWidth : 300;\n const height = Math.floor((containerWidth * 9) / 16);\n return { width: containerWidth, height };\n};\n\nconst reinitializePreviewer = async () => {\n if (!containerRef.value || !arrayBufferRef || slideCount.value === 0) return;\n\n try {\n if (previewer) {\n try {\n previewer.destroy();\n } catch {\n // ignore\n }\n }\n\n containerRef.value.innerHTML = '';\n\n const currentDimensions = calculateDimensions();\n previewer = init(containerRef.value, {\n width: currentDimensions.width,\n height: props.tiled ? currentDimensions.height * slideCount.value : currentDimensions.height,\n mode: props.tiled ? 'list' : 'slide',\n });\n\n await previewer.preview(arrayBufferRef);\n } catch {\n // 静默处理\n }\n};\n\nconst loadPptx = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n let timeoutId: number | null = window.setTimeout(() => {\n error.value = t.value('pptx.timeout');\n loading.value = false;\n }, 30000);\n\n try {\n const response = await fetch(props.url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) throw new Error(t.value('pptx.not_found'));\n if (response.status === 403) throw new Error('无权限访问此文件');\n if (response.status >= 500) throw new Error('服务器错误,请稍后重试');\n throw new Error(`文件加载失败 (${response.status})`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n if (arrayBuffer.byteLength === 0) throw new Error('文件为空');\n\n arrayBufferRef = arrayBuffer;\n\n // 步骤 1: 创建隐藏容器获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t.value('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n if (!count || count === 0) throw new Error(t.value('pptx.no_pages'));\n\n tempPreviewer.destroy();\n\n slideCount.value = count;\n\n if (containerRef.value) {\n containerRef.value.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n previewer = init(containerRef.value, {\n width: currentDimensions.width,\n height: props.tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: props.tiled ? 'list' : 'slide',\n });\n\n await previewer.preview(arrayBuffer);\n\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n loading.value = false;\n } finally {\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n if (timeoutId !== null) clearTimeout(timeoutId);\n let errorMsg = t.value('pptx.parse_failed');\n if (err instanceof Error) errorMsg = err.message;\n else if (typeof err === 'string') errorMsg = err;\n error.value = errorMsg;\n loading.value = false;\n }\n};\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n let isInitialRender = true;\n\n resizeObserver = new ResizeObserver(() => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensions = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensions = newDimensions;\n\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n\n resizeTimeout = window.setTimeout(() => {\n if (previewer && arrayBufferRef) reinitializePreviewer();\n }, 800);\n });\n\n resizeObserver.observe(containerRef.value);\n\n setTimeout(() => {\n requestAnimationFrame(() => requestAnimationFrame(() => loadPptx()));\n }, 150);\n});\n\nwatch(\n () => props.url,\n () => {\n loadPptx();\n }\n);\n\nonBeforeUnmount(() => {\n if (resizeObserver) resizeObserver.disconnect();\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n arrayBufferRef = null;\n slideCount.value = 0;\n if (previewer) {\n try {\n previewer.destroy();\n } catch {\n // ignore\n }\n }\n previewer = null;\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full\">\n <div\n v-if=\"loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('pptx.loading') }}</p>\n </div>\n </div>\n\n <div\n v-if=\"error && !loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4\">\n <div\n class=\"vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-orange-500 vfp-via-red-500 vfp-to-pink-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl\"\n >\n <Presentation class=\"vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary\" />\n </div>\n <p class=\"vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium\">\n {{ t('pptx.load_failed') }}\n </p>\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6\">{{ error }}</p>\n <a\n :href=\"url\"\n download\n class=\"vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg\"\n >\n 下载文件\n </a>\n <p class=\"vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"containerRef\"\n class=\"pptx-wrapper vfp-w-full vfp-max-w-full md:vfp-max-w-6xl\"\n :style=\"{ opacity: loading ? 0 : 1 }\"\n />\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","loading","ref","error","slideCount","containerRef","previewer","resizeObserver","arrayBufferRef","resizeTimeout","lastDimensions","calculateDimensions","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","init","loadPptx","timeoutId","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","onMounted","isInitialRender","newDimensions","widthDiff","heightDiff","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_hoisted_4","_toDisplayString","_unref","_hoisted_5","_hoisted_6","_hoisted_7","_createVNode","Presentation","_hoisted_8","_hoisted_9","_hoisted_10","_cache"],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { defineComponent as Z, ref as h, onMounted as ee, watch as te, onBeforeUnmount as oe, openBlock as u, createElementBlock as c, createElementVNode as v, toDisplayString as E, createCommentVNode as y, normalizeStyle as b, unref as X, createVNode as re, Fragment as $, renderList as D } from "vue";
|
|
2
|
+
import ae from "@likecoin/epub-ts";
|
|
3
|
+
import { X as ne } from "lucide-vue-next";
|
|
4
|
+
import { u as le } from "./index-DpAxU2JM.mjs";
|
|
5
|
+
const se = {
|
|
6
|
+
class: "vfp-relative vfp-w-full vfp-h-full vfp-flex vfp-justify-center vfp-overflow-hidden",
|
|
7
|
+
style: { background: "#f5f5f0" }
|
|
8
|
+
}, ie = {
|
|
9
|
+
key: 0,
|
|
10
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-text-fg-secondary vfp-text-center"
|
|
11
|
+
}, fe = { class: "vfp-text-lg" }, pe = {
|
|
12
|
+
key: 1,
|
|
13
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-z-10"
|
|
14
|
+
}, ue = {
|
|
15
|
+
class: "vfp-flex vfp-items-center vfp-justify-between vfp-flex-shrink-0",
|
|
16
|
+
style: { padding: "12px 16px", "border-bottom": "1px solid rgba(255,255,255,0.1)" }
|
|
17
|
+
}, ce = { style: { color: "white", "font-weight": "500", "font-size": "14px" } }, ve = {
|
|
18
|
+
class: "vfp-flex-1 vfp-overflow-y-auto",
|
|
19
|
+
style: { padding: "8px 4px" }
|
|
20
|
+
}, de = ["title", "onClick", "onMouseenter", "onMouseleave"], he = ["title", "onClick", "onMouseenter", "onMouseleave"], ge = 794, we = /* @__PURE__ */ Z({
|
|
21
|
+
__name: "index",
|
|
22
|
+
props: {
|
|
23
|
+
url: {}
|
|
24
|
+
},
|
|
25
|
+
emits: ["chapterChange", "fullWidthChange"],
|
|
26
|
+
setup(I, { expose: O, emit: U }) {
|
|
27
|
+
const w = I, { t: R } = le(), k = U, l = h(null), _ = h(!0), g = h(null), C = h(!1), x = h([]), f = h(!1), L = h("");
|
|
28
|
+
let s = null, e = null, m = 0, S = null;
|
|
29
|
+
const F = () => {
|
|
30
|
+
var o;
|
|
31
|
+
try {
|
|
32
|
+
(o = e == null ? void 0 : e.destroy) == null || o.call(e);
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
s == null || s.destroy();
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
e = null, s = null, m = 0, S = null;
|
|
40
|
+
}, G = () => {
|
|
41
|
+
e == null || e.prev();
|
|
42
|
+
}, J = () => {
|
|
43
|
+
e == null || e.next();
|
|
44
|
+
}, K = () => {
|
|
45
|
+
C.value = !C.value, k("fullWidthChange", C.value), setTimeout(() => {
|
|
46
|
+
l.value && e && (e.resize(l.value.offsetWidth, l.value.offsetHeight), S && e.display(S), P());
|
|
47
|
+
}, 350);
|
|
48
|
+
}, Q = () => {
|
|
49
|
+
f.value = !f.value;
|
|
50
|
+
}, B = (o) => {
|
|
51
|
+
L.value = o, e == null || e.display(o), f.value = !1;
|
|
52
|
+
}, p = (o) => o === L.value;
|
|
53
|
+
O({ prevPage: G, nextPage: J, toggleFullWidth: K, toggleToc: Q });
|
|
54
|
+
const N = async () => {
|
|
55
|
+
if (l.value) {
|
|
56
|
+
_.value = !0, g.value = null, x.value = [], f.value = !1, l.value.innerHTML = "", F();
|
|
57
|
+
try {
|
|
58
|
+
let o = w.url;
|
|
59
|
+
w.url.startsWith("blob:") && (o = await (await fetch(w.url)).arrayBuffer()), s = ae(o), e = s.renderTo(l.value, {
|
|
60
|
+
manager: "continuous",
|
|
61
|
+
flow: "scrolled",
|
|
62
|
+
width: "100%",
|
|
63
|
+
height: "100%"
|
|
64
|
+
}), e.themes.register("default", {
|
|
65
|
+
body: {
|
|
66
|
+
background: "#ffffff !important",
|
|
67
|
+
color: "#1a1a1a !important",
|
|
68
|
+
"font-family": '"Noto Serif SC", "Source Han Serif SC", Georgia, "Times New Roman", serif !important',
|
|
69
|
+
"font-size": "16px !important",
|
|
70
|
+
"line-height": "2 !important",
|
|
71
|
+
padding: "40px 60px !important",
|
|
72
|
+
"max-width": "100% !important",
|
|
73
|
+
"box-sizing": "border-box !important",
|
|
74
|
+
"word-break": "break-word !important",
|
|
75
|
+
"overflow-wrap": "break-word !important"
|
|
76
|
+
},
|
|
77
|
+
p: { "text-indent": "2em !important", margin: "0.8em 0 !important" },
|
|
78
|
+
h1: { "text-align": "center !important", margin: "1.5em 0 1em !important" },
|
|
79
|
+
h2: { margin: "1.2em 0 0.8em !important" },
|
|
80
|
+
h3: { margin: "1em 0 0.6em !important" },
|
|
81
|
+
img: { "max-width": "100% !important", height: "auto !important" },
|
|
82
|
+
a: { color: "#2563eb !important", "text-decoration": "none !important" }
|
|
83
|
+
}), e.themes.select("default"), await s.ready, s.locations.generate(1024).then(() => {
|
|
84
|
+
var r;
|
|
85
|
+
if (!s) return;
|
|
86
|
+
m = s.locations.length();
|
|
87
|
+
const t = e == null ? void 0 : e.currentLocation(), n = ((r = t == null ? void 0 : t.start) == null ? void 0 : r.location) ?? 0;
|
|
88
|
+
k("chapterChange", n + 1, m);
|
|
89
|
+
}).catch(() => {
|
|
90
|
+
});
|
|
91
|
+
const a = await s.loaded.navigation;
|
|
92
|
+
Array.isArray(a == null ? void 0 : a.toc) && (x.value = a.toc), await e.display(), _.value = !1, k("chapterChange", 1, m || 1), e.on("relocated", (t) => {
|
|
93
|
+
var W, d, q;
|
|
94
|
+
const n = t;
|
|
95
|
+
if ((W = n == null ? void 0 : n.start) != null && W.cfi && (S = n.start.cfi), (d = n == null ? void 0 : n.start) != null && d.href) {
|
|
96
|
+
const A = n.start.href, H = [], V = (Y) => {
|
|
97
|
+
for (const z of Y) {
|
|
98
|
+
const T = z.href.split("#")[0];
|
|
99
|
+
T && (A === T || A.endsWith("/" + T) || A.endsWith(T)) && H.push(z.href), z.subitems && V(z.subitems);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
V(x.value), H.length === 1 && (L.value = H[0]);
|
|
103
|
+
}
|
|
104
|
+
const r = (q = n == null ? void 0 : n.start) == null ? void 0 : q.location;
|
|
105
|
+
typeof r == "number" && m > 0 && k("chapterChange", r + 1, m);
|
|
106
|
+
});
|
|
107
|
+
} catch (o) {
|
|
108
|
+
console.error("EPUB 加载错误:", o), g.value = R.value("epub.load_failed"), _.value = !1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, j = () => {
|
|
112
|
+
!l.value || !e || e.resize(l.value.offsetWidth, l.value.offsetHeight);
|
|
113
|
+
};
|
|
114
|
+
let i = null;
|
|
115
|
+
const M = () => {
|
|
116
|
+
var a;
|
|
117
|
+
if (!i) return;
|
|
118
|
+
const o = i;
|
|
119
|
+
if (o.scrollTop + o.clientHeight >= o.scrollHeight - 200)
|
|
120
|
+
try {
|
|
121
|
+
const t = e == null ? void 0 : e.manager;
|
|
122
|
+
(a = t == null ? void 0 : t.check) == null || a.call(t, 500, 500);
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
}, P = () => {
|
|
126
|
+
i && (i.removeEventListener("scroll", M), i = null);
|
|
127
|
+
const o = () => {
|
|
128
|
+
var a;
|
|
129
|
+
i = ((a = l.value) == null ? void 0 : a.querySelector(".epub-container")) ?? null, i ? i.addEventListener("scroll", M, { passive: !0 }) : requestAnimationFrame(o);
|
|
130
|
+
};
|
|
131
|
+
requestAnimationFrame(o);
|
|
132
|
+
};
|
|
133
|
+
return ee(() => {
|
|
134
|
+
N(), window.addEventListener("resize", j), P();
|
|
135
|
+
}), te(() => w.url, () => N()), oe(() => {
|
|
136
|
+
window.removeEventListener("resize", j), i == null || i.removeEventListener("scroll", M), F();
|
|
137
|
+
}), (o, a) => (u(), c("div", se, [
|
|
138
|
+
g.value ? (u(), c("div", ie, [
|
|
139
|
+
v("p", fe, E(g.value), 1)
|
|
140
|
+
])) : y("", !0),
|
|
141
|
+
_.value && !g.value ? (u(), c("div", pe, [...a[2] || (a[2] = [
|
|
142
|
+
v("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
143
|
+
])])) : y("", !0),
|
|
144
|
+
x.value.length > 0 ? (u(), c("div", {
|
|
145
|
+
key: 2,
|
|
146
|
+
class: "vfp-absolute vfp-inset-0 vfp-z-20 vfp-flex",
|
|
147
|
+
style: b({ opacity: f.value ? 1 : 0, pointerEvents: f.value ? "auto" : "none", transition: "opacity 0.3s" })
|
|
148
|
+
}, [
|
|
149
|
+
v("div", {
|
|
150
|
+
class: "vfp-w-72 vfp-h-full vfp-flex vfp-flex-col",
|
|
151
|
+
style: b({
|
|
152
|
+
maxWidth: "80%",
|
|
153
|
+
background: "rgba(0,0,0,0.9)",
|
|
154
|
+
backdropFilter: "blur(12px)",
|
|
155
|
+
borderRight: "1px solid rgba(255,255,255,0.1)",
|
|
156
|
+
boxShadow: "0 25px 50px -12px rgba(0,0,0,0.25)",
|
|
157
|
+
transform: f.value ? "translateX(0)" : "translateX(-100%)",
|
|
158
|
+
transition: "transform 0.3s ease"
|
|
159
|
+
})
|
|
160
|
+
}, [
|
|
161
|
+
v("div", ue, [
|
|
162
|
+
v("span", ce, E(X(R)("toolbar.toc")), 1),
|
|
163
|
+
v("button", {
|
|
164
|
+
style: { color: "rgba(255,255,255,0.6)", background: "none", border: "none", cursor: "pointer", padding: "4px" },
|
|
165
|
+
onClick: a[0] || (a[0] = (t) => f.value = !1)
|
|
166
|
+
}, [
|
|
167
|
+
re(X(ne), { style: { width: "16px", height: "16px" } })
|
|
168
|
+
])
|
|
169
|
+
]),
|
|
170
|
+
v("div", ve, [
|
|
171
|
+
(u(!0), c($, null, D(x.value, (t, n) => (u(), c($, {
|
|
172
|
+
key: `${t.href}-${n}`
|
|
173
|
+
}, [
|
|
174
|
+
v("button", {
|
|
175
|
+
style: b({
|
|
176
|
+
width: "100%",
|
|
177
|
+
textAlign: "left",
|
|
178
|
+
padding: "8px 12px",
|
|
179
|
+
fontSize: "14px",
|
|
180
|
+
color: p(t.href) ? "white" : "rgba(255,255,255,0.7)",
|
|
181
|
+
fontWeight: p(t.href) ? "500" : "400",
|
|
182
|
+
background: p(t.href) ? "rgba(255,255,255,0.15)" : "none",
|
|
183
|
+
border: "none",
|
|
184
|
+
cursor: "pointer",
|
|
185
|
+
borderRadius: "4px",
|
|
186
|
+
overflow: "hidden",
|
|
187
|
+
textOverflow: "ellipsis",
|
|
188
|
+
whiteSpace: "nowrap",
|
|
189
|
+
display: "block",
|
|
190
|
+
transition: "all 0.15s"
|
|
191
|
+
}),
|
|
192
|
+
title: t.label,
|
|
193
|
+
onClick: (r) => B(t.href),
|
|
194
|
+
onMouseenter: (r) => !p(t.href) && (r.target.style.background = "rgba(255,255,255,0.1)"),
|
|
195
|
+
onMouseleave: (r) => !p(t.href) && (r.target.style.background = "none")
|
|
196
|
+
}, E(t.label.trim()), 45, de),
|
|
197
|
+
t.subitems && t.subitems.length > 0 ? (u(!0), c($, { key: 0 }, D(t.subitems, (r, W) => (u(), c("button", {
|
|
198
|
+
key: `${r.href}-${W}`,
|
|
199
|
+
style: b({
|
|
200
|
+
width: "100%",
|
|
201
|
+
textAlign: "left",
|
|
202
|
+
padding: "8px 12px 8px 28px",
|
|
203
|
+
fontSize: "13px",
|
|
204
|
+
color: p(r.href) ? "white" : "rgba(255,255,255,0.6)",
|
|
205
|
+
fontWeight: p(r.href) ? "500" : "400",
|
|
206
|
+
background: p(r.href) ? "rgba(255,255,255,0.15)" : "none",
|
|
207
|
+
border: "none",
|
|
208
|
+
cursor: "pointer",
|
|
209
|
+
borderRadius: "4px",
|
|
210
|
+
overflow: "hidden",
|
|
211
|
+
textOverflow: "ellipsis",
|
|
212
|
+
whiteSpace: "nowrap",
|
|
213
|
+
display: "block",
|
|
214
|
+
transition: "all 0.15s"
|
|
215
|
+
}),
|
|
216
|
+
title: r.label,
|
|
217
|
+
onClick: (d) => B(r.href),
|
|
218
|
+
onMouseenter: (d) => !p(r.href) && (d.target.style.background = "rgba(255,255,255,0.1)"),
|
|
219
|
+
onMouseleave: (d) => !p(r.href) && (d.target.style.background = "none")
|
|
220
|
+
}, E(r.label.trim()), 45, he))), 128)) : y("", !0)
|
|
221
|
+
], 64))), 128))
|
|
222
|
+
])
|
|
223
|
+
], 4),
|
|
224
|
+
v("div", {
|
|
225
|
+
class: "vfp-flex-1",
|
|
226
|
+
style: b({ background: f.value ? "rgba(0,0,0,0.3)" : "transparent", transition: "background 0.3s" }),
|
|
227
|
+
onClick: a[1] || (a[1] = (t) => f.value = !1)
|
|
228
|
+
}, null, 4)
|
|
229
|
+
], 4)) : y("", !0),
|
|
230
|
+
g.value ? y("", !0) : (u(), c("div", {
|
|
231
|
+
key: 3,
|
|
232
|
+
ref_key: "viewerRef",
|
|
233
|
+
ref: l,
|
|
234
|
+
class: "vfp-h-full vfp-bg-surface-toolbar",
|
|
235
|
+
style: b({
|
|
236
|
+
width: C.value ? "100%" : `${ge}px`,
|
|
237
|
+
maxWidth: "100%",
|
|
238
|
+
transition: "width 0.3s ease",
|
|
239
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.12)",
|
|
240
|
+
overflow: "hidden"
|
|
241
|
+
})
|
|
242
|
+
}, null, 4))
|
|
243
|
+
]));
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
export {
|
|
247
|
+
we as default
|
|
248
|
+
};
|
|
249
|
+
//# sourceMappingURL=index-ClxBxmPR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-ClxBxmPR.mjs","sources":["../../src/renderers/Epub/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport ePub from '@likecoin/epub-ts';\nimport { X } from 'lucide-vue-next';\nimport { useTranslator } from '../../composables/useTranslator';\n\ninterface TocItem {\n label: string;\n href: string;\n subitems?: TocItem[];\n}\n\ninterface RenditionLike {\n display: (target?: string) => Promise<unknown>;\n next: () => Promise<unknown>;\n prev: () => Promise<unknown>;\n on: (event: string, cb: (...args: unknown[]) => void) => void;\n resize: (width: number, height: number) => void;\n currentLocation: () => unknown;\n destroy?: () => void;\n themes: {\n register: (name: string, styles: Record<string, unknown>) => void;\n select: (name: string) => void;\n };\n}\n\ninterface BookLike {\n ready: Promise<unknown>;\n loaded: { navigation: Promise<unknown> };\n locations: {\n generate: (chars: number) => Promise<string[]>;\n length: () => number;\n locationFromCfi: (cfi: string) => number;\n };\n renderTo: (el: HTMLElement, opts: Record<string, unknown>) => RenditionLike;\n destroy: () => void;\n}\n\nconst A4_WIDTH = 794;\n\nconst props = defineProps<{ url: string }>();\n\nconst { t } = useTranslator();\n\nconst emit = defineEmits<{\n (e: 'chapterChange', current: number, total: number): void;\n (e: 'fullWidthChange', isFullWidth: boolean): void;\n}>();\n\nconst viewerRef = ref<HTMLDivElement | null>(null);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst isFullWidth = ref(false);\nconst toc = ref<TocItem[]>([]);\nconst showToc = ref(false);\nconst activeTocHref = ref('');\n\nlet book: BookLike | null = null;\nlet rendition: RenditionLike | null = null;\nlet totalLocations = 0;\nlet lastCfi: string | null = null;\n\nconst cleanup = () => {\n try { rendition?.destroy?.(); } catch { /* ignore */ }\n try { book?.destroy(); } catch { /* ignore */ }\n rendition = null;\n book = null;\n totalLocations = 0;\n lastCfi = null;\n};\n\nconst prevPage = () => { rendition?.prev(); };\nconst nextPage = () => { rendition?.next(); };\nconst toggleFullWidth = () => {\n isFullWidth.value = !isFullWidth.value;\n emit('fullWidthChange', isFullWidth.value);\n setTimeout(() => {\n if (viewerRef.value && rendition) {\n rendition.resize(viewerRef.value.offsetWidth, viewerRef.value.offsetHeight);\n if (lastCfi) {\n rendition.display(lastCfi);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }\n }, 350);\n};\nconst toggleToc = () => { showToc.value = !showToc.value; };\nconst handleTocClick = (href: string) => {\n activeTocHref.value = href;\n rendition?.display(href);\n showToc.value = false;\n};\n\nconst isActive = (href: string) => {\n return href === activeTocHref.value;\n};\n\ndefineExpose({ prevPage, nextPage, toggleFullWidth, toggleToc });\n\nconst loadEpub = async () => {\n if (!viewerRef.value) return;\n\n loading.value = true;\n error.value = null;\n toc.value = [];\n showToc.value = false;\n viewerRef.value.innerHTML = '';\n cleanup();\n\n try {\n let bookInput: string | ArrayBuffer = props.url;\n if (props.url.startsWith('blob:')) {\n const resp = await fetch(props.url);\n bookInput = await resp.arrayBuffer();\n }\n\n book = ePub(bookInput) as unknown as BookLike;\n\n rendition = book.renderTo(viewerRef.value, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n\n rendition.themes.register('default', {\n body: {\n background: '#ffffff !important',\n color: '#1a1a1a !important',\n 'font-family': '\"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important',\n 'font-size': '16px !important',\n 'line-height': '2 !important',\n padding: '40px 60px !important',\n 'max-width': '100% !important',\n 'box-sizing': 'border-box !important',\n 'word-break': 'break-word !important',\n 'overflow-wrap': 'break-word !important',\n },\n p: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引\n book.locations.generate(1024).then(() => {\n if (!book) return;\n totalLocations = book.locations.length();\n const loc = rendition?.currentLocation() as { start?: { location?: number } } | undefined;\n const cur = loc?.start?.location ?? 0;\n emit('chapterChange', cur + 1, totalLocations);\n }).catch(() => { /* ignore */ });\n\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (Array.isArray(nav?.toc)) {\n toc.value = nav.toc;\n }\n\n await rendition.display();\n\n loading.value = false;\n emit('chapterChange', 1, totalLocations || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfi = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(toc.value);\n if (matches.length === 1) {\n activeTocHref.value = matches[0];\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n if (typeof cur === 'number' && totalLocations > 0) {\n emit('chapterChange', cur + 1, totalLocations);\n }\n });\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n error.value = t.value('epub.load_failed');\n loading.value = false;\n }\n};\n\nconst onResize = () => {\n if (!viewerRef.value || !rendition) return;\n rendition.resize(viewerRef.value.offsetWidth, viewerRef.value.offsetHeight);\n};\n\n// 监听 epub-container 滚动,接近底部时强制加载后续 section\nlet scrollContainer: Element | null = null;\nconst onContainerScroll = () => {\n if (!scrollContainer) return;\n const el = scrollContainer as HTMLElement;\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 200) {\n try {\n const mgr = (rendition as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n // 传递垂直偏移量参数,让 check() 在接近底部时就触发加载下一节\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n};\n\nconst reattachScrollListener = () => {\n // 清理旧监听\n if (scrollContainer) {\n scrollContainer.removeEventListener('scroll', onContainerScroll);\n scrollContainer = null;\n }\n const tryAttach = () => {\n scrollContainer = viewerRef.value?.querySelector('.epub-container') ?? null;\n if (scrollContainer) {\n scrollContainer.addEventListener('scroll', onContainerScroll, { passive: true });\n } else {\n requestAnimationFrame(tryAttach);\n }\n };\n requestAnimationFrame(tryAttach);\n};\n\nonMounted(() => {\n loadEpub();\n window.addEventListener('resize', onResize);\n reattachScrollListener();\n});\n\nwatch(() => props.url, () => loadEpub());\n\nonBeforeUnmount(() => {\n window.removeEventListener('resize', onResize);\n scrollContainer?.removeEventListener('scroll', onContainerScroll);\n cleanup();\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-w-full vfp-h-full vfp-flex vfp-justify-center vfp-overflow-hidden\" style=\"background: #f5f5f0\">\n <div v-if=\"error\" class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error }}</p>\n </div>\n\n <div\n v-if=\"loading && !error\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-z-10\"\n >\n <div class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\" />\n </div>\n\n <!-- 目录侧栏 - 滑入动画 -->\n <div\n v-if=\"toc.length > 0\"\n class=\"vfp-absolute vfp-inset-0 vfp-z-20 vfp-flex\"\n :style=\"{ opacity: showToc ? 1 : 0, pointerEvents: showToc ? 'auto' : 'none', transition: 'opacity 0.3s' }\"\n >\n <div\n class=\"vfp-w-72 vfp-h-full vfp-flex vfp-flex-col\"\n :style=\"{\n maxWidth: '80%',\n background: 'rgba(0,0,0,0.9)',\n backdropFilter: 'blur(12px)',\n borderRight: '1px solid rgba(255,255,255,0.1)',\n boxShadow: '0 25px 50px -12px rgba(0,0,0,0.25)',\n transform: showToc ? 'translateX(0)' : 'translateX(-100%)',\n transition: 'transform 0.3s ease',\n }\"\n >\n <div class=\"vfp-flex vfp-items-center vfp-justify-between vfp-flex-shrink-0\" style=\"padding: 12px 16px; border-bottom: 1px solid rgba(255,255,255,0.1)\">\n <span style=\"color: white; font-weight: 500; font-size: 14px\">{{ t('toolbar.toc') }}</span>\n <button style=\"color: rgba(255,255,255,0.6); background: none; border: none; cursor: pointer; padding: 4px\" @click=\"showToc = false\">\n <X style=\"width: 16px; height: 16px\" />\n </button>\n </div>\n <div class=\"vfp-flex-1 vfp-overflow-y-auto\" style=\"padding: 8px 4px\">\n <template v-for=\"(item, i) in toc\" :key=\"`${item.href}-${i}`\">\n <button\n :style=\"{\n width: '100%', textAlign: 'left', padding: '8px 12px', fontSize: '14px',\n color: isActive(item.href) ? 'white' : 'rgba(255,255,255,0.7)',\n fontWeight: isActive(item.href) ? '500' : '400',\n background: isActive(item.href) ? 'rgba(255,255,255,0.15)' : 'none',\n border: 'none', cursor: 'pointer', borderRadius: '4px',\n overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block',\n transition: 'all 0.15s',\n }\"\n :title=\"item.label\"\n @click=\"handleTocClick(item.href)\"\n @mouseenter=\"!isActive(item.href) && (($event.target as HTMLElement).style.background = 'rgba(255,255,255,0.1)')\"\n @mouseleave=\"!isActive(item.href) && (($event.target as HTMLElement).style.background = 'none')\"\n >\n {{ item.label.trim() }}\n </button>\n <template v-if=\"item.subitems && item.subitems.length > 0\">\n <button\n v-for=\"(sub, j) in item.subitems\"\n :key=\"`${sub.href}-${j}`\"\n :style=\"{\n width: '100%', textAlign: 'left', padding: '8px 12px 8px 28px', fontSize: '13px',\n color: isActive(sub.href) ? 'white' : 'rgba(255,255,255,0.6)',\n fontWeight: isActive(sub.href) ? '500' : '400',\n background: isActive(sub.href) ? 'rgba(255,255,255,0.15)' : 'none',\n border: 'none', cursor: 'pointer', borderRadius: '4px',\n overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block',\n transition: 'all 0.15s',\n }\"\n :title=\"sub.label\"\n @click=\"handleTocClick(sub.href)\"\n @mouseenter=\"!isActive(sub.href) && (($event.target as HTMLElement).style.background = 'rgba(255,255,255,0.1)')\"\n @mouseleave=\"!isActive(sub.href) && (($event.target as HTMLElement).style.background = 'none')\"\n >\n {{ sub.label.trim() }}\n </button>\n </template>\n </template>\n </div>\n </div>\n <div\n class=\"vfp-flex-1\"\n :style=\"{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent', transition: 'background 0.3s' }\"\n @click=\"showToc = false\"\n />\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"viewerRef\"\n class=\"vfp-h-full vfp-bg-surface-toolbar\"\n :style=\"{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n boxShadow: '0 1px 3px rgba(0,0,0,0.12)',\n overflow: 'hidden',\n }\"\n />\n </div>\n</template>\n\n<style>\n.epub-container { overflow-y: auto !important; scrollbar-width: thin; }\n.epub-container::-webkit-scrollbar { width: 8px; }\n.epub-container::-webkit-scrollbar-track { background: transparent; }\n.epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }\n.epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }\n.epub-view > iframe { background: white; }\n</style>\n"],"names":["A4_WIDTH","props","__props","t","useTranslator","emit","__emit","viewerRef","ref","loading","error","isFullWidth","toc","showToc","activeTocHref","book","rendition","totalLocations","lastCfi","cleanup","_a","prevPage","nextPage","toggleFullWidth","reattachScrollListener","toggleToc","handleTocClick","href","isActive","__expose","loadEpub","bookInput","ePub","loc","cur","nav","location","_b","spineHref","matches","collect","items","item","base","_c","err","onResize","scrollContainer","onContainerScroll","el","mgr","tryAttach","onMounted","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_toDisplayString","_hoisted_4","_cache","_normalizeStyle","_hoisted_5","_hoisted_6","_unref","_createVNode","X","_hoisted_7","_Fragment","_renderList","i","$event","_hoisted_8","sub","j","_hoisted_9"],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { defineComponent as H, ref as x, onMounted as M, watch as S, onBeforeUnmount as j, openBlock as u, createElementBlock as g, createElementVNode as y, toDisplayString as b, createCommentVNode as w, withDirectives as W, vShow as q, nextTick as A } from "vue";
|
|
2
|
+
import { S as F, u as I } from "./index-DpAxU2JM.mjs";
|
|
3
|
+
import * as D from "pdfjs-dist/build/pdf.mjs";
|
|
4
|
+
const N = {
|
|
5
|
+
key: 0,
|
|
6
|
+
class: "vfp-text-fg-secondary vfp-text-center"
|
|
7
|
+
}, U = { class: "vfp-text-lg" }, G = {
|
|
8
|
+
key: 1,
|
|
9
|
+
class: "vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen"
|
|
10
|
+
}, J = { class: "pdf-pages vfp-flex vfp-flex-col vfp-gap-4" }, K = {
|
|
11
|
+
key: 2,
|
|
12
|
+
class: "vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak"
|
|
13
|
+
}, X = /* @__PURE__ */ H({
|
|
14
|
+
__name: "index",
|
|
15
|
+
props: {
|
|
16
|
+
url: {},
|
|
17
|
+
zoom: {},
|
|
18
|
+
currentPage: {}
|
|
19
|
+
},
|
|
20
|
+
emits: ["pageChange", "totalPagesChange", "pageWidthChange"],
|
|
21
|
+
setup(C, { emit: R }) {
|
|
22
|
+
F(D);
|
|
23
|
+
const p = C, v = R, { t: V } = I(), l = x(0), i = x(null), r = x(null);
|
|
24
|
+
let n = null;
|
|
25
|
+
const m = [], B = async (e, o, a) => {
|
|
26
|
+
if (!n) return;
|
|
27
|
+
const c = await n.getPage(e), s = c.getViewport({ scale: o }), t = document.createElement("canvas");
|
|
28
|
+
t.width = s.width, t.height = s.height, t.style.maxWidth = "100%", t.style.height = "auto", t.style.borderRadius = "0", t.style.display = "block", t.style.boxShadow = "0 25px 50px -12px rgba(0,0,0,0.25)", t.style.filter = "brightness(0.95) contrast(1.05)";
|
|
29
|
+
const d = t.getContext("2d");
|
|
30
|
+
if (!d) return;
|
|
31
|
+
if (await c.render({ canvasContext: d, viewport: s }).promise, e === 1) {
|
|
32
|
+
const h = c.getViewport({ scale: 1 });
|
|
33
|
+
v("pageWidthChange", h.width);
|
|
34
|
+
}
|
|
35
|
+
a.innerHTML = "", a.appendChild(t);
|
|
36
|
+
const f = document.createElement("div");
|
|
37
|
+
f.textContent = String(e), f.style.cssText = "position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;", a.appendChild(f);
|
|
38
|
+
}, k = async () => {
|
|
39
|
+
if (!n || !r.value) return;
|
|
40
|
+
const e = r.value.querySelector(".pdf-pages");
|
|
41
|
+
if (e) {
|
|
42
|
+
e.innerHTML = "", m.length = 0;
|
|
43
|
+
for (let o = 1; o <= l.value; o++) {
|
|
44
|
+
const a = document.createElement("div");
|
|
45
|
+
a.style.cssText = "position:relative;display:flex;justify-content:center;", e.appendChild(a), m.push(a), await B(o, p.zoom, a);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, _ = async () => {
|
|
49
|
+
if (i.value = null, l.value = 0, n) {
|
|
50
|
+
try {
|
|
51
|
+
n.destroy();
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
n = null;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
n = await D.getDocument({ url: p.url }).promise, l.value = n.numPages, v("totalPagesChange", n.numPages), v("pageChange", 1), await A(), await k();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error("PDF 加载错误:", e), i.value = V.value("pdf.load_failed");
|
|
60
|
+
}
|
|
61
|
+
}, P = () => {
|
|
62
|
+
if (!r.value) return;
|
|
63
|
+
const e = r.value, o = e.scrollTop, a = e.clientHeight, c = o + a / 2;
|
|
64
|
+
let s = 1, t = 1 / 0;
|
|
65
|
+
m.forEach((d, f) => {
|
|
66
|
+
const h = f + 1, T = d.getBoundingClientRect(), L = e.getBoundingClientRect(), z = T.top - L.top + T.height / 2 + o, E = Math.abs(z - c);
|
|
67
|
+
E < t && (t = E, s = h);
|
|
68
|
+
}), s !== p.currentPage && v("pageChange", s);
|
|
69
|
+
};
|
|
70
|
+
return M(() => {
|
|
71
|
+
_(), r.value && r.value.addEventListener("scroll", P);
|
|
72
|
+
}), S(
|
|
73
|
+
() => p.url,
|
|
74
|
+
() => {
|
|
75
|
+
_();
|
|
76
|
+
}
|
|
77
|
+
), S(
|
|
78
|
+
() => p.zoom,
|
|
79
|
+
() => {
|
|
80
|
+
k();
|
|
81
|
+
}
|
|
82
|
+
), j(() => {
|
|
83
|
+
if (r.value && r.value.removeEventListener("scroll", P), n) {
|
|
84
|
+
try {
|
|
85
|
+
n.destroy();
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
n = null;
|
|
89
|
+
}
|
|
90
|
+
}), (e, o) => (u(), g("div", {
|
|
91
|
+
ref_key: "containerRef",
|
|
92
|
+
ref: r,
|
|
93
|
+
class: "vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4"
|
|
94
|
+
}, [
|
|
95
|
+
i.value ? (u(), g("div", N, [
|
|
96
|
+
y("p", U, b(i.value), 1)
|
|
97
|
+
])) : w("", !0),
|
|
98
|
+
!i.value && l.value === 0 ? (u(), g("div", G, [...o[0] || (o[0] = [
|
|
99
|
+
y("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
100
|
+
])])) : w("", !0),
|
|
101
|
+
W(y("div", J, null, 512), [
|
|
102
|
+
[q, !i.value && l.value > 0]
|
|
103
|
+
]),
|
|
104
|
+
l.value > 0 ? (u(), g("div", K, " 第 " + b(C.currentPage) + " 页 / 共 " + b(l.value) + " 页 ", 1)) : w("", !0)
|
|
105
|
+
], 512));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
export {
|
|
109
|
+
X as default
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=index-D9lByoJw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-D9lByoJw.mjs","sources":["../../src/renderers/Pdf/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';\nimport { configurePdfWorker } from '@eternalheart/file-preview-core';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\nimport { useTranslator } from '../../composables/useTranslator';\n\n// 在模块加载时配置 PDF.js worker(默认走 CDN)\nconfigurePdfWorker(pdfjsLib);\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\nconst props = defineProps<{\n url: string;\n zoom: number;\n currentPage: number;\n}>();\n\nconst emit = defineEmits<{\n (e: 'pageChange', page: number): void;\n (e: 'totalPagesChange', total: number): void;\n (e: 'pageWidthChange', width: number): void;\n}>();\n\nconst { t } = useTranslator();\n\nconst numPages = ref(0);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet pdfDoc: PdfDocumentProxy | null = null;\nconst pageElements: HTMLDivElement[] = [];\n\nconst renderPage = async (pageNumber: number, scale: number, container: HTMLDivElement) => {\n if (!pdfDoc) return;\n const page = await pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n canvas.style.boxShadow = '0 25px 50px -12px rgba(0,0,0,0.25)';\n canvas.style.filter = 'brightness(0.95) contrast(1.05)';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n await page.render({ canvasContext: ctx, viewport }).promise;\n\n // 上报第一页原始宽度\n if (pageNumber === 1) {\n const baseViewport = page.getViewport({ scale: 1 });\n emit('pageWidthChange', baseViewport.width);\n }\n\n container.innerHTML = '';\n container.appendChild(canvas);\n\n // 页码标签\n const label = document.createElement('div');\n label.textContent = String(pageNumber);\n label.style.cssText =\n 'position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;';\n container.appendChild(label);\n};\n\nconst renderAll = async () => {\n if (!pdfDoc || !containerRef.value) return;\n const wrapper = containerRef.value.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n wrapper.innerHTML = '';\n pageElements.length = 0;\n\n for (let i = 1; i <= numPages.value; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.style.cssText = 'position:relative;display:flex;justify-content:center;';\n wrapper.appendChild(pageDiv);\n pageElements.push(pageDiv);\n // eslint-disable-next-line no-await-in-loop\n await renderPage(i, props.zoom, pageDiv);\n }\n};\n\nconst loadPdf = async () => {\n error.value = null;\n numPages.value = 0;\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url: props.url });\n pdfDoc = (await loadingTask.promise) as PdfDocumentProxy;\n numPages.value = pdfDoc.numPages;\n emit('totalPagesChange', pdfDoc.numPages);\n emit('pageChange', 1);\n await nextTick();\n await renderAll();\n } catch (err) {\n console.error('PDF 加载错误:', err);\n error.value = t.value('pdf.load_failed');\n }\n};\n\nconst handleScroll = () => {\n if (!containerRef.value) return;\n\n const container = containerRef.value;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageElements.forEach((pageEl, idx) => {\n const pageNumber = idx + 1;\n const rect = pageEl.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== props.currentPage) {\n emit('pageChange', currentVisiblePage);\n }\n};\n\nonMounted(() => {\n loadPdf();\n if (containerRef.value) {\n containerRef.value.addEventListener('scroll', handleScroll);\n }\n});\n\nwatch(\n () => props.url,\n () => {\n loadPdf();\n }\n);\n\nwatch(\n () => props.zoom,\n () => {\n renderAll();\n }\n);\n\nonBeforeUnmount(() => {\n if (containerRef.value) {\n containerRef.value.removeEventListener('scroll', handleScroll);\n }\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n});\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4\"\n >\n <div v-if=\"error\" class=\"vfp-text-fg-secondary vfp-text-center\">\n <p class=\"vfp-text-lg\">{{ error }}</p>\n </div>\n\n <div v-if=\"!error && numPages === 0\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen\">\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <div v-show=\"!error && numPages > 0\" class=\"pdf-pages vfp-flex vfp-flex-col vfp-gap-4\" />\n\n <div\n v-if=\"numPages > 0\"\n class=\"vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak\"\n >\n 第 {{ currentPage }} 页 / 共 {{ numPages }} 页\n </div>\n </div>\n</template>\n"],"names":["configurePdfWorker","pdfjsLib","props","__props","emit","__emit","t","useTranslator","numPages","ref","error","containerRef","pdfDoc","pageElements","renderPage","pageNumber","scale","container","page","viewport","canvas","ctx","baseViewport","label","renderAll","wrapper","i","pageDiv","loadPdf","nextTick","err","handleScroll","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","pageEl","idx","rect","containerRect","pageCenter","distance","onMounted","watch","onBeforeUnmount","_createElementBlock","_openBlock","_hoisted_1","_createElementVNode","_hoisted_2","_toDisplayString","_hoisted_3","_cache","_withDirectives","_hoisted_4","_vShow","_hoisted_5"],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { defineComponent as E, ref as h, onMounted as T, watch as D, onBeforeUnmount as M, openBlock as u, createElementBlock as c, createElementVNode as s, toDisplayString as x, unref as w, createCommentVNode as g, createVNode as S, normalizeStyle as z } from "vue";
|
|
2
|
+
import { FileSpreadsheet as W } from "lucide-vue-next";
|
|
3
|
+
import B from "exceljs";
|
|
4
|
+
import C from "x-data-spreadsheet";
|
|
5
|
+
/* empty css */
|
|
6
|
+
import { u as H, C as R } from "./index-DpAxU2JM.mjs";
|
|
7
|
+
const j = { class: "vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full" }, L = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10"
|
|
10
|
+
}, N = { class: "vfp-text-center" }, V = { class: "vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium" }, F = {
|
|
11
|
+
key: 1,
|
|
12
|
+
class: "vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10"
|
|
13
|
+
}, O = { class: "vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4" }, q = { class: "vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-green-500 vfp-via-emerald-500 vfp-to-teal-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl" }, A = { class: "vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium" }, G = { class: "vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6" }, I = ["href"], X = /* @__PURE__ */ E({
|
|
14
|
+
__name: "index",
|
|
15
|
+
props: {
|
|
16
|
+
url: {}
|
|
17
|
+
},
|
|
18
|
+
setup(b) {
|
|
19
|
+
const _ = b, { t: p } = H(), o = h(!0), l = h(null), r = h(null);
|
|
20
|
+
let n = null, v = null, a = null, d = { width: 0, height: 0 };
|
|
21
|
+
const m = () => {
|
|
22
|
+
if (!r.value) return { width: 800, height: 600 };
|
|
23
|
+
const e = r.value.clientWidth, t = r.value.clientHeight, f = e > 100 ? e : 800, i = t > 100 ? t : 600;
|
|
24
|
+
return { width: f, height: i };
|
|
25
|
+
}, y = () => {
|
|
26
|
+
if (!r.value || !n) return;
|
|
27
|
+
r.value.innerHTML = "";
|
|
28
|
+
const { width: e, height: t } = m(), f = e < 640;
|
|
29
|
+
new C(r.value, {
|
|
30
|
+
mode: "read",
|
|
31
|
+
showToolbar: !1,
|
|
32
|
+
showContextmenu: !1,
|
|
33
|
+
showGrid: !0,
|
|
34
|
+
row: {
|
|
35
|
+
len: 100,
|
|
36
|
+
height: 25
|
|
37
|
+
},
|
|
38
|
+
col: {
|
|
39
|
+
len: 26,
|
|
40
|
+
width: f ? 80 : 100,
|
|
41
|
+
indexWidth: f ? 40 : 60,
|
|
42
|
+
minWidth: f ? 40 : 60
|
|
43
|
+
},
|
|
44
|
+
view: {
|
|
45
|
+
height: () => t,
|
|
46
|
+
width: () => e
|
|
47
|
+
}
|
|
48
|
+
}).loadData(n);
|
|
49
|
+
}, k = async () => {
|
|
50
|
+
if (r.value) {
|
|
51
|
+
o.value = !0, l.value = null;
|
|
52
|
+
try {
|
|
53
|
+
const e = await fetch(_.url, {
|
|
54
|
+
mode: "cors",
|
|
55
|
+
credentials: "omit",
|
|
56
|
+
redirect: "follow"
|
|
57
|
+
});
|
|
58
|
+
if (!e.ok)
|
|
59
|
+
throw e.status === 404 ? new Error(p.value("xlsx.not_found")) : e.status === 403 ? new Error("无权限访问此文件") : new Error(`文件加载失败 (${e.status})`);
|
|
60
|
+
const t = await e.arrayBuffer();
|
|
61
|
+
if (t.byteLength === 0)
|
|
62
|
+
throw new Error("文件为空");
|
|
63
|
+
const f = new B.Workbook();
|
|
64
|
+
await f.xlsx.load(t), n = R(f), y(), o.value = !1;
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.error("Excel 解析错误:", e);
|
|
67
|
+
let t = p.value("xlsx.parse_failed");
|
|
68
|
+
e instanceof Error && (t = e.message), l.value = t, o.value = !1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return T(() => {
|
|
73
|
+
if (!r.value) return;
|
|
74
|
+
let e = !0;
|
|
75
|
+
v = new ResizeObserver(() => {
|
|
76
|
+
if (e) {
|
|
77
|
+
e = !1, d = m();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const t = m(), f = Math.abs(d.width - t.width), i = Math.abs(d.height - t.height);
|
|
81
|
+
f < 10 && i < 10 || (d = t, a !== null && clearTimeout(a), a = window.setTimeout(() => {
|
|
82
|
+
n && y();
|
|
83
|
+
}, 500));
|
|
84
|
+
}), v.observe(r.value), setTimeout(() => {
|
|
85
|
+
requestAnimationFrame(() => k());
|
|
86
|
+
}, 100);
|
|
87
|
+
}), D(
|
|
88
|
+
() => _.url,
|
|
89
|
+
() => {
|
|
90
|
+
k();
|
|
91
|
+
}
|
|
92
|
+
), M(() => {
|
|
93
|
+
v && v.disconnect(), a !== null && clearTimeout(a), n = null, r.value && (r.value.innerHTML = "");
|
|
94
|
+
}), (e, t) => (u(), c("div", j, [
|
|
95
|
+
o.value ? (u(), c("div", L, [
|
|
96
|
+
s("div", N, [
|
|
97
|
+
t[0] || (t[0] = s("div", { class: "vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)),
|
|
98
|
+
s("p", V, x(w(p)("xlsx.loading")), 1)
|
|
99
|
+
])
|
|
100
|
+
])) : g("", !0),
|
|
101
|
+
l.value && !o.value ? (u(), c("div", F, [
|
|
102
|
+
s("div", O, [
|
|
103
|
+
s("div", q, [
|
|
104
|
+
S(w(W), { class: "vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary" })
|
|
105
|
+
]),
|
|
106
|
+
s("p", A, x(w(p)("xlsx.load_failed")), 1),
|
|
107
|
+
s("p", G, x(l.value), 1),
|
|
108
|
+
s("a", {
|
|
109
|
+
href: b.url,
|
|
110
|
+
download: "",
|
|
111
|
+
class: "vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg"
|
|
112
|
+
}, " 下载文件 ", 8, I),
|
|
113
|
+
t[1] || (t[1] = s("p", { class: "vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4" }, "提示:可以使用 Microsoft Excel 或 WPS 打开", -1))
|
|
114
|
+
])
|
|
115
|
+
])) : g("", !0),
|
|
116
|
+
l.value ? g("", !0) : (u(), c("div", {
|
|
117
|
+
key: 2,
|
|
118
|
+
ref_key: "containerRef",
|
|
119
|
+
ref: r,
|
|
120
|
+
class: "xlsx-spreadsheet-container vfp-w-full vfp-h-full",
|
|
121
|
+
style: z({ opacity: o.value ? 0 : 1 })
|
|
122
|
+
}, null, 4))
|
|
123
|
+
]));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
export {
|
|
127
|
+
X as default
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=index-DTLDLOGO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-DTLDLOGO.mjs","sources":["../../src/renderers/Xlsx/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount } from 'vue';\nimport { FileSpreadsheet } from 'lucide-vue-next';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\n\nconst props = defineProps<{\n url: string;\n}>();\n\nconst { t } = useTranslator();\n\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet sheetData: Record<string, unknown>[] | null = null;\nlet resizeObserver: ResizeObserver | null = null;\nlet resizeTimeout: number | null = null;\nlet lastDimensions = { width: 0, height: 0 };\n\nconst calculateDimensions = () => {\n if (!containerRef.value) return { width: 800, height: 600 };\n const rawWidth = containerRef.value.clientWidth;\n const rawHeight = containerRef.value.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n};\n\nconst mountSpreadsheet = () => {\n if (!containerRef.value || !sheetData) return;\n\n containerRef.value.innerHTML = '';\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.value, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetData as unknown as Record<string, unknown>);\n};\n\nconst loadExcel = async () => {\n if (!containerRef.value) return;\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(props.url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) throw new Error(t.value('xlsx.not_found'));\n if (response.status === 403) throw new Error('无权限访问此文件');\n throw new Error(`文件加载失败 (${response.status})`);\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n const data = convertWorkbookToSpreadsheetData(workbook);\n\n sheetData = data as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n loading.value = false;\n } catch (err) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t.value('xlsx.parse_failed');\n if (err instanceof Error) errorMsg = err.message;\n error.value = errorMsg;\n loading.value = false;\n }\n};\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n let isInitialRender = true;\n\n resizeObserver = new ResizeObserver(() => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensions = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensions = newDimensions;\n\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n\n resizeTimeout = window.setTimeout(() => {\n if (sheetData) mountSpreadsheet();\n }, 500);\n });\n\n resizeObserver.observe(containerRef.value);\n\n setTimeout(() => {\n requestAnimationFrame(() => loadExcel());\n }, 100);\n});\n\nwatch(\n () => props.url,\n () => {\n loadExcel();\n }\n);\n\nonBeforeUnmount(() => {\n if (resizeObserver) resizeObserver.disconnect();\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n sheetData = null;\n if (containerRef.value) containerRef.value.innerHTML = '';\n});\n</script>\n\n<template>\n <div class=\"vfp-relative vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full\">\n <div\n v-if=\"loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center\">\n <div\n class=\"vfp-w-10 vfp-h-10 md:vfp-w-12 md:vfp-h-12 vfp-mx-auto vfp-mb-3 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-secondary vfp-font-medium\">{{ t('xlsx.loading') }}</p>\n </div>\n </div>\n\n <div\n v-if=\"error && !loading\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-items-center vfp-justify-center vfp-bg-surface-toolbar vfp-backdrop-blur-sm vfp-z-10\"\n >\n <div class=\"vfp-text-center vfp-max-w-sm md:vfp-max-w-md vfp-px-4\">\n <div\n class=\"vfp-w-24 vfp-h-24 md:vfp-w-32 md:vfp-h-32 vfp-mx-auto vfp-mb-4 md:vfp-mb-6 vfp-rounded-2xl md:vfp-rounded-3xl vfp-bg-gradient-to-br vfp-from-green-500 vfp-via-emerald-500 vfp-to-teal-500 vfp-flex vfp-items-center vfp-justify-center vfp-shadow-2xl\"\n >\n <FileSpreadsheet class=\"vfp-w-12 vfp-h-12 md:vfp-w-16 md:vfp-h-16 vfp-text-fg-primary\" />\n </div>\n <p class=\"vfp-text-lg md:vfp-text-xl vfp-text-fg-primary vfp-mb-2 md:vfp-mb-3 vfp-font-medium\">\n {{ t('xlsx.load_failed') }}\n </p>\n <p class=\"vfp-text-xs md:vfp-text-sm vfp-text-fg-tertiary vfp-mb-4 md:vfp-mb-6\">{{ error }}</p>\n <a\n :href=\"url\"\n download\n class=\"vfp-inline-flex vfp-items-center vfp-gap-2 vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-bg-gradient-to-r vfp-from-purple-500 vfp-to-pink-500 vfp-text-fg-primary vfp-text-sm md:vfp-text-base vfp-rounded-lg md:vfp-rounded-xl hover:vfp-scale-105 vfp-transition-all vfp-shadow-lg\"\n >\n 下载文件\n </a>\n <p class=\"vfp-text-xs vfp-text-fg-muted vfp-mt-3 md:vfp-mt-4\">提示:可以使用 Microsoft Excel 或 WPS 打开</p>\n </div>\n </div>\n\n <div\n v-if=\"!error\"\n ref=\"containerRef\"\n class=\"xlsx-spreadsheet-container vfp-w-full vfp-h-full\"\n :style=\"{ opacity: loading ? 0 : 1 }\"\n />\n </div>\n</template>\n"],"names":["props","__props","t","useTranslator","loading","ref","error","containerRef","sheetData","resizeObserver","resizeTimeout","lastDimensions","calculateDimensions","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","Spreadsheet","loadExcel","response","arrayBuffer","workbook","ExcelJS","convertWorkbookToSpreadsheetData","err","errorMsg","onMounted","isInitialRender","newDimensions","widthDiff","heightDiff","watch","onBeforeUnmount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_3","_hoisted_4","_toDisplayString","_unref","_hoisted_5","_hoisted_6","_hoisted_7","_createVNode","FileSpreadsheet","_hoisted_8","_hoisted_9","_hoisted_10","_cache"],"mappings":"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"}
|