diff --git a/src/api/monitoring.js b/src/api/monitoring.js
index 3f9fa3a..cdbc004 100644
--- a/src/api/monitoring.js
+++ b/src/api/monitoring.js
@@ -3,35 +3,40 @@ 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
+ * @param {string} [params.start_date] - 开始时间,格式:YYYY-MM-DD
+ * @param {string} [params.end_date] - 结束时间,格式:YYYY-MM-DD
+ * @param {string} [params.indicator_ids] - 指标ID,多个用逗号分隔
+ * @param {string} [params.point_id] - 监测点ID
+ * @param {string} [params.device_id] - 设备ID
*/
export function getMonitoringData(params) {
- return request.get('/api/monitoring/data', { params })
+ return request.get('/api/monitoring/dataQuery', { params })
}
/**
* 获取最新数据
* @param {Object} params - 查询参数
- * @param {number} params.point_id - 监测点ID
- * @param {Array} params.indicator_ids - 指标ID数组
- * @param {number} params.device_id - 设备ID
+ * @param {string} [params.point_id] - 监测点ID
+ * @param {string} [params.indicator_ids] - 指标ID,多个用逗号分隔
+ * @param {string} [params.device_id] - 设备ID
*/
export function getLatestData(params) {
- return request.get('/api/monitoring/data/latest', { params })
+ // 确保 indicator_ids 是字符串格式
+ const formattedParams = {
+ ...params,
+ indicator_ids: Array.isArray(params.indicator_ids) ? params.indicator_ids.join(',') : params.indicator_ids
+ }
+ return request.get('/api/monitoring/data/latest', { params: formattedParams })
}
/**
* 获取统计数据
* @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
+ * @param {string} [params.start_date] - 开始时间,格式:YYYY-MM-DD
+ * @param {string} [params.end_date] - 结束时间,格式:YYYY-MM-DD
+ * @param {string} [params.indicator_id] - 指标ID
+ * @param {string} [params.point_id] - 监测点ID
+ * @param {string} [params.device_id] - 设备ID
*/
export function getStatistics(params) {
return request.get('/api/monitoring/data/statistics', { params })
@@ -40,9 +45,9 @@ export function getStatistics(params) {
/**
* 获取数据质量统计
* @param {Object} params - 查询参数
- * @param {string} params.start_date - 开始时间
- * @param {string} params.end_date - 结束时间
- * @param {number} params.point_id - 监测点ID
+ * @param {string} [params.start_date] - 开始时间,格式:YYYY-MM-DD
+ * @param {string} [params.end_date] - 结束时间,格式:YYYY-MM-DD
+ * @param {string} [params.point_id] - 监测点ID
*/
export function getQualityStatistics(params) {
return request.get('/api/monitoring/data/quality-statistics', { params })
diff --git a/src/views/dashboard/screen/components/CenterPanel/DataChart.vue b/src/views/dashboard/screen/components/CenterPanel/DataChart.vue
index 2b52468..50ccb57 100644
--- a/src/views/dashboard/screen/components/CenterPanel/DataChart.vue
+++ b/src/views/dashboard/screen/components/CenterPanel/DataChart.vue
@@ -13,19 +13,109 @@ const fetchSpeciesData = async () => {
try {
const res = await request.get('/api/admin/species/statistics/overview')
if (res.success && res.data) {
- updateSpeciesChart(res.data)
+ // 中文名称映射
+ const categoryNames = {
+ bird: '鸟类',
+ mammal: '哺乳类',
+ fish: '鱼类',
+ amphibian: '两栖类',
+ reptile: '爬行类',
+ insect: '昆虫类',
+ plant: '植物'
+ }
+
+ // 将数据转换为饼图所需格式
+ const chartData = Object.entries(res.data.categories).map(([key, value]) => ({
+ name: categoryNames[key],
+ value: parseInt(value.total_count),
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: getSpeciesColor(key)[0] },
+ { offset: 1, color: getSpeciesColor(key)[1] }
+ ])
+ }
+ })).sort((a, b) => b.value - a.value) // 按数量从大到小排序
+
+ speciesChart.setOption({
+ series: [{
+ data: chartData
+ }]
+ })
}
} catch (error) {
console.error('获取物种统计数据失败:', error)
}
}
+// 获取物种类别的颜色
+const getSpeciesColor = (category) => {
+ const colors = {
+ bird: ['#36CFFF', '#2861F5'],
+ mammal: ['#FF36D9', '#C92AF5'],
+ fish: ['#FFB72C', '#F5612A'],
+ amphibian: ['#4EF568', '#2AB256'],
+ reptile: ['#36FFB0', '#2AF5A1'],
+ insect: ['#7636FF', '#2A3CF5'],
+ plant: ['#FF7636', '#F52A2A']
+ }
+ return colors[category] || ['#36CFFF', '#2861F5']
+}
+
// 获取巡护统计数据
const fetchPatrolData = async () => {
try {
const res = await request.get('/api/admin/patrol/records/statistics/overview')
if (res.success && res.data) {
- updatePatrolChart(res.data)
+ const { overview } = res.data
+ const chartData = [
+ {
+ name: '已完成',
+ value: Number(overview.completed_count) || 0,
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#67C23A' },
+ { offset: 1, color: '#67C23A99' }
+ ])
+ }
+ },
+ {
+ name: '进行中',
+ value: Number(overview.in_progress_count) || 0,
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#409EFF' },
+ { offset: 1, color: '#409EFF99' }
+ ])
+ }
+ },
+ {
+ name: '总任务',
+ value: Number(overview.total_count) || 0,
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: '#909399' },
+ { offset: 1, color: '#90939999' }
+ ])
+ }
+ }
+ ]
+
+ patrolChart.setOption({
+ xAxis: {
+ data: chartData.map(item => item.name)
+ },
+ series: [{
+ data: chartData,
+ label: {
+ show: true,
+ position: 'top',
+ color: '#fff',
+ formatter: function(params) {
+ return Math.floor(params.value)
+ }
+ }
+ }]
+ })
}
} catch (error) {
console.error('获取巡护统计数据失败:', error)
@@ -39,54 +129,50 @@ const initSpeciesChart = () => {
speciesChart = echarts.init(speciesChartRef.value)
const option = {
backgroundColor: 'transparent',
- title: {
- text: '物种分布统计',
- textStyle: {
- color: '#fff',
- fontSize: 16
- },
- left: 'center',
- top: 0
- },
tooltip: {
trigger: 'item',
- formatter: '{b}: {c} ({d}%)'
+ formatter: function(params) {
+ const percent = parseInt(params.percent)
+ return `${params.name}: ${parseInt(params.value)}种 (${percent}%)`
+ }
},
legend: {
- orient: 'vertical',
- right: '5%',
- top: 'middle',
- textStyle: {
- color: '#fff'
- }
+ show: false
},
series: [
{
+ name: '物种分布',
type: 'pie',
radius: ['40%', '70%'],
- center: ['40%', '55%'],
+ center: ['50%', '50%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 10,
- borderColor: '#fff',
+ borderColor: 'rgba(0, 0, 0, 0.2)',
borderWidth: 2
},
label: {
show: true,
+ position: 'outside',
+ formatter: function(params) {
+ return `${params.name}\n${parseInt(params.value)}种`
+ },
color: '#fff',
- formatter: '{b}\n{c}种'
+ fontSize: 12
},
- emphasis: {
- label: {
- show: true,
- fontSize: 16,
- fontWeight: 'bold'
+ labelLine: {
+ length: 15,
+ length2: 0,
+ maxSurfaceAngle: 80,
+ lineStyle: {
+ color: 'rgba(255, 255, 255, 0.3)'
}
},
data: []
}
]
}
+
speciesChart.setOption(option)
}
@@ -97,19 +183,13 @@ const initPatrolChart = () => {
patrolChart = echarts.init(patrolChartRef.value)
const option = {
backgroundColor: 'transparent',
- title: {
- text: '巡护任务统计',
- textStyle: {
- color: '#fff',
- fontSize: 16
- },
- left: 'center',
- top: 0
- },
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
+ },
+ formatter: function(params) {
+ return `${params[0].name}: ${Math.floor(params[0].value)}`
}
},
grid: {
@@ -121,7 +201,7 @@ const initPatrolChart = () => {
},
xAxis: {
type: 'category',
- data: ['已完成', '进行中', '未开始', '已超时'],
+ data: ['已完成', '进行中', '总任务'],
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
@@ -134,6 +214,9 @@ const initPatrolChart = () => {
},
yAxis: {
type: 'value',
+ minInterval: 1,
+ splitNumber: 4,
+ min: 0,
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)',
@@ -141,7 +224,10 @@ const initPatrolChart = () => {
}
},
axisLabel: {
- color: '#fff'
+ color: '#fff',
+ formatter: function(value) {
+ return Math.floor(value)
+ }
}
},
series: [
@@ -154,7 +240,10 @@ const initPatrolChart = () => {
label: {
show: true,
position: 'top',
- color: '#fff'
+ color: '#fff',
+ formatter: function(params) {
+ return parseInt(params.value || 0) + '个'
+ }
},
data: []
}
@@ -163,62 +252,6 @@ const initPatrolChart = () => {
patrolChart.setOption(option)
}
-// 更新物种统计图表
-const updateSpeciesChart = (data) => {
- const colors = {
- '鸟类': '#36CFFF',
- '鱼类': '#FFB72C',
- '两栖类': '#4EF568',
- '爬行类': '#FF36D9',
- '哺乳类': '#9E87FF'
- }
-
- const chartData = Object.entries(data.category_counts || {}).map(([name, value]) => ({
- name,
- value,
- itemStyle: {
- color: colors[name] || '#36CFFF'
- }
- }))
-
- speciesChart.setOption({
- series: [{
- data: chartData
- }]
- })
-}
-
-// 更新巡护统计图表
-const updatePatrolChart = (data) => {
- const colors = {
- '已完成': '#67C23A',
- '进行中': '#409EFF',
- '未开始': '#909399',
- '已超时': '#F56C6C'
- }
-
- const chartData = [
- { name: '已完成', value: data.completed || 0 },
- { name: '进行中', value: data.in_progress || 0 },
- { name: '未开始', value: data.not_started || 0 },
- { name: '已超时', value: data.overdue || 0 }
- ].map(item => ({
- value: item.value,
- itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: colors[item.name] },
- { offset: 1, color: colors[item.name].replace('FF', '99') }
- ])
- }
- }))
-
- patrolChart.setOption({
- series: [{
- data: chartData
- }]
- })
-}
-
// 自动刷新数据
let timer = null
const startAutoRefresh = () => {
@@ -295,10 +328,10 @@ onUnmounted(() => {
border-radius: 4px;
padding: 12px;
- .chart-title {
- font-size: 16px;
+ .chart-title {
+ font-size: 16px;
font-weight: bold;
- color: #fff;
+ color: #fff;
text-align: center;
margin-bottom: 12px;
background: linear-gradient(to bottom, #ffffff, #3fa7dd);
diff --git a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
index 58537c6..d247829 100644
--- a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
+++ b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
@@ -1,17 +1,11 @@
@@ -307,36 +179,67 @@ onUnmounted(() => {
.middle-card {
height: 100%;
padding: 16px;
- background: rgba(0, 0, 0, 0.2);
- border-radius: 8px;
+ 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-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+
+ .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;
+ }
+ }
}
.card-content {
- height: calc(100% - 32px);
- display: flex;
- flex-direction: column;
- gap: 16px;
+ height: calc(100% - 60px);
- .indicator-chart {
- flex: 1;
- min-height: 180px;
- }
+ .chart-item {
+ height: 100%;
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 4px;
+ padding: 12px;
- .trend-chart {
- flex: 2;
- min-height: 200px;
- }
-
- .quality-chart {
- flex: 1;
- min-height: 180px;
+ .chart {
+ height: 100%;
+ width: 100%;
+ }
}
}
}
+
+@keyframes blink {
+ 0% { opacity: 0.2; }
+ 50% { opacity: 1; }
+ 100% { opacity: 0.2; }
+}
\ No newline at end of file