Compare commits

...

5 Commits

Author SHA1 Message Date
LiuJiaNan d5c9321cd6 隐患修改 12.4 2025-12-05 14:32:10 +08:00
LiuJiaNan e75c601e73 Merge remote-tracking branch 'origin/master' 2025-12-05 14:30:19 +08:00
LiuJiaNan 5da98bec37 隐患修改 12.4 2025-12-05 10:19:05 +08:00
LiuJiaNan 9b16bab9dd 隐患修改 12.4 2025-12-04 17:29:43 +08:00
LiuJiaNan 9af12d3be8 隐患修改 12.4 2025-12-04 15:15:30 +08:00
8 changed files with 493 additions and 155 deletions

View File

@ -31,7 +31,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-to-print": "^3.2.0",
"zy-react-library": "^1.0.130"
"zy-react-library": "^1.0.139"
},
"devDependencies": {
"@antfu/eslint-config": "^5.4.1",

View File

@ -24,3 +24,7 @@ export const hiddenExportColumn = declareRequest(
"ledgerLoading",
`Get > /hidden/hidden/exportHiddenFields`,
);
export const hiddenAiRecognize = declareRequest(
"ledgerLoading",
`Post > @/hidden/hidden/aiHidden`,
);

View File

@ -5,7 +5,6 @@ import Search from "zy-react-library/components/Search";
import DepartmentSelectTree from "zy-react-library/components/SelectTree/Department/Gwj";
import DictionarySelectTree from "zy-react-library/components/SelectTree/Dictionary";
import HiddenLevelSelectTree from "zy-react-library/components/SelectTree/HiddenLevel/Gwj";
import HiddenPartSelectTree from "zy-react-library/components/SelectTree/HiddenPart/Gwj";
import Table from "zy-react-library/components/Table";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { HIDDEN_RECTIFICATION_TYPE_ENUM, HIDDEN_SOURCE_ENUM } from "zy-react-library/enum/hidden/gwj";
@ -36,11 +35,6 @@ function List(props) {
label: "隐患类型",
render: <DictionarySelectTree dictValue="hiddenType" onlyLastLevel />,
},
{
name: "hiddenPart",
label: "隐患部位",
render: <HiddenPartSelectTree />,
},
{
name: "hiddenLevel",
label: "隐患级别",
@ -68,7 +62,6 @@ function List(props) {
{ title: "隐患描述", dataIndex: "hiddenDesc" },
{ title: "隐患级别", dataIndex: "hiddenLevelName", width: 100 },
{ title: "隐患类型", dataIndex: "hiddenTypeName" },
{ title: "隐患部位", dataIndex: "hiddenPartName" },
{ title: "隐患发现部门", dataIndex: "hiddenFindDeptName" },
{ title: "隐患发现人", dataIndex: "createName", width: 130 },
{

View File

@ -1,9 +1,12 @@
import HiddenInfo from "zy-react-library/components/HiddenInfo/gwj";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
function HiddenView() {
const query = useGetUrlQuery();
return (
<div>
<HiddenInfo />
<HiddenInfo history={query.history === "1"} />
</div>
);
}

View File

@ -1,5 +1,5 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, Input, message } from "antd";
import { Button, Col, Form, Image, Input, message, Modal, Row } from "antd";
import { useEffect, useRef, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder";
import HeaderBack from "zy-react-library/components/HeaderBack";
@ -9,6 +9,7 @@ import DepartmentSelectTree from "zy-react-library/components/SelectTree/Departm
import DictionarySelectTree from "zy-react-library/components/SelectTree/Dictionary";
import HiddenLevelSelectTree from "zy-react-library/components/SelectTree/HiddenLevel/Gwj";
import HiddenPartSelectTree from "zy-react-library/components/SelectTree/HiddenPart/Gwj";
import Table from "zy-react-library/components/Table";
import Upload from "zy-react-library/components/Upload";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { HIDDEN_RECTIFICATION_TYPE_ENUM } from "zy-react-library/enum/hidden/gwj";
@ -18,7 +19,7 @@ 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 useUploadFile from "zy-react-library/hooks/useUploadFile";
import { getFileUrl } from "zy-react-library/utils";
import { createGuid, getFileUrl, getLabelName } from "zy-react-library/utils";
import ai_recognize from "~/assets/images/ai_recognize.png";
import { NS_CONFIRM_USER, NS_LEDGER, NS_PART } from "~/enumerate/namespace";
@ -29,16 +30,25 @@ function Add(props) {
const rectificationDeptId = Form.useWatch("rectificationDeptId", form);
const checkDeptId = Form.useWatch("checkDeptId", form);
const isAi = Form.useWatch("isAi", form);
const isRelated = Form.useWatch("isRelated", form);
const defaultValues = { isRelated: 2, rectificationType: 2 };
const [aiHiddenImageRecognizeLoading, setAIHiddenImageRecognizeLoading] = useState(false);
const aiHiddenImageRecognizeFilePath = useRef("");
const [aiHiddens, setAiHiddens] = useState([]);
const [aiHiddenModalOpen, setAiHiddenModalOpen] = useState(false);
const [selectHiddens, setSelectHiddens] = useState([]);
const [currentProcessHiddenIndex, setCurrentProcessHiddenIndex] = useState(-1);
const [imageSelectModalOpen, setImageSelectModalOpen] = useState(false);
const processedImageUids = useRef([]);
const [uploadedImages, setUploadedImages] = useState([]);
const [modalTitle, setModalTitle] = useState("选择图片进行AI识别");
const [isShowAiButton, setIsShowAiButton] = useState(true);
const [hiddenPartType, setHiddenPartType] = useState("select");
const [confirmUserList, setConfirmUserList] = useState([]);
const [deleteHiddenImageFiles, setDeleteHiddenImageFiles] = useState([]);
const [deleteHiddenVideoFiles, setDeleteHiddenVideoFiles] = useState([]);
const [deleteAfterRectificationImageFiles, setDeleteAfterRectificationImageFiles] = useState([]);
const deleteHiddenImageFiles = useRef([]);
const deleteHiddenVideoFiles = useRef([]);
const deleteAfterRectificationImageFiles = useRef([]);
const { getUserInfo } = useGetUserInfo();
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
@ -93,10 +103,91 @@ function Add(props) {
getConfirmUserList();
}, []);
const clearHiddenRecognizeState = () => {
setSelectHiddens([]);
setCurrentProcessHiddenIndex(-1);
form.setFieldValue("isAi", "");
form.setFieldValue("hiddenDesc", "");
form.setFieldValue("legalBasis", "");
form.setFieldValue("rectificationDescr", "");
form.setFieldValue("aiBatch", "");
};
const getAIHiddenImageRecognize = async (imageToProcess) => {
const { filePath } = await uploadFile({ files: [imageToProcess], params: { type: UPLOAD_FILE_TYPE_ENUM["3"] } });
// const { data } = await props["hiddenAiRecognize"]({ hiddenUrl: "https://pic.rmb.bdstatic.com/bjh/news/0a68c2681805fcaea506d922f024420c.png" });
const { data } = await props["hiddenAiRecognize"]({ hiddenUrl: getFileUrl() + filePath });
if (data?.aiHiddens) {
processedImageUids.current.push(imageToProcess.uid);
setAiHiddens(data?.aiHiddens.map(item => ({ ...JSON.parse(item), id: createGuid() })));
setAiHiddenModalOpen(true);
clearHiddenRecognizeState();
await deleteFile({ files: [{ filePath }] });
}
};
const getUnprocessedImages = () => {
const hiddenImageFiles = form.getFieldValue("hiddenImageFiles") || [];
return hiddenImageFiles.filter(item => !processedImageUids.current.includes(item.uid));
};
const getUnprocessedImagesCount = () => {
return getUnprocessedImages().length;
};
const handleSelectOtherImage = () => {
Modal.confirm({
title: "确认切换图片",
content: "当前有未处理完的隐患信息确认后进入选择图片选择图片重新AI识别将丢弃之前没有处理完的隐患",
onOk: () => {
setModalTitle("选择其他图片进行AI识别");
setImageSelectModalOpen(true);
setUploadedImages(getUnprocessedImages());
},
});
};
const handleAiRecognizeClick = () => {
const hiddenImageFiles = form.getFieldValue("hiddenImageFiles") || [];
if (hiddenImageFiles.length === 0) {
message.error("请上传图片");
return;
}
if (hiddenImageFiles.length === 1) {
getAIHiddenImageRecognize(hiddenImageFiles[0]);
return;
}
setUploadedImages(hiddenImageFiles);
setImageSelectModalOpen(true);
};
const onMergeHidden = (selectedRowKeys) => {
const toBeMerged = aiHiddens.filter(hidden => selectedRowKeys.includes(hidden.id));
const mergedHiddenDescr = toBeMerged.map(h => h.hiddenDescr).join("\n");
const mergedLegalBasis = toBeMerged.map(h => h.legalBasis).join("\n");
const mergedRectificationSuggestions = toBeMerged.map(h => h.rectificationSuggestions).join("\n");
const newMergedHidden = {
id: createGuid(),
hiddenDescr: mergedHiddenDescr,
legalBasis: mergedLegalBasis,
rectificationSuggestions: mergedRectificationSuggestions,
};
setAiHiddens([
...aiHiddens.filter(hidden => !selectedRowKeys.includes(hidden.id)),
newMergedHidden,
]);
};
const isExistNextOneHidden = () => {
if (currentProcessHiddenIndex !== -1)
return currentProcessHiddenIndex !== selectHiddens.length - 1;
return false;
};
const onSubmit = async (values) => {
await deleteFile({ single: false, files: deleteHiddenImageFiles });
await deleteFile({ single: false, files: deleteHiddenVideoFiles });
await deleteFile({ single: false, files: deleteAfterRectificationImageFiles });
await deleteFile({ single: false, files: deleteHiddenImageFiles.current });
await deleteFile({ single: false, files: deleteHiddenVideoFiles.current });
await deleteFile({ single: false, files: deleteAfterRectificationImageFiles.current });
const { id } = await uploadFile({
single: false,
files: values.hiddenImageFiles,
@ -115,51 +206,45 @@ function Add(props) {
if (hiddenPartType === "input") {
await props["partAdd"]({ hiddenregion: values.hiddenPart });
}
const hiddenImageFiles = await getFile({ eqType: UPLOAD_FILE_TYPE_ENUM["3"], eqForeignKey: id });
const { success } = await props[!query.id ? "hiddenAdd" : "hiddenEdit"]({
...values,
id: query.id,
hiddenId: id,
source: "1",
hiddenJson: {
confirm: 1, // 确认 0否1是
rectify: 1, // 整改 0否1是
check: 1, // 验收 0否1是
special: 1, // 特殊处置 0否1是
extension: 1, // 延期 0否1是
},
hiddenImgAddCmds: hiddenImageFiles.map(item => ({ url: item.url })),
});
if (success) {
message.success("操作成功");
props.history.goBack();
}
};
const getAIHiddenImageRecognize = async () => {
const hiddenImageFiles = form.getFieldValue("hiddenImageFiles");
if (!hiddenImageFiles || hiddenImageFiles.length === 0) {
message.warning("请上传图片");
return;
}
if (hiddenImageFiles.length > 1) {
message.warning("只能上传一张图片");
return;
}
setAIHiddenImageRecognizeLoading(true);
if (!aiHiddenImageRecognizeFilePath.current) {
const { filePath } = await uploadFile({ files: hiddenImageFiles, params: { type: UPLOAD_FILE_TYPE_ENUM["3"] } });
aiHiddenImageRecognizeFilePath.current = filePath;
}
try {
const response = await fetch("http://101.201.170.9:3000/ai-manager/ai/url/modelResult", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: getFileUrl() + aiHiddenImageRecognizeFilePath.current }),
});
const { data } = await response.json();
form.setFieldValue("isAi", 1);
form.setFieldValue("hiddenDesc", data.description);
form.setFieldValue("legalBasis", data.legalBasis);
form.setFieldValue("rectificationDescr", data.guidance);
aiHiddenImageRecognizeFilePath.current = "";
await deleteFile({ files: [{ filePath: aiHiddenImageRecognizeFilePath.current }] });
}
catch {
message.error("获取图片识别结果失败");
}
finally {
setAIHiddenImageRecognizeLoading(false);
if (isExistNextOneHidden()) {
setCurrentProcessHiddenIndex(currentProcessHiddenIndex + 1);
setIsShowAiButton(false);
const currentValues = form.getFieldsValue();
const hiddenImageFiles = form.getFieldValue("hiddenImageFiles");
const resetValues = {};
Object.keys(currentValues).forEach((key) => {
resetValues[key] = undefined;
});
form.setFieldsValue({
...resetValues,
...defaultValues,
isAi: 1,
hiddenImageFiles,
hiddenDesc: selectHiddens[currentProcessHiddenIndex + 1].hiddenDescr,
legalBasis: selectHiddens[currentProcessHiddenIndex + 1].legalBasis,
rectificationDescr: selectHiddens[currentProcessHiddenIndex + 1].rectificationSuggestions,
});
}
else {
props.history.goBack();
}
}
};
@ -169,42 +254,51 @@ function Add(props) {
<div style={{ paddingBottom: 10 }}>
<FormBuilder
form={form}
loading={deleteFileLoading || uploadFileLoading || getFileLoading || aiHiddenImageRecognizeLoading || props.ledger.ledgerLoading}
values={{
isRelated: 2,
rectificationType: 2,
}}
loading={deleteFileLoading || uploadFileLoading || getFileLoading || props.ledger.ledgerLoading}
values={defaultValues}
onFinish={onSubmit}
submitButtonText={isExistNextOneHidden() ? "提交并下一个" : "提交"}
extraActionButtons={[
(!isShowAiButton && getUnprocessedImagesCount() > 0)
&& (
<Button key="selectOther" onClick={handleSelectOtherImage}>
选择其他图片 (
{getUnprocessedImagesCount()}
)
</Button>
),
]}
options={[
{
name: "hiddenImageFiles",
label: "隐患图片",
render: (
<Upload
maxCount={isAi === 1 ? 1 : 4}
disabled={!isShowAiButton}
listType="picture-card"
onRemove={() => {
if (isAi === 1) {
form.setFieldValue("isAi", "");
form.setFieldValue("hiddenDesc", "");
form.setFieldValue("legalBasis", "");
form.setFieldValue("rectificationDescr", "");
setAiHiddens([]);
clearHiddenRecognizeState();
}
}}
onGetRemoveFile={(file) => {
setDeleteHiddenImageFiles([...deleteHiddenImageFiles, file]);
deleteHiddenImageFiles.current = [...deleteHiddenImageFiles.current, file];
}}
tipContent={(
<>
<img
src={ai_recognize}
alt="ai_recognize"
style={{ width: 150, height: 30, cursor: "pointer", marginBottom: 10 }}
onClick={getAIHiddenImageRecognize}
/>
{
(!query.id && isShowAiButton) && (
<img
src={ai_recognize}
alt="ai_recognize"
style={{ width: 150, height: 30, cursor: "pointer", marginBottom: 10 }}
onClick={handleAiRecognizeClick}
/>
)
}
<div>
最多上传
{isAi === 1 ? 1 : 4}
个文件并且只能上传jpgjpegpng格式的文件
最多上传4个文件并且只能上传jpgjpegpng格式的文件
</div>
</>
)}
@ -213,6 +307,7 @@ function Add(props) {
span: 24,
},
{ name: "isAi", label: "是否AI识别隐患", onlyForLabel: true },
{ name: "aiBatch", label: "AI识别隐患批次号", onlyForLabel: true },
{ name: "hiddenDesc", label: "隐患描述", render: FORM_ITEM_RENDER_ENUM.TEXTAREA, span: 24 },
{
name: "legalBasis",
@ -221,43 +316,7 @@ function Add(props) {
span: 24,
required: false,
hidden: !(isAi === 1),
componentProps: { readOnly: true },
},
{
name: "hiddenPart",
customizeRender: true,
render: (
<Form.Item label="隐患部位" required>
<div style={{ display: "flex", gap: 10 }}>
<Form.Item
name="hiddenPart"
noStyle
rules={[
{ required: true, message: "请选择隐患部位" },
...(hiddenPartType === "input" ? [{ max: 50, message: "最多输入50字符" }] : []),
]}
>
{
hiddenPartType === "select"
? <HiddenPartSelectTree />
: <Input maxLength={50} placeholder="请输入隐患部位" />
}
</Form.Item>
<Button
type="primary"
onClick={() => {
if (hiddenPartType === "select")
setHiddenPartType("input");
if (hiddenPartType === "input")
setHiddenPartType("select");
form.setFieldValue("hiddenPart", "");
}}
>
{hiddenPartType === "select" ? "输入" : "选择"}
</Button>
</div>
</Form.Item>
),
componentProps: { disabled: true },
},
{
name: "hiddenLevel",
@ -293,9 +352,76 @@ function Add(props) {
label: "是否相关方",
render: FORM_ITEM_RENDER_ENUM.RADIO,
items: [{ bianma: 1, name: "是" }, { bianma: 2, name: "否" }],
componentProps: {
onChange: () => {
form.setFieldValue("projectName", "");
form.setFieldValue("rectificationDeptId", "");
form.setFieldValue("rectificationDeptName", "");
form.setFieldValue("rectificationUserId", "");
form.setFieldValue("rectificationUserName", "");
form.setFieldValue("checkDeptId", "");
form.setFieldValue("hiddenYDeptName", "");
form.setFieldValue("checkUserId", "");
form.setFieldValue("hiddenYUserName", "");
},
},
},
{
name: "projectId",
label: "相关方项目",
dependencies: ["isRelated"],
hidden: formValues => !(formValues.isRelated === 1),
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: [{ bianma: 1, name: "相关方未做" }, { bianma: 2, name: "后期补全" }], // TODO
componentProps: {
onChange: (value) => {
form.setFieldValue("projectName", getLabelName({
list: [],
status: value,
}));
},
},
},
{ name: "projectName", label: "相关方项目名称", onlyForLabel: true },
{
name: "hiddenPart",
span: 24,
customizeRender: true,
render: (
<Form.Item label="隐患部位" required labelCol={{ span: 2 }} wrapperCol={{ span: 22 }}>
<div style={{ display: "flex", gap: 10 }}>
<Form.Item
name="hiddenPart"
noStyle
rules={[
{ required: true, message: "请选择隐患部位" },
...(hiddenPartType === "input" ? [{ max: 50, message: "最多输入50字符" }] : []),
]}
>
{
hiddenPartType === "select"
? <HiddenPartSelectTree />
: <Input maxLength={50} placeholder="请输入隐患部位" />
}
</Form.Item>
<Button
type="primary"
onClick={() => {
if (hiddenPartType === "select")
setHiddenPartType("input");
if (hiddenPartType === "input")
setHiddenPartType("select");
form.setFieldValue("hiddenPart", "");
}}
>
{hiddenPartType === "select" ? "输入" : "选择"}
</Button>
</div>
</Form.Item>
),
},
{ name: "map", customizeRender: true, render: <Map required={false} />, span: 24 },
{ name: "positionDesc", label: "隐患位置描述", required: false, span: 24 },
{ name: "map", customizeRender: true, render: <Map required={false} />, span: 24 },
{
name: "hiddenVideoFiles",
label: "隐患视频",
@ -303,7 +429,7 @@ function Add(props) {
<Upload
fileType="video"
onGetRemoveFile={(file) => {
setDeleteHiddenVideoFiles([...deleteHiddenVideoFiles, file]);
deleteHiddenVideoFiles.current = [...deleteHiddenVideoFiles, file];
}}
/>
),
@ -411,7 +537,7 @@ function Add(props) {
label: "整改后图片",
render: (
<Upload onGetRemoveFile={(file) => {
setDeleteAfterRectificationImageFiles([...deleteAfterRectificationImageFiles, file]);
deleteAfterRectificationImageFiles.current = [...deleteAfterRectificationImageFiles.current, file];
}}
/>
),
@ -421,19 +547,24 @@ function Add(props) {
},
{
name: "rectificationDeptId",
label: "整改部门",
label: isRelated === 2 ? "整改部门" : "整改单位",
required: false,
render: (
<DepartmentSelectTree
onChange={() => {
form.setFieldValue("rectificationUserId", "");
form.setFieldValue("rectificationUserName", "");
}}
onGetLabel={(label) => {
form.setFieldValue("rectificationDeptName", label);
}}
/>
isRelated === 2 && (
<DepartmentSelectTree
onChange={() => {
form.setFieldValue("rectificationUserId", "");
form.setFieldValue("rectificationUserName", "");
}}
onGetLabel={(label) => {
form.setFieldValue("rectificationDeptName", label);
}}
/>
)
),
componentProps: {
disabled: isRelated === 1,
},
},
{ name: "rectificationDeptName", label: "整改部门名称", onlyForLabel: true },
{
@ -441,28 +572,38 @@ function Add(props) {
label: "整改人",
required: false,
render: (
<PersonnelSelect
params={{ departmentId: rectificationDeptId }}
onGetLabel={label => form.setFieldValue("rectificationUserName", label)}
/>
isRelated === 2 && (
<PersonnelSelect
params={{ departmentId: rectificationDeptId }}
onGetLabel={label => form.setFieldValue("rectificationUserName", label)}
/>
)
),
componentProps: {
disabled: isRelated === 1,
},
},
{ name: "rectificationUserName", label: "整改人名称", onlyForLabel: true },
{
name: "checkDeptId",
label: "验收部门",
label: isRelated === 2 ? "验收部门" : "验收单位",
required: false,
render: (
<DepartmentSelectTree
onChange={() => {
form.setFieldValue("checkUserId", "");
form.setFieldValue("hiddenYUserName", "");
}}
onGetLabel={(label) => {
form.setFieldValue("hiddenYDeptName", label);
}}
/>
isRelated === 2 && (
<DepartmentSelectTree
onChange={() => {
form.setFieldValue("checkUserId", "");
form.setFieldValue("hiddenYUserName", "");
}}
onGetLabel={(label) => {
form.setFieldValue("hiddenYDeptName", label);
}}
/>
)
),
componentProps: {
disabled: isRelated === 1,
},
dependencies: ["rectificationType"],
hidden: formValues => !(formValues.rectificationType === 1),
},
@ -472,11 +613,16 @@ function Add(props) {
label: "验收人",
required: false,
render: (
<PersonnelSelect
params={{ departmentId: checkDeptId }}
onGetLabel={label => form.setFieldValue("hiddenYUserName", label)}
/>
isRelated === 2 && (
<PersonnelSelect
params={{ departmentId: checkDeptId }}
onGetLabel={label => form.setFieldValue("hiddenYUserName", label)}
/>
)
),
componentProps: {
disabled: isRelated === 1,
},
dependencies: ["rectificationType"],
hidden: formValues => !(formValues.rectificationType === 1),
},
@ -484,8 +630,168 @@ function Add(props) {
]}
/>
</div>
{
aiHiddenModalOpen && (
<AiHiddenModal
aiHiddens={aiHiddens}
onCancel={() => {
setAiHiddenModalOpen(false);
}}
onConfirm={(selectedRows) => {
setSelectHiddens(selectedRows);
setCurrentProcessHiddenIndex(0);
form.setFieldValue("isAi", 1);
form.setFieldValue("hiddenDesc", selectedRows[0].hiddenDescr);
form.setFieldValue("legalBasis", selectedRows[0].legalBasis);
form.setFieldValue("rectificationDescr", selectedRows[0].rectificationSuggestions);
form.setFieldValue("aiBatch", createGuid());
}}
onMergeHidden={onMergeHidden}
/>
)
}
{
imageSelectModalOpen && (
<ImageSelectModal
title={modalTitle}
images={uploadedImages}
onCancel={() => setImageSelectModalOpen(false)}
onConfirm={(selectedImage) => {
getAIHiddenImageRecognize(selectedImage);
}}
/>
)
}
</div>
);
}
const AiHiddenModal = (props) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
return (
<Modal
title="AI识别隐患"
open
onCancel={props.onCancel}
maskClosable={false}
width={1000}
footer={[
<Button
key="merge"
type="primary"
onClick={() => {
if (selectedRowKeys.length < 2) {
message.warning("至少选择两个隐患才能进行合并");
return;
}
Modal.confirm({
title: "合并隐患",
content: "确定要合并所选的隐患吗?",
onOk: () => {
props.onConfirm(selectedRowKeys);
},
});
}}
>
合并隐患
</Button>,
<Button
key="process"
type="primary"
onClick={() => {
if (selectedRows.length === 0) {
message.error("请选择要处理的隐患");
return;
}
props.onConfirm(selectedRows);
props.onCancel();
}}
>
处理隐患
</Button>,
<Button key="cancel" onClick={props.onCancel}>取消</Button>,
]}
>
<Table
rowSelection={{
preserveSelectedRowKeys: true,
selectedRowKeys,
onChange: (selectedRowKeys, selectedRows) => {
setSelectedRowKeys(selectedRowKeys);
setSelectedRows(selectedRows);
},
}}
dataSource={props.aiHiddens}
pagination={false}
options={false}
disabledResizer={true}
columns={[
{ title: "隐患描述", dataIndex: "hiddenDescr" },
{ title: "法律依据", dataIndex: "legalBasis" },
{ title: "整改描述", dataIndex: "rectificationSuggestions" },
]}
/>
</Modal>
);
};
const ImageSelectModal = (props) => {
const [selectedImage, setSelectedImage] = useState(null);
const handleConfirm = () => {
if (!selectedImage) {
message.warning("请选择一张图片进行AI识别");
return;
}
props.onConfirm(selectedImage);
props.onCancel();
};
return (
<Modal
title={props.title || "选择图片进行AI识别"}
open
onCancel={props.onCancel}
maskClosable={false}
width={800}
onOk={handleConfirm}
okText="开始识别"
cancelText="取消"
>
<Row gutter={[16, 16]}>
{props.images.map((image, index) => (
<Col key={index} span={6}>
<div
style={{
border: selectedImage === image ? "2px solid #1890ff" : "1px solid #d9d9d9",
borderRadius: 8,
padding: 8,
cursor: "pointer",
textAlign: "center",
height: 200,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
onClick={() => setSelectedImage(image)}
>
<Image
src={image.url || URL.createObjectURL(image.originFileObj)}
alt={`图片 ${index + 1}`}
style={{
maxWidth: "100%",
maxHeight: "100%",
objectFit: "contain",
}}
preview={false}
/>
</div>
</Col>
))}
</Row>
</Modal>
);
};
export default Connect([NS_LEDGER, NS_CONFIRM_USER, NS_PART], true)(Add);

View File

@ -186,11 +186,12 @@ function List(props) {
{ title: "隐患级别", dataIndex: "hiddenLevelName", width: 100 },
{ title: "隐患类型", dataIndex: "hiddenTypeName" },
{ title: "隐患部位", dataIndex: "hiddenPartName" },
{ title: "隐患发现部门", dataIndex: "hiddenFindDeptName" },
{ title: "隐患发现部门", dataIndex: "hiddenFindDeptName", width: 180 },
{ title: "隐患发现人", dataIndex: "createName", width: 130 },
{
title: "隐患发现时间",
dataIndex: "hiddenFindTime",
width: 180,
render: (_, record) => record.hiddenFindTime ? dayjs(record.hiddenFindTime).format("YYYY-MM-DD hh:mm:ss") : "",
},
{
@ -206,6 +207,15 @@ function List(props) {
{ title: "整改人", dataIndex: "rectificationUserName", width: 100 },
{ title: "整改时间", dataIndex: "rectificationTime" },
{ title: "验收人", dataIndex: "hiddenYUserName", width: 100 },
{
title: "是否相关方",
dataIndex: "isRelated",
width: 150,
render: (_, record) => getLabelName({
list: [{ bianma: 1, name: "是" }, { bianma: 2, name: "否" }],
status: record.isRelated,
}),
},
{
title: "隐患状态",
dataIndex: "state",
@ -213,7 +223,7 @@ function List(props) {
},
{
title: "操作",
width: 150,
width: 220,
fixed: "right",
render: (_, record) => (
<Space>
@ -237,7 +247,15 @@ function List(props) {
</Button>
)
}
<Button type="link" danger onClick={() => onDelete(record.id)}>删除</Button>
{record.state === 100 && <Button type="link" danger onClick={() => onDelete(record.id)}>删除</Button>}
<Button
type="link"
onClick={() => {
props.history.push(`../HiddenView?id=${record.id}&hiddenId=${record.hiddenId}&history=1`);
}}
>
过程记录
</Button>
</Space>
),
},
@ -326,7 +344,7 @@ const PrintModal = (props) => {
contentRef,
pageStyle: `@page {
size: landscape;
margin: 0mm;
margin: 3mm;
}
@media print {
body {
@ -360,13 +378,21 @@ const PrintModal = (props) => {
dataSource={props.data}
pagination={false}
columns={[
{ title: "排查时间", dataIndex: "hiddenFindTime", render: (_, record) => dayjs(record.hiddenFindTime).format("YYYY-MM-DD hh:mm:ss") },
{
title: "排查时间",
dataIndex: "hiddenFindTime",
render: (_, record) => dayjs(record.hiddenFindTime).format("YYYY-MM-DD hh:mm:ss"),
},
{ title: "检查人", dataIndex: "createName" },
{ title: "责任部门", dataIndex: "hiddenFindDeptName" },
{ title: "事故隐患", dataIndex: "hiddenDesc" },
{ title: "隐患等级", dataIndex: "hiddenLevelName" },
{ title: "治理措施", dataIndex: "tempSafeMeasure" },
{ title: "完成时限", dataIndex: "rectificationDeadline" },
{
title: "完成时限",
dataIndex: "rectificationDeadline",
render: (_, record) => record.rectificationDeadline && dayjs(record.rectificationDeadline).format("YYYY-MM-DD hh:mm:ss"),
},
{ title: "整改责任人", dataIndex: "rectificationUserName" },
{
title: "验收人员",
@ -407,7 +433,7 @@ const PrintModal = (props) => {
<td>{item.hiddenDesc}</td>
<td>{item.hiddenLevelName}</td>
<td>{item.RECTIFYDESCR}</td>
<td>{item.RECTIFICATIONDEADLINE}</td>
<td>{dayjs(item.rectificationDeadline).format("YYYY-MM-DD hh:mm:ss")}</td>
<td>{item.rectificationUserName}</td>
<td>{item.state === 301 ? item.hiddenYUserName : ""}</td>
<td>{item.hiddenYTime}</td>

View File

@ -116,7 +116,7 @@ function Part(props) {
)}
columns={[
{
title: "区域/设备名称",
title: "区域名称",
dataIndex: "hiddenregion",
render: (_, record) => (
<Button
@ -215,8 +215,8 @@ const AddModalComponent = (props) => {
showActionButtons={false}
onFinish={onSubmit}
options={[
{ name: "parentName", label: "上级区域/设备名称", required: false, render: <Tag color="blue">{props.parentName || "无"}</Tag> },
{ name: "hiddenregion", label: "区域/设备名称" },
{ name: "parentName", label: "上级区域名称", required: false, render: <Tag color="blue">{props.parentName || "无"}</Tag> },
{ name: "hiddenregion", label: "区域名称" },
{
name: "responsibleDeptId",
label: "负责部门",

View File

@ -10,6 +10,7 @@ import Table from "zy-react-library/components/Table";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import useIsExistenceDuplicateSelection from "zy-react-library/hooks/useIsExistenceDuplicateSelection";
import useTable from "zy-react-library/hooks/useTable";
import { getLabelName } from "zy-react-library/utils";
import { NS_EVALUATION_TEAM_CONFIG } from "~/enumerate/namespace";
const STATE_ENUM = [
@ -325,7 +326,12 @@ const AddModalComponent = (props) => {
itemsField: { valueKey: "id", labelKey: "corpName" },
componentProps: {
onChange: (value) => {
form.setFieldValue("corpinfoName", corpInfoList.find(item => item.id === value)?.corpName);
form.setFieldValue("corpinfoName", getLabelName({
list: corpInfoList,
status: value,
idKey: "id",
nameKey: "corpName",
}));
},
},
},