diff --git a/src/api/monitor/alert.js b/src/api/monitor/alert.js new file mode 100644 index 0000000..dba235c --- /dev/null +++ b/src/api/monitor/alert.js @@ -0,0 +1,33 @@ +import request from '@/utils/request' + +/** + * 获取预警统计概览 + * @returns {Promise} 返回预警统计数据 + */ +export function getAlertStatisticsOverview() { + return request.get('/api/admin/alert/statistics/overview') +} + +/** + * 获取预警趋势统计 + * @returns {Promise} 返回预警趋势统计数据 + */ +export function getAlertStatisticsTrend() { + return request.get('/api/admin/alert/statistics/trend') +} + +/** + * 获取指标预警统计 + * @returns {Promise} 返回各指标预警统计数据 + */ +export function getAlertStatisticsByIndicator() { + return request.get('/api/admin/alert/statistics/by-indicator') +} + +/** + * 获取规则预警统计 + * @returns {Promise} 返回规则预警统计数据 + */ +export function getAlertStatisticsByRule() { + return request.get('/api/admin/alert/statistics/by-rule') +} \ No newline at end of file diff --git a/src/api/monitoring.js b/src/api/monitoring.js new file mode 100644 index 0000000..3f9fa3a --- /dev/null +++ b/src/api/monitoring.js @@ -0,0 +1,49 @@ +import request from '@/utils/request' + +/** + * 按时间范围查询监测数据 + * @param {Object} params - 查询参数 + * @param {string} params.start_date - 开始时间 + * @param {string} params.end_date - 结束时间 + * @param {Array} params.indicator_ids - 指标ID数组 + * @param {number} params.point_id - 监测点ID + * @param {number} params.device_id - 设备ID + */ +export function getMonitoringData(params) { + return request.get('/api/monitoring/data', { params }) +} + +/** + * 获取最新数据 + * @param {Object} params - 查询参数 + * @param {number} params.point_id - 监测点ID + * @param {Array} params.indicator_ids - 指标ID数组 + * @param {number} params.device_id - 设备ID + */ +export function getLatestData(params) { + return request.get('/api/monitoring/data/latest', { params }) +} + +/** + * 获取统计数据 + * @param {Object} params - 查询参数 + * @param {string} params.start_date - 开始时间 + * @param {string} params.end_date - 结束时间 + * @param {number} params.indicator_id - 指标ID + * @param {number} params.point_id - 监测点ID + * @param {number} params.device_id - 设备ID + */ +export function getStatistics(params) { + return request.get('/api/monitoring/data/statistics', { params }) +} + +/** + * 获取数据质量统计 + * @param {Object} params - 查询参数 + * @param {string} params.start_date - 开始时间 + * @param {string} params.end_date - 结束时间 + * @param {number} params.point_id - 监测点ID + */ +export function getQualityStatistics(params) { + return request.get('/api/monitoring/data/quality-statistics', { params }) +} \ No newline at end of file diff --git a/src/views/dashboard/screen/components/CenterPanel/DataChart.vue b/src/views/dashboard/screen/components/CenterPanel/DataChart.vue index 788ff59..2b52468 100644 --- a/src/views/dashboard/screen/components/CenterPanel/DataChart.vue +++ b/src/views/dashboard/screen/components/CenterPanel/DataChart.vue @@ -1,13 +1,275 @@ @@ -16,22 +278,40 @@ .data-chart { height: 100%; padding: 16px; + box-sizing: border-box; + background: rgba(6, 30, 93, 0.5); + border-radius: 4px; - .chart-title { - font-size: 16px; - font-weight: 500; - color: #fff; - margin-bottom: 16px; - } - - .chart-content { - height: calc(100% - 32px); + .chart-container { + height: 100%; display: flex; - align-items: center; - justify-content: center; + gap: 16px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .chart-item { + flex: 1; + display: flex; + flex-direction: column; + background: rgba(0, 0, 0, 0.2); + border-radius: 4px; + padding: 12px; + + .chart-title { + font-size: 16px; + font-weight: bold; + color: #fff; + text-align: center; + margin-bottom: 12px; + background: linear-gradient(to bottom, #ffffff, #3fa7dd); + -webkit-background-clip: text; + color: transparent; + letter-spacing: 2px; + } + + .species-chart, + .patrol-chart { + flex: 1; + min-height: 0; + } } } } diff --git a/src/views/dashboard/screen/components/LeftPanel/BottomCard.vue b/src/views/dashboard/screen/components/LeftPanel/BottomCard.vue index 33fc283..c67dadd 100644 --- a/src/views/dashboard/screen/components/LeftPanel/BottomCard.vue +++ b/src/views/dashboard/screen/components/LeftPanel/BottomCard.vue @@ -1,14 +1,215 @@ @@ -16,23 +217,56 @@ .bottom-card { height: 100%; padding: 16px; + box-sizing: border-box; + background: rgba(6, 30, 93, 0.5); + border-radius: 4px; - .card-title { - font-size: 16px; - font-weight: 500; - color: #fff; - margin-bottom: 16px; - } - - .card-content { - height: calc(100% - 32px); + .card-header { display: flex; + justify-content: space-between; align-items: center; - justify-content: center; + margin-bottom: 20px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .title { + font-size: 18px; + font-weight: bold; + background: linear-gradient(to bottom, #ffffff, #3fa7dd); + -webkit-background-clip: text; + color: transparent; + letter-spacing: 2px; + } + + .update-time { + font-size: 14px; + color: #3fa7dd; + opacity: 0.8; + position: relative; + padding-left: 20px; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 8px; + height: 8px; + background: #67C23A; + border-radius: 50%; + animation: blink 1s infinite; + } } } + + .chart-container { + height: calc(100% - 60px); + width: 100%; + } +} + +@keyframes blink { + 0% { opacity: 0.2; } + 50% { opacity: 1; } + 100% { opacity: 0.2; } } \ No newline at end of file diff --git a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue index aa2f5d3..58537c6 100644 --- a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue +++ b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue @@ -1,13 +1,304 @@ @@ -16,6 +307,8 @@ .middle-card { height: 100%; padding: 16px; + background: rgba(0, 0, 0, 0.2); + border-radius: 8px; .card-title { font-size: 16px; @@ -27,11 +320,22 @@ .card-content { height: calc(100% - 32px); display: flex; - align-items: center; - justify-content: center; + flex-direction: column; + gap: 16px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .indicator-chart { + flex: 1; + min-height: 180px; + } + + .trend-chart { + flex: 2; + min-height: 200px; + } + + .quality-chart { + flex: 1; + min-height: 180px; } } } diff --git a/src/views/dashboard/screen/components/LeftPanel/TopCard.vue b/src/views/dashboard/screen/components/LeftPanel/TopCard.vue index 5c80ac9..c5613ab 100644 --- a/src/views/dashboard/screen/components/LeftPanel/TopCard.vue +++ b/src/views/dashboard/screen/components/LeftPanel/TopCard.vue @@ -1,39 +1,56 @@ @@ -16,23 +204,68 @@ .bottom-card { height: 100%; padding: 16px; + box-sizing: border-box; + background: rgba(6, 30, 93, 0.5); + border-radius: 4px; - .card-title { - font-size: 16px; - font-weight: 500; - color: #fff; - margin-bottom: 16px; - } - - .card-content { - height: calc(100% - 32px); + .card-header { display: flex; + justify-content: space-between; align-items: center; - justify-content: center; + margin-bottom: 20px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .title { + font-size: 18px; + font-weight: bold; + background: linear-gradient(to bottom, #ffffff, #3fa7dd); + -webkit-background-clip: text; + color: transparent; + letter-spacing: 2px; + } + + .total-alert { + font-size: 14px; + color: rgba(255, 255, 255, 0.8); + + .value { + color: #36CFFF; + font-size: 20px; + font-weight: bold; + margin-left: 4px; + } + } + + .update-time { + font-size: 14px; + color: #3fa7dd; + opacity: 0.8; + position: relative; + padding-left: 20px; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 8px; + height: 8px; + background: #67C23A; + border-radius: 50%; + animation: blink 1s infinite; + } } } + + .chart-container { + height: calc(100% - 60px); + width: 100%; + } +} + +@keyframes blink { + 0% { opacity: 0.2; } + 50% { opacity: 1; } + 100% { opacity: 0.2; } } \ No newline at end of file diff --git a/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue b/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue index ba06998..b48657b 100644 --- a/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue +++ b/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue @@ -1,14 +1,170 @@ @@ -16,23 +172,56 @@ .middle-card { height: 100%; padding: 16px; + box-sizing: border-box; + background: rgba(6, 30, 93, 0.5); + border-radius: 4px; - .card-title { - font-size: 16px; - font-weight: 500; - color: #fff; - margin-bottom: 16px; - } - - .card-content { - height: calc(100% - 32px); + .card-header { display: flex; + justify-content: space-between; align-items: center; - justify-content: center; + margin-bottom: 20px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .title { + font-size: 18px; + font-weight: bold; + background: linear-gradient(to bottom, #ffffff, #3fa7dd); + -webkit-background-clip: text; + color: transparent; + letter-spacing: 2px; + } + + .update-time { + font-size: 14px; + color: #3fa7dd; + opacity: 0.8; + position: relative; + padding-left: 20px; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 8px; + height: 8px; + background: #67C23A; + border-radius: 50%; + animation: blink 1s infinite; + } } } + + .chart-container { + height: calc(100% - 60px); + width: 100%; + } +} + +@keyframes blink { + 0% { opacity: 0.2; } + 50% { opacity: 1; } + 100% { opacity: 0.2; } } \ No newline at end of file diff --git a/src/views/dashboard/screen/components/RightPanel/TopCard.vue b/src/views/dashboard/screen/components/RightPanel/TopCard.vue index 850656d..2267822 100644 --- a/src/views/dashboard/screen/components/RightPanel/TopCard.vue +++ b/src/views/dashboard/screen/components/RightPanel/TopCard.vue @@ -1,14 +1,163 @@ @@ -16,23 +165,56 @@ .top-card { height: 100%; padding: 16px; + box-sizing: border-box; + background: rgba(6, 30, 93, 0.5); + border-radius: 4px; - .card-title { - font-size: 16px; - font-weight: 500; - color: #fff; - margin-bottom: 16px; - } - - .card-content { - height: calc(100% - 32px); + .card-header { display: flex; + justify-content: space-between; align-items: center; - justify-content: center; + margin-bottom: 20px; - .placeholder { - color: rgba(255, 255, 255, 0.6); + .title { + font-size: 18px; + font-weight: bold; + background: linear-gradient(to bottom, #ffffff, #3fa7dd); + -webkit-background-clip: text; + color: transparent; + letter-spacing: 2px; + } + + .update-time { + font-size: 14px; + color: #3fa7dd; + opacity: 0.8; + position: relative; + padding-left: 20px; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 8px; + height: 8px; + background: #67C23A; + border-radius: 50%; + animation: blink 1s infinite; + } } } + + .chart-container { + height: calc(100% - 60px); + width: 100%; + } +} + +@keyframes blink { + 0% { opacity: 0.2; } + 50% { opacity: 1; } + 100% { opacity: 0.2; } } \ No newline at end of file