Merge pull request 'dev' (#169) from dev into master

Reviewed-on: http://git.feashow.cn/clay/tunnel-cloud-web/pulls/169
This commit is contained in:
odjbin
2023-12-18 15:24:18 +00:00
33 changed files with 2497 additions and 574 deletions

View File

@@ -31,3 +31,6 @@ onMounted(() => {
});
});
</script>
<style>
@import "./assets/fonts/font.css";
</style>

View File

@@ -1,8 +1,37 @@
import request from '@/utils/request.js'
//大屏获取设备信息
export const getLargeScreen = (tunnelId) => {
return request({
url: `/tunnel/large/screen/equipment/${tunnelId}`,
method: 'get'
})
}
//大屏信息接口
export const getLargeScreenInfo = () => {
return request({
url: '/tunnel/large/screen/info',
method: 'get'
})
}
//通过站点id获取隧道信息
export const getTunnelBySiteId = (siteId) => {
return request({
url: `/tunnel/large/screen/tunnel/option/${siteId}`,
method: 'get'
})
}
// 风压echarts数据
export const getEchartsInfo = (equipmentId) => {
return request({
url: `/tunnel/large/screen/echarts/wind/pressure/${equipmentId}`,
method: 'get'
})
}
// 有害气体echarts数据
export const getBadGasEchartsInfo = (tunnelId) => {
return request({
url: `/tunnel/large/screen/echarts/gas/sensor/${tunnelId}`,
method: 'get'
})
}

Binary file not shown.

View File

@@ -0,0 +1,6 @@
@font-face {
font-family: 'MicrosoftYaHei';
src: url('MicrosoftYaHei.ttf');
font-weight: normal;
font-style: normal;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

View File

@@ -6,6 +6,27 @@
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: center;
-moz-user-select: none; /*火狐*/
-webkit-user-select: none; /*webkit浏览器*/
-ms-user-select: none; /*IE10*/
-khtml-user-select: none; /*早期浏览器*/
user-select: none;
font-family: "MicrosoftYaHei", "微软雅黑", "Helvetica Neue", Helvetica, Arial,
sans-serif;
}
body {
background-color: #f5f5f5;
}
.el-container {
height: 100%;
}
.el-aside {
background-color: #ffffff;
height: 100%;
overflow: auto;
}
a {
@@ -13,7 +34,12 @@ a {
color: #333;
}
html, body, #app, .el-container, .el-aside, .el-main {
html,
body,
#app,
.el-container,
.el-aside,
.el-main {
height: 100%;
}
@@ -25,7 +51,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
top: 0;
left: 50%;
margin-left: -859px;
background-image: url('../images/topAndDown/sp_tb.png');
background-image: url("../images/topAndDown/sp_tb.png");
}
.box-top {
@@ -44,7 +70,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
> * {
font-size: 28px;
color: #FFFFFF;
color: #ffffff;
line-height: 37px;
}
@@ -55,7 +81,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
}
.select-active {
color: #11EAF2 !important;
color: #11eaf2 !important;
}
}
}
@@ -66,14 +92,13 @@ html, body, #app, .el-container, .el-aside, .el-main {
top: 50px;
right: 70px;
font-size: 28px;
color: #FFFFFF;
color: #ffffff;
.current-site {
display: flex;
align-items: center;
> span:first-child {
color: #F7B500;
color: #f7b500;
margin-right: 20px;
}
@@ -81,7 +106,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
cursor: pointer;
width: 50px;
height: 50px;
background-image: url('../images/topAndDown/sp_icon_zdqh.png');
background-image: url("../images/topAndDown/sp_icon_zdqh.png");
}
}
@@ -91,7 +116,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
align-items: center;
> span:first-child {
color: #F7B500;
color: #f7b500;
margin-right: 20px;
}
@@ -100,7 +125,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
margin-left: 27px;
width: 50px;
height: 50px;
background-image: url('../images/topAndDown/sp_icon_tcdl.png');
background-image: url("../images/topAndDown/sp_icon_tcdl.png");
}
}
}
@@ -124,7 +149,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
left: 900px;
width: 100px;
height: 114px;
background-image: url('../images/topAndDown/sp_icon_zyc.png');
background-image: url("../images/topAndDown/sp_icon_zyc.png");
}
.tunnel-length {
@@ -141,7 +166,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
left: 0;
width: 100px;
height: 114px;
background-image: url('../images/topAndDown/sp_yyc.png');
background-image: url("../images/topAndDown/sp_yyc.png");
}
.right-arrow {
@@ -151,7 +176,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
right: 900px;
width: 100px;
height: 114px;
background-image: url('../images/topAndDown/sp_yyc.png');
background-image: url("../images/topAndDown/sp_yyc.png");
}
.shrink-right {
@@ -161,7 +186,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
right: 0;
width: 100px;
height: 114px;
background-image: url('../images/topAndDown/sp_icon_zyc.png');
background-image: url("../images/topAndDown/sp_icon_zyc.png");
}
.switch-btn {
@@ -174,10 +199,10 @@ html, body, #app, .el-container, .el-aside, .el-main {
bottom: 0;
left: 50%;
margin-left: -925px;
background-image: url('../images/topAndDown/sp_dbbj.png');
background-image: url("../images/topAndDown/sp_dbbj.png");
.el-carousel__mask {
display: none;
display: none
}
.el-carousel {
@@ -207,14 +232,14 @@ html, body, #app, .el-container, .el-aside, .el-main {
margin: 50px 0 0 263px;
width: 46px;
height: 54px;
background-image: url('../images/topAndDown/sp_icon_zst.png');
background-image: url("../images/topAndDown/sp_icon_zst.png");
}
.btn {
width: 100%;
margin-top: 14px;
font-size: 26px;
color: #9FC3CD;
color: #9fc3cd;
.el-carousel__item {
left: 19%;
@@ -226,16 +251,16 @@ html, body, #app, .el-container, .el-aside, .el-main {
padding-top: 5px;
width: 158px;
height: 50px;
background-image: url('../images/topAndDown/sp_icon_sdqhx.png');
background-image: url("../images/topAndDown/sp_icon_sdqhx.png");
}
.is-active {
margin-top: -5px;
color: #FFFFFF;
color: #ffffff;
padding-top: 7px;
width: 201px;
height: 62px;
background-image: url('../images/topAndDown/sp_icon_sdqhd.png');
background-image: url("../images/topAndDown/sp_icon_sdqhd.png");
}
}
@@ -247,28 +272,46 @@ html, body, #app, .el-container, .el-aside, .el-main {
//弹窗样式
.digital-tunnel {
.chat-dialog {
display: flex;
.chat-dialog{
display: flex;
#container {
flex: 1;
height: 1160px;
//width: 1300px;
}
#containerEle {
flex: 1;
height: 1060px;
//width: 2180px;
}
}
#container {
flex: 1;
height: 1160px;
//width: 1300px;
}
#containerBad {
flex: 1;
height: 1160px;
//width: 1300px;
}
#containerWind {
flex: 1;
height: 1160px;
//width: 1300px;
}
#containerEle {
flex: 1;
height: 1060px;
//width: 2180px;
}
#containerAir {
flex: 1;
height: 1150px;
//width: 2180px;
}
}
.el-dialog {
position: relative;
display: flex;
flex-direction: column;
height: 1300px;
border: 2px solid #0F82AF;
border: 2px solid #0f82af;
background: rgba(6, 34, 71, 0.78);
border-radius: 20px;
padding: 47px 30px;
@@ -281,13 +324,18 @@ html, body, #app, .el-container, .el-aside, .el-main {
.el-dialog__title {
font-size: 50px;
font-weight: bold;
color: #D6F1FA;
color: #d6f1fa;
}
.el-dialog__close {
color: #05FEFF;
font-size: 35px;
.el-dialog__headerbtn {
right: 22px;
.el-dialog__close {
color: #05feff;
font-size: 73px;
}
}
}
.el-dialog__body {
@@ -349,7 +397,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
width: 300px;
height: 200px;
border-radius: 10px;
border: 2px solid #0F82AF;
border: 2px solid #0f82af;
display: flex;
flex-direction: column;
align-items: center;
@@ -364,57 +412,69 @@ html, body, #app, .el-container, .el-aside, .el-main {
align-items: center;
width: 300px;
height: 100px;
background: #264A78;
background: #264a78;
font-size: 45px;
color: #FFFFFF;
color: #ffffff;
}
.value {
margin-top: 15px;
font-size: 50px;
font-family: MicrosoftYaHei;
color: #FFFFFF;
color: #ffffff;
}
}
}
}
.el-overlay-message-box{
.el-message-box{
.el-overlay-message-box {
.el-message-box {
width: 500px;
height: 230px;
background: rgba(7,35,72,0.79);
background: rgba(7, 35, 72, 0.79);
border-radius: 20px;
border: 2px solid #0F82AF;
.el-message-box__title{
border: 2px solid #0f82af;
.el-message-box__title {
display: none;
}
.el-message-box__content{
.el-icon{
.el-message-box__content {
.el-icon {
display: none;
}
.el-message-box__message{
.el-message-box__message {
//width: 315px;
height: 80px;
font-size: 32px;
font-weight: bold;
color: #08B7B8;
color: #08b7b8;
letter-spacing: 3px;
p {
line-height: 40px;
}
}
}
.el-message-box__btns{
.el-message-box__btns {
margin-top: 20px;
display: flex;
justify-content: space-around;
.el-button{
.el-button {
width: 130px;
height: 50px;
border: 2px solid #0F82AF;
border: 2px solid #0f82af;
font-size: 28px;
background-color: #072348;
color: #08B7B8;
color: #08b7b8;
}
.el-button--primary{
background: #08B7B8;
color: #FFFFFF;
.el-button--primary {
background: #08b7b8;
color: #ffffff;
}
}
}
@@ -422,41 +482,51 @@ html, body, #app, .el-container, .el-aside, .el-main {
//el-select 下拉框样式
.el-select__popper {
margin-top: -12px!important;
background: #072247!important;
border: 1px solid #0F82AF!important;
margin-top: -12px !important;
background: #072247 !important;
border: 1px solid #0F82AF !important;
}
.el-popper {
max-width: 202px!important;
max-width: 202px !important;
box-sizing: border-box;
}
.el-popper__arrow::before{
.el-popper__arrow::before {
display: none;
}
.el-select-dropdown{
width: 200px!important;
.el-select-dropdown {
width: 200px !important;
}
.el-select-dropdown__item{
color: #fff!important;
.el-select-dropdown__item {
color: #fff !important;
}
.el-select-dropdown__item.hover{
background-color: #072247!important;
.el-select-dropdown__item.hover {
background-color: #072247 !important;
}
.el-select-dropdown__item:hover {
background-color: #072247!important;
color: #08B7B8!important;
background-color: #072247 !important;
color: #08B7B8 !important;
}
.el-select-dropdown__item.selected {
color: #08B7B8!important;
color: #08B7B8 !important;
}
.el-select-dropdown__list{
.el-select-dropdown__item:first-child{
.el-select-dropdown__list {
.el-select-dropdown__item:first-child {
color: #FFFFFF;
&:hover{
color: #08B7B8!important;
&:hover {
color: #08B7B8 !important;
}
}
}
//input number 右侧加减隐藏
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
@@ -466,19 +536,66 @@ input::-webkit-inner-spin-button {
input[type="number"] {
-moz-appearance: textfield;
}
//checkbox
.el-checkbox__inner {
width: 40px !important;
height: 40px !important;
border-radius: 25px!important;
border-radius: 25px !important;
border: 4px solid #05FEFF!important;
background-color: transparent!important;
}
.el-checkbox__input.is-checked .el-checkbox__inner {
width: 25px;
height: 25px;
background-color: #05FEFF!important;
//background-color: #05FEFF !important;
}
.el-checkbox__input.is-checked .el-checkbox__inner::after {
display: none;
//display: none;
width: 18px;
height: 18px;
border-width: 3px;
//border-left: 0;
//border-top: 0;
border-radius: 25px;
top: 6px;
left:6px;
//left: 12px;
font-size: 30px;
background: #05FEFF;
border-color: transparent!important;
}
//取消 确定按钮
.btns {
display: flex;
justify-content: space-around;
margin-top: 80px;
.cancel-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 220px;
height: 80px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #08B7B8;
line-height: 80px;
font-size: 38px;
box-sizing: border-box;
}
.sure-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 220px;
height: 80px;
line-height: 80px;
background: #08B7B8;
border-radius: 11px;
color: #FFFFFF;
font-size: 38px;
}
}

View File

@@ -2,9 +2,9 @@
<div id="air-info">
<div class="fan-speed">
<img src="@/assets/images/airInfo/fan-v-icon.png" alt=""/>
<div class="fan-info">
<div class="fan-info" @click="handleOpenChart">
<div class="input-fan"><span>风速</span><span>进风{{ windSpeed }}m/s</span></div>
<div class="output-fan"><span>出风{{windSpeed}}m/s</span></div>
<div class="output-fan"><span>出风{{ windSpeed }}m/s</span></div>
</div>
</div>
<item-info
@@ -14,32 +14,107 @@
:icon="item.icon"
:name="item.name"
:unit="item.unit"
@click="handleOpenAirChart(item)"
/>
<div class="digital-tunnel">
<el-dialog v-model="isWindSpeedVisited" :title="'风速监控数据'" width="2175px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="chat-dialog">
<div id="containerWind"></div>
<div style="width: 1px;"></div>
</div>
<div class="time-select">
<time-range-btn
:buttonList="timeList"
v-model="selectTimeButton"
@select="timeSelect"
/>
</div>
<div class="left-bottom-icon"></div>
<div class="right-bottom-icon"></div>
</el-dialog>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isAirVisited" :title="airTitle+'监控数据'" width="2175px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="chat-dialog">
<div id="containerAir"></div>
<div style="width: 1px;"></div>
</div>
<div class="time-select">
<time-range-btn
:buttonList="timeList"
v-model="selectTimeButton"
@select="timeSelect"
/>
</div>
<div class="left-bottom-icon"></div>
<div class="right-bottom-icon"></div>
</el-dialog>
</div>
</div>
</template>
<script setup>
import ItemInfo from "./childComps/ItemInfo.vue";
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue"
import * as echarts from 'echarts';
let myEcharts = reactive({});
let myAirEcharts = reactive({});
const props = defineProps({
list: Array,
airData: Array
});
const windSpeed=ref('')
const windSpeed = ref('')
const airTitle = ref('')
const airList = ref([])
const timeList = ref(["年", "月", "日"]);
const selectTimeButton = ref(2);
const isWindSpeedVisited = ref(false);
const isAirVisited = ref(false);
watch(() => props.list, (now) => {
airList.value.forEach(item=>{
now.forEach(newItem=>{
if(item.equipmentId === newItem.equipmentId){
airList.value?.forEach(item => {
now.forEach(newItem => {
if (item.equipmentId === newItem.equipmentId) {
item.value = newItem.value
}
})
})
}, {deep: true});
watch(() => props.airData, (now) => {
getAirInfo(now.sensorList)
if(now.sensorList===null){
airList.value=[]
}else {
getAirInfo(now.sensorList)
}
}, {deep: true});
const handleOpenChart = () => {
isWindSpeedVisited.value = true
nextTick(() => {
initChart()
})
}
const handleOpenAirChart = (item) => {
isAirVisited.value = true
airTitle.value = item.name
nextTick(() => {
initAirChart()
})
}
const timeSelect = (index) => {
console.log('选择时间', index)
if (index === 0) {
console.log('--年')
} else if (index === 1) {
console.log('--月')
} else if (index === 2) {
console.log('--日')
}
};
const changeData = (item) => {
return {
equipmentId: item.equipmentId,
@@ -64,19 +139,220 @@ const changeIcon = (type) => {
}
}
const getAirInfo = (now) => {
let windPressureObj = {}
let windPressureArr = []
now.map(item => {
if (now === null) return;
let airObj = {}
let airArr = []
now?.map(item => {
if (item.equipmentType === "dust" || item.equipmentType === "oxygen" || item.equipmentType === "temperature" || item.equipmentType === "humidness") {
windPressureObj = changeData(item)
windPressureArr.push(windPressureObj)
}else if(item.equipmentType === "windDirection"){
airObj = changeData(item)
airArr.push(airObj)
} else if (item.equipmentType === "windDirection") {
windSpeed.value = item.value
}
})
windPressureArr.push(windPressureArr.shift())
airList.value = windPressureArr
airArr.push(airArr.shift())
airList.value = airArr
}
const initChart = () => {
//3.初始化container容器
myEcharts = echarts.init(document.getElementById('containerWind'));
//5.传入数据
let option = {
//图例
legend: {
// left: 0,
textStyle: {
color: '#FFFFFF',
fontSize: 40
},
itemWidth: 70,
itemHeight: 5,
icon: "rect",
},
//离容器四侧的距离
grid: {
left: 0, // 左边距
right: 20, // 右边距
top: 80, // 顶边距
bottom: 0, // 底边距
containLabel: true,
},
//提示框组件
tooltip: {
show: true,
trigger: 'axis',
backgroundColor: "transparent", // 设置背景颜色为透明
borderColor: "transparent", // 设置边框颜色为透明
padding: 0, // 设置内边距为0
textStyle: {
fontSize: 40
},
formatter: function (params) {
let content = `
<div style="background: linear-gradient(180deg, #254062 0%, rgba(20,36,51,0.3) 100%);;border: 2px solid #6087BA;border-radius: 4px;padding: 8px 16px;">
<div style="font-size: 52px;font-family: PingFang SC-Regular, PingFang SC;font-weight: 400;color: #EFEEEE;margin-bottom: 8px;">${params[0].name}</div>
<div style="font-size: 48px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;"><span style="color: #FFFFFF">进风口: </span><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[0].value}</span></div>
<div style="font-size: 48px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;margin-top: 30px"><span style="color: #FFFFFF">出风口: </span><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[1].value}</span></div>
</div>`;
return content;
},
},
toolbox: {
show: false,
right: 10,
feature: {
dataZoom: {
yAxisIndex: 'none'
}
}
},
dataZoom: [{
type: 'inside'
}],
//X轴
xAxis: {
type: 'category',
data: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00', '24:00'],
axisLabel: {
textStyle: {
fontSize: 45,
color: '#D6F1FA'
},
},
},
//Y轴
yAxis: {
type: 'value',
axisLabel: {
textStyle: {
fontSize: 45,
color: '#D6F1FA'
},
},
},
//配置项
series: [
{
name: '进风口',
data: [56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76, 69, 25, 31, 49, 81, 63],
type: 'line',
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
},
{
name: '出风口',
data: [3, 85, 47, 92, 17, 76, 69, 25, 56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 31, 49, 81, 63],
type: 'line',
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
}
]
}
myEcharts.setOption(option);
//图表大小自适应窗口大小变化
window.onresize = () => {
myEcharts.resize();
}
}
const initAirChart = () => {
//3.初始化container容器
myAirEcharts = echarts.init(document.getElementById('containerAir'));
//5.传入数据
let option = {
//图例
legend: {
// left: 0,
textStyle: {
color: '#FFFFFF',
fontSize: 40
}
},
//离容器四侧的距离
grid: {
left: 0, // 左边距
right: 20, // 右边距
top: 80, // 顶边距
bottom: 0, // 底边距
containLabel: true,
},
//提示框组件
tooltip: {
show: true,
trigger: 'axis',
backgroundColor: "transparent", // 设置背景颜色为透明
borderColor: "transparent", // 设置边框颜色为透明
padding: 0, // 设置内边距为0
textStyle: {
fontSize: 40
},
formatter: function (params) {
let content = `
<div style="background: linear-gradient(180deg, #254062 0%, rgba(20,36,51,0.3) 100%);;border: 2px solid #6087BA;border-radius: 4px;padding: 8px 16px;">
<div style="font-size: 52px;font-family: PingFang SC-Regular, PingFang SC;font-weight: 400;color: #EFEEEE;margin-bottom: 8px;">${params[0].name}</div>
<div style="font-size: 52px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;"><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[0].value}</span></div>
</div>`;
return content;
},
},
toolbox: {
show: false,
right: 10,
feature: {
dataZoom: {
yAxisIndex: 'none'
}
}
},
dataZoom: [{
type: 'inside'
}],
//X轴
xAxis: {
type: 'category',
data: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00', '24:00'],
axisLabel: {
textStyle: {
fontSize: 45,
color: '#D6F1FA'
},
},
},
//Y轴
yAxis: {
type: 'value',
axisLabel: {
textStyle: {
fontSize: 45,
color: '#D6F1FA'
},
},
},
//配置项
series: [
{
data: [56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76, 69, 25, 31, 49, 81, 63],
type: 'line',
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
}
]
}
myAirEcharts.setOption(option);
//图表大小自适应窗口大小变化
window.onresize = () => {
myAirEcharts.resize();
}
}
</script>
<style lang="scss" scoped>

View File

@@ -1,29 +1,28 @@
<template>
<div
id="bad-gas-info"
:style="{ backgroundImage: 'url(' + getImageUrl(bgImage) + ')' }"
@click="handleOpenChart"
>
:style="{ backgroundImage: 'url(' + getImageUrl(bgImage) + ')' }">
<div class="title">有害气体</div>
<div class="info-list">
<gas-info-item
v-for="item in badGasList"
:key="item.equipmentId"
:gasInfo="item"
@click="handleOpenChart"
/>
</div>
<div class="digital-tunnel">
<el-dialog
v-model="isVisited"
v-model="isBadGasVisited"
title="有害气体监控数据"
width="2400px"
width="2175px"
:modal="false"
>
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="chat-dialog">
<div id="container"></div>
<div id="containerBad"></div>
<div style="width: 1px"></div>
</div>
<div class="time-select">
@@ -44,21 +43,23 @@
import GasInfoItem from "./childComps/GasInfoItem.vue";
import * as echarts from "echarts";
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue";
import {getBadGasEchartsInfo} from "@/api/largeScreen";
const props = defineProps({
list: Array,
badGasData: Array,
tunnelId:Number
});
const timeList = ref(["年", "月", "日"]);
const selectTimeButton = ref(2);
const isVisited = ref(false);
const isBadGasVisited = ref(false);
const badGasList = ref([]);
let myEcharts = reactive({});
const bgImage = computed(() => (isVisited.value ? "sp_active.png" : "bg.png"));
const bgImage = computed(() => (isBadGasVisited.value ? "sp_active.png" : "bg.png"));
watch(
() => props.list,
(now) => {
badGasList.value.forEach((item) => {
badGasList.value?.forEach((item) => {
now.forEach((newItem) => {
if (item.equipmentId === newItem.equipmentId) {
item.value = newItem.value;
@@ -72,10 +73,22 @@ watch(
watch(
() => props.badGasData,
(now) => {
getBadGasInfo(now.sensorList);
if(now.sensorList===null){
badGasList.value=[]
}else {
getBadGasInfo(now.sensorList);
}
},
{ deep: true }
);
watch(
() => props.tunnelId,
(now) => {
props.tunnelId=now
},
{ deep: true }
);
const timeSelect = (index) => {
console.log("选择时间", index);
if (index === 0) {
@@ -87,9 +100,10 @@ const timeSelect = (index) => {
}
};
const getBadGasInfo = (now) => {
if(now===null)return;
let windPressureObj = {};
let windPressureArr = [];
now.map((item) => {
now?.map((item) => {
if (
item.equipmentType === "carbonDioxide" ||
item.equipmentType === "carbonMonoxide" ||
@@ -114,12 +128,19 @@ const changeData = (item) => {
unit: item.unit,
};
};
const getBadGasChartInfo = () => {
let id =props.tunnelId
getBadGasEchartsInfo(id).then(res => {
if (res?.code === 1000) {
isBadGasVisited.value = true
nextTick(() => {
initChart(res.data.dates, res.data)
})
}
})
}
const handleOpenChart = () => {
console.log("有害气体弹窗");
isVisited.value = true;
nextTick(() => {
initChart();
});
getBadGasChartInfo()
};
const getImageUrl = (name) => {
return new URL(`../../../assets/images/badGasInfo/${name}`, import.meta.url)
@@ -128,9 +149,9 @@ const getImageUrl = (name) => {
/**
* 初始化echarts实例方法
*/
const initChart = () => {
const initChart = (type, values) => {
//3.初始化container容器
myEcharts = echarts.init(document.getElementById("container"));
myEcharts = echarts.init(document.getElementById("containerBad"));
//5.传入数据
let option = {
//图例
@@ -156,40 +177,68 @@ const initChart = () => {
tooltip: {
show: true,
trigger: "axis",
backgroundColor: "rgba(20,36,51,0.7)", // 设置背景颜色为透明
borderColor: "#6087BA", // 设置边框颜色为透明
padding: 0, // 设置内边距为0
borderWidth:2,
textStyle: {
fontSize: 40
fontSize: 40,
},
formatter: (params)=> {
let res = ` <div style="font-size: 52px;font-family: PingFang SC-Regular, PingFang SC;font-weight: 400;color: #EFEEEE;margin-bottom: -30px">${params[0].name}</div>` + '<br/>'
for (let i = 0; i < params.length; i++) {
res += `
<div style="font-size: 52px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;margin:0 20px 30px 20px;"><span style="color: #FFFFFF">${params[i].seriesName}: </span><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[i].value}</span></div>
`;
}
return res
// return content;
},
},
toolbox: {
show: false,
right: 10,
feature: {
dataZoom: {
yAxisIndex: 'none'
}
}
},
dataZoom: [{
type: 'inside'
}],
//X轴
xAxis: {
type: "category",
data: [
"00:00",
"01:00",
"02:00",
"03:00",
"04:00",
"05:00",
"06:00",
"07:00",
"08:00",
"09:00",
"10:00",
"11:00",
"12:00",
"13:00",
"14:00",
"15:00",
"16:00",
"17:00",
"18:00",
"19:00",
"20:00",
"21:00",
"22:00",
"23:00",
"24:00",
],
// data: [
// "00:00",
// "01:00",
// "02:00",
// "03:00",
// "04:00",
// "05:00",
// "06:00",
// "07:00",
// "08:00",
// "09:00",
// "10:00",
// "11:00",
// "12:00",
// "13:00",
// "14:00",
// "15:00",
// "16:00",
// "17:00",
// "18:00",
// "19:00",
// "20:00",
// "21:00",
// "22:00",
// "23:00",
// "24:00",
// ],
data:type,
axisLabel: {
textStyle: {
fontSize: 45,
@@ -211,10 +260,11 @@ const initChart = () => {
series: [
{
name: "二氧化碳",
data: [
56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76,
69, 25, 31, 49, 81, 63,
],
// data: [
// 56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76,
// 69, 25, 31, 49, 81, 63,
// ],
data:values.carbonDioxideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -224,10 +274,11 @@ const initChart = () => {
},
{
name: "一氧化碳",
data: [
96, 38, 75, 10, 62, 81, 41, 27, 69, 16, 33, 57, 73, 87, 22, 46, 11,
79, 51, 29, 60, 48, 83, 15,
],
// data: [
// 96, 38, 75, 10, 62, 81, 41, 27, 69, 16, 33, 57, 73, 87, 22, 46, 11,
// 79, 51, 29, 60, 48, 83, 15,
// ],
data:values.carbonMonoxideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -237,10 +288,11 @@ const initChart = () => {
},
{
name: "二氧化氮",
data: [
53, 88, 10, 67, 92, 31, 74, 46, 20, 37, 85, 16, 63, 70, 41, 99, 25,
77, 82, 13, 68, 49, 55, 7, 39,
],
// data: [
// 53, 88, 10, 67, 92, 31, 74, 46, 20, 37, 85, 16, 63, 70, 41, 99, 25,
// 77, 82, 13, 68, 49, 55, 7, 39,
// ],
data:values.nitrogenDioxideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -250,10 +302,11 @@ const initChart = () => {
},
{
name: "一氧化氮",
data: [
37, 19, 85, 62, 28, 91, 43, 76, 14, 68, 33, 52, 71, 26, 97, 49, 82,
17, 66, 30, 78, 55, 23, 47,
],
// data: [
// 37, 19, 85, 62, 28, 91, 43, 76, 14, 68, 33, 52, 71, 26, 97, 49, 82,
// 17, 66, 30, 78, 55, 23, 47,
// ],
data:values.sulfurMonoxideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -263,10 +316,11 @@ const initChart = () => {
},
{
name: "二氧化硫",
data: [
6, 30, 91, 77, 28, 51, 42, 83, 16, 65, 35, 72, 18, 96, 47, 79, 100,
23, 80, 44, 62, 59, 13, 86,
],
// data: [
// 6, 30, 91, 77, 28, 51, 42, 83, 16, 65, 35, 72, 18, 96, 47, 79, 100,
// 23, 80, 44, 62, 59, 13, 86,
// ],
data:values.sulfurDioxideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -276,10 +330,11 @@ const initChart = () => {
},
{
name: "硫化氢",
data: [
13, 27, 39, 51, 62, 73, 84, 95, 10, 20, 30, 40, 50, 60, 70, 80, 90,
100, 11, 21, 31, 41, 51,
],
// data: [
// 13, 27, 39, 51, 62, 73, 84, 95, 10, 20, 30, 40, 50, 60, 70, 80, 90,
// 100, 11, 21, 31, 41, 51,
// ],
data:values.hydrogenSulfideValues,
type: "line",
smooth: true,
symbolSize: 24,
@@ -289,7 +344,7 @@ const initChart = () => {
},
],
};
myEcharts.setOption(option);
myEcharts.setOption(option,true);
//图表大小自适应窗口大小变化
window.onresize = () => {
myEcharts.resize();
@@ -301,7 +356,6 @@ const initChart = () => {
#bad-gas-info {
cursor: pointer;
position: absolute;
z-index: 100;
width: 824px;
height: 621px;
top: 1441px;

View File

@@ -82,13 +82,6 @@ watch(() => props.list, (now) => {
handleOnMounted()
}, {deep: true});
onMounted(() => {
setTimeout(() => {
nextTick(() => {
handleOnMounted()
})
}, 100);
});
const getImage = (type) => {
switch (type) {
case false:
@@ -110,7 +103,7 @@ const changeNum = (index) => {
const getBasicData = (data) => {
let tranObj = {}
let tranArr = []
data.map(item => {
data?.map(item => {
tranObj = {
equipmentId: item.equipmentId,
autoMode: item.autoMode,//自动模式
@@ -121,6 +114,9 @@ const getBasicData = (data) => {
tranArr.push(tranObj)
})
socketData.value = tranArr
nextTick(() => {
handleOnMounted()
})
}
const handleOnMounted = () => {
@@ -293,7 +289,9 @@ input[type="number"] {
}
#fan_info {
height: 795px;
min-height: 547px;
max-height: 795px;
height: 547px;
width: 830px;
position: absolute;
z-index: 100;
@@ -321,7 +319,7 @@ input[type="number"] {
height: calc(100% - 30px);
.fan-item {
height: 33.3%;
height: 50%;
display: flex;
font-size: 14px;
@@ -447,7 +445,7 @@ input[type="number"] {
border: 2px solid #0f82af;
background: transparent;
margin-left: 14px;
outline:none;
font-size: 28px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;

View File

@@ -85,7 +85,7 @@ const stateC = ref(false)
const getBasicData = (data) => {
let tranObj = {}
let tranArr = []
data.map(item => {
data?.map(item => {
tranObj = {
equipmentId: item.equipmentId,
equipmentName: item.equipmentName,
@@ -125,10 +125,12 @@ const getBasicData = (data) => {
#transducer-list {
color: rgb(226, 26, 26);
position: absolute;
top: 1015px;
//top: 1015px;
top: 760px;
left: 70px;
width: 830px;
height: 928px;
//height: 928px;
height: 620px;
background-image: url(@/assets/images/transducer/bg.png);
padding: 0 30px;
box-sizing: border-box;

View File

@@ -2,15 +2,22 @@
<div id="scene">
<div id="cvs" ref="content"></div>
<dev-info ref="info" :devInfo="devInfo" />
<edit-dialog
ref="edit"
@addEquipment="handleAddEqu"
@removeEquipment="handleRemoveEqu"
@cancel="handleCancel"
:hasDev="hasDevice"
:pointNum="pointNum"
pointGap="500"
/>
<edit-dialog ref="edit" @addEquipment="handleAddEqu" @removeEquipment="handleRemoveEqu" @cancel="handleCancel"
:hasDev="hasDevice" :pointNum="pointNum" pointGap="500" />
<el-dialog v-model="centerDialogVisible" width="30%" destroy-on-close center :show-close="false" style="
margin: 20% auto;
width: 569px;
height: 330px;
background: rgba(7, 35, 72, 0.79);
border-radius: 20px;
border: 2px solid #0f82af;
">
<p id="remove-title">是否确定删除该设备</p>
<div class="btn">
<button @click="centerDialogVisible = false">取消</button>
<button @click="handleConfirmAddEqu">确定</button>
</div>
</el-dialog>
</div>
</template>
@@ -18,7 +25,7 @@
import * as three from "three";
import ThreeDScene from "./sceneClass/demo.js";
import DevInfo from "./displayInfoComp/DevInfo.vue";
import editDialog from "./editEquComp/editDialog.vue";
import EditDialog from "./editEquComp/editDialog.vue";
// 导入模模型加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
@@ -39,7 +46,7 @@ import {
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { onMounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
// 获取html标签跟随组件dom
const content = ref(null);
const info = ref(null);
@@ -77,6 +84,9 @@ async function handleMounted() {
} catch (err) {
console.log(err);
}
demo.tunnelModeInit();
}
// 每个模型加载回调
@@ -87,7 +97,7 @@ function loadModel(path) {
(obj) => {
resolve(obj);
},
(xhr) => {},
(xhr) => { },
(err) => {
reject(err);
}
@@ -153,22 +163,47 @@ function rClickCallback(demo) {
demo.addFunction("editDev", editDev);
}
// 添加设备
function handleAddEqu(formInfo) {
if (!formInfo.equipmentType) {
alert("请选择设备");
ElMessage({
message: "请选择传感器!",
type: "warning",
});
return;
}
//表单信息
//这里利用处理请求
demo.addEquipment(targetP, formInfo);
ElMessage({
message: "添加成功!",
type: "success",
});
}
const centerDialogVisible = ref(false);
// 删除设备
async function handleRemoveEqu() {
demo.removeEquipment(targetP);
function handleRemoveEqu() {
if (!targetP.hasDevice) {
ElMessage({
message: "该点位不存在设备!",
type: "warning",
});
return;
}
centerDialogVisible.value = true;
}
// 对话框确认删除
function handleConfirmAddEqu() {
demo.removeEquipment(targetP);
centerDialogVisible.value = false;
ElMessage({
message: "删除成功!",
type: "success",
});
}
// 处理取消关闭编辑框事件
function handleCancel() {
if (!demo) return;
@@ -177,15 +212,92 @@ function handleCancel() {
demo._resetState();
demo.clearTagsObj();
}
//现在首先有二种方案是写在TunnelScene.vue中还是demo.js中呢
//我认为可能看数据在哪获取到时候看在哪里导入首先我们放在TunnelScene里面吧
//因为没获取到接口,我们先写死!!!
//需要参考接口的数据结构!!!,主要是传入函数的参数应该是什么结构???
const ThreeConfig = {
code: 0,
data: {
tunnelThreeConfig: [{
equipmentId: 'fan_01',//传感器id
equipmentName: '01',//设备名称
pointName: 'point_005_tl',//附着点名称(定位)
equipmentType: 'fan',//设备类型(类型可根据后端
equipmentValue: 23, //设备存的值
}, {
equipmentId: 'sensors_01',//传感器id
equipmentName: '01',//设备名称
pointName: 'point_009_bl',//附着点名称(定位)
equipmentType: 'sensors',//设备类型(类型可根据后端
equipmentValue: 67, //设备存的值
}],
},
msg: "dda"
}
//取值方便操作
// const tunnelConfigEquipment = ThreeConfig.data.tunnelThreeConfig
// function tunnelModeInit() {
// for (const item of tunnelConfigEquipment) {
// let pointmodel = demo.scene.getobjectByName(item.pointName)
// console.log(pointmodel);
// }
// }
// tunnelModeInit()
</script>
<style lang="scss" scope>
<style lang="scss" scoped>
#scene {
position: relative;
height: 100%;
width: 100%;
#cvs {
height: 100%;
}
}
#remove-title {
height: 42px;
font-size: 32px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #08b7b8;
line-height: 42px;
letter-spacing: 3px;
text-align: center;
margin: 65px 0px 70px 0px;
}
.btn {
display: flex;
justify-content: center;
gap: 80px;
:nth-child(1) {
width: 190px;
height: 60px;
border-radius: 11px;
border: 2px solid #0f82af;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #08b7b8;
line-height: 37px;
background: transparent;
}
:nth-child(2) {
width: 190px;
height: 60px;
background: #08b7b8;
border-radius: 11px;
font-size: 28px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #ffffff;
line-height: 37px;
}
}
</style>

View File

@@ -1,12 +1,7 @@
<template>
<div id="input-num">
<p>{{ params.name }}</p>
<input
type="text"
:placeholder="params.placeholder"
@input="handleChange"
:disabled="params.disabled"
/>
<input type="text" :placeholder="params.placeholder" @input="handleChange" :disabled="params.disabled" />
</div>
</template>
@@ -34,6 +29,7 @@ function handleUnmounted() {
<style lang="scss" scoped>
#input-num {
margin: 40px 30px 0px 30px;
P {
width: 130px;
height: 35px;
@@ -42,6 +38,7 @@ function handleUnmounted() {
color: #ffffff;
line-height: 35px;
}
input {
width: 284px;
height: 51px;
@@ -55,6 +52,7 @@ function handleUnmounted() {
padding: 0px 10px;
overflow: hidden;
}
::placeholder {
color: #0f82af;
}

View File

@@ -2,54 +2,25 @@
<div id="edit-dialog">
<div class="distance-back">
<p>当前距离洞口{{ pointDistance_str }}</p>
<img
src="/images/htmlEditDialog/back-icon.png"
alt=""
@click="handleCancel"
/>
<img src="/images/htmlEditDialog/back-icon.png" alt="" @click="handleCancel" />
</div>
<div class="equ-info">当前风压:{{ p }}Pa</div>
<div class="setting">
<div class="setting-item">
<p>传感器类型</p>
<el-select
v-model="equipmentSetting.equipmentType"
:fit-input-width="true"
filterable
clearable
placeholder="请选择设备类型"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="equipmentSetting.equipmentType" :fit-input-width="true" filterable clearable
placeholder="请选择设备类型">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="setting-item">
<p>设备选择</p>
<el-select
v-model="equipmentSetting.chooseEquipment"
:fit-input-width="true"
filterable
clearable
placeholder="请选择设备类型"
>
<el-option
v-for="item in options2"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select v-model="equipmentSetting.chooseEquipment" :fit-input-width="true" filterable clearable
placeholder="请选择设备类型">
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<input-num
name="阈值"
placeholder="请输入阈值"
@inputValue="handelInput"
:disabled="isDisabledInputNum"
/>
<input-num name="阈值" placeholder="请输入阈值" @inputValue="handelInput" :disabled="isDisabledInputNum" />
</div>
<div class="btn">
<button @click="removeEquipment">删除</button>
@@ -80,8 +51,7 @@ let p = ref(57);
//计算锚点之间距离
const pointDistance_str = computed(
() =>
`${params.pointGap}米*${params.pointNum}=${
params.pointGap * params.pointNum
`${params.pointGap}米*${params.pointNum}=${params.pointGap * params.pointNum
}`
);
@@ -156,15 +126,6 @@ function removeEquipment() {
// 添加设备
function addEquipment() {
// // 处理不合法情况
// if (
// !equipmentSetting.chooseEquipment ||
// !equipmentSetting.equipmentType ||
// !equipmentSetting.threshold
// ) {
// alert("选项不能有空");
// return;
// }
emit("addEquipment", equipmentSetting);
equipmentSetting.chooseEquipment = "";
equipmentSetting.equipmentType = "";
@@ -192,11 +153,13 @@ const equipment = {
z-index: 999;
display: block;
opacity: 0;
.distance-back {
height: 30px;
display: flex;
justify-content: space-between;
margin: 20px 20px 0px 30px;
p {
width: 388px;
height: 35px;
@@ -205,13 +168,16 @@ const equipment = {
color: #ffffff;
line-height: 35px;
}
img {
cursor: pointer;
}
img:active {
transform: scale(0.9);
}
}
.equ-info {
width: 190px;
height: 35px;
@@ -221,6 +187,7 @@ const equipment = {
line-height: 35px;
margin: 20px 30px 0px 30px;
}
.setting {
.setting-item {
padding: 30px 30px 10px 30px;
@@ -235,23 +202,27 @@ const equipment = {
margin-bottom: 20px;
}
}
:deep(.el-select) {
width: 284px;
//height: 51px;
border: transparent;
}
:deep(.el-input--suffix) {
width: 284px;
height: 51px;
background: rgba(7, 35, 72, 0.79);
border: 2px solid #0f82af;
}
:deep(.el-input__wrapper) {
background: transparent;
border: none !important;
padding: 0px 12px 0px 10px;
box-shadow: none !important;
}
:deep(.el-input__wrapper input) {
background: transparent;
height: 100%;
@@ -260,19 +231,23 @@ const equipment = {
color: #08b7b8;
line-height: 37px;
}
:deep(.el-icon) {
color: #05feff;
font-size: 34px;
}
}
.btn {
margin: 100px 40px 40px 40px;
display: flex;
justify-content: space-between;
button {
cursor: pointer;
transition: transform 0.1s linear 0s;
}
& :nth-child(1) {
width: 190px;
height: 60px;
@@ -284,6 +259,7 @@ const equipment = {
color: #08b7b8;
line-height: 60px;
}
& :nth-child(2) {
width: 190px;
height: 60px;
@@ -295,6 +271,7 @@ const equipment = {
color: #ffffff;
line-height: 60px;
}
button:active {
transform: scale(0.9);
}

View File

@@ -370,8 +370,8 @@ export default class Demo {
// 初始化风机颜色
this.equMap.get("equ_fan").traverse((v) => {
// v.material = new this.THREE.MeshBasicMaterial();
// v.material.color = new this.THREE.Color("#191a05");
v.material = new this.THREE.MeshBasicMaterial();
v.material.color = new this.THREE.Color(0xC0C0C0);
if (/^leaf/.test(v.name) || /^roller/.test(v.name)) {
group.add(v.clone());
v.visible = false;
@@ -487,4 +487,39 @@ export default class Demo {
opacityTween(0.1, 0.5, true);
}
}
ThreeConfig = {
code: 0,
data: {
tunnelThreeConfig: [{
equipmentId: 'fan_01',//传感器id
equipmentName: '01',//设备名称
pointName: 'point_005_tl',//附着点名称(定位)
equipmentType: 'fan',//设备类型(类型可根据后端
equipmentValue: 23, //设备存的值
}, {
equipmentId: 'sensors_01',//传感器id
equipmentName: '01',//设备名称
pointName: 'point_009_bl',//附着点名称(定位)
equipmentType: 'sensors',//设备类型(类型可根据后端
equipmentValue: 67, //设备存的值
}],
},
msg: "dda"
}
tunnelConfigEquipment = this.ThreeConfig.data.tunnelThreeConfig
tunnelModeInit() {
for (const item of this.tunnelConfigEquipment) {
//使用api取拿到附着点
let pointmodel = this.scene.getObjectByName(item.pointName)
// pointmodel.hasDevice = true;
let formInfo = {
equipmentType: item.equipmentType, //设备类型
chooseEquipment: item.equipmentName, //设备选择(设备名称)
threshold: item.equipmentValue, //阈值
}
this.addEquipment(pointmodel, formInfo);
}
}
}

View File

@@ -4,6 +4,9 @@ import EquipmentTag from "../utils/EquipmentTag";
* @param {Mesh} targetPoint
* @param {String} equType "fan" "sensors"
*/
//formInfo需要的信息这里包括了
//equipmentType、
function addEquipment(targetPoint, formInfo) {
if (targetPoint.hasDevice) {
alert("已添加设备");

View File

@@ -11,7 +11,7 @@
</div>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isVisited" width="2400px" :modal="false">
<el-dialog v-model="isVisited" width="2175px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="top-tag">
@@ -76,7 +76,7 @@ watch(() => props.list, (now) => {
const getBasicData = (data) => {
let tranObj = {}
let tranArr = []
data.map(item => {
data?.map(item => {
electricityConsumptionMonthly.value = item.electricityConsumptionMonthly,
tranObj = {
equipmentId: item.equipmentId,
@@ -127,10 +127,34 @@ const initChart = () => {
tooltip: {
show: true,
trigger: 'axis',
backgroundColor: "transparent", // 设置背景颜色为透明
borderColor: "transparent", // 设置边框颜色为透明
padding: 0, // 设置内边距为0
textStyle: {
fontSize: 40
},
formatter: function (params) {
let content = `
<div style="background: linear-gradient(180deg, #254062 0%, rgba(20,36,51,0.3) 100%);border: 2px solid #6087BA;border-radius: 4px;padding: 8px 16px;">
<div style="font-size: 52px;font-family: PingFang SC-Regular, PingFang SC;font-weight: 400;color: #EFEEEE;margin-bottom: 8px;">${params[0].name}日</div>
<div style="font-size: 48px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;"><span style="color: #FFFFFF">日用电量: </span><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[0].value}</span></div>
<div style="font-size: 48px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;margin-top: 30px"><span style="color: #FFFFFF">日节省量: </span><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[1].value}</span></div>
</div>`;
return content;
},
},
toolbox: {
show: false,
right: 10,
feature: {
dataZoom: {
yAxisIndex: 'none'
}
}
},
dataZoom: [{
type: 'inside'
}],
//X轴
xAxis: {
type: 'category',
@@ -187,7 +211,8 @@ const getImageUrl = (name) => {
height: 90px;
color: aliceblue;
position: absolute;
top: 1980px;
//top: 1980px;
top: 1420px;
left: 68px;
background-image: url(../../../assets/images/usedEle/bg.png);
padding: 21px 62px 35px 62px;

View File

@@ -2,10 +2,11 @@
<div id="wind-pressure">
<div class="name">风压</div>
<div class="list">
<wind-pressure-item v-for="(item,index) in wpList" :key="item.equipmentId" :wp="item" :index="index+1" @click="handleOpenChart(index+1)"/>
<wind-pressure-item v-for="(item,index) in wpList" :key="item.equipmentId" :wp="item" :index="index+1"
@click="handleOpenChart(item,index+1)"/>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isVisited" :title="windSort+'号风压监控数据'" width="2400px" :modal="false">
<el-dialog v-model="isVisited" :title="windSort+'号风压监控数据'" width="2175px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="chat-dialog">
@@ -30,20 +31,23 @@
import WindPressureItem from "./childComps/WindPressureItem.vue";
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue"
import * as echarts from 'echarts';
import {getEchartsInfo} from "@/api/largeScreen";
const props = defineProps({
list: Array,
winData: Array
});
const windSort=ref(1)
const windSort = ref(1)
const timeList = ref(["年", "月", "日"]);
const selectTimeButton = ref(2);
const isVisited = ref(false);
let myEcharts = reactive({});
const wpList = ref([]);
const chartData = ref()
watch(() => props.list, (now) => {
wpList.value.forEach(item=>{
now.forEach(newItem=>{
if(item.equipmentId === newItem.equipmentId){
wpList.value.forEach(item => {
now.forEach(newItem => {
if (item.equipmentId === newItem.equipmentId) {
item.value = newItem.value
}
})
@@ -53,30 +57,38 @@ watch(() => props.list, (now) => {
watch(() => props.winData, (now) => {
getScreenInfo(now.windPressureSensorList)
}, {deep: true});
const handleOpenChart = (index) => {
console.log('用电量弹窗')
isVisited.value = true
windSort.value=index
nextTick(() => {
initChart()
const getWindInfo = (equipmentId) => {
getEchartsInfo(equipmentId).then(res => {
if (res?.code === 1000) {
isVisited.value = true
nextTick(() => {
initChart(res.data.dates, res.data.values)
})
}
})
}
const handleOpenChart = (item, index) => {
getWindInfo(item.equipmentId)
windSort.value = index
}
const timeSelect = (index) => {
console.log('选择时间', index)
if(index===0){
if (index === 0) {
console.log('--年')
}else if(index===1){
} else if (index === 1) {
console.log('--月')
}else if(index===2){
} else if (index === 2) {
console.log('--日')
}
};
const getScreenInfo = (now) => {
const getScreenInfo = (now) => {
let windPressureObj = {}
let windPressureArr = []
now.map(item => {
now?.map(item => {
windPressureObj = {
equipmentId:item.equipmentId,
equipmentId: item.equipmentId,
max: 120,
value: item.value,
point: item.valueThreshold,
@@ -89,7 +101,7 @@ const getScreenInfo = (now) => {
/**
* 初始化echarts实例方法
*/
const initChart = () => {
const initChart = (type, values) => {
//3.初始化container容器
myEcharts = echarts.init(document.getElementById('container'));
//5.传入数据
@@ -116,14 +128,38 @@ const initChart = () => {
tooltip: {
show: true,
trigger: 'axis',
backgroundColor: "transparent", // 设置背景颜色为透明
borderColor: "transparent", // 设置边框颜色为透明
padding: 0, // 设置内边距为0
textStyle: {
fontSize: 40
},
formatter: function (params) {
let content = `
<div style="background: linear-gradient(180deg, #254062 0%, rgba(20,36,51,0.3) 100%);;border: 2px solid #6087BA;border-radius: 4px;padding: 8px 16px;">
<div style="font-size: 52px;font-family: PingFang SC-Regular, PingFang SC;font-weight: 400;color: #EFEEEE;margin-bottom: 8px;">${params[0].name}</div>
<div style="font-size: 52px;line-height: 48px;font-family: Bebas Neue-Regular, Bebas Neue;font-weight: 400;margin-top: 20px"><span style="background: linear-gradient(180deg, #F5B85F 0%, #FFFFFF 100%);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;">${params[0].value}</span></div>
</div>`;
return content;
},
},
toolbox: {
show: false,
right: 10,
feature: {
dataZoom: {
yAxisIndex: 'none'
}
}
},
dataZoom: [{
type: 'inside'
}],
//X轴
xAxis: {
type: 'category',
data: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00','07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00','19:00', '20:00', '21:00', '22:00', '23:00','24:00'],
// data: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00','07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00','19:00', '20:00', '21:00', '22:00', '23:00','24:00'],
data: type,
axisLabel: {
textStyle: {
fontSize: 45,
@@ -144,13 +180,14 @@ const initChart = () => {
//配置项
series: [
{
data: [56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76, 69, 25, 31, 49, 81, 63],
// data: [56, 12, 89, 34, 71, 43, 67, 20, 98, 72, 19, 61, 3, 85, 47, 92, 17, 76, 69, 25, 31, 49, 81, 63],
data: values,
type: 'line',
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
},
}
]
}

View File

@@ -11,24 +11,43 @@
const props = defineProps({
modelValue: {
type: Number,
default: 0,
default: 0
},
list: {
type: Array,
default: []
},
})
watch(() => props.list, (now) => {
let newArr=[]
btnList.value.forEach((btnList) => {
now.forEach((item) => {
if (btnList.route==item) {
newArr.push(btnList)
}
})
})
btnList.value=newArr
}, {deep: true});
const emit = defineEmits(["update:modelValue", "select"]);
const btnList = ref([
{
route: '/site',
icon: 'sp_icon_zdgl.png',
name: '站点管理'
},
{
route: '/tunnel',
icon: 'sp_icon_sdgl.png',
name: '隧道管理'
},
{
route: '/user',
icon: 'sp_icon_yhgl.png',
name: '用户管理'
},
{
route: '/system',
icon: 'sp_icon_xtgl.png',
name: '系统管理'
},

View File

@@ -8,7 +8,7 @@ const routes = [
{
path: '/login',
name: 'login',
component: ()=>import('@/views/login/index.vue'),
component: () => import('@/views/login/index.vue'),
meta: {
hidden: true,
title: '登录'
@@ -23,6 +23,15 @@ const routes = [
breadcrumb: true
}
},
{
path: '/preview',
name: 'tunnelpreview',
component: () => import('@/views/tunnel/preview.vue'),
meta: {
title: '预览首页',
breadcrumb: true
}
},
{
path: '/debug',
name: 'debug',
@@ -41,6 +50,15 @@ const routes = [
breadcrumb: true
}
},
{
path: '/user',
name: 'user',
component: () => import('@/views/user/index.vue'),
meta: {
title: 'user',
breadcrumb: true
}
},
{
path: '/tunnel/:siteId(\\d+)',
name: 'tunnel',
@@ -65,26 +83,26 @@ const router = createRouter({
history: createWebHashHistory(),
routes,
});
router.beforeEach( (to,form,next)=>{
NProgress.start()
if(!getToken()) {
if (to.path === '/login') {
next()
NProgress.done()
} else {
next({path: '/login'})
}
}else {
console.log('有token')
if(to.path === '/login') {
next('/')
NProgress.done()
}else {
next()
}
router.beforeEach((to, form, next) => {
NProgress.start()
if (!getToken()) {
if (to.path === '/login') {
next()
NProgress.done()
} else {
next({ path: '/login' })
}
} else {
console.log('有token')
if (to.path === '/login') {
next('/')
NProgress.done()
} else {
next()
}
}
})
router.afterEach(()=>{
router.afterEach(() => {
NProgress.done()
})

View File

@@ -13,11 +13,9 @@
<div class="device-content">
<div class="device-box">
<div class="box-left">
<!-- <div>风机</div>-->
<!-- <div>风压</div>-->
<!-- <div>其他传感器</div>-->
<el-menu
default-active="1"
@select="handleChangeMenu"
>
<el-menu-item index="1">
<span>风机</span>
@@ -30,8 +28,185 @@
</el-menu-item>
</el-menu>
</div>
<div class="box-right">
<div class="box-right" v-if="changeIndex==1">
<div class="device-title">
<span>风机设备管理</span>
<div class="collection-frequency">
<span>采集频率</span>
<span class="units">
<input
type="number"
min="0"
v-model="collectionFrequency"
/>
</span>
</div>
</div>
<div class="device-table">
<el-table stripe
style="border-bottom: 1px #06e5e5 solid;background-color: #011c29;--el-table-border-color: none;"
:header-cell-style="{backgroundColor: '#064B66',color: '#fff',fontSize: '40px',borderBottom: 'none' }"
:cell-style="{textAlign: 'center',borderBottom: 'none'}" :data="fanData">
<el-table-column prop="name" label="设备名称" align="center"/>
<el-table-column prop="currentA" label="A电流" align="center">
<template #default="scope">
<el-input placeholder="请输入A电流" v-model="scope.row.currentA"></el-input>
</template>
</el-table-column>
<el-table-column prop="currentB" label="B电流" align="center">
<template #default="scope">
<el-input placeholder="请输入B电流" v-model="scope.row.currentB"></el-input>
</template>
</el-table-column>
<el-table-column prop="currentC" label="C电流" align="center">
<template #default="scope">
<el-input placeholder="请输入C电流" v-model="scope.row.currentC"></el-input>
</template>
</el-table-column>
<el-table-column prop="state" label="状态" align="center">
<template #default="scope">
<div class="switch">
<div
:class="{ active: scope.row.state }"
@click=" scope.row.state = true"
>
启动
</div>
<div
:class="{ active: ! scope.row.state }"
@click=" scope.row.state = false"
>
停止
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="btns">
<div class="cancel-btn">
取消
</div>
<div class="sure-btn" @click="router.back(-1)">
确定
</div>
</div>
</div>
<div class="box-right" v-if="changeIndex==2">
<div class="device-title">
<span>风压设备管理</span>
<div class="collection-frequency">
<span>采集频率</span>
<span class="units">
<input
type="number"
min="0"
v-model="collectionFrequency"
/>
</span>
</div>
</div>
<div class="device-table">
<el-table stripe
style="border-bottom: 1px #06e5e5 solid;background-color: #011c29;--el-table-border-color: none;"
:header-cell-style="{backgroundColor: '#064B66',color: '#fff',fontSize: '40px',borderBottom: 'none' }"
:cell-style="{textAlign: 'center',borderBottom: 'none'}" :data="winData">
<el-table-column prop="name" label="设备名称" align="center"/>
<el-table-column prop="offset" label="偏移量" align="center"/>
<el-table-column prop="unit" label="单位" align="center"/>
<el-table-column prop="thresholdValue" label="阈值" align="center">
<template #default="scope">
<el-input placeholder="请输入阈值" v-model="scope.row.thresholdValue"></el-input>
</template>
</el-table-column>
<el-table-column prop="state" label="状态" align="center">
<template #default="scope">
<div class="switch">
<div
:class="{ active: scope.row.state }"
@click=" scope.row.state = true"
>
启动
</div>
<div
:class="{ active: ! scope.row.state }"
@click=" scope.row.state = false"
>
停止
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="btns">
<div class="cancel-btn">
取消
</div>
<div class="sure-btn" @click="router.back(-1)">
确定
</div>
</div>
</div>
<div class="box-right" v-if="changeIndex==3">
<div class="device-title">
<span>其他传感器设备管理</span>
<div class="collection-frequency">
<span>采集频率</span>
<span class="units">
<input
type="number"
min="0"
v-model="collectionFrequency"
/>
</span>
</div>
</div>
<div class="device-table">
<el-table stripe
style="border-bottom: 1px #06e5e5 solid;background-color: #011c29;--el-table-border-color: none;"
:header-cell-style="{backgroundColor: '#064B66',color: '#fff',fontSize: '40px',borderBottom: 'none' }"
:cell-style="{textAlign: 'center',borderBottom: 'none'}" :data="otherData">
<el-table-column prop="name" label="设备名称" align="center"/>
<el-table-column prop="offset" label="偏移量" align="center"/>
<el-table-column prop="unit" label="单位" align="center">
<template #default="scope">
<el-input placeholder="请输入单位" v-model="scope.row.unit"></el-input>
</template>
</el-table-column>
<el-table-column prop="thresholdValue" label="阈值" align="center">
<template #default="scope">
<el-input placeholder="请输入阈值" v-model="scope.row.thresholdValue"></el-input>
</template>
</el-table-column>
<el-table-column prop="state" label="状态" align="center">
<template #default="scope">
<div class="switch">
<div
:class="{ active: scope.row.state }"
@click=" scope.row.state = true"
>
启动
</div>
<div
:class="{ active: ! scope.row.state }"
@click=" scope.row.state = false"
>
停止
</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="btns">
<div class="cancel-btn" @click="isVisited=false">
取消
</div>
<div class="sure-btn" @click="router.back(-1)">
确定
</div>
</div>
</div>
</div>
</div>
@@ -40,10 +215,179 @@
<script setup>
const router = useRouter()
const collectionFrequency = ref(0)
const changeIndex = ref(1)
const fanData = [
{
name: '一号风机',
currentA: '2342',
currentB: '2342',
currentC: '2342',
state: false,
},
{
name: '二号风机',
currentA: '2342',
currentB: '2342',
currentC: '2342',
state: true,
},
{
name: '三号风机',
currentA: '2342',
currentB: '2342',
currentC: '2342',
state: false,
}
]
const winData = [
{
name: '1号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '2号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '3号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '4号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '5号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '6号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '7号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '8号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '9号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
{
name: '10号风压',
offset: '2342',
unit: 'Pa',
thresholdValue: '2342',
state: false,
},
]
const otherData = [
{
name: '风速',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '氧 气',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '温 度',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '湿 度',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '粉 尘',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '二氧化碳',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '一氧化碳',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '二氧化氮',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '一氧化氮',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '二氧化硫',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}, {
name: '硫 化 氢',
offset: '2342',
unit: 'm/s',
thresholdValue: '2342',
state: false,
}
]
const handleChangeMenu = (e) => {
console.log('切换', e)
changeIndex.value = e
}
</script>
<style scoped lang="scss">
.tunnel-bgc {
padding: 85px 0 0 0;
width: 100%;
@@ -89,31 +433,189 @@ const router = useRouter()
.device-content {
display: flex;
justify-content: center;
padding-top: 246px;
padding-top: 220px;
.device-box {
display: flex;
width: 2194px;
height: 1321px;
height: 1500px;
background: #064B66;
border-radius: 20px;
border: 2px solid #05FEFF;
box-sizing: border-box;
.box-left {
padding-left: 24px;
width: 300px;
height: 1318px;
height: 1498px;
background: #0D5A7A;
border-radius: 20px 0px 0px 20px;
:deep(.el-menu){
:deep(.el-menu) {
border-right: none;
margin-top: 261px;
background-color: #0D5A7A;
.el-menu-item.is-active {
background-image: url(../../assets/images/device/sdgl_xz.png);
}
.el-menu-item {
color: #fff;
height: 90px;
font-size: 40px;
&:hover {
background-color: #0D5A7A;
}
&:first-child {
letter-spacing: 120px;
}
&:nth-child(2) {
letter-spacing: 120px;
}
}
}
}
.box-right {
flex: 1;
display: flex;
flex-direction: column;
position: relative;
.device-title {
margin-top: 60px;
line-height: 61px;
color: #FFFFFF;
display: flex;
justify-content: center;
> span:first-child {
font-size: 46px;
font-weight: bold;
}
.collection-frequency {
position: absolute;
right: 102px;
> span:first-child {
font-size: 38px !important;
}
.units {
position: relative;
input {
width: 166px;
height: 50px;
border: 1px solid #05FEFF;
background: transparent;
margin-left: 14px;
font-size: 35px;
color: #FFFFFF;
outline: none;
}
}
.units::after {
content: "秒/次";
position: absolute;
right: 6px;
top: 26%;
transform: translateY(-50%);
font-size: 35px;
color: #08B7B8;
}
}
}
}
.btns {
width: 100%;
margin: 0 auto;
position: absolute;
bottom: 70px;
}
.device-table {
margin-top: 50px;
margin-left: 97px;
.active {
color: #FFFFFF;
background: #0f7da9;
}
.switch {
margin-top: 22px;
margin-left: 60px;
display: flex;
width: 200px;
height: 50px;
border-radius: 6px;
border: 1px solid #05FEFF;
overflow: hidden;
color: #51A2B3;
line-height: 40px;
font-size: 36px;
& > div {
flex: 1;
text-align: center;
cursor: pointer;
}
}
:deep(.el-table--fit) {
width: 1700px !important;
}
:deep(.cell) {
height: 80px;
line-height: 80px;
color: #fff;
font-size: 38px;
}
:deep(.el-table tr) {
background-color: #1C5971;
}
:deep(.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell) {
background-color: #1C5971;
}
:deep(.el-table__row--striped) {
background-color: #13849C!important;
}
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell){
background-color: #13849C!important;
}
:deep(.el-table__cell) {
.el-input {
width: 180px;
height: 53px;
}
.el-input__wrapper {
border-radius: 6px;
border: 1px solid #05FEFF;
background-color: transparent;
.el-input__inner {
color: #FFFFFF;
font-size: 40px;
}
}
}
:deep(.el-table__inner-wrapper::before) {
display: none;
}
}
}
}

View File

@@ -1,47 +1,47 @@
<template>
<div class="login-box" id="login-box">
<el-form
:model="loginForm"
ref="formInstance"
:rules="rules"
label-width="65px"
:model="loginForm"
ref="formInstance"
:rules="rules"
label-width="65px"
>
<h3>FateVerse</h3>
<h3>Tunnel Cloud</h3>
<el-form-item prop="username" label="账号">
<el-input v-model="loginForm.username" :prefix-icon="User"></el-input>
</el-form-item>
<el-form-item prop="password" label="密码">
<el-input
v-model="loginForm.password"
type="password"
:prefix-icon="Lock"
v-model="loginForm.password"
type="password"
:prefix-icon="Lock"
></el-input>
</el-form-item>
<el-form-item prop="code" label="验证码">
<div class="code">
<el-input
v-model="loginForm.code"
:prefix-icon="key"
@keyup.enter.native="handleLogin(formInstance)"
v-model="loginForm.code"
:prefix-icon="key"
@keyup.enter.native="handleLogin(formInstance)"
></el-input>
<img :src="codeImg" alt="" @click="getCode" />
<img :src="codeImg" alt="" @click="getCode"/>
</div>
</el-form-item>
<el-form-item>
<el-button @click="handleLogin(formInstance)" type="primary"
>登录</el-button
>
<el-button @click="handleLogin(formInstance)" type="primary">登录
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { useRouter } from "vue-router";
import { getCodeImg } from "../../api/login";
import { useAuthStore } from "@/store/userstore";
import { ElLoading } from "element-plus";
import { User, Lock, Key } from "@element-plus/icons-vue";
import {useRouter} from "vue-router";
import {getCodeImg} from "../../api/login";
import {useAuthStore} from "@/store/userstore";
import {ElLoading} from "element-plus";
import {User, Lock, Key} from "@element-plus/icons-vue";
const router = useRouter();
const authStore = useAuthStore();
const loginForm = reactive({
@@ -53,9 +53,9 @@ const loginForm = reactive({
const codeImg = ref("");
const formInstance = ref();
const rules = reactive({
username: [{ required: true, message: "请输入账户名", trigger: "blur" }],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
username: [{required: true, message: "请输入账户名", trigger: "blur"}],
password: [{required: true, message: "请输入密码", trigger: "blur"}],
code: [{required: true, message: "请输入验证码", trigger: "blur"}],
});
//获取二维码
@@ -98,14 +98,27 @@ onBeforeUnmount(() => {
</script>
<style lang="scss" scoped>
:deep(.el-button){
font-size:22px;
height: 40px;
}
:deep(.el-form-item__label) {
width: 80px!important;
font-size: 18px;
}
:deep(.el-input__wrapper ) {
padding: 5px 11px;
font-size: 22px;
}
.login-box {
height: 100%;
background-color: #4158d0;
background-image: linear-gradient(
43deg,
#4158d0 0%,
#c850c0 46%,
#ffcc70 100%
43deg,
#4158d0 0%,
#c850c0 46%,
#ffcc70 100%
);
display: flex;
justify-content: center;
@@ -128,17 +141,20 @@ onBeforeUnmount(() => {
}
}
}
.code {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.el-input {
// width: ;
flex: 2;
}
img {
height: 32px;
height: 45px;
flex: 1;
}
}

View File

@@ -10,7 +10,7 @@
<div class="all-btn" style=" margin-right: 40px;" v-if="!showAddIcon" @click="handleAdd">
添加
</div>
<div class="all-btn">
<div class="all-btn" @click="handleChooseAll">
全选
</div>
<div class="all-btn del-btn" @click="handleMoreDelete">
@@ -30,7 +30,7 @@
<div>隧道数量{{ item.info.tunnelNum }}
</div>
<div>
<div class="tunnel" v-if="showFirstTunnel">
<div class="tunnel" v-if="item.info.tunnelName">
<div>{{ item.info.tunnelName }}</div>
<div class="tunnel-icon"></div>
<div>施工长度{{ item.info.constructionLength }}</div>
@@ -41,13 +41,13 @@
<div class="add-icon"></div>
</div>
</div>
<div class="more" @click="router.push('/tunnel')" v-if="showFirstTunnel">
<div class="more" @click="goToAddTunnel(item.siteId)" v-if="item.info.tunnelName">
更多
<div class="icon"></div>
</div>
</div>
</div>
<div class="edit-btn" @click="handleEdit(item.siteId)">
<div class="edit-btn" @click="handleEdit(item)">
<div class="edit-icon"></div>
<div>站点编辑</div>
</div>
@@ -100,21 +100,48 @@ import {editSite, getSiteDetail, getSiteList, addSite, deleteSite} from "@/api/s
import {ElMessage, ElMessageBox} from "element-plus";
const router = useRouter()
const siteList = ref([])
const siteList = ref([
{
siteName: '松江站',
info:{
tunnelNum: 1,
tunnelName: '一号隧道',
constructionLength: 500,
implementationLength: 10
}
},
{
siteName: '松江站',
info:{
tunnelNum: 1,
tunnelName: '二号隧道',
constructionLength: 500,
implementationLength: 10
}
},
{
siteName: '松江站',
info:{
tunnelNum: 1,
tunnelName: '三号隧道',
constructionLength: 500,
implementationLength: 10
}
}
])
const siteIds = ref([])
const siteNameList = ref([])
const info = ref({
tunnelNum: 0,
tunnelName: '隧道',
tunnelName: '',
constructionLength: 0,
implementationLength: 0
})
const title = ref('新增站点')
const isClick = ref(false);
const isVisited = ref(false);
const total = ref();
const showAddIcon = ref(false)
const showFirstTunnel = ref(true)
const total = ref(10);
const showAddIcon = ref(true)
const pageInfo = reactive({
pageNum: 1,
pageSize: 6
@@ -136,12 +163,13 @@ const getList = () => {
showAddIcon.value = total.value !== 6;
res.data.rows.map(item => {
if (item.tunnelList === null || item.tunnelList === []) {
showFirstTunnel.value = false
item.info = info.value
}else{
item.info=item.tunnelList[0]
}
item.info = info.value
item.checked = false
})
siteList.value = res.data.rows;
// siteList.value = res.data.rows;
});
}
getList()
@@ -163,7 +191,8 @@ const handleClickSite = (type) => {
}
}
const goToAddTunnel = (siteId) => {
router.push('/tunnel/' + siteId)
// router.push('/tunnel/' + siteId)
router.push('/tunnel/1')
}
//重置from表单
const restFrom = () => {
@@ -173,13 +202,14 @@ const restFrom = () => {
describe: ''
}
}
const handleEdit = (siteId) => {
const handleEdit = (item) => {
title.value = '编辑站点'
restFrom()
getSiteDetail(siteId).then((res) => {
form.value = res.data;
// getSiteDetail(item.siteId).then((res) => {
// form.value = res.data;
form.value = item;
isVisited.value = true
});
// });
}
const handleAdd = () => {
@@ -188,20 +218,25 @@ const handleAdd = () => {
isVisited.value = true
}
const handleSubmit = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) return
if (title.value === '编辑站点') {
editSite(form.value).then(() => {
// if (!instance) return
// instance.validate(async (valid) => {
// if (!valid) return
// if (title.value === '编辑站点') {
// editSite(form.value).then(() => {
// isVisited.value = false
// getList()
// });
// } else {
// addSite(form.value).then(() => {
isVisited.value = false
getList()
});
} else {
addSite(form.value).then(() => {
isVisited.value = false
getList()
});
}
// getList()
// });
// }
// })
}
const handleChooseAll=()=>{
siteList.value.map(item=>{
item.checked=!item.checked
})
}
const handleMoreDelete = () => {
@@ -214,24 +249,24 @@ const handleMoreDelete = () => {
type: 'warning',
customClass: 'delBox'
}).then(() => {
deleteSite(siteIds.value).then(res => {
if (res.code === 1000) {
ElMessage.success(res.msg)
getList()
siteIds.value = []
siteNameList.value = []
} else {
ElMessage.error(res.msg)
}
})
// deleteSite(siteIds.value).then(res => {
// if (res.code === 1000) {
// ElMessage.success(res.msg)
// getList()
// siteIds.value = []
// siteNameList.value = []
// } else {
// ElMessage.error(res.msg)
// }
// })
})
}
}
//点击页码进行分页功能
const handleCurrentChange = async (val) => {
const handleCurrentChange = (val) => {
pageInfo.pageNum = val
await getList()
getList()
}
</script>
@@ -254,39 +289,6 @@ const handleCurrentChange = async (val) => {
color: #FFFFFF;
}
.btns {
display: flex;
justify-content: space-around;
margin-top: 80px;
.cancel-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 220px;
height: 80px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #08B7B8;
line-height: 80px;
font-size: 38px;
box-sizing: border-box;
}
.sure-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 220px;
height: 80px;
line-height: 80px;
background: #08B7B8;
border-radius: 11px;
color: #FFFFFF;
font-size: 38px;
}
}
:deep(.el-dialog) {
border: 2px solid #05FEFF;
background: #0D6578;
@@ -399,11 +401,14 @@ const handleCurrentChange = async (val) => {
}
.box-content {
height: 1850px;
display: flex;
flex-wrap: wrap;
padding-left: 100px;
padding-right: 100px;
justify-content: space-between;
box-sizing: border-box;
overflow: hidden;
.add-box {
cursor: pointer;
@@ -425,7 +430,7 @@ const handleCurrentChange = async (val) => {
.site-box {
margin-top: 122px;
//margin-right: 60px;
//margin-right: 1%;
padding: 40px 50px;
width: 1250px;
height: 750px;

View File

@@ -7,16 +7,19 @@
</div>
<div class="tunnel-title"></div>
<div class="all-del-btn">
<div class="all-btn">
<div class="all-btn" style=" margin-right: 40px;" v-if="!showAddIcon" @click="handleAdd">
添加
</div>
<div class="all-btn" @click="handleChooseAll">
全选
</div>
<div class="all-btn del-btn">
<div class="all-btn del-btn" @click="handleMoreDelete">
删除
</div>
</div>
</div>
<div class="box-content">
<div class="site-box" v-for="item in siteList" :key="item.tunnelId">
<div class="site-box" v-for="item in tunnelList" :key="item.tunnelId">
<div class="top">
<span>{{ item.tunnelName }}</span>
<span>施工长度500米 隧道长度10公里</span>
@@ -84,16 +87,19 @@
</el-dialog>
<div class="pagination">
<span>首页</span>
<el-pagination background :page-size="6" :total="50" prev-text="上一页" next-text="下一页" layout="prev, pager, next"/>
<el-pagination background :page-size="6" :total="50" prev-text="上一页" next-text="下一页" layout="prev, pager, next" />
<span>尾页</span>
</div>
</div>
</template>
<script setup>
import {ElMessage, ElMessageBox} from "element-plus";
const router = useRouter()
const showAddIcon = ref(true)
const siteId = reactive(router.currentRoute.value.params.siteId)
const siteList = ref([
const tunnelList = ref([
{
tunnelName: '一号隧道',
num: 1,
@@ -159,51 +165,49 @@ const siteList = ref([
num: 1,
constructionLength: 500,
implementationLength: 10
},
}
])
const iconsList = ref([
{
icon: 'white-state-icon.png',
icon: 'sd_icon_fj.png',
name: '风机',
num: 2
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
icon: 'sd_icon_sd.png',
name: '湿度',
num: '无'
},
{
icon: 'white-state-icon.png',
name: '风',
num: 2
icon: 'sd_icon_fy.png',
name: '风',
num: 10
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
icon: 'sd_icon_yq.png',
name: '氧气',
num: '无'
},
{
icon: 'white-state-icon.png',
name: '风',
icon: 'sd_icon_fs.png',
name: '风',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
icon: 'sd_icon_fc.png',
name: '粉尘',
num: 1
},
{
icon: 'sd_icon_wd.png',
name: '温度',
num: 11
},
{
icon: 'sd_icon_qt.png',
name: '有害气体',
num: '无'
},
])
const title = ref('新增隧道')
const isVisited = ref(false);
@@ -215,12 +219,17 @@ const form = ref({
tunnelLength: '',
remarks: ''
});
const handleChooseAll=()=>{
tunnelList.value.map(item=>{
item.checked=!item.checked
})
}
const handleEdit = () => {
title.value = '编辑隧道'
isVisited.value = true
}
const handleEditDevice = () => {
router.push('/device/'+1)
router.push('/device/' + 1)
}
const handleAdd = () => {
@@ -232,8 +241,8 @@ const getImageUrl = (name) => {
}
const handleClickSite = (type) => {
if (type.checked) {
// tunnelIds.value.push(type.siteId)
// tunnelNameList.value.push(type.siteName)
tunnelIds.value.push(type.siteId)
tunnelNameList.value.push(type.siteName)
} else {
// tunnelIds.value.map((item, index) => {
// if (item === type.siteId) {
@@ -247,6 +256,30 @@ const handleClickSite = (type) => {
// })
}
}
const handleMoreDelete = () => {
if (tunnelIds.value.length === 0) {
ElMessage.warning('请先选择隧道进行删除')
} else {
ElMessageBox.confirm(`是否确定删除该隧道`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
customClass: 'delBox'
}).then(() => {
// deleteSite(tunnelIds.value).then(res => {
// if (res.code === 1000) {
// ElMessage.success(res.msg)
// getList()
// tunnelIds.value = []
// tunnelNameList.value = []
// } else {
// ElMessage.error(res.msg)
// }
// })
})
}
}
</script>
<style scoped lang="scss">
@@ -299,37 +332,6 @@ const handleClickSite = (type) => {
color: #FFFFFF;
}
.btns {
display: flex;
justify-content: space-around;
margin-top: 80px;
.cancel-btn {
cursor: pointer;
width: 220px;
height: 80px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #08B7B8;
line-height: 80px;
padding-left: 67px;
font-size: 38px;
box-sizing: border-box;
}
.sure-btn {
cursor: pointer;
width: 220px;
height: 80px;
line-height: 80px;
background: #08B7B8;
border-radius: 11px;
color: #FFFFFF;
font-size: 38px;
padding-left: 67px;
}
}
.tunnel-bgc {
background-color: #072348;
padding: 85px 0 0 0;
@@ -393,12 +395,14 @@ const handleClickSite = (type) => {
}
.box-content {
height: 1850px;
display: flex;
flex-wrap: wrap;
padding-left: 67px;
padding-right: 70px;
justify-content: space-between;
box-sizing: border-box;
overflow: hidden;
.add-box {
cursor: pointer;
font-weight: bold;
@@ -419,7 +423,7 @@ const handleClickSite = (type) => {
.site-box {
margin-top: 50px;
//margin-right: 122px;
margin-right: 1.5%;
padding: 40px 30px;
width: 925px;
height: 550px;
@@ -427,7 +431,7 @@ const handleClickSite = (type) => {
//box-sizing: border-box;
position: relative;
&:nth-child(3) {
&:nth-child(4n) {
margin-right: 0;
}
@@ -474,13 +478,13 @@ const handleClickSite = (type) => {
display: flex;
align-items: center;
justify-content: space-between;
margin-right:30px;
margin-right: 30px;
}
}
.left-img {
margin-top: 110px;
margin-right: 70px;
margin-right: 50px;
width: 340px;
height: 148px;
background-image: url('@/assets/images/tunnel/sdgl_sdt.png');
@@ -492,7 +496,7 @@ const handleClickSite = (type) => {
display: flex;
align-items: center;
justify-content: flex-start;
font-size: 34px;
font-size: 30px;
color: #60DDDE;
//margin-left: 175px;
@@ -538,10 +542,14 @@ const handleClickSite = (type) => {
justify-content: space-between;
align-items: center;
color: #FFFFFF;
font-size: 36px;
margin-right: 27px;
font-size: 34px;
margin-right: 17px;
margin-bottom: 30px;
&:first-child {
margin-right: 37px;
}
&:nth-child(2n) {
margin-right: 0;
}
@@ -563,7 +571,7 @@ const handleClickSite = (type) => {
align-items: center;
position: absolute;
left: 50%;
transform: translate(-50%,-50%);
transform: translate(-50%, -50%);
bottom: 50px;
color: #60DDDE;
font-size: 38px;

View File

@@ -1,13 +1,20 @@
<template>
<div id="main">
<div class="box-top">
<manage-btn v-model="selectIndex" @select="manageSelect" />
<manage-btn v-model="selectIndex" @select="manageSelect" :list="routeList"/>
<div class="tunnel-title"></div>
<manage-length class="tunnel-length"></manage-length>
<div class="top-right">
<div class="current-site">
当前站点<span>{{ currentSite }}</span>
<div class="toggle"></div>
<el-dropdown trigger="click" @command="handleCommand">
<div class="toggle"></div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in siteList" :key="item.value" :command="item">{{ item.label }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div class="current-user">
上午好<span>{{ currentUser }}</span>
@@ -16,66 +23,33 @@
</div>
</div>
</div>
<tunnel-scene id="tunnel-box" />
<tunnel-scene id="tunnel-box"/>
<div class="left">
<el-drawer
v-model="drawerLeft"
direction="ltr"
modal-class="modal-box"
:modal="false"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<fan-info
v-if="showFan"
:list="socketData.leftData"
:fan-data="largeScreenData"
/>
<transducer-list
:list="socketData.leftData"
:transducer-data="largeScreenData"
/>
<used-ele :list="socketData.leftData" :ele-data="largeScreenData" />
<el-drawer v-model="drawerLeft" direction="ltr" modal-class="modal-box" :modal="false" :show-close="false"
:close-on-click-modal="false" :close-on-press-escape="false">
<fan-info v-if="showFan" :list="socketData.leftData" :fan-data="largeScreenData"/>
<transducer-list v-if="showFan" :list="socketData.leftData" :transducer-data="largeScreenData"/>
<used-ele v-if="showFan" :list="socketData.leftData" :ele-data="largeScreenData"/>
</el-drawer>
<div v-if="drawerLeft" class="left-arrow" @click="closeLeft"></div>
<div v-else class="shrink-left" @click="closeLeft"></div>
</div>
<div class="right">
<el-drawer
v-model="drawerRight"
direction="rtl"
modal-class="modal-box"
:modal="false"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<wind-pressure-list
v-if="showFan"
:list="socketData.windPressure"
:win-data="largeScreenData"
/>
<air-info
v-if="showFan"
:list="socketData.sensor"
:air-data="largeScreenData"
/>
<bad-gas-info
v-if="showFan"
:list="socketData.sensor"
:bad-gas-data="largeScreenData"
/>
<el-drawer v-model="drawerRight" direction="rtl" modal-class="modal-box" :modal="false" :show-close="false"
:close-on-click-modal="false" :close-on-press-escape="false">
<wind-pressure-list v-if="showFan" :list="socketData.windPressure" :win-data="largeScreenData"/>
<air-info v-if="showFan" :list="socketData.sensor" :air-data="largeScreenData"/>
<bad-gas-info v-if="showFan" :list="socketData.sensor" :bad-gas-data="largeScreenData" :tunnelId="tunnelId"/>
</el-drawer>
<div v-if="drawerRight" class="right-arrow" @click="closeRight"></div>
<div v-else class="shrink-right" @click="closeRight"></div>
</div>
<div class="switch-btn">
<div class="arrow" @click="previousBtn"></div>
<el-carousel height="150px" type="card" ref="tunnelBtn" :autoplay="false">
<el-carousel height="150px" type="card" ref="tunnelBtn" :autoplay="false" @change="changeTunnel">
<div class="btn">
<el-carousel-item v-for="item in tunnelList" :key="item.value">
{{ item.name }}
{{ item.label }}
</el-carousel-item>
</div>
</el-carousel>
@@ -94,12 +68,12 @@ import AirInfo from "@/components/content/airInfo/AirInfo.vue";
import BadGasInfo from "@/components/content/badGasInfo/BadGasInfo.vue";
import ManageBtn from "@/components/manageBtn/index.vue";
import ManageLength from "@/components/manageLength/index.vue";
import { dateFormat } from "@/utils/date.js";
import { onMounted } from "vue";
import { getToken } from "@/utils/auth";
import { useAuthStore } from "@/store/userstore.js";
import { getLargeScreen } from "@/api/largeScreen";
import {dateFormat} from "@/utils/date.js";
import {getToken} from "@/utils/auth";
import {useAuthStore} from "@/store/userstore.js";
import {getLargeScreen, getLargeScreenInfo, getTunnelBySiteId} from "@/api/largeScreen";
import {ElMessageBox} from "element-plus";
import {getUserInfo} from "@/api/login";
const authStore = useAuthStore();
const router = useRouter();
@@ -107,36 +81,14 @@ const selectIndex = ref(-1);
const showFan = ref(false);
const drawerLeft = ref(true);
const drawerRight = ref(true);
const currentSite = ref("松江站");
const currentUser = ref("admin");
const currentSite = ref("");
const siteList = ref([])
const currentUser = ref("");
const currentDate = ref(dateFormat());
const tunnelBtn = ref();
const tunnelList = ref([
{
value: 0,
name: "一号隧道",
},
{
value: 1,
name: "二号隧道",
},
{
value: 2,
name: "三号隧道",
},
{
value: 3,
name: "四号隧道",
},
{
value: 4,
name: "五号隧道",
},
{
value: 5,
name: "六号隧道",
},
]);
const tunnelList = ref([]);
const tunnelId = ref(0);
const routeList = ref([]);
let socket = reactive("");
const serialNumber = ref("SC00DY00GH00ELBT");
let token = getToken();
@@ -154,24 +106,72 @@ onMounted(() => {
nextTick(() => {
showFan.value = true;
});
getScreenInfo();
getUser()
getOtherInfo()
});
const getScreenInfo = async () => {
await getLargeScreen(1).then((res) => {
const getUser = () => {
getUserInfo().then(res => {
currentUser.value = res.data.user.userName
})
}
const getOtherInfo = () => {
getLargeScreenInfo().then((res) => {
if (res?.code === 1000) {
routeList.value = res.data.routeList
currentSite.value = res.data.siteOption[0].label
siteList.value = res.data.siteOption
tunnelId.value = res.data.tunnelOption[0].value
getTunnel(res.data.siteOption[0].value)
getScreenInfo(tunnelId.value);
}
});
};
const getScreenInfo = async (id) => {
await getLargeScreen(id).then((res) => {
if (res?.code === 1000) {
largeScreenData.value = res.data;
}
});
};
//根据站点id获取隧道信息
const getTunnel = (id) => {
getTunnelBySiteId(id).then((res) => {
if (res?.code === 1000) {
tunnelList.value = res.data
getScreenInfo(res.data[0].value)
}
});
}
const changeTunnel = (e) => {
tunnelId.value = e
let newObj = {}
tunnelList.value.forEach((item, index) => {
if (index === e) {
newObj = item
}
})
getScreenInfo(newObj.value)
nextTick(() => {
showFan.value = true;
});
}
const manageSelect = (index) => {
console.log("首页点击-", index);
if (index === 0) {
router.push("/site");
}else if (index === 1){
} else if (index === 1) {
router.push("/tunnel/1");
}else if (index === 2) {
router.push("/user");
}
};
const handleCommand=(item)=>{
console.log('commads',item)
currentSite.value=item.label
getTunnel(item.value)
}
const closeLeft = () => {
drawerLeft.value = !drawerLeft.value;
};
@@ -239,12 +239,54 @@ const closeSocket = () => {
};
initWebSocket();
</script>
<style lang="scss">
.el-dropdown__popper.el-popper {
background: transparent;
//border: none;
border: 1px solid #0E7DAA;
border-radius: 10px;
}
.is-light{
background:rgba(7,35,72,0.9);
}
.el-popper{
padding: 20px;
margin-left: 50px;
width: 150px;
background:rgba(7,35,72,0.9);
.el-scrollbar__wrap {
.el-dropdown__list {
.el-dropdown-menu {
background-color:rgba(7,35,72,0.9);
border-radius: 10px;
padding: 5px;
.el-dropdown-menu__item{
color: #FFFFFF;
//border:none;
padding: 5px;
border-bottom: 1px solid #05FEFF;
&:last-child{
border-bottom: none;
}
}
.el-dropdown-menu__item.hover,.el-dropdown-menu__item:hover{
background-color:transparent!important;
color: #F7B500;
}
}
}
}
}
</style>
<style lang="scss" scoped>
#main {
height: 100%;
width: 100%;
background-color: #072348;
#tunnel-box {
height: 100%;
}

View File

@@ -0,0 +1,169 @@
<template>
<div id="main">
<div class="box-top">
<manage-btn v-model="selectIndex" @select="manageSelect" :list="routeList" />
<div class="tunnel-title"></div>
<manage-length class="tunnel-length"></manage-length>
<div class="top-right">
<div class="current-site">
当前站点<span>{{ currentSite }}</span>
<div class="toggle"></div>
</div>
<div class="current-user">
上午好<span>{{ currentUser }}</span>
<span>今天是{{ currentDate }}</span>
<div class="logout" @click="handleLogout"></div>
</div>
</div>
</div>
<tunnel-scene id="tunnel-box" />
</div>
</template>
<script setup>
import TunnelScene from "@/components/content/tunnelScene/TunnelScene.vue";
import ManageBtn from "@/components/manageBtn/index.vue";
import ManageLength from "@/components/manageLength/index.vue";
import { dateFormat } from "@/utils/date.js";
import { onMounted } from "vue";
import { getToken } from "@/utils/auth";
import { useAuthStore } from "@/store/userstore.js";
import { getLargeScreen, getLargeScreenInfo } from "@/api/largeScreen";
import { ElMessageBox } from "element-plus";
const authStore = useAuthStore();
const router = useRouter();
const selectIndex = ref(-1);
const showFan = ref(false);
const drawerLeft = ref(true);
const drawerRight = ref(true);
const currentSite = ref("松江站");
const currentUser = ref("admin");
const currentDate = ref(dateFormat());
const tunnelBtn = ref();
const tunnelList = ref([]);
const routeList = ref([]);
let socket = reactive("");
const serialNumber = ref("SC00DY00GH00ELBT");
let token = getToken();
let send = {
type: "ping",
};
const largeScreenData = ref(null);
const socketData = reactive({
leftData: [],
windPressure: [],
sensor: [],
});
onMounted(() => {
nextTick(() => {
showFan.value = true;
});
getOtherInfo()
getScreenInfo();
});
const getOtherInfo = async () => {
await getLargeScreenInfo().then((res) => {
if (res?.code === 1000) {
routeList.value = res.data.routeList
currentSite.value = res.data.siteOption[0].label
tunnelList.value = res.data.tunnelOption
}
});
};
const getScreenInfo = async () => {
await getLargeScreen(1).then((res) => {
if (res?.code === 1000) {
largeScreenData.value = res.data;
}
});
};
const manageSelect = (index) => {
console.log("首页点击-", index);
if (index === 0) {
router.push("/site");
} else if (index === 1) {
router.push("/tunnel/1");
}
};
const closeLeft = () => {
drawerLeft.value = !drawerLeft.value;
};
const closeRight = () => {
drawerRight.value = !drawerRight.value;
};
const handleLogout = () => {
ElMessageBox.confirm(`确认退出登录吗`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
authStore.userLogout();
router.push("/login");
})
};
const previousBtn = () => {
tunnelBtn.value.prev();
};
const nextBtn = () => {
tunnelBtn.value.next();
};
const initWebSocket = () => {
// let wsUrl = `ws://192.168.31.175:9000/websocket/equipment/${token}/${serialNumber.value}`
let wsUrl = `ws://web-tunnel.feashow.com/api/wstunnel/websocket/equipment/${token}/${serialNumber.value}`;
console.log(wsUrl);
socket = new WebSocket(wsUrl);
//连接发生错误的回调方法
socket.onerror = function () {
console.log("ws连接发生错误");
};
//连接成功建立的回调方法
socket.onopen = function () {
console.log("ws连接成功");
};
//接收到消息的回调方法
socket.onmessage = function (event) {
console.log("服务器返回的信息: ", JSON.parse(event.data));
const type = JSON.parse(event.data).type;
const data = JSON.parse(event.data).data;
if (type === "equipment") {
data.forEach((item) => {
if (item.typeKey === "frequency") {
socketData.leftData = data;
} else if (item.typeKey === "windPressure") {
socketData.windPressure = data;
} else if (item.typeKey === "sensor") {
socketData.sensor = data;
}
});
}
};
//连接关闭的回调方法
socket.onclose = function () {
console.log("ws连接关闭");
// initWebSocket()
};
setInterval(() => {
socket.send(JSON.stringify(send));
}, 30000);
};
const closeSocket = () => {
socket.close();
};
initWebSocket();
</script>
<style lang="scss" scoped>
#main {
height: 100%;
width: 100%;
background-color: #072348;
#tunnel-box {
height: 100%;
}
}
</style>

472
src/views/user/index.vue Normal file
View File

@@ -0,0 +1,472 @@
<template>
<div class="tunnel-bgc">
<div class="box-top">
<div class="back-tunnel" @click="router.push('/')">
<div class="back-icon"></div>
<span>返回</span>
</div>
<div class="tunnel-title"></div>
<div class="all-del-btn">
<div class="all-btn" @click="handleAll">
全选
</div>
<div class="all-btn del-btn" @click="handleMoreDelete">
删除
</div>
</div>
</div>
<div class="user-content">
<div class="user-box">
<div class="user-top">
<div class="search-box">
<div>
<el-input
v-model="username"
placeholder="输入搜索内容"
/>
</div>
<el-button type="primary" :icon="Search" style="margin-left: 20px">搜索</el-button>
</div>
<div>用户管理</div>
<div class="add-btn" @click="addUser">添加用户</div>
</div>
<div class="device-table">
<el-table stripe ref="multipleTable"
style="border-bottom: 1px #06e5e5 solid;background-color: #011c29;--el-table-border-color: none;margin-top: 80px;"
:header-cell-style="{backgroundColor: '#064B66',color: '#fff',fontSize: '40px',borderBottom: 'none' }"
:cell-style="{textAlign: 'center',borderBottom: 'none'}" :data="userData">
<el-table-column type="selection" width="80"/>
<el-table-column prop="account" label="账户" align="center"/>
<el-table-column prop="password" label="密码" align="center"/>
<el-table-column prop="identity" label="身份" align="center"/>
<el-table-column label="操作" align="center">
<template #default>
<el-button link type="primary" size="large" style="font-size: 40px;color: #17E1E2;" @click="editUser">
修改
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<el-dialog v-model="isVisited" width="1658px">
<div class="siteId">
<span>{{ title }}</span>
</div>
<el-form :model="form" :label-position="right" :rules="formRules" ref="formInstance" label-width="168px">
<el-form-item label="输入账户">
<el-input v-model="form.account" placeholder="请输入账户"/>
</el-form-item>
<el-form-item label="输入密码">
<el-input v-model="form.password" placeholder="请输入密码"/>
</el-form-item>
<el-form-item label="选择身份">
<el-checkbox-group v-model="form.identity" @change="handleChangeCheckbox">
<el-checkbox v-for="item in checkList" :label="item.label" :key="item.value"/>
</el-checkbox-group>
</el-form-item>
</el-form>
<template #footer>
<div class="btns">
<div class="cancel-btn" @click="isVisited=false">
取消
</div>
<div class="sure-btn" @click="handleSubmit(formInstance)">
确定
</div>
</div>
</template>
</el-dialog>
<div class="pagination">
<span>首页</span>
<el-pagination background v-model:current-page="pageInfo.pageNum" v-model:page-size="pageInfo.pageSize"
:total="total" prev-text="上一页" next-text="下一页" layout="prev, pager, next"
@current-change="handleCurrentChange"/>
<span>尾页</span>
</div>
</div>
</template>
<script setup>
import {Search} from '@element-plus/icons-vue'
const router = useRouter()
const username = ref()
const userData = ref([
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
},
{
account: '123343546',
password: '243',
identity: '超级管理员'
}
])
const pageInfo = reactive({
pageNum: 1,
pageSize: 6
});
const total = ref(10);
const isVisited = ref(false);
const form = ref({
password: '',
account: '',
identity: []
});
const formRules = ref({
account: [{required: true, message: '请输入站点名称', trigger: 'blur'}],
password: [{required: true, message: '请输入密码', trigger: 'blur'}]
})
const checkList = ref([
{label: "系统管理员", value: 111},
{label: "站点管理员", value: 222},
{label: "隧道管理员", value: 333},
{label: "巡查员", value: 444}
])
const multipleTable = ref()
const addUser = () => {
isVisited.value = true
}
const editUser = () => {
isVisited.value = true
}
const handleAll = () => {
multipleTable.value.toggleAllSelection()
}
</script>
<style scoped lang="scss">
.tunnel-bgc {
padding: 85px 0 0 0;
width: 100%;
height: 100%;
background-image: url('@/assets/images/tunnel/sd_bj.png');
.box-top {
display: flex;
justify-content: space-between;
.back-tunnel {
cursor: pointer;
margin: 0 0 0 70px;
display: flex;
align-items: center;
width: 178px;
height: 70px;
line-height: 70px;
border-radius: 11px;
border: 2px solid #08B7B8;
font-size: 38px;
color: #FFFFFF;
.back-icon {
margin-right: 20px;
margin-left: 23px;
width: 33px;
height: 33px;
background-image: url('@/assets/images/site/zdgl_icon_fh.png');
}
}
.all-del-btn {
display: flex;
.del-btn {
width: 168px;
height: 60px;
background: #08B7B8;
border-radius: 11px;
}
.all-btn {
cursor: pointer;
padding-left: 53px;
width: 178px;
height: 70px;
line-height: 70px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #FFFFFF;
font-size: 38px;
&:last-child {
margin-left: 40px;
margin-right: 70px;
}
}
}
}
.user-content {
display: flex;
justify-content: center;
margin-top: 247px;
.user-box {
display: flex;
flex-direction: column;
width: 2194px;
height: 1480px;
background: #064B66;
border-radius: 20px;
border: 2px solid #05FEFF;
box-sizing: border-box;
padding: 73px 98px;
.user-top {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
> div:nth-child(2) {
margin-left: -250px;
height: 61px;
font-size: 46px;
font-weight: bold;
color: #FFFFFF;
line-height: 61px;
}
.add-btn {
cursor: pointer;
width: 170px;
height: 60px;
line-height: 60px;
background: #08B7B8;
border-radius: 6px;
color: #FFFFFF;
font-size: 35px;
padding-left: 19px;
}
.search-box {
display: flex;
:deep(.el-button) {
width: 140px;
height: 60px;
background: #08B7B8;
border-radius: 6px;
border: none;
font-size: 35px;
color: #FFFFFF;
}
:deep(.el-input__wrapper) {
width: 292px;
height: 60px;
border-radius: 6px;
border: 1px solid #05FEFF;
background-color: transparent;
font-size: 35px;
.el-input__inner {
height: 60px;
line-height: 60px;
color: #FFFFFF;
}
}
}
}
:deep(.el-table--fit) {
width: 2000px !important;
}
:deep(.cell) {
height: 80px;
line-height: 80px;
color: #fff;
font-size: 38px;
}
:deep(.el-table tr) {
background-color: #1C5971;
}
:deep(.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell) {
background-color: #1C5971;
}
:deep(.el-table__row--striped) {
background-color: #13849C !important;
}
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell) {
background-color: #13849C !important;
}
:deep(.el-table__inner-wrapper::before) {
display: none;
}
}
}
:deep(.el-dialog) {
border: 2px solid #05FEFF;
background: #0D6578;
border-radius: 20px;
padding: 30px 40px;
box-sizing: border-box;
margin: 458px auto 0 auto;
.el-dialog__header {
padding: 0;
display: none;
}
}
:deep(.el-form-item) {
margin-top: 40px;
}
:deep(.el-form-item__label) {
font-size: 38px;
font-family: MicrosoftYaHei;
color: #FFFFFF;
margin-right: 12px;
line-height: 50px;
}
:deep(.el-input) {
height: 75px;
.el-input__wrapper {
background-color: transparent;
border: 1px solid #08B7B8;
.el-input__inner {
height: auto;
color: #fff;
font-size: 38px;
}
}
}
:deep(.el-checkbox-group) {
margin-top: 10px;
}
:deep(.el-checkbox__label) {
color: #FFFFFF;
font-size: 38px;
}
.pagination {
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
bottom: 90px;
display: flex;
align-items: center;
color: #60DDDE;
font-size: 38px;
font-weight: bold;
> span:first-child {
cursor: pointer;
margin-right: 60px;
}
> span:last-child {
cursor: pointer;
margin-left: 71px;
}
:deep(.btn-prev) {
background-color: transparent;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;
margin-right: 20px;
}
:deep(.btn-next) {
background-color: transparent;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;
margin-left: 30px;
}
:deep(.el-pager li.is-active ) {
width: 70px;
height: 70px;
background: #60DDDE;
border-radius: 50%;
color: #071F40;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
}
:deep(.el-pager li) {
margin-left: 40px;
}
:deep(.el-pager li:not(.is-active) ) {
width: 70px;
height: 70px;
border: 1px solid #60DDDE;
border-radius: 50%;
background-color: transparent;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;
}
}
}
</style>