526 lines
18 KiB
JavaScript
526 lines
18 KiB
JavaScript
import React, { useEffect, useState, useRef } from "react";
|
||
import {
|
||
Tag,
|
||
Button,
|
||
Card,
|
||
Row,
|
||
Col,
|
||
Table,
|
||
Form,
|
||
Input,
|
||
Select,
|
||
Radio,
|
||
DatePicker,
|
||
Flex,
|
||
message,
|
||
Spin,
|
||
Modal,
|
||
} from "antd";
|
||
import dayjs from "dayjs";
|
||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
||
import { tools } from "@cqsjjb/jjb-common-lib";
|
||
|
||
const { router } = tools;
|
||
const { TextArea } = Input;
|
||
|
||
const EVAL_TYPE_OPTIONS = [
|
||
{ label: "安全预评价", value: "PRE" },
|
||
{ label: "安全验收评价", value: "ACCEPT" },
|
||
{ label: "安全现状评价", value: "STATUS" },
|
||
];
|
||
|
||
const RiskAnalysisContent = (props) => {
|
||
const [form] = Form.useForm();
|
||
|
||
const projectId = router.query?.id;
|
||
|
||
const {
|
||
safetyEvalBusiness,
|
||
evalRiskAnalysisGet,
|
||
evalRiskAnalysisSave,
|
||
evalRiskAnalysisPeopleSave,
|
||
} = props;
|
||
const {
|
||
riskAnalysisLoading,
|
||
evalProjectDetailLoading,
|
||
riskAnalysisSaveLoading,
|
||
evalProjectDetailData,
|
||
} = safetyEvalBusiness || {};
|
||
|
||
// 查询风险分析数据回显
|
||
const [participantModalOpen, setParticipantModalOpen] = useState(false);
|
||
const [selectedParticipantIds, setSelectedParticipantIds] = useState([]);
|
||
const addParticipantRef = useRef(null);
|
||
|
||
const fetchData = async () => {
|
||
if (!projectId) return;
|
||
|
||
const res = await evalRiskAnalysisGet({ projectId });
|
||
if (res?.success !== false && res?.data) {
|
||
form.setFieldsValue({
|
||
...res.data,
|
||
analysisDate: res.data.analysisDate
|
||
? dayjs(res.data.analysisDate)
|
||
: undefined,
|
||
});
|
||
} else {
|
||
form.setFieldsValue({
|
||
evalTypeCode: evalProjectDetailData.evalTypeCode,
|
||
projectName: evalProjectDetailData.projectName,
|
||
industryName: evalProjectDetailData.industryCode,
|
||
});
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (evalProjectDetailData?.id) {
|
||
fetchData();
|
||
}
|
||
}, [projectId, evalProjectDetailData?.id]);
|
||
|
||
// 保存
|
||
const handleSave = async (statusCode) => {
|
||
const values = await form.validateFields();
|
||
|
||
const { analysisDate, ...rest } = values;
|
||
if (!rest.participants?.length) {
|
||
message.warning("请选择风险分析人员");
|
||
return;
|
||
}
|
||
const res = await evalRiskAnalysisSave({
|
||
...rest,
|
||
projectId,
|
||
statusCode,
|
||
analysisDate: analysisDate
|
||
? analysisDate.format("YYYY-MM-DD")
|
||
: undefined,
|
||
});
|
||
if (res?.success && res.data && rest.participants?.length) {
|
||
const result = await evalRiskAnalysisPeopleSave(
|
||
rest.participants.map((item) => {
|
||
return {
|
||
...item,
|
||
riskId: res.data.id,
|
||
};
|
||
}),
|
||
);
|
||
if (result.success) {
|
||
message.success(statusCode === 2 ? "风险分析已完成" : "已暂存");
|
||
props.getDetail()
|
||
}
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Spin spinning={evalProjectDetailLoading || riskAnalysisLoading}>
|
||
<div>
|
||
<div className="pf-permission">
|
||
<Tag color="blue" className="pf-tag">
|
||
市场部经办人 / 市场部经理
|
||
</Tag>
|
||
<span className="pf-desc">
|
||
市场部组织前置条件调查和风险分析,相关职能部门参与;市场部经理依据分析结果决定是否签订技术服务合同。
|
||
</span>
|
||
</div>
|
||
<Card
|
||
title="安全评价风险分析记录表"
|
||
styles={{ header: { textAlign: "center" } }}
|
||
>
|
||
<Form form={form} layout="vertical">
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item label="风险分析时间" name="analysisDate">
|
||
<DatePicker className="pf-w-full" allowClear />
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item label="评价项目名称" name="projectName">
|
||
<Input
|
||
placeholder="请输入评价项目名称"
|
||
maxLength={50}
|
||
allowClear
|
||
/>
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Row gutter={16}>
|
||
<Col span={12}>
|
||
<Form.Item label="评价类别" name="evalTypeCode">
|
||
<Select placeholder="请选择评价类别" allowClear>
|
||
{EVAL_TYPE_OPTIONS.map((opt) => (
|
||
<Select.Option key={opt.value} value={opt.value}>
|
||
{opt.label}
|
||
</Select.Option>
|
||
))}
|
||
</Select>
|
||
</Form.Item>
|
||
</Col>
|
||
<Col span={12}>
|
||
<Form.Item label="所属行业" name="industryName">
|
||
<Select placeholder="请选择所属行业" allowClear>
|
||
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
||
<Select.Option key={opt.value} value={opt.value}>
|
||
{opt.label}
|
||
</Select.Option>
|
||
))}
|
||
</Select>
|
||
</Form.Item>
|
||
</Col>
|
||
</Row>
|
||
|
||
<Form.Item label="评价范围" name="evalScope">
|
||
<TextArea
|
||
rows={2}
|
||
placeholder="明确本项目安全评价对象、装置、区域及委托范围"
|
||
maxLength={200}
|
||
showCount
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item label="是否在公司资质业务范围内" name="inBizScopeFlag">
|
||
<Radio.Group>
|
||
<Radio value={1}>是</Radio>
|
||
<Radio value={2}>否</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
|
||
<Card
|
||
type="inner"
|
||
size="small"
|
||
title="一、被评价单位基本概况"
|
||
className="pf-section"
|
||
>
|
||
<Form.Item name="unitOverview">
|
||
<TextArea
|
||
rows={4}
|
||
placeholder="填写项目简介、投资规模、地理位置、周边环境、主要设施及客户要求"
|
||
maxLength={500}
|
||
showCount
|
||
/>
|
||
</Form.Item>
|
||
</Card>
|
||
|
||
<Card
|
||
type="inner"
|
||
size="small"
|
||
title="二、项目行业风险特性分析"
|
||
className="pf-section"
|
||
>
|
||
<Form.Item name="industryRiskDesc">
|
||
<TextArea
|
||
rows={3}
|
||
placeholder="分析项目所属行业的主要危险、有害因素"
|
||
maxLength={500}
|
||
showCount
|
||
/>
|
||
</Form.Item>
|
||
<div className="pf-hint-blue">
|
||
应结合项目行业特点、地理位置、周边环境和评价类别填写;非常规项目应通过风险分析会议形成记录。
|
||
</div>
|
||
</Card>
|
||
|
||
<Card
|
||
type="inner"
|
||
size="small"
|
||
title="三、评价机构符合情况"
|
||
className="pf-section"
|
||
>
|
||
<Form.Item
|
||
label="(1)评价人员专业构成是否满足该项目的评价需求"
|
||
name="staffMatchCode"
|
||
>
|
||
<Radio.Group>
|
||
<Radio value={1}>满足</Radio>
|
||
<Radio value={2}>不满足</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<Form.Item
|
||
label="(2)是否需要聘请相关技术专家"
|
||
name="needExpertCode"
|
||
>
|
||
<Radio.Group>
|
||
<Radio value={2}>不需要</Radio>
|
||
<Radio value={1}>需要</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<Form.Item
|
||
label="(3)是否有能力承担该项目的评价风险"
|
||
name="capabilityCode"
|
||
>
|
||
<Radio.Group>
|
||
<Radio value={1}>是</Radio>
|
||
<Radio value={2}>否</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<Form.Item label="(4)项目的可行性分析" name="feasibleCode">
|
||
<Radio.Group>
|
||
<Radio value={1}>可行</Radio>
|
||
<Radio value={2}>不可行</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<Form.Item label="(5)项目的经济性分析" name="economicCode">
|
||
<Radio.Group>
|
||
<Radio value={1}>有经济效益</Radio>
|
||
<Radio value={2}>无经济效益</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
</Card>
|
||
|
||
<Card
|
||
type="inner"
|
||
size="small"
|
||
title="风险分析结论"
|
||
className="pf-section"
|
||
>
|
||
<Form.Item label="风险程度" name="riskLevelCode">
|
||
<Radio.Group>
|
||
<Radio value={1}>低度</Radio>
|
||
<Radio value={2}>中度</Radio>
|
||
<Radio value={3}>高度</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<div className="pf-risk-note">
|
||
中度:化工、金属非金属矿山、金属冶炼、陆地油气开采等行业评价项目。
|
||
</div>
|
||
<Form.Item label="合同签订" name="signContractCode">
|
||
<Radio.Group>
|
||
<Radio value={1}>签合同</Radio>
|
||
<Radio value={2}>不签合同</Radio>
|
||
</Radio.Group>
|
||
</Form.Item>
|
||
<div className="pf-hint-blue">
|
||
系统建议:当前条件具备签约基础,最终结论由市场部经理批准。
|
||
</div>
|
||
</Card>
|
||
|
||
<Card type="inner" size="small" title="参与风险分析人员签字">
|
||
<Form.List name="participants">
|
||
{(fields, { add, remove }) => {
|
||
addParticipantRef.current = add;
|
||
return (
|
||
<>
|
||
<Table
|
||
dataSource={fields}
|
||
columns={[
|
||
{
|
||
title: "姓名",
|
||
dataIndex: "name",
|
||
render: (_, field) => {
|
||
const { key, ...fieldProps } = field;
|
||
return (
|
||
<Form.Item
|
||
{...fieldProps}
|
||
name={[field.name, "personnelName"]}
|
||
noStyle
|
||
>
|
||
<Input
|
||
placeholder="姓名"
|
||
disabled
|
||
maxLength={20}
|
||
allowClear
|
||
/>
|
||
</Form.Item>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
title: "部门/岗位",
|
||
dataIndex: "deptName",
|
||
render: (_, field) => {
|
||
const { key, ...fieldProps } = field;
|
||
return (
|
||
<Form.Item
|
||
{...fieldProps}
|
||
name={[field.name, "deptName"]}
|
||
noStyle
|
||
>
|
||
<Input
|
||
placeholder="部门/岗位"
|
||
disabled
|
||
maxLength={20}
|
||
allowClear
|
||
/>
|
||
</Form.Item>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
title: "分析意见",
|
||
dataIndex: "opinion",
|
||
render: (_, field) => {
|
||
const { key, ...fieldProps } = field;
|
||
return (
|
||
<Form.Item
|
||
{...fieldProps}
|
||
name={[field.name, "opinion"]}
|
||
noStyle
|
||
>
|
||
<Input
|
||
placeholder="填写分析意见"
|
||
maxLength={30}
|
||
allowClear
|
||
/>
|
||
</Form.Item>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
title: "签字状态",
|
||
render: (_, field) => (
|
||
<Button size="small">发起APP签字</Button>
|
||
),
|
||
},
|
||
{
|
||
title: "操作",
|
||
render: (_, field) =>
|
||
fields.length > 1 ? (
|
||
<Button
|
||
type="link"
|
||
danger
|
||
size="small"
|
||
onClick={() => remove(field.name)}
|
||
>
|
||
删除
|
||
</Button>
|
||
) : null,
|
||
},
|
||
]}
|
||
rowKey={(_, index) => index}
|
||
pagination={false}
|
||
/>
|
||
<Button
|
||
type="dashed"
|
||
size="small"
|
||
style={{ marginTop: 8 }}
|
||
onClick={() => {
|
||
setSelectedParticipantIds([]);
|
||
setParticipantModalOpen(true);
|
||
}}
|
||
>
|
||
+ 添加参与人员
|
||
</Button>
|
||
</>
|
||
);
|
||
}}
|
||
</Form.List>
|
||
</Card>
|
||
|
||
<Modal
|
||
title="选择参与人员"
|
||
open={participantModalOpen}
|
||
onCancel={() => setParticipantModalOpen(false)}
|
||
onOk={() => {
|
||
const selected = (evalProjectDetailData?.participants || []).filter(
|
||
(p) => selectedParticipantIds.includes(p.id),
|
||
);
|
||
selected.forEach((p) => {
|
||
addParticipantRef.current?.({
|
||
personnelName: p.name,
|
||
deptName: p.deptName,
|
||
opinion: "",
|
||
});
|
||
});
|
||
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>
|
||
</Card>
|
||
|
||
<Card
|
||
title="管理办法判定提示"
|
||
size="small"
|
||
className="pf-rule-card pf-section"
|
||
>
|
||
<Row gutter={16}>
|
||
<Col span={8}>
|
||
<Card size="small" type="inner">
|
||
<div>
|
||
<strong>低度风险</strong>
|
||
</div>
|
||
<div className="pf-risk-card">
|
||
小型露天采石场、加油站,以及机构熟悉且开展过类似评价工作的常规项目。
|
||
</div>
|
||
</Card>
|
||
</Col>
|
||
<Col span={8}>
|
||
<Card size="small" type="inner">
|
||
<div>
|
||
<strong>中度风险</strong>
|
||
</div>
|
||
<div className="pf-risk-card">
|
||
化工生产、金属非金属矿山、金属冶炼、陆地石油和天然气开采行业的评价项目。
|
||
</div>
|
||
</Card>
|
||
</Col>
|
||
<Col span={8}>
|
||
<Card size="small" type="inner">
|
||
<div>
|
||
<strong>高度风险</strong>
|
||
</div>
|
||
<div className="pf-risk-card">
|
||
机构未开展过的非常规项目,原则上组织专项风险分析会议,必要时总经理参加。
|
||
</div>
|
||
</Card>
|
||
</Col>
|
||
</Row>
|
||
<div className="pf-reject-note">
|
||
<strong>不签合同重点条件:</strong>
|
||
超出资质范围;无法提供合法有效资料;客户提出违法或不合理要求;经济性达不到预期;评价时间不能满足;机构与被评价对象存在投资咨询、设计、监理、物资供应等利益关系。
|
||
</div>
|
||
</Card>
|
||
|
||
<Flex justify="flex-end" gap={8}>
|
||
<Button
|
||
onClick={() => handleSave(1)}
|
||
loading={riskAnalysisSaveLoading}
|
||
>
|
||
暂存
|
||
</Button>
|
||
<Button>打印记录表</Button>
|
||
<Button
|
||
type="primary"
|
||
onClick={() => handleSave(2)}
|
||
loading={riskAnalysisSaveLoading}
|
||
>
|
||
完成分析并保存
|
||
</Button>
|
||
</Flex>
|
||
</div>
|
||
</Spin>
|
||
);
|
||
};
|
||
|
||
export default Connect([NS_SAFETY_EVAL_BUSINESS], true)(RiskAnalysisContent);
|