Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
AI_VUE2_Ruoyi
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
lei
AI_VUE2_Ruoyi
Commits
c31afea9
Commit
c31afea9
authored
May 08, 2025
by
lei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add:接口联调(算法配置)
parent
469da564
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
564 additions
and
217 deletions
+564
-217
alarmlog.js
src/api/business/alarmlog.js
+24
-0
algorithmconfig.js
src/api/business/algorithmconfig.js
+35
-0
cameraconfig.js
src/api/business/cameraconfig.js
+69
-0
index.vue
src/components/ImageUpload/index.vue
+36
-30
alarmlog.vue
src/views/AlarmCenter/alarmlog.vue
+18
-15
index.vue
src/views/AlgorithmConfig/index.vue
+93
-10
index.vue
src/views/CameraConfig/index.vue
+186
-101
PieChart.vue
src/views/dashboard/PieChart.vue
+51
-39
resize.js
src/views/dashboard/mixins/resize.js
+7
-1
index.vue
src/views/index.vue
+41
-17
vue.config.js
vue.config.js
+4
-4
No files found.
src/api/business/alarmlog.js
0 → 100644
View file @
c31afea9
import
request
from
'
@/utils/request
'
//获取报警日志列表
export
function
getAlarmLogList
(
query
)
{
return
request
({
url
:
'
/system/log/list
'
,
method
:
'
get
'
,
params
:
query
})
}
//删除报警日志
export
function
delAlarmLog
(
id
)
{
return
request
({
url
:
'
/system/log/
'
+
id
,
method
:
'
delete
'
})
}
//修改报警日志
export
function
updateAlarmLog
(
data
)
{
return
request
({
url
:
'
/system/log
'
,
method
:
'
put
'
,
data
:
data
})
}
\ No newline at end of file
src/api/business/algorithmconfig.js
0 → 100644
View file @
c31afea9
import
request
from
'
@/utils/request
'
//获取算法配置列表
export
function
getAlgorithmList
(
query
)
{
return
request
({
url
:
'
/system/algorithmConfig/list
'
,
method
:
'
get
'
,
params
:
query
})
}
//新增算法配置
export
function
addAlgorithm
(
data
)
{
return
request
({
url
:
'
/system/algorithmConfig
'
,
method
:
'
post
'
,
data
:
data
})
}
//修改算法配置
export
function
updateAlgorithm
(
data
)
{
return
request
({
url
:
'
/system/algorithmConfig
'
,
method
:
'
put
'
,
data
:
data
})
}
//删除算法配置
export
function
delAlgorithm
(
id
)
{
return
request
({
url
:
'
/system/algorithmConfig/
'
+
id
,
method
:
'
delete
'
})
}
\ No newline at end of file
src/api/business/cameraconfig.js
0 → 100644
View file @
c31afea9
import
request
from
'
@/utils/request
'
// 获取摄像头表格数据
export
function
getCameraList
(
query
)
{
return
request
({
url
:
'
/system/cameraConfig/list
'
,
method
:
'
get
'
,
params
:
query
})
}
// 新增摄像头
export
function
addCamera
(
data
)
{
return
request
({
url
:
'
/system/cameraConfig
'
,
method
:
'
post
'
,
data
:
data
})
}
// 修改摄像头
export
function
updateCamera
(
data
)
{
return
request
({
url
:
'
/system/cameraConfig
'
,
method
:
'
put
'
,
data
:
data
})
}
// 删除摄像头
export
function
delCamera
(
id
)
{
return
request
({
url
:
'
/system/cameraConfig/
'
+
id
,
method
:
'
delete
'
})
}
//获取摄像头位置列表
export
function
getCameraPositionList
()
{
return
request
({
url
:
'
/system/position/treeList
'
,
method
:
'
get
'
})
}
//新增摄像头位置
export
function
addCameraPosition
(
data
)
{
return
request
({
url
:
'
/system/position
'
,
method
:
'
post
'
,
data
:
data
})
}
//修改摄像头位置
export
function
updateCameraPosition
(
data
)
{
return
request
({
url
:
'
/system/position
'
,
method
:
'
put
'
,
data
:
data
})
}
//删除摄像头位置
export
function
delCameraPosition
(
id
)
{
return
request
({
url
:
'
/system/position/
'
+
id
,
method
:
'
delete
'
})
}
\ No newline at end of file
src/components/ImageUpload/index.vue
View file @
c31afea9
...
...
@@ -16,7 +16,7 @@
:headers=
"headers"
:file-list=
"fileList"
:on-preview=
"handlePictureCardPreview"
:class=
"
{
hide: this.fileList.length >= this.limit
}"
:class=
"
{
hide: this.fileList.length >= this.limit
}"
>
<i
class=
"el-icon-plus"
></i>
</el-upload>
...
...
@@ -24,8 +24,12 @@
<!-- 上传提示 -->
<div
class=
"el-upload__tip"
slot=
"tip"
v-if=
"showTip"
>
请上传
<template
v-if=
"fileSize"
>
大小不超过
<b
style=
"color: #f56c6c"
>
{{
fileSize
}}
MB
</b>
</
template
>
<
template
v-if=
"fileType"
>
格式为
<b
style=
"color: #f56c6c"
>
{{
fileType
.
join
(
"
/
"
)
}}
</b>
</
template
>
<template
v-if=
"fileSize"
>
大小不超过
<b
style=
"color: #f56c6c"
>
{{
fileSize
}}
MB
</b>
</
template
>
<
template
v-if=
"fileType"
>
格式为
<b
style=
"color: #f56c6c"
>
{{
fileType
.
join
(
"
/
"
)
}}
</b>
</
template
>
的文件
</div>
...
...
@@ -36,7 +40,7 @@
append-to-body
>
<img
:src=
"dialogImageUrl"
:src=
"
baseUrl +
dialogImageUrl"
style=
"display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
...
...
@@ -53,20 +57,20 @@ export default {
// 上传接口地址
action
:
{
type
:
String
,
default
:
"
/common/upload
"
default
:
"
/common/upload
"
,
},
// 上传携带的参数
data
:
{
type
:
Object
type
:
Object
,
},
// 图片数量限制
limit
:
{
type
:
Number
,
default
:
5
,
default
:
1
,
},
// 大小限制(MB)
fileSize
:
{
type
:
Number
,
type
:
Number
,
default
:
5
,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
...
...
@@ -77,8 +81,8 @@ export default {
// 是否显示提示
isShowTip
:
{
type
:
Boolean
,
default
:
true
}
default
:
true
,
}
,
},
data
()
{
return
{
...
...
@@ -92,7 +96,7 @@ export default {
headers
:
{
Authorization
:
"
Bearer
"
+
getToken
(),
},
fileList
:
[]
fileList
:
[]
,
};
},
watch
:
{
...
...
@@ -100,14 +104,14 @@ export default {
handler
(
val
)
{
if
(
val
)
{
// 首先将值转为数组
const
list
=
Array
.
isArray
(
val
)
?
val
:
this
.
value
.
split
(
'
,
'
);
const
list
=
Array
.
isArray
(
val
)
?
val
:
this
.
value
.
split
(
"
,
"
);
// 然后将数组转为对象数组
this
.
fileList
=
list
.
map
(
item
=>
{
this
.
fileList
=
list
.
map
(
(
item
)
=>
{
if
(
typeof
item
===
"
string
"
)
{
if
(
item
.
indexOf
(
this
.
baseUrl
)
===
-
1
&&
!
isExternal
(
item
))
{
item
=
{
name
:
this
.
baseUrl
+
item
,
url
:
this
.
baseUrl
+
item
};
item
=
{
name
:
this
.
baseUrl
+
item
,
url
:
this
.
baseUrl
+
item
};
}
else
{
item
=
{
name
:
item
,
url
:
item
};
item
=
{
name
:
item
,
url
:
item
};
}
}
return
item
;
...
...
@@ -118,8 +122,8 @@ export default {
}
},
deep
:
true
,
immediate
:
true
}
immediate
:
true
,
}
,
},
computed
:
{
// 是否显示提示
...
...
@@ -136,7 +140,7 @@ export default {
if
(
file
.
name
.
lastIndexOf
(
"
.
"
)
>
-
1
)
{
fileExtension
=
file
.
name
.
slice
(
file
.
name
.
lastIndexOf
(
"
.
"
)
+
1
);
}
isImg
=
this
.
fileType
.
some
(
type
=>
{
isImg
=
this
.
fileType
.
some
(
(
type
)
=>
{
if
(
file
.
type
.
indexOf
(
type
)
>
-
1
)
return
true
;
if
(
fileExtension
&&
fileExtension
.
indexOf
(
type
)
>
-
1
)
return
true
;
return
false
;
...
...
@@ -146,11 +150,13 @@ export default {
}
if
(
!
isImg
)
{
this
.
$modal
.
msgError
(
`文件格式不正确,请上传
${
this
.
fileType
.
join
(
"
/
"
)}
图片格式文件!`
);
this
.
$modal
.
msgError
(
`文件格式不正确,请上传
${
this
.
fileType
.
join
(
"
/
"
)}
图片格式文件!`
);
return
false
;
}
if
(
file
.
name
.
includes
(
'
,
'
))
{
this
.
$modal
.
msgError
(
'
文件名不正确,不能包含英文逗号!
'
);
if
(
file
.
name
.
includes
(
"
,
"
))
{
this
.
$modal
.
msgError
(
"
文件名不正确,不能包含英文逗号!
"
);
return
false
;
}
if
(
this
.
fileSize
)
{
...
...
@@ -170,7 +176,7 @@ export default {
// 上传成功回调
handleUploadSuccess
(
res
,
file
)
{
if
(
res
.
code
===
200
)
{
this
.
uploadList
.
push
({
name
:
res
.
fileName
,
url
:
res
.
fileName
});
this
.
uploadList
.
push
({
name
:
res
.
fileName
,
url
:
res
.
url
});
this
.
uploadedSuccessfully
();
}
else
{
this
.
number
--
;
...
...
@@ -182,7 +188,7 @@ export default {
},
// 删除图片
handleDelete
(
file
)
{
const
findex
=
this
.
fileList
.
map
(
f
=>
f
.
name
).
indexOf
(
file
.
name
);
const
findex
=
this
.
fileList
.
map
(
(
f
)
=>
f
.
name
).
indexOf
(
file
.
name
);
if
(
findex
>
-
1
)
{
this
.
fileList
.
splice
(
findex
,
1
);
this
.
$emit
(
"
input
"
,
this
.
listToString
(
this
.
fileList
));
...
...
@@ -217,25 +223,25 @@ export default {
strs
+=
list
[
i
].
url
.
replace
(
this
.
baseUrl
,
""
)
+
separator
;
}
}
return
strs
!=
''
?
strs
.
substr
(
0
,
strs
.
length
-
1
)
:
''
;
}
}
return
strs
!=
""
?
strs
.
substr
(
0
,
strs
.
length
-
1
)
:
""
;
}
,
}
,
};
</
script
>
<
style
scoped
lang=
"scss"
>
// .el-upload--picture-card 控制加号部分
::v-deep
.hide
.el-upload--picture-card
{
display
:
none
;
display
:
none
;
}
// 去掉动画效果
::v-deep
.el-list-enter-active
,
::v-deep
.el-list-leave-active
{
transition
:
all
0s
;
transition
:
all
0s
;
}
::v-deep
.el-list-enter
,
.el-list-leave-active
{
::v-deep
.el-list-enter
,
.el-list-leave-active
{
opacity
:
0
;
transform
:
translateY
(
0
);
}
</
style
>
src/views/AlarmCenter/alarmlog.vue
View file @
c31afea9
...
...
@@ -53,7 +53,7 @@
<el-table
:data=
"tableList"
>
<el-table-column
label=
"摄像头ID"
prop=
"
i
d"
prop=
"
cameraI
d"
align=
"center"
></el-table-column>
<el-table-column
...
...
@@ -125,6 +125,11 @@
</template>
<
script
>
import
{
getAlarmLogList
,
delAlarmLog
,
updateAlarmLog
,
}
from
"
@/api/business/alarmlog.js
"
;
export
default
{
dicts
:
[
"
algorithm_level
"
],
name
:
"
Alarmlog
"
,
...
...
@@ -142,18 +147,7 @@ export default {
algorithmLevel
:
1
,
// 算法报警等级
alarmStatus
:
0
,
// 报警处理状态
},
tableList
:
[
{
id
:
1
,
// 摄像头ID
videoAnlysisTasksName
:
"
yi
"
,
// 视频分析任务名称
cameraName
:
"
er
"
,
// 摄像头名称
alarmImg
:
"
1121
"
,
// 报警图片
alarmTime
:
"
1212
"
,
// 报警时间
algorithmName
:
"
1212
"
,
// 算法名称
algorithmLevel
:
1
,
// 算法报警等级
alarmStatus
:
0
,
// 报警处理状态
},
],
tableList
:
[],
cameraAdderss
:
[
{
name
:
"
摄像头1
"
,
// 摄像头名称
...
...
@@ -170,7 +164,9 @@ export default {
},
computed
:
{},
watch
:
{},
created
()
{},
created
()
{
this
.
getList
();
},
mounted
()
{},
methods
:
{
// 搜索
...
...
@@ -186,7 +182,14 @@ export default {
// 编辑
editBut
(
row
)
{},
// 获取数据列表
getList
()
{},
getList
()
{
getAlarmLogList
(
this
.
queryParams
).
then
((
res
)
=>
{
if
(
res
.
code
==
200
)
{
this
.
tableList
=
res
.
rows
;
this
.
total
=
res
.
total
;
}
});
},
},
};
</
script
>
...
...
src/views/AlgorithmConfig/index.vue
View file @
c31afea9
...
...
@@ -8,25 +8,30 @@
empty-text
>
<el-table-column
prop=
"
name
"
prop=
"
algorithmId
"
align=
"center"
label=
"算法ID"
width=
"100"
></el-table-column>
<el-table-column
prop=
"a
ddress
"
prop=
"a
lgorithmVersion
"
align=
"center"
label=
"算法版本"
width=
"100"
></el-table-column>
<el-table-column
prop=
"
videoAdress
"
prop=
"
algorithmName
"
label=
"算法名称"
align=
"center"
></el-table-column>
<el-table-column
prop=
"imageUrl"
align=
"center"
label=
"算法等级"
></el-table-column>
<el-table-column
prop=
"algorithmLevel"
align=
"center"
label=
"算法等级"
>
<template
slot-scope=
"scope"
>
<dict-tag
:options=
"dict.type.algorithm_level"
:value=
"Number(scope.row.algorithmLevel)"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"200"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<el-button
type=
"text"
size=
"mini"
@
click=
"tableEdit(scope.row)"
>
...
...
@@ -43,11 +48,47 @@
@
pagination=
"getList"
/>
</div>
// 修改弹窗部分的模板
<el-dialog
title=
"修改等级"
:visible.sync=
"editDialogVisible"
:close-on-click-modal=
"false"
width=
"30%"
center
>
<el-form
:model=
"form"
:rules=
"rules"
ref=
"form"
inline
>
<el-form-item
label=
"算法等级"
prop=
"algorithmLevel"
>
<el-select
v-model=
"form.algorithmLevel"
placeholder=
"请选择等级"
style=
"width: 100%"
>
<el-option
v-for=
"dict in dict.type.algorithm_level"
:key=
"dict.value"
:label=
"dict.label"
:value=
"parseInt(dict.value)"
/>
</el-select>
</el-form-item>
</el-form>
<span
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"editDialogVisible = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"handleEditConfirm"
>
确 定
</el-button>
</span>
</el-dialog>
</div>
</template>
<
script
>
import
{
getAlgorithmList
,
addAlgorithm
,
updateAlgorithm
,
delAlgorithm
,
}
from
"
@/api/business/algorithmconfig.js
"
;
export
default
{
dicts
:
[
"
algorithm_level
"
],
name
:
"
AlgorithmConfig
"
,
props
:
{},
components
:
{},
...
...
@@ -60,17 +101,59 @@ export default {
pageNum
:
1
,
pageSize
:
10
,
},
editDialogVisible
:
false
,
form
:
{
algorithmId
:
null
,
algorithmLevel
:
null
,
},
rules
:
{
algorithmLevel
:
[
{
required
:
true
,
message
:
"
请选择算法等级
"
,
trigger
:
"
change
"
},
],
},
};
},
computed
:
{},
watch
:
{},
created
()
{},
created
()
{
this
.
getList
();
},
mounted
()
{},
methods
:
{
//编辑
tableEdit
(
row
)
{},
//获取列表
getList
()
{
//获取列表
getAlgorithmList
(
this
.
queryParams
).
then
((
res
)
=>
{
if
(
res
.
code
==
200
)
{
this
.
tableList
=
res
.
rows
;
this
.
total
=
res
.
total
;
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
},
// 编辑按钮点击事件
tableEdit
(
row
)
{
this
.
form
=
{
algorithmId
:
row
.
algorithmId
,
algorithmLevel
:
Number
(
row
.
algorithmLevel
),
};
this
.
editDialogVisible
=
true
;
},
// 确认修改方法
handleEditConfirm
()
{
this
.
$refs
.
form
.
validate
((
valid
)
=>
{
if
(
!
valid
)
return
;
updateAlgorithm
(
data
).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
$modal
.
msgSuccess
(
"
修改成功
"
);
this
.
getList
();
this
.
editDialogVisible
=
false
;
}
});
});
},
},
};
...
...
src/views/CameraConfig/index.vue
View file @
c31afea9
...
...
@@ -17,7 +17,8 @@
</div>
<el-tree
:data=
"data"
node-key=
"id"
node-key=
"positionId"
:props=
"treeProps"
default-expand-all
:expand-on-click-node=
"false"
@
node-click=
"handleClickChange"
...
...
@@ -63,10 +64,19 @@
plain
size=
"mini"
@
click=
"addCamera"
:disabled=
"clickId == null"
:disabled=
"click
Data.position
Id == null"
>
<i
class=
"el-icon-plus el-icon--left"
></i>
新增摄像头
</el-button
>
<el-tag
closable
type=
"success"
@
close=
"closeTag"
v-if=
"clickData.positionName"
style=
"margin-left: 10px"
>
{{
clickData
.
positionName
}}
</el-tag>
</el-col>
<el-col
:span=
"6"
>
<span></span>
...
...
@@ -98,25 +108,29 @@
empty-text
>
<el-table-column
prop=
"
n
ame"
prop=
"
cameraN
ame"
align=
"center"
label=
"名称"
></el-table-column>
<el-table-column
prop=
"
address
"
prop=
"
cameraPosition
"
align=
"center"
label=
"地址"
></el-table-column>
<el-table-column
prop=
"
videoA
dress"
prop=
"
cameraAd
dress"
label=
"视频地址"
align=
"center"
></el-table-column>
<el-table-column
prop=
"imageUrl"
align=
"center"
label=
"图片地址"
></el-table-column>
<el-table-column
prop=
"cameraImage"
align=
"center"
label=
"图片地址"
>
<template
slot-scope=
"scope"
>
<image-preview
:src=
"scope.row.cameraImage"
:width=
"100"
:height=
"60"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"200"
align=
"center"
>
<
template
slot-scope=
"scope"
>
<el-button
...
...
@@ -129,7 +143,7 @@
<el-button
type=
"text"
size=
"mini"
@
click=
"tableDelete(scope.row)"
@
click=
"tableDelete(scope.row
.cameraId
)"
>
删除
</el-button>
...
...
@@ -159,28 +173,34 @@
label-width=
"100px"
size=
"mini"
>
<el-form-item
label=
"摄像头位置"
prop=
"
address
"
>
<el-form-item
label=
"摄像头位置"
prop=
"
cameraPosition
"
>
<el-input
:disabled=
"visibleType !== 'addAddress'"
v-model=
"form.address"
:disabled=
"
visibleType !== 'addPosition' && visibleType !== 'editPosition'
"
v-model=
"form.cameraPosition"
></el-input>
</el-form-item>
<el-form-item
v-if=
"visibleType === 'addCamera'"
v-if=
"visibleType === 'addCamera'
|| visibleType === 'editCamera'
"
label=
"摄像头名称"
prop=
"
n
ame"
prop=
"
cameraN
ame"
>
<el-input
v-model=
"form.
n
ame"
></el-input>
<el-input
v-model=
"form.
cameraN
ame"
></el-input>
</el-form-item>
<el-form-item
v-if=
"visibleType === 'addCamera'"
v-if=
"visibleType === 'addCamera'
|| visibleType === 'editCamera'
"
label=
"视频地址"
prop=
"
videoA
dress"
prop=
"
cameraAd
dress"
>
<el-input
v-model=
"form.
videoA
dress"
></el-input>
<el-input
v-model=
"form.
cameraAd
dress"
></el-input>
</el-form-item>
<el-form-item
v-if=
"visibleType === 'addCamera'"
label=
"摄像头封面"
>
<ImageUpload
/>
<el-form-item
v-if=
"visibleType === 'addCamera' || visibleType === 'editCamera'"
label=
"摄像头封面"
prop=
"cameraImage"
>
<image-upload
:value=
"form.cameraImage"
@
input=
"getImageUrl"
/>
</el-form-item>
</el-form>
...
...
@@ -193,56 +213,59 @@
</template>
<
script
>
import
{
getCameraList
,
addCamera
,
updateCamera
,
delCamera
,
getCameraPositionList
,
addCameraPosition
,
updateCameraPosition
,
delCameraPosition
,
}
from
"
@/api/business/cameraconfig.js
"
;
export
default
{
name
:
"
Cameraconfig
"
,
props
:
{},
components
:
{},
data
()
{
const
data
=
[
{
id
:
1
,
label
:
"
一级 1
"
,
children
:
[
{
id
:
4
,
label
:
"
二级 1-1
"
,
children
:
[
{
id
:
9
,
label
:
"
三级 1-1-1
"
,
},
{
id
:
10
,
label
:
"
三级 1-1-2
"
,
},
],
},
],
},
];
return
{
data
:
JSON
.
parse
(
JSON
.
stringify
(
data
)),
data
:
[],
treeProps
:
{
// tree节点配置
label
:
"
positionName
"
,
children
:
"
children
"
,
},
id
:
11
,
dialogVisible
:
false
,
visibleType
:
"
addAddress
"
,
// 'addAddress' 或 'addCamera'
/**
* 新增摄像头 addCamera
* 新增摄像头位置 addPosition
* 编辑摄像头 editCamera
* 编辑摄像头位置 editPosition
*/
visibleType
:
"
addPosition
"
,
form
:
{
address
:
""
,
cameraPosition
:
""
,
cameraImage
:
""
,
// 确保初始化为空字符串而不是 null
},
rules
:
{
address
:
[
cameraPosition
:
[
{
required
:
true
,
message
:
"
请输入摄像头地址
"
,
trigger
:
"
blur
"
},
],
n
ame
:
[
cameraN
ame
:
[
{
required
:
true
,
message
:
"
请输入摄像头名称
"
,
trigger
:
"
blur
"
},
],
videoA
dress
:
[
cameraAd
dress
:
[
{
required
:
true
,
message
:
"
请输入视频地址
"
,
trigger
:
"
blur
"
},
],
},
selectedData
:
null
,
// 新增变量,用于保存当前选中的节点数据
isEditing
:
false
,
// 新增编辑状态变量
state
:
""
,
// 搜索框的值
clickId
:
null
,
// 点击的id
clickData
:
{
positionId
:
null
,
// 点击的id
positionName
:
null
,
// 点击的名称
},
// 点击的id
/**table数据 */
total
:
0
,
queryParams
:
{
...
...
@@ -254,83 +277,123 @@ export default {
},
computed
:
{},
watch
:
{},
created
()
{},
created
()
{
this
.
getCameraPositionList
();
this
.
getList
();
},
mounted
()
{},
methods
:
{
/**
* 树状操作部分
*/
getCameraPositionList
()
{
getCameraPositionList
().
then
((
res
)
=>
{
this
.
data
=
res
.
data
;
});
},
// 添加摄像头位置
append
(
data
)
{
this
.
dialogVisible
=
true
;
this
.
selectedData
=
data
;
// 保存当前操作的节点数据
this
.
visibleType
=
"
addPosition
"
;
// 设置为添加摄像头位置
this
.
form
.
cameraPosition
=
""
;
// 清空表单数据
},
//编辑
edit
(
node
,
data
)
{
this
.
isEditing
=
true
;
this
.
dialogVisible
=
true
;
this
.
selectedData
=
data
;
// 保存当前操作的节点数据
this
.
form
.
address
=
data
.
label
;
// 编辑时填充表单数据
this
.
form
.
cameraPosition
=
data
.
positionName
;
// 编辑时填充表单数据
this
.
visibleType
=
"
editPosition
"
;
// 设置为编辑摄像头位置
},
//删除
remove
(
node
,
data
)
{
const
parent
=
node
.
parent
;
const
children
=
parent
.
data
.
children
||
parent
.
data
;
const
index
=
children
.
findIndex
((
d
)
=>
d
.
id
===
data
.
id
);
children
.
splice
(
index
,
1
);
},
// 添加节点逻辑统一处理
handleAddNode
(
parent
,
newChild
)
{
if
(
!
parent
)
{
this
.
data
.
push
(
newChild
);
return
;
}
if
(
!
parent
.
children
)
{
this
.
$set
(
parent
,
"
children
"
,
[]);
}
parent
.
children
.
push
(
newChild
);
},
// 确认操作拆分
handleConfirmAdd
()
{
const
newChild
=
{
id
:
this
.
id
++
,
label
:
this
.
form
.
address
,
children
:
[],
};
this
.
handleAddNode
(
this
.
selectedData
,
newChild
);
delCameraPosition
(
data
.
positionId
).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
getCameraPositionList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
},
// 弹窗状态重置
resetForm
()
{
this
.
dialogVisible
=
false
;
this
.
form
=
{
address
:
""
};
this
.
form
=
{
cameraPosition
:
""
};
this
.
selectedData
=
null
;
this
.
isEditing
=
false
;
},
// 优化后的确认方法
conform
()
{
this
.
$refs
.
form
.
validate
((
valid
)
=>
{
if
(
!
valid
)
return
;
if
(
this
.
isEditing
)
{
this
.
$set
(
this
.
selectedData
,
"
label
"
,
this
.
form
.
address
);
}
else
{
this
.
handleConfirmAdd
();
//新增摄像头信息
if
(
this
.
visibleType
===
"
addCamera
"
)
{
addCamera
({
...
this
.
form
}).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
$modal
.
msgSuccess
(
"
添加成功
"
);
this
.
getList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
}
//编辑摄像头信息
if
(
this
.
visibleType
===
"
editCamera
"
)
{
updateCamera
({
...
this
.
form
}).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
$modal
.
msgSuccess
(
"
编辑成功
"
);
this
.
getList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
}
//新增摄像头位置
if
(
this
.
visibleType
===
"
addPosition
"
)
{
// this.handleConfirmAdd();
let
param
=
{
cameraPosition
:
this
.
form
.
cameraPosition
,
parentId
:
this
.
clickData
.
positionId
,
};
addCameraPosition
(
param
).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
getCameraPositionList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
}
//编辑摄像头位置
if
(
this
.
visibleType
===
"
editPosition
"
)
{
let
param
=
{
cameraPosition
:
this
.
form
.
cameraPosition
,
positionId
:
this
.
clickData
.
positionId
,
};
updateCameraPosition
({
...
param
}).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
getCameraPositionList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
}
this
.
resetForm
();
});
},
// 保持原有递归方法但简化实现
updateNodeById
(
nodes
,
targetId
,
newLabel
)
{
nodes
.
some
((
node
)
=>
{
if
(
node
.
id
===
targetId
)
return
(
node
.
label
=
newLabel
);
return
(
node
.
children
&&
this
.
updateNodeById
(
node
.
children
,
targetId
,
newLabel
)
);
});
},
//选中的tree数据
handleClickChange
(
data
,
checked
,
indeterminate
)
{
this
.
clickId
=
data
.
id
;
this
.
clickData
=
data
;
this
.
getList
();
},
closeTag
()
{
this
.
clickData
=
{
positionId
:
null
,
// 点击的id
positionName
:
null
,
// 点击的名称
};
this
.
getList
();
},
getImageUrl
(
val
)
{
this
.
form
.
cameraImage
=
val
;
},
/**
* 表格操作部分
...
...
@@ -354,24 +417,46 @@ export default {
//新增摄像头
addCamera
()
{
this
.
visibleType
=
"
addCamera
"
;
this
.
form
.
cameraPosition
=
this
.
clickData
.
positionName
;
this
.
form
.
positionId
=
this
.
clickData
.
positionId
;
this
.
dialogVisible
=
true
;
},
//导出按钮操作
handleExport
()
{
this
.
download
(
"
system/post
/export
"
,
"
/system/cameraConfig
/export
"
,
{
...
this
.
queryParams
,
},
`
post
_
${
new
Date
().
getTime
()}
.xlsx`
`
摄像头列表
_
${
new
Date
().
getTime
()}
.xlsx`
);
},
//获取表格数据
getList
()
{},
getList
()
{
getCameraList
({
...
this
.
queryParams
,
positionId
:
this
.
clickData
.
positionId
,
}).
then
((
res
)
=>
{
this
.
tableList
=
res
.
rows
;
this
.
total
=
res
.
total
;
});
},
//表格编辑
tableEdit
()
{},
tableEdit
(
data
)
{
this
.
form
=
{
...
data
};
this
.
dialogVisible
=
true
;
this
.
visibleType
=
"
editCamera
"
;
},
//表格删除
tableDelete
()
{},
tableDelete
(
id
)
{
delCamera
(
id
).
then
((
res
)
=>
{
if
(
res
.
code
===
200
)
{
this
.
getList
();
}
else
{
this
.
$modal
.
msgError
(
res
.
msg
);
}
});
},
},
};
</
script
>
...
...
src/views/dashboard/PieChart.vue
View file @
c31afea9
<
template
>
<div
:class=
"className"
:style=
"
{
height:height,width:width
}" />
<div
:class=
"className"
:style=
"
{
height: height, width: width
}" />
</
template
>
<
script
>
import
*
as
echarts
from
'
echarts
'
require
(
'
echarts/theme/macarons
'
)
// echarts theme
import
resize
from
'
./mixins/resize
'
import
*
as
echarts
from
"
echarts
"
;
require
(
"
echarts/theme/macarons
"
);
// echarts theme
import
resize
from
"
./mixins/resize
"
;
export
default
{
mixins
:
[
resize
],
props
:
{
className
:
{
type
:
String
,
default
:
'
chart
'
default
:
"
chart
"
,
},
width
:
{
type
:
String
,
default
:
'
100%
'
default
:
"
100%
"
,
},
height
:
{
type
:
String
,
default
:
'
300px
'
}
default
:
"
300px
"
,
}
,
},
data
()
{
return
{
chart
:
null
}
chart
:
null
,
}
;
},
mounted
()
{
this
.
$nextTick
(()
=>
{
this
.
initChart
()
})
this
.
initChart
()
;
})
;
},
beforeDestroy
()
{
if
(
!
this
.
chart
)
{
return
return
;
}
this
.
chart
.
dispose
()
this
.
chart
=
null
this
.
chart
.
dispose
()
;
this
.
chart
=
null
;
},
methods
:
{
initChart
()
{
this
.
chart
=
echarts
.
init
(
this
.
$el
,
'
macarons
'
)
this
.
chart
=
echarts
.
init
(
this
.
$el
,
"
macarons
"
);
this
.
chart
.
setOption
({
tooltip
:
{
trigger
:
'
item
'
,
formatter
:
'
{a} <br/>{b} : {c} ({d}%)
'
trigger
:
"
item
"
,
formatter
:
"
{a} <br/>{b} : {c} ({d}%)
"
,
},
legend
:
{
left
:
'
center
'
,
bottom
:
'
10
'
,
data
:
[
'
Industries
'
,
'
Technology
'
,
'
Forex
'
,
'
Gold
'
,
'
Forecasts
'
]
left
:
"
center
"
,
top
:
"
5%
"
,
data
:
[
"
已启动
"
,
"
未启动
"
],
},
series
:
[
{
name
:
'
WEEKLY WRITE ARTICLES
'
,
type
:
'
pie
'
,
r
oseType
:
'
radius
'
,
radius
:
[
15
,
95
],
c
enter
:
[
'
50%
'
,
'
38%
'
],
name
:
"
监控摄像头
"
,
type
:
"
pie
"
,
r
adius
:
[
"
45%
"
,
"
75%
"
]
,
center
:
[
"
50%
"
,
"
55%
"
],
c
olor
:
[
"
#67C23A
"
,
"
#F56C6C
"
],
// 新增颜色数组配置
data
:
[
{
value
:
320
,
name
:
'
Industries
'
},
{
value
:
240
,
name
:
'
Technology
'
},
{
value
:
149
,
name
:
'
Forex
'
},
{
value
:
100
,
name
:
'
Gold
'
},
{
value
:
59
,
name
:
'
Forecasts
'
}
{
value
:
320
,
name
:
"
已启动
"
},
{
value
:
240
,
name
:
"
未启动
"
},
],
animationEasing
:
'
cubicInOut
'
,
animationDuration
:
2600
}
]
})
}
}
}
avoidLabelOverlap
:
false
,
itemStyle
:
{
borderRadius
:
10
,
borderColor
:
"
#fff
"
,
borderWidth
:
2
,
},
emphasis
:
{
label
:
{
show
:
true
,
fontSize
:
40
,
fontWeight
:
"
bold
"
,
},
},
label
:
{
position
:
"
center
"
,
},
},
],
});
},
},
};
</
script
>
src/views/dashboard/mixins/resize.js
View file @
c31afea9
...
...
@@ -34,12 +34,18 @@ export default {
}
},
initListener
()
{
// 创建防抖的resize事件处理器(100ms延迟)
this
.
$_resizeHandler
=
debounce
(()
=>
{
this
.
resize
()
this
.
resize
()
// 触发图表重绘
},
100
)
// 监听窗口resize事件
window
.
addEventListener
(
'
resize
'
,
this
.
$_resizeHandler
)
// 获取侧边栏DOM元素
this
.
$_sidebarElm
=
document
.
getElementsByClassName
(
'
sidebar-container
'
)[
0
]
// 监听侧边栏过渡动画结束事件(当侧边栏展开/折叠时)
this
.
$_sidebarElm
&&
this
.
$_sidebarElm
.
addEventListener
(
'
transitionend
'
,
this
.
$_sidebarResizeHandler
)
},
destroyListener
()
{
...
...
src/views/index.vue
View file @
c31afea9
...
...
@@ -18,18 +18,30 @@
<div
class=
"status-container"
>
<h3
class=
"status-title"
>
视频分析任务启动状态
</h3>
<div
class=
"status-group"
>
<div
class=
"status-item"
>
<
bar
-chart
/>
<div
class=
"status-item"
style=
"height: 300px"
>
<
pie
-chart
/>
</div>
</div>
</div>
</el-col>
<el-col
:span=
"13"
>
<el-card
shadow=
"hover"
:body-style=
"
{ padding: '20px', height: 'calc(100vh - 200px)' }"
>
</el-card>
<div
class=
"status-container"
>
<h3
class=
"status-title both-end"
>
<span
><span>
{{
selectVidoe
.
name
}}
</span
><span>
正在查看
</span></span
>
<el-select
v-model=
"selectVidoe"
value-key=
"url"
placeholder=
""
>
<el-option
v-for=
"item in videoList"
:key=
"item.id"
:label=
"item.name"
:value=
"item"
></el-option>
</el-select>
</h3>
<div
class=
"video-box"
></div>
</div>
</el-col>
<el-col
:span=
"6"
>
<el-card
...
...
@@ -43,12 +55,20 @@
</
template
>
<
script
>
import
{
barChart
}
from
"
./dashboard/BarChart
"
;
import
PieChart
from
"
./dashboard/PieChart.vue
"
;
export
default
{
name
:
"
Index
"
,
components
:
{
bar
Chart
},
components
:
{
Pie
Chart
},
data
()
{
return
{};
return
{
selectVidoe
:
{},
// 选择视频
videoList
:
[
// 视频列表
{
name
:
"
视频1
"
,
url
:
"
URL_ADDRESS
"
,
id
:
1
},
{
name
:
"
视频2
"
,
url
:
"
URL_ADDRESS:8080/video1.mp4
"
,
id
:
2
},
{
name
:
"
视频3
"
,
url
:
"
URL_ADDRESSlhost:8080/video1.mp4
"
,
id
:
3
},
],
};
},
methods
:
{},
};
...
...
@@ -68,27 +88,28 @@ export default {
background
:
#f8f9fa
;
border-radius
:
5px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.1
);
margin-bottom
:
20px
;
.status-title
{
margin
:
0
0
20px
0
;
font-size
:
16px
;
color
:
#333
;
.title-icon
{
margin-right
:
8px
;
font-size
:
20px
;
color
:
#409eff
;
}
}
.both-end
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.status-group
{
display
:
flex
;
gap
:
20px
;
.status-item
{
flex
:
1
;
text-align
:
center
;
.count
{
font-size
:
32px
;
font-weight
:
bold
;
...
...
@@ -102,11 +123,9 @@ export default {
color
:
#f56c6c
;
}
}
.label
{
font-size
:
14px
;
color
:
#666
;
.svg-icon
{
vertical-align
:
middle
;
margin-right
:
5px
;
...
...
@@ -115,6 +134,11 @@ export default {
}
}
}
.video-box
{
height
:
440px
;
width
:
100%
;
background
:
#409eff
;
}
}
}
</
style
>
vue.config.js
View file @
c31afea9
...
...
@@ -29,10 +29,10 @@ module.exports = {
productionSourceMap
:
false
,
transpileDependencies
:
[
'
quill
'
],
// webpack-dev-server 相关配置
hot
:
true
,
headers
:
{
'
Cache-Control
'
:
'
no-store
'
},
//
hot: true,
//
headers: {
//
'Cache-Control': 'no-store'
//
},
devServer
:
{
host
:
'
0.0.0.0
'
,
port
:
port
,
...
...
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