diff --git a/.env.production b/.env.production index 328bd30..7b64a88 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,2 @@ GENERATE_SOURCEMAP=false -PUBLIC_URL=/ssDp +PUBLIC_URL=/ssDp \ No newline at end of file diff --git a/src/components/ant_override.less b/src/components/ant_override.less index 012932a..195da0a 100644 --- a/src/components/ant_override.less +++ b/src/components/ant_override.less @@ -238,6 +238,22 @@ input:-webkit-autofill:active { &:not(.ant-select-disabled):hover .ant-select-selector { border-color: #3b7cff !important; } + + // Multiple Select Tags + &.ant-select-multiple .ant-select-selection-item { + background: rgba(0, 160, 233, 0.2); // Light blue transparent + border: 1px solid #00a0e9; + color: #fff; + margin-top: 2px; + margin-bottom: 2px; + + .ant-select-selection-item-remove { + color: rgba(255, 255, 255, 0.7); + &:hover { + color: #fff; + } + } + } } // Dropdowns (Select, DatePicker, etc.) @@ -271,14 +287,42 @@ input:-webkit-autofill:active { } .ant-picker-cell { + color: rgba(255, 255, 255, 0.5); // Default inactive color + &:hover .ant-picker-cell-inner { - background: rgba(0, 160, 233, 0.3); + background: rgba(0, 160, 233, 0.3) !important; } + &-in-view { + color: #fff; // Active month days + } + + // Fix: Remove white background from cells + .ant-picker-cell-inner { + background: transparent !important; + color: inherit; + } + + &-selected .ant-picker-cell-inner { + background: #00a0e9 !important; // Project Cyan color: #fff; } - &-selected .ant-picker-cell-inner { - background: #3b7cff !important; + + &-today .ant-picker-cell-inner { + border: 1px solid #00a0e9; + &::before { + border: 1px solid #00a0e9 !important; + } + } + + // Range Selection + &-in-range::before { + background: rgba(0, 160, 233, 0.2) !important; + } + &-range-start .ant-picker-cell-inner, + &-range-end .ant-picker-cell-inner { + background: #00a0e9 !important; + color: #fff; } } @@ -308,14 +352,76 @@ input:-webkit-autofill:active { // 4. Button Component (Ghost Blue Style) // ============================================================================== .ant-btn-ghost-blue { - background: rgba(24, 144, 255, 0.3) !important; // Slight blue tint background - border: 1px solid #1890ff !important; + background: rgba(18, 56, 102, 0.6) !important; + border: 1px solid #00a0e9 !important; color: #fff !important; - box-shadow: 0 0 8px rgba(24, 144, 255, 0.3) inset; + box-shadow: 0 0 8px rgba(0, 160, 233, 0.2) inset; +} + +.ant-btn.ant-btn-ghost-blue, +.ant-btn.ant-btn-primary.ant-btn-ghost-blue { + background: rgba(18, 56, 102, 0.6) !important; + border-color: #00a0e9 !important; + color: #fff !important; +} + +.ant-btn.ant-btn-ghost-blue:hover, +.ant-btn.ant-btn-ghost-blue:focus, +.ant-btn.ant-btn-primary.ant-btn-ghost-blue:hover, +.ant-btn.ant-btn-primary.ant-btn-ghost-blue:focus { + background: rgba(0, 160, 233, 0.3) !important; + border-color: #33b5ed !important; + color: #fff !important; +} + +// ============================================================================== +// 5. Timeline Component +// ============================================================================== +.ant-timeline { + color: #fff; - &:hover, &:focus { - background: rgba(24, 144, 255, 0.3) !important; - border-color: #40a9ff !important; - color: #fff !important; + .ant-timeline-item-label { + color: #fff; + width: calc(50% - 12px); + } + + .ant-timeline-item-tail { + border-left: 2px solid rgba(0, 160, 233, 0.3); + } + + .ant-timeline-item-head { + background-color: transparent; + border-color: #00a0e9; + } + + .ant-timeline-item-head-blue { + color: #00a0e9; + border-color: #00a0e9; + } +} + +// ============================================================================== +// 6. Button Component (Global Override for Dark Theme) +// ============================================================================== +.ant-btn { + &.ant-btn-primary { + background: #00a0e9; // Project Theme Cyan + border-color: #00a0e9; + &:hover, &:focus { + background: #33b5ed; + border-color: #33b5ed; + } + } + + // Default button style in dark mode + &:not(.ant-btn-primary):not(.ant-btn-link):not(.ant-btn-text):not(.ant-btn-danger) { + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.3); + color: #fff; + + &:hover, &:focus { + color: #00a0e9; + border-color: #00a0e9; + } } } diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 0000000..79a40d7 --- /dev/null +++ b/src/config/index.js @@ -0,0 +1,4 @@ +export const config = { + ip: 'http://223.75.53.141:83', + minioIp:"http://223.75.53.141:9100/gs-ss" +} \ No newline at end of file diff --git a/src/service/apiurl.js b/src/service/apiurl.js index 6fb13d9..905522e 100644 --- a/src/service/apiurl.js +++ b/src/service/apiurl.js @@ -24,7 +24,11 @@ const apiurl = { qth: { rainList: { list:service + '/attResBase/rainBasinDivision/queryStPptnDetails/list', - } + }, + }, + qzq: { + list: service + '/projectEvents/doc/page', + export: service + '/projectEvents/export' } } } diff --git a/src/utils/request.js b/src/utils/request.js index 305328e..7a52516 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -49,6 +49,15 @@ async function send(url, options) { return {}; } +async function sendFile(url, options) { + try { + const res = await request(url, options,'blob'); + return res; + } catch (e) { + message.error(e); + } + return {}; + } export function httpget(url, data = {}) { const params = []; @@ -106,7 +115,7 @@ export function ry_httpget(url, data = {}) { } -export function httppost(url, data = {}) { +export function httppost(url, data = {},type) { const options = { method: 'POST', headers: { @@ -117,8 +126,8 @@ export function httppost(url, data = {}) { }, body: JSON.stringify(data), }; - - return send(url, options); + const fun = type == 'blob' ? sendFile(url, options) : send(url, options); + return fun; } export function httpPostFile(url, data = {}) { diff --git a/src/utils/tools.js b/src/utils/tools.js index d70027b..e17cbf1 100644 --- a/src/utils/tools.js +++ b/src/utils/tools.js @@ -19,6 +19,22 @@ export function objType(obj) { } return typeof obj === 'object' || typeof obj === 'function' ? class2type[toString.call(obj)] || 'object' : typeof obj; } + +export const exportFile = (name, res) => { + // 创建a标签 + let blob = new Blob([res],{ type: 'application/octet-stream' }) + // 创建下载链接 + const downloadUrl = URL.createObjectURL(blob); + // 创建下载链接的 元素 + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = name; + // 模拟点击下载链接 + downloadLink.click(); + // 清理创建的 URL 对象 + URL.revokeObjectURL(downloadUrl); + +} /** * 是否数组 * @param {object} obj 需要判断的对象 diff --git a/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.js b/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.js index d6f83ee..64ea239 100644 --- a/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.js +++ b/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.js @@ -41,12 +41,12 @@ const AllWeatherControl = () => { // Reservoir Data const reservoirData = [ - { label: '主坝坝前', value: '103.17', unit: 'm', isPrimary: true, showArrow: true, underline: true }, + { label: '主坝坝前', value: '103.17', unit: 'm', showArrow: true, underline: true }, { label: '汛限水位', value: '104.50', unit: 'm' }, { label: '距汛限', value: '-1.67', unit: 'm', isNegative: true }, { label: '副坝坝前', value: '104.17', unit: 'm' }, - { label: '当前库容', value: '3867.0', unit: '万m³', isPrimary: true }, - { label: '有效库容', value: '2867.0', unit: '万m³', isPrimary: true }, + { label: '当前库容', value: '3867.0', unit: '万m³'}, + { label: '有效库容', value: '2867.0', unit: '万m³'}, ]; const getRainList = async () => { diff --git a/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.less b/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.less index dcf1fe5..f6ba746 100644 --- a/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.less +++ b/src/views/Home/components/Business/SiQuan/components/AllWeatherControl/index.less @@ -138,7 +138,7 @@ color: #fff; } - &.primary { color: #00eaff; } + &.positive { color: #ff4d52; } &.negative { color: #68c639; } } diff --git a/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.js b/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.js new file mode 100644 index 0000000..0c2a64d --- /dev/null +++ b/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.js @@ -0,0 +1,116 @@ +import React, { useEffect, useMemo, useState } from 'react'; +import { DatePicker, Button, Table } from 'antd'; +import ReactEcharts from 'echarts-for-react'; +import usePageTable from '@/components/crud/usePageTable'; +import { createCrudService } from '@/components/crud/_'; +import apiurl from '@/service/apiurl'; +import './index.less'; + +const { RangePicker } = DatePicker; + +const RainPanel = () => { + const { tableProps, search } = usePageTable(createCrudService(apiurl.sq.qth.rainList).find); + const [range, setRange] = useState(); + useEffect(() => { + search({ search: {} }); + }, []); + const columns = [ + { title: '时间', dataIndex: 'tm', key: 'tm', width: 140, align: 'center' }, + { title: '小时雨量(mm)', dataIndex: 'drp', key: 'drp', align: 'center' }, + ]; + const option = useMemo(() => ({ + title: { text: '雨量趋势', left: 'center', textStyle: { color: '#fff' } }, + tooltip: { trigger: 'axis' }, + grid: { left: '8%', right: '4%', bottom: '10%', top: '15%' }, + xAxis: { type: 'category', data: (tableProps.dataSource || []).map(i => i.tm), axisLabel: { color: '#fff' } }, + yAxis: { type: 'value', axisLabel: { color: '#fff' }, splitLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.2)' } } }, + series: [{ type: 'line', smooth: true, data: (tableProps.dataSource || []).map(i => i.drp), areaStyle: { color: 'rgba(0,160,233,0.25)' }, lineStyle: { color: '#00a0e9' } }], + }), [tableProps.dataSource]); + return ( +
+
+
+ + +
+ + +
+ +
+ + ); +}; + +const ReservoirPanel = () => { + const columns = [ + { title: '时间', dataIndex: 'tm', key: 'tm', width: 140, align: 'center' }, + { title: '水位(m)', dataIndex: 'rz', key: 'rz', align: 'center' }, + { title: '库容(万m³)', dataIndex: 'w', key: 'w', align: 'center' }, + ]; + const data = []; + const option = { + title: { text: '水位趋势', left: 'center', textStyle: { color: '#fff' } }, + grid: { left: '8%', right: '4%', bottom: '10%', top: '15%' }, + tooltip: { trigger: 'axis' }, + xAxis: { type: 'category', data: data.map(i => i.tm), axisLabel: { color: '#fff' } }, + yAxis: { type: 'value', axisLabel: { color: '#fff' }, splitLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.2)' } } }, + series: [{ type: 'line', smooth: true, data: data.map(i => i.rz), lineStyle: { color: '#00a0e9' } }], + }; + return ( +
+
+
+ +
+ +
+ + ); +}; + +const FlowPanel = () => { + const columns = [ + { title: '时间', dataIndex: 'tm', key: 'tm', width: 140, align: 'center' }, + { title: '入库(m³/s)', dataIndex: 'qin', key: 'qin', align: 'center' }, + { title: '出库(m³/s)', dataIndex: 'qout', key: 'qout', align: 'center' }, + ]; + const data = []; + const option = { + title: { text: '出入库流量', left: 'center', textStyle: { color: '#fff' } }, + grid: { left: '8%', right: '4%', bottom: '10%', top: '15%' }, + tooltip: { trigger: 'axis' }, + legend: { data: ['入库', '出库'], textStyle: { color: '#fff' } }, + xAxis: { type: 'category', data: data.map(i => i.tm), axisLabel: { color: '#fff' } }, + yAxis: { type: 'value', axisLabel: { color: '#fff' }, splitLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.2)' } } }, + series: [ + { name: '入库', type: 'line', data: data.map(i => i.qin), lineStyle: { color: '#00a0e9' } }, + { name: '出库', type: 'line', data: data.map(i => i.qout), lineStyle: { color: '#3b7cff' } }, + ], + }; + return ( +
+
+
+ +
+ +
+ + ); +}; + +const SafetyPanel = () => { + return ( +
内容待接入
+ ); +}; + +const AllWeatherModal = ({ active }) => { + if (active === 'rain') return ; + if (active === 'reservoir') return ; + if (active === 'flow') return ; + return ; +}; + +export default AllWeatherModal; diff --git a/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.less b/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.less new file mode 100644 index 0000000..8314bc2 --- /dev/null +++ b/src/views/Home/components/Business/SiQuan/components/ModalComponents/AllWeatherModal/index.less @@ -0,0 +1,32 @@ +.all-weather-modal { + height: 100%; + display: flex; + flex-direction: column; +} +.awm-grid { + height: calc(100% - 48px); + display: flex; + gap: 16px; +} +.awm-left { + flex: 0 0 420px; + display: flex; + flex-direction: column; + gap: 10px; +} +.awm-toolbar { + display: flex; + align-items: center; + gap: 10px; +} +.awm-right { + flex: 1; + min-width: 0; +} +.awm-empty { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: rgba(255,255,255,0.6); +} 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 new file mode 100644 index 0000000..9669e60 --- /dev/null +++ b/src/views/Home/components/Business/SiQuan/components/ModalComponents/CycleArchive/index.js @@ -0,0 +1,187 @@ +import React, { useState, useEffect } from 'react'; +import { Timeline, Select, DatePicker, Button, Tag, Image, Tooltip } from 'antd'; +import { SearchOutlined, ReloadOutlined, DownloadOutlined, FilePdfOutlined, FileOutlined } from '@ant-design/icons'; +import apiurl from '@/service/apiurl'; +import usePageTable from '@/components/crud/usePageTable'; +import { createCrudService } from '@/components/crud/_'; +import { exportFile } from '@/utils/tools' +import { httppost } from '@/utils/request'; +import { config } from '@/config'; +import PdfView from '@/views/Home/components/UI/PdfView'; +import './index.less'; + +const { RangePicker } = DatePicker; + +const CycleArchive = () => { + const { tableProps, search, refresh } = usePageTable(createCrudService(apiurl.sq.qzq.list).find); + const [keyword, setKeyword] = useState([]); + const [dates, setDates] = useState(); + const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' }); + + useEffect(() => { + search({ search: {} }); + }, []); + + const handleSearch = () => { + const params = { + search: { + types: keyword.length > 0 ? keyword : undefined, + dateSo: dates ? { + start: dates[0]?.format('YYYY-MM-DD'), + end: dates[1]?.format('YYYY-MM-DD') + } : undefined + } + }; + search(params); + }; + + const handleReset = () => { + setKeyword([]); + setDates(undefined); + search({ search: {} }); + }; + + const onExport = () => { + let params = { + search: { + types: keyword.length > 0 ? keyword : undefined, + dateSo: dates ? { + start: dates[0]?.format('YYYY-MM-DD'), + end: dates[1]?.format('YYYY-MM-DD') + } : undefined + }, + pageSo:{ + pageNum:1,pageSize:9999 + } + } + httppost(apiurl.sq.qzq.export, params,'blob').then(res => { + exportFile(`全周期档案.xlsx`,res.data) + }) +} + + const handleFileClick = (file) => { + const fileType = file.fileName?.split('.').pop()?.toLowerCase(); + if (fileType === 'pdf') { + setPdfInfo({ + visible: true, + title: file.fileName, + fileId: file.fileId + }); + } else { + // Download for non-pdf files + window.open(config.minioIp + file.filePath, '_blank'); + } + }; + + const renderFileIcon = (file) => { + const fileType = file.fileName?.split('.').pop()?.toLowerCase(); + const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(fileType); + + if (isImage) { + return ( + + ); + } else if (fileType === 'pdf') { + return ; + } else { + return ; + } + }; + + return ( +
+ {/* Filters */} +
+
+ 类型: +