safety-eval-service-frontend/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ControlContent.js

381 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

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

import React, { useState, useEffect } from "react";
import {
Button,
Card,
Table,
Select,
Input,
Flex,
Typography,
message,
Collapse,
} from "antd";
import { CheckCircleFilled } from "@ant-design/icons";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
import { tools } from "@cqsjjb/jjb-common-lib";
const { TextArea } = Input;
const { router } = tools;
const ControlContent = ({ readOnly, ...props }) => {
const projectId = router.query?.id;
const { processControlDetail } = props.safetyEvalBusiness || {};
const { processControl, controllers, reviewItems, orgHeads } =
processControlDetail || {};
const [selectPeople, setSelectPeople] = useState(null);
// 当前步骤1-过程控制审核 2-机构负责人签发
const [step, setStep] = useState(1);
// 过程控制审核
const [rows, setRows] = useState([]);
// 机构负责人签发
const [approvalOpinion, setApprovalOpinion] = useState("");
const fetchDetail = () => {
props.evalProcessControlDetail({ projectId }).then((res) => {
if (res?.success) {
if (res?.data?.signTaskPersonCo) {
setSelectPeople({
value: res?.data?.signTaskPersonCo?.signerPersonnelId,
label: res?.data?.signTaskPersonCo?.signerName,
});
}
}
});
};
useEffect(() => {
if (projectId) {
fetchDetail();
}
}, [projectId]);
useEffect(() => {
if (reviewItems) {
setRows(
reviewItems.map((item) => ({
...item,
reviewConclusion: item.reviewConclusion || "conform_to",
_key: item.id || item.reviewDimensionCode,
})),
);
}
if (processControl?.opinionContent) {
setApprovalOpinion(processControl.opinionContent);
}
}, [processControlDetail]);
const updateRow = (index, field, value) => {
const next = [...rows];
next[index] = { ...next[index], [field]: value };
setRows(next);
};
const isDispatched = processControl?.reviewerSignatureTaskStatus !== "completed";
const isOrgHeadSignature = processControl?.orgHeadSignatureTaskStatus !== "non_dispatched";
// 过程控制签字提交confirm
const handleConfirm = async (resultCode) => {
if (!projectId) return;
if (!rows.every((r) => r.reviewConclusion)) {
message.error("请填写所有核查项的结果");
return;
}
const payload = {
id: processControl?.id,
projectId,
resultCode,
opinionContent: approvalOpinion,
signTaskPersonCmd: {
signerPersonnelId: controllers?.[0]?.personnelId,
signerName: controllers?.[0]?.personnelName,
},
reviewItems: rows.map((r) => ({
bizType: "eval_process_control",
bizId: processControl?.id,
reviewDimensionCode: r.reviewDimensionCode,
reviewDimensionName: r.reviewDimensionName,
reviewFocus: r.reviewFocus,
reviewConclusion: r.reviewConclusion,
reviewOpinion: r.reviewOpinion,
})),
};
const res = await props.evalProcessControlConfirm(payload);
if (res?.success !== false) {
message.success(
resultCode === "passed" ? "已提交通过审核" : "已提交退回修改",
);
fetchDetail();
}
};
// 下发签字任务assign
const handleAssign = async () => {
if (!projectId) return;
const res = await props.evalProcessControlAssign({
projectId,
signTaskPersonCmd: {
signerPersonnelId: selectPeople?.value,
signerName: selectPeople?.label,
},
opinionContent: approvalOpinion,
});
if (res?.success !== false) {
message.success("已下发签字任务");
fetchDetail();
}
};
const reviewColumns = [
{ title: "程序审核项", dataIndex: "reviewDimensionName", width: 120 },
{ title: "核查内容", dataIndex: "reviewFocus", width: 200 },
{
title: "结果",
dataIndex: "reviewConclusion",
width: 150,
render: (val, _, idx) => (
<Select
value={val}
size="small"
style={{ width: 130 }}
allowClear
disabled={readOnly}
placeholder="请选择结果"
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
>
<Select.Option value="conform_to">符合</Select.Option>
<Select.Option value="not_conform_to">不符合</Select.Option>
</Select>
),
},
{
title: "意见",
dataIndex: "reviewOpinion",
render: (val, _, idx) => (
<Input
size="small"
value={val}
allowClear
disabled={readOnly}
maxLength={60}
placeholder="请输入意见"
onChange={(e) => updateRow(idx, "reviewOpinion", e.target.value)}
/>
),
},
];
const STEP_ITEMS = [
{ key: 1, label: "过程控制审核" },
{ key: 2, label: "机构负责人签发" },
];
const reviewerSignatureTaskStatusMap={
dispatched: "已下发",
non_dispatched: "过程控制签字提交",
completed: "已完成",
}
const OrgHeadSignatureTaskStatusMap={
dispatched: "已下发",
non_dispatched: "下发APP签字",
completed: "已完成",
}
return (
<div>
<Flex
gap={0}
style={{ marginBottom: 16, borderBottom: "1px solid #e8e8e8" }}
>
{STEP_ITEMS.map((item) => (
<Button
key={item.key}
type="text"
onClick={() => setStep(item.key)}
style={{
minWidth: 128,
borderBottom:
step === item.key
? "3px solid #1677ff"
: "3px solid transparent",
borderRadius: 0,
fontWeight: step === item.key ? 700 : 400,
color: step === item.key ? "#1677ff" : undefined,
background: step === item.key ? "#e6f4ff" : "transparent",
}}
>
{item.label}
</Button>
))}
</Flex>
{step === 1 && (
<Card
title="过程控制审核"
style={{ marginBottom: 16 }}
styles={{ body: { paddingBottom: 0 } }}
>
<Table
dataSource={rows}
columns={reviewColumns}
rowKey="_key"
pagination={false}
size="small"
/>
<Collapse
style={{ marginTop: 12 }}
items={[
{
key: "checklist",
label: "过程控制完整核查清单13项",
children: (
<ol
style={{
margin: 0,
paddingLeft: 20,
fontSize: 13,
color: "#475569",
lineHeight: 1.8,
}}
>
<li>合同签订前是否进行项目风险分析</li>
<li>是否签订技术服务合同</li>
<li>是否下达项目任务通知单</li>
<li>是否有项目组成立和项目负责人任命记录</li>
<li>是否编制项目实施计划</li>
<li>现场检查记录是否完整有效</li>
<li>是否有书面整改通知单并由被评价单位盖章或签字确认</li>
<li>
是否进行现场复查复查单是否双方签名或盖章并注明日期
</li>
<li>是否有现场勘查整改复查影像资料</li>
<li>是否完成内审技审并保留审核记录签字和日期</li>
<li>委托方提供资料是否齐全并由被评价单位盖章</li>
<li>
委托方资料评价过程资料和评价报告存档是否符合要求
</li>
<li>存档资料是否完整且具有可追溯性</li>
</ol>
),
},
]}
/>
<Flex justify="flex-end" gap={8} style={{ padding: "12px 0" }}>
{!readOnly && (
<Button
type="primary"
disabled={processControl?.reviewerSignatureTaskStatus !== "non_dispatched"}
onClick={() => handleConfirm("passed")}
loading={props.safetyEvalBusiness?.processControlConfirmLoading}
>
{reviewerSignatureTaskStatusMap[processControl?.reviewerSignatureTaskStatus]}
</Button>
)}
</Flex>
</Card>
)}
{step === 2 && (
<Card
title="机构负责人签发"
style={{ marginBottom: 16 }}
styles={{ body: { paddingBottom: 0 } }}
>
<div className="final-approval-card">
<div
style={{
marginBottom: 12,
display: "flex",
alignItems: "center",
gap: 8,
}}
>
<CheckCircleFilled style={{ color: "#52c41a", fontSize: 16 }} />
<span>无可能引发法律纠纷的重大风险</span>
</div>
<div
style={{
marginBottom: 12,
display: "flex",
alignItems: "center",
gap: 8,
}}
>
<CheckCircleFilled style={{ color: "#52c41a", fontSize: 16 }} />
<span>评价过程无违规现象</span>
</div>
<div
style={{
marginBottom: 12,
display: "flex",
alignItems: "center",
gap: 8,
}}
>
<CheckCircleFilled style={{ color: "#52c41a", fontSize: 16 }} />
<span>全过程记录和签字完整</span>
</div>
<div style={{ marginBottom: 12 }}>
<Typography.Text strong>签发意见</Typography.Text>
<TextArea
rows={3}
value={approvalOpinion}
onChange={(e) => setApprovalOpinion(e.target.value)}
disabled={readOnly}
placeholder="请输入签发意见"
style={{ marginTop: 4 }}
/>
</div>
<Flex
justify="space-between"
align="center"
style={{ paddingBottom: 16 }}
>
<Flex gap={8} align="center">
<Typography.Text type="secondary">
评价机构负责人
</Typography.Text>
<Select
placeholder="请选择评价机构负责人"
size="small"
allowClear
style={{ width: 180 }}
disabled={isDispatched || isOrgHeadSignature || readOnly}
value={selectPeople?.value}
onChange={(value, option) => {
setSelectPeople(option);
}}
options={(orgHeads || []).map((r) => ({
value: r.personnelId,
label: r.personnelName,
}))}
/>
<Button
size="small"
onClick={handleAssign}
loading={
props.safetyEvalBusiness?.processControlAssignLoading
}
disabled={isDispatched || isOrgHeadSignature || !selectPeople?.value || readOnly}
>
{isDispatched ? "过程控制审核暂未完成" : OrgHeadSignatureTaskStatusMap[processControl?.orgHeadSignatureTaskStatus]}
</Button>
</Flex>
</Flex>
</div>
</Card>
)}
</div>
);
};
export default Connect([NS_SAFETY_EVAL_BUSINESS], true)(ControlContent);