feat
parent
6ad6475911
commit
77af783720
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Tag, Button, Card, Row, Col, Table, Select, Input, Flex, Typography, message } from "antd";
|
import { Tag, Button, Card, Table, Select, Input, Flex, Typography, message, Popover } from "antd";
|
||||||
|
import { CheckCircleFilled } from "@ant-design/icons";
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
|
@ -7,15 +8,14 @@ import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
const CONCLUSION_OPTIONS = [
|
|
||||||
{ value: "conform_to", label: "符合" },
|
|
||||||
{ value: "not_conform_to", label: "需修改" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const ControlContent = (props) => {
|
const ControlContent = (props) => {
|
||||||
const projectId = router.query?.id;
|
const projectId = router.query?.id;
|
||||||
const { processControlDetail, processControlFiles } = props.safetyEvalBusiness || {};
|
const { processControlDetail, processControlFiles } =
|
||||||
const { processControl, controllers, reviewItems } = processControlDetail || {};
|
props.safetyEvalBusiness || {};
|
||||||
|
const { processControl, controllers, reviewItems } =
|
||||||
|
processControlDetail || {};
|
||||||
|
|
||||||
|
const [selectPeople, setSelectPeople] = useState(null);
|
||||||
|
|
||||||
// 当前步骤:1-过程控制审核 2-机构负责人签发 3-项目归档
|
// 当前步骤:1-过程控制审核 2-机构负责人签发 3-项目归档
|
||||||
const [step, setStep] = useState(1);
|
const [step, setStep] = useState(1);
|
||||||
|
|
@ -27,8 +27,21 @@ const ControlContent = (props) => {
|
||||||
// 项目归档
|
// 项目归档
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
|
|
||||||
|
// 机构负责人签发
|
||||||
|
const [approvalOpinion, setApprovalOpinion] = useState("");
|
||||||
|
|
||||||
const fetchDetail = () => {
|
const fetchDetail = () => {
|
||||||
props.evalProcessControlDetail({ projectId });
|
props.evalProcessControlDetail({ projectId }).then((res) => {
|
||||||
|
if (res?.success) {
|
||||||
|
setOpinionContent(res?.data?.opinionContent);
|
||||||
|
if (res?.data?.signTaskPersonCo) {
|
||||||
|
setSelectPeople({
|
||||||
|
value: res?.data?.signTaskPersonCo?.signerPersonnelId,
|
||||||
|
label: res?.data?.signTaskPersonCo?.signerName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchFiles = () => {
|
const fetchFiles = () => {
|
||||||
|
|
@ -68,11 +81,12 @@ const ControlContent = (props) => {
|
||||||
setRows(next);
|
setRows(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const controllerName = processControl?.controllerName || "";
|
const isDispatched =
|
||||||
const isDispatched = processControl?.reviewerSignatureTaskStatus !== "non_dispatched";
|
processControl?.reviewerSignatureTaskStatus !== "non_dispatched";
|
||||||
const isSignatureCompleted = processControl?.reviewerSignatureTaskStatus === "completed";
|
const isSignatureCompleted =
|
||||||
|
processControl?.reviewerSignatureTaskStatus === "completed";
|
||||||
const hasHandoverForm = !!processControl?.handoverFormUrl;
|
const hasHandoverForm = !!processControl?.handoverFormUrl;
|
||||||
const problemCount = rows.filter((r) => r.reviewConclusion === "not_conform_to").length;
|
|
||||||
const canArchive = isSignatureCompleted && hasHandoverForm;
|
const canArchive = isSignatureCompleted && hasHandoverForm;
|
||||||
|
|
||||||
// 过程控制签字提交(confirm)
|
// 过程控制签字提交(confirm)
|
||||||
|
|
@ -95,7 +109,9 @@ const ControlContent = (props) => {
|
||||||
};
|
};
|
||||||
const res = await props.evalProcessControlConfirm(payload);
|
const res = await props.evalProcessControlConfirm(payload);
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success(resultCode === "passed" ? "已提交通过审核" : "已提交退回修改");
|
message.success(
|
||||||
|
resultCode === "passed" ? "已提交通过审核" : "已提交退回修改",
|
||||||
|
);
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -103,23 +119,20 @@ const ControlContent = (props) => {
|
||||||
// 下发签字任务(assign)
|
// 下发签字任务(assign)
|
||||||
const handleAssign = async () => {
|
const handleAssign = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
const res = await props.evalProcessControlAssign({ projectId });
|
const res = await props.evalProcessControlAssign({
|
||||||
|
projectId,
|
||||||
|
signTaskPersonCmd: {
|
||||||
|
signerPersonnelId: selectPeople?.value,
|
||||||
|
signerName: selectPeople?.label,
|
||||||
|
},
|
||||||
|
opinionContent: approvalOpinion,
|
||||||
|
});
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success("已下发签字任务");
|
message.success("已下发签字任务");
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 生成归档交接单
|
|
||||||
const handleGenerateHandover = async () => {
|
|
||||||
if (!projectId) return;
|
|
||||||
const res = await props.evalProcessControlGenerateHandover({ projectId });
|
|
||||||
if (res?.success !== false) {
|
|
||||||
message.success("归档交接单已生成");
|
|
||||||
fetchDetail();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 归档项目并入库
|
// 归档项目并入库
|
||||||
const handleArchive = async () => {
|
const handleArchive = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
|
|
@ -131,10 +144,10 @@ const ControlContent = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const reviewColumns = [
|
const reviewColumns = [
|
||||||
{ title: "审核维度", dataIndex: "reviewDimensionName", width: 120 },
|
{ title: "程序审核项", dataIndex: "reviewDimensionName", width: 120 },
|
||||||
{ title: "审核重点", dataIndex: "reviewFocus", width: 200 },
|
{ title: "核查内容", dataIndex: "reviewFocus", width: 200 },
|
||||||
{
|
{
|
||||||
title: "结论",
|
title: "结果",
|
||||||
dataIndex: "reviewConclusion",
|
dataIndex: "reviewConclusion",
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (val, _, idx) => (
|
render: (val, _, idx) => (
|
||||||
|
|
@ -144,21 +157,21 @@ const ControlContent = (props) => {
|
||||||
style={{ width: 100 }}
|
style={{ width: 100 }}
|
||||||
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
onChange={(v) => updateRow(idx, "reviewConclusion", v)}
|
||||||
>
|
>
|
||||||
{CONCLUSION_OPTIONS.map((opt) => (
|
<Select.Option value="conform_to">符合</Select.Option>
|
||||||
<Select.Option key={opt.value} value={opt.value}>
|
<Select.Option value="not_conform_to">不符合</Select.Option>
|
||||||
{opt.label}
|
|
||||||
</Select.Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
</Select>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "审核意见",
|
title: "意见",
|
||||||
dataIndex: "reviewOpinion",
|
dataIndex: "reviewOpinion",
|
||||||
render: (val, _, idx) => (
|
render: (val, _, idx) => (
|
||||||
<Input
|
<Input
|
||||||
size="small"
|
size="small"
|
||||||
value={val}
|
value={val}
|
||||||
|
allowClear
|
||||||
|
maxLength={60}
|
||||||
|
placeholder="请输入意见"
|
||||||
onChange={(e) => updateRow(idx, "reviewOpinion", e.target.value)}
|
onChange={(e) => updateRow(idx, "reviewOpinion", e.target.value)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
@ -166,23 +179,61 @@ const ControlContent = (props) => {
|
||||||
];
|
];
|
||||||
|
|
||||||
const fileColumns = [
|
const fileColumns = [
|
||||||
{ title: "流程名称", dataIndex: "processName", width: 100 },
|
{ title: "流程名称", dataIndex: "processName", ellipsis: true },
|
||||||
{ title: "条目名称", dataIndex: "itemName", width: 120 },
|
{ title: "条目名称", dataIndex: "itemName", ellipsis: true },
|
||||||
{ title: "文件名称", dataIndex: "materialName", width: 200 },
|
|
||||||
{
|
{
|
||||||
title: "文件地址",
|
title: "文件",
|
||||||
dataIndex: "projectDocUrl",
|
dataIndex: "projectDocUrl",
|
||||||
width: 200,
|
|
||||||
render: (url) =>
|
render: (val) => {
|
||||||
url ? (
|
let files = [];
|
||||||
<a href={url} target="_blank" rel="noreferrer">
|
if (typeof val === "string") {
|
||||||
查看文件
|
try { files = JSON.parse(val); } catch { files = []; }
|
||||||
|
} else if (Array.isArray(val)) {
|
||||||
|
files = val;
|
||||||
|
}
|
||||||
|
if (!files.length) return "-";
|
||||||
|
return (
|
||||||
|
<Flex vertical gap={2}>
|
||||||
|
<Popover
|
||||||
|
title="附件列表"
|
||||||
|
placement="topLeft"
|
||||||
|
content={
|
||||||
|
<Flex vertical gap={4} >
|
||||||
|
{files.map((f, i) => (
|
||||||
|
<a
|
||||||
|
key={f.uid || i}
|
||||||
|
href={f.url }
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
style={{
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
display: "inline-block",
|
||||||
|
maxWidth: 280,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
📎 {f.name || f.url || "查看文件"}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
))}
|
||||||
"-"
|
</Flex>
|
||||||
),
|
}
|
||||||
|
trigger="hover"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
onClick={(e) => e.preventDefault()}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
{files.length}个附件
|
||||||
|
</a>
|
||||||
|
</Popover>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
{ title: "资料类型", dataIndex: "materialType", width: 100 },
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const STEP_ITEMS = [
|
const STEP_ITEMS = [
|
||||||
|
|
@ -193,7 +244,10 @@ const ControlContent = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Flex gap={0} style={{ marginBottom: 16, borderBottom: "1px solid #e8e8e8" }}>
|
<Flex
|
||||||
|
gap={0}
|
||||||
|
style={{ marginBottom: 16, borderBottom: "1px solid #e8e8e8" }}
|
||||||
|
>
|
||||||
{STEP_ITEMS.map((item) => (
|
{STEP_ITEMS.map((item) => (
|
||||||
<Button
|
<Button
|
||||||
key={item.key}
|
key={item.key}
|
||||||
|
|
@ -201,7 +255,10 @@ const ControlContent = (props) => {
|
||||||
onClick={() => setStep(item.key)}
|
onClick={() => setStep(item.key)}
|
||||||
style={{
|
style={{
|
||||||
minWidth: 128,
|
minWidth: 128,
|
||||||
borderBottom: step === item.key ? "3px solid #1677ff" : "3px solid transparent",
|
borderBottom:
|
||||||
|
step === item.key
|
||||||
|
? "3px solid #1677ff"
|
||||||
|
: "3px solid transparent",
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
fontWeight: step === item.key ? 700 : 400,
|
fontWeight: step === item.key ? 700 : 400,
|
||||||
color: step === item.key ? "#1677ff" : undefined,
|
color: step === item.key ? "#1677ff" : undefined,
|
||||||
|
|
@ -219,42 +276,6 @@ const ControlContent = (props) => {
|
||||||
style={{ marginBottom: 16 }}
|
style={{ marginBottom: 16 }}
|
||||||
styles={{ body: { paddingBottom: 0 } }}
|
styles={{ body: { paddingBottom: 0 } }}
|
||||||
>
|
>
|
||||||
<div className="pf-permission">
|
|
||||||
<Tag color="blue" className="pf-tag">
|
|
||||||
过程控制负责人
|
|
||||||
</Tag>
|
|
||||||
<span className="pf-desc">过程控制负责人核验前7节点完成及签字记录</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Row gutter={16} style={{ marginBottom: 16 }}>
|
|
||||||
<Col span={8}>
|
|
||||||
<Card size="small">
|
|
||||||
<Typography.Text type="secondary">过程控制负责人</Typography.Text>
|
|
||||||
<div>
|
|
||||||
<strong>{controllerName || "-"}</strong>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Card size="small">
|
|
||||||
<Typography.Text type="secondary">审核项</Typography.Text>
|
|
||||||
<div>
|
|
||||||
<strong>{rows.length}项</strong>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Card size="small">
|
|
||||||
<Typography.Text type="secondary">问题</Typography.Text>
|
|
||||||
<div>
|
|
||||||
<Typography.Text strong type={problemCount > 0 ? "warning" : undefined}>
|
|
||||||
{problemCount}项
|
|
||||||
</Typography.Text>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
dataSource={rows}
|
dataSource={rows}
|
||||||
columns={reviewColumns}
|
columns={reviewColumns}
|
||||||
|
|
@ -263,40 +284,15 @@ const ControlContent = (props) => {
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ margin: "12px 0" }}>
|
<Flex justify="flex-end" gap={8} style={{ padding: "12px 0" }}>
|
||||||
<Typography.Text strong>总体过程控制意见</Typography.Text>
|
|
||||||
<TextArea
|
|
||||||
rows={2}
|
|
||||||
value={opinionContent}
|
|
||||||
onChange={(e) => setOpinionContent(e.target.value)}
|
|
||||||
style={{ marginTop: 4 }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Flex justify="space-between" align="center" style={{ marginTop: 10, paddingBottom: 16 }}>
|
|
||||||
<Flex gap={8} align="center">
|
|
||||||
<Typography.Text type="secondary">过程控制负责人签字</Typography.Text>
|
|
||||||
<strong>{controllerName}</strong>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
onClick={handleAssign}
|
|
||||||
loading={props.safetyEvalBusiness?.processControlAssignLoading}
|
|
||||||
disabled={isDispatched}
|
|
||||||
>
|
|
||||||
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
<Flex gap={8}>
|
|
||||||
<Button onClick={() => handleConfirm("not_passed")}>退回修改</Button>
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => handleConfirm("passed")}
|
onClick={() => handleConfirm("passed")}
|
||||||
loading={props.safetyEvalBusiness?.processControlConfirmLoading}
|
loading={props.safetyEvalBusiness?.processControlConfirmLoading}
|
||||||
>
|
>
|
||||||
通过
|
过程控制签字提交
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -306,47 +302,89 @@ const ControlContent = (props) => {
|
||||||
style={{ marginBottom: 16 }}
|
style={{ marginBottom: 16 }}
|
||||||
styles={{ body: { paddingBottom: 0 } }}
|
styles={{ body: { paddingBottom: 0 } }}
|
||||||
>
|
>
|
||||||
<div className="pf-permission">
|
<div className="final-approval-card">
|
||||||
<Tag color="blue" className="pf-tag">
|
<div
|
||||||
评价机构负责人
|
style={{
|
||||||
</Tag>
|
marginBottom: 12,
|
||||||
<span className="pf-desc">机构负责人终审并签发,确认项目成果</span>
|
display: "flex",
|
||||||
</div>
|
alignItems: "center",
|
||||||
|
gap: 8,
|
||||||
<Row gutter={16} style={{ marginBottom: 16 }}>
|
}}
|
||||||
{controllers?.map((c) => (
|
|
||||||
<Col span={8} key={c.id || c.personnelId}>
|
|
||||||
<Card size="small">
|
|
||||||
<Typography.Text type="secondary">机构负责人</Typography.Text>
|
|
||||||
<div>
|
|
||||||
<strong>{c.personnelName}</strong>
|
|
||||||
</div>
|
|
||||||
{c.deptName && (
|
|
||||||
<div>
|
|
||||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
|
||||||
{c.deptName}
|
|
||||||
</Typography.Text>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
))}
|
|
||||||
{(!controllers || controllers.length === 0) && (
|
|
||||||
<Col span={24}>
|
|
||||||
<Typography.Text type="secondary">暂无机构负责人信息</Typography.Text>
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Flex justify="flex-end" style={{ paddingBottom: 16 }}>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleAssign}
|
|
||||||
loading={props.safetyEvalBusiness?.processControlAssignLoading}
|
|
||||||
>
|
>
|
||||||
终审并签发
|
<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)}
|
||||||
|
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}
|
||||||
|
value={selectPeople?.value}
|
||||||
|
onChange={(value, option) => {
|
||||||
|
setSelectPeople(option);
|
||||||
|
}}
|
||||||
|
options={(controllers || []).map((r) => ({
|
||||||
|
value: r.personnelId,
|
||||||
|
label: r.personnelName,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={handleAssign}
|
||||||
|
loading={
|
||||||
|
props.safetyEvalBusiness?.processControlAssignLoading
|
||||||
|
}
|
||||||
|
disabled={isDispatched || !selectPeople?.value}
|
||||||
|
>
|
||||||
|
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -360,28 +398,27 @@ const ControlContent = (props) => {
|
||||||
<Tag color="blue" className="pf-tag">
|
<Tag color="blue" className="pf-tag">
|
||||||
项目归档
|
项目归档
|
||||||
</Tag>
|
</Tag>
|
||||||
<span className="pf-desc">项目过程文件清单,确认签字完成后归档入库</span>
|
<span className="pf-desc">
|
||||||
|
项目过程文件清单,确认签字完成后归档入库
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
dataSource={files}
|
dataSource={files}
|
||||||
columns={fileColumns}
|
columns={fileColumns}
|
||||||
rowKey={(record) => `${record.processName}-${record.materialName}-${record.itemName}`}
|
rowKey={(record) =>
|
||||||
|
`${record.processName}-${record.materialName}-${record.itemName}`
|
||||||
|
}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Flex justify="space-between" align="center" style={{ marginTop: 12, paddingBottom: 16 }}>
|
<Flex
|
||||||
<Flex gap={8} align="center">
|
justify="space-between"
|
||||||
{!hasHandoverForm && (
|
align="center"
|
||||||
<Button
|
style={{ marginTop: 12, paddingBottom: 16 }}
|
||||||
size="small"
|
|
||||||
onClick={handleGenerateHandover}
|
|
||||||
loading={props.safetyEvalBusiness?.processControlHandoverLoading}
|
|
||||||
>
|
>
|
||||||
生成归档交接单
|
<Flex gap={8} align="center">
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{hasHandoverForm && (
|
{hasHandoverForm && (
|
||||||
<Typography.Text type="success">
|
<Typography.Text type="success">
|
||||||
归档交接单已生成
|
归档交接单已生成
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
message,
|
message,
|
||||||
|
Tooltip,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
|
|
@ -36,9 +37,14 @@ const InternalReviewContent = (props) => {
|
||||||
|
|
||||||
const [rows, setRows] = useState([]);
|
const [rows, setRows] = useState([]);
|
||||||
const [overallOpinion, setOverallOpinion] = useState("");
|
const [overallOpinion, setOverallOpinion] = useState("");
|
||||||
|
const [selectedReviewer, setSelectedReviewer] = useState(undefined);
|
||||||
|
|
||||||
const fetchDetail = () => {
|
const fetchDetail = () => {
|
||||||
props.evalInternalReviewDetail({ projectId });
|
props.evalInternalReviewDetail({ projectId }).then((res) => {
|
||||||
|
if (res?.success && res.data.signTaskPersonCo) {
|
||||||
|
setSelectedReviewer(res.data.signTaskPersonCo?.signerPersonnelId);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -65,7 +71,7 @@ const InternalReviewContent = (props) => {
|
||||||
setRows(next);
|
setRows(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reviewerName = internalReview?.reviewerName || "";
|
|
||||||
const isDispatched =
|
const isDispatched =
|
||||||
internalReview?.reviewerSignatureTaskStatus === "dispatched";
|
internalReview?.reviewerSignatureTaskStatus === "dispatched";
|
||||||
const problemCount = rows.filter(
|
const problemCount = rows.filter(
|
||||||
|
|
@ -74,7 +80,10 @@ const InternalReviewContent = (props) => {
|
||||||
|
|
||||||
const handleAssign = async () => {
|
const handleAssign = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
const res = await props.evalInternalReviewAssign({ projectId });
|
const res = await props.evalInternalReviewAssign({ projectId, signTaskPersonCmd:{
|
||||||
|
signerPersonnelId: selectedReviewer,
|
||||||
|
signerName: reviewers.find((item) => item.personnelId === selectedReviewer)?.personnelName ,
|
||||||
|
} });
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success("已下发签字任务");
|
message.success("已下发签字任务");
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
|
|
@ -159,8 +168,10 @@ 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>
|
<div style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
|
||||||
<strong>{reviewerName || "-"}</strong>
|
<Tooltip title={(reviewers || []).map((r) => r.personnelName).join("、")}>
|
||||||
|
<strong>{(reviewers || []).map((r) => r.personnelName).join("、") || "-"}</strong>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
@ -209,12 +220,23 @@ const InternalReviewContent = (props) => {
|
||||||
<Flex justify="space-between" align="center" style={{ marginTop: 10 }}>
|
<Flex justify="space-between" align="center" style={{ marginTop: 10 }}>
|
||||||
<Flex gap={8} align="center">
|
<Flex gap={8} align="center">
|
||||||
<Typography.Text type="secondary">内审人独立签字</Typography.Text>
|
<Typography.Text type="secondary">内审人独立签字</Typography.Text>
|
||||||
<strong>{reviewerName}</strong>
|
<Select
|
||||||
|
placeholder="请选择内审人"
|
||||||
|
size="small"
|
||||||
|
style={{ width: 140 }}
|
||||||
|
value={selectedReviewer}
|
||||||
|
onChange={setSelectedReviewer}
|
||||||
|
options={(reviewers || []).map((r) => ({
|
||||||
|
value: r.personnelId,
|
||||||
|
label: r.personnelName,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
onClick={handleAssign}
|
onClick={handleAssign}
|
||||||
loading={internalReviewAssignLoading}
|
loading={internalReviewAssignLoading}
|
||||||
disabled={isDispatched}
|
disabled={isDispatched || !selectedReviewer}
|
||||||
|
|
||||||
>
|
>
|
||||||
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,18 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Tag, Button, Card, Row, Col, Table, Select, Input, Flex, Typography, message } from "antd";
|
import {
|
||||||
|
Tag,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Table,
|
||||||
|
Select,
|
||||||
|
Input,
|
||||||
|
Flex,
|
||||||
|
Typography,
|
||||||
|
message,
|
||||||
|
Tooltip,
|
||||||
|
} from "antd";
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
|
@ -19,9 +32,17 @@ const TechnicalReviewContent = (props) => {
|
||||||
|
|
||||||
const [rows, setRows] = useState([]);
|
const [rows, setRows] = useState([]);
|
||||||
const [overallOpinion, setOverallOpinion] = useState("");
|
const [overallOpinion, setOverallOpinion] = useState("");
|
||||||
|
const [selectedReviewer, setSelectedReviewer] = useState(undefined);
|
||||||
|
|
||||||
const fetchDetail = () => {
|
const fetchDetail = () => {
|
||||||
props.evalTechReviewDetail({ projectId });
|
props.evalTechReviewDetail({ projectId }).then((res) => {
|
||||||
|
if (res?.success) {
|
||||||
|
const co = res.data?.signTaskPersonCo;
|
||||||
|
if (co?.signerPersonnelId) {
|
||||||
|
setSelectedReviewer(co.signerPersonnelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -48,14 +69,22 @@ const TechnicalReviewContent = (props) => {
|
||||||
setRows(next);
|
setRows(next);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reviewerName = techReview?.reviewerName || "";
|
const isDispatched = techReview?.reviewerSignatureTaskStatus === "dispatched";
|
||||||
const isDispatched = techReview?.reviewerSignatureTaskStatus !== "non_dispatched";
|
|
||||||
const staffMatch = techReview?.staffMatchCode === 1 ? "满足" : "不满足";
|
const staffMatch = techReview?.staffMatchCode === 1 ? "满足" : "不满足";
|
||||||
const inBizScope = techReview?.inBizScopeFlag === 1 ? "在范围内" : "不在范围内";
|
const inBizScope =
|
||||||
|
techReview?.inBizScopeFlag === 1 ? "在范围内" : "不在范围内";
|
||||||
|
|
||||||
const handleAssign = async () => {
|
const handleAssign = async () => {
|
||||||
if (!projectId) return;
|
if (!projectId) return;
|
||||||
const res = await props.evalTechReviewAssign({ projectId });
|
const res = await props.evalTechReviewAssign({
|
||||||
|
projectId,
|
||||||
|
signTaskPersonCmd: {
|
||||||
|
signerPersonnelId: selectedReviewer,
|
||||||
|
signerName:
|
||||||
|
reviewers?.find((r) => r.personnelId === selectedReviewer)
|
||||||
|
?.personnelName || "",
|
||||||
|
},
|
||||||
|
});
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success("已下发签字任务");
|
message.success("已下发签字任务");
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
|
|
@ -81,7 +110,9 @@ const TechnicalReviewContent = (props) => {
|
||||||
};
|
};
|
||||||
const res = await props.evalTechReviewConfirm(payload);
|
const res = await props.evalTechReviewConfirm(payload);
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success(resultCode === "1" ? "已确认技审并提交过程控制" : "已保存");
|
message.success(
|
||||||
|
resultCode === "1" ? "已确认技审并提交过程控制" : "已保存",
|
||||||
|
);
|
||||||
fetchDetail();
|
fetchDetail();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -136,8 +167,21 @@ const TechnicalReviewContent = (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>
|
<div
|
||||||
<strong>{reviewerName || "-"}</strong>
|
style={{
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
title={(reviewers || []).map((r) => r.personnelName).join("、")}
|
||||||
|
>
|
||||||
|
<strong>
|
||||||
|
{(reviewers || []).map((r) => r.personnelName).join("、") ||
|
||||||
|
"-"}
|
||||||
|
</strong>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
@ -145,7 +189,10 @@ const TechnicalReviewContent = (props) => {
|
||||||
<Card size="small">
|
<Card size="small">
|
||||||
<Typography.Text type="secondary">专业匹配</Typography.Text>
|
<Typography.Text type="secondary">专业匹配</Typography.Text>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Text strong type={techReview?.staffMatchCode === 1 ? "success" : "warning"}>
|
<Typography.Text
|
||||||
|
strong
|
||||||
|
type={techReview?.staffMatchCode === 1 ? "success" : "warning"}
|
||||||
|
>
|
||||||
{staffMatch}
|
{staffMatch}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -155,7 +202,10 @@ const TechnicalReviewContent = (props) => {
|
||||||
<Card size="small">
|
<Card size="small">
|
||||||
<Typography.Text type="secondary">资质范围</Typography.Text>
|
<Typography.Text type="secondary">资质范围</Typography.Text>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Text strong type={techReview?.inBizScopeFlag === 1 ? "success" : "warning"}>
|
<Typography.Text
|
||||||
|
strong
|
||||||
|
type={techReview?.inBizScopeFlag === 1 ? "success" : "warning"}
|
||||||
|
>
|
||||||
{inBizScope}
|
{inBizScope}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -168,6 +218,7 @@ const TechnicalReviewContent = (props) => {
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="_key"
|
rowKey="_key"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
loading={props.safetyEvalBusiness?.techReviewDetailLoading}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -184,12 +235,22 @@ const TechnicalReviewContent = (props) => {
|
||||||
<Flex justify="space-between" align="center" style={{ marginTop: 10 }}>
|
<Flex justify="space-between" align="center" style={{ marginTop: 10 }}>
|
||||||
<Flex gap={8} align="center">
|
<Flex gap={8} align="center">
|
||||||
<Typography.Text type="secondary">技术负责人签字</Typography.Text>
|
<Typography.Text type="secondary">技术负责人签字</Typography.Text>
|
||||||
<strong>{reviewerName}</strong>
|
<Select
|
||||||
|
placeholder="请选择技术负责人"
|
||||||
|
size="small"
|
||||||
|
style={{ width: 160 }}
|
||||||
|
value={selectedReviewer}
|
||||||
|
onChange={setSelectedReviewer}
|
||||||
|
options={(reviewers || []).map((r) => ({
|
||||||
|
value: r.personnelId,
|
||||||
|
label: r.personnelName,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
onClick={handleAssign}
|
onClick={handleAssign}
|
||||||
loading={props.safetyEvalBusiness?.techReviewAssignLoading}
|
loading={props.safetyEvalBusiness?.techReviewAssignLoading}
|
||||||
disabled={isDispatched}
|
disabled={isDispatched || !selectedReviewer}
|
||||||
>
|
>
|
||||||
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
{isDispatched ? "已下发APP签字" : "下发APP签字"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -192,12 +192,18 @@ const ProjectFlow = (props) => {
|
||||||
<div>
|
<div>
|
||||||
<span>项目法定流程工作台</span>
|
<span>项目法定流程工作台</span>
|
||||||
<div className="pageLayout-extra">
|
<div className="pageLayout-extra">
|
||||||
华安化工园区安全预评价 | XP-2026-001
|
{evalProjectDetailData?.evalTypeName} |{" "}
|
||||||
|
{evalProjectDetailData?.projectNo}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tabs activeKey={activeKey} onChange={handleTabChange} items={tabItems} />
|
<Tabs
|
||||||
|
activeKey={activeKey}
|
||||||
|
onChange={handleTabChange}
|
||||||
|
items={tabItems}
|
||||||
|
destroyOnHidden
|
||||||
|
/>
|
||||||
{visible && (
|
{visible && (
|
||||||
<WpsEditor onCancel={() => setVisible(false)} fileId={wpsDoc?.fileId} />
|
<WpsEditor onCancel={() => setVisible(false)} fileId={wpsDoc?.fileId} />
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
.micro-temp-page-header-heading-left{
|
||||||
|
align-items: baseline !important;
|
||||||
|
}
|
||||||
|
|
||||||
.micro-temp-modal-body {
|
.micro-temp-modal-body {
|
||||||
max-height: 630px;
|
max-height: 630px;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue