safety-eval-service-frontend/src/pages/Container/QualificationReview/FilingTabs/index.js

256 lines
14 KiB
JavaScript
Raw Normal View History

2026-06-30 15:59:15 +08:00
import React, { useState } from "react";
import { Button, Descriptions, Table, Tag, Tabs, Select, Modal, Space } from "antd";
import {
MOCK_MATERIALS,
MOCK_PERSONNEL,
MOCK_EQUIPMENT,
MOCK_EQUIP_DETAIL,
MOCK_PERSONNEL_DETAIL,
MOCK_CERTIFICATES,
CALIBRATION_MAP,
} from "../mockData";
/**
* 共享组件资质备案 5 个标签页详情 / 审核共用
* @param {Object} props
* @param {Object} props.detail - 备案详情数据
* @param {boolean} [props.isReview=false] - 审核模式开启后材料上传显示"上传附件"+"符合性"
* @param {Object} [props.compliance={}] - 审核模式下的符合性状态
* @param {Function} [props.onComplianceChange] - 符合性变动回调
* @param {Function} [props.onPersonnelView] - 查看人员详情回调覆盖默认弹窗
* @param {Function} [props.onEquipView] - 查看设备详情回调 (record) => void覆盖默认弹窗
*/
const FilingTabs = ({
detail,
isReview = false,
compliance = {},
onComplianceChange,
onPersonnelView,
onEquipView,
}) => {
const [personnelVisible, setPersonnelVisible] = useState(false);
const [equipVisible, setEquipVisible] = useState(false);
const [selectedEquip, setSelectedEquip] = useState(null);
const baseCols = [
{ title: "序号", width: 60, render: (_, __, i) => i + 1 },
{ title: "材料名称", dataIndex: "name" },
];
const materialCols = isReview
? [
...baseCols,
{ title: "上传附件", dataIndex: "attachment", width: 120 },
{ title: "格式", dataIndex: "format", width: 80 },
{ title: "状态", dataIndex: "status", width: 100, render: () => <Tag color="success">已上传</Tag> },
{ title: "符合性", width: 100,
render: (_, record) => (
<Select
style={{ width: "100%", fontSize: "0.75rem" }}
size="small"
placeholder="请选择"
value={compliance[record.id]}
onChange={(v) => onComplianceChange?.(record.id, v)}
>
<Select.Option value="pass">符合</Select.Option>
<Select.Option value="fail">不符合</Select.Option>
</Select>
),
},
]
: [
...baseCols,
{ title: "格式", dataIndex: "format", width: 80 },
{ title: "状态", dataIndex: "status", width: 100, render: () => <Tag color="success">已上传</Tag> },
{ title: "操作", width: 80, render: () => <Button type="link" size="small">预览</Button> },
];
const items = [
{
key: "info",
label: "1.备案基本信息",
children: (
<Descriptions column={2} bordered size="small" style={{ background: "#fff" }}>
<Descriptions.Item label="申请的业务范围" span={2}>{detail.scopeName}</Descriptions.Item>
<Descriptions.Item label="备案属地">{detail.filingRegion}</Descriptions.Item>
<Descriptions.Item label="备案单位">{detail.orgName}</Descriptions.Item>
<Descriptions.Item label="备案单位类型">{detail.orgType}</Descriptions.Item>
<Descriptions.Item label="统一社会信用代码">{detail.creditCode}</Descriptions.Item>
<Descriptions.Item label="办公地址" span={2}>{detail.officeAddress}</Descriptions.Item>
<Descriptions.Item label="注册地址" span={2}>{detail.registerAddress}</Descriptions.Item>
<Descriptions.Item label="资质证书编号">{detail.certNo}</Descriptions.Item>
<Descriptions.Item label="信息公开网址">{detail.website}</Descriptions.Item>
<Descriptions.Item label="法人代表及电话">{detail.legalPerson} / {detail.legalPhone}</Descriptions.Item>
<Descriptions.Item label="联系人及电话">{detail.contactPerson} / {detail.contactPhone}</Descriptions.Item>
<Descriptions.Item label="固定资产总值(万元)">{detail.fixedAssets}</Descriptions.Item>
<Descriptions.Item label="工作场所建筑面积">{detail.officeArea}</Descriptions.Item>
<Descriptions.Item label="档案室面积">{detail.archiveArea}</Descriptions.Item>
<Descriptions.Item label="专职安全评价师数量">{detail.evaluatorCount}</Descriptions.Item>
<Descriptions.Item label="注册安全工程师数量">{detail.registerEngineerCount}</Descriptions.Item>
<Descriptions.Item label="单位基本情况介绍" span={2}>{detail.description}</Descriptions.Item>
</Descriptions>
),
},
{
key: "materials",
label: "2.备案材料上传",
children: (
<Table size="small" bordered rowKey="id" pagination={false} dataSource={MOCK_MATERIALS} columns={materialCols} />
),
},
{
key: "promise",
label: "3.法定代表人承诺书",
children: (
<div style={{ border: "1px solid #d9d9d9", borderRadius: 6, padding: "1.25rem 1.5rem", background: "#fafafa", fontSize: "0.85rem", lineHeight: 1.9 }}>
<p style={{ textAlign: "center", fontWeight: 600, fontSize: "0.95rem", marginBottom: "0.75rem" }}>申请单位法定代表人承诺书</p>
<p>本人{detail.legalPerson}{detail.orgName}法定代表人现代表我单位承诺如下</p>
<p>我单位自愿申请安全评价机构资质本人已经认真学习了解并掌握安全生产法行政许可法行政处罚法安全评价检测检验机构管理办法等法律法规的相关规定知悉开展安全评价工作的法律责任义务权力和风险</p>
<p>本人承诺本单位满足安全评价检测检验机构管理办法所规定的资质条件要求本人及单位三年内无重大违法失信行为申请资质所提交的有关材料真实合法有效并对其真实性合法性承担相应法律责任接受并配合有关部门对本单位开展的专业能力审查</p>
<p>如能获准资质本单位将严格按照法律法规规章标准的要求开展安全评价活动遵守执业准则和职业道德并对作出的安全评价报告结果承担法律责任自觉接受应急管理部门煤矿安全监督管理部门等行政执法部门的监督检查</p>
<p style={{ marginTop: "0.75rem" }}>法定代表人{detail.legalPerson}已签名</p>
<p>单位盖章</p>
<p style={{ textAlign: "right" }}>2026年06月25日</p>
</div>
),
},
{
key: "personnel",
label: "4.备案人员管理",
children: (
<Table size="small" bordered rowKey="id" pagination={false} dataSource={MOCK_PERSONNEL}
columns={[
{ title: "序号", width: 60, render: (_, __, i) => i + 1 },
{ title: "人员姓名", dataIndex: "name", width: 100 },
{ title: "类型", dataIndex: "type", width: 100 },
{ title: "职务", dataIndex: "position", width: 120 },
{ title: "职称", dataIndex: "title", width: 100 },
{ title: "专业能力", dataIndex: "ability" },
{ title: "操作", width: 80,
render: () => (
<Button type="link" size="small" onClick={onPersonnelView || (() => setPersonnelVisible(true))}>
查看
</Button>
),
},
]}
/>
),
},
{
key: "equipment",
label: "5.装备清单",
children: (
<Table size="small" bordered rowKey="id" pagination={false} dataSource={MOCK_EQUIPMENT}
columns={[
{ title: "序号", width: 60, render: (_, __, i) => i + 1 },
{ title: "装备名称", dataIndex: "name", width: 140 },
{ title: "规格型号", dataIndex: "model", width: 120 },
{ title: "生产厂家", dataIndex: "manufacturer", width: 140 },
{ title: "计量检定情况", dataIndex: "calibration", width: 120,
render: (s) => {
const cfg = CALIBRATION_MAP[s];
return cfg ? <Tag color={cfg.color}>{cfg.label}</Tag> : s;
},
},
{ title: "操作", width: 80,
render: (_, record) => (
<Button type="link" size="small" onClick={() => onEquipView ? onEquipView(record) : (setSelectedEquip(record), setEquipVisible(true))}>
查看
</Button>
),
},
]}
/>
),
},
];
return (
<>
<Tabs items={items} />
{/* 人员详细信息弹窗 */}
<Modal
title="人员详细信息"
open={personnelVisible}
onCancel={() => setPersonnelVisible(false)}
width={720}
footer={(originNode, { CancelBtn }) => <CancelBtn />}
>
<Descriptions column={2} bordered size="small">
<Descriptions.Item label="姓名">{MOCK_PERSONNEL_DETAIL.name}</Descriptions.Item>
<Descriptions.Item label="性别">{MOCK_PERSONNEL_DETAIL.gender}</Descriptions.Item>
<Descriptions.Item label="资质范围">{MOCK_PERSONNEL_DETAIL.qualScope}</Descriptions.Item>
<Descriptions.Item label="出生日期">{MOCK_PERSONNEL_DETAIL.birthDate}</Descriptions.Item>
<Descriptions.Item label="办公地址" span={2}>{MOCK_PERSONNEL_DETAIL.officeAddress}</Descriptions.Item>
<Descriptions.Item label="专业">{MOCK_PERSONNEL_DETAIL.major}</Descriptions.Item>
<Descriptions.Item label="职业等级及证书编号">{MOCK_PERSONNEL_DETAIL.certLevel}</Descriptions.Item>
<Descriptions.Item label="邮箱">{MOCK_PERSONNEL_DETAIL.email}</Descriptions.Item>
<Descriptions.Item label="人员类型">{MOCK_PERSONNEL_DETAIL.personnelType}</Descriptions.Item>
<Descriptions.Item label="身份证号">{MOCK_PERSONNEL_DETAIL.idCard}</Descriptions.Item>
<Descriptions.Item label="现住地址" span={2}>{MOCK_PERSONNEL_DETAIL.currentAddress}</Descriptions.Item>
<Descriptions.Item label="学历">{MOCK_PERSONNEL_DETAIL.education}</Descriptions.Item>
<Descriptions.Item label="毕业院校">{MOCK_PERSONNEL_DETAIL.graduateSchool}</Descriptions.Item>
<Descriptions.Item label="职务">{MOCK_PERSONNEL_DETAIL.position}</Descriptions.Item>
<Descriptions.Item label="是否注册安全工程师">
<Tag color={MOCK_PERSONNEL_DETAIL.isRegisterEngineer === "是" ? "success" : "error"}>
{MOCK_PERSONNEL_DETAIL.isRegisterEngineer}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="出版学术专著、专利、获奖、发表学术论文等" span={2}>{MOCK_PERSONNEL_DETAIL.publications}</Descriptions.Item>
<Descriptions.Item label="自我申报的专业能力及认定方式" span={2}>{MOCK_PERSONNEL_DETAIL.selfDeclaration}</Descriptions.Item>
<Descriptions.Item label="主要学习工作经历" span={2}>{MOCK_PERSONNEL_DETAIL.workExperience}</Descriptions.Item>
<Descriptions.Item label="申报专业能力证明材料" span={2}>
<Space><Button type="link" size="small">查看附件</Button><Tag color="success">.pdf</Tag></Space>
</Descriptions.Item>
</Descriptions>
<h4 style={{ fontSize: "0.85rem", color: "#1890ff", margin: "1.25rem 0 0.6rem", paddingBottom: "0.3rem", borderBottom: "2px solid #e6f7ff" }}>证照信息</h4>
<Table size="small" bordered rowKey="id" pagination={false} dataSource={MOCK_CERTIFICATES} scroll={{ x: 920 }}
columns={[
{ title: "证照名称", dataIndex: "name", ellipsis: true },
{ title: "证书编号", dataIndex: "certNo", width: 120 },
{ title: "证书类别", dataIndex: "category", width: 120 },
{ title: "发证机关", dataIndex: "issuer", width: 150, ellipsis: true },
{ title: "有效开始日期", dataIndex: "startDate", width: 120 },
{ title: "有效结束日期", dataIndex: "endDate", width: 120 },
{ title: "操作", fixed: "right", width: 80, render: () => <Button type="link" size="small">查看证书</Button> },
]}
/>
</Modal>
{/* 设备详细信息弹窗 */}
<Modal
title="设备详细信息"
open={equipVisible}
onCancel={() => setEquipVisible(false)}
width={600}
footer={<Button onClick={() => setEquipVisible(false)}>关闭</Button>}
>
{selectedEquip && (
<Descriptions column={1} size="small">
<Descriptions.Item label="设备名称">{MOCK_EQUIP_DETAIL.name}</Descriptions.Item>
<Descriptions.Item label="型号">{MOCK_EQUIP_DETAIL.model}</Descriptions.Item>
<Descriptions.Item label="仪器分类">{MOCK_EQUIP_DETAIL.category}</Descriptions.Item>
<Descriptions.Item label="设备类型">{MOCK_EQUIP_DETAIL.type}</Descriptions.Item>
<Descriptions.Item label="厂家">{MOCK_EQUIP_DETAIL.manufacturer}</Descriptions.Item>
<Descriptions.Item label="现场校验类型">{MOCK_EQUIP_DETAIL.calibrationType}</Descriptions.Item>
<Descriptions.Item label="设备流量说明">{MOCK_EQUIP_DETAIL.flowDesc}</Descriptions.Item>
<Descriptions.Item label="最大流量">{MOCK_EQUIP_DETAIL.maxFlow}</Descriptions.Item>
<Descriptions.Item label="最小流量">{MOCK_EQUIP_DETAIL.minFlow}</Descriptions.Item>
<Descriptions.Item label="是否双路">{MOCK_EQUIP_DETAIL.dualChannel}</Descriptions.Item>
<Descriptions.Item label="校准初始值" span={2}>{MOCK_EQUIP_DETAIL.calibInitValue}</Descriptions.Item>
<Descriptions.Item label="校准单位" span={2}>{MOCK_EQUIP_DETAIL.calibUnit}</Descriptions.Item>
<Descriptions.Item label="设备状态">
<Tag color={CALIBRATION_MAP[MOCK_EQUIP_DETAIL.status]?.color}>{CALIBRATION_MAP[MOCK_EQUIP_DETAIL.status]?.label}</Tag>
</Descriptions.Item>
</Descriptions>
)}
</Modal>
</>
);
};
export default FilingTabs;