需求修改

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",
"antd": "^6.6.1",
"dayjs": "^1.11.7",
"docx-preview": "^0.4.0",
"docxtemplater": "latest",
"echarts": "^6.1.0",
"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,
Popover,
Button,
message,
} from "antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
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 { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant";
import { PROJECT_TYPE_MAP } from "~/enumerate/constant";
import WpsEditor from "~/pages/Container/WpsEditor";
import { OfficePreview } from "~/components";
import "./index.less";
const { router } = tools;
@ -368,7 +369,8 @@ const EvalProjectMonitorDetail = (props) => {
const [surveyPersonnel, setSurveyPersonnel] = useState([]);
const [surveyAttachments, setSurveyAttachments] = useState({});
const [activeKey, setActiveKey] = useState("BUSINESS_CONTRACT");
const [wpsVisible, setWpsVisible] = useState(false);
const [previewOpen, setPreviewOpen] = useState(false);
const [previewUrl, setPreviewUrl] = useState("");
const fetchContract = async () => {
if (!projectId) return;
@ -470,7 +472,14 @@ const EvalProjectMonitorDetail = (props) => {
activeKey={activeKey}
onChange={(key) => {
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;
}
setActiveKey(key);
@ -507,13 +516,13 @@ const EvalProjectMonitorDetail = (props) => {
},
]}
/>
{wpsVisible && (
<WpsEditor
onCancel={() => setWpsVisible(false)}
fileId={wpsDoc?.fileId}
readOnly
/>
)}
<OfficePreview
mode="modal"
open={previewOpen}
onCancel={() => setPreviewOpen(false)}
url={previewUrl}
width={1100}
/>
</PageLayout>
);
};

View File

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

View File

@ -17,6 +17,7 @@ import { tools } from "@cqsjjb/jjb-common-lib";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
import "./index.less";
import ErrorBoundary from "./ErrorBoundary";
const { router } = tools;
@ -82,24 +83,58 @@ const App = (props) => {
setExpandedMap((prev) => ({ ...prev, [index]: !prev[index] }));
};
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 () {
const instance = WebOfficeSDK.init({
// 必填项
officeType: WebOfficeSDK.OfficeType.Writer,
appId: "AK20260805KPWYZJ",
mount: document.getElementById("app-wps"),
fileId: fileId,
token: sessionStorage.getItem("token"),
customArgs: {
readOnly,
},
...(readOnly ? { commonOptions: { isBrowserViewMode: true } } : {}),
});
await instance.ready();
sdkRef.current = instance;
// 2026-08-18 兜底保护:用 try/catch 包裹 SDK 初始化与 ready 流程,
// SDK 内部同步阶段任何缺省参数导致的异常,统一捕获并转为友好提示。
try {
const instance = WebOfficeSDK.init({
// 必填项
officeType: WebOfficeSDK.OfficeType.Writer,
appId: "AK20260805KPWYZJ",
mount: document.getElementById("app-wps"),
fileId: fileId,
token: sessionStorage.getItem("token"),
customArgs: {
readOnly,
},
...(readOnly ? { commonOptions: { isBrowserViewMode: true } } : {}),
});
await instance.ready();
sdkRef.current = instance;
} catch (e) {
console.error("WebOfficeSDK 初始化失败", e);
message.error("报告文档加载失败,请稍后重试或联系管理员");
}
})();
return () => {
sdkRef.current?.destroy();
window.removeEventListener("error", onWindowError, { capture: true });
window.removeEventListener("unhandledrejection", onWindowError, { capture: true });
};
}, [fileId]);
@ -386,7 +421,15 @@ const App = (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);