import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message, Modal, Space } from "antd";
import { useEffect, useRef, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import Search from "zy-react-library/components/Search";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import PersonnelSelect from "zy-react-library/components/Select/Personnel/Gwj";
import Table from "zy-react-library/components/Table";
import TooltipPreviewImg from "zy-react-library/components/TooltipPreviewImg";
import Upload from "zy-react-library/components/Upload";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
import useDeleteFile from "zy-react-library/hooks/useDeleteFile";
import useGetFile from "zy-react-library/hooks/useGetFile";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import useGetUserInfo from "zy-react-library/hooks/useGetUserInfo";
import useTable from "zy-react-library/hooks/useTable";
import useUploadFile from "zy-react-library/hooks/useUploadFile";
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
import { useDebounce } from "~/utils";
import { useLocation } from 'react-router-dom';
const JOB_STATUS = {
1: "在职",
0: "离职",
2: "信息变更中",
3: "未入职",
4: "实习生",
5: "实习结束",
6: "退休",
7: "劳务派遣",
8: "劳务派遣结束",
11: "入职待审核",
10: "离职待审核",
};
function List({ props, certificatePhotoType, displayType, personnelType, permissionAdd, permissionEdit, permissionView, permissionDel, dictionaryType }) {
const [addModalOpen, setAddModalOpen] = useState(false);
const [currentId, setCurrentId] = useState("");
const queryParams = useGetUrlQuery();
const { loading: getFileLoading, getFile } = useGetFile();
const [form] = Form.useForm();
const { tableProps, getData } = useTable(props["userCertificateList"], {
form,
transform: (formData) => {
return {
...formData,
eqCorpinfoId: queryParams["corpinfoId"],
eqType: personnelType,
};
},
});
const onDelete = async (row) => {
props["projectHasUser"]({ eqUserId: row.userId }).then((res) => {
console.log(res);
if (res.data && res.data.length > 0) {
const arr = [];
const userArr = [];
res.data.forEach((item) => {
arr.push(item.projectName);
userArr.push(item.userName);
});
Modal.confirm({
title: "提示",
content: (
【
{[...new Set(userArr)].join(",")}
】有正在进行的项目,包含【
{
[...new Set(arr)].join(",")
}
】确定删除吗?
删除可能会对正在进行的项目造成异常状态,请谨慎操作。
),
onOk: () => {
props["userCertificateRemove"]({
id: row.id,
}).then((res) => {
if (res.success) {
message.success("删除成功");
getData();
}
});
},
});
}
else {
Modal.confirm({
title: "提示",
content: "确定删除吗?",
onOk: () => {
props["userCertificateRemove"]({
id: row.id,
}).then((res) => {
if (res.success) {
message.success("删除成功");
getData();
}
});
},
});
}
});
};
const [fileCache, setFileCache] = useState({});
const [loadingKeys, setLoadingKeys] = useState(new Set());
const pendingLoadIdsRef = useRef(new Set());
const requestQueueRef = useRef([]);
const activeRequestsRef = useRef(0);
const MAX_CONCURRENT_REQUESTS = 3; // 最大并发请求数
const processQueue = () => {
while (
requestQueueRef.current.length > 0
&& activeRequestsRef.current < MAX_CONCURRENT_REQUESTS
) {
const { id, resolve, reject } = requestQueueRef.current.shift();
activeRequestsRef.current++;
getFile({
eqType: UPLOAD_FILE_TYPE_ENUM[certificatePhotoType],
eqForeignKey: id,
})
.then((res) => {
setFileCache(prev => ({
...prev,
[id]: res || [],
}));
resolve(res);
})
.catch((err) => {
console.error("图片加载失败:", err);
reject(err);
})
.finally(() => {
activeRequestsRef.current--;
setLoadingKeys((prev) => {
const newSet = new Set(prev);
newSet.delete(id);
return newSet;
});
processQueue();
});
}
};
const loadFileForRecord = (userQualificationinfoId) => {
if (!userQualificationinfoId)
return Promise.resolve();
if (fileCache[userQualificationinfoId])
return Promise.resolve();
if (loadingKeys.has(userQualificationinfoId))
return Promise.resolve();
if (pendingLoadIdsRef.current.has(userQualificationinfoId))
return Promise.resolve();
pendingLoadIdsRef.current.add(userQualificationinfoId);
setLoadingKeys(prev => new Set([...prev, userQualificationinfoId]));
return new Promise((resolve, reject) => {
requestQueueRef.current.push({ id: userQualificationinfoId, resolve, reject });
processQueue();
}).finally(() => {
pendingLoadIdsRef.current.delete(userQualificationinfoId);
});
};
// 清除伪类
useEffect(() => {
if (displayType === "View") {
const style = document.createElement("style");
style.innerHTML = `
.search-layout::after {
content: none !important;
display: none !important;
}
`;
document.head.appendChild(style);
// 清理函数,在组件卸载时移除样式
return () => {
document.head.removeChild(style);
};
}
}, []);
// 缓存数据变化时清空图片缓存
useEffect(() => {
if (tableProps.dataSource) {
const currentIds = new Set(tableProps.dataSource.map(item => item.userCertificateId).filter(Boolean));
setFileCache((prev) => {
const newCache = {};
Object.keys(prev).forEach((id) => {
if (currentIds.has(id)) {
newCache[id] = prev[id];
}
});
return newCache;
});
}
}, [tableProps.dataSource]);
// 记录已经触发过加载的 ID,避免 render 重复触发
const triggeredLoadIdsRef = useRef(new Set());
useEffect(() => {
if (tableProps.dataSource) {
tableProps.dataSource.forEach((record) => {
const id = record.userCertificateId;
if (id && !triggeredLoadIdsRef.current.has(id)) {
triggeredLoadIdsRef.current.add(id);
loadFileForRecord(id);
}
});
}
// 组件卸载或数据源变化时重置
return () => {
triggeredLoadIdsRef.current.clear();
};
}, [tableProps.dataSource]);
return (
(
<>
{
(displayType !== "View" && props.permission(permissionAdd))
&& (
}
onClick={() => {
setAddModalOpen(true);
}}
>
新增
)
}
>
)}
columns={[
{
title: "姓名",
dataIndex: "name",
},
{
title: "证书名称",
dataIndex: "certificateName",
},
{
title: "证书编号",
dataIndex: "certificateCode",
},
{
title: "岗位名称",
dataIndex: "postName",
},
{
title: "有效期至",
dataIndex: "certificateNo",
width: 280,
render: (_, record) =>
{`${record.certificateDateStart ?? ""} - ${record.certificateDateEnd ?? ""}`}
,
},
{
title: "就职状态",
dataIndex: "certificateNo",
render: (_, record) => (
{JOB_STATUS[record.employmentStatus] || "-"}
),
},
{
title: "图片",
dataIndex: "name",
render: (_, record) => {
const id = record.userCertificateId;
const files = fileCache[id] || [];
if (!files.length)
return 无;
return ;
},
},
{
title: "操作",
width: 200,
render: (_, record) => (
{
props.permission(permissionView)
&& (
)
}
{
(displayType !== "View" && props.permission(permissionEdit))
&& (
)
}
{
(displayType !== "View" && props.permission(permissionDel))
&& (
)
}
),
},
]}
{...tableProps}
/>
{addModalOpen && (
{
setAddModalOpen(false);
setCurrentId("");
}}
onSuccess={(userQualificationinfoId) => {
// 清除该记录的图片缓存,强制下次 render 时重新加载
setFileCache((prev) => {
const newCache = { ...prev };
delete newCache[userQualificationinfoId];
return newCache;
});
}}
/>
)}
);
}
function AddModalComponent(props) {
const [form] = Form.useForm();
const [userQualificationinfoId, setUserQualificationinfoId] = useState("");
const [userObj, setUserObj] = useState({});
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
const { loading: getFileLoading, getFile } = useGetFile();
const { getUserInfo } = useGetUserInfo();
const [deleteCardImageFiles, setDeleteCardImageFiles] = useState([]);
const [CertificateCodeValue, setPertificateCodeValue] = useState(null);
const debouncedCertificateCodeValue = useDebounce(CertificateCodeValue, 100);
const [personnelData, setPersonnelData] = useState([]);
const [isSubmit, setIsSubmit] = useState(true);
const location = useLocation();
const getUserInfoFun = async () => {
const userInfo = await getUserInfo();
setUserObj(userInfo);
};
const getUserlistFun = async () => {
props.getUserlistAll({menuPath:"/certificate"+location.pathname}).then(res => {
if(res.data) {
res.data.forEach(item => {
item.bianma=item.id;
})
setPersonnelData(res.data)
}
})
};
useEffect(() => {
if (props.currentId) {
const fetchData = async () => {
const { data } = await props.requestDetails({
id: props.currentId,
});
const certificateImgs = await getFile({
eqType: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
eqForeignKey: data.userCertificateId,
});
data.certificateDate = [data.certificateDateStart, data.certificateDateEnd];
data.certificateImgs = certificateImgs;
form.setFieldsValue(data);
setUserQualificationinfoId(data.userCertificateId);
};
fetchData();
}
getUserInfoFun();
getUserlistFun()
}, [props.currentId]);
const onCancel = () => {
form.resetFields();
props.onCancel();
};
const onSubmit = async (values) => {
if (!isSubmit) {
form.setFields([
{
name: "certificateCode",
errors: ["证书编号重复"],
},
]);
return;
}
if (values.certificateImgs.length !== 2) {
message.error("证照照片必须上传正反面两张");
return;
}
const maxSizeInBytes = 10 * 1024 * 1024;
const isOverSize = values.certificateImgs.some(file => file.size > maxSizeInBytes);
if (isOverSize) {
message.error("选择的图片不能大于10MB");
return;
}
await deleteFile({
single: false,
files: deleteCardImageFiles,
});
const { id } = await uploadFile({
single: false,
files: values.certificateImgs,
params: {
type: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
foreignKey: userQualificationinfoId,
},
});
values.certificateDateStart = values.certificateDate[0];
values.certificateDateEnd = values.certificateDate[1];
values.type = props.personnelType;
const personnelTypeMap = {
tezhongzuoye: "特种作业人员",
tzsbczry: "特种设备操作人员",
zyfzr: "主要负责人",
aqscglry: "安全生产管理人员",
};
values.typeName = personnelTypeMap[props.personnelType];
if (props.currentId) {
values.id = props.currentId;
values.userCertificateId = userQualificationinfoId;
await props.requestEdit(values).then((res) => {
if (res.success) {
onCancel();
props.getData();
props.onSuccess(userQualificationinfoId);
message.success("编辑成功");
}
});
}
else {
values.userCertificateId = id;
await props.requestAdd(values).then((res) => {
if (res.success) {
onCancel();
props.getData();
props.onSuccess(userQualificationinfoId);
message.success("新增成功");
}
});
}
};
// 校验重复
useEffect(() => {
if (!debouncedCertificateCodeValue) {
form.setFields([
{
name: "certificateCode",
errors: [],
},
]);
return;
}
props["userCertificateIsExistCertNo"]({
certNo: debouncedCertificateCodeValue,
id: props.currentId ?? "",
}).then((res) => {
if (res.data) {
form.setFields([
{
name: "certificateCode",
errors: ["证书编号重复"],
},
]);
setIsSubmit(false);
}
else {
setIsSubmit(true);
}
});
}, [debouncedCertificateCodeValue]);
const onValuesChange = (changedValues) => {
if ("certificateCode" in changedValues) {
setPertificateCodeValue(changedValues.certificateCode ?? "");
}
};
return (
form.setFieldValue("postName", label)}
/>
),
},
{ name: "postName", label: "岗位名称", onlyForLabel: true },
{
name: "issuingAuthority",
label: "发证机构",
},
{
name: "dateIssue",
label: "发证日期",
render: FORM_ITEM_RENDER_ENUM.DATE,
},
{
name: "certificateDate",
label: "有效期",
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
rules: [
{
validator: (_, value) => {
const allEmptyStrings = Array.isArray(value) && value.every(item => item === "");
if (allEmptyStrings) {
return Promise.reject(new Error("请选择有效期"));
}
return Promise.resolve();
},
},
],
},
{
name: "certificateImgs",
label: "证照照片",
render: (
{
setDeleteCardImageFiles([...deleteCardImageFiles, file]);
}}
tipContent={(
温馨提示:用户要上传证照照片正反面(证照照片数量是2张)单张大小不超过10MB,支持jpg、jpeg、png格式。
)}
/>
),
},
]}
labelCol={{
span: 10,
}}
showActionButtons={false}
onFinish={onSubmit}
/>
);
}
const AddModal = AddModalComponent;
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));