0.3.9修复onlyoffice 的打开问题
This commit is contained in:
@@ -17,11 +17,13 @@ const useTableData = (tableId: string) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [version, setVersion] = useState(0);
|
||||
|
||||
const refresh = useCallback(() => setVersion((prev) => prev + 1), []);
|
||||
const refresh = useCallback(() => {
|
||||
setIsLoading(true);
|
||||
setVersion((prev) => prev + 1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let canceled = false;
|
||||
setIsLoading(true);
|
||||
getDocumentTable(tableId)
|
||||
.then((data) => {
|
||||
if (!canceled) {
|
||||
@@ -47,7 +49,7 @@ const useTableData = (tableId: string) => {
|
||||
return { table, isLoading, refresh };
|
||||
};
|
||||
|
||||
const CompactTablePreview: React.FC<CompactTablePreviewProps> = ({
|
||||
const CompactTablePreviewInner: React.FC<CompactTablePreviewProps> = ({
|
||||
tableId,
|
||||
onFullScreen,
|
||||
onDelete,
|
||||
@@ -304,4 +306,8 @@ const CompactTablePreview: React.FC<CompactTablePreviewProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const CompactTablePreview: React.FC<CompactTablePreviewProps> = (props) => (
|
||||
<CompactTablePreviewInner key={props.tableId} {...props} />
|
||||
);
|
||||
|
||||
export default CompactTablePreview;
|
||||
|
||||
@@ -200,7 +200,7 @@ const FullScreenTableEditor: React.FC<FullScreenTableEditorProps> = ({ tableId,
|
||||
stopSavingHint();
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, [startSavingHint, stopSavingHint, tableData, tableId]);
|
||||
}, [luckysheetSheets, startSavingHint, stopSavingHint, tableData, tableId]);
|
||||
|
||||
const debouncedPersist = useDebouncedCallback(() => {
|
||||
void persistSnapshot("auto");
|
||||
@@ -515,17 +515,36 @@ const FullScreenTableEditor: React.FC<FullScreenTableEditorProps> = ({ tableId,
|
||||
return;
|
||||
}
|
||||
|
||||
// 首次加载时,资源/样式可能刚完成注入,强制触发一次 resize 让 Luckysheet 重新计算布局(避免工具栏/公式栏不显示)
|
||||
requestAnimationFrame(() => {
|
||||
try {
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
(window.luckysheet as any)?.resize?.();
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
setTimeout(() => {
|
||||
try {
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
(window.luckysheet as any)?.resize?.();
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
}, 80);
|
||||
});
|
||||
|
||||
// 等待首帧渲染完成再开放 updated 事件
|
||||
setTimeout(() => {
|
||||
isApplyingSnapshotRef.current = false;
|
||||
}, 0);
|
||||
|
||||
const containerEl = containerRef.current;
|
||||
return () => {
|
||||
if (window.luckysheet) {
|
||||
window.luckysheet?.destroy?.(LUCKY_SHEET_CONTAINER_ID);
|
||||
}
|
||||
if (containerRef.current) {
|
||||
containerRef.current.innerHTML = "";
|
||||
if (containerEl) {
|
||||
containerEl.innerHTML = "";
|
||||
}
|
||||
hasInitializedRef.current = false;
|
||||
};
|
||||
@@ -627,34 +646,35 @@ const FullScreenTableEditor: React.FC<FullScreenTableEditorProps> = ({ tableId,
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Luckysheet 容器 */}
|
||||
<div
|
||||
id={LUCKY_SHEET_CONTAINER_ID}
|
||||
ref={containerRef}
|
||||
className="flex-grow w-full h-full"
|
||||
tabIndex={-1}
|
||||
aria-label="在线表格全屏编辑区域"
|
||||
style={{ display: isLuckysheetReady && !isTableLoading && !tableError ? "block" : "none" }}
|
||||
/>
|
||||
<div className="relative flex-grow w-full">
|
||||
{/* Luckysheet 容器(始终占位,避免 create 时容器不可见导致布局计算错误) */}
|
||||
<div
|
||||
id={LUCKY_SHEET_CONTAINER_ID}
|
||||
ref={containerRef}
|
||||
className="h-full w-full"
|
||||
tabIndex={-1}
|
||||
aria-label="在线表格全屏编辑区域"
|
||||
/>
|
||||
|
||||
{showLoadingOverlay && (
|
||||
<div className="flex justify-center items-center h-full text-gray-500 border border-dashed">
|
||||
<p>{loadingMessage}</p>
|
||||
</div>
|
||||
)}
|
||||
{showLoadingOverlay && (
|
||||
<div className="absolute inset-0 flex justify-center items-center text-gray-500 bg-white/90 dark:bg-gray-900/90">
|
||||
<p>{loadingMessage}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tableError && !showLoadingOverlay && (
|
||||
<div className="flex flex-col justify-center items-center h-full text-red-500 border border-dashed space-y-2">
|
||||
<p>{tableError}</p>
|
||||
<button
|
||||
type="button"
|
||||
className="px-3 py-1 rounded-md border border-red-300 text-sm"
|
||||
onClick={() => fetchTable(tableId)}
|
||||
>
|
||||
重试
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{tableError && !showLoadingOverlay && (
|
||||
<div className="absolute inset-0 flex flex-col justify-center items-center text-red-500 bg-white/95 dark:bg-gray-900/95 space-y-2">
|
||||
<p>{tableError}</p>
|
||||
<button
|
||||
type="button"
|
||||
className="px-3 py-1 rounded-md border border-red-300 text-sm"
|
||||
onClick={() => fetchTable(tableId)}
|
||||
>
|
||||
重试
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -118,7 +118,7 @@ const HeadlessTableViewer: React.FC<HeadlessTableViewerProps> = ({ tableId, embe
|
||||
return () => {
|
||||
canceled = true;
|
||||
};
|
||||
}, [tableId, reloadVersion]);
|
||||
}, [computeSnapshotHash, reloadVersion, tableId]);
|
||||
|
||||
|
||||
const allowInlineEdit = editable ?? embed;
|
||||
@@ -217,7 +217,7 @@ const HeadlessTableViewer: React.FC<HeadlessTableViewerProps> = ({ tableId, embe
|
||||
stopSavingHint();
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, [allowInlineEdit, startSavingHint, stopSavingHint, table, tableId]);
|
||||
}, [allowInlineEdit, computeSnapshotHash, startSavingHint, stopSavingHint, table, tableId]);
|
||||
|
||||
const debouncedPersist = useDebouncedCallback(() => {
|
||||
void persistSnapshot();
|
||||
|
||||
@@ -21,20 +21,45 @@ export const LUCKYSHEET_RESOURCES = {
|
||||
|
||||
let loaderPromise: Promise<void> | null = null;
|
||||
|
||||
const appendCssOnce = (href: string) => {
|
||||
if (typeof document === "undefined") {
|
||||
return;
|
||||
}
|
||||
const marker = `link[data-luckysheet-href="${href}"]`;
|
||||
if (document.querySelector(marker)) {
|
||||
return;
|
||||
}
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = href;
|
||||
link.dataset.luckysheetHref = href;
|
||||
document.head.appendChild(link);
|
||||
};
|
||||
const appendCssOnce = (href: string) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
if (typeof document === "undefined") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const marker = `link[data-luckysheet-href="${href}"]`;
|
||||
const existing = document.querySelector<HTMLLinkElement>(marker);
|
||||
if (existing) {
|
||||
if (existing.dataset.loaded === "1") {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const handleLoad = () => {
|
||||
existing.dataset.loaded = "1";
|
||||
resolve();
|
||||
};
|
||||
const handleError = () => {
|
||||
reject(new Error(`加载 Luckysheet 样式失败: ${href}`));
|
||||
};
|
||||
existing.addEventListener("load", handleLoad, { once: true });
|
||||
existing.addEventListener("error", handleError, { once: true });
|
||||
return;
|
||||
}
|
||||
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = href;
|
||||
link.dataset.luckysheetHref = href;
|
||||
link.onload = () => {
|
||||
link.dataset.loaded = "1";
|
||||
resolve();
|
||||
};
|
||||
link.onerror = () => {
|
||||
reject(new Error(`加载 Luckysheet 样式失败: ${href}`));
|
||||
};
|
||||
document.head.appendChild(link);
|
||||
});
|
||||
|
||||
const appendScriptOnce = (src: string) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
@@ -87,10 +112,16 @@ export const ensureLuckysheetLoaded = async () => {
|
||||
}
|
||||
|
||||
loaderPromise = (async () => {
|
||||
LUCKYSHEET_RESOURCES.css.forEach((href) => appendCssOnce(href));
|
||||
const cssPromises = LUCKYSHEET_RESOURCES.css.map((href) => appendCssOnce(href));
|
||||
for (const src of LUCKYSHEET_RESOURCES.js) {
|
||||
await appendScriptOnce(src);
|
||||
}
|
||||
await Promise.all(cssPromises);
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
(window as unknown as { __wolaiLuckysheetResources?: typeof LUCKYSHEET_RESOURCES }).__wolaiLuckysheetResources = LUCKYSHEET_RESOURCES;
|
||||
console.log("[LuckysheetLoader] 资源加载完成", LUCKYSHEET_RESOURCES);
|
||||
}
|
||||
})();
|
||||
|
||||
await loaderPromise;
|
||||
@@ -106,10 +137,6 @@ export const useLuckysheetLoader = () => {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (window.luckysheet) {
|
||||
setIsReady(true);
|
||||
return;
|
||||
}
|
||||
ensureLuckysheetLoaded()
|
||||
.then(() => {
|
||||
if (!canceled) {
|
||||
|
||||
Reference in New Issue
Block a user