diff --git a/src/assets/fonts/HuXiaoBoNanShenTi-2.otf b/src/assets/fonts/HuXiaoBoNanShenTi-2.otf new file mode 100644 index 0000000..4cdf94c Binary files /dev/null and b/src/assets/fonts/HuXiaoBoNanShenTi-2.otf differ diff --git a/src/assets/fonts/douyuFont-2.otf b/src/assets/fonts/douyuFont-2.otf new file mode 100644 index 0000000..3d9732c Binary files /dev/null and b/src/assets/fonts/douyuFont-2.otf differ diff --git a/src/assets/images/business/barType.png b/src/assets/images/business/barType.png new file mode 100644 index 0000000..c3ff89c Binary files /dev/null and b/src/assets/images/business/barType.png differ diff --git a/src/assets/images/business/bhfw.png b/src/assets/images/business/bhfw.png new file mode 100644 index 0000000..0c5fc79 Binary files /dev/null and b/src/assets/images/business/bhfw.png differ diff --git a/src/assets/images/business/glfw.png b/src/assets/images/business/glfw.png new file mode 100644 index 0000000..1ac69af Binary files /dev/null and b/src/assets/images/business/glfw.png differ diff --git a/src/assets/images/business/wjx.png b/src/assets/images/business/wjx.png new file mode 100644 index 0000000..2cc12ca Binary files /dev/null and b/src/assets/images/business/wjx.png differ diff --git a/src/assets/images/business/wrj.png b/src/assets/images/business/wrj.png new file mode 100644 index 0000000..b5b6ae7 Binary files /dev/null and b/src/assets/images/business/wrj.png differ diff --git a/src/assets/images/business/xcr.png b/src/assets/images/business/xcr.png new file mode 100644 index 0000000..4ccdf3c Binary files /dev/null and b/src/assets/images/business/xcr.png differ diff --git a/src/assets/images/business/zgl.png b/src/assets/images/business/zgl.png new file mode 100644 index 0000000..a5847ea Binary files /dev/null and b/src/assets/images/business/zgl.png differ diff --git a/src/assets/images/business/zm.png b/src/assets/images/business/zm.png new file mode 100644 index 0000000..300191d Binary files /dev/null and b/src/assets/images/business/zm.png differ diff --git a/src/assets/styles/font.css b/src/assets/styles/font.css index b8eea30..ba7c1ad 100644 --- a/src/assets/styles/font.css +++ b/src/assets/styles/font.css @@ -1,4 +1,14 @@ @font-face { font-family: 'youshe'; src: url("../fonts/优设标题黑.ttf"); +} + +@font-face { + font-family: 'douyu'; + src: url("../fonts/douyuFont-2.otf"); +} + +@font-face { + font-family: 'huxiaopo'; + src: url("../fonts/HuXiaoBoNanShenTi-2.otf"); } \ No newline at end of file diff --git a/src/service/apiurl.js b/src/service/apiurl.js index 0e827a9..cf6fe7a 100644 --- a/src/service/apiurl.js +++ b/src/service/apiurl.js @@ -1,3 +1,4 @@ +import { reservoirlist } from "./station" const service = '/gunshiApp/ss' const apiurl = { @@ -167,6 +168,34 @@ const apiurl = { floodPerson: service + '/screen/responsibility/getFxPerson', train:service + '/screen/responsibility/getTraining' } + }, + sy: { + sssyq: { + rain: service + '/screen/monitoring/rain', + reservoir: service + '/screen/monitoring/rsvr', + flow:service + '/screen/monitoring/flow' + }, + ya: { + rota: service + '/screen/plan/rota', + document:service + '/screen/plan/doc' + } + }, + sg: { + aqjd: { + info:service + '/wholeCycle/security', + }, + aqyh:{ + info:service + '/screen/hidden/get/', + }, + skhj:{ + info:service + '/screen/reservoirDemarcationInfo/get', + }, + byjc:{ + info:service + '/screen/byfz/get/', + }, + wxyh:{ + info:service + '/screen/mfr/get/', + } } } diff --git a/src/views/Home/components/Business/SiGuan/components/Maintenance/index.js b/src/views/Home/components/Business/SiGuan/components/Maintenance/index.js new file mode 100644 index 0000000..aea2881 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/Maintenance/index.js @@ -0,0 +1,200 @@ +import React, { useEffect, useRef, useState } from 'react'; +import * as echarts from 'echarts'; +import './index.less'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; + +const Maintenance = ({ year }) => { + const chartRef = useRef(null); + const chartInstance = useRef(null); + const [activeIndex, setActiveIndex] = useState(0); + const [selectedPieItem, setSelectedPieItem] = useState(null); + const [startAngle, setStartAngle] = useState(90); + const [chartData, setChartData] = useState([]); + + // Color mapping configuration + const colorMap = { + '溢洪道清障': '#0090FF', + '除草除杂': '#00FFFF', + '设备养护': '#3355FB', + '环境清洁': '#BCEBF7', + '危险提示': '#00D085', + '其他': '#1890FF' + }; + + const defaultColors = ['#0090FF', '#00FFFF', '#3355FB', '#BCEBF7', '#00D085', '#1890FF']; + + const getInfo = async (year) => { + try { + const result = await httpget(apiurl.sg.wxyh.info + year); + if (result.code === 200 && result.data) { + // Transform object to array format + const transformedData = Object.entries(result.data).map(([name, value], index) => ({ + name, + value, + color: colorMap[name] || defaultColors[index % defaultColors.length] + })); + setChartData(transformedData); + } else { + setChartData([]); + } + } catch (error) { + console.error(error); + setChartData([]); + } + }; + + const total = chartData.reduce((sum, item) => sum + item.value, 0); + + const setSelectionByIndex = (index) => { + if (!chartData || chartData.length === 0 || index >= chartData.length) return; + + const item = chartData[index]; + let sumBefore = 0; + for (let i = 0; i < index; i++) { + sumBefore += chartData[i].value; + } + const offset = total > 0 ? (sumBefore + item.value / 2) / total * 360 : 0; + const newStartAngle = 90 + offset; + setStartAngle(newStartAngle); + setSelectedPieItem({ + name: item.name, + value: item.value, + percent: total > 0 ? ((item.value / total) * 100).toFixed(0) + '%' : '0%' + }); + }; + + useEffect(() => { + if (year) { + getInfo(year); + } + }, [year]); + + useEffect(() => { + if (chartData && chartData.length > 0) { + setSelectionByIndex(0); + setActiveIndex(0); + } else { + setSelectedPieItem(null); + setStartAngle(90); + } + }, [chartData]); + + useEffect(() => { + if (!chartRef.current) return; + + if (!chartInstance.current) { + chartInstance.current = echarts.init(chartRef.current); + chartInstance.current.on('click', (params) => { + if (params.dataIndex !== undefined) { + setActiveIndex(params.dataIndex); + setSelectionByIndex(params.dataIndex); + } + }); + } + + if (chartData.length === 0) { + chartInstance.current.clear(); + return; + } + + const centerName = selectedPieItem ? selectedPieItem.name : (chartData.length === 1 ? chartData[0].name : '维修养护'); + const centerValue = selectedPieItem ? selectedPieItem.value : total; + const centerPercent = selectedPieItem ? selectedPieItem.percent : '100%'; + + const option = { + tooltip: { + trigger: 'item', + formatter: '{b}: {c} ({d}%)' + }, + series: [ + { + name: '维修养护-外圈', + type: 'pie', + radius: ['52%', '94%'], + center: ['50%', '50%'], + startAngle: startAngle, + avoidLabelOverlap: false, + label: { + show: true, + position: 'inside', + formatter: '{b}', + color: '#fff', + fontSize: 10 + }, + itemStyle: { + opacity: 0.4 + }, + labelLine: { show: false }, + data: chartData.map(item => ({ + value: item.value, + name: item.name, + itemStyle: { color: item.color } + })) + }, + { + name: '维修养护-内圈', + type: 'pie', + radius: ['60%', '70%'], + center: ['50%', '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 } + })) + } + ] + }; + + chartInstance.current.setOption(option); + + const handleResize = () => { + chartInstance.current?.resize(); + }; + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [activeIndex, selectedPieItem, startAngle, chartData]); + + return ( +
+
+
+ {chartData.map((item, index) => ( +
{ + setActiveIndex(index); + setSelectionByIndex(index); + }} + > +
+
{item.name}
+
{item.value}
+
+ ))} +
+
+ ); +}; + +export default Maintenance; diff --git a/src/views/Home/components/Business/SiGuan/components/Maintenance/index.less b/src/views/Home/components/Business/SiGuan/components/Maintenance/index.less new file mode 100644 index 0000000..687e8a8 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/Maintenance/index.less @@ -0,0 +1,53 @@ +.maintenance-container { + width: 100%; + height: 100%; + display: flex; + align-items: center; + padding: 0; + box-sizing: border-box; + + .chart-wrapper { + flex: 1; + height: 100%; + min-width: 0; + } + + .legend-wrapper { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 10px; + + .legend-item { + display: flex; + align-items: center; + color: rgba(255, 255, 255, 0.85); + font-size: 14px; + cursor: pointer; + padding: 4px 8px; + border-radius: 4px; + transition: background-color 0.3s; + + &.active, &:hover { + background-color: rgba(255, 255, 255, 0.1); + } + + .legend-color { + width: 10px; + height: 10px; + margin-right: 10px; + border-radius: 2px; + } + + .legend-name { + flex: 1; + } + + .legend-value { + font-size: 14px; + color: #fff; + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.js b/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.js new file mode 100644 index 0000000..ec9ab14 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.js @@ -0,0 +1,187 @@ +import React, { useEffect, useRef,useState } from 'react'; +import * as echarts from 'echarts'; +import arrowIcon from '@/assets/images/card/arrow.png'; +import glfwBg from '@/assets/images/business/glfw.png'; +import bhfwBg from '@/assets/images/business/bhfw.png'; +import smallCard from '@/assets/images/card/smallCard.png'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; +import './index.less'; + +const ReservoirDemarcation = () => { + const chartRef = useRef(null); + const chartInstance = useRef(null); + const [info, setInfo] = useState({ + managementScopeArea: 0, + protectionScopeArea: 0, + propertyCertificateArea: 0, + totalUseArea: 0 + }); + + const getInfo = async () => { + try { + const result = await httpget(apiurl.sg.skhj.info); + if (result.code === 200) { + setInfo(result.data); + } + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + if (!chartRef.current) return; + + if (!chartInstance.current) { + chartInstance.current = echarts.init(chartRef.current); + } + + const total = Number(info.totalUseArea) || 0; + const property = Number(info.propertyCertificateArea) || 0; + const maxVal = total > 0 ? total : 1; + const rate = total > 0 ? Math.min(Math.max(property / total, 0), 1) : 0; + const option = { + series: [ + { + type: 'gauge', + startAngle: 210, + endAngle: -30, + min: 0, + max: maxVal, + splitNumber: 40, + radius: '125%', + center: ['50%', '65%'], + axisLine: { + show: true, + lineStyle: { + width: 10, + opacity: 0, + color: [ + [rate, '#0bbafe'], + [1, 'rgba(255, 255, 255, 0.1)'] + ] + } + }, + axisTick: { + show: true, + length: 12, + distance: -12, + lineStyle: { + color: 'auto', + width: 3 + } + }, + splitLine: { + show: false + }, + axisLabel: { + show: false + }, + pointer: { + show: false + }, + title: { + show: true, + offsetCenter: [0, '30%'], + fontSize: 14, + color: '#fff' + }, + detail: { + valueAnimation: true, + formatter: '{value}万亩', + color: '#00D8FF', + fontSize: 14, + fontWeight: 'bold', + offsetCenter: [0, '-15%'] + }, + data: [ + { + value: property, + name: '不动产权' + } + ] + } + ] + }; + + chartInstance.current.setOption(option); + + const handleResize = () => { + chartInstance.current && chartInstance.current.resize(); + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [info]); + + // Clean up chart instance on unmount + useEffect(() => { + getInfo() + return () => { + if (chartInstance.current) { + chartInstance.current.dispose(); + chartInstance.current = null; + } + }; + }, []); + + return ( +
+ {/* Section 1: Management and Protection Scope */} +
+
+ arrow + 管理和保护范围 +
+
+ +
+
+
+
+ {info.managementScopeArea} + km² +
+
管理范围
+
+
+
+
+
+ {info.protectionScopeArea} + km² +
+
保护范围
+
+
+
+ + {/* Section 2: Clear Property Rights */} +
+
+ arrow + 产权清晰 +
+
+ +
+
+
+
+ 已取得不动产权证书面积: + {info.propertyCertificateArea}万亩 +
+
+ 用地总面积: + {info.totalUseArea}万亩 +
+
+
+
+ ); +}; + +export default ReservoirDemarcation; diff --git a/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.less b/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.less new file mode 100644 index 0000000..7ae1b41 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/ReservoirDemarcation/index.less @@ -0,0 +1,94 @@ +.reservoir-demarcation { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + box-sizing: border-box; + + .scope-area { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + + .scope-card { + width: 48%; + height: 60px; + background-size: 100% 100%; + background-repeat: no-repeat; + display: flex; + align-items: center; + padding-left: 80px; // Make space for the icon in the bg image + box-sizing: border-box; + + .scope-content { + display: flex; + flex-direction: column; + justify-content: center; + + .value-wrapper { + margin-bottom: 2px; + .value { + font-size: 16px; + font-weight: bold; + color: #00D8FF; + font-family: 'huxiaopo', sans-serif; + margin-right: 4px; + } + .unit { + font-size: 14px; + color: #00D8FF; + } + } + + .label { + font-size: 14px; + color: rgba(255, 255, 255); + } + } + } + } + + .property-area { + flex: 1; + display: flex; + align-items: center; + min-height: 0; + + .chart-wrapper { + width: 36%; + height: 100%; + position: relative; + } + + .info-list { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + gap: 8px; + padding-left: 10px; + + .info-item { + width: 100%; + height: 32px; + background-size: 100% 100%; + background-repeat: no-repeat; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 10px; + box-sizing: border-box; + + .label { + font-size: 14px; + color: #fff; + } + + .value { + font-size: 14px; + color: #00D8FF; + } + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.js b/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.js new file mode 100644 index 0000000..b2641cb --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.js @@ -0,0 +1,44 @@ +import React from 'react'; +import xcrIcon from '@/assets/images/business/xcr.png'; +import wrjIcon from '@/assets/images/business/wrj.png'; +import './index.less'; + +const ReservoirInspection = () => { + // Mock data matching the design + const data = { + annualCount: 78, + droneCount: 156 + }; + + return ( +
+
+
+ 年度巡查 +
+
+
+ {data.annualCount} + +
+
年度巡查
+
+
+ +
+
+ 无人机巡查 +
+
+
+ {data.droneCount} + +
+
无人机巡查
+
+
+
+ ); +}; + +export default ReservoirInspection; diff --git a/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.less b/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.less new file mode 100644 index 0000000..419b496 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/ReservoirInspection/index.less @@ -0,0 +1,54 @@ +.reservoir-inspection { + width: 100%; + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 20px; + + .inspection-item { + display: flex; + align-items: center; + gap: 15px; + + .icon-wrapper { + width: 50px; + display: flex; + justify-content: center; + + img { + height: 60px; + width: auto; + } + } + + .info { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + + .count-row { + .count { + font-size: 20px; + font-weight: bold; + color: #00D8FF; + margin-right: 2px; + } + + .unit { + font-size: 14px; + color: #00D8FF; + } + } + + .label { + font-size: 14px; + color: rgba(255, 255, 255, 0.7); + margin-top: 2px; + white-space: nowrap; + + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.js b/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.js new file mode 100644 index 0000000..2c3a17e --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.js @@ -0,0 +1,82 @@ +import React,{useEffect,useState} from 'react'; +import smallCard from '@/assets/images/card/smallCard.png'; +import barTypeIcon from '@/assets/images/business/barType.png'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; +import './index.less'; + +const SafetyAppraisal = () => { + const [info, setInfo] = useState({}) + const topCards = [ + { label: '', value: '双石水库', isTitle: true }, + { label: '', value: '赤壁市/\n官塘驿镇', isLocation: true }, + { label: '', value: '中型', isType: true }, + ]; + const getInfo = async () => { + try { + const result = await httpget(apiurl.sg.aqjd.info); + if (result.code === 200) { + setInfo(result.data); + } + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + getInfo() + }, []) + + + return ( +
+ {/* Top Section: Cards */} +
+ {topCards.map((item, index) => ( +
+
+ {item.isLocation ? ( +
+
赤壁市/
+
官塘驿镇
+
+ ) : ( + item.value + )} +
+
+ ))} +
+ + {/* Bottom Section: Timeline */} +
+
+ +
+
+
鉴定时间
+
{info?.identifyDate ??'-'}年
+
+ +
+
+ Type +
+
{info?.identifyType ??'-'}
+
+ +
+
+
下次鉴定时间
+
{info?.nextVerifyDate ??'-'}年
+
+
+
+ ); +}; + +export default SafetyAppraisal; diff --git a/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.less b/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.less new file mode 100644 index 0000000..cb6c65d --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SafetyAppraisal/index.less @@ -0,0 +1,124 @@ +.safety-appraisal { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + box-sizing: border-box; + + .top-cards { + display: flex; + justify-content: space-between; + height: 70px; + margin-bottom: 15px; + .info-card { + width: 32%; + height: 100%; + background-size: 100% 100%; + background-repeat: no-repeat; + display: flex; + align-items: center; + justify-content: center; + + .sg-card-content { + text-align: center; + color: #fff; + font-size: 14px; + font-weight: 500; + + &.title-style { + font-size: 18px; + font-family: douyu; + letter-spacing: 1px; + } + + &.type-style { + font-size: 18px; + color: #00D8FF; + font-family: douyu; + + } + + .location-text { + font-size: 14px; + line-height: 1.4; + } + } + } + } + + .timeline-section { + flex: 1; + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 20px; + + .timeline-line { + position: absolute; + top: 30%; + left: 20px; + right: 20px; + height: 2px; + background: #007acc; + transform: translateY(-50%); + z-index: 0; + } + + .timeline-item { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + width: 100px; + + &.left, &.right { + margin-top:20px; + .dot { + width: 12px; + height: 12px; + background: #00D8FF; + border-radius: 50%; + margin-bottom: 10px; + box-shadow: 0 0 5px #00D8FF; + } + + .label { + color: #00D8FF; + font-size: 16px; + margin-bottom: 5px; + font-weight: bold; + } + + .date { + color: #fff; + font-size: 16px; + font-weight: bold; + } + } + + &.center { + margin-top: -40px; // Adjust to lift the icon above the line slightly if needed, or rely on flex alignment + .icon-wrapper { + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 2px; + img { + width: 30px; + height: 30px; + } + } + + .label.type-label { + color: #00D8FF; + font-size: 18px; + font-family: douyu; + } + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.js b/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.js new file mode 100644 index 0000000..4f930de --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.js @@ -0,0 +1,165 @@ +import React, { useEffect, useRef, useState } from 'react'; +import * as echarts from 'echarts'; +import zglIcon from '@/assets/images/business/zgl.png'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; +import './index.less'; + +const SafetyHazard = ({ year }) => { + const chartRef = useRef(null); + const chartInstance = useRef(null); + const [info, setInfo] = useState({ + totalCount: 0, + finishCount: 0, + finishPercent: 0, + months: {} + }); + + const getInfo = async (params) => { + try { + const result = await httpget(apiurl.sg.aqyh.info + params); + if (result.code === 200) { + setInfo(result.data); + } + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + if (year) { + getInfo(year); + } + }, [year]); + + useEffect(() => { + if (!chartRef.current) return; + + if (!chartInstance.current) { + chartInstance.current = echarts.init(chartRef.current); + } + + const monthlyData = Array.from({ length: 12 }, (_, i) => info.months?.[i + 1] || 0); + console.log(monthlyData); + + const option = { + grid: { + top: '15%', + left: '5%', + right: '5%', + bottom: '5%', + containLabel: true + }, + xAxis: { + type: 'category', + data: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12 月'], + axisLine: { + lineStyle: { + color: 'rgba(255, 255, 255, 0.5)' + } + }, + axisTick: { + show: false + }, + axisLabel: { + color: '#fff', + fontSize: 12, + interval: 0 + } + }, + yAxis: { + type: 'value', + splitLine: { + lineStyle: { + color: 'rgba(255, 255, 255, 0.1)', + type: 'dashed' + } + }, + axisLabel: { + color: '#fff', + fontSize: 12 + } + }, + series: [ + { + type: 'bar', + barWidth: '30%', + data: monthlyData, + itemStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#00D8FF' }, + { offset: 1, color: 'rgba(0, 216, 255, 0.1)' } + ]), + borderRadius: [2, 2, 0, 0] + } + } + ] + }; + + chartInstance.current.setOption(option); + + const handleResize = () => { + chartInstance.current && chartInstance.current.resize(); + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, [info]); + + // Clean up chart instance on unmount + useEffect(() => { + return () => { + if (chartInstance.current) { + chartInstance.current.dispose(); + chartInstance.current = null; + } + }; + }, []); + + return ( +
+ {/* Top Section */} +
+
+
+
+ 隐患总数 + {info.totalCount} +
+
+ 已整改 + {info.finishCount} +
+
+
+
0 ? (info.finishCount / info.totalCount) * 100 : 0}%` }} + >
+
+
+ +
+
+ Rate +
+
+
+ {info.finishPercent} + % +
+
整改率
+
+
+
+ + {/* Chart Section */} +
+
+ ); +}; + +export default SafetyHazard; diff --git a/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.less b/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.less new file mode 100644 index 0000000..2837943 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SafetyHazard/index.less @@ -0,0 +1,123 @@ +.safety-hazard { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + padding: 5px; + box-sizing: border-box; + + .top-section { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + height: 60px; + + .progress-area { + flex: 1; + margin-right: 15px; + display: flex; + flex-direction: column; + justify-content: center; + + .labels { + display: flex; + justify-content: space-between; + .total-label, .rectified-label { + display: flex; + flex-direction: column; + + .text { + font-size: 14px; + color: rgba(255, 255, 255); + margin-bottom: 0; + } + + .num { + font-size: 16px; + font-weight: bold; + color: #fff; + } + } + + .rectified-label { + align-items: flex-end; + .text { + color: #00D8FF; + } + .num { + color: #00D8FF; + } + } + } + + .progress-bar-bg { + width: 100%; + height: 18px; + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + overflow: hidden; + + .progress-bar-fill { + height: 100%; + background: #f59e0b; // Orange color matching the design + border-radius: 6px; + } + } + } + + .rate-box { + width: 130px; + border: 1px solid #00a0e9; + display: flex; + align-items: center; + padding: 5px; + position: relative; + + // Add corner markers if needed, or simple border + + .icon-wrapper { + width: 40px; + margin-right: 5px; + display: flex; + justify-content: center; + + img { + width: 30px; + height: auto; + } + } + + .rate-info { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding-right: 5px; + + .rate-num { + font-family: 'huxiaopo', sans-serif; + font-size: 16px; + color: #00D8FF; + // line-height: 1; + margin-bottom: 2px; + + .percent { + font-size: 14px; + margin-left: 2px; + } + } + + .rate-text { + font-size: 14px; + color: #fff; + } + } + } + } + + .chart-container { + flex: 1; + width: 100%; + min-height: 0; // Important for flex child to shrink + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.js b/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.js new file mode 100644 index 0000000..354814a --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.js @@ -0,0 +1,35 @@ +import React from 'react'; +import zmIcon from '@/assets/images/business/zm.png'; +import './index.less'; + +const SluiceMonitor = () => { + // Mock data based on the UI image + const gateData = [ + { id: 1, name: 'XXXX闸门1', opening: 0.3, time: '12-25 09:32' }, + { id: 2, name: 'XXXX闸门2', opening: 0.0, time: '12-25 09:32' }, + { id: 3, name: 'XXXX闸门3', opening: 0.0, time: '12-25 09:32' }, + ]; + + return ( +
+ {gateData.map((item) => ( +
+
+ gate +
+
+ {item.name} +
+ 开度: + {item.opening.toFixed(1)} + m +
+ {item.time} +
+
+ ))} +
+ ); +}; + +export default SluiceMonitor; diff --git a/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.less b/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.less new file mode 100644 index 0000000..09b58a7 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/SluiceMonitor/index.less @@ -0,0 +1,71 @@ +.sluice-monitor { + width: 100%; + height: 100%; + overflow-y: auto; + padding: 0 10px; + + &::-webkit-scrollbar { + width: 0; + height: 0; + } + + .gate-item { + display: flex; + align-items: center; + padding: 6px 0; + &:last-child { + border-bottom: none; + } + + .icon-wrapper { + margin-right: 15px; + img { + width: 32px; + height: auto; + } + } + + .gate-info { + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + color: #fff; + font-size: 14px; + + .gate-name { + flex: 1; + } + + .status-wrapper { + display: flex; + align-items: baseline; + margin: 0 20px; + + .label { + color: rgba(255, 255, 255, 0.8); + margin-right: 5px; + } + + .value { + font-size: 16px; + color: #00D8FF; + font-family: huxiaopo; + margin-right: 5px; + } + + .unit { + color: #00D8FF; + font-family: huxiaopo; + } + } + + .time { + color: rgba(255, 255, 255); + font-size: 14px; + min-width: 90px; + text-align: right; + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.js b/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.js new file mode 100644 index 0000000..621e8d8 --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.js @@ -0,0 +1,103 @@ +import React, { useState,useEffect } from 'react'; +import moment from 'moment'; +import YearSelect from '../../../../UI/YearSelect'; +import smallCard from '@/assets/images/card/smallCard.png'; +import arrowIcon from '@/assets/images/card/arrow.png'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; +import './index.less'; + +const TermiteControl = () => { + const [year, setYear] = useState(moment().format('YYYY')); + const [info, setInfo] = useState({ + searchCount: 0, + hasByCount: 0, + hasByCount: 0, + }); + + const getInfo = async (year) => { + try { + const result = await httpget(apiurl.sg.byjc.info+year); + if (result.code === 200) { + setInfo(result.data); + } + } catch (error) { + console.error(error); + } + }; + const data = { + monitorRange: 13600, + monitorDevices: 89, + }; + + useEffect(() => { + if (year) { + getInfo(year) + } + }, [year]) + + + return ( +
+ {/* Section 1: Termite Monitoring Devices */} +
+
+ arrow + 白蚁监控装置 +
+
+ +
+
+
+ {data.monitorRange} + +
+
白蚁监控范围
+
+
+
+ {data.monitorDevices} + +
+
监控装置数量
+
+
+ + {/* Section 2: Census and Prevention Results */} +
+
+ arrow + 普查及防治结果 +
+ +
+ +
+
+
+ {info.searchCount} + +
+
白蚁普查
+
+
+
+ {info.hasByCount} + +
+
有白蚁危害
+
+
+
+ {info.hasByCount} + +
+
已处置
+
+
+
+ ); +}; + +export default TermiteControl; diff --git a/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.less b/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.less new file mode 100644 index 0000000..b68ac4f --- /dev/null +++ b/src/views/Home/components/Business/SiGuan/components/TermiteControl/index.less @@ -0,0 +1,94 @@ +.termite-control { + height: 100%; + display: flex; + flex-direction: column; + + .section-header { + margin-bottom: 10px; + + &.with-action { + margin-top: 15px; + margin-bottom: 10px; + } + } + + .monitor-grid { + display: flex; + gap: 25px; + min-height: 0; + justify-content: center; + .info-card { + width: 45%; + background-size: 100% 100%; + background-repeat: no-repeat; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px 0; + + .value-wrapper { + display: flex; + align-items: baseline; + + .value { + font-size: 16px; + font-weight: bold; + color: #00D8FF; + } + .unit { + font-size: 14px; + color: #00D8FF; + margin-left: 2px; + } + } + + .label { + font-size: 14px; + color: rgba(255, 255, 255); + } + } + } + + .census-grid { + display: flex; + gap: 10px; + flex: 1; + min-height: 0; + + .info-card { + // flex: 1; + width: 33%; + background-size: 100% 100%; + background-repeat: no-repeat; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px 0; + .value-wrapper { + display: flex; + align-items: baseline; + + .value { + font-size: 16px; + font-weight: bold; + + &.text-blue { color: #00D8FF; } + &.text-red { color: #FF4D4F; } + &.text-green { color: #52C41A; } + } + .unit { + font-size: 14px; + color: #00D8FF; // Always blue + margin-left: 2px; + } + } + + .label { + font-size: 14px; + color: rgba(255, 255, 255, 0.8); + } + } + } +} diff --git a/src/views/Home/components/Business/SiGuan/index.js b/src/views/Home/components/Business/SiGuan/index.js index 4d845b6..a021e6b 100644 --- a/src/views/Home/components/Business/SiGuan/index.js +++ b/src/views/Home/components/Business/SiGuan/index.js @@ -1,39 +1,62 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; +import moment from 'moment'; import CommonCard from '../../UI/CommonCard'; import YearSelect from '../../UI/YearSelect'; +import SafetyAppraisal from './components/SafetyAppraisal'; +import ReservoirInspection from './components/ReservoirInspection'; +import SafetyHazard from './components/SafetyHazard'; +import SluiceMonitor from './components/SluiceMonitor'; +import ReservoirDemarcation from './components/ReservoirDemarcation'; +import TermiteControl from './components/TermiteControl'; +import Maintenance from './components/Maintenance'; import './index.less'; const SiGuan = () => { + const showPanels = useSelector(s => s.runtime.showPanels); + const [inspectionYear, setInspectionYear] = useState(moment().format('YYYY')); + const [hazardYear, setHazardYear] = useState(moment().format('YYYY')); + const [wxYear, setWxYear] = useState(moment().format('YYYY')); + return (
-
+
-
内容填充区域
+
- -
内容填充区域
+ } + style={{minHeight:120}} + > + -
内容填充区域
+
} + headerExtra={} > -
内容填充区域
+
-
+
-
内容填充区域
+
-
内容填充区域
+
- -
内容填充区域
+ } + > +
diff --git a/src/views/Home/components/Business/SiGuan/index.less b/src/views/Home/components/Business/SiGuan/index.less index 35278ae..0c9e635 100644 --- a/src/views/Home/components/Business/SiGuan/index.less +++ b/src/views/Home/components/Business/SiGuan/index.less @@ -6,10 +6,10 @@ @import "../common.less"; .left { - .card-1 { flex: 6; } - .card-2 { flex: 3; } - .card-3 { flex: 4; } - .card-4 { flex: 6; } + .card-1 { flex: 1; } + .card-2 { flex: 2; } + .card-3 { flex: 3; } + .card-4 { flex: 5; } } .right { diff --git a/src/views/Home/components/Business/SiQuan/components/ModalComponents/CycleArchive/index.js b/src/views/Home/components/Business/SiQuan/components/ModalComponents/CycleArchive/index.js index 9669e60..d3fff80 100644 --- a/src/views/Home/components/Business/SiQuan/components/ModalComponents/CycleArchive/index.js +++ b/src/views/Home/components/Business/SiQuan/components/ModalComponents/CycleArchive/index.js @@ -4,7 +4,7 @@ import { SearchOutlined, ReloadOutlined, DownloadOutlined, FilePdfOutlined, File import apiurl from '@/service/apiurl'; import usePageTable from '@/components/crud/usePageTable'; import { createCrudService } from '@/components/crud/_'; -import { exportFile } from '@/utils/tools' +import { download, exportFile } from '@/utils/tools' import { httppost } from '@/utils/request'; import { config } from '@/config'; import PdfView from '@/views/Home/components/UI/PdfView'; @@ -61,6 +61,7 @@ const CycleArchive = () => { const handleFileClick = (file) => { const fileType = file.fileName?.split('.').pop()?.toLowerCase(); + const downloadUrl = `/gunshiApp/ss/projectEvents/file/download/${file.fileId}`; if (fileType === 'pdf') { setPdfInfo({ visible: true, @@ -68,8 +69,7 @@ const CycleArchive = () => { fileId: file.fileId }); } else { - // Download for non-pdf files - window.open(config.minioIp + file.filePath, '_blank'); + download(downloadUrl) } }; diff --git a/src/views/Home/components/Business/SiQuan/index.js b/src/views/Home/components/Business/SiQuan/index.js index d0ad9ec..cf61081 100644 --- a/src/views/Home/components/Business/SiQuan/index.js +++ b/src/views/Home/components/Business/SiQuan/index.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useSelector } from 'react-redux'; import CommonCard from '../../UI/CommonCard'; import ThreeDots from '../../UI/ThreeDots'; import SupervisionCoverage from './components/SupervisionCoverage'; @@ -17,6 +18,7 @@ import './index.less'; const SiQuan = () => { + const showPanels = useSelector(s => s.runtime.showPanels); const [modalVisible, setModalVisible] = useState(false); const [modalType, setModalType] = useState('monitor'); // 'monitor' | 'cycle' | 'allweather' const [infos, setInfos] = useState({}); @@ -77,7 +79,7 @@ const SiQuan = () => { return (
-
+
@@ -91,7 +93,7 @@ const SiQuan = () => {
-
+
{ + const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' }); + const [imagePreview, setImagePreview] = useState({ visible: false, src: '' }); + const [rotaInfo, setRotaInfo] = useState({}); + const [docList, setDocList] = useState([]); + // 获取值班信息 + const getRotaInfo = async () => { + try { + const result = await httpget(apiurl.sy.ya.rota); + if (result.code === 200) { + setRotaInfo(result.data); + } + } catch (error) { + console.error(error); + } + }; + + // 获取预案列表 + const getDocInfo = async () => { + try { + const result = await httpget(apiurl.sy.ya.document); + if (result.code === 200) { + setDocList(result.data); + } + } catch (error) { + console.error(error); + } + }; + + const getDutyList = () => { + const todayList = rotaInfo.today || []; + const nextDayList = rotaInfo.nextDay || []; + + const formatDuty = (list, defaultDate) => { + const dateStr = list.length > 0 ? list[0].rotaDate : defaultDate; + const date = moment(dateStr).format('MM-DD'); + const leader = list.find(item => item.rotaType === 1)?.userName || '无'; + const staff = list.filter(item => item.rotaType === 2).map(i => i.userName).join('、') || '无'; + return { date, leader, staff }; + }; + + return [ + formatDuty(todayList, moment().format('YYYY-MM-DD')), + formatDuty(nextDayList, moment().add(1, 'days').format('YYYY-MM-DD')) + ]; + }; + + const dutyData = getDutyList(); + + const handlePreview = (item) => { + const file = item?.files?.[0]; + if (!file || !item.fileName) return; + const fileName = file.fileName; + const fileId = file.fileId; + const extension = fileName.split('.').pop().toLowerCase(); + const downloadUrl = `/gunshiApp/ss/resPlanB/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) + } + }; + + useEffect(() => { + getRotaInfo() + getDocInfo() + }, []) + + + return ( +
+ {/* Section 1: Duty Info */} +
+
+ arrow + 值班信息 +
+
+ +
+ {dutyData.map((item, index) => ( +
+
+ {item.date} +
+
+
+ leader +
+ 值班领导 + {item.leader} +
+
+
+ staff +
+ 值班人员 + {item.staff} +
+
+
+
+ ))} +
+ + {/* Section 2: Scheme Materials */} +
+
+ arrow + 方案资料 +
+
+ +
+ {docList.map((item, index) => { + const isPlan = item.type === 1; + const typeText = isPlan ? '防汛预案' : '调度规程'; + const colorClass = isPlan ? 'orange' : 'blue'; + + return ( +
+
+ {typeText} +
+
handlePreview(item)} + title={item.planName} + > + {item.planName} +
+
+ ); + })} +
+ + {/* PDF Viewer */} + {pdfInfo.visible && ( + setPdfInfo({ ...pdfInfo, visible: false })} + title={pdfInfo.title} + fileId={pdfInfo.fileId} + url="/gunshiApp/ss/resPlanB/file/download/" + /> + )} + + {/* Image Preview */} +
+ { + setImagePreview({ ...imagePreview, visible: value }); + }, + }} + /> +
+
+ ); +}; + +export default PlanSection; diff --git a/src/views/Home/components/Business/SiYu/components/PlanSection/index.less b/src/views/Home/components/Business/SiYu/components/PlanSection/index.less new file mode 100644 index 0000000..efc264a --- /dev/null +++ b/src/views/Home/components/Business/SiYu/components/PlanSection/index.less @@ -0,0 +1,145 @@ +.plan-section { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + box-sizing: border-box; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 0; + height: 0; + } + + .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); + } + } + } + + .duty-info { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + + .duty-card { + display: flex; + align-items: center; + width: 48%; + + .date-box { + width: 60px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + background-size: 100% 100%; + background-repeat: no-repeat; + margin-right: 10px; + font-size: 14px; + color: #fff; + // font-weight: bold; + padding: 0 5px; + white-space: nowrap; + } + + .staff-info { + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 5px; + // height: 80px; + + .staff-item { + display: flex; + align-items: center; + + .avatar { + width: 30px; + height: 30px; + margin-right: 8px; + object-fit: contain; + } + + .info-text { + display: flex; + flex-direction: column; + + .role { + font-size: 14px; + color: rgba(255, 255, 255); + } + + .name { + font-size: 14px; + color: #00eaff; + } + } + } + } + } + } + + .scheme-list { + overflow-y: auto; + max-height: 120px; + .scheme-item { + display: flex; + align-items: center; + margin-bottom: 12px; + + .tag { + width: 80px; + height: 28px; + line-height: 28px; + text-align: center; + color: #fff; + font-size: 13px; + margin-right: 15px; + flex-shrink: 0; + + &.blue { + background: #1890ff; + } + + &.orange { + background: #fa8c16; + } + } + + .doc-name { + flex: 1; + font-size: 14px; + color: #00eaff; + cursor: pointer; + text-decoration: underline; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + color: #fff; + } + } + } + } +} diff --git a/src/views/Home/components/Business/SiYu/components/WarningSection/index.less b/src/views/Home/components/Business/SiYu/components/WarningSection/index.less index 5b1199c..5ebbe57 100644 --- a/src/views/Home/components/Business/SiYu/components/WarningSection/index.less +++ b/src/views/Home/components/Business/SiYu/components/WarningSection/index.less @@ -15,14 +15,14 @@ .tab-item { flex: 1; text-align: center; - padding: 5px 0; + 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; - margin: 0 5px; + // margin: 0 5px; &.active { color: #fff; diff --git a/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.js b/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.js new file mode 100644 index 0000000..5a443c9 --- /dev/null +++ b/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.js @@ -0,0 +1,256 @@ +import React, { useState, useEffect } from 'react'; +import { Table } from 'antd'; +import selectedBg from '@/assets/images/modal/selected.png'; +import apiurl from '@/service/apiurl'; +import { httpget } from '@/utils/request'; +import CommonModal from '@/views/Home/components/UI/CommonModal'; +import RightPanel from '../../../SiQuan/components/ModalComponents/AllWeatherModal/RainMonitor/RightPanel'; +import ReservoirPanel from '../../../SiQuan/components/ModalComponents/AllWeatherModal/ReservoirPanel'; +import FlowPanel from '../../../SiQuan/components/ModalComponents/AllWeatherModal/FlowPanel'; +import './index.less'; + +const WaterRainSection = () => { + const [activeTab, setActiveTab] = useState('rain'); + const [dataList, setDataList] = useState([]); + const [loading, setLoading] = useState(false); + + // Detail Modal State + const [detailVisible, setDetailVisible] = useState(false); + const [selectedItem, setSelectedItem] = useState(null); + + const tabs = [ + { key: 'rain', label: '实时雨情' }, + { key: 'reservoir', label: '实时水库水情' }, + { key: 'flow', label: '出入库流量' } + ]; + + // Fetch Data Functions + const getRainList = async () => { + setLoading(true); + try { + const result = await httpget(apiurl.sy.sssyq.reservoir); + if (result.code === 200) { + setDataList(result.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false); + } + }; + + const getReservoirList = async () => { + setLoading(true); + try { + const result = await httpget(apiurl.sy.sssyq.rain); + if (result.code === 200) { + setDataList(result.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false); + } + }; + + const getFlowList = async () => { + setLoading(true); + try { + const result = await httpget(apiurl.sy.sssyq.flow); + if (result.code === 200) { + setDataList(result.data); + } + } catch (error) { + console.error(error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + setDataList([]); + if (activeTab === 'rain') { + getRainList(); + } else if (activeTab === 'reservoir') { + getReservoirList(); + } else if (activeTab === 'flow') { + getFlowList(); + } + }, [activeTab]); + + // Columns Definitions + const rainColumns = [ + { + title: '站点名称', + dataIndex: 'stnm', + key: 'stnm', + align: 'center', + width: 120, + ellipsis: true + }, + { + title: '今日', + dataIndex: 'todayDrp', + key: 'todayDrp', + align: 'center', + render: (text) => text ?? '-' + }, + { + title: '昨日', + dataIndex: 'yesterdayDrp', + key: 'yesterdayDrp', + align: 'center', + render: (text) => text ?? '-' + }, + { + title: '24h', + dataIndex: 'drp24', + key: 'drp24', + align: 'center', + render: (text) => text ?? '-' + }, + { + title: '48h', + dataIndex: 'drp48', // Assuming API has this, otherwise mock/calc + key: 'drp48', + align: 'center', + render: (text) => text ?? '-' + }, + { + title: '72h', + dataIndex: 'drp72', // Assuming API has this + key: 'drp72', + align: 'center', + render: (text) => text ?? '-' + } + ]; + + const reservoirColumns = [ + { + title: '站点名称', + dataIndex: 'stnm', + key: 'stnm', + align: 'center', + width: 120, + ellipsis: true + }, + { + title: '实时水位(m)', + dataIndex: 'rz', + key: 'rz', + align: 'center', + render: (text) => text ?? '-' + }, + { + title: '监测时间', + dataIndex: 'tm', + key: 'tm', + align: 'center', + width: 140, + render: (text) => text ? text.substring(5, 16) : '-' // Format: MM-DD HH:mm + } + ]; + + const flowColumns = [ + { + title: '站点名称', + dataIndex: 'stnm', + key: 'stnm', + align: 'center', + width: 120, + ellipsis: true + }, + { + title: '实时流量(m³/s)', + dataIndex: 'q', + key: 'q', + align: 'center', + }, + { + title: '监测时间', + dataIndex: 'tm', + key: 'tm', + align: 'center', + width: 140, + render: (text) => text ? text.substring(5, 16) : '-' // Format: MM-DD HH:mm + } + ]; + + const getColumns = () => { + switch (activeTab) { + case 'rain': return rainColumns; + case 'reservoir': return reservoirColumns; + case 'flow': return flowColumns; + default: return []; + } + }; + + const handleRowClick = (record) => { + setSelectedItem(record); + setDetailVisible(true); + }; + + const renderModalContent = () => { + if (!selectedItem) return null; + + if (activeTab === 'rain') { + return ; + } else if (activeTab === 'reservoir') { + return ; + } else if (activeTab === 'flow') { + return ; + } + return null; + }; + + const getModalTitle = () => { + if(activeTab === 'rain') return selectedItem?.stnm || '雨情详情'; + if(activeTab === 'reservoir') return selectedItem?.stnm || '水库详情'; + if(activeTab === 'flow') return selectedItem?.stnm || '流量详情'; + return '详情'; + } + + return ( +
+
+ {tabs.map(tab => ( +
setActiveTab(tab.key)} + style={activeTab === tab.key ? { backgroundImage: `url(${selectedBg})` } : {}} + > + {tab.label} +
+ ))} +
+ +
+ {activeTab === 'rain' &&
单位:mm
} + ({ + onClick: () => handleRowClick(record) + })} + /> + + + setDetailVisible(false)} + width={"80%"} + > + {renderModalContent()} + + + ); +}; + +export default WaterRainSection; diff --git a/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.less b/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.less new file mode 100644 index 0000000..682f2fd --- /dev/null +++ b/src/views/Home/components/Business/SiYu/components/WaterRainSection/index.less @@ -0,0 +1,96 @@ +.water-rain-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: 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; + margin: 0 5px; + + &.active { + color: #fff; + text-shadow: 0 0 10px #00a0e9; + border: none; + } + + &:hover { + color: #fff; + } + } + } + + .content-list { + flex: 1; + overflow-y: auto; + padding: 0 5px; + + // Scrollbar styling + &::-webkit-scrollbar { + width: 4px; + } + &::-webkit-scrollbar-thumb { + background: rgba(0, 160, 233, 0.5); + border-radius: 2px; + } + &::-webkit-scrollbar-track { + background: transparent; + } + + .unit-label { + text-align: right; + color: rgba(255,255,255,0.7); + font-size: 12px; + margin-bottom: 5px; + padding-right: 10px; + } + + .ant-table-wrapper { + .ant-table { + background: transparent; + color: #fff; + + .ant-table-thead > tr > th { + background: rgba(0, 70, 110, 0.6); + color: #fff; + border-bottom: none; + padding: 8px 4px; + text-align: center; + font-size: 13px; + } + + .ant-table-tbody > tr > td { + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + color: #fff; + padding: 8px 4px; + text-align: center; + font-size: 13px; + } + + .ant-table-tbody > tr:hover > td { + background: rgba(0, 160, 233, 0.1) !important; + } + + .ant-empty-normal { + color: rgba(255,255,255,0.5); + } + } + } + } +} diff --git a/src/views/Home/components/Business/SiYu/index.js b/src/views/Home/components/Business/SiYu/index.js index bfde3db..d4bdc3a 100644 --- a/src/views/Home/components/Business/SiYu/index.js +++ b/src/views/Home/components/Business/SiYu/index.js @@ -1,7 +1,12 @@ -import React from 'react'; +import React,{useState} from 'react'; +import { useSelector } from 'react-redux'; import CommonCard from '../../UI/CommonCard'; import ThreeDots from '../../UI/ThreeDots'; +import CommonModal from '../../UI/CommonModal'; import WarningSection from './components/WarningSection'; +import WaterRainSection from './components/WaterRainSection'; +import PlanSection from './components/PlanSection'; +import AllWeatherModal from '../SiQuan/components/ModalComponents/AllWeatherModal'; import './index.less'; @@ -27,11 +32,26 @@ const WarningToggles = ({ activeType, onToggle }) => { } const SiYu = () => { - const [warningType, setWarningType] = React.useState('monitor'); + const showPanels = useSelector(s => s.runtime.showPanels); + const [warningType, setWarningType] = useState('monitor'); + const [modalVisible, setModalVisible] = useState(false); + const [activeTab, setActiveTab] = useState('rain'); + + const tabsAllWeather = [ + { label: '雨情监测', value: 'rain' }, + { label: '水库水情', value: 'reservoir' }, + { label: '出入库流量', value: 'flow' }, + { label: '安全监测', value: 'safety' }, + ]; + + const handleOpenModal = () => { + setActiveTab('rain'); + setModalVisible(true); + }; return (
-
+
内容填充区域
@@ -40,7 +60,7 @@ const SiYu = () => {
-
+
{ console.log('实时水雨情 clicked')} />} + headerExtra={} > -
内容填充区域
+
-
内容填充区域
+
+ + setModalVisible(false)} + title="实时水雨情" + tabs={tabsAllWeather} + activeTab={activeTab} + onTabChange={setActiveTab} + width={'90%'} + > +
+ +
+
); }; diff --git a/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.js b/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.js index 395c1da..36ea79b 100644 --- a/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.js +++ b/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.js @@ -120,8 +120,8 @@ const StrengthenRuleOfLaw = () => { { name: '水政执法-外圈', type: 'pie', - radius: ['48%', '82%'], - center: ['34%', '50%'], + radius: ['52%', '94%'], + center: ['50%', '50%'], startAngle: startAngle, avoidLabelOverlap: false, label: { @@ -143,8 +143,8 @@ const StrengthenRuleOfLaw = () => { { name: '水政执法-内圈', type: 'pie', - radius: ['50%', '56%'], - center: ['34%', '50%'], + radius: ['60%', '70%'], + center: ['50%', '50%'], startAngle: startAngle, avoidLabelOverlap: false, label: { @@ -305,43 +305,50 @@ const StrengthenRuleOfLaw = () => {
arrow - 水政执法 + 水政执法
- +
- -
- {chartData.length > 0 ? ( - <> -
+ +
+
+ {chartData.length > 0 ? ( -
-
- {chartData.map((item, index) => ( -
- - {item.name} - {item.value} -
- ))} -
- - ) : ( -
+ ) : ( +
暂无数据} /> -
- )} +
+ )} +
+
+ {chartData.map((item, index) => ( +
{ + // Logic to highlight item if needed, currently main interaction is click on chart + const fakeParams = { + componentType: 'series', + name: item.name, + value: item.value, + dataIndex: index + }; + // Optional: trigger hover effect or selection + // onChartClick(fakeParams); // This might be too aggressive on hover + }} + > +
+
{item.name}
+
{item.value}
+
+ ))} +
diff --git a/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.less b/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.less index 17e01c9..294379c 100644 --- a/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.less +++ b/src/views/Home/components/Business/SiZhi/components/StrengthenRuleOfLaw/index.less @@ -75,12 +75,14 @@ flex: 1; display: flex; flex-direction: column; + min-height: 0; /* Add this to allow flex container to shrink properly */ .section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; + flex-shrink: 0; .title-wrapper { display: flex; @@ -93,53 +95,64 @@ object-fit: contain; } - span { - font-size: 14px; - color: #fff; - text-shadow: 0 0 5px rgba(0, 160, 233, 0.5); - } + } } - .chart-legend-container { + .chart-container { flex: 1; display: flex; align-items: center; + min-height: 0; /* Critical for nested flex scrolling/sizing */ .chart-wrapper { flex: 1; height: 100%; - min-height: 140px; + min-width: 0; } .legend-wrapper { - width: 140px; + flex: 1; display: flex; flex-direction: column; justify-content: center; padding-left: 10px; + height: 100%; + overflow-y: auto; .legend-item { display: flex; align-items: center; - margin-bottom: 6px; - font-size: 12px; + color: rgba(255, 255, 255, 0.85); + font-size: 14px; + cursor: pointer; + padding: 4px 8px; + border-radius: 4px; + transition: background-color 0.3s; - .color-dot { - width: 8px; - height: 8px; - margin-right: 8px; + &.active, &:hover { + background-color: rgba(255, 255, 255, 0.1); + } + + .legend-color { + width: 10px; + height: 10px; + margin-right: 10px; border-radius: 2px; + flex-shrink: 0; } - .name { + .legend-name { flex: 1; - color: rgba(255, 255, 255, 0.8); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-right: 10px; } - .value { + .legend-value { + font-size: 14px; color: #fff; - font-weight: bold; } } } diff --git a/src/views/Home/components/Business/SiZhi/index.js b/src/views/Home/components/Business/SiZhi/index.js index 5802b82..e52db89 100644 --- a/src/views/Home/components/Business/SiZhi/index.js +++ b/src/views/Home/components/Business/SiZhi/index.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useSelector } from 'react-redux'; import CommonCard from '../../UI/CommonCard'; import PerfectSystem from './components/PerfectSystem'; import SoundMechanism from './components/SoundMechanism'; @@ -9,6 +10,7 @@ import apiurl from '@/service/apiurl'; import './index.less'; const SiZhi = () => { + const showPanels = useSelector(s => s.runtime.showPanels); const [infos, setInfos] = useState({}); const getInfo = async () => { @@ -27,7 +29,7 @@ const SiZhi = () => { }, []); return (
-
+
@@ -36,7 +38,7 @@ const SiZhi = () => {
-
+
diff --git a/src/views/Home/components/Business/common.less b/src/views/Home/components/Business/common.less index 92e7cf2..edfc9af 100644 --- a/src/views/Home/components/Business/common.less +++ b/src/views/Home/components/Business/common.less @@ -12,10 +12,16 @@ &.left { left: 20px; + &.hidden { + transform: translateX(-120%); + } } &.right { right: 20px; + &.hidden { + transform: translateX(120%); + } } > * { @@ -38,3 +44,28 @@ height: 100%; color: rgba(255, 255, 255, 0.5); } + +.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); + } + } +} diff --git a/src/views/Home/index.js b/src/views/Home/index.js index 113672b..9b8c8bd 100644 --- a/src/views/Home/index.js +++ b/src/views/Home/index.js @@ -56,15 +56,15 @@ const HomePage = () => { // style={{position:"relative"}} 这段以后写在.home-page里
-
-
+
+
{renderContent()}
{/* 地图相关 */} -
+
{/* 地图 */} diff --git a/src/views/Home/index.less b/src/views/Home/index.less index ea05201..6e0b5ca 100644 --- a/src/views/Home/index.less +++ b/src/views/Home/index.less @@ -10,11 +10,19 @@ color: #fff; font-family: "Microsoft YaHei", sans-serif; + .dashboard-header { + position: relative; + z-index: 10; + pointer-events: auto; + } + .main-content-wrapper { flex: 1; overflow: hidden; padding: 0; position: relative; + pointer-events: none; + z-index: 5; .content-overlay { position: absolute; @@ -24,31 +32,8 @@ height: 100%; z-index: 5; // Content sits above the map pointer-events: none; // Let clicks pass through to map by default - - // Re-enable pointer events for actual interactive children - > * { - pointer-events: auto; - } - } - } - .content-layer { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 10; // Above map - pointer-events: none; // Let clicks pass through to map by default - - // But children (cards) must be clickable. - // This will be handled in child components or we can set it here if all children are full-screen overlays - // It's safer to handle in children, but for now, since SiQuan is the child: - > * { - pointer-events: none; - width: 100%; - height: 100%; - } } } +}