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 */}
+
+
+

+
管理和保护范围
+
+
+
+
+
+
+
+ {info.managementScopeArea}
+ km²
+
+
管理范围
+
+
+
+
+
+ {info.protectionScopeArea}
+ km²
+
+
保护范围
+
+
+
+
+ {/* Section 2: Clear Property Rights */}
+
+
+

+
产权清晰
+
+
+
+
+
+
+
+ 已取得不动产权证书面积:
+ {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 ??'-'}年
+
+
+
+
+

+
+
{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}%` }}
+ >
+
+
+
+
+
+

+
+
+
+ {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) => (
+
+
+

+
+
+
{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 */}
+
+
+

+
白蚁监控装置
+
+
+
+
+
+
+ {data.monitorRange}
+ m²
+
+
白蚁监控范围
+
+
+
+ {data.monitorDevices}
+ 处
+
+
监控装置数量
+
+
+
+ {/* Section 2: Census and Prevention Results */}
+
+
+

+
普查及防治结果
+
+
+
+
+
+
+
+ {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 */}
+
+
+

+
值班信息
+
+
+
+
+ {dutyData.map((item, index) => (
+
+
+ {item.date}
+
+
+
+

+
+ 值班领导
+ {item.leader}
+
+
+
+

+
+ 值班人员
+ {item.staff}
+
+
+
+
+ ))}
+
+
+ {/* Section 2: Scheme Materials */}
+
+
+

+
方案资料
+
+
+
+
+ {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 = () => {

-
水政执法
+
水政执法
-
+
-
-
- {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里
-
-
+
{/* 地图相关 */}
-
+
{/* 地图 */}
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%;
- }
}
}
+}