diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue
index 573ca28..50e311a 100644
--- a/src/views/dashboard/index.vue
+++ b/src/views/dashboard/index.vue
@@ -397,7 +397,7 @@ const initTrendChart = () => {
xAxis: {
type: "category",
boundaryGap: false,
- data: ["3-14", "3-15", "3-16", "3-17", "3-18", "3-19", "3-20"],
+ data: ["2-14", "2-15", "2-16", "2-17", "2-18", "2-19", "2-20"],
axisLine: {
lineStyle: {
color: "#DCDFE6",
@@ -719,66 +719,6 @@ onUnmounted(() => {
-
-
-
-
-
-
- 水质指标
- 优
-
-
- 空气质量
- 良
-
-
- 土壤湿度
- 42%
-
-
-
-
-
-
-
- 巡护人员
- 8人
-
-
- 巡护里程
- 12.5km
-
-
- 记录上报
- 26条
-
-
-
-
-
-
-
- 活动区域
- A3、B5区
-
-
- 活跃物种
- 15种
-
-
- 监测频次
- 4次/天
-
-
-
-
@@ -959,64 +899,5 @@ onUnmounted(() => {
}
}
}
-
- .bottom-stats-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- gap: 20px;
- margin-top: 40px;
- padding-bottom: 20px;
-
- .stat-card {
- background: #fff;
- border-radius: 8px;
- padding: 16px;
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
-
- .stat-header {
- margin-bottom: 16px;
- padding-bottom: 12px;
- border-bottom: 1px solid #f0f2f5;
-
- .stat-title {
- font-size: 16px;
- font-weight: 500;
- color: #303133;
- }
- }
-
- .stat-content {
- .stat-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 12px;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- .label {
- color: #909399;
- font-size: 14px;
- }
-
- .value {
- font-size: 14px;
- font-weight: 500;
- color: #303133;
-
- &.good {
- color: #67c23a;
- }
-
- &.normal {
- color: #e6a23c;
- }
- }
- }
- }
- }
- }
}
diff --git a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
index abe5cd4..d38c3c7 100644
--- a/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
+++ b/src/views/dashboard/screen/components/LeftPanel/MiddleCard.vue
@@ -92,37 +92,25 @@ const initChart = async () => {
const option = {
backgroundColor: 'transparent',
tooltip: {
- trigger: 'item'
- },
- legend: {
- orient: 'vertical',
- left: '0%',
- top: 'middle',
- textStyle: {
- color: '#fff',
- fontSize: 14
- },
- itemGap: 20,
- icon: 'circle',
- itemWidth: 10,
- itemHeight: 10,
- formatter: function(name) {
- return name
- }
+ trigger: 'item',
+ formatter: '{b}: {c}'
},
radar: {
- center: ['65%', '50%'],
- radius: '60%',
+ center: ['50%', '50%'],
+ radius: '65%',
indicator: [],
shape: 'circle',
- splitNumber: 5,
+ splitNumber: 8,
axisName: {
color: 'rgba(255, 255, 255, 0.7)',
fontSize: 12
},
splitLine: {
lineStyle: {
- color: 'rgba(255, 255, 255, 0.1)'
+ color: 'rgba(255, 255, 255, 0.2)',
+ width: 2,
+ type: 'dashed',
+ dashOffset: 0
}
},
splitArea: {
@@ -132,8 +120,9 @@ const initChart = async () => {
}
},
axisLine: {
+ show: true,
lineStyle: {
- color: 'rgba(255, 255, 255, 0.1)'
+ color: 'rgba(255, 255, 255, 0.3)'
}
}
},
@@ -142,6 +131,27 @@ const initChart = async () => {
chart.setOption(option)
+ // 添加动画效果
+ let angle = 0
+ let dashOffset = 0
+ const animate = () => {
+ angle = (angle + 0.5) % 360
+ dashOffset = (dashOffset + 1) % 20
+
+ chart.setOption({
+ radar: {
+ startAngle: angle,
+ splitLine: {
+ lineStyle: {
+ dashOffset: -dashOffset
+ }
+ }
+ }
+ })
+ requestAnimationFrame(animate)
+ }
+ animate()
+
// 确保图表正确渲染
setTimeout(() => {
if (chart) {
@@ -183,14 +193,18 @@ const updateChart = () => {
// 生成系列数据
const series = [{
type: 'radar',
+ animation: true,
+ animationDuration: 2000,
+ animationEasing: 'quadraticInOut',
data: points.map(point => {
const pointType = point.type
const colors = {
- water: ['#409EFF', '#36CE9E'],
- air: ['#E6A23C', '#F56C6C'],
- soil: ['#67C23A', '#95D475']
+ water: ['rgba(64, 158, 255, 1)', 'rgba(54, 206, 158, 0.1)'],
+ air: ['rgba(230, 162, 60, 1)', 'rgba(245, 108, 108, 0.1)'],
+ soil: ['rgba(103, 194, 58, 1)', 'rgba(149, 212, 117, 0.1)'],
+ default: ['rgba(64, 158, 255, 1)', 'rgba(54, 206, 158, 0.1)']
}
- const colorSet = colors[pointType] || colors.water
+ const colorSet = colors[pointType] || colors.default
return {
name: point.point,
@@ -198,27 +212,36 @@ const updateChart = () => {
const ind = point.indicators.find(i => i.name === indicator.name)
return ind ? ind.value : 0
}),
+ symbol: 'circle',
+ symbolSize: 6,
itemStyle: {
- color: colorSet[0]
+ color: colorSet[0],
+ borderColor: '#fff',
+ borderWidth: 2,
+ shadowColor: colorSet[0],
+ shadowBlur: 10
+ },
+ lineStyle: {
+ color: colorSet[0],
+ width: 2,
+ type: [5, 10],
+ shadowColor: colorSet[0],
+ shadowBlur: 5
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colorSet[0] },
{ offset: 1, color: colorSet[1] }
]),
- opacity: 0.3
+ opacity: 0.5
},
- lineStyle: {
- width: 2
- },
- symbol: 'circle',
- symbolSize: 6,
emphasis: {
- lineStyle: {
- width: 4
+ scale: true,
+ itemStyle: {
+ shadowBlur: 20
},
areaStyle: {
- opacity: 0.5
+ opacity: 0.8
}
}
}
@@ -226,14 +249,34 @@ const updateChart = () => {
}]
chart.setOption({
- legend: {
- data: points.map(item => item.point)
- },
radar: {
indicator: radarIndicators
},
series: series
})
+
+ // 添加呼吸动画
+ let breatheEffect = 0
+ const animate = () => {
+ breatheEffect = (breatheEffect + 1) % 100
+ const opacity = 0.3 + Math.sin(breatheEffect * Math.PI / 50) * 0.2
+
+ series[0].data.forEach((item, index) => {
+ chart.setOption({
+ series: [{
+ data: series[0].data.map((dataItem, i) => ({
+ ...dataItem,
+ areaStyle: {
+ ...dataItem.areaStyle,
+ opacity: i === index ? opacity : 0.3
+ }
+ }))
+ }]
+ })
+ })
+ requestAnimationFrame(animate)
+ }
+ animate()
}
// 定时更新数据
@@ -369,6 +412,7 @@ onUnmounted(() => {
background: rgba(0, 0, 0, 0.2);
border-radius: 4px;
padding: 12px;
+ position: relative;
.chart {
height: 100%;
diff --git a/src/views/dashboard/screen/components/RightPanel/BottomCard.vue b/src/views/dashboard/screen/components/RightPanel/BottomCard.vue
index d3e0691..ad71e38 100644
--- a/src/views/dashboard/screen/components/RightPanel/BottomCard.vue
+++ b/src/views/dashboard/screen/components/RightPanel/BottomCard.vue
@@ -9,6 +9,14 @@ const chartRef = ref(null)
// 预警数据
const alertData = ref({
total: 0,
+ level1: {
+ name: '低微预警',
+ total: 0,
+ color: '#909399',
+ pending: 0,
+ processed: 0,
+ ignored: 0
+ },
level2: {
name: '中等预警',
total: 0,
@@ -75,7 +83,7 @@ const initChart = async () => {
},
xAxis: {
type: 'category',
- data: ['严重预警', '中等预警'],
+ data: ['严重预警', '中等预警', '低微预警'],
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
@@ -135,7 +143,7 @@ const initChart = async () => {
])
}
},
- data: [0, 0]
+ data: [0, 0, 0]
},
{
name: '已处理',
@@ -156,7 +164,7 @@ const initChart = async () => {
])
}
},
- data: [0, 0]
+ data: [0, 0, 0]
},
{
name: '已忽略',
@@ -177,7 +185,7 @@ const initChart = async () => {
])
}
},
- data: [0, 0]
+ data: [0, 0, 0]
}
]
}
@@ -192,6 +200,7 @@ const fetchAlertData = async () => {
if (res.success && res.data) {
// 更新总数和各级别预警数据
let total = 0
+ let level1Data = { pending: 0, processed: 0, ignored: 0 }
let level2Data = { pending: 0, processed: 0, ignored: 0 }
let level3Data = { pending: 0, processed: 0, ignored: 0 }
@@ -199,7 +208,13 @@ const fetchAlertData = async () => {
const count = Number(item.total_count) || 0
total += count
- if (item.alert_level === 2) {
+ if (item.alert_level === 1) {
+ level1Data = {
+ pending: Number(item.pending_count) || 0,
+ processed: Number(item.processed_count) || 0,
+ ignored: Number(item.ignored_count) || 0
+ }
+ } else if (item.alert_level === 2) {
level2Data = {
pending: Number(item.pending_count) || 0,
processed: Number(item.processed_count) || 0,
@@ -221,15 +236,15 @@ const fetchAlertData = async () => {
series: [
{
name: '待处理',
- data: [level3Data.pending, level2Data.pending]
+ data: [level3Data.pending, level2Data.pending, level1Data.pending]
},
{
name: '已处理',
- data: [level3Data.processed, level2Data.processed]
+ data: [level3Data.processed, level2Data.processed, level1Data.processed]
},
{
name: '已忽略',
- data: [level3Data.ignored, level2Data.ignored]
+ data: [level3Data.ignored, level2Data.ignored, level1Data.ignored]
}
]
})
diff --git a/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue b/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue
index 04e1347..cb90cfe 100644
--- a/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue
+++ b/src/views/dashboard/screen/components/RightPanel/MiddleCard.vue
@@ -34,9 +34,9 @@ const initChart = async () => {
}
},
grid: {
- top: '3%',
- right: '5%',
- bottom: '3%',
+ top: '8%',
+ right: '15%',
+ bottom: '15%',
left: '15%',
containLabel: true
},
@@ -46,7 +46,7 @@ const initChart = async () => {
nameTextStyle: {
color: 'rgba(255, 255, 255, 0.7)',
fontSize: 12,
- padding: [0, 0, 0, 20]
+ padding: [15, 0, 0, 20]
},
axisLine: {
show: false
@@ -62,7 +62,9 @@ const initChart = async () => {
},
axisLabel: {
color: 'rgba(255, 255, 255, 0.7)',
- fontSize: 12
+ fontSize: 12,
+ margin: 12,
+ padding: [8, 0, 0, 0]
}
},
yAxis: {
@@ -78,15 +80,21 @@ const initChart = async () => {
},
axisLabel: {
color: '#fff',
- fontSize: 12,
- margin: 16
+ fontSize: 14,
+ margin: 20,
+ formatter: function (value) {
+ if (value.length > 6) {
+ return value.substring(0, 6) + '...'
+ }
+ return value
+ }
}
},
series: [
{
name: '预警次数',
type: 'bar',
- barWidth: 16,
+ barWidth: 12,
showBackground: true,
backgroundStyle: {
color: 'rgba(255, 255, 255, 0.05)',
@@ -98,8 +106,9 @@ const initChart = async () => {
label: {
show: true,
position: 'right',
+ distance: 15,
color: '#fff',
- fontSize: 12,
+ fontSize: 14,
formatter: '{c}次'
},
data: []
@@ -115,7 +124,7 @@ const fetchIndicatorData = async () => {
try {
const res = await getAlertStatisticsByIndicator()
if (res.success && res.data) {
- // 将数据转换为图表所需格式
+ // 将数据转换为图表所需格式,并限制显示数量为6个
const chartData = res.data
.filter(item => item.indicator_name)
.map(item => ({
@@ -128,20 +137,45 @@ const fetchIndicatorData = async () => {
}
}))
.sort((a, b) => b.value - a.value)
+ .slice(0, 6) // 只显示前6个数据
// 更新图表配置
chart.setOption({
+ grid: {
+ top: '8%',
+ right: '20%',
+ bottom: '8%',
+ left: '0%',
+ containLabel: true
+ },
yAxis: {
- data: chartData.map(item => item.name)
+ data: chartData.map(item => item.name),
+ axisLabel: {
+ margin: 20,
+ fontSize: 14
+ }
},
series: [
{
data: chartData,
+ barWidth: 12,
+ itemStyle: {
+ borderRadius: [0, 4, 4, 0]
+ },
+ label: {
+ show: true,
+ position: 'right',
+ distance: 15,
+ color: '#fff',
+ fontSize: 14,
+ formatter: '{c}次'
+ },
markLine: {
silent: true,
symbol: ['none', 'none'],
lineStyle: {
- color: 'rgba(255, 255, 255, 0.3)'
+ color: 'rgba(255, 255, 255, 0.2)',
+ type: [5, 10]
},
data: [
{
@@ -153,55 +187,77 @@ const fetchIndicatorData = async () => {
}
}
]
- },
- animationDelay: function(idx) {
- return idx * 100
}
}
]
})
+
+ // 添加渐变动画效果
+ let currentIndex = 0
+ const animate = () => {
+ if (currentIndex >= chartData.length) {
+ currentIndex = 0
+ }
+
+ chart.dispatchAction({
+ type: 'highlight',
+ seriesIndex: 0,
+ dataIndex: currentIndex
+ })
+
+ // 取消上一个高亮
+ const lastIndex = (currentIndex - 1 + chartData.length) % chartData.length
+ chart.dispatchAction({
+ type: 'downplay',
+ seriesIndex: 0,
+ dataIndex: lastIndex
+ })
+
+ currentIndex++
+ setTimeout(animate, 2000)
+ }
+ animate()
}
} catch (error) {
console.error('获取指标预警统计数据失败:', error)
}
-
}
// 获取指标颜色
const getIndicatorColor = (indicatorName) => {
const colors = {
'水体pH值': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#36CFFF' },
- { offset: 1, color: '#2861F5' }
+ { offset: 0, color: 'rgba(54, 207, 255, 1)' },
+ { offset: 1, color: 'rgba(40, 97, 245, 0.8)' }
]),
'溶解氧': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#4EF568' },
- { offset: 1, color: '#2AB256' }
+ { offset: 0, color: 'rgba(78, 245, 104, 1)' },
+ { offset: 1, color: 'rgba(42, 178, 86, 0.8)' }
]),
'盐度': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#FFB72C' },
- { offset: 1, color: '#F5612A' }
+ { offset: 0, color: 'rgba(255, 183, 44, 1)' },
+ { offset: 1, color: 'rgba(245, 97, 42, 0.8)' }
]),
'水温': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#FF36D9' },
- { offset: 1, color: '#C92AF5' }
+ { offset: 0, color: 'rgba(255, 54, 217, 1)' },
+ { offset: 1, color: 'rgba(201, 42, 245, 0.8)' }
]),
'浊度': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#36FFB0' },
- { offset: 1, color: '#2AF5A1' }
+ { offset: 0, color: 'rgba(54, 255, 176, 1)' },
+ { offset: 1, color: 'rgba(42, 245, 161, 0.8)' }
]),
'PM2.5': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#7636FF' },
- { offset: 1, color: '#2A3CF5' }
+ { offset: 0, color: 'rgba(118, 54, 255, 1)' },
+ { offset: 1, color: 'rgba(42, 60, 245, 0.8)' }
]),
'氮氧化物': new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#FF7636' },
- { offset: 1, color: '#F52A2A' }
+ { offset: 0, color: 'rgba(255, 118, 54, 1)' },
+ { offset: 1, color: 'rgba(245, 42, 42, 0.8)' }
])
}
return colors[indicatorName] || new echarts.graphic.LinearGradient(1, 0, 0, 0, [
- { offset: 0, color: '#36CFFF' },
- { offset: 1, color: '#2861F5' }
+ { offset: 0, color: 'rgba(54, 207, 255, 1)' },
+ { offset: 1, color: 'rgba(40, 97, 245, 0.8)' }
])
}
diff --git a/src/views/dashboard/screen/components/RightPanel/TopCard.vue b/src/views/dashboard/screen/components/RightPanel/TopCard.vue
index 18b0df6..bd200ab 100644
--- a/src/views/dashboard/screen/components/RightPanel/TopCard.vue
+++ b/src/views/dashboard/screen/components/RightPanel/TopCard.vue
@@ -40,7 +40,7 @@ const initChart = async () => {
fontSize: 12
},
top: 0,
- right: '5%',
+ right: '0%',
itemWidth: 12,
itemHeight: 12
},