Merge remote-tracking branch 'origin/dev' into dev
commit
ecd3573a78
|
|
@ -4,6 +4,7 @@
|
|||
/node_modules
|
||||
|
||||
# production
|
||||
/prototype
|
||||
/dist
|
||||
/demo
|
||||
/.trae/
|
||||
|
|
|
|||
|
|
@ -2,4 +2,51 @@
|
|||
* 全局常量定义
|
||||
*/
|
||||
|
||||
export {};
|
||||
/** 证书状态 */
|
||||
export const CERT_STATUS_MAP = {
|
||||
normal: { label: "正常", color: "success" },
|
||||
expiring: { label: "即将到期", color: "warning" },
|
||||
expired: { label: "已过期", color: "error" },
|
||||
};
|
||||
|
||||
/** 核验状态 */
|
||||
export const VERIFY_STATUS_MAP = {
|
||||
pending: { label: "待确认", color: "warning" },
|
||||
passed: { label: "确认通过", color: "success" },
|
||||
rejected: { label: "打回", color: "error" },
|
||||
};
|
||||
|
||||
/** 审核状态 */
|
||||
export const REVIEW_STATUS_MAP = {
|
||||
pending: { label: "待审核", color: "warning" },
|
||||
reviewing: { label: "审核中", color: "processing" },
|
||||
rejected: { label: "打回", color: "error" },
|
||||
};
|
||||
|
||||
/** 专家核验状态 */
|
||||
export const EXPERT_STATUS_MAP = {
|
||||
pending: { label: "待核验", color: "blue" },
|
||||
arranging: { label: "待安排", color: "warning" },
|
||||
passed: { label: "已核验", color: "success" },
|
||||
|
||||
};
|
||||
|
||||
/** 公示状态 */
|
||||
export const PUBLICITY_STATUS_MAP = {
|
||||
pending: { label: "待公示", color: "warning" },
|
||||
published: { label: "已公示", color: "success" },
|
||||
};
|
||||
|
||||
/** 变更状态 */
|
||||
export const CHANGE_STATUS_MAP = {
|
||||
stuck: { label: "停滞中", color: "error" },
|
||||
pending: { label: "待审核", color: "warning" },
|
||||
approved: { label: "已审核", color: "success" },
|
||||
};
|
||||
|
||||
/** 专家等级 */
|
||||
export const EXPERT_LEVEL_MAP = {
|
||||
1: "一级",
|
||||
2: "二级",
|
||||
3: "三级",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ import { getFileUrlFromServer } from "zy-react-library/utils";
|
|||
import "dayjs/locale/zh-cn";
|
||||
import "../blessed_by_buddha";
|
||||
|
||||
require("antd/dist/reset.css");
|
||||
require("zy-react-library/css/common.less");
|
||||
|
||||
|
||||
dayjs.locale("zh-cn");
|
||||
setJJBCommonAntdMessage(message);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,213 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Form, Select, Space, 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 { VERIFY_STATUS_MAP } from "~/enumerate/constant";
|
||||
|
||||
|
||||
|
||||
// 静态模拟数据
|
||||
const MOCK_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
orgName: "重庆安评技术研究院有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2026-001",
|
||||
businessScope: "化工, 石油加工",
|
||||
confirmStatus: "pending",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orgName: "北京中安评价中心(重庆分公司)",
|
||||
orgType: "异地机构",
|
||||
certNo: "API-2026-015",
|
||||
businessScope: "矿山",
|
||||
confirmStatus: "passed",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orgName: "重庆华安评价有限公司",
|
||||
orgType: "异地机构",
|
||||
certNo: "API-2025-088",
|
||||
businessScope: "石油加工",
|
||||
confirmStatus: "pending",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
orgName: "重庆安评科技有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2024-056",
|
||||
businessScope: "化工",
|
||||
confirmStatus: "rejected",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
orgName: "重庆恒安安全评价有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2025-032",
|
||||
businessScope: "矿山, 石油加工",
|
||||
confirmStatus: "passed",
|
||||
},
|
||||
];
|
||||
|
||||
const {router} = tools;
|
||||
|
||||
const ExpertVerification = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = () => {
|
||||
setLoading(true);
|
||||
console.log(router.query);
|
||||
setTimeout(() => setLoading(false), 500);
|
||||
};
|
||||
|
||||
const handleReset = (values) => {
|
||||
setLoading(true);
|
||||
router.query={
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
}
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "id",
|
||||
width: 60,
|
||||
fixed: "left",
|
||||
render: (text, record, index) => index + 1,
|
||||
},
|
||||
{ title: "机构名称", dataIndex: "orgName", width: 220, ellipsis: true },
|
||||
{ title: "机构类型", dataIndex: "orgType", width: 100 },
|
||||
{ title: "证书编号", dataIndex: "certNo", width: 140, ellipsis: true },
|
||||
{ title: "安全评价业务范围", dataIndex: "businessScope", width: 180, ellipsis: true },
|
||||
{
|
||||
title: "确认状态",
|
||||
dataIndex: "confirmStatus",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = VERIFY_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 140,
|
||||
fixed: "right",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`FilingDetail?id=${record.id}`)}>
|
||||
查看
|
||||
</Button>
|
||||
{record.confirmStatus === "pending" && (
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`QualReviewForm?id=${record.id}`)}>
|
||||
核验
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageLayout title="专家资料核验">
|
||||
|
||||
<SearchForm
|
||||
style={{ marginBottom: 24 }}
|
||||
form={form}
|
||||
loading={loading}
|
||||
formLine={[
|
||||
<Form.Item key="orgName" name="orgName">
|
||||
<ControlWrapper.Input label="机构名称" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="orgType" name="orgType">
|
||||
<ControlWrapper.Select
|
||||
label="机构类型"
|
||||
placeholder="请输入"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="本地机构">本地机构</Select.Option>
|
||||
<Select.Option value="异地机构">异地机构</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
key="businessScope"
|
||||
name="businessScope"
|
||||
>
|
||||
<ControlWrapper.Select
|
||||
label="安全评价业务范围"
|
||||
placeholder="请输入"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="石油加工">石油加工</Select.Option>
|
||||
<Select.Option value="化工">化工</Select.Option>
|
||||
<Select.Option value="矿山">矿山</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="confirmStatus" name="confirmStatus">
|
||||
<ControlWrapper.Select
|
||||
label="确认状态"
|
||||
placeholder="请输入"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="pending">待确认</Select.Option>
|
||||
<Select.Option value="passed">确认通过</Select.Option>
|
||||
<Select.Option value="rejected">打回</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
]}
|
||||
onReset={handleReset}
|
||||
onFinish={(values) => {
|
||||
router.query={
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
}
|
||||
handleSearch();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={MOCK_DATA}
|
||||
scroll={{ y: props.scrollY }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: MOCK_DATA.length,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
current: router.query.current,
|
||||
pageSize: router.query.pageSize,
|
||||
onChange: (page, pageSize) => {
|
||||
|
||||
router.query={
|
||||
...router.query,
|
||||
current: page,
|
||||
pageSize,
|
||||
};
|
||||
handleSearch();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AntdTableFuncControl(ExpertVerification);
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import React, { useMemo } from "react";
|
||||
import { Tag, Space } from "antd";
|
||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||
import { REVIEW_STATUS_MAP } from "~/enumerate/constant";
|
||||
import { MOCK_DETAIL } from "../mockData";
|
||||
import FilingTabs from "../FilingTabs";
|
||||
|
||||
function parseQueryId(location) {
|
||||
const search = location?.search || window.location.search || "";
|
||||
return new URLSearchParams(search).get("id");
|
||||
}
|
||||
|
||||
const FilingDetail = (props) => {
|
||||
const id = useMemo(() => parseQueryId(props.location), [props.location?.search]);
|
||||
const detail = MOCK_DETAIL;
|
||||
const statusConfig = REVIEW_STATUS_MAP[detail.reviewStatus];
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
title={
|
||||
<Space>
|
||||
<span>备案申请详情</span>
|
||||
{statusConfig && <Tag color={statusConfig.color}>{statusConfig.label}</Tag>}
|
||||
</Space>
|
||||
}
|
||||
history={props.history}
|
||||
previous
|
||||
>
|
||||
<FilingTabs detail={detail} />
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilingDetail;
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Form, Select, Space, 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 { CHANGE_STATUS_MAP } from "~/enumerate/constant";
|
||||
|
||||
const MOCK_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
orgName: "重庆安评技术研究院有限公司",
|
||||
orgType: "本地机构",
|
||||
filingNo: "BA-2026-001",
|
||||
businessScope: "化工",
|
||||
changeItem: "法定代表人变更",
|
||||
changeStatus: "pending",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orgName: "重庆恒安安全评价有限公司",
|
||||
orgType: "本地机构",
|
||||
filingNo: "BA-2025-032",
|
||||
businessScope: "化工, 建筑施工",
|
||||
changeItem: "注册地址变更",
|
||||
changeStatus: "stuck",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orgName: "北京中安评价中心(重庆分公司)",
|
||||
orgType: "异地机构",
|
||||
filingNo: "BA-2026-015",
|
||||
businessScope: "矿山",
|
||||
changeItem: "业务范围变更",
|
||||
changeStatus: "approved",
|
||||
},
|
||||
];
|
||||
|
||||
const { router } = tools;
|
||||
|
||||
const QualChange = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = () => {
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 500);
|
||||
};
|
||||
|
||||
const handleReset = (values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "id",
|
||||
width: 60,
|
||||
fixed: "left",
|
||||
render: (text, record, index) => index + 1,
|
||||
},
|
||||
{ title: "机构名称", dataIndex: "orgName", width: 220, ellipsis: true },
|
||||
{ title: "机构类型", dataIndex: "orgType", width: 100 },
|
||||
{ title: "备案编号", dataIndex: "filingNo", width: 140, ellipsis: true },
|
||||
{ title: "安全评价业务范围", dataIndex: "businessScope", width: 180, ellipsis: true },
|
||||
{ title: "变更项", dataIndex: "changeItem", width: 140, ellipsis: true },
|
||||
{
|
||||
title: "变更状态",
|
||||
dataIndex: "changeStatus",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = CHANGE_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 140,
|
||||
fixed: "right",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`FilingDetail?id=${record.id}`)}>
|
||||
查看
|
||||
</Button>
|
||||
{record.changeStatus !== "approved" && (
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`QualReviewForm?id=${record.id}`)}>
|
||||
审核
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageLayout title="备案变更管理">
|
||||
<SearchForm
|
||||
style={{ marginBottom: 24 }}
|
||||
form={form}
|
||||
loading={loading}
|
||||
formLine={[
|
||||
<Form.Item key="orgName" name="orgName">
|
||||
<ControlWrapper.Input label="机构名称" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="filingNo" name="filingNo">
|
||||
<ControlWrapper.Input label="备案编号" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="businessScope" name="businessScope">
|
||||
<ControlWrapper.Select
|
||||
label="安全评价业务范围"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="石油加工">石油加工</Select.Option>
|
||||
<Select.Option value="化工">化工</Select.Option>
|
||||
<Select.Option value="矿山">矿山</Select.Option>
|
||||
<Select.Option value="建筑施工">建筑施工</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="changeStatus" name="changeStatus">
|
||||
<ControlWrapper.Select
|
||||
label="变更状态"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="stuck">停滞中</Select.Option>
|
||||
<Select.Option value="pending">待审核</Select.Option>
|
||||
<Select.Option value="approved">已审核</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
]}
|
||||
onReset={handleReset}
|
||||
onFinish={(values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={MOCK_DATA}
|
||||
scroll={{ y: props.scrollY }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: MOCK_DATA.length,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
current: router.query.current,
|
||||
pageSize: router.query.pageSize,
|
||||
onChange: (page, pageSize) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
current: page,
|
||||
pageSize,
|
||||
};
|
||||
handleSearch();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AntdTableFuncControl(QualChange);
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Form, Select, Space, 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 { VERIFY_STATUS_MAP } from "~/enumerate/constant";
|
||||
|
||||
const MOCK_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
orgName: "重庆恒安安全评价有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2025-032",
|
||||
businessScope: "化工, 建筑施工",
|
||||
confirmStatus: "pending",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orgName: "重庆安环检测技术有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2025-028",
|
||||
businessScope: "矿山",
|
||||
confirmStatus: "passed",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orgName: "上海安信评价中心(重庆办)",
|
||||
orgType: "异地机构",
|
||||
certNo: "API-2025-045",
|
||||
businessScope: "石油加工",
|
||||
confirmStatus: "rejected",
|
||||
},
|
||||
];
|
||||
|
||||
const { router } = tools;
|
||||
|
||||
const QualConfirm = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = () => {
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 500);
|
||||
};
|
||||
|
||||
const handleReset = (values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "id",
|
||||
width: 60,
|
||||
fixed: "left",
|
||||
render: (text, record, index) => index + 1,
|
||||
},
|
||||
{ title: "机构名称", dataIndex: "orgName", width: 220, ellipsis: true },
|
||||
{ title: "机构类型", dataIndex: "orgType", width: 100 },
|
||||
{ title: "证书编号", dataIndex: "certNo", width: 140, ellipsis: true },
|
||||
{ title: "安全评价业务范围", dataIndex: "businessScope", width: 180, ellipsis: true },
|
||||
{
|
||||
title: "确认状态",
|
||||
dataIndex: "confirmStatus",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = VERIFY_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 140,
|
||||
fixed: "right",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`FilingDetail?id=${record.id}`)}>
|
||||
查看
|
||||
</Button>
|
||||
{record.confirmStatus !== "passed" && (
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`QualConfirmForm?id=${record.id}`)}>
|
||||
确认
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageLayout title="资质备案确认">
|
||||
<SearchForm
|
||||
style={{ marginBottom: 24 }}
|
||||
form={form}
|
||||
loading={loading}
|
||||
formLine={[
|
||||
<Form.Item key="orgName" name="orgName">
|
||||
<ControlWrapper.Input label="机构名称" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="orgType" name="orgType">
|
||||
<ControlWrapper.Select
|
||||
label="机构类型"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="本地机构">本地机构</Select.Option>
|
||||
<Select.Option value="异地机构">异地机构</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="businessScope" name="businessScope">
|
||||
<ControlWrapper.Select
|
||||
label="安全评价业务范围"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="石油加工">石油加工</Select.Option>
|
||||
<Select.Option value="化工">化工</Select.Option>
|
||||
<Select.Option value="矿山">矿山</Select.Option>
|
||||
<Select.Option value="建筑施工">建筑施工</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="confirmStatus" name="confirmStatus">
|
||||
<ControlWrapper.Select
|
||||
label="确认状态"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="pending">待确认</Select.Option>
|
||||
<Select.Option value="passed">确认通过</Select.Option>
|
||||
<Select.Option value="rejected">打回</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
]}
|
||||
onReset={handleReset}
|
||||
onFinish={(values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={MOCK_DATA}
|
||||
scroll={{ y: props.scrollY }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: MOCK_DATA.length,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
current: router.query.current,
|
||||
pageSize: router.query.pageSize,
|
||||
onChange: (page, pageSize) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
current: page,
|
||||
pageSize,
|
||||
};
|
||||
handleSearch();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AntdTableFuncControl(QualConfirm);
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
.qual-confirm-form {
|
||||
.summary-card {
|
||||
background: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.summary-card-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.summary-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-size: 0.72rem;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 0.88rem;
|
||||
font-weight: 500;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.analysis-card {
|
||||
background: #f8fafc;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.analysis-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.analysis-item {
|
||||
background: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.analysis-number {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
margin: 0.15rem 0;
|
||||
|
||||
&.green {
|
||||
color: #52c41a;
|
||||
}
|
||||
}
|
||||
|
||||
.analysis-warning {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.4rem 0.6rem;
|
||||
background: #fffbeb;
|
||||
border: 1px solid #fde68a;
|
||||
border-radius: 6px;
|
||||
font-size: 0.78rem;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.opinion-card {
|
||||
background: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.opinion-grid {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.opinion-label {
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.footer-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import React, { useState } from "react";
|
||||
import { Button, Select, Tag, Space, Input } from "antd";
|
||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||
import { MOCK_DETAIL, MOCK_MATERIALS, MOCK_PERSONNEL } from "../mockData";
|
||||
import "./indes.less";
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const LIST_PATH = "./../";
|
||||
|
||||
const QualConfirmForm = (props) => {
|
||||
const [result, setResult] = useState(undefined);
|
||||
const [opinion, setOpinion] = useState("");
|
||||
const detail = MOCK_DETAIL;
|
||||
|
||||
const totalCount = MOCK_MATERIALS.length;
|
||||
const qualifiedCount = 8; // mock 符合数
|
||||
const isPersonnelMet = MOCK_PERSONNEL.length >= 25;
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log("确认提交:", { result, opinion });
|
||||
// TODO: 调用接口
|
||||
};
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
title={
|
||||
<Space>
|
||||
<span>资质备案确认</span>
|
||||
<Tag color="warning">待确认</Tag>
|
||||
</Space>
|
||||
}
|
||||
history={props.history}
|
||||
previous
|
||||
>
|
||||
<div className="qual-confirm-form">
|
||||
{/* 基本信息 */}
|
||||
<div className="summary-card">
|
||||
<div className="summary-card-title">基本信息</div>
|
||||
<div className="summary-card-grid">
|
||||
<div>
|
||||
<div className="summary-label">机构名称</div>
|
||||
<div className="summary-value">{detail.orgName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="summary-label">证书编号</div>
|
||||
<div className="summary-value">{detail.certNo}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="summary-label">业务范围</div>
|
||||
<div className="summary-value">{detail.scopeName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="summary-label">提交时间</div>
|
||||
<div className="summary-value">2026-06-20</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 分析结果 */}
|
||||
<div className="analysis-card">
|
||||
<div className="summary-card-title">分析结果</div>
|
||||
<div className="analysis-grid">
|
||||
<div className="analysis-item">
|
||||
<div className="summary-label">备案材料核验</div>
|
||||
<div className="analysis-number green">{totalCount}/{totalCount}</div>
|
||||
<div className="summary-label">全部已上传</div>
|
||||
</div>
|
||||
<div className="analysis-item">
|
||||
<div className="summary-label">材料符合性</div>
|
||||
<div className="analysis-number green">{qualifiedCount}/{totalCount}</div>
|
||||
<div className="summary-label">符合要求</div>
|
||||
</div>
|
||||
<div className="analysis-item">
|
||||
<div className="summary-label">人员配备</div>
|
||||
<div className="analysis-number" style={{ color: isPersonnelMet ? "#52c41a" : "#faad14" }}>
|
||||
{MOCK_PERSONNEL.length}/25
|
||||
</div>
|
||||
<div className="summary-label">{isPersonnelMet ? "满足要求" : "不满足要求"}</div>
|
||||
</div>
|
||||
</div>
|
||||
{!isPersonnelMet && (
|
||||
<div className="analysis-warning">
|
||||
当前备案人员{MOCK_PERSONNEL.length}人,需满足专职技术人员不少于25人的要求,建议机构补充人员后再确认。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{/* 确认意见 */}
|
||||
<div className="opinion-card">
|
||||
<div className="summary-card-title">确认意见</div>
|
||||
<div className="opinion-grid">
|
||||
<div>
|
||||
<div className="opinion-label">确认结果</div>
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
placeholder="请选择"
|
||||
value={result}
|
||||
onChange={setResult}
|
||||
>
|
||||
<Select.Option value="passed">确认通过</Select.Option>
|
||||
<Select.Option value="rejected">打回</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<div className="opinion-label">确认意见</div>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="请输入确认意见..."
|
||||
value={opinion}
|
||||
onChange={(e) => setOpinion(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<div className="footer-bar">
|
||||
<Button onClick={() => props.history?.push(LIST_PATH)}>取消</Button>
|
||||
<Button type="primary" onClick={handleSubmit}>提交确认</Button>
|
||||
</div>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default QualConfirmForm;
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Form, Select, Space, Table, Tag, Modal, Input, DatePicker } 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 { PUBLICITY_STATUS_MAP } from "~/enumerate/constant";
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const MOCK_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
orgName: "重庆安评技术研究院有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2026-001",
|
||||
businessScope: "化工, 石油加工",
|
||||
reviewDept: "市应急管理局",
|
||||
reviewTime: "2026-06-20",
|
||||
status: "pending",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orgName: "重庆恒安安全评价有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2025-032",
|
||||
businessScope: "化工",
|
||||
reviewDept: "市应急管理局",
|
||||
reviewTime: "2026-05-15",
|
||||
status: "published",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orgName: "北京中安评价中心(重庆分公司)",
|
||||
orgType: "异地机构",
|
||||
certNo: "API-2026-015",
|
||||
businessScope: "矿山, 建筑施工",
|
||||
reviewDept: "市应急管理局",
|
||||
reviewTime: "2026-06-18",
|
||||
status: "pending",
|
||||
},
|
||||
];
|
||||
|
||||
const { router } = tools;
|
||||
|
||||
const QualPublicity = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [publicityVisible, setPublicityVisible] = useState(false);
|
||||
const [publicityTarget, setPublicityTarget] = useState(null);
|
||||
const [publicityDept, setPublicityDept] = useState(undefined);
|
||||
const [publicityContent, setPublicityContent] = useState("");
|
||||
const [publicityStartDate, setPublicityStartDate] = useState(null);
|
||||
const [publicityEndDate, setPublicityEndDate] = useState(null);
|
||||
|
||||
const openPublicity = (record) => {
|
||||
setPublicityTarget(record);
|
||||
setPublicityDept(undefined);
|
||||
setPublicityContent(
|
||||
"依据《安全评价机构管理规定》等相关法规,经审核,该机构符合安全评价机构资质条件,现予以公示,接受社会监督。"
|
||||
);
|
||||
setPublicityStartDate(null);
|
||||
setPublicityEndDate(null);
|
||||
setPublicityVisible(true);
|
||||
};
|
||||
|
||||
const handlePublicitySubmit = () => {
|
||||
console.log("公示提交:", {
|
||||
target: publicityTarget,
|
||||
dept: publicityDept,
|
||||
content: publicityContent,
|
||||
startDate: publicityStartDate,
|
||||
endDate: publicityEndDate,
|
||||
});
|
||||
setPublicityVisible(false);
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 500);
|
||||
};
|
||||
|
||||
const handleReset = (values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "id",
|
||||
width: 60,
|
||||
fixed: "left",
|
||||
render: (text, record, index) => index + 1,
|
||||
},
|
||||
{ title: "机构名称", dataIndex: "orgName", width: 220, ellipsis: true },
|
||||
{ title: "机构类型", dataIndex: "orgType", width: 100 },
|
||||
{ title: "证书编号", dataIndex: "certNo", width: 140, ellipsis: true },
|
||||
{ title: "安全评价业务范围", dataIndex: "businessScope", width: 180, ellipsis: true },
|
||||
{ title: "审核部门", dataIndex: "reviewDept", width: 120, ellipsis: true },
|
||||
{ title: "审核通过时间", dataIndex: "reviewTime", width: 120 },
|
||||
{
|
||||
title: "公示状态",
|
||||
dataIndex: "status",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = PUBLICITY_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 180,
|
||||
fixed: "right",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`FilingDetail?id=${record.id}`)}>
|
||||
查看
|
||||
</Button>
|
||||
{record.status === "pending" && (
|
||||
<Button type="link" size="small" onClick={() => openPublicity(record)}>
|
||||
公示
|
||||
</Button>
|
||||
)}
|
||||
<Button type="link" size="small">
|
||||
公示信息
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageLayout title="备案公示管理">
|
||||
<SearchForm
|
||||
style={{ marginBottom: 24 }}
|
||||
form={form}
|
||||
loading={loading}
|
||||
formLine={[
|
||||
<Form.Item key="orgName" name="orgName">
|
||||
<ControlWrapper.Input label="机构名称" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="orgType" name="orgType">
|
||||
<ControlWrapper.Select
|
||||
label="机构类型"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="本地机构">本地机构</Select.Option>
|
||||
<Select.Option value="异地机构">异地机构</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="businessScope" name="businessScope">
|
||||
<ControlWrapper.Select
|
||||
label="安全评价业务范围"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="石油加工">石油加工</Select.Option>
|
||||
<Select.Option value="化工">化工</Select.Option>
|
||||
<Select.Option value="矿山">矿山</Select.Option>
|
||||
<Select.Option value="建筑施工">建筑施工</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="status" name="status">
|
||||
<ControlWrapper.Select
|
||||
label="公示状态"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="pending">待公示</Select.Option>
|
||||
<Select.Option value="published">已公示</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
]}
|
||||
onReset={handleReset}
|
||||
onFinish={(values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={MOCK_DATA}
|
||||
scroll={{ y: props.scrollY }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: MOCK_DATA.length,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
current: router.query.current,
|
||||
pageSize: router.query.pageSize,
|
||||
onChange: (page, pageSize) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
current: page,
|
||||
pageSize,
|
||||
};
|
||||
handleSearch();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="备案公示"
|
||||
open={publicityVisible}
|
||||
onCancel={() => setPublicityVisible(false)}
|
||||
width={560}
|
||||
footer={
|
||||
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
|
||||
<Button onClick={() => setPublicityVisible(false)}>取消</Button>
|
||||
<Button type="primary" onClick={handlePublicitySubmit}>提交公示</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div style={{ display: "grid", gap: "0.8rem" }}>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>公示信息</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>机构名称</div>
|
||||
<div style={{ fontSize: "0.88rem", fontWeight: 500 }}>{publicityTarget?.orgName || "—"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>公示部门</div>
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
placeholder="请选择"
|
||||
value={publicityDept}
|
||||
onChange={setPublicityDept}
|
||||
>
|
||||
<Select.Option value="city">市应急管理局</Select.Option>
|
||||
<Select.Option value="district">县区应急管理局</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>公示内容</div>
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="请输入公示内容..."
|
||||
value={publicityContent}
|
||||
onChange={(e) => setPublicityContent(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.5rem" }}>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>公示开始时间</div>
|
||||
<DatePicker
|
||||
style={{ width: "100%" }}
|
||||
placeholder="请选择"
|
||||
value={publicityStartDate}
|
||||
onChange={setPublicityStartDate}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>公示结束时间</div>
|
||||
<DatePicker
|
||||
style={{ width: "100%" }}
|
||||
placeholder="请选择"
|
||||
value={publicityEndDate}
|
||||
onChange={setPublicityEndDate}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AntdTableFuncControl(QualPublicity);
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Form, Select, Space, 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 { REVIEW_STATUS_MAP, EXPERT_STATUS_MAP } from "~/enumerate/constant";
|
||||
|
||||
// 静态模拟数据
|
||||
const MOCK_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
orgName: "重庆安评技术研究院有限公司",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2026-001",
|
||||
businessScope: "化工, 石油加工",
|
||||
expertStatus: "pending",
|
||||
reviewStatus: "pending",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orgName: "北京中安评价中心(重庆分公司)",
|
||||
orgType: "异地机构",
|
||||
certNo: "API-2026-015",
|
||||
businessScope: "矿山, 建筑施工",
|
||||
expertStatus: "arranging",
|
||||
reviewStatus: "reviewing",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orgName: "重庆渝安风险评估中心",
|
||||
orgType: "本地机构",
|
||||
certNo: "API-2026-008",
|
||||
businessScope: "化工",
|
||||
expertStatus: "none",
|
||||
reviewStatus: "rejected",
|
||||
},
|
||||
];
|
||||
|
||||
const { router } = tools;
|
||||
|
||||
const QualReview = (props) => {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const handleSearch = () => {
|
||||
setLoading(true);
|
||||
setTimeout(() => setLoading(false), 500);
|
||||
};
|
||||
|
||||
const handleReset = (values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(router.query);
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "序号",
|
||||
dataIndex: "id",
|
||||
width: 60,
|
||||
fixed: "left",
|
||||
render: (text, record, index) => index + 1,
|
||||
},
|
||||
{ title: "机构名称", dataIndex: "orgName", width: 220, ellipsis: true },
|
||||
{ title: "机构类型", dataIndex: "orgType", width: 100 },
|
||||
{ title: "证书编号", dataIndex: "certNo", width: 140, ellipsis: true },
|
||||
{ title: "安全评价业务范围", dataIndex: "businessScope", width: 180, ellipsis: true },
|
||||
{
|
||||
title: "专家核验",
|
||||
dataIndex: "expertStatus",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = EXPERT_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : '--';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "审核状态",
|
||||
dataIndex: "reviewStatus",
|
||||
width: 100,
|
||||
render: (status) => {
|
||||
const config = REVIEW_STATUS_MAP[status];
|
||||
return config ? <Tag color={config.color}>{config.label}</Tag> : '--';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
width: 140,
|
||||
fixed: "right",
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`FilingDetail?id=${record.id}`)}>
|
||||
查看
|
||||
</Button>
|
||||
{record.reviewStatus === "pending" && (
|
||||
<Button type="link" size="small" onClick={() => props.history.push(`QualReviewForm?id=${record.id}`)}>
|
||||
审核
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageLayout title="资质备案审核">
|
||||
<SearchForm
|
||||
style={{ marginBottom: 24 }}
|
||||
form={form}
|
||||
loading={loading}
|
||||
formLine={[
|
||||
<Form.Item key="orgName" name="orgName">
|
||||
<ControlWrapper.Input label="机构名称" placeholder="请输入" allowClear />
|
||||
</Form.Item>,
|
||||
<Form.Item key="orgType" name="orgType">
|
||||
<ControlWrapper.Select
|
||||
label="机构类型"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="本地机构">本地机构</Select.Option>
|
||||
<Select.Option value="异地机构">异地机构</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="businessScope" name="businessScope">
|
||||
<ControlWrapper.Select
|
||||
label="安全评价业务范围"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="石油加工">石油加工</Select.Option>
|
||||
<Select.Option value="化工">化工</Select.Option>
|
||||
<Select.Option value="矿山">矿山</Select.Option>
|
||||
<Select.Option value="建筑施工">建筑施工</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="needExpertCheck" name="needExpertCheck">
|
||||
<ControlWrapper.Select
|
||||
label="是否专家核验"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="yes">是</Select.Option>
|
||||
<Select.Option value="no">否</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
<Form.Item key="reviewStatus" name="reviewStatus">
|
||||
<ControlWrapper.Select
|
||||
label="审核状态"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<Select.Option value="pending">待审核</Select.Option>
|
||||
<Select.Option value="reviewing">审核中</Select.Option>
|
||||
<Select.Option value="rejected">打回</Select.Option>
|
||||
</ControlWrapper.Select>
|
||||
</Form.Item>,
|
||||
]}
|
||||
onReset={handleReset}
|
||||
onFinish={(values) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
...values,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleSearch();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={MOCK_DATA}
|
||||
scroll={{ y: props.scrollY }}
|
||||
loading={loading}
|
||||
pagination={{
|
||||
total: MOCK_DATA.length,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条`,
|
||||
current: router.query.current,
|
||||
pageSize: router.query.pageSize,
|
||||
onChange: (page, pageSize) => {
|
||||
router.query = {
|
||||
...router.query,
|
||||
current: page,
|
||||
pageSize,
|
||||
};
|
||||
handleSearch();
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AntdTableFuncControl(QualReview);
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
.qual-review-form {
|
||||
// 法律规定内容
|
||||
.legal-check-bar {
|
||||
background: #f8fafc;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
padding: 0.6rem 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.legal-check-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.legal-check-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.legal-check-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.4rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.legal-check-item-desc {
|
||||
font-size: 0.72rem;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
// 底部操作栏
|
||||
.footer-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
import React, { useState } from "react";
|
||||
import { Button, Tag, Space, Modal, Select, Input } from "antd";
|
||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||
import { REVIEW_STATUS_MAP } from "~/enumerate/constant";
|
||||
import { MOCK_DETAIL, MOCK_MATERIALS, LEGAL_CHECK_ITEMS, LEGAL_STATUS_STYLE } from "../mockData";
|
||||
import FilingTabs from "../FilingTabs";
|
||||
import "./indes.less";
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
const QualReviewForm = (props) => {
|
||||
const [compliance, setCompliance] = useState({});
|
||||
const [reviewVisible, setReviewVisible] = useState(false);
|
||||
const [reviewResult, setReviewResult] = useState(undefined);
|
||||
const [expert, setExpert] = useState(undefined);
|
||||
const [remark, setRemark] = useState("");
|
||||
const detail = MOCK_DETAIL;
|
||||
const statusConfig = REVIEW_STATUS_MAP[detail.reviewStatus];
|
||||
|
||||
const passCount = Object.values(compliance).filter((v) => v === "pass").length;
|
||||
const failCount = Object.values(compliance).filter((v) => v === "fail").length;
|
||||
const evaluatedCount = passCount + failCount;
|
||||
const unmetCount = MOCK_MATERIALS.length - evaluatedCount;
|
||||
|
||||
const handleSubmit = (action) => {
|
||||
console.log("审核提交:", { action, reviewResult, expert, remark, compliance });
|
||||
setReviewVisible(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
title={
|
||||
<Space>
|
||||
<span>资质备案审核</span>
|
||||
{statusConfig && <Tag color={statusConfig.color}>{statusConfig.label}</Tag>}
|
||||
</Space>
|
||||
}
|
||||
history={props.history}
|
||||
previous
|
||||
footer={<Button type="primary" onClick={() => setReviewVisible(true)}>审核操作</Button>}
|
||||
>
|
||||
<div className="qual-review-form">
|
||||
<div className="legal-check-bar">
|
||||
<div className="legal-check-title">法律规定内容</div>
|
||||
<div className="legal-check-grid">
|
||||
{LEGAL_CHECK_ITEMS.map((item) => {
|
||||
const style = LEGAL_STATUS_STYLE[item.status];
|
||||
return (
|
||||
<div key={item.key} className="legal-check-item" style={{ borderLeft: `3px solid ${style.borderColor}`, background: style.bg }}>
|
||||
<span>{style.icon}</span>
|
||||
<div>
|
||||
<div style={{ fontWeight: 500 }}>{item.title}</div>
|
||||
<div className="legal-check-item-desc">{item.desc}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FilingTabs
|
||||
detail={detail}
|
||||
isReview
|
||||
compliance={compliance}
|
||||
onComplianceChange={(id, v) => setCompliance((prev) => ({ ...prev, [id]: v }))}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="审核操作"
|
||||
open={reviewVisible}
|
||||
onCancel={() => setReviewVisible(false)}
|
||||
width={580}
|
||||
footer={
|
||||
<div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
|
||||
<Button onClick={() => setReviewVisible(false)}>取消</Button>
|
||||
<Button type="primary" onClick={() => handleSubmit("submit")}>提交</Button>
|
||||
<Button type="primary" style={{ background: "#52c41a", borderColor: "#52c41a" }} onClick={() => handleSubmit("pass")}>通过</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div style={{ background: "#f8fafc", border: "1px solid #d9d9d9", borderRadius: 6, padding: "0.75rem", marginBottom: "1rem" }}>
|
||||
<div style={{ fontSize: "0.88rem", fontWeight: 600, marginBottom: "0.5rem" }}>评价分析</div>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: "0.4rem" }}>
|
||||
<div style={statStyle}><div style={statLabelStyle}>已核验材料</div><div style={{ fontSize: "1.1rem", fontWeight: 700, color: "#1677ff" }}>{evaluatedCount}</div></div>
|
||||
<div style={statStyle}><div style={statLabelStyle}>符合</div><div style={{ fontSize: "1.1rem", fontWeight: 700, color: "#52c41a" }}>{passCount}</div></div>
|
||||
<div style={statStyle}><div style={statLabelStyle}>不符合</div><div style={{ fontSize: "1.1rem", fontWeight: 700, color: "#ff4d4f" }}>{failCount}</div></div>
|
||||
<div style={statStyle}><div style={statLabelStyle}>条件未满足</div><div style={{ fontSize: "1.1rem", fontWeight: 700, color: "#faad14" }}>{unmetCount}</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "grid", gap: "0.6rem" }}>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>审核结果</div>
|
||||
<Select style={{ width: "100%" }} placeholder="请选择" value={reviewResult} onChange={setReviewResult}>
|
||||
<Select.Option value="pass">通过</Select.Option>
|
||||
<Select.Option value="pending">待定</Select.Option>
|
||||
<Select.Option value="reject">不通过</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>指派专家</div>
|
||||
<Select style={{ width: "100%" }} placeholder="— 请选择 —" value={expert} onChange={setExpert}>
|
||||
<Select.Option value="chen">陈教授(化工安全)</Select.Option>
|
||||
<Select.Option value="li">李教授(矿山安全)</Select.Option>
|
||||
<Select.Option value="wang">王高工(建筑施工)</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: "0.8rem", marginBottom: 4 }}>综合审核意见</div>
|
||||
<TextArea rows={3} placeholder="请输入综合审核意见..." value={remark} onChange={(e) => setRemark(e.target.value)} />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
const statStyle = { background: "#fff", border: "1px solid #d9d9d9", borderRadius: 6, padding: "0.4rem", textAlign: "center" };
|
||||
const statLabelStyle = { fontSize: "0.7rem", color: "rgba(0,0,0,0.45)" };
|
||||
|
||||
export default QualReviewForm;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from "react";
|
||||
|
||||
export default (props)=>{
|
||||
return (
|
||||
<div style={{height: "100%"}}>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
// 资质备案审核相关 mock 数据,FilingDetail 和 QualReviewForm 共享
|
||||
|
||||
export const MOCK_DETAIL = {
|
||||
id: 1,
|
||||
scopeName: "化工、石油加工",
|
||||
filingRegion: "重庆市渝北区",
|
||||
orgName: "重庆安评技术研究院有限公司",
|
||||
orgType: "本地单位",
|
||||
creditCode: "915001072028699512",
|
||||
officeAddress: "重庆市沙坪坝区大学城东路20号重庆科技学院第39栋西南角实习用房三楼",
|
||||
registerAddress: "同上",
|
||||
certNo: "API-2026-001",
|
||||
website: "www.cqap.com",
|
||||
legalPerson: "郑远平",
|
||||
legalPhone: "023-68705577",
|
||||
contactPerson: "陈芳",
|
||||
contactPhone: "139****9012",
|
||||
fixedAssets: "1200",
|
||||
officeArea: "1200 ㎡",
|
||||
archiveArea: "80 ㎡",
|
||||
evaluatorCount: "25 人",
|
||||
registerEngineerCount: "12 人",
|
||||
description: "重庆安评技术研究院成立于2015年,是一家专业从事安全评价、安全咨询、安全技术开发与转让的综合性安全技术服务机构。",
|
||||
reviewStatus: "pending",
|
||||
};
|
||||
|
||||
export const MOCK_MATERIALS = [
|
||||
{ id: 1, name: "申请材料目录(原件)", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 2, name: "申请书(原件)", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 3, name: "法人证明(复印件)", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 4, name: "三年内无重大违法失信记录查询证明", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 5, name: "法定代表人承诺书(原件)", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 6, name: "固定资产法定证明材料", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 7, name: "工作场所及档案室面积证明", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 8, name: "安全评价师专业能力证明", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 9, name: "相关负责人证明材料", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
{ id: 10, name: "机构内部管理制度", attachment: "纸质版扫描件", format: "pdf", status: "uploaded" },
|
||||
];
|
||||
|
||||
export const MOCK_PERSONNEL = [
|
||||
{ id: 1, name: "张建国", type: "评价师", position: "高级评价师", title: "高级工程师", ability: "化工工艺安全风险评估" },
|
||||
{ id: 2, name: "李明华", type: "评价师", position: "评价师", title: "工程师", ability: "矿山安全评价" },
|
||||
{ id: 3, name: "王丽萍", type: "管理人员", position: "人事主管", title: "—", ability: "人力资源管理" },
|
||||
{ id: 4, name: "陈志强", type: "评价师", position: "评价师", title: "工程师", ability: "建筑施工安全评估" },
|
||||
{ id: 5, name: "赵磊", type: "管理人员", position: "综合部主任", title: "—", ability: "安全管理体系" },
|
||||
];
|
||||
|
||||
export const MOCK_EQUIPMENT = [
|
||||
{ id: 1, name: "气相色谱仪", model: "GC-2018", manufacturer: "岛津", calibration: "done" },
|
||||
{ id: 2, name: "噪声计", model: "HS-6288", manufacturer: "杭州爱华", calibration: "done" },
|
||||
{ id: 3, name: "粉尘采样器", model: "FC-5A", manufacturer: "北京劳保所", calibration: "pending" },
|
||||
];
|
||||
|
||||
export const MOCK_EQUIP_DETAIL = {
|
||||
name: "气相色谱仪",
|
||||
model: "GC-2018",
|
||||
category: "分析仪器",
|
||||
type: "色谱检测类",
|
||||
manufacturer: "岛津",
|
||||
calibrationType: "定期检定",
|
||||
flowDesc: "载气流量 30mL/min",
|
||||
maxFlow: "100 mL/min",
|
||||
minFlow: "1 mL/min",
|
||||
dualChannel: "否",
|
||||
calibInitValue: "0.0001 mg/m³",
|
||||
calibUnit: "重庆市计量质量检测研究院",
|
||||
status: "done",
|
||||
};
|
||||
|
||||
export const MOCK_PERSONNEL_DETAIL = {
|
||||
name: "张建国",
|
||||
gender: "男",
|
||||
qualScope: "化工",
|
||||
birthDate: "1985-03-15",
|
||||
officeAddress: "重庆市渝北区龙山街道100号",
|
||||
major: "安全工程",
|
||||
certLevel: "安全评价师一级 / SJP-2020-****",
|
||||
email: "zhangjg@cqap.com",
|
||||
personnelType: "专职评价师",
|
||||
idCard: "500***********1234",
|
||||
currentAddress: "重庆市渝北区新牌坊某路某号",
|
||||
education: "全日制 · 本科",
|
||||
graduateSchool: "重庆大学",
|
||||
position: "高级评价师",
|
||||
isRegisterEngineer: "是",
|
||||
publications: "发表安全评价相关论文3篇,参与编制行业标准1项",
|
||||
selfDeclaration: "化工工艺安全风险评估,通过注册安全工程师资格考试认定",
|
||||
workExperience: "2008-2012 重庆大学 安全工程专业 本科;2012-至今 重庆安评技术研究院有限公司 评价师",
|
||||
};
|
||||
|
||||
export const MOCK_CERTIFICATES = [
|
||||
{ id: 1, name: "危险化学品经营许可证", certNo: "AQSC001", category: "安全生产证书", issuer: "重庆市应急管理局", startDate: "2025-03-29", endDate: "2028-03-28" },
|
||||
{ id: 2, name: "安全评价机构资质证书", certNo: "API-2026-001", category: "甲级资质", issuer: "重庆市应急管理局", startDate: "2026-01-15", endDate: "2029-01-14" },
|
||||
];
|
||||
|
||||
export const CALIBRATION_MAP = {
|
||||
done: { label: "已检定", color: "success" },
|
||||
pending: { label: "待检定", color: "warning" },
|
||||
};
|
||||
|
||||
export const LEGAL_CHECK_ITEMS = [
|
||||
{ key: "qualification", title: "主体资格", desc: "独立法人资格,固定资产不少于一千万元", status: "pass" },
|
||||
{ key: "facility", title: "场所与设备", desc: "工作场所建筑面积不少于1000㎡", status: "pass" },
|
||||
{ key: "staffCount", title: "人员数量与结构", desc: "专职技术人员≥25人,中级注安师≥30%", status: "pass" },
|
||||
{ key: "staffExp", title: "人员资历", desc: "专职技术人员在本行业领域工作二年以上", status: "pass" },
|
||||
{ key: "keyRole", title: "关键岗位要求", desc: "负责人具有高级职称,工作八年以上", status: "pass" },
|
||||
{ key: "management", title: "管理体系", desc: "需核验文件化管理体系是否符合要求", status: "warn" },
|
||||
{ key: "commitment", title: "责任承诺", desc: "法定代表人已出具承诺书", status: "pass" },
|
||||
{ key: "disclosure", title: "信息公开", desc: "未检测到公示网站", status: "fail" },
|
||||
{ key: "credit", title: "信用记录", desc: "三年内无重大违法失信记录", status: "pass" },
|
||||
{ key: "other", title: "其他", desc: "法律、行政法规规定的其他条件", status: "pass" },
|
||||
];
|
||||
|
||||
export const LEGAL_STATUS_STYLE = {
|
||||
pass: { icon: "✅", borderColor: "#059669", bg: "#f0fdf4" },
|
||||
warn: { icon: "⚠️", borderColor: "#d97706", bg: "#fffbeb" },
|
||||
fail: { icon: "❌", borderColor: "#dc2626", bg: "#fef2f2" },
|
||||
};
|
||||
|
|
@ -2,6 +2,7 @@ import { ImportCore } from "@cqsjjb/jjb-common-decorator/module";
|
|||
import { theme as antdTheme, App, ConfigProvider } from "antd";
|
||||
import language from "antd/locale/zh_CN";
|
||||
import React from "react";
|
||||
import "./index.less";
|
||||
|
||||
import { InjectContext } from "~/enumerate/context";
|
||||
import SimulatedLayout from "./Layout";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
.pageLayout-extra{
|
||||
margin: 0px 0px 24px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
.micro-temp-modal-body{
|
||||
max-height: 630px;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
body{
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.micro-temp-layout-container .micro-temp-lay-container-bottom{
|
||||
padding: 10px 24px !important;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
Loading…
Reference in New Issue