You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

605 lines
25 KiB
JavaScript

1 month ago
import React, { useEffect, useRef, useState } from 'react';
import { Card, Table, Tag, Space, Typography, Progress, Row, Col, Button, Input, Select } from 'antd';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './LicenseManagement.less';
import icon_echart from '@/assets/business_basic/icon_echart.svg';
const { Title } = Typography;
const { Search } = Input;
const { Option } = Select;
const LicenseManagement = () => {
const chartRef = useRef(null);
const [searchValue, setSearchValue] = useState('');
const [selectedType, setSelectedType] = useState('all');
// 图表数据
const chartData = [
{ name: '安全生产许可证', value: 35, itemStyle: { color: '#3C7DFF' } },
{ name: '安全评估报告', value: 25, itemStyle: { color: '#FF8800' } },
{ name: '安全三同时材料', value: 20, itemStyle: { color: '#FF3E48' } },
{ name: '施工资质证书', value: 15, itemStyle: { color: '#FFC403' } },
{ name: '应急预案', value: 10, itemStyle: { color: '#22C55E' } },
{ name: '其他', value: 5, itemStyle: { color: '#31BCFF' } }
];
// 初始化图表
useEffect(() => {
if (chartRef.current) {
const chart = echarts.init(chartRef.current);
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'horizontal',
bottom: 0,
left: 'center',
itemWidth: 14,
itemHeight: 4,
itemGap: 10,
textStyle: {
fontSize: 12,
color: '#333',
width: 100
},
formatter: function (name) {
return name;
},
data: (() => {
// 找到最长的名称长度
const maxLength = Math.max(...chartData.map(item => item.name.length));
// 将所有名称填充到相同长度
return chartData.map(item => {
const paddingLength = maxLength - item.name.length;
return item.name + ' '.repeat(paddingLength);
});
})()
},
series: [
{
name: '证件类型分布',
type: 'pie',
radius: ['20%', '65%'],
center: ['50%', '38%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 5,
// color:"red",/
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '16',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: (() => {
// 找到最长的名称长度
const maxLength = Math.max(...chartData.map(item => item.name.length));
// 将所有名称填充到相同长度
return chartData.map(item => ({
...item,
name: item.name + ' '.repeat(maxLength - item.name.length)
}));
})()
}
]
};
chart.setOption(option);
// 响应式处理
const handleResize = () => {
chart.resize();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
chart.dispose();
};
}
}, []);
// 表格数据
const tableData = [
{
key: '1',
no: '01',
name: '安全生产许可证',
type: '资质证书',
id: 'HQ-XF-01-001',
authority: '应急管理部',
validUntil: '2025-09-10',
status: '已过期',
statusType: 'error'
},
{
key: '2',
no: '02',
name: '安全预评估报告',
type: '安全三同时',
id: 'HQ-XF-02-015',
authority: '第三方评估机构',
validUntil: '2025-09-10',
status: '有效',
statusType: 'warning'
},
{
key: '3',
no: '03',
name: '施工资质证书',
type: '资质证书',
id: 'HQ-XF-03-007',
authority: '3设计院',
validUntil: '2025-09-10',
status: '有效',
statusType: 'success'
},
{
key: '4',
no: '04',
name: '安全标准化证书',
type: '资质证书',
id: 'HQ-XF-03-007',
authority: '第三方评估机构',
validUntil: '2025-09-10',
status: '有效',
statusType: 'success'
},
{
key: '5',
no: '05',
name: '消防验收合格证',
type: '消防证书',
id: 'HQ-XF-05-012',
authority: '消防局',
validUntil: '2026-03-15',
status: '有效',
statusType: 'success'
},
{
key: '6',
no: '06',
name: '职业健康安全管理体系认证',
type: '管理体系认证',
id: 'HQ-XF-06-008',
authority: '认证机构',
validUntil: '2026-06-20',
status: '有效',
statusType: 'success'
},
{
key: '7',
no: '07',
name: '环境管理体系认证',
type: '管理体系认证',
id: 'HQ-XF-07-009',
authority: '认证机构',
validUntil: '2026-08-25',
status: '有效',
statusType: 'success'
},
{
key: '8',
no: '08',
name: '特种设备使用登记证',
type: '特种设备证书',
id: 'HQ-XF-08-011',
authority: '质量技术监督局',
validUntil: '2026-12-10',
status: '有效',
statusType: 'success'
},
{
key: '9',
no: '09',
name: '危险化学品经营许可证',
type: '经营许可证',
id: 'HQ-XF-09-013',
authority: '应急管理局',
validUntil: '2027-01-30',
status: '有效',
statusType: 'success'
},
{
key: '10',
no: '10',
name: '辐射安全许可证',
type: '辐射安全证书',
id: 'HQ-XF-10-014',
authority: '生态环境部',
validUntil: '2027-04-18',
status: '有效',
statusType: 'success'
}
];
// 表格列定义
const columns = [
{
title: '编号',
dataIndex: 'no',
key: 'no',
width: 80,
},
{
title: '证照名称',
dataIndex: 'name',
key: 'name',
width: 150,
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
width: 120,
},
{
title: '编号',
dataIndex: 'id',
key: 'id',
width: 150,
},
{
title: '发证机关',
dataIndex: 'authority',
key: 'authority',
width: 150,
},
{
title: '有效期至',
dataIndex: 'validUntil',
key: 'validUntil',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 120,
render: (text, record) => {
const getStatusStyle = (status) => {
if (status === '有效') {
return {
color: '#44BB5F',
backgroundColor: '#D8F7DE',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
display: 'inline-block'
};
} else if (status === '即将到期') {
return {
color: '#FF8800',
backgroundColor: '#FFF3E9',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
display: 'inline-block'
};
} else if (status === '已过期') {
return {
color: '#FF3E48',
backgroundColor: '#FFE0E2',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
display: 'inline-block'
};
}
return {};
};
return (
<span style={getStatusStyle(text)}>
{text}
</span>
);
}
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
width: 120,
render: (text, record) => {
const handleEdit = (record) => {
console.log('编辑记录:', record);
};
const handleDelete = (record) => {
console.log('删除记录:', record);
};
return (
<div style={{
display: 'flex',
gap: '8px',
justifyContent: 'center',
alignItems: 'center'
}}>
<Button
onClick={() => handleEdit(record)}
style={{
color: '#2E4CD4',
backgroundColor: 'transparent',
// borderColor: '#E6E9FB',
fontSize: '12px',
height: '28px',
padding: '0 12px'
}}
>
更新
</Button>
<Button
onClick={() => handleDelete(record)}
style={{
color: '#2E4CD4',
backgroundColor: 'transparent',
// borderColor: '#E6E9FB',
fontSize: '12px',
height: '28px',
padding: '0 12px'
}}
>
查看
</Button>
</div>
);
}
},
];
return (
<div className={styles.licenseManagementContainer}>
<div className={styles.topSectionContainer}>
<div className={styles.firstBlock}>
<div className={styles.chartHeader}>
<div className={styles.colorBlock}></div>
<span className={styles.chartTitle}>证件类型分布</span>
</div>
<div className={styles.chartContainer}>
<div ref={chartRef} className={styles.chart}></div>
</div>
</div>
<div className={styles.secondBlock}>
<div className={styles.chartHeader}>
<div className={styles.colorBlock}></div>
<span className={styles.chartTitle}>证件状态概览</span>
</div>
<div className={styles.chartContainer}>
{/* 上半部分:进度条和百分比 */}
<div className={styles.progressSection}>
<div className={styles.progressItem}>
<div className={styles.progressLabel}>有效证照</div>
<div className={styles.progressWrapper}>
<Progress
percent={50}
strokeColor="#3C7DFF"
trailColor="#F0F0F0"
showInfo={false}
className={styles.customProgress}
/>
<span className={styles.progressPercent}>50%</span>
</div>
</div>
<div className={styles.progressItem}>
<div className={styles.progressLabel}>即将到期</div>
<div className={styles.progressWrapper}>
<Progress
percent={15}
strokeColor="#FFC403"
trailColor="#F0F0F0"
showInfo={false}
className={styles.customProgress}
/>
<span className={styles.progressPercent}>15%</span>
</div>
</div>
<div className={styles.progressItem}>
<div className={styles.progressLabel}>已过期</div>
<div className={styles.progressWrapper}>
<Progress
percent={20}
strokeColor="#FF3E48"
trailColor="#F0F0F0"
showInfo={false}
className={styles.customProgress}
/>
<span className={styles.progressPercent}>20%</span>
</div>
</div>
<div className={styles.progressItem}>
<div className={styles.progressLabel}>待审核材料</div>
<div className={styles.progressWrapper}>
<Progress
percent={15}
strokeColor="#FF8800"
trailColor="#F0F0F0"
showInfo={false}
className={styles.customProgress}
/>
<span className={styles.progressPercent}>15%</span>
</div>
</div>
</div>
{/* 下半部分:数字统计 */}
<div className={styles.statsSection}>
<Row gutter={[16, 16]}>
<Col span={6}>
<div className={styles.statItem}>
<div className={styles.statNumber} style={{ color: '#3C7DFF' }}>42</div>
<div className={styles.statLabel}>总证照数</div>
</div>
</Col>
<Col span={6}>
<div className={styles.statItem}>
<div className={styles.statNumber} style={{ color: '#FFC403' }}>8</div>
<div className={styles.statLabel}>即将过期</div>
</div>
</Col>
<Col span={6}>
<div className={styles.statItem}>
<div className={styles.statNumber} style={{ color: '#FF3E48' }}>6</div>
<div className={styles.statLabel}>已过期</div>
</div>
</Col>
<Col span={6}>
<div className={styles.statItem}>
<div className={styles.statNumber} style={{ color: '#FF8800' }}>6</div>
<div className={styles.statLabel}>待审核材料</div>
</div>
</Col>
</Row>
</div>
</div>
</div>
<div className={styles.thirdBlock}>
<div className={styles.chartHeader}>
<div className={styles.colorBlock}></div>
<span className={styles.chartTitle}>临期预警</span>
</div>
<div className={styles.chartContainer}>
{/* 透明块容器 */}
<div className={styles.transparentBlock}>
{/* 四个垂直分布的卡片 */}
<div className={styles.licenseCard}>
<div className={styles.cardContent}>
<div className={styles.licenseName}>安全生产许可证</div>
<div className={styles.licenseNumber}>编号: AQXK-2023-0582</div>
</div>
<div className={styles.expiryTag}>
<span className={styles.expiryText}>15天后到期</span>
</div>
</div>
<div className={styles.licenseCard}>
<div className={styles.cardContent}>
<div className={styles.licenseName}>安全评估报告</div>
<div className={styles.licenseNumber}>编号: AQPG-2023-0125</div>
</div>
<div className={styles.expiryTag}>
<span className={styles.expiryText}>30天后到期</span>
</div>
</div>
<div className={styles.licenseCard}>
<div className={styles.cardContent}>
<div className={styles.licenseName}>施工资质证书</div>
<div className={styles.licenseNumber}>编号: SGZZ-2023-0089</div>
</div>
<div className={styles.expiryTag} style={{ backgroundColor: '#FFE0E2' }}>
<span className={styles.expiryText} style={{ color: '#FF2526' }}>7天后到期</span>
</div>
</div>
<div className={styles.licenseCard}>
<div className={styles.cardContent}>
<div className={styles.licenseName}>应急预案</div>
<div className={styles.licenseNumber}>编号: YJYA-2023-0045</div>
</div>
<div className={styles.expiryTag} style={{ backgroundColor: '#FFE0E2' }}>
<span className={styles.expiryText} style={{ color: '#FF2526' }}>4天后到期</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 证照列表区域 */}
<div className={styles.listCard}>
<div className={styles.chartHeader}>
<div className={styles.headerLeft}>
<div className={styles.colorBlock}></div>
<span className={styles.chartTitle}>证照列表</span>
</div>
<div className={styles.headerRight}>
<Search
placeholder="搜索证照名称或编号..."
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
onSearch={(value) => console.log('搜索:', value)}
className={styles.searchInput}
/>
<Select
value={selectedType}
onChange={setSelectedType}
className={styles.typeSelector}
>
<Option value="all">全部类型</Option>
<Option value="safety">安全生产许可证</Option>
<Option value="assessment">安全评估报告</Option>
<Option value="construction">施工资质证书</Option>
<Option value="emergency">应急预案</Option>
<Option value="other">其他</Option>
</Select>
<Button
type="primary"
className={styles.addButton}
onClick={() => console.log('新增证照')}
>
新增证照
</Button>
</div>
</div>
<StandardTable
columns={columns}
data={{
list: tableData, // ======== 表格数据列表 ========
pagination: { // ======== 分页配置 ========
currentPage: 1, // ======== 当前页码 ========
pageSize: 5, // ======== 每页显示5条数据 ========
total: tableData.length, // ======== 总数据条数 ========
} // ======== 分页配置结束 ========
}} // ======== 数据对象结束 ========
selectedRows={[]} // ======== 选中的行数据,初始为空数组 ========
onSelectRow={() => { }} // ======== 行选择事件处理函数 ========
onChange={() => { }} // ======== 表格变化事件处理函数 ========
pagination={{
currentPage: 1,
pageSize: 5,
total: tableData.length,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total, range) =>
`${total}`,
locale: {
jump_to: '前往',
page: '页',
items_per_page: '条/页',
}
}}
/>
</div>
</div>
);
};
export default LicenseManagement;