feat
parent
c60fbb57e2
commit
0dbc0a18d9
|
|
@ -167,6 +167,11 @@ export const evalSurveyList = declareRequest(
|
||||||
"Get > /safetyEval/institution/eval-survey/list",
|
"Get > /safetyEval/institution/eval-survey/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const evalSurveyPage = declareRequest(
|
||||||
|
"evalSurveyPageLoading",
|
||||||
|
"Get > /safetyEval/institution/eval-survey/page",
|
||||||
|
);
|
||||||
|
|
||||||
export const evalSurveySaveAttach = declareRequest(
|
export const evalSurveySaveAttach = declareRequest(
|
||||||
"evalSurveySaveAttachLoading",
|
"evalSurveySaveAttachLoading",
|
||||||
"Post > @/safetyEval/institution/eval-survey/saveSurveyAttach",
|
"Post > @/safetyEval/institution/eval-survey/saveSurveyAttach",
|
||||||
|
|
|
||||||
|
|
@ -398,3 +398,23 @@ export const NODE_LABELS = {
|
||||||
TECHNICAL_REVIEW: "技术审核",
|
TECHNICAL_REVIEW: "技术审核",
|
||||||
PROCESS_CONTROL: "过程控制",
|
PROCESS_CONTROL: "过程控制",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const ROLE_DEFINITIONS = [
|
||||||
|
{ value: "MARKETING_BUSINESS_REP", name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" },
|
||||||
|
{ value: "TECHNICAL_LEAD", name: "技术负责人", unique: false, summary: "评估人员专业匹配与技术可行性,审核检查表并开展评价报告技术审核。" },
|
||||||
|
{ value: "PROCESS_CONTROL_LEAD", name: "过程控制负责人", unique: true, summary: "核查利益冲突、资质范围和人员配置,负责受控管理、程序合规审核及归档前校验。" },
|
||||||
|
{ value: "FINANCE_STAFF", name: "财务人员", unique: false, summary: "核算人工、费用、税金和利润等全成本,评估项目经济性及合同金额合理性。" },
|
||||||
|
{ value: "EVALUATION_AGENCY_HEAD", name: "评价机构负责人", unique: false, summary: "综合多方意见决定是否承接项目,并在全部审核通过后终审签发评价报告。" },
|
||||||
|
{ value: "EVALUATION_DEPT_MANAGER", name: "评价部经理", unique: false, summary: "签发项目组任命文件,审核组长资格、行业经验及成员专业配置。" },
|
||||||
|
{ value: "PROJECT_LEAD", name: "项目负责人(项目组组长)", unique: true, summary: "制定实施计划并组织启动、初勘、检查表、现场勘查、整改复查及报告编制。" },
|
||||||
|
{ value: "PROJECT_TEAM_MEMBERS", name: "项目组各专业组员", unique: false, summary: "按专业分工开展资料收集、检查表编制、现场检查、危险辨识和评价报告专业内容编写。" },
|
||||||
|
{ value: "INTERNAL_AUDITOR", name: "内审人", unique: false, summary: "审核报告初稿及修改结果,重点核查依据、危险辨识、单元划分、评价方法和结论。" },
|
||||||
|
{ value: "REPORT_COMPILER", name: "报告编制人", unique: false, summary: "整合各专业内容形成报告初稿,根据各级审核意见修改并整理全过程档案。" },
|
||||||
|
{ value: "ARCHIVES_ADMIN", name: "档案管理员", unique: false, summary: "办理档案交接、编号、分类、装订和入库,并按规定开展报告信息公开。" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ROLE_DEFINITIONS_MAP = ROLE_DEFINITIONS.reduce((acc, cur) => {
|
||||||
|
acc[cur.value] = cur.name;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
@ -187,7 +187,7 @@ const menuItems = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/MonitorManage",
|
key: "/safetyEval/container/MonitorManage",
|
||||||
label: "监督管理",
|
label: "机构执业监管",
|
||||||
icon: <SafetyCertificateOutlined />,
|
icon: <SafetyCertificateOutlined />,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|
@ -195,13 +195,13 @@ const menuItems = [
|
||||||
label: "资质保持监控",
|
label: "资质保持监控",
|
||||||
icon: <BarChartOutlined />,
|
icon: <BarChartOutlined />,
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/MonitorManage/RiskCenter",
|
key: "/safetyEval/container/MonitorManage/RiskCenter",
|
||||||
label: "风险预警中心",
|
label: "风险预警中心",
|
||||||
icon: <ExperimentOutlined />,
|
icon: <ExperimentOutlined />,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/SafetyEvalBusiness",
|
key: "/safetyEval/container/SafetyEvalBusiness",
|
||||||
label: "安评业务管理",
|
label: "安评业务管理",
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ const EvalProjectCreate = (props) => {
|
||||||
<Card title="客户所在地与打卡定位" style={{ marginBottom: 24 }}>
|
<Card title="客户所在地与打卡定位" style={{ marginBottom: 24 }}>
|
||||||
<Form.Item label="客户所在地" style={{ marginBottom: 16 }}>
|
<Form.Item label="客户所在地" style={{ marginBottom: 16 }}>
|
||||||
<Flex>
|
<Flex>
|
||||||
<Form.Item name="customerAddress" noStyle>
|
<Form.Item name="customerAddress" noStyle rules={[{ required: true, message: "请选择客户或打开地图定位" }]}>
|
||||||
<Input
|
<Input
|
||||||
placeholder="请选择客户或打开地图定位"
|
placeholder="请选择客户或打开地图定位"
|
||||||
disabled
|
disabled
|
||||||
|
|
@ -298,17 +298,17 @@ const EvalProjectCreate = (props) => {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Row gutter={24}>
|
<Row gutter={24}>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Form.Item name="longitude" label="经度">
|
<Form.Item name="longitude" label="经度" rules={[{ required: true, message: "请输入经度" }]}>
|
||||||
<Input placeholder="自动获取" disabled />
|
<Input placeholder="自动获取" disabled />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Form.Item name="latitude" label="纬度">
|
<Form.Item name="latitude" label="纬度" rules={[{ required: true, message: "请输入纬度" }]}>
|
||||||
<Input placeholder="自动获取" disabled />
|
<Input placeholder="自动获取" disabled />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
<Form.Item name="checkinRadiusMeters" label="打卡有效范围">
|
<Form.Item name="checkinRadiusMeters" label="打卡有效范围" rules={[{ required: true, message: "请选择打卡有效范围" }]}>
|
||||||
<Select placeholder="请选择" allowClear>
|
<Select placeholder="请选择" allowClear>
|
||||||
{CHECKIN_RADIUS_OPTIONS.map((opt) => (
|
{CHECKIN_RADIUS_OPTIONS.map((opt) => (
|
||||||
<Select.Option key={opt.value} value={opt.value}>
|
<Select.Option key={opt.value} value={opt.value}>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ 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";
|
||||||
import AttachmentUpload from "~/components/AttachmentUpload";
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
|
import {ROLE_DEFINITIONS_MAP} from '~/enumerate/constant'
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
|
|
@ -70,7 +72,16 @@ const NoticePanel = () => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const InspectionPanel = () => (
|
const InspectionPanel = ({ dataSource = [], evalProjectDetailData = {} }) => {
|
||||||
|
const calcDuration = (signIn, signOut) => {
|
||||||
|
if (!signIn || !signOut) return '-';
|
||||||
|
const start = new Date(signIn);
|
||||||
|
const end = new Date(signOut);
|
||||||
|
const diff = (end - start) / 60000;
|
||||||
|
if (diff <= 0) return '-';
|
||||||
|
return `${Math.floor(diff / 60)}h${Math.round(diff % 60)}m`;
|
||||||
|
};
|
||||||
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="pf-section-header">
|
<div className="pf-section-header">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -83,34 +94,34 @@ const InspectionPanel = () => (
|
||||||
|
|
||||||
<Card type="inner" size="small" title="人员现场打卡情况" style={{ marginBottom: 12 }}>
|
<Card type="inner" size="small" title="人员现场打卡情况" style={{ marginBottom: 12 }}>
|
||||||
<Table
|
<Table
|
||||||
dataSource={[
|
dataSource={dataSource}
|
||||||
{ name: "张建国", role: "项目负责人", face: "通过", gps: "正常", signIn: "08:52", signOut: "16:45", duration: "7h53m", photos: 12, sign: "已签字" },
|
|
||||||
{ name: "李明华", role: "报告编制人", face: "通过", gps: "正常", signIn: "08:55", signOut: "16:43", duration: "7h48m", photos: 9, sign: "已签字" },
|
|
||||||
{ name: "赵东升", role: "专业组员", face: "通过", gps: "正常", signIn: "08:57", signOut: "16:40", duration: "7h43m", photos: 7, sign: "已签字" },
|
|
||||||
]}
|
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "人员", dataIndex: "name" },
|
{ title: "人员", dataIndex: "personnelName" },
|
||||||
{ title: "项目角色", dataIndex: "role" },
|
{ title: "项目角色", dataIndex: "role", render: (v) => Array.isArray(v) ? v.map(item => ROLE_DEFINITIONS_MAP[item]).join('、') : v,ellipsis: true },
|
||||||
{ title: "人脸识别", dataIndex: "face", render: (v) => <Tag color="success">{v}</Tag> },
|
{ title: "人脸识别", dataIndex: "faceState", render: (v) => <Tag color={v === 1 ? "success" : "error"}>{v === 1 ? "通过" : "未通过"}</Tag> },
|
||||||
{ title: "GPS定位", dataIndex: "gps", render: (v) => <Tag color="success">{v}</Tag> },
|
{ title: "GPS定位", dataIndex: "gpsState", render: (v) => <Tag color={v === 1 ? "success" : "error"}>{v === 1 ? "正常" : "异常"}</Tag> },
|
||||||
{ title: "签到时间", dataIndex: "signIn" },
|
{ title: "签到时间", dataIndex: "singInTime" },
|
||||||
{ title: "签退时间", dataIndex: "signOut" },
|
{ title: "签退时间", dataIndex: "signOutTime" },
|
||||||
{ title: "在场时长", dataIndex: "duration" },
|
{ title: "在场时长", render: (_, r) => calcDuration(r.singInTime, r.signOutTime) },
|
||||||
{ title: "现场照片", dataIndex: "photos", render: (v) => <Button type="link" size="small">{v}张</Button> },
|
{ title: "现场照片", dataIndex: "sceneUrl", render: (v) => {
|
||||||
{ title: "本人签字", dataIndex: "sign", render: (v) => <Tag color="success">{v}</Tag> },
|
const count = v ? v.split(',').filter(Boolean).length : 0;
|
||||||
|
return <Button type="link" size="small">{count}张</Button>;
|
||||||
|
}},
|
||||||
|
{ title: "本人签字", dataIndex: "signatureUrl", render: (v) => <Tag color={v ? "success" : "default"}>{v ? "已签字" : "未签字"}</Tag> },
|
||||||
]}
|
]}
|
||||||
rowKey="name"
|
rowKey="id"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<div style={{ display: "flex", gap: 24, marginTop: 8, fontSize: 12 }}>
|
<div style={{ display: "flex", gap: 24, marginTop: 8, fontSize: 12 }}>
|
||||||
<span>打卡企业地址:重庆市渝北区化工园区东路18号</span>
|
<span>打卡企业地址:{evalProjectDetailData?.customerAddress || '-'}</span>
|
||||||
<span>允许打卡范围:企业地址周边500米</span>
|
<span>允许打卡范围:企业地址周边{evalProjectDetailData?.checkinRadiusMeters || '-'}米</span>
|
||||||
<span>签到日期:2026-07-15</span>
|
<span>签到日期:{dataSource?.[0]?.singInTime ? dayjs(dataSource?.[0]?.singInTime).format('YYYY-MM-DD') : '-'}</span>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const SimpleUploadPanel = ({ index, title, desc }) => (
|
const SimpleUploadPanel = ({ index, title, desc }) => (
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -124,34 +135,12 @@ const SimpleUploadPanel = ({ index, title, desc }) => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const STEP_PANELS = {
|
|
||||||
notice: () => <NoticePanel />,
|
|
||||||
inspection: () => <InspectionPanel />,
|
|
||||||
rectification: () => (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="03" title="整改通知单上传"
|
|
||||||
desc="本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
enterprise: () => (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="04" title="企业整改报告上传"
|
|
||||||
desc="企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
review: () => (
|
|
||||||
<SimpleUploadPanel
|
|
||||||
index="05" title="整改复查单上传"
|
|
||||||
desc="机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。"
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
const SurveyContent = (props) => {
|
const SurveyContent = (props) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [activeStage, setActiveStage] = useState("notice");
|
const [activeStage, setActiveStage] = useState("notice");
|
||||||
const [attachMap, setAttachMap] = useState({});
|
const [attachMap, setAttachMap] = useState({});
|
||||||
const { evalSurveyListLoading, evalSurveySaveAttachLoading } = props.safetyEvalBusiness;
|
const [surveyPersonnel, setSurveyPersonnel] = useState([]);
|
||||||
|
const { evalSurveyListLoading, evalSurveySaveAttachLoading, evalProjectDetailData } = props.safetyEvalBusiness;
|
||||||
const projectId = router.query?.id;
|
const projectId = router.query?.id;
|
||||||
const currentIdx = STAGES.findIndex((s) => s.key === activeStage);
|
const currentIdx = STAGES.findIndex((s) => s.key === activeStage);
|
||||||
const isFirst = currentIdx === 0;
|
const isFirst = currentIdx === 0;
|
||||||
|
|
@ -185,6 +174,16 @@ const SurveyContent = (props) => {
|
||||||
loadAttachments();
|
loadAttachments();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (projectId) {
|
||||||
|
props.evalSurveyPage({ projectId, size: 100 }).then((res) => {
|
||||||
|
if (res?.success) {
|
||||||
|
setSurveyPersonnel(res.data || []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [projectId]);
|
||||||
|
|
||||||
const goPrev = () => {
|
const goPrev = () => {
|
||||||
if (currentIdx > 0) setActiveStage(STAGES[currentIdx - 1].key);
|
if (currentIdx > 0) setActiveStage(STAGES[currentIdx - 1].key);
|
||||||
};
|
};
|
||||||
|
|
@ -226,7 +225,26 @@ const SurveyContent = (props) => {
|
||||||
items={STAGES.map((s) => ({ title: s.label }))}
|
items={STAGES.map((s) => ({ title: s.label }))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{STEP_PANELS[activeStage]()}
|
{activeStage === "notice" && <NoticePanel />}
|
||||||
|
{activeStage === "inspection" && <InspectionPanel dataSource={surveyPersonnel} evalProjectDetailData={evalProjectDetailData} />}
|
||||||
|
{activeStage === "rectification" && (
|
||||||
|
<SimpleUploadPanel
|
||||||
|
index="03" title="整改通知单上传"
|
||||||
|
desc="本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeStage === "enterprise" && (
|
||||||
|
<SimpleUploadPanel
|
||||||
|
index="04" title="企业整改报告上传"
|
||||||
|
desc="企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeStage === "review" && (
|
||||||
|
<SimpleUploadPanel
|
||||||
|
index="05" title="整改复查单上传"
|
||||||
|
desc="机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Form form={form} layout="vertical">
|
<Form form={form} layout="vertical">
|
||||||
{Object.entries(ATTACH_TYPE).map(([key, typeCode]) => (
|
{Object.entries(ATTACH_TYPE).map(([key, typeCode]) => (
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,11 @@ import {
|
||||||
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";
|
||||||
|
import {ROLE_DEFINITIONS} from '~/enumerate/constant'
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
const ROLE_DEFINITIONS = [
|
|
||||||
{ value: "MARKETING_BUSINESS_REP", name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" },
|
|
||||||
{ value: "TECHNICAL_LEAD", name: "技术负责人", unique: false, summary: "评估人员专业匹配与技术可行性,审核检查表并开展评价报告技术审核。" },
|
|
||||||
{ value: "PROCESS_CONTROL_LEAD", name: "过程控制负责人", unique: true, summary: "核查利益冲突、资质范围和人员配置,负责受控管理、程序合规审核及归档前校验。" },
|
|
||||||
{ value: "FINANCE_STAFF", name: "财务人员", unique: false, summary: "核算人工、费用、税金和利润等全成本,评估项目经济性及合同金额合理性。" },
|
|
||||||
{ value: "EVALUATION_AGENCY_HEAD", name: "评价机构负责人", unique: false, summary: "综合多方意见决定是否承接项目,并在全部审核通过后终审签发评价报告。" },
|
|
||||||
{ value: "EVALUATION_DEPT_MANAGER", name: "评价部经理", unique: false, summary: "签发项目组任命文件,审核组长资格、行业经验及成员专业配置。" },
|
|
||||||
{ value: "PROJECT_LEAD", name: "项目负责人(项目组组长)", unique: true, summary: "制定实施计划并组织启动、初勘、检查表、现场勘查、整改复查及报告编制。" },
|
|
||||||
{ value: "PROJECT_TEAM_MEMBERS", name: "项目组各专业组员", unique: false, summary: "按专业分工开展资料收集、检查表编制、现场检查、危险辨识和评价报告专业内容编写。" },
|
|
||||||
{ value: "INTERNAL_AUDITOR", name: "内审人", unique: false, summary: "审核报告初稿及修改结果,重点核查依据、危险辨识、单元划分、评价方法和结论。" },
|
|
||||||
{ value: "REPORT_COMPILER", name: "报告编制人", unique: false, summary: "整合各专业内容形成报告初稿,根据各级审核意见修改并整理全过程档案。" },
|
|
||||||
{ value: "ARCHIVES_ADMIN", name: "档案管理员", unique: false, summary: "办理档案交接、编号、分类、装订和入库,并按规定开展报告信息公开。" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const TeamContent = (props) => {
|
const TeamContent = (props) => {
|
||||||
const { safetyEvalBusiness, evalProjectMemberPage, evalProjectMemberSave } = props;
|
const { safetyEvalBusiness, evalProjectMemberPage, evalProjectMemberSave } = props;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue