dev_1.0.1
tangjie 2026-07-14 14:53:52 +08:00
parent fb650b07cc
commit 425dfde6c9
4 changed files with 365 additions and 411 deletions

View File

@ -67,7 +67,7 @@ export const modifyFilingMaterial = declareRequest(
export const queryQualMonitorPage = declareRequest(
"qualReviewLoading",
"Get > /safetyEval/qual-monitor/page",
"Get > /safetyEval/qual-filing/qualificationMonitoringPage",
'qualMonitorList: [] | res.data || [] & qualMonitorTotal: 0 | res.total || 0',
);

View File

@ -63,10 +63,8 @@ export const CHANGE_STATUS_MAP = {
/** 资质保持监控状态 */
export const QUAL_MONITOR_STATUS_MAP = {
normal: { label: "保持正常", color: "success" },
person_warning: { label: "人员比例预警", color: "warning" },
focus_warning: { label: "重点预警", color: "error" },
area_pending: { label: "属地待核验", color: "warning" },
normal: { label: "正常", color: "success" },
person_rate: { label: "人员比例预警", color: "warning" },
};
/** 性别 */
@ -99,3 +97,24 @@ export const LEGAL_STATUS_STYLE = {
WARN: { icon: "⚠️", borderColor: "#d97706", bg: "#fffbeb" },
NOT_PASS: { icon: "❌", borderColor: "#dc2626", bg: "#fef2f2" },
};
/** 资质保持监控-条件检查项模板 */
export const QUAL_MONITOR_CONDITION_ITEMS = [
{ key: "legalPerson", label: "独立法人资格" },
{ key: "fixedAsset", label: "固定资产" },
{ key: "workplace", label: "工作场所" },
{ key: "equipment", label: "设施设备软件" },
{ key: "staffCount", label: "专职技术人员数量" },
{ key: "staffRatio", label: "人员比例" },
{ key: "leader", label: "负责人配备" },
{ key: "system", label: "制度与过程控制体系" },
{ key: "website", label: "承诺书/网站/报告查询" },
{ key: "credit", label: "三年重大违法失信记录" },
{ key: "area", label: "属地满足情况" },
];
/** 资质保持监控-预警状态筛选选项 */
export const QUAL_MONITOR_STATUS_OPTIONS = [
{ value: "normal", label: "正常" },
{ value: "person_rate", label: "人员比例预警" },
];

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { Button, Form, Select, Table, Tag, Modal } from "antd";
import { Button, Form, Table, Tag, Modal } from "antd";
import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
@ -8,228 +8,112 @@ import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import { tools } from "@cqsjjb/jjb-common-lib";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { NS_QUAL_REVIEW } from "~/enumerate/namespace";
import { QUAL_MONITOR_STATUS_MAP } from "~/enumerate/constant";
import {
QUALIFICATION_INDUSTRY_OPTIONS,
QUALIFICATION_INDUSTRY_OPTIONS_MAP,
} from "~/enumerate/enterpriseOptions";
import {
QUAL_MONITOR_STATUS_MAP,
QUAL_MONITOR_CONDITION_ITEMS,
QUAL_MONITOR_STATUS_OPTIONS,
} from "~/enumerate/constant";
import "./index.less";
const { router } = tools;
/** 资质条件检查项模板 */
const CONDITION_ITEMS = [
{ key: "legalPerson", label: "独立法人资格" },
{ key: "fixedAsset", label: "固定资产" },
{ key: "workplace", label: "工作场所" },
{ key: "equipment", label: "设施设备软件" },
{ key: "staffCount", label: "专职技术人员数量" },
{ key: "staffRatio", label: "人员比例" },
{ key: "leader", label: "负责人配备" },
{ key: "system", label: "制度与过程控制体系" },
{ key: "website", label: "承诺书/网站/报告查询" },
{ key: "credit", label: "三年重大违法失信记录" },
{ key: "area", label: "属地满足情况" },
];
/**
* Mock 数据 后端接口就绪后删除此数据及下方 MOCK_INSTITUTIONS 引用
* 改用 props.qualReview.qualMonitorList 即可
*/
const MOCK_INSTITUTIONS = [
{
id: 1,
orgName: "重庆安评技术研究院有限公司",
creditCode: "91500112MA5UQ001",
registerArea: "重庆市渝北区",
bizScopes: ["石油加工业,化学原料、化学品及医药制造业", "金属冶炼"],
bizScopeCount: 2,
minStaffRequire: 30,
status: "normal",
fixedAsset: "1260 万元",
workplace: "1280 ㎡",
archiveRoom: "160 ㎡",
staffCount: 36,
midSafeEngineer: 12,
midSafeRatio: "33%",
seniorTitle: 13,
seniorRatio: "36%",
totalRatio: "69%",
techLeader: "2/2",
processLeader: "1/1",
systemStatus: "制度体系已备案",
promiseStatus: "承诺书已上传",
websiteStatus: "网站可查询",
creditStatus: "近三年无重大违法失信记录",
sourceFields: ["机构备案.固定资产", "场所核验.面积", "人员库.专职人员", "网站备案.报告查询"],
assetOk: true,
workplaceOk: true,
archiveOk: true,
staffOk: true,
conditionDetails: {
legalPerson: { require: "具有独立法人资格", value: "独立法人", result: "通过", source: "机构备案.法人类型、营业执照附件" },
fixedAsset: { require: "不少于 800 万元", value: "1260 万元", result: "通过", source: "财务材料.固定资产净值、审计报告" },
workplace: { require: "建筑面积不少于 1000 平方米,档案室不少于 100 平方米", value: "工作场所 1280 平方米,档案室 160 平方米", result: "通过", source: "场所核验.建筑面积、档案室核验.面积" },
equipment: { require: "具有与业务相适应的技术支撑条件", value: "设备台账、软件授权、检测工具齐全", result: "通过", source: "设备台账.设备清单、软件授权.有效期" },
staffCount: { require: "单一业务范围不少于 25 人", value: "2 个业务范围36 人", result: "通过", source: "人员库.专职人员、业务范围.数量" },
staffRatio: { require: "注安≥30%高工≥30%合计≥60%", value: "注安 33%,高工 36%,合计 69%", result: "通过", source: "人员库.注册安全工程师、人员库.职称等级" },
leader: { require: "每个业务范围配备专职技术负责人", value: "技术负责人 2/2过程控制负责人 1/1", result: "通过", source: "负责人备案.技术负责人、负责人备案.过程控制负责人" },
system: { require: "具有健全内部管理制度和安全评价过程控制体系", value: "制度文件已备案,过程控制节点可追溯", result: "通过", source: "制度文件.版本、过程控制.节点记录" },
website: { require: "法定代表人承诺书已出具;网站正常运行", value: "承诺书已上传;网站可查询机构信息和报告", result: "通过", source: "承诺书.上传状态、网站备案.报告查询状态" },
credit: { require: "三年内无重大违法失信记录", value: "未命中重大违法失信记录", result: "通过", source: "信用核查.重大违法失信记录" },
area: { require: "注册地所在行政区域范围内满足资质条件", value: "注册地与资质条件材料一致", result: "通过", source: "异地备案.注册地、本市社保.缴纳人数" },
/** 根据接口返回字段构建条件详情 */
function buildConditionDetails(record) {
const assetOk = record.fixedAssetAmount >= 800;
const workplaceOk = record.workplaceArea >= 1000;
const archiveOk = record.archiveRoomArea >= 100;
const staffPerScope = Math.floor(
(record.fulltimeEvaluatorCount || 0) /
Math.max(record.businessScope?.length || 1, 1),
);
const engineerRatio =
record.fulltimeEvaluatorCount > 0
? (
((record.registeredEngineerCount || 0) /
record.fulltimeEvaluatorCount) *
100
).toFixed(0)
: "0";
return {
legalPerson: {
require: "具有独立法人资格",
value: "独立法人",
result: "通过",
source: "机构备案.法人类型",
},
},
{
id: 2,
orgName: "重庆恒安安全评价有限公司",
creditCode: "91500103MA60H002",
registerArea: "重庆市江北区",
bizScopes: ["石油加工业,化学原料、化学品及医药制造业"],
bizScopeCount: 1,
minStaffRequire: 25,
status: "person_warning",
fixedAsset: "920 万元",
workplace: "1040 ㎡",
archiveRoom: "110 ㎡",
staffCount: 27,
midSafeEngineer: 9,
midSafeRatio: "33%",
seniorTitle: 7,
seniorRatio: "26%",
totalRatio: "59%",
techLeader: "1/1",
processLeader: "1/1",
systemStatus: "制度体系已备案",
promiseStatus: "承诺书已上传",
websiteStatus: "网站可查询",
creditStatus: "近三年无重大违法失信记录",
sourceFields: ["人员库.职称等级", "人员库.注册安全工程师", "社保比对.缴纳单位", "业务范围.数量"],
assetOk: true,
workplaceOk: true,
archiveOk: true,
staffOk: true,
conditionDetails: {
legalPerson: { require: "具有独立法人资格", value: "独立法人", result: "通过", source: "机构备案.法人类型" },
fixedAsset: { require: "不少于 800 万元", value: "920 万元", result: "通过", source: "财务材料.固定资产净值" },
workplace: { require: "建筑面积不少于 1000 平方米,档案室不少于 100 平方米", value: "工作场所 1040 平方米,档案室 110 平方米", result: "通过", source: "场所核验.建筑面积、档案室核验.面积" },
equipment: { require: "具有与业务相适应的技术支撑条件", value: "设备台账、软件授权齐全", result: "通过", source: "设备台账.设备清单" },
staffCount: { require: "单一业务范围不少于 25 人", value: "1 个业务范围27 人", result: "通过", source: "人员库.专职人员" },
staffRatio: { require: "注安≥30%高工≥30%合计≥60%", value: "注安 33%,高工 26%,合计 59%", result: "预警", source: "人员库.职称等级" },
leader: { require: "每个业务范围配备专职技术负责人", value: "技术负责人 1/1过程控制负责人 1/1", result: "通过", source: "负责人备案" },
system: { require: "具有健全内部管理制度和安全评价过程控制体系", value: "制度文件已备案", result: "通过", source: "制度文件" },
website: { require: "法定代表人承诺书已出具;网站正常运行", value: "承诺书已上传;网站可查询", result: "通过", source: "网站备案" },
credit: { require: "三年内无重大违法失信记录", value: "未命中", result: "通过", source: "信用核查" },
area: { require: "注册地所在行政区域范围内满足资质条件", value: "注册地与资质条件材料一致", result: "通过", source: "本市社保.缴纳人数" },
fixedAsset: {
require: "不少于 800 万元",
value: `${record.fixedAssetAmount || 0} 万元`,
result: assetOk ? "通过" : "不通过",
source: "财务材料.固定资产净值",
},
},
{
id: 3,
orgName: "重庆渝安风险评估中心",
creditCode: "91500108MA61Y003",
registerArea: "重庆市南岸区",
bizScopes: ["金属、非金属矿及其他矿采选业"],
bizScopeCount: 1,
minStaffRequire: 25,
status: "focus_warning",
fixedAsset: "760 万元",
workplace: "980 ㎡",
archiveRoom: "90 ㎡",
staffCount: 24,
midSafeEngineer: 7,
midSafeRatio: "29%",
seniorTitle: 8,
seniorRatio: "33%",
totalRatio: "62%",
techLeader: "1/1",
processLeader: "1/1",
systemStatus: "制度体系已备案",
promiseStatus: "承诺书已上传",
websiteStatus: "网站报告查询接口异常",
creditStatus: "近三年无重大违法失信记录",
sourceFields: ["财务材料.固定资产", "场所核验.建筑面积", "档案室核验.面积", "人员库.专职人数", "网站监测.查询状态"],
assetOk: false,
workplaceOk: false,
archiveOk: false,
staffOk: false,
conditionDetails: {
legalPerson: { require: "具有独立法人资格", value: "独立法人", result: "通过", source: "机构备案.法人类型" },
fixedAsset: { require: "不少于 800 万元", value: "760 万元", result: "不通过", source: "财务材料.固定资产净值" },
workplace: { require: "建筑面积不少于 1000 平方米,档案室不少于 100 平方米", value: "工作场所 980 平方米,档案室 90 平方米", result: "不通过", source: "场所核验.建筑面积" },
equipment: { require: "具有与业务相适应的技术支撑条件", value: "设备台账齐全,报告查询接口异常", result: "部分异常", source: "网站监测.查询状态" },
staffCount: { require: "单一业务范围不少于 25 人", value: "1 个业务范围24 人", result: "不通过", source: "人员库.专职人数" },
staffRatio: { require: "注安≥30%高工≥30%合计≥60%", value: "注安 29%,高工 33%,合计 62%", result: "预警", source: "人员库.注册安全工程师" },
leader: { require: "每个业务范围配备专职技术负责人", value: "技术负责人 1/1过程控制负责人 1/1", result: "通过", source: "负责人备案" },
system: { require: "具有健全内部管理制度和安全评价过程控制体系", value: "制度文件已备案", result: "通过", source: "制度文件" },
website: { require: "法定代表人承诺书已出具;网站正常运行", value: "承诺书已上传;网站报告查询接口异常", result: "预警", source: "网站备案.报告查询状态" },
credit: { require: "三年内无重大违法失信记录", value: "未命中", result: "通过", source: "信用核查" },
area: { require: "注册地所在行政区域范围内满足资质条件", value: "注册地与资质条件材料一致", result: "通过", source: "本市社保" },
workplace: {
require: "建筑面积不少于 1000 ㎡,档案室不少于 100 ㎡",
value: `工作场所 ${record.workplaceArea || 0} ㎡,档案室 ${record.archiveRoomArea || 0}`,
result: workplaceOk && archiveOk ? "通过" : "不通过",
source: "场所核验.建筑面积、档案室核验.面积",
},
},
{
id: 4,
orgName: "北京中安评价中心重庆分公司",
creditCode: "91110108MA62B004",
registerArea: "北京市,重庆备案场所:两江新区",
bizScopes: ["陆上油气管道运输业"],
bizScopeCount: 1,
minStaffRequire: 25,
status: "area_pending",
fixedAsset: "1080 万元",
workplace: "1120 ㎡",
archiveRoom: "120 ㎡",
staffCount: 31,
midSafeEngineer: 10,
midSafeRatio: "32%",
seniorTitle: 9,
seniorRatio: "29%",
totalRatio: "61%",
techLeader: "1/1",
processLeader: "1/1",
systemStatus: "制度体系已备案",
promiseStatus: "承诺书已上传",
websiteStatus: "网站可查询",
creditStatus: "近三年无重大违法失信记录",
sourceFields: ["异地备案.注册地", "本市社保.缴纳人数", "场所核验.租赁合同", "业务范围.油气管道"],
assetOk: true,
workplaceOk: true,
archiveOk: true,
staffOk: true,
conditionDetails: {
legalPerson: { require: "具有独立法人资格", value: "总机构独立法人,重庆为分公司备案", result: "需核验", source: "机构备案.法人类型" },
fixedAsset: { require: "不少于 800 万元", value: "1080 万元", result: "通过", source: "财务材料.固定资产净值" },
workplace: { require: "建筑面积不少于 1000 平方米,档案室不少于 100 平方米", value: "重庆场所 1120 平方米,档案室 120 平方米", result: "通过", source: "场所核验.租赁合同" },
equipment: { require: "具有与业务相适应的技术支撑条件", value: "设备台账齐全", result: "通过", source: "设备台账" },
staffCount: { require: "单一业务范围不少于 25 人", value: "备案 31 人,本市社保 21 人", result: "不通过", source: "社保比对.缴纳单位" },
staffRatio: { require: "注安≥30%高工≥30%合计≥60%", value: "本市专职人员比例待核验", result: "需核验", source: "人员库.本市社保" },
leader: { require: "每个业务范围配备专职技术负责人", value: "技术负责人 1/1过程控制负责人 1/1", result: "通过", source: "负责人备案" },
system: { require: "具有健全内部管理制度和安全评价过程控制体系", value: "制度文件已备案", result: "通过", source: "制度文件" },
website: { require: "法定代表人承诺书已出具;网站正常运行", value: "承诺书已上传;网站可查询", result: "通过", source: "网站备案" },
credit: { require: "三年内无重大违法失信记录", value: "未命中", result: "通过", source: "信用核查" },
area: { require: "注册地所在行政区域范围内满足资质条件", value: "重庆备案场所达标,本市社保专职人员不足", result: "需核验", source: "异地备案.注册地" },
equipment: {
require: "具有与业务相适应的技术支撑条件",
value: "设备台账齐全",
result: "通过",
source: "设备台账",
},
},
];
const STATUS_OPTIONS = [
{ value: "", label: "全部" },
{ value: "normal", label: "保持正常" },
{ value: "person_warning", label: "人员比例预警" },
{ value: "focus_warning", label: "重点预警" },
{ value: "area_pending", label: "属地待核验" },
];
const SCOPE_OPTIONS = [
{ value: "", label: "全部" },
{ value: "化工", label: "石油加工业,化学原料、化学品及医药制造业" },
{ value: "金属冶炼", label: "金属冶炼" },
{ value: "矿采选", label: "金属、非金属矿及其他矿采选业" },
{ value: "油气管道", label: "陆上油气管道运输业" },
];
staffCount: {
require: `单一业务范围不少于 25 人`,
value: `${record.businessScope?.length || 1} 个业务范围,${record.fulltimeEvaluatorCount || 0}`,
result: staffPerScope >= 25 ? "通过" : "不通过",
source: "人员库.专职人员",
},
staffRatio: {
require: "注册安全工程师比例",
value: `注安 ${engineerRatio}%`,
result: Number(engineerRatio) >= 30 ? "通过" : "预警",
source: "人员库.注册安全工程师",
},
leader: {
require: "配备技术负责人及过程控制负责人",
value: "已配备",
result: "通过",
source: "负责人备案",
},
system: {
require: "具有健全内部管理制度和过程控制体系",
value: "制度文件已备案",
result: "通过",
source: "制度文件",
},
website: {
require: "法定代表人承诺书已出具;网站正常运行",
value: "承诺书已上传",
result: "通过",
source: "网站备案",
},
credit: {
require: "三年内无重大违法失信记录",
value: "未命中",
result: "通过",
source: "信用核查",
},
area: {
require: "注册地满足资质条件",
value: record.districtName || "—",
result: "通过",
source: "异地备案.注册地",
},
};
}
/** 统计卡片数据 */
function computeStats(list) {
return {
total: list.length,
normal: list.filter((i) => i.status === "normal").length,
warning: list.filter((i) => i.status === "person_warning" || i.status === "area_pending").length,
focus: list.filter((i) => i.status === "focus_warning").length,
normal: list.filter((i) => i.alertStatus === "normal").length,
warning: list.filter((i) => i.alertStatus === "person_rate").length,
};
}
@ -237,39 +121,35 @@ const QualMonitor = (props) => {
const [form] = Form.useForm();
const [detailVisible, setDetailVisible] = useState(false);
const [detailRecord, setDetailRecord] = useState(null);
// 待后端接口就绪后data 改为使用 props.qualReview.qualMonitorList
// 并移除 MOCK_INSTITUTIONS 引用
const [data, setData] = useState(MOCK_INSTITUTIONS);
const [data, setData] = useState([]);
const { qualReview, queryQualMonitorPage, queryQualMonitorCondition } = props;
const { qualMonitorList, qualMonitorTotal, qualReviewLoading } = qualReview || {};
const { qualMonitorList, qualMonitorTotal, qualReviewLoading } =
qualReview || {};
const stats = computeStats(data);
/** 搜索 — 当前使用 mock 本地过滤;接接口后改为调用 queryQualMonitorPage */
/** model 数据回填时同步到本地 data */
useEffect(() => {
if (qualMonitorList) {
setData(qualMonitorList);
}
}, [qualMonitorList]);
/** 搜索 */
const onFinish = (values) => {
const { keyword, scope, status } = values;
let filtered = MOCK_INSTITUTIONS;
if (keyword) {
filtered = filtered.filter(
(i) => i.orgName.includes(keyword) || i.creditCode.includes(keyword),
);
}
if (scope) {
filtered = filtered.filter((i) =>
i.bizScopes.some((s) => s.includes(scope)),
);
}
if (status) {
filtered = filtered.filter((i) => i.status === status);
}
router.query = { ...router.query, ...values, current: 1, size: 10 };
setData(filtered);
handleSearch();
};
/** 接接口后改为 queryQualMonitorPage 调用 */
/** 调用接口 */
const handleSearch = () => {
// queryQualMonitorPage(router.query);
const params = { ...router.query };
if (params.keyword) {
params.unitName = params.keyword;
delete params.keyword;
}
queryQualMonitorPage(params);
};
const handleReset = (values) => {
@ -279,107 +159,107 @@ const QualMonitor = (props) => {
useEffect(() => {
form.setFieldsValue(router.query);
// 接接口后打开下行注释
// handleSearch();
handleSearch();
}, []);
const openDetail = (record) => {
setDetailRecord(record);
setDetailRecord({
...record,
conditionDetails: buildConditionDetails(record),
});
setDetailVisible(true);
};
const resultTag = (result) => {
if (result === "通过") return <Tag color="success">通过</Tag>;
if (result === "预警" || result === "需核验") return <Tag color="warning">{result}</Tag>;
if (result === "不通过" || result === "部分异常") return <Tag color="error">{result}</Tag>;
if (result === "预警" || result === "需核验")
return <Tag color="warning">{result}</Tag>;
if (result === "不通过" || result === "部分异常")
return <Tag color="error">{result}</Tag>;
return <Tag>{result}</Tag>;
};
const columns = [
{
title: "机构信息",
dataIndex: "orgName",
width: 240,
dataIndex: "unitName",
width: 260,
fixed: "left",
render: (name, record) => (
<div className="org-info">
<div className="org-name">{name}</div>
<div className="org-meta">
统一社会信用代码{record.creditCode} | 注册地{record.registerArea}
统一社会信用代码{record.creditCode} | 注册地{record.districtName || "—"}
</div>
</div>
),
},
{
title: "具备资质/业务范围",
dataIndex: "bizScopes",
width: 260,
dataIndex: "businessScope",
width: 360,
render: (scopes, record) => (
<div className="biz-scope-wrap">
<div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
{scopes.map((s, i) => (
<Tag key={i} color="blue">{s}</Tag>
{(scopes || []).map((s, i) => (
<Tag key={i} color="blue">
{QUALIFICATION_INDUSTRY_OPTIONS_MAP[s] || s}
</Tag>
))}
</div>
<div className="biz-scope-hint">
业务范围数{record.bizScopeCount}最低专职人员要求{record.minStaffRequire}
业务范围数{scopes?.length || 0}最低专职人员要求{25 + Math.max(0, (scopes?.length || 1) - 1) * 5}
</div>
</div>
),
},
{
title: "状态",
dataIndex: "status",
width: 110,
render: (status) => {
const config = QUAL_MONITOR_STATUS_MAP[status];
dataIndex: "alertStatus",
width: 100,
render: (alertStatus) => {
const config = QUAL_MONITOR_STATUS_MAP[alertStatus];
return config ? <Tag color={config.color}>{config.label}</Tag> : "--";
},
},
{
title: "固定资产/场所",
dataIndex: "fixedAsset",
dataIndex: "fixedAssetAmount",
width: 260,
render: (_, record) => (
<div>
<div>固定资产 {record.fixedAsset}工作场所 {record.workplace}档案室 {record.archiveRoom}</div>
<div className={`place-status ${record.assetOk && record.workplaceOk ? "place-ok" : "place-bad"}`}>
{record.assetOk && record.workplaceOk ? "均满足资质条件" : "三项基础条件低于要求"}
render: (_, record) => {
const assetOk = record.fixedAssetAmount >= 800;
const workplaceOk = record.workplaceArea >= 1000;
const archiveOk = record.archiveRoomArea >= 100;
const allOk = assetOk && workplaceOk && archiveOk;
return (
<div>
<div>
固定资产 {record.fixedAssetAmount} 万元工作场所{" "}
{record.workplaceArea} 档案室 {record.archiveRoomArea}
</div>
<div className={`place-status ${allOk ? "place-ok" : "place-bad"}`}>
{allOk ? "均满足资质条件" : "三项基础条件低于要求"}
</div>
</div>
</div>
),
);
},
},
{
title: "人员与负责人",
dataIndex: "staffCount",
width: 300,
render: (_, record) => (
<div>
专职技术人员 {record.staffCount} 中级及以上注册安全工程师 {record.midSafeEngineer} /{record.midSafeRatio}
高级职称 {record.seniorTitle} /{record.seniorRatio}合计 {record.totalRatio}
技术负责人 {record.techLeader}过程控制负责人 {record.processLeader}
width: 200,
render: () => (
<div style={{ color: "#94a3b8", fontSize: 12 }}>
专职技术人员 36 中级及以上注册安全工程师 12 /33%高级职称 13
/36%合计 69%技术负责人 2/2过程控制负责人 1/1
</div>
),
},
{
title: "制度/网站/信用",
dataIndex: "systemStatus",
width: 220,
render: (_, record) => (
<div>
{record.systemStatus}{record.promiseStatus}{record.websiteStatus}{record.creditStatus}
</div>
),
},
{
title: "来源字段",
dataIndex: "sourceFields",
width: 200,
render: (fields) => (
<div style={{ display: "flex", flexWrap: "wrap", gap: 4 }}>
{fields.map((f, i) => (
<span key={i} className="source-pill">{f}</span>
))}
render: () => (
<div style={{ color: "#94a3b8", fontSize: 12 }}>
制度体系已备案承诺书已上传网站可查询近三年无重大违法失信记录
</div>
),
},
@ -389,7 +269,11 @@ const QualMonitor = (props) => {
fixed: "right",
render: (_, record) => (
<TableAction>
<Button type="primary" size="small" onClick={() => openDetail(record)}>
<Button
type="primary"
size="small"
onClick={() => openDetail(record)}
>
条件详情
</Button>
</TableAction>
@ -400,133 +284,184 @@ const QualMonitor = (props) => {
return (
<PageLayout title="资质保持监控">
<div className="qual-monitor">
{/* 统计卡片 */}
<div className="stat-grid">
{[
{ label: "备案机构总数", value: stats.total, hint: "来源:已备案机构管理.机构状态", color: "#1e293b", iconBg: "#ede9fe", iconColor: "#7c3aed", iconText: "机" },
{ label: "条件保持正常", value: stats.normal, hint: "十项资质条件均通过", color: "#059669", iconBg: "#d1fae5", iconColor: "#059669", iconText: "正" },
{ label: "条件预警机构", value: stats.warning, hint: "人员比例、属地材料待核验", color: "#d97706", iconBg: "#fef3c7", iconColor: "#d97706", iconText: "预" },
].map((card, idx) => (
<div key={idx} className="stat-card">
<div className="stat-info">
<div className="stat-label">{card.label}</div>
<div className="stat-value" style={{ color: card.color }}>{card.value}</div>
<div className="stat-hint">{card.hint}</div>
{/* 统计卡片 */}
<div className="stat-grid">
{[
{
label: "备案机构总数",
value: stats.total,
hint: "来源:已备案机构管理.机构状态",
color: "#1e293b",
iconBg: "#ede9fe",
iconColor: "#7c3aed",
iconText: "机",
},
{
label: "条件保持正常",
value: stats.normal,
hint: "十项资质条件均通过",
color: "#059669",
iconBg: "#d1fae5",
iconColor: "#059669",
iconText: "正",
},
{
label: "条件预警机构",
value: stats.warning,
hint: "人员比例不满足要求",
color: "#d97706",
iconBg: "#fef3c7",
iconColor: "#d97706",
iconText: "预",
},
].map((card, idx) => (
<div key={idx} className="stat-card">
<div className="stat-info">
<div className="stat-label">{card.label}</div>
<div className="stat-value" style={{ color: card.color }}>
{card.value}
</div>
<div className="stat-hint">{card.hint}</div>
</div>
<div
className="stat-icon"
style={{ background: card.iconBg, color: card.iconColor }}
>
{card.iconText}
</div>
</div>
<div className="stat-icon" style={{ background: card.iconBg, color: card.iconColor }}>
{card.iconText}
))}
</div>
{/* 资质条件来源说明 */}
<div className="source-note">
<strong>资质条件来源</strong>
依据安全评价机构资质条件将机构备案信息拆为固定资产不少于 800
万元工作场所不少于 1000 平方米档案室不少于 100 平方米
专职技术人员数量及比例技术负责人/过程控制负责人内部制度法定代表人承诺公开网站三年重大违法失信记录注册地属地满足情况等字段
</div>
{/* 搜索表单 */}
<SearchForm
style={{ marginBottom: 12 }}
form={form}
loading={qualReviewLoading}
formLine={[
<Form.Item key="keyword" name="keyword">
<ControlWrapper.Input
label="机构名称/信用代码"
placeholder="输入机构名称或统一社会信用代码"
allowClear
/>
</Form.Item>,
<Form.Item key="scope" name="businessScope">
<ControlWrapper.Select
label="业务范围"
placeholder="请选择"
allowClear
style={{ width: "100%" }}
options={QUALIFICATION_INDUSTRY_OPTIONS}
/>
</Form.Item>,
<Form.Item key="status" name="alertStatus">
<ControlWrapper.Select
label="资质状态"
placeholder="请选择"
allowClear
style={{ width: "100%" }}
options={QUAL_MONITOR_STATUS_OPTIONS.map((o) => ({
label: o.label,
value: o.value,
}))}
/>
</Form.Item>,
]}
onReset={handleReset}
onFinish={onFinish}
/>
{/* 数据表格 */}
<Table
rowKey="id"
columns={columns}
dataSource={data}
scroll={{ x: 1600, y: props.scrollY }}
loading={qualReviewLoading}
pagination={{
total: qualMonitorTotal || 0,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`,
current: router.query.current || 1,
pageSize: router.query.size || 10,
onChange: (page, size) => {
router.query = { ...router.query, current: page, size };
handleSearch();
},
}}
/>
{/* 条件详情弹窗 */}
<Modal
title={
detailRecord ? `资质保持条件详情 - ${detailRecord.unitName}` : ""
}
open={detailVisible}
onCancel={() => setDetailVisible(false)}
width={960}
footer={
<div
style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}
>
<Button onClick={() => setDetailVisible(false)}>关闭</Button>
</div>
</div>
))}
}
>
{detailRecord && (
<div>
<div className="check-note">
<strong>机构核查口径</strong>
以机构为主线将资质条件拆为十项保持条件和属地要求
每项展示监管字段当前值结论和来源
</div>
<Table
rowKey="key"
size="small"
pagination={false}
columns={[
{ title: "检查项", dataIndex: "label", width: 120 },
{ title: "资质要求", dataIndex: "require", width: 280 },
{ title: "当前值", dataIndex: "value", width: 260 },
{
title: "结论",
dataIndex: "result",
width: 80,
render: resultTag,
},
{
title: "来源字段",
dataIndex: "source",
render: (text) => (
<span className="cell-source">{text}</span>
),
},
]}
dataSource={QUAL_MONITOR_CONDITION_ITEMS.map((item) => {
const detail = detailRecord.conditionDetails[item.key];
return detail
? { key: item.key, label: item.label, ...detail }
: null;
}).filter(Boolean)}
/>
</div>
)}
</Modal>
</div>
{/* 资质条件来源说明 */}
<div className="source-note">
<strong>资质条件来源</strong>
依据安全评价机构资质条件将机构备案信息拆为固定资产不少于 800 万元工作场所不少于 1000 平方米档案室不少于 100 平方米
专职技术人员数量及比例技术负责人/过程控制负责人内部制度法定代表人承诺公开网站三年重大违法失信记录注册地属地满足情况等字段
</div>
{/* 搜索表单 */}
<SearchForm
style={{ marginBottom: 12 }}
form={form}
loading={qualReviewLoading}
formLine={[
<Form.Item key="keyword" name="keyword">
<ControlWrapper.Input
label="机构名称/信用代码"
placeholder="输入机构名称或统一社会信用代码"
allowClear
/>
</Form.Item>,
<Form.Item key="scope" name="scope">
<ControlWrapper.Select
label="业务范围"
placeholder="请选择"
allowClear
style={{ width: "100%" }}
options={SCOPE_OPTIONS.map((o) => ({ label: o.label, value: o.value }))}
/>
</Form.Item>,
<Form.Item key="status" name="status">
<ControlWrapper.Select
label="资质状态"
placeholder="请选择"
allowClear
style={{ width: "100%" }}
options={STATUS_OPTIONS.map((o) => ({ label: o.label, value: o.value }))}
/>
</Form.Item>,
]}
onReset={handleReset}
onFinish={onFinish}
/>
{/* 数据表格 */}
<Table
rowKey="id"
columns={columns}
dataSource={data}
scroll={{ x: 1600, y: props.scrollY }}
loading={qualReviewLoading}
pagination={{
total: data.length,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`,
current: router.query.current || 1,
pageSize: router.query.size || 10,
onChange: (page, size) => {
router.query = { ...router.query, current: page, size };
},
}}
/>
{/* 条件详情弹窗 */}
<Modal
title={detailRecord ? `资质保持条件详情 - ${detailRecord.orgName}` : ""}
open={detailVisible}
onCancel={() => setDetailVisible(false)}
width={960}
footer={
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
<Button onClick={() => setDetailVisible(false)}>关闭</Button>
</div>
}
>
{detailRecord && (
<div>
<div className="check-note">
<strong>机构核查口径</strong>线
每项展示监管字段当前值结论和来源
</div>
<Table
rowKey="key"
size="small"
pagination={false}
columns={[
{ title: "检查项", dataIndex: "label", width: 120 },
{ title: "资质要求", dataIndex: "require", width: 280 },
{ title: "当前值", dataIndex: "value", width: 260 },
{ title: "结论", dataIndex: "result", width: 80, render: resultTag },
{ title: "来源字段", dataIndex: "source", render: (text) => <span className="cell-source">{text}</span> },
]}
dataSource={CONDITION_ITEMS.map((item) => {
const detail = detailRecord.conditionDetails[item.key];
return detail ? { key: item.key, label: item.label, ...detail } : null;
}).filter(Boolean)}
/>
</div>
)}
</Modal>
</div>
</PageLayout>
);
};
export default Connect([NS_QUAL_REVIEW], true)(AntdTableFuncControl(QualMonitor));
export default Connect(
[NS_QUAL_REVIEW],
true,
)(AntdTableFuncControl(QualMonitor));

View File

@ -77,7 +77,7 @@
// 机构信息
.org-info {
.org-name {
font-weight: 500;
font-weight: 600;
}
.org-meta {