feat():完善体制模块开发
parent
84016faa09
commit
793319bbdc
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.2 KiB |
|
|
@ -44,6 +44,14 @@ const apiurl = {
|
|||
export: service + '/projectEvents/export',
|
||||
info :service + '/wholeCycle/get'
|
||||
}
|
||||
},
|
||||
sz: {
|
||||
jqjz: {
|
||||
budgetInfo: service + '/fundBudget/get/',
|
||||
manageInfo: service + '/screen/mechanisms/equipment',
|
||||
managePic: service + '/screen/manageHouseImg/get',
|
||||
wzPage:service + '/rescue/goods/page/query'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ const AllWeatherControl = () => {
|
|||
className="reservoir-card"
|
||||
style={{ backgroundImage: `url(${smallCard})` }}
|
||||
>
|
||||
<div className={`value ${item.isPrimary ? 'primary' : ''} ${item.isNegative ? 'negative' : 'positive'}`}>
|
||||
<div className={`value ${item.isPrimary ? 'primary' : ''} ${item.label == '距汛限'?item.isNegative ? 'negative' : 'positive':""}`}>
|
||||
<span className={`num ${item.underline ? 'underline' : ''}`}>{item.value}</span>
|
||||
<span className="unit">{item.unit}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -20,18 +20,19 @@ const ManagementCycle = () => {
|
|||
value: info?.dispatchTime,
|
||||
underline: true,
|
||||
clickable: true,
|
||||
fileId:info?.dispatchFileIds?.length? info?.dispatchFileIds[0] + '':undefined // Assuming this field exists
|
||||
fileId:info?.dispatchFileIds?.length? info?.dispatchFileIds[0]:undefined // Assuming this field exists
|
||||
},
|
||||
{
|
||||
label: '应急预案',
|
||||
value: info?.emergencyTime,
|
||||
underline: true,
|
||||
clickable: true,
|
||||
fileId:info?.emergencyFileIds?.length? info?.emergencyFileIds[0] + '':undefined // Assuming this field exists
|
||||
fileId:info?.emergencyFileIds?.length? info?.emergencyFileIds[0]:undefined // Assuming this field exists
|
||||
},
|
||||
];
|
||||
|
||||
const handleItemClick = (item) => {
|
||||
if (!item.fileId) return;
|
||||
const url = '/gunshiApp/ss/resPlanB/file/download/';
|
||||
// if (!item?.dispatchFileIds || item?.dispatchFileIds.length) return;
|
||||
// const field = item.label == '调度规程' ? item?.dispatchFileIds[0] + '' :
|
||||
|
|
@ -85,7 +86,7 @@ const ManagementCycle = () => {
|
|||
<PdfView
|
||||
visible={pdfVisible}
|
||||
title={pdfConfig.title}
|
||||
url={'/gunshiApp/ss/resPlanB/file/download'}
|
||||
url={pdfConfig.url}
|
||||
fileId={pdfConfig.fileId}
|
||||
onClose={() => setPdfVisible(false)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
.cycle-card {
|
||||
width: calc((100% - 20px) / 3);
|
||||
height: 80px; // Slightly taller to accommodate text comfortably
|
||||
height: 70px; // Slightly taller to accommodate text comfortably
|
||||
margin-bottom: 15px;
|
||||
margin-right: 10px;
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
align-items: center;
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
|
||||
justify-content: space-between;
|
||||
.label {
|
||||
color: #CCF3FF;
|
||||
margin-right: 10px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Input, Button } from 'antd';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import CommonModal from '@/views/Home/components/UI/CommonModal';
|
||||
import usePageTable from '@/components/crud/usePageTable';
|
||||
import { createCrudService } from '@/components/crud/_';
|
||||
import apiurl from '@/service/apiurl';
|
||||
|
||||
const OrgnizeModal = ({ visible, onClose,title }) => {
|
||||
|
||||
const columns = [
|
||||
{ title: '序号', dataIndex: 'inx', key: 'inx', width: 60, align: 'center' },
|
||||
{ title: '用户姓名', dataIndex: 'spec', key: 'spec', align: 'center' },
|
||||
{ title: '手机号码', dataIndex: 'phone', key: 'phone', align: 'center' },
|
||||
{ title: '部门', dataIndex: 'contactPerson', key: 'contactPerson', align: 'center' },
|
||||
];
|
||||
const { tableProps, search} = usePageTable(createCrudService(apiurl.sz.jqjz.wzPage).find);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
search()
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
return (
|
||||
<CommonModal
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
title={title}
|
||||
width="70%"
|
||||
>
|
||||
<div className="material-modal-content">
|
||||
<div className="table-wrapper">
|
||||
<Table
|
||||
columns={columns}
|
||||
{...tableProps}
|
||||
className="custom-table"
|
||||
size="middle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CommonModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrgnizeModal;
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { UserOutlined, BankOutlined, ApartmentOutlined } from '@ant-design/icons';
|
||||
import textBg from '@/assets/images/card/textbg.png';
|
||||
import arrowIcon from '@/assets/images/card/arrow.png';
|
||||
import OrgnizeModal from './OrgnizeModal'
|
||||
import './index.less';
|
||||
|
||||
const PerfectSystem = ({ data }) => {
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState('');
|
||||
const managementInfo = [
|
||||
{ label: '管理单位', value: data?.managName ?? '-', icon: <BankOutlined />, type: 'unit' },
|
||||
{ label: '负责人', value: data?.chargePerson ?? '-', icon: <UserOutlined />, type: 'person' },
|
||||
{ label: '归口管理部门', value: data?.admDep ?? '-', icon: <ApartmentOutlined />, type: 'dept' },
|
||||
];
|
||||
|
||||
const leftOrg = [
|
||||
{ name: '工程科', count: 3 },
|
||||
{ name: '办公室', count: 2 },
|
||||
{ name: '财务科', count: 1 },
|
||||
{ name: '...', count: null },
|
||||
];
|
||||
|
||||
const rightOrg = [
|
||||
{ name: '后勤保障', subName: '中心', count: 5 },
|
||||
{ name: '...', count: null },
|
||||
];
|
||||
|
||||
const handleCardClick = (item) => {
|
||||
setModalTitle(item.name);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="perfect-system">
|
||||
<div className="section">
|
||||
<div className="section-title">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>管理单位</span>
|
||||
</div>
|
||||
<div className="info-list">
|
||||
{managementInfo.map((item, index) => (
|
||||
<div key={index} className="info-item" style={{ backgroundImage: `url(${textBg})` }}>
|
||||
<div className={`icon-box ${item.type}`}>
|
||||
{item.icon}
|
||||
</div>
|
||||
<div className="info-content">
|
||||
<span className="label">{item.label}:</span>
|
||||
<span className="value">{item.value}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="section mt-15">
|
||||
<div className="section-title">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>水库组织机构</span>
|
||||
</div>
|
||||
<div className="org-chart">
|
||||
<div className="side-column left">
|
||||
{leftOrg.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`org-node ${item.count === null ? 'placeholder' : ''}`}
|
||||
style={{cursor:'pointer'}}
|
||||
onClick={() => handleCardClick(item)}
|
||||
>
|
||||
<span className="node-text" style={{borderBottom:"1px solid #00a0e9"}}>{item.name}{item.count !== null ? `(${item.count})` : ''}</span>
|
||||
<div className="connector-line"></div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="center-column">
|
||||
<div className="main-node">
|
||||
<span className="vertical-text">双石水库管理处</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="side-column right">
|
||||
{rightOrg.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`org-node ${item.count === null ? 'placeholder' : ''}`}
|
||||
style={{cursor:'pointer'}}
|
||||
onClick={() => handleCardClick(item)}
|
||||
>
|
||||
<div className="connector-line"></div>
|
||||
<span className="node-text" style={{borderBottom:"1px solid #00a0e9"}}>
|
||||
{item.name}
|
||||
{item.subName && <><br />{item.subName}</>}
|
||||
{item.count !== null ? `(${item.count})` : ''}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
{/* Fill empty space to match left side height roughly */}
|
||||
<div className="org-node placeholder" style={{ opacity: 0 }}>
|
||||
<div className="connector-line"></div>
|
||||
</div>
|
||||
<div className="org-node placeholder" style={{ opacity: 0 }}>
|
||||
<div className="connector-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<OrgnizeModal
|
||||
visible={modalVisible}
|
||||
title={modalTitle}
|
||||
onClose={() => setModalVisible(false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PerfectSystem;
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
.perfect-system {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
|
||||
// Scrollbar hidden
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 10px;
|
||||
|
||||
&.mt-15 {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.arrow-icon {
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
margin-right: 8px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 5px rgba(0, 160, 233, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 10px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
.icon-box {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
margin-right: 15px;
|
||||
font-size: 18px;
|
||||
|
||||
&.unit {
|
||||
background: linear-gradient(135deg, #1890ff 0%, #0050b3 100%);
|
||||
}
|
||||
|
||||
&.person {
|
||||
background: linear-gradient(135deg, #00eaff 0%, #006d75 100%);
|
||||
}
|
||||
|
||||
&.dept {
|
||||
background: linear-gradient(135deg, #722ed1 0%, #391085 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.info-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
.label {
|
||||
color: #CCF3FF;
|
||||
margin-right: 10px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #CCF3FF;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.org-chart {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
padding: 0 5px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
|
||||
.center-column {
|
||||
flex: 0 0 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 2;
|
||||
|
||||
.main-node {
|
||||
background: url('../../../../../../../assets/images/card/ognize.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.vertical-text {
|
||||
writing-mode: vertical-rl;
|
||||
font-size: 16px;
|
||||
letter-spacing: 4px;
|
||||
color: #fff;
|
||||
text-orientation: upright;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side-column {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 5px 0;
|
||||
position: relative;
|
||||
|
||||
.org-node {
|
||||
position: relative;
|
||||
background: url('../../../../../../../assets/images/card/smallCard.png');
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
min-height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 90px;
|
||||
box-shadow: inset 0 0 10px rgba(0, 160, 233, 0.2);
|
||||
|
||||
&.placeholder {
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
|
||||
.node-text {
|
||||
font-size: 20px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
// border-bottom: 1px solid #00a0e9;
|
||||
}
|
||||
|
||||
.connector-line {
|
||||
border-top-color: rgba(0, 160, 233, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.connector-line {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
height: 1px;
|
||||
border-top: 1px dashed #00a0e9;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.left {
|
||||
align-items: flex-start;
|
||||
|
||||
.org-node {
|
||||
.connector-line {
|
||||
left: 100%;
|
||||
width: 500px; // Large width to ensure it reaches center
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
align-items: flex-end;
|
||||
|
||||
.org-node {
|
||||
.connector-line {
|
||||
right: 100%;
|
||||
width: 500px; // Large width to ensure it reaches center
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import CommonModal from '@/views/Home/components/UI/CommonModal';
|
||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import './index.less';
|
||||
|
||||
const GalleryModal = ({ visible, onClose, title, data = [] }) => {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
const currentItem = data[selectedIndex] || {};
|
||||
|
||||
const handlePrev = () => {
|
||||
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : data.length - 1));
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
setSelectedIndex((prev) => (prev < data.length - 1 ? prev + 1 : 0));
|
||||
};
|
||||
|
||||
return (
|
||||
<CommonModal
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
title={title}
|
||||
width={'60%'}
|
||||
|
||||
>
|
||||
<div className="gallery-modal-content">
|
||||
<div className="main-image-container">
|
||||
<img src={currentItem.url} alt={currentItem.name} className="main-image" />
|
||||
</div>
|
||||
<div className="image-info">
|
||||
图片名称:{currentItem.name}
|
||||
</div>
|
||||
<div className="thumbnail-strip">
|
||||
<div className="scroll-btn left" onClick={handlePrev}><LeftOutlined /></div>
|
||||
<div className="thumbnails-wrapper">
|
||||
{data.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`thumbnail-item ${index === selectedIndex ? 'thumb-active' : ''}`}
|
||||
onClick={() => setSelectedIndex(index)}
|
||||
>
|
||||
<img src={item.url} alt={item.name} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="scroll-btn right" onClick={handleNext}><RightOutlined /></div>
|
||||
</div>
|
||||
</div>
|
||||
</CommonModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default GalleryModal;
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
.gallery-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 700px;
|
||||
color: #fff;
|
||||
|
||||
.main-image-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #000;
|
||||
overflow: hidden;
|
||||
|
||||
.main-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// object-fit: contain;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
// background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 160, 233, 0.8);
|
||||
}
|
||||
|
||||
&.prev { left: 20px; }
|
||||
&.next { right: 20px; }
|
||||
}
|
||||
}
|
||||
|
||||
.image-info {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.thumbnail-strip {
|
||||
height: 100px;
|
||||
// background: #111;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
border-top: 1px solid #0181e6;
|
||||
|
||||
.scroll-btn {
|
||||
width: 30px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
&:hover { color: #00a0e9; }
|
||||
}
|
||||
|
||||
.thumbnails-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
overflow-x: auto;
|
||||
padding: 10px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
background: #333;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #666;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.thumbnail-item {
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
&.thumb-active {
|
||||
border-color: #00a0e9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(0, 160, 233, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Input, Button } from 'antd';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import CommonModal from '@/views/Home/components/UI/CommonModal';
|
||||
import usePageTable from '@/components/crud/usePageTable';
|
||||
import { createCrudService } from '@/components/crud/_';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import './index.less';
|
||||
|
||||
const MaterialModal = ({ visible, onClose }) => {
|
||||
const unitType = {
|
||||
1:'个',
|
||||
2:'件',
|
||||
3:'米',
|
||||
4:'把',
|
||||
5:'台',
|
||||
6:'套',
|
||||
7:'副',
|
||||
8:'箱',
|
||||
9:'卷',
|
||||
10:'立方米',
|
||||
11:'平方米',
|
||||
}
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const columns = [
|
||||
{ title: '序号', dataIndex: 'inx', key: 'inx', width: 60, align: 'center' },
|
||||
{
|
||||
title: '物资名称',
|
||||
dataIndex: 'goodsName',
|
||||
key: 'goodsName',
|
||||
align: 'center',
|
||||
sorter: (a, b) => (a.goodsName || '').localeCompare(b.goodsName || ''),
|
||||
showSorterTooltip: { title: '整理' }
|
||||
},
|
||||
{
|
||||
title: '物资类型', dataIndex: 'goodsType', key: 'goodsType', align: 'center',
|
||||
render: (_, record) => <span>{ record.goodsType === 1 ? "抢险物资" : "救生器材"}</span>
|
||||
},
|
||||
{ title: '规格', dataIndex: 'spec', key: 'spec', align: 'center' },
|
||||
{
|
||||
title: '单位', dataIndex: 'unit', key: 'unit', align: 'center',
|
||||
render: (v) => <span>{unitType[v]}</span>
|
||||
},
|
||||
{ title: '库存数量', dataIndex: 'storeQuantity', key: 'storeQuantity', align: 'center' },
|
||||
{
|
||||
title: '仓库地点',
|
||||
dataIndex: 'storeLocation',
|
||||
key: 'storeLocation',
|
||||
align: 'center',
|
||||
sorter: (a, b) => (a.storeLocation || '').localeCompare(b.storeLocation || ''),
|
||||
showSorterTooltip: { title: '整理' }
|
||||
},
|
||||
{ title: '联系人', dataIndex: 'contactPerson', key: 'contactPerson', align: 'center' },
|
||||
{ title: '联系电话', dataIndex: 'phone', key: 'phone', align: 'center' },
|
||||
];
|
||||
const { tableProps, search} = usePageTable(createCrudService(apiurl.sz.jqjz.wzPage).find);
|
||||
|
||||
const handleSearch = () => {
|
||||
let params = {
|
||||
search: {
|
||||
goodsName:searchText
|
||||
}
|
||||
}
|
||||
search(params);
|
||||
};
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
handleSearch()
|
||||
}
|
||||
setSearchText('')
|
||||
}, [visible]);
|
||||
|
||||
return (
|
||||
<CommonModal
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
title="防汛物资"
|
||||
width="70%"
|
||||
>
|
||||
<div className="material-modal-content">
|
||||
<div className="search-bar">
|
||||
<span className="label">物资名称:</span>
|
||||
<Input
|
||||
value={searchText}
|
||||
onChange={e => setSearchText(e.target.value)}
|
||||
placeholder="请输入物资名称"
|
||||
style={{ width: 240 }}
|
||||
allowClear
|
||||
/>
|
||||
<Button type="primary" icon={<SearchOutlined />} onClick={handleSearch} className="search-btn ant-btn-ghost-blue">查询</Button>
|
||||
</div>
|
||||
<div className="table-wrapper">
|
||||
<Table
|
||||
columns={columns}
|
||||
{...tableProps}
|
||||
className="custom-table"
|
||||
size="middle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CommonModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaterialModal;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.material-modal-content {
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.search-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
import React, { useState,useEffect } from 'react';
|
||||
import moment from 'moment';
|
||||
import arrowIcon from '@/assets/images/card/arrow.png';
|
||||
import smallCard from '@/assets/images/card/smallCard.png';
|
||||
import homeImg from '@/assets/images/home.png'; // Placeholder for gallery
|
||||
import jingfeiIcon from '@/assets/images/card/jingfei.png';
|
||||
import lightBg from '@/assets/images/card/light.png';
|
||||
import GalleryModal from './GalleryModal';
|
||||
import MaterialModal from './MaterialModal';
|
||||
import YearSelect from '@/views/Home/components/UI/YearSelect';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import { httpget } from '@/utils/request';
|
||||
import { config } from '@/config';
|
||||
import './index.less';
|
||||
|
||||
const SoundMechanism = () => {
|
||||
const [year, setYear] = useState(moment().format('YYYY'));
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [materialVisible, setMaterialVisible] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState('');
|
||||
const [galleryData, setGalleryData] = useState([]);
|
||||
|
||||
|
||||
const [manageInfo, setManageInfo] = useState({}) //管理设施
|
||||
const [budgetInfo, setBudgetInfo] = useState({}) //经费
|
||||
// Mock data for gallery
|
||||
const houseImages = [
|
||||
{ name: '管理用房.jpg', url: homeImg },
|
||||
{ name: '监控室.jpg', url: homeImg },
|
||||
{ name: '水库全景.jpg', url: homeImg },
|
||||
{ name: '会议室.jpg', url: homeImg },
|
||||
{ name: '值班室.jpg', url: homeImg },
|
||||
{ name: '物资仓库.jpg', url: homeImg },
|
||||
];
|
||||
|
||||
|
||||
|
||||
// Facility Data (Mocked as per UI)
|
||||
const facilities = [
|
||||
{ value: manageInfo?.managementHousing??'-', unit: 'm²', label: '管理用房', underline: true, clickable: true},
|
||||
{ value: manageInfo?.rainWaterCount??'-', unit: '个', label: '雨水情测报' },
|
||||
{ value: manageInfo?.safeCheckCount??'-', unit: '个', label: '安全监测设施' },
|
||||
{ value: manageInfo?.cctvCount??'-', unit: '个', label: '视频监控设施' },
|
||||
{ value: manageInfo?.goodsTypeCount??'-', unit: '项', label: '防汛物资种类', underline: true, clickable: true, type: 'material' },
|
||||
{ value: manageInfo?.roadLength??'-', unit: '米', label: '防汛道路' },
|
||||
];
|
||||
|
||||
const handleCardClick = (item) => {
|
||||
if (!item.clickable) return;
|
||||
if (item.label == '管理用房') {
|
||||
getManagePic()
|
||||
} else if (item.type === 'material') {
|
||||
setMaterialVisible(true);
|
||||
} else {
|
||||
setModalTitle(item.label);
|
||||
setModalVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
// Funding Data (Mocked as per UI)
|
||||
const fundingData = [
|
||||
{ label: '年度收入预算', value: budgetInfo?.annualExpenditureBudget ?? '-', unit: '万元' },
|
||||
{ label: '年度支出预算', value: budgetInfo?.annualIncomeBudget ?? '-', unit: '万元' },
|
||||
];
|
||||
|
||||
// 获取管理设施
|
||||
const getManage= async () => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sz.jqjz.manageInfo)
|
||||
if (result.code == 200) {
|
||||
setManageInfo(result?.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取管理用房图片
|
||||
const getManagePic= async () => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sz.jqjz.managePic)
|
||||
if (result.code == 200) {
|
||||
const files = result.data?.files || [];
|
||||
if (files.length > 0) {
|
||||
setGalleryData(files.map(item=>({name:item.fileName,url:config.minioIp +item.filePath})))
|
||||
setModalTitle('管理用房');
|
||||
setModalVisible(true);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取年度预算
|
||||
const getBudget = async (params) => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sz.jqjz.budgetInfo + params)
|
||||
if (result.code == 200) {
|
||||
setBudgetInfo(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getBudget(year)
|
||||
}, [year])
|
||||
|
||||
useEffect(() => {
|
||||
getManage()
|
||||
}, [])
|
||||
return (
|
||||
<div className="sound-mechanism">
|
||||
{/* Section 1: Management Facilities */}
|
||||
<div className="section">
|
||||
<div className="section-title">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>管理设施</span>
|
||||
</div>
|
||||
<div className="facility-grid">
|
||||
{facilities.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`facility-card ${item.clickable ? 'clickable' : ''}`}
|
||||
style={{ backgroundImage: `url(${smallCard})` }}
|
||||
onClick={() => handleCardClick(item)}
|
||||
>
|
||||
<div className={`value-wrapper ${item.underline ? 'underlined' : ''}`}>
|
||||
<span className="value">{item.value}</span>
|
||||
<span className="unit">{item.unit}</span>
|
||||
</div>
|
||||
<div className="label">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<GalleryModal
|
||||
visible={modalVisible}
|
||||
title={modalTitle}
|
||||
onClose={() => setModalVisible(false)}
|
||||
data={galleryData}
|
||||
/>
|
||||
<MaterialModal
|
||||
visible={materialVisible}
|
||||
onClose={() => setMaterialVisible(false)}
|
||||
/>
|
||||
|
||||
{/* Section 2: Funding Guarantee */}
|
||||
<div className="section mt-15">
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>经费保障</span>
|
||||
</div>
|
||||
<YearSelect
|
||||
value={year}
|
||||
onChange={setYear}
|
||||
/>
|
||||
</div>
|
||||
<div className="funding-container">
|
||||
{fundingData.map((item, index) => (
|
||||
<div key={index} className="funding-item">
|
||||
<div className="icon-wrapper" style={{width:40}}>
|
||||
<img src={jingfeiIcon} alt="icon" className="jingfei-icon" />
|
||||
</div>
|
||||
<div
|
||||
className="content"
|
||||
style={{ backgroundImage: `url(${lightBg})` }}
|
||||
>
|
||||
<div className="value-row">
|
||||
<span className="value">{item.value}</span>
|
||||
<span className="unit">{item.unit}</span>
|
||||
</div>
|
||||
<div className="label">{item.label}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SoundMechanism;
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
.sound-mechanism {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
overflow-y: hidden;
|
||||
|
||||
// Scrollbar hidden
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 0px;
|
||||
&.mt-15 { margin-top: 5px; }
|
||||
|
||||
.section-title, .section-header .title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
.arrow-icon {
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
margin-right: 8px;
|
||||
object-fit: contain;
|
||||
}
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 5px rgba(0, 160, 233, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.facility-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.facility-card {
|
||||
width: calc((100% - 20px) / 3);
|
||||
height: 70px;
|
||||
margin-bottom: 15px;
|
||||
margin-right: 10px;
|
||||
&:nth-child(3n) { margin-right: 0; }
|
||||
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.value-wrapper {
|
||||
margin-bottom: 4px;
|
||||
&.underlined {
|
||||
border-bottom: 1px solid #00a0e9;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #00D8FF;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.unit {
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.funding-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
margin-top: 15px;
|
||||
|
||||
.funding-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
position: relative;
|
||||
|
||||
// Add a glow effect at the bottom like in the UI
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
left: 20%;
|
||||
width: 60%;
|
||||
height: 10px;
|
||||
background: radial-gradient(ellipse at center, rgba(0, 160, 233, 0.4) 0%, rgba(0,0,0,0) 70%);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.jingfei-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
justify-content: center;
|
||||
padding-left: 10px;
|
||||
width: 140px;
|
||||
height: 60px;
|
||||
|
||||
.value-row {
|
||||
.value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #00D8FF;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.unit {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,16 +1,36 @@
|
|||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import CommonCard from '../../UI/CommonCard';
|
||||
import PerfectSystem from './components/PerfectSystem';
|
||||
import SoundMechanism from './components/SoundMechanism';
|
||||
import { httppost } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import './index.less';
|
||||
|
||||
const SiZhi = () => {
|
||||
const [infos, setInfos] = useState({});
|
||||
|
||||
const getInfo = async () => {
|
||||
try {
|
||||
const result = await httppost(apiurl.sq.qfg.info);
|
||||
if (result.code == 200) {
|
||||
const info = result.data[0];
|
||||
setInfos(info);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
getInfo();
|
||||
}, []);
|
||||
return (
|
||||
<div className="sizhi-view">
|
||||
<div className="side-panel left">
|
||||
<CommonCard title="完善体系" className="panel-card card-1">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
<PerfectSystem data={infos}/>
|
||||
</CommonCard>
|
||||
<CommonCard title="健全机制" className="panel-card card-2">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
<SoundMechanism />
|
||||
</CommonCard>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,27 @@
|
|||
import React from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { DatePicker } from 'antd';
|
||||
import moment from 'moment';
|
||||
import './index.less';
|
||||
|
||||
const { Option } = Select;
|
||||
const YearSelect = ({ value, onChange, className, style, ...props }) => {
|
||||
const handleChange = (date, dateString) => {
|
||||
if (onChange) {
|
||||
onChange(dateString);
|
||||
}
|
||||
};
|
||||
|
||||
const YearSelect = ({ defaultValue = "2025", style, className, ...props }) => (
|
||||
<Select
|
||||
defaultValue={defaultValue}
|
||||
style={{ width: 80, color: '#fff',marginRight:15,marginTop:5, ...style }}
|
||||
bordered={false}
|
||||
dropdownClassName="year-select-dropdown"
|
||||
className={`year-select ${className || ''}`}
|
||||
{...props}
|
||||
>
|
||||
<Option value="2025">2025</Option>
|
||||
<Option value="2024">2024</Option>
|
||||
<Option value="2023">2023</Option>
|
||||
</Select>
|
||||
);
|
||||
return (
|
||||
<DatePicker
|
||||
picker="year"
|
||||
value={value ? moment(value, 'YYYY') : null}
|
||||
onChange={handleChange}
|
||||
className={`custom-year-select ${className || ''}`}
|
||||
dropdownClassName="custom-year-select-dropdown"
|
||||
style={style}
|
||||
allowClear={false}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default YearSelect;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,81 @@
|
|||
.year-select {
|
||||
color: #fff;
|
||||
.ant-select-selector {
|
||||
color: #fff !important;
|
||||
background-color: transparent !important;
|
||||
.custom-year-select {
|
||||
background: transparent !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3) !important; // Added border
|
||||
border-radius: 4px; // Optional: rounded corners for better look
|
||||
width: 90px;
|
||||
|
||||
input {
|
||||
color: #fff !important;
|
||||
font-size: 16px;
|
||||
font-weight: normal; // Changed from bold to normal
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-select-arrow {
|
||||
|
||||
&:hover {
|
||||
border-color: #00a0e9 !important; // Highlight border on hover
|
||||
}
|
||||
|
||||
.ant-picker-suffix {
|
||||
color: #00a0e9;
|
||||
}
|
||||
|
||||
.ant-picker-clear {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.ant-picker-focused {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Global styles for dropdown (since it renders in body)
|
||||
.year-select-dropdown {
|
||||
background-color: rgba(0, 20, 50, 0.9) !important;
|
||||
border: 1px solid rgba(0, 160, 233, 0.3);
|
||||
|
||||
.ant-select-item {
|
||||
.custom-year-select-dropdown {
|
||||
background-color: rgba(0, 40, 70, 0.95) !important;
|
||||
border: 1px solid #00a0e9;
|
||||
|
||||
.ant-picker-header {
|
||||
color: #fff;
|
||||
&:hover, &.ant-select-item-option-selected {
|
||||
background-color: rgba(0, 160, 233, 0.3);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
button {
|
||||
color: #fff;
|
||||
&:hover { color: #00a0e9; }
|
||||
}
|
||||
.ant-picker-header-super-prev-btn, .ant-picker-header-super-next-btn {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-body {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-picker-content {
|
||||
th, td { color: #fff; }
|
||||
}
|
||||
|
||||
.ant-picker-cell {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
&:hover .ant-picker-cell-inner {
|
||||
background-color: rgba(0, 160, 233, 0.3) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-cell-in-view {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-picker-cell-selected .ant-picker-cell-inner {
|
||||
background-color: #00a0e9 !important;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-picker-year-panel {
|
||||
.ant-picker-cell-inner {
|
||||
color: #fff;
|
||||
&:hover {
|
||||
background: rgba(0, 160, 233, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue