bug修复
parent
4cb916cf5c
commit
3f6eb45b6b
|
|
@ -10,8 +10,8 @@ module.exports = {
|
||||||
javaGitBranch: "dev",
|
javaGitBranch: "dev",
|
||||||
// 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095)
|
// 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095)
|
||||||
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
||||||
//API_HOST: "https://gbs-gateway.qhdsafety.com",
|
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||||
API_HOST: "http://192.168.0.150",
|
//API_HOST: "http://192.168.0.150",
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
// 应用后端分支名称,部署上线需要
|
// 应用后端分支名称,部署上线需要
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
fetchStaffCertListByPersonnelId,
|
fetchStaffCertListByPersonnelId,
|
||||||
} from "~/api/staffCertificate";
|
} from "~/api/staffCertificate";
|
||||||
import { fetchOrgPersonnelDetail } from "~/utils/qualFiling/personnelHelper";
|
import { fetchOrgPersonnelDetail } from "~/utils/qualFiling/personnelHelper";
|
||||||
import { TITLE_LEVEL_MAP } from "~/enumerate/enterpriseOptions";
|
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP, TITLE_LEVEL_MAP } from "~/enumerate/enterpriseOptions";
|
||||||
|
|
||||||
const GENDER_MAP = { 1: "男", 2: "女" };
|
const GENDER_MAP = { 1: "男", 2: "女" };
|
||||||
const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" };
|
const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" };
|
||||||
|
|
@ -138,7 +138,7 @@ export default function StaffViewModal({
|
||||||
{info.personTypeName || "基础人员"}
|
{info.personTypeName || "基础人员"}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="资质范围">
|
<Descriptions.Item label="资质范围">
|
||||||
{info.qualScope || "-"}
|
{QUALIFICATION_INDUSTRY_OPTIONS_MAP[info.qualScope] || info.qualScope || "-"}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="职业等级">
|
<Descriptions.Item label="职业等级">
|
||||||
{info.professionalLevelName || "-"}
|
{info.professionalLevelName || "-"}
|
||||||
|
|
@ -307,13 +307,18 @@ export default function StaffViewModal({
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="查看证书">
|
<Descriptions.Item label="查看证书">
|
||||||
{certPreviewInfo.certAttachmentUrl &&
|
{certPreviewInfo.certAttachmentUrl &&
|
||||||
certPreviewInfo.certAttachmentUrl.split(",").map((item) => (
|
certPreviewInfo.certAttachmentUrl.split(",").map((item) => {
|
||||||
<div>
|
const isImage = /\.(png|jpe?g|gif|bmp|webp|svg)(\?|#|$)/i.test(item);
|
||||||
<a key={item} onClick={() => window.open(item)}>
|
return (
|
||||||
{item}
|
<div key={item} style={{ marginBottom: 4 }}>
|
||||||
</a>
|
{isImage ? (
|
||||||
|
<Image src={item} width={100} style={{ cursor: "pointer" }} />
|
||||||
|
) : (
|
||||||
|
<a onClick={() => window.open(item)}>{item}</a>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Button, Upload } from "antd";
|
import { Button, Upload, message } from "antd";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -19,6 +19,21 @@ export default function UploadButton({
|
||||||
}) {
|
}) {
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
|
|
||||||
|
const allowedExts = uploadProps?.accept
|
||||||
|
? uploadProps.accept.split(",").map((e) => e.trim().toLowerCase())
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
if (allowedExts.length > 0) {
|
||||||
|
const ext = "." + file.name.split(".").pop().toLowerCase();
|
||||||
|
if (!allowedExts.includes(ext)) {
|
||||||
|
message.error(`不支持 ${ext} 格式文件,仅支持 ${uploadProps.accept}`);
|
||||||
|
return Upload.LIST_IGNORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Upload
|
<Upload
|
||||||
showUploadList={false}
|
showUploadList={false}
|
||||||
|
|
@ -26,6 +41,7 @@ export default function UploadButton({
|
||||||
headers={{
|
headers={{
|
||||||
token: sessionStorage.getItem("token"),
|
token: sessionStorage.getItem("token"),
|
||||||
}}
|
}}
|
||||||
|
beforeUpload={beforeUpload}
|
||||||
onChange={(info) => {
|
onChange={(info) => {
|
||||||
if (info.file.status === "uploading") {
|
if (info.file.status === "uploading") {
|
||||||
setUploading(true);
|
setUploading(true);
|
||||||
|
|
|
||||||
|
|
@ -13,27 +13,67 @@ export default function EquipmentStep({
|
||||||
}) {
|
}) {
|
||||||
const [selectOpen, setSelectOpen] = useState(false);
|
const [selectOpen, setSelectOpen] = useState(false);
|
||||||
const [previewImage, setPreviewImage] = useState("");
|
const [previewImage, setPreviewImage] = useState("");
|
||||||
const existingIds = equipmentList.map((item) => String(item.sourceEquipmentId || ""));
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
|
const existingIds = equipmentList.map((item) =>
|
||||||
|
String(item.sourceEquipmentId || ""),
|
||||||
|
);
|
||||||
|
|
||||||
const isImage = (url) => /\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i.test(url || "");
|
const isImage = (url) =>
|
||||||
|
/\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i.test(url || "");
|
||||||
|
|
||||||
|
const handleBatchRemove = () => {
|
||||||
|
const records = selectedRowKeys
|
||||||
|
.map((key) =>
|
||||||
|
equipmentList.find(
|
||||||
|
(item) => String(item.sourceEquipmentId || item.id) === key,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(Boolean);
|
||||||
|
if (records.length > 0) {
|
||||||
|
onRemove?.(records);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 12 }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<span style={{ fontWeight: 600 }}>申请单位装备清单</span>
|
<span style={{ fontWeight: 600 }}>申请单位装备清单</span>
|
||||||
{!disabled && (
|
{!disabled && (
|
||||||
<Button size="small" onClick={() => setSelectOpen(true)}>添加设备</Button>
|
<Space size="small">
|
||||||
|
<Button size="small" onClick={() => setSelectOpen(true)}>
|
||||||
|
添加设备
|
||||||
|
</Button>
|
||||||
|
{selectedRowKeys.length > 0 && (
|
||||||
|
<Button danger size="small" onClick={handleBatchRemove}>
|
||||||
|
批量移除
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
rowKey="id"
|
rowKey={(record) => String(record.sourceEquipmentId || record.id)}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
dataSource={equipmentList || []}
|
dataSource={equipmentList || []}
|
||||||
|
rowSelection={
|
||||||
|
!disabled
|
||||||
|
? {
|
||||||
|
selectedRowKeys,
|
||||||
|
onChange: setSelectedRowKeys,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
||||||
{ title: "装备名称", dataIndex: "deviceName", ellipsis: true },
|
{ title: "装备名称", dataIndex: "deviceName", ellipsis: true },
|
||||||
{ title: "规格型号", dataIndex: "deviceModel",ellipsis: true },
|
{ title: "规格型号", dataIndex: "deviceModel", ellipsis: true },
|
||||||
{ title: "生产厂家", dataIndex: "manufacturer" },
|
{ title: "生产厂家", dataIndex: "manufacturer" },
|
||||||
{
|
{
|
||||||
title: "计量检定情况",
|
title: "计量检定情况",
|
||||||
|
|
@ -57,6 +97,10 @@ export default function EquipmentStep({
|
||||||
) : (
|
) : (
|
||||||
!disabled && (
|
!disabled && (
|
||||||
<UploadButton
|
<UploadButton
|
||||||
|
uploadProps={{
|
||||||
|
accept:
|
||||||
|
".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.bmp,.webp",
|
||||||
|
}}
|
||||||
onSuccess={(data) => onUploadCalibration?.(record, data)}
|
onSuccess={(data) => onUploadCalibration?.(record, data)}
|
||||||
buttonProps={{ children: "上传报告" }}
|
buttonProps={{ children: "上传报告" }}
|
||||||
/>
|
/>
|
||||||
|
|
@ -68,10 +112,16 @@ export default function EquipmentStep({
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, record) => (
|
render: (_, record) =>
|
||||||
!disabled && (
|
!disabled && (
|
||||||
<Button type="link" size="small" danger onClick={() => onRemove?.(record)}>移除</Button>
|
<Button
|
||||||
)
|
type="link"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
onClick={() => onRemove?.(record)}
|
||||||
|
>
|
||||||
|
移除
|
||||||
|
</Button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
@ -85,7 +135,8 @@ export default function EquipmentStep({
|
||||||
setSelectOpen(false);
|
setSelectOpen(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{previewImage&&<Image
|
{previewImage && (
|
||||||
|
<Image
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
preview={{
|
preview={{
|
||||||
visible: !!previewImage,
|
visible: !!previewImage,
|
||||||
|
|
@ -94,7 +145,8 @@ export default function EquipmentStep({
|
||||||
if (!visible) setPreviewImage("");
|
if (!visible) setPreviewImage("");
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>}
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ export default function MaterialStep({
|
||||||
{!disabled && (
|
{!disabled && (
|
||||||
<UploadButton
|
<UploadButton
|
||||||
onSuccess={(data) => onUpload?.(record, data)}
|
onSuccess={(data) => onUpload?.(record, data)}
|
||||||
|
uploadProps={{ accept: ".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg,.gif,.bmp,.webp" }}
|
||||||
>
|
>
|
||||||
{record.attachmentUrl ? "重新上传" : "上传"}
|
{record.attachmentUrl ? "重新上传" : "上传"}
|
||||||
</UploadButton>
|
</UploadButton>
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,22 @@ const PersonnelStep=({
|
||||||
})=> {
|
})=> {
|
||||||
const [selectOpen, setSelectOpen] = useState(false);
|
const [selectOpen, setSelectOpen] = useState(false);
|
||||||
const [viewId, setViewId] = useState("");
|
const [viewId, setViewId] = useState("");
|
||||||
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||||
|
|
||||||
const existingIds = personnelList.map((item) => String(item.sourcePersonnelId || item.id || ""));
|
const existingIds = personnelList.map((item) => String(item.sourcePersonnelId || item.id || ""));
|
||||||
|
|
||||||
|
const handleBatchRemove = () => {
|
||||||
|
const records = selectedRowKeys
|
||||||
|
.map((key) => personnelList.find(
|
||||||
|
(item) => String(item.sourcePersonnelId || item.id) === key,
|
||||||
|
))
|
||||||
|
.filter(Boolean);
|
||||||
|
if (records.length > 0) {
|
||||||
|
onRemove?.(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 12 }}>
|
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 12 }}>
|
||||||
|
|
@ -25,15 +38,24 @@ const PersonnelStep=({
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{!disabled && (
|
{!disabled && (
|
||||||
|
<Space size="small">
|
||||||
<Button type="primary" size="small" onClick={() => setSelectOpen(true)}>添加人员信息</Button>
|
<Button type="primary" size="small" onClick={() => setSelectOpen(true)}>添加人员信息</Button>
|
||||||
|
{selectedRowKeys.length > 0 && (
|
||||||
|
<Button danger size="small" onClick={handleBatchRemove}>批量删除</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
rowKey="id"
|
rowKey={(record) => String(record.sourcePersonnelId || record.id)}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
scroll={{ y: 400 }}
|
scroll={{ y: 400 }}
|
||||||
dataSource={personnelList}
|
dataSource={personnelList}
|
||||||
|
rowSelection={!disabled ? {
|
||||||
|
selectedRowKeys,
|
||||||
|
onChange: setSelectedRowKeys,
|
||||||
|
} : undefined}
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
||||||
{ title: "人员姓名", dataIndex: "userName", render: (_, record) => record.userName || record.personName },
|
{ title: "人员姓名", dataIndex: "userName", render: (_, record) => record.userName || record.personName },
|
||||||
|
|
|
||||||
|
|
@ -264,15 +264,18 @@ function FilingFormPage(props) {
|
||||||
message.success(`已添加至列表,${saveActionHint}`);
|
message.success(`已添加至列表,${saveActionHint}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePersonnelRemove = (record) => {
|
const handlePersonnelRemove = (records) => {
|
||||||
|
const list = Array.isArray(records) ? records : [records];
|
||||||
|
const names = list.map((r) => r.userName || r.personName).join("、");
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "提示",
|
title: "提示",
|
||||||
content: `确认删除人员「${record.userName || record.personName}」?`,
|
content: `确认删除人员「${names}」?`,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
|
const ids = new Set(list.map((r) => r.id));
|
||||||
setDetail((prev) => ({
|
setDetail((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
personnelList: (prev.personnelList || []).filter(
|
personnelList: (prev.personnelList || []).filter(
|
||||||
(item) => item.id !== record.id,
|
(item) => !ids.has(item.id),
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
@ -305,15 +308,18 @@ function FilingFormPage(props) {
|
||||||
message.success(`已添加至列表,${saveActionHint}`);
|
message.success(`已添加至列表,${saveActionHint}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEquipmentRemove = (record) => {
|
const handleEquipmentRemove = (records) => {
|
||||||
|
const list = Array.isArray(records) ? records : [records];
|
||||||
|
const names = list.map((r) => r.deviceName).join("、");
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "提示",
|
title: "提示",
|
||||||
content: `确认移除装备「${record.deviceName}」?`,
|
content: `确认移除装备「${names}」?`,
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
|
const ids = new Set(list.map((r) => r.id));
|
||||||
setDetail((prev) => ({
|
setDetail((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
equipmentList: (prev.equipmentList || []).filter(
|
equipmentList: (prev.equipmentList || []).filter(
|
||||||
(item) => item.id !== record.id,
|
(item) => !ids.has(item.id),
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -72,14 +72,24 @@ export function verifyFilingPrerequisites(detail = {}) {
|
||||||
return !isNaN(joinDate.getTime()) && joinDate <= twoYearsAgo;
|
return !isNaN(joinDate.getTime()) && joinDate <= twoYearsAgo;
|
||||||
}).length;
|
}).length;
|
||||||
|
|
||||||
|
const noExperienceNames = personnel
|
||||||
|
.filter((p) => {
|
||||||
|
const joinDate = new Date(p.joinWorkDate);
|
||||||
|
return isNaN(joinDate.getTime()) || joinDate > twoYearsAgo;
|
||||||
|
})
|
||||||
|
.map((p) => p.userName || p.personName || "");
|
||||||
|
|
||||||
|
const personnelExpPassed = total >= 25 && ratio(withExperience, total) >= 1;
|
||||||
items.push({
|
items.push({
|
||||||
key: "personnelExp",
|
key: "personnelExp",
|
||||||
label: "人员资历",
|
label: "人员资历",
|
||||||
desc: "专职技术人员在本行业领域工作二年以上",
|
desc: `专职技术人员在本行业领域工作二年以上${
|
||||||
|
!SKIP_PERSONNEL_VERIFY && !personnelExpPassed && noExperienceNames.length > 0
|
||||||
|
? `(不满足:${noExperienceNames.join("、")})`
|
||||||
|
: ""
|
||||||
|
}`,
|
||||||
passed:
|
passed:
|
||||||
SKIP_PERSONNEL_VERIFY ||
|
SKIP_PERSONNEL_VERIFY || personnelExpPassed,
|
||||||
(total >= 25 && ratio(withExperience, total) >= 1),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyOk = KEY_POSITIONS.every((pos) =>
|
const keyOk = KEY_POSITIONS.every((pos) =>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,22 @@
|
||||||
import { Button, Card, Form, Spin, Table, Tabs, Tag, message } from "antd";
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Col,
|
||||||
|
DatePicker,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Spin,
|
||||||
|
Table,
|
||||||
|
Tabs,
|
||||||
|
Tag,
|
||||||
|
Upload,
|
||||||
|
message,
|
||||||
|
} from "antd";
|
||||||
|
import dayjs from "dayjs";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
|
||||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
import FilePreviewModal from "~/components/FilePreviewModal";
|
import FilePreviewModal from "~/components/FilePreviewModal";
|
||||||
import {
|
import {
|
||||||
|
|
@ -8,11 +24,18 @@ import {
|
||||||
fetchRegisteredOrgPersonnelList,
|
fetchRegisteredOrgPersonnelList,
|
||||||
fetchRegisteredOrgQualificationGroups,
|
fetchRegisteredOrgQualificationGroups,
|
||||||
} from "~/utils/regulatorOrgInfo";
|
} from "~/utils/regulatorOrgInfo";
|
||||||
import { buildOrgInfoFormOptions } from "../../../../EnterpriseInfo/OrgInfo/formOptions";
|
import {
|
||||||
|
CHONGQING_DISTRICTS,
|
||||||
|
ENTERPRISE_SCALE_OPTIONS,
|
||||||
|
ENTERPRISE_STATUS_OPTIONS,
|
||||||
|
FILING_RECORD_STATUS_OPTIONS,
|
||||||
|
FILING_TYPE_OPTIONS,
|
||||||
|
QUALIFICATION_INDUSTRY_OPTIONS_MAP,
|
||||||
|
} from "~/enumerate/enterpriseOptions";
|
||||||
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
import StaffViewModal from "~/components/StaffViewModal";
|
import StaffViewModal from "~/components/StaffViewModal";
|
||||||
|
|
||||||
const LIST_PATH = "/container/supervision/basicInfo/registeredOrg/list";
|
const LIST_PATH = "/container/supervision/basicInfo/registeredOrg/list";
|
||||||
const ORG_INFO_FORM_OPTIONS = buildOrgInfoFormOptions();
|
|
||||||
const GENDER_MAP = { 1: "男", 2: "女" };
|
const GENDER_MAP = { 1: "男", 2: "女" };
|
||||||
|
|
||||||
/** 后端字段名 → 前端表单字段名映射 */
|
/** 后端字段名 → 前端表单字段名映射 */
|
||||||
|
|
@ -47,7 +70,7 @@ const BACKEND_TO_FORM_FIELD = {
|
||||||
enterpriseScaleName: "enterpriseScale",
|
enterpriseScaleName: "enterpriseScale",
|
||||||
filingTypeName: "filingType",
|
filingTypeName: "filingType",
|
||||||
filingRecordStatusName: "filingRecordStatus",
|
filingRecordStatusName: "filingRecordStatus",
|
||||||
attachments: "attachments",
|
attachmentUrls: "attachmentUrls",
|
||||||
};
|
};
|
||||||
|
|
||||||
function toFormFields(backendData) {
|
function toFormFields(backendData) {
|
||||||
|
|
@ -55,8 +78,12 @@ function toFormFields(backendData) {
|
||||||
const result = {};
|
const result = {};
|
||||||
Object.entries(BACKEND_TO_FORM_FIELD).forEach(([backendKey, formKey]) => {
|
Object.entries(BACKEND_TO_FORM_FIELD).forEach(([backendKey, formKey]) => {
|
||||||
if (backendData[backendKey] !== undefined) {
|
if (backendData[backendKey] !== undefined) {
|
||||||
|
if (formKey === "productionDate" && backendData[backendKey]) {
|
||||||
|
result[formKey] = dayjs(backendData[backendKey]);
|
||||||
|
} else {
|
||||||
result[formKey] = backendData[backendKey];
|
result[formKey] = backendData[backendKey];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -75,14 +102,17 @@ function resolvePreviewUrl(raw) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isImageUrl(url) {
|
function isImageUrl(url) {
|
||||||
return /\.(jpe?g|png|gif|webp|bmp)(\?|#|$)/i.test(String(url || "").toLowerCase());
|
return /\.(jpe?g|png|gif|webp|bmp)(\?|#|$)/i.test(
|
||||||
|
String(url || "").toLowerCase(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function MaterialsTab({ materialGroups, loading, onPreview }) {
|
function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Spin />;
|
return <Spin />;
|
||||||
}
|
}
|
||||||
const groups = Object.entries(materialGroups || {}).map(([code, list], index) => {
|
const groups = Object.entries(materialGroups || {}).map(
|
||||||
|
([code, list], index) => {
|
||||||
const items = Array.isArray(list) ? list : [];
|
const items = Array.isArray(list) ? list : [];
|
||||||
const scopeName = items[0]?.licenseTypeName || code || `资质${index + 1}`;
|
const scopeName = items[0]?.licenseTypeName || code || `资质${index + 1}`;
|
||||||
const expireDate = items.reduce((latest, item) => {
|
const expireDate = items.reduce((latest, item) => {
|
||||||
|
|
@ -105,11 +135,17 @@ function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
expireWarning,
|
expireWarning,
|
||||||
materials: items.map((item, idx) => {
|
materials: items.map((item, idx) => {
|
||||||
const certImgs = item.certImageUrl
|
const certImgs = item.certImageUrl
|
||||||
? (Array.isArray(item.certImageUrl)
|
? Array.isArray(item.certImageUrl)
|
||||||
? item.certImageUrl
|
? item.certImageUrl
|
||||||
: String(item.certImageUrl).startsWith("[")
|
: String(item.certImageUrl).startsWith("[")
|
||||||
? (() => { try { return JSON.parse(item.certImageUrl); } catch { return [{ url: item.certImageUrl }]; } })()
|
? (() => {
|
||||||
: [{ url: item.certImageUrl }])
|
try {
|
||||||
|
return JSON.parse(item.certImageUrl);
|
||||||
|
} catch {
|
||||||
|
return [{ url: item.certImageUrl }];
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
: [{ url: item.certImageUrl }]
|
||||||
: item.certImgFiles || [];
|
: item.certImgFiles || [];
|
||||||
const previewUrl = certImgs[0]?.url || "";
|
const previewUrl = certImgs[0]?.url || "";
|
||||||
return {
|
return {
|
||||||
|
|
@ -122,7 +158,8 @@ function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
});
|
},
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ marginBottom: 12, color: "rgba(0,0,0,0.45)" }}>
|
<div style={{ marginBottom: 12, color: "rgba(0,0,0,0.45)" }}>
|
||||||
|
|
@ -136,15 +173,20 @@ function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
size="small"
|
size="small"
|
||||||
style={{ marginBottom: 16 }}
|
style={{ marginBottom: 16 }}
|
||||||
title={`业务范围:${group.scopeName}`}
|
title={`业务范围:${group.scopeName}`}
|
||||||
extra={(
|
extra={
|
||||||
<span style={{ fontSize: 12 }}>
|
<span style={{ fontSize: 12 }}>
|
||||||
证书有效期:
|
证书有效期:
|
||||||
<span style={{ color: group.expireWarning ? "#faad14" : "#52c41a", fontWeight: 500 }}>
|
<span
|
||||||
|
style={{
|
||||||
|
color: group.expireWarning ? "#faad14" : "#52c41a",
|
||||||
|
fontWeight: 500,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{group.expireDate}
|
{group.expireDate}
|
||||||
{group.expireWarning ? "(即将到期)" : ""}
|
{group.expireWarning ? "(即将到期)" : ""}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
)}
|
}
|
||||||
>
|
>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
|
|
@ -158,7 +200,13 @@ function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 80,
|
width: 80,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Button type="link" size="small" onClick={() => onPreview(record)}>预览</Button>
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={() => onPreview(record)}
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</Button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
@ -170,12 +218,11 @@ function MaterialsTab({ materialGroups, loading, onPreview }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function PersonnelTab({ personnel, loading, onView }) {
|
function PersonnelTab({ personnel, loading, onView }) {
|
||||||
if (loading) {
|
|
||||||
return <Spin />;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
|
loading={loading}
|
||||||
bordered
|
bordered
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
|
@ -183,15 +230,28 @@ function PersonnelTab({ personnel, loading, onView }) {
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
{ title: "序号", width: 60, render: (_, __, index) => index + 1 },
|
||||||
{ title: "姓名", dataIndex: "userName", width: 90 },
|
{ title: "姓名", dataIndex: "userName", width: 90 },
|
||||||
{ title: "性别", width: 60, render: (_, record) => GENDER_MAP[record.genderCode] || "-" },
|
{
|
||||||
|
title: "性别",
|
||||||
|
width: 60,
|
||||||
|
render: (_, record) => GENDER_MAP[record.genderCode] || "-",
|
||||||
|
},
|
||||||
{ title: "岗位", dataIndex: "postName", width: 110 },
|
{ title: "岗位", dataIndex: "postName", width: 110 },
|
||||||
{ title: "资质范围", dataIndex: "qualScope", width: 90 },
|
{
|
||||||
|
title: "资质范围",
|
||||||
|
width: 90,
|
||||||
|
render: (_, record) =>
|
||||||
|
QUALIFICATION_INDUSTRY_OPTIONS_MAP[record.qualScope] ||
|
||||||
|
record.qualScope ||
|
||||||
|
"-",
|
||||||
|
},
|
||||||
{ title: "学历", dataIndex: "educationName", width: 80 },
|
{ title: "学历", dataIndex: "educationName", width: 80 },
|
||||||
{
|
{
|
||||||
title: "注册安全工程师",
|
title: "注册安全工程师",
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Tag color={record.registerEngineerFlag === 1 ? "success" : "error"}>
|
<Tag
|
||||||
|
color={record.registerEngineerFlag === 1 ? "success" : "error"}
|
||||||
|
>
|
||||||
{record.registerEngineerFlag === 1 ? "是" : "否"}
|
{record.registerEngineerFlag === 1 ? "是" : "否"}
|
||||||
</Tag>
|
</Tag>
|
||||||
),
|
),
|
||||||
|
|
@ -200,7 +260,9 @@ function PersonnelTab({ personnel, loading, onView }) {
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 80,
|
width: 80,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Button type="link" size="small" onClick={() => onView(record)}>查看</Button>
|
<Button type="link" size="small" onClick={() => onView(record)}>
|
||||||
|
查看
|
||||||
|
</Button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
@ -209,10 +271,17 @@ function PersonnelTab({ personnel, loading, onView }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function RegisteredOrgDetailPage(props) {
|
function RegisteredOrgDetailPage(props) {
|
||||||
const id = useMemo(() => parseQueryId(props.location), [props.location?.search]);
|
const id = useMemo(
|
||||||
|
() => parseQueryId(props.location),
|
||||||
|
[props.location?.search],
|
||||||
|
);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [orgLoading, setOrgLoading] = useState(Boolean(parseQueryId(props.location)));
|
const [orgLoading, setOrgLoading] = useState(
|
||||||
const [extrasLoading, setExtrasLoading] = useState(Boolean(parseQueryId(props.location)));
|
Boolean(parseQueryId(props.location)),
|
||||||
|
);
|
||||||
|
const [extrasLoading, setExtrasLoading] = useState(
|
||||||
|
Boolean(parseQueryId(props.location)),
|
||||||
|
);
|
||||||
const [orgName, setOrgName] = useState("");
|
const [orgName, setOrgName] = useState("");
|
||||||
const [materialGroups, setMaterialGroups] = useState({});
|
const [materialGroups, setMaterialGroups] = useState({});
|
||||||
const [personnel, setPersonnel] = useState([]);
|
const [personnel, setPersonnel] = useState([]);
|
||||||
|
|
@ -235,7 +304,10 @@ function RegisteredOrgDetailPage(props) {
|
||||||
const [orgRes, groups, staffList] = await Promise.all([
|
const [orgRes, groups, staffList] = await Promise.all([
|
||||||
fetchRegisteredOrgDetail(id),
|
fetchRegisteredOrgDetail(id),
|
||||||
fetchRegisteredOrgQualificationGroups(id).catch((err) => {
|
fetchRegisteredOrgQualificationGroups(id).catch((err) => {
|
||||||
console.warn("[RegisteredOrgDetail] qualification load failed:", err);
|
console.warn(
|
||||||
|
"[RegisteredOrgDetail] qualification load failed:",
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
|
||||||
return { data: {} };
|
return { data: {} };
|
||||||
}),
|
}),
|
||||||
|
|
@ -254,14 +326,12 @@ function RegisteredOrgDetailPage(props) {
|
||||||
}
|
}
|
||||||
setMaterialGroups(groups?.data || {});
|
setMaterialGroups(groups?.data || {});
|
||||||
setPersonnel(staffList || []);
|
setPersonnel(staffList || []);
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
console.warn("[RegisteredOrgDetail] load failed:", err);
|
console.warn("[RegisteredOrgDetail] load failed:", err);
|
||||||
message.error("加载机构详情失败");
|
message.error("加载机构详情失败");
|
||||||
}
|
}
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setOrgLoading(false);
|
setOrgLoading(false);
|
||||||
setExtrasLoading(false);
|
setExtrasLoading(false);
|
||||||
|
|
@ -288,8 +358,13 @@ function RegisteredOrgDetailPage(props) {
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return (
|
return (
|
||||||
<PageLayout title="备案信息详情" extra={<Button onClick={goBack}>返回</Button>}>
|
<PageLayout
|
||||||
<p style={{ margin: 0, marginBottom: 24, color: "rgba(0, 0, 0, 0.45)" }}>
|
title="备案信息详情"
|
||||||
|
extra={<Button onClick={goBack}>返回</Button>}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
style={{ margin: 0, marginBottom: 24, color: "rgba(0, 0, 0, 0.45)" }}
|
||||||
|
>
|
||||||
缺少机构 ID 参数
|
缺少机构 ID 参数
|
||||||
</p>
|
</p>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|
@ -302,15 +377,214 @@ function RegisteredOrgDetailPage(props) {
|
||||||
label: "备案信息",
|
label: "备案信息",
|
||||||
children: (
|
children: (
|
||||||
<Spin spinning={orgLoading}>
|
<Spin spinning={orgLoading}>
|
||||||
<FormBuilder
|
<Form form={form} disabled labelCol={{ span: 10 }}>
|
||||||
form={form}
|
<Row gutter={16}>
|
||||||
span={12}
|
<Col span={12}>
|
||||||
disabled
|
<Form.Item name="orgName" label="生产经营单位名称">
|
||||||
useAutoGenerateRequired={false}
|
<Input />
|
||||||
options={ORG_INFO_FORM_OPTIONS}
|
</Form.Item>
|
||||||
labelCol={{ span: 10 }}
|
</Col>
|
||||||
showActionButtons={false}
|
<Col span={12}>
|
||||||
|
<Form.Item name="creditCode" label="统一社会信用代码">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="safetyIndustryCategory"
|
||||||
|
label="安全生产监管行业类别"
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="regionCountyName" label="属地">
|
||||||
|
<Select options={CHONGQING_DISTRICTS} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="regionStreetName" label="所属镇、街道">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="regionCommunityName" label="属村(社区)">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="longitude" label="所在地坐标经度">
|
||||||
|
<InputNumber
|
||||||
|
min={-180}
|
||||||
|
max={180}
|
||||||
|
precision={6}
|
||||||
|
style={{ width: "100%" }}
|
||||||
/>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="latitude" label="所在地坐标纬度">
|
||||||
|
<InputNumber
|
||||||
|
min={-90}
|
||||||
|
max={90}
|
||||||
|
precision={6}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="registerAddress" label="注册地址">
|
||||||
|
<Input.TextArea />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="businessAddress" label="经营地址">
|
||||||
|
<Input.TextArea />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="ownershipType" label="归属类型">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="gbIndustryCode"
|
||||||
|
label="国民经济行业分类(GB/T4754-2017)"
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="legalRepresentative" label="法定代表人">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="legalRepPhone" label="法定代表人联系电话">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="principal" label="主要负责人">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="principalPhone" label="主要负责人联系电话">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="safetyDeptHead" label="安全管理部门负责人">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="safetyDeptPhone"
|
||||||
|
label="安全管理部门负责人联系电话"
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="safetyVp" label="主管安全副总">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="safetyVpPhone" label="主管安全副总联系电话">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="productionDate" label="投产日期">
|
||||||
|
<DatePicker style={{ width: "100%" }} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="businessStatus" label="企业经营状态">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="disclosureUrl" label="信息公开网址">
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="workplaceArea" label="工作场所建筑面积">
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
precision={2}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="archiveRoomArea" label="档案室面积">
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
precision={2}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="fullTimeEvaluatorCount"
|
||||||
|
label="专职安全评价师数量"
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
precision={0}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="registeredSafetyEngineerCount"
|
||||||
|
label="注册安全工程师数量"
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
precision={0}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="enterpriseStatus" label="企业状态">
|
||||||
|
<Select options={ENTERPRISE_STATUS_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="enterpriseScale" label="企业规模">
|
||||||
|
<Select options={ENTERPRISE_SCALE_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="filingType" label="备案类型">
|
||||||
|
<Select options={FILING_TYPE_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item name="filingRecordStatus" label="备案状态">
|
||||||
|
<Select options={FILING_RECORD_STATUS_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="attachmentUrls"
|
||||||
|
label="上传附件"
|
||||||
|
disabled
|
||||||
|
maxCount={5}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
</Spin>
|
</Spin>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -368,7 +642,6 @@ function RegisteredOrgDetailPage(props) {
|
||||||
<StaffViewModal
|
<StaffViewModal
|
||||||
open={!!viewPersonnelId}
|
open={!!viewPersonnelId}
|
||||||
currentId={viewPersonnelId}
|
currentId={viewPersonnelId}
|
||||||
|
|
||||||
onCancel={() => setViewPersonnelId("")}
|
onCancel={() => setViewPersonnelId("")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue