feat():落实责任制培训内容弹框开发

lsf-dev
李神峰 2026-02-08 14:06:26 +08:00
parent 194b0dbff1
commit 83d69416e1
3 changed files with 205 additions and 53 deletions

View File

@ -0,0 +1,133 @@
import React, { useState } from 'react';
import { Descriptions, Image } from 'antd';
import { DownloadOutlined, EyeOutlined } from '@ant-design/icons';
import CommonModal from '@/views/Home/components/UI/CommonModal';
import PdfView from '@/views/Home/components/UI/PdfView';
import { download } from '@/utils/tools';
import './TrainingModal.less';
const TrainingModal = ({ visible, onClose, data }) => {
const typeInfo = {
1:"水利",
2:"岗前培训",
3:"在岗培训",
4:"政治学习教育",
5:"其他",
}
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
const [previewImage, setPreviewImage] = useState('');
const [previewVisible, setPreviewVisible] = useState(false);
if (!data) return null;
const commonLabelStyle = {
width: '150px',
textAlign: 'right',
};
const descriptionStyle = {
marginBottom: '20px',
};
const getDescriptionsProps = (title) => ({
title: <span style={{ color: '#1890ff', fontSize: '16px', fontWeight: 'bold', borderLeft: '4px solid #1890ff', paddingLeft: '10px' }}>{title}</span>,
column: 2,
bordered: true,
size: 'small',
className: 'engineering-descriptions',
labelStyle: commonLabelStyle,
style: descriptionStyle,
});
const handleFilePreview = (file) => {
const extension = file.fileName.split('.').pop().toLowerCase();
const downloadUrl = `/gunshiApp/ss/personnelPlan/file/download/${file.fileId}`;
if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(extension)) {
setPreviewImage(downloadUrl);
setPreviewVisible(true);
} else if (extension === 'pdf') {
setPdfInfo({
visible: true,
title: file.fileName,
fileId: file.fileId
});
} else {
download(downloadUrl);
}
};
const getTrainingType = (type) => {
const typeName = typeInfo[type]
return typeName;
};
return (
<CommonModal
visible={visible}
onClose={onClose}
title={data.content || "培训详情"}
width={1000}
>
<div className="training-modal-content" style={{ padding: '20px', height: '600px', overflowY: 'auto' }}>
<Descriptions {...getDescriptionsProps('基本信息')}>
<Descriptions.Item label="培训计划">{data.name || '-'}</Descriptions.Item>
<Descriptions.Item label="培训分类">{getTrainingType(data.type) || '-'}</Descriptions.Item>
<Descriptions.Item label="培训日期">{data.stm || '-'}</Descriptions.Item>
<Descriptions.Item label="标题名称">{data.name || '-'}</Descriptions.Item>
<Descriptions.Item label="培训时段">{data.stm && data.etm ? `${data.stm}${data.etm}` : '-'}</Descriptions.Item>
<Descriptions.Item label="培训时长(小时)">{data.num || '-'}</Descriptions.Item>
<Descriptions.Item label="培训地点">{data.addr || '-'}</Descriptions.Item>
<Descriptions.Item label="主办单位">{data.unit || '-'}</Descriptions.Item>
<Descriptions.Item label="培训内容" span={2}>{data.content || '-'}</Descriptions.Item>
<Descriptions.Item label="培训范围" span={2}>{data.scope || '-'}</Descriptions.Item>
<Descriptions.Item label="参训人员">{data.trainees || '-'}</Descriptions.Item>
<Descriptions.Item label="参训人数">{data.numPeople || '-'}</Descriptions.Item>
<Descriptions.Item label="填报人">{data.applicant || '-'}</Descriptions.Item>
<Descriptions.Item label="登记日期">{data.regDate || '-'}</Descriptions.Item>
</Descriptions>
<Descriptions {...getDescriptionsProps('其他信息')} column={1}>
<Descriptions.Item label="附件">
<div className="file-list" style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
{data.files && data.files.length > 0 ? data.files.map((file, index) => (
<div key={index} className="file-item" style={{ width: '240px', padding: '8px', borderRadius: '4px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', marginRight: '5px', flex: 1 }} title={file.fileName}>{file.fileName}</span>
<div style={{ flexShrink: 0 }}>
<EyeOutlined onClick={() => handleFilePreview(file)} style={{ cursor: 'pointer', marginRight: '8px', color: '#1890ff', fontSize: '16px' }} title="预览" />
<DownloadOutlined onClick={() => download(`/gunshiApp/ss/personnelPlan/file/download/${file.fileId}`)} style={{ cursor: 'pointer', color: '#1890ff', fontSize: '16px' }} title="下载" />
</div>
</div>
)) : <span style={{ color: '#rgba(255,255,255,0.5)' }}>无附件</span>}
</div>
</Descriptions.Item>
</Descriptions>
</div>
{/* PDF Viewer */}
{pdfInfo.visible && (
<PdfView
visible={pdfInfo.visible}
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
title={pdfInfo.title}
fileId={pdfInfo.fileId}
url="/gunshiApp/ss/personnelPlan/file/download/"
/>
)}
<div style={{ display: 'none' }}>
<Image
src={previewImage}
preview={{
visible: previewVisible,
src: previewImage,
onVisibleChange: (value) => {
setPreviewVisible(value);
},
}}
/>
</div>
</CommonModal>
);
};
export default TrainingModal;

View File

@ -0,0 +1,59 @@
.training-modal-content {
.engineering-descriptions {
table {
table-layout: fixed !important;
}
.ant-descriptions-view {
border-radius: 4px;
border: 1px solid rgba(0, 160, 233, 0.3);
table {
border-collapse: collapse;
}
}
.ant-descriptions-row {
border-bottom: 1px solid rgba(0, 160, 233, 0.3);
&:last-child {
border-bottom: none;
}
& > th, & > td {
border-right: 1px solid rgba(0, 160, 233, 0.3);
&:last-child {
border-right: none;
}
}
}
.ant-descriptions-item-label {
background-color: rgba(0, 160, 233, 0.1) !important;
color: #fff !important;
font-weight: normal;
padding: 12px 16px !important;
border-color: rgba(0, 160, 233, 0.3) !important;
}
.ant-descriptions-item-content {
color: #fff !important;
padding: 12px 16px !important;
border-color: rgba(0, 160, 233, 0.3) !important;
background-color: transparent !important;
}
}
.file-item {
background: rgba(0, 160, 233, 0.1);
border: 1px solid rgba(0, 160, 233, 0.3) !important;
color: #fff;
transition: all 0.3s;
&:hover {
background: rgba(0, 160, 233, 0.2);
box-shadow: 0 0 5px rgba(0, 160, 233, 0.5);
}
}
}

View File

@ -1,14 +1,12 @@
import React, { useState,useEffect } from 'react';
import { Image } from 'antd';
import arrowIcon from '@/assets/images/card/arrow.png';
import selectedBg from '@/assets/images/modal/selected.png';
import resperson from '@/assets/images/card/resperson.png';
import smallCard from '@/assets/images/card/smallCard.png';
import qys from '@/assets/images/business/qys.png';
import PdfView from '@/views/Home/components/UI/PdfView';
import apiurl from '@/service/apiurl';
import { httpget } from '@/utils/request';
import { download } from '@/utils/tools';
import TrainingModal from './components/TrainingModal';
import './index.less';
const ImplementResponsibility = () => {
@ -20,12 +18,10 @@ const ImplementResponsibility = () => {
5:"技术责任人",
}
const [activeTab, setActiveTab] = useState('dam'); // 'dam' or 'flood'
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
const [imagePreview, setImagePreview] = useState({ visible: false, src: '' });
const [respData, setRespData] = useState([])
const [floodData, setFloodData] = useState([])
const [trainData, setTrainData] = useState({})
const [trainFileData, setTrainFileData] = useState({})
const [trainingModalVisible, setTrainingModalVisible] = useState(false);
// 获取大坝安全责任人
const getRespData = async () => {
@ -58,7 +54,6 @@ const ImplementResponsibility = () => {
const { code, data } = await httpget(apiurl.sz.zrz.train)
if (code == 200) {
setTrainData(data)
setTrainFileData(data?.latestPersonnelPlan?.files[0])
}
} catch (error) {
console.log(error);
@ -73,28 +68,8 @@ const ImplementResponsibility = () => {
];
const handleTrainingClick = () => {
if (!trainFileData || !trainFileData.fileName) return;
const fileName = trainFileData.fileName;
const fileId = trainFileData.fileId;
const extension = fileName.split('.').pop().toLowerCase();
const downloadUrl = `/gunshiApp/ss/personnelPlan/file/download/${fileId}`;
if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(extension)) {
setImagePreview({
visible: true,
src: downloadUrl
});
} else if (extension === 'pdf') {
setPdfInfo({
visible: true,
title: fileName,
fileId: fileId
});
} else {
download(downloadUrl)
// window.location.href = downloadUrl;
}
if (!latestPersonnelPlan) return;
setTrainingModalVisible(true);
};
const currentPersonList = activeTab === 'dam' ? respData : floodData;
@ -175,36 +150,21 @@ const ImplementResponsibility = () => {
<div
className="value-box"
onClick={handleTrainingClick}
title={trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
title={latestPersonnelPlan?.content}
style={{ cursor: 'pointer' }}
>
{trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
{latestPersonnelPlan?.content || "暂无培训内容"}
</div>
</div>
{/* PDF Viewer */}
{pdfInfo.visible && (
<PdfView
visible={pdfInfo.visible}
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
title={pdfInfo.title}
fileId={pdfInfo.fileId}
url="/gunshiApp/ss/personnelPlan/file/download/"
{/* Training Detail Modal */}
{trainingModalVisible && (
<TrainingModal
visible={trainingModalVisible}
onClose={() => setTrainingModalVisible(false)}
data={latestPersonnelPlan}
/>
)}
{/* Image Preview */}
<div style={{ display: 'none' }}>
<Image
src={imagePreview.src}
preview={{
visible: imagePreview.visible,
src: imagePreview.src,
onVisibleChange: (value) => {
setImagePreview({ ...imagePreview, visible: value });
},
}}
/>
</div>
</div>
);
};