Compare commits
No commits in common. "9181d55cad590e8b56a1752c664b5dd3cf51a14a" and "83372f9739d399e9fc4c045b0af1b16e364e0a45" have entirely different histories.
9181d55cad
...
83372f9739
Binary file not shown.
|
Before Width: | Height: | Size: 824 B |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
|
|
@ -337,13 +337,6 @@ input:-webkit-autofill:active {
|
|||
color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-picker-cell-disabled {
|
||||
pointer-events: none;
|
||||
.ant-picker-cell-inner {
|
||||
color: rgba(255, 255, 255, 0.25) !important;
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Footer/Ranges
|
||||
.ant-picker-footer {
|
||||
|
|
|
|||
|
|
@ -157,17 +157,33 @@ const apiurl = {
|
|||
managePic: service + '/screen/manageHouseImg/get',
|
||||
wzPage:service + '/rescue/goods/page/query'
|
||||
},
|
||||
qhfz: {
|
||||
lawPage: service + '/SzRuleByLaw/page',
|
||||
systemPage: service + '/SzRegulatoryFramework/page',
|
||||
caseSta:service + '/szCase/statistics/1'
|
||||
zrrgl: {
|
||||
page: service + "/resPerson/page",
|
||||
edit: service + "/resPerson/update",
|
||||
delete: service + "/resPerson/del",
|
||||
save: service + "/resPerson/insert",
|
||||
},
|
||||
zrz: {
|
||||
respPerson: service + '/screen/responsibility/getPerson',
|
||||
floodPerson: service + '/screen/responsibility/getFxPerson',
|
||||
train:service + '/screen/responsibility/getTraining'
|
||||
}
|
||||
}
|
||||
},
|
||||
sy: {
|
||||
fxya:{
|
||||
page: service + "/resPlanB/list",
|
||||
update: service + "/resPlanB/update",
|
||||
save: service + "/resPlanB/insert",
|
||||
delete: service + "/resPlanB/del",
|
||||
getFile: service + "/resPlanB/file/get"
|
||||
},
|
||||
},
|
||||
gcaqjc: {
|
||||
gcaqyj: {
|
||||
yjgzpz:{
|
||||
page: service + '/osmoticWarnRule/page',
|
||||
save: service + '/osmoticWarnRule/insert',
|
||||
edit: service + "/osmoticWarnRule/update",
|
||||
delete: service + "/osmoticWarnRule/del",
|
||||
list: service + "/osmoticPressDevice/list"
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default apiurl
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import centerOfMass from '@turf/center-of-mass';
|
|||
import bbox from '@turf/bbox';
|
||||
import turfLength from '@turf/length';
|
||||
import along from '@turf/along';
|
||||
import { config } from '@/config';
|
||||
|
||||
const class2type = {};
|
||||
const { toString } = class2type;
|
||||
'Boolean Number String Function Array Date RegExp Object Error'.split(' ').forEach((name) => {
|
||||
|
|
@ -613,17 +613,4 @@ export const myFiltrate = (data,params)=>{
|
|||
return query.substring(iStart);
|
||||
|
||||
return query.substring(iStart, iEnd);
|
||||
}
|
||||
|
||||
export const download = (url) => {
|
||||
let downloadLink = document.createElement("a");
|
||||
// downloadLink.href = `${process.env.REACT_APP_API_URL}/gunshiApp/ss/personnelPlan/file/download/${params}`;
|
||||
downloadLink.href = config.ip +url;
|
||||
// downloadLink.download = `${params.fileName}`;
|
||||
downloadLink.style.display = "none";
|
||||
// 将链接添加到页面中
|
||||
document.body.appendChild(downloadLink);
|
||||
|
||||
// 模拟点击事件,开始下载
|
||||
downloadLink.click();
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import { treeList, srcData, videoList, ysyToken } from './http'
|
|||
import VideoControler from "@/components/VideoCom/VideoControler"
|
||||
import { httppost } from "@/utils/request"
|
||||
import apiurl from "@/service/apiurl"
|
||||
import { Spin } from "antd"
|
||||
|
||||
|
||||
const VideoList = () => {
|
||||
|
|
@ -16,7 +15,6 @@ const VideoList = () => {
|
|||
const [size, setSize] = useState(1)
|
||||
const [treeListData, setTreeData] = useState([])
|
||||
const [selectList, setSelectList] = useState()
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const selectedKeys = async (list, node) => {
|
||||
console.log(node, 'node');
|
||||
|
|
@ -76,24 +74,18 @@ const VideoList = () => {
|
|||
|
||||
}
|
||||
const getTreeData = async () => {
|
||||
try {
|
||||
const res = await treeList()
|
||||
const res1 = await videoList()
|
||||
const arr = res1.data.filter(item => item.menuId).map((item, index) => {
|
||||
item.parentId = item.menuId
|
||||
item.id = 999 + index
|
||||
item.isLeaf = true
|
||||
// item.icon=<VideoCameraFilled />
|
||||
return item
|
||||
})
|
||||
const arr1 = [...arr, ...res.data]
|
||||
console.log("before", arr1);
|
||||
setTreeData(buildTree(arr1))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
const res = await treeList()
|
||||
const res1 = await videoList()
|
||||
const arr = res1.data.filter(item => item.menuId).map((item, index) => {
|
||||
item.parentId = item.menuId
|
||||
item.id = 999 + index
|
||||
item.isLeaf = true
|
||||
// item.icon=<VideoCameraFilled />
|
||||
return item
|
||||
})
|
||||
const arr1 = [...arr, ...res.data]
|
||||
console.log("before", arr1);
|
||||
setTreeData(buildTree(arr1))
|
||||
}
|
||||
function buildTree(data, parentId = "0") {
|
||||
const tree = [];
|
||||
|
|
@ -145,28 +137,20 @@ const VideoList = () => {
|
|||
}, [])
|
||||
return (
|
||||
<div className='flex videoList'>
|
||||
{loading ? (
|
||||
<div style={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Spin tip="加载中..." />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className={['treeRight', (selectList && selectList.type == 1) ? 'ptz-visible' : ''].join(' ')}>
|
||||
<TreeData size={size} selectedKeys={selectedKeys} treeListData={treeListData} videoArr={videoArr} />
|
||||
{
|
||||
selectList && selectList.type == 1 ?
|
||||
<div style={{ position: "absolute", bottom: 0, left: 0 }}>
|
||||
<VideoControler
|
||||
selectItem={selectList}
|
||||
onOperation={onOperation}
|
||||
/>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className='treeLeft'><SplitScreen count={count} videoArr={videoArr} clickIndex={clickIndex} getType={getType} /></div>
|
||||
</>
|
||||
)}
|
||||
<div className={['treeRight', (selectList && selectList.type == 1) ? 'ptz-visible' : ''].join(' ')}>
|
||||
<TreeData size={size} selectedKeys={selectedKeys} treeListData={treeListData} videoArr={videoArr} />
|
||||
{
|
||||
selectList && selectList.type == 1 ?
|
||||
<div style={{ position: "absolute", bottom: 0, left: 0 }}>
|
||||
<VideoControler
|
||||
selectItem={selectList}
|
||||
onOperation={onOperation}
|
||||
/>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<div className='treeLeft'><SplitScreen count={count} videoArr={videoArr} clickIndex={clickIndex} getType={getType} /></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,164 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import selectedBg from '@/assets/images/modal/selected.png';
|
||||
import skbg from '@/assets/images/card/skbg.png';
|
||||
import gth from '@/assets/images/card/gth.png';
|
||||
import syl from '@/assets/images/card/syl.png';
|
||||
import wy from '@/assets/images/card/wy.png';
|
||||
import './index.less';
|
||||
|
||||
const WarningSection = ({ type = 'monitor' }) => {
|
||||
const [activeTab, setActiveTab] = useState('water'); // 'water' or 'safety' for monitor; 'flood' or 'weather' for forecast
|
||||
|
||||
// Mock Data
|
||||
const waterWarnings = [
|
||||
{
|
||||
id: 1,
|
||||
name: '双石水库',
|
||||
limitLevel: '108.89',
|
||||
currentLevel: '109.09',
|
||||
exceedance: '0.20',
|
||||
time: '2025-10-28 09:00:00'
|
||||
}
|
||||
];
|
||||
|
||||
const safetyMonitorItems = [
|
||||
{ label: '渗压监测', value: 2, icon: syl },
|
||||
{ label: '渗流监测', value: 1, icon: syl },
|
||||
{ label: '位移监测', value: 0, icon: wy }
|
||||
];
|
||||
|
||||
const floodWarnings = [
|
||||
{
|
||||
id: 1,
|
||||
message: '根据上游流量站实测和产汇流预测结果,未来24小时预计总入库564.2万m³,平均入库流量65.2m³/s,达到橙色预警级别。',
|
||||
time: '2025-10-28 08:10:00'
|
||||
}
|
||||
];
|
||||
|
||||
const weatherWarnings = [
|
||||
{
|
||||
id: 1,
|
||||
title: '赤壁市气象台发布暴雨红色预警[Ⅰ级/特别...',
|
||||
time: '2025-07-28 06:35:30',
|
||||
content: '赤壁市2025年08月10日07时33分08秒发布暴雨红色预警信号:过去3小时最大降水出现在XXXXX为71毫米。受强降雨云团持续影响,预计未来3小时,上述地区及周边乡镇仍将有50-80毫米的降雨,累计雨量可达150毫米以上,局地阵风7-9级。城乡积涝、山区山洪、地质灾害、中小河流洪水风险极高,请特别加强防范。'
|
||||
}
|
||||
];
|
||||
|
||||
const renderContent = () => {
|
||||
if (type === 'monitor') {
|
||||
if (activeTab === 'water') {
|
||||
return (
|
||||
<div className="warning-list">
|
||||
{waterWarnings.map((item) => (
|
||||
<div key={item.id} className="warning-item">
|
||||
<div className="item-header">
|
||||
<img src={gth} alt="warning" className="warning-icon" />
|
||||
<div className="item-title" style={{ backgroundImage: `url(${skbg})` }}>{item.name}</div>
|
||||
</div>
|
||||
<div className="item-content">
|
||||
<p>水库汛限水位 {item.limitLevel} m。</p>
|
||||
<p>实时监测水位 {item.currentLevel} m,超出汛限水位 <span className="highlight"> {item.exceedance} m</span></p>
|
||||
<div className="item-time">{item.time}</div>
|
||||
</div>
|
||||
<div className="divider" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="safety-monitor-view">
|
||||
{safetyMonitorItems.map((item, index) => (
|
||||
<div key={index} className="monitor-item">
|
||||
<div className="monitor-value" style={{ color: item.value > 0 ? '#ff4d4f' : '#fff' }}>{item.value}</div>
|
||||
<img src={item.icon} alt={item.label} className="monitor-icon" />
|
||||
<div className="monitor-label">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Forecast Warning
|
||||
if (activeTab === 'flood') {
|
||||
return (
|
||||
<div className="warning-list">
|
||||
{floodWarnings.map(item => (
|
||||
<div key={item.id} className="warning-item">
|
||||
<div className="item-content full-width">
|
||||
<div className="warning-text-wrapper">
|
||||
<img src={gth} alt="warning" className="warning-icon-inline" />
|
||||
<span className="warning-text">{item.message}</span>
|
||||
</div>
|
||||
<div className="item-time" style={{marginLeft:25,marginTop:0}}>预报时间:{item.time}</div>
|
||||
</div>
|
||||
<div className="divider" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div className="warning-list">
|
||||
{weatherWarnings.map(item => (
|
||||
<div key={item.id} className="warning-item">
|
||||
<div className="item-header weather-header">
|
||||
<img src={gth} alt="rainstorm" className="weather-icon" />
|
||||
<div className="item-title" title={item.title} style={{ backgroundImage: `url(${skbg})`,paddingLeft:38 }}>{item.title}</div>
|
||||
</div>
|
||||
<div className="item-time weather-time">{item.time}</div>
|
||||
<div className="item-content weather-content">
|
||||
{item.content}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getTabs = () => {
|
||||
if (type === 'monitor') {
|
||||
return [
|
||||
{ key: 'water', label: `水库水情 (${waterWarnings.length})` },
|
||||
{ key: 'safety', label: `安全监测 (${safetyMonitorItems.reduce((acc, cur) => acc + cur.value, 0)})` } // Sum of values or just count of items? Design shows (3) which matches items count 3. Let's use 3.
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{ key: 'flood', label: `洪水预报 (${floodWarnings.length})` },
|
||||
{ key: 'weather', label: `气象预报 (${weatherWarnings.length})` }
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
// Reset active tab when type changes
|
||||
React.useEffect(() => {
|
||||
setActiveTab(type === 'monitor' ? 'water' : 'flood');
|
||||
}, [type]);
|
||||
|
||||
const tabs = getTabs();
|
||||
|
||||
return (
|
||||
<div className="warning-section">
|
||||
{/* Tabs */}
|
||||
<div className="tabs-container">
|
||||
{tabs.map(tab => (
|
||||
<div
|
||||
key={tab.key}
|
||||
className={`tab-item ${activeTab === tab.key ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab(tab.key)}
|
||||
style={activeTab === tab.key ? { backgroundImage: `url(${selectedBg})` } : {}}
|
||||
>
|
||||
{tab.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
{renderContent()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WarningSection;
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
.warning-section {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 10px;
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
cursor: pointer;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
transition: all 0.3s;
|
||||
margin: 0 5px;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 10px #00a0e9;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.warning-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 10px;
|
||||
max-height: 180px;
|
||||
|
||||
.warning-item {
|
||||
margin-bottom: 15px;
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.warning-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
width: 40px;
|
||||
height: 30px;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
width: 180px;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
padding: 2px 20px 2px 20px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&.weather-header {
|
||||
.item-title {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
padding-left: 34px; /* Align with title (icon width + margin) */
|
||||
|
||||
&.full-width {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
&.weather-content {
|
||||
padding-left: 0;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.5;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.warning-text-wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.warning-icon-inline {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 5px 0;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.5;
|
||||
|
||||
.highlight {
|
||||
color: #ff4d4f; /* Red for warning values */
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.item-time {
|
||||
margin-top: 5px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255);
|
||||
}
|
||||
|
||||
.weather-time {
|
||||
padding-left: 50px;
|
||||
margin-bottom: 5px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin-top: 10px;
|
||||
height: 1px;
|
||||
background: repeating-linear-gradient(to right, rgba(0, 160, 233, 0.5) 0, rgba(0, 160, 233, 0.5) 5px, transparent 5px, transparent 10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.safety-monitor-view {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 20px 10px;
|
||||
height: 100%;
|
||||
|
||||
.monitor-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.monitor-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.monitor-icon {
|
||||
width: 80px;
|
||||
height: 60px;
|
||||
margin-bottom: 10px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.monitor-label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +1,56 @@
|
|||
import React from 'react';
|
||||
import CommonCard from '../../UI/CommonCard';
|
||||
import ThreeDots from '../../UI/ThreeDots';
|
||||
import WarningSection from './components/WarningSection';
|
||||
import './index.less';
|
||||
|
||||
|
||||
const WarningToggles = ({ activeType, onToggle }) => {
|
||||
return (
|
||||
<div className="warning-toggles">
|
||||
<div
|
||||
className={`toggle-item ${activeType === 'monitor' ? 'active' : ''}`}
|
||||
onClick={() => onToggle('monitor')}
|
||||
>
|
||||
<span>监测预警</span>
|
||||
<span className="badge">4</span>
|
||||
</div>
|
||||
<div
|
||||
className={`toggle-item ${activeType === 'forecast' ? 'active' : ''}`}
|
||||
onClick={() => onToggle('forecast')}
|
||||
>
|
||||
<span>预报预警</span>
|
||||
<span className="badge bg-red">2</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
const WarningToggles = () => {
|
||||
return (
|
||||
<div className="warning-toggles">
|
||||
<div className="toggle-item active">
|
||||
<span>监测预警</span>
|
||||
<span className="badge">4</span>
|
||||
</div>
|
||||
<div className="toggle-item">
|
||||
<span>预报预警</span>
|
||||
<span className="badge bg-red">2</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SiYu = () => {
|
||||
const [warningType, setWarningType] = React.useState('monitor');
|
||||
|
||||
return (
|
||||
<div className="siyu-view">
|
||||
<div className="side-panel left">
|
||||
<CommonCard title="预报" className="panel-card card-1">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
<CommonCard title="预演" className="panel-card card-2">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
</div>
|
||||
|
||||
<div className="side-panel right">
|
||||
<CommonCard
|
||||
title="预警"
|
||||
className="panel-card card-1"
|
||||
headerExtra={<WarningToggles activeType={warningType} onToggle={setWarningType} />}
|
||||
>
|
||||
<WarningSection type={warningType} />
|
||||
</CommonCard>
|
||||
<CommonCard
|
||||
title="实时水雨情"
|
||||
className="panel-card card-2"
|
||||
headerExtra={<ThreeDots onClick={() => console.log('实时水雨情 clicked')} />}
|
||||
>
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
|
||||
<CommonCard title="预案" className="panel-card card-3">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
</div>
|
||||
<div className="side-panel left">
|
||||
<CommonCard title="预报" className="panel-card card-1">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
<CommonCard title="预演" className="panel-card card-2">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
</div>
|
||||
|
||||
<div className="side-panel right">
|
||||
<CommonCard
|
||||
title="预警"
|
||||
className="panel-card card-1"
|
||||
headerExtra={<WarningToggles />}
|
||||
>
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
<CommonCard
|
||||
title="实时水雨情"
|
||||
className="panel-card card-2"
|
||||
headerExtra={<ThreeDots onClick={() => console.log('实时水雨情 clicked')} />}
|
||||
>
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
|
||||
<CommonCard title="预案" className="panel-card card-3">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,44 +11,7 @@
|
|||
}
|
||||
|
||||
.right {
|
||||
.card-1 {
|
||||
flex: 1;
|
||||
|
||||
.warning-toggles {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.toggle-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 15px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255,0.7);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 10px #00a0e9;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
background: #ff4d4f; /* Default red */
|
||||
border-radius: 7px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
margin-left: 5px;
|
||||
padding: 0 4px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-1 { flex: 1; }
|
||||
.card-2 { flex: 1; }
|
||||
.card-3 { flex: 1; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,212 +0,0 @@
|
|||
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 './index.less';
|
||||
|
||||
const ImplementResponsibility = () => {
|
||||
const types = {
|
||||
1:"行政责任人",
|
||||
2:"主管部门责任人",
|
||||
3:"管理单位责任人",
|
||||
4:"巡查责任人",
|
||||
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 getRespData = async () => {
|
||||
try {
|
||||
const { code, data } = await httpget(apiurl.sz.zrz.respPerson)
|
||||
if (code == 200 && data.length > 0) {
|
||||
const list = data.map(item => ({name:item.name,phone:item.contactInfo,role:types[item.type]}))
|
||||
setRespData(list)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
// 获取防汛安全责任人
|
||||
const getFloodData = async () => {
|
||||
try {
|
||||
const { code, data } = await httpget(apiurl.sz.zrz.floodPerson)
|
||||
if (code == 200 && data.length > 0) {
|
||||
const list = data.map(item => ({name:item.name,phone:item.contactInfo,role:types[item.type]}))
|
||||
setFloodData(list)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取岗位培训
|
||||
const getTrainData = async () => {
|
||||
try {
|
||||
const { code, data } = await httpget(apiurl.sz.zrz.train)
|
||||
if (code == 200) {
|
||||
setTrainData(data)
|
||||
setTrainFileData(data?.latestPersonnelPlan?.files[0])
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
const {trainingCount,hasTraining,hasNoTraining,totalTraining,latestPersonnelPlan} = trainData||{}
|
||||
const trainingStats = [
|
||||
{ label: '培训计划', value: trainingCount??'-' },
|
||||
{ label: '已开展', value: hasTraining??'-' },
|
||||
{ label: '未开展', value: hasNoTraining??'-' },
|
||||
{ label: '参训总人次', value: totalTraining??'-' }
|
||||
];
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
const currentPersonList = activeTab === 'dam' ? respData : floodData;
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTab === 'dam') {
|
||||
getRespData()
|
||||
} else {
|
||||
getFloodData()
|
||||
}
|
||||
}, [activeTab])
|
||||
|
||||
useEffect(() => {
|
||||
getTrainData()
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<div className="implement-responsibility">
|
||||
{/* Top Tabs */}
|
||||
<div className="tabs-container">
|
||||
<div
|
||||
className={`tab-item ${activeTab === 'dam' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('dam')}
|
||||
style={activeTab === 'dam' ? { backgroundImage: `url(${selectedBg})` } : {}}
|
||||
>
|
||||
大坝安全责任人
|
||||
</div>
|
||||
<div
|
||||
className={`tab-item ${activeTab === 'flood' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('flood')}
|
||||
style={activeTab === 'flood' ? { backgroundImage: `url(${selectedBg})` } : {}}
|
||||
>
|
||||
防汛 “三个责任人”
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Person List */}
|
||||
<div className="person-list">
|
||||
{currentPersonList.map((person, index) => (
|
||||
<div key={index} className="person-item">
|
||||
<img src={resperson} alt="avatar" className="avatar" />
|
||||
<span className="name">{person.name}</span>
|
||||
<span className="phone">{person.phone}</span>
|
||||
<div
|
||||
className="role-label"
|
||||
style={{ backgroundImage: `url(${smallCard})` }}
|
||||
title={person.role}
|
||||
>
|
||||
{person.role}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Job Training Section */}
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>岗位培训</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Training Stats */}
|
||||
<div className="training-stats">
|
||||
{trainingStats.map((stat, index) => (
|
||||
<div key={index} className="stat-item">
|
||||
<span className="stat-value">{stat.value}</span>
|
||||
<img src={qys} alt="icon" className="stat-icon" />
|
||||
<span className="stat-label">{stat.label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Latest Training Content */}
|
||||
<div className="latest-training" style={{ backgroundImage: `url(${smallCard})` }}>
|
||||
<span className="label">最新培训内容:</span>
|
||||
<div
|
||||
className="value-box"
|
||||
onClick={handleTrainingClick}
|
||||
title={trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
|
||||
>
|
||||
{trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
|
||||
</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/"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 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>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImplementResponsibility;
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
.implement-responsibility {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 3px 0;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
cursor: pointer;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 10px #00a0e9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.person-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.person-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 30%;
|
||||
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 45px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.phone {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.role-label {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.training-stats {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.stat-value {
|
||||
font-size: 18px;
|
||||
color: #00eaff;
|
||||
font-weight: bold;
|
||||
margin-bottom: -5px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 100px;
|
||||
height: 60px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.latest-training {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
margin-top: auto;
|
||||
margin-bottom: 10px;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
margin-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.value-box {
|
||||
flex: 1;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 10px;
|
||||
color: #00eaff;
|
||||
font-size: 14px;
|
||||
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,362 +0,0 @@
|
|||
import React, { useState,useEffect } from 'react';
|
||||
import ReactEcharts from 'echarts-for-react';
|
||||
import arrowIcon from '@/assets/images/card/arrow.png';
|
||||
import selectedBg from '@/assets/images/modal/selected.png';
|
||||
import YearSelect from '@/views/Home/components/UI/YearSelect';
|
||||
import PdfView from '@/views/Home/components/UI/PdfView';
|
||||
import { FileTextOutlined } from '@ant-design/icons';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import { httppost, httpget } from '@/utils/request';
|
||||
import { Empty } from 'antd';
|
||||
import './index.less';
|
||||
import moment from 'moment';
|
||||
|
||||
const StrengthenRuleOfLaw = () => {
|
||||
const params = {
|
||||
pageSo:{ pageSize: 9999, pageNumber: 1 }
|
||||
}
|
||||
const [activeTab, setActiveTab] = useState('laws');
|
||||
const [lawData, setLawData] = useState([]);
|
||||
const [systemData, setSystemData] = useState([]);
|
||||
const [year, setYear] = useState(moment().format('YYYY'));
|
||||
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
|
||||
|
||||
// 获取法律法规文件
|
||||
const lawsFiles = async () => {
|
||||
try {
|
||||
const { code, data } = await httppost(apiurl.sz.qhfz.lawPage, params)
|
||||
if (code == 200) {
|
||||
const list = data?.records.map(item => {
|
||||
if (item?.files?.length === 0) {
|
||||
return []
|
||||
}
|
||||
return { name: item?.files[0]?.fileName?.replace(/\.pdf$/i, ''), fileId: item?.files[0]?.fileId }
|
||||
}).flat()
|
||||
setLawData(list)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取系统文件
|
||||
const systemFiles = async () => {
|
||||
try {
|
||||
const { code, data } = await httppost(apiurl.sz.qhfz.systemPage, params)
|
||||
if (code == 200) {
|
||||
const list = data?.records.map(item => {
|
||||
if (item?.files?.length === 0) {
|
||||
return []
|
||||
}
|
||||
return { name: item?.files[0]?.fileName?.replace(/\.pdf$/i, ''), fileId: item?.files[0]?.fileId }
|
||||
}).flat()
|
||||
|
||||
setSystemData(list)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const [chartData, setChartData] = useState([]);
|
||||
const [selectedPieItem, setSelectedPieItem] = useState(null);
|
||||
const [startAngle, setStartAngle] = useState(90);
|
||||
|
||||
const typeMapping = {
|
||||
0: { name: '违建', color: '#1890ff' },
|
||||
1: { name: '毁林垦荒', color: '#00eaff' },
|
||||
2: { name: '筑坝拦汊', color: '#3155fb' },
|
||||
3: { name: '填占库容', color: '#bcebf7' },
|
||||
4: { name: '违法取水', color: '#00d085' },
|
||||
5: { name: '其他', color: '#1890ff' },
|
||||
};
|
||||
|
||||
// 获取水政执法数据 0:违建,1:毀林垦荒,2:筑坝拦汊,3:填占库容,4:违法取水,5:其他
|
||||
const caseList = async (params) => {
|
||||
try {
|
||||
const { code, data } = await httppost(apiurl.sz.qhfz.caseSta, params)
|
||||
if (code == 200) {
|
||||
if (!data || data.length === 0) {
|
||||
setChartData([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const newChartData = data.map(item => {
|
||||
const typeInfo = typeMapping[item.type] || { name: '未知', color: '#ccc' };
|
||||
return {
|
||||
name: typeInfo.name,
|
||||
value: item.count,
|
||||
color: typeInfo.color
|
||||
};
|
||||
});
|
||||
setChartData(newChartData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const total = chartData.reduce((acc, cur) => acc + cur.value, 0);
|
||||
|
||||
const getOption = () => {
|
||||
let centerName = '案件总数';
|
||||
let centerValue = total;
|
||||
let centerPercent = '100%';
|
||||
|
||||
if (selectedPieItem) {
|
||||
centerName = selectedPieItem.name;
|
||||
centerValue = selectedPieItem.value;
|
||||
centerPercent = selectedPieItem.percent;
|
||||
} else if (chartData.length === 1) {
|
||||
centerName = chartData[0].name;
|
||||
}
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '水政执法-外圈',
|
||||
type: 'pie',
|
||||
radius: ['48%', '82%'],
|
||||
center: ['34%', '50%'],
|
||||
startAngle: startAngle,
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: '{b}',
|
||||
color: '#fff',
|
||||
fontSize: 10
|
||||
},
|
||||
itemStyle: {
|
||||
opacity: 0.4
|
||||
},
|
||||
data: chartData.map(item => ({
|
||||
value: item.value,
|
||||
name: item.name,
|
||||
itemStyle: { color: item.color }
|
||||
}))
|
||||
},
|
||||
{
|
||||
name: '水政执法-内圈',
|
||||
type: 'pie',
|
||||
radius: ['50%', '56%'],
|
||||
center: ['34%', '50%'],
|
||||
startAngle: startAngle,
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'center',
|
||||
formatter: () => `{name|${centerName}}\n{value|${centerValue}}\n{percent|${centerPercent}}`,
|
||||
rich: {
|
||||
name: {
|
||||
fontSize: 12,
|
||||
color: 'rgba(255,255,255,0.6)',
|
||||
lineHeight: 16
|
||||
},
|
||||
value: {
|
||||
fontSize: 14,
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 20
|
||||
},
|
||||
percent: {
|
||||
fontSize: 12,
|
||||
color: '#fff',
|
||||
lineHeight: 16
|
||||
}
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: chartData.map(item => ({
|
||||
value: item.value,
|
||||
name: item.name,
|
||||
itemStyle: { color: item.color }
|
||||
}))
|
||||
}
|
||||
]
|
||||
}};
|
||||
|
||||
const onChartClick = (params) => {
|
||||
if (params.componentType !== 'series') return;
|
||||
|
||||
const { name, value, dataIndex } = params;
|
||||
|
||||
// Toggle selection
|
||||
if (selectedPieItem && selectedPieItem.name === name) {
|
||||
setSelectedPieItem(null);
|
||||
setStartAngle(90);
|
||||
return;
|
||||
}
|
||||
|
||||
let sumBefore = 0;
|
||||
for (let i = 0; i < dataIndex; i++) {
|
||||
sumBefore += chartData[i].value;
|
||||
}
|
||||
|
||||
const offset = (sumBefore + value / 2) / total * 360;
|
||||
const newStartAngle = 90 + offset;
|
||||
|
||||
setStartAngle(newStartAngle);
|
||||
setSelectedPieItem({
|
||||
name,
|
||||
value,
|
||||
percent: ((value / total) * 100).toFixed(0) + '%'
|
||||
});
|
||||
};
|
||||
|
||||
const handleItemClick = (item) => {
|
||||
setPdfInfo({
|
||||
visible: true,
|
||||
title: item.name,
|
||||
fileId: item.fileId
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (chartData && chartData.length > 0) {
|
||||
const totalVal = chartData.reduce((acc, cur) => acc + cur.value, 0);
|
||||
const firstItem = chartData[0];
|
||||
const value = firstItem.value;
|
||||
|
||||
const offset = (value / 2) / totalVal * 360;
|
||||
const newStartAngle = 90 + offset;
|
||||
|
||||
setStartAngle(newStartAngle);
|
||||
setSelectedPieItem({
|
||||
name: firstItem.name,
|
||||
value: value,
|
||||
percent: ((value / totalVal) * 100).toFixed(0) + '%'
|
||||
});
|
||||
} else {
|
||||
setSelectedPieItem(null);
|
||||
setStartAngle(90);
|
||||
}
|
||||
}, [chartData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTab == 'laws') {
|
||||
lawsFiles()
|
||||
} else {
|
||||
systemFiles()
|
||||
}
|
||||
}, [activeTab])
|
||||
useEffect(() => {
|
||||
if (year) {
|
||||
const params = {
|
||||
stm: moment(year).format('YYYY-01-01 00:00:00'),
|
||||
etm: moment(year).format('YYYY-12-31 23:59:59'),
|
||||
}
|
||||
caseList(params)
|
||||
}
|
||||
}, [year])
|
||||
return (
|
||||
<div className="strengthen-rule-of-law">
|
||||
{/* Top Tabs */}
|
||||
<div className="tabs-container">
|
||||
<div
|
||||
className={`tab-item ${activeTab === 'laws' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('laws')}
|
||||
style={activeTab === 'laws' ? { backgroundImage: `url(${selectedBg})` } : {}}
|
||||
>
|
||||
法律法规
|
||||
</div>
|
||||
<div
|
||||
className={`tab-item ${activeTab === 'system' ? 'active' : ''}`}
|
||||
onClick={() => setActiveTab('system')}
|
||||
style={activeTab === 'system' ? { backgroundImage: `url(${selectedBg})` } : {}}
|
||||
>
|
||||
制度管理
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* List Content */}
|
||||
<div className="list-content">
|
||||
{(activeTab === 'laws' ? lawData : systemData).length > 0 ? (
|
||||
(activeTab === 'laws' ? lawData : systemData).map((item, index) => (
|
||||
<div key={index} className="list-item" onClick={() => handleItemClick(item)}>
|
||||
<div className="icon-wrapper">
|
||||
<FileTextOutlined style={{ color: '#1890ff', fontSize: '16px' }} />
|
||||
</div>
|
||||
<span className="text">{item.name}</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span style={{color:'#fff'}}>暂无数据</span>} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Water Administration Law Enforcement */}
|
||||
<div className="enforcement-section">
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span>水政执法</span>
|
||||
</div>
|
||||
<YearSelect
|
||||
value={year}
|
||||
onChange={setYear}
|
||||
style={{ width: 100 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="chart-legend-container">
|
||||
{chartData.length > 0 ? (
|
||||
<>
|
||||
<div className="chart-wrapper">
|
||||
<ReactEcharts
|
||||
option={getOption()}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
notMerge={true}
|
||||
onEvents={{
|
||||
'click': onChartClick
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="legend-wrapper">
|
||||
{chartData.map((item, index) => (
|
||||
<div key={index} className="legend-item">
|
||||
<span className="color-dot" style={{ backgroundColor: item.color }}></span>
|
||||
<span className="name">{item.name}</span>
|
||||
<span className="value">{item.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span style={{color:'#fff'}}>暂无数据</span>} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PDF Viewer */}
|
||||
{pdfInfo.visible && (
|
||||
<PdfView
|
||||
visible={pdfInfo.visible}
|
||||
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
|
||||
title={pdfInfo.title}
|
||||
fileId={pdfInfo.fileId}
|
||||
url="/gunshiApp/ss/projectEvents/file/download/"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StrengthenRuleOfLaw;
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
.strengthen-rule-of-law {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 3px 0;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
cursor: pointer;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 10px #00a0e9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 15px;
|
||||
max-height: 120px; /* Limit height to show scroll if needed, though items are few */
|
||||
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
.text {
|
||||
color: #00a0e9;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-wrapper {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 10px;
|
||||
background: rgba(24, 144, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.enforcement-section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-legend-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.chart-wrapper {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
min-height: 140px;
|
||||
}
|
||||
|
||||
.legend-wrapper {
|
||||
width: 140px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-left: 10px;
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
font-size: 12px;
|
||||
|
||||
.color-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,6 @@ import React, { useState, useEffect } from 'react';
|
|||
import CommonCard from '../../UI/CommonCard';
|
||||
import PerfectSystem from './components/PerfectSystem';
|
||||
import SoundMechanism from './components/SoundMechanism';
|
||||
import StrengthenRuleOfLaw from './components/StrengthenRuleOfLaw';
|
||||
import ImplementResponsibility from './components/ImplementResponsibility';
|
||||
import { httppost } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import './index.less';
|
||||
|
|
@ -38,10 +36,10 @@ const SiZhi = () => {
|
|||
|
||||
<div className="side-panel right">
|
||||
<CommonCard title="强化法治" className="panel-card card-1">
|
||||
<StrengthenRuleOfLaw />
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
<CommonCard title="落实责任制" className="panel-card card-2">
|
||||
<ImplementResponsibility />
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
</CommonCard>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const PdfView = ({ visible, title, onClose, url, fileId }) => {
|
|||
return (
|
||||
<CommonModal
|
||||
visible={visible}
|
||||
title={title?.replace(/\.pdf$/i, '')}
|
||||
title={title}
|
||||
onClose={onClose}
|
||||
width="60%"
|
||||
bodyStyle={{ padding: 0, overflow: 'hidden' }}
|
||||
|
|
|
|||
|
|
@ -9,18 +9,14 @@ const YearSelect = ({ value, onChange, className, style, ...props }) => {
|
|||
onChange(dateString);
|
||||
}
|
||||
};
|
||||
const disabledDate = (current) => {
|
||||
return current && current > moment().endOf('day');
|
||||
};
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
picker="year"
|
||||
disabledDate={disabledDate}
|
||||
value={value ? moment(value, 'YYYY') : null}
|
||||
onChange={handleChange}
|
||||
className={`custom-year-select ${className || ''}`}
|
||||
// dropdownClassName="custom-year-select-dropdown"
|
||||
dropdownClassName="custom-year-select-dropdown"
|
||||
style={style}
|
||||
allowClear={false}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -65,14 +65,6 @@
|
|||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-picker-cell-disabled {
|
||||
pointer-events: none;
|
||||
.ant-picker-cell-inner {
|
||||
color: rgba(255, 255, 255, 0.25) !important;
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-cell-selected .ant-picker-cell-inner {
|
||||
background-color: #00a0e9 !important;
|
||||
color: #fff;
|
||||
|
|
|
|||
Loading…
Reference in New Issue