feat
parent
aa37a77ebd
commit
dacae8af48
|
|
@ -11,7 +11,8 @@ module.exports = {
|
|||
// 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095)
|
||||
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
||||
//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: {
|
||||
// 应用后端分支名称,部署上线需要
|
||||
|
|
|
|||
|
|
@ -75,4 +75,10 @@ export const queryQualMonitorCondition = declareRequest(
|
|||
"qualReviewLoading",
|
||||
"Get > /safetyEval/qual-monitor/condition-detail",
|
||||
'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 || ''",
|
||||
);
|
||||
|
|
@ -117,4 +117,18 @@ export const QUAL_MONITOR_CONDITION_ITEMS = [
|
|||
export const QUAL_MONITOR_STATUS_OPTIONS = [
|
||||
{ value: "normal", 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_EXPERT = defineNamespace("qualExpert");
|
||||
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 AttachmentUpload from "~/components/AttachmentUpload";
|
||||
import { dateRangeRule } from "~/utils/validators";
|
||||
import { CERT_TYPE_OPTIONS, CERT_TYPE_MAP } from "~/enumerate/constant";
|
||||
|
||||
const { router } = tools;
|
||||
|
||||
|
|
@ -115,8 +116,8 @@ function StaffCertificatePage(props) {
|
|||
<Table
|
||||
rowKey="id"
|
||||
columns={[
|
||||
{ title: "证照名称", dataIndex: "certName" },
|
||||
{ title: "证书类型", dataIndex: "certTypeName" },
|
||||
{ title: "证照名称", dataIndex: "certName" ,ellipsis:true},
|
||||
{ title: "证书类型", dataIndex: "certTypeCode", render: (v) => CERT_TYPE_MAP[v] || v },
|
||||
{ title: "证书类别", dataIndex: "certCategoryName" },
|
||||
{ title: "证书作业类别", dataIndex: "operationCategoryName" },
|
||||
{ title: "证书编号", dataIndex: "certNo" },
|
||||
|
|
@ -332,17 +333,10 @@ function CertModal({
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
name="certTypeCode"
|
||||
label="证书类型编码"
|
||||
rules={[{ max: 32, message: "证书类型编码不能超过32个字符" }]}
|
||||
label="证书类型"
|
||||
rules={[{ required: true, message: "请选择证书类型" }]}
|
||||
>
|
||||
<Input placeholder="请输入证书类型编码" maxLength={32} showCount />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="certTypeName"
|
||||
label="证书类型名称"
|
||||
rules={[{ max: 50, message: "证书类型名称不能超过50个字符" }]}
|
||||
>
|
||||
<Input placeholder="请输入证书类型名称" maxLength={50} showCount />
|
||||
<Select placeholder="请选择证书类型" options={CERT_TYPE_OPTIONS} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="certCategoryCode"
|
||||
|
|
@ -435,8 +429,7 @@ function ViewModal({ open, currentId, staffCertificateInfo, onCancel }) {
|
|||
>
|
||||
<Descriptions bordered column={1} labelStyle={{ width: 160 }}>
|
||||
<Descriptions.Item label="证照名称">{info.certName}</Descriptions.Item>
|
||||
<Descriptions.Item label="证书类型编码">{info.certTypeCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="证书类型名称">{info.certTypeName}</Descriptions.Item>
|
||||
<Descriptions.Item label="证书类型">{CERT_TYPE_MAP[info.certTypeCode] || info.certTypeCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="证书类别编码">{info.certCategoryCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="证书类别名称">{info.certCategoryName}</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 [form] = Form.useForm();
|
||||
const [detailVisible, setDetailVisible] = useState(false);
|
||||
const [detailRecord, setDetailRecord] = useState(null);
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
const { qualReview, queryQualMonitorPage, queryQualMonitorCondition } = props;
|
||||
const { qualMonitorList, qualMonitorTotal, qualReviewLoading } =
|
||||
const { qualReview, queryQualMonitorPage, queryQualMonitorCondition, queryQualMonitoringPageStatistics } = props;
|
||||
const { qualMonitorList, qualMonitorTotal, qualReviewLoading, monitorStats = {} } =
|
||||
qualReview || {};
|
||||
|
||||
const stats = computeStats(data);
|
||||
const stats = {
|
||||
total: monitorStats.orgInfoSum ?? 0,
|
||||
normal: monitorStats.normalSum ?? 0,
|
||||
warning: monitorStats.earlyWarningSum ?? 0,
|
||||
};
|
||||
|
||||
/** model 数据回填时同步到本地 data */
|
||||
useEffect(() => {
|
||||
|
|
@ -145,10 +140,7 @@ const QualMonitor = (props) => {
|
|||
/** 调用接口 */
|
||||
const handleSearch = () => {
|
||||
const params = { ...router.query };
|
||||
if (params.keyword) {
|
||||
params.unitName = params.keyword;
|
||||
delete params.keyword;
|
||||
}
|
||||
|
||||
queryQualMonitorPage(params);
|
||||
};
|
||||
|
||||
|
|
@ -160,6 +152,7 @@ const QualMonitor = (props) => {
|
|||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
handleSearch();
|
||||
queryQualMonitoringPageStatistics();
|
||||
}, []);
|
||||
|
||||
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 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 { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
import { NS_RISK_CENTER } from "~/enumerate/namespace";
|
||||
import "./index.less";
|
||||
|
||||
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 [form] = Form.useForm();
|
||||
const [data] = useState(MOCK_DATA);
|
||||
|
||||
/** 统计卡片数据 */
|
||||
const stats = {
|
||||
qualRisk: data.filter((i) => i.type === "qual").length,
|
||||
projRisk: data.filter((i) => i.type === "proj").length,
|
||||
pendingFeedback: data.filter((i) => i.orgStatus === "submitted").length,
|
||||
todayClosed: data.filter((i) => i.stage === "closed").length,
|
||||
};
|
||||
const { riskCenter, queryRiskOverviewAction } = props;
|
||||
const { overviewStats = [], riskOverviewLoading } = riskCenter || {};
|
||||
|
||||
useEffect(() => {
|
||||
queryRiskOverviewAction();
|
||||
}, []);
|
||||
|
||||
const handleSearch = () => {
|
||||
// 接口搜索
|
||||
|
|
@ -232,70 +241,24 @@ const RiskCenter = (props) => {
|
|||
<div className="risk-center">
|
||||
{/* 统计卡片 */}
|
||||
<div className="stat-grid cols-4">
|
||||
<div className="stat-card">
|
||||
<div className="stat-info">
|
||||
<div className="stat-label">资质预警</div>
|
||||
<div className="stat-value stat-value--high">
|
||||
{stats.qualRisk}
|
||||
{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-label">{stat.label}</div>
|
||||
<div className="stat-value">{stat.value}</div>
|
||||
<div className="stat-hint">{stat.hint}</div>
|
||||
</div>
|
||||
<div
|
||||
className="stat-icon"
|
||||
style={{ background: theme.bg, color: theme.color }}
|
||||
>
|
||||
{stat.label.charAt(0)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="stat-hint">
|
||||
条件保持、人员比例、属地材料
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="stat-icon"
|
||||
style={{ background: "#fee2e2", color: "#dc2626" }}
|
||||
>
|
||||
资
|
||||
</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>
|
||||
|
||||
{/* 项目预警规则提示 */}
|
||||
|
|
@ -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