2026-07-20 15:03:26 +08:00
|
|
|
|
import { useState, useEffect, useRef } from "react";
|
2026-07-20 11:16:32 +08:00
|
|
|
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
2026-07-20 15:03:26 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Flex,
|
|
|
|
|
|
Button,
|
|
|
|
|
|
Tabs,
|
|
|
|
|
|
Input,
|
|
|
|
|
|
Tag,
|
|
|
|
|
|
Progress,
|
|
|
|
|
|
Typography,
|
|
|
|
|
|
message,
|
|
|
|
|
|
} from "antd";
|
2026-07-20 13:38:09 +08:00
|
|
|
|
import { ArrowLeftOutlined } from "@ant-design/icons";
|
2026-07-20 11:16:32 +08:00
|
|
|
|
import WebOfficeSDK from "~/web-office-sdk-solution-v2.0.7/web-office-sdk-solution-v2.0.7.es.js";
|
|
|
|
|
|
import { createPortal } from "react-dom";
|
|
|
|
|
|
import "./index.less";
|
|
|
|
|
|
|
2026-07-20 13:38:09 +08:00
|
|
|
|
const App = (props) => {
|
2026-07-20 16:57:49 +08:00
|
|
|
|
const { onCancel, fileId } = props;
|
2026-07-20 11:16:32 +08:00
|
|
|
|
const [expandedMap, setExpandedMap] = useState({});
|
2026-07-20 15:03:26 +08:00
|
|
|
|
const sdkRef = useRef(null);
|
|
|
|
|
|
|
|
|
|
|
|
const handleSave = async () => {
|
|
|
|
|
|
if (!sdkRef.current) {
|
|
|
|
|
|
message.warning("文档尚未加载完成");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await sdkRef.current.save();
|
|
|
|
|
|
message.success("保存成功");
|
|
|
|
|
|
};
|
2026-07-20 11:16:32 +08:00
|
|
|
|
|
|
|
|
|
|
const toggleExpand = (index) => {
|
|
|
|
|
|
setExpandedMap((prev) => ({ ...prev, [index]: !prev[index] }));
|
|
|
|
|
|
};
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
(async function () {
|
|
|
|
|
|
const instance = WebOfficeSDK.init({
|
|
|
|
|
|
// 必填项
|
|
|
|
|
|
officeType: WebOfficeSDK.OfficeType.Writer,
|
|
|
|
|
|
appId: "SX20260717TSGKEA",
|
|
|
|
|
|
mount: document.getElementById("app-sbsb"),
|
2026-07-20 16:57:49 +08:00
|
|
|
|
fileId: fileId || "123",
|
2026-07-20 11:16:32 +08:00
|
|
|
|
token: sessionStorage.getItem("token"),
|
|
|
|
|
|
});
|
|
|
|
|
|
await instance.ready();
|
2026-07-20 15:03:26 +08:00
|
|
|
|
sdkRef.current = instance;
|
2026-07-20 11:16:32 +08:00
|
|
|
|
})();
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="WpsEditor-container">
|
|
|
|
|
|
<PageLayout
|
2026-07-20 13:38:09 +08:00
|
|
|
|
title={
|
|
|
|
|
|
<Flex align="center" gap={8}>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<ArrowLeftOutlined
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
console.log("点击了返回按钮");
|
|
|
|
|
|
onCancel();
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-07-20 13:38:09 +08:00
|
|
|
|
<span>安全评价报告编制</span>
|
|
|
|
|
|
</Flex>
|
|
|
|
|
|
}
|
2026-07-20 11:16:32 +08:00
|
|
|
|
extra={
|
|
|
|
|
|
<Flex gap={12}>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Button onClick={handleSave}>保存</Button>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<Button>下载报告</Button>
|
|
|
|
|
|
<Button type="primary">提交内审</Button>
|
|
|
|
|
|
</Flex>
|
|
|
|
|
|
}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="WpsEditor-flexContainer">
|
|
|
|
|
|
<div id="app-sbsb" className="WpsEditor-editorArea"></div>
|
|
|
|
|
|
<div className="WpsEditor-sidePanel">
|
|
|
|
|
|
<Tabs
|
|
|
|
|
|
type="card"
|
|
|
|
|
|
tabPlacement="top"
|
|
|
|
|
|
items={[
|
|
|
|
|
|
{
|
|
|
|
|
|
label: "知识库",
|
|
|
|
|
|
key: "1",
|
|
|
|
|
|
children: (
|
|
|
|
|
|
<div className="WpsEditor-dock">
|
|
|
|
|
|
<Input.Search placeholder="搜索法规、案例、措施" />
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Flex gap={4} className="WpsEditor-dock-cats">
|
|
|
|
|
|
{[
|
|
|
|
|
|
"推荐",
|
|
|
|
|
|
"法规标准",
|
|
|
|
|
|
"危险因素",
|
|
|
|
|
|
"评价方法",
|
|
|
|
|
|
"事故案例",
|
|
|
|
|
|
].map((cat) => (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
key={cat}
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
type={cat === "推荐" ? "primary" : "default"}
|
|
|
|
|
|
>
|
|
|
|
|
|
{cat}
|
|
|
|
|
|
</Button>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
))}
|
|
|
|
|
|
</Flex>
|
|
|
|
|
|
<div className="WpsEditor-dock-list">
|
|
|
|
|
|
{[
|
2026-07-20 15:03:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
cat: "法规标准",
|
|
|
|
|
|
title: "中华人民共和国安全生产法",
|
|
|
|
|
|
desc: "2021年修正,当前有效。可引用至评价依据章节发多少个给梵蒂换个房间官方电话冈的是非观大使馆反对给多少给多少规范化的。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "危险因素",
|
|
|
|
|
|
title: "液氨泄漏事故场景",
|
|
|
|
|
|
desc: "包含泄漏扩散、中毒窒息、次生火灾及应急处置要点。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "评价方法",
|
|
|
|
|
|
title: "安全检查表法",
|
|
|
|
|
|
desc: "适用于法规符合性、设施状态和安全管理制度逐项检查。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "评价方法",
|
|
|
|
|
|
title: "安全检查表法",
|
|
|
|
|
|
desc: "适用于法规符合性、设施状态和安全管理制度逐项检查。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "评价方法",
|
|
|
|
|
|
title: "安全检查表法",
|
|
|
|
|
|
desc: "适用于法规符合性、设施状态和安全管理制度逐项检查。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "评价方法",
|
|
|
|
|
|
title: "安全检查表法",
|
|
|
|
|
|
desc: "适用于法规符合性、设施状态和安全管理制度逐项检查。",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
cat: "评价方法",
|
|
|
|
|
|
title: "安全检查表法",
|
|
|
|
|
|
desc: "适用于法规符合性、设施状态和安全管理制度逐项检查。",
|
|
|
|
|
|
},
|
2026-07-20 11:16:32 +08:00
|
|
|
|
].map((item, i) => {
|
|
|
|
|
|
const expanded = expandedMap[i];
|
|
|
|
|
|
return (
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<div key={i} className="WpsEditor-resourceCard">
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<Tag color="blue">{item.cat}</Tag>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Typography.Text
|
|
|
|
|
|
strong
|
|
|
|
|
|
className="WpsEditor-resourceTitle"
|
|
|
|
|
|
>
|
|
|
|
|
|
{item.title}
|
|
|
|
|
|
</Typography.Text>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<Typography.Paragraph
|
|
|
|
|
|
type="secondary"
|
|
|
|
|
|
className="WpsEditor-resourceDesc"
|
|
|
|
|
|
ellipsis={expanded ? false : { rows: 2 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{item.desc}
|
|
|
|
|
|
</Typography.Paragraph>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
onClick={() => toggleExpand(i)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{expanded ? "收起" : "展开"}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
label: "模板",
|
|
|
|
|
|
key: "2",
|
|
|
|
|
|
children: (
|
|
|
|
|
|
<div className="WpsEditor-dock">
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Flex
|
|
|
|
|
|
justify="space-between"
|
|
|
|
|
|
align="center"
|
|
|
|
|
|
className="WpsEditor-dock-heading"
|
|
|
|
|
|
>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<Typography.Text strong>机构报告模板</Typography.Text>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Button type="link" size="small">
|
|
|
|
|
|
管理
|
|
|
|
|
|
</Button>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</Flex>
|
|
|
|
|
|
<div className="WpsEditor-dock-list">
|
|
|
|
|
|
{[
|
2026-07-20 15:03:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
name: "安全预评价报告",
|
|
|
|
|
|
desc: "AQ 8001 / AQ 8002 · V3.2",
|
|
|
|
|
|
active: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "安全验收评价报告",
|
|
|
|
|
|
desc: "AQ 8001 / AQ 8003 · V2.8",
|
|
|
|
|
|
active: false,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "安全现状评价报告",
|
|
|
|
|
|
desc: "机构标准模板 · V4.1",
|
|
|
|
|
|
active: false,
|
|
|
|
|
|
},
|
2026-07-20 11:16:32 +08:00
|
|
|
|
].map((tmpl, i) => (
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<div
|
|
|
|
|
|
key={i}
|
|
|
|
|
|
className={`WpsEditor-templateCard${tmpl.active ? " active" : ""}`}
|
|
|
|
|
|
>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<div>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Typography.Text strong>
|
|
|
|
|
|
{tmpl.name}
|
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
|
<Typography.Paragraph
|
|
|
|
|
|
type="secondary"
|
|
|
|
|
|
style={{ margin: 0, fontSize: 12 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{tmpl.desc}
|
|
|
|
|
|
</Typography.Paragraph>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</div>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
{tmpl.active ? (
|
|
|
|
|
|
<Tag color="blue">使用中</Tag>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Button size="small">应用</Button>
|
|
|
|
|
|
)}
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="WpsEditor-templateNote">
|
|
|
|
|
|
<Typography.Text strong>模板包含</Typography.Text>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Typography.Paragraph
|
|
|
|
|
|
type="secondary"
|
|
|
|
|
|
style={{ margin: 0, fontSize: 12 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
封面、责任页、目录、章节结构、页眉页脚、表格样式、附件与附图目录。
|
|
|
|
|
|
</Typography.Paragraph>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
label: "签字",
|
|
|
|
|
|
key: "3",
|
|
|
|
|
|
children: (
|
|
|
|
|
|
<div className="WpsEditor-dock">
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Flex
|
|
|
|
|
|
justify="space-between"
|
|
|
|
|
|
align="center"
|
|
|
|
|
|
className="WpsEditor-dock-heading"
|
|
|
|
|
|
>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<Typography.Text strong>责任页签字</Typography.Text>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<span className="WpsEditor-signProgress">
|
|
|
|
|
|
1 / 5 已完成
|
|
|
|
|
|
</span>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</Flex>
|
|
|
|
|
|
<Progress percent={20} size="small" />
|
|
|
|
|
|
<div className="WpsEditor-dock-list">
|
|
|
|
|
|
{[
|
2026-07-20 15:03:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
initial: "张",
|
|
|
|
|
|
name: "张建国",
|
|
|
|
|
|
role: "项目负责人",
|
|
|
|
|
|
status: "signed",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
initial: "李",
|
|
|
|
|
|
name: "李明华",
|
|
|
|
|
|
role: "报告编制人",
|
|
|
|
|
|
status: "pending",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
initial: "王",
|
|
|
|
|
|
name: "王丽萍",
|
|
|
|
|
|
role: "内部审核人",
|
|
|
|
|
|
status: "locked",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
initial: "陈",
|
|
|
|
|
|
name: "陈志强",
|
|
|
|
|
|
role: "技术负责人",
|
|
|
|
|
|
status: "locked",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
initial: "王",
|
|
|
|
|
|
name: "王丽萍",
|
|
|
|
|
|
role: "过程控制负责人",
|
|
|
|
|
|
status: "locked",
|
|
|
|
|
|
},
|
2026-07-20 11:16:32 +08:00
|
|
|
|
].map((signer, i) => (
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<div
|
|
|
|
|
|
key={i}
|
|
|
|
|
|
className={`WpsEditor-signer ${signer.status}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="WpsEditor-signerAvatar">
|
|
|
|
|
|
{signer.initial}
|
|
|
|
|
|
</div>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
<div className="WpsEditor-signerInfo">
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Typography.Text strong>
|
|
|
|
|
|
{signer.name}
|
|
|
|
|
|
</Typography.Text>
|
|
|
|
|
|
<Typography.Paragraph
|
|
|
|
|
|
type="secondary"
|
|
|
|
|
|
style={{ margin: 0, fontSize: 12 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{signer.role}
|
|
|
|
|
|
</Typography.Paragraph>
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</div>
|
2026-07-20 15:03:26 +08:00
|
|
|
|
{signer.status === "signed" && (
|
|
|
|
|
|
<Tag color="success">已签字</Tag>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{signer.status === "pending" && (
|
|
|
|
|
|
<Button size="small" type="primary" ghost>
|
|
|
|
|
|
下发APP签字
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
)}
|
2026-07-20 11:16:32 +08:00
|
|
|
|
{signer.status === "locked" && <Tag>待内审</Tag>}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="WpsEditor-signRule">
|
2026-07-20 15:03:26 +08:00
|
|
|
|
<Typography.Paragraph
|
|
|
|
|
|
type="secondary"
|
|
|
|
|
|
style={{ margin: 0, fontSize: 12 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
签字由 PC 端下发至本人
|
|
|
|
|
|
APP,手写签署后自动回传。各版本签字独立留痕。
|
2026-07-20 11:16:32 +08:00
|
|
|
|
</Typography.Paragraph>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</PageLayout>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-07-20 13:38:09 +08:00
|
|
|
|
export default function WpsEditor(props) {
|
|
|
|
|
|
return createPortal(<App {...props} />, document.body);
|
2026-07-20 11:16:32 +08:00
|
|
|
|
}
|