Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
I
iot-web
Overview
Overview
Details
Activity
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
吴春元
iot-web
Commits
568600c8
Commit
568600c8
authored
Nov 25, 2025
by
吴春元
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
对接:设备接入数量、系统分类统计、设备分类占比、设备告警统计、近 7 天告警统计、已部署系统、下级单位设备统计
parent
0768b0b5
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
818 additions
and
174 deletions
+818
-174
components.d.ts
components.d.ts
+11
-0
index.html
index.html
+7
-0
_metadata.json
node_modules/.vite/deps/_metadata.json
+224
-34
element-plus.js
node_modules/.vite/deps/element-plus.js
+3
-2
home.ts
src/api/iot/home.ts
+62
-0
element-plus.scss
src/assets/styles/element-plus.scss
+1
-0
User.vue
src/layout/components/User.vue
+23
-11
main.vue
src/layout/main.vue
+3
-0
Home.vue
src/views/Home.vue
+35
-19
Alert7Days.vue
src/views/components/Alert7Days.vue
+174
-28
DeployProject.vue
src/views/components/DeployProject.vue
+46
-6
DeviceClassification.vue
src/views/components/DeviceClassification.vue
+36
-19
DeviceNumber.vue
src/views/components/DeviceNumber.vue
+35
-11
EquipmentAlarm.vue
src/views/components/EquipmentAlarm.vue
+49
-4
Map1.vue
src/views/components/Map1.vue
+60
-0
SubsidiaryCompanyEquipment.vue
src/views/components/SubsidiaryCompanyEquipment.vue
+29
-22
login.vue
src/views/login.vue
+20
-18
No files found.
components.d.ts
View file @
568600c8
...
...
@@ -10,13 +10,24 @@ declare module 'vue' {
export
interface
GlobalComponents
{
AsyncMap3D
:
typeof
import
(
'./src/components/ThreeMap/AsyncMap3D.vue'
)[
'default'
]
ContainerWrap
:
typeof
import
(
'./src/components/ContainerWrap/index.vue'
)[
'default'
]
ElButton
:
typeof
import
(
'element-plus/es'
)[
'ElButton'
]
ElCascader
:
typeof
import
(
'element-plus/es'
)[
'ElCascader'
]
ElCheckbox
:
typeof
import
(
'element-plus/es'
)[
'ElCheckbox'
]
ElCol
:
typeof
import
(
'element-plus/es'
)[
'ElCol'
]
ElDialog
:
typeof
import
(
'element-plus/es'
)[
'ElDialog'
]
ElEmpty
:
typeof
import
(
'element-plus/es'
)[
'ElEmpty'
]
ElForm
:
typeof
import
(
'element-plus/es'
)[
'ElForm'
]
ElFormItem
:
typeof
import
(
'element-plus/es'
)[
'ElFormItem'
]
ElIcon
:
typeof
import
(
'element-plus/es'
)[
'ElIcon'
]
ElImage
:
typeof
import
(
'element-plus/es'
)[
'ElImage'
]
ElInput
:
typeof
import
(
'element-plus/es'
)[
'ElInput'
]
ElOption
:
typeof
import
(
'element-plus/es'
)[
'ElOption'
]
ElRadioButton
:
typeof
import
(
'element-plus/es'
)[
'ElRadioButton'
]
ElRadioGroup
:
typeof
import
(
'element-plus/es'
)[
'ElRadioGroup'
]
ElRow
:
typeof
import
(
'element-plus/es'
)[
'ElRow'
]
ElSelect
:
typeof
import
(
'element-plus/es'
)[
'ElSelect'
]
ElTable
:
typeof
import
(
'element-plus/es'
)[
'ElTable'
]
ElTableColumn
:
typeof
import
(
'element-plus/es'
)[
'ElTableColumn'
]
HelloWorld
:
typeof
import
(
'./src/components/HelloWorld.vue'
)[
'default'
]
ItemWrap
:
typeof
import
(
'./src/components/ItemWrap/index.vue'
)[
'default'
]
ItemWrap2
:
typeof
import
(
'./src/components/ItemWrap2/index.vue'
)[
'default'
]
...
...
index.html
View file @
568600c8
...
...
@@ -35,6 +35,12 @@
<script
type=
"text/javascript"
src=
"https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=i8RgXE4a6vzGgbFs5s4ynlyUh6YnUQIB"
>
</script>
<script
type=
"text/javascript"
src=
"https://webapi.amap.com/maps?v=2.0&key=fee919a8e608c39d1d528ec662a2ca17&plugin=AMap.DistrictSearch"
></script>
<script
src=
"https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"
></script>
<!-- <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" /> -->
</body>
</html>
\ No newline at end of file
node_modules/.vite/deps/_metadata.json
View file @
568600c8
...
...
@@ -2,159 +2,348 @@
"hash"
:
"3d95d7cd"
,
"configHash"
:
"beb1c48d"
,
"lockfileHash"
:
"2e2ef206"
,
"browserHash"
:
"
c584cccb
"
,
"browserHash"
:
"
80dbb247
"
,
"optimized"
:
{
"vue"
:
{
"src"
:
"../../vue/dist/vue.runtime.esm-bundler.js"
,
"file"
:
"vue.js"
,
"fileHash"
:
"
04ed1a8d
"
,
"fileHash"
:
"
27726b81
"
,
"needsInterop"
:
false
},
"vue-router"
:
{
"src"
:
"../../vue-router/dist/vue-router.mjs"
,
"file"
:
"vue-router.js"
,
"fileHash"
:
"
d0d63c13
"
,
"fileHash"
:
"
0e4a94be
"
,
"needsInterop"
:
false
},
"element-plus"
:
{
"src"
:
"../../element-plus/es/index.mjs"
,
"file"
:
"element-plus.js"
,
"fileHash"
:
"
0023de30
"
,
"fileHash"
:
"
d9930fe7
"
,
"needsInterop"
:
false
},
"@element-plus/icons-vue"
:
{
"src"
:
"../../@element-plus/icons-vue/dist/index.js"
,
"file"
:
"@element-plus_icons-vue.js"
,
"fileHash"
:
"
b1b62eda
"
,
"fileHash"
:
"
2651facd
"
,
"needsInterop"
:
false
},
"nprogress"
:
{
"src"
:
"../../nprogress/nprogress.js"
,
"file"
:
"nprogress.js"
,
"fileHash"
:
"
592ef64d
"
,
"fileHash"
:
"
17e27234
"
,
"needsInterop"
:
true
},
"pinia"
:
{
"src"
:
"../../pinia/dist/pinia.mjs"
,
"file"
:
"pinia.js"
,
"fileHash"
:
"
35bb846
2"
,
"fileHash"
:
"
25cdbaf
2"
,
"needsInterop"
:
false
},
"js-cookie"
:
{
"src"
:
"../../js-cookie/dist/js.cookie.mjs"
,
"file"
:
"js-cookie.js"
,
"fileHash"
:
"
809f3851
"
,
"fileHash"
:
"
3e9ef2cb
"
,
"needsInterop"
:
false
},
"axios"
:
{
"src"
:
"../../axios/index.js"
,
"file"
:
"axios.js"
,
"fileHash"
:
"
93780ea1
"
,
"fileHash"
:
"
4d97a917
"
,
"needsInterop"
:
false
},
"element-plus/es"
:
{
"src"
:
"../../element-plus/es/index.mjs"
,
"file"
:
"element-plus_es.js"
,
"fileHash"
:
"
3cd56c8a
"
,
"fileHash"
:
"
eff4ad91
"
,
"needsInterop"
:
false
},
"element-plus/es/components/base/style/index"
:
{
"src"
:
"../../element-plus/es/components/base/style/index.mjs"
,
"file"
:
"element-plus_es_components_base_style_index.js"
,
"fileHash"
:
"
3ad3246e
"
,
"fileHash"
:
"
bb275ed1
"
,
"needsInterop"
:
false
},
"element-plus/es/components/select/style/index"
:
{
"src"
:
"../../element-plus/es/components/select/style/index.mjs"
,
"file"
:
"element-plus_es_components_select_style_index.js"
,
"fileHash"
:
"
14ec8502
"
,
"fileHash"
:
"
a7c12d1a
"
,
"needsInterop"
:
false
},
"element-plus/es/components/option/style/index"
:
{
"src"
:
"../../element-plus/es/components/option/style/index.mjs"
,
"file"
:
"element-plus_es_components_option_style_index.js"
,
"fileHash"
:
"
4bbdcb43
"
,
"fileHash"
:
"
f0a4374a
"
,
"needsInterop"
:
false
},
"element-plus/es/components/cascader/style/index"
:
{
"src"
:
"../../element-plus/es/components/cascader/style/index.mjs"
,
"file"
:
"element-plus_es_components_cascader_style_index.js"
,
"fileHash"
:
"
9fe4e813
"
,
"fileHash"
:
"
f3c25105
"
,
"needsInterop"
:
false
},
"mitt"
:
{
"src"
:
"../../mitt/dist/mitt.mjs"
,
"file"
:
"mitt.js"
,
"fileHash"
:
"
1128ae26
"
,
"fileHash"
:
"
27983b13
"
,
"needsInterop"
:
false
},
"element-plus/es/components/dialog/style/index"
:
{
"src"
:
"../../element-plus/es/components/dialog/style/index.mjs"
,
"file"
:
"element-plus_es_components_dialog_style_index.js"
,
"fileHash"
:
"
32c6577a
"
,
"fileHash"
:
"
250cc421
"
,
"needsInterop"
:
false
},
"element-plus/es/components/icon/style/index"
:
{
"src"
:
"../../element-plus/es/components/icon/style/index.mjs"
,
"file"
:
"element-plus_es_components_icon_style_index.js"
,
"fileHash"
:
"
ac36d8d2
"
,
"fileHash"
:
"
ffaccf8e
"
,
"needsInterop"
:
false
},
"element-plus/es/components/row/style/index"
:
{
"src"
:
"../../element-plus/es/components/row/style/index.mjs"
,
"file"
:
"element-plus_es_components_row_style_index.js"
,
"fileHash"
:
"
bdb7445c
"
,
"fileHash"
:
"
8146d606
"
,
"needsInterop"
:
false
},
"element-plus/es/components/col/style/index"
:
{
"src"
:
"../../element-plus/es/components/col/style/index.mjs"
,
"file"
:
"element-plus_es_components_col_style_index.js"
,
"fileHash"
:
"
9d3f3730
"
,
"fileHash"
:
"
0537d086
"
,
"needsInterop"
:
false
},
"@bmapgl-plugin/cluster"
:
{
"src"
:
"../../@bmapgl-plugin/cluster/index.js"
,
"file"
:
"@bmapgl-plugin_cluster.js"
,
"fileHash"
:
"7
dcbcecf
"
,
"fileHash"
:
"7
6122e4a
"
,
"needsInterop"
:
true
},
"echarts"
:
{
"src"
:
"../../echarts/index.js"
,
"file"
:
"echarts.js"
,
"fileHash"
:
"
458581f4
"
,
"fileHash"
:
"
1c4eb8d2
"
,
"needsInterop"
:
false
},
"lodash-es"
:
{
"src"
:
"../../lodash-es/lodash.js"
,
"file"
:
"lodash-es.js"
,
"fileHash"
:
"bf9153cd"
,
"fileHash"
:
"810dae55"
,
"needsInterop"
:
false
},
"element-plus/es/components/form/style/index"
:
{
"src"
:
"../../element-plus/es/components/form/style/index.mjs"
,
"file"
:
"element-plus_es_components_form_style_index.js"
,
"fileHash"
:
"970d9f3d"
,
"needsInterop"
:
false
},
"element-plus/es/components/button/style/index"
:
{
"src"
:
"../../element-plus/es/components/button/style/index.mjs"
,
"file"
:
"element-plus_es_components_button_style_index.js"
,
"fileHash"
:
"9f2dfef8"
,
"needsInterop"
:
false
},
"element-plus/es/components/checkbox/style/index"
:
{
"src"
:
"../../element-plus/es/components/checkbox/style/index.mjs"
,
"file"
:
"element-plus_es_components_checkbox_style_index.js"
,
"fileHash"
:
"9af6d3a5"
,
"needsInterop"
:
false
},
"element-plus/es/components/form-item/style/index"
:
{
"src"
:
"../../element-plus/es/components/form-item/style/index.mjs"
,
"file"
:
"element-plus_es_components_form-item_style_index.js"
,
"fileHash"
:
"796b51f1"
,
"needsInterop"
:
false
},
"element-plus/es/components/input/style/index"
:
{
"src"
:
"../../element-plus/es/components/input/style/index.mjs"
,
"file"
:
"element-plus_es_components_input_style_index.js"
,
"fileHash"
:
"6810a81c"
,
"needsInterop"
:
false
},
"jsencrypt"
:
{
"src"
:
"../../jsencrypt/lib/index.js"
,
"file"
:
"jsencrypt.js"
,
"fileHash"
:
"0700df96"
,
"needsInterop"
:
false
},
"gsap"
:
{
"src"
:
"../../gsap/index.js"
,
"file"
:
"gsap.js"
,
"fileHash"
:
"93435ea0"
,
"needsInterop"
:
false
},
"element-plus/es/components/image/style/index"
:
{
"src"
:
"../../element-plus/es/components/image/style/index.mjs"
,
"file"
:
"element-plus_es_components_image_style_index.js"
,
"fileHash"
:
"ade67ad6"
,
"needsInterop"
:
false
},
"element-plus/es/components/radio-group/style/index"
:
{
"src"
:
"../../element-plus/es/components/radio-group/style/index.mjs"
,
"file"
:
"element-plus_es_components_radio-group_style_index.js"
,
"fileHash"
:
"2230c661"
,
"needsInterop"
:
false
},
"element-plus/es/components/radio-button/style/index"
:
{
"src"
:
"../../element-plus/es/components/radio-button/style/index.mjs"
,
"file"
:
"element-plus_es_components_radio-button_style_index.js"
,
"fileHash"
:
"215535d2"
,
"needsInterop"
:
false
},
"element-plus/es/components/table/style/index"
:
{
"src"
:
"../../element-plus/es/components/table/style/index.mjs"
,
"file"
:
"element-plus_es_components_table_style_index.js"
,
"fileHash"
:
"8fc19294"
,
"needsInterop"
:
false
},
"element-plus/es/components/table-column/style/index"
:
{
"src"
:
"../../element-plus/es/components/table-column/style/index.mjs"
,
"file"
:
"element-plus_es_components_table-column_style_index.js"
,
"fileHash"
:
"0e0deee5"
,
"needsInterop"
:
false
},
"element-plus/es/components/empty/style/index"
:
{
"src"
:
"../../element-plus/es/components/empty/style/index.mjs"
,
"file"
:
"element-plus_es_components_empty_style_index.js"
,
"fileHash"
:
"193464b9"
,
"needsInterop"
:
false
},
"three"
:
{
"src"
:
"../../three/build/three.module.js"
,
"file"
:
"three.js"
,
"fileHash"
:
"a2a26ed0"
,
"needsInterop"
:
false
},
"three/examples/jsm/controls/OrbitControls.js"
:
{
"src"
:
"../../three/examples/jsm/controls/OrbitControls.js"
,
"file"
:
"three_examples_jsm_controls_OrbitControls__js.js"
,
"fileHash"
:
"34cf4c25"
,
"needsInterop"
:
false
},
"three/examples/jsm/renderers/CSS2DRenderer.js"
:
{
"src"
:
"../../three/examples/jsm/renderers/CSS2DRenderer.js"
,
"file"
:
"three_examples_jsm_renderers_CSS2DRenderer__js.js"
,
"fileHash"
:
"7468204b"
,
"needsInterop"
:
false
},
"three/addons/renderers/CSS3DRenderer.js"
:
{
"src"
:
"../../three/examples/jsm/renderers/CSS3DRenderer.js"
,
"file"
:
"three_addons_renderers_CSS3DRenderer__js.js"
,
"fileHash"
:
"7bef1bf6"
,
"needsInterop"
:
false
},
"three/addons/postprocessing/EffectComposer.js"
:
{
"src"
:
"../../three/examples/jsm/postprocessing/EffectComposer.js"
,
"file"
:
"three_addons_postprocessing_EffectComposer__js.js"
,
"fileHash"
:
"9ef4409f"
,
"needsInterop"
:
false
},
"three/addons/postprocessing/RenderPass.js"
:
{
"src"
:
"../../three/examples/jsm/postprocessing/RenderPass.js"
,
"file"
:
"three_addons_postprocessing_RenderPass__js.js"
,
"fileHash"
:
"b83c3a33"
,
"needsInterop"
:
false
},
"three/addons/postprocessing/OutlinePass.js"
:
{
"src"
:
"../../three/examples/jsm/postprocessing/OutlinePass.js"
,
"file"
:
"three_addons_postprocessing_OutlinePass__js.js"
,
"fileHash"
:
"6e02a652"
,
"needsInterop"
:
false
},
"d3"
:
{
"src"
:
"../../d3/src/index.js"
,
"file"
:
"d3.js"
,
"fileHash"
:
"8a875b0d"
,
"needsInterop"
:
false
},
"three/examples/jsm/lines/Line2.js"
:
{
"src"
:
"../../three/examples/jsm/lines/Line2.js"
,
"file"
:
"three_examples_jsm_lines_Line2__js.js"
,
"fileHash"
:
"b09fa5aa"
,
"needsInterop"
:
false
},
"three/examples/jsm/lines/LineGeometry.js"
:
{
"src"
:
"../../three/examples/jsm/lines/LineGeometry.js"
,
"file"
:
"three_examples_jsm_lines_LineGeometry__js.js"
,
"fileHash"
:
"2853a7f4"
,
"needsInterop"
:
false
},
"three/examples/jsm/lines/LineMaterial.js"
:
{
"src"
:
"../../three/examples/jsm/lines/LineMaterial.js"
,
"file"
:
"three_examples_jsm_lines_LineMaterial__js.js"
,
"fileHash"
:
"a4ea8742"
,
"needsInterop"
:
false
},
"three/examples/jsm/renderers/CSS3DRenderer.js"
:
{
"src"
:
"../../three/examples/jsm/renderers/CSS3DRenderer.js"
,
"file"
:
"three_examples_jsm_renderers_CSS3DRenderer__js.js"
,
"fileHash"
:
"6deae146"
,
"needsInterop"
:
false
},
"element-plus/es/locales.mjs"
:
{
"src"
:
"../../element-plus/es/locales.mjs"
,
"file"
:
"element-plus_es_locales__mjs.js"
,
"fileHash"
:
"61130207"
,
"needsInterop"
:
false
}
},
"chunks"
:
{
"chunk-
QOFRX7VY
"
:
{
"file"
:
"chunk-
QOFRX7VY
.js"
"chunk-
IYMVL6BZ
"
:
{
"file"
:
"chunk-
IYMVL6BZ
.js"
},
"chunk-
S4WGN4L
U"
:
{
"file"
:
"chunk-
S4WGN4L
U.js"
"chunk-
NY4Z4LN
U"
:
{
"file"
:
"chunk-
NY4Z4LN
U.js"
},
"chunk-
TKM7ANES
"
:
{
"file"
:
"chunk-
TKM7ANES
.js"
"chunk-
FEBRQDH5
"
:
{
"file"
:
"chunk-
FEBRQDH5
.js"
},
"chunk-JDSL2H4L"
:
{
"file"
:
"chunk-JDSL2H4L.js"
"chunk-ZYSY3OGM"
:
{
"file"
:
"chunk-ZYSY3OGM.js"
},
"chunk-MFBDIXYG"
:
{
"file"
:
"chunk-MFBDIXYG.js"
},
"chunk-ZS2WBNEI"
:
{
"file"
:
"chunk-ZS2WBNEI.js"
},
"chunk-4GXJ2MCF"
:
{
"file"
:
"chunk-4GXJ2MCF.js"
},
"chunk-HNP5HSLD"
:
{
"file"
:
"chunk-HNP5HSLD.js"
},
"chunk-RG7S6HTO"
:
{
"file"
:
"chunk-RG7S6HTO.js"
},
"chunk-TZOTQKIH"
:
{
"file"
:
"chunk-TZOTQKIH.js"
},
"chunk-
EYASHUGA
"
:
{
"file"
:
"chunk-
EYASHUGA
.js"
"chunk-
372N3PK6
"
:
{
"file"
:
"chunk-
372N3PK6
.js"
},
"chunk-G3PMV62Z"
:
{
"file"
:
"chunk-G3PMV62Z.js"
"chunk-PCQ6BLF2"
:
{
"file"
:
"chunk-PCQ6BLF2.js"
},
"chunk-IQCPA24U"
:
{
"file"
:
"chunk-IQCPA24U.js"
},
"chunk-TKM7ANES"
:
{
"file"
:
"chunk-TKM7ANES.js"
},
"chunk-S4WGN4LU"
:
{
"file"
:
"chunk-S4WGN4LU.js"
},
"chunk-3EK6V4TN"
:
{
"file"
:
"chunk-3EK6V4TN.js"
},
"chunk-5HXAQIWW"
:
{
"file"
:
"chunk-5HXAQIWW.js"
},
"chunk-JDSL2H4L"
:
{
"file"
:
"chunk-JDSL2H4L.js"
},
"chunk-G3PMV62Z"
:
{
"file"
:
"chunk-G3PMV62Z.js"
}
}
}
\ No newline at end of file
node_modules/.vite/deps/element-plus.js
View file @
568600c8
...
...
@@ -510,9 +510,10 @@ import {
virtualizedScrollbarProps
,
watermarkProps
,
zIndexContextKey
}
from
"./chunk-QOFRX7VY.js"
;
import
"./chunk-S4WGN4LU.js"
;
}
from
"./chunk-IQCPA24U.js"
;
import
"./chunk-TKM7ANES.js"
;
import
"./chunk-S4WGN4LU.js"
;
import
"./chunk-3EK6V4TN.js"
;
import
"./chunk-JDSL2H4L.js"
;
import
"./chunk-G3PMV62Z.js"
;
var
export_dayjs
=
import_dayjs
.
default
;
...
...
src/api/iot/home.ts
0 → 100644
View file @
568600c8
import
request
from
"@/utils/request"
;
// 获取截止时间
export
function
nowTime
()
{
return
request
({
url
:
"/system/dept/getNow"
,
method
:
"get"
,
});
}
// 获取设备接入数量(在线、离线)
export
function
allDevice
(
deptId
:
number
)
{
return
request
({
url
:
"/device/baseDevice/getAllDevice?deptId="
+
deptId
,
method
:
"get"
,
});
}
// 获取设备分类占比
export
function
deviceCountByType
(
deptId
:
number
,
grade
:
String
)
{
return
request
({
url
:
"/device/baseDevice/getDeviceCountByType?deptId="
+
deptId
+
"&grade="
+
grade
,
method
:
"get"
,
});
}
// 获取设备接入数量(在线、离线)
export
function
deviceCountByChild
(
deptId
:
number
)
{
return
request
({
url
:
"/device/baseDevice/getDeviceCountByChild?deptId="
+
deptId
,
method
:
"get"
,
});
}
// 设备告警统计
export
function
alarmNumCount
(
deptId
:
number
)
{
return
request
({
url
:
"/device/alarmInfo/alarmNumCount?deptId="
+
deptId
,
method
:
"get"
,
});
}
// 近7天告警统计
export
function
countByDay
(
data
:
any
)
{
return
request
({
url
:
"/device/alarmInfo/countByDay"
,
method
:
"post"
,
data
:
data
,
});
}
// 已部署系统
export
function
countBySysType
(
deptId
:
number
)
{
return
request
({
url
:
"/system/dept/countBySysType?deptId="
+
deptId
,
method
:
"get"
,
});
}
src/assets/styles/element-plus.scss
View file @
568600c8
...
...
@@ -71,6 +71,7 @@ $blue-hover: #40a9ff; // 悬停蓝色
.el-input__inner
{
color
:
#{
$white-text
}
;
}
}
...
...
src/layout/components/User.vue
View file @
568600c8
<
template
>
<div
class=
"user flex items-center cursor-pointer
"
>
<el-icon
color=
"#fff"
size=
"24"
><SwitchButton
/></el-icon>
</div>
<div
class=
"user flex cursor-pointer mt-4 mr-3"
@
click=
"logout
"
>
<el-icon
color=
"#fff"
size=
"24"
><SwitchButton
/></el-icon>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
import
{
SwitchButton
}
from
'@element-plus/icons-vue'
import
{
ref
}
from
"vue"
;
import
{
SwitchButton
}
from
"@element-plus/icons-vue"
;
import
useUserStore
from
"@/store/modules/user"
;
import
{
ElMessageBox
}
from
"element-plus"
;
const
user
=
ref
({
name
:
'张三'
,
avatar
:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif'
,
})
</
script
>
\ No newline at end of file
function
logout
()
{
ElMessageBox
.
confirm
(
"确定注销并退出系统吗?"
,
"提示"
,
{
confirmButtonText
:
"确定"
,
cancelButtonText
:
"取消"
,
type
:
"warning"
,
})
.
then
(()
=>
{
useUserStore
()
.
logOut
()
.
then
(()
=>
{
location
.
href
=
"/"
;
});
})
.
catch
(()
=>
{});
}
</
script
>
src/layout/main.vue
View file @
568600c8
...
...
@@ -45,7 +45,9 @@
</el-select>
</div>
</div>
<User
class=
""
></User>
</div>
<div
class=
"content relative"
>
<router-view></router-view>
</div>
...
...
@@ -55,6 +57,7 @@
<
script
setup
lang=
"ts"
>
import
{
AppSetting
}
from
"@/setting"
;
import
Menu
from
"./components/Menu.vue"
;
import
User
from
"./components/User.vue"
;
import
{
ref
}
from
"vue"
;
import
{
eventBus
}
from
"@/eventBus"
;
...
...
src/views/Home.vue
View file @
568600c8
...
...
@@ -4,18 +4,18 @@
<!-- 第一列(3个均匀分布的框) -->
<el-col
:span=
"7"
class=
"column"
>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"设备接入数量"
endDate=
"2025-10-18
"
>
<DeviceNumber
/>
<ContainerWrap
title=
"设备接入数量"
:endDate=
"nowTimes
"
>
<DeviceNumber
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"系统分类统计"
endDate=
"2025-10-18
"
>
<SysClassification
/>
<ContainerWrap
title=
"系统分类统计"
:endDate=
"nowTimes
"
>
<SysClassification
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"设备分类占比"
endDate=
"2025-10-18
"
>
<DeviceClassification
/>
<ContainerWrap
title=
"设备分类占比"
:endDate=
"nowTimes
"
>
<DeviceClassification
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
</el-col>
...
...
@@ -23,13 +23,13 @@
<!-- 第二列(第一个框占2/3,第二个框占1/3) -->
<el-col
:span=
"10"
class=
"column"
>
<div
class=
"grid-content wide-box"
style=
"flex: 2"
>
<ContainerWrap
title=
"设备分布图"
endDate=
"2025-10-18
"
>
<MapEcharts
/>
<ContainerWrap
title=
"设备分布图"
:endDate=
"nowTimes
"
>
<MapEcharts
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
<div
class=
"grid-content wide-box"
style=
"flex: 1"
>
<ContainerWrap
title=
"
各分子公司设备统计"
endDate=
"2025-10-18
"
>
<SubsidiaryCompanyEquipment
/>
<ContainerWrap
title=
"
下级单位设备统计"
:endDate=
"nowTimes
"
>
<SubsidiaryCompanyEquipment
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
</el-col>
...
...
@@ -37,18 +37,18 @@
<!-- 第三列(3个均匀分布的框) -->
<el-col
:span=
"7"
class=
"column"
>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"设备告警统计"
endDate=
"2025-10-18
"
>
<EquipmentAlarm
/>
<ContainerWrap
title=
"设备告警统计"
:endDate=
"nowTimes
"
>
<EquipmentAlarm
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"近7天告警统计"
endDate=
"2025-10-18
"
>
<Alert7Days
/>
<ContainerWrap
title=
"近7天告警统计"
:endDate=
"nowTimes
"
>
<Alert7Days
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
<div
class=
"grid-content tall-box"
>
<ContainerWrap
title=
"已部署系统"
endDate=
"2025-10-18
"
>
<DeployProject
/>
<ContainerWrap
title=
"已部署系统"
:endDate=
"nowTimes
"
>
<DeployProject
:dept-id=
"selectedOffice[0]"
/>
</ContainerWrap>
</div>
</el-col>
...
...
@@ -126,7 +126,7 @@ import SysClassification from "./components/SysClassification.vue";
import
DeviceClassification
from
"./components/DeviceClassification.vue"
;
import
EquipmentAlarm
from
"./components/EquipmentAlarm.vue"
;
import
Alert7Days
from
"./components/Alert7Days.vue"
;
import
MapEcharts
from
"./components/Map
Echarts
.vue"
;
import
MapEcharts
from
"./components/Map
1
.vue"
;
import
DeployProject
from
"./components/DeployProject.vue"
;
import
SubsidiaryCompanyEquipment
from
"./components/SubsidiaryCompanyEquipment.vue"
;
import
ContainerWrap
from
"@/components/ContainerWrap/index.vue"
;
...
...
@@ -134,8 +134,10 @@ import ContainerWrap from "@/components/ContainerWrap/index.vue";
import
{
ref
,
onMounted
,
onUnmounted
}
from
"vue"
;
import
{
eventBus
}
from
"@/eventBus"
;
import
{
nowTime
}
from
"@/api/iot/home"
;
const
nowTimes
=
ref
(
""
);
const
dialogVisible
=
ref
(
false
);
const
selectedOffice
=
ref
([]);
const
selectedOffice
=
ref
([
100
]);
const
officeTree
=
ref
([
{
value
:
"1"
,
...
...
@@ -251,12 +253,26 @@ onMounted(() => {
});
// 监听机构变化事件
eventBus
.
on
(
"officeChange"
,
(
office
)
=>
{});
eventBus
.
on
(
"officeChange"
,
(
office
)
=>
{
selectedOffice
.
value
=
office
;
});
});
onUnmounted
(()
=>
{
eventBus
.
off
(
"sceneChange"
);
// 避免内存泄漏
});
//获取截止时间
function
getNowTime
()
{
nowTime
().
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
//将res.data时间戳转换为时间格式
nowTimes
.
value
=
new
Date
(
res
.
data
).
toLocaleString
();
}
});
}
getNowTime
();
</
script
>
<
style
scoped
>
...
...
src/views/components/Alert7Days.vue
View file @
568600c8
...
...
@@ -6,21 +6,70 @@
<
script
setup
lang=
"ts"
>
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
"vue"
;
import
*
as
echarts
from
"echarts"
;
import
{
countByDay
}
from
"@/api/iot/home"
;
import
{
de
}
from
"element-plus/es/locales.mjs"
;
const
chartRef
=
ref
<
HTMLDivElement
>
();
const
chartContainer
=
ref
<
HTMLDivElement
>
();
const
chartInstance
=
ref
<
echarts
.
ECharts
|
null
>
(
null
);
let
resizeObserver
:
ResizeObserver
|
null
=
null
;
const
yData
=
ref
([
2
,
1
,
1
,
1
,
3
,
2
,
2
]);
const
wData
=
ref
([
0
,
0
,
0
,
1
,
1
,
1
,
0
]);
const
xData
=
ref
<
any
[]
>
([
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
{
time
:
""
,
timestamp
:
0
,
haveHandle
:
0
,
//已处理
notHandle
:
0
,
//未处理
haveIgnore
:
0
,
//已忽略
},
]);
const
initChart
=
()
=>
{
if
(
!
chartRef
.
value
)
return
;
// 销毁旧实例
chartInstance
.
value
?.
dispose
();
chartInstance
.
value
=
echarts
.
init
(
chartRef
.
value
);
const
option
=
{
...
...
@@ -31,7 +80,7 @@ const initChart = () => {
},
},
legend
:
{
data
:
[
"已处理"
,
"未处理"
],
data
:
[
"已处理"
,
"未处理"
,
"已忽略"
],
top
:
0
,
right
:
7
,
itemWidth
:
15
,
...
...
@@ -42,18 +91,11 @@ const initChart = () => {
},
},
xAxis
:
{
data
:
[
"2025-10-13"
,
"2025-10-14"
,
"2025-10-15"
,
"2025-10-16"
,
"2025-10-17"
,
"2025-10-18"
,
"2025-10-19"
,
],
data
:
xData
.
value
.
map
((
item
)
=>
item
.
time
.
substring
(
0
,
10
)),
axisLabel
:
{
color
:
"#66FFFF"
,
fontSize
:
11
,
rotate
:
15
,
},
},
yAxis
:
{
...
...
@@ -73,7 +115,7 @@ const initChart = () => {
{
name
:
"已处理"
,
type
:
"bar"
,
barWidth
:
1
6
,
barWidth
:
1
3
,
label
:
{
show
:
true
,
position
:
"top"
,
...
...
@@ -88,14 +130,14 @@ const initChart = () => {
{
offset
:
1
,
color
:
"rgba(146, 225, 255, 1)"
},
]),
},
data
:
yData
.
value
,
data
:
xData
.
value
.
map
((
item
)
=>
item
.
haveHandle
)
,
z
:
10
,
zlevel
:
0
,
},
{
name
:
"未处理"
,
type
:
"bar"
,
barWidth
:
1
6
,
barWidth
:
1
3
,
label
:
{
show
:
true
,
position
:
"top"
,
...
...
@@ -110,7 +152,31 @@ const initChart = () => {
{
offset
:
1
,
color
:
"rgba(250, 76, 102, 1)"
},
]),
},
data
:
wData
.
value
,
data
:
xData
.
value
.
map
((
item
)
=>
item
.
notHandle
),
z
:
10
,
zlevel
:
0
,
},
{
name
:
"已忽略"
,
type
:
"bar"
,
barWidth
:
13
,
label
:
{
show
:
true
,
position
:
"top"
,
textStyle
:
{
color
:
"#fff"
,
fontSize
:
10
,
},
},
itemStyle
:
{
color
:
new
echarts
.
graphic
.
LinearGradient
(
0
,
0
,
0
,
1
,
[
// 已忽略灰色
// 已忽略灰色
{
offset
:
1
,
color
:
"rgba(128, 128, 128, 1)"
},
{
offset
:
0
,
color
:
"rgba(255, 255, 255, 1)"
},
]),
},
data
:
xData
.
value
.
map
((
item
)
=>
item
.
haveIgnore
),
z
:
10
,
zlevel
:
0
,
},
...
...
@@ -124,10 +190,10 @@ const initChart = () => {
symbolMargin
:
2
,
symbol
:
"rect"
,
symbolClip
:
true
,
symbolSize
:
[
1
8
,
2
],
symbolSize
:
[
1
4
,
2
],
symbolPosition
:
"start"
,
symbolOffset
:
[
-
9
,
1
],
data
:
yData
.
value
,
symbolOffset
:
[
-
14
,
1
],
data
:
xData
.
value
.
map
((
item
)
=>
item
.
haveHandle
)
,
width
:
2
,
z
:
0
,
zlevel
:
1
,
...
...
@@ -142,20 +208,38 @@ const initChart = () => {
symbolMargin
:
2
,
symbol
:
"rect"
,
symbolClip
:
true
,
symbolSize
:
[
1
8
,
2
],
symbolSize
:
[
1
3
,
2
],
symbolPosition
:
"start"
,
symbolOffset
:
[
9
,
1
],
data
:
wData
.
value
,
symbolOffset
:
[
0
,
1
],
data
:
xData
.
value
.
map
((
item
)
=>
item
.
notHandle
),
width
:
2
,
z
:
0
,
zlevel
:
1
,
},
{
// 已忽略分隔
type
:
"pictorialBar"
,
itemStyle
:
{
color
:
"#0F375F"
,
},
symbolRepeat
:
"fixed"
,
symbolMargin
:
2
,
symbol
:
"rect"
,
symbolClip
:
true
,
symbolSize
:
[
14
,
2
],
symbolPosition
:
"start"
,
symbolOffset
:
[
14
,
1
],
data
:
xData
.
value
.
map
((
item
)
=>
item
.
haveIgnore
),
width
:
2
,
z
:
0
,
zlevel
:
1
,
},
],
color
:
[
"#4C9FFF"
,
"#FF6E76"
],
color
:
[
"#4C9FFF"
,
"#FF6E76"
,
"#FF0000"
],
barWidth
:
"20%"
,
grid
:
{
left
:
"
4
%"
,
right
:
"
5
%"
,
left
:
"
7
%"
,
right
:
"
3
%"
,
bottom
:
"5%"
,
top
:
"20%"
,
containLabel
:
true
,
...
...
@@ -176,7 +260,69 @@ onMounted(() => {
chartContainer
.
value
.
style
.
height
=
"100%"
;
}
initChart
();
// 构建请求参数 beginTime(年月日时分秒)7天前 endTime(年月日时分秒)今天
const
data
=
{
beginTime
:
new
Date
(
new
Date
().
getTime
()
-
7
*
24
*
60
*
60
*
1000
)
.
toISOString
()
.
substring
(
0
,
10
)
+
" 00:00:00"
,
endTime
:
new
Date
().
toISOString
().
substring
(
0
,
10
)
+
" 23:59:59"
,
};
// 获取近7天告警统计
countByDay
(
data
).
then
((
res
)
=>
{
const
haveHandle
=
res
.
data
.
haveHandle
;
//已处理
const
notHandle
=
res
.
data
.
notHandle
;
//未处理
const
haveIgnore
=
res
.
data
.
haveIgnore
;
//已忽略
// 将近7天的日期添加到xData.time中,格式为yyyy-MM-dd 00:00:00
xData
.
value
.
forEach
((
item
,
index
)
=>
{
item
.
time
=
`
${
new
Date
(
new
Date
().
getTime
()
-
(
6
-
index
)
*
24
*
60
*
60
*
1000
).
getFullYear
()}
-
${
new
Date
(
new
Date
().
getTime
()
-
(
6
-
index
)
*
24
*
60
*
60
*
1000
).
getMonth
()
+
1
}
-
${
new
Date
(
new
Date
().
getTime
()
-
(
6
-
index
)
*
24
*
60
*
60
*
1000
).
getDate
()}
00:00:00`
;
});
// 将近7天的时间戳添加到xData.timestamp中
xData
.
value
.
forEach
((
item
,
index
)
=>
{
item
.
timestamp
=
new
Date
(
item
.
time
).
getTime
();
});
if
(
haveHandle
)
{
//将haveHandle的 key 和 xData.timestamp 进行匹配,将对应的值添加到xData.haveHandle中
for
(
let
key
in
haveHandle
)
{
for
(
let
item
of
xData
.
value
)
{
if
(
item
.
timestamp
===
Number
(
key
))
{
item
.
haveHandle
=
haveHandle
[
key
];
}
}
}
}
if
(
notHandle
)
{
//将notHandle的 key 和 xData.timestamp 进行匹配,将对应的值添加到xData.notHandle中
for
(
let
key
in
notHandle
)
{
for
(
let
item
of
xData
.
value
)
{
if
(
item
.
timestamp
===
Number
(
key
))
{
item
.
notHandle
=
notHandle
[
key
];
}
}
}
}
if
(
haveIgnore
)
{
//将haveIgnore的 key 和 xData.timestamp 进行匹配,将对应的值添加到xData.haveIgnore中
for
(
let
key
in
haveIgnore
)
{
for
(
let
item
of
xData
.
value
)
{
if
(
item
.
timestamp
===
Number
(
key
))
{
item
.
haveIgnore
=
haveIgnore
[
key
];
}
}
}
}
initChart
();
});
// 使用 ResizeObserver 监听容器尺寸变化
if
(
chartRef
.
value
)
{
...
...
src/views/components/DeployProject.vue
View file @
568600c8
...
...
@@ -8,7 +8,7 @@
class=
"flex flex-1 w-full h-full"
>
<div
class=
"flex flex-col justify-center"
>
<
img
:src=
"item.imageUrl"
width=
"90px"
/
>
<
!--
<img
:src=
"item.imageUrl"
width=
"90px"
/>
--
>
<div
class=
"bg-container flex flex-col items-center"
>
<div
class=
"text-[#66FFFF] text-[14px]"
>
{{
item
.
name
}}
...
...
@@ -29,28 +29,68 @@ import sysBg1 from "@/assets/imgs/sys-bg1.png";
import
sysBg2
from
"@/assets/imgs/sys-bg2.png"
;
import
sysBg3
from
"@/assets/imgs/sys-bg3.png"
;
import
sysBg4
from
"@/assets/imgs/sys-bg4.png"
;
import
{
countBySysType
}
from
"@/api/iot/home"
;
const
props
=
defineProps
({
deptId
:
{
type
:
Number
,
default
:
0
,
},
});
const
projectList
=
ref
([
{
type
:
1
,
name
:
"智慧隧道"
,
imageUrl
:
sysBg1
,
num
:
"3"
,
num
:
0
,
},
{
type
:
2
,
name
:
"幸福小镇"
,
imageUrl
:
sysBg2
,
num
:
"2"
,
num
:
0
,
},
{
type
:
3
,
name
:
"智慧园区"
,
imageUrl
:
sysBg3
,
num
:
0
,
},
{
type
:
4
,
name
:
"拌合站"
,
imageUrl
:
sysBg3
,
num
:
0
,
},
{
type
:
5
,
name
:
"视频监控"
,
imageUrl
:
sysBg3
,
num
:
"5"
,
num
:
0
,
},
{
name
:
"智慧园区"
,
type
:
6
,
name
:
"钢筋场"
,
imageUrl
:
sysBg4
,
num
:
"7"
,
num
:
0
,
},
]);
function
getCountBySysType
()
{
countBySysType
(
props
.
deptId
).
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
res
.
data
.
map
((
item
:
any
)
=>
{
projectList
.
value
.
map
((
i
:
any
)
=>
{
if
(
i
.
type
===
item
.
type
)
{
i
.
num
=
item
.
count
||
0
;
}
});
});
}
});
}
getCountBySysType
();
</
script
>
<
style
scoped
lang=
"scss"
>
.bg-container
{
...
...
src/views/components/DeviceClassification.vue
View file @
568600c8
...
...
@@ -7,11 +7,22 @@
<
script
setup
lang=
"ts"
>
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
"vue"
;
import
*
as
echarts
from
"echarts"
;
import
{
deviceCountByType
}
from
"@/api/iot/home"
;
const
chartContainer
=
ref
<
HTMLElement
|
null
>
(
null
);
const
chartInstance
=
ref
<
echarts
.
ECharts
|
null
>
(
null
);
let
resizeObserver
:
ResizeObserver
|
null
=
null
;
const
props
=
defineProps
({
deptId
:
{
type
:
Number
,
default
:
0
,
},
});
const
datas
=
ref
([]);
const
totalCount
=
ref
(
0
);
const
initChart
=
()
=>
{
if
(
!
chartContainer
.
value
)
return
;
// 销毁旧实例
...
...
@@ -19,16 +30,6 @@ const initChart = () => {
// 初始化图表
chartInstance
.
value
=
echarts
.
init
(
chartContainer
.
value
);
const
datas
=
[
{
value
:
1048
,
name
:
"视频监控"
},
{
value
:
735
,
name
:
"人车识别"
},
{
value
:
580
,
name
:
"水电监测"
},
{
value
:
484
,
name
:
"消防监测"
},
{
value
:
300
,
name
:
"人员定位监测"
},
{
value
:
300
,
name
:
"环境气体监测"
},
{
value
:
300
,
name
:
"车辆定位监测"
},
];
const
chartPieColors
=
[
[
{
offset
:
0
,
color
:
"#F5C815"
},
...
...
@@ -64,7 +65,7 @@ const initChart = () => {
],
];
const
seriesData
=
datas
.
map
((
item
,
index
)
=>
({
const
seriesData
=
datas
.
value
.
map
((
item
:
any
,
index
:
number
)
=>
({
value
:
item
.
value
,
name
:
item
.
name
,
itemStyle
:
{
...
...
@@ -115,18 +116,19 @@ const initChart = () => {
right
:
150
,
radius
:
[
"50%"
,
"70%"
],
center
:
[
"53%"
,
"48%"
],
avoidLabelOverlap
:
fals
e
,
avoidLabelOverlap
:
tru
e
,
label
:
{
show
:
false
,
position
:
"outside"
,
formatter
:
"{a|{b}:{d}%}
\
n{hr|}"
,
rich
:
{
hr
:
{
backgroundColor
:
"t"
,
borderRadius
:
3
,
width
:
3
,
height
:
3
,
padding
:
[
3
,
3
,
0
,
-
12
],
width
:
1
,
height
:
1
,
padding
:
[
2
,
1
,
0
,
-
0
],
},
a
:
{
padding
:
[
-
30
,
15
,
-
20
,
15
],
...
...
@@ -161,9 +163,11 @@ const initChart = () => {
label
:
{
show
:
true
,
position
:
"center"
,
formatter
:
"37800"
,
//item.value的设备总数
formatter
:
""
+
totalCount
.
value
,
// formatter: "",
color
:
"#FEBC22"
,
fontSize
:
2
3
,
fontSize
:
2
2
,
fontWeight
:
"bold"
,
fontFamily
:
"Arial"
,
},
...
...
@@ -178,7 +182,6 @@ const initChart = () => {
},
],
};
chartInstance
.
value
.
setOption
(
option
);
};
...
...
@@ -187,7 +190,21 @@ const handleResize = () => {
};
onMounted
(()
=>
{
initChart
();
deviceCountByType
(
props
.
deptId
,
"1"
).
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
//将res.dcbt中的数据赋值给datas.value
datas
.
value
=
res
.
dcbt
.
map
((
item
:
any
)
=>
({
value
:
item
.
count
,
name
:
item
.
deviceType
.
name
,
}));
// 计算总设备数量
totalCount
.
value
=
res
.
dcbt
.
reduce
(
(
acc
:
number
,
item
:
any
)
=>
acc
+
item
.
count
,
0
);
initChart
();
}
});
// 使用 ResizeObserver 监听容器大小变化
if
(
chartContainer
.
value
)
{
...
...
src/views/components/DeviceNumber.vue
View file @
568600c8
...
...
@@ -4,7 +4,7 @@
<!-- 数量 -->
<div
class=
"gap-2 flex"
>
<div
v-for=
"(digit, index) in
digitsNumber
"
v-for=
"(digit, index) in
sumCount
"
:key=
"index"
class=
"card-container flex-1"
>
...
...
@@ -40,7 +40,7 @@
在线数量
<text
class=
"text-[#66FFFF] xl:text-[14px] 2xl:text-[18px] pl-1 font-[YouSheBiaoTiHei]"
>
{{
on
lineNumber
}}
</text
>
{{
on
LineCount
}}
</text
>
</div>
...
...
@@ -51,7 +51,7 @@
>
<text
class=
"text-[#F01111] xl:text-[14px] 2xl:text-[18px] pr-1 font-[YouSheBiaoTiHei]"
>
{{
offlineNumber
}}
</text
>
{{
noLineCount
}}
</text
>
离线数量
</div>
...
...
@@ -61,27 +61,51 @@
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
"vue"
;
import
{
computed
}
from
"vue"
;
import
{
allDevice
}
from
"@/api/iot/home"
;
var
originalNumber
=
ref
(
"1610"
);
//将数字转换为字符串并补零到9位,并将其拆分为单个数字数组
var
digitsNumber
=
originalNumber
.
value
.
padStart
(
9
,
"0"
).
split
(
""
);
const
props
=
defineProps
({
deptId
:
{
type
:
Number
,
default
:
0
,
},
});
// 设备接入数量(在线、离线)
var
sumCount
=
ref
([]);
//在线数量
var
on
lineNumber
=
ref
(
150
0
);
var
on
LineCount
=
ref
(
0
);
//离线数量
var
offlineNumber
=
ref
(
11
0
);
var
noLineCount
=
ref
(
0
);
//计算在线和离线百分比
const
totalDevices
=
computed
(()
=>
on
lineNumber
.
value
+
offlineNumber
.
value
);
const
totalDevices
=
computed
(()
=>
on
LineCount
.
value
+
noLineCount
.
value
);
const
onlinePercent
=
computed
(()
=>
{
return
totalDevices
.
value
>
0
?
Math
.
round
((
on
lineNumber
.
value
/
totalDevices
.
value
)
*
100
)
?
Math
.
round
((
on
LineCount
.
value
/
totalDevices
.
value
)
*
100
)
:
0
;
});
const
offlinePercent
=
computed
(()
=>
{
return
totalDevices
.
value
>
0
?
Math
.
round
((
offlineNumber
.
value
/
totalDevices
.
value
)
*
100
)
?
Math
.
round
((
noLineCount
.
value
/
totalDevices
.
value
)
*
100
)
:
0
;
});
// 获取设备接入数量(在线、离线)
function
getAllDevice
()
{
allDevice
(
props
.
deptId
).
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
// 将数字转换为字符串并补零到9位,并将其拆分为单个数字数组
sumCount
.
value
=
(
res
.
numMap
?.
sumCount
?.
toString
()
||
"0"
)
.
padStart
(
9
,
"0"
)
.
split
(
""
);
// 在线数量
onLineCount
.
value
=
res
.
numMap
?.
onLineCount
||
0
;
// 离线数量
noLineCount
.
value
=
res
.
numMap
?.
noLineCount
||
0
;
}
});
}
getAllDevice
();
</
script
>
<
style
scoped
lang=
"scss"
>
...
...
src/views/components/EquipmentAlarm.vue
View file @
568600c8
...
...
@@ -5,7 +5,7 @@
<div
class=
"text-center font-bold text-[34px] text-[#66FFFF] font-[YouSheBiaoTiHei]"
>
10
{{
alarmTotal
}}
</div>
<div
class=
"text-center text-[12px] text-[#66FFFF] mt-0"
>
告警总数
</div>
</div>
...
...
@@ -16,7 +16,7 @@
<div
class=
"font-medium text-[28px] text-[#66FFFF] font-[YouSheBiaoTiHei]"
>
0
{{
unprocessedCount
}}
</div>
<img
src=
"@/assets/imgs/equ-right-icon.png"
...
...
@@ -31,7 +31,7 @@
<div
class=
"font-medium text-[28px] text-[#66FFFF] font-[YouSheBiaoTiHei]"
>
8
{{
processedCount
}}
</div>
<img
src=
"@/assets/imgs/equ-right-icon.png"
...
...
@@ -40,12 +40,57 @@
/>
<div
class=
"text-[12px] text-white mt-1"
>
已处理
</div>
</div>
<!-- 已处理统计 -->
<div
class=
"flex flex-col items-center"
>
<div
class=
"font-medium text-[28px] text-[#66FFFF] font-[YouSheBiaoTiHei]"
>
{{
processedCount
}}
</div>
<img
src=
"@/assets/imgs/equ-right-icon.png"
class=
"w-[45px] h-[50px] my-1"
alt=
"已处理图标"
/>
<div
class=
"text-[12px] text-white mt-1"
>
已忽略
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
// 可以保留空的script setup,或者移除如果不需要
import
{
alarmNumCount
}
from
"@/api/iot/home"
;
import
{
onMounted
,
ref
}
from
"vue"
;
// 告警总数
let
alarmTotal
=
ref
(
0
);
// 未处理统计
let
unprocessedCount
=
ref
(
0
);
// 已处理统计
let
processedCount
=
ref
(
0
);
// 已忽略统计
let
ignoredCount
=
ref
(
0
);
const
props
=
defineProps
({
deptId
:
{
type
:
Number
,
default
:
0
,
},
});
// 获取设备告警统计
function
getAlarmNumCount
()
{
alarmNumCount
(
props
.
deptId
).
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
alarmTotal
.
value
=
res
.
data
.
count
;
unprocessedCount
.
value
=
res
.
data
.
notHandle
;
processedCount
.
value
=
res
.
data
.
haveHandle
;
ignoredCount
.
value
=
res
.
data
.
haveIgnore
;
}
});
}
getAlarmNumCount
();
</
script
>
<
style
scoped
lang=
"scss"
>
...
...
src/views/components/Map1.vue
0 → 100644
View file @
568600c8
<
template
>
<div
id=
"map-container"
ref=
"mapContainer"
class=
"w-full h-full"
></div>
</
template
>
<
script
>
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
"vue"
;
onMounted
(()
=>
{
initMap
();
});
function
initMap
()
{
//创建地图对象
this
.
map
=
new
AMap
.
Map
(
"map"
,
{
center
:
[
113.280637
,
23.125178
],
resizeEnable
:
true
,
zoom
:
7
,
});
//获取边界坐标点
AMap
.
plugin
(
"AMap.DistrictSearch"
,
()
=>
{
var
districtSearch
=
new
AMap
.
DistrictSearch
({
// 关键字对应的行政区级别,共有5种级别
level
:
"province"
,
// 是否显示下级行政区级数,1表示返回下一级行政区
subdistrict
:
0
,
// 返回行政区边界坐标点
extensions
:
"all"
,
});
// 搜索所有省/直辖市信息
districtSearch
.
search
(
"广东"
,
(
status
,
result
)
=>
{
// 查询成功时,result即为对应的行政区信息
this
.
handlePolygon
(
result
);
});
});
}
// function handlePolygon(result) {
// let bounds = result.districtList[0].boundaries
// if (bounds) {
// for (let i = 0, l = bounds.length; i
<
l
;
i
++
)
{
// //生成行政区划polygon
// let polygon = new AMap.Polygon({
// map: this.map, // 指定地图对象
// strokeWeight: 1, // 轮廓线宽度
// path: bounds[i], //轮廓线的节点坐标数组
// fillOpacity: 0.15, //透明度
// fillColor: '#256edc', //填充颜色
// strokeColor: '#256edc', //线条颜色
// })
// polygon.on('click', (e) => {
// // 点击绘制的区域时执行其他交互
// // ......
// })
// }
// // 地图自适应
// this.map.setFitView()
// }
</
script
>
<
style
scoped
></
style
>
src/views/components/SubsidiaryCompanyEquipment.vue
View file @
568600c8
...
...
@@ -7,13 +7,21 @@
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
"vue"
;
import
*
as
echarts
from
"echarts"
;
import
{
debounce
}
from
"lodash-es"
;
// 或使用自定义防抖函数
import
{
deviceCountByChild
}
from
"@/api/iot/home"
;
import
{
de
}
from
"element-plus/es/locales.mjs"
;
const
chartRef
=
ref
<
HTMLDivElement
>
();
const
chart
=
ref
<
echarts
.
ECharts
|
null
>
(
null
);
let
resizeObserver
:
ResizeObserver
|
null
=
null
;
const
yData
=
ref
<
any
[]
>
([]);
const
xData
=
ref
<
any
[]
>
([]);
const
yData
=
ref
([
120
,
200
,
150
,
190
,
170
,
110
,
130
,
130
,
130
,
130
,
130
]);
const
props
=
defineProps
({
deptId
:
{
type
:
Number
,
default
:
0
,
},
});
// 防抖的重绘函数
const
handleResize
=
debounce
(()
=>
{
chart
.
value
?.
resize
();
...
...
@@ -22,12 +30,9 @@ const handleResize = debounce(() => {
// 初始化图表
const
initChart
=
()
=>
{
if
(
!
chartRef
.
value
)
return
;
// 如果已有图表实例,先销毁
chart
.
value
?.
dispose
();
chart
.
value
=
echarts
.
init
(
chartRef
.
value
);
const
option
=
{
tooltip
:
{
trigger
:
"axis"
,
...
...
@@ -39,19 +44,7 @@ const initChart = () => {
show
:
false
,
},
xAxis
:
{
data
:
[
"路桥一公司"
,
"路桥二公司"
,
"路桥三公司"
,
"路桥四公司"
,
"路桥五公司"
,
"路桥七公司"
,
"路桥八公司"
,
"路桥九公司"
,
"浙江分公司"
,
"市政公司"
,
"特种分公司"
,
],
data
:
xData
.
value
,
axisLabel
:
{
color
:
"#66FFFF"
,
fontSize
:
11
,
...
...
@@ -108,8 +101,24 @@ const initChart = () => {
};
onMounted
(()
=>
{
initChart
();
deviceCountByChild
(
props
.
deptId
).
then
((
res
:
any
)
=>
{
if
(
res
.
code
===
200
)
{
const
childDeptList
=
res
.
result
?.
childDeptList
||
[];
const
numMap
=
res
.
result
?.
numMap
||
[];
//numMap中的 key 和childDeptList.deptId 进行匹配
Object
.
entries
(
numMap
).
forEach
(([
key
,
value
])
=>
{
console
.
log
(
`Key:
${
key
}
, Value:
${
value
}
`
);
yData
.
value
.
push
(
value
);
// 匹配到后,将对应的部门名称添加到 xData 中
for
(
let
i
=
0
;
i
<
childDeptList
.
length
;
i
++
)
{
if
(
childDeptList
[
i
].
deptId
===
Number
(
key
))
{
xData
.
value
.
push
(
childDeptList
[
i
].
deptName
);
}
}
});
initChart
();
}
});
// 使用 ResizeObserver 监听容器尺寸变化
if
(
chartRef
.
value
)
{
resizeObserver
=
new
ResizeObserver
(()
=>
{
...
...
@@ -117,7 +126,6 @@ onMounted(() => {
});
resizeObserver
.
observe
(
chartRef
.
value
);
}
// 仍然监听窗口大小变化作为后备
window
.
addEventListener
(
"resize"
,
handleResize
);
});
...
...
@@ -128,7 +136,6 @@ onBeforeUnmount(() => {
resizeObserver
.
disconnect
();
resizeObserver
=
null
;
}
window
.
removeEventListener
(
"resize"
,
handleResize
);
chart
.
value
?.
dispose
();
chart
.
value
=
null
;
...
...
src/views/login.vue
View file @
568600c8
<
template
>
<div
class=
"login flex-col pb-10"
>
<h3
class=
"text-
5xl font-bold text-center mb-15
"
>
<h3
class=
"text-
6xl font-bold text-center mb-15 text-[#fff]
"
>
{{
AppSetting
.
projectName
}}
</h3>
...
...
@@ -81,7 +81,10 @@
</el-form>
<!-- 底部 -->
<div
class=
"el-login-footer"
>
<span>
Copyright © 2018-2024 ruoyi.vip All Rights Reserved.
</span>
<span
>
Copyright © 2025 {{ AppSetting.projectName }} All Rights
Reserved.
</span
>
</div>
</div>
</template>
...
...
@@ -267,23 +270,22 @@ getCookie();
//
display
:
flex
;
//
//
--font-size
:
14px
;
//
margin-bottom
:
13px
;
//
}
:deep
(
.el-input
.el-input__inner
)
{
color
:
#fff
;
//
background
:
yellow
!important
;
//
border
:
0px
solid
rgba
(
255
,
255
,
255
,
0.3
);
}
:deep
(
.el-input--large
.el-input__wrapper
)
{
//
padding
:
1px
15px
;
background-color
:
#163054
;
//
box-shadow
:
0
0
0
1px
#2261ba
inset
!important
;
/* 可选:修改边框颜色 */
box-shadow
:
0px
2px
4px
rgba
(
79
,
151
,
214
,
0.33
);
//
border
:
0px
solid
rgba
(
255
,
255
,
255
,
0.3
);
}
//
:deep
(
.el-input
.el-input__inner
)
{
//
color
:
#fff
;
//
background-color
:
#163054
;
//
border
:
0px
solid
rgba
(
255
,
255
,
255
,
0.3
);
//
}
//
:deep
(
.el-input--large
.el-input__wrapper
)
{
//
//
padding
:
1px
15px
;
//
background-color
:
#163054
;
//
//
box-shadow
:
0
0
0
1px
#2261ba
inset
!important
;
/* 可选:修改边框颜色 */
//
box-shadow
:
0px
2px
4px
rgba
(
79
,
151
,
214
,
0.33
);
//
//
border
:
0px
solid
rgba
(
255
,
255
,
255
,
0.3
);
//
}
:deep
(
.el-input__inner
)
{
//
background-color
:
rgba
(
22
,
48
,
84
,
0.6
);
}
//
:deep
(
.el-input__inner
)
{
//
background-color
:
rgba
(
22
,
48
,
84
,
0.6
);
//
}
</
style
>
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