feat
parent
aa37a77ebd
commit
dacae8af48
|
|
@ -11,7 +11,8 @@ module.exports = {
|
||||||
// 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095)
|
// 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095)
|
||||||
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
||||||
//API_HOST: "https://gbs-gateway.qhdsafety.com",
|
//API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||||
API_HOST: "http://192.168.0.150",
|
//API_HOST: "http://192.168.0.150",太浅
|
||||||
|
API_HOST: "http://192.168.0.152",
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
// 应用后端分支名称,部署上线需要
|
// 应用后端分支名称,部署上线需要
|
||||||
|
|
|
||||||
|
|
@ -76,3 +76,9 @@ export const queryQualMonitorCondition = declareRequest(
|
||||||
"Get > /safetyEval/qual-monitor/condition-detail",
|
"Get > /safetyEval/qual-monitor/condition-detail",
|
||||||
'qualMonitorCondition: {} | res.data || {}',
|
'qualMonitorCondition: {} | res.data || {}',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const queryQualMonitoringPageStatistics = declareRequest(
|
||||||
|
"qualReviewLoading",
|
||||||
|
"Get > /safetyEval/qual-filing/qualificationMonitoringPageStatistics",
|
||||||
|
"monitorStats: {} | res.data || {}",
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
|
||||||
|
export const queryRiskOverviewAction = declareRequest(
|
||||||
|
"riskOverviewLoading",
|
||||||
|
"Get > /safetyEval/regulator/risk-center/overview",
|
||||||
|
"overviewStats: [] | res.data.stats || [] & processGuide: '' | res.data.processGuide || ''",
|
||||||
|
);
|
||||||
|
|
@ -118,3 +118,17 @@ export const QUAL_MONITOR_STATUS_OPTIONS = [
|
||||||
{ value: "normal", label: "正常" },
|
{ value: "normal", label: "正常" },
|
||||||
{ value: "person_rate", label: "人员比例预警" },
|
{ value: "person_rate", label: "人员比例预警" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** 证书类型选项 */
|
||||||
|
export const CERT_TYPE_OPTIONS = [
|
||||||
|
{ value: "registered_safety_engineer", label: "注册安全工程师" },
|
||||||
|
{ value: "senior_engineer", label: "高工" },
|
||||||
|
{ value: "evaluator", label: "评价师" },
|
||||||
|
];
|
||||||
|
|
||||||
|
/** 证书类型 value → label 映射 */
|
||||||
|
export const CERT_TYPE_MAP = {
|
||||||
|
registered_safety_engineer: "注册安全工程师",
|
||||||
|
senior_engineer: "高工",
|
||||||
|
evaluator: "评价师",
|
||||||
|
};
|
||||||
|
|
@ -21,3 +21,4 @@ export const NS_QUAL_FILING = defineNamespace("qualFiling");
|
||||||
export const NS_QUAL_REVIEW = defineNamespace("qualReview");
|
export const NS_QUAL_REVIEW = defineNamespace("qualReview");
|
||||||
export const NS_QUAL_EXPERT = defineNamespace("qualExpert");
|
export const NS_QUAL_EXPERT = defineNamespace("qualExpert");
|
||||||
export const NS_DRIVER = defineNamespace("driver");
|
export const NS_DRIVER = defineNamespace("driver");
|
||||||
|
export const NS_RISK_CENTER = defineNamespace("riskCenter");
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { NS_STAFF_CERTIFICATE } from "~/enumerate/namespace";
|
||||||
import CertPreviewImg from "~/components/CertPreviewImg";
|
import CertPreviewImg from "~/components/CertPreviewImg";
|
||||||
import AttachmentUpload from "~/components/AttachmentUpload";
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
import { dateRangeRule } from "~/utils/validators";
|
import { dateRangeRule } from "~/utils/validators";
|
||||||
|
import { CERT_TYPE_OPTIONS, CERT_TYPE_MAP } from "~/enumerate/constant";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
|
|
@ -115,8 +116,8 @@ function StaffCertificatePage(props) {
|
||||||
<Table
|
<Table
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "证照名称", dataIndex: "certName" },
|
{ title: "证照名称", dataIndex: "certName" ,ellipsis:true},
|
||||||
{ title: "证书类型", dataIndex: "certTypeName" },
|
{ title: "证书类型", dataIndex: "certTypeCode", render: (v) => CERT_TYPE_MAP[v] || v },
|
||||||
{ title: "证书类别", dataIndex: "certCategoryName" },
|
{ title: "证书类别", dataIndex: "certCategoryName" },
|
||||||
{ title: "证书作业类别", dataIndex: "operationCategoryName" },
|
{ title: "证书作业类别", dataIndex: "operationCategoryName" },
|
||||||
{ title: "证书编号", dataIndex: "certNo" },
|
{ title: "证书编号", dataIndex: "certNo" },
|
||||||
|
|
@ -332,17 +333,10 @@ function CertModal({
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="certTypeCode"
|
name="certTypeCode"
|
||||||
label="证书类型编码"
|
label="证书类型"
|
||||||
rules={[{ max: 32, message: "证书类型编码不能超过32个字符" }]}
|
rules={[{ required: true, message: "请选择证书类型" }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入证书类型编码" maxLength={32} showCount />
|
<Select placeholder="请选择证书类型" options={CERT_TYPE_OPTIONS} />
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
name="certTypeName"
|
|
||||||
label="证书类型名称"
|
|
||||||
rules={[{ max: 50, message: "证书类型名称不能超过50个字符" }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="请输入证书类型名称" maxLength={50} showCount />
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="certCategoryCode"
|
name="certCategoryCode"
|
||||||
|
|
@ -435,8 +429,7 @@ function ViewModal({ open, currentId, staffCertificateInfo, onCancel }) {
|
||||||
>
|
>
|
||||||
<Descriptions bordered column={1} labelStyle={{ width: 160 }}>
|
<Descriptions bordered column={1} labelStyle={{ width: 160 }}>
|
||||||
<Descriptions.Item label="证照名称">{info.certName}</Descriptions.Item>
|
<Descriptions.Item label="证照名称">{info.certName}</Descriptions.Item>
|
||||||
<Descriptions.Item label="证书类型编码">{info.certTypeCode}</Descriptions.Item>
|
<Descriptions.Item label="证书类型">{CERT_TYPE_MAP[info.certTypeCode] || info.certTypeCode}</Descriptions.Item>
|
||||||
<Descriptions.Item label="证书类型名称">{info.certTypeName}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="证书类别编码">{info.certCategoryCode}</Descriptions.Item>
|
<Descriptions.Item label="证书类别编码">{info.certCategoryCode}</Descriptions.Item>
|
||||||
<Descriptions.Item label="证书类别名称">{info.certCategoryName}</Descriptions.Item>
|
<Descriptions.Item label="证书类别名称">{info.certCategoryName}</Descriptions.Item>
|
||||||
<Descriptions.Item label="证书作业类别编码">{info.operationCategoryCode}</Descriptions.Item>
|
<Descriptions.Item label="证书作业类别编码">{info.operationCategoryCode}</Descriptions.Item>
|
||||||
|
|
|
||||||
|
|
@ -108,26 +108,21 @@ function buildConditionDetails(record) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 统计卡片数据 */
|
|
||||||
function computeStats(list) {
|
|
||||||
return {
|
|
||||||
total: list.length,
|
|
||||||
normal: list.filter((i) => i.alertStatus === "normal").length,
|
|
||||||
warning: list.filter((i) => i.alertStatus === "person_rate").length,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const QualMonitor = (props) => {
|
const QualMonitor = (props) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [detailVisible, setDetailVisible] = useState(false);
|
const [detailVisible, setDetailVisible] = useState(false);
|
||||||
const [detailRecord, setDetailRecord] = useState(null);
|
const [detailRecord, setDetailRecord] = useState(null);
|
||||||
const [data, setData] = useState([]);
|
const [data, setData] = useState([]);
|
||||||
|
|
||||||
const { qualReview, queryQualMonitorPage, queryQualMonitorCondition } = props;
|
const { qualReview, queryQualMonitorPage, queryQualMonitorCondition, queryQualMonitoringPageStatistics } = props;
|
||||||
const { qualMonitorList, qualMonitorTotal, qualReviewLoading } =
|
const { qualMonitorList, qualMonitorTotal, qualReviewLoading, monitorStats = {} } =
|
||||||
qualReview || {};
|
qualReview || {};
|
||||||
|
|
||||||
const stats = computeStats(data);
|
const stats = {
|
||||||
|
total: monitorStats.orgInfoSum ?? 0,
|
||||||
|
normal: monitorStats.normalSum ?? 0,
|
||||||
|
warning: monitorStats.earlyWarningSum ?? 0,
|
||||||
|
};
|
||||||
|
|
||||||
/** model 数据回填时同步到本地 data */
|
/** model 数据回填时同步到本地 data */
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -145,10 +140,7 @@ const QualMonitor = (props) => {
|
||||||
/** 调用接口 */
|
/** 调用接口 */
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
const params = { ...router.query };
|
const params = { ...router.query };
|
||||||
if (params.keyword) {
|
|
||||||
params.unitName = params.keyword;
|
|
||||||
delete params.keyword;
|
|
||||||
}
|
|
||||||
queryQualMonitorPage(params);
|
queryQualMonitorPage(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -160,6 +152,7 @@ const QualMonitor = (props) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.setFieldsValue(router.query);
|
form.setFieldsValue(router.query);
|
||||||
handleSearch();
|
handleSearch();
|
||||||
|
queryQualMonitoringPageStatistics();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const openDetail = (record) => {
|
const openDetail = (record) => {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Button, Form, Table, Tag } from "antd";
|
import { Button, Form, Table, Tag } from "antd";
|
||||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
|
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
|
||||||
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
||||||
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
import { NS_RISK_CENTER } from "~/enumerate/namespace";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
@ -129,17 +131,24 @@ const MOCK_DATA = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** 统计卡片样式主题 */
|
||||||
|
const CARD_THEMES = [
|
||||||
|
{ bg: "#fee2e2", color: "#dc2626" },
|
||||||
|
{ bg: "#fef3c7", color: "#d97706" },
|
||||||
|
{ bg: "#dbeafe", color: "#2563eb" },
|
||||||
|
{ bg: "#d1fae5", color: "#059669" },
|
||||||
|
];
|
||||||
|
|
||||||
const RiskCenter = (props) => {
|
const RiskCenter = (props) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [data] = useState(MOCK_DATA);
|
const [data] = useState(MOCK_DATA);
|
||||||
|
|
||||||
/** 统计卡片数据 */
|
const { riskCenter, queryRiskOverviewAction } = props;
|
||||||
const stats = {
|
const { overviewStats = [], riskOverviewLoading } = riskCenter || {};
|
||||||
qualRisk: data.filter((i) => i.type === "qual").length,
|
|
||||||
projRisk: data.filter((i) => i.type === "proj").length,
|
useEffect(() => {
|
||||||
pendingFeedback: data.filter((i) => i.orgStatus === "submitted").length,
|
queryRiskOverviewAction();
|
||||||
todayClosed: data.filter((i) => i.stage === "closed").length,
|
}, []);
|
||||||
};
|
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
// 接口搜索
|
// 接口搜索
|
||||||
|
|
@ -232,70 +241,24 @@ const RiskCenter = (props) => {
|
||||||
<div className="risk-center">
|
<div className="risk-center">
|
||||||
{/* 统计卡片 */}
|
{/* 统计卡片 */}
|
||||||
<div className="stat-grid cols-4">
|
<div className="stat-grid cols-4">
|
||||||
<div className="stat-card">
|
{overviewStats.map((stat, idx) => {
|
||||||
|
const theme = CARD_THEMES[idx % CARD_THEMES.length];
|
||||||
|
return (
|
||||||
|
<div className="stat-card" key={idx}>
|
||||||
<div className="stat-info">
|
<div className="stat-info">
|
||||||
<div className="stat-label">资质预警</div>
|
<div className="stat-label">{stat.label}</div>
|
||||||
<div className="stat-value stat-value--high">
|
<div className="stat-value">{stat.value}</div>
|
||||||
{stats.qualRisk}
|
<div className="stat-hint">{stat.hint}</div>
|
||||||
</div>
|
|
||||||
<div className="stat-hint">
|
|
||||||
条件保持、人员比例、属地材料
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="stat-icon"
|
className="stat-icon"
|
||||||
style={{ background: "#fee2e2", color: "#dc2626" }}
|
style={{ background: theme.bg, color: theme.color }}
|
||||||
>
|
>
|
||||||
资
|
{stat.label.charAt(0)}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="stat-card">
|
|
||||||
<div className="stat-info">
|
|
||||||
<div className="stat-label">项目预警</div>
|
|
||||||
<div className="stat-value stat-value--mid">
|
|
||||||
{stats.projRisk}
|
|
||||||
</div>
|
|
||||||
<div className="stat-hint">
|
|
||||||
进度、人员、告知、勘查、质控
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="stat-icon"
|
|
||||||
style={{ background: "#fef3c7", color: "#d97706" }}
|
|
||||||
>
|
|
||||||
项
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="stat-card">
|
|
||||||
<div className="stat-info">
|
|
||||||
<div className="stat-label">待机构反馈</div>
|
|
||||||
<div className="stat-value stat-value--mid">
|
|
||||||
{stats.pendingFeedback}
|
|
||||||
</div>
|
|
||||||
<div className="stat-hint">整改说明或证明材料</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="stat-icon"
|
|
||||||
style={{ background: "#dbeafe", color: "#2563eb" }}
|
|
||||||
>
|
|
||||||
反
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="stat-card">
|
|
||||||
<div className="stat-info">
|
|
||||||
<div className="stat-label">今日闭环</div>
|
|
||||||
<div className="stat-value stat-value--ok">
|
|
||||||
{stats.todayClosed}
|
|
||||||
</div>
|
|
||||||
<div className="stat-hint">监管复核已完成</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="stat-icon"
|
|
||||||
style={{ background: "#d1fae5", color: "#059669" }}
|
|
||||||
>
|
|
||||||
结
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 项目预警规则提示 */}
|
{/* 项目预警规则提示 */}
|
||||||
|
|
@ -397,4 +360,7 @@ const RiskCenter = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AntdTableFuncControl(RiskCenter);
|
export default Connect(
|
||||||
|
[NS_RISK_CENTER],
|
||||||
|
true,
|
||||||
|
)(AntdTableFuncControl(RiskCenter));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue