wps只读去掉工具栏
parent
e45c4d2404
commit
fcf1a193f2
|
|
@ -14,8 +14,8 @@ module.exports = {
|
||||||
|
|
||||||
// API_HOST: "http://192.168.0.134",
|
// API_HOST: "http://192.168.0.134",
|
||||||
// API_HOST: "http://192.168.0.150", //太浅
|
// API_HOST: "http://192.168.0.150", //太浅
|
||||||
// API_HOST: "https://gbs-gateway.qhdsafety.com",
|
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||||
API_HOST: "http://192.168.0.103", //huwei
|
// API_HOST: "http://192.168.0.103", //huwei
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
// 应用后端分支名称,部署上线需要
|
// 应用后端分支名称,部署上线需要
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
"@rc-component/util": "^1.11.1",
|
"@rc-component/util": "^1.11.1",
|
||||||
"antd": "^6.6.1",
|
"antd": "^6.6.1",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"docx-preview": "^0.4.0",
|
|
||||||
"docxtemplater": "latest",
|
"docxtemplater": "latest",
|
||||||
"echarts": "^6.1.0",
|
"echarts": "^6.1.0",
|
||||||
"history": "^4.10.1",
|
"history": "^4.10.1",
|
||||||
|
|
|
||||||
1992
pnpm-lock.yaml
1992
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1,193 +0,0 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import { Modal, Empty, Alert } from "antd";
|
|
||||||
import { renderAsync } from "docx-preview";
|
|
||||||
import "./index.less";
|
|
||||||
|
|
||||||
const FILE_TYPE_MAP = {
|
|
||||||
docx: "word",
|
|
||||||
pdf: "pdf",
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 根据 url/类型识别文件类型,仅支持 docx/pdf */
|
|
||||||
function resolveFileType(url, type) {
|
|
||||||
if (type && FILE_TYPE_MAP[type]) return type;
|
|
||||||
const ext = (url || "").split("?")[0].split(".").pop()?.toLowerCase();
|
|
||||||
return FILE_TYPE_MAP[ext] ? ext : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 相对地址拼接文件服务前缀 */
|
|
||||||
function resolveUrl(raw) {
|
|
||||||
if (!raw) return "";
|
|
||||||
const u = String(raw).trim();
|
|
||||||
if (/^https?:\/\//i.test(u)) return u;
|
|
||||||
const base = window.fileUrl || "";
|
|
||||||
return base ? `${base}${u}` : u;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 渲染 Word 文档到容器 */
|
|
||||||
async function renderDocx(url, container) {
|
|
||||||
if (!container) throw new Error("预览容器尚未就绪,请稍后重试");
|
|
||||||
const res = await fetch(url, { credentials: "same-origin" });
|
|
||||||
if (!res.ok) throw new Error(`文档加载失败:${res.status} ${res.statusText}`);
|
|
||||||
const blob = await res.blob();
|
|
||||||
await renderAsync(blob, container, container, {
|
|
||||||
className: "office-preview-docx",
|
|
||||||
inWrapper: true,
|
|
||||||
ignoreWidth: false,
|
|
||||||
ignoreHeight: false,
|
|
||||||
ignoreFonts: false,
|
|
||||||
breakPages: true,
|
|
||||||
renderHeaders: true,
|
|
||||||
renderFooters: true,
|
|
||||||
renderFootnotes: true,
|
|
||||||
renderEndnotes: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 文档预览组件:支持 Word(docx)、PDF,支持弹窗/页面两种模式 */
|
|
||||||
export default function OfficePreview({
|
|
||||||
url,
|
|
||||||
fileType = "auto",
|
|
||||||
mode = "modal",
|
|
||||||
open = false,
|
|
||||||
onCancel,
|
|
||||||
title = "文档预览",
|
|
||||||
width = 1000,
|
|
||||||
className = "",
|
|
||||||
style = {},
|
|
||||||
emptyText = "暂无文档",
|
|
||||||
}) {
|
|
||||||
const containerRef = useRef(null);
|
|
||||||
const aliveRef = useRef(true);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
const [ready, setReady] = useState(false);
|
|
||||||
const resolvedUrl = resolveUrl(url);
|
|
||||||
const type = resolveFileType(resolvedUrl, fileType);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
aliveRef.current = true;
|
|
||||||
return () => {
|
|
||||||
aliveRef.current = false;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (mode === "modal" && !open) {
|
|
||||||
setReady(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!resolvedUrl || type !== "docx") return;
|
|
||||||
|
|
||||||
setReady(false);
|
|
||||||
setError("");
|
|
||||||
|
|
||||||
let rafId = null;
|
|
||||||
let cancelled = false;
|
|
||||||
|
|
||||||
const tryRender = () => {
|
|
||||||
if (cancelled) return;
|
|
||||||
const node = containerRef.current;
|
|
||||||
if (!node) {
|
|
||||||
rafId = requestAnimationFrame(tryRender);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
renderDocx(resolvedUrl, node)
|
|
||||||
.then(() => {
|
|
||||||
if (aliveRef.current && !cancelled) {
|
|
||||||
setReady(true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.error("OfficePreview 文档渲染失败", e);
|
|
||||||
if (aliveRef.current && !cancelled) {
|
|
||||||
setError(e?.message || "文档渲染失败,请稍后重试");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
if (aliveRef.current && !cancelled) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
tryRender();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
||||||
const node = containerRef.current;
|
|
||||||
if (node) node.innerHTML = "";
|
|
||||||
};
|
|
||||||
}, [resolvedUrl, type, open, mode]);
|
|
||||||
|
|
||||||
const renderContent = () => {
|
|
||||||
if (!resolvedUrl) {
|
|
||||||
return <Empty description={emptyText} image={Empty.PRESENTED_IMAGE_SIMPLE} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
return (
|
|
||||||
<Alert
|
|
||||||
type="warning"
|
|
||||||
showIcon
|
|
||||||
message="不支持的文件类型"
|
|
||||||
description="当前仅支持 Word(.docx) 和 PDF(.pdf) 格式预览。"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return <Alert type="error" showIcon message={error} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`office-preview-body office-preview-${type}`} style={style}>
|
|
||||||
{type === "docx" && (
|
|
||||||
<div
|
|
||||||
ref={containerRef}
|
|
||||||
className="office-preview-docxContainer"
|
|
||||||
style={{ display: ready ? "block" : "none" }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{type === "pdf" && (
|
|
||||||
<iframe
|
|
||||||
className="office-preview-pdfFrame"
|
|
||||||
src={resolvedUrl}
|
|
||||||
title={title}
|
|
||||||
frameBorder="0"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{loading && (
|
|
||||||
<div className="office-preview-loading">
|
|
||||||
<div className="office-preview-loading-text">文档加载中...</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const body = (
|
|
||||||
<div className={`office-preview ${className}`}>{renderContent()}</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mode === "page") {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
title={title}
|
|
||||||
open={open}
|
|
||||||
onCancel={onCancel}
|
|
||||||
width={width}
|
|
||||||
footer={null}
|
|
||||||
destroyOnHidden
|
|
||||||
centered={false}
|
|
||||||
className="office-preview-modal"
|
|
||||||
>
|
|
||||||
{body}
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
.office-preview {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.office-preview-body {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.office-preview-docxContainer {
|
|
||||||
/* 固定占弹窗 90% 视口高度,确保有足够可视区域同时保留滚动条 */
|
|
||||||
height: 90vh;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: auto;
|
|
||||||
background: #f5f5f5;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 12px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.office-preview-pdfFrame {
|
|
||||||
height: 90vh;
|
|
||||||
max-height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.office-preview-loading {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: rgba(255, 255, 255, 0.6);
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.office-preview-loading-text {
|
|
||||||
color: #1677ff;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.office-preview-modal {
|
|
||||||
/* 弹窗顶部紧贴,让中间文档区域最大化 */
|
|
||||||
.micro-temp-modal {
|
|
||||||
top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.micro-temp-modal-content {
|
|
||||||
/* 弹窗内容占满视口高度,由正文容器再以 90vh 显示 */
|
|
||||||
height: 75vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.micro-temp-modal-header {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.micro-temp-modal-body {
|
|
||||||
flex: 1;
|
|
||||||
/* 覆盖 src/pages/Container/index.less 中全局 .micro-temp-modal-body { max-height: 66vh } 的限制,
|
|
||||||
让文档预览区域能占满更大可视高度 */
|
|
||||||
max-height: none !important;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 4px 8px 8px 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,2 @@
|
||||||
export { default as OrgInfoGuard } from "./OrgInfoGuard";
|
export { default as OrgInfoGuard } from "./OrgInfoGuard";
|
||||||
export { default as PreviewUrlButton } from "./PreviewUrlButton";
|
export { default as PreviewUrlButton } from "./PreviewUrlButton";
|
||||||
export { default as OfficePreview } from "./OfficePreview";
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
import { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant";
|
import { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant";
|
||||||
import { PROJECT_TYPE_MAP } from "~/enumerate/constant";
|
import { PROJECT_TYPE_MAP } from "~/enumerate/constant";
|
||||||
import { OfficePreview } from "~/components";
|
import WpsEditor from "~/pages/Container/WpsEditor";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
@ -369,8 +369,7 @@ const EvalProjectMonitorDetail = (props) => {
|
||||||
const [surveyPersonnel, setSurveyPersonnel] = useState([]);
|
const [surveyPersonnel, setSurveyPersonnel] = useState([]);
|
||||||
const [surveyAttachments, setSurveyAttachments] = useState({});
|
const [surveyAttachments, setSurveyAttachments] = useState({});
|
||||||
const [activeKey, setActiveKey] = useState("BUSINESS_CONTRACT");
|
const [activeKey, setActiveKey] = useState("BUSINESS_CONTRACT");
|
||||||
const [previewOpen, setPreviewOpen] = useState(false);
|
const [wpsVisible, setWpsVisible] = useState(false);
|
||||||
const [previewUrl, setPreviewUrl] = useState("");
|
|
||||||
|
|
||||||
const fetchContract = async () => {
|
const fetchContract = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
|
@ -472,14 +471,11 @@ const EvalProjectMonitorDetail = (props) => {
|
||||||
activeKey={activeKey}
|
activeKey={activeKey}
|
||||||
onChange={(key) => {
|
onChange={(key) => {
|
||||||
if (key === "REPORT_PREPARATION") {
|
if (key === "REPORT_PREPARATION") {
|
||||||
// 2026-08-18 监管端报告改用本地 OfficePreview 预览,避免 WPS SDK 内部空指针报错
|
if (!wpsDoc?.fileId) {
|
||||||
const url = wpsDoc?.wpsUrl;
|
|
||||||
if (!url) {
|
|
||||||
message.warning("暂无报告文档,请先在机构端生成报告后再查看");
|
message.warning("暂无报告文档,请先在机构端生成报告后再查看");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setPreviewUrl(url);
|
setWpsVisible(true);
|
||||||
setPreviewOpen(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setActiveKey(key);
|
setActiveKey(key);
|
||||||
|
|
@ -516,13 +512,13 @@ const EvalProjectMonitorDetail = (props) => {
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<OfficePreview
|
{wpsVisible && (
|
||||||
mode="modal"
|
<WpsEditor
|
||||||
open={previewOpen}
|
onCancel={() => setWpsVisible(false)}
|
||||||
onCancel={() => setPreviewOpen(false)}
|
fileId={wpsDoc?.fileId}
|
||||||
url={previewUrl}
|
readOnly
|
||||||
width={1100}
|
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,15 @@ const App = (props) => {
|
||||||
customArgs: {
|
customArgs: {
|
||||||
readOnly,
|
readOnly,
|
||||||
},
|
},
|
||||||
...(readOnly ? { commonOptions: { isBrowserViewMode: true } } : {}),
|
...(readOnly
|
||||||
|
? {
|
||||||
|
commonOptions: {
|
||||||
|
isBrowserViewMode: true,
|
||||||
|
// 只读模式下隐藏 WPS 顶部区域(头部和工具栏),页面已有自己的标题栏
|
||||||
|
isShowTopArea: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
await instance.ready();
|
await instance.ready();
|
||||||
sdkRef.current = instance;
|
sdkRef.current = instance;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue