dev_1.2
tangjie 2026-07-27 15:41:29 +08:00
parent 12b5d7b7a6
commit bbfb21730c
14 changed files with 686 additions and 59 deletions

View File

@ -0,0 +1,56 @@
{
"openapi": "3.0.1",
"info": { "title": "人员打卡信息查询", "version": "1.0.0" },
"paths": {
"/safetyEval/regulator/eval-project-monitor/survey-clock-in": {
"get": {
"summary": "人员打卡信息查询",
"tags": ["监管端-安评项目"],
"parameters": [
{ "name": "projectId", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/SingleResponseListRegulatorEvalSurveyClockInCO" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"SingleResponseListRegulatorEvalSurveyClockInCO": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"code": { "type": "string" },
"message": { "type": "string" },
"errMessage": { "type": "string" },
"data": {
"type": "array",
"items": { "$ref": "#/components/schemas/RegulatorEvalSurveyClockInCO" }
}
}
},
"RegulatorEvalSurveyClockInCO": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"userName": { "type": "string" },
"role": { "type": "string" },
"faceState": { "type": "integer" },
"gpsState": { "type": "integer" },
"singInTime": { "type": "string" },
"signOutTime": { "type": "string" },
"sceneUrl": { "type": "string" },
"signatureUrl": { "type": "string" }
}
}
}
}
}

View File

@ -0,0 +1,11 @@
export interface RegulatorEvalSurveyClockInCO {
id: number;
userName: string;
role: string;
faceState: number;
gpsState: number;
singInTime: string;
signOutTime: string;
sceneUrl: string;
signatureUrl: string;
}

View File

@ -0,0 +1,66 @@
{
"openapi": "3.0.1",
"info": { "title": "踏勘监管分页", "version": "1.0.0" },
"paths": {
"/safetyEval/regulator/eval-project-monitor/survey-page": {
"get": {
"summary": "项目踏勘监管分页",
"tags": ["监管端-安评项目"],
"parameters": [
{ "name": "current", "in": "query", "schema": { "type": "integer", "default": 1 } },
{ "name": "size", "in": "query", "schema": { "type": "integer", "default": 10 } },
{ "name": "startTime", "in": "query", "schema": { "type": "string" } },
{ "name": "endTime", "in": "query", "schema": { "type": "string" } },
{ "name": "projectNameOrNo", "in": "query", "schema": { "type": "string" } },
{ "name": "orgId", "in": "query", "schema": { "type": "integer" } },
{ "name": "clockInStatus", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/PageResponseRegulatorEvalProjectSurveyPageCO" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"PageResponseRegulatorEvalProjectSurveyPageCO": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"code": { "type": "string" },
"message": { "type": "string" },
"errMessage": { "type": "string" },
"data": {
"type": "array",
"items": { "$ref": "#/components/schemas/RegulatorEvalProjectSurveyPageCO" }
},
"total": { "type": "integer" }
}
},
"RegulatorEvalProjectSurveyPageCO": {
"type": "object",
"properties": {
"id": { "type": "string" },
"orgId": { "type": "string" },
"projectNo": { "type": "string" },
"projectName": { "type": "string" },
"orgName": { "type": "string" },
"expectedCount": { "type": "integer" },
"actualCount": { "type": "integer" },
"signInCount": { "type": "integer" },
"signOutCount": { "type": "integer" },
"faceCount": { "type": "integer" },
"scenePhotoCount": { "type": "integer" },
"notificationFileUrl": { "type": "string" }
}
}
}
}
}

View File

@ -0,0 +1,14 @@
export interface RegulatorEvalProjectSurveyPageCO {
id: string;
orgId: string;
projectNo: string;
projectName: string;
orgName: string;
expectedCount: number;
actualCount: number;
signInCount: number;
signOutCount: number;
faceCount: number;
scenePhotoCount: number;
notificationFileUrl: string;
}

View File

@ -0,0 +1,45 @@
{
"openapi": "3.0.1",
"info": { "title": "踏勘监管统计", "version": "1.0.0" },
"paths": {
"/safetyEval/regulator/eval-project-monitor/survey-stat": {
"get": {
"summary": "项目踏勘监管统计",
"tags": ["监管端-安评项目"],
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/SingleResponseRegulatorEvalProjectSurveyStatCO" }
}
}
}
}
}
}
},
"components": {
"schemas": {
"SingleResponseRegulatorEvalProjectSurveyStatCO": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"code": { "type": "string" },
"message": { "type": "string" },
"errMessage": { "type": "string" },
"data": { "$ref": "#/components/schemas/RegulatorEvalProjectSurveyStatCO" }
}
},
"RegulatorEvalProjectSurveyStatCO": {
"type": "object",
"properties": {
"notificationArchivedCount": { "type": "integer", "description": "告知书已归档数" },
"notificationAbnormalCount": { "type": "integer", "description": "告知异常数" },
"clockInNormalCount": { "type": "integer", "description": "人员打卡正常数" },
"clockInAbnormalCount": { "type": "integer", "description": "打卡异常数" }
}
}
}
}
}

View File

@ -0,0 +1,6 @@
export interface RegulatorEvalProjectSurveyStatCO {
notificationArchivedCount: number;
notificationAbnormalCount: number;
clockInNormalCount: number;
clockInAbnormalCount: number;
}

View File

@ -264,3 +264,22 @@ export const evalProjectMonitorPage = declareRequest(
"evalProjectMonitorPageLoading", "evalProjectMonitorPageLoading",
"Get > /safetyEval/regulator/eval-project-monitor/realtime-page", "Get > /safetyEval/regulator/eval-project-monitor/realtime-page",
); );
// ===== 监管端-项目踏勘监管 =====
export const evalSurveyMonitorStat = declareRequest(
"evalSurveyMonitorStatLoading",
"Get > /safetyEval/regulator/eval-project-monitor/survey-stat",
"evalSurveyMonitorStat: {} | res.data || {}",
);
export const evalSurveyMonitorPage = declareRequest(
"evalSurveyMonitorPageLoading",
"Get > /safetyEval/regulator/eval-project-monitor/survey-page",
);
export const evalSurveyClockIn = declareRequest(
"evalSurveyClockInLoading",
"Get > /safetyEval/regulator/eval-project-monitor/survey-clock-in",
"evalSurveyClockIn: [] | res.data || []",
);

View File

@ -411,6 +411,23 @@ export const MONITOR_WARING_STATUS_OPTIONS = [
{ label: "人员异常", value: "PERSONNEL_ABNORMAL" }, { label: "人员异常", value: "PERSONNEL_ABNORMAL" },
]; ];
/** 监管端-项目踏勘监管 - 打卡状态筛选选项 */
export const CLOCK_IN_STATUS_OPTIONS = [
{ label: "正常", value: "normal" },
{ label: "异常", value: "abnormal" },
];
export const PROJECT_TYPE_OPTIONS = [
{ label: "新建项目", value: "NEW" },
{ label: "续评项目", value: "RENEW" },
{ label: "变更项目", value: "CHANGE" },
];
export const PROJECT_TYPE_MAP= PROJECT_TYPE_OPTIONS.reduce((acc, cur) => {
acc[cur.value] = cur.label;
return acc;
}, {});
export const ROLE_DEFINITIONS = [ export const ROLE_DEFINITIONS = [
{ value: "MARKETING_BUSINESS_REP", name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" }, { value: "MARKETING_BUSINESS_REP", name: "市场部业务员", unique: false, summary: "获取项目基础信息,形成风险分析记录;风险通过后签订合同并下达任务通知单。" },

View File

@ -22,6 +22,7 @@ import {
CheckCircleOutlined, CheckCircleOutlined,
SyncOutlined, SyncOutlined,
BellOutlined, BellOutlined,
EnvironmentOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
const menuItems = [ const menuItems = [
@ -200,6 +201,11 @@ const menuItems = [
label: "安评项目实时监控", label: "安评项目实时监控",
icon: <FileTextOutlined />, icon: <FileTextOutlined />,
}, },
{
key: "/safetyEval/container/MonitorManage/SurveyMonitor",
label: "项目踏勘监管",
icon: <EnvironmentOutlined />,
},
], ],
}, },
{ {

View File

@ -15,18 +15,13 @@ 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 { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant"; import { EVAL_TYPE_MAP, ROLE_DEFINITIONS_MAP } from "~/enumerate/constant";
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP } from "~/enumerate/enterpriseOptions"; import { PROJECT_TYPE_MAP } from "~/enumerate/constant";
import "./index.less"; import "./index.less";
const { router } = tools; const { router } = tools;
const PROJECT_TYPE_MAP = {
NEW: "新建项目",
RENEW: "续评项目",
CHANGE: "变更项目",
};
const YES_NO_MAP = { 1: "是", 2: "否" };
const ATTACH_TYPE_LABELS = { const ATTACH_TYPE_LABELS = {
PRACTICE_NOTIFICATION: "从业告知书", PRACTICE_NOTIFICATION: "从业告知书",
@ -166,8 +161,36 @@ const TeamPanel = ({ data, loading }) => {
ellipsis: true, ellipsis: true,
}, },
]; ];
let leader=null;
let processLeader=null;
data.forEach((item) => {
if (item.role.includes('PROJECT_LEAD')) {
leader = item.personnelName;
}
if (item.role.includes('PROCESS_CONTROL_LEAD')) {
processLeader = item.personnelName;
}
});
return <>
<div className="epm-detail-band">
<div className="epm-detail-band-item">
<span>项目组人数</span>
<strong>
{data.length || 0}
</strong>
</div>
<div className="epm-detail-band-item">
<span>项目负责人</span>
<strong>{leader || "-"}</strong>
</div>
<div className="epm-detail-band-item">
<span>过程控制负责人</span>
<strong>
{processLeader || "-"}
</strong>
</div>
return ( </div>
<Table <Table
dataSource={data} dataSource={data}
columns={columns} columns={columns}
@ -176,7 +199,7 @@ const TeamPanel = ({ data, loading }) => {
size="small" size="small"
scroll={{ x: 800 }} scroll={{ x: 800 }}
/> />
); </>
}; };
// ===== 踏勘情况面板 ===== // ===== 踏勘情况面板 =====
@ -315,7 +338,7 @@ const EvalProjectMonitorDetail = (props) => {
const [teamMembers, setTeamMembers] = useState([]); const [teamMembers, setTeamMembers] = useState([]);
const [surveyPersonnel, setSurveyPersonnel] = useState([]); const [surveyPersonnel, setSurveyPersonnel] = useState([]);
const [surveyAttachments, setSurveyAttachments] = useState({}); const [surveyAttachments, setSurveyAttachments] = useState({});
const [activeKey, setActiveKey] = useState("contract"); const [activeKey, setActiveKey] = useState("BUSINESS_CONTRACT");
const fetchContract = async () => { const fetchContract = async () => {
if (!projectId) return; if (!projectId) return;
@ -360,6 +383,24 @@ const EvalProjectMonitorDetail = (props) => {
fetchSurvey(); fetchSurvey();
}, []); }, []);
const projectNode = JSON.parse(evalProjectDetailData?.projectNode || "[]") || [];
const nodeMap = {};
projectNode.forEach((n) => {
nodeMap[n.type] = n;
});
const renderTabLabel = (label, nodeType) => {
const done = nodeMap[nodeType]?.state === 1;
return (
<span>
{label}
<Tag color={done ? "success" : "default"} style={{ marginLeft: 6 }}>
{done ? "已完成" : "待办理"}
</Tag>
</span>
);
};
const projectInfo = ( const projectInfo = (
<div className="epm-detail-band"> <div className="epm-detail-band">
<div className="epm-detail-band-item"> <div className="epm-detail-band-item">
@ -377,12 +418,16 @@ const EvalProjectMonitorDetail = (props) => {
<div className="epm-detail-band-item"> <div className="epm-detail-band-item">
<span>评价机构</span> <span>评价机构</span>
<strong> <strong>
{contractData?.orgName || evalProjectDetailData?.orgName || "-"} {contractData?.orgName || "-"}
</strong> </strong>
</div> </div>
<div className="epm-detail-band-item"> <div className="epm-detail-band-item">
<span>项目负责人</span> <span>项目负责人</span>
<strong>{evalProjectDetailData?.leaderName || "-"}</strong> <strong>{evalProjectDetailData?.projectLeaderName || "-"}</strong>
</div>
<div className="epm-detail-band-item">
<span>总体状态</span>
<strong>{projectNode.filter((item) => item.state === 1).length}/{projectNode.length}</strong>
</div> </div>
</div> </div>
); );
@ -395,20 +440,20 @@ const EvalProjectMonitorDetail = (props) => {
onChange={setActiveKey} onChange={setActiveKey}
items={[ items={[
{ {
key: "contract", key: "BUSINESS_CONTRACT",
label: "项目合同", label: renderTabLabel("项目合同", "BUSINESS_CONTRACT"),
children: ( children: (
<ContractPanel data={contractData} loading={contractLoading} /> <ContractPanel data={contractData} loading={contractLoading} />
), ),
}, },
{ {
key: "team", key: "PROJECT_GROUP",
label: "项目组人员", label: renderTabLabel("项目组人员", "PROJECT_GROUP"),
children: <TeamPanel data={teamMembers} loading={memberLoading} />, children: <TeamPanel data={teamMembers} loading={memberLoading} />,
}, },
{ {
key: "survey", key: "SITE_SURVEY",
label: "踏勘情况", label: renderTabLabel("踏勘情况", "SITE_SURVEY"),
children: ( children: (
<SurveyPanel <SurveyPanel
personnel={surveyPersonnel} personnel={surveyPersonnel}

View File

@ -0,0 +1,354 @@
import React, { useState, useEffect } from "react";
import {
Row,
Col,
Card,
Statistic,
Table,
Tag,
Button,
Form,
Modal,
Space,
Typography,
} from "antd";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
import { tools } from "@cqsjjb/jjb-common-lib";
import {
CLOCK_IN_STATUS_OPTIONS,
ROLE_DEFINITIONS_MAP,
} from "~/enumerate/constant";
import "./index.less";
const { router } = tools;
const STAT_ITEMS = [
{ key: "notificationArchivedCount", title: "告知书已归档", color: "#1677ff" },
{ key: "clockInNormalCount", title: "人员打卡正常", color: "#52c41a" },
{ key: "notificationAbnormalCount", title: "告知异常", color: "#faad14" },
{ key: "clockInAbnormalCount", title: "打卡异常", color: "#ff4d4f" },
];
/** 解析文件 JSON */
const parseFileList = (raw) => {
if (!raw) return [];
try {
const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
};
/** 根据打卡数据计算状态 */
const getClockInStatus = (record) => {
if (record.actualCount < record.expectedCount) {
return { color: "error", text: "人员未到齐" };
}
if (
record.signInCount < record.actualCount ||
record.signOutCount < record.actualCount
) {
return { color: "warning", text: "异常" };
}
return { color: "success", text: "正常" };
};
const SurveyMonitor = (props) => {
const [searchForm] = Form.useForm();
const [dataSource, setDataSource] = useState([]);
const [total, setTotal] = useState(0);
const [clockInModal, setClockInModal] = useState(false);
const [clockInData, setClockInData] = useState([]);
const [clockInProjectName, setClockInProjectName] = useState("");
const { safetyEvalBusiness, evalSurveyMonitorStat, evalSurveyMonitorPage,
evalSurveyClockIn } = props;
const { evalSurveyMonitorStatLoading, evalSurveyMonitorPageLoading,
evalSurveyClockInLoading } = safetyEvalBusiness || {};
const statData = safetyEvalBusiness?.evalSurveyMonitorStat || {};
const getStat = () => {
evalSurveyMonitorStat();
};
const getData = async () => {
const params = {
...router.query,
current: router.query.current || 1,
size: router.query.size || 10,
};
const res = await evalSurveyMonitorPage(params);
if (res?.success !== false) {
setDataSource(res?.data || []);
setTotal(res?.total || 0);
}
};
useEffect(() => {
searchForm.setFieldsValue({
...router.query,
dateRange:
router.query.startTime && router.query.endTime
? [router.query.startTime, router.query.endTime]
: undefined,
});
getStat();
getData();
}, []);
const handleSearch = (values) => {
const { dateRange, ...rest } = values;
router.query = {
...rest,
startTime: dateRange?.[0]?.format?.("YYYY-MM-DD") || undefined,
endTime: dateRange?.[1]?.format?.("YYYY-MM-DD") || undefined,
current: 1,
size: 10,
};
getData();
};
const handleReset = (values) => {
searchForm.resetFields();
router.query = { ...values, current: 1, size: 10 };
getData();
};
const handlePageChange = (pagination) => {
router.query = {
...router.query,
current: pagination.current,
size: pagination.pageSize,
};
getData();
};
const handleViewClockIn = async (record) => {
setClockInProjectName(record.projectName);
setClockInModal(true);
const res = await evalSurveyClockIn({ projectId: record.id });
if (res?.success !== false) {
setClockInData(res?.data || []);
}
};
const handleViewNotice = (record) => {
const files = parseFileList(record.notificationFileUrl);
if (files.length > 0 && files[0].url) {
window.open(files[0].url, "_blank");
}
};
const clockInColumns = [
{ title: "人员", dataIndex: "userName", width: 100 },
{
title: "项目角色",
dataIndex: "role",
width: 160,
ellipsis: true,
render: (v) =>
Array.isArray(v)
? v.map((r) => ROLE_DEFINITIONS_MAP[r] || r).join("、")
: v || "-",
},
{
title: "人脸识别",
dataIndex: "faceState",
width: 90,
render: (v) => (
<Tag color={v === 1 ? "success" : "error"}>
{v === 1 ? "通过" : "未通过"}
</Tag>
),
},
{
title: "GPS定位",
dataIndex: "gpsState",
width: 90,
render: (v) => (
<Tag color={v === 1 ? "success" : "error"}>
{v === 1 ? "正常" : "异常"}
</Tag>
),
},
{ title: "签到时间", dataIndex: "singInTime", width: 160 },
{ title: "签退时间", dataIndex: "signOutTime", width: 160 },
{
title: "现场照片",
dataIndex: "sceneUrl",
width: 80,
render: (v) => {
const count = v ? v.split(",").filter(Boolean).length : 0;
return count > 0 ? `${count}` : "-";
},
},
{
title: "本人签字",
dataIndex: "signatureUrl",
width: 90,
render: (v) => (
<Tag color={v ? "success" : "default"}>
{v ? "已签字" : "未签字"}
</Tag>
),
},
];
const columns = [
{ title: "项目编号", dataIndex: "projectNo", width: 140 },
{ title: "项目名称", dataIndex: "projectName", ellipsis: true, width: 220 },
{ title: "评价机构", dataIndex: "orgName", ellipsis: true, width: 200 },
{
title: "告知书状态",
dataIndex: "notificationFileUrl",
width: 120,
render: (v) => {
const files = parseFileList(v);
return files.length > 0 ? (
<Tag color="success">已归档</Tag>
) : (
<Tag color="warning">待上传</Tag>
);
},
},
{
title: "应到/实到",
width: 100,
render: (_, r) => `${r.expectedCount} / ${r.actualCount}`,
},
{
title: "签到/签退",
width: 100,
render: (_, r) => `${r.signInCount} / ${r.signOutCount}`,
},
{
title: "现场照片",
dataIndex: "scenePhotoCount",
width: 90,
render: (v) => (v ? `${v}` : "-"),
},
{
title: "打卡状态",
width: 100,
render: (_, r) => {
const status = getClockInStatus(r);
return <Tag color={status.color}>{status.text}</Tag>;
},
},
{
title: "操作",
width: 160,
fixed: "right",
render: (_, record) => (
<Space size={4}>
<Button
type="link"
size="small"
disabled={!parseFileList(record.notificationFileUrl).length}
onClick={() => handleViewNotice(record)}
>
告知书
</Button>
<Button type="link" size="small" onClick={() => handleViewClockIn(record)}>
人员打卡
</Button>
</Space>
),
},
];
return (
<PageLayout title="项目踏勘监管">
<Row gutter={16} className="sm-stat-row">
{STAT_ITEMS.map((item) => (
<Col span={6} key={item.key}>
<Card size="small">
<Statistic
title={item.title}
value={statData[item.key] ?? "-"}
valueStyle={{ color: item.color }}
/>
</Card>
</Col>
))}
</Row>
<SearchForm
form={searchForm}
loading={false}
style={{ marginBottom: 16 }}
formLine={[
<Form.Item key="projectNameOrNo" name="projectNameOrNo">
<ControlWrapper.Input
label="项目名称/编号"
placeholder="请输入"
allowClear
/>
</Form.Item>,
<Form.Item key="dateRange" name="dateRange">
<ControlWrapper.DatePicker.RangePicker
label="踏勘日期"
style={{ width: "100%" }}
/>
</Form.Item>,
<Form.Item key="clockInStatus" name="clockInStatus">
<ControlWrapper.Select
label="打卡状态"
placeholder="全部"
allowClear
options={CLOCK_IN_STATUS_OPTIONS}
/>
</Form.Item>,
]}
onFinish={handleSearch}
onReset={handleReset}
/>
<Table
rowKey="id"
columns={columns}
dataSource={dataSource}
loading={evalSurveyMonitorPageLoading}
scroll={{ y: props.scrollY, x: 1300 }}
pagination={{
total,
current: Number(router.query.current) || 1,
pageSize: Number(router.query.size) || 10,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (t) => `${t}`,
}}
onChange={handlePageChange}
/>
<Modal
title={`人员打卡详情 - ${clockInProjectName}`}
open={clockInModal}
onCancel={() => setClockInModal(false)}
footer={null}
width={1000}
>
<Table
dataSource={clockInData}
columns={clockInColumns}
rowKey="id"
pagination={false}
size="small"
loading={evalSurveyClockInLoading}
scroll={{ x: 900 }}
/>
</Modal>
</PageLayout>
);
};
export default Connect(
[NS_SAFETY_EVAL_BUSINESS],
true,
)(AntdTableFuncControl(SurveyMonitor));

View File

@ -0,0 +1,3 @@
.sm-stat-row {
margin-bottom: 16px;
}

View File

@ -15,6 +15,7 @@ import {
Spin, Spin,
} from "antd"; } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import {PROJECT_TYPE_OPTIONS ,EVAL_TYPE_OPTIONS} from '~/enumerate/constant';
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 { district } from "~/enumerate/constant"; import { district } from "~/enumerate/constant";
@ -25,17 +26,9 @@ import AttachmentUpload from "~/components/AttachmentUpload";
const { router } = tools; const { router } = tools;
const { TextArea } = Input; const { TextArea } = Input;
const PROJECT_TYPE_OPTIONS = [
{ label: "新建项目", value: "NEW" },
{ label: "续评项目", value: "RENEW" },
{ label: "变更项目", value: "CHANGE" },
];
const EVAL_TYPE_OPTIONS = [
{ label: "安全预评价", value: "PRE" },
{ label: "安全验收评价", value: "ACCEPT" },
{ label: "安全现状评价", value: "STATUS" },
];
const YES_NO_OPTIONS = [ const YES_NO_OPTIONS = [
{ label: "是", value: 1 }, { label: "是", value: 1 },

View File

@ -12,21 +12,13 @@ import dayjs from "dayjs";
const { router } = tools; const { router } = tools;
const STAGES = [ const STAGES = [
{ key: "notice", index: "01", label: "从业告知" }, { key: "PRACTICE_NOTIFICATION", index: "01", label: "从业告知" },
{ key: "inspection", index: "02", label: "现场勘查" }, { key: "SITE_INSPECTION_FORM", index: "02", label: "现场勘查" },
{ key: "rectification", index: "03", label: "整改通知" }, { key: "RECTIFICATION_NOTICE", index: "03", label: "整改通知" },
{ key: "enterprise", index: "04", label: "企业整改" }, { key: "ENTERPRISE_RECTIFICATION", index: "04", label: "企业整改" },
{ key: "review", index: "05", label: "整改复查" }, { key: "RECTIFICATION_REVIEW", index: "05", label: "整改复查" },
]; ];
const ATTACH_TYPE = {
notice: "PRACTICE_NOTIFICATION",
inspection: "SITE_INSPECTION_FORM",
rectification: "RECTIFICATION_NOTICE",
enterprise: "ENTERPRISE_RECTIFICATION",
review: "RECTIFICATION_REVIEW",
};
const downloadTemplate = async () => { const downloadTemplate = async () => {
try { try {
const res = await fetch("https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/6a608cb30dc53ed98d0b13ae.pdf"); const res = await fetch("https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/6a608cb30dc53ed98d0b13ae.pdf");
@ -137,7 +129,7 @@ const SimpleUploadPanel = ({ index, 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("PRACTICE_NOTIFICATION");
const [attachMap, setAttachMap] = useState({}); const [attachMap, setAttachMap] = useState({});
const [surveyPersonnel, setSurveyPersonnel] = useState([]); const [surveyPersonnel, setSurveyPersonnel] = useState([]);
const { evalSurveyListLoading, evalSurveySaveAttachLoading, evalProjectDetailData } = props.safetyEvalBusiness; const { evalSurveyListLoading, evalSurveySaveAttachLoading, evalProjectDetailData } = props.safetyEvalBusiness;
@ -163,8 +155,8 @@ const SurveyContent = (props) => {
setAttachMap(map); setAttachMap(map);
// 回填所有步骤的附件到表单 // 回填所有步骤的附件到表单
const values = {}; const values = {};
Object.entries(ATTACH_TYPE).forEach(([, typeCode]) => { STAGES.forEach((s) => {
values[typeCode] = map[typeCode] || []; values[s.key] = map[s.key] || [];
}); });
form.setFieldsValue(values); form.setFieldsValue(values);
} }
@ -195,17 +187,17 @@ const SurveyContent = (props) => {
const handleSave = async () => { const handleSave = async () => {
const values = form.getFieldsValue(); const values = form.getFieldsValue();
const payload = []; const payload = [];
for (const [key, typeCode] of Object.entries(ATTACH_TYPE)) { for (const s of STAGES) {
const fileList = values[typeCode] || []; const fileList = values[s.key] || [];
const validFiles = fileList.filter((f) => f.status === "done" && f.url); const validFiles = fileList.filter((f) => f.status === "done" && f.url);
if (validFiles.length === 0) { if (validFiles.length === 0) {
setActiveStage(key); setActiveStage(s.key);
message.warning(`请先在"${STAGES.find((s) => s.key === key).label}"步骤上传附件`); message.warning(`请先在"${s.label}"步骤上传附件`);
return; return;
} }
payload.push({ payload.push({
projectId, projectId,
attachTypeCode: typeCode, attachTypeCode: s.key,
fileUrl: JSON.stringify(fileList), fileUrl: JSON.stringify(fileList),
}); });
} }
@ -225,21 +217,21 @@ const SurveyContent = (props) => {
items={STAGES.map((s) => ({ title: s.label }))} items={STAGES.map((s) => ({ title: s.label }))}
/> />
{activeStage === "notice" && <NoticePanel />} {activeStage === "PRACTICE_NOTIFICATION" && <NoticePanel />}
{activeStage === "inspection" && <InspectionPanel dataSource={surveyPersonnel} evalProjectDetailData={evalProjectDetailData} />} {activeStage === "SITE_INSPECTION_FORM" && <InspectionPanel dataSource={surveyPersonnel} evalProjectDetailData={evalProjectDetailData} />}
{activeStage === "rectification" && ( {activeStage === "RECTIFICATION_NOTICE" && (
<SimpleUploadPanel <SimpleUploadPanel
index="03" title="整改通知单上传" index="03" title="整改通知单上传"
desc="本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。" desc="本节点不在线编制整改通知,只归档机构已出具的《整改通知单》文件;上传成功即完成,后续可替换修改。"
/> />
)} )}
{activeStage === "enterprise" && ( {activeStage === "ENTERPRISE_RECTIFICATION" && (
<SimpleUploadPanel <SimpleUploadPanel
index="04" title="企业整改报告上传" index="04" title="企业整改报告上传"
desc="企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。" desc="企业线下提交《整改报告》后,由机构人员上传归档;本系统不提供企业在线提交和逐项整改流程。"
/> />
)} )}
{activeStage === "review" && ( {activeStage === "RECTIFICATION_REVIEW" && (
<SimpleUploadPanel <SimpleUploadPanel
index="05" title="整改复查单上传" index="05" title="整改复查单上传"
desc="机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。" desc="机构人员现场复查后,将经双方签字确认的《整改复查单》上传归档;上传后本节点自动标记完成。"
@ -247,10 +239,10 @@ const SurveyContent = (props) => {
)} )}
<Form form={form} layout="vertical"> <Form form={form} layout="vertical">
{Object.entries(ATTACH_TYPE).map(([key, typeCode]) => ( {STAGES.map((s) => (
<div key={key} style={{ display: key === activeStage ? "block" : "none" }}> <div key={s.key} style={{ display: s.key === activeStage ? "block" : "none" }}>
<AttachmentUpload <AttachmentUpload
name={typeCode} name={s.key}
label="上传附件" label="上传附件"
maxCount={10} maxCount={10}
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xls,.xlsx" accept=".pdf,.doc,.docx,.jpg,.jpeg,.png,.xls,.xlsx"