295 lines
8.4 KiB
JavaScript
295 lines
8.4 KiB
JavaScript
import { Button, Card, Form, Spin, Table, Tabs, Tag, message } from "antd";
|
||
import { useEffect, useMemo, useState } from "react";
|
||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||
import FilePreviewModal from "~/components/FilePreviewModal";
|
||
import {
|
||
fetchRegisteredOrgDetail,
|
||
fetchRegisteredOrgPersonnelCertDetail,
|
||
fetchRegisteredOrgPersonnelCertList,
|
||
fetchRegisteredOrgPersonnelDetail,
|
||
fetchRegisteredOrgPersonnelList,
|
||
fetchRegisteredOrgQualificationGroups,
|
||
} from "~/utils/regulatorOrgInfo";
|
||
import { buildOrgInfoFormOptions } from "../../../../EnterpriseInfo/OrgInfo/formOptions";
|
||
import StaffViewModal from "~/components/StaffViewModal";
|
||
|
||
const LIST_PATH = "/container/supervision/basicInfo/registeredOrg/list";
|
||
const ORG_INFO_FORM_OPTIONS = buildOrgInfoFormOptions();
|
||
|
||
function parseQueryId(location) {
|
||
const search = location?.search || window.location.search || "";
|
||
return new URLSearchParams(search).get("id");
|
||
}
|
||
|
||
function resolvePreviewUrl(raw) {
|
||
if (!raw) return "";
|
||
const u = String(raw);
|
||
if (/^https?:\/\//i.test(u)) return u;
|
||
const base = window.fileUrl || "";
|
||
return base ? `${base}${u}` : u;
|
||
}
|
||
|
||
function isImageUrl(url) {
|
||
return /\.(jpe?g|png|gif|webp|bmp)(\?|#|$)/i.test(String(url || "").toLowerCase());
|
||
}
|
||
|
||
function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||
if (loading) {
|
||
return <Spin />;
|
||
}
|
||
return (
|
||
<div>
|
||
<div style={{ marginBottom: 12, color: "rgba(0,0,0,0.45)" }}>
|
||
该机构共申请
|
||
<strong>{materialGroups.length}</strong>
|
||
个业务范围资质,以下为各范围对应的申请材料清单
|
||
</div>
|
||
{materialGroups.map((group) => (
|
||
<Card
|
||
key={group.id}
|
||
size="small"
|
||
style={{ marginBottom: 16 }}
|
||
title={`业务范围:${group.scopeName}`}
|
||
extra={(
|
||
<span style={{ fontSize: 12 }}>
|
||
证书有效期:
|
||
<span style={{ color: group.expireWarning ? "#faad14" : "#52c41a", fontWeight: 500 }}>
|
||
{group.expireDate}
|
||
{group.expireWarning ? "(即将到期)" : ""}
|
||
</span>
|
||
</span>
|
||
)}
|
||
>
|
||
<Table
|
||
size="small"
|
||
bordered
|
||
rowKey="id"
|
||
pagination={false}
|
||
dataSource={group.materials}
|
||
columns={[
|
||
{ title: "材料名称", dataIndex: "name" },
|
||
{
|
||
title: "操作",
|
||
width: 80,
|
||
render: (_, record) => (
|
||
<Button type="link" size="small" onClick={() => onPreview(record)}>预览</Button>
|
||
),
|
||
},
|
||
]}
|
||
/>
|
||
</Card>
|
||
))}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function PersonnelTab({ personnel, loading, onView }) {
|
||
if (loading) {
|
||
return <Spin />;
|
||
}
|
||
return (
|
||
<Table
|
||
size="small"
|
||
bordered
|
||
rowKey="id"
|
||
pagination={false}
|
||
dataSource={personnel}
|
||
columns={[
|
||
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
||
{ title: "姓名", dataIndex: "name", width: 90 },
|
||
{ title: "性别", dataIndex: "gender", width: 60 },
|
||
{ title: "岗位", dataIndex: "position", width: 110 },
|
||
{ title: "资质范围", dataIndex: "qualScope", width: 90 },
|
||
{ title: "学历", dataIndex: "education", width: 80 },
|
||
{
|
||
title: "注册安全工程师",
|
||
width: 120,
|
||
render: (_, record) => (
|
||
<Tag color={record.registerEngineer === 1 ? "success" : "error"}>
|
||
{record.registerEngineer === 1 ? "是" : "否"}
|
||
</Tag>
|
||
),
|
||
},
|
||
{
|
||
title: "操作",
|
||
width: 80,
|
||
render: (_, record) => (
|
||
<Button type="link" size="small" onClick={() => onView(record)}>查看</Button>
|
||
),
|
||
},
|
||
]}
|
||
/>
|
||
);
|
||
}
|
||
|
||
function RegisteredOrgDetailPage(props) {
|
||
const id = useMemo(() => parseQueryId(props.location), [props.location?.search]);
|
||
const [form] = Form.useForm();
|
||
const [orgLoading, setOrgLoading] = useState(Boolean(parseQueryId(props.location)));
|
||
const [extrasLoading, setExtrasLoading] = useState(Boolean(parseQueryId(props.location)));
|
||
const [orgName, setOrgName] = useState("");
|
||
const [materialGroups, setMaterialGroups] = useState([]);
|
||
const [personnel, setPersonnel] = useState([]);
|
||
const [filePreview, setFilePreview] = useState(null);
|
||
const [viewPersonnelId, setViewPersonnelId] = useState("");
|
||
|
||
useEffect(() => {
|
||
if (!id) {
|
||
setOrgLoading(false);
|
||
setExtrasLoading(false);
|
||
return;
|
||
}
|
||
|
||
let cancelled = false;
|
||
setOrgLoading(true);
|
||
setExtrasLoading(true);
|
||
|
||
(async () => {
|
||
try {
|
||
const [orgRes, groups, staffList] = await Promise.all([
|
||
fetchRegisteredOrgDetail(id),
|
||
fetchRegisteredOrgQualificationGroups(id).catch((err) => {
|
||
console.warn("[RegisteredOrgDetail] qualification load failed:", err);
|
||
|
||
return [];
|
||
}),
|
||
fetchRegisteredOrgPersonnelList(id).catch((err) => {
|
||
console.warn("[RegisteredOrgDetail] personnel load failed:", err);
|
||
|
||
return [];
|
||
}),
|
||
]);
|
||
if (cancelled) {
|
||
return;
|
||
}
|
||
if (orgRes?.data) {
|
||
form.setFieldsValue(orgRes.data);
|
||
setOrgName(orgRes.data.orgName || "");
|
||
}
|
||
setMaterialGroups(groups || []);
|
||
setPersonnel(staffList || []);
|
||
}
|
||
catch (err) {
|
||
if (!cancelled) {
|
||
console.warn("[RegisteredOrgDetail] load failed:", err);
|
||
message.error("加载机构详情失败");
|
||
}
|
||
}
|
||
finally {
|
||
if (!cancelled) {
|
||
setOrgLoading(false);
|
||
setExtrasLoading(false);
|
||
}
|
||
}
|
||
})();
|
||
|
||
return () => {
|
||
cancelled = true;
|
||
};
|
||
}, [id]);
|
||
|
||
const goBack = () => {
|
||
if (props.history?.goBack && props.history.length > 1) {
|
||
props.history.goBack();
|
||
return;
|
||
}
|
||
if (props.history?.push) {
|
||
props.history.push(LIST_PATH);
|
||
return;
|
||
}
|
||
window.location.href = `/certificate${LIST_PATH}`;
|
||
};
|
||
|
||
if (!id) {
|
||
return (
|
||
<PageLayout title="备案信息详情" extra={<Button onClick={goBack}>返回</Button>}>
|
||
<p style={{ margin: 0, marginBottom: 24, color: "rgba(0, 0, 0, 0.45)" }}>
|
||
缺少机构 ID 参数
|
||
</p>
|
||
</PageLayout>
|
||
);
|
||
}
|
||
|
||
const tabItems = [
|
||
{
|
||
key: "info",
|
||
label: "备案信息",
|
||
children: (
|
||
<Spin spinning={orgLoading}>
|
||
<FormBuilder
|
||
form={form}
|
||
span={12}
|
||
disabled
|
||
useAutoGenerateRequired={false}
|
||
options={ORG_INFO_FORM_OPTIONS}
|
||
labelCol={{ span: 10 }}
|
||
showActionButtons={false}
|
||
/>
|
||
</Spin>
|
||
),
|
||
},
|
||
{
|
||
key: "materials",
|
||
label: "申请清单材料",
|
||
children: (
|
||
<MaterialsTab
|
||
materialGroups={materialGroups}
|
||
loading={extrasLoading}
|
||
onPreview={(record) => {
|
||
const url = resolvePreviewUrl(record?.previewUrl);
|
||
if (!url) {
|
||
message.warning("该材料暂无可预览的附件");
|
||
return;
|
||
}
|
||
if (isImageUrl(url)) {
|
||
setFilePreview(record);
|
||
} else {
|
||
window.open(url, "_blank");
|
||
}
|
||
}}
|
||
/>
|
||
),
|
||
},
|
||
{
|
||
key: "personnel",
|
||
label: "人员信息",
|
||
children: (
|
||
<PersonnelTab
|
||
personnel={personnel}
|
||
loading={extrasLoading}
|
||
onView={(record) => setViewPersonnelId(record.id)}
|
||
/>
|
||
),
|
||
},
|
||
];
|
||
|
||
return (
|
||
<PageLayout title="备案信息详情" history={props.history} previous>
|
||
<p style={{ margin: 0, marginBottom: 24, color: "rgba(0, 0, 0, 0.45)" }}>
|
||
{orgName || undefined}
|
||
</p>
|
||
<Tabs items={tabItems} />
|
||
|
||
<FilePreviewModal
|
||
open={!!filePreview}
|
||
title="文件预览"
|
||
fileName={filePreview?.name}
|
||
url={resolvePreviewUrl(filePreview?.previewUrl)}
|
||
onCancel={() => setFilePreview(null)}
|
||
/>
|
||
|
||
{viewPersonnelId && (
|
||
<StaffViewModal
|
||
open={!!viewPersonnelId}
|
||
currentId={viewPersonnelId}
|
||
|
||
onCancel={() => setViewPersonnelId("")}
|
||
/>
|
||
)}
|
||
</PageLayout>
|
||
);
|
||
}
|
||
|
||
export default RegisteredOrgDetailPage;
|