Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
DC-TOM
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
刘照晖
DC-TOM
Commits
554f2579
Commit
554f2579
authored
May 22, 2025
by
Cai Wei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(*): 布袋除尘页面开发
parent
4ab71b43
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
568 additions
and
4 deletions
+568
-4
index.js
src/router/index.js
+6
-2
chart.js
src/utils/chart.js
+92
-1
map-svg.vue
src/views/dashboard/components/map-svg.vue
+2
-1
bag-monitoring.vue
src/views/dustMonitoring/bag-monitoring.vue
+468
-0
No files found.
src/router/index.js
View file @
554f2579
...
@@ -2,13 +2,12 @@ import { createWebHistory, createRouter } from 'vue-router'
...
@@ -2,13 +2,12 @@ import { createWebHistory, createRouter } from 'vue-router'
import
Dashboard
from
'../views/dashboard/index.vue'
import
Dashboard
from
'../views/dashboard/index.vue'
import
DustOverview
from
'../views/dustOverview/index.vue'
import
DustOverview
from
'../views/dustOverview/index.vue'
import
HomeView
from
'../views/HomeView.vue'
import
AboutView
from
'../views/AboutView.vue'
import
AboutView
from
'../views/AboutView.vue'
import
User
from
'../views/user.vue'
import
Layout
from
'../layout/index.vue'
import
Layout
from
'../layout/index.vue'
import
Login
from
'../views/login/index.vue'
import
Login
from
'../views/login/index.vue'
import
equipmentManagement
from
'../views/equipmentManagement/index.vue'
import
equipmentManagement
from
'../views/equipmentManagement/index.vue'
import
dustMonitoring
from
'../views/dustMonitoring/index.vue'
import
dustMonitoring
from
'../views/dustMonitoring/index.vue'
import
bagMonitoring
from
'../views/dustMonitoring/bag-monitoring.vue'
import
myAgency
from
'@/views/closeManage/myAgency.vue'
;
import
myAgency
from
'@/views/closeManage/myAgency.vue'
;
import
myDone
from
'@/views/closeManage/myDone.vue'
;
import
myDone
from
'@/views/closeManage/myDone.vue'
;
...
@@ -37,6 +36,11 @@ const routes = [
...
@@ -37,6 +36,11 @@ const routes = [
component
:
dustMonitoring
,
component
:
dustMonitoring
,
meta
:
{
title
:
'除尘器监控'
},
meta
:
{
title
:
'除尘器监控'
},
},
},
{
path
:
'/bag-monitor'
,
component
:
bagMonitoring
,
meta
:
{
title
:
'BME布袋监测'
},
},
{
{
path
:
'/alerts'
,
path
:
'/alerts'
,
component
:
AboutView
,
component
:
AboutView
,
...
...
src/utils/chart.js
View file @
554f2579
...
@@ -57,4 +57,95 @@ export const getLineOption = (xData = [], seriesData = []) => ({
...
@@ -57,4 +57,95 @@ export const getLineOption = (xData = [], seriesData = []) => ({
smooth
:
true
,
smooth
:
true
,
},
},
],
],
});
});
\ No newline at end of file
// 布袋监测图表配置
export
const
getBagMonitoringChartOption
=
(
xData
=
[],
seriesData
=
[])
=>
({
tooltip
:
{
trigger
:
'axis'
,
axisPointer
:
{
type
:
'line'
,
lineStyle
:
{
color
:
'#6E7079'
,
width
:
1
}
}
},
grid
:
{
left
:
'20'
,
right
:
'20'
,
bottom
:
'30'
,
top
:
'3%'
,
containLabel
:
true
},
xAxis
:
{
type
:
'category'
,
boundaryGap
:
false
,
axisLine
:
{
lineStyle
:
{
color
:
'#E9ECF2'
}
},
axisLabel
:
{
color
:
'rgba(0,0,0,0.6)'
,
fontSize
:
12
,
interval
:
'auto'
,
rotate
:
0
},
axisTick
:
{
show
:
false
},
data
:
xData
},
yAxis
:
{
type
:
'value'
,
min
:
0
,
max
:
600
,
interval
:
200
,
axisLabel
:
{
color
:
'rgba(0,0,0,0.6)'
,
formatter
:
'{value}'
},
splitLine
:
{
lineStyle
:
{
color
:
'#E9ECF2'
,
type
:
'dashed'
}
}
},
series
:
[
{
name
:
'监测值'
,
type
:
'line'
,
smooth
:
false
,
symbol
:
'none'
,
sampling
:
'average'
,
itemStyle
:
{
color
:
'#7B68EE'
},
lineStyle
:
{
width
:
1
},
areaStyle
:
{
color
:
{
type
:
'linear'
,
x
:
0
,
y
:
0
,
x2
:
0
,
y2
:
1
,
colorStops
:
[
{
offset
:
0
,
color
:
'rgba(123, 104, 238, 0.4)'
},
{
offset
:
1
,
color
:
'rgba(123, 104, 238, 0.1)'
}
]
}
},
data
:
seriesData
,
}
]
});
\ No newline at end of file
src/views/dashboard/components/map-svg.vue
View file @
554f2579
...
@@ -234,6 +234,7 @@ onBeforeUnmount(() => {
...
@@ -234,6 +234,7 @@ onBeforeUnmount(() => {
&
.active
{
&
.active
{
box-shadow
:
0
0
10px
rgba
(
255
,
255
,
255
,
0
.5
);
box-shadow
:
0
0
10px
rgba
(
255
,
255
,
255
,
0
.5
);
z-index
:
100
;
}
}
.pulse
{
.pulse
{
...
@@ -284,7 +285,7 @@ onBeforeUnmount(() => {
...
@@ -284,7 +285,7 @@ onBeforeUnmount(() => {
padding
:
12px
;
padding
:
12px
;
color
:
#fff
;
color
:
#fff
;
pointer-events
:
none
;
pointer-events
:
none
;
z-index
:
3
;
z-index
:
999
;
.text-status-normal
{
.text-status-normal
{
color
:
#00ff9d
!
important
;
color
:
#00ff9d
!
important
;
...
...
src/views/dustMonitoring/bag-monitoring.vue
0 → 100644
View file @
554f2579
<
template
>
<div
class=
"page-container bag-monitoring-container"
>
<div
class=
"header"
>
<div
class=
"select-container"
>
<span>
检测仪器11
</span>
<el-select
v-model=
"selectedDevice"
placeholder=
"1#布袋检测仪"
>
<el-option
label=
"1#布袋检测仪"
value=
"1"
></el-option>
</el-select>
</div>
<div
class=
"title"
>
BME布袋监测
</div>
</div>
<div
class=
"chart-container"
>
<div
class=
"chart-wrapper"
ref=
"chartRef"
></div>
<div
class=
"data-panel"
:class=
"
{ 'collapsed': !isPanelOpen }">
<div
class=
"panel-toggle"
:class=
"
{ 'collapsed-icon': !isPanelOpen, 'expanded-icon': isPanelOpen }" @click="togglePanel">
<el-icon
v-if=
"isPanelOpen"
><ArrowRightBold
/></el-icon>
<el-icon
v-if=
"!isPanelOpen"
><ArrowLeftBold
/></el-icon>
</div>
<div
class=
"data-box"
>
<div
class=
"data-item"
>
<div>
时间:
{{
currentData
.
time
}}
</div>
<div>
仓室:
{{
currentData
.
chamber
}}
</div>
<div>
反吹:
{{
currentData
.
backwash
}}
</div>
</div>
<div
class=
"data-item"
>
<div>
DI3:
{{
currentData
.
di3
}}
</div>
<div>
排:
{{
currentData
.
row
}}
</div>
<div>
实时值:
{{
currentData
.
realValue
}}
</div>
</div>
<div
class=
"data-item"
>
<div>
基线值:
{{
currentData
.
baseline
}}
</div>
<div>
Delay:
{{
currentData
.
delay
}}
</div>
<div>
totaltime:
{{
currentData
.
totaltime
}}
</div>
</div>
<div
class=
"data-item"
>
<div>
{{
currentData
.
next
}}
</div>
<div>
valve:
{{
currentData
.
valve
}}
</div>
<div>
DI_TIME=
{{
currentData
.
di_time
}}
</div>
</div>
<div
class=
"data-item"
>
<div>
false:
{{
currentData
.
false
}}
</div>
<div>
peak=
{{
currentData
.
peak
}}
</div>
</div>
</div>
<div
class=
"data-box second-box"
>
<div>
时间:
{{
secondaryData
.
time
}}
, 仓室:
{{
secondaryData
.
chamber
}}
, 反吹:
{{
secondaryData
.
backwash
}}
, 谷值:
{{
secondaryData
.
valleyValue
}}
, 仓室状态阀门
{{
secondaryData
.
status
}}
False
{{
secondaryData
.
falseVal
}}
</div>
</div>
</div>
</div>
<div
class=
"data-table"
>
<div
class=
"time-controls"
>
<el-button>
<i
class=
"el-icon-back"
></i>
</el-button>
<el-button>
<i
class=
"el-icon-right"
></i>
</el-button>
<span
class=
"time-label"
>
间隔
</span>
<el-input
v-model=
"timeInterval"
class=
"time-input"
></el-input>
<span
class=
"time-unit"
>
分钟
</span>
</div>
<table>
<thead>
<tr>
<th>
名称
</th>
<th
v-for=
"i in 20"
:key=
"i"
>
{{
i
}}
仓
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
峰值_R
</td>
<td
v-for=
"(value, index) in peakValuesR"
:key=
"'r'+index"
>
{{
value
}}
</td>
</tr>
<tr>
<td>
峰值_H
</td>
<td
v-for=
"(value, index) in peakValuesH"
:key=
"'h'+index"
>
{{
value
}}
</td>
</tr>
<tr>
<td>
状态
</td>
<td
v-for=
"(value, index) in statusValues"
:key=
"'s'+index"
:class=
"
{ 'error': value === '故障' }">
{{
value
}}
</td>
</tr>
<tr>
<td>
反吹中
</td>
<td
v-for=
"(value, index) in backwashValues"
:key=
"'b'+index"
:class=
"
{ 'highlight': index === 1 }">
{{
value
}}
</td>
</tr>
<tr>
<td>
谷值
</td>
<td
v-for=
"(value, index) in valleyValues"
:key=
"'v'+index"
>
{{
value
}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
reactive
,
onMounted
,
onBeforeUnmount
}
from
'vue'
import
*
as
echarts
from
'echarts'
import
{
ArrowRightBold
,
ArrowLeftBold
}
from
'@element-plus/icons-vue'
import
{
getBagMonitoringChartOption
}
from
'@/utils/chart.js'
// 设备选择
const
selectedDevice
=
ref
(
'1'
)
const
isPanelOpen
=
ref
(
true
)
// 图表相关
const
chartRef
=
ref
(
null
)
let
chartInstance
=
null
let
updateTimer
=
null
// 定时器引用
// 图表数据
const
chartData
=
reactive
({
xData
:
[],
seriesData
:
[]
})
// 当前数据面板
const
currentData
=
reactive
({
time
:
'641'
,
chamber
:
'5'
,
backwash
:
'0'
,
di3
:
'0, 0,'
,
row
:
'1,'
,
realValue
:
'18.87,'
,
baseline
:
'10,'
,
delay
:
'0,'
,
totaltime
:
'1837'
,
next
:
'next:765,'
,
valve
:
'5'
,
di_time
:
'1848'
,
false
:
'0:0,'
,
peak
:
'4, 1, 46'
})
// 次要数据面板
const
secondaryData
=
reactive
({
time
:
'784'
,
chamber
:
'6'
,
backwash
:
'0'
,
valleyValue
:
'3'
,
status
:
'212'
,
falseVal
:
'0'
})
// 表格数据
const
peakValuesR
=
[
0
,
0
,
-
30
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]
const
peakValuesH
=
[
30
,
56
,
60
,
70
,
18
,
56
,
18
,
41
,
41
,
0
,
41
,
41
,
41
,
41
,
41
,
41
,
500
,
41
,
31
,
41
]
const
statusValues
=
Array
(
20
).
fill
(
'正常'
)
statusValues
[
2
]
=
'故障'
statusValues
[
16
]
=
'故障'
const
backwashValues
=
[
0
,
15
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]
const
valleyValues
=
[
-
8
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
-
9
,
0
,
0
,
0
,
0
,
0
]
// 时间控制
const
timeInterval
=
ref
(
'10'
)
const
togglePanel
=
()
=>
{
isPanelOpen
.
value
=
!
isPanelOpen
.
value
}
// 格式化时间为 HH:MM:SS 格式
const
formatTime
=
(
date
)
=>
{
const
hours
=
date
.
getHours
().
toString
().
padStart
(
2
,
'0'
)
const
minutes
=
date
.
getMinutes
().
toString
().
padStart
(
2
,
'0'
)
const
seconds
=
date
.
getSeconds
().
toString
().
padStart
(
2
,
'0'
)
return
`
${
hours
}
:
${
minutes
}
:
${
seconds
}
`
}
// 初始化图表
const
initChart
=
()
=>
{
if
(
chartInstance
)
{
chartInstance
.
dispose
()
}
// 初始化图表数据
initChartData
()
chartInstance
=
echarts
.
init
(
chartRef
.
value
)
updateChart
()
// 启动定时更新
startRealTimeUpdates
()
}
// 初始化图表数据
const
initChartData
=
()
=>
{
const
now
=
new
Date
()
chartData
.
xData
=
[]
chartData
.
seriesData
=
[]
// 创建初始数据点,从5分钟前开始
for
(
let
i
=
300
;
i
>=
0
;
i
--
)
{
const
time
=
new
Date
(
now
.
getTime
()
-
i
*
1000
)
chartData
.
xData
.
push
(
formatTime
(
time
))
chartData
.
seriesData
.
push
(
generateRandomValue
())
}
}
// 生成一个介于 20-300 之间的随机值,模拟实时数据
const
generateRandomValue
=
()
=>
{
// 有10%的概率生成峰值
if
(
Math
.
random
()
<
0.1
)
{
return
Math
.
floor
(
Math
.
random
()
*
200
)
+
200
// 200-400之间的峰值
}
return
Math
.
floor
(
Math
.
random
()
*
130
)
+
20
// 20-150之间的基础值
}
// 更新图表
const
updateChart
=
()
=>
{
if
(
chartInstance
)
{
chartInstance
.
setOption
(
getBagMonitoringChartOption
(
chartData
.
xData
,
chartData
.
seriesData
))
}
}
// 启动实时更新
const
startRealTimeUpdates
=
()
=>
{
if
(
updateTimer
)
{
clearInterval
(
updateTimer
)
}
updateTimer
=
setInterval
(()
=>
{
// 添加新数据点
const
now
=
new
Date
()
chartData
.
xData
.
push
(
formatTime
(
now
))
chartData
.
seriesData
.
push
(
generateRandomValue
())
// 移除最旧的数据点以保持固定长度
if
(
chartData
.
xData
.
length
>
31
)
{
// 保持30秒的数据
chartData
.
xData
.
shift
()
chartData
.
seriesData
.
shift
()
}
// 更新图表
updateChart
()
updateDataPanels
()
},
1000
)
}
// 更新数据面板
const
updateDataPanels
=
()
=>
{
// 随机更新当前数据面板的实时值
currentData
.
realValue
=
(
Math
.
random
()
*
30
+
10
).
toFixed
(
2
)
+
','
// 更新时间显示
const
now
=
new
Date
()
currentData
.
time
=
Math
.
floor
((
now
.
getTime
()
/
1000
)
%
1000
).
toString
()
// 每10秒更新一次次要数据面板
if
(
now
.
getSeconds
()
%
10
===
0
)
{
secondaryData
.
time
=
Math
.
floor
((
now
.
getTime
()
/
1000
)
%
1000
).
toString
()
secondaryData
.
valleyValue
=
Math
.
floor
(
Math
.
random
()
*
10
).
toString
()
}
}
// 监听窗口大小变化,调整图表大小
const
handleResize
=
()
=>
{
if
(
chartInstance
)
{
chartInstance
.
resize
()
}
}
onMounted
(()
=>
{
initChart
()
window
.
addEventListener
(
'resize'
,
handleResize
)
})
onBeforeUnmount
(()
=>
{
window
.
removeEventListener
(
'resize'
,
handleResize
)
// 清除定时器
if
(
updateTimer
)
{
clearInterval
(
updateTimer
)
updateTimer
=
null
}
// 销毁图表实例
if
(
chartInstance
)
{
chartInstance
.
dispose
()
chartInstance
=
null
}
})
</
script
>
<
style
scoped
lang=
"scss"
>
.bag-monitoring-container
{
width
:
100%
;
height
:
calc
(
100%
-
14px
);
box-sizing
:
border-box
;
overflow-x
:
hidden
;
.header
{
position
:
relative
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
margin-bottom
:
10px
;
.select-container
{
position
:
absolute
;
left
:
0
;
top
:
0
;
width
:
400px
;
display
:
flex
;
align-items
:
center
;
z-index
:
99
;
span
{
display
:
block
;
width
:
110px
;
margin-right
:
10px
;
}
.device-number
{
background
:
#fcf0c2
;
padding
:
2px
8px
;
margin-left
:
10px
;
border-radius
:
4px
;
}
}
.title
{
font-size
:
18px
;
font-weight
:
bold
;
color
:
#409EFF
;
}
}
.chart-container
{
width
:
100%
;
height
:
calc
(
100%
-
350px
);
background-color
:
#fff
;
border-radius
:
4px
;
display
:
flex
;
flex-direction
:
column
;
.chart-wrapper
{
flex
:
1
;
width
:
100%
;
}
.data-panel
{
position
:
absolute
;
top
:
80px
;
right
:
25px
;
width
:
320px
;
z-index
:
10
;
transition
:
transform
0
.3s
ease-in-out
;
&
.collapsed
{
transform
:
translateX
(
345px
);
}
.panel-toggle
{
position
:
absolute
;
width
:
25px
;
height
:
30px
;
background
:
#fff
;
top
:
1px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
border-radius
:
4px
;
}
.collapsed-icon
{
left
:
-23px
;
}
.expanded-icon
{
right
:
-23px
;
}
.data-box
{
padding
:
10px
;
background-color
:
rgba
(
255
,
255
,
255
,
0
.9
);
border-radius
:
4px
;
border
:
1px
solid
#ebeef5
;
box-shadow
:
0
2px
12px
0
rgba
(
0
,
0
,
0
,
0
.1
);
margin-bottom
:
10px
;
.data-item
{
display
:
flex
;
justify-content
:
space-between
;
margin-bottom
:
5px
;
font-size
:
14px
;
div
{
flex
:
1
;
}
}
}
.second-box
{
font-size
:
12px
;
}
}
}
.data-table
{
background-color
:
#fff
;
border-radius
:
4px
;
padding
:
10px
0
;
box-sizing
:
border-box
;
table
{
width
:
100%
;
border-collapse
:
collapse
;
th
,
td
{
border
:
1px
solid
#EBEEF5
;
text-align
:
center
;
padding
:
8px
;
font-size
:
14px
;
}
th
{
background-color
:
#F5F7FA
;
color
:
#606266
;
}
.error
{
color
:
#F56C6C
;
}
.highlight
{
background-color
:
#FCF8E3
;
position
:
relative
;
&
:
:
after
{
content
:
""
;
position
:
absolute
;
width
:
16px
;
height
:
16px
;
background-color
:
#E6A23C
;
border-radius
:
50%
;
top
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
z-index
:
1
;
}
}
}
.time-controls
{
margin-top
:
10px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-end
;
.time-label
,
.time-unit
{
margin
:
0
5px
;
}
.time-input
{
width
:
60px
;
}
}
}
}
</
style
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment