safety-eval-service-frontend/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/Detail/index.js

297 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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 "../../../../EnterpriseInfo/PersonnelInfo/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);
message.error(err?.message || "加载申请材料失败");
return [];
}),
fetchRegisteredOrgPersonnelList(id).catch((err) => {
console.warn("[RegisteredOrgDetail] personnel load failed:", err);
message.error(err?.message || "加载人员信息失败");
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="备案信息详情" extra={<Button onClick={goBack}> 返回</Button>}>
<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}
requestDetails={fetchRegisteredOrgPersonnelDetail}
requestCertList={fetchRegisteredOrgPersonnelCertList}
requestCertDetails={fetchRegisteredOrgPersonnelCertDetail}
onCancel={() => setViewPersonnelId("")}
/>
)}
</PageLayout>
);
}
export default RegisteredOrgDetailPage;