Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
JINRUN-DP
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
xinzhedeai
JINRUN-DP
Commits
62a1c35f
Commit
62a1c35f
authored
Dec 09, 2025
by
xinzhedeai
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add:canvas charts
parent
c9fc65ef
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
210 additions
and
85 deletions
+210
-85
LeftDeviceStatus.vue
src/components/MineMonitor/LeftDeviceStatus.vue
+0
-4
RightAiWarning.vue
src/components/MineMonitor/RightAiWarning.vue
+198
-79
index.vue
src/views/_builtin/cesiumDeom/index.vue
+12
-2
No files found.
src/components/MineMonitor/LeftDeviceStatus.vue
View file @
62a1c35f
...
@@ -123,10 +123,6 @@ onMounted(() => {
...
@@ -123,10 +123,6 @@ onMounted(() => {
// background-size: cover;
// background-size: cover;
// margin-left: -0.1rem;
// margin-left: -0.1rem;
}
}
.card-footer
{
height
:
0
.1rem
;
background-image
:
url()
;
}
.status-grid
{
.status-grid
{
display
:
grid
;
display
:
grid
;
...
...
src/components/MineMonitor/RightAiWarning.vue
View file @
62a1c35f
<
template
>
<
template
>
<n-card
:bordered=
"false"
class=
"ai-warning-card"
>
<!-- 图表容器 Canvas -->
<div
class=
"card-header"
>
<div
class=
"chart-container wrapper"
>
<h2
class=
"card-title"
>
当月司机AI预警分析
</h2>
<h2
class=
"card-title"
>
设备状态总览
</h2>
</div>
<canvas
<div
class=
"chart-container"
ref=
"chartRef"
></div>
ref=
"chartCanvasRef"
<div
class=
"legend"
>
width=
"430"
<div
class=
"item"
><span
class=
"dot blue"
></span>
疲劳闭眼: 10
</div>
height=
"290"
<div
class=
"item"
><span
class=
"dot cyan"
></span>
疲劳打哈欠: 5
</div>
class=
"chart-canvas"
<div
class=
"item"
><span
class=
"dot green"
></span>
违规打电话: 15
</div>
></canvas>
<div
class=
"item"
><span
class=
"dot yellow"
></span>
违规抽烟: 0
</div>
</div>
<div
class=
"item"
><span
class=
"dot orange"
></span>
左顾右盼: 2
</div>
<div
class=
"item"
><span
class=
"dot red"
></span>
人脸丢失: 0
</div>
</div>
</n-card>
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
onMounted
,
onUnmounted
,
nextTick
}
from
'
vue
'
;
import
{
ref
,
onMounted
,
watch
}
from
'
vue
'
;
import
*
as
echarts
from
'
echarts
'
;
// 1. 定义 TS 类型接口
const
chartRef
=
ref
<
HTMLDivElement
|
null
>
(
null
);
interface
ChartDataItem
{
let
chartInstance
:
echarts
.
ECharts
|
null
=
null
;
name
:
string
;
value
:
number
;
const
initChart
=
()
=>
{
color
:
string
;
if
(
!
chartRef
.
value
)
return
;
}
chartInstance
=
echarts
.
init
(
chartRef
.
value
);
chartInstance
.
setOption
({
interface
RingLayer
{
series
:
[{
outer
:
number
;
name
:
'
预警类型
'
,
type
:
'
pie
'
,
radius
:
[
'
30%
'
,
'
70%
'
],
inner
:
number
;
itemStyle
:
{
borderRadius
:
4
,
borderColor
:
'
var(--n-bg-color-secondary)
'
,
borderWidth
:
2
},
}
label
:
{
show
:
false
},
data
:
[
// 2. 核心配置与数据(可通过 props 透传扩展)
{
value
:
10
,
name
:
'
疲劳闭眼
'
,
itemStyle
:
{
color
:
'
#36a2eb
'
}
},
const
chartData
:
ChartDataItem
[]
=
[
{
value
:
5
,
name
:
'
疲劳打哈欠
'
,
itemStyle
:
{
color
:
'
#4bc0c0
'
}
},
{
name
:
'
疲劳驾驶
'
,
value
:
10
,
color
:
'
#409EFF
'
},
{
value
:
15
,
name
:
'
违规打电话
'
,
itemStyle
:
{
color
:
'
#6dd230
'
}
},
{
name
:
'
违规打电话
'
,
value
:
15
,
color
:
'
#52C41A
'
},
{
value
:
0
,
name
:
'
违规抽烟
'
,
itemStyle
:
{
color
:
'
#facc15
'
}
},
{
name
:
'
违规抽烟
'
,
value
:
0
,
color
:
'
#FAAD14
'
},
{
value
:
2
,
name
:
'
左顾右盼
'
,
itemStyle
:
{
color
:
'
#ff9f40
'
}
},
{
name
:
'
左顾右盼
'
,
value
:
2
,
color
:
'
#FA8C16
'
},
{
value
:
0
,
name
:
'
人脸丢失
'
,
itemStyle
:
{
color
:
'
#ff6384
'
}
}
{
name
:
'
人脸丢失
'
,
value
:
0
,
color
:
'
#F5222D
'
},
]
];
}]
});
// 调整环形图层尺寸以适应新的 canvas 尺寸
};
const
ringLayers
:
RingLayer
[]
=
[
{
outer
:
110
,
inner
:
100
},
// 第1层:疲劳闭眼
{
outer
:
90
,
inner
:
80
},
// 第3层:违规打电话
{
outer
:
80
,
inner
:
70
},
// 第4层:违规抽烟
{
outer
:
70
,
inner
:
60
},
// 第5层:左顾右盼
{
outer
:
60
,
inner
:
50
},
// 第6层:人脸丢失
];
// 3. 获取 Canvas 元素 Ref
const
chartCanvasRef
=
ref
<
HTMLCanvasElement
|
null
>
(
null
);
// 4. 封装绘制核心函数
const
drawChart
=
()
=>
{
const
canvas
=
chartCanvasRef
.
value
;
if
(
!
canvas
)
{
console
.
error
(
'
Canvas element not found
'
);
return
;
}
const
ctx
=
canvas
.
getContext
(
'
2d
'
);
if
(
!
ctx
)
{
console
.
error
(
'
Failed to get 2D context
'
);
return
;
}
// 清空画布(防止重复绘制)
ctx
.
clearRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
);
const
centerX
=
canvas
.
width
/
2
;
const
centerY
=
canvas
.
height
/
2
;
const
bgColor
=
'
#E5E6EB
'
;
// 每层独立背景色
const
startAngle
=
-
Math
.
PI
/
2
;
// 12点钟方向起始
// 步骤1:绘制每层独立的深灰色背景
const
drawBackground
=
()
=>
{
ringLayers
.
forEach
((
layer
)
=>
{
ctx
.
beginPath
();
ctx
.
arc
(
centerX
,
centerY
,
layer
.
outer
,
0
,
Math
.
PI
*
2
);
ctx
.
arc
(
centerX
,
centerY
,
layer
.
inner
,
Math
.
PI
*
2
,
0
,
true
);
ctx
.
closePath
();
ctx
.
fillStyle
=
bgColor
;
ctx
.
fill
();
// 层间白色描边区分
ctx
.
strokeStyle
=
'
#fff
'
;
ctx
.
lineWidth
=
1
;
ctx
.
stroke
();
});
};
// 步骤2:按比例绘制数值扇区
const
drawSectors
=
()
=>
{
const
validData
=
chartData
.
filter
((
item
)
=>
item
.
value
>
0
);
const
total
=
validData
.
reduce
((
sum
,
item
)
=>
sum
+
item
.
value
,
0
);
if
(
total
===
0
)
{
console
.
warn
(
'
No valid data to draw
'
);
// 即使没有有效数据也绘制背景和图例
drawBackground
();
drawLegend
();
return
;
}
// 先绘制背景
drawBackground
();
chartData
.
forEach
((
item
,
index
)
=>
{
if
(
item
.
value
<=
0
)
return
;
const
layer
=
ringLayers
[
index
];
if
(
!
layer
)
return
;
const
resizeChart
=
()
=>
chartInstance
?.
resize
();
// 计算扇区角度比例
const
angleRatio
=
item
.
value
/
total
;
const
endAngle
=
startAngle
+
Math
.
PI
*
2
*
angleRatio
;
// 绘制扇区
ctx
.
beginPath
();
ctx
.
moveTo
(
centerX
,
centerY
);
ctx
.
arc
(
centerX
,
centerY
,
layer
.
outer
,
startAngle
,
endAngle
);
ctx
.
lineTo
(
centerX
+
layer
.
inner
*
Math
.
cos
(
endAngle
),
centerY
+
layer
.
inner
*
Math
.
sin
(
endAngle
)
);
ctx
.
arc
(
centerX
,
centerY
,
layer
.
inner
,
endAngle
,
startAngle
,
true
);
ctx
.
closePath
();
ctx
.
fillStyle
=
item
.
color
;
ctx
.
fill
();
ctx
.
strokeStyle
=
'
#fff
'
;
ctx
.
lineWidth
=
1
;
ctx
.
stroke
();
});
};
// 步骤3:绘制右侧图例
const
drawLegend
=
()
=>
{
const
legendX
=
centerX
+
120
;
// 调整图例位置以适应新尺寸
const
legendYStart
=
60
;
const
itemGap
=
25
;
chartData
.
forEach
((
item
,
index
)
=>
{
const
legendY
=
legendYStart
+
index
*
itemGap
;
// 绘制颜色方块
ctx
.
fillStyle
=
item
.
color
;
ctx
.
fillRect
(
legendX
,
legendY
,
15
,
15
);
ctx
.
strokeStyle
=
'
#e0e0e0
'
;
ctx
.
strokeRect
(
legendX
,
legendY
,
15
,
15
);
// 绘制类别名称
ctx
.
fillStyle
=
'
#333
'
;
ctx
.
font
=
'
12px Microsoft YaHei
'
;
ctx
.
fillText
(
item
.
name
,
legendX
+
25
,
legendY
+
12
);
// 绘制数值
ctx
.
fillStyle
=
'
#666
'
;
ctx
.
fillText
(
item
.
value
.
toString
(),
legendX
+
100
,
legendY
+
12
);
});
};
// 执行绘制流程
drawSectors
();
drawLegend
();
};
// 5. 挂载后初始化图表(DOM 渲染完成后执行)
onMounted
(()
=>
{
onMounted
(()
=>
{
nextTick
(
initChart
);
console
.
log
(
'
Component mounted, attempting to draw chart
'
);
window
.
addEventListener
(
'
resize
'
,
resizeChart
);
// 使用 nextTick 确保 DOM 已完全渲染
setTimeout
(()
=>
{
drawChart
();
},
0
);
});
});
onUnmounted
(()
=>
{
// 可选:监听数据变化重新绘制(如需动态更新数据可启用)
window
.
removeEventListener
(
'
resize
'
,
resizeChart
);
watch
([()
=>
chartData
],
()
=>
{
chartInstance
?.
dispose
();
drawChart
();
},
{
deep
:
true
});
// 导出绘制函数以便外部调用
defineExpose
({
drawChart
});
});
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
.ai-warning-card
{
.chart-container
{
padding
:
0
.15rem
;
width
:
100%
;
background
:
var
(
--
n-bg-color-secondary
);
overflow
:
auto
;
background-image
:
url("@/assets/jinrun/module-bg.png")
;
.card-header
{
background-repeat
:
no-repeat
;
margin-bottom
:
0
.15rem
;
}
.card-title
{
font-size
:
0
.18rem
;
font-weight
:
600
;
color
:
var
(
--
n-text-color-primary
);
}
}
.chart-container
{
.chart-canvas
{
width
:
100%
;
// background: #fff;
height
:
1
.2rem
;
border-radius
:
8px
;
}
box-shadow
:
0
2px
10px
rgba
(
0
,
0
,
0
,
0
.08
);
// margin: 20px 0;
display
:
block
;
}
.legend
{
display
:
grid
;
.wrapper
{
grid-template-columns
:
1fr
1fr
;
overflow
:
visible
;
gap
:
0
.05rem
;
width
:
4
.6rem
;
margin-top
:
0
.1rem
;
height
:
3rem
;
font-size
:
0
.12rem
;
position
:
relative
;
color
:
var
(
--
n-text-color-secondary
);
padding
:
0
.15rem
;
padding-top
:
0
.45rem
;
.item
{
display
:
flex
;
align-items
:
center
;
gap
:
0
.05rem
;
}
.card-title
{
.dot
{
position
:
absolute
;
width
:
0
.1rem
;
height
:
0
.1rem
;
border-radius
:
50%
;
display
:
inline-block
;
left
:
0
.25rem
;
&
.blue
{
background
:
#36a2eb
;
}
top
:
-0
.15rem
;
&
.cyan
{
background
:
#4bc0c0
;
}
font-weight
:
500
;
&
.green
{
background
:
#6dd230
;
}
font-size
:
0
.2rem
;
&
.yellow
{
background
:
#facc15
;
}
color
:
#ffffff
;
&
.orange
{
background
:
#ff9f40
;
}
text-shadow
:
0rem
0rem
0rem
rgba
(
5
,
38
,
68
,
0
.5
);
&
.red
{
background
:
#ff6384
;
}
}
}
}
}
}
</
style
>
</
style
>
\ No newline at end of file
src/views/_builtin/cesiumDeom/index.vue
View file @
62a1c35f
...
@@ -237,7 +237,8 @@ const navTo = () => {
...
@@ -237,7 +237,8 @@ const navTo = () => {
<!-- 右侧模块容器 -->
<!-- 右侧模块容器 -->
<transition
name=
"slide-right"
>
<transition
name=
"slide-right"
>
<div
class=
"right-modules"
v-show=
"isRightModulesVisible"
>
<div
class=
"right-modules"
v-show=
"isRightModulesVisible"
>
<!--
<RightAiWarning
/>
<RightAiWarning
/>
<!--
<RightEnvMonitor
/>
<RightEnvMonitor
/>
<RightTodayAlarm
/>
-->
<RightTodayAlarm
/>
-->
</div>
</div>
...
@@ -478,14 +479,23 @@ const navTo = () => {
...
@@ -478,14 +479,23 @@ const navTo = () => {
.right-modules
:not
(
.v-enter-active
)
:not
(
.v-leave-active
)
~
.right-toggle
:not
(
.collapsed
)
{
.right-modules
:not
(
.v-enter-active
)
:not
(
.v-leave-active
)
~
.right-toggle
:not
(
.collapsed
)
{
right
:
0
;
right
:
0
;
border-radius
:
10px
0
0
10px
;
border-radius
:
10px
0
0
10px
;
background
:
pink
;
}
}
.left-modules
,
.right-modules
{
.left-modules
,
.right-modules
{
width
:
4
.6rem
;
width
:
4
.6rem
;
// background: pink;
// background: pink;
// margin-top: .6rem;
// margin-top: .6rem;
padding-top
:
0
.6
rem
;
padding-top
:
1
rem
;
margin-left
:
0
.4rem
;
margin-left
:
0
.4rem
;
position
:
absolute
;
}
.left-modules
{
left
:
0
;
}
.right-modules
{
right
:
0
;
}
}
.arrow-font
{
.arrow-font
{
...
...
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