Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # jjb.config.jsdev_1.2
commit
19bd1f998a
|
|
@ -4,7 +4,7 @@ import { PlusOutlined } from "@ant-design/icons";
|
||||||
const isImage = (url) =>
|
const isImage = (url) =>
|
||||||
/\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i.test(url || "");
|
/\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i.test(url || "");
|
||||||
|
|
||||||
export default function AttachmentUpload({ name, label, disabled = false, maxCount, accept, extra ,rules }) {
|
export default function AttachmentUpload({ name, label, disabled = false, maxCount, accept, extra ,rules, style }) {
|
||||||
const [previewImage, setPreviewImage] = useState("");
|
const [previewImage, setPreviewImage] = useState("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -13,6 +13,7 @@ export default function AttachmentUpload({ name, label, disabled = false, maxCou
|
||||||
name={name}
|
name={name}
|
||||||
label={label}
|
label={label}
|
||||||
extra={extra}
|
extra={extra}
|
||||||
|
style={style}
|
||||||
valuePropName="fileList"
|
valuePropName="fileList"
|
||||||
rules={rules}
|
rules={rules}
|
||||||
getValueProps={(value) => {
|
getValueProps={(value) => {
|
||||||
|
|
@ -90,7 +91,7 @@ export default function AttachmentUpload({ name, label, disabled = false, maxCou
|
||||||
</button>
|
</button>
|
||||||
</Upload>
|
</Upload>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Image
|
{previewImage && <Image
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
preview={{
|
preview={{
|
||||||
visible: !!previewImage,
|
visible: !!previewImage,
|
||||||
|
|
@ -99,7 +100,7 @@ export default function AttachmentUpload({ name, label, disabled = false, maxCou
|
||||||
if (!visible) setPreviewImage("");
|
if (!visible) setPreviewImage("");
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,22 @@ function saveState(tabs, activeKey) {
|
||||||
export default function SimulatedLayout({ children, history }) {
|
export default function SimulatedLayout({ children, history }) {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
const [state, setState] = useState(loadState);
|
const [state, setState] = useState(loadState);
|
||||||
const currentPath = window.location.pathname;
|
const [currentPath, setCurrentPath] = useState(window.location.pathname);
|
||||||
|
|
||||||
// 页面加载时自动将当前路径加入标签
|
// 监听路由变化,更新 currentPath
|
||||||
|
useEffect(() => {
|
||||||
|
const unlisten = history?.listen?.((location) => {
|
||||||
|
setCurrentPath(location.pathname || window.location.pathname);
|
||||||
|
});
|
||||||
|
return () => unlisten?.();
|
||||||
|
}, [history]);
|
||||||
|
|
||||||
|
// 路由变化时自动将当前路径加入标签
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentPath && !currentPath.endsWith("/container/")) {
|
if (currentPath && !currentPath.endsWith("/container/")) {
|
||||||
addTab(currentPath);
|
addTab(currentPath);
|
||||||
}
|
}
|
||||||
}, []); // 仅挂载时执行一次
|
}, [currentPath]);
|
||||||
|
|
||||||
/* ---- 标签操作 ---- */
|
/* ---- 标签操作 ---- */
|
||||||
const addTab = useCallback((path) => {
|
const addTab = useCallback((path) => {
|
||||||
|
|
@ -73,9 +81,11 @@ export default function SimulatedLayout({ children, history }) {
|
||||||
|
|
||||||
const navigateTo = useCallback((path) => {
|
const navigateTo = useCallback((path) => {
|
||||||
if (path !== currentPath) {
|
if (path !== currentPath) {
|
||||||
window.location.href = path;
|
history.replace(path.replace(/^\/safetyEval/, ""));
|
||||||
|
// history.listen 可能不存在,手动同步 currentPath
|
||||||
|
setCurrentPath(window.location.pathname);
|
||||||
}
|
}
|
||||||
}, [currentPath]);
|
}, [currentPath, history]);
|
||||||
|
|
||||||
const handleCloseTab = useCallback((targetKey) => {
|
const handleCloseTab = useCallback((targetKey) => {
|
||||||
setState((prev) => {
|
setState((prev) => {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Flex,
|
Flex,
|
||||||
Tag,
|
Tag,
|
||||||
|
Radio,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
|
@ -103,7 +104,7 @@ const EvalProjectCreate = (props) => {
|
||||||
name: item.userName,
|
name: item.userName,
|
||||||
deptName: item.deptName,
|
deptName: item.deptName,
|
||||||
posName: item.postName,
|
posName: item.postName,
|
||||||
capacity: '龟派气功波',
|
capacity: '',
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
if (isView) {
|
if (isView) {
|
||||||
|
|
@ -298,12 +299,13 @@ const EvalProjectCreate = (props) => {
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row gutter={24}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="industryCode"
|
name="industryCode"
|
||||||
label="所属行业"
|
label="所属行业"
|
||||||
rules={[{ required: true, message: "请选择所属行业" }]}
|
rules={[{ required: true, message: "请选择所属行业" }]}
|
||||||
|
|
||||||
>
|
>
|
||||||
<Select placeholder="请选择" allowClear>
|
<Select placeholder="请选择" allowClear>
|
||||||
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
||||||
|
|
@ -314,6 +316,18 @@ const EvalProjectCreate = (props) => {
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="is_statutory"
|
||||||
|
label="是否法定项目"
|
||||||
|
rules={[{ required: true, message: "请选择是否法定项目" }]}
|
||||||
|
>
|
||||||
|
<Radio.Group>
|
||||||
|
<Radio value={true}>是</Radio>
|
||||||
|
<Radio value={false}>否</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
|
||||||
import AttachmentUpload from "~/components/AttachmentUpload";
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
|
import PreviewUrlButton from "~/components/PreviewUrlButton";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
|
|
@ -265,13 +266,7 @@ const ProjectDocLibrary = (props) => {
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Button
|
<PreviewUrlButton url={record.project_doc_url} />
|
||||||
type="link"
|
|
||||||
size="small"
|
|
||||||
onClick={() => window.open(record.project_doc_url)}
|
|
||||||
>
|
|
||||||
预览
|
|
||||||
</Button>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|
|
||||||
|
|
@ -501,10 +501,12 @@ const ContractContent = (props) => {
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item label="职工人数" name="staffCount">
|
<Form.Item label="职工人数" name="staffCount">
|
||||||
<Input
|
<InputNumber
|
||||||
|
style={{ width: "100%" }}
|
||||||
placeholder="请输入职工人数"
|
placeholder="请输入职工人数"
|
||||||
maxLength={10}
|
min={0}
|
||||||
allowClear
|
precision={0}
|
||||||
|
max={99999}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const ControlContent = (props) => {
|
||||||
|
|
||||||
// 过程控制审核
|
// 过程控制审核
|
||||||
const [rows, setRows] = useState([]);
|
const [rows, setRows] = useState([]);
|
||||||
const [opinionContent, setOpinionContent] = useState("");
|
|
||||||
|
|
||||||
// 项目归档
|
// 项目归档
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
|
|
@ -34,7 +34,7 @@ const ControlContent = (props) => {
|
||||||
const fetchDetail = () => {
|
const fetchDetail = () => {
|
||||||
props.evalProcessControlDetail({ projectId }).then((res) => {
|
props.evalProcessControlDetail({ projectId }).then((res) => {
|
||||||
if (res?.success) {
|
if (res?.success) {
|
||||||
setOpinionContent(res?.data?.opinionContent);
|
|
||||||
if (res?.data?.signTaskPersonCo) {
|
if (res?.data?.signTaskPersonCo) {
|
||||||
setSelectPeople({
|
setSelectPeople({
|
||||||
value: res?.data?.signTaskPersonCo?.signerPersonnelId,
|
value: res?.data?.signTaskPersonCo?.signerPersonnelId,
|
||||||
|
|
@ -65,8 +65,10 @@ const ControlContent = (props) => {
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processControl?.opinionContent) {
|
if (processControl?.opinionContent) {
|
||||||
setOpinionContent(processControl.opinionContent);
|
setApprovalOpinion(processControl.opinionContent);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [processControlDetail]);
|
}, [processControlDetail]);
|
||||||
|
|
||||||
|
|
@ -93,11 +95,15 @@ const ControlContent = (props) => {
|
||||||
// 过程控制签字提交(confirm)
|
// 过程控制签字提交(confirm)
|
||||||
const handleConfirm = async (resultCode) => {
|
const handleConfirm = async (resultCode) => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
if(!rows.every((r) => r.reviewConclusion)){
|
||||||
|
message.error("请填写所有核查项的结果");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const payload = {
|
const payload = {
|
||||||
id: processControl?.id,
|
id: processControl?.id,
|
||||||
projectId,
|
projectId,
|
||||||
resultCode,
|
resultCode,
|
||||||
opinionContent,
|
opinionContent: approvalOpinion,
|
||||||
reviewItems: rows.map((r) => ({
|
reviewItems: rows.map((r) => ({
|
||||||
bizType: "eval_process_control",
|
bizType: "eval_process_control",
|
||||||
bizId: processControl?.id,
|
bizId: processControl?.id,
|
||||||
|
|
@ -151,12 +157,14 @@ const ControlContent = (props) => {
|
||||||
{
|
{
|
||||||
title: "结果",
|
title: "结果",
|
||||||
dataIndex: "reviewConclusion",
|
dataIndex: "reviewConclusion",
|
||||||
width: 120,
|
width: 150,
|
||||||
render: (val, _, idx) => (
|
render: (val, _, idx) => (
|
||||||
<Select
|
<Select
|
||||||
value={val}
|
value={val}
|
||||||
size="small"
|
size="small"
|
||||||
style={{ width: 100 }}
|
style={{ width: 130 }}
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择结果"
|
||||||
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
||||||
>
|
>
|
||||||
<Select.Option value="conform_to">符合</Select.Option>
|
<Select.Option value="conform_to">符合</Select.Option>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ const InternalReviewContent = (props) => {
|
||||||
setRows(next);
|
setRows(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const isDispatched =
|
const isDispatched =
|
||||||
internalReview?.reviewerSignatureTaskStatus === "dispatched";
|
internalReview?.reviewerSignatureTaskStatus === "dispatched";
|
||||||
const problemCount = rows.filter(
|
const problemCount = rows.filter(
|
||||||
|
|
@ -80,17 +79,29 @@ const InternalReviewContent = (props) => {
|
||||||
|
|
||||||
const handleAssign = async () => {
|
const handleAssign = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
const res = await props.evalInternalReviewAssign({ projectId, signTaskPersonCmd:{
|
const result= await handleConfirm("not_passed");
|
||||||
|
if(!result) return;
|
||||||
|
const res = await props.evalInternalReviewAssign({
|
||||||
|
projectId,
|
||||||
|
signTaskPersonCmd: {
|
||||||
signerPersonnelId: selectedReviewer,
|
signerPersonnelId: selectedReviewer,
|
||||||
signerName: reviewers.find((item) => item.personnelId === selectedReviewer)?.personnelName ,
|
signerName: reviewers.find(
|
||||||
} });
|
(item) => item.personnelId === selectedReviewer,
|
||||||
|
)?.personnelName,
|
||||||
|
},
|
||||||
|
});
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success("已下发签字任务");
|
message.success("已下发签字任务");
|
||||||
fetchDetail();
|
fetchDetail()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirm = async (resultCode) => {
|
const handleConfirm = async (resultCode) => {
|
||||||
|
if(!rows.every((r) => r.reviewConclusion)){
|
||||||
|
message.error("请填写审核结论");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
const payload = {
|
const payload = {
|
||||||
id: internalReview?.id,
|
id: internalReview?.id,
|
||||||
|
|
@ -109,12 +120,16 @@ const InternalReviewContent = (props) => {
|
||||||
};
|
};
|
||||||
const res = await props.evalInternalReviewConfirm(payload);
|
const res = await props.evalInternalReviewConfirm(payload);
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success(
|
message.success(resultCode === "passed" ? "已提交" : "已保存");
|
||||||
resultCode === "passed" ? "已提交" : "已保存",
|
resolve(res);
|
||||||
);
|
if (resultCode === "passed") {
|
||||||
fetchDetail();
|
|
||||||
props.getDetail?.();
|
props.getDetail?.();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -128,7 +143,9 @@ const InternalReviewContent = (props) => {
|
||||||
<Select
|
<Select
|
||||||
value={val}
|
value={val}
|
||||||
size="small"
|
size="small"
|
||||||
style={{ width: 100 }}
|
style={{ width: 130 }}
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择结论"
|
||||||
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
||||||
>
|
>
|
||||||
{CONCLUSION_OPTIONS.map((opt) => (
|
{CONCLUSION_OPTIONS.map((opt) => (
|
||||||
|
|
@ -169,9 +186,20 @@ const InternalReviewContent = (props) => {
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Card size="small">
|
<Card size="small">
|
||||||
<Typography.Text type="secondary">内审人</Typography.Text>
|
<Typography.Text type="secondary">内审人</Typography.Text>
|
||||||
<div style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
<div
|
||||||
<Tooltip title={(reviewers || []).map((r) => r.personnelName).join("、")}>
|
style={{
|
||||||
<strong>{(reviewers || []).map((r) => r.personnelName).join("、") || "-"}</strong>
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
title={(reviewers || []).map((r) => r.personnelName).join("、")}
|
||||||
|
>
|
||||||
|
<strong>
|
||||||
|
{(reviewers || []).map((r) => r.personnelName).join("、") ||
|
||||||
|
"-"}
|
||||||
|
</strong>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -213,6 +241,9 @@ const InternalReviewContent = (props) => {
|
||||||
<TextArea
|
<TextArea
|
||||||
rows={2}
|
rows={2}
|
||||||
value={overallOpinion}
|
value={overallOpinion}
|
||||||
|
allowClear
|
||||||
|
placeholder="请输入总体审核意见"
|
||||||
|
maxLength={120}
|
||||||
onChange={(e) => setOverallOpinion(e.target.value)}
|
onChange={(e) => setOverallOpinion(e.target.value)}
|
||||||
style={{ marginTop: 4 }}
|
style={{ marginTop: 4 }}
|
||||||
/>
|
/>
|
||||||
|
|
@ -237,7 +268,6 @@ const InternalReviewContent = (props) => {
|
||||||
onClick={handleAssign}
|
onClick={handleAssign}
|
||||||
loading={internalReviewAssignLoading}
|
loading={internalReviewAssignLoading}
|
||||||
disabled={isDispatched || !selectedReviewer}
|
disabled={isDispatched || !selectedReviewer}
|
||||||
|
|
||||||
>
|
>
|
||||||
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
@ -64,6 +65,7 @@ const RiskAnalysisContent = (props) => {
|
||||||
if (res?.success !== false && res?.data) {
|
if (res?.success !== false && res?.data) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...res.data,
|
...res.data,
|
||||||
|
riskFileUrl: res.data.riskFileUrl? JSON.parse(res.data.riskFileUrl) :undefined,
|
||||||
analysisDate: res.data.analysisDate
|
analysisDate: res.data.analysisDate
|
||||||
? dayjs(res.data.analysisDate)
|
? dayjs(res.data.analysisDate)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
@ -96,6 +98,7 @@ const RiskAnalysisContent = (props) => {
|
||||||
...rest,
|
...rest,
|
||||||
projectId,
|
projectId,
|
||||||
statusCode,
|
statusCode,
|
||||||
|
riskFileUrl: rest.riskFileUrl? JSON.stringify(rest.riskFileUrl) :undefined,
|
||||||
analysisDate: analysisDate
|
analysisDate: analysisDate
|
||||||
? analysisDate.format("YYYY-MM-DD")
|
? analysisDate.format("YYYY-MM-DD")
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
@ -325,7 +328,7 @@ const RiskAnalysisContent = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card type="inner" size="small" title="参与风险分析人员签字">
|
<Card type="inner" size="small" title="参与风险分析人员签字" className="pf-section">
|
||||||
<Form.List name="participants">
|
<Form.List name="participants">
|
||||||
{(fields, { add, remove }) => {
|
{(fields, { add, remove }) => {
|
||||||
addParticipantRef.current = add;
|
addParticipantRef.current = add;
|
||||||
|
|
@ -463,55 +466,14 @@ const RiskAnalysisContent = (props) => {
|
||||||
</Form.List>
|
</Form.List>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Modal
|
<AttachmentUpload
|
||||||
title="选择参与人员"
|
name="riskFileUrl"
|
||||||
open={participantModalOpen}
|
style={{ marginBottom: 0 }}
|
||||||
onCancel={() => setParticipantModalOpen(false)}
|
label="风险分析表附件"
|
||||||
onOk={() => {
|
accept=".pdf,.docx,.jpg,.png"
|
||||||
const selected = (
|
maxCount={10}
|
||||||
evalProjectDetailData?.participants || []
|
extra="支持 PDF、Word、JPG、PNG 格式。上传后可替换修改,系统保留当前归档文件信息"
|
||||||
).filter((p) => selectedParticipantIds.includes(p.id));
|
|
||||||
selected.forEach((p) => {
|
|
||||||
addParticipantRef.current?.({
|
|
||||||
personnelId: p.id,
|
|
||||||
personnelName: p.name,
|
|
||||||
deptName: p.deptName,
|
|
||||||
opinion: "",
|
|
||||||
projectId,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
setParticipantModalOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Table
|
|
||||||
dataSource={(() => {
|
|
||||||
const existing = (
|
|
||||||
form.getFieldValue("participants") || []
|
|
||||||
).map((p) => p.personnelName);
|
|
||||||
return (evalProjectDetailData?.participants || []).filter(
|
|
||||||
(p) => !existing.includes(p.name),
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
rowKey="id"
|
|
||||||
rowSelection={{
|
|
||||||
type: "checkbox",
|
|
||||||
selectedRowKeys: selectedParticipantIds,
|
|
||||||
onChange: (keys) => setSelectedParticipantIds(keys),
|
|
||||||
getCheckboxProps: (record) => ({
|
|
||||||
disabled: false,
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
columns={[
|
|
||||||
{ title: "姓名", dataIndex: "name", width: 100 },
|
|
||||||
{ title: "部门", dataIndex: "deptName", width: 120 },
|
|
||||||
{ title: "岗位", dataIndex: "posName", width: 120 },
|
|
||||||
{ title: "能力", dataIndex: "capacity", width: 120 },
|
|
||||||
]}
|
|
||||||
pagination={false}
|
|
||||||
size="small"
|
|
||||||
locale={{ emptyText: "所有人员均已添加" }}
|
|
||||||
/>
|
/>
|
||||||
</Modal>
|
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
@ -558,6 +520,56 @@ const RiskAnalysisContent = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="选择参与人员"
|
||||||
|
open={participantModalOpen}
|
||||||
|
onCancel={() => setParticipantModalOpen(false)}
|
||||||
|
onOk={() => {
|
||||||
|
const selected = (evalProjectDetailData?.participants || []).filter(
|
||||||
|
(p) => selectedParticipantIds.includes(p.id),
|
||||||
|
);
|
||||||
|
selected.forEach((p) => {
|
||||||
|
addParticipantRef.current?.({
|
||||||
|
personnelId: p.id,
|
||||||
|
personnelName: p.name,
|
||||||
|
deptName: p.deptName,
|
||||||
|
opinion: "",
|
||||||
|
projectId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setParticipantModalOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
dataSource={(() => {
|
||||||
|
const existing = (form.getFieldValue("participants") || []).map(
|
||||||
|
(p) => p.personnelName,
|
||||||
|
);
|
||||||
|
return (evalProjectDetailData?.participants || []).filter(
|
||||||
|
(p) => !existing.includes(p.name),
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
rowKey="id"
|
||||||
|
rowSelection={{
|
||||||
|
type: "checkbox",
|
||||||
|
selectedRowKeys: selectedParticipantIds,
|
||||||
|
onChange: (keys) => setSelectedParticipantIds(keys),
|
||||||
|
getCheckboxProps: (record) => ({
|
||||||
|
disabled: false,
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
columns={[
|
||||||
|
{ title: "姓名", dataIndex: "name", width: 100 },
|
||||||
|
{ title: "部门", dataIndex: "deptName", width: 120 },
|
||||||
|
{ title: "岗位", dataIndex: "posName", width: 120 },
|
||||||
|
{ title: "能力", dataIndex: "capacity", width: 120 },
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
size="small"
|
||||||
|
locale={{ emptyText: "所有人员均已添加" }}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<Flex justify="flex-end" gap={8}>
|
<Flex justify="flex-end" gap={8}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleSave(1)}
|
onClick={() => handleSave(1)}
|
||||||
|
|
@ -565,7 +577,7 @@ const RiskAnalysisContent = (props) => {
|
||||||
>
|
>
|
||||||
暂存
|
暂存
|
||||||
</Button>
|
</Button>
|
||||||
<Button>打印记录表</Button>
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => handleSave(2)}
|
onClick={() => handleSave(2)}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,13 @@ const NoticePanel = () => (
|
||||||
下载模板
|
下载模板
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="PRACTICE_NOTIFICATION"
|
||||||
|
label="从业告知书"
|
||||||
|
maxCount={1}
|
||||||
|
accept=".docx"
|
||||||
|
extra="仅支持上传 Word 格式文件"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -111,19 +118,72 @@ const InspectionPanel = ({ dataSource = [], evalProjectDetailData = {} }) => {
|
||||||
<span>签到日期:{dataSource?.[0]?.singInTime ? dayjs(dataSource?.[0]?.singInTime).format('YYYY-MM-DD') : '-'}</span>
|
<span>签到日期:{dataSource?.[0]?.singInTime ? dayjs(dataSource?.[0]?.singInTime).format('YYYY-MM-DD') : '-'}</span>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="SITE_INSPECTION_FORM"
|
||||||
|
label="现场检查表"
|
||||||
|
maxCount={10}
|
||||||
|
accept=".pdf,.doc,.docx,.xls,.xlsx"
|
||||||
|
extra="检查表应包含项目名称、检查日期、检查人员、检查依据、逐项检查结果和不符合项记录;上传后与人员打卡记录共同作为现场踏勘凭证。
|
||||||
|
支持Excel、Word、PDF和清晰扫描件"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SimpleUploadPanel = ({ index, title, desc }) => (
|
const RectificationNoticePanel = () => (
|
||||||
<div>
|
<div>
|
||||||
<div className="pf-section-header">
|
<div className="pf-section-header">
|
||||||
<div>
|
<div>
|
||||||
<span style={{ fontSize: 20, fontWeight: 600, color: "#1677ff", marginRight: 8 }}>{index}</span>
|
<span style={{ fontSize: 20, fontWeight: 600, color: "#1677ff", marginRight: 8 }}>03</span>
|
||||||
<Typography.Text strong style={{ fontSize: 15 }}>{title}</Typography.Text>
|
<Typography.Text strong style={{ fontSize: 15 }}>整改通知单上传</Typography.Text>
|
||||||
<Typography.Paragraph type="secondary" style={{ margin: 0 }}>{desc}</Typography.Paragraph>
|
<Typography.Paragraph type="secondary" style={{ margin: 0 }}>本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。</Typography.Paragraph>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="RECTIFICATION_NOTICE"
|
||||||
|
label="整改通知单"
|
||||||
|
maxCount={10}
|
||||||
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xls,.xlsx"
|
||||||
|
extra="支持 PDF、Word、JPG、PNG、Excel 格式,最多上传 10 个文件"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const EnterpriseRectificationPanel = () => (
|
||||||
|
<div>
|
||||||
|
<div className="pf-section-header">
|
||||||
|
<div>
|
||||||
|
<span style={{ fontSize: 20, fontWeight: 600, color: "#1677ff", marginRight: 8 }}>04</span>
|
||||||
|
<Typography.Text strong style={{ fontSize: 15 }}>企业整改报告上传</Typography.Text>
|
||||||
|
<Typography.Paragraph type="secondary" style={{ margin: 0 }}>企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。</Typography.Paragraph>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="ENTERPRISE_RECTIFICATION"
|
||||||
|
label="企业整改报告"
|
||||||
|
maxCount={10}
|
||||||
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.zip,.rar,.7z"
|
||||||
|
extra="支持 PDF、Word、压缩包、图片格式,最多上传 10 个文件"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const RectificationReviewPanel = () => (
|
||||||
|
<div>
|
||||||
|
<div className="pf-section-header">
|
||||||
|
<div>
|
||||||
|
<span style={{ fontSize: 20, fontWeight: 600, color: "#1677ff", marginRight: 8 }}>05</span>
|
||||||
|
<Typography.Text strong style={{ fontSize: 15 }}>整改复查单上传</Typography.Text>
|
||||||
|
<Typography.Paragraph type="secondary" style={{ margin: 0 }}>机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。</Typography.Paragraph>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AttachmentUpload
|
||||||
|
name="RECTIFICATION_REVIEW"
|
||||||
|
label="整改情况复查单"
|
||||||
|
maxCount={10}
|
||||||
|
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xls,.xlsx"
|
||||||
|
extra="支持 PDF、Word、JPG、PNG、Excel 格式,最多上传 10 个文件"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -217,39 +277,22 @@ const SurveyContent = (props) => {
|
||||||
items={STAGES.map((s) => ({ title: s.label }))}
|
items={STAGES.map((s) => ({ title: s.label }))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{activeStage === "PRACTICE_NOTIFICATION" && <NoticePanel />}
|
|
||||||
{activeStage === "SITE_INSPECTION_FORM" && <InspectionPanel dataSource={surveyPersonnel} evalProjectDetailData={evalProjectDetailData} />}
|
|
||||||
{activeStage === "RECTIFICATION_NOTICE" && (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="03" title="整改通知单上传"
|
|
||||||
desc="本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{activeStage === "ENTERPRISE_RECTIFICATION" && (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="04" title="企业整改报告上传"
|
|
||||||
desc="企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{activeStage === "RECTIFICATION_REVIEW" && (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="05" title="整改复查单上传"
|
|
||||||
desc="机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Form form={form} layout="vertical">
|
<Form form={form} layout="vertical">
|
||||||
{STAGES.map((s) => (
|
<div style={{ display: activeStage === "PRACTICE_NOTIFICATION" ? "block" : "none" }}>
|
||||||
<div key={s.key} style={{ display: s.key === activeStage ? "block" : "none" }}>
|
<NoticePanel />
|
||||||
<AttachmentUpload
|
</div>
|
||||||
name={s.key}
|
<div style={{ display: activeStage === "SITE_INSPECTION_FORM" ? "block" : "none" }}>
|
||||||
label="上传附件"
|
<InspectionPanel dataSource={surveyPersonnel} evalProjectDetailData={evalProjectDetailData} />
|
||||||
maxCount={10}
|
</div>
|
||||||
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xls,.xlsx"
|
<div style={{ display: activeStage === "RECTIFICATION_NOTICE" ? "block" : "none" }}>
|
||||||
extra="支持 PDF、Word、JPG、PNG、Excel 格式,最多上传 10 个文件"
|
<RectificationNoticePanel />
|
||||||
/>
|
</div>
|
||||||
|
<div style={{ display: activeStage === "ENTERPRISE_RECTIFICATION" ? "block" : "none" }}>
|
||||||
|
<EnterpriseRectificationPanel />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: activeStage === "RECTIFICATION_REVIEW" ? "block" : "none" }}>
|
||||||
|
<RectificationReviewPanel />
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<Flex justify="flex-end" gap={8} style={{ marginTop: 16 }}>
|
<Flex justify="flex-end" gap={8} style={{ marginTop: 16 }}>
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,8 @@ const TechnicalReviewContent = (props) => {
|
||||||
|
|
||||||
const handleAssign = async () => {
|
const handleAssign = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
const result= await handleConfirm("not_passed");
|
||||||
|
if(!result) return;
|
||||||
const res = await props.evalTechReviewAssign({
|
const res = await props.evalTechReviewAssign({
|
||||||
projectId,
|
projectId,
|
||||||
signTaskPersonCmd: {
|
signTaskPersonCmd: {
|
||||||
|
|
@ -87,12 +89,17 @@ const TechnicalReviewContent = (props) => {
|
||||||
});
|
});
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success("已下发签字任务");
|
message.success("已下发签字任务");
|
||||||
fetchDetail();
|
fetchDetail()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirm = async (resultCode) => {
|
const handleConfirm = async (resultCode) => {
|
||||||
|
if (!rows.every((r) => r.reviewConclusion)) {
|
||||||
|
message.error("请填写审核结论");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
id: techReview?.id,
|
id: techReview?.id,
|
||||||
projectId,
|
projectId,
|
||||||
|
|
@ -110,12 +117,17 @@ const TechnicalReviewContent = (props) => {
|
||||||
};
|
};
|
||||||
const res = await props.evalTechReviewConfirm(payload);
|
const res = await props.evalTechReviewConfirm(payload);
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
|
resolve(res);
|
||||||
message.success(
|
message.success(
|
||||||
resultCode === "1" ? "已确认技审并提交过程控制" : "已保存",
|
resultCode === "passed" ? "已确认技审并提交过程控制" : "已保存",
|
||||||
);
|
);
|
||||||
fetchDetail();
|
if (resultCode === "passed") {
|
||||||
props.getDetail?.();
|
props.getDetail?.();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -129,7 +141,9 @@ const TechnicalReviewContent = (props) => {
|
||||||
<Select
|
<Select
|
||||||
value={val}
|
value={val}
|
||||||
size="small"
|
size="small"
|
||||||
style={{ width: 100 }}
|
style={{ width: 130 }}
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择结论"
|
||||||
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
||||||
>
|
>
|
||||||
{CONCLUSION_OPTIONS.map((opt) => (
|
{CONCLUSION_OPTIONS.map((opt) => (
|
||||||
|
|
@ -228,6 +242,9 @@ const TechnicalReviewContent = (props) => {
|
||||||
<TextArea
|
<TextArea
|
||||||
rows={2}
|
rows={2}
|
||||||
value={overallOpinion}
|
value={overallOpinion}
|
||||||
|
allowClear
|
||||||
|
placeholder="请输入技术审核意见"
|
||||||
|
maxLength={120}
|
||||||
onChange={(e) => setOverallOpinion(e.target.value)}
|
onChange={(e) => setOverallOpinion(e.target.value)}
|
||||||
style={{ marginTop: 4 }}
|
style={{ marginTop: 4 }}
|
||||||
/>
|
/>
|
||||||
|
|
@ -259,10 +276,15 @@ const TechnicalReviewContent = (props) => {
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex justify="flex-end" gap={8} style={{ marginTop: 16 }}>
|
<Flex justify="flex-end" gap={8} style={{ marginTop: 16 }}>
|
||||||
<Button onClick={() => handleConfirm("2")}>保存意见</Button>
|
<Button
|
||||||
|
loading={props.safetyEvalBusiness?.techReviewConfirmLoading}
|
||||||
|
onClick={() => handleConfirm("not_passed")}
|
||||||
|
>
|
||||||
|
保存意见
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => handleConfirm("1")}
|
onClick={() => handleConfirm("passed")}
|
||||||
loading={props.safetyEvalBusiness?.techReviewConfirmLoading}
|
loading={props.safetyEvalBusiness?.techReviewConfirmLoading}
|
||||||
>
|
>
|
||||||
确认技审并提交过程控制
|
确认技审并提交过程控制
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export default class Container extends React.Component {
|
||||||
function AppMiddle(props) {
|
function AppMiddle(props) {
|
||||||
|
|
||||||
const content = process.env.NODE_ENV === "development" && !window.__POWERED_BY_QIANKUN__ && props.location.pathname !== "/container/Driver"
|
const content = process.env.NODE_ENV === "development" && !window.__POWERED_BY_QIANKUN__ && props.location.pathname !== "/container/Driver"
|
||||||
? <SimulatedLayout>{props.children}</SimulatedLayout>
|
? <SimulatedLayout history={props.history}>{props.children}</SimulatedLayout>
|
||||||
: props.children;
|
: props.children;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue