需求修改

dev-tmp1
huwei 2026-08-18 22:03:12 +08:00
parent 31234feaf2
commit 69c5a16b59
6 changed files with 1142 additions and 1018 deletions

View File

@ -29,6 +29,7 @@
"@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",

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,3 @@
export { default as OrgInfoGuard } from "./OrgInfoGuard"; export { default as OrgInfoGuard } from "./OrgInfoGuard";
export { default as PreviewUrlButton } from "./PreviewUrlButton";
export { default as OfficePreview } from "./OfficePreview";

View File

@ -11,6 +11,7 @@ import {
Image, Image,
Popover, Popover,
Button, Button,
message,
} from "antd"; } from "antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd"; import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
@ -19,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 WpsEditor from "~/pages/Container/WpsEditor"; import { OfficePreview } from "~/components";
import "./index.less"; import "./index.less";
const { router } = tools; const { router } = tools;
@ -368,7 +369,8 @@ 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 [wpsVisible, setWpsVisible] = useState(false); const [previewOpen, setPreviewOpen] = useState(false);
const [previewUrl, setPreviewUrl] = useState("");
const fetchContract = async () => { const fetchContract = async () => {
if (!projectId) return; if (!projectId) return;
@ -470,7 +472,14 @@ const EvalProjectMonitorDetail = (props) => {
activeKey={activeKey} activeKey={activeKey}
onChange={(key) => { onChange={(key) => {
if (key === "REPORT_PREPARATION") { if (key === "REPORT_PREPARATION") {
setWpsVisible(true); // 2026-08-18 监管端报告改用本地 OfficePreview 预览,避免 WPS SDK 内部空指针报错
const url = wpsDoc?.wpsUrl;
if (!url) {
message.warning("暂无报告文档,请先在机构端生成报告后再查看");
return;
}
setPreviewUrl(url);
setPreviewOpen(true);
return; return;
} }
setActiveKey(key); setActiveKey(key);
@ -507,13 +516,13 @@ const EvalProjectMonitorDetail = (props) => {
}, },
]} ]}
/> />
{wpsVisible && ( <OfficePreview
<WpsEditor mode="modal"
onCancel={() => setWpsVisible(false)} open={previewOpen}
fileId={wpsDoc?.fileId} onCancel={() => setPreviewOpen(false)}
readOnly url={previewUrl}
/> width={1100}
)} />
</PageLayout> </PageLayout>
); );
}; };

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Tabs, Tag, Flex } from "antd"; import { Tabs, Tag, Flex, message } from "antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd"; import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
@ -173,6 +173,11 @@ const ProjectFlow = (props) => {
}; };
const openReportEditor = async () => { const openReportEditor = async () => {
// 2026-08-18 前置拦截:报告文档 fileId 缺省(文档尚未生成/加载完成)时提示,不打开编辑器,避免 SDK 报错
if (!wpsDoc?.fileId) {
message.warning("报告文档尚未生成,请先创建报告后再查看");
return;
}
setVisible(true); setVisible(true);
}; };

View File

@ -17,6 +17,7 @@ import { tools } from "@cqsjjb/jjb-common-lib";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace"; import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
import "./index.less"; import "./index.less";
import ErrorBoundary from "./ErrorBoundary";
const { router } = tools; const { router } = tools;
@ -82,24 +83,58 @@ const App = (props) => {
setExpandedMap((prev) => ({ ...prev, [index]: !prev[index] })); setExpandedMap((prev) => ({ ...prev, [index]: !prev[index] }));
}; };
useEffect(() => { useEffect(() => {
// 2026-08-18 前置拦截fileId 缺失时如报告尚未生成、后端未返回文档ID
// 直接提示而不初始化 SDK避免 WebOfficeSDK 内部因缺省参数抛
// "Cannot read properties of undefined (reading 'officeType')" 未捕获异常。
if (!fileId) {
message.warning("暂无报告文档,请先在机构端生成报告后再查看");
return;
}
// 2026-08-18 全局兜底SDK 在收到 "open.result" 事件时内部会读取
// o.fileInfo.officeType若后端未返回 fileInfo文档文件信息缺失会抛
// "Cannot read properties of undefined (reading 'officeType')" 的异步未捕获异常。
// 该异常发生在 SDK 事件回调中,非本组件的 try/catch 可拦截,
// 故挂载期间通过 window error/unhandledrejection 监听统一转为友好提示。
const onWindowError = (event) => {
const err = event?.error || event?.reason;
const msg = err?.message || event?.message || "";
if (msg.includes("officeType")) {
// 阻止冒泡,防止 webpack-dev-server runtime error overlay 显示红屏
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
message.error("报告文档加载失败(文档文件信息缺失),请稍后重试或联系管理员");
}
};
window.addEventListener("error", onWindowError, { capture: true });
window.addEventListener("unhandledrejection", onWindowError, { capture: true });
(async function () { (async function () {
const instance = WebOfficeSDK.init({ // 2026-08-18 兜底保护:用 try/catch 包裹 SDK 初始化与 ready 流程,
// 必填项 // SDK 内部同步阶段任何缺省参数导致的异常,统一捕获并转为友好提示。
officeType: WebOfficeSDK.OfficeType.Writer, try {
appId: "AK20260805KPWYZJ", const instance = WebOfficeSDK.init({
mount: document.getElementById("app-wps"), // 必填项
fileId: fileId, officeType: WebOfficeSDK.OfficeType.Writer,
token: sessionStorage.getItem("token"), appId: "AK20260805KPWYZJ",
customArgs: { mount: document.getElementById("app-wps"),
readOnly, fileId: fileId,
}, token: sessionStorage.getItem("token"),
...(readOnly ? { commonOptions: { isBrowserViewMode: true } } : {}), customArgs: {
}); readOnly,
await instance.ready(); },
sdkRef.current = instance; ...(readOnly ? { commonOptions: { isBrowserViewMode: true } } : {}),
});
await instance.ready();
sdkRef.current = instance;
} catch (e) {
console.error("WebOfficeSDK 初始化失败", e);
message.error("报告文档加载失败,请稍后重试或联系管理员");
}
})(); })();
return () => { return () => {
sdkRef.current?.destroy(); sdkRef.current?.destroy();
window.removeEventListener("error", onWindowError, { capture: true });
window.removeEventListener("unhandledrejection", onWindowError, { capture: true });
}; };
}, [fileId]); }, [fileId]);
@ -386,7 +421,15 @@ const App = (props) => {
}; };
export default function WpsEditor(props) { export default function WpsEditor(props) {
return createPortal(<ConnectApp {...props} />, document.body); // 2026-08-18用 ErrorBoundary 包裹渲染树,兜底第三方 SDKWebOfficeSDK
// 渲染期或事件回调中抛出的 "Cannot read properties of undefined (reading 'officeType')"
// 等未捕获异常,渲染降级 UI避免 React DevTools runtime error overlay 弹出红屏。
return createPortal(
<ErrorBoundary message="报告文档加载失败或文件不存在">
<ConnectApp {...props} />
</ErrorBoundary>,
document.body,
);
} }
const ConnectApp = Connect([NS_SAFETY_EVAL_BUSINESS], true)(App); const ConnectApp = Connect([NS_SAFETY_EVAL_BUSINESS], true)(App);