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

Reviewed-on: http://git.feashow.cn/clay/tunnel-cloud-web/pulls/147
This commit is contained in:
odjbin
2023-12-16 08:35:10 +00:00
44 changed files with 83160 additions and 20626 deletions

File diff suppressed because it is too large Load Diff

40418
public/devicesModel/model.obj Normal file

File diff suppressed because it is too large Load Diff

40418
public/devicesModel/model2.obj Normal file

File diff suppressed because it is too large Load Diff

35
src/api/site.js Normal file
View File

@@ -0,0 +1,35 @@
import request from '@/utils/request.js'
export const getSiteList = (params) => {
return request({
url: '/tunnel/site/screenlist',
method: 'get',
params
})
}
export const getSiteDetail = (siteId) => {
return request({
url: `/tunnel/site/${siteId}`,
method: 'get'
})
}
export const editSite = (data) => {
return request({
url: '/tunnel/site',
method: 'put',
data
})
}
export const addSite = (data) => {
return request({
url: '/tunnel/site',
method: 'post',
data
})
}
export const deleteSite = (siteIdList) => {
return request({
url: `/tunnel/site/${siteIdList}`,
method: 'delete'
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -18,13 +18,13 @@ html, body, #app, .el-container, .el-aside, .el-main {
}
.tunnel-title {
width: 2330px;
height: 156px;
width: 1718px;
height: 146px;
z-index: 2;
position: absolute;
top: 0;
left: 50%;
margin-left: -1165px;
margin-left: -859px;
background-image: url('../images/topAndDown/sp_tb.png');
}
@@ -247,32 +247,39 @@ html, body, #app, .el-container, .el-aside, .el-main {
//弹窗样式
.digital-tunnel {
#container {
height: 650px;
width: 1300px;
}
#containerEle {
height: 564px;
width: 1300px;
.chat-dialog{
display: flex;
#container {
flex: 1;
height: 1160px;
//width: 1300px;
}
#containerEle {
flex: 1;
height: 1060px;
//width: 2180px;
}
}
.el-dialog {
position: relative;
display: flex;
flex-direction: column;
height: 785px;
height: 1300px;
border: 2px solid #0F82AF;
background: rgba(6, 34, 71, 0.78);
border-radius: 20px;
padding: 47px 30px;
box-sizing: border-box;
margin: 588px auto 0 auto;
margin: 520px auto 0 auto;
.el-dialog__header {
padding:0 0 25px 0;
padding: 0 0 28px 0;
//display: none;
.el-dialog__title {
font-size: 32px;
font-size: 50px;
font-weight: bold;
color: #D6F1FA;
}
@@ -339,8 +346,8 @@ html, body, #app, .el-container, .el-aside, .el-main {
justify-content: center;
.allUsedEle {
width: 240px;
height: 149px;
width: 300px;
height: 200px;
border-radius: 10px;
border: 2px solid #0F82AF;
display: flex;
@@ -355,19 +362,123 @@ html, body, #app, .el-container, .el-aside, .el-main {
display: flex;
justify-content: center;
align-items: center;
width: 240px;
height: 50px;
width: 300px;
height: 100px;
background: #264A78;
font-size: 26px;
font-size: 45px;
color: #FFFFFF;
}
.value {
margin-top: 20px;
font-size: 40px;
margin-top: 15px;
font-size: 50px;
font-family: MicrosoftYaHei;
color: #FFFFFF;
}
}
}
}
}
.el-overlay-message-box{
.el-message-box{
width: 500px;
height: 230px;
background: rgba(7,35,72,0.79);
border-radius: 20px;
border: 2px solid #0F82AF;
.el-message-box__title{
display: none;
}
.el-message-box__content{
.el-icon{
display: none;
}
.el-message-box__message{
//width: 315px;
height: 80px;
font-size: 32px;
font-weight: bold;
color: #08B7B8;
letter-spacing: 3px;
}
}
.el-message-box__btns{
display: flex;
justify-content: space-around;
.el-button{
width: 130px;
height: 50px;
border: 2px solid #0F82AF;
font-size: 28px;
background-color: #072348;
color: #08B7B8;
}
.el-button--primary{
background: #08B7B8;
color: #FFFFFF;
}
}
}
}
//el-select 下拉框样式
.el-select__popper {
margin-top: -12px!important;
background: #072247!important;
border: 1px solid #0F82AF!important;
}
.el-popper {
max-width: 202px!important;
box-sizing: border-box;
}
.el-popper__arrow::before{
display: none;
}
.el-select-dropdown{
width: 200px!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;
color: #08B7B8!important;
}
.el-select-dropdown__item.selected {
color: #08B7B8!important;
}
.el-select-dropdown__list{
.el-select-dropdown__item:first-child{
color: #FFFFFF;
&:hover{
color: #08B7B8!important;
}
}
}
//input number 右侧加减隐藏
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type="number"] {
-moz-appearance: textfield;
}
//checkbox
.el-checkbox__inner {
width: 40px !important;
height: 40px !important;
border-radius: 25px!important;
}
.el-checkbox__input.is-checked .el-checkbox__inner {
width: 25px;
height: 25px;
background-color: #05FEFF!important;
}
.el-checkbox__input.is-checked .el-checkbox__inner::after {
display: none;
}

View File

@@ -1,20 +1,36 @@
<template>
<div id="bad-gas-info">
<div
id="bad-gas-info"
:style="{ backgroundImage: 'url(' + getImageUrl(bgImage) + ')' }"
@click="handleOpenChart"
>
<div class="title">有害气体</div>
<div class="info-list">
<gas-info-item v-for="item in badGasList" :key="item.equipmentId" :gasInfo="item" @click="handleOpenChart"/>
<gas-info-item
v-for="item in badGasList"
:key="item.equipmentId"
:gasInfo="item"
/>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isVisited" title="有害气体监控数据" width="1365px" :modal="false">
<el-dialog
v-model="isVisited"
title="有害气体监控数据"
width="2400px"
:modal="false"
>
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div id="container"></div>
<div class="chat-dialog">
<div id="container"></div>
<div style="width: 1px"></div>
</div>
<div class="time-select">
<time-range-btn
:buttonList="timeList"
v-model="selectTimeButton"
@select="timeSelect"
width="124px"
:buttonList="timeList"
v-model="selectTimeButton"
@select="timeSelect"
/>
</div>
<div class="left-bottom-icon"></div>
@@ -26,53 +42,68 @@
<script setup>
import GasInfoItem from "./childComps/GasInfoItem.vue";
import * as echarts from 'echarts';
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue"
import * as echarts from "echarts";
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue";
const props = defineProps({
list: Array,
badGasData: Array
badGasData: Array,
});
const timeList = ref(["年", "月", "日"]);
const selectTimeButton = ref(0);
const selectTimeButton = ref(2);
const isVisited = ref(false);
const badGasList = ref([])
const badGasList = ref([]);
let myEcharts = reactive({});
const bgImage = computed(() => (isVisited.value ? "sp_active.png" : "bg.png"));
watch(
() => props.list,
(now) => {
badGasList.value.forEach((item) => {
now.forEach((newItem) => {
if (item.equipmentId === newItem.equipmentId) {
item.value = newItem.value;
}
});
});
},
{ deep: true }
);
watch(() => props.list, (now) => {
badGasList.value.forEach(item => {
now.forEach(newItem => {
if (item.equipmentId === newItem.equipmentId) {
item.value = newItem.value
}
})
})
}, {deep: true});
watch(() => props.badGasData, (now) => {
getBadGasInfo(now.sensorList)
}, {deep: true});
watch(
() => props.badGasData,
(now) => {
getBadGasInfo(now.sensorList);
},
{ deep: true }
);
const timeSelect = (index) => {
console.log('选择时间', index)
if(index===0){
console.log('--年')
}else if(index===1){
console.log('--月')
}else if(index===2){
console.log('--日')
console.log("选择时间", index);
if (index === 0) {
console.log("--年");
} else if (index === 1) {
console.log("--月");
} else if (index === 2) {
console.log("--日");
}
};
const getBadGasInfo = (now) => {
let windPressureObj = {}
let windPressureArr = []
now.map(item => {
if (item.equipmentType === "carbonDioxide" || item.equipmentType === "carbonMonoxide" || item.equipmentType === "hydrogenSulfide" || item.equipmentType === "sulfurDioxide" || item.equipmentType === "sulfurMonoxide" || item.equipmentType === "nitrogenDioxide") {
windPressureObj = changeData(item)
windPressureArr.push(windPressureObj)
let windPressureObj = {};
let windPressureArr = [];
now.map((item) => {
if (
item.equipmentType === "carbonDioxide" ||
item.equipmentType === "carbonMonoxide" ||
item.equipmentType === "hydrogenSulfide" ||
item.equipmentType === "sulfurDioxide" ||
item.equipmentType === "sulfurMonoxide" ||
item.equipmentType === "nitrogenDioxide"
) {
windPressureObj = changeData(item);
windPressureArr.push(windPressureObj);
}
})
badGasList.value = windPressureArr
}
});
badGasList.value = windPressureArr;
};
const changeData = (item) => {
return {
equipmentId: item.equipmentId,
@@ -80,38 +111,43 @@ const changeData = (item) => {
max: 120,
value: item.value,
point: item.valueThreshold,
unit: item.unit
}
}
unit: item.unit,
};
};
const handleOpenChart = () => {
console.log('有害气体弹窗')
isVisited.value = true
console.log("有害气体弹窗");
isVisited.value = true;
nextTick(() => {
initChart()
})
}
initChart();
});
};
const getImageUrl = (name) => {
return new URL(`../../../assets/images/badGasInfo/${name}`, import.meta.url)
.href;
};
/**
* 初始化echarts实例方法
*/
const initChart = () => {
//3.初始化container容器
myEcharts = echarts.init(document.getElementById('container'));
myEcharts = echarts.init(document.getElementById("container"));
//5.传入数据
let option = {
//图例
legend: {
left: 0,
textStyle: {
color: '#FFFFFF',
fontSize: 28
color: '#60DDDE',
fontSize: 40
},
// itemWidth: 20,
// itemHeight: 20
itemWidth: 30,
itemHeight: 30,
icon: "circle",
},
//离容器四侧的距离
grid: {
left: 0, // 左边距
right: 0, // 右边距
right: 20, // 右边距
top: 80, // 顶边距
bottom: 0, // 底边距
containLabel: true,
@@ -119,102 +155,158 @@ const initChart = () => {
//提示框组件
tooltip: {
show: true,
trigger: 'axis'
trigger: "axis",
textStyle: {
fontSize: 40
}
},
//X轴
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
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: 24,
color: '#D6F1FA'
fontSize: 45,
color: "#D6F1FA",
},
},
},
//Y轴
yAxis: {
type: 'value',
type: "value",
axisLabel: {
textStyle: {
fontSize: 24,
color: '#D6F1FA'
fontSize: 45,
color: "#D6F1FA",
},
},
},
//配置项
series: [
{
name: '二氧化碳',
data: [5, 9, 10, 7, 8, 15, 12],
type: 'line',
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
}
width: 5,
},
},
{
name: '一氧化碳',
data: [8, 15, 5, 9, 10, 7, 12],
type: 'line',
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,
],
type: "line",
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
width: 5,
},
},
{
name: '二氧化氮',
data: [5, 15, 1, 9, 10, 7, 8],
type: 'line',
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,
],
type: "line",
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
width: 5,
},
},
{
name: '二氧化硫',
data: [8, 15, 12, 5, 9, 2, 7],
type: 'line',
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,
],
type: "line",
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
width: 5,
},
},
{
name: '硫化氢',
data: [2, 9, 10, 15, 12, 7, 8,],
type: 'line',
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,
],
type: "line",
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5
}
width: 5,
},
},
]
}
{
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,
],
type: "line",
smooth: true,
symbolSize: 24,
lineStyle: {
width: 5,
},
},
],
};
myEcharts.setOption(option);
//图表大小自适应窗口大小变化
window.onresize = () => {
myEcharts.resize();
}
}
};
};
</script>
<style lang="scss" scoped>
#bad-gas-info {
cursor: pointer;
position: absolute;
z-index: 100;
width: 824px;
height: 621px;
top: 1441px;
right: 72px;
background-image: url(@/assets/images/badGasInfo/bg.png);
background-image: url(../../../assets/images/badGasInfo/bg.png);
.title {
width: 128px;

View File

@@ -2,30 +2,30 @@
<div id="fan_info">
<div class="title">风机</div>
<div class="fans">
<div class="fan-item">
<div class="fan-item" v-for="(item,index) in socketData" :key="item.equipmentId">
<!-- echarts -->
<div class="echart" ref="info1"></div>
<div class="echart"></div>
<!-- 风机名 -->
<div class="fan-name">号风机</div>
<div class="fan-name">{{ changeNum(index + 1) }}号风机</div>
<!-- 功能 -->
<div class="option-nav">
<div class="state " :class="{ 'blue-state': isStartOne }">
<div :class="{ stopColor: !stateOne }">
<div :style="{ backgroundImage: 'url(' +getImageUrl(stateIconOne)+')' }" class="state-icon"></div>
状态{{ stateOne ? '运行' : '故障' }}
<div class="state " :class="{ 'blue-state': !item.breakdown }">
<div :class="{ stopColor: item.breakdown }">
<div :style="{ backgroundImage: 'url(' +getImageUrl(item.breakdown)+')' }" class="state-icon"></div>
状态{{ item.breakdown ? '故障' : '运行' }}
</div>
<div class="switch">
<div
id="auto"
:class="{ active: isStartOne }"
@click="isStartOne = true"
:class="{ active: item.running }"
@click="item.running = true"
>
启动
</div>
<div
id="stop"
:class="{ active: !isStartOne }"
@click="isStartOne = false"
:class="{ active: !item.running }"
@click="item.running = false"
>
停止
</div>
@@ -33,9 +33,9 @@
</div>
<div class="power">
<div class="check-box">
<el-radio-group v-model="isSAuto1" class="radio-group">
<el-radio label="true">自动</el-radio>
<el-radio label="false">手动</el-radio>
<el-radio-group v-model="item.autoMode" class="radio-group">
<el-radio :label="true">自动</el-radio>
<el-radio :label="false">手动</el-radio>
</el-radio-group>
</div>
<div class="edit-power">
@@ -44,107 +44,13 @@
><input
type="number"
min="0"
v-model="powerOne"
:disabled="isSAuto1 === 'true'"
v-model="item.frequencyFeedback"
:disabled="item.autoMode"
/></span>
</div>
</div>
</div>
</div>
<div class="fan-item">
<!-- echarts -->
<div class="echart" ref="info2"></div>
<!-- 风机名称 -->
<div class="fan-name">二号风机</div>
<!-- 功能 -->
<div class="option-nav">
<div class="state" :class="{ 'blue-state': isStartTwo }">
<div :class="{ stopColor: !stateTwo }">
<div :style="{ backgroundImage: 'url(' +getImageUrl(stateIconTwo)+')' }" class="state-icon"></div>
状态{{ stateTwo ? '运行' : '故障' }}
</div>
<div class="switch">
<div
:class="{ active: isStartTwo }"
@click="isStartTwo = true"
>
启动
</div>
<div
:class="{ active: !isStartTwo }"
@click="isStartTwo = false"
>
停止
</div>
</div>
</div>
<div class="power">
<div class="check-box">
<el-radio-group v-model="isSAuto2" class="radio-group">
<el-radio label="true">自动</el-radio>
<el-radio label="false">手动</el-radio>
</el-radio-group>
</div>
<div class="edit-power">
<span style="color: white">当前功率</span>
<span class="units"
><input
type="number"
min="0"
v-model="powerTwo"
:disabled="isSAuto2 === 'true'"
/></span>
</div>
</div>
</div>
</div>
<!-- <div class="fan-item">-->
<!-- &lt;!&ndash; echarts &ndash;&gt;-->
<!-- <div class="echart" ref="info3"></div>-->
<!-- &lt;!&ndash; 风机名称 &ndash;&gt;-->
<!-- <div class="fan-name">三号风机</div>-->
<!-- &lt;!&ndash; 功能 &ndash;&gt;-->
<!-- <div class="option-nav">-->
<!-- <div class="state" :class="{ 'blue-state': isStartTwo }">-->
<!-- <div :class="{ stopColor: !stateTwo }">-->
<!-- <div :style="{ backgroundImage: 'url(' +getImageUrl(stateIconTwo)+')' }" class="state-icon"></div>-->
<!-- 状态{{ stateTwo ? '运行' : '故障' }}-->
<!-- </div>-->
<!-- <div class="switch">-->
<!-- <div-->
<!-- :class="{ active: isStartTwo }"-->
<!-- @click="isStartTwo = true"-->
<!-- >-->
<!-- 启动-->
<!-- </div>-->
<!-- <div-->
<!-- :class="{ active: !isStartTwo }"-->
<!-- @click="isStartTwo = false"-->
<!-- >-->
<!-- 停止-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="power">-->
<!-- <div class="check-box">-->
<!-- <el-radio-group v-model="isSAuto2" class="radio-group">-->
<!-- <el-radio label="true">自动</el-radio>-->
<!-- <el-radio label="false">手动</el-radio>-->
<!-- </el-radio-group>-->
<!-- </div>-->
<!-- <div class="edit-power">-->
<!-- <span style="color: white">当前功率</span>-->
<!-- <span class="units"-->
<!-- ><input-->
<!-- type="number"-->
<!-- min="0"-->
<!-- v-model="powerThree"-->
<!-- :disabled="isSAuto2 === 'true'"-->
<!-- /></span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</template>
@@ -156,61 +62,51 @@ const props = defineProps({
list: Array,
fanData: Array
});
//当前功率
const powerOne = ref()
const powerTwo = ref()
const powerThree = ref(555)
//状态
const stateOne = ref()
const stateTwo = ref()
// 一号风机启动停止按钮
const isStartOne = ref(true);
const isStartTwo = ref(true);
// 功率是否自动
let isSAuto1 = ref("false");
let isSAuto2 = ref("false");
const socketData = ref()
// 一号风机echarts实例
const info1 = ref(null);
let Echarts_info1 = null;
// 二号风机实例
const info2 = ref(null);
let Echarts_info2 = null;
const info3 = ref(null);
let Echarts_info3 = null;
let fan01_option = reactive();
let fan02_option = reactive();
let fan03_option = reactive();
watch(() => props.fanData, (now) => {
getBasicData(now.frequencyChangerList)
}, {deep: true});
watch(() => props.list, (now) => {
console.log('socketDatawatch------------', now)
socketData.value.forEach(item => {
now.forEach(newItem => {
if (item.equipmentId === newItem.equipmentId) {
if(newItem.frequencyFeedback){
item.frequencyFeedback= newItem.frequencyFeedback
if (newItem.frequencyFeedback) {
item.frequencyFeedback = newItem.frequencyFeedback
}
}
})
})
// socketData.value=now
}, {deep: true});
const stateIconOne = computed(() =>
stateOne.value
? "blue-state-icon.png"
: "red-state-icon.png"
);
const stateIconTwo = computed(() =>
stateTwo.value
? "blue-state-icon.png"
: "red-state-icon.png"
);
onMounted(() => {
handleOnMounted()
}, {deep: true});
onMounted(() => {
setTimeout(() => {
nextTick(() => {
handleOnMounted()
})
}, 100);
});
const getImage = (type) => {
switch (type) {
case false:
return "blue-state-icon.png";
case true:
return "red-state-icon.png";
}
}
const changeNum = (index) => {
switch (index) {
case 1:
return '一';
case 2:
return '二';
case 3:
return '三';
}
}
const getBasicData = (data) => {
let tranObj = {}
let tranArr = []
@@ -219,252 +115,135 @@ const getBasicData = (data) => {
equipmentId: item.equipmentId,
autoMode: item.autoMode,//自动模式
breakdown: item.breakdown,//故障
manualMode: item.manualMode,//手动模式
running: item.running,//启动,
frequencyFeedback: item.frequencyFeedback//当前功率
}
tranArr.push(tranObj)
})
socketData.value = tranArr
powerOne.value = socketData.value[0].frequencyFeedback
powerTwo.value = socketData.value[1].frequencyFeedback
stateOne.value = socketData.value[0].breakdown
stateTwo.value = socketData.value[1].breakdown
isStartOne.value = socketData.value[0].running
isStartTwo.value = socketData.value[1].running
handleOnMounted()
}
const handleOnMounted = () => {
Echarts_info1 = echarts.init(info1.value);
fan01_option = {
series: [
{
type: "gauge",
startAngle: -120,
endAngle: -420,
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 10,
borderColor: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
color: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
}
const chart = document.getElementsByClassName('echart');
for (let i = 0; i < chart.length; i++) {
Echarts_info1 = echarts.init(chart[i]);
fan01_option = {
series: [
{
type: "gauge",
startAngle: -120,
endAngle: -420,
pointer: {
show: false,
},
},
max: 1000,
splitLine: {
show: false,
},
axisTick: {
show: true,
splitNumber: 1,
length: 10,
},
axisLabel: {
show: false,
},
data: [
{
value: powerOne.value,
fontSize: 2100,
detail: {
valueAnimation: true,
offsetCenter: ["0%", "0%"],
fontSize: 40,
color: "white",
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 10,
borderColor: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
color: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
}
},
},
],
axisLine: {
lineStyle: {
width: 3,
color: [[1, "#155F7C"]],
max: 1000,
splitLine: {
show: false,
},
axisTick: {
show: true,
splitNumber: 1,
length: 10,
},
axisLabel: {
show: false,
},
data: [
{
value: socketData.value[i].frequencyFeedback,
fontSize: 2100,
detail: {
valueAnimation: true,
offsetCenter: ["0%", "0%"],
fontSize: 40,
color: "white",
},
},
],
axisLine: {
lineStyle: {
width: 3,
color: [[1, "#155F7C"]],
},
},
detail: {
width: 100,
height: 14,
fontSize: 26,
color: "inherit",
formatter: "{value}",
},
},
detail: {
width: 100,
height: 14,
fontSize: 26,
color: "inherit",
formatter: "{value}",
},
},
],
],
}
fan01_option && Echarts_info1.setOption(fan01_option);
}
Echarts_info1.setOption(fan01_option);
// 挂载二号风机实例
Echarts_info2 = echarts.init(info2.value);
fan02_option = {
series: [
{
type: "gauge",
startAngle: -120,
endAngle: -420,
pointer: {
show: false,
},
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: {
borderWidth: 10,
borderColor: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
},
color: {
type: "linear",
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: "#4BB10E", // 0% 处的颜色
},
{
offset: 0.25,
color: "#B1AD0E", // 100% 处的颜色
},
{
offset: 0.75,
color: "#B1880E", // 100% 处的颜色
},
{
offset: 1,
color: "#D77E01", // 100% 处的颜色
},
],
global: false, // 缺省为 false
}
},
},
max: 1000,
splitLine: {
show: false,
},
axisTick: {
show: true,
splitNumber: 1,
length: 10,
},
axisLabel: {
show: false,
},
data: [
{
value: powerTwo.value,
fontSize: 2100,
detail: {
valueAnimation: true,
offsetCenter: ["0%", "0%"],
fontSize: 40,
color: "white",
},
},
],
axisLine: {
lineStyle: {
width: 3,
color: [[1, "#155F7C"]],
},
},
detail: {
width: 100,
height: 14,
fontSize: 26,
color: "inherit",
formatter: "{value}",
},
},
],
}
Echarts_info2.setOption(fan02_option);
}
const getImageUrl = (name) => {
return new URL(`../../../assets/images/fanInfo/${name}`, import.meta.url).href
let icon = getImage(name)
return new URL(`../../../assets/images/fanInfo/${icon}`, import.meta.url).href
}
</script>
@@ -524,7 +303,8 @@ input[type="number"] {
background-image: url(../../../assets/images/fanInfo/bg.png);
//clip-path: polygon(0% 0%, 40% 0%, 48% 15%, 100% 15%, 100% 100%, 0% 100%);
color: #2fb0df;
box-sizing: border-box;
box-sizing: border-box;
.title {
width: 40%;
text-align: left;

View File

@@ -5,7 +5,7 @@
<img src="@/assets/images/transducer/sp_icon_dl.png" alt=""/>
<div class="info">
<div class="name-state">
<div class="name">{{item.equipmentName}}</div>
<div class="name">{{ item.equipmentName }}</div>
<div class="state" v-if="stateA||stateB||stateC">
<img src="@/assets/images/transducer/sp_icon_yc.png" alt=""/>
<span style="color: red">异常</span>
@@ -26,7 +26,7 @@
<img src="@/assets/images/transducer/sp_icon_pbq.png"/>
<div class="info">
<div class="name-state">
<div class="name">{{item.equipmentName}}</div>
<div class="name">{{ item.equipmentName }}</div>
<div class="state">
<img src="@/assets/images/transducer/greenLight.png"/>
<span>正常</span>
@@ -79,16 +79,16 @@ watch(() => props.list, (now) => {
})
})
}, {deep: true});
const stateA=ref(false)
const stateB=ref(false)
const stateC=ref(false)
const stateA = ref(false)
const stateB = ref(false)
const stateC = ref(false)
const getBasicData = (data) => {
let tranObj = {}
let tranArr = []
data.map(item => {
tranObj = {
equipmentId: item.equipmentId,
equipmentName:item.equipmentName,
equipmentName: item.equipmentName,
phaseCurrentA: item.phaseCurrentA,
phaseCurrentAThreshold: item.phaseCurrentAThreshold,
phaseCurrentB: item.phaseCurrentB,
@@ -98,25 +98,25 @@ const getBasicData = (data) => {
frequencySetting: item.frequencySetting,
frequencyFeedback: item.frequencyFeedback,
}
stateA.value=item.phaseCurrentA>item.phaseCurrentAThreshold
stateB.value=item.phaseCurrentB>item.phaseCurrentBThreshold
stateC.value=item.phaseCurrentC>item.phaseCurrentCThreshold
stateA.value = item.phaseCurrentA > item.phaseCurrentAThreshold
stateB.value = item.phaseCurrentB > item.phaseCurrentBThreshold
stateC.value = item.phaseCurrentC > item.phaseCurrentCThreshold
tranArr.push(tranObj)
})
//mock数据
// let newObj = {
// equipmentId: 0,
// equipmentName:'3号变频器',
// phaseCurrentA: 210,
// phaseCurrentAThreshold: 200,
// phaseCurrentB: 231,
// phaseCurrentBThreshold: 300,
// phaseCurrentC: 154,
// phaseCurrentCThreshold:200,
// frequencySetting: 23,
// frequencyFeedback: 34,
// }
// tranArr.push(newObj)
// let newObj = {
// equipmentId: 0,
// equipmentName:'3号变频器',
// phaseCurrentA: 210,
// phaseCurrentAThreshold: 200,
// phaseCurrentB: 231,
// phaseCurrentBThreshold: 300,
// phaseCurrentC: 154,
// phaseCurrentCThreshold:200,
// frequencySetting: 23,
// frequencyFeedback: 34,
// }
// tranArr.push(newObj)
transducerData.value = tranArr
}
</script>
@@ -127,10 +127,11 @@ const getBasicData = (data) => {
position: absolute;
top: 1015px;
left: 70px;
width: 826px;
width: 830px;
height: 928px;
background-image: url(@/assets/images/transducer/bg.png);
padding: 0 30px;
box-sizing: border-box;
.transducer-item {
border-bottom: rgba(107, 163, 237, 0.4) solid 2px;

View File

@@ -46,7 +46,7 @@ const info = ref(null);
const edit = ref(null);
let demo; //定义demo全局变量
// const loader = new OBJLoader();
const loader = new GLTFLoader();
const loader = new OBJLoader();
let hdrLoader = new RGBELoader();
let backColorSet = three.sRGBEncoding;
@@ -68,17 +68,12 @@ async function handleMounted() {
// 初始化设备模型
try {
const deviceList = [];
let result = await loadModel("/devicesModel/fan.glb");
deviceList.push(result);
result = await loadModel("/devicesModel/sensor.glb");
deviceList.push(result);
const map = new Map();
map.set("equ_fan", await loadModel("/devicesModel/model2.obj"));
map.set("equ_sensors", await loadModel("/devicesModel/sensors.obj"));
// 给对象初加载设备模型
demo.initDevicesModel(deviceList);
console.info("设备模型加载完毕");
// 清空内存
result = null;
demo.initDevicesModel(map);
} catch (err) {
console.log(err);
}
@@ -139,15 +134,17 @@ function lClickCallback(demo) {
}
let pointNum = ref(0);
let targetP;
// 右键点击附着点后调函数
function rClickCallback(demo) {
function editDev(targetPoint = null) {
hasDevice = targetPoint.hasDevice;
targetP = targetPoint;
pointNum.value = Number(
targetPoint.name.substring(
targetPoint.name.indexOf("_") + 1,
targetPoint.name.lastIndexOf("_")
)
) - 1
);
if (!targetPoint.info) return;
@@ -157,22 +154,19 @@ function rClickCallback(demo) {
}
// 添加设备
function handleAddEqu() {
console.log("添加", pointInfo);
function handleAddEqu(formInfo) {
if (!formInfo.equipmentType) {
alert("请选择设备");
return;
}
//表单信息
//这里利用处理请求
demo.addEquipment(targetP, formInfo);
}
// 删除设备
async function handleRemoveEqu() {
// const result = await demo.removeDev(devInfo.meshId);
// if (result === "ok") {
// hasDevice.value = false;
// editDevInfo();
// ElMessage({
// message: "删除成功",
// type: "success",
// });
// }
console.log("删除");
demo.removeEquipment(targetP);
}
// 处理取消关闭编辑框事件
@@ -180,6 +174,7 @@ function handleCancel() {
if (!demo) return;
// 关闭标签
demo.isControlOrbit(true);
demo._resetState();
demo.clearTagsObj();
}
</script>

View File

@@ -5,6 +5,7 @@
type="text"
:placeholder="params.placeholder"
@input="handleChange"
:disabled="params.disabled"
/>
</div>
</template>
@@ -14,6 +15,7 @@ import { ref, defineProps, defineEmits, onUnmounted } from "vue";
const params = defineProps({
name: String,
placeholder: String,
disabled: Boolean,
});
const emit = defineEmits(["inputValue"]);
let timer = null;
@@ -43,7 +45,7 @@ function handleUnmounted() {
input {
width: 284px;
height: 51px;
border: 1px solid #0f82af;
border: 2px solid #0f82af;
background: transparent;
margin-top: 20px;
font-size: 26px;

View File

@@ -1,99 +0,0 @@
<template>
<div id="select-input">
<p>{{ params.name }}</p>
<div class="select">
<div class="value">
<span>{{ value }}</span>
<img
src="/images/htmlEditDialog/select-icon.png"
alt=""
@click="isShowList = !isShowList"
/>
</div>
<ul v-show="isShowList">
<li
v-for="(item, index) of params.options"
:key="index"
@click="handleClickItem(index)"
>
{{ item.label }}
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { ref, reactive, defineEmits, defineProps } from "vue";
const params = defineProps({
name: String,
options: Array,
placeholder: String,
});
const emit = defineEmits(["selected"]);
let isShowList = ref(false);
const value = ref(params.placeholder);
function handleClickItem(index) {
value.value = params.options[index].label;
isShowList.value = false;
emit("selected", params.options[index]);
}
</script>
<style lang="scss" scoped>
#select-input {
margin: 40px 30px 0px 30px;
P {
width: 130px;
height: 35px;
font-size: 26px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 35px;
}
.select {
position: relative;
.value {
width: 284px;
height: 51px;
border: 1px solid #0f82af;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #08b7b8;
line-height: 51px;
margin-top: 20px;
padding: 0px 0px 0px 10px;
position: relative;
img {
position: absolute;
right: 20px;
bottom: 18px;
cursor: pointer;
}
img:active {
transform: scale(0.8);
}
}
ul {
position: absolute;
width: 284px;
background: #072247;
border-radius: 0px 0px 20px 20px;
border: 1px solid #0f82af;
z-index: 10000;
li {
height: 37px;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 37px;
margin: 20px 10px;
cursor: pointer;
}
li:hover {
color: #08b7b8;
}
}
}
}
</style>

View File

@@ -1,32 +1,54 @@
<template>
<div id="edit-dialog">
<div class="distance-back">
<p>{{ pointDistance_str }}</p>
<p>当前距离洞口{{ pointDistance_str }}</p>
<img
src="/images/htmlEditDialog/back-icon.png"
alt=""
@click="handleCancel"
/>
</div>
<div class="dev-info"></div>
+
<div class="equ-info">当前风压:{{ p }}Pa</div>
<div class="setting">
<select-input
name="传感器类型"
placeholder="请选择传感器类型"
:options="options"
@selected="handelSelectType"
/>
<select-input
name="设备选择"
placeholder="请选择设备"
:options="options"
@selected="handelSelectEquipment"
/>
<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>
</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>
</div>
<input-num
name="阈值"
placeholder="请输入阈值"
@inputValue="handelInput"
:disabled="isDisabledInputNum"
/>
</div>
<div class="btn">
@@ -37,16 +59,24 @@
</template>
<script setup>
import { reactive, computed, defineEmits, defineProps } from "vue";
import SelectInput from "./childComps/SelectInput.vue";
import InputNum from "./childComps/InputNum.vue";
import { remove } from "three/examples/jsm/libs/tween.module";
import {
reactive,
computed,
defineEmits,
defineProps,
watch,
nextTick,
} from "vue";
// 定义事件发射器,父组件监听
const emit = defineEmits(["cancel", "removeEquipment", "addEquipment"]);
const params = defineProps(["pointNum", "pointGap"]); //隧道第几个锚点
// 当前风压
let p = ref(57);
//计算锚点之间距离
const pointDistance_str = computed(
() =>
@@ -62,13 +92,36 @@ const equipmentSetting = reactive({
threshold: "", //阈值
});
// 选项参数
// 设备类型选项参数
const options = reactive([
{ label: "风机1", id: "321321" },
{ label: "风机2", id: "321321" },
{ label: "风机3", id: "321321" },
{ label: "风机4", id: "321321" },
{ label: "风机", value: "fan" },
{ label: "风压传感器", value: "sensors" },
{ label: "普通传感器", value: "sensors_2" },
]);
// 设备编号参数
let options2 = reactive([]);
let isDisabledInputNum = ref(false);
watch(
() => equipmentSetting.equipmentType,
() => {
let label;
options2 = [];
equipmentSetting.chooseEquipment = "";
isDisabledInputNum = false;
if (equipmentSetting.equipmentType === "fan") {
label = "风机";
isDisabledInputNum = true;
}
if (equipmentSetting.equipmentType === "windPressure") label = "风压传感器";
if (equipmentSetting.equipmentType === "sensors") label = "普通传感器";
for (let i = 1; i < 11; i++) {
options2.push({ label: `${i}${label}`, value: `${label}_${i}` });
}
}
);
// const obj = {
// equipmentId: String, //传感器id
// equipmentName: String, //设备名称
@@ -82,18 +135,12 @@ const options = reactive([
// const tunnel = {
// tunnelId: "",
// };
// 显示锚点距离
let point_num = ref(0);
function handelSelectType(e) {
equipmentSetting.equipmentType = e;
}
function handelSelectEquipment(e) {
equipmentSetting.chooseEquipment = e;
}
function handelInput(e) {
equipmentSetting.threshold = e;
console.log(equipmentSetting);
}
// 处理取消事件
@@ -106,10 +153,32 @@ function handleCancel() {
function removeEquipment() {
emit("removeEquipment");
}
// 添加设备
function addEquipment() {
emit("addEquipment");
// // 处理不合法情况
// if (
// !equipmentSetting.chooseEquipment ||
// !equipmentSetting.equipmentType ||
// !equipmentSetting.threshold
// ) {
// alert("选项不能有空");
// return;
// }
emit("addEquipment", equipmentSetting);
equipmentSetting.chooseEquipment = "";
equipmentSetting.equipmentType = "";
equipmentSetting.threshold = "";
}
const equipmentType = {
label: String, //传感器类型
typeId: String, //传感器类型ID(方便查找该类型的所有设备)
};
// 通过以上选项请求以下具体哪个设备
const equipment = {
label: String, //传感器编号加名称
equId: String, // 传感器Id
};
</script>
<style lang="scss" scoped>
@@ -131,7 +200,7 @@ function addEquipment() {
p {
width: 388px;
height: 35px;
font-size: 26px;
font-size: 24px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 35px;
@@ -143,18 +212,58 @@ function addEquipment() {
transform: scale(0.9);
}
}
.equ-info {
width: 190px;
height: 35px;
font-size: 26px;
font-family: MicrosoftYaHei;
color: #f7b500;
line-height: 35px;
margin: 20px 30px 0px 30px;
}
.setting {
.dev-type {
margin: 30px 30px;
P {
.setting-item {
padding: 30px 30px 10px 30px;
p {
width: 130px;
height: 35px;
font-size: 26px;
font-family: MicrosoftYaHei;
color: #ffffff;
line-height: 35px;
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%;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #08b7b8;
line-height: 37px;
}
:deep(.el-icon) {
color: #05feff;
font-size: 34px;
}
}
.btn {
margin: 100px 40px 40px 40px;

View File

@@ -1,37 +0,0 @@
export default function (devInfo) {
const dev = this.deviceList[devInfo.checkIndex].clone(); //克隆对应的moxin
const p = this.targetPoint.getWorldPosition(new this.THREE.Vector3());
dev.position.copy(p);
this.scene.add(dev);
this.targetPoint.hasDevice = true; //标记还存在设备
// 附着点记录信息
this.targetPoint.info = {
meshId: dev.id,
name: devInfo.devName,
position: transformPosition(this.targetPoint.name, this.distance),
state: devInfo.devState,
};
// this.targetPoint.visible = false;
return this.targetPoint.info;
}
function transformPosition(position, distance) {
return `${equal(position.charAt(position.lastIndexOf("_") + 1))}边隧道${equal(
position.charAt(position.lastIndexOf("_") + 2)
)}侧设备约${
(Number(
position.substring(position.indexOf("_") + 1, position.lastIndexOf("_"))
) +
1) *
distance
}米处`;
}
function equal(str) {
switch (str) {
case "r":
return "右";
case "l":
return "左";
}
}

View File

@@ -1,30 +0,0 @@
export function addDev(devId) {
if (!this.checkDevId) {
alert("请选择设备");
return;
}
const devModel = this.devMap.get(devId).clone();
handleLoadedDevice.call(this, devModel);
}
function handleLoadedDevice(model) {
if (!this.targetPoint) return;
//获取定位位置
const wp = this.targetPoint.getWorldPosition(new this.THREE.Vector3());
model.position.copy(wp);
this.targetPoint.visible = false;
this.scene.add(model);
if (model.name === "camera") {
model.translateX(-5);
model.translateZ(4);
model.translateY(-0.5);
}
// 添加的信息请求或初始化的信息
this.targetPoint.info = {
name: "摄像头",
state: "未开启",
devId: model.id,
};
this.targetPoint.hasDevice = true;
}

View File

@@ -1 +0,0 @@
export function checkDevModel() {}

View File

@@ -8,9 +8,8 @@ import {
} from "./handleOrbitControlsChange";
import { saveState, resetState } from "./viewBack";
import addFunction from "./addEvent";
import addDev from "./addDev";
import removeDev from "./removeDev";
import { addEquipment, removeEquipment } from "./editEquipment";
import { Group } from "three/examples/jsm/libs/tween.module";
export default class Demo {
// 摄像机看向位置
origin = null;
@@ -19,18 +18,15 @@ export default class Demo {
//设备模型数组
deviceModels = [];
constructor(three, mountedElement) {
// 外部引入匿名函数
this._handleLClick = handleLClick;
this._handleRClick = handleRClick;
this._handleDBLClick = handleDBLClick;
this._checkAnimation = checkAnimation;
this._saveSate = saveState;
this._saveState = saveState;
this._resetState = resetState;
this.addEquipment = addEquipment;
this.removeEquipment = removeEquipment;
// 增加设备模型
this.addDev = addDev;
// 删除设备模型
this.removeDev = removeDev;
// 外部可添加函数
this.addFunction = addFunction;
this.THREE = three;
@@ -58,7 +54,7 @@ export default class Demo {
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.domElement.style.position = "absolute";
this.mountedElement.appendChild(this.renderer.domElement);
console.log(this.renderer.domElement);
// 创建渲染帧
this.render = () => {
this.__renderScope();
@@ -77,11 +73,6 @@ export default class Demo {
// console.log(this.camera.position);
}
// 摄像头移动动画
if (this.cameraPositionTween) {
this.cameraPositionTween.update();
}
//html标签渲染
if (this.CSS2Renderer) {
this.CSS2Renderer.render(this.scene, this.camera);
@@ -106,6 +97,15 @@ export default class Demo {
if (this.opacityTween) {
this.opacityTween.update();
}
// 双击进入动画
if (this.dblIntoTween) {
this.dblIntoTween.update();
}
// 风机叶片旋转动画
if (this.fanSpinArray && this.fanSpinArray.length) {
this.fanSpinArray.forEach((element) => element.update());
}
}
// 添加世界坐标系
@@ -185,9 +185,11 @@ export default class Demo {
this.camera,
this.renderer.domElement
);
this.orbitControls.object.position.set(-27.285, 16.356, -54.925);
//限制轨道控制器的视角变化
this.orbitControls.maxPolarAngle = Math.PI * (3 / 5);
//初始化轨道控制器
this.orbitControls.object.position.set(-29, 18, -50);
this.orbitControls.maxPolarAngle = (4 * Math.PI) / 7;
this.orbitControls.minDistance = 5;
this.orbitControls.maxDistance = 87;
// 监听控制器变化
this.orbitControls.addEventListener("end", handleEndChange.bind(this));
this.orbitControls.addEventListener("start", handleStartChange.bind(this));
@@ -285,9 +287,9 @@ export default class Demo {
this.setBoxHelper(intersects[0].object);
// 处理点击左右键事件
if (e.button === 2) {
if (e.button === 0) {
this._handleLClick(intersects[0].object);
} else if (e.button === 0) {
} else if (e.button === 2) {
this._handleRClick(intersects[0].object);
}
}, 400);
@@ -310,19 +312,17 @@ export default class Demo {
this.tagCSS2DObj = new CSS2DObject(this.tagHtml);
this.tag2CSS2DObj = new CSS2DObject(this.tag2Html);
this.tag3CSS2DObj = new CSS2DObject(this.tag3Html);
// 设置该标签初始化透明
this.tagCSS2DObj.element.style.opacity = "1";
this.tag2CSS2DObj.element.style.opacity = "1";
this.tag3CSS2DObj.element.style.opacity = "1";
this.tagCSS2DObj.element.style.display = "none";
this.tag2CSS2DObj.element.style.display = "none";
this.tag3CSS2DObj.element.style.display = "none";
// // 设置该标签初始化透明
// this.tagCSS2DObj.element.style.opacity = "1";
// this.tag2CSS2DObj.element.style.opacity = "1";
this.tagCSS2DObj.scale.set(0.1, 0.1, 0.1);
this.tag2CSS2DObj.scale.set(0.1, 0.1, 0.1);
this.tag3CSS2DObj.scale.set(0.025, 0.025, 0.025); //编辑框
this.tag3CSS2DObj.scale.set(0.02, 0.02, 0.02); //编辑框
this.tag3CSS2DObj.position.set(10, 0, 10);
this.tagCSS2DObj.scale.set(0.5, 0.5, 0.5);
}
clearTagsObj() {
if (this.preDBLModel) {
@@ -331,6 +331,7 @@ export default class Demo {
// 所有标签看不见
this.scene.remove(this.tag2CSS2DObj);
this.scene.remove(this.tag3CSS2DObj);
this.tag3CSS2DObj.element.style.opacity = "0";
// 删除标记动画
this.scene.remove(this.group);
}
@@ -358,14 +359,59 @@ export default class Demo {
}
/**
* @param {Meshes} meshes gltf加载过后的模型数组
* @param {Map} meshes gltf加载过后的模型Map
*/
initDevicesModel(meshes) {
this.deviceList = [];
meshes.forEach((mesh) => {
this.deviceList.push(mesh);
initDevicesModel(equMap) {
// 把风机叶片做为一个组,方便后期旋转
const group = new this.THREE.Group();
group.name = "fanLeaf";
// 初始化风机
this.equMap = equMap;
// 初始化风机颜色
this.equMap.get("equ_fan").traverse((v) => {
// v.material = new this.THREE.MeshBasicMaterial();
// v.material.color = new this.THREE.Color("#191a05");
if (/^leaf/.test(v.name) || /^roller/.test(v.name)) {
group.add(v.clone());
v.visible = false;
// console.log(v);
}
});
console.log(this.deviceList);
const axesHelper = new this.THREE.AxesHelper(100);
// 改变叶子旋转中心
let x = 0,
y = -0.2,
z = 0;
const wrapper = new this.THREE.Object3D();
wrapper.position.set(x, y, z);
wrapper.add(group);
group.position.set(-x, -y, -z);
// wrapper.add(axesHelper);
wrapper.rotation.z = Math.PI / 4;
wrapper.name = "fan_leafs";
this.equMap.get("equ_fan").add(wrapper);
// 初其他传感器机颜色
this.equMap.get("equ_sensors").scale.set(0.1, 0.1, 0.1);
this.equMap.get("equ_sensors").traverse((v) => {
v.material = new this.THREE.MeshBasicMaterial();
v.material.color = new this.THREE.Color("#7e7b7b");
});
// 初始标签面板
const tag = new this.THREE.Mesh(
new this.THREE.PlaneGeometry(10, 4),
new this.THREE.MeshBasicMaterial({ color: "white" })
);
this.equMap.get("equ_sensors").add(tag);
// const axesHelper = new this.THREE.AxesHelper(100);
// this.equMap.get("equ_sensors").add(axesHelper);
tag.name = "tag";
tag.rotation.x = Math.PI / 2;
tag.rotation.z = Math.PI / 2; //旋转这里改变文字顺序
tag.rotation.y = Math.PI;
tag.translateZ(2.0);
}
/**
@@ -424,10 +470,10 @@ export default class Demo {
);
this.opacityTween.start();
this.opacityTween.onUpdate((obj) => {
mesh.material.opacity = obj.opacity;
mesh2.material.opacity = obj.opacity;
mesh3.material.opacity = obj.opacity;
mesh4.material.opacity = obj.opacity;
// mesh.material.opacity = obj.opacity;
// mesh2.material.opacity = obj.opacity;
// mesh3.material.opacity = obj.opacity;
// mesh4.material.opacity = obj.opacity;
if (!isNeedLookAt) return;
this.camera.lookAt(obj.lookX, obj.lookY, obj.lookZ);
this.orbitControls.target.set(obj.lookX, obj.lookY, obj.lookZ);

View File

@@ -0,0 +1,108 @@
import EquipmentTag from "../utils/EquipmentTag";
/**
*
* @param {Mesh} targetPoint
* @param {String} equType "fan" "sensors"
*/
function addEquipment(targetPoint, formInfo) {
if (targetPoint.hasDevice) {
alert("已添加设备");
return;
}
switch (formInfo.equipmentType) {
case "fan":
handleFanEqu.call(this, targetPoint);
break;
case "sensors":
case "sensors_2":
handleOtherEqu.call(this, targetPoint, formInfo.equipmentType);
break;
default:
break;
}
targetPoint.hasDevice = true;
// 标识设备信息
this.clearTagsObj();
}
// 其他传感器
function handleOtherEqu(targetPoint, EqeName) {
const equMesh = this.equMap.get("equ_sensors").clone();
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
equMesh.position.copy(worldP);
//设备添加标签
const tag = EquipmentTag(EqeName === "sensors" ? "风压传感器" : "普通传感器");
equMesh.getObjectByName("tag").material = tag;
if (/tr$/.test(targetPoint.name)) {
equMesh.rotation.z = -(3 * Math.PI) / 4;
targetPoint.scale.set(0.03, 0.03, 0.03);
equMesh.getObjectByName("tag").rotation.z += Math.PI; ///注意在原来的基础上加
} else if (/tl$/.test(targetPoint.name)) {
equMesh.rotation.z = -(5 * Math.PI) / 4;
targetPoint.scale.set(0.03, 0.03, 0.03);
} else if (/tc$/.test(targetPoint.name)) {
equMesh.rotation.z = Math.PI;
targetPoint.scale.set(0.03, 0.03, 0.03);
} else if (/br$/.test(targetPoint.name)) {
equMesh.rotation.z = -Math.PI / 2;
equMesh.translateX(-1);
equMesh.getObjectByName("tag").rotation.z += Math.PI; ///注意在原来的基础上加
targetPoint.scale.set(0.03, 0.03, 0.075);
} else if (/bl$/.test(targetPoint.name)) {
equMesh.rotation.z = Math.PI / 2;
equMesh.translateX(1);
targetPoint.scale.set(0.03, 0.03, 0.075);
}
this.scene.add(equMesh);
targetPoint.visible = false;
// 保存该设备id后期直接从附附着点进行删除
targetPoint.info = {
id: equMesh.id,
};
}
// 风机
function handleFanEqu(targetPoint, speed = Math.random().toFixed(1) * 1000) {
// 由于风机比较多,每个风机转速不一直,保存在一个数中遍历
if (!this.fanSpinArray) {
this.fanSpinArray = [];
}
const equMesh = this.equMap.get("equ_fan").clone();
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
equMesh.position.copy(worldP);
equMesh.translateY(-0.6);
this.scene.add(equMesh);
targetPoint.visible = false;
// 放大附着点方便选中风机的范围
targetPoint.scale.set(0.06, 0.06, 0.06);
// 保存该设备id后期直接从附附着点进行删除
targetPoint.info = {
id: equMesh.id, //模型在场景id
};
// 定义风机旋转
const fanLeaf = equMesh.getObjectByName("fan_leafs");
const fanSpin = new this.TWEEN.Tween({ rotation: 0 });
fanSpin.to({ rotation: 2 * Math.PI }, speed);
fanSpin.repeat(Infinity);
fanSpin.start();
fanSpin.onUpdate((obj) => {
fanLeaf.rotation.z = obj.rotation;
});
this.fanSpinArray.push(fanSpin);
}
// 删除传感器
function removeEquipment(targetPoint) {
if (!targetPoint.hasDevice) return;
const mesh = this.scene.getObjectById(targetPoint.info.id);
this.scene.remove(mesh);
targetPoint.visible = true;
targetPoint.hasDevice = false;
targetPoint.scale.set(0.01, 0.01, 0.01);
}
export { addEquipment, removeEquipment };

View File

@@ -1,68 +1,45 @@
export function handleDBLClick(e) {
return;
this._saveSate();
// 注意位置不能改变
export function handleDBLClick(targetPoint) {
if (!targetPoint.hasDevice) return;
this.clearTagsObj();
this.preDBLModel = e;
//获取模型世界坐标位置
const modelP = new this.THREE.Vector3();
e.getWorldPosition(modelP);
this._checkAnimation(modelP);
this.setBoxHelper(e);
if (/l$/.test(e.name)) {
//匹配单个隧道左边附着点
modelP.x += 5;
modelP.y -= 5;
modelP.z += 10;
this.orbitControls.target = modelP;
this.cameraPositionTween = new this.TWEEN.Tween(this.camera.position);
this.cameraPositionTween.to(modelP, 400);
this.cameraPositionTween.start();
modelP.x -= 4;
modelP.y += 4;
modelP.z -= 20;
} else if (/r$/.test(e.name)) {
//匹配单个隧道右边附着点
modelP.x -= 5;
modelP.y -= 5;
modelP.z += 10;
this.orbitControls.target = modelP;
this.cameraPositionTween = new this.TWEEN.Tween(this.camera.position);
this.cameraPositionTween.to(modelP, 400);
this.cameraPositionTween.start();
modelP.x += 4;
modelP.y += 4;
modelP.z -= 20;
}
if (this.preTargetModel) {
this.preTargetModel.remove(this.tagCSS2DObj);
}
this.cameraPositionTween.onComplete(() => {
this.orbitControls.target = modelP;
this.camera.lookAt(modelP);
// 动画完成过后自动弹出标签
autoOutTag(e, this);
this.listenerEventFlag = false;
// 返回个组件
this.displayDevInfo(e);
this._saveState();
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
const viewAng = viewAngle(targetPoint.name);
this.dblIntoTween = new this.TWEEN.Tween({
x: this.camera.position.x,
y: this.camera.position.y,
z: this.camera.position.z,
targetX: this.orbitControls.target.x,
targetY: this.orbitControls.target.y,
targetZ: this.orbitControls.target.z,
});
this.dblIntoTween.to(
{
x: worldP.x + viewAng.x,
y: worldP.y + viewAng.y,
z: worldP.z + viewAng.z,
targetX: worldP.x,
targetY: worldP.y,
targetZ: worldP.z,
},
500
);
this.dblIntoTween.start();
this.dblIntoTween.onUpdate((obj) => {
this.camera.position.set(obj.x, obj.y, obj.z);
this.camera.lookAt(obj.targetX, obj.targetY, obj.targetZ);
this.orbitControls.target.set(obj.targetX, obj.targetY, obj.targetZ);
});
}
// 视角移动过去自动弹出标签
function autoOutTag(targetModel, context) {
// 判断是否纯在设备
// if (targetModel.hasDevice) return;
context.preTargetModel = targetModel;
context.tagCSS2DObj.element.style.display = "block";
targetModel.add(context.tagCSS2DObj);
if (/l$/.test(targetModel.name)) {
context.tagCSS2DObj.position.set(150, 0, 700);
} else if (/r$/.test(targetModel.name)) {
context.tagCSS2DObj.position.set(-150, 0, 700);
function viewAngle(targetPointName) {
if (/tr$/.test(targetPointName)) {
return { x: 5, y: -1, z: 1 };
} else if (/tl$/.test(targetPointName)) {
return { x: -5, y: -1, z: 1 };
} else if (/tc$/.test(targetPointName)) {
return { x: -1, y: -1, z: -9 };
} else if (/br$/.test(targetPointName)) {
return { x: 5, y: 1, z: 1 };
} else if (/bl$/.test(targetPointName)) {
return { x: -5, y: 1, z: 1 };
}
}

View File

@@ -6,4 +6,39 @@ export function handleEndChange(e) {
// 围绕点到照相机的位置
// console.log("结束");
// console.log(this.orbitControls.object.position);
// console.log(this.camera.position, this.position);
// console.log(
// this.camera.position.x - this.position.x,
// this.camera.position.y - this.position.y,
// this.camera.position.z - this.position.z
// );
// const cx =
// (this.scene
// .getObjectByName("point_001_br")
// .getWorldPosition(new this.THREE.Vector3()).x +
// this.scene
// .getObjectByName("point_001_bl")
// .getWorldPosition(new this.THREE.Vector3()).x) /
// 2;
// const cy =
// (this.scene
// .getObjectByName("point_001_br")
// .getWorldPosition(new this.THREE.Vector3()).y +
// this.scene
// .getObjectByName("point_001_bl")
// .getWorldPosition(new this.THREE.Vector3()).y) /
// 2;
// const cz =
// (this.scene
// .getObjectByName("point_001_br")
// .getWorldPosition(new this.THREE.Vector3()).z +
// this.scene
// .getObjectByName("point_001_bl")
// .getWorldPosition(new this.THREE.Vector3()).z) /
// 2;
// console.log(cx, cy, cz);
// console.log(
// this.scene
// .getObjectByName("point_001_tr")
// .getWorldPosition(new this.THREE.Vector3())
}

View File

@@ -1,32 +1,56 @@
export function handleLClick(targetPoint) {
return;
// 保存进入状态
this._saveState();
this.clearTagsObj();
// 全局临时标记该选中的模型;
this.targetPoint = targetPoint;
const worldPosition = new this.THREE.Vector3();
//获取附着点的世界坐标系
targetPoint.getWorldPosition(worldPosition);
this._checkAnimation(worldPosition);
// 显示左键属性栏
this.tag2CSS2DObj.element.style.display = "block";
// 设置标签位置
// this.tag2CSS2DObj.position.set(
// worldPosition.x,
// worldPosition.y,
// worldPosition.z
// );
// 标签定位
this.tag2CSS2DObj.translateY(-15);
this.tag2CSS2DObj.translateX(15);
this.scene.add(this.tag2CSS2DObj);
intoAnimation.call(this, targetPoint);
//调用该函数回调作用返回给组件操作 very important-----
this.displayDevInfo(targetPoint);
this.tag3CSS2DObj.position.set(
worldPosition.x,
worldPosition.y,
worldPosition.z
);
this.isControlOrbit(false);
this.position = worldPosition;
if (/tr$/.test(targetPoint.name)) {
this.tag3CSS2DObj.translateX(3);
this.tag3CSS2DObj.translateZ(10);
this.tag3CSS2DObj.translateY(-5);
intoAnimation.call(this, 4.31, -2.55, -11);
} else if (/tl$/.test(targetPoint.name)) {
this.tag3CSS2DObj.translateX(-3);
this.tag3CSS2DObj.translateZ(10);
this.tag3CSS2DObj.translateY(-5);
intoAnimation.call(this, -4.31, -2.55, -11);
} else if (/tc$/.test(targetPoint.name)) {
this.tag3CSS2DObj.translateX(0);
this.tag3CSS2DObj.translateZ(10);
this.tag3CSS2DObj.translateY(-6);
intoAnimation.call(this, 0, -2.55, -11);
} else if (/br$/.test(targetPoint.name)) {
this.tag3CSS2DObj.translateX(2);
this.tag3CSS2DObj.translateZ(10);
this.tag3CSS2DObj.translateY(3);
intoAnimation.call(this, 4.31, 5, -11);
} else if (/bl$/.test(targetPoint.name)) {
this.tag3CSS2DObj.translateX(-2);
this.tag3CSS2DObj.translateZ(10);
this.tag3CSS2DObj.translateY(3);
intoAnimation.call(this, -4.31, 5, -11);
}
this.scene.add(this.tag3CSS2DObj);
// 返回给编辑组件的回调函数
this.editDev(targetPoint);
}
// 视角进入动画
function intoAnimation(targetPoint) {
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
function intoAnimation(x = -10, y = 3, z = -12) {
const worldP = this.targetPoint.getWorldPosition(new this.THREE.Vector3());
const positionOBj = this.camera.position;
const start = this.orbitControls.target;
this.intoPointAnimation = new this.TWEEN.Tween({
x: positionOBj.x,
@@ -35,26 +59,33 @@ function intoAnimation(targetPoint) {
xTarget: start.x,
yTarget: start.y,
zTarget: start.z,
ctlTargetX: 0,
ctlTargetY: 0,
ctlTargetZ: 0,
});
this.intoPointAnimation.to(
{
x: worldP.x + 20,
y: worldP.y + 5,
z: worldP.z + 50,
xTarget: worldP.x,
yTarget: worldP.y,
zTarget: worldP.z,
x: worldP.x + x,
y: worldP.y + y,
z: worldP.z + z,
xTarget: -5,
yTarget: 8.814,
zTarget: worldP.z + 30,
ctlTargetX: 0,
ctlTargetY: 0,
ctlTargetZ: 120,
},
600
500
);
this.intoPointAnimation.start();
this.intoPointAnimation.onUpdate((obj) => {
this.camera.position.set(obj.x, obj.y, obj.z);
this.camera.lookAt(obj.xTarget, obj.yTarget, obj.zTarget);
// this.orbitControls.target.set(obj.x, obj.y, -obj.z);
this.orbitControls.target.set(obj.xTarget, obj.yTarget, obj.zTarget);
});
this.intoPointAnimation.onComplete(() => {
this.camera.lookAt(worldP.x, worldP.y, worldP.z);
this.tag3CSS2DObj.element.style.opacity = "1";
this.tag3CSS2DObj.element.style.display = "block";
});
}

View File

@@ -1,33 +1,33 @@
import toImg from "../utils/EquipmentTag";
export function handleRClick(targetPoint) {
return;
this.clearTagsObj();
// 全局临时标记该选中的模型;
this.targetPoint = targetPoint;
const worldPosition = new this.THREE.Vector3();
//获取附着点的世界坐标系
targetPoint.getWorldPosition(worldPosition);
this._checkAnimation(worldPosition);
// 显示左键属性栏
this.tag3CSS2DObj.element.style.display = "block";
this.tag2CSS2DObj.element.style.display = "block";
// 设置标签位置
this.tag3CSS2DObj.position.set(
worldPosition.x,
worldPosition.y,
worldPosition.z
);
this.isControlOrbit(false);
this.tag3CSS2DObj.translateX(-3);
this.tag3CSS2DObj.translateZ(10);
this.scene.add(this.tag3CSS2DObj);
intoAnimation.call(this);
// 返回给编辑组件的回调函数
this.editDev(targetPoint);
// this.tag2CSS2DObj.position.set(
// worldPosition.x,
// worldPosition.y,
// worldPosition.z
// );
// 标签定位
this.tag2CSS2DObj.translateY(-15);
this.tag2CSS2DObj.translateX(15);
this.scene.add(this.tag2CSS2DObj);
intoAnimation.call(this, targetPoint);
//调用该函数回调作用返回给组件操作 very important-----
this.displayDevInfo(targetPoint);
}
function intoAnimation() {
const worldP = this.targetPoint.getWorldPosition(new this.THREE.Vector3());
// 视角进入动画
function intoAnimation(targetPoint) {
const worldP = targetPoint.getWorldPosition(new this.THREE.Vector3());
const positionOBj = this.camera.position;
const start = this.orbitControls.target;
this.intoPointAnimation = new this.TWEEN.Tween({
x: positionOBj.x,
@@ -37,11 +37,12 @@ function intoAnimation() {
yTarget: start.y,
zTarget: start.z,
});
this.intoPointAnimation.to(
{
x: worldP.x - 10,
y: worldP.y + 3,
z: worldP.z - 12,
x: worldP.x + 20,
y: worldP.y + 5,
z: worldP.z + 50,
xTarget: worldP.x,
yTarget: worldP.y,
zTarget: worldP.z,
@@ -54,4 +55,7 @@ function intoAnimation() {
this.camera.lookAt(obj.xTarget, obj.yTarget, obj.zTarget);
this.orbitControls.target.set(obj.xTarget, obj.yTarget, obj.zTarget);
});
this.intoPointAnimation.onComplete(() => {
this.camera.lookAt(worldP.x, worldP.y, worldP.z);
});
}

View File

@@ -1,10 +0,0 @@
export default function (meshId) {
return new Promise((resolve, reject) => {
if (!meshId) {
reject("null");
}
const mesh = this.scene.getObjectById(meshId);
this.scene.remove(mesh);
resolve("ok");
});
}

View File

@@ -1,4 +1,6 @@
import * as THREE from "three";
/**
* 返回一个带有文字的几何平面
* @param {String} text 把输入的文字转化为base64的img图片
*/
export default function (text, width = 100, height = 50) {
@@ -9,7 +11,10 @@ export default function (text, width = 100, height = 50) {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.font = "30px serif";
ctx.fillText(text, 0, 30);
return canvas.toDataURL();
ctx.font = "16px serif";
ctx.fillText(text, (100 - text.length * 16.6) / 2, 30);
const base64 = canvas.toDataURL();
return new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(base64),
});
}

View File

@@ -16,14 +16,37 @@ export function saveState() {
export function resetState() {
if (this.viewSate && this.viewSate.isSave) {
this.viewSate.isSave = false;
//恢复原始的镜头指向
this.camera.lookAt(0, 0, 0);
this.orbitControls.target.set(0, 0, 0);
this.orbitControls.enabled = true;
// //恢复原始的镜头指向
// this.camera.lookAt(0, 0, 0);
// this.orbitControls.target.set(0, 0, 0);
//创建动画
this.viewSateResetAnimation = new this.TWEEN.Tween(this.camera.position);
this.viewSateResetAnimation.to(this.viewSate.position, 800);
this.viewSateResetAnimation = new this.TWEEN.Tween({
x: this.camera.position.x,
y: this.camera.position.y,
z: this.camera.position.z,
tx: this.orbitControls.target.x,
ty: this.orbitControls.target.y,
tz: this.orbitControls.target.z,
});
this.viewSateResetAnimation.to(
{
x: this.viewSate.position.x,
y: this.viewSate.position.y,
z: this.viewSate.position.z,
tx: 0,
ty: 0,
tz: 0,
},
500
);
this.viewSateResetAnimation.start();
//清空boxHelper
this.scene.remove(this.scene.getObjectByName("boxHelper"));
this.viewSateResetAnimation.onUpdate((obj) => {
this.camera.position.set(obj.x, obj.y, obj.z);
this.camera.lookAt(obj.tx, obj.ty, obj.tz);
this.orbitControls.target.set(obj.tx, obj.ty, obj.tz);
}),
//清空boxHelper
this.scene.remove(this.scene.getObjectByName("boxHelper"));
}
}

View File

@@ -1,6 +1,6 @@
<template>
<div id="used-ele">
<div class="content" @click="handleOpenChart">
<div id="used-ele" :style="{ backgroundImage: 'url(' +getImageUrl(bgImage)+')' }" @click="handleOpenChart">
<div class="content" >
<div class="item">
<div></div>
<span>当月用电量{{ electricityConsumptionMonthly }}v</span>
@@ -11,7 +11,7 @@
</div>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isVisited" width="1365px" :modal="false">
<el-dialog v-model="isVisited" width="2400px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="top-tag">
@@ -28,7 +28,10 @@
<div class="value">345v</div>
</div>
</div>
<div id="containerEle"></div>
<div class="chat-dialog">
<div id="containerEle"></div>
<div style="width: 1px;"></div>
</div>
<div class="left-bottom-icon"></div>
<div class="right-bottom-icon"></div>
</el-dialog>
@@ -48,6 +51,11 @@ const isVisited = ref(false);
const eleData = ref([])
const electricityConsumptionMonthly = ref()
const monthlySavings = ref(55555)
const bgImage = computed(() =>
isVisited.value
? "bpq_active.png"
: "bg.png"
);
watch(() => props.eleData, (now) => {
getBasicData(now.frequencyChangerList)
}, {deep: true});
@@ -100,24 +108,28 @@ const initChart = () => {
legend: {
left: 0,
textStyle: {
color: '#FFFFFF',
fontSize: 28
color: '#60DDDE',
fontSize: 45
},
// itemWidth: 20,
// itemHeight: 20
itemWidth: 30,
itemHeight:30,
icon: "circle",
},
//离容器四侧的距离
grid: {
left: 0, // 左边距
right: 20, // 右边距
// top: 80, // 顶边距
top: 80, // 顶边距
bottom: 20, // 底边距
containLabel: true,
},
//提示框组件
tooltip: {
show: true,
trigger: 'axis'
trigger: 'axis',
textStyle: {
fontSize: 40
}
},
//X轴
xAxis: {
@@ -125,7 +137,7 @@ const initChart = () => {
data: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31'],
axisLabel: {
textStyle: {
fontSize: 24,
fontSize: 45,
color: '#D6F1FA'
},
},
@@ -135,7 +147,7 @@ const initChart = () => {
type: 'value',
axisLabel: {
textStyle: {
fontSize: 24,
fontSize: 45,
color: '#D6F1FA'
},
},
@@ -143,9 +155,15 @@ const initChart = () => {
//配置项
series: [
{
name:'日用电量',
data: [120, 200, 150, 80, 70, 110, 130, 100, 140, 130, 160, 150, 90, 130, 110, 120, 150, 140, 130, 120, 110, 100, 90, 80, 100, 140, 130, 160, 150, 24, 50],
type: 'bar'
},
{
name:'日节省量',
data: [140, 130, 160, 150, 90, 130, 110, 120, 150, 140, 130, 120, 110, 100, 90, 80, 100, 140, 130, 160, 150, 24, 50,120, 200, 150, 80, 70, 110, 130, 100, ],
type: 'bar'
},
]
}
myEcharts.setOption(option);
@@ -154,11 +172,17 @@ const initChart = () => {
myEcharts.resize();
}
}
const getImageUrl = (name) => {
return new URL(`../../../assets/images/usedEle/${name}`, import.meta.url).href
}
</script>
<style lang="scss" scoped>
:deep(.el-dialog__header) {
padding: 0!important;
}
#used-ele {
cursor: pointer;
width: 830px;
height: 90px;
color: aliceblue;
@@ -184,7 +208,6 @@ const initChart = () => {
align-items: center;
justify-content: space-between;
cursor: pointer;
.item {
height: 37px;
font-size: 28px;

View File

@@ -2,18 +2,43 @@
<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"/>
<wind-pressure-item v-for="(item,index) in wpList" :key="item.equipmentId" :wp="item" :index="index+1" @click="handleOpenChart(index+1)"/>
</div>
<div class="digital-tunnel">
<el-dialog v-model="isVisited" :title="windSort+'号风压监控数据'" width="2400px" :modal="false">
<div class="left-top-icon"></div>
<div class="right-top-icon"></div>
<div class="chat-dialog">
<div id="container"></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 WindPressureItem from "./childComps/WindPressureItem.vue";
import TimeRangeBtn from "@/components/timeRangeBtn/index.vue"
import * as echarts from 'echarts';
const props = defineProps({
list: Array,
winData: Array
});
const windSort=ref(1)
const timeList = ref(["年", "月", "日"]);
const selectTimeButton = ref(2);
const isVisited = ref(false);
let myEcharts = reactive({});
const wpList = ref([]);
watch(() => props.list, (now) => {
wpList.value.forEach(item=>{
@@ -28,7 +53,24 @@ 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 timeSelect = (index) => {
console.log('选择时间', index)
if(index===0){
console.log('--年')
}else if(index===1){
console.log('--月')
}else if(index===2){
console.log('--日')
}
};
const getScreenInfo = (now) => {
let windPressureObj = {}
let windPressureArr = []
@@ -44,6 +86,81 @@ const getScreenInfo = (now) => {
})
wpList.value = windPressureArr
}
/**
* 初始化echarts实例方法
*/
const initChart = () => {
//3.初始化container容器
myEcharts = echarts.init(document.getElementById('container'));
//5.传入数据
let option = {
//图例
legend: {
left: 0,
textStyle: {
color: '#FFFFFF',
fontSize: 40
},
// itemWidth: 20,
// itemHeight: 20
},
//离容器四侧的距离
grid: {
left: 0, // 左边距
right: 20, // 右边距
top: 80, // 顶边距
bottom: 0, // 底边距
containLabel: true,
},
//提示框组件
tooltip: {
show: true,
trigger: 'axis',
textStyle: {
fontSize: 40
}
},
//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
}
}
]
}
myEcharts.setOption(option);
//图表大小自适应窗口大小变化
window.onresize = () => {
myEcharts.resize();
}
}
</script>
<style lang="scss" scoped>

View File

@@ -99,7 +99,6 @@ let isWaring = computed(() => {
white-space: nowrap;
height: 37px;
font-size: 28px;
font-family: MicrosoftYaHei;
color: #d6f1fa;
line-height: 37px;
margin: 0 20px 0 14px;
@@ -125,7 +124,7 @@ let isWaring = computed(() => {
#point {
position: absolute;
height: 20px;
background: #60ddde;
background: #92D18F;
width: 3px;
border-radius: 4px;
box-shadow: 0 0 10px #92D18F;

View File

@@ -20,7 +20,6 @@ const btnList = ref([
icon: 'sp_icon_zdgl.png',
name: '站点管理'
},
{
icon: 'sp_icon_sdgl.png',
name: '隧道管理'

View File

@@ -47,16 +47,16 @@ watchEffect(() => {
<style scoped lang="scss">
.time-range-group {
width: 204px;
height: 68px;
//width: 254px;
//height: 78px;
border: 2px solid #0F82AF;
border-radius: 10px;
background: #062247;
display: flex;
font-size: 28px;
font-size: 40px;
.time-range-button {
cursor: pointer;
padding: 15px 20px;
padding: 18px 24px;
box-sizing: border-box;
color: #FFFFFF;
&.time-range-button-active {

View File

@@ -40,6 +40,24 @@ const routes = [
title: 'site',
breadcrumb: true
}
},
{
path: '/tunnel/:siteId(\\d+)',
name: 'tunnel',
component: () => import('@/views/tunnel-manage/index.vue'),
meta: {
title: 'tunnel',
breadcrumb: true
}
},
{
path: '/device/:tunnelId(\\d+)',
name: 'device',
component: () => import('@/views/device-manage/index.vue'),
meta: {
title: 'device',
breadcrumb: true
}
}
];

View File

@@ -0,0 +1,121 @@
<template>
<div class="tunnel-bgc">
<div class="box-top">
<div class="back-tunnel" @click="router.back(-1)">
<div class="back-icon"></div>
<span>返回</span>
</div>
<div class="tunnel-name">
一号隧道
</div>
<div class="tunnel-title"></div>
</div>
<div class="device-content">
<div class="device-box">
<div class="box-left">
<!-- <div>风机</div>-->
<!-- <div>风压</div>-->
<!-- <div>其他传感器</div>-->
<el-menu
default-active="1"
>
<el-menu-item index="1">
<span>风机</span>
</el-menu-item>
<el-menu-item index="2">
<span>风压</span>
</el-menu-item>
<el-menu-item index="3">
<span>其他传感器</span>
</el-menu-item>
</el-menu>
</div>
<div class="box-right">
</div>
</div>
</div>
</div>
</template>
<script setup>
const router = useRouter()
</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: flex-start;
.tunnel-name {
margin-left: 120px;
height: 61px;
font-size: 46px;
font-weight: bold;
color: #FFFFFF;
line-height: 61px;
}
.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');
}
}
}
.device-content {
display: flex;
justify-content: center;
padding-top: 246px;
.device-box {
display: flex;
width: 2194px;
height: 1321px;
background: #064B66;
border-radius: 20px;
border: 2px solid #05FEFF;
box-sizing: border-box;
.box-left {
width: 300px;
height: 1318px;
background: #0D5A7A;
border-radius: 20px 0px 0px 20px;
:deep(.el-menu){
border-right: none;
margin-top: 261px;
background-color: #0D5A7A;
}
}
.box-right {
flex: 1;
}
}
}
}
</style>

View File

@@ -7,150 +7,251 @@
</div>
<div class="tunnel-title"></div>
<div class="all-del-btn">
<div class="all-btn" style=" margin-right: 40px;" v-if="!showAddIcon" @click="handleAdd">
添加
</div>
<div class="all-btn">
全选
</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">
<div class="site-box" v-for="item in siteList" :key="item.siteId">
<div class="top">
<span>站点名称{{ item.siteName }}</span>
<div @click.stop="handleClickSite"><span :class="{ clickColor: isClick }"></span></div>
<el-checkbox v-model="item.checked" size="large" @change="handleClickSite(item)"/>
</div>
<div class="box-center">
<div class="left-img"></div>
<div class="right-tunnel">
<div>隧道数量{{ item.num }}</div>
<div>隧道数量{{ item.info.tunnelNum }}
</div>
<div>
<div class="tunnel">
<div>{{ item.sortTunnel }}</div>
<div class="tunnel" v-if="showFirstTunnel">
<div>{{ item.info.tunnelName }}</div>
<div class="tunnel-icon"></div>
<div>施工长度{{ item.constructionLength }}</div>
<div>实现长度{{ item.implementationLength }}公里</div>
<div>施工长度{{ item.info.constructionLength }}</div>
<div>实现长度{{ item.info.implementationLength }}公里
</div>
</div>
<div class="tunnel-add">
<div class="tunnel-add" @click="goToAddTunnel(item.siteId)">
<div class="add-icon"></div>
</div>
</div>
<div class="more">
<div class="more" @click="router.push('/tunnel')" v-if="showFirstTunnel">
更多
<div class="icon"></div>
</div>
</div>
</div>
<div class="edit-btn" @click="isVisited=true">
<div class="edit-btn" @click="handleEdit(item.siteId)">
<div class="edit-icon"></div>
<div>站点编辑</div>
</div>
</div>
<div class="site-box add-box" @click="isVisited=true">
<div class="site-box add-box" v-if="showAddIcon" @click="handleAdd">
<div class="add-icon"></div>
<div style="cursor: pointer">添加站点</div>
</div>
</div>
<el-dialog v-model="isVisited" width="958px">
<el-dialog v-model="isVisited" width="1958px">
<div class="siteId">
<span>站点id{{ siteId }}</span>
<span>站点管理员id{{ siteManageId }}</span>
<span>{{ title }}</span>
</div>
<el-form :model="form" :label-position="right" label-width="116px">
<el-form :model="form" :label-position="right" :rules="formRules" ref="formInstance" label-width="168px">
<el-form-item label="站点名称">
<el-input v-model="form.siteName" placeholder="请输入站点名称"/>
</el-form-item>
<el-form-item label="站点地址">
<el-input v-model="form.address" placeholder="请输入站点地址"/>
</el-form-item>
<el-form-item label="站点名称">
<el-input v-model="form.name" placeholder="请输入站点名称"/>
</el-form-item>
<el-form-item label="站点描述">
<el-input v-model="form.desc" type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" placeholder="请输入站点信息"/>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" placeholder="请输入备注"/>
<el-input v-model="form.describe" type="textarea" :autosize="{ minRows: 5, maxRows: 7 }"
placeholder="请输入站点信息"/>
</el-form-item>
</el-form>
<div class="btns">
<div class="cancel-btn" @click="isVisited=false">
取消
<template #footer>
<div class="btns">
<div class="cancel-btn" @click="isVisited=false">
取消
</div>
<div class="sure-btn" @click="handleSubmit(formInstance)">
确定
</div>
</div>
<div class="sure-btn">
确定
</div>
</div>
</template>
</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 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 {editSite, getSiteDetail, getSiteList, addSite, deleteSite} from "@/api/site";
import {ElMessage, ElMessageBox} from "element-plus";
const router = useRouter()
const siteList = ref([
{
siteName: '松江站',
num: 1,
sortTunnel: '一号隧道',
constructionLength: 500,
implementationLength: 10
},
{
siteName: '松江站',
num: 1,
sortTunnel: '一号隧道',
constructionLength: 500,
implementationLength: 10
},
{
siteName: '松江站',
num: 1,
sortTunnel: '一号隧道',
constructionLength: 500,
implementationLength: 10
},
{
siteName: '松江站',
num: 1,
sortTunnel: '一号隧道',
constructionLength: 500,
implementationLength: 10
},
{
siteName: '松江站',
num: 1,
sortTunnel: '一号隧道',
constructionLength: 500,
implementationLength: 10
},
])
const siteId = ref('iu78686')
const siteManageId = ref('j98h0')
const siteList = ref([])
const siteIds = ref([])
const siteNameList = ref([])
const info = ref({
tunnelNum: 0,
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 pageInfo = reactive({
pageNum: 1,
pageSize: 6
});
const form = ref({
address: '',
name: '',
desc: '',
remark: ''
siteName: '',
describe: ''
});
const handleClickSite = () => {
isClick.value = !isClick.value
const formRules = ref({
siteName: [{required: true, message: '请输入站点名称', trigger: 'blur'}]
})
const formInstance = ref()
const getList = () => {
getSiteList({
...pageInfo
}).then((res) => {
total.value = res.data.total;
showAddIcon.value = total.value !== 6;
res.data.rows.map(item => {
if (item.tunnelList === null || item.tunnelList === []) {
showFirstTunnel.value = false
}
item.info = info.value
item.checked = false
})
siteList.value = res.data.rows;
});
}
getList()
const handleClickSite = (type) => {
if (type.checked) {
siteIds.value.push(type.siteId)
siteNameList.value.push(type.siteName)
} else {
siteIds.value.map((item, index) => {
if (item === type.siteId) {
siteIds.value.splice(index, 1)
}
})
siteNameList.value.map((item, index) => {
if (item === type.siteName) {
siteNameList.value.splice(index, 1)
}
})
}
}
const goToAddTunnel = (siteId) => {
router.push('/tunnel/' + siteId)
}
//重置from表单
const restFrom = () => {
form.value = {
address: '',
siteName: '',
describe: ''
}
}
const handleEdit = (siteId) => {
title.value = '编辑站点'
restFrom()
getSiteDetail(siteId).then((res) => {
form.value = res.data;
isVisited.value = true
});
}
const handleAdd = () => {
restFrom()
title.value = '新增站点'
isVisited.value = true
}
const handleSubmit = (instance) => {
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()
});
}
})
}
const handleMoreDelete = () => {
if (siteIds.value.length === 0) {
ElMessage.warning('请先选择站点进行删除')
} else {
ElMessageBox.confirm(`是否确定删除该站点`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
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)
}
})
})
}
}
//点击页码进行分页功能
const handleCurrentChange = async (val) => {
pageInfo.pageNum = val
await getList()
}
</script>
<style scoped lang="scss">
.siteId {
font-size: 30px;
color: #FFFFFF;
margin-bottom: 48px;
.clickColor {
position: absolute;
top: 7px;
left: 6.5px;
width: 25px;
height: 25px;
background-color: #05FEFF;
border-radius: 25px;
}
> span:first-child {
margin-right: 70px;
}
.siteId {
display: flex;
justify-content: center;
margin: 0 0 60px 0;
font-size: 50px;
color: #FFFFFF;
}
.btns {
@@ -159,72 +260,40 @@ const handleClickSite = () => {
margin-top: 80px;
.cancel-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 190px;
height: 60px;
width: 220px;
height: 80px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #08B7B8;
line-height: 60px;
padding-left: 67px;
font-size: 28px;
line-height: 80px;
font-size: 38px;
box-sizing: border-box;
}
.sure-btn {
display: flex;
justify-content: center;
cursor: pointer;
width: 190px;
height: 60px;
line-height: 60px;
width: 220px;
height: 80px;
line-height: 80px;
background: #08B7B8;
border-radius: 11px;
color: #FFFFFF;
font-size: 28px;
padding-left: 67px;
font-size: 38px;
}
}
:deep(.el-form-item) {
margin-top: 40px;
}
:deep(.el-form-item__label) {
font-size: 26px;
font-family: MicrosoftYaHei;
color: #FFFFFF;
margin-right: 12px;
line-height: 50px;
}
:deep(.el-input) {
height: 50px;
.el-input__wrapper {
background-color: transparent;
border: 1px solid #08B7B8;
.el-input__inner {
color: #fff;
font-size: 26px;
}
}
}
:deep(.el-textarea__inner) {
background-color: transparent;
border: 1px solid #08B7B8;
//min-height: 50px!important;
color: #fff;
font-size: 26px;
}
:deep(.el-dialog) {
border: 2px solid #05FEFF;
background: #0D6578;
border-radius: 20px;
padding: 30px 40px;
box-sizing: border-box;
margin: 588px auto 0 auto;
margin: 458px auto 0 auto;
.el-dialog__header {
padding: 0;
@@ -232,7 +301,43 @@ const handleClickSite = () => {
}
}
: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-textarea__inner) {
background-color: transparent;
border: 1px solid #08B7B8;
color: #fff;
font-size: 38px;
}
.site-bgc {
background-color: #072348;
padding: 85px 0 0 0;
width: 100%;
height: 100%;
@@ -247,19 +352,19 @@ const handleClickSite = () => {
margin: 0 0 0 70px;
display: flex;
align-items: center;
width: 168px;
height: 60px;
line-height: 60px;
width: 178px;
height: 70px;
line-height: 70px;
border-radius: 11px;
border: 2px solid #08B7B8;
font-size: 28px;
font-size: 38px;
color: #FFFFFF;
.back-icon {
margin-right: 20px;
margin-left: 33px;
width: 26px;
height: 26px;
margin-left: 23px;
width: 33px;
height: 33px;
background-image: url('@/assets/images/site/zdgl_icon_fh.png');
}
}
@@ -276,14 +381,14 @@ const handleClickSite = () => {
.all-btn {
cursor: pointer;
padding-left: 56px;
width: 168px;
height: 60px;
line-height: 60px;
padding-left: 53px;
width: 178px;
height: 70px;
line-height: 70px;
border-radius: 11px;
border: 2px solid #08B7B8;
color: #FFFFFF;
font-size: 28px;
font-size: 38px;
&:last-child {
margin-left: 40px;
@@ -304,7 +409,7 @@ const handleClickSite = () => {
cursor: pointer;
font-weight: bold;
color: #60DDDE;
font-size: 32px;
font-size: 38px;
display: flex;
flex-direction: column;
align-items: center;
@@ -320,43 +425,33 @@ const handleClickSite = () => {
.site-box {
margin-top: 122px;
//margin-right: 122px;
//margin-right: 60px;
padding: 40px 50px;
width: 1158px;
height: 718px;
width: 1250px;
height: 750px;
background-image: url('@/assets/images/site/zdgl_bj.png');
//box-sizing: border-box;
position: relative;
&:nth-child(3) {
&:nth-child(3n) {
margin-right: 0;
}
.top {
display: flex;
justify-content: space-between;
font-size: 32px;
font-size: 45px;
font-weight: bold;
color: #FFFFFF;
line-height: 42px;
> div:last-child {
cursor: pointer;
width: 30px;
height: 30px;
width: 40px;
height: 40px;
border: 2px solid #05FEFF;
border-radius: 25px;
position: relative;
.clickColor {
position: absolute;
top: 5.5px;
left: 5.5px;
width: 16px;
height: 16px;
background-color: #05FEFF;
border-radius: 25px;
}
}
}
@@ -366,8 +461,8 @@ const handleClickSite = () => {
.left-img {
margin-top: 50px;
margin-right: 60px;
width: 480px;
height: 350px;
width: 500px;
height: 370px;
background-image: url('@/assets/images/site/zdgl_zd.png');
}
@@ -375,7 +470,7 @@ const handleClickSite = () => {
position: relative;
> div:first-child {
font-size: 32px;
font-size: 38px;
font-family: MicrosoftYaHei;
color: #FFFFFF;
line-height: 42px;
@@ -386,21 +481,19 @@ const handleClickSite = () => {
margin-top: 29px;
.tunnel {
width: 256px;
height: 310px;
margin-right: 20px;
width: 280px;
height: 350px;
background: #3FBED1;
border-radius: 16px;
display: flex;
flex-direction: column;
//justify-content: center;
align-items: center;
color: #FFFFFF;
> div:first-child {
width: 112px;
height: 37px;
font-size: 28px;
line-height: 37px;
font-size: 32px;
margin-top: 20px;
}
@@ -409,21 +502,20 @@ const handleClickSite = () => {
}
> div:nth-child(3), > div:nth-child(4) {
font-size: 26px;
font-size: 32px;
}
.tunnel-icon {
width: 62px;
height: 64px;
width: 82px;
height: 84px;
background-image: url('@/assets/images/site/zdgl_icon_sd.png');
margin: 30px 0 40px 0;
margin: 30px 0 30px 0;
}
}
.tunnel-add {
margin-left: 20px;
width: 256px;
height: 310px;
width: 280px;
height: 350px;
background: #1891A3;
border-radius: 16px;
display: flex;
@@ -432,8 +524,8 @@ const handleClickSite = () => {
.add-icon {
cursor: pointer;
width: 112px;
height: 112px;
width: 122px;
height: 122px;
background-image: url('@/assets/images/site/zdgl_icon_tjz.png');
}
}
@@ -448,13 +540,13 @@ const handleClickSite = () => {
right: 0;
font-weight: bold;
color: #35C5CC;
font-size: 28px;
font-size: 38px;
.icon {
margin-left: 19px;
transform: rotate(180deg);
width: 26px;
height: 26px;
width: 33px;
height: 33px;
background-image: url('@/assets/images/site/zdgl_icon_fh.png');
}
}
@@ -462,47 +554,48 @@ const handleClickSite = () => {
}
.edit-btn {
width: 174px;
cursor: pointer;
margin-top: 147px;
margin-top: 117px;
display: flex;
align-items: center;
font-size: 32px;
font-size: 40px;
color: #60DDDE;
line-height: 42px;
margin-left: 492px;
.edit-icon {
width: 30px;
height: 32px;
width: 42px;
height: 44px;
background-image: url('@/assets/images/site/zdgl_icon_bj.png');
margin-right: 16px;
}
}
}
}
.pagination {
margin-top: 120px;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
bottom: 80px;
display: flex;
justify-content: center;
align-items: center;
color: #60DDDE;
font-size: 32px;
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: 32px;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;
@@ -511,7 +604,7 @@ const handleClickSite = () => {
:deep(.btn-next) {
background-color: transparent;
font-size: 32px;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;
@@ -519,12 +612,12 @@ const handleClickSite = () => {
}
:deep(.el-pager li.is-active ) {
width: 60px;
height: 60px;
width: 70px;
height: 70px;
background: #60DDDE;
border-radius: 50%;
color: #071F40;
font-size: 32px;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
}
@@ -534,12 +627,12 @@ const handleClickSite = () => {
}
:deep(.el-pager li:not(.is-active) ) {
width: 60px;
height: 60px;
width: 70px;
height: 70px;
border: 1px solid #60DDDE;
border-radius: 50%;
background-color: transparent;
font-size: 32px;
font-size: 38px;
font-family: MicrosoftYaHei, MicrosoftYaHei;
font-weight: bold;
color: #60DDDE;

View File

@@ -0,0 +1,627 @@
<template>
<div class="tunnel-bgc">
<div class="box-top">
<div class="back-tunnel" @click="router.back(-1)">
<div class="back-icon"></div>
<span>返回</span>
</div>
<div class="tunnel-title"></div>
<div class="all-del-btn">
<div class="all-btn">
全选
</div>
<div class="all-btn del-btn">
删除
</div>
</div>
</div>
<div class="box-content">
<div class="site-box" v-for="item in siteList" :key="item.tunnelId">
<div class="top">
<span>{{ item.tunnelName }}</span>
<span>施工长度500米 隧道长度10公里</span>
<el-checkbox v-model="item.checked" size="large" @change="handleClickSite(item)"/>
</div>
<div class="box-center">
<div>
<div class="left-img"></div>
<div>
<div class="edit-btn" @click="handleEdit">
<div class="edit-icon"></div>
<div>隧道编辑</div>
</div>
<div class="edit-btn" @click="handleEditDevice">
<div class="edit-icon-two"></div>
<div>设备管理</div>
</div>
</div>
</div>
<div class="tunnel-right">
<div>
<div class="fan-icon"></div>
<span>风机异常</span>
</div>
<div class="icons-block">
<div v-for="item in iconsList" :key="item.icon" class="icon-text">
<div :style="{ backgroundImage: 'url(' +getImageUrl(item.icon)+')' }" class="icon"></div>
<span>{{ item.name }}{{ item.num }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="site-box add-box" @click="handleAdd">
<div class="add-icon"></div>
<div style="cursor: pointer">添加隧道</div>
</div>
</div>
<el-dialog v-model="isVisited" width="1958px">
<div class="siteId">
<span>{{ title }}</span>
</div>
<el-form :model="form" :label-position="right" label-width="168px">
<el-form-item label="隧道名称">
<el-input v-model="form.name" placeholder="请输入隧道名称"/>
</el-form-item>
<el-form-item label="序列号">
<el-input v-model="form.serialNumber" placeholder="请输入序列号"/>
</el-form-item>
<el-form-item label="隧道长度">
<el-input type="number" v-model="form.tunnelLength" placeholder="请输入隧道长度"/>
</el-form-item>
<el-form-item label="隧道备注">
<el-input v-model="form.remarks" placeholder="请输入隧道备注"/>
</el-form-item>
</el-form>
<div class="btns">
<div class="cancel-btn" @click="isVisited=false">
取消
</div>
<div class="sure-btn">
确定
</div>
</div>
</el-dialog>
<div class="pagination">
<span>首页</span>
<el-pagination background :page-size="6" :total="50" prev-text="上一页" next-text="下一页" layout="prev, pager, next"/>
<span>尾页</span>
</div>
</div>
</template>
<script setup>
const router = useRouter()
const siteId = reactive(router.currentRoute.value.params.siteId)
const siteList = ref([
{
tunnelName: '一号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '二号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
{
tunnelName: '三号隧道',
num: 1,
constructionLength: 500,
implementationLength: 10
},
])
const iconsList = ref([
{
icon: 'white-state-icon.png',
name: '风机',
num: 2
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
num: '无'
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 2
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
num: '无'
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
{
icon: 'white-state-icon.png',
name: '风机',
num: 11
},
])
const title = ref('新增隧道')
const isVisited = ref(false);
const tunnelIds = ref([])
const tunnelNameList = ref([])
const form = ref({
name: '',
serialNumber: '',
tunnelLength: '',
remarks: ''
});
const handleEdit = () => {
title.value = '编辑隧道'
isVisited.value = true
}
const handleEditDevice = () => {
router.push('/device/'+1)
}
const handleAdd = () => {
title.value = '新增隧道'
isVisited.value = true
}
const getImageUrl = (name) => {
return new URL(`../../assets/images/tunnel/${name}`, import.meta.url).href
}
const handleClickSite = (type) => {
if (type.checked) {
// tunnelIds.value.push(type.siteId)
// tunnelNameList.value.push(type.siteName)
} else {
// tunnelIds.value.map((item, index) => {
// if (item === type.siteId) {
// tunnelIds.value.splice(index, 1)
// }
// })
// tunnelNameList.value.map((item, index) => {
// if (item === type.siteName) {
// tunnelNameList.value.splice(index, 1)
// }
// })
}
}
</script>
<style scoped lang="scss">
: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;
}
}
}
.siteId {
display: flex;
justify-content: center;
margin: 0 0 60px 0;
font-size: 50px;
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;
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;
}
}
}
}
.box-content {
display: flex;
flex-wrap: wrap;
padding-left: 67px;
padding-right: 70px;
justify-content: space-between;
.add-box {
cursor: pointer;
font-weight: bold;
color: #60DDDE;
font-size: 38px;
display: flex;
flex-direction: column;
align-items: center;
.add-icon {
margin-top: 110px;
margin-bottom: 87px;
width: 220px;
height: 220px;
background-image: url('@/assets/images/site/zdgl_icon_tjz.png');
}
}
.site-box {
margin-top: 50px;
//margin-right: 122px;
padding: 40px 30px;
width: 925px;
height: 550px;
background-image: url('@/assets/images/site/zdgl_bj.png');
//box-sizing: border-box;
position: relative;
&:nth-child(3) {
margin-right: 0;
}
.top {
display: flex;
justify-content: space-between;
font-size: 45px;
font-weight: bold;
color: #FFFFFF;
line-height: 42px;
> span:nth-child(2) {
font-size: 38px;
color: #5CE4F2;
}
> div:last-child {
cursor: pointer;
width: 40px;
height: 40px;
border: 2px solid #05FEFF;
border-radius: 25px;
position: relative;
.clickColor {
position: absolute;
top: 7px;
left: 6.5px;
width: 25px;
height: 25px;
background-color: #05FEFF;
border-radius: 25px;
}
}
}
.box-center {
display: flex;
//flex-direction: column;
> div:first-child {
> div:nth-child(2) {
display: flex;
align-items: center;
justify-content: space-between;
margin-right:30px;
}
}
.left-img {
margin-top: 110px;
margin-right: 70px;
width: 340px;
height: 148px;
background-image: url('@/assets/images/tunnel/sdgl_sdt.png');
}
.edit-btn {
cursor: pointer;
margin-top: 100px;
display: flex;
align-items: center;
justify-content: flex-start;
font-size: 34px;
color: #60DDDE;
//margin-left: 175px;
.edit-icon {
width: 32px;
height: 34px;
background-image: url('@/assets/images/site/zdgl_icon_bj.png');
margin-right: 10px;
}
.edit-icon-two {
width: 32px;
height: 34px;
background-image: url('@/assets/images/tunnel/device.png');
margin-right: 10px;
}
}
.tunnel-right {
padding-top: 40px;
> div:first-child {
display: flex;
align-items: center;
font-size: 36px;
color: #FB3838;
.fan-icon {
margin-right: 10px;
width: 32px;
height: 32px;
background-image: url('@/assets/images/tunnel/sp_icon_yc.png');
}
}
.icons-block {
margin-top: 30px;
display: flex;
flex-wrap: wrap;
.icon-text {
display: flex;
justify-content: space-between;
align-items: center;
color: #FFFFFF;
font-size: 36px;
margin-right: 27px;
margin-bottom: 30px;
&:nth-child(2n) {
margin-right: 0;
}
.icon {
width: 32px;
height: 32px;
margin-right: 10px;
}
}
}
}
}
}
}
.pagination {
display: flex;
align-items: center;
position: absolute;
left: 50%;
transform: translate(-50%,-50%);
bottom: 50px;
color: #60DDDE;
font-size: 38px;
font-weight: bold;
> span:first-child {
margin-right: 60px;
}
> span:last-child {
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>

View File

@@ -99,10 +99,11 @@ import { onMounted } from "vue";
import { getToken } from "@/utils/auth";
import { useAuthStore } from "@/store/userstore.js";
import { getLargeScreen } from "@/api/largeScreen";
import {ElMessageBox} from "element-plus";
const authStore = useAuthStore();
const router = useRouter();
const selectIndex = ref(1);
const selectIndex = ref(-1);
const showFan = ref(false);
const drawerLeft = ref(true);
const drawerRight = ref(true);
@@ -167,6 +168,8 @@ const manageSelect = (index) => {
console.log("首页点击-", index);
if (index === 0) {
router.push("/site");
}else if (index === 1){
router.push("/tunnel/1");
}
};
const closeLeft = () => {
@@ -176,8 +179,14 @@ const closeRight = () => {
drawerRight.value = !drawerRight.value;
};
const handleLogout = () => {
authStore.userLogout();
router.push("/login");
ElMessageBox.confirm(`确认退出登录吗`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
authStore.userLogout();
router.push("/login");
})
};
const previousBtn = () => {
tunnelBtn.value.prev();
@@ -235,6 +244,7 @@ initWebSocket();
#main {
height: 100%;
width: 100%;
background-color: #072348;
#tunnel-box {
height: 100%;
}