public/favicon.icosrc/assets/images/air-condit.png
src/assets/images/earth-light-circle.png
src/assets/images/earth.png
src/assets/style/basic.css
@@ -1,18 +1,42 @@ * { box-sizing: border-box; } /*basic end*/ ::-webkit-scrollbar { /* 滚动条整体样式 */ width: 3px; height: 10px; /* 滚动条整体样式 */ width: 3px; height: 10px; } ::-webkit-scrollbar-thumb { /* 滚动条里面小方块 */ border-radius: 10px; -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); background: #02b0bd; /* 滚动条里面小方块 */ border-radius: 10px; -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); background: #02b0bd; } ::-webkit-scrollbar-track { /* 滚动条里面轨道 */ -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); border-radius: 10px; background: #003d64; /* 滚动条里面轨道 */ -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); border-radius: 10px; background: #003d64; } .flex-layout--container { display: flex; flex-direction: column; box-sizing: border-box; height: 100%; } .flex-layout--container.row { flex-direction: row; } .flex-layout--body { flex: 1; } .center--container { display: flex; height: 100%; box-sizing: border-box; flex-direction: row; justify-content: center; align-items: center; } src/components/FlexBox.vue
New file @@ -0,0 +1,106 @@ <script setup> import {computed} from "vue"; const props = defineProps({ type: { type: String, default: "", }, title: { type: String, default: "", }, noHeader: { type: Boolean, default: false, }, noHeaderBg: { type: Boolean, default: false, }, size: { type: String, default: "", }, }); const sizeClass = computed(()=>{ let size = props.size; let result = ""; switch (size) { case "mini": result = "flex-box-mini"; break; } return result; }); </script> <template> <div class="flex-box"> <div class="flex-box-border border-top-left"></div> <div class="flex-box-border border-top-right"></div> <div class="flex-box-border border-bottom-left"></div> <div class="flex-box-border border-bottom-right"></div> <div class="flex-box-header" v-if="!noHeader"> <slot name="header"></slot> </div> <div class="flex-box-body"> <slot></slot> </div> <div class="flex-box-footer"> <slot name="footer"></slot> </div> </div> </template> <style lang="less" scoped> @border-color: #00feff; @size: 32px; .flex-box { position: relative; display: flex; flex-direction: column; height: 100%; background-image: radial-gradient(#151f4140, #3667ec40); >.flex-box-border { position: absolute; z-index: 9; width: 20px; height: 20px; box-sizing: border-box; &.border-top-left { top: 0; left: 0; border-top: 2px solid @border-color; border-left: 2px solid @border-color; } &.border-top-right { top: 0; right: 0; border-top: 2px solid @border-color; border-right: 2px solid @border-color; } &.border-bottom-left { bottom: 0; left: 0; border-bottom: 2px solid @border-color; border-left: 2px solid @border-color; } &.border-bottom-right { bottom: 0; right: 0; border-bottom: 2px solid @border-color; border-right: 2px solid @border-color; } } >.flex-box-body { flex: 1; } } </style> src/components/HdwLight.vue
New file @@ -0,0 +1,84 @@ <script setup> import {computed} from "vue"; const props = defineProps({ type: { type: [Number, String], default: 0, } }); const lightState = computed(()=>{ let state = ""; let type = props.type > 1 ? 1 : props.type; switch (type) { case 1: state = "error-light"; break; case -1: state = "gray-light"; break; default: state = ""; break; } return state; }); </script> <template> <div class="hdw-light" :class="lightState"></div> </template> <style lang="less" scoped> /* light */ .hdw-light { position: relative; display: inline-block; width: 22px; height: 22px; vertical-align: middle; } .hdw-light:before { content: ""; display: inline-block; position: absolute; top: 50%; left: 50%; margin-top: -5px; margin-left: -5px; width: 10px; height: 10px; border-radius: 10px; background-color: #4afd88; box-shadow: 0 0 6px 6px #4afd8880; } .hdw-light.error-light:before { background-color: #fd5b67; animation: errorLight 1000ms infinite; box-shadow: 0 0 6px 6px #fd586480; } .hdw-light.gray-light:before { background-color: #878787; width: 12px; height: 12px; box-shadow: none; } @keyframes errorLight { 0% { opacity: 1; box-shadow: 0 0 6px 6px #fd586480; } 50% { opacity: 0.3; box-shadow: 0 0 0 0 #fd586480; } 100% { opacity: 1; box-shadow: 0 0 6px 6px #fd586480; } } </style> src/components/MapPin.vue
@@ -2,6 +2,10 @@ import {computed, onMounted} from "vue"; const props = defineProps({ visible: { type: Boolean, default: false, }, name: { type: String, default: "" @@ -42,7 +46,7 @@ <template> <div class="map-pin" :style="posStyle"> <el-tooltip placement="top"> <el-tooltip placement="top" :visible="visible"> <template #content> {{name}} </template> src/components/TitleIcon.vue
New file @@ -0,0 +1,39 @@ <script setup> </script> <template> <span class="title-icon"> <span class="title-icon-content"></span> </span> </template> <style lang="less" scoped> .title-icon { display: inline-block; width: 30px; height: 30px; } .title-icon:before, .title-icon:after, .title-icon-content { display: inline-block; content: ""; width: 4px; vertical-align: middle; } .title-icon:before { height: 14px; background-color: #0f448d; } .title-icon-content { margin-left: 4px; height: 18px; background-color: #1e77b8; } .title-icon:after { margin-left: 4px; height: 22px; background-color: #2cabe3; } </style> src/router/routes.js
@@ -51,6 +51,11 @@ component: ()=>import('../views/assetManagement/videoAsset.vue'), }, { path: "asset/homeModule", name: "homeModule", component: ()=>import('../views/assetManagement/homeModule.vue'), }, { path: '/:pathMatch(.*)*', name: "", component: () => import('../views/404.vue') src/views/airConditioning/airConditioning.vue
@@ -1,11 +1,414 @@ <script setup> import FlexBox from "@/components/FlexBox.vue"; import {DArrowRight, CaretTop} from "@element-plus/icons-vue"; import HdwLight from "@/components/HdwLight.vue"; import {reactive} from "vue"; const runMonitorData = reactive([ { label: "压缩机运行时间", value: 0, unit: "H" }, { label: "加热需求", value: 0, unit: "%" }, { label: "制冷需求", value: 0, unit: "%" }, { label: "除湿需求", value: 0, unit: "%" }, { label: "回风温度", value: 0, unit: "℃" }, { label: "回风湿度", value: 0, unit: "%" }, ]); </script> <template> <div>空调</div> <div class="flex-layout--container row"> <div class="page-left"> <div class="flex-layout--container"> <div class="air-state"> <flex-box> <template #header> <div class="header-wrapper"> <el-icon><DArrowRight /></el-icon> <span class="title-text">状态指示</span> </div> </template> <div class="state-list"> <div class="state-item"> <div class="state-text">正常状态</div> <div class="light-container"> <hdw-light :type="0"></hdw-light> </div> </div> <div class="state-item"> <div class="state-text">异常状态</div> <div class="light-container"> <hdw-light :type="1"></hdw-light> </div> </div> <div class="state-item"> <div class="state-text">关闭状态</div> <div class="light-container"> <hdw-light :type="-1"></hdw-light> </div> </div> </div> </flex-box> </div> <div class="flex-layout--body"> <div class="run-data"> <flex-box> <template #header> <div class="header-wrapper"> <el-icon><DArrowRight /></el-icon> <span class="title-text">空调运行监控</span> </div> </template> <div class="flex-layout--container"> <div class="flex-layout--body"> <div class="input-list"> <div class="input-item" v-for="(item, index) in runMonitorData" :key="'key'+index"> <div class="input-box input-text">{{ item.label }}</div> <div class="input-box input-content">{{ item.value }}</div> <div class="input-box input-unit">{{ item.unit }}</div> </div> </div> </div> <div class="flex-layout--body"> <div class="input-box-list"> <div class="input-box-wrapper"> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> </div> <div class="input-box-wrapper"> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> </div> <div class="input-box-wrapper"> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> <div class="input-box-container"> <div class="input-text">加热器运行状态</div> <div class="input-light"> <hdw-light :type="0"></hdw-light> </div> </div> </div> </div> </div> </div> </flex-box> </div> </div> </div> </div> <div class="flex-layout--body"> <div class="move-img"> <flex-box> <template #header> <div class="header-wrapper"> <el-icon><DArrowRight /></el-icon> <span class="title-text">空调监控</span> </div> </template> <div class="center--container"> <div class="earth-wrapper"> <div class="earth-light-circle"> <img src="@/assets/images/earth-light-circle.png" alt=""/> </div> <div class="earth-light"> <div class="earth-light-wrapper"> <img src="@/assets/images/earth.png" alt=""/> </div> </div> <div class="earth-light-border"> <div class="earth-light-border-wrapper"> <div class="sanjiao-wrapper sanjiao-top"> <el-icon><CaretTop /></el-icon> </div> <div class="sanjiao-wrapper sanjiao-bottom"> <el-icon><CaretTop /></el-icon> </div> <div class="sanjiao-wrapper sanjiao-left"> <el-icon><CaretTop /></el-icon> </div> <div class="sanjiao-wrapper sanjiao-right"> <el-icon><CaretTop /></el-icon> </div> </div> </div> <div class="air-condit"> <img src="@/assets/images/air-condit.png" /> </div> </div> </div> </flex-box> </div> </div> <div class="page-right"> <div class="flex-layout--container"> <div class="flex-layout--body"> <flex-box> <template #header> <div class="header-wrapper"> <el-icon><DArrowRight /></el-icon> <span class="title-text">空调参数监控</span> </div> </template> </flex-box> </div> <div class="flex-layout--body"> <flex-box> <template #header> <div class="header-wrapper"> <el-icon><DArrowRight /></el-icon> <span class="title-text">空调报警监控</span> </div> </template> </flex-box> </div> </div> </div> </div> </template> <style scoped> <style lang="less" scoped> .header-wrapper { color: @font-color-high-light; font-weight: bold; font-size: 14px; padding: 8px 16px; box-sizing: border-box; .title-text { margin-left: 4px; } } .page-left, .page-right { box-sizing: border-box; padding: 4px 8px; } .air-state { box-sizing: border-box; padding: 4px 0; } .run-data { box-sizing: border-box; height: 100%; padding: 4px 0; } .move-img { height: 100%; padding: 8px 0; box-sizing: border-box; } .state-list { padding-bottom: 16px; } .state-item { display: inline-block; color: #ffffff; padding: 4px 28px; font-size: 14px; } .light-container { margin-top: 8px; text-align: center; } .earth-wrapper { position: relative; display: inline-block; width: 600px; } .earth-light-circle img, .earth-light img, .air-condit img { width: 100%; height: 100%; -o-object-fit: contain; -webkit-object-fit: contain; object-fit: contain; } .earth-light, .earth-light-border { position: absolute; width: 65%; height: 65%; top: 13%; left: 16%; } .earth-light-border-wrapper { position: relative; width: 100%; height: 100%; animation: rotateAntiClockAnimation 40s linear infinite; } .earth-light-wrapper { position: relative; width: 100%; height: 100%; animation: rotateClockAnimation 40s linear infinite; } .air-condit { position: absolute; width: 50%; height: 50%; top: 21%; left: 23%; } .sanjiao-wrapper { position: absolute; } .sanjiao-wrapper i { font-size: 35px; color: #00fefe; } .sanjiao-wrapper.sanjiao-top, .sanjiao-wrapper.sanjiao-bottom { left: 50%; margin-left: -15px; } .sanjiao-wrapper.sanjiao-top { top: -20px; } .sanjiao-wrapper.sanjiao-top i { transform: rotate(-0deg); } .sanjiao-wrapper.sanjiao-bottom { bottom: -25px; } .sanjiao-wrapper.sanjiao-bottom i { transform: rotate(-180deg); } .sanjiao-wrapper.sanjiao-left, .sanjiao-wrapper.sanjiao-right { top: 50%; margin-left: -15px; } .sanjiao-wrapper.sanjiao-left { left: -10px; } .sanjiao-wrapper.sanjiao-left i { transform: rotate(-90deg); } .sanjiao-wrapper.sanjiao-right { right: -25px; } .sanjiao-wrapper.sanjiao-right i { transform: rotate(-270deg); } @keyframes rotateClockAnimation { from { transform: rotate(0deg); } to { transform: rotate(359deg); } } @keyframes rotateAntiClockAnimation { from { transform: rotate(359deg); } to { transform: rotate(0deg); } } .input-list { .input-item { text-align: center; margin-top: 16px; .input-box { display: inline-block; font-size: 14px; text-align: right; color: #ffffff; &.input-text { min-width: 8rem; } &.input-content { margin-left: 8px; margin-right: 8px; padding: 4px; min-width: 6rem; background-color: #2c5774; border: 1px solid #42d4ff; text-align: center; } } } } .input-box-container { display: inline-block; border: 1px solid #00feff; border-radius: 4px; padding: 4px 8px; margin-left: 8px; margin-right: 8px; background-color: #00253F; .input-text { display: inline-block; text-align: center; color: #00feff; font-size: 14px; vertical-align: middle; margin-right: 8px; } .input-light { display: inline-block; } } .input-box-list { margin-top: 16px; .input-box-wrapper { text-align: center; margin-bottom: 16px; } } </style> src/views/assetManagement/homeModule.vue
New file @@ -0,0 +1,11 @@ <script setup> </script> <template> <div>机房采集模块管理</div> </template> <style scoped> </style> src/views/home/images/home-plus.png
src/views/home/index.vue
@@ -1,11 +1,9 @@ <script setup> import CardBox from "@/components/CardBox.vue"; import {onMounted, onUnmounted, watch} from "vue"; import MapPin from "@/components/MapPin.vue"; import slideMenu from "@/views/mainLayout/js/slideMenu"; import homeContentModule from "@/views/home/js/homeContentModule"; import homeInfoModule from "@/views/home/js/homeInfoModule"; import {Setting} from "@element-plus/icons-vue"; const { isCollapse @@ -19,8 +17,6 @@ } = homeContentModule(); const {homeInfo} = homeInfoModule(); homeInfo[0].hum = 123; watch(isCollapse, ()=>{ setTimeout(()=>{ @@ -45,6 +41,7 @@ <div class="home-content" ref="homeContentDom"> <map-pin v-for="(item, index) in homeInfo" :key="'key'+index" :visible="item.pos.visible" :name="item.name" :c-width="cWidth" :c-height="cHeight" :d-width="dWidth" :d-height="dHeight" @@ -59,7 +56,7 @@ .home-content { position: relative; height: 100%; background-image: url("./images/home.png"); background-image: url("./images/home-plus.png"); background-repeat: no-repeat; background-size: 100% 100%; } src/views/home/js/homeContentModule.js
@@ -7,8 +7,8 @@ const homeContentDom = ref(null); const cWidth = ref(0); const cHeight = ref(0); const dWidth = ref(1279); const dHeight = ref(649); const dWidth = ref(2500); const dHeight = ref(1389); /** * 设置容器的大小 src/views/home/js/homeInfoModule.js
@@ -8,8 +8,9 @@ hum: 7, diffPre: 1, pos: { x: 446, y: 355 visible: true, x: 710, y: 690 } }, { @@ -18,8 +19,9 @@ hum: 7, diffPre: 1, pos: { x: 555, y: 385 visible: true, x: 916, y: 690 } }, { @@ -28,8 +30,9 @@ hum: 7, diffPre: 1, pos: { x: 765, y: 450 visible: true, x: 1212, y: 690 } }, { @@ -38,8 +41,9 @@ hum: 7, diffPre: 1, pos: { x: 910, y: 495 visible: true, x: 1395, y: 690 } }, { @@ -48,8 +52,42 @@ hum: 7, diffPre: 1, pos: { x: 1105, y: 530 visible: true, x: 1576, y: 650 } }, { name: "样品及文库制备室", temp: 32, hum: 7, diffPre: 1, pos: { visible: true, x: 1495, y: 337 } }, { name: "试剂准备室", temp: 32, hum: 7, diffPre: 1, pos: { visible: true, x: 1190, y: 355 } }, { name: "电泳室", temp: 32, hum: 7, diffPre: 1, pos: { visible: true, x: 1009, y: 378 } } ]); src/views/mainLayout/components/SlideMenu.vue
@@ -50,6 +50,10 @@ { title: "视频监控资产管理", path: "/asset/video", }, { title: "机房采集模块管理", path: "/asset/homeModule", } ] }, @@ -71,7 +75,7 @@ <template #header> <div class="sys-logo"> <div class="logo-img"> <img src="@/assets/images/logo.png" alt="" /> <img src="../components/images/logo.png" alt="" /> </div> <div class="sys-name" v-if="isOpen"> 环境监控系统 src/views/mainLayout/components/images/logo.png